📄 token.c
字号:
/* * =========================================================================== * PRODUCTION $Log: token.c,v $ * PRODUCTION Revision 1000.1 2004/04/01 21:01:24 gouriano * PRODUCTION PRODUCTION: UPGRADED [CORE_002] Dev-tree R1.5 * PRODUCTION * =========================================================================== *//* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998-1999 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include <tds_config.h>#include "tds.h"#include "tdsutil.h"#include "tdsconvert.h"#ifdef DMALLOC#include <dmalloc.h>#endifstatic char software_version[] = "$Id: token.c,v 1000.1 2004/04/01 21:01:24 gouriano Exp $";static void *no_unused_var_warn[] = {software_version, no_unused_var_warn};static int tds_process_msg(TDSSOCKET *tds,int marker);static int tds_process_compute_result(TDSSOCKET *tds);static int tds_process_result(TDSSOCKET *tds);static int tds_process_col_name(TDSSOCKET *tds);static int tds_process_col_info(TDSSOCKET *tds);static int tds_process_compute(TDSSOCKET *tds);static int tds_process_row(TDSSOCKET *tds);static int tds_process_param_result(TDSSOCKET *tds);static int tds7_process_result(TDSSOCKET *tds);static int tds_process_param_result_tokens(TDSSOCKET *tds);static void tds_process_dyn_result(TDSSOCKET *tds);static int tds_process_dynamic(TDSSOCKET *tds);static int tds_process_auth(TDSSOCKET *tds);static int tds_get_varint_size(int datatype);static int tds_get_cardinal_type(int datatype);void tds_swap_datatype(int coltype, unsigned char *buf);/*** The following little table is indexed by precision and will** tell us the number of bytes required to store the specified** precision.*/extern const int g__numeric_bytes_per_prec[];/*** tds_process_default_tokens() is a catch all function that is called to** process tokens not known to other tds_process_* routines*/int tds_process_default_tokens(TDSSOCKET *tds, int marker){int order_len;int tok_size;int more_results;int cancelled; tdsdump_log(TDS_DBG_FUNC, "%L inside tds_process_default_tokens() marker is %x\n", marker); if (!tds->s) { tdsdump_log(TDS_DBG_FUNC, "%L leaving tds_process_default_tokens() connection dead\n"); tds->state=TDS_DEAD; return TDS_FAIL; } switch(marker) { case TDS_AUTH_TOKEN: tds_process_auth(tds); break; case TDS_ENV_CHG_TOKEN: { tds_process_env_chg(tds); break; } case TDS_DONE_TOKEN: case TDS_DONEPROC_TOKEN: case TDS_DONEINPROC_TOKEN: { tds_process_end(tds, marker, &more_results, &cancelled); if (!more_results) tds->state=TDS_COMPLETED; break; } case TDS_124_TOKEN: tds_get_n(tds,NULL,8); break; case TDS_RET_STAT_TOKEN: tds->has_status=1; tds->ret_status=tds_get_int(tds); break; case TDS_ERR_TOKEN: case TDS_MSG_TOKEN: case TDS_EED_TOKEN: return tds_process_msg(tds,marker); break; case TDS_CAP_TOKEN: tok_size = tds_get_smallint(tds); tds_get_n(tds,tds->capabilities,tok_size > TDS_MAX_CAPABILITY ? TDS_MAX_CAPABILITY : tok_size); break; case TDS_LOGIN_ACK_TOKEN: tds_get_n(tds,NULL,tds_get_smallint(tds)); break; case TDS_ORDER_BY_TOKEN: order_len = tds_get_smallint(tds); tds_get_n(tds, NULL, order_len); /* get the next token which is ROW_TOKEN (209) tds_get_byte(tds); if(orderLen > 1) tds_process_column_row(tds); */ break; case TDS_168_TOKEN: tds_process_compute_result(tds); break; case TDS_PARAM_TOKEN: tds_unget_byte(tds); tds_process_param_result_tokens(tds); break; /* 167 is somehow related to compute columns */ case TDS_167_TOKEN: case TDS_174_TOKEN: tds_get_n(tds, NULL, tds_get_smallint(tds)); break; case TDS7_RESULT_TOKEN: tds7_process_result(tds); break; case TDS_RESULT_TOKEN: tds_process_result(tds); break; case TDS_COL_NAME_TOKEN: tds_process_col_name(tds); break; case TDS_COL_INFO_TOKEN: tds_process_col_info(tds); break; case TDS_CMP_ROW_TOKEN: tds_process_compute(tds); break; case TDS_ROW_TOKEN: tds_process_row(tds); break; case TDS5_DYN_TOKEN: case TDS5_DYNRES_TOKEN: case TDS5_DYN3_TOKEN:#ifdef NCBI_FTDS case TDS_COL_INFO_TOKEN2:#endif tdsdump_log(TDS_DBG_WARN, "eating token %d\n",marker); tds_get_n(tds, NULL, tds_get_smallint(tds)); break; default: tdsdump_log(TDS_DBG_ERROR, "Unknown marker: %d(%x)!!\n",marker,(unsigned char)marker); return TDS_FAIL; } return TDS_SUCCEED;} /*** tds_process_login_tokens() is called after sending the login packet ** to the server. It returns the success or failure of the login ** dependent on the protocol version. 4.2 sends an ACK token only when** successful, TDS 5.0 sends it always with a success byte within*/int tds_process_login_tokens(TDSSOCKET *tds){int succeed=0;int marker;int len;unsigned char major_ver, minor_ver;unsigned char ack;#ifdef WORDS_BIGENDIANchar *tmpbuf;#endif tdsdump_log(TDS_DBG_FUNC, "%L inside tds_process_login_tokens()\n"); /* get_incoming(tds->s); */ do { marker=tds_get_byte(tds); switch(marker) { case TDS_AUTH_TOKEN: tds_process_auth(tds); break; case TDS_LOGIN_ACK_TOKEN: len = tds_get_smallint(tds); ack = tds_get_byte(tds); major_ver = tds_get_byte(tds); minor_ver = tds_get_byte(tds); tds_get_n(tds, NULL, len-4); tds_get_byte(tds);#ifdef WORDS_BIGENDIAN/* if (major_ver==7) { tds->broken_dates=1; }*/#endif/* tmpbuf = (char *) malloc(len); tds_get_n(tds, tmpbuf, len); tdsdump_log(TDS_DBG_INFO1, "%L login ack marker = %d\n%D\n", marker, tmpbuf, len); free(tmpbuf);*/ /* TDS 5.0 reports 5 on success 6 on failure ** TDS 4.2 reports 1 on success and is not ** present on failure */ if (ack==5 || ack==1) succeed=TDS_SUCCEED; break; default: if (tds_process_default_tokens(tds,marker)==TDS_FAIL) return TDS_FAIL; break; } } while (marker!=TDS_DONE_TOKEN); tdsdump_log(TDS_DBG_FUNC, "%L leaving tds_process_login_tokens() returning %d\n",succeed); return succeed;}static int tds_process_auth(TDSSOCKET *tds){int pdu_size, ntlm_size;char nonce[10];/* char domain[30]; */int where = 0; pdu_size = tds_get_smallint(tds); tdsdump_log(TDS_DBG_INFO1, "TDS_AUTH_TOKEN PDU size %d\n", pdu_size); tds_get_n(tds, NULL, 8); /* NTLMSSP\0 */ where += 8; tds_get_int(tds); /* sequence -> 2 */ where += 4; tds_get_n(tds, NULL, 4); /* domain len (2 time) */ where += 4; ntlm_size = tds_get_int(tds); /* size of remainder of ntlmssp packet */ where += 4; tdsdump_log(TDS_DBG_INFO1, "TDS_AUTH_TOKEN NTLMSSP size %d\n", ntlm_size); tds_get_n(tds, NULL, 4); /* flags */ where += 4; tds_get_n(tds, nonce, 8); where += 8; tdsdump_log(TDS_DBG_INFO1, "TDS_AUTH_TOKEN nonce\n"); tdsdump_dump_buf(nonce, 8); tds_get_n(tds, NULL, 8); where += 8; /* tds_get_ntstring(tds, domain, 30); tdsdump_log(TDS_DBG_INFO1, "TDS_AUTH_TOKEN domain %s\n", domain); where += strlen(domain); */ tds_get_n(tds, NULL, pdu_size - where); tdsdump_log(TDS_DBG_INFO1,"%L Draining %d bytes\n", pdu_size - where); tds7_send_auth(tds, nonce); return TDS_SUCCEED;}/*** tds_process_result_tokens() is called after submitting a query with** tds_submit_query() and is responsible for calling the routines to** populate tds->res_info if appropriate (some query have no result sets)*/int tds_process_result_tokens(TDSSOCKET *tds){int result=0;int marker;int more_results = 0;int cancelled;int retcode=TDS_NO_MORE_RESULTS;int rc; if (tds->state==TDS_COMPLETED) { /* tds_process_row() now eats the end marker and sets ** state to TDS_COMPLETED */ return TDS_NO_MORE_RESULTS; } /* get_incoming(tds->s); */ do { marker=tds_get_byte(tds);tdsdump_log(TDS_DBG_INFO1, "%L processing result tokens. marker is %x\n", marker); switch(marker) { case TDS_ERR_TOKEN: case TDS_MSG_TOKEN: case TDS_EED_TOKEN: rc = tds_process_msg(tds,marker); /* don't fail until we get a DONE */ if (rc == TDS_ERROR) retcode=TDS_FAIL; break; case TDS7_RESULT_TOKEN: if (!result) { tds7_process_result(tds); result++; } else { tds_unget_byte(tds); return TDS_SUCCEED; } break; case TDS_RESULT_TOKEN: if (!result) { tds_process_result(tds); result++; } else { tds_unget_byte(tds); return TDS_SUCCEED; } break; case TDS_COL_NAME_TOKEN: if (!result) { tds_process_col_name(tds); result++; } else { tds_unget_byte(tds); return TDS_SUCCEED; } break; case TDS_ROW_TOKEN: if (!result) { } else { tds->res_info->rows_exist=1; tds_unget_byte(tds); return TDS_SUCCEED; }#ifdef NCBI_FTDS break; /* <-- looks like it should be here (v. soussov) */#endif case TDS_RET_STAT_TOKEN: tds->has_status=1; tds->ret_status=tds_get_int(tds); /* return TDS_SUCCEED; */ break; case TDS5_DYN_TOKEN: tds->cur_dyn_elem = tds_process_dynamic(tds); break; case TDS5_DYNRES_TOKEN: tds_process_dyn_result(tds); break; case TDS_DONE_TOKEN: case TDS_DONEPROC_TOKEN: case TDS_DONEINPROC_TOKEN: tds_process_end(tds, marker, &more_results, &cancelled); break; default: if (tds_process_default_tokens(tds, marker)==TDS_FAIL) return TDS_FAIL; break; } } while (!is_end_token(marker) || more_results); tds->state=TDS_COMPLETED; return retcode;}/* ** tds_process_row_tokens() is called once a result set has been obtained** with tds_process_result_tokens(). It calls tds_process_row() to copy** data into the row buffer.*/int tds_process_row_tokens(TDSSOCKET *tds){int marker;int more_results;int cancelled; if (tds->state==TDS_COMPLETED) { return TDS_NO_MORE_ROWS; } while (1) { marker=tds_get_byte(tds); tdsdump_log(TDS_DBG_INFO1, "%L processing row tokens. marker is %x\n", marker); switch(marker) { case TDS_RESULT_TOKEN: case TDS7_RESULT_TOKEN: tds_unget_byte(tds); return TDS_NO_MORE_ROWS; case TDS_ROW_TOKEN: tds_process_row(tds); return TDS_SUCCEED; case TDS_DONE_TOKEN: case TDS_DONEPROC_TOKEN: case TDS_DONEINPROC_TOKEN: tds_process_end(tds, marker, &more_results, &cancelled); tds->res_info->more_results = more_results; return TDS_NO_MORE_ROWS; default: if (tds_process_default_tokens(tds,marker)==TDS_FAIL) return TDS_FAIL; break; } } return TDS_SUCCEED;}/* ** tds_process_col_name() is one half of the result set under TDS 4.2** it contains all the column names, a TDS_COLINFO_TOKEN should ** immediately follow this token with the datatype/size information** This is a 4.2 only function*/static int tds_process_col_name(TDSSOCKET *tds){int hdrsize, len=0;int col,num_cols=0;struct tmp_col_struct { char *column_name; int column_namelen; struct tmp_col_struct *next;};struct tmp_col_struct *head=NULL, *cur=NULL, *prev;TDSCOLINFO *curcol;TDSRESULTINFO *info; hdrsize = tds_get_smallint(tds); /* this is a little messy...TDS 5.0 gives the number of columns ** upfront, while in TDS 4.2, you're expected to figure it out ** by the size of the message. So, I use a link list to get the ** colum names and then allocate the result structure, copy ** and delete the linked list */ while (len<hdrsize) { prev = cur; cur = (struct tmp_col_struct *) malloc(sizeof (struct tmp_col_struct)); if (prev) prev->next=cur; if (!head) head = cur; cur->column_namelen = tds_get_byte(tds); cur->column_name = (char *) malloc(cur->column_namelen+1); tds_get_n(tds,cur->column_name, cur->column_namelen); cur->column_name[cur->column_namelen]='\0'; cur->next=NULL; len += cur->column_namelen + 1; num_cols++; } /* free results/computes/params etc... */ tds_free_all_results(tds); tds->res_info = tds_alloc_results(num_cols); info = tds->res_info; /* tell the upper layers we are processing results */ tds->state = TDS_PENDING;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -