📄 query.c
字号:
dyn = tds_alloc_dynamic(tds, id); } if (!dyn) return TDS_FAIL; /* TDS5 sometimes cannot accept prepare so we need to store query */ if (!IS_TDS7_PLUS(tds)) { dyn->query = strdup(query); if (!dyn->query) { tds_free_dynamic(tds, dyn); return TDS_FAIL; } } tds->cur_dyn = dyn; if (dyn_out) *dyn_out = dyn; if (!IS_TDS50(tds) && !IS_TDS7_PLUS(tds)) { dyn->emulated = 1; return TDS_SUCCEED; } if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING) goto failure_nostate; query_len = strlen(query); if (IS_TDS7_PLUS(tds)) { size_t definition_len = 0; char *param_definition = NULL; int converted_query_len; const char *converted_query; converted_query = tds_convert_string(tds, tds->char_convs[client2ucs2], query, query_len, &converted_query_len); if (!converted_query) goto failure; param_definition = tds7_build_param_def_from_query(tds, converted_query, converted_query_len, params, &definition_len); if (!param_definition) { tds_convert_string_free(query, converted_query); goto failure; } tds->out_flag = TDS_RPC; START_QUERY; /* procedure name */ if (IS_TDS8_PLUS(tds)) { tds_put_smallint(tds, -1); tds_put_smallint(tds, TDS_SP_PREPARE); } else { tds_put_smallint(tds, 10); TDS_PUT_N_AS_UCS2(tds, "sp_prepare"); } tds_put_smallint(tds, 0); /* return param handle (int) */ tds_put_byte(tds, 0); tds_put_byte(tds, 1); /* result */ tds_put_byte(tds, SYBINTN); tds_put_byte(tds, 4); tds_put_byte(tds, 0); tds7_put_params_definition(tds, param_definition, definition_len); tds7_put_query_params(tds, converted_query, converted_query_len); tds_convert_string_free(query, converted_query); free(param_definition); /* 1 param ?? why ? flags ?? */ tds_put_byte(tds, 0); tds_put_byte(tds, 0); tds_put_byte(tds, SYBINTN); tds_put_byte(tds, 4); tds_put_byte(tds, 4); tds_put_int(tds, 1); tds->internal_sp_called = TDS_SP_PREPARE; } else { tds->out_flag = TDS_NORMAL; id_len = strlen(dyn->id); tds_put_byte(tds, TDS5_DYNAMIC_TOKEN); tds_put_smallint(tds, query_len + id_len * 2 + 21); tds_put_byte(tds, 0x01); tds_put_byte(tds, 0x00); tds_put_byte(tds, id_len); tds_put_n(tds, dyn->id, id_len); /* TODO ICONV convert string, do not put with tds_put_n */ /* TODO how to pass parameters type? like store procedures ? */ tds_put_smallint(tds, query_len + id_len + 16); tds_put_n(tds, "create proc ", 12); tds_put_n(tds, dyn->id, id_len); tds_put_n(tds, " as ", 4); tds_put_n(tds, query, query_len); } rc = tds_query_flush_packet(tds); if (rc != TDS_FAIL) return rc;failure: /* TODO correct if writing fail ?? */ tds_set_state(tds, TDS_IDLE);failure_nostate: tds->cur_dyn = NULL; tds_free_dynamic(tds, dyn); if (dyn_out) *dyn_out = NULL; return TDS_FAIL;}/** * Submit a prepared query with parameters * \param tds state information for the socket and the TDS protocol * \param query language query with given placeholders (?) * \param params parameters to send * \return TDS_FAIL or TDS_SUCCEED */inttds_submit_execdirect(TDSSOCKET * tds, const char *query, TDSPARAMINFO * params){ int query_len; TDSCOLUMN *param; char *tmp_id = NULL; TDSDYNAMIC *dyn; int id_len; CHECK_TDS_EXTRA(tds); CHECK_PARAMINFO_EXTRA(params); if (!query) return TDS_FAIL; query_len = strlen(query); if (IS_TDS7_PLUS(tds)) { size_t definition_len = 0; int i; char *param_definition = NULL; int converted_query_len; const char *converted_query; if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING) return TDS_FAIL; converted_query = tds_convert_string(tds, tds->char_convs[client2ucs2], query, query_len, &converted_query_len); if (!converted_query) { tds_set_state(tds, TDS_IDLE); return TDS_FAIL; } param_definition = tds7_build_param_def_from_query(tds, converted_query, converted_query_len, params, &definition_len); if (!param_definition) { tds_convert_string_free(query, converted_query); tds_set_state(tds, TDS_IDLE); return TDS_FAIL; } tds->out_flag = TDS_RPC; START_QUERY; /* procedure name */ if (IS_TDS8_PLUS(tds)) { tds_put_smallint(tds, -1); tds_put_smallint(tds, TDS_SP_EXECUTESQL); } else { tds_put_smallint(tds, 13); TDS_PUT_N_AS_UCS2(tds, "sp_executesql"); } tds_put_smallint(tds, 0); tds7_put_query_params(tds, converted_query, converted_query_len); tds7_put_params_definition(tds, param_definition, definition_len); tds_convert_string_free(query, converted_query); free(param_definition); for (i = 0; i < params->num_cols; i++) { param = params->columns[i]; /* TODO check error */ tds_put_data_info(tds, param, 0); tds_put_data(tds, param); } tds->internal_sp_called = TDS_SP_EXECUTESQL; return tds_query_flush_packet(tds); } /* allocate a structure for this thing */ if (tds_get_dynid(tds, &tmp_id) == TDS_FAIL) return TDS_FAIL; dyn = tds_alloc_dynamic(tds, tmp_id); free(tmp_id); if (!dyn) return TDS_FAIL; /* check is no parameters */ if (params && !params->num_cols) params = NULL; /* TDS 4.2, emulate prepared statements */ /* * TODO Sybase seems to not support parameters in prepared execdirect * so use language or prepare and then exec */ if (!IS_TDS50(tds) || params) { int ret = TDS_SUCCEED; dyn->emulated = 1; dyn->params = params; dyn->query = strdup(query); if (!dyn->query) ret = TDS_FAIL; if (ret != TDS_FAIL) if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING) ret = TDS_FAIL; if (ret != TDS_FAIL) { ret = tds_send_emulated_execute(tds, dyn->query, dyn->params); if (ret == TDS_SUCCEED) ret = tds_query_flush_packet(tds); } /* do not free our parameters */ dyn->params = NULL; tds_free_dynamic(tds, dyn); return ret; } tds->cur_dyn = dyn; if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING) return TDS_FAIL; tds->out_flag = TDS_NORMAL; id_len = strlen(dyn->id); tds_put_byte(tds, TDS5_DYNAMIC_TOKEN); tds_put_smallint(tds, query_len + id_len * 2 + 21); tds_put_byte(tds, 0x08); tds_put_byte(tds, params ? 0x01 : 0); tds_put_byte(tds, id_len); tds_put_n(tds, dyn->id, id_len); /* TODO ICONV convert string, do not put with tds_put_n */ /* TODO how to pass parameters type? like store procedures ? */ tds_put_smallint(tds, query_len + id_len + 16); tds_put_n(tds, "create proc ", 12); tds_put_n(tds, dyn->id, id_len); tds_put_n(tds, " as ", 4); tds_put_n(tds, query, query_len); if (params) tds_put_params(tds, params, 0); return tds_flush_packet(tds);}/** * Put data information to wire * \param tds state information for the socket and the TDS protocol * \param curcol column where to store information * \param flags bit flags on how to send data (use TDS_PUT_DATA_USE_NAME for use name information) * \return TDS_SUCCEED or TDS_FAIL */static inttds_put_data_info(TDSSOCKET * tds, TDSCOLUMN * curcol, int flags){ int len; CHECK_TDS_EXTRA(tds); CHECK_COLUMN_EXTRA(curcol); if (flags & TDS_PUT_DATA_USE_NAME) { len = curcol->column_namelen; tdsdump_log(TDS_DBG_ERROR, "tds_put_data_info putting param_name \n"); if (IS_TDS7_PLUS(tds)) { int converted_param_len; const char *converted_param; /* TODO use a fixed buffer to avoid error ? */ converted_param = tds_convert_string(tds, tds->char_convs[client2ucs2], curcol->column_name, len, &converted_param_len); if (!converted_param) return TDS_FAIL; if (!(flags & TDS_PUT_DATA_PREFIX_NAME)) { tds_put_byte(tds, converted_param_len / 2); } else { tds_put_byte(tds, converted_param_len / 2 + 1); tds_put_n(tds, "@", 2); } tds_put_n(tds, converted_param, converted_param_len); tds_convert_string_free(curcol->column_name, converted_param); } else { /* TODO ICONV convert */ tds_put_byte(tds, len); /* param name len */ tds_put_n(tds, curcol->column_name, len); } } else { tds_put_byte(tds, 0x00); /* param name len */ } /* * TODO support other flags (use defaul null/no metadata) * bit 1 (2 as flag) in TDS7+ is "default value" bit * (what's the meaning of "default value" ?) */ tdsdump_log(TDS_DBG_ERROR, "tds_put_data_info putting status \n"); tds_put_byte(tds, curcol->column_output); /* status (input) */ if (!IS_TDS7_PLUS(tds)) tds_put_int(tds, curcol->column_usertype); /* usertype */ tds_put_byte(tds, curcol->on_server.column_type); if (is_numeric_type(curcol->on_server.column_type)) {#if 1 tds_put_byte(tds, tds_numeric_bytes_per_prec[curcol->column_prec]); tds_put_byte(tds, curcol->column_prec); tds_put_byte(tds, curcol->column_scale);#else TDS_NUMERIC *num = (TDS_NUMERIC *) curcol->column_data; tds_put_byte(tds, tds_numeric_bytes_per_prec[num->precision]); tds_put_byte(tds, num->precision); tds_put_byte(tds, num->scale);#endif } else { switch (curcol->column_varint_size) { case 0: break; case 1: tds_put_byte(tds, MAX(MIN(curcol->column_size, 255), 1)); break; case 2: tds_put_smallint(tds, MAX(MIN(curcol->column_size, 8000), 1)); break; case 4: tds_put_int(tds, MAX(MIN(curcol->column_size, 0x7fffffff), 1)); break; } } /* TDS8 output collate information */ if (IS_TDS8_PLUS(tds) && is_collate_type(curcol->on_server.column_type)) tds_put_n(tds, tds->collation, 5); /* TODO needed in TDS4.2 ?? now is called only is TDS >= 5 */ if (!IS_TDS7_PLUS(tds)) { tdsdump_log(TDS_DBG_ERROR, "HERE! \n"); tds_put_byte(tds, 0x00); /* locale info length */ } return TDS_SUCCEED;}/** * Calc information length in bytes (useful for calculating full packet length) * \param tds state information for the socket and the TDS protocol * \param curcol column where to store information * \param flags bit flags on how to send data (use TDS_PUT_DATA_USE_NAME for use name information) * \return TDS_SUCCEED or TDS_FAIL */static inttds_put_data_info_length(TDSSOCKET * tds, TDSCOLUMN * curcol, int flags){ int len = 8; CHECK_TDS_EXTRA(tds); CHECK_COLUMN_EXTRA(curcol);#if ENABLE_EXTRA_CHECKS if (IS_TDS7_PLUS(tds)) tdsdump_log(TDS_DBG_ERROR, "tds_put_data_info_length called with TDS7+\n");#endif /* TODO ICONV convert string if needed (see also tds_put_data_info) */ if (flags & TDS_PUT_DATA_USE_NAME) len += curcol->column_namelen; if (is_numeric_type(curcol->on_server.column_type)) len += 2; return len + curcol->column_varint_size;}/** * Write data to 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_put_data(TDSSOCKET * tds, TDSCOLUMN * curcol){ unsigned char *src; TDS_NUMERIC *num; TDSBLOB *blob = NULL; TDS_INT colsize; CHECK_TDS_EXTRA(tds); CHECK_COLUMN_EXTRA(curcol); colsize = curcol->column_cur_size; src = curcol->column_data; tdsdump_log(TDS_DBG_INFO1, "tds_put_data: colsize = %d\n", (int) colsize); if (colsize < 0) { tdsdump_log(TDS_DBG_INFO1, "tds_put_data: null param\n"); switch (curcol->column_varint_size) { case 4: tds_put_int(tds, -1); break; case 2: tds_put_smallint(tds, -1); break; default: assert(curcol->column_varint_size); /* FIXME not good for SYBLONGBINARY/SYBLONGCHAR (still not supported) */ tds_put_byte(tds, 0); break; } return TDS_SUCCEED; } /* * TODO here we limit data sent with MIN, should mark somewhere * and inform client ?? * Test proprietary behavior */ if (IS_TDS7_PLUS(tds)) { const char *s; int converted = 0; tdsdump_log(TDS_DBG_INFO1, "tds_put_data: not null param varint_size = %d\n", curcol->column_varint_size); if (is_blob_type(curcol->column_type)) { blob = (TDSBLOB *) src; src = (unsigned char *) blob->textvalue; } s = (char *) src; /* convert string if needed */ if (curcol->char_conv && curcol->char_conv->flags != TDS_ENCODING_MEMCPY) {#if 0 /* TODO this case should be optimized */ /* we know converted bytes */ if (curcol->char_conv->client_charset.min_bytes_per_char == curcol->char_conv->client_charset.max_bytes_per_char && curcol->char_conv->server_charset.min_bytes_per_char == curcol->char_conv->server_charset.max_bytes_per_char) { converted_size = colsize * curcol->char_conv->server_charset.min_bytes_per_char / curcol->char_conv->client_charset.min_bytes_per_char; } else {#endif /* we need to convert data before */ /* TODO this can be a waste of memory... */ s = tds_convert_string(tds, curcol->char_conv, s, colsize, &colsize); if (!s) { /* FIXME this is a bad place to return error... */ /* TODO on memory failure we should compute comverted size and use chunks */ return TDS_FAIL; } converted = 1; } switch (curcol->column_varint_size) { case 4: /* It's a BLOB... */ blob = (TDSBLOB *) curcol->column_data; colsize = MIN(colsize, 0x7fffffff); /* mssql require only size */ tds_put_int(tds, colsize); break; case 2: colsize = MIN(colsize, 8000); tds_put_smallint(tds, colsize); break; case 1: if (is_numeric_type(curcol->on_server.column_type)) colsize = tds_numeric_bytes_per_prec[((TDS_NUMERIC *) src)->precision]; colsize = MIN(colsize, 255); tds_put_byte(tds, colsize); break; case 0: /* TODO should be column_size */ colsize = tds_get_size_by_type(curcol->on_server.column_type); break; } /* put real data */ if (is_numeric_type(curcol->on_server.column_type)) { TDS_NUMERIC buf; memcpy(&buf, src, sizeof(buf)); tdsdump_log(TDS_DBG_INFO1, "swapping numeric data...\n"); tds_swap_numeric(&buf); tds_put_n(tds, buf.array, colsize); } else if (blob) { tds_put_n(tds, s, colsize); } else {#ifdef WORDS_BIGENDIAN unsigned char buf[64]; if (tds->emul_little_endian && !converted && colsize < 64) { tdsdump_log(TDS_DBG_INFO1, "swapping coltype %d\n", tds_get_conversion_type(curcol->column_type, colsize)); memcpy(buf, s, colsize); tds_swap_datatype(tds_get_conversion_type(curcol->column_type, colsize), buf); s = (char *) buf; }#endif tds_put_n(tds, s, colsize); } if (converted)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -