📄 token.c
字号:
/* Adjust column size according to client's encoding */ curcol->on_server.column_size = curcol->column_size; adjust_character_column_size(tds, curcol); /* discard Locale */ tds_get_n(tds, NULL, tds_get_byte(tds)); /* * Dump all information on this column */ tdsdump_log(TDS_DBG_INFO1, "col %d:\n", col); tdsdump_log(TDS_DBG_INFO1, "\tcolumn_name=[%s]\n", curcol->column_name);/* tdsdump_log(TDS_DBG_INFO1, "\tcolumn_name=[%s]\n", curcol->column_colname); tdsdump_log(TDS_DBG_INFO1, "\tcatalog=[%s] schema=[%s] table=[%s]\n", curcol->catalog_name, curcol->schema_name, curcol->table_name, curcol->column_colname);*/ tdsdump_log(TDS_DBG_INFO1, "\tflags=%x utype=%d type=%d varint=%d\n", curcol->column_flags, curcol->column_usertype, curcol->column_type, curcol->column_varint_size); tdsdump_log(TDS_DBG_INFO1, "\tcolsize=%d prec=%d scale=%d\n", curcol->column_size, curcol->column_prec, curcol->column_scale); } return tds_alloc_row(info);}/** * tds_process_compute() processes compute rows and places them in the row * buffer. */static inttds_process_compute(TDSSOCKET * tds, TDS_INT * pcomputeid){ int i; TDSCOLUMN *curcol; TDSCOMPUTEINFO *info; TDS_INT id; CHECK_TDS_EXTRA(tds); id = tds_get_smallint(tds); tdsdump_log(TDS_DBG_INFO1, "tds_process_compute() found compute id %d\n", id); for (i = 0;; ++i) { if (i >= tds->num_comp_info) { tdsdump_log(TDS_DBG_INFO1, "tds_process_compute() FAIL: id exceeds bound (%d)\n", tds->num_comp_info); return TDS_FAIL; } info = tds->comp_info[i]; if (info->computeid == id) break; } tds->current_results = info; for (i = 0; i < info->num_cols; i++) { curcol = info->columns[i]; if (tds_get_data(tds, curcol) != TDS_SUCCEED) { tdsdump_log(TDS_DBG_INFO1, "tds_process_compute() FAIL: tds_get_data() failed\n"); return TDS_FAIL; } } if (pcomputeid) *pcomputeid = id; return TDS_SUCCEED;}/** * Read a data from wire * \param tds state information for the socket and the TDS protocol * \param curcol column where store column information * \return TDS_FAIL on error or TDS_SUCCEED */static inttds_get_data(TDSSOCKET * tds, TDSCOLUMN * curcol){ unsigned char *dest; int len, colsize; int fillchar; TDSBLOB *blob = NULL; CHECK_TDS_EXTRA(tds); CHECK_COLUMN_EXTRA(curcol); tdsdump_log(TDS_DBG_INFO1, "tds_get_data: type %d, varint size %d\n", curcol->column_type, curcol->column_varint_size); switch (curcol->column_varint_size) { case 4: /* * TODO finish * This strange type has following structure * 0 len (int32) -- NULL * len (int32), type (int8), data -- ints, date, etc * len (int32), type (int8), 7 (int8), collation, column size (int16) -- [n]char, [n]varchar, binary, varbinary * BLOBS (text/image) not supported */ if (curcol->column_type == SYBVARIANT) { colsize = tds_get_int(tds); tds_get_n(tds, NULL, colsize); curcol->column_cur_size = -1; return TDS_SUCCEED; } /* * LONGBINARY * This type just stores a 4-byte length */ if (curcol->column_type == SYBLONGBINARY) { colsize = tds_get_int(tds); break; } /* It's a BLOB... */ len = tds_get_byte(tds); blob = (TDSBLOB *) curcol->column_data; if (len == 16) { /* Jeff's hack */ tds_get_n(tds, blob->textptr, 16); tds_get_n(tds, blob->timestamp, 8); colsize = tds_get_int(tds); } else { colsize = -1; } break; case 5: colsize = tds_get_int(tds); break; case 2: colsize = tds_get_smallint(tds); break; case 1: colsize = tds_get_byte(tds); if (colsize == 0) colsize = -1; break; case 0: /* TODO this should be column_size */ colsize = tds_get_size_by_type(curcol->column_type); break; default: colsize = -1; break; } if (IS_TDSDEAD(tds)) return TDS_FAIL; tdsdump_log(TDS_DBG_INFO1, "tds_get_data(): wire column size is %d \n", colsize); /* set NULL flag in the row buffer */ if (colsize < 0) { curcol->column_cur_size = -1; return TDS_SUCCEED; } /* * We're now set to read the data from the wire. For varying types (e.g. char/varchar) * make sure that curcol->column_cur_size reflects the size of the read data, * after any charset conversion. tds_get_char_data() does that for you, * but of course tds_get_n() doesn't. * * colsize == wire_size, bytes to read * curcol->column_cur_size == sizeof destination buffer, room to write */ dest = curcol->column_data; if (is_numeric_type(curcol->column_type)) { /* * Handling NUMERIC datatypes: * Since these can be passed around independent * of the original column they came from, we embed the TDS_NUMERIC datatype in the row buffer * instead of using the wire representation, even though it uses a few more bytes. */ TDS_NUMERIC *num = (TDS_NUMERIC *) dest; memset(num, '\0', sizeof(TDS_NUMERIC)); /* TODO perhaps it would be fine to change format ?? */ num->precision = curcol->column_prec; num->scale = curcol->column_scale; /* server is going to crash freetds ?? */ /* TODO close connection it server try to do so ?? */ if (colsize > sizeof(num->array)) return TDS_FAIL; tds_get_n(tds, num->array, colsize); /* corrected colsize for column_cur_size */ colsize = sizeof(TDS_NUMERIC); if (IS_TDS7_PLUS(tds)) { tdsdump_log(TDS_DBG_INFO1, "swapping numeric data...\n"); tds_swap_numeric(num); } curcol->column_cur_size = colsize; } else if (is_blob_type(curcol->column_type)) { TDS_CHAR *p; int new_blob_size; assert(blob == (TDSBLOB *) dest); /* cf. column_varint_size case 4, above */ /* * Blobs don't use a column's fixed buffer because the official maximum size is 2 GB. * Instead, they're reallocated as necessary, based on the data's size. * Here we allocate memory, if need be. */ /* TODO this can lead to a big waste of memory */ new_blob_size = determine_adjusted_size(curcol->char_conv, colsize); if (new_blob_size == 0) { curcol->column_cur_size = 0; if (blob->textvalue) TDS_ZERO_FREE(blob->textvalue); return TDS_SUCCEED; } p = blob->textvalue; /* save pointer in case realloc fails */ if (!p) { p = (TDS_CHAR *) malloc(new_blob_size); } else { /* TODO perhaps we should store allocated bytes too ? */ if (new_blob_size > curcol->column_cur_size || (curcol->column_cur_size - new_blob_size) > 10240) { p = (TDS_CHAR *) realloc(p, new_blob_size); } } if (!p) return TDS_FAIL; blob->textvalue = p; curcol->column_cur_size = new_blob_size; /* read the data */ if (is_char_type(curcol->column_type)) { if (tds_get_char_data(tds, (char *) blob, colsize, curcol) == TDS_FAIL) return TDS_FAIL; } else { assert(colsize == new_blob_size); tds_get_n(tds, blob->textvalue, colsize); } } else { /* non-numeric and non-blob */ curcol->column_cur_size = colsize; if (curcol->char_conv) { if (tds_get_char_data(tds, (char *) dest, colsize, curcol) == TDS_FAIL) return TDS_FAIL; } else { /* * special case, some servers seem to return more data in some conditions * (ASA 7 returning 4 byte nullable integer) */ int discard_len = 0; if (colsize > curcol->column_size) { discard_len = colsize - curcol->column_size; colsize = curcol->column_size; } if (tds_get_n(tds, dest, colsize) == NULL) return TDS_FAIL; if (discard_len > 0) tds_get_n(tds, NULL, discard_len); curcol->column_cur_size = colsize; } /* pad (UNI)CHAR and BINARY types */ fillchar = 0; switch (curcol->column_type) { /* extra handling for SYBLONGBINARY */ case SYBLONGBINARY: if (curcol->column_usertype != USER_UNICHAR_TYPE) break; case SYBCHAR: case XSYBCHAR: if (curcol->column_size != curcol->on_server.column_size) break; /* FIXME use client charset */ fillchar = ' '; case SYBBINARY: case XSYBBINARY: if (colsize < curcol->column_size) memset(dest + colsize, fillchar, curcol->column_size - colsize); colsize = curcol->column_size; break; } if (curcol->column_type == SYBDATETIME4) { tdsdump_log(TDS_DBG_INFO1, "datetime4 %d %d %d %d\n", dest[0], dest[1], dest[2], dest[3]); } }#ifdef WORDS_BIGENDIAN /* * MS SQL Server 7.0 has broken date types from big endian * machines, this swaps the low and high halves of the * affected datatypes * * Thought - this might be because we don't have the * right flags set on login. -mjs * * Nope its an actual MS SQL bug -bsb */ /* TODO test on login, remove configuration -- freddy77 */ if (tds->broken_dates && (curcol->column_type == SYBDATETIME || curcol->column_type == SYBDATETIME4 || curcol->column_type == SYBDATETIMN || curcol->column_type == SYBMONEY || curcol->column_type == SYBMONEY4 || (curcol->column_type == SYBMONEYN && curcol->column_size > 4))) /* * above line changed -- don't want this for 4 byte SYBMONEYN * values (mlilback, 11/7/01) */ { unsigned char temp_buf[8]; memcpy(temp_buf, dest, colsize / 2); memcpy(dest, &dest[colsize / 2], colsize / 2); memcpy(&dest[colsize / 2], temp_buf, colsize / 2); } if (tds->emul_little_endian) { tdsdump_log(TDS_DBG_INFO1, "swapping coltype %d\n", tds_get_conversion_type(curcol->column_type, colsize)); tds_swap_datatype(tds_get_conversion_type(curcol->column_type, colsize), dest); }#endif return TDS_SUCCEED;}/** * tds_process_row() processes rows and places them in the row buffer. */static inttds_process_row(TDSSOCKET * tds){ int i; TDSCOLUMN *curcol; TDSRESULTINFO *info; CHECK_TDS_EXTRA(tds); info = tds->current_results; if (!info) return TDS_FAIL; assert(info->num_cols > 0); info->row_count++; for (i = 0; i < info->num_cols; i++) { tdsdump_log(TDS_DBG_INFO1, "tds_process_row(): reading column %d \n", i); curcol = info->columns[i]; if (tds_get_data(tds, curcol) != TDS_SUCCEED) return TDS_FAIL; } return TDS_SUCCEED;}/** * tds_process_end() processes any of the DONE, DONEPROC, or DONEINPROC * tokens. * \param tds state information for the socket and the TDS protocol * \param marker TDS token number * \param flags_parm filled with bit flags (see TDS_DONE_ constants). * Is NULL nothing is returned */static inttds_process_end(TDSSOCKET * tds, int marker, int *flags_parm){ int more_results, was_cancelled, error, done_count_valid; int tmp, state; TDS_INT8 rows_affected; CHECK_TDS_EXTRA(tds); tmp = tds_get_smallint(tds); state = tds_get_smallint(tds); more_results = (tmp & TDS_DONE_MORE_RESULTS) != 0; was_cancelled = (tmp & TDS_DONE_CANCELLED) != 0; error = (tmp & TDS_DONE_ERROR) != 0; done_count_valid = (tmp & TDS_DONE_COUNT) != 0; tdsdump_log(TDS_DBG_FUNC, "tds_process_end: more_results = %d\n" "\t\twas_cancelled = %d\n" "\t\terror = %d\n" "\t\tdone_count_valid = %d\n", more_results, was_cancelled, error, done_count_valid); if (tds->res_info) { tds->res_info->more_results = more_results; if (tds->current_results == NULL) tds->current_results = tds->res_info; } if (flags_parm) *flags_parm = tmp; if (was_cancelled || (!more_results && !tds->in_cancel)) { tdsdump_log(TDS_DBG_FUNC, "tds_process_end() state set to TDS_IDLE\n"); /* reset of in_cancel should must done before setting IDLE */ tds->in_cancel = 0; tds_set_state(tds, TDS_IDLE); } if (IS_TDSDEAD(tds)) return TDS_FAIL; /* * rows affected is in the tds struct because a query may affect rows but * have no result set. */ rows_affected = IS_TDS90(tds) ? tds_get_int8(tds) : tds_get_int(tds); tdsdump_log(TDS_DBG_FUNC, " rows_affected = %" TDS_I64_FORMAT "\n", rows_affected); if (done_count_valid) tds->rows_affected = rows_affected; else tds->rows_affected = TDS_NO_COUNT; if (IS_TDSDEAD(tds)) return TDS_FAIL; return was_cancelled ? TDS_CANCELLED : TDS_SUCCEED;}/** * tds_process_env_chg() * when ever certain things change on the server, such as database, character * set, language, or block size. A environment change message is generated * There is no action taken currently, but certain functions at the CLI level * that return the name of the current database will need to use this. */static inttds_process_env_chg(TDSSOCKET * tds){ int size, type; char *oldval = NULL; char *newval = NULL; char **dest; int new_block_size; int lcid; int memrc = 0; CHECK_TDS_EXTRA(tds); size = tds_get_smallint(tds); /* * this came in a patch, apparently someone saw an env message * that was different from what we are handling? -- brian * changed back because it won't handle multibyte chars -- 7.0 */ /* tds_get_n(tds,NULL,size); */ type = tds_get_byte(tds); /* * handle collate default change (if you change db or during login) * this environment is not a string so need different handles */ if (type == TDS_ENV_SQLCOLLATION) { /* save new collation */ size = tds_get_byte(tds); tdsdump_log(TDS_DBG_ERROR, "tds_process_env_chg(): %d bytes of collation data received\n", size); tdsdump_dump_buf(TDS_DBG_NETWORK, "tds->collation was", tds->collation, 5); memset(tds->collation, 0, 5); if (size < 5) { tds_get_n(tds, tds->collation, size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -