diff --git a/src/odbc/odbc.c b/src/odbc/odbc.c index 25dd85f7a..721ecdbc5 100644 --- a/src/odbc/odbc.c +++ b/src/odbc/odbc.c @@ -731,6 +731,53 @@ get_int_col(TDSSOCKET *tds, TDSCOLUMN *col, TDS_INT default_value) return res.i; } +static char * +tds5_fix_dot_query(const char *query, size_t *query_len, bool is_func) +{ +#define PRM_FMT "@P%d" + int i = 0; + size_t len, pos; + const char *e, *s; + size_t size = *query_len + 30; + char *out; + + if (is_func) + size += 10; + + out = tds_new(char, size); + if (!out) + goto memory_error; + pos = 0; + if (is_func) + pos += sprintf(out + pos, "exec " PRM_FMT "=", ++i); + + s = query; + for (;; ++i) { + e = tds_next_placeholder(s); + len = e ? e - s : strlen(s); + if (pos + len + 12 >= size) { + size = pos + len + 30; + if (!TDS_RESIZE(out, size)) + goto memory_error; + } + memcpy(out + pos, s, len); + pos += len; + if (!e) + break; + pos += sprintf(out + pos, PRM_FMT, i + 1); + + s = e + 1; + } + out[pos] = 0; + *query_len = pos; + return out; + +memory_error: + free(out); + return NULL; +#undef PRM_FMT +} + static bool read_params(TDS_STMT *stmt) { @@ -754,12 +801,16 @@ read_params(TDS_STMT *stmt) "SUGGESTED_TDS_LENGTH", }; unsigned column_idx[NUM_COLUMNS]; - unsigned num_params = tds_count_placeholders("INSERT INTO describe(i, vc, num) VALUES(?, ?, ?)"); // TODO - const char *query = "INSERT INTO describe(i, vc, num) VALUES(@P1, @P2, @P3)"; + const char *query = tds_dstr_cstr(&stmt->query); + size_t query_len = tds_dstr_len(&stmt->query); + unsigned num_params = tds_count_placeholders(query); + char *new_query = NULL; /* allocate tds */ - if (!odbc_lock_statement(stmt)) + if (!odbc_lock_statement(stmt)) { + odbc_errs_reset(&stmt->errs); return false; + } tds = stmt->tds; stmt->params_queried = 1; @@ -770,17 +821,30 @@ read_params(TDS_STMT *stmt) return false; } + /* replace parameters with names */ + if (stmt->prepared_query_is_func) + ++num_params; + if (num_params) { + new_query = tds5_fix_dot_query(query, &query_len, stmt->prepared_query_is_func); + if (!new_query) { + odbc_unlock_statement(stmt); + odbc_errs_add(&stmt->errs, "HY001", NULL); + return false; + } + query = new_query; + } + /* send query */ - // TODO replace parameters with names, see tds5_fix_dot_query - params = odbc_add_char_param(tds, NULL, "", query, strlen(query)); -// params = odbc_add_char_param(tds, NULL, "", tds_dstr_cstr(&stmt->query), tds_dstr_len(&stmt->query)); + params = odbc_add_char_param(tds, NULL, "", query, query_len); if (!params) { + free(new_query); odbc_unlock_statement(stmt); odbc_errs_add(&stmt->errs, "HY001", NULL); return false; } if (TDS_FAILED(tds_submit_rpc(tds, "sp_describe_undeclared_parameters", params, NULL))) { + free(new_query); tds_free_param_results(params); odbc_unlock_statement(stmt); return false; @@ -846,7 +910,7 @@ printf("%d: XXXX Try to read params %d %u\n", __LINE__, in_row, num_params); break; // extract int values res_info = tds->current_results; -printf("Mao\n"); + TDSCOLUMN col[1]; memset(col, 0, sizeof(col)); int idx = 0; @@ -881,6 +945,7 @@ printf("Col %d %d %d %d\n", tds_type, len, precision, scale); break; } odbc_unlock_statement(stmt); + free(new_query); /* clear IPD on error */ if (!ret) @@ -4974,6 +5039,12 @@ ODBC_FUNC(SQLPrepare, (P(SQLHSTMT,hstmt), PCHARIN(SqlStr,SQLINTEGER) WIDE)) /* count parameters */ stmt->param_count = tds_count_placeholders(tds_dstr_cstr(&stmt->query)); + /* reset IPD and APD */ + if (!stmt->params_set) { + desc_alloc_records(stmt->ipd, 0); + desc_alloc_records(stmt->apd, 0); + } + /* trasform to native (one time, not for every SQLExecute) */ if (SQL_SUCCESS != prepare_call(stmt)) ODBC_EXIT(stmt, SQL_ERROR);