Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001 Brian Bruns
3 : * Copyright (C) 2002-2012 Frediano Ziglio
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Library General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Library General Public
16 : * License along with this library; if not, write to the
17 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 : * Boston, MA 02111-1307, USA.
19 : */
20 :
21 : #include <config.h>
22 :
23 : #include <stdarg.h>
24 : #include <stdio.h>
25 :
26 : #if HAVE_STDLIB_H
27 : #include <stdlib.h>
28 : #endif /* HAVE_STDLIB_H */
29 :
30 : #if HAVE_STRING_H
31 : #include <string.h>
32 : #endif /* HAVE_STRING_H */
33 :
34 : #include <assert.h>
35 : #include <ctype.h>
36 :
37 : #include <freetds/utils.h>
38 : #include <freetds/odbc.h>
39 : #include <freetds/tds/iconv.h>
40 : #include <freetds/utils/string.h>
41 : #include <freetds/utils/ascii.h>
42 : #include <freetds/tds/convert.h>
43 : #include <freetds/encodings.h>
44 : #include <freetds/replacements.h>
45 : #include "sqlwparams.h"
46 :
47 : /* Include odbcss.h with all bcp functions */
48 : /* The define trick is to make inline functions calls internal
49 : * odbc_SQLSetConnectAttr instead of SQLSetConnectAttr */
50 : ODBC_FUNC(SQLSetConnectAttr, (P(SQLHDBC,hdbc), P(SQLINTEGER,Attribute), P(SQLPOINTER,ValuePtr), P(SQLINTEGER,StringLength) WIDE));
51 : #define TDSODBC_BCP
52 : #undef SQLSetConnectAttr
53 : #define SQLSetConnectAttr(h, n, p, t) odbc_SQLSetConnectAttr(h, n, p, t _wide0)
54 : #include <odbcss.h>
55 : #undef SQLSetConnectAttr
56 :
57 : static SQLRETURN odbc_SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc);
58 : static SQLRETURN odbc_SQLAllocEnv(SQLHENV FAR * phenv, SQLINTEGER odbc_version);
59 : static SQLRETURN odbc_SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt);
60 : static SQLRETURN odbc_SQLAllocDesc(SQLHDBC hdbc, SQLHDESC FAR * phdesc);
61 : static SQLRETURN odbc_SQLFreeConnect(SQLHDBC hdbc);
62 : static SQLRETURN odbc_SQLFreeEnv(SQLHENV henv);
63 : static SQLRETURN odbc_SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption, int force);
64 : static SQLRETURN odbc_SQLFreeDesc(SQLHDESC hdesc);
65 : static SQLRETURN odbc_SQLExecute(TDS_STMT * stmt);
66 : static SQLRETURN odbc_SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength WIDE);
67 : static SQLRETURN odbc_SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength,
68 : SQLINTEGER * StringLength WIDE);
69 : static SQLRETURN odbc_SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc,
70 : SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc _WIDE);
71 : static SQLRETURN odbc_SQLFetch(TDS_STMT * stmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset);
72 : static SQLRETURN odbc_populate_ird(TDS_STMT * stmt);
73 : static int odbc_errmsg_handler(const TDSCONTEXT * ctx, TDSSOCKET * tds, TDSMESSAGE * msg);
74 : static void odbc_log_unimplemented_type(const char function_name[], int fType);
75 : static void odbc_upper_column_names(TDS_STMT * stmt);
76 : static void odbc_col_setname(TDS_STMT * stmt, int colpos, const char *name);
77 : static SQLRETURN odbc_stat_execute(TDS_STMT * stmt _WIDE, const char *begin, int nparams, ...);
78 : static SQLRETURN odbc_free_dynamic(TDS_STMT * stmt);
79 : static SQLRETURN odbc_free_cursor(TDS_STMT * stmt);
80 : static SQLRETURN odbc_update_ird(TDS_STMT *stmt, TDS_ERRS *errs);
81 : static SQLRETURN odbc_prepare(TDS_STMT *stmt);
82 : static SQLSMALLINT odbc_swap_datetime_sql_type(SQLSMALLINT sql_type, int version);
83 : static int odbc_process_tokens(TDS_STMT * stmt, unsigned flag);
84 : static bool odbc_lock_statement(TDS_STMT* stmt);
85 : static void odbc_unlock_statement(TDS_STMT* stmt);
86 : static bool read_params(TDS_STMT *stmt);
87 :
88 : #if ENABLE_EXTRA_CHECKS
89 : static void odbc_ird_check(TDS_STMT * stmt);
90 :
91 : #define IRD_CHECK odbc_ird_check(stmt)
92 : #else
93 : #define IRD_CHECK
94 : #endif
95 :
96 : /**
97 : * \defgroup odbc_api ODBC API
98 : * Functions callable by \c ODBC client programs
99 : */
100 :
101 :
102 : /* utils to check handles */
103 : #define INIT_HANDLE(t, n) \
104 : TDS_##t *n = (TDS_##t*)h##n; \
105 : if (SQL_NULL_H##t == h##n || (n)->htype != SQL_HANDLE_##t) return SQL_INVALID_HANDLE; \
106 : tds_mutex_lock(&n->mtx); \
107 : CHECK_##t##_EXTRA(n); \
108 : odbc_errs_reset(&n->errs);
109 :
110 : #define ODBC_ENTER_HSTMT INIT_HANDLE(STMT, stmt)
111 : #define ODBC_ENTER_HDBC INIT_HANDLE(DBC, dbc)
112 : #define ODBC_ENTER_HENV INIT_HANDLE(ENV, env)
113 : #define ODBC_ENTER_HDESC INIT_HANDLE(DESC, desc)
114 :
115 : #define IS_VALID_LEN(len) ((len) >= 0 || (len) == SQL_NTS || (len) == SQL_NULL_DATA)
116 :
117 : #define ODBC_SAFE_ERROR(stmt) \
118 : do { \
119 : if (!stmt->errs.num_errors) \
120 : odbc_errs_add(&stmt->errs, "HY000", "Unknown error"); \
121 : } while(0)
122 :
123 : #define DEFAULT_QUERY_TIMEOUT (~((SQLUINTEGER) 0))
124 :
125 : /*
126 : * Note: I *HATE* hungarian notation, it has to be the most idiotic thing
127 : * I've ever seen. So, you will note it is avoided other than in the function
128 : * declarations. "Gee, let's make our code totally hard to read and they'll
129 : * beg for GUI tools"
130 : * Bah!
131 : */
132 :
133 : static const char *
134 0 : odbc_prret(SQLRETURN ret, char *unknown, size_t unknown_size)
135 : {
136 0 : switch (ret) {
137 : case SQL_ERROR: return "SQL_ERROR";
138 0 : case SQL_INVALID_HANDLE: return "SQL_INVALID_HANDLE";
139 0 : case SQL_SUCCESS: return "SQL_SUCCESS";
140 0 : case SQL_SUCCESS_WITH_INFO: return "SQL_SUCCESS_WITH_INFO";
141 : #if ODBCVER >= 0x0300
142 0 : case SQL_NO_DATA: return "SQL_NO_DATA";
143 : #endif
144 0 : case SQL_STILL_EXECUTING: return "SQL_STILL_EXECUTING";
145 0 : case SQL_NEED_DATA: return "SQL_NEED_DATA";
146 : }
147 :
148 0 : snprintf(unknown, unknown_size, "unknown: %d", (int)ret);
149 :
150 0 : return unknown;
151 : }
152 : #define ODBC_PRRET_BUF char unknown_prret_buf[24]
153 : #define odbc_prret(ret) odbc_prret(ret, unknown_prret_buf, sizeof(unknown_prret_buf))
154 :
155 : static void
156 516 : odbc_col_setname(TDS_STMT * stmt, int colpos, const char *name)
157 : {
158 : #if ENABLE_EXTRA_CHECKS
159 : TDSRESULTINFO *resinfo;
160 : #endif
161 :
162 516 : IRD_CHECK;
163 :
164 : #if ENABLE_EXTRA_CHECKS
165 516 : if (colpos > 0 && stmt->tds != NULL && (resinfo = stmt->tds->current_results) != NULL) {
166 516 : if (colpos <= resinfo->num_cols) {
167 : /* no overflow possible, name is always shorter */
168 516 : if (!tds_dstr_copy(&resinfo->columns[colpos - 1]->column_name, name))
169 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
170 516 : tds_dstr_empty(&resinfo->columns[colpos - 1]->table_column_name);
171 : }
172 : }
173 : #endif
174 :
175 516 : if (colpos > 0 && colpos <= stmt->ird->header.sql_desc_count) {
176 516 : --colpos;
177 516 : if (!tds_dstr_copy(&stmt->ird->records[colpos].sql_desc_label, name)
178 516 : || !tds_dstr_copy(&stmt->ird->records[colpos].sql_desc_name, name))
179 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
180 : }
181 516 : }
182 :
183 : /* spinellia@acm.org : copied shamelessly from change_database */
184 : static SQLRETURN
185 260 : change_autocommit(TDS_DBC * dbc, int state)
186 : {
187 260 : TDSSOCKET *tds = dbc->tds_socket;
188 : TDSRET ret;
189 :
190 260 : tds_mutex_check_owned(&dbc->mtx);
191 260 : if (dbc->attr.autocommit == state)
192 : return SQL_SUCCESS;
193 :
194 : /*
195 : * We may not be connected yet and dbc->tds_socket
196 : * may not initialized.
197 : */
198 232 : if (tds) {
199 : /* TODO better idle check, not thread safe */
200 190 : if (tds->state == TDS_IDLE)
201 190 : tds->query_timeout = dbc->default_query_timeout;
202 :
203 190 : if (state == SQL_AUTOCOMMIT_ON)
204 58 : ret = tds_submit_rollback(tds, 0);
205 : else
206 132 : ret = tds_submit_begin_tran(tds);
207 :
208 190 : if (TDS_FAILED(ret)) {
209 0 : odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");
210 0 : return SQL_ERROR;
211 : }
212 190 : if (TDS_FAILED(tds_process_simple_query(tds))) {
213 0 : odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");
214 0 : return SQL_ERROR;
215 : }
216 190 : dbc->attr.autocommit = state;
217 : } else {
218 : /* if not connected we will change auto-commit after login */
219 42 : dbc->attr.autocommit = state;
220 : }
221 232 : ODBC_RETURN_(dbc);
222 : }
223 :
224 : static SQLRETURN
225 80 : change_database(TDS_DBC * dbc, const char *database, size_t database_len)
226 : {
227 80 : TDSSOCKET *tds = dbc->tds_socket;
228 80 : tds_mutex_check_owned(&dbc->mtx);
229 :
230 : /*
231 : * We may not be connected yet and dbc->tds_socket
232 : * may not initialized.
233 : */
234 80 : if (tds) {
235 : /* build query */
236 40 : char *query = tds_new(char, 6 + tds_quote_id(tds, NULL, database, database_len));
237 :
238 40 : if (!query) {
239 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
240 0 : return SQL_ERROR;
241 : }
242 40 : strcpy(query, "USE ");
243 40 : tds_quote_id(tds, query + 4, database, database_len);
244 :
245 :
246 40 : tdsdump_log(TDS_DBG_INFO1, "change_database: executing %s\n", query);
247 :
248 : /* TODO better idle check, not thread safe */
249 40 : if (tds->state == TDS_IDLE)
250 40 : tds->query_timeout = dbc->default_query_timeout;
251 40 : if (TDS_FAILED(tds_submit_query(tds, query))) {
252 0 : free(query);
253 0 : odbc_errs_add(&dbc->errs, "HY000", "Could not change database");
254 0 : return SQL_ERROR;
255 : }
256 40 : free(query);
257 40 : if (TDS_FAILED(tds_process_simple_query(tds))) {
258 10 : odbc_errs_add(&dbc->errs, "HY000", "Could not change database");
259 10 : return SQL_ERROR;
260 : }
261 : } else {
262 40 : if (!tds_dstr_copyn(&dbc->attr.current_catalog, database, database_len)) {
263 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
264 0 : return SQL_ERROR;
265 : }
266 : }
267 70 : ODBC_RETURN_(dbc);
268 : }
269 :
270 : static SQLRETURN
271 124 : change_txn(TDS_DBC * dbc, SQLUINTEGER txn_isolation)
272 : {
273 : char query[64];
274 : const char *level;
275 124 : TDSSOCKET *tds = dbc->tds_socket;
276 124 : tds_mutex_check_owned(&dbc->mtx);
277 :
278 124 : switch (txn_isolation) {
279 : case SQL_TXN_READ_COMMITTED:
280 : level = "READ COMMITTED";
281 : break;
282 30 : case SQL_TXN_READ_UNCOMMITTED:
283 30 : level = "READ UNCOMMITTED";
284 30 : break;
285 44 : case SQL_TXN_REPEATABLE_READ:
286 44 : level = "REPEATABLE READ";
287 44 : break;
288 30 : case SQL_TXN_SERIALIZABLE:
289 30 : level = "SERIALIZABLE";
290 30 : break;
291 10 : default:
292 10 : odbc_errs_add(&dbc->errs, "HY024", NULL);
293 10 : return SQL_ERROR;
294 : }
295 :
296 : /* if not connected return success, will be set after connection */
297 114 : if (!tds)
298 : return SQL_SUCCESS;
299 :
300 82 : if (tds->state != TDS_IDLE) {
301 10 : odbc_errs_add(&dbc->errs, "HY011", NULL);
302 10 : return SQL_ERROR;
303 : }
304 :
305 72 : tds->query_timeout = dbc->default_query_timeout;
306 72 : sprintf(query, "SET TRANSACTION ISOLATION LEVEL %s", level);
307 72 : if (TDS_FAILED(tds_submit_query(tds, query))) {
308 0 : ODBC_SAFE_ERROR(dbc);
309 : return SQL_ERROR;
310 : }
311 72 : if (TDS_FAILED(tds_process_simple_query(tds))) {
312 0 : ODBC_SAFE_ERROR(dbc);
313 : return SQL_ERROR;
314 : }
315 :
316 : return SQL_SUCCESS;
317 : }
318 :
319 : static TDS_DBC*
320 10914 : odbc_get_dbc(TDSSOCKET *tds)
321 : {
322 10914 : TDS_CHK *chk = (TDS_CHK *) tds_get_parent(tds);
323 10914 : if (!chk)
324 : return NULL;
325 10914 : if (chk->htype == SQL_HANDLE_DBC)
326 : return (TDS_DBC *) chk;
327 4582 : assert(chk->htype == SQL_HANDLE_STMT);
328 4582 : return ((TDS_STMT *) chk)->dbc;
329 : }
330 :
331 : static TDS_STMT*
332 : odbc_get_stmt(TDSSOCKET *tds)
333 : {
334 6267 : TDS_CHK *chk = (TDS_CHK *) tds_get_parent(tds);
335 6267 : if (!chk || chk->htype != SQL_HANDLE_STMT)
336 : return NULL;
337 : return (TDS_STMT *) chk;
338 : }
339 :
340 :
341 : static void
342 4843 : odbc_env_change(TDSSOCKET * tds, int type, char *oldval TDS_UNUSED, char *newval)
343 : {
344 : TDS_DBC *dbc;
345 :
346 4843 : assert(tds);
347 :
348 4843 : dbc = odbc_get_dbc(tds);
349 4843 : if (!dbc)
350 : return;
351 :
352 4843 : switch (type) {
353 2515 : case TDS_ENV_DATABASE:
354 2515 : tds_dstr_copy(&dbc->attr.current_catalog, newval);
355 2515 : break;
356 1164 : case TDS_ENV_PACKSIZE:
357 1164 : dbc->attr.packet_size = atoi(newval);
358 1164 : break;
359 : }
360 : }
361 :
362 : static SQLRETURN
363 1176 : odbc_connect(TDS_DBC * dbc, TDSLOGIN * login)
364 : {
365 1176 : TDS_ENV *env = dbc->env;
366 1176 : tds_mutex_check_owned(&dbc->mtx);
367 :
368 : #ifdef ENABLE_ODBC_WIDE
369 1176 : dbc->mb_conv = NULL;
370 : #endif
371 1176 : dbc->tds_socket = tds_alloc_socket(env->tds_ctx, 512);
372 1176 : if (!dbc->tds_socket)
373 : goto memory_error;
374 :
375 1176 : dbc->tds_socket->conn->use_iconv_in = 0;
376 1176 : tds_set_parent(dbc->tds_socket, (void *) dbc);
377 :
378 : /* Set up our environment change hook */
379 1176 : dbc->tds_socket->env_chg_func = odbc_env_change;
380 :
381 1176 : tds_fix_login(login);
382 :
383 : /* use connection timeout if set */
384 1176 : if (dbc->attr.connection_timeout)
385 10 : login->connect_timeout = dbc->attr.connection_timeout;
386 :
387 : /* but override with login timeout, if set */
388 1176 : if (dbc->attr.login_timeout)
389 10 : login->connect_timeout = dbc->attr.login_timeout;
390 :
391 1176 : if (dbc->attr.mars_enabled != SQL_MARS_ENABLED_NO)
392 548 : login->mars = 1;
393 1176 : if (dbc->attr.bulk_enabled != SQL_BCP_OFF)
394 10 : tds_set_bulk(login, true);
395 :
396 : #ifdef ENABLE_ODBC_WIDE
397 : /* force utf-8 in order to support wide characters */
398 2352 : dbc->original_charset_num = tds_canonical_charset(tds_dstr_cstr(&login->client_charset));
399 1176 : if (dbc->original_charset_num < 0) {
400 : char *msg;
401 :
402 0 : tds_free_socket(dbc->tds_socket);
403 0 : dbc->tds_socket = NULL;
404 :
405 0 : if (asprintf(&msg, "Invalid \"%s\" character set specified", tds_dstr_cstr(&login->client_charset)) > 0) {
406 0 : odbc_errs_add(&dbc->errs, "HY024", msg);
407 0 : free(msg);
408 : } else {
409 0 : odbc_errs_add(&dbc->errs, "HY024", "Invalid character set specified");
410 : }
411 0 : ODBC_RETURN_(dbc);
412 : }
413 1176 : if (!tds_dstr_copy(&login->client_charset, "UTF-8"))
414 : goto memory_error;
415 : #endif
416 :
417 : /* replace password with old one */
418 1176 : if (dbc->use_oldpwd) {
419 2 : if (!tds_dstr_dup(&login->new_password, &login->password)
420 2 : || !tds_dstr_dup(&login->password, &dbc->oldpwd))
421 : goto memory_error;
422 2 : login->use_new_password = 1;
423 : }
424 :
425 1176 : if (!tds_dstr_dup(&login->db_filename, &dbc->db_filename))
426 : goto memory_error;
427 :
428 1176 : if (TDS_FAILED(tds_connect_and_login(dbc->tds_socket, login))) {
429 12 : tds_free_socket(dbc->tds_socket);
430 12 : dbc->tds_socket = NULL;
431 12 : odbc_errs_add(&dbc->errs, "08001", NULL);
432 12 : return SQL_ERROR;
433 : }
434 : #ifdef ENABLE_ODBC_WIDE
435 1164 : dbc->mb_conv = tds_iconv_get_info(dbc->tds_socket->conn, dbc->original_charset_num, TDS_CHARSET_UTF_8);
436 : #endif
437 :
438 1164 : dbc->default_query_timeout = dbc->tds_socket->query_timeout;
439 :
440 1164 : if (IS_TDS7_PLUS(dbc->tds_socket->conn))
441 942 : dbc->cursor_support = 1;
442 :
443 : #if ENABLE_ODBC_MARS
444 : /* check if mars is enabled */
445 582 : if (!IS_TDS72_PLUS(dbc->tds_socket->conn) || !dbc->tds_socket->conn->mars)
446 365 : dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
447 : #else
448 582 : dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
449 : #endif
450 :
451 1164 : if (dbc->attr.txn_isolation != SQL_TXN_READ_COMMITTED) {
452 32 : if (!SQL_SUCCEEDED(change_txn(dbc, dbc->attr.txn_isolation)))
453 0 : ODBC_RETURN_(dbc);
454 : }
455 :
456 1164 : if (dbc->attr.autocommit != SQL_AUTOCOMMIT_ON) {
457 42 : dbc->attr.autocommit = SQL_AUTOCOMMIT_ON;
458 42 : if (!SQL_SUCCEEDED(change_autocommit(dbc, SQL_AUTOCOMMIT_OFF)))
459 0 : ODBC_RETURN_(dbc);
460 : }
461 :
462 : /* this overwrite any error arrived (wanted behavior, Sybase return error for conversion errors) */
463 1164 : ODBC_RETURN(dbc, SQL_SUCCESS);
464 :
465 0 : memory_error:
466 0 : tds_free_socket(dbc->tds_socket);
467 0 : dbc->tds_socket = NULL;
468 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
469 0 : ODBC_RETURN_(dbc);
470 : }
471 :
472 : /**
473 : * Update IRD information.
474 : * This is needed if the IRD is not updated as requires query to be prepared.
475 : * For instance calling SQLNumResultCols after SQLPrepare we need to
476 : * know how many rows the query could return.
477 : */
478 : static SQLRETURN
479 74 : odbc_update_ird(TDS_STMT *stmt, TDS_ERRS *errs TDS_UNUSED)
480 : {
481 : SQLRETURN res;
482 :
483 74 : if (!stmt->need_reprepare || stmt->prepared_query_is_rpc
484 66 : || !stmt->dbc || !IS_TDS7_PLUS(stmt->dbc->tds_socket->conn)) {
485 10 : stmt->need_reprepare = 0;
486 : return SQL_SUCCESS;
487 : }
488 :
489 : /* FIXME where error are put ?? on stmt... */
490 64 : if (!odbc_lock_statement(stmt))
491 0 : ODBC_RETURN_(stmt);
492 :
493 : /* FIXME error */
494 64 : res = start_parse_prepared_query(stmt, false);
495 64 : if (res != SQL_SUCCESS) {
496 : /* prepare with dummy parameters just to fill IRD */
497 8 : tds_free_param_results(stmt->params);
498 8 : stmt->params = NULL;
499 8 : stmt->param_num = 0;
500 : /*
501 : * TODO
502 : * we need to prepare again with parameters but need_reprepare
503 : * flag is reset by odbc_prepare... perhaps should be checked
504 : * later, not calling describeCol or similar
505 : * we need prepare to get dynamic and cause we change parameters
506 : */
507 : }
508 :
509 64 : return odbc_prepare(stmt);
510 : }
511 :
512 : static SQLRETURN
513 370 : odbc_prepare(TDS_STMT *stmt)
514 : {
515 370 : TDSSOCKET *tds = stmt->tds;
516 370 : bool in_row = false;
517 :
518 740 : if (TDS_FAILED(tds_submit_prepare(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params))) {
519 20 : ODBC_SAFE_ERROR(stmt);
520 : return SQL_ERROR;
521 : }
522 :
523 : /* try to go to the next recordset */
524 : /* TODO merge with similar code */
525 350 : desc_free_records(stmt->ird);
526 350 : stmt->row_status = PRE_NORMAL_ROW;
527 : for (;;) {
528 : TDS_INT result_type;
529 : int done_flags;
530 :
531 786 : switch (tds_process_tokens(tds, &result_type, &done_flags, TDS_RETURN_ROWFMT|TDS_RETURN_DONE)) {
532 436 : case TDS_SUCCESS:
533 436 : switch (result_type) {
534 340 : case TDS_DONE_RESULT:
535 : case TDS_DONEPROC_RESULT:
536 : case TDS_DONEINPROC_RESULT:
537 340 : stmt->row_count = tds->rows_affected;
538 340 : if (done_flags & TDS_DONE_ERROR && !stmt->dyn->emulated)
539 2 : stmt->errs.lastrc = SQL_ERROR;
540 : /* FIXME this row is used only as a flag for update binding,
541 : * should be cleared if binding/result changed */
542 340 : stmt->row = 0;
543 340 : break;
544 :
545 96 : case TDS_ROWFMT_RESULT:
546 : /* store first row information */
547 96 : if (!in_row)
548 80 : odbc_populate_ird(stmt);
549 96 : stmt->row = 0;
550 96 : stmt->row_count = TDS_NO_COUNT;
551 96 : stmt->row_status = PRE_NORMAL_ROW;
552 96 : in_row = true;
553 96 : break;
554 : }
555 436 : continue;
556 : case TDS_NO_MORE_RESULTS:
557 : break;
558 0 : case TDS_CANCELLED:
559 0 : odbc_errs_add(&stmt->errs, "HY008", NULL);
560 10 : default:
561 10 : stmt->errs.lastrc = SQL_ERROR;
562 10 : break;
563 : }
564 350 : break;
565 : }
566 :
567 350 : if (stmt->errs.lastrc == SQL_ERROR && !stmt->dyn->emulated) {
568 12 : tds_release_dynamic(&stmt->dyn);
569 : }
570 350 : odbc_unlock_statement(stmt);
571 350 : stmt->need_reprepare = 0;
572 350 : ODBC_RETURN_(stmt);
573 : }
574 :
575 168 : ODBC_FUNC(SQLDriverConnect, (P(SQLHDBC,hdbc), P(SQLHWND,hwnd), PCHARIN(ConnStrIn,SQLSMALLINT),
576 : PCHAROUT(ConnStrOut,SQLSMALLINT), P(SQLUSMALLINT,fDriverCompletion) WIDE))
577 : {
578 : TDSLOGIN *login;
579 : TDS_PARSED_PARAM params[ODBC_PARAM_SIZE];
580 168 : DSTR conn_str = DSTR_INITIALIZER;
581 :
582 168 : ODBC_ENTER_HDBC;
583 :
584 : #ifdef TDS_NO_DM
585 : /* Check string length */
586 168 : if (!IS_VALID_LEN(cbConnStrIn) || cbConnStrIn == 0) {
587 0 : odbc_errs_add(&dbc->errs, "HY090", NULL);
588 0 : ODBC_EXIT_(dbc);
589 : }
590 :
591 : /* Check completion param */
592 168 : switch (fDriverCompletion) {
593 : case SQL_DRIVER_NOPROMPT:
594 : case SQL_DRIVER_COMPLETE:
595 : case SQL_DRIVER_PROMPT:
596 : case SQL_DRIVER_COMPLETE_REQUIRED:
597 : break;
598 0 : default:
599 0 : odbc_errs_add(&dbc->errs, "HY110", NULL);
600 0 : ODBC_EXIT_(dbc);
601 : }
602 : #endif
603 :
604 168 : if (!odbc_dstr_copy(dbc, &conn_str, cbConnStrIn, szConnStrIn)) {
605 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
606 0 : ODBC_EXIT_(dbc);
607 : }
608 :
609 168 : login = tds_alloc_login(false);
610 168 : if (!login || !tds_init_login(login, dbc->env->tds_ctx->locale)) {
611 0 : tds_free_login(login);
612 0 : tds_dstr_free(&conn_str);
613 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
614 0 : ODBC_EXIT_(dbc);
615 : }
616 :
617 336 : if (!tds_dstr_isempty(&dbc->attr.current_catalog))
618 20 : if (!tds_dstr_dup(&login->database, &dbc->attr.current_catalog)) {
619 0 : tds_free_login(login);
620 0 : tds_dstr_free(&conn_str);
621 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
622 0 : ODBC_EXIT_(dbc);
623 : }
624 :
625 : /* parse the DSN string */
626 504 : if (!odbc_parse_connect_string(&dbc->errs, tds_dstr_buf(&conn_str), tds_dstr_buf(&conn_str) + tds_dstr_len(&conn_str),
627 : login, dbc, params)) {
628 10 : tds_free_login(login);
629 10 : tds_dstr_free(&conn_str);
630 10 : ODBC_EXIT_(dbc);
631 : }
632 :
633 474 : odbc_set_dstr(dbc, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, &conn_str);
634 158 : tds_dstr_free(&conn_str);
635 :
636 : /* add login info */
637 158 : if (hwnd && fDriverCompletion != SQL_DRIVER_NOPROMPT
638 0 : && (fDriverCompletion == SQL_DRIVER_PROMPT || (!params[ODBC_PARAM_UID].p && !params[ODBC_PARAM_Trusted_Connection].p)
639 0 : || tds_dstr_isempty(&login->server_name))) {
640 : #ifdef _WIN32
641 : char *out = NULL;
642 :
643 : /* prompt for login information */
644 : if (!get_login_info(hwnd, login)) {
645 : tds_free_login(login);
646 : odbc_errs_add(&dbc->errs, "08001", "User canceled login");
647 : ODBC_EXIT_(dbc);
648 : }
649 : if (tds_dstr_isempty(&login->user_name)) {
650 : params[ODBC_PARAM_UID].p = NULL;
651 : params[ODBC_PARAM_PWD].p = NULL;
652 : params[ODBC_PARAM_Trusted_Connection].p = "Yes";
653 : params[ODBC_PARAM_Trusted_Connection].len = 3;
654 : } else {
655 : params[ODBC_PARAM_UID].p = tds_dstr_cstr(&login->user_name);
656 : params[ODBC_PARAM_UID].len = tds_dstr_len(&login->user_name);
657 : params[ODBC_PARAM_PWD].p = tds_dstr_cstr(&login->password);
658 : params[ODBC_PARAM_PWD].len = tds_dstr_len(&login->password);
659 : params[ODBC_PARAM_Trusted_Connection].p = NULL;
660 : }
661 : if (!odbc_build_connect_string(&dbc->errs, params, &out))
662 : ODBC_EXIT_(dbc);
663 :
664 : odbc_set_string(dbc, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, out, -1);
665 : tdsdump_log(TDS_DBG_INFO1, "connection string is now: %s\n", out);
666 : free(out);
667 : #else
668 : /* we dont support a dialog box */
669 0 : odbc_errs_add(&dbc->errs, "HYC00", NULL);
670 : #endif
671 : }
672 :
673 316 : if (tds_dstr_isempty(&login->server_name)) {
674 0 : tds_free_login(login);
675 0 : odbc_errs_add(&dbc->errs, "IM007", "Could not find Servername or server parameter");
676 0 : ODBC_EXIT_(dbc);
677 : }
678 :
679 158 : odbc_connect(dbc, login);
680 :
681 158 : tds_free_login(login);
682 158 : ODBC_EXIT_(dbc);
683 : }
684 :
685 : #if 0
686 : SQLRETURN ODBC_PUBLIC ODBC_API
687 : SQLBrowseConnect(SQLHDBC hdbc, SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR FAR * szConnStrOut,
688 : SQLSMALLINT cbConnStrOutMax, SQLSMALLINT FAR * pcbConnStrOut)
689 : {
690 : ODBC_ENTER_HDBC;
691 :
692 : tdsdump_log(TDS_DBG_FUNC, "SQLBrowseConnect(%p, %s, %d, %p, %d, %p)\n",
693 : hdbc, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut);
694 : odbc_errs_add(&dbc->errs, "HYC00", "SQLBrowseConnect: function not implemented");
695 : ODBC_EXIT_(dbc);
696 : }
697 : #endif
698 :
699 :
700 0 : ODBC_FUNC(SQLColumnPrivileges, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT), PCHARIN(SchemaName,SQLSMALLINT),
701 : PCHARIN(TableName,SQLSMALLINT), PCHARIN(ColumnName,SQLSMALLINT) WIDE))
702 : {
703 : int retcode;
704 :
705 0 : ODBC_ENTER_HSTMT;
706 :
707 0 : retcode =
708 0 : odbc_stat_execute(stmt _wide, "sp_column_privileges", 4, "O@table_qualifier", szCatalogName, cbCatalogName,
709 : "O@table_owner", szSchemaName, cbSchemaName, "O@table_name", szTableName, cbTableName,
710 : "P@column_name", szColumnName, cbColumnName);
711 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
712 0 : odbc_col_setname(stmt, 1, "TABLE_CAT");
713 0 : odbc_col_setname(stmt, 2, "TABLE_SCHEM");
714 : }
715 0 : ODBC_EXIT_(stmt);
716 : }
717 :
718 : SQLRETURN ODBC_PUBLIC ODBC_API
719 : SQLDescribeParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT FAR * pfSqlType, SQLULEN FAR * pcbParamDef,
720 : SQLSMALLINT FAR * pibScale, SQLSMALLINT FAR * pfNullable)
721 : {
722 : TDS_DESC *ipd;
723 : struct _drecord *drec;
724 :
725 27 : ODBC_ENTER_HSTMT;
726 :
727 27 : tdsdump_log(TDS_DBG_FUNC, "SQLDescribeParam(%p, %d, %p, %p, %p, %p)\n",
728 : hstmt, ipar, pfSqlType, pcbParamDef, pibScale, pfNullable);
729 :
730 : /* Check if we need to ask server (not set params, we not asked before). */
731 : /* We need to reset set params resetting them. */
732 27 : if (!stmt->params_queried && !stmt->params_set && stmt->param_count > 0)
733 9 : read_params(stmt);
734 :
735 : /* return information from IPD */
736 27 : ipd = stmt->ipd;
737 27 : if (ipar < 1 || ipar > ipd->header.sql_desc_count) {
738 7 : odbc_errs_add(&stmt->errs, "07009", NULL);
739 7 : ODBC_EXIT_(stmt);
740 : }
741 20 : drec = &ipd->records[ipar - 1];
742 :
743 20 : if (pfSqlType)
744 20 : *pfSqlType = drec->sql_desc_type;
745 20 : if (pfNullable)
746 20 : *pfNullable = drec->sql_desc_nullable;
747 20 : switch (drec->sql_desc_type) {
748 2 : case SQL_DECIMAL:
749 : case SQL_NUMERIC:
750 2 : if (pcbParamDef)
751 2 : *pcbParamDef = drec->sql_desc_precision;
752 2 : if (pibScale)
753 2 : *pibScale = drec->sql_desc_scale;
754 : break;
755 18 : default:
756 18 : if (pcbParamDef)
757 18 : *pcbParamDef = drec->sql_desc_length;
758 18 : if (pibScale)
759 18 : *pibScale = 0;
760 : break;
761 : }
762 20 : ODBC_EXIT_(stmt);
763 : }
764 :
765 : SQLRETURN ODBC_PUBLIC ODBC_API
766 : SQLExtendedFetch(SQLHSTMT hstmt, SQLUSMALLINT fFetchType, SQLROWOFFSET irow,
767 : SQLROWSETSIZE FAR * pcrow, SQLUSMALLINT FAR * rgfRowStatus)
768 : {
769 : SQLRETURN ret;
770 : SQLULEN *tmp_rows;
771 : SQLUSMALLINT *tmp_status;
772 : SQLULEN tmp_size;
773 : SQLPOINTER tmp_bookmark;
774 : SQLULEN bookmark;
775 28 : SQLULEN out_len = 0;
776 :
777 28 : ODBC_ENTER_HSTMT;
778 :
779 28 : tdsdump_log(TDS_DBG_FUNC, "SQLExtendedFetch(%p, %d, %d, %p, %p)\n",
780 : hstmt, fFetchType, (int)irow, pcrow, rgfRowStatus);
781 :
782 28 : if (fFetchType != SQL_FETCH_NEXT && !stmt->dbc->cursor_support) {
783 0 : odbc_errs_add(&stmt->errs, "HY106", NULL);
784 0 : ODBC_EXIT_(stmt);
785 : }
786 :
787 : /* save and change IRD/ARD state */
788 28 : tmp_rows = stmt->ird->header.sql_desc_rows_processed_ptr;
789 28 : stmt->ird->header.sql_desc_rows_processed_ptr = &out_len;
790 28 : tmp_status = stmt->ird->header.sql_desc_array_status_ptr;
791 28 : stmt->ird->header.sql_desc_array_status_ptr = rgfRowStatus;
792 28 : tmp_size = stmt->ard->header.sql_desc_array_size;
793 28 : stmt->ard->header.sql_desc_array_size = stmt->sql_rowset_size;
794 28 : tmp_bookmark = stmt->attr.fetch_bookmark_ptr;
795 :
796 : /* SQL_FETCH_BOOKMARK different */
797 28 : if (fFetchType == SQL_FETCH_BOOKMARK) {
798 0 : bookmark = irow;
799 0 : irow = 0;
800 0 : stmt->attr.fetch_bookmark_ptr = &bookmark;
801 : }
802 :
803 : /* TODO errors are sligthly different ... perhaps it's better to leave DM do this job ?? */
804 : /* TODO check fFetchType can be converted to USMALLINT */
805 28 : ret = odbc_SQLFetch(stmt, fFetchType, irow);
806 :
807 : /* restore IRD/ARD */
808 28 : stmt->ird->header.sql_desc_rows_processed_ptr = tmp_rows;
809 28 : if (pcrow)
810 28 : *pcrow = out_len;
811 28 : stmt->ird->header.sql_desc_array_status_ptr = tmp_status;
812 28 : stmt->ard->header.sql_desc_array_size = tmp_size;
813 28 : stmt->attr.fetch_bookmark_ptr = tmp_bookmark;
814 :
815 28 : ODBC_EXIT(stmt, ret);
816 : }
817 :
818 0 : ODBC_FUNC(SQLForeignKeys, (P(SQLHSTMT,hstmt), PCHARIN(PkCatalogName,SQLSMALLINT),
819 : PCHARIN(PkSchemaName,SQLSMALLINT), PCHARIN(PkTableName,SQLSMALLINT),
820 : PCHARIN(FkCatalogName,SQLSMALLINT), PCHARIN(FkSchemaName,SQLSMALLINT),
821 : PCHARIN(FkTableName,SQLSMALLINT) WIDE))
822 : {
823 : int retcode;
824 :
825 0 : ODBC_ENTER_HSTMT;
826 :
827 0 : retcode =
828 0 : odbc_stat_execute(stmt _wide, "sp_fkeys", 6,
829 : "O@pktable_qualifier", szPkCatalogName, cbPkCatalogName,
830 : "O@pktable_owner", szPkSchemaName, cbPkSchemaName,
831 : "O@pktable_name", szPkTableName, cbPkTableName,
832 : "O@fktable_qualifier", szFkCatalogName, cbFkCatalogName,
833 : "O@fktable_owner", szFkSchemaName, cbFkSchemaName,
834 : "O@fktable_name", szFkTableName, cbFkTableName);
835 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
836 0 : odbc_col_setname(stmt, 1, "PKTABLE_CAT");
837 0 : odbc_col_setname(stmt, 2, "PKTABLE_SCHEM");
838 0 : odbc_col_setname(stmt, 5, "FKTABLE_CAT");
839 0 : odbc_col_setname(stmt, 6, "FKTABLE_SCHEM");
840 : }
841 0 : ODBC_EXIT_(stmt);
842 : }
843 :
844 : static bool
845 69677 : odbc_lock_statement(TDS_STMT* stmt)
846 : {
847 : #if ENABLE_ODBC_MARS
848 35012 : TDSSOCKET *tds = stmt->tds;
849 :
850 :
851 : /* we already own a socket, just use it */
852 35012 : if (!tds) {
853 : /* try with one saved into DBC */
854 16799 : TDSSOCKET *dbc_tds = stmt->dbc->tds_socket;
855 16799 : tds_mutex_lock(&stmt->dbc->mtx);
856 :
857 16799 : if (stmt->dbc->current_statement == NULL
858 54 : || stmt->dbc->current_statement == stmt) {
859 16745 : tds = dbc_tds;
860 16745 : stmt->dbc->current_statement = stmt;
861 : }
862 :
863 : /* try to grab current locked one */
864 16799 : if (!tds && dbc_tds->state == TDS_IDLE) {
865 40 : stmt->dbc->current_statement->tds = NULL;
866 40 : tds = dbc_tds;
867 40 : stmt->dbc->current_statement = stmt;
868 : }
869 16799 : tds_mutex_unlock(&stmt->dbc->mtx);
870 :
871 : /* try with MARS */
872 16799 : if (!tds) {
873 14 : tds = tds_alloc_additional_socket(dbc_tds->conn);
874 14 : if (tds)
875 8 : tdsdump_log(TDS_DBG_INFO1, "MARS SID %d allocated with new TDSSOCKET\n", tds->sid);
876 : }
877 : }
878 35012 : if (tds) {
879 70012 : tds->query_timeout = (stmt->attr.query_timeout != DEFAULT_QUERY_TIMEOUT) ?
880 35006 : stmt->attr.query_timeout : stmt->dbc->default_query_timeout;
881 35006 : tds_set_parent(tds, stmt);
882 35006 : stmt->tds = tds;
883 35006 : return true;
884 : }
885 6 : odbc_errs_add(&stmt->errs, "24000", NULL);
886 6 : return false;
887 : #else
888 34665 : TDSSOCKET *tds = stmt->dbc->tds_socket;
889 :
890 34665 : tds_mutex_lock(&stmt->dbc->mtx);
891 34665 : if (stmt->dbc->current_statement != NULL
892 17925 : && stmt->dbc->current_statement != stmt) {
893 51 : if (!tds || tds->state != TDS_IDLE) {
894 11 : tds_mutex_unlock(&stmt->dbc->mtx);
895 11 : odbc_errs_add(&stmt->errs, "24000", NULL);
896 11 : return false;
897 : }
898 40 : stmt->dbc->current_statement->tds = NULL;
899 : }
900 34654 : stmt->dbc->current_statement = stmt;
901 34654 : if (tds) {
902 69308 : tds->query_timeout = (stmt->attr.query_timeout != DEFAULT_QUERY_TIMEOUT) ?
903 34654 : stmt->attr.query_timeout : stmt->dbc->default_query_timeout;
904 34654 : tds_set_parent(tds, stmt);
905 34654 : stmt->tds = tds;
906 : }
907 34654 : tds_mutex_unlock(&stmt->dbc->mtx);
908 34654 : return true;
909 : #endif
910 : }
911 :
912 : static void
913 48752 : odbc_unlock_statement(TDS_STMT* stmt)
914 : {
915 : TDSSOCKET * tds;
916 :
917 48752 : tds_mutex_lock(&stmt->dbc->mtx);
918 48752 : tds = stmt->tds;
919 48752 : if (stmt->dbc->current_statement == stmt) {
920 32987 : assert(tds == stmt->dbc->tds_socket);
921 32987 : if (tds->state == TDS_IDLE || tds->state == TDS_DEAD) {
922 32987 : stmt->dbc->current_statement = NULL;
923 32987 : tds_set_parent(tds, stmt->dbc);
924 32987 : stmt->tds = NULL;
925 : }
926 : }
927 : /* NOTE: MARS socket now released when statement freed. */
928 48752 : tds_mutex_unlock(&stmt->dbc->mtx);
929 48752 : }
930 :
931 : SQLRETURN ODBC_PUBLIC ODBC_API
932 : SQLMoreResults(SQLHSTMT hstmt)
933 : {
934 : TDSSOCKET *tds;
935 : TDS_INT result_type;
936 : TDSRET tdsret;
937 10914 : bool in_row = false;
938 : SQLUSMALLINT param_status;
939 : unsigned int token_flags;
940 :
941 10914 : ODBC_ENTER_HSTMT;
942 :
943 10914 : tdsdump_log(TDS_DBG_FUNC, "SQLMoreResults(%p)\n", hstmt);
944 :
945 10914 : tds = stmt->tds;
946 :
947 : /* We already read all results... */
948 10914 : if (!tds)
949 785 : ODBC_EXIT(stmt, SQL_NO_DATA);
950 :
951 10129 : stmt->row_count = TDS_NO_COUNT;
952 10129 : stmt->special_row = ODBC_SPECIAL_NONE;
953 :
954 : /* TODO this code is TOO similar to odbc_SQLExecute, merge it - freddy77 */
955 : /* try to go to the next recordset */
956 10129 : if (stmt->row_status == IN_COMPUTE_ROW) {
957 : /* FIXME doesn't seem so fine ... - freddy77 */
958 16 : tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
959 16 : stmt->row_status = IN_COMPUTE_ROW;
960 16 : in_row = true;
961 : }
962 :
963 10129 : param_status = SQL_PARAM_SUCCESS;
964 10129 : token_flags = (TDS_TOKEN_RESULTS & (~TDS_STOPAT_COMPUTE)) | TDS_RETURN_COMPUTE;
965 10129 : if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
966 8307 : token_flags |= TDS_RETURN_MSG;
967 : for (;;) {
968 10672 : result_type = odbc_process_tokens(stmt, token_flags);
969 10672 : tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: result_type=%d, row_count=%" PRId64 ", lastrc=%d\n",
970 : result_type, stmt->row_count, stmt->errs.lastrc);
971 10672 : switch (result_type) {
972 8969 : case TDS_CMD_DONE:
973 : #if 1 /* !UNIXODBC */
974 8969 : tds_free_all_results(tds);
975 : #endif
976 8969 : odbc_populate_ird(stmt);
977 8969 : odbc_unlock_statement(stmt);
978 8969 : if (stmt->row_count == TDS_NO_COUNT && !in_row) {
979 8911 : stmt->row_status = NOT_IN_ROW;
980 8911 : tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: row_status=%d\n", stmt->row_status);
981 : }
982 8969 : tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: row_count=%" PRId64 ", lastrc=%d\n", stmt->row_count,
983 : stmt->errs.lastrc);
984 8969 : if (stmt->row_count == TDS_NO_COUNT) {
985 8923 : if (stmt->errs.lastrc == SQL_SUCCESS || stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO)
986 8919 : ODBC_EXIT(stmt, SQL_NO_DATA);
987 : }
988 50 : ODBC_EXIT_(stmt);
989 :
990 0 : case TDS_CMD_FAIL:
991 0 : ODBC_SAFE_ERROR(stmt);
992 0 : ODBC_EXIT_(stmt);
993 :
994 48 : case TDS_COMPUTE_RESULT:
995 48 : switch (stmt->row_status) {
996 : /* skip this recordset */
997 : case IN_COMPUTE_ROW:
998 : /* TODO here we should set current_results to normal results */
999 : in_row = true;
1000 : /* fall through */
1001 : /* in normal row, put in compute status */
1002 48 : case AFTER_COMPUTE_ROW:
1003 : case IN_NORMAL_ROW:
1004 : case PRE_NORMAL_ROW:
1005 48 : stmt->row_status = IN_COMPUTE_ROW;
1006 48 : odbc_populate_ird(stmt);
1007 48 : ODBC_EXIT_(stmt);
1008 0 : case NOT_IN_ROW:
1009 : /* this should never happen, protocol error */
1010 0 : ODBC_SAFE_ERROR(stmt);
1011 0 : ODBC_EXIT_(stmt);
1012 : break;
1013 : }
1014 : break;
1015 :
1016 389 : case TDS_ROW_RESULT:
1017 389 : if (in_row || (stmt->row_status != IN_NORMAL_ROW && stmt->row_status != PRE_NORMAL_ROW)) {
1018 158 : stmt->row_status = PRE_NORMAL_ROW;
1019 158 : odbc_populate_ird(stmt);
1020 158 : ODBC_EXIT_(stmt);
1021 : }
1022 : /* Skipping current result set's rows to access next resultset or proc's retval */
1023 231 : tdsret = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_STOPAT_COMPUTE);
1024 : /* TODO should we set in_row ?? */
1025 231 : switch (tdsret) {
1026 0 : case TDS_CANCELLED:
1027 0 : odbc_errs_add(&stmt->errs, "HY008", NULL);
1028 231 : default:
1029 231 : if (TDS_FAILED(tdsret)) {
1030 0 : ODBC_SAFE_ERROR(stmt);
1031 0 : ODBC_EXIT_(stmt);
1032 : }
1033 : }
1034 : break;
1035 :
1036 872 : case TDS_DONE_RESULT:
1037 : case TDS_DONEPROC_RESULT:
1038 : /* FIXME here ??? */
1039 872 : if (!in_row)
1040 804 : tds_free_all_results(tds);
1041 872 : switch (stmt->errs.lastrc) {
1042 70 : case SQL_ERROR:
1043 70 : param_status = SQL_PARAM_ERROR;
1044 70 : break;
1045 58 : case SQL_SUCCESS_WITH_INFO:
1046 58 : param_status = SQL_PARAM_SUCCESS_WITH_INFO;
1047 58 : break;
1048 : }
1049 872 : if (stmt->curr_param_row < stmt->num_param_rows) {
1050 0 : if (stmt->ipd->header.sql_desc_array_status_ptr)
1051 0 : stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
1052 0 : ++stmt->curr_param_row;
1053 0 : if (stmt->ipd->header.sql_desc_rows_processed_ptr)
1054 0 : *stmt->ipd->header.sql_desc_rows_processed_ptr = stmt->curr_param_row;
1055 : }
1056 872 : if (stmt->curr_param_row < stmt->num_param_rows) {
1057 : #if 0
1058 : if (stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO)
1059 : found_info = 1;
1060 : if (stmt->errs.lastrc == SQL_ERROR)
1061 : found_error = 1;
1062 : #endif
1063 0 : stmt->errs.lastrc = SQL_SUCCESS;
1064 0 : param_status = SQL_PARAM_SUCCESS;
1065 0 : break;
1066 : }
1067 872 : odbc_populate_ird(stmt);
1068 872 : ODBC_EXIT_(stmt);
1069 : break;
1070 :
1071 : /*
1072 : * TODO test flags ? check error and change result ?
1073 : * see also other DONEINPROC handle (below)
1074 : */
1075 86 : case TDS_DONEINPROC_RESULT:
1076 86 : if (in_row) {
1077 70 : odbc_populate_ird(stmt);
1078 70 : ODBC_EXIT_(stmt);
1079 : }
1080 : /* TODO perhaps it can be a problem if SET NOCOUNT ON, test it */
1081 16 : tds_free_all_results(tds);
1082 16 : odbc_populate_ird(stmt);
1083 16 : break;
1084 :
1085 : /* do not stop at metadata, an error can follow... */
1086 194 : case TDS_ROWFMT_RESULT:
1087 194 : if (in_row) {
1088 12 : odbc_populate_ird(stmt);
1089 12 : ODBC_EXIT_(stmt);
1090 : }
1091 182 : stmt->row = 0;
1092 182 : stmt->row_count = TDS_NO_COUNT;
1093 : /* we expect a row */
1094 182 : stmt->row_status = PRE_NORMAL_ROW;
1095 182 : in_row = true;
1096 182 : break;
1097 :
1098 114 : case TDS_MSG_RESULT:
1099 114 : if (!in_row) {
1100 114 : tds_free_all_results(tds);
1101 114 : odbc_populate_ird(stmt);
1102 : }
1103 : in_row = true;
1104 : break;
1105 : }
1106 : }
1107 : ODBC_EXIT(stmt, SQL_ERROR);
1108 : }
1109 :
1110 0 : ODBC_FUNC(SQLNativeSql, (P(SQLHDBC,hdbc), PCHARIN(SqlStrIn,SQLINTEGER),
1111 : PCHAROUT(SqlStr,SQLINTEGER) WIDE))
1112 : {
1113 0 : SQLRETURN ret = SQL_SUCCESS;
1114 0 : DSTR query = DSTR_INITIALIZER;
1115 :
1116 0 : ODBC_ENTER_HDBC;
1117 :
1118 : #ifdef TDS_NO_DM
1119 0 : if (!szSqlStrIn || !IS_VALID_LEN(cbSqlStrIn)) {
1120 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
1121 0 : ODBC_EXIT_(dbc);
1122 : }
1123 : #endif
1124 :
1125 0 : if (!odbc_dstr_copy(dbc, &query, cbSqlStrIn, szSqlStrIn)) {
1126 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1127 0 : ODBC_EXIT_(dbc);
1128 : }
1129 :
1130 0 : native_sql(dbc, &query);
1131 :
1132 : /* FIXME if error set some kind of error */
1133 0 : ret = odbc_set_dstr(dbc, szSqlStr, cbSqlStrMax, pcbSqlStr, &query);
1134 :
1135 0 : tds_dstr_free(&query);
1136 :
1137 0 : ODBC_EXIT(dbc, ret);
1138 : }
1139 :
1140 : SQLRETURN ODBC_PUBLIC ODBC_API
1141 : SQLNumParams(SQLHSTMT hstmt, SQLSMALLINT FAR * pcpar)
1142 : {
1143 46 : ODBC_ENTER_HSTMT;
1144 46 : tdsdump_log(TDS_DBG_FUNC, "SQLNumParams(%p, %p)\n", hstmt, pcpar);
1145 46 : *pcpar = stmt->param_count;
1146 46 : ODBC_EXIT_(stmt);
1147 : }
1148 :
1149 : SQLRETURN ODBC_PUBLIC ODBC_API
1150 : SQLParamOptions(SQLHSTMT hstmt, SQLULEN crow, SQLULEN FAR * pirow)
1151 : {
1152 : SQLRETURN res;
1153 :
1154 20 : tdsdump_log(TDS_DBG_FUNC, "SQLParamOptions(%p, %lu, %p)\n", hstmt, (unsigned long int)crow, pirow);
1155 :
1156 : /* emulate for ODBC 2 DM */
1157 20 : res = odbc_SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, pirow, 0 _wide0);
1158 20 : if (res != SQL_SUCCESS)
1159 : return res;
1160 20 : return odbc_SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) (TDS_INTPTR) crow, 0 _wide0);
1161 : }
1162 :
1163 0 : ODBC_FUNC(SQLPrimaryKeys, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
1164 : PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT) WIDE))
1165 : {
1166 : int retcode;
1167 :
1168 0 : ODBC_ENTER_HSTMT;
1169 :
1170 0 : retcode =
1171 0 : odbc_stat_execute(stmt _wide, "sp_pkeys", 3, "O@table_qualifier", szCatalogName, cbCatalogName, "O@table_owner",
1172 : szSchemaName, cbSchemaName, "O@table_name", szTableName, cbTableName);
1173 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1174 0 : odbc_col_setname(stmt, 1, "TABLE_CAT");
1175 0 : odbc_col_setname(stmt, 2, "TABLE_SCHEM");
1176 : }
1177 0 : ODBC_EXIT_(stmt);
1178 : }
1179 :
1180 20 : ODBC_FUNC(SQLProcedureColumns, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
1181 : PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(ProcName,SQLSMALLINT), PCHARIN(ColumnName,SQLSMALLINT) WIDE))
1182 : {
1183 : int retcode;
1184 :
1185 20 : ODBC_ENTER_HSTMT;
1186 :
1187 20 : retcode =
1188 20 : odbc_stat_execute(stmt _wide, "sp_sproc_columns", TDS_IS_MSSQL(stmt->dbc->tds_socket) ? 5 : 4,
1189 : "O@procedure_qualifier", szCatalogName, cbCatalogName,
1190 : "P@procedure_owner", szSchemaName, cbSchemaName, "P@procedure_name", szProcName, cbProcName,
1191 : "P@column_name", szColumnName, cbColumnName, "V@ODBCVer", (char*) NULL, 0);
1192 20 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1193 10 : odbc_col_setname(stmt, 1, "PROCEDURE_CAT");
1194 10 : odbc_col_setname(stmt, 2, "PROCEDURE_SCHEM");
1195 10 : odbc_col_setname(stmt, 8, "COLUMN_SIZE");
1196 10 : odbc_col_setname(stmt, 9, "BUFFER_LENGTH");
1197 10 : odbc_col_setname(stmt, 10, "DECIMAL_DIGITS");
1198 10 : odbc_col_setname(stmt, 11, "NUM_PREC_RADIX");
1199 10 : if (TDS_IS_SYBASE(stmt->dbc->tds_socket))
1200 2 : stmt->special_row = ODBC_SPECIAL_PROCEDURECOLUMNS;
1201 : }
1202 20 : ODBC_EXIT_(stmt);
1203 : }
1204 :
1205 0 : ODBC_FUNC(SQLProcedures, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
1206 : PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(ProcName,SQLSMALLINT) WIDE))
1207 : {
1208 : int retcode;
1209 :
1210 0 : ODBC_ENTER_HSTMT;
1211 :
1212 0 : retcode =
1213 0 : odbc_stat_execute(stmt _wide, "..sp_stored_procedures", 3,
1214 : "P@sp_name", szProcName, cbProcName,
1215 : "P@sp_owner", szSchemaName, cbSchemaName,
1216 : "O@sp_qualifier", szCatalogName, cbCatalogName);
1217 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1218 0 : odbc_col_setname(stmt, 1, "PROCEDURE_CAT");
1219 0 : odbc_col_setname(stmt, 2, "PROCEDURE_SCHEM");
1220 : }
1221 0 : ODBC_EXIT_(stmt);
1222 : }
1223 :
1224 : static TDSPARAMINFO*
1225 80 : odbc_build_update_params(TDS_STMT * stmt, SQLSETPOSIROW n_row)
1226 : {
1227 : SQLSMALLINT n;
1228 80 : TDSPARAMINFO * params = NULL;
1229 : struct _drecord *drec_ird;
1230 :
1231 240 : for (n = 0; n < stmt->ird->header.sql_desc_count && n < stmt->ard->header.sql_desc_count; ++n) {
1232 : TDSPARAMINFO *temp_params;
1233 : TDSCOLUMN *curcol;
1234 :
1235 160 : drec_ird = &stmt->ird->records[n];
1236 :
1237 160 : if (drec_ird->sql_desc_updatable == SQL_FALSE)
1238 16 : continue;
1239 :
1240 : /* we have certainly a parameter */
1241 144 : if (!(temp_params = tds_alloc_param_result(params)))
1242 : goto memory_error;
1243 144 : params = temp_params;
1244 :
1245 144 : curcol = params->columns[params->num_cols - 1];
1246 144 : if (!tds_dstr_dup(&curcol->column_name, &drec_ird->sql_desc_name))
1247 : goto memory_error;
1248 :
1249 : /* TODO use all infos... */
1250 144 : if (!tds_dstr_dup(&curcol->table_name, &drec_ird->sql_desc_base_table_name))
1251 : goto memory_error;
1252 :
1253 144 : switch (odbc_sql2tds(stmt, drec_ird, &stmt->ard->records[n], curcol, true, stmt->ard, n_row)) {
1254 : case SQL_NEED_DATA:
1255 : goto memory_error;
1256 0 : case SQL_ERROR:
1257 0 : tds_free_param_results(params);
1258 0 : return NULL;
1259 : }
1260 : }
1261 : return params;
1262 :
1263 0 : memory_error:
1264 0 : tds_free_param_results(params);
1265 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
1266 0 : return NULL;
1267 : }
1268 :
1269 : SQLRETURN ODBC_PUBLIC ODBC_API
1270 : SQLSetPos(SQLHSTMT hstmt, SQLSETPOSIROW irow, SQLUSMALLINT fOption, SQLUSMALLINT fLock)
1271 : {
1272 : TDSRET ret;
1273 : TDSSOCKET *tds;
1274 : TDS_CURSOR_OPERATION op;
1275 320 : TDSPARAMINFO *params = NULL;
1276 320 : ODBC_ENTER_HSTMT;
1277 :
1278 320 : tdsdump_log(TDS_DBG_FUNC, "SQLSetPos(%p, %ld, %d, %d)\n",
1279 : hstmt, (long) irow, fOption, fLock);
1280 :
1281 320 : if (!stmt->dbc->cursor_support) {
1282 0 : odbc_errs_add(&stmt->errs, "HYC00", "SQLSetPos: function not implemented");
1283 0 : ODBC_EXIT_(stmt);
1284 : }
1285 :
1286 : /* TODO handle irow == 0 (all rows) */
1287 :
1288 320 : if (!stmt->cursor) {
1289 0 : odbc_errs_add(&stmt->errs, "HY109", NULL);
1290 0 : ODBC_EXIT_(stmt);
1291 : }
1292 :
1293 320 : switch (fOption) {
1294 : case SQL_POSITION:
1295 : op = TDS_CURSOR_POSITION;
1296 : break;
1297 : /* TODO cursor support */
1298 0 : case SQL_REFRESH:
1299 : default:
1300 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
1301 0 : ODBC_EXIT_(stmt);
1302 : break;
1303 80 : case SQL_UPDATE:
1304 80 : op = TDS_CURSOR_UPDATE;
1305 : /* prepare paremeters for update */
1306 : /* scan all columns and build parameter list */
1307 80 : params = odbc_build_update_params(stmt, irow >= 1 ? irow - 1 : 0);
1308 80 : if (!params) {
1309 0 : ODBC_SAFE_ERROR(stmt);
1310 0 : ODBC_EXIT_(stmt);
1311 : }
1312 : break;
1313 80 : case SQL_DELETE:
1314 80 : op = TDS_CURSOR_DELETE;
1315 80 : break;
1316 0 : case SQL_ADD:
1317 0 : op = TDS_CURSOR_INSERT;
1318 0 : break;
1319 : }
1320 :
1321 320 : if (!odbc_lock_statement(stmt)) {
1322 0 : tds_free_param_results(params);
1323 0 : ODBC_EXIT_(stmt);
1324 : }
1325 :
1326 320 : tds = stmt->tds;
1327 :
1328 320 : if (TDS_FAILED(tds_cursor_update(tds, stmt->cursor, op, irow, params))) {
1329 0 : tds_free_param_results(params);
1330 0 : ODBC_SAFE_ERROR(stmt);
1331 0 : ODBC_EXIT_(stmt);
1332 : }
1333 320 : tds_free_param_results(params);
1334 320 : params = NULL;
1335 :
1336 320 : ret = tds_process_simple_query(tds);
1337 320 : odbc_unlock_statement(stmt);
1338 320 : if (TDS_FAILED(ret)) {
1339 0 : ODBC_SAFE_ERROR(stmt);
1340 0 : ODBC_EXIT_(stmt);
1341 : }
1342 :
1343 320 : ODBC_EXIT_(stmt);
1344 : }
1345 :
1346 0 : ODBC_FUNC(SQLTablePrivileges, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
1347 : PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT) WIDE))
1348 : {
1349 : int retcode;
1350 :
1351 0 : ODBC_ENTER_HSTMT;
1352 :
1353 0 : retcode =
1354 0 : odbc_stat_execute(stmt _wide, "sp_table_privileges", 3, "O@table_qualifier", szCatalogName, cbCatalogName,
1355 : "P@table_owner", szSchemaName, cbSchemaName, "P@table_name", szTableName, cbTableName);
1356 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1357 0 : odbc_col_setname(stmt, 1, "TABLE_CAT");
1358 0 : odbc_col_setname(stmt, 2, "TABLE_SCHEM");
1359 : }
1360 0 : ODBC_EXIT_(stmt);
1361 : }
1362 :
1363 : #if (ODBCVER >= 0x0300)
1364 : SQLRETURN ODBC_PUBLIC ODBC_API
1365 : SQLSetEnvAttr(SQLHENV henv, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength)
1366 : {
1367 618 : SQLINTEGER i_val = (SQLINTEGER) (TDS_INTPTR) Value;
1368 :
1369 618 : ODBC_ENTER_HENV;
1370 :
1371 618 : tdsdump_log(TDS_DBG_FUNC, "SQLSetEnvAttr(%p, %d, %p, %d)\n", henv, (int)Attribute, Value, (int)StringLength);
1372 :
1373 618 : switch (Attribute) {
1374 0 : case SQL_ATTR_CONNECTION_POOLING:
1375 : case SQL_ATTR_CP_MATCH:
1376 0 : odbc_errs_add(&env->errs, "HYC00", NULL);
1377 0 : break;
1378 618 : case SQL_ATTR_ODBC_VERSION:
1379 618 : switch (i_val) {
1380 618 : case SQL_OV_ODBC3:
1381 : case SQL_OV_ODBC2:
1382 618 : env->attr.odbc_version = i_val;
1383 618 : break;
1384 0 : default:
1385 0 : odbc_errs_add(&env->errs, "HY024", NULL);
1386 0 : break;
1387 : }
1388 : break;
1389 0 : case SQL_ATTR_OUTPUT_NTS:
1390 : /* TODO - Make this really work */
1391 : /* env->attr.output_nts = i_val; */
1392 0 : env->attr.output_nts = SQL_TRUE;
1393 0 : break;
1394 0 : default:
1395 0 : odbc_errs_add(&env->errs, "HY092", NULL);
1396 0 : break;
1397 : }
1398 618 : ODBC_EXIT_(env);
1399 : }
1400 :
1401 : SQLRETURN ODBC_PUBLIC ODBC_API
1402 : SQLGetEnvAttr(SQLHENV henv, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
1403 : {
1404 : static const SQLINTEGER unicode_type =
1405 : sizeof(SQLWCHAR) == 4 ? SQL_DM_CP_UCS4 : SQL_DM_CP_UTF16;
1406 : SQLINTEGER size;
1407 : const void *src;
1408 :
1409 0 : ODBC_ENTER_HENV;
1410 :
1411 0 : tdsdump_log(TDS_DBG_FUNC, "SQLGetEnvAttr(%p, %d, %p, %d, %p)\n",
1412 : henv, (int)Attribute, Value, (int)BufferLength, StringLength);
1413 :
1414 0 : switch (Attribute) {
1415 0 : case SQL_ATTR_CONNECTION_POOLING:
1416 0 : src = &env->attr.connection_pooling;
1417 0 : size = sizeof(env->attr.connection_pooling);
1418 0 : break;
1419 0 : case SQL_ATTR_CP_MATCH:
1420 0 : src = &env->attr.cp_match;
1421 0 : size = sizeof(env->attr.cp_match);
1422 0 : break;
1423 0 : case SQL_ATTR_ODBC_VERSION:
1424 0 : src = &env->attr.odbc_version;
1425 0 : size = sizeof(env->attr.odbc_version);
1426 0 : break;
1427 0 : case SQL_ATTR_OUTPUT_NTS:
1428 : /* TODO handle output_nts flags */
1429 0 : env->attr.output_nts = SQL_TRUE;
1430 0 : src = &env->attr.output_nts;
1431 0 : size = sizeof(env->attr.output_nts);
1432 0 : break;
1433 : case SQL_ATTR_DRIVER_UNICODE_TYPE:
1434 : /* iODBC extension, tell which Unicode encoding we support */
1435 : src = &unicode_type;
1436 : size = sizeof(unicode_type);
1437 : break;
1438 0 : default:
1439 0 : odbc_errs_add(&env->errs, "HY092", NULL);
1440 0 : ODBC_EXIT_(env);
1441 : break;
1442 : }
1443 :
1444 0 : if (StringLength) {
1445 0 : *StringLength = size;
1446 : }
1447 0 : memcpy(Value, src, size);
1448 :
1449 0 : ODBC_EXIT_(env);
1450 : }
1451 :
1452 : #endif
1453 :
1454 : #define IRD_UPDATE(desc, errs, exit) \
1455 : do { \
1456 : if (desc->type == DESC_IRD && ((TDS_STMT*)desc->parent)->need_reprepare && \
1457 : odbc_update_ird((TDS_STMT*)desc->parent, errs) != SQL_SUCCESS) \
1458 : exit; \
1459 : } while(0)
1460 :
1461 : static SQLRETURN
1462 15182 : odbc_SQLBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType,
1463 : SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
1464 : {
1465 : TDS_DESC *apd, *ipd;
1466 : struct _drecord *drec;
1467 : SQLSMALLINT orig_apd_size, orig_ipd_size;
1468 15182 : bool is_numeric = false;
1469 :
1470 15182 : ODBC_ENTER_HSTMT;
1471 :
1472 15182 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLBindParameter(%p, %u, %d, %d, %d, %u, %d, %p, %d, %p)\n",
1473 : hstmt, (unsigned)ipar, (int)fParamType, (int)fCType, (int)fSqlType, (unsigned int)cbColDef,
1474 : (int)ibScale, rgbValue, (int)cbValueMax, pcbValue);
1475 :
1476 : #ifdef TDS_NO_DM
1477 : /* TODO - more error checking ... XXX smurph */
1478 :
1479 : /* Check param type */
1480 : switch (fParamType) {
1481 : case SQL_PARAM_INPUT:
1482 : case SQL_PARAM_INPUT_OUTPUT:
1483 : case SQL_PARAM_OUTPUT:
1484 : break;
1485 0 : default:
1486 0 : odbc_errs_add(&stmt->errs, "HY105", NULL);
1487 0 : ODBC_EXIT_(stmt);
1488 : }
1489 :
1490 : /* Check max buffer length */
1491 15182 : if (cbValueMax < 0 && cbValueMax != SQL_NTS) {
1492 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
1493 0 : ODBC_EXIT_(stmt);
1494 : }
1495 : #endif
1496 :
1497 : /* check cbColDef and ibScale */
1498 15182 : if (fSqlType == SQL_DECIMAL || fSqlType == SQL_NUMERIC) {
1499 220 : is_numeric = true;
1500 220 : if (cbColDef < 1 || cbColDef > 38) {
1501 0 : odbc_errs_add(&stmt->errs, "HY104", "Invalid precision value");
1502 0 : ODBC_EXIT_(stmt);
1503 : }
1504 220 : if (ibScale < 0 || (SQLULEN) ibScale > cbColDef) {
1505 0 : odbc_errs_add(&stmt->errs, "HY104", "Invalid scale value");
1506 0 : ODBC_EXIT_(stmt);
1507 : }
1508 : }
1509 :
1510 : /* Check parameter number */
1511 15182 : if (ipar <= 0 || ipar > 4000) {
1512 0 : odbc_errs_add(&stmt->errs, "07009", NULL);
1513 0 : ODBC_EXIT_(stmt);
1514 : }
1515 :
1516 : /* special checks for table type */
1517 15182 : if (fSqlType == SQL_SS_TABLE) {
1518 : /* Table types are strictly read-only */
1519 4152 : if (fParamType != SQL_PARAM_INPUT) {
1520 12 : odbc_errs_add(&stmt->errs, "HY105", NULL);
1521 12 : ODBC_EXIT_(stmt);
1522 : }
1523 :
1524 : /* Only SQL_C_DEFAULT is accepted */
1525 4140 : if (fCType != SQL_C_DEFAULT) {
1526 4 : odbc_errs_add(&stmt->errs, "07006", NULL);
1527 4 : ODBC_EXIT_(stmt);
1528 : }
1529 : fCType = SQL_C_BINARY;
1530 : }
1531 :
1532 15166 : apd = stmt->apd;
1533 15166 : ipd = stmt->ipd;
1534 :
1535 : /* If the parameter focus is set to 0, bind values as arguments */
1536 : /* Otherwise, bind values as the columns of a table-valued parameter */
1537 15166 : if (stmt->attr.param_focus != 0) {
1538 : SQLTVP *tvp;
1539 :
1540 : /* a table type cannot contain a table type */
1541 4148 : if (fSqlType == SQL_SS_TABLE) {
1542 8 : odbc_errs_add(&stmt->errs, "HY004", NULL);
1543 8 : ODBC_EXIT_(stmt);
1544 : }
1545 :
1546 : /* Columns of table types are strictly read-only */
1547 4140 : if (fParamType != SQL_PARAM_INPUT) {
1548 0 : odbc_errs_add(&stmt->errs, "HY105", NULL);
1549 0 : ODBC_EXIT_(stmt);
1550 : }
1551 :
1552 : /* check index */
1553 4140 : if (stmt->attr.param_focus > ipd->header.sql_desc_count) {
1554 0 : odbc_errs_add(&stmt->errs, "IM020", NULL);
1555 0 : ODBC_EXIT_(stmt);
1556 : }
1557 :
1558 4140 : drec = &ipd->records[stmt->attr.param_focus - 1];
1559 :
1560 : /* check ipd type */
1561 4140 : if (drec->sql_desc_concise_type != SQL_SS_TABLE) {
1562 0 : odbc_errs_add(&stmt->errs, "IM020", NULL);
1563 0 : ODBC_EXIT_(stmt);
1564 : }
1565 :
1566 4140 : tvp = (SQLTVP *) drec->sql_desc_data_ptr;
1567 4140 : apd = tvp->apd;
1568 4140 : ipd = tvp->ipd;
1569 : }
1570 :
1571 : /* fill APD related fields */
1572 15158 : orig_apd_size = apd->header.sql_desc_count;
1573 15158 : if (ipar > apd->header.sql_desc_count && desc_alloc_records(apd, ipar) != SQL_SUCCESS) {
1574 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
1575 0 : ODBC_EXIT_(stmt);
1576 : }
1577 15158 : drec = &apd->records[ipar - 1];
1578 :
1579 15158 : if (odbc_set_concise_c_type(fCType, drec, 0) != SQL_SUCCESS) {
1580 70 : desc_alloc_records(apd, orig_apd_size);
1581 70 : odbc_errs_add(&stmt->errs, "HY004", NULL);
1582 70 : ODBC_EXIT_(stmt);
1583 : }
1584 :
1585 15088 : stmt->need_reprepare = 1;
1586 :
1587 : /* TODO other types ?? handle SQL_C_DEFAULT */
1588 15088 : if (drec->sql_desc_type == SQL_C_CHAR || drec->sql_desc_type == SQL_C_WCHAR || drec->sql_desc_type == SQL_C_BINARY)
1589 7478 : drec->sql_desc_octet_length = cbValueMax;
1590 15088 : drec->sql_desc_indicator_ptr = pcbValue;
1591 15088 : drec->sql_desc_octet_length_ptr = pcbValue;
1592 15088 : drec->sql_desc_data_ptr = (char *) rgbValue;
1593 :
1594 15088 : if (fSqlType == SQL_SS_TABLE)
1595 4128 : drec->sql_desc_length = 1;
1596 :
1597 : /* field IPD related fields */
1598 15088 : orig_ipd_size = ipd->header.sql_desc_count;
1599 15088 : if (ipar > ipd->header.sql_desc_count && desc_alloc_records(ipd, ipar) != SQL_SUCCESS) {
1600 0 : desc_alloc_records(apd, orig_apd_size);
1601 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
1602 0 : ODBC_EXIT_(stmt);
1603 : }
1604 15088 : drec = &ipd->records[ipar - 1];
1605 :
1606 15088 : drec->sql_desc_parameter_type = fParamType;
1607 :
1608 15088 : if (odbc_set_concise_sql_type(fSqlType, drec, 0) != SQL_SUCCESS) {
1609 0 : desc_alloc_records(ipd, orig_ipd_size);
1610 0 : desc_alloc_records(apd, orig_apd_size);
1611 0 : odbc_errs_add(&stmt->errs, "HY004", NULL);
1612 0 : ODBC_EXIT_(stmt);
1613 : }
1614 15088 : if (is_numeric) {
1615 220 : drec->sql_desc_precision = (SQLSMALLINT) cbColDef;
1616 220 : drec->sql_desc_scale = ibScale;
1617 : } else {
1618 14868 : drec->sql_desc_length = cbColDef;
1619 : }
1620 :
1621 15088 : if (fSqlType == SQL_SS_TABLE) {
1622 : SQLTVP *tvp;
1623 4128 : int wide TDS_UNUSED = 1;
1624 :
1625 4128 : tvp = tvp_alloc(stmt);
1626 4128 : if (tvp == NULL) {
1627 0 : desc_alloc_records(ipd, orig_ipd_size);
1628 0 : desc_alloc_records(apd, orig_apd_size);
1629 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
1630 0 : ODBC_EXIT_(stmt);
1631 : }
1632 4128 : tvp->apd->header.sql_desc_array_size = cbColDef;
1633 :
1634 4128 : if (!odbc_dstr_copy_oct(stmt->dbc, &tvp->type_name, cbValueMax, (ODBC_CHAR *) rgbValue)) {
1635 0 : free(tvp);
1636 0 : desc_alloc_records(ipd, orig_ipd_size);
1637 0 : desc_alloc_records(apd, orig_apd_size);
1638 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
1639 0 : ODBC_EXIT_(stmt);
1640 : }
1641 :
1642 : /* Use this the column type as a marker for us */
1643 : /* to free up memory allocated with odbc_alloc_table() */
1644 4128 : drec->sql_desc_type = drec->sql_desc_concise_type = SQL_SS_TABLE;
1645 :
1646 4128 : drec->sql_desc_data_ptr = tvp;
1647 :
1648 4128 : drec->sql_desc_length = 0;
1649 : }
1650 :
1651 15088 : stmt->params_set = 1;
1652 15088 : ODBC_EXIT_(stmt);
1653 : }
1654 :
1655 : SQLRETURN ODBC_PUBLIC ODBC_API
1656 : SQLBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType,
1657 : SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
1658 : {
1659 15182 : tdsdump_log(TDS_DBG_FUNC, "SQLBindParameter(%p, %u, %d, %d, %d, %u, %d, %p, %d, %p)\n",
1660 : hstmt, (unsigned)ipar, fParamType, fCType, (int)fSqlType, (unsigned)cbColDef, ibScale,
1661 : rgbValue, (int)cbValueMax, pcbValue);
1662 15182 : return odbc_SQLBindParameter(hstmt, ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, cbValueMax, pcbValue);
1663 : }
1664 :
1665 :
1666 : /* compatibility with X/Open */
1667 : SQLRETURN ODBC_PUBLIC ODBC_API
1668 : SQLBindParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLULEN cbColDef, SQLSMALLINT ibScale,
1669 : SQLPOINTER rgbValue, SQLLEN FAR * pcbValue)
1670 : {
1671 0 : tdsdump_log(TDS_DBG_FUNC, "SQLBindParam(%p, %d, %d, %d, %u, %d, %p, %p)\n",
1672 : hstmt, ipar, fCType, fSqlType, (unsigned)cbColDef, ibScale, rgbValue, pcbValue);
1673 0 : return odbc_SQLBindParameter(hstmt, ipar, SQL_PARAM_INPUT, fCType, fSqlType, cbColDef, ibScale, rgbValue, 0, pcbValue);
1674 : }
1675 :
1676 : #if (ODBCVER >= 0x0300)
1677 : SQLRETURN ODBC_PUBLIC ODBC_API
1678 : SQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE * OutputHandle)
1679 : {
1680 1356 : tdsdump_log(TDS_DBG_FUNC, "SQLAllocHandle(%d, %p, %p)\n", HandleType, InputHandle, OutputHandle);
1681 :
1682 1356 : if (OutputHandle)
1683 1356 : *OutputHandle = SQL_NULL_HANDLE;
1684 :
1685 1356 : switch (HandleType) {
1686 120 : case SQL_HANDLE_STMT:
1687 120 : return odbc_SQLAllocStmt(InputHandle, OutputHandle);
1688 : break;
1689 608 : case SQL_HANDLE_DBC:
1690 608 : return odbc_SQLAllocConnect(InputHandle, OutputHandle);
1691 : break;
1692 608 : case SQL_HANDLE_ENV:
1693 608 : return odbc_SQLAllocEnv(OutputHandle, SQL_OV_ODBC3);
1694 : break;
1695 20 : case SQL_HANDLE_DESC:
1696 20 : return odbc_SQLAllocDesc(InputHandle, OutputHandle);
1697 : break;
1698 : }
1699 :
1700 : /*
1701 : * As the documentation puts it,
1702 : * "There is no handle with which to associate additional diagnostic information."
1703 : *
1704 : * The DM must catch HY092 because the driver has no valid handle at this early stage in which
1705 : * to store the error for later retrieval by the application.
1706 : */
1707 0 : tdsdump_log(TDS_DBG_FUNC, "SQLAllocHandle(): invalid HandleType, error HY092: should be caught by DM\n");
1708 : return SQL_ERROR;
1709 : }
1710 : #endif
1711 :
1712 : static SQLRETURN
1713 1206 : odbc_SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc)
1714 : {
1715 : TDS_DBC *dbc;
1716 :
1717 1206 : ODBC_ENTER_HENV;
1718 :
1719 1206 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLAllocConnect(%p, %p)\n", henv, phdbc);
1720 :
1721 1206 : if (!phdbc) {
1722 0 : odbc_errs_add(&env->errs, "HY009", NULL);
1723 0 : ODBC_EXIT_(env);
1724 : }
1725 :
1726 1206 : dbc = tds_new0(TDS_DBC, 1);
1727 1206 : if (!dbc) {
1728 0 : odbc_errs_add(&env->errs, "HY001", NULL);
1729 0 : ODBC_EXIT_(env);
1730 : }
1731 :
1732 1206 : dbc->htype = SQL_HANDLE_DBC;
1733 1206 : dbc->env = env;
1734 2412 : tds_dstr_init(&dbc->dsn);
1735 :
1736 1206 : dbc->attr.cursor_type = SQL_CURSOR_FORWARD_ONLY;
1737 1206 : dbc->attr.access_mode = SQL_MODE_READ_WRITE;
1738 1206 : dbc->attr.async_enable = SQL_ASYNC_ENABLE_OFF;
1739 1206 : dbc->attr.auto_ipd = SQL_FALSE;
1740 : /*
1741 : * spinellia@acm.org
1742 : * after login is enabled autocommit
1743 : */
1744 1206 : dbc->attr.autocommit = SQL_AUTOCOMMIT_ON;
1745 1206 : dbc->attr.connection_dead = SQL_CD_TRUE; /* No connection yet */
1746 1206 : dbc->attr.connection_timeout = 0;
1747 : /* This is set in the environment change function */
1748 2412 : tds_dstr_init(&dbc->attr.current_catalog);
1749 1206 : dbc->attr.login_timeout = 0; /* TODO */
1750 1206 : dbc->attr.metadata_id = SQL_FALSE;
1751 1206 : dbc->attr.odbc_cursors = SQL_CUR_USE_DRIVER;
1752 1206 : dbc->attr.packet_size = 0;
1753 1206 : dbc->attr.quite_mode = NULL; /* We don't support GUI dialogs yet */
1754 : #ifdef TDS_NO_DM
1755 1206 : dbc->attr.trace = SQL_OPT_TRACE_OFF;
1756 2412 : tds_dstr_init(&dbc->attr.tracefile);
1757 : #endif
1758 2412 : tds_dstr_init(&dbc->attr.translate_lib);
1759 : #ifdef ENABLE_ODBC_WIDE
1760 1206 : dbc->original_charset_num = TDS_CHARSET_UTF_8;
1761 : #endif
1762 2412 : tds_dstr_init(&dbc->oldpwd);
1763 2412 : tds_dstr_init(&dbc->db_filename);
1764 1206 : dbc->attr.translate_option = 0;
1765 1206 : dbc->attr.txn_isolation = SQL_TXN_READ_COMMITTED;
1766 1206 : dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
1767 1206 : dbc->attr.bulk_enabled = SQL_BCP_OFF;
1768 :
1769 : /* Initial values of DBC date formats taken from environment context.
1770 : * odbc_SQLAllocEnv() always initializes that. */
1771 2412 : tds_dstr_init(&dbc->datetime_fmt);
1772 2412 : tds_dstr_init(&dbc->date_fmt);
1773 2412 : tds_dstr_init(&dbc->time_fmt);
1774 :
1775 2412 : if (!tds_dstr_copy(&dbc->datetime_fmt, env->tds_ctx->locale->datetime_fmt) ||
1776 2412 : !tds_dstr_copy(&dbc->date_fmt, env->tds_ctx->locale->date_fmt) ||
1777 1206 : !tds_dstr_copy(&dbc->time_fmt, env->tds_ctx->locale->time_fmt)) {
1778 0 : tds_dstr_free(&dbc->datetime_fmt);
1779 0 : tds_dstr_free(&dbc->date_fmt);
1780 0 : tds_dstr_free(&dbc->time_fmt);
1781 0 : free(dbc);
1782 0 : odbc_errs_add(&env->errs, "HY001", NULL);
1783 0 : ODBC_EXIT_(env);
1784 : }
1785 :
1786 2412 : tds_mutex_init(&dbc->mtx);
1787 1206 : *phdbc = (SQLHDBC) dbc;
1788 :
1789 1206 : ODBC_EXIT_(env);
1790 : }
1791 :
1792 : SQLRETURN ODBC_PUBLIC ODBC_API
1793 : SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc)
1794 : {
1795 598 : tdsdump_log(TDS_DBG_FUNC, "SQLAllocConnect(%p, %p)\n", henv, phdbc);
1796 :
1797 598 : return odbc_SQLAllocConnect(henv, phdbc);
1798 : }
1799 :
1800 : static SQLRETURN
1801 1206 : odbc_SQLAllocEnv(SQLHENV FAR * phenv, SQLINTEGER odbc_version)
1802 : {
1803 : TDS_ENV *env;
1804 : TDSCONTEXT *ctx;
1805 :
1806 1206 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLAllocEnv(%p, %d)\n",
1807 : phenv, (int) odbc_version);
1808 :
1809 1206 : if (!phenv)
1810 : return SQL_ERROR;
1811 :
1812 1206 : env = tds_new0(TDS_ENV, 1);
1813 1206 : if (!env)
1814 : return SQL_ERROR;
1815 :
1816 1206 : env->htype = SQL_HANDLE_ENV;
1817 1206 : env->attr.odbc_version = odbc_version;
1818 : /* TODO use it */
1819 1206 : env->attr.output_nts = SQL_TRUE;
1820 :
1821 1206 : ctx = tds_alloc_context(env);
1822 1206 : if (!ctx) {
1823 0 : free(env);
1824 0 : return SQL_ERROR;
1825 : }
1826 1206 : env->tds_ctx = ctx;
1827 1206 : ctx->msg_handler = odbc_errmsg_handler;
1828 1206 : ctx->err_handler = odbc_errmsg_handler;
1829 :
1830 : /* ODBC driver date-to-char conversion: mimic MS client */
1831 1206 : free(ctx->locale->datetime_fmt);
1832 1206 : ctx->locale->datetime_fmt = strdup("%Y-%m-%d %H:%M:%S.%z");
1833 1206 : free(ctx->locale->date_fmt);
1834 1206 : ctx->locale->date_fmt = strdup("%Y-%m-%d");
1835 1206 : free(ctx->locale->time_fmt);
1836 1206 : ctx->locale->time_fmt = strdup("%H:%M:%S.%z");
1837 :
1838 2412 : tds_mutex_init(&env->mtx);
1839 1206 : *phenv = (SQLHENV) env;
1840 :
1841 1206 : return SQL_SUCCESS;
1842 : }
1843 :
1844 : SQLRETURN ODBC_PUBLIC ODBC_API
1845 : SQLAllocEnv(SQLHENV FAR * phenv)
1846 : {
1847 598 : tdsdump_log(TDS_DBG_FUNC, "SQLAllocEnv(%p)\n", phenv);
1848 :
1849 598 : return odbc_SQLAllocEnv(phenv, SQL_OV_ODBC2);
1850 : }
1851 :
1852 : static SQLRETURN
1853 20 : odbc_SQLAllocDesc(SQLHDBC hdbc, SQLHDESC FAR * phdesc)
1854 : {
1855 : int i;
1856 :
1857 20 : ODBC_ENTER_HDBC;
1858 :
1859 20 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLAllocDesc(%p, %p)\n", hdbc, phdesc);
1860 :
1861 20 : if (!phdesc) {
1862 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
1863 0 : ODBC_EXIT_(dbc);
1864 : }
1865 :
1866 10 : for (i = 0; ; ++i) {
1867 40 : if (i >= TDS_MAX_APP_DESC) {
1868 0 : odbc_errs_add(&dbc->errs, "HY014", NULL);
1869 0 : break;
1870 : }
1871 30 : if (dbc->uad[i] == NULL) {
1872 20 : TDS_DESC *desc = desc_alloc(dbc, DESC_ARD, SQL_DESC_ALLOC_USER);
1873 20 : if (desc == NULL) {
1874 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1875 0 : break;
1876 : }
1877 20 : dbc->uad[i] = desc;
1878 20 : *phdesc = (SQLHDESC) desc;
1879 20 : break;
1880 : }
1881 : }
1882 20 : ODBC_EXIT_(dbc);
1883 : }
1884 :
1885 : static SQLRETURN
1886 17795 : odbc_SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt)
1887 : {
1888 : TDS_STMT *stmt;
1889 : char *pstr;
1890 :
1891 17795 : ODBC_ENTER_HDBC;
1892 :
1893 17795 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLAllocStmt(%p, %p)\n", hdbc, phstmt);
1894 :
1895 17795 : if (!phstmt) {
1896 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
1897 0 : ODBC_EXIT_(dbc);
1898 : }
1899 :
1900 17795 : stmt = tds_new0(TDS_STMT, 1);
1901 17795 : if (!stmt) {
1902 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1903 0 : ODBC_EXIT_(dbc);
1904 : }
1905 35590 : tds_dstr_init(&stmt->cursor_name);
1906 35590 : tds_dstr_init(&stmt->query);
1907 :
1908 17795 : stmt->htype = SQL_HANDLE_STMT;
1909 17795 : stmt->dbc = dbc;
1910 17795 : stmt->num_param_rows = 1;
1911 17795 : pstr = NULL;
1912 : /* TODO test initial cursor ... */
1913 17795 : if (asprintf(&pstr, "SQL_CUR%p", stmt) < 0 || !tds_dstr_set(&stmt->cursor_name, pstr)) {
1914 0 : free(stmt);
1915 0 : free(pstr);
1916 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1917 0 : ODBC_EXIT_(dbc);
1918 : }
1919 : /* do not free pstr tds_dstr_set do it if necessary */
1920 :
1921 : /* allocate descriptors */
1922 17795 : stmt->ird = desc_alloc(stmt, DESC_IRD, SQL_DESC_ALLOC_AUTO);
1923 17795 : stmt->ard = desc_alloc(stmt, DESC_ARD, SQL_DESC_ALLOC_AUTO);
1924 17795 : stmt->ipd = desc_alloc(stmt, DESC_IPD, SQL_DESC_ALLOC_AUTO);
1925 17795 : stmt->apd = desc_alloc(stmt, DESC_APD, SQL_DESC_ALLOC_AUTO);
1926 17795 : if (!stmt->ird || !stmt->ard || !stmt->ipd || !stmt->apd) {
1927 0 : tds_dstr_free(&stmt->cursor_name);
1928 0 : desc_free(stmt->ird);
1929 0 : desc_free(stmt->ard);
1930 0 : desc_free(stmt->ipd);
1931 0 : desc_free(stmt->apd);
1932 0 : free(stmt);
1933 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1934 0 : ODBC_EXIT_(dbc);
1935 : }
1936 :
1937 : /* save original ARD and APD */
1938 17795 : stmt->orig_apd = stmt->apd;
1939 17795 : stmt->orig_ard = stmt->ard;
1940 :
1941 : /* set the default statement attributes */
1942 : /* stmt->attr.app_param_desc = stmt->apd; */
1943 : /* stmt->attr.app_row_desc = stmt->ard; */
1944 17795 : stmt->attr.async_enable = SQL_ASYNC_ENABLE_OFF;
1945 17795 : stmt->attr.concurrency = SQL_CONCUR_READ_ONLY;
1946 17795 : stmt->attr.cursor_scrollable = SQL_NONSCROLLABLE;
1947 17795 : stmt->attr.cursor_sensitivity = SQL_INSENSITIVE;
1948 17795 : stmt->attr.cursor_type = SQL_CURSOR_FORWARD_ONLY;
1949 : /* TODO ?? why two attributes */
1950 17795 : stmt->attr.enable_auto_ipd = dbc->attr.auto_ipd = SQL_FALSE;
1951 17795 : stmt->attr.fetch_bookmark_ptr = NULL;
1952 : /* stmt->attr.imp_param_desc = stmt->ipd; */
1953 : /* stmt->attr.imp_row_desc = stmt->ird; */
1954 17795 : stmt->attr.keyset_size = 0;
1955 17795 : stmt->attr.max_length = 0;
1956 17795 : stmt->attr.max_rows = 0;
1957 17795 : stmt->attr.metadata_id = dbc->attr.metadata_id;
1958 : /* TODO check this flag in prepare_call */
1959 17795 : stmt->attr.noscan = SQL_NOSCAN_OFF;
1960 17795 : assert(stmt->apd->header.sql_desc_bind_offset_ptr == NULL);
1961 17795 : assert(stmt->apd->header.sql_desc_bind_type == SQL_PARAM_BIND_BY_COLUMN);
1962 17795 : assert(stmt->apd->header.sql_desc_array_status_ptr == NULL);
1963 17795 : assert(stmt->ipd->header.sql_desc_array_status_ptr == NULL);
1964 17795 : assert(stmt->ipd->header.sql_desc_rows_processed_ptr == NULL);
1965 17795 : assert(stmt->apd->header.sql_desc_array_size == 1);
1966 17795 : stmt->attr.query_timeout = DEFAULT_QUERY_TIMEOUT;
1967 17795 : stmt->attr.retrieve_data = SQL_RD_ON;
1968 17795 : assert(stmt->ard->header.sql_desc_array_size == 1);
1969 17795 : assert(stmt->ard->header.sql_desc_bind_offset_ptr == NULL);
1970 17795 : assert(stmt->ard->header.sql_desc_bind_type == SQL_BIND_BY_COLUMN);
1971 17795 : stmt->attr.row_number = 0;
1972 17795 : assert(stmt->ard->header.sql_desc_array_status_ptr == NULL);
1973 17795 : assert(stmt->ird->header.sql_desc_array_status_ptr == NULL);
1974 17795 : assert(stmt->ird->header.sql_desc_rows_processed_ptr == NULL);
1975 17795 : stmt->attr.simulate_cursor = SQL_SC_NON_UNIQUE;
1976 17795 : stmt->attr.use_bookmarks = SQL_UB_OFF;
1977 35590 : tds_dstr_init(&stmt->attr.qn_msgtext);
1978 35590 : tds_dstr_init(&stmt->attr.qn_options);
1979 17795 : stmt->attr.qn_timeout = 432000;
1980 :
1981 17795 : stmt->sql_rowset_size = 1;
1982 :
1983 17795 : stmt->row_count = TDS_NO_COUNT;
1984 17795 : stmt->row_status = NOT_IN_ROW;
1985 :
1986 : /* insert into list */
1987 17795 : stmt->next = dbc->stmt_list;
1988 17795 : if (dbc->stmt_list)
1989 349 : dbc->stmt_list->prev = stmt;
1990 17795 : dbc->stmt_list = stmt;
1991 :
1992 35590 : tds_mutex_init(&stmt->mtx);
1993 17795 : *phstmt = (SQLHSTMT) stmt;
1994 :
1995 17795 : if (dbc->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY)
1996 0 : odbc_SQLSetStmtAttr(stmt, SQL_CURSOR_TYPE, (SQLPOINTER) (TDS_INTPTR) dbc->attr.cursor_type, SQL_IS_INTEGER _wide0);
1997 :
1998 17795 : stmt->attr.param_focus = 0;
1999 :
2000 17795 : ODBC_EXIT_(dbc);
2001 : }
2002 :
2003 : SQLRETURN ODBC_PUBLIC ODBC_API
2004 : SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt)
2005 : {
2006 17675 : tdsdump_log(TDS_DBG_FUNC, "SQLAllocStmt(%p, %p)\n", hdbc, phstmt);
2007 :
2008 17675 : return odbc_SQLAllocStmt(hdbc, phstmt);
2009 : }
2010 :
2011 : SQLRETURN ODBC_PUBLIC ODBC_API
2012 : SQLBindCol(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
2013 : {
2014 : TDS_DESC *ard;
2015 : struct _drecord *drec;
2016 : SQLSMALLINT orig_ard_size;
2017 :
2018 6120 : ODBC_ENTER_HSTMT;
2019 :
2020 6120 : tdsdump_log(TDS_DBG_FUNC, "SQLBindCol(%p, %d, %d, %p, %d, %p)\n",
2021 : hstmt, icol, fCType, rgbValue, (int)cbValueMax, pcbValue);
2022 :
2023 : /* TODO - More error checking XXX smurph */
2024 :
2025 : #ifdef TDS_NO_DM
2026 : /* check conversion type */
2027 6120 : switch (fCType) {
2028 3158 : case SQL_C_CHAR:
2029 : case SQL_C_WCHAR:
2030 : case SQL_C_BINARY:
2031 : case SQL_C_DEFAULT:
2032 : /* check max buffer length */
2033 3158 : if (!IS_VALID_LEN(cbValueMax)) {
2034 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
2035 0 : ODBC_EXIT_(stmt);
2036 : }
2037 : break;
2038 : }
2039 : #endif
2040 :
2041 6120 : if (icol <= 0 || icol > 4000) {
2042 0 : odbc_errs_add(&stmt->errs, "07009", NULL);
2043 0 : ODBC_EXIT_(stmt);
2044 : }
2045 :
2046 6120 : ard = stmt->ard;
2047 6120 : orig_ard_size = ard->header.sql_desc_count;
2048 6120 : if (icol > ard->header.sql_desc_count && desc_alloc_records(ard, icol) != SQL_SUCCESS) {
2049 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
2050 0 : ODBC_EXIT_(stmt);
2051 : }
2052 :
2053 6120 : drec = &ard->records[icol - 1];
2054 :
2055 6120 : if (odbc_set_concise_c_type(fCType, drec, 0) != SQL_SUCCESS) {
2056 0 : desc_alloc_records(ard, orig_ard_size);
2057 0 : odbc_errs_add(&stmt->errs, "HY003", NULL);
2058 0 : ODBC_EXIT_(stmt);
2059 : }
2060 6120 : drec->sql_desc_octet_length = cbValueMax;
2061 6120 : drec->sql_desc_octet_length_ptr = pcbValue;
2062 6120 : drec->sql_desc_indicator_ptr = pcbValue;
2063 6120 : drec->sql_desc_data_ptr = rgbValue;
2064 :
2065 : /* force rebind */
2066 6120 : stmt->row = 0;
2067 :
2068 6120 : ODBC_EXIT_(stmt);
2069 : }
2070 :
2071 : SQLRETURN ODBC_PUBLIC ODBC_API
2072 : SQLCancel(SQLHSTMT hstmt)
2073 : {
2074 : TDSSOCKET *tds;
2075 :
2076 : /*
2077 : * FIXME this function can be called from other thread, do not free
2078 : * errors for this function
2079 : * If function is called from another thread errors are not touched
2080 : */
2081 : /* TODO some tests required */
2082 80 : TDS_STMT *stmt = (TDS_STMT*)hstmt;
2083 80 : if (SQL_NULL_HSTMT == hstmt || !IS_HSTMT(hstmt))
2084 : return SQL_INVALID_HANDLE;
2085 :
2086 80 : tdsdump_log(TDS_DBG_FUNC, "SQLCancel(%p)\n", hstmt);
2087 :
2088 80 : tds = stmt->tds;
2089 :
2090 : /* cancelling an inactive statement */
2091 80 : if (!tds)
2092 : /* Just return success */
2093 : /* Note that we don't own locks so don't use ODBC_EXIT here. */
2094 : return SQL_SUCCESS;
2095 :
2096 50 : if (tds_mutex_trylock(&stmt->mtx) == 0) {
2097 10 : CHECK_STMT_EXTRA(stmt);
2098 10 : odbc_errs_reset(&stmt->errs);
2099 :
2100 : /* FIXME test current statement */
2101 : /* FIXME here we are unlocked */
2102 :
2103 10 : if (TDS_FAILED(tds_send_cancel(tds))) {
2104 0 : ODBC_SAFE_ERROR(stmt);
2105 0 : ODBC_EXIT_(stmt);
2106 : }
2107 :
2108 10 : if (TDS_FAILED(tds_process_cancel(tds))) {
2109 0 : ODBC_SAFE_ERROR(stmt);
2110 0 : ODBC_EXIT_(stmt);
2111 : }
2112 :
2113 : /* only if we processed cancel reset statement */
2114 10 : if (tds->state == TDS_IDLE)
2115 10 : odbc_unlock_statement(stmt);
2116 :
2117 10 : ODBC_EXIT_(stmt);
2118 : }
2119 :
2120 : /* don't access error here, just return error */
2121 40 : if (TDS_FAILED(tds_send_cancel(tds)))
2122 : return SQL_ERROR;
2123 40 : return SQL_SUCCESS;
2124 : }
2125 :
2126 1018 : ODBC_FUNC(SQLConnect, (P(SQLHDBC,hdbc), PCHARIN(DSN,SQLSMALLINT), PCHARIN(UID,SQLSMALLINT),
2127 : PCHARIN(AuthStr,SQLSMALLINT) WIDE))
2128 : {
2129 : TDSLOGIN *login;
2130 : DSTR *s;
2131 :
2132 1018 : ODBC_ENTER_HDBC;
2133 :
2134 : #ifdef TDS_NO_DM
2135 1018 : if (szDSN && !IS_VALID_LEN(cbDSN)) {
2136 0 : odbc_errs_add(&dbc->errs, "HY090", "Invalid DSN buffer length");
2137 0 : ODBC_EXIT_(dbc);
2138 : }
2139 :
2140 1018 : if (szUID && !IS_VALID_LEN(cbUID)) {
2141 0 : odbc_errs_add(&dbc->errs, "HY090", "Invalid UID buffer length");
2142 0 : ODBC_EXIT_(dbc);
2143 : }
2144 :
2145 1018 : if (szAuthStr && !IS_VALID_LEN(cbAuthStr)) {
2146 0 : odbc_errs_add(&dbc->errs, "HY090", "Invalid PWD buffer length");
2147 0 : ODBC_EXIT_(dbc);
2148 : }
2149 : #endif
2150 :
2151 1018 : login = tds_alloc_login(false);
2152 1018 : if (!login || !tds_init_login(login, dbc->env->tds_ctx->locale))
2153 : goto memory_error;
2154 :
2155 : /* data source name */
2156 1018 : if (odbc_get_string_size(cbDSN, szDSN _wide))
2157 1018 : s = odbc_dstr_copy(dbc, &dbc->dsn, cbDSN, szDSN);
2158 : else
2159 0 : s = tds_dstr_copy(&dbc->dsn, "DEFAULT");
2160 1018 : if (!s)
2161 : goto memory_error;
2162 :
2163 :
2164 2036 : if (!odbc_get_dsn_info(&dbc->errs, tds_dstr_cstr(&dbc->dsn), login)) {
2165 0 : tds_free_login(login);
2166 0 : ODBC_EXIT_(dbc);
2167 : }
2168 :
2169 2036 : if (!tds_dstr_isempty(&dbc->attr.current_catalog))
2170 20 : if (!tds_dstr_dup(&login->database, &dbc->attr.current_catalog))
2171 : goto memory_error;
2172 :
2173 : /*
2174 : * username/password are never saved to ini file,
2175 : * so you do not check in ini file
2176 : */
2177 : /* user id */
2178 1018 : if (odbc_get_string_size(cbUID, szUID _wide)) {
2179 1018 : if (!odbc_dstr_copy(dbc, &login->user_name, cbUID, szUID))
2180 : goto memory_error;
2181 : }
2182 :
2183 : /* password */
2184 2036 : if (szAuthStr && !tds_dstr_isempty(&login->user_name)) {
2185 1018 : if (!odbc_dstr_copy(dbc, &login->password, cbAuthStr, szAuthStr))
2186 : goto memory_error;
2187 : }
2188 :
2189 : /* DO IT */
2190 1018 : odbc_connect(dbc, login);
2191 :
2192 1018 : tds_free_login(login);
2193 1018 : ODBC_EXIT_(dbc);
2194 :
2195 0 : memory_error:
2196 0 : tds_free_login(login);
2197 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
2198 0 : ODBC_EXIT_(dbc);
2199 : }
2200 :
2201 2354 : ODBC_FUNC(SQLDescribeCol, (P(SQLHSTMT,hstmt), P(SQLUSMALLINT,icol), PCHAROUT(ColName,SQLSMALLINT),
2202 : P(SQLSMALLINT FAR *,pfSqlType), P(SQLULEN FAR *,pcbColDef),
2203 : P(SQLSMALLINT FAR *,pibScale), P(SQLSMALLINT FAR *,pfNullable) WIDE))
2204 : {
2205 : TDS_DESC *ird;
2206 : struct _drecord *drec;
2207 : SQLRETURN result;
2208 :
2209 2354 : ODBC_ENTER_HSTMT;
2210 :
2211 2354 : ird = stmt->ird;
2212 2354 : IRD_UPDATE(ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
2213 :
2214 2354 : if (icol <= 0 || icol > ird->header.sql_desc_count) {
2215 0 : odbc_errs_add(&stmt->errs, "07009", "Column out of range");
2216 0 : ODBC_EXIT_(stmt);
2217 : }
2218 : /* check name length */
2219 2354 : if (cbColNameMax < 0) {
2220 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
2221 0 : ODBC_EXIT_(stmt);
2222 : }
2223 2354 : drec = &ird->records[icol - 1];
2224 :
2225 : /* cbColNameMax can be 0 (to retrieve name length) */
2226 2354 : if (szColName == NULL)
2227 1052 : cbColNameMax = 0;
2228 :
2229 : /* straight copy column name up to cbColNameMax */
2230 7062 : result = odbc_set_dstr(stmt->dbc, szColName, cbColNameMax, pcbColName, &drec->sql_desc_label);
2231 2354 : if (szColName && result == SQL_SUCCESS_WITH_INFO)
2232 30 : odbc_errs_add(&stmt->errs, "01004", NULL);
2233 :
2234 2354 : if (pfSqlType) {
2235 : /* TODO sure ? check documentation for date and intervals */
2236 2354 : *pfSqlType = drec->sql_desc_concise_type;
2237 : }
2238 :
2239 2354 : if (pcbColDef) {
2240 1226 : if (drec->sql_desc_type == SQL_NUMERIC || drec->sql_desc_type == SQL_DECIMAL) {
2241 180 : *pcbColDef = drec->sql_desc_precision;
2242 : } else {
2243 1046 : *pcbColDef = drec->sql_desc_length;
2244 : }
2245 : }
2246 2354 : if (pibScale) {
2247 1226 : *pibScale = drec->sql_desc_scale;
2248 : }
2249 2354 : if (pfNullable) {
2250 1226 : *pfNullable = drec->sql_desc_nullable;
2251 : }
2252 2354 : ODBC_EXIT_(stmt);
2253 : }
2254 :
2255 : static SQLRETURN
2256 6572 : odbc_SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax,
2257 : SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc _WIDE)
2258 : {
2259 : TDS_DESC *ird;
2260 : struct _drecord *drec;
2261 6572 : SQLRETURN result = SQL_SUCCESS;
2262 :
2263 6572 : ODBC_ENTER_HSTMT;
2264 :
2265 6572 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLColAttribute(%p, %u, %u, %p, %d, %p, %p)\n",
2266 : hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2267 :
2268 6572 : ird = stmt->ird;
2269 :
2270 : #define COUT(src) result = odbc_set_string_oct(stmt->dbc, rgbDesc, cbDescMax, pcbDesc, src ? src : "", -1);
2271 : #define SOUT(src) result = odbc_set_dstr_oct(stmt->dbc, rgbDesc, cbDescMax, pcbDesc, &src);
2272 :
2273 : /* SQLColAttribute returns always attributes using SQLINTEGER */
2274 : #if ENABLE_EXTRA_CHECKS
2275 : #define IOUT(type, src) do { \
2276 : /* trick warning if type wrong */ \
2277 : type *p_test = &src; p_test = p_test; \
2278 : *pfDesc = src; } while(0)
2279 : #else
2280 : #define IOUT(type, src) *pfDesc = src
2281 : #endif
2282 :
2283 6572 : IRD_UPDATE(ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
2284 :
2285 : /* dont check column index for these */
2286 6572 : switch (fDescType) {
2287 : #if SQL_COLUMN_COUNT != SQL_DESC_COUNT
2288 0 : case SQL_COLUMN_COUNT:
2289 : #endif
2290 : case SQL_DESC_COUNT:
2291 0 : IOUT(SQLSMALLINT, ird->header.sql_desc_count);
2292 0 : ODBC_EXIT(stmt, SQL_SUCCESS);
2293 : break;
2294 : }
2295 :
2296 6572 : if (!ird->header.sql_desc_count) {
2297 0 : odbc_errs_add(&stmt->errs, "07005", NULL);
2298 0 : ODBC_EXIT_(stmt);
2299 : }
2300 :
2301 6572 : if (icol <= 0 || icol > ird->header.sql_desc_count) {
2302 0 : odbc_errs_add(&stmt->errs, "07009", "Column out of range");
2303 0 : ODBC_EXIT_(stmt);
2304 : }
2305 6572 : drec = &ird->records[icol - 1];
2306 :
2307 6572 : tdsdump_log(TDS_DBG_INFO1, "SQLColAttribute: fDescType is %d\n", fDescType);
2308 :
2309 6572 : switch (fDescType) {
2310 0 : case SQL_DESC_AUTO_UNIQUE_VALUE:
2311 0 : IOUT(SQLUINTEGER, drec->sql_desc_auto_unique_value);
2312 : break;
2313 0 : case SQL_DESC_BASE_COLUMN_NAME:
2314 0 : SOUT(drec->sql_desc_base_column_name);
2315 0 : break;
2316 0 : case SQL_DESC_BASE_TABLE_NAME:
2317 0 : SOUT(drec->sql_desc_base_table_name);
2318 0 : break;
2319 0 : case SQL_DESC_CASE_SENSITIVE:
2320 0 : IOUT(SQLINTEGER, drec->sql_desc_case_sensitive);
2321 : break;
2322 0 : case SQL_DESC_CATALOG_NAME:
2323 0 : SOUT(drec->sql_desc_catalog_name);
2324 0 : break;
2325 : #if SQL_COLUMN_TYPE != SQL_DESC_CONCISE_TYPE
2326 : case SQL_COLUMN_TYPE:
2327 : #endif
2328 152 : case SQL_DESC_CONCISE_TYPE:
2329 : /* special case, get ODBC 2 type, not ODBC 3 SQL_DESC_CONCISE_TYPE (different for datetime) */
2330 152 : if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
2331 112 : IOUT(SQLSMALLINT, drec->sql_desc_concise_type);
2332 : break;
2333 : }
2334 :
2335 : /* get type and convert it to ODBC 2 type */
2336 : {
2337 40 : SQLSMALLINT type = drec->sql_desc_concise_type;
2338 :
2339 40 : switch (type) {
2340 0 : case SQL_TYPE_DATE:
2341 0 : type = SQL_DATE;
2342 0 : break;
2343 0 : case SQL_TYPE_TIME:
2344 0 : type = SQL_TIME;
2345 0 : break;
2346 20 : case SQL_TYPE_TIMESTAMP:
2347 20 : type = SQL_TIMESTAMP;
2348 20 : break;
2349 : }
2350 40 : IOUT(SQLSMALLINT, type);
2351 : }
2352 : break;
2353 516 : case SQL_DESC_DISPLAY_SIZE:
2354 516 : IOUT(SQLLEN, drec->sql_desc_display_size);
2355 : break;
2356 0 : case SQL_DESC_FIXED_PREC_SCALE:
2357 0 : IOUT(SQLSMALLINT, drec->sql_desc_fixed_prec_scale);
2358 : break;
2359 1068 : case SQL_DESC_LABEL:
2360 3204 : SOUT(drec->sql_desc_label);
2361 1068 : break;
2362 : /* FIXME special cases for SQL_COLUMN_LENGTH */
2363 460 : case SQL_COLUMN_LENGTH:
2364 460 : IOUT(SQLLEN, drec->sql_desc_octet_length);
2365 : break;
2366 516 : case SQL_DESC_LENGTH:
2367 516 : IOUT(SQLULEN, drec->sql_desc_length);
2368 : break;
2369 0 : case SQL_DESC_LITERAL_PREFIX:
2370 0 : COUT(drec->sql_desc_literal_prefix);
2371 0 : break;
2372 0 : case SQL_DESC_LITERAL_SUFFIX:
2373 0 : COUT(drec->sql_desc_literal_suffix);
2374 0 : break;
2375 0 : case SQL_DESC_LOCAL_TYPE_NAME:
2376 0 : SOUT(drec->sql_desc_local_type_name);
2377 0 : break;
2378 : #if SQL_COLUMN_NAME != SQL_DESC_NAME
2379 1068 : case SQL_COLUMN_NAME:
2380 : #endif
2381 : case SQL_DESC_NAME:
2382 3204 : SOUT(drec->sql_desc_name);
2383 1068 : break;
2384 : #if SQL_COLUMN_NULLABLE != SQL_DESC_NULLABLE
2385 0 : case SQL_COLUMN_NULLABLE:
2386 : #endif
2387 : case SQL_DESC_NULLABLE:
2388 0 : IOUT(SQLSMALLINT, drec->sql_desc_nullable);
2389 : break;
2390 0 : case SQL_DESC_NUM_PREC_RADIX:
2391 0 : IOUT(SQLINTEGER, drec->sql_desc_num_prec_radix);
2392 : break;
2393 516 : case SQL_DESC_OCTET_LENGTH:
2394 516 : IOUT(SQLLEN, drec->sql_desc_octet_length);
2395 : break;
2396 : /* FIXME special cases for SQL_COLUMN_PRECISION */
2397 460 : case SQL_COLUMN_PRECISION:
2398 460 : if (drec->sql_desc_concise_type == SQL_REAL) {
2399 20 : *pfDesc = 7;
2400 : break;
2401 : }
2402 440 : if (drec->sql_desc_concise_type == SQL_DOUBLE) {
2403 20 : *pfDesc = 15;
2404 : break;
2405 : }
2406 420 : if (drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP || drec->sql_desc_concise_type == SQL_TIMESTAMP) {
2407 40 : *pfDesc = drec->sql_desc_precision ? 23 : 16;
2408 : break;
2409 : }
2410 : case SQL_DESC_PRECISION: /* this section may be wrong */
2411 1792 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2412 896 : || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP
2413 684 : || drec->sql_desc_concise_type == SQL_TYPE_DATE
2414 678 : || drec->sql_desc_concise_type == SQL_TYPE_TIME
2415 678 : || drec->sql_desc_concise_type == SQL_TIMESTAMP
2416 678 : || drec->sql_desc_concise_type == SQL_SS_TIME2
2417 668 : || drec->sql_desc_concise_type == SQL_SS_TIMESTAMPOFFSET)
2418 236 : IOUT(SQLSMALLINT, drec->sql_desc_precision);
2419 : else
2420 660 : *pfDesc = drec->sql_desc_length;
2421 : break;
2422 : /* FIXME special cases for SQL_COLUMN_SCALE */
2423 980 : case SQL_COLUMN_SCALE:
2424 : case SQL_DESC_SCALE: /* this section may be wrong */
2425 1960 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2426 980 : || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP
2427 728 : || drec->sql_desc_concise_type == SQL_TYPE_DATE
2428 720 : || drec->sql_desc_concise_type == SQL_TYPE_TIME
2429 720 : || drec->sql_desc_concise_type == SQL_TIMESTAMP
2430 720 : || drec->sql_desc_concise_type == SQL_FLOAT
2431 720 : || drec->sql_desc_concise_type == SQL_SS_TIME2
2432 708 : || drec->sql_desc_concise_type == SQL_SS_TIMESTAMPOFFSET)
2433 280 : IOUT(SQLSMALLINT, drec->sql_desc_scale);
2434 : else
2435 700 : *pfDesc = 0;
2436 : break;
2437 0 : case SQL_DESC_SCHEMA_NAME:
2438 0 : SOUT(drec->sql_desc_schema_name);
2439 0 : break;
2440 0 : case SQL_DESC_SEARCHABLE:
2441 0 : IOUT(SQLSMALLINT, drec->sql_desc_searchable);
2442 : break;
2443 0 : case SQL_DESC_TABLE_NAME:
2444 0 : SOUT(drec->sql_desc_table_name);
2445 0 : break;
2446 60 : case SQL_DESC_TYPE:
2447 60 : IOUT(SQLSMALLINT, drec->sql_desc_type);
2448 : break;
2449 144 : case SQL_DESC_TYPE_NAME:
2450 144 : COUT(drec->sql_desc_type_name);
2451 144 : break;
2452 0 : case SQL_DESC_UNNAMED:
2453 0 : IOUT(SQLSMALLINT, drec->sql_desc_unnamed);
2454 : break;
2455 116 : case SQL_DESC_UNSIGNED:
2456 116 : IOUT(SQLSMALLINT, drec->sql_desc_unsigned);
2457 : break;
2458 0 : case SQL_DESC_UPDATABLE:
2459 0 : IOUT(SQLSMALLINT, drec->sql_desc_updatable);
2460 : break;
2461 0 : default:
2462 0 : tdsdump_log(TDS_DBG_INFO2, "SQLColAttribute: fDescType %d not catered for...\n", fDescType);
2463 0 : odbc_errs_add(&stmt->errs, "HY091", NULL);
2464 0 : ODBC_EXIT_(stmt);
2465 : break;
2466 : }
2467 :
2468 2280 : if (result == SQL_SUCCESS_WITH_INFO)
2469 0 : odbc_errs_add(&stmt->errs, "01004", NULL);
2470 :
2471 6572 : ODBC_EXIT(stmt, result);
2472 :
2473 : #undef COUT
2474 : #undef SOUT
2475 : #undef IOUT
2476 : }
2477 :
2478 : SQLRETURN ODBC_PUBLIC ODBC_API
2479 : SQLColAttributes(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType,
2480 : SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc)
2481 : {
2482 0 : tdsdump_log(TDS_DBG_FUNC, "SQLColAttributes(%p, %d, %d, %p, %d, %p, %p)\n",
2483 : hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2484 :
2485 0 : return odbc_SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc _wide0);
2486 : }
2487 :
2488 : #if (ODBCVER >= 0x0300)
2489 : SQLRETURN ODBC_PUBLIC ODBC_API
2490 : SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType,
2491 : SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc,
2492 : #ifdef TDS_SQLCOLATTRIBUTE_SQLLEN
2493 : SQLLEN FAR * pfDesc
2494 : #else
2495 : SQLPOINTER pfDesc
2496 : #endif
2497 : )
2498 : {
2499 :
2500 3286 : return odbc_SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, (SQLLEN*) pfDesc _wide0);
2501 : }
2502 :
2503 : #ifdef ENABLE_ODBC_WIDE
2504 : SQLRETURN ODBC_PUBLIC ODBC_API
2505 : SQLColAttributeW(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType,
2506 : SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc,
2507 : #ifdef TDS_SQLCOLATTRIBUTE_SQLLEN
2508 : SQLLEN FAR * pfDesc
2509 : #else
2510 : SQLPOINTER pfDesc
2511 : #endif
2512 : )
2513 : {
2514 3286 : tdsdump_log(TDS_DBG_FUNC, "SQLColAttributeW(%p, %u, %u, %p, %d, %p, %p)\n",
2515 : hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2516 :
2517 3286 : return odbc_SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc, 1);
2518 : }
2519 : #endif
2520 : #endif
2521 :
2522 : SQLRETURN ODBC_PUBLIC ODBC_API
2523 : SQLDisconnect(SQLHDBC hdbc)
2524 : {
2525 : int i;
2526 :
2527 1206 : ODBC_ENTER_HDBC;
2528 :
2529 1206 : tdsdump_log(TDS_DBG_FUNC, "SQLDisconnect(%p)\n", hdbc);
2530 :
2531 : /* free all associated statements */
2532 1242 : while (dbc->stmt_list) {
2533 36 : tds_mutex_unlock(&dbc->mtx);
2534 36 : odbc_SQLFreeStmt(dbc->stmt_list, SQL_DROP, 1);
2535 36 : tds_mutex_lock(&dbc->mtx);
2536 : }
2537 :
2538 : /* free all associated descriptors */
2539 120600 : for (i = 0; i < TDS_MAX_APP_DESC; ++i) {
2540 120600 : if (dbc->uad[i]) {
2541 10 : desc_free(dbc->uad[i]);
2542 10 : dbc->uad[i] = NULL;
2543 : }
2544 : }
2545 :
2546 : #ifdef ENABLE_ODBC_WIDE
2547 1206 : dbc->mb_conv = NULL;
2548 : #endif
2549 1206 : tds_close_socket(dbc->tds_socket);
2550 1206 : tds_free_socket(dbc->tds_socket);
2551 1206 : dbc->tds_socket = NULL;
2552 1206 : dbc->cursor_support = 0;
2553 :
2554 1206 : ODBC_EXIT_(dbc);
2555 : }
2556 :
2557 : static int
2558 6267 : odbc_errmsg_handler(const TDSCONTEXT * ctx, TDSSOCKET * tds, TDSMESSAGE * msg)
2559 : {
2560 6267 : struct _sql_errors *errs = NULL;
2561 6267 : TDS_DBC *dbc = NULL;
2562 6267 : TDS_STMT *stmt = NULL;
2563 :
2564 6267 : tdsdump_log(TDS_DBG_INFO1, "msgno %d %d\n", (int) msg->msgno, TDSETIME);
2565 :
2566 6267 : if (msg->msgno == TDSETIME) {
2567 :
2568 206 : tdsdump_log(TDS_DBG_INFO1, "in timeout\n");
2569 206 : if (!tds)
2570 : return TDS_INT_CANCEL;
2571 :
2572 196 : if ((stmt = odbc_get_stmt(tds)) != NULL) {
2573 : /* first time, try to send a cancel */
2574 196 : if (!tds->in_cancel) {
2575 176 : odbc_errs_add(&stmt->errs, "HYT00", "Timeout expired");
2576 176 : tdsdump_log(TDS_DBG_INFO1, "returning from timeout\n");
2577 : return TDS_INT_TIMEOUT;
2578 : }
2579 10 : } else if ((dbc = odbc_get_dbc(tds)) != NULL) {
2580 10 : odbc_errs_add(&dbc->errs, "HYT00", "Timeout expired");
2581 : }
2582 :
2583 30 : tds_close_socket(tds);
2584 30 : tdsdump_log(TDS_DBG_INFO1, "returning cancel from timeout\n");
2585 : return TDS_INT_CANCEL;
2586 : }
2587 :
2588 6061 : if (tds && (dbc = odbc_get_dbc(tds)) != NULL) {
2589 6061 : errs = &dbc->errs;
2590 3464 : stmt = odbc_get_stmt(tds);
2591 : if (stmt)
2592 3464 : errs = &stmt->errs;
2593 0 : } else if (ctx->parent) {
2594 0 : errs = &((TDS_ENV *) ctx->parent)->errs;
2595 : }
2596 6061 : if (errs) {
2597 6061 : int severity = msg->severity;
2598 6061 : const char * state = msg->sql_state;
2599 :
2600 : /* fix severity for Sybase */
2601 6061 : if (severity <= 10 && dbc && !TDS_IS_MSSQL(dbc->tds_socket) && msg->sql_state && msg->sql_state[0]
2602 15 : && strncmp(msg->sql_state, "00", 2) != 0) {
2603 15 : if (strncmp(msg->sql_state, "01", 2) != 0 && strncmp(msg->sql_state, "IM", 2) != 0)
2604 11 : severity = 11;
2605 : }
2606 :
2607 : /* compute state if not available */
2608 6061 : if (!state)
2609 4154 : state = severity <= 10 ? "01000" : "42000";
2610 : /* add error, do not overwrite connection timeout error */
2611 6061 : if (msg->msgno != TDSEFCON || errs->lastrc != SQL_ERROR || errs->num_errors < 1)
2612 15562 : odbc_errs_add_rdbms(errs, msg->msgno, state, msg->message, msg->line_number, msg->severity,
2613 9513 : msg->server, stmt ? stmt->curr_param_row + 1 : 0);
2614 :
2615 : /* set lastrc according */
2616 6061 : if (severity <= 10) {
2617 4755 : if (errs->lastrc == SQL_SUCCESS)
2618 2602 : errs->lastrc = SQL_SUCCESS_WITH_INFO;
2619 : } else {
2620 1306 : errs->lastrc = SQL_ERROR;
2621 : }
2622 : }
2623 : return TDS_INT_CANCEL;
2624 : }
2625 :
2626 : /* TODO optimize, change only if some data change (set same value should not set this flag) */
2627 : #define DESC_SET_NEED_REPREPARE \
2628 : do {\
2629 : if (desc->type == DESC_IPD) {\
2630 : assert(IS_HSTMT(desc->parent));\
2631 : ((TDS_STMT *) desc->parent)->need_reprepare = 1;\
2632 : }\
2633 : } while(0)
2634 :
2635 : SQLRETURN ODBC_PUBLIC ODBC_API
2636 : SQLSetDescRec(SQLHDESC hdesc, SQLSMALLINT nRecordNumber, SQLSMALLINT nType, SQLSMALLINT nSubType, SQLLEN nLength,
2637 : SQLSMALLINT nPrecision, SQLSMALLINT nScale, SQLPOINTER pData, SQLLEN FAR * pnStringLength, SQLLEN FAR * pnIndicator)
2638 : {
2639 : struct _drecord *drec;
2640 : SQLSMALLINT concise_type;
2641 :
2642 0 : ODBC_ENTER_HDESC;
2643 :
2644 0 : tdsdump_log(TDS_DBG_FUNC, "SQLSetDescRec(%p, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n",
2645 : hdesc, nRecordNumber, nType, nSubType, (int)nLength, nPrecision, nScale,
2646 : pData, pnStringLength, pnIndicator);
2647 :
2648 0 : if (desc->type == DESC_IRD) {
2649 0 : odbc_errs_add(&desc->errs, "HY016", NULL);
2650 0 : ODBC_EXIT_(desc);
2651 : }
2652 :
2653 0 : if (nRecordNumber > desc->header.sql_desc_count || nRecordNumber <= 0) {
2654 0 : odbc_errs_add(&desc->errs, "07009", NULL);
2655 0 : ODBC_EXIT_(desc);
2656 : }
2657 :
2658 0 : drec = &desc->records[nRecordNumber - 1];
2659 :
2660 : /* check for valid types and return "HY021" if not */
2661 0 : if (desc->type == DESC_IPD) {
2662 0 : DESC_SET_NEED_REPREPARE;
2663 0 : concise_type = odbc_get_concise_sql_type(nType, nSubType);
2664 : } else {
2665 0 : concise_type = odbc_get_concise_c_type(nType, nSubType);
2666 : }
2667 0 : if (nType == SQL_INTERVAL || nType == SQL_DATETIME) {
2668 0 : if (!concise_type) {
2669 0 : odbc_errs_add(&desc->errs, "HY021", NULL);
2670 0 : ODBC_EXIT_(desc);
2671 : }
2672 : } else {
2673 0 : if (concise_type != nType) {
2674 0 : odbc_errs_add(&desc->errs, "HY021", NULL);
2675 0 : ODBC_EXIT_(desc);
2676 : }
2677 : nSubType = 0;
2678 : }
2679 0 : drec->sql_desc_concise_type = concise_type;
2680 0 : drec->sql_desc_type = nType;
2681 0 : drec->sql_desc_datetime_interval_code = nSubType;
2682 :
2683 0 : drec->sql_desc_octet_length = nLength;
2684 0 : drec->sql_desc_precision = nPrecision;
2685 0 : drec->sql_desc_scale = nScale;
2686 0 : drec->sql_desc_data_ptr = pData;
2687 0 : drec->sql_desc_octet_length_ptr = pnStringLength;
2688 0 : drec->sql_desc_indicator_ptr = pnIndicator;
2689 :
2690 0 : ODBC_EXIT_(desc);
2691 : }
2692 :
2693 30 : ODBC_FUNC(SQLGetDescRec, (P(SQLHDESC,hdesc), P(SQLSMALLINT,RecordNumber), PCHAROUT(Name,SQLSMALLINT),
2694 : P(SQLSMALLINT *,Type), P(SQLSMALLINT *,SubType), P(SQLLEN FAR *,Length),
2695 : P(SQLSMALLINT *,Precision), P(SQLSMALLINT *,Scale), P(SQLSMALLINT *,Nullable) WIDE))
2696 : {
2697 30 : struct _drecord *drec = NULL;
2698 30 : SQLRETURN rc = SQL_SUCCESS;
2699 :
2700 30 : ODBC_ENTER_HDESC;
2701 :
2702 30 : if (RecordNumber <= 0) {
2703 10 : odbc_errs_add(&desc->errs, "07009", NULL);
2704 10 : ODBC_EXIT_(desc);
2705 : }
2706 :
2707 20 : IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2708 20 : if (RecordNumber > desc->header.sql_desc_count)
2709 10 : ODBC_EXIT(desc, SQL_NO_DATA);
2710 :
2711 : if (desc->type == DESC_IRD && !desc->header.sql_desc_count) {
2712 : odbc_errs_add(&desc->errs, "HY007", NULL);
2713 : ODBC_EXIT_(desc);
2714 : }
2715 :
2716 10 : drec = &desc->records[RecordNumber - 1];
2717 :
2718 30 : if ((rc = odbc_set_dstr(desc_get_dbc(desc), szName, cbNameMax, pcbName, &drec->sql_desc_name)) != SQL_SUCCESS)
2719 0 : odbc_errs_add(&desc->errs, "01004", NULL);
2720 :
2721 10 : if (Type)
2722 0 : *Type = drec->sql_desc_type;
2723 10 : if (Length)
2724 0 : *Length = drec->sql_desc_octet_length;
2725 10 : if (Precision)
2726 0 : *Precision = drec->sql_desc_precision;
2727 10 : if (Scale)
2728 0 : *Scale = drec->sql_desc_scale;
2729 10 : if (SubType)
2730 0 : *SubType = drec->sql_desc_datetime_interval_code;
2731 10 : if (Nullable)
2732 0 : *Nullable = drec->sql_desc_nullable;
2733 :
2734 10 : ODBC_EXIT(desc, rc);
2735 : }
2736 :
2737 : static TDS_DESC*
2738 2852 : desc_get_focused(TDS_DESC *desc)
2739 : {
2740 : struct _drecord *drec;
2741 2852 : int focus = desc->focus;
2742 2852 : bool was_apd = false;
2743 :
2744 2852 : if (focus <= 0)
2745 : return desc;
2746 20 : if (desc->type != DESC_IPD && IS_HSTMT(desc->parent)) {
2747 12 : desc = ((TDS_STMT *) desc->parent)->ipd;
2748 12 : was_apd = true;
2749 : }
2750 20 : if (desc->type == DESC_IPD) {
2751 20 : if (focus > desc->header.sql_desc_count)
2752 : return desc;
2753 :
2754 20 : drec = &desc->records[focus - 1];
2755 20 : if (drec->sql_desc_concise_type != SQL_SS_TABLE)
2756 : return desc;
2757 20 : if (was_apd)
2758 12 : return ((SQLTVP *) drec->sql_desc_data_ptr)->apd;
2759 8 : return ((SQLTVP *) drec->sql_desc_data_ptr)->ipd;
2760 : }
2761 : return desc;
2762 : }
2763 :
2764 2142 : ODBC_FUNC(SQLGetDescField, (P(SQLHDESC,hdesc), P(SQLSMALLINT,icol), P(SQLSMALLINT,fDescType), P(SQLPOINTER,Value),
2765 : P(SQLINTEGER,BufferLength), P(SQLINTEGER *,StringLength) WIDE))
2766 : {
2767 : struct _drecord *drec;
2768 2142 : SQLRETURN result = SQL_SUCCESS;
2769 : SQLINTEGER dummy_size;
2770 : TDS_DESC *fdesc;
2771 :
2772 2142 : ODBC_ENTER_HDESC;
2773 :
2774 : #define COUT(src) result = odbc_set_string_oct(desc_get_dbc(desc), Value, BufferLength, StringLength, src, -1);
2775 : #define SOUT(src) result = odbc_set_dstr_oct(desc_get_dbc(desc), Value, BufferLength, StringLength, &src);
2776 :
2777 : #if ENABLE_EXTRA_CHECKS
2778 : #define IOUT(type, src) do { \
2779 : /* trick warning if type wrong */ \
2780 : type *p_test = &src; p_test = p_test; \
2781 : *((type *)Value) = src; \
2782 : *StringLength = sizeof(type); } while(0)
2783 : #else
2784 : #define IOUT(type, src) do { \
2785 : *((type *)Value) = src; \
2786 : *StringLength = sizeof(type); } while(0)
2787 : #endif
2788 :
2789 2142 : if (!StringLength)
2790 0 : StringLength = &dummy_size;
2791 :
2792 2142 : fdesc = desc_get_focused(desc);
2793 :
2794 : /* dont check column index for these */
2795 2142 : switch (fDescType) {
2796 40 : case SQL_DESC_ALLOC_TYPE:
2797 40 : IOUT(SQLSMALLINT, fdesc->header.sql_desc_alloc_type);
2798 40 : ODBC_EXIT_(desc);
2799 : break;
2800 8 : case SQL_DESC_ARRAY_SIZE:
2801 8 : IOUT(SQLULEN, fdesc->header.sql_desc_array_size);
2802 8 : ODBC_EXIT_(desc);
2803 : break;
2804 0 : case SQL_DESC_ARRAY_STATUS_PTR:
2805 0 : IOUT(SQLUSMALLINT *, fdesc->header.sql_desc_array_status_ptr);
2806 0 : ODBC_EXIT_(desc);
2807 : break;
2808 0 : case SQL_DESC_BIND_OFFSET_PTR:
2809 0 : IOUT(const SQLLEN *, fdesc->header.sql_desc_bind_offset_ptr);
2810 0 : ODBC_EXIT_(desc);
2811 : break;
2812 0 : case SQL_DESC_BIND_TYPE:
2813 0 : IOUT(SQLINTEGER, fdesc->header.sql_desc_bind_type);
2814 0 : ODBC_EXIT_(desc);
2815 : break;
2816 118 : case SQL_DESC_COUNT:
2817 118 : IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2818 118 : IOUT(SQLSMALLINT, fdesc->header.sql_desc_count);
2819 118 : ODBC_EXIT_(desc);
2820 : break;
2821 110 : case SQL_DESC_ROWS_PROCESSED_PTR:
2822 110 : IOUT(SQLULEN *, fdesc->header.sql_desc_rows_processed_ptr);
2823 110 : ODBC_EXIT_(desc);
2824 : break;
2825 : }
2826 :
2827 1866 : IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2828 1866 : if (!fdesc->header.sql_desc_count) {
2829 0 : odbc_errs_add(&desc->errs, "07005", NULL);
2830 0 : ODBC_EXIT_(desc);
2831 : }
2832 :
2833 1866 : if (icol < 1) {
2834 0 : odbc_errs_add(&desc->errs, "07009", "Column out of range");
2835 0 : ODBC_EXIT_(desc);
2836 : }
2837 1866 : if (icol > fdesc->header.sql_desc_count)
2838 0 : ODBC_EXIT(desc, SQL_NO_DATA);
2839 1866 : drec = &fdesc->records[icol - 1];
2840 :
2841 1866 : tdsdump_log(TDS_DBG_INFO1, "SQLGetDescField: fDescType is %d\n", fDescType);
2842 :
2843 1866 : switch (fDescType) {
2844 0 : case SQL_DESC_AUTO_UNIQUE_VALUE:
2845 0 : IOUT(SQLUINTEGER, drec->sql_desc_auto_unique_value);
2846 : break;
2847 0 : case SQL_DESC_BASE_COLUMN_NAME:
2848 0 : SOUT(drec->sql_desc_base_column_name);
2849 0 : break;
2850 0 : case SQL_DESC_BASE_TABLE_NAME:
2851 0 : SOUT(drec->sql_desc_base_table_name);
2852 0 : break;
2853 0 : case SQL_DESC_CASE_SENSITIVE:
2854 0 : IOUT(SQLINTEGER, drec->sql_desc_case_sensitive);
2855 : break;
2856 0 : case SQL_DESC_CATALOG_NAME:
2857 0 : SOUT(drec->sql_desc_catalog_name);
2858 0 : break;
2859 604 : case SQL_DESC_CONCISE_TYPE:
2860 604 : IOUT(SQLSMALLINT, drec->sql_desc_concise_type);
2861 : break;
2862 16 : case SQL_DESC_DATA_PTR:
2863 16 : IOUT(SQLPOINTER, drec->sql_desc_data_ptr);
2864 : break;
2865 590 : case SQL_DESC_DATETIME_INTERVAL_CODE:
2866 590 : IOUT(SQLSMALLINT, drec->sql_desc_datetime_interval_code);
2867 : break;
2868 0 : case SQL_DESC_DATETIME_INTERVAL_PRECISION:
2869 0 : IOUT(SQLINTEGER, drec->sql_desc_datetime_interval_precision);
2870 : break;
2871 0 : case SQL_DESC_DISPLAY_SIZE:
2872 0 : IOUT(SQLLEN, drec->sql_desc_display_size);
2873 : break;
2874 0 : case SQL_DESC_FIXED_PREC_SCALE:
2875 0 : IOUT(SQLSMALLINT, drec->sql_desc_fixed_prec_scale);
2876 : break;
2877 8 : case SQL_DESC_INDICATOR_PTR:
2878 8 : IOUT(SQLLEN *, drec->sql_desc_indicator_ptr);
2879 : break;
2880 0 : case SQL_DESC_LABEL:
2881 0 : SOUT(drec->sql_desc_label);
2882 0 : break;
2883 14 : case SQL_DESC_LENGTH:
2884 14 : IOUT(SQLULEN, drec->sql_desc_length);
2885 : break;
2886 0 : case SQL_DESC_LITERAL_PREFIX:
2887 0 : COUT(drec->sql_desc_literal_prefix);
2888 0 : break;
2889 0 : case SQL_DESC_LITERAL_SUFFIX:
2890 0 : COUT(drec->sql_desc_literal_suffix);
2891 0 : break;
2892 0 : case SQL_DESC_LOCAL_TYPE_NAME:
2893 0 : SOUT(drec->sql_desc_local_type_name);
2894 0 : break;
2895 0 : case SQL_DESC_NAME:
2896 0 : SOUT(drec->sql_desc_name);
2897 0 : break;
2898 0 : case SQL_DESC_NULLABLE:
2899 0 : IOUT(SQLSMALLINT, drec->sql_desc_nullable);
2900 : break;
2901 0 : case SQL_DESC_NUM_PREC_RADIX:
2902 0 : IOUT(SQLINTEGER, drec->sql_desc_num_prec_radix);
2903 : break;
2904 8 : case SQL_DESC_OCTET_LENGTH:
2905 8 : IOUT(SQLLEN, drec->sql_desc_octet_length);
2906 : break;
2907 8 : case SQL_DESC_OCTET_LENGTH_PTR:
2908 8 : IOUT(SQLLEN *, drec->sql_desc_octet_length_ptr);
2909 : break;
2910 0 : case SQL_DESC_PARAMETER_TYPE:
2911 0 : IOUT(SQLSMALLINT, drec->sql_desc_parameter_type);
2912 : break;
2913 6 : case SQL_DESC_PRECISION:
2914 12 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2915 6 : || drec->sql_desc_concise_type == SQL_TIMESTAMP
2916 4 : || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP)
2917 2 : IOUT(SQLSMALLINT, drec->sql_desc_precision);
2918 : else
2919 : /* TODO support date/time */
2920 4 : *((SQLSMALLINT *) Value) = 0;
2921 : break;
2922 : #ifdef SQL_DESC_ROWVER
2923 0 : case SQL_DESC_ROWVER:
2924 0 : IOUT(SQLSMALLINT, drec->sql_desc_rowver);
2925 : break;
2926 : #endif
2927 6 : case SQL_DESC_SCALE:
2928 12 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2929 6 : || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP
2930 4 : || drec->sql_desc_concise_type == SQL_TIMESTAMP
2931 4 : || drec->sql_desc_concise_type == SQL_FLOAT)
2932 2 : IOUT(SQLSMALLINT, drec->sql_desc_scale);
2933 : else
2934 4 : *((SQLSMALLINT *) Value) = 0;
2935 : break;
2936 0 : case SQL_DESC_SCHEMA_NAME:
2937 0 : SOUT(drec->sql_desc_schema_name);
2938 0 : break;
2939 0 : case SQL_DESC_SEARCHABLE:
2940 0 : IOUT(SQLSMALLINT, drec->sql_desc_searchable);
2941 : break;
2942 0 : case SQL_DESC_TABLE_NAME:
2943 0 : SOUT(drec->sql_desc_table_name);
2944 0 : break;
2945 606 : case SQL_DESC_TYPE:
2946 606 : IOUT(SQLSMALLINT, drec->sql_desc_type);
2947 : break;
2948 0 : case SQL_DESC_TYPE_NAME:
2949 0 : COUT(drec->sql_desc_type_name);
2950 0 : break;
2951 0 : case SQL_DESC_UNNAMED:
2952 0 : IOUT(SQLSMALLINT, drec->sql_desc_unnamed);
2953 : break;
2954 0 : case SQL_DESC_UNSIGNED:
2955 0 : IOUT(SQLSMALLINT, drec->sql_desc_unsigned);
2956 : break;
2957 0 : case SQL_DESC_UPDATABLE:
2958 0 : IOUT(SQLSMALLINT, drec->sql_desc_updatable);
2959 : break;
2960 0 : default:
2961 0 : odbc_errs_add(&desc->errs, "HY091", NULL);
2962 0 : ODBC_EXIT_(desc);
2963 : break;
2964 : }
2965 :
2966 0 : if (result == SQL_SUCCESS_WITH_INFO)
2967 0 : odbc_errs_add(&desc->errs, "01004", NULL);
2968 :
2969 1866 : ODBC_EXIT(desc, result);
2970 :
2971 : #undef COUT
2972 : #undef SOUT
2973 : #undef IOUT
2974 : }
2975 :
2976 : static SQLRETURN
2977 12 : resize_desc(TDS_DESC *desc, struct _sql_errors *errs, int n)
2978 : {
2979 12 : if (n < 0 || n > 4000) {
2980 0 : odbc_errs_add(errs, "07009", NULL);
2981 0 : return SQL_ERROR;
2982 : }
2983 12 : if (desc_alloc_records(desc, n) != SQL_SUCCESS) {
2984 0 : odbc_errs_add(errs, "HY001", NULL);
2985 0 : return SQL_ERROR;
2986 : }
2987 : return SQL_SUCCESS;
2988 : }
2989 :
2990 : static struct _drecord *
2991 658 : get_drec(TDS_DESC *desc, struct _sql_errors *errs, SQLSMALLINT icol)
2992 : {
2993 658 : if (icol > 0 && (icol <= desc->header.sql_desc_count || resize_desc(desc, errs, icol) == SQL_SUCCESS))
2994 658 : return &desc->records[icol - 1];
2995 :
2996 : return NULL;
2997 : }
2998 :
2999 710 : ODBC_FUNC(SQLSetDescField, (P(SQLHDESC,hdesc), P(SQLSMALLINT,icol), P(SQLSMALLINT,fDescType),
3000 : P(SQLPOINTER,Value), P(SQLINTEGER,BufferLength) WIDE))
3001 : {
3002 : struct _drecord *drec;
3003 710 : SQLRETURN result = SQL_SUCCESS;
3004 : TDS_DESC *fdesc;
3005 :
3006 710 : ODBC_ENTER_HDESC;
3007 :
3008 : #if ENABLE_EXTRA_CHECKS
3009 : #define IIN(type, dest) do { \
3010 : /* trick warning if type wrong */ \
3011 : type *p_test = &dest; p_test = p_test; \
3012 : dest = (type)(TDS_INTPTR)Value; } while(0)
3013 : #define PIN(type, dest) do { \
3014 : /* trick warning if type wrong */ \
3015 : type *p_test = &dest; p_test = p_test; \
3016 : dest = (type)Value; } while(0)
3017 : #else
3018 : #define IIN(type, dest) dest = (type)(TDS_INTPTR)Value
3019 : #define PIN(type, dest) dest = (type)Value
3020 : #endif
3021 : #define GET_DREC do { \
3022 : drec = get_drec(fdesc, &desc->errs, icol); \
3023 : if (!drec) goto default_err; \
3024 : } while(0)
3025 :
3026 : /* special case for IRD */
3027 710 : if (desc->type == DESC_IRD && fDescType != SQL_DESC_ARRAY_STATUS_PTR && fDescType != SQL_DESC_ROWS_PROCESSED_PTR) {
3028 0 : odbc_errs_add(&desc->errs, "HY016", NULL);
3029 0 : ODBC_EXIT_(desc);
3030 : }
3031 :
3032 710 : fdesc = desc_get_focused(desc);
3033 :
3034 : /* dont check column index for these */
3035 710 : switch (fDescType) {
3036 0 : case SQL_DESC_ALLOC_TYPE:
3037 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3038 0 : ODBC_EXIT_(desc);
3039 : break;
3040 0 : case SQL_DESC_ARRAY_SIZE:
3041 0 : IIN(SQLULEN, fdesc->header.sql_desc_array_size);
3042 0 : ODBC_EXIT_(desc);
3043 : break;
3044 0 : case SQL_DESC_ARRAY_STATUS_PTR:
3045 0 : PIN(SQLUSMALLINT *, fdesc->header.sql_desc_array_status_ptr);
3046 0 : ODBC_EXIT_(desc);
3047 : break;
3048 40 : case SQL_DESC_ROWS_PROCESSED_PTR:
3049 40 : PIN(SQLULEN *, fdesc->header.sql_desc_rows_processed_ptr);
3050 40 : ODBC_EXIT_(desc);
3051 : break;
3052 0 : case SQL_DESC_BIND_TYPE:
3053 0 : IIN(SQLINTEGER, fdesc->header.sql_desc_bind_type);
3054 0 : ODBC_EXIT_(desc);
3055 : break;
3056 2 : case SQL_DESC_COUNT:
3057 2 : resize_desc(fdesc, &desc->errs, (int) (TDS_INTPTR) Value);
3058 2 : ODBC_EXIT_(desc);
3059 : break;
3060 : }
3061 :
3062 668 : if (icol <= 0) {
3063 0 : odbc_errs_add(&desc->errs, "07009", "Column out of range");
3064 0 : ODBC_EXIT_(desc);
3065 : }
3066 :
3067 668 : tdsdump_log(TDS_DBG_INFO1, "SQLSetDescField: fDescType is %d\n", fDescType);
3068 :
3069 668 : switch (fDescType) {
3070 10 : case SQL_DESC_AUTO_UNIQUE_VALUE:
3071 : case SQL_DESC_BASE_COLUMN_NAME:
3072 : case SQL_DESC_BASE_TABLE_NAME:
3073 : case SQL_DESC_CASE_SENSITIVE:
3074 : case SQL_DESC_CATALOG_NAME:
3075 10 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3076 10 : result = SQL_ERROR;
3077 10 : break;
3078 544 : case SQL_DESC_CONCISE_TYPE:
3079 544 : GET_DREC;
3080 544 : DESC_SET_NEED_REPREPARE;
3081 544 : if (fdesc->type == DESC_IPD)
3082 450 : result = odbc_set_concise_sql_type((SQLSMALLINT) (TDS_INTPTR) Value, drec, 0);
3083 : else
3084 94 : result = odbc_set_concise_c_type((SQLSMALLINT) (TDS_INTPTR) Value, drec, 0);
3085 544 : if (result != SQL_SUCCESS)
3086 310 : odbc_errs_add(&desc->errs, "HY021", NULL);
3087 : break;
3088 0 : case SQL_DESC_DATA_PTR:
3089 0 : GET_DREC;
3090 0 : PIN(SQLPOINTER, drec->sql_desc_data_ptr);
3091 0 : break;
3092 : /* TODO SQL_DESC_DATETIME_INTERVAL_CODE remember to check sql_desc_type */
3093 : /* TODO SQL_DESC_DATETIME_INTERVAL_PRECISION */
3094 0 : case SQL_DESC_DISPLAY_SIZE:
3095 : case SQL_DESC_FIXED_PREC_SCALE:
3096 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3097 0 : result = SQL_ERROR;
3098 0 : break;
3099 0 : case SQL_DESC_INDICATOR_PTR:
3100 0 : GET_DREC;
3101 0 : PIN(SQLLEN *, drec->sql_desc_indicator_ptr);
3102 0 : break;
3103 0 : case SQL_DESC_LABEL:
3104 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3105 0 : result = SQL_ERROR;
3106 0 : break;
3107 0 : case SQL_DESC_LENGTH:
3108 0 : GET_DREC;
3109 0 : DESC_SET_NEED_REPREPARE;
3110 0 : IIN(SQLULEN, drec->sql_desc_length);
3111 0 : break;
3112 0 : case SQL_DESC_LITERAL_PREFIX:
3113 : case SQL_DESC_LITERAL_SUFFIX:
3114 : case SQL_DESC_LOCAL_TYPE_NAME:
3115 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3116 0 : result = SQL_ERROR;
3117 0 : break;
3118 0 : case SQL_DESC_NAME:
3119 0 : GET_DREC;
3120 0 : if (!odbc_dstr_copy_oct(desc_get_dbc(fdesc), &drec->sql_desc_name, BufferLength, (ODBC_CHAR *) Value)) {
3121 0 : odbc_errs_add(&desc->errs, "HY001", NULL);
3122 0 : result = SQL_ERROR;
3123 : }
3124 : break;
3125 0 : case SQL_DESC_NULLABLE:
3126 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3127 0 : result = SQL_ERROR;
3128 0 : break;
3129 0 : case SQL_DESC_NUM_PREC_RADIX:
3130 0 : GET_DREC;
3131 0 : IIN(SQLINTEGER, drec->sql_desc_num_prec_radix);
3132 0 : break;
3133 0 : case SQL_DESC_OCTET_LENGTH:
3134 0 : GET_DREC;
3135 0 : DESC_SET_NEED_REPREPARE;
3136 0 : IIN(SQLLEN, drec->sql_desc_octet_length);
3137 0 : break;
3138 4 : case SQL_DESC_OCTET_LENGTH_PTR:
3139 4 : GET_DREC;
3140 4 : PIN(SQLLEN *, drec->sql_desc_octet_length_ptr);
3141 4 : break;
3142 0 : case SQL_DESC_PARAMETER_TYPE:
3143 0 : GET_DREC;
3144 0 : DESC_SET_NEED_REPREPARE;
3145 0 : IIN(SQLSMALLINT, drec->sql_desc_parameter_type);
3146 0 : break;
3147 50 : case SQL_DESC_PRECISION:
3148 50 : GET_DREC;
3149 50 : DESC_SET_NEED_REPREPARE;
3150 : /* TODO correct ?? */
3151 50 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL)
3152 10 : IIN(SQLSMALLINT, drec->sql_desc_precision);
3153 : else
3154 40 : IIN(SQLULEN, drec->sql_desc_length);
3155 : break;
3156 : #ifdef SQL_DESC_ROWVER
3157 0 : case SQL_DESC_ROWVER:
3158 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3159 0 : result = SQL_ERROR;
3160 0 : break;
3161 : #endif
3162 60 : case SQL_DESC_SCALE:
3163 60 : GET_DREC;
3164 60 : DESC_SET_NEED_REPREPARE;
3165 60 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL)
3166 10 : IIN(SQLSMALLINT, drec->sql_desc_scale);
3167 : else
3168 : /* TODO even for datetime/money ?? */
3169 50 : drec->sql_desc_scale = 0;
3170 : break;
3171 0 : case SQL_DESC_SCHEMA_NAME:
3172 : case SQL_DESC_SEARCHABLE:
3173 : case SQL_DESC_TABLE_NAME:
3174 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3175 0 : result = SQL_ERROR;
3176 0 : break;
3177 0 : case SQL_DESC_TYPE:
3178 0 : GET_DREC;
3179 0 : DESC_SET_NEED_REPREPARE;
3180 0 : IIN(SQLSMALLINT, drec->sql_desc_type);
3181 : /* FIXME what happen for interval/datetime ?? */
3182 0 : drec->sql_desc_concise_type = drec->sql_desc_type;
3183 0 : break;
3184 0 : case SQL_DESC_TYPE_NAME:
3185 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3186 0 : result = SQL_ERROR;
3187 0 : break;
3188 0 : case SQL_DESC_UNNAMED:
3189 0 : GET_DREC;
3190 0 : IIN(SQLSMALLINT, drec->sql_desc_unnamed);
3191 0 : break;
3192 0 : case SQL_DESC_UNSIGNED:
3193 : case SQL_DESC_UPDATABLE:
3194 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3195 0 : result = SQL_ERROR;
3196 0 : break;
3197 0 : default:
3198 0 : odbc_errs_add(&desc->errs, "HY091", NULL);
3199 0 : ODBC_EXIT_(desc);
3200 : break;
3201 : }
3202 :
3203 : #undef IIN
3204 :
3205 668 : ODBC_EXIT(desc, result);
3206 :
3207 0 : default_err:
3208 0 : ODBC_EXIT_(desc);
3209 : }
3210 :
3211 : SQLRETURN ODBC_PUBLIC ODBC_API
3212 : SQLCopyDesc(SQLHDESC hsrc, SQLHDESC hdesc)
3213 : {
3214 : TDS_DESC *src;
3215 :
3216 50 : ODBC_ENTER_HDESC;
3217 :
3218 30 : tdsdump_log(TDS_DBG_FUNC, "SQLCopyDesc(%p, %p)\n",
3219 : hsrc, hdesc);
3220 :
3221 : /* check source descriptor handle, destination one was already checked */
3222 30 : if (SQL_NULL_HDESC == hsrc || !IS_HDESC(hsrc)) {
3223 20 : tds_mutex_unlock(&desc->mtx);
3224 20 : return SQL_INVALID_HANDLE;
3225 : }
3226 :
3227 10 : src = (TDS_DESC *) hsrc;
3228 10 : CHECK_DESC_EXTRA(src);
3229 :
3230 : /* do not write on IRD */
3231 10 : if (desc->type == DESC_IRD) {
3232 0 : odbc_errs_add(&desc->errs, "HY016", NULL);
3233 0 : ODBC_EXIT_(desc);
3234 : }
3235 10 : IRD_UPDATE(src, &src->errs, ODBC_EXIT(desc, SQL_ERROR));
3236 :
3237 10 : ODBC_EXIT(desc, desc_copy(desc, src));
3238 : }
3239 :
3240 : #if ENABLE_EXTRA_CHECKS
3241 : static void
3242 19418 : odbc_ird_check(TDS_STMT * stmt TDS_UNUSED)
3243 : {
3244 : #if !ENABLE_ODBC_MARS
3245 19418 : TDS_DESC *ird = stmt->ird;
3246 19418 : TDSRESULTINFO *res_info = NULL;
3247 19418 : int cols = 0, i;
3248 :
3249 19418 : if (!stmt->tds)
3250 : return;
3251 18438 : if (stmt->tds->current_results) {
3252 18417 : res_info = stmt->tds->current_results;
3253 18417 : cols = res_info->num_cols;
3254 : }
3255 18438 : if (stmt->cursor != NULL)
3256 : return;
3257 :
3258 : /* check columns number */
3259 18090 : assert(ird->header.sql_desc_count <= cols || ird->header.sql_desc_count == 0);
3260 :
3261 :
3262 : /* check all columns */
3263 74633 : for (i = 0; i < ird->header.sql_desc_count; ++i) {
3264 74633 : struct _drecord *drec = &ird->records[i];
3265 74633 : TDSCOLUMN *col = res_info->columns[i];
3266 :
3267 223899 : assert(strcmp(tds_dstr_cstr(&drec->sql_desc_label), tds_dstr_cstr(&col->column_name)) == 0);
3268 : }
3269 : #endif
3270 : }
3271 : #endif
3272 :
3273 : static void
3274 3710 : odbc_unquote(char *buf, size_t buf_len, const char *start, const char *end)
3275 : {
3276 : char quote;
3277 3710 : assert(buf_len > 0);
3278 :
3279 : /* empty string */
3280 3710 : if (start >= end) {
3281 0 : buf[0] = 0;
3282 0 : return;
3283 : }
3284 :
3285 : /* not quoted */
3286 3710 : if (*start != '[' && *start != '\"') {
3287 2622 : --buf_len;
3288 2622 : if (end < start + buf_len)
3289 2622 : buf_len = end - start;
3290 2622 : memcpy(buf, start, buf_len);
3291 2622 : buf[buf_len] = 0;
3292 2622 : return;
3293 : }
3294 :
3295 : /* quoted... unquote */
3296 1088 : quote = (*start == '[') ? ']' : *start;
3297 1088 : ++start;
3298 7856 : while (buf_len > 0 && start < end) {
3299 6768 : if (*start == quote)
3300 1088 : if (++start >= end)
3301 : break;
3302 5680 : *buf++ = *start++;
3303 5680 : --buf_len;
3304 : }
3305 1088 : *buf = 0;
3306 : }
3307 :
3308 : /* FIXME check result !!! */
3309 : static SQLRETURN
3310 43260 : odbc_populate_ird(TDS_STMT * stmt)
3311 : {
3312 43260 : TDS_DESC *ird = stmt->ird;
3313 : struct _drecord *drec;
3314 : TDSCOLUMN *col;
3315 : TDSRESULTINFO *res_info;
3316 : int num_cols;
3317 : int i;
3318 :
3319 43260 : desc_free_records(ird);
3320 43260 : if (!stmt->tds || !(res_info = stmt->tds->current_results))
3321 : return SQL_SUCCESS;
3322 12073 : if (res_info == stmt->tds->param_info)
3323 : return SQL_SUCCESS;
3324 11337 : num_cols = res_info->num_cols;
3325 :
3326 : /* ignore hidden columns... TODO correct? */
3327 23106 : while (num_cols > 0 && res_info->columns[num_cols - 1]->column_hidden == 1)
3328 432 : --num_cols;
3329 :
3330 11337 : if (desc_alloc_records(ird, num_cols) != SQL_SUCCESS)
3331 : goto memory_error;
3332 :
3333 18331 : for (i = 0; i < num_cols; i++) {
3334 18331 : drec = &ird->records[i];
3335 18331 : col = res_info->columns[i];
3336 18331 : drec->sql_desc_auto_unique_value = col->column_identity ? SQL_TRUE : SQL_FALSE;
3337 : /* TODO SQL_FALSE ?? */
3338 18331 : drec->sql_desc_case_sensitive = SQL_TRUE;
3339 :
3340 : /*
3341 : * TODO how to handle when in datetime we change precision ??
3342 : * should we change display size too ??
3343 : * is formatting function correct ??
3344 : * we should not convert to string with invalid precision!
3345 : */
3346 18331 : odbc_set_sql_type_info(col, drec, stmt->dbc);
3347 :
3348 18331 : drec->sql_desc_fixed_prec_scale = (col->column_prec && col->column_scale) ? SQL_TRUE : SQL_FALSE;
3349 18331 : if (!tds_dstr_dup(&drec->sql_desc_label, &col->column_name))
3350 : goto memory_error;
3351 :
3352 36662 : if (tds_dstr_isempty(&col->table_column_name)) {
3353 16063 : if (!tds_dstr_dup(&drec->sql_desc_name, &col->column_name))
3354 : goto memory_error;
3355 : } else {
3356 2268 : if (!tds_dstr_dup(&drec->sql_desc_name, &col->table_column_name))
3357 : goto memory_error;
3358 2268 : if (!tds_dstr_dup(&drec->sql_desc_base_column_name, &col->table_column_name))
3359 : goto memory_error;
3360 : }
3361 :
3362 : /* extract sql_desc_(catalog/schema/base_table)_name */
3363 : /* TODO extract them dinamically (when needed) ? */
3364 : /* TODO store in libTDS in different way (separately) ? */
3365 36662 : if (!tds_dstr_isempty(&col->table_name)) {
3366 : struct {
3367 : const char *start;
3368 : const char *end;
3369 : } partials[4];
3370 : const char *p;
3371 : char buf[256];
3372 : int i;
3373 :
3374 7420 : p = tds_dstr_cstr(&col->table_name);
3375 3710 : for (i = 0; ; ++i) {
3376 : const char *pend;
3377 :
3378 3710 : if (*p == '[' || *p == '\"') {
3379 1088 : pend = tds_skip_quoted(p);
3380 : } else {
3381 2622 : pend = strchr(p, '.');
3382 2622 : if (!pend)
3383 2622 : pend = strchr(p, 0);
3384 : }
3385 3710 : partials[i].start = p;
3386 3710 : partials[i].end = pend;
3387 3710 : p = pend;
3388 3710 : if (i == 3 || *p != '.')
3389 : break;
3390 0 : ++p;
3391 : }
3392 :
3393 : /* here i points to last element */
3394 3710 : odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3395 3710 : if (!tds_dstr_copy(&drec->sql_desc_base_table_name, buf))
3396 : goto memory_error;
3397 :
3398 3710 : --i;
3399 3710 : if (i >= 0) {
3400 0 : odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3401 0 : if (!tds_dstr_copy(&drec->sql_desc_schema_name, buf))
3402 : goto memory_error;
3403 : }
3404 :
3405 3710 : --i;
3406 3710 : if (i >= 0) {
3407 0 : odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3408 0 : if (!tds_dstr_copy(&drec->sql_desc_catalog_name, buf))
3409 : goto memory_error;
3410 : }
3411 : }
3412 :
3413 36662 : drec->sql_desc_unnamed = tds_dstr_isempty(&drec->sql_desc_name) ? SQL_UNNAMED : SQL_NAMED;
3414 : /* TODO use is_nullable_type ?? */
3415 18331 : drec->sql_desc_nullable = col->column_nullable ? SQL_TRUE : SQL_FALSE;
3416 :
3417 18331 : drec->sql_desc_octet_length_ptr = NULL;
3418 : /* TODO test timestamp from db, FOR BROWSE query */
3419 18331 : drec->sql_desc_rowver = SQL_FALSE;
3420 : /* TODO seem not correct */
3421 18331 : drec->sql_desc_searchable = (drec->sql_desc_unnamed == SQL_NAMED) ? SQL_PRED_SEARCHABLE : SQL_UNSEARCHABLE;
3422 18331 : drec->sql_desc_updatable = col->column_writeable && !col->column_identity ? SQL_TRUE : SQL_FALSE;
3423 : }
3424 : return SQL_SUCCESS;
3425 :
3426 0 : memory_error:
3427 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
3428 0 : return SQL_ERROR;
3429 : }
3430 :
3431 : static TDSRET
3432 2314 : odbc_cursor_execute(TDS_STMT * stmt)
3433 : {
3434 2314 : TDSSOCKET *tds = stmt->tds;
3435 : int i;
3436 2314 : bool send = false;
3437 : TDSRET ret;
3438 : TDSCURSOR *cursor;
3439 2314 : TDSPARAMINFO *params = stmt->params;
3440 :
3441 2314 : assert(tds);
3442 2314 : assert(stmt->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY || stmt->attr.concurrency != SQL_CONCUR_READ_ONLY);
3443 :
3444 2314 : tds_release_cursor(&stmt->cursor);
3445 11570 : cursor = tds_alloc_cursor(tds, tds_dstr_cstr(&stmt->cursor_name), tds_dstr_len(&stmt->cursor_name),
3446 4628 : tds_dstr_cstr(&stmt->query), tds_dstr_len(&stmt->query));
3447 2314 : if (!cursor) {
3448 0 : odbc_unlock_statement(stmt);
3449 :
3450 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
3451 0 : return TDS_FAIL;
3452 : }
3453 2314 : stmt->cursor = cursor;
3454 :
3455 : /* TODO cursor add enums for tds7 */
3456 2314 : switch (stmt->attr.cursor_type) {
3457 : default:
3458 : case SQL_CURSOR_FORWARD_ONLY:
3459 : i = TDS_CUR_TYPE_FORWARD;
3460 : break;
3461 : case SQL_CURSOR_STATIC:
3462 : i = TDS_CUR_TYPE_STATIC;
3463 : break;
3464 : case SQL_CURSOR_KEYSET_DRIVEN:
3465 : i = TDS_CUR_TYPE_KEYSET;
3466 : break;
3467 : case SQL_CURSOR_DYNAMIC:
3468 : i = TDS_CUR_TYPE_DYNAMIC;
3469 : break;
3470 : }
3471 2314 : cursor->type = i;
3472 :
3473 2314 : switch (stmt->attr.concurrency) {
3474 : default:
3475 : case SQL_CONCUR_READ_ONLY:
3476 : i = TDS_CUR_CONCUR_READ_ONLY;
3477 : break;
3478 : case SQL_CONCUR_LOCK:
3479 : i = TDS_CUR_CONCUR_SCROLL_LOCKS;
3480 : break;
3481 : case SQL_CONCUR_ROWVER:
3482 : i = TDS_CUR_CONCUR_OPTIMISTIC;
3483 : break;
3484 : case SQL_CONCUR_VALUES:
3485 : i = TDS_CUR_CONCUR_OPTIMISTIC_VALUES;
3486 : break;
3487 : }
3488 2314 : cursor->concurrency = TDS_CUR_CONCUR_ALLOW_DIRECT | i;
3489 :
3490 2314 : ret = tds_cursor_declare(tds, cursor, &send);
3491 2314 : if (TDS_FAILED(ret))
3492 : return ret;
3493 2314 : ret = tds_cursor_open(tds, cursor, params, &send);
3494 2314 : if (TDS_FAILED(ret))
3495 : return ret;
3496 : /* TODO read results, set row count, check type and scroll returned */
3497 2314 : ret = tds_flush_packet(tds);
3498 2314 : tds_set_state(tds, TDS_PENDING);
3499 : /* set cursor name for TDS7+ */
3500 4628 : if (TDS_SUCCEED(ret) && IS_TDS7_PLUS(tds->conn) && !tds_dstr_isempty(&stmt->cursor_name)) {
3501 2314 : ret = odbc_process_tokens(stmt, TDS_RETURN_DONE|TDS_STOPAT_ROW|TDS_STOPAT_COMPUTE);
3502 2314 : stmt->row_count = tds->rows_affected;
3503 2314 : if (ret == TDS_CMD_DONE && cursor->cursor_id != 0) {
3504 248 : ret = tds_cursor_setname(tds, cursor);
3505 248 : tds_set_state(tds, TDS_PENDING);
3506 : } else {
3507 2066 : ret = (ret == TDS_CMD_FAIL) ? TDS_FAIL : TDS_SUCCESS;
3508 : }
3509 2314 : if (!cursor->cursor_id) {
3510 2058 : tds_cursor_dealloc(tds, cursor);
3511 2058 : tds_release_cursor(&stmt->cursor);
3512 : }
3513 : }
3514 : return ret;
3515 : }
3516 :
3517 : static TDSHEADERS *
3518 27833 : odbc_init_headers(TDS_STMT * stmt, TDSHEADERS * head)
3519 : {
3520 55670 : if (tds_dstr_isempty(&stmt->attr.qn_msgtext) || tds_dstr_isempty(&stmt->attr.qn_options))
3521 : return NULL;
3522 :
3523 4 : memset(head, 0, sizeof(*head));
3524 4 : head->qn_timeout = stmt->attr.qn_timeout;
3525 8 : head->qn_msgtext = tds_dstr_cstr(&stmt->attr.qn_msgtext);
3526 8 : head->qn_options = tds_dstr_cstr(&stmt->attr.qn_options);
3527 4 : return head;
3528 : }
3529 :
3530 : static SQLRETURN
3531 32949 : odbc_SQLExecute(TDS_STMT * stmt)
3532 : {
3533 : TDSRET ret;
3534 : TDSSOCKET *tds;
3535 : TDS_INT result_type;
3536 32949 : TDS_INT done = 0;
3537 32949 : bool in_row = false;
3538 : SQLUSMALLINT param_status;
3539 32949 : int found_info = 0, found_error = 0;
3540 32949 : TDS_INT8 total_rows = TDS_NO_COUNT;
3541 : TDSHEADERS head;
3542 :
3543 32949 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLExecute(%p)\n",
3544 : stmt);
3545 :
3546 32949 : stmt->row = 0;
3547 :
3548 :
3549 : /* check parameters are all OK */
3550 32949 : if (stmt->params && stmt->param_num <= (int) stmt->param_count) {
3551 : /* TODO what error ?? */
3552 0 : ODBC_SAFE_ERROR(stmt);
3553 : return SQL_ERROR;
3554 : }
3555 :
3556 32949 : if (!odbc_lock_statement(stmt))
3557 : return SQL_ERROR;
3558 :
3559 32941 : tds = stmt->tds;
3560 32941 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLExecute() starting with state %d\n", tds->state);
3561 :
3562 32941 : if (tds->state != TDS_IDLE) {
3563 0 : if (tds->state == TDS_DEAD) {
3564 0 : odbc_errs_add(&stmt->errs, "08S01", NULL);
3565 : } else {
3566 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
3567 : }
3568 : return SQL_ERROR;
3569 : }
3570 :
3571 32941 : stmt->curr_param_row = 0;
3572 32941 : stmt->num_param_rows = TDS_MAX(1, stmt->apd->header.sql_desc_array_size);
3573 :
3574 32941 : stmt->row_count = TDS_NO_COUNT;
3575 :
3576 32941 : if (stmt->prepared_query_is_rpc) {
3577 : /* TODO support stmt->apd->header.sql_desc_array_size for RPC */
3578 : /* get rpc name */
3579 : /* TODO change method */
3580 : /* TODO cursor change way of calling */
3581 2212 : char *name = tds_dstr_buf(&stmt->query);
3582 : char *end, tmp;
3583 :
3584 1106 : end = name;
3585 1106 : end = (char *) odbc_skip_rpc_name(end);
3586 1106 : stmt->prepared_pos = end - name;
3587 1106 : tmp = *end;
3588 1106 : *end = 0;
3589 1106 : ret = tds_submit_rpc(tds, name, stmt->params, odbc_init_headers(stmt, &head));
3590 1106 : *end = tmp;
3591 31835 : } else if (stmt->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY || stmt->attr.concurrency != SQL_CONCUR_READ_ONLY) {
3592 2314 : ret = odbc_cursor_execute(stmt);
3593 29521 : } else if (!stmt->is_prepared_query) {
3594 : /* not prepared query */
3595 : /* TODO cursor change way of calling */
3596 : /* SQLExecDirect */
3597 26727 : if (stmt->num_param_rows <= 1) {
3598 26639 : if (!stmt->params) {
3599 51650 : ret = tds_submit_query_params(tds, tds_dstr_cstr(&stmt->query), NULL,
3600 : odbc_init_headers(stmt, &head));
3601 : } else {
3602 1628 : ret = tds_submit_execdirect(tds, tds_dstr_cstr(&stmt->query), stmt->params,
3603 : odbc_init_headers(stmt, &head));
3604 : }
3605 : } else {
3606 : /* pack multiple submit using language */
3607 : TDSMULTIPLE multiple;
3608 :
3609 88 : ret = tds_multiple_init(tds, &multiple, TDS_MULTIPLE_QUERY, odbc_init_headers(stmt, &head));
3610 728 : for (stmt->curr_param_row = 0; TDS_SUCCEED(ret); ) {
3611 : /* submit a query */
3612 1280 : ret = tds_multiple_query(tds, &multiple, tds_dstr_cstr(&stmt->query), stmt->params);
3613 640 : if (++stmt->curr_param_row >= stmt->num_param_rows)
3614 : break;
3615 : /* than process others parameters */
3616 : /* TODO handle all results*/
3617 552 : if (start_parse_prepared_query(stmt, true) != SQL_SUCCESS)
3618 : break;
3619 : }
3620 88 : if (TDS_SUCCEED(ret))
3621 88 : ret = tds_multiple_done(tds, &multiple);
3622 : }
3623 2794 : } else if (stmt->num_param_rows <= 1 && IS_TDS71_PLUS(tds->conn)
3624 2312 : && (!stmt->dyn || stmt->need_reprepare || !stmt->dyn->num_id)) {
3625 1830 : if (stmt->dyn) {
3626 86 : tdsdump_log(TDS_DBG_INFO1, "Re-prepare dynamic statement (num_id was %d)\n", stmt->dyn->num_id);
3627 86 : if (odbc_free_dynamic(stmt) != SQL_SUCCESS)
3628 0 : ODBC_RETURN(stmt, SQL_ERROR);
3629 : }
3630 1830 : stmt->need_reprepare = 0;
3631 3660 : ret = tds71_submit_prepexec(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params);
3632 : } else {
3633 : /* TODO cursor change way of calling */
3634 : /* SQLPrepare */
3635 : TDSDYNAMIC *dyn;
3636 :
3637 : /* prepare dynamic query (only for first SQLExecute call) */
3638 964 : if (!stmt->dyn || (stmt->need_reprepare && !stmt->dyn->emulated && IS_TDS7_PLUS(tds->conn))) {
3639 :
3640 : /* free previous prepared statement */
3641 64 : if (stmt->dyn) {
3642 0 : if (odbc_free_dynamic(stmt) != SQL_SUCCESS)
3643 0 : ODBC_RETURN(stmt, SQL_ERROR);
3644 : }
3645 64 : stmt->need_reprepare = 0;
3646 :
3647 64 : tdsdump_log(TDS_DBG_INFO1, "Creating prepared statement\n");
3648 : /* TODO use tds_submit_prepexec (mssql2k, tds71) */
3649 128 : if (TDS_FAILED(tds_submit_prepare(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params))) {
3650 : /* TODO ?? tds_free_param_results(params); */
3651 0 : ODBC_SAFE_ERROR(stmt);
3652 : return SQL_ERROR;
3653 : }
3654 64 : if (TDS_FAILED(tds_process_simple_query(tds))) {
3655 0 : tds_release_dynamic(&stmt->dyn);
3656 : /* TODO ?? tds_free_param_results(params); */
3657 0 : ODBC_SAFE_ERROR(stmt);
3658 : return SQL_ERROR;
3659 : }
3660 : }
3661 964 : stmt->row_count = TDS_NO_COUNT;
3662 964 : if (stmt->num_param_rows <= 1) {
3663 898 : dyn = stmt->dyn;
3664 898 : tds_free_input_params(dyn);
3665 898 : dyn->params = stmt->params;
3666 : /* prevent double free */
3667 898 : stmt->params = NULL;
3668 898 : tdsdump_log(TDS_DBG_INFO1, "End prepare, execute\n");
3669 : /* TODO return error to client */
3670 898 : ret = tds_submit_execute(tds, dyn);
3671 : } else {
3672 : TDSMULTIPLE multiple;
3673 :
3674 66 : ret = tds_multiple_init(tds, &multiple, TDS_MULTIPLE_EXECUTE, NULL);
3675 656 : for (stmt->curr_param_row = 0; TDS_SUCCEED(ret); ) {
3676 590 : dyn = stmt->dyn;
3677 590 : tds_free_input_params(dyn);
3678 590 : dyn->params = stmt->params;
3679 : /* prevent double free */
3680 590 : stmt->params = NULL;
3681 590 : ret = tds_multiple_execute(tds, &multiple, dyn);
3682 590 : if (++stmt->curr_param_row >= stmt->num_param_rows)
3683 : break;
3684 : /* than process others parameters */
3685 : /* TODO handle all results*/
3686 524 : if (start_parse_prepared_query(stmt, true) != SQL_SUCCESS)
3687 : break;
3688 : }
3689 66 : if (TDS_SUCCEED(ret))
3690 66 : ret = tds_multiple_done(tds, &multiple);
3691 : }
3692 : }
3693 32941 : if (TDS_FAILED(ret)) {
3694 20 : ODBC_SAFE_ERROR(stmt);
3695 : return SQL_ERROR;
3696 : }
3697 : /* catch all errors */
3698 32921 : if (!odbc_lock_statement(stmt))
3699 0 : ODBC_RETURN_(stmt);
3700 :
3701 32921 : stmt->row_status = PRE_NORMAL_ROW;
3702 :
3703 32921 : stmt->curr_param_row = 0;
3704 32921 : param_status = SQL_PARAM_SUCCESS;
3705 :
3706 : /* TODO review this, ODBC return parameter in other way, for compute I don't know */
3707 : /* TODO perhaps we should return SQL_NO_DATA if no data available... see old SQLExecute code */
3708 : for (;;) {
3709 54382 : result_type = odbc_process_tokens(stmt, TDS_TOKEN_RESULTS);
3710 54382 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLExecute: odbc_process_tokens returned result_type %d\n", result_type);
3711 54382 : switch (result_type) {
3712 28925 : case TDS_CMD_FAIL:
3713 : case TDS_CMD_DONE:
3714 : case TDS_COMPUTE_RESULT:
3715 : case TDS_ROW_RESULT:
3716 28925 : done = 1;
3717 28925 : break;
3718 :
3719 4994 : case TDS_DONE_RESULT:
3720 : case TDS_DONEPROC_RESULT:
3721 4994 : switch (stmt->errs.lastrc) {
3722 968 : case SQL_ERROR:
3723 968 : found_error = 1;
3724 968 : param_status = SQL_PARAM_ERROR;
3725 968 : break;
3726 634 : case SQL_SUCCESS_WITH_INFO:
3727 634 : found_info = 1;
3728 634 : param_status = SQL_PARAM_SUCCESS_WITH_INFO;
3729 634 : break;
3730 : }
3731 4994 : if (stmt->curr_param_row < stmt->num_param_rows && stmt->ipd->header.sql_desc_array_status_ptr)
3732 820 : stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
3733 4994 : param_status = SQL_PARAM_SUCCESS;
3734 4994 : ++stmt->curr_param_row;
3735 : /* actually is quite strange, if prepared always success with info or success
3736 : * if not prepared return last one
3737 : */
3738 4994 : if (stmt->curr_param_row < stmt->num_param_rows || result_type == TDS_DONEPROC_RESULT)
3739 1614 : stmt->errs.lastrc = SQL_SUCCESS;
3740 4994 : if (total_rows == TDS_NO_COUNT)
3741 4110 : total_rows = stmt->row_count;
3742 884 : else if (stmt->row_count != TDS_NO_COUNT)
3743 674 : total_rows += stmt->row_count;
3744 4994 : stmt->row_count = TDS_NO_COUNT;
3745 4994 : if (stmt->curr_param_row >= stmt->num_param_rows) {
3746 3918 : done = 1;
3747 3918 : break;
3748 : }
3749 : break;
3750 :
3751 9948 : case TDS_DONEINPROC_RESULT:
3752 9948 : if (in_row)
3753 78 : done = 1;
3754 : break;
3755 :
3756 : /* ignore metadata, stop at done or row */
3757 10479 : case TDS_ROWFMT_RESULT:
3758 10479 : if (in_row) {
3759 : done = 1;
3760 : break;
3761 : }
3762 10479 : stmt->row = 0;
3763 10479 : stmt->row_count = TDS_NO_COUNT;
3764 10479 : stmt->row_status = PRE_NORMAL_ROW;
3765 10479 : in_row = true;
3766 10479 : break;
3767 : }
3768 54382 : if (done)
3769 : break;
3770 : }
3771 32921 : if (found_error) {
3772 : /* if the application uses status array it can examine it to determine
3773 : which rows resulted in errors, but if it doesn't, it has no way to
3774 : do it and we must return an error and not success with info to it */
3775 432 : if (stmt->ipd->header.sql_desc_array_status_ptr)
3776 64 : stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3777 : else
3778 368 : stmt->errs.lastrc = SQL_ERROR;
3779 32489 : } else if (found_info && stmt->errs.lastrc != SQL_ERROR)
3780 634 : stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3781 :
3782 98763 : if (tds_dstr_isempty(&stmt->attr.qn_msgtext) != tds_dstr_isempty(&stmt->attr.qn_options)) {
3783 0 : odbc_errs_add(&stmt->errs, "HY000", "Attribute ignored");
3784 0 : stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3785 : }
3786 32921 : if (found_error && stmt->num_param_rows <= 1)
3787 352 : stmt->errs.lastrc = SQL_ERROR;
3788 32921 : if (stmt->curr_param_row < stmt->num_param_rows) {
3789 29003 : if (stmt->ipd->header.sql_desc_array_status_ptr)
3790 0 : stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
3791 29003 : ++stmt->curr_param_row;
3792 29003 : if (total_rows == TDS_NO_COUNT)
3793 29003 : total_rows = stmt->row_count;
3794 0 : else if (stmt->row_count != TDS_NO_COUNT)
3795 0 : total_rows += stmt->row_count;
3796 29003 : stmt->row_count = TDS_NO_COUNT;
3797 : }
3798 32921 : if (stmt->ipd->header.sql_desc_rows_processed_ptr)
3799 144 : *stmt->ipd->header.sql_desc_rows_processed_ptr = TDS_MIN(stmt->curr_param_row, stmt->num_param_rows);
3800 :
3801 32921 : if (total_rows != TDS_NO_COUNT)
3802 8288 : stmt->row_count = total_rows;
3803 :
3804 32921 : odbc_populate_ird(stmt);
3805 32921 : switch (result_type) {
3806 18472 : case TDS_CMD_DONE:
3807 18472 : odbc_unlock_statement(stmt);
3808 18472 : if (stmt->errs.lastrc == SQL_SUCCESS && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3
3809 15718 : && stmt->row_count == TDS_NO_COUNT && !stmt->cursor && stmt->ird->header.sql_desc_count <= 0)
3810 10914 : ODBC_RETURN(stmt, SQL_NO_DATA);
3811 : break;
3812 :
3813 206 : case TDS_CMD_FAIL:
3814 : /* TODO test what happened, report correct error to client */
3815 206 : tdsdump_log(TDS_DBG_INFO1, "SQLExecute: bad results\n");
3816 206 : ODBC_SAFE_ERROR(stmt);
3817 : return SQL_ERROR;
3818 : }
3819 21801 : ODBC_RETURN_(stmt);
3820 : }
3821 :
3822 27895 : ODBC_FUNC(SQLExecDirect, (P(SQLHSTMT,hstmt), PCHARIN(SqlStr,SQLINTEGER) WIDE))
3823 : {
3824 : SQLRETURN res;
3825 :
3826 27895 : ODBC_ENTER_HSTMT;
3827 :
3828 27895 : if (SQL_SUCCESS != odbc_set_stmt_query(stmt, szSqlStr, cbSqlStr _wide)) {
3829 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
3830 0 : ODBC_EXIT_(stmt);
3831 : }
3832 :
3833 : /* count placeholders */
3834 : /* note: szSqlStr can be no-null terminated, so first we set query and then count placeholders */
3835 55790 : stmt->param_count = tds_count_placeholders(tds_dstr_cstr(&stmt->query));
3836 27895 : stmt->param_data_called = 0;
3837 :
3838 27895 : if (SQL_SUCCESS != prepare_call(stmt)) {
3839 : /* TODO return another better error, prepare_call should set error ?? */
3840 0 : odbc_errs_add(&stmt->errs, "HY000", "Could not prepare call");
3841 0 : ODBC_EXIT_(stmt);
3842 : }
3843 :
3844 27895 : res = start_parse_prepared_query(stmt, true);
3845 27895 : if (SQL_SUCCESS != res)
3846 102 : ODBC_EXIT(stmt, res);
3847 :
3848 27793 : ODBC_EXIT(stmt, odbc_SQLExecute(stmt));
3849 : }
3850 :
3851 : SQLRETURN ODBC_PUBLIC ODBC_API
3852 : SQLExecute(SQLHSTMT hstmt)
3853 : {
3854 : ODBC_PRRET_BUF;
3855 : SQLRETURN res;
3856 :
3857 4748 : ODBC_ENTER_HSTMT;
3858 :
3859 4748 : tdsdump_log(TDS_DBG_FUNC, "SQLExecute(%p)\n", hstmt);
3860 :
3861 4748 : if (!stmt->is_prepared_query) {
3862 : /* TODO error report, only without DM ?? */
3863 0 : tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns SQL_ERROR (not prepared)\n");
3864 0 : ODBC_EXIT(stmt, SQL_ERROR);
3865 : }
3866 :
3867 : /* TODO rebuild should be done for every bindings change, not every time */
3868 : /* TODO free previous parameters */
3869 : /* build parameters list */
3870 4748 : stmt->param_data_called = 0;
3871 4748 : stmt->curr_param_row = 0;
3872 4748 : if ((res = start_parse_prepared_query(stmt, true)) != SQL_SUCCESS) {
3873 112 : tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns %s (start_parse_prepared_query failed)\n", odbc_prret(res));
3874 112 : ODBC_EXIT(stmt, res);
3875 : }
3876 :
3877 : /* TODO test if two SQLPrepare on a statement */
3878 : /* TODO test unprepare on statement free or connection close */
3879 :
3880 4636 : res = odbc_SQLExecute(stmt);
3881 :
3882 4636 : tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns %s\n", odbc_prret(res));
3883 :
3884 4636 : ODBC_EXIT(stmt, res);
3885 : }
3886 :
3887 : static int
3888 98044 : odbc_process_tokens(TDS_STMT * stmt, unsigned flag)
3889 : {
3890 : TDS_INT result_type;
3891 98044 : int done_flags = 0;
3892 98044 : TDSSOCKET * tds = stmt->tds;
3893 :
3894 98044 : flag |= TDS_RETURN_DONE | TDS_RETURN_PROC;
3895 : for (;;) {
3896 216977 : TDSRET retcode = tds_process_tokens(tds, &result_type, &done_flags, flag);
3897 216977 : tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: tds_process_tokens returned %d\n", retcode);
3898 216977 : tdsdump_log(TDS_DBG_FUNC, " result_type=%d, TDS_DONE_COUNT=%x, TDS_DONE_ERROR=%x\n",
3899 : result_type, (done_flags & TDS_DONE_COUNT), (done_flags & TDS_DONE_ERROR));
3900 216977 : switch (retcode) {
3901 : case TDS_SUCCESS:
3902 : break;
3903 : case TDS_NO_MORE_RESULTS:
3904 : return TDS_CMD_DONE;
3905 196 : case TDS_CANCELLED:
3906 196 : odbc_errs_add(&stmt->errs, "HY008", NULL);
3907 : default:
3908 : return TDS_CMD_FAIL;
3909 : }
3910 :
3911 186090 : switch (result_type) {
3912 1221 : case TDS_STATUS_RESULT:
3913 1221 : odbc_set_return_status(stmt, TDS_MIN(stmt->curr_param_row, stmt->num_param_rows - 1));
3914 1221 : break;
3915 834 : case TDS_PARAM_RESULT:
3916 834 : odbc_set_return_params(stmt, TDS_MIN(stmt->curr_param_row, stmt->num_param_rows - 1));
3917 834 : break;
3918 :
3919 130116 : case TDS_DONE_RESULT:
3920 : case TDS_DONEPROC_RESULT:
3921 130116 : if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3922 91682 : flag |= TDS_STOPAT_MSG;
3923 130116 : if (done_flags & TDS_DONE_COUNT) {
3924 : /* correct ?? overwrite ?? */
3925 11892 : if (stmt->row_count == TDS_NO_COUNT)
3926 11792 : stmt->row_count = tds->rows_affected;
3927 : }
3928 130116 : if (done_flags & TDS_DONE_ERROR)
3929 690 : stmt->errs.lastrc = SQL_ERROR;
3930 : /* test for internal_sp not very fine, used for param set -- freddy77 */
3931 130116 : if ((done_flags & (TDS_DONE_COUNT|TDS_DONE_ERROR)) != 0
3932 117654 : || (stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3933 116994 : || (result_type == TDS_DONEPROC_RESULT && tds->current_op == TDS_OP_EXECUTE)) {
3934 : /* FIXME this row is used only as a flag for update binding,
3935 : * should be cleared if binding/result changed */
3936 14186 : stmt->row = 0;
3937 : #if 0
3938 : tds_free_all_results(tds);
3939 : odbc_populate_ird(stmt);
3940 : #endif
3941 14186 : tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: row_count=%" PRId64 "\n", stmt->row_count);
3942 14186 : return result_type;
3943 : }
3944 115930 : tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: processed %s\n",
3945 : result_type==TDS_DONE_RESULT? "TDS_DONE_RESULT" : "TDS_DONEPROC_RESULT");
3946 : break;
3947 :
3948 : /*
3949 : * TODO test flags ? check error and change result ?
3950 : * see also other DONEINPROC handle (below)
3951 : */
3952 10994 : case TDS_DONEINPROC_RESULT:
3953 10994 : if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3954 6342 : flag |= TDS_STOPAT_MSG;
3955 10994 : if (done_flags & TDS_DONE_COUNT) {
3956 7142 : stmt->row_count = tds->rows_affected;
3957 : }
3958 10994 : if (done_flags & TDS_DONE_ERROR)
3959 448 : stmt->errs.lastrc = SQL_ERROR;
3960 : /* TODO perhaps it can be a problem if SET NOCOUNT ON, test it */
3961 : #if 0
3962 : tds_free_all_results(tds);
3963 : odbc_populate_ird(stmt);
3964 : #endif
3965 10994 : tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: processed TDS_DONEINPROC_RESULT\n");
3966 10994 : if (stmt->row_status == PRE_NORMAL_ROW)
3967 10046 : return result_type;
3968 : break;
3969 :
3970 42925 : default:
3971 42925 : tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: returning result_type %d\n", result_type);
3972 42925 : return result_type;
3973 : }
3974 : }
3975 : }
3976 :
3977 : static void
3978 160 : odbc_fix_data_type_col(TDS_STMT *stmt, int idx)
3979 : {
3980 160 : TDSSOCKET *tds = stmt->tds;
3981 : TDSRESULTINFO *resinfo;
3982 : TDSCOLUMN *colinfo;
3983 :
3984 160 : if (!tds)
3985 : return;
3986 :
3987 160 : resinfo = tds->current_results;
3988 160 : if (!resinfo || resinfo->num_cols <= idx)
3989 : return;
3990 :
3991 160 : colinfo = resinfo->columns[idx];
3992 160 : if (colinfo->column_cur_size < 0)
3993 : return;
3994 :
3995 160 : switch (tds_get_conversion_type(colinfo->column_type, colinfo->column_size)) {
3996 160 : case SYBINT2: {
3997 160 : TDS_SMALLINT *data = (TDS_SMALLINT *) colinfo->column_data;
3998 320 : *data = odbc_swap_datetime_sql_type(*data, 0);
3999 : }
4000 160 : break;
4001 0 : case SYBINT4: {
4002 0 : TDS_INT *data = (TDS_INT *) colinfo->column_data;
4003 0 : *data = odbc_swap_datetime_sql_type(*data, 0);
4004 : }
4005 0 : break;
4006 : default:
4007 : break;
4008 : }
4009 : }
4010 :
4011 : static SQLUSMALLINT
4012 20684 : copy_row(TDS_STMT * const stmt, const SQLLEN row_offset, const SQLULEN curr_row)
4013 : {
4014 20684 : const TDS_DESC *const ard = stmt->ard;
4015 20684 : TDSRESULTINFO *const resinfo = stmt->tds->current_results;
4016 : int i;
4017 20684 : bool truncated = false;
4018 :
4019 : #define AT_ROW(ptr, type) (row_offset ? (type*)(((char*)(ptr)) + row_offset) : &ptr[curr_row])
4020 :
4021 99934 : for (i = 0; i < resinfo->num_cols; i++) {
4022 : TDSCOLUMN *colinfo;
4023 : struct _drecord *drec_ard;
4024 : SQLLEN len;
4025 :
4026 79250 : colinfo = resinfo->columns[i];
4027 79250 : colinfo->column_text_sqlgetdatapos = 0;
4028 79250 : colinfo->column_iconv_left = 0;
4029 79250 : drec_ard = (i < ard->header.sql_desc_count) ? &ard->records[i] : NULL;
4030 19678 : if (!drec_ard)
4031 59572 : continue;
4032 19678 : if (colinfo->column_cur_size < 0) {
4033 2410 : if (drec_ard->sql_desc_indicator_ptr) {
4034 1294 : *AT_ROW(drec_ard->sql_desc_indicator_ptr, SQLLEN) = SQL_NULL_DATA;
4035 1116 : } else if (drec_ard->sql_desc_data_ptr) {
4036 0 : odbc_errs_add(&stmt->errs, "22002", NULL);
4037 0 : return SQL_ROW_ERROR;
4038 : }
4039 2410 : continue;
4040 : }
4041 : /* set indicator to 0 if data is not null */
4042 17268 : if (drec_ard->sql_desc_indicator_ptr)
4043 12272 : *AT_ROW(drec_ard->sql_desc_indicator_ptr, SQLLEN) = 0;
4044 :
4045 : /* TODO what happen to length if no data is returned (drec->sql_desc_data_ptr == NULL) ?? */
4046 17268 : len = 0;
4047 17268 : if (drec_ard->sql_desc_data_ptr) {
4048 : int c_type;
4049 11936 : TDS_CHAR *data_ptr = (TDS_CHAR *) drec_ard->sql_desc_data_ptr;
4050 :
4051 11936 : colinfo->column_text_sqlgetdatapos = 0;
4052 11936 : colinfo->column_iconv_left = 0;
4053 11936 : c_type = drec_ard->sql_desc_concise_type;
4054 11936 : if (c_type == SQL_C_DEFAULT)
4055 10 : c_type = odbc_sql_to_c_type_default(stmt->ird->records[i].sql_desc_concise_type);
4056 11936 : if (row_offset || curr_row == 0) {
4057 10778 : data_ptr += row_offset;
4058 : } else {
4059 1158 : data_ptr += odbc_get_octet_len(c_type, drec_ard) * curr_row;
4060 : }
4061 11936 : len = odbc_tds2sql_col(stmt, colinfo, c_type, data_ptr, drec_ard->sql_desc_octet_length, drec_ard);
4062 11936 : if (len == SQL_NULL_DATA)
4063 : return SQL_ROW_ERROR;
4064 :
4065 11936 : if ((c_type == SQL_C_CHAR && len >= drec_ard->sql_desc_octet_length)
4066 11748 : || (c_type == SQL_C_BINARY && len > drec_ard->sql_desc_octet_length)) {
4067 188 : truncated = true;
4068 188 : stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
4069 : }
4070 : }
4071 17268 : if (drec_ard->sql_desc_octet_length_ptr)
4072 12272 : *AT_ROW(drec_ard->sql_desc_octet_length_ptr, SQLLEN) = len;
4073 : }
4074 :
4075 20684 : return truncated ? SQL_ROW_SUCCESS_WITH_INFO : SQL_ROW_SUCCESS;
4076 : #undef AT_ROW
4077 : }
4078 :
4079 : /*
4080 : * - handle correctly SQLGetData (for forward cursors accept only row_size == 1
4081 : * for other types application must use SQLSetPos)
4082 : * - handle correctly results (SQL_SUCCESS_WITH_INFO if error on some rows,
4083 : * SQL_ERROR for all rows, see doc)
4084 : */
4085 : static SQLRETURN
4086 28298 : odbc_SQLFetch(TDS_STMT * stmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)
4087 : {
4088 : TDSSOCKET *tds;
4089 : TDSRESULTINFO *resinfo;
4090 : int i;
4091 : SQLULEN curr_row, num_rows;
4092 28298 : const TDS_DESC *const ard = stmt->ard;
4093 : SQLULEN dummy, *fetched_ptr;
4094 28298 : SQLUSMALLINT *status_ptr, row_status = SQL_ROW_SUCCESS;
4095 : TDS_INT result_type;
4096 28298 : bool truncated = false;
4097 :
4098 28298 : SQLLEN row_offset = 0;
4099 :
4100 28298 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLFetch(%p, %d, %d)\n", stmt, (int) FetchOrientation, (int) FetchOffset);
4101 :
4102 28298 : if (ard->header.sql_desc_bind_offset_ptr)
4103 30 : row_offset = *ard->header.sql_desc_bind_offset_ptr;
4104 :
4105 28298 : tds = stmt->tds;
4106 28298 : num_rows = ard->header.sql_desc_array_size;
4107 :
4108 : /* TODO cursor check also type of cursor (scrollable, not forward) */
4109 28298 : if (FetchOrientation != SQL_FETCH_NEXT && (!stmt->cursor || !stmt->dbc->cursor_support)) {
4110 0 : odbc_errs_add(&stmt->errs, "HY106", NULL);
4111 0 : return SQL_ERROR;
4112 : }
4113 :
4114 : /* handle cursors, fetch wanted rows */
4115 28298 : if (stmt->cursor && odbc_lock_statement(stmt)) {
4116 696 : TDSCURSOR *cursor = stmt->cursor;
4117 696 : TDS_CURSOR_FETCH fetch_type = TDS_CURSOR_FETCH_NEXT;
4118 :
4119 696 : tds = stmt->tds;
4120 :
4121 696 : switch (FetchOrientation) {
4122 : case SQL_FETCH_NEXT:
4123 : break;
4124 16 : case SQL_FETCH_FIRST:
4125 16 : fetch_type = TDS_CURSOR_FETCH_FIRST;
4126 16 : break;
4127 24 : case SQL_FETCH_LAST:
4128 24 : fetch_type = TDS_CURSOR_FETCH_LAST;
4129 24 : break;
4130 32 : case SQL_FETCH_PRIOR:
4131 32 : fetch_type = TDS_CURSOR_FETCH_PREV;
4132 32 : break;
4133 16 : case SQL_FETCH_ABSOLUTE:
4134 16 : fetch_type = TDS_CURSOR_FETCH_ABSOLUTE;
4135 16 : break;
4136 56 : case SQL_FETCH_RELATIVE:
4137 56 : fetch_type = TDS_CURSOR_FETCH_RELATIVE;
4138 56 : break;
4139 : /* TODO cursor bookmark */
4140 0 : default:
4141 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
4142 0 : return SQL_ERROR;
4143 : }
4144 :
4145 696 : if (cursor->cursor_rows != num_rows) {
4146 248 : bool send = false;
4147 248 : cursor->cursor_rows = num_rows;
4148 : /* TODO handle change rows (tds5) */
4149 : /*
4150 : * TODO curerntly we support cursors only using tds7+
4151 : * so this function can't fail but remember to add error
4152 : * check when tds5 will be supported
4153 : */
4154 248 : tds_cursor_setrows(tds, cursor, &send);
4155 : }
4156 :
4157 696 : if (TDS_FAILED(tds_cursor_fetch(tds, cursor, fetch_type, FetchOffset))) {
4158 : /* TODO what kind of error ?? */
4159 0 : ODBC_SAFE_ERROR(stmt);
4160 : return SQL_ERROR;
4161 : }
4162 :
4163 : /* TODO handle errors in a better way */
4164 696 : odbc_process_tokens(stmt, TDS_RETURN_ROW|TDS_STOPAT_COMPUTE|TDS_STOPAT_ROW);
4165 696 : stmt->row_status = PRE_NORMAL_ROW;
4166 : }
4167 :
4168 28298 : if (!tds && stmt->row_status == PRE_NORMAL_ROW && stmt->ird->header.sql_desc_count > 0)
4169 10 : ODBC_RETURN(stmt, SQL_NO_DATA);
4170 28288 : if (!tds || stmt->row_status == NOT_IN_ROW) {
4171 30 : odbc_errs_add(&stmt->errs, "24000", NULL);
4172 30 : return SQL_ERROR;
4173 : }
4174 28258 : IRD_CHECK;
4175 :
4176 28258 : if (stmt->ird->header.sql_desc_count <= 0) {
4177 34 : odbc_errs_add(&stmt->errs, "24000", NULL);
4178 34 : return SQL_ERROR;
4179 : }
4180 :
4181 28224 : stmt->row++;
4182 :
4183 28224 : fetched_ptr = &dummy;
4184 28224 : if (stmt->ird->header.sql_desc_rows_processed_ptr)
4185 640 : fetched_ptr = stmt->ird->header.sql_desc_rows_processed_ptr;
4186 28224 : *fetched_ptr = 0;
4187 :
4188 28224 : status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
4189 28224 : if (status_ptr) {
4190 2704 : for (i = 0; (SQLULEN) i < num_rows; ++i)
4191 2704 : *status_ptr++ = SQL_ROW_NOROW;
4192 : status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
4193 : }
4194 :
4195 : curr_row = 0;
4196 : do {
4197 30044 : row_status = SQL_ROW_SUCCESS;
4198 :
4199 : /* do not get compute row if we are not expecting a compute row */
4200 30044 : switch (stmt->row_status) {
4201 32 : case AFTER_COMPUTE_ROW:
4202 : /* handle done if needed */
4203 : /* FIXME doesn't seem so fine ... - freddy77 */
4204 32 : tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
4205 32 : goto all_done;
4206 :
4207 32 : case IN_COMPUTE_ROW:
4208 : /* compute recorset contains only a row */
4209 : /* we already fetched compute row in SQLMoreResults so do not fetch another one */
4210 32 : num_rows = 1;
4211 32 : stmt->row_status = AFTER_COMPUTE_ROW;
4212 32 : break;
4213 :
4214 29980 : default:
4215 : /* FIXME stmt->row_count set correctly ?? TDS_DONE_COUNT not checked */
4216 29980 : switch (odbc_process_tokens(stmt, TDS_STOPAT_ROWFMT|TDS_RETURN_ROW|TDS_STOPAT_COMPUTE)) {
4217 : case TDS_ROW_RESULT:
4218 : break;
4219 9328 : default:
4220 : #if 0
4221 : stmt->row_count = tds->rows_affected;
4222 : #endif
4223 : /*
4224 : * NOTE do not set row_status to NOT_IN_ROW,
4225 : * if compute tds_process_tokens above returns TDS_NO_MORE_RESULTS
4226 : */
4227 9328 : stmt->row_status = PRE_NORMAL_ROW;
4228 9328 : stmt->special_row = ODBC_SPECIAL_NONE;
4229 : #if 0
4230 : odbc_populate_ird(stmt);
4231 : #endif
4232 9328 : tdsdump_log(TDS_DBG_INFO1, "SQLFetch: NO_DATA_FOUND\n");
4233 : goto all_done;
4234 : break;
4235 0 : case TDS_CMD_FAIL:
4236 0 : ODBC_SAFE_ERROR(stmt);
4237 : return SQL_ERROR;
4238 : break;
4239 : }
4240 :
4241 20652 : stmt->row_status = IN_NORMAL_ROW;
4242 :
4243 : /* handle special row */
4244 20652 : switch (stmt->special_row) {
4245 148 : case ODBC_SPECIAL_GETTYPEINFO:
4246 148 : odbc_fix_data_type_col(stmt, 1);
4247 148 : break;
4248 4 : case ODBC_SPECIAL_COLUMNS:
4249 4 : odbc_fix_data_type_col(stmt, 4);
4250 4 : odbc_fix_data_type_col(stmt, 13); /* TODO sure ?? */
4251 4 : break;
4252 2 : case ODBC_SPECIAL_PROCEDURECOLUMNS:
4253 2 : odbc_fix_data_type_col(stmt, 5);
4254 2 : odbc_fix_data_type_col(stmt, 14); /* TODO sure ?? */
4255 2 : break;
4256 0 : case ODBC_SPECIAL_SPECIALCOLUMNS:
4257 0 : odbc_fix_data_type_col(stmt, 2);
4258 0 : break;
4259 : case ODBC_SPECIAL_NONE:
4260 : break;
4261 : }
4262 : }
4263 :
4264 20684 : resinfo = tds->current_results;
4265 20684 : if (!resinfo) {
4266 0 : tdsdump_log(TDS_DBG_INFO1, "SQLFetch: !resinfo\n");
4267 : break;
4268 : }
4269 :
4270 : /* we got a row, return a row readed even if error (for ODBC specifications) */
4271 20684 : ++(*fetched_ptr);
4272 20684 : row_status = copy_row(stmt, row_offset, curr_row);
4273 20684 : if (row_status == SQL_ROW_SUCCESS_WITH_INFO)
4274 188 : truncated = true;
4275 :
4276 20684 : if (status_ptr)
4277 2096 : *status_ptr++ = truncated ? SQL_ROW_ERROR : row_status;
4278 20684 : if (row_status == SQL_ROW_ERROR) {
4279 0 : stmt->errs.lastrc = SQL_ERROR;
4280 0 : break;
4281 : }
4282 : #if SQL_BIND_BY_COLUMN != 0
4283 : if (ard->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN)
4284 : #endif
4285 20684 : row_offset += ard->header.sql_desc_bind_type;
4286 20684 : } while (++curr_row < num_rows);
4287 :
4288 18864 : if (truncated)
4289 98 : odbc_errs_add(&stmt->errs, "01004", NULL);
4290 :
4291 46990 : all_done:
4292 : /* TODO cursor correct ?? */
4293 28224 : if (stmt->cursor) {
4294 696 : tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
4295 696 : odbc_unlock_statement(stmt);
4296 : }
4297 28224 : if (*fetched_ptr == 0 && (stmt->errs.lastrc == SQL_SUCCESS || stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO))
4298 9142 : ODBC_RETURN(stmt, SQL_NO_DATA);
4299 19082 : if (stmt->errs.lastrc == SQL_ERROR && (*fetched_ptr > 1 || (*fetched_ptr == 1 && row_status != SQL_ROW_ERROR)))
4300 0 : ODBC_RETURN(stmt, SQL_SUCCESS_WITH_INFO);
4301 19082 : ODBC_RETURN_(stmt);
4302 : }
4303 :
4304 : SQLRETURN ODBC_PUBLIC ODBC_API
4305 : SQLFetch(SQLHSTMT hstmt)
4306 : {
4307 : SQLRETURN ret;
4308 : struct {
4309 : SQLULEN array_size;
4310 : SQLULEN *rows_processed_ptr;
4311 : SQLUSMALLINT *array_status_ptr;
4312 : } keep;
4313 :
4314 27628 : ODBC_ENTER_HSTMT;
4315 :
4316 27628 : tdsdump_log(TDS_DBG_FUNC, "SQLFetch(%p)\n", hstmt);
4317 :
4318 27628 : keep.array_size = stmt->ard->header.sql_desc_array_size;
4319 27628 : keep.rows_processed_ptr = stmt->ird->header.sql_desc_rows_processed_ptr;
4320 27628 : keep.array_status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
4321 :
4322 27628 : if (stmt->dbc->env->attr.odbc_version != SQL_OV_ODBC3) {
4323 4762 : stmt->ard->header.sql_desc_array_size = 1;
4324 4762 : stmt->ird->header.sql_desc_rows_processed_ptr = NULL;
4325 4762 : stmt->ird->header.sql_desc_array_status_ptr = NULL;
4326 : }
4327 :
4328 27628 : ret = odbc_SQLFetch(stmt, SQL_FETCH_NEXT, 0);
4329 :
4330 27628 : if (stmt->dbc->env->attr.odbc_version != SQL_OV_ODBC3) {
4331 4762 : stmt->ard->header.sql_desc_array_size = keep.array_size;
4332 4762 : stmt->ird->header.sql_desc_rows_processed_ptr = keep.rows_processed_ptr;
4333 4762 : stmt->ird->header.sql_desc_array_status_ptr = keep.array_status_ptr;
4334 : }
4335 :
4336 27628 : ODBC_EXIT(stmt, ret);
4337 : }
4338 :
4339 : #if (ODBCVER >= 0x0300)
4340 : SQLRETURN ODBC_PUBLIC ODBC_API
4341 : SQLFetchScroll(SQLHSTMT hstmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)
4342 : {
4343 642 : ODBC_ENTER_HSTMT;
4344 :
4345 642 : tdsdump_log(TDS_DBG_FUNC, "SQLFetchScroll(%p, %d, %d)\n", hstmt, FetchOrientation, (int)FetchOffset);
4346 :
4347 642 : if (FetchOrientation != SQL_FETCH_NEXT && !stmt->dbc->cursor_support) {
4348 0 : odbc_errs_add(&stmt->errs, "HY106", NULL);
4349 0 : ODBC_EXIT_(stmt);
4350 : }
4351 :
4352 642 : ODBC_EXIT(stmt, odbc_SQLFetch(stmt, FetchOrientation, FetchOffset));
4353 : }
4354 : #endif
4355 :
4356 :
4357 : #if (ODBCVER >= 0x0300)
4358 : SQLRETURN ODBC_PUBLIC ODBC_API
4359 : SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle)
4360 : {
4361 138 : tdsdump_log(TDS_DBG_INFO1, "SQLFreeHandle(%d, %p)\n", HandleType, (void *) Handle);
4362 :
4363 138 : switch (HandleType) {
4364 128 : case SQL_HANDLE_STMT:
4365 128 : return odbc_SQLFreeStmt(Handle, SQL_DROP, 0);
4366 : break;
4367 0 : case SQL_HANDLE_DBC:
4368 0 : return odbc_SQLFreeConnect(Handle);
4369 : break;
4370 0 : case SQL_HANDLE_ENV:
4371 0 : return odbc_SQLFreeEnv(Handle);
4372 : break;
4373 10 : case SQL_HANDLE_DESC:
4374 10 : return odbc_SQLFreeDesc(Handle);
4375 : break;
4376 : }
4377 : return SQL_ERROR;
4378 : }
4379 :
4380 : static SQLRETURN
4381 1206 : odbc_SQLFreeConnect(SQLHDBC hdbc)
4382 : {
4383 : int i;
4384 :
4385 1206 : ODBC_ENTER_HDBC;
4386 :
4387 1206 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLFreeConnect(%p)\n",
4388 : hdbc);
4389 :
4390 1206 : tds_close_socket(dbc->tds_socket);
4391 :
4392 : /* TODO if connected return error */
4393 1206 : tds_free_socket(dbc->tds_socket);
4394 :
4395 1206 : odbc_bcp_free_storage(dbc);
4396 :
4397 1206 : tds_dstr_free(&dbc->datetime_fmt);
4398 1206 : tds_dstr_free(&dbc->date_fmt);
4399 1206 : tds_dstr_free(&dbc->time_fmt);
4400 :
4401 : /* free attributes */
4402 : #ifdef TDS_NO_DM
4403 1206 : tds_dstr_free(&dbc->attr.tracefile);
4404 : #endif
4405 1206 : tds_dstr_free(&dbc->attr.current_catalog);
4406 1206 : tds_dstr_free(&dbc->attr.translate_lib);
4407 1206 : tds_dstr_zero(&dbc->oldpwd);
4408 1206 : tds_dstr_free(&dbc->oldpwd);
4409 1206 : tds_dstr_free(&dbc->db_filename);
4410 :
4411 1206 : tds_dstr_free(&dbc->dsn);
4412 :
4413 121806 : for (i = 0; i < TDS_MAX_APP_DESC; i++) {
4414 120600 : if (dbc->uad[i]) {
4415 0 : desc_free(dbc->uad[i]);
4416 : }
4417 : }
4418 1206 : odbc_errs_reset(&dbc->errs);
4419 1206 : tds_mutex_unlock(&dbc->mtx);
4420 1206 : tds_mutex_free(&dbc->mtx);
4421 :
4422 1206 : free(dbc);
4423 :
4424 1206 : return SQL_SUCCESS;
4425 : }
4426 :
4427 : SQLRETURN ODBC_PUBLIC ODBC_API
4428 : SQLFreeConnect(SQLHDBC hdbc)
4429 : {
4430 1206 : tdsdump_log(TDS_DBG_INFO2, "SQLFreeConnect(%p)\n", hdbc);
4431 1206 : return odbc_SQLFreeConnect(hdbc);
4432 : }
4433 : #endif
4434 :
4435 : static SQLRETURN
4436 1206 : odbc_SQLFreeEnv(SQLHENV henv)
4437 : {
4438 1206 : ODBC_ENTER_HENV;
4439 :
4440 1206 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLFreeEnv(%p)\n",
4441 : henv);
4442 :
4443 1206 : odbc_errs_reset(&env->errs);
4444 1206 : tds_free_context(env->tds_ctx);
4445 1206 : tds_mutex_unlock(&env->mtx);
4446 1206 : tds_mutex_free(&env->mtx);
4447 1206 : free(env);
4448 :
4449 1206 : return SQL_SUCCESS;
4450 : }
4451 :
4452 : SQLRETURN ODBC_PUBLIC ODBC_API
4453 : SQLFreeEnv(SQLHENV henv)
4454 : {
4455 1206 : tdsdump_log(TDS_DBG_FUNC, "SQLFreeEnv(%p)\n", henv);
4456 :
4457 1206 : return odbc_SQLFreeEnv(henv);
4458 : }
4459 :
4460 : static SQLRETURN
4461 20171 : odbc_SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption, int force)
4462 : {
4463 20171 : ODBC_ENTER_HSTMT;
4464 :
4465 20171 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLFreeStmt(%p, %d, %d)\n", hstmt, fOption, force);
4466 :
4467 : /* check if option correct */
4468 20171 : if (fOption != SQL_DROP && fOption != SQL_CLOSE && fOption != SQL_UNBIND && fOption != SQL_RESET_PARAMS) {
4469 0 : tdsdump_log(TDS_DBG_ERROR, "SQLFreeStmt: Unknown option %d\n", fOption);
4470 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
4471 0 : ODBC_EXIT_(stmt);
4472 : }
4473 :
4474 : /* if we have bound columns, free the temporary list */
4475 20171 : if (fOption == SQL_DROP || fOption == SQL_UNBIND) {
4476 18629 : desc_free_records(stmt->ard);
4477 : }
4478 :
4479 : /* do the same for bound parameters */
4480 20171 : if (fOption == SQL_DROP || fOption == SQL_RESET_PARAMS) {
4481 18641 : desc_free_records(stmt->apd);
4482 18641 : desc_free_records(stmt->ipd);
4483 18641 : stmt->params_set = 0;
4484 : }
4485 :
4486 : /* close statement */
4487 20171 : if (fOption == SQL_DROP || fOption == SQL_CLOSE) {
4488 : SQLRETURN retcode;
4489 : TDSSOCKET *tds;
4490 :
4491 18491 : tds = stmt->tds;
4492 : /*
4493 : * FIXME -- otherwise make sure the current statement is complete
4494 : */
4495 : /* do not close other running query ! */
4496 18491 : if (tds && tds->state != TDS_IDLE && tds->state != TDS_DEAD) {
4497 602 : if (TDS_SUCCEED(tds_send_cancel(tds)))
4498 602 : tds_process_cancel(tds);
4499 : }
4500 :
4501 : /* free cursor */
4502 18491 : retcode = odbc_free_cursor(stmt);
4503 18491 : if (!force && retcode != SQL_SUCCESS)
4504 0 : ODBC_EXIT(stmt, retcode);
4505 : }
4506 :
4507 : /* free it */
4508 20171 : if (fOption == SQL_DROP) {
4509 : #if ENABLE_ODBC_MARS
4510 : TDSSOCKET *tds;
4511 : #endif
4512 : SQLRETURN retcode;
4513 :
4514 : /* close prepared statement or add to connection */
4515 17795 : retcode = odbc_free_dynamic(stmt);
4516 17795 : if (!force && retcode != SQL_SUCCESS)
4517 0 : ODBC_EXIT(stmt, retcode);
4518 :
4519 : /* detatch from list */
4520 17795 : tds_mutex_lock(&stmt->dbc->mtx);
4521 17795 : if (stmt->next)
4522 333 : stmt->next->prev = stmt->prev;
4523 17795 : if (stmt->prev)
4524 24 : stmt->prev->next = stmt->next;
4525 17795 : if (stmt->dbc->stmt_list == stmt)
4526 17771 : stmt->dbc->stmt_list = stmt->next;
4527 17795 : tds_mutex_unlock(&stmt->dbc->mtx);
4528 :
4529 17795 : tds_dstr_free(&stmt->query);
4530 17795 : tds_free_param_results(stmt->params);
4531 17795 : odbc_errs_reset(&stmt->errs);
4532 17795 : odbc_unlock_statement(stmt);
4533 : #if ENABLE_ODBC_MARS
4534 8902 : tds = stmt->tds;
4535 8902 : if (tds && tds != stmt->dbc->tds_socket) {
4536 8 : if (tds->state != TDS_IDLE && tds->state != TDS_DEAD)
4537 0 : tdsdump_log(TDS_DBG_WARN, "MARS SID %d was not idle/dead\n", tds->sid);
4538 :
4539 8 : tdsdump_log(TDS_DBG_INFO1, "MARS SID %d socket freeing\n", tds->sid);
4540 8 : tds_free_socket(tds);
4541 8 : stmt->tds = NULL;
4542 : }
4543 : #endif
4544 17795 : tds_dstr_free(&stmt->cursor_name);
4545 17795 : tds_dstr_free(&stmt->attr.qn_msgtext);
4546 17795 : tds_dstr_free(&stmt->attr.qn_options);
4547 17795 : desc_free(stmt->ird);
4548 17795 : desc_free(stmt->ipd);
4549 17795 : desc_free(stmt->orig_ard);
4550 17795 : desc_free(stmt->orig_apd);
4551 17795 : tds_mutex_unlock(&stmt->mtx);
4552 17795 : tds_mutex_free(&stmt->mtx);
4553 17795 : free(stmt);
4554 :
4555 : /* NOTE we freed stmt, do not use ODBC_EXIT */
4556 17795 : return SQL_SUCCESS;
4557 : }
4558 2376 : ODBC_EXIT_(stmt);
4559 : }
4560 :
4561 : SQLRETURN ODBC_PUBLIC ODBC_API
4562 : SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption)
4563 : {
4564 19539 : tdsdump_log(TDS_DBG_FUNC, "SQLFreeStmt(%p, %d)\n", hstmt, fOption);
4565 19539 : return odbc_SQLFreeStmt(hstmt, fOption, 0);
4566 : }
4567 :
4568 :
4569 : SQLRETURN ODBC_PUBLIC ODBC_API
4570 : SQLCloseCursor(SQLHSTMT hstmt)
4571 : {
4572 : /* TODO cursors */
4573 : /*
4574 : * Basic implementation for when no driver manager is present.
4575 : * - according to ODBC documentation SQLCloseCursor is more or less
4576 : * equivalent to SQLFreeStmt(..., SQL_CLOSE).
4577 : * - indeed that is what the DM does if it can't find the function
4578 : * in the driver, so this is pretty close.
4579 : */
4580 : /* TODO remember to close cursors really when get implemented */
4581 : /* TODO read all results and discard them or use cancellation ?? test behaviour */
4582 :
4583 468 : tdsdump_log(TDS_DBG_FUNC, "SQLCloseCursor(%p)\n", hstmt);
4584 468 : return odbc_SQLFreeStmt(hstmt, SQL_CLOSE, 0);
4585 : }
4586 :
4587 : static SQLRETURN
4588 10 : odbc_SQLFreeDesc(SQLHDESC hdesc)
4589 : {
4590 10 : ODBC_ENTER_HDESC;
4591 :
4592 10 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLFreeDesc(%p)\n",
4593 : hdesc);
4594 :
4595 10 : if (desc->header.sql_desc_alloc_type != SQL_DESC_ALLOC_USER) {
4596 0 : odbc_errs_add(&desc->errs, "HY017", NULL);
4597 0 : ODBC_EXIT_(desc);
4598 : }
4599 :
4600 10 : if (IS_HDBC(desc->parent)) {
4601 10 : TDS_DBC *dbc = (TDS_DBC *) desc->parent;
4602 : TDS_STMT *stmt;
4603 : int i;
4604 :
4605 : /* freeing descriptors associated to statements revert state of statements */
4606 10 : tds_mutex_lock(&dbc->mtx);
4607 20 : for (stmt = dbc->stmt_list; stmt != NULL; stmt = stmt->next) {
4608 10 : if (stmt->ard == desc)
4609 0 : stmt->ard = stmt->orig_ard;
4610 10 : if (stmt->apd == desc)
4611 0 : stmt->apd = stmt->orig_apd;
4612 : }
4613 10 : tds_mutex_unlock(&dbc->mtx);
4614 :
4615 20 : for (i = 0; i < TDS_MAX_APP_DESC; ++i) {
4616 20 : if (dbc->uad[i] == desc) {
4617 10 : dbc->uad[i] = NULL;
4618 10 : tds_mutex_unlock(&desc->mtx);
4619 10 : desc_free(desc);
4620 10 : break;
4621 : }
4622 : }
4623 : }
4624 : return SQL_SUCCESS;
4625 : }
4626 :
4627 : static SQLRETURN
4628 1140 : odbc_SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value,
4629 : SQLINTEGER BufferLength, SQLINTEGER * StringLength WIDE)
4630 : {
4631 : static const SQLUINTEGER zero_ui = 0;
4632 : const void *src;
4633 : SQLINTEGER size;
4634 :
4635 1140 : ODBC_ENTER_HSTMT;
4636 :
4637 : /* TODO assign directly, use macro for size */
4638 1140 : switch (Attribute) {
4639 524 : case SQL_ATTR_APP_PARAM_DESC:
4640 524 : size = sizeof(stmt->apd);
4641 524 : src = &stmt->apd;
4642 524 : break;
4643 150 : case SQL_ATTR_APP_ROW_DESC:
4644 150 : size = sizeof(stmt->ard);
4645 150 : src = &stmt->ard;
4646 150 : break;
4647 0 : case SQL_ATTR_ASYNC_ENABLE:
4648 0 : size = sizeof(stmt->attr.async_enable);
4649 0 : src = &stmt->attr.async_enable;
4650 0 : break;
4651 16 : case SQL_ATTR_CONCURRENCY:
4652 16 : size = sizeof(stmt->attr.concurrency);
4653 16 : src = &stmt->attr.concurrency;
4654 16 : break;
4655 16 : case SQL_ATTR_CURSOR_TYPE:
4656 16 : size = sizeof(stmt->attr.cursor_type);
4657 16 : src = &stmt->attr.cursor_type;
4658 16 : break;
4659 0 : case SQL_ATTR_ENABLE_AUTO_IPD:
4660 0 : size = sizeof(stmt->attr.enable_auto_ipd);
4661 0 : src = &stmt->attr.enable_auto_ipd;
4662 0 : break;
4663 0 : case SQL_ATTR_FETCH_BOOKMARK_PTR:
4664 0 : size = sizeof(stmt->attr.fetch_bookmark_ptr);
4665 0 : src = &stmt->attr.fetch_bookmark_ptr;
4666 0 : break;
4667 0 : case SQL_ATTR_KEYSET_SIZE:
4668 0 : size = sizeof(stmt->attr.keyset_size);
4669 0 : src = &stmt->attr.keyset_size;
4670 0 : break;
4671 0 : case SQL_ATTR_MAX_LENGTH:
4672 0 : size = sizeof(stmt->attr.max_length);
4673 0 : src = &stmt->attr.max_length;
4674 0 : break;
4675 0 : case SQL_ATTR_MAX_ROWS:
4676 0 : size = sizeof(stmt->attr.max_rows);
4677 0 : src = &stmt->attr.max_rows;
4678 0 : break;
4679 0 : case SQL_ATTR_METADATA_ID:
4680 0 : size = sizeof(stmt->attr.metadata_id);
4681 0 : src = &stmt->attr.metadata_id;
4682 0 : break;
4683 0 : case SQL_ATTR_NOSCAN:
4684 0 : size = sizeof(stmt->attr.noscan);
4685 0 : src = &stmt->attr.noscan;
4686 0 : break;
4687 0 : case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
4688 0 : size = sizeof(stmt->apd->header.sql_desc_bind_offset_ptr);
4689 0 : src = &stmt->apd->header.sql_desc_bind_offset_ptr;
4690 0 : break;
4691 0 : case SQL_ATTR_PARAM_BIND_TYPE:
4692 0 : size = sizeof(stmt->apd->header.sql_desc_bind_type);
4693 0 : src = &stmt->apd->header.sql_desc_bind_type;
4694 0 : break;
4695 0 : case SQL_ATTR_PARAM_OPERATION_PTR:
4696 0 : size = sizeof(stmt->apd->header.sql_desc_array_status_ptr);
4697 0 : src = &stmt->apd->header.sql_desc_array_status_ptr;
4698 0 : break;
4699 0 : case SQL_ATTR_PARAM_STATUS_PTR:
4700 0 : size = sizeof(stmt->ipd->header.sql_desc_array_status_ptr);
4701 0 : src = &stmt->ipd->header.sql_desc_array_status_ptr;
4702 0 : break;
4703 60 : case SQL_ATTR_PARAMS_PROCESSED_PTR:
4704 60 : size = sizeof(stmt->ipd->header.sql_desc_rows_processed_ptr);
4705 60 : src = &stmt->ipd->header.sql_desc_rows_processed_ptr;
4706 60 : break;
4707 0 : case SQL_ATTR_PARAMSET_SIZE:
4708 0 : size = sizeof(stmt->apd->header.sql_desc_array_size);
4709 0 : src = &stmt->apd->header.sql_desc_array_size;
4710 0 : break;
4711 32 : case SQL_ATTR_QUERY_TIMEOUT:
4712 32 : size = sizeof(stmt->attr.query_timeout);
4713 32 : src = (stmt->attr.query_timeout != DEFAULT_QUERY_TIMEOUT) ? &stmt->attr.query_timeout : &zero_ui;
4714 : break;
4715 0 : case SQL_ATTR_RETRIEVE_DATA:
4716 0 : size = sizeof(stmt->attr.retrieve_data);
4717 0 : src = &stmt->attr.retrieve_data;
4718 0 : break;
4719 0 : case SQL_ATTR_ROW_BIND_OFFSET_PTR:
4720 0 : size = sizeof(stmt->ard->header.sql_desc_bind_offset_ptr);
4721 0 : src = &stmt->ard->header.sql_desc_bind_offset_ptr;
4722 0 : break;
4723 : #if SQL_BIND_TYPE != SQL_ATTR_ROW_BIND_TYPE
4724 : case SQL_BIND_TYPE: /* although this is ODBC2 we must support this attribute */
4725 : #endif
4726 0 : case SQL_ATTR_ROW_BIND_TYPE:
4727 0 : size = sizeof(stmt->ard->header.sql_desc_bind_type);
4728 0 : src = &stmt->ard->header.sql_desc_bind_type;
4729 0 : break;
4730 24 : case SQL_ATTR_ROW_NUMBER:
4731 : /* TODO do not get info every time, cache somewhere */
4732 24 : if (stmt->cursor && odbc_lock_statement(stmt)) {
4733 : TDS_UINT row_number, row_count;
4734 :
4735 24 : tds_cursor_get_cursor_info(stmt->tds, stmt->cursor, &row_number, &row_count);
4736 24 : stmt->attr.row_number = row_number;
4737 : }
4738 24 : size = sizeof(stmt->attr.row_number);
4739 24 : src = &stmt->attr.row_number;
4740 24 : break;
4741 0 : case SQL_ATTR_ROW_OPERATION_PTR:
4742 0 : size = sizeof(stmt->ard->header.sql_desc_array_status_ptr);
4743 0 : src = &stmt->ard->header.sql_desc_array_status_ptr;
4744 0 : break;
4745 0 : case SQL_ATTR_ROW_STATUS_PTR:
4746 0 : size = sizeof(stmt->ird->header.sql_desc_array_status_ptr);
4747 0 : src = &stmt->ird->header.sql_desc_array_status_ptr;
4748 0 : break;
4749 50 : case SQL_ATTR_ROWS_FETCHED_PTR:
4750 50 : size = sizeof(stmt->ird->header.sql_desc_rows_processed_ptr);
4751 50 : src = &stmt->ird->header.sql_desc_rows_processed_ptr;
4752 50 : break;
4753 0 : case SQL_ATTR_ROW_ARRAY_SIZE:
4754 0 : size = sizeof(stmt->ard->header.sql_desc_array_size);
4755 0 : src = &stmt->ard->header.sql_desc_array_size;
4756 0 : break;
4757 0 : case SQL_ATTR_SIMULATE_CURSOR:
4758 0 : size = sizeof(stmt->attr.simulate_cursor);
4759 0 : src = &stmt->attr.simulate_cursor;
4760 0 : break;
4761 0 : case SQL_ATTR_USE_BOOKMARKS:
4762 0 : size = sizeof(stmt->attr.use_bookmarks);
4763 0 : src = &stmt->attr.use_bookmarks;
4764 0 : break;
4765 16 : case SQL_ATTR_CURSOR_SCROLLABLE:
4766 16 : size = sizeof(stmt->attr.cursor_scrollable);
4767 16 : src = &stmt->attr.cursor_scrollable;
4768 16 : break;
4769 16 : case SQL_ATTR_CURSOR_SENSITIVITY:
4770 16 : size = sizeof(stmt->attr.cursor_sensitivity);
4771 16 : src = &stmt->attr.cursor_sensitivity;
4772 16 : break;
4773 90 : case SQL_ATTR_IMP_ROW_DESC:
4774 90 : size = sizeof(stmt->ird);
4775 90 : src = &stmt->ird;
4776 90 : break;
4777 136 : case SQL_ATTR_IMP_PARAM_DESC:
4778 136 : size = sizeof(stmt->ipd);
4779 136 : src = &stmt->ipd;
4780 136 : break;
4781 10 : case SQL_ROWSET_SIZE: /* although this is ODBC2 we must support this attribute */
4782 10 : size = sizeof(stmt->sql_rowset_size);
4783 10 : src = &stmt->sql_rowset_size;
4784 10 : break;
4785 0 : case SQL_SOPT_SS_QUERYNOTIFICATION_TIMEOUT:
4786 0 : size = sizeof(stmt->attr.qn_timeout);
4787 0 : src = &stmt->attr.qn_timeout;
4788 0 : break;
4789 0 : case SQL_SOPT_SS_QUERYNOTIFICATION_MSGTEXT:
4790 : {
4791 0 : SQLRETURN rc = odbc_set_dstr_oct(stmt->dbc, Value, BufferLength, StringLength, &stmt->attr.qn_msgtext);
4792 0 : ODBC_EXIT(stmt, rc);
4793 : }
4794 0 : case SQL_SOPT_SS_QUERYNOTIFICATION_OPTIONS:
4795 : {
4796 0 : SQLRETURN rc = odbc_set_dstr_oct(stmt->dbc, Value, BufferLength, StringLength, &stmt->attr.qn_options);
4797 0 : ODBC_EXIT(stmt, rc);
4798 : }
4799 : /* TODO SQL_COLUMN_SEARCHABLE, although ODBC2 */
4800 0 : default:
4801 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
4802 0 : ODBC_EXIT_(stmt);
4803 : }
4804 :
4805 1140 : memcpy(Value, src, size);
4806 1140 : if (StringLength)
4807 978 : *StringLength = size;
4808 :
4809 1140 : ODBC_EXIT_(stmt);
4810 : }
4811 :
4812 : #if (ODBCVER >= 0x0300)
4813 : SQLRETURN ODBC_PUBLIC ODBC_API
4814 : SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
4815 : {
4816 570 : tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtAttr(%p, %d, %p, %d, %p)\n",
4817 : hstmt, (int)Attribute, Value, (int)BufferLength, StringLength);
4818 :
4819 570 : return odbc_SQLGetStmtAttr(hstmt, Attribute, Value, BufferLength, StringLength _wide0);
4820 : }
4821 :
4822 : #ifdef ENABLE_ODBC_WIDE
4823 : SQLRETURN ODBC_PUBLIC ODBC_API
4824 : SQLGetStmtAttrW(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
4825 : {
4826 570 : tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtAttr(%p, %d, %p, %d, %p)\n",
4827 : hstmt, (int)Attribute, Value, (int)BufferLength, StringLength);
4828 :
4829 570 : return odbc_SQLGetStmtAttr(hstmt, Attribute, Value, BufferLength, StringLength, 1);
4830 : }
4831 : #endif
4832 : #endif
4833 :
4834 : SQLRETURN ODBC_PUBLIC ODBC_API
4835 : SQLGetStmtOption(SQLHSTMT hstmt, SQLUSMALLINT fOption, SQLPOINTER pvParam)
4836 : {
4837 0 : tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtOption(%p, %d, %p)\n",
4838 : hstmt, fOption, pvParam);
4839 :
4840 0 : return odbc_SQLGetStmtAttr(hstmt, (SQLINTEGER) fOption, pvParam, SQL_MAX_OPTION_STRING_LENGTH, NULL _wide0);
4841 : }
4842 :
4843 : SQLRETURN ODBC_PUBLIC ODBC_API
4844 : SQLNumResultCols(SQLHSTMT hstmt, SQLSMALLINT FAR * pccol)
4845 : {
4846 838 : ODBC_ENTER_HSTMT;
4847 :
4848 838 : tdsdump_log(TDS_DBG_FUNC, "SQLNumResultCols(%p, %p)\n",
4849 : hstmt, pccol);
4850 :
4851 : /*
4852 : * 3/15/2001 bsb - DBD::ODBC calls SQLNumResultCols on non-result
4853 : * generating queries such as 'drop table'
4854 : */
4855 : #if 0
4856 : if (stmt->row_status == NOT_IN_ROW) {
4857 : odbc_errs_add(&stmt->errs, "24000", NULL);
4858 : ODBC_EXIT_(stmt);
4859 : }
4860 : #endif
4861 838 : IRD_UPDATE(stmt->ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
4862 814 : *pccol = stmt->ird->header.sql_desc_count;
4863 814 : ODBC_EXIT_(stmt);
4864 : }
4865 :
4866 4147 : ODBC_FUNC(SQLPrepare, (P(SQLHSTMT,hstmt), PCHARIN(SqlStr,SQLINTEGER) WIDE))
4867 : {
4868 : SQLRETURN retcode;
4869 :
4870 4147 : ODBC_ENTER_HSTMT;
4871 :
4872 : /* try to free dynamic associated */
4873 4147 : retcode = odbc_free_dynamic(stmt);
4874 4147 : if (retcode != SQL_SUCCESS)
4875 0 : ODBC_EXIT(stmt, retcode);
4876 :
4877 4147 : if (SQL_SUCCESS != odbc_set_stmt_query(stmt, szSqlStr, cbSqlStr _wide))
4878 0 : ODBC_EXIT(stmt, SQL_ERROR);
4879 4147 : stmt->is_prepared_query = 1;
4880 :
4881 : /* count parameters */
4882 8294 : stmt->param_count = tds_count_placeholders(tds_dstr_cstr(&stmt->query));
4883 :
4884 : /* reset IPD and APD */
4885 4147 : if (!stmt->params_set) {
4886 2229 : desc_alloc_records(stmt->ipd, 0);
4887 2229 : desc_alloc_records(stmt->apd, 0);
4888 : }
4889 :
4890 : /* trasform to native (one time, not for every SQLExecute) */
4891 4147 : if (SQL_SUCCESS != prepare_call(stmt))
4892 0 : ODBC_EXIT(stmt, SQL_ERROR);
4893 :
4894 : /* TODO needed ?? */
4895 4147 : tds_release_dynamic(&stmt->dyn);
4896 :
4897 : /* try to prepare query */
4898 : /* TODO support getting info for RPC */
4899 4147 : if (!stmt->prepared_query_is_rpc
4900 3499 : && (stmt->attr.cursor_type == SQL_CURSOR_FORWARD_ONLY && stmt->attr.concurrency == SQL_CONCUR_READ_ONLY)) {
4901 :
4902 2191 : tds_free_param_results(stmt->params);
4903 2191 : stmt->params = NULL;
4904 2191 : stmt->param_num = 0;
4905 2191 : stmt->need_reprepare = 0;
4906 : /*
4907 : * using TDS7+ we need parameters to prepare a query so try
4908 : * to get them
4909 : * TDS5 do not need parameters type and we have always to
4910 : * prepare sepatately so this is not an issue
4911 : */
4912 2191 : if (IS_TDS7_PLUS(stmt->dbc->tds_socket->conn)) {
4913 1885 : stmt->need_reprepare = 1;
4914 1885 : ODBC_EXIT_(stmt);
4915 : }
4916 :
4917 306 : tdsdump_log(TDS_DBG_INFO1, "Creating prepared statement\n");
4918 306 : if (odbc_lock_statement(stmt))
4919 306 : odbc_prepare(stmt);
4920 : }
4921 :
4922 2262 : ODBC_EXIT_(stmt);
4923 : }
4924 :
4925 : /* TDS_NO_COUNT must be -1 for SQLRowCount to return -1 when there is no rowcount */
4926 : #if TDS_NO_COUNT != -1
4927 : # error TDS_NO_COUNT != -1
4928 : #endif
4929 :
4930 : SQLRETURN
4931 696 : odbc_SQLRowCount(SQLHSTMT hstmt, SQLLEN FAR * pcrow)
4932 : {
4933 696 : ODBC_ENTER_HSTMT;
4934 :
4935 696 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLRowCount(%p, %p), %ld rows \n", hstmt, pcrow, (long)stmt->row_count);
4936 :
4937 696 : *pcrow = stmt->row_count;
4938 :
4939 696 : ODBC_EXIT_(stmt);
4940 : }
4941 :
4942 : SQLRETURN ODBC_PUBLIC ODBC_API
4943 : SQLRowCount(SQLHSTMT hstmt, SQLLEN FAR * pcrow)
4944 : {
4945 696 : SQLRETURN rc = odbc_SQLRowCount(hstmt, pcrow);
4946 696 : tdsdump_log(TDS_DBG_INFO1, "SQLRowCount returns %d, row count %ld\n", rc, (long int) *pcrow);
4947 696 : return rc;
4948 : }
4949 :
4950 104 : ODBC_FUNC(SQLSetCursorName, (P(SQLHSTMT,hstmt), PCHARIN(Cursor,SQLSMALLINT) WIDE))
4951 : {
4952 104 : ODBC_ENTER_HSTMT;
4953 :
4954 : /* cursor already present, we cannot set name */
4955 104 : if (stmt->cursor) {
4956 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
4957 0 : ODBC_EXIT_(stmt);
4958 : }
4959 :
4960 104 : if (!odbc_dstr_copy(stmt->dbc, &stmt->cursor_name, cbCursor, szCursor)) {
4961 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
4962 0 : ODBC_EXIT_(stmt);
4963 : }
4964 104 : ODBC_EXIT_(stmt);
4965 : }
4966 :
4967 0 : ODBC_FUNC(SQLGetCursorName, (P(SQLHSTMT,hstmt), PCHAROUT(Cursor,SQLSMALLINT) WIDE))
4968 : {
4969 : SQLRETURN rc;
4970 :
4971 0 : ODBC_ENTER_HSTMT;
4972 :
4973 0 : if ((rc = odbc_set_dstr(stmt->dbc, szCursor, cbCursorMax, pcbCursor, &stmt->cursor_name)))
4974 0 : odbc_errs_add(&stmt->errs, "01004", NULL);
4975 :
4976 0 : ODBC_EXIT(stmt, rc);
4977 : }
4978 :
4979 : /*
4980 : * spinellia@acm.org : copied shamelessly from change_database
4981 : * transaction support
4982 : * 1 = commit, 0 = rollback
4983 : */
4984 : static SQLRETURN
4985 760 : change_transaction(TDS_DBC * dbc, int state)
4986 : {
4987 760 : TDSSOCKET *tds = dbc->tds_socket;
4988 : int cont;
4989 : TDSRET ret;
4990 :
4991 760 : tdsdump_log(TDS_DBG_INFO1, "change_transaction(0x%p,%d)\n", dbc, state);
4992 760 : tds_mutex_check_owned(&dbc->mtx);
4993 :
4994 760 : if (dbc->attr.autocommit == SQL_AUTOCOMMIT_ON)
4995 : return SQL_SUCCESS;
4996 740 : cont = 1;
4997 :
4998 : /* if pending drop all recordset, don't issue cancel */
4999 740 : if (tds->state == TDS_PENDING && dbc->current_statement != NULL) {
5000 : /* TODO what happen on multiple errors ?? discard all ?? */
5001 20 : if (TDS_FAILED(tds_process_simple_query(tds)))
5002 : return SQL_ERROR;
5003 : }
5004 :
5005 : /* TODO better idle check, not thread safe */
5006 740 : if (tds->state == TDS_IDLE)
5007 740 : tds->query_timeout = dbc->default_query_timeout;
5008 :
5009 : /* reset statement so errors will be reported on connection.
5010 : * Note that we own the connection lock */
5011 740 : if (dbc->current_statement) {
5012 498 : dbc->current_statement->tds = NULL;
5013 498 : dbc->current_statement = NULL;
5014 : }
5015 740 : tds_set_parent(tds, dbc);
5016 :
5017 740 : if (state)
5018 282 : ret = tds_submit_commit(tds, cont);
5019 : else
5020 458 : ret = tds_submit_rollback(tds, cont);
5021 :
5022 740 : if (TDS_FAILED(ret)) {
5023 10 : odbc_errs_add(&dbc->errs, "HY000", "Could not perform COMMIT or ROLLBACK");
5024 10 : return SQL_ERROR;
5025 : }
5026 :
5027 730 : if (TDS_FAILED(tds_process_simple_query(tds)))
5028 : return SQL_ERROR;
5029 :
5030 : /* TODO some query can collect errors so perhaps it's better to return SUCCES_WITH_INFO in such case... */
5031 730 : return SQL_SUCCESS;
5032 : }
5033 :
5034 : static SQLRETURN
5035 760 : odbc_SQLTransact(SQLHENV henv, SQLHDBC hdbc, SQLUSMALLINT fType)
5036 : {
5037 760 : int op = (fType == SQL_COMMIT ? 1 : 0);
5038 :
5039 : /* I may live without a HENV */
5040 : /* CHECK_HENV; */
5041 : /* ..but not without a HDBC! */
5042 760 : ODBC_ENTER_HDBC;
5043 :
5044 760 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLTransact(%p, %p, %d)\n",
5045 : henv, hdbc, fType);
5046 :
5047 760 : ODBC_EXIT(dbc, change_transaction(dbc, op));
5048 : }
5049 :
5050 : SQLRETURN ODBC_PUBLIC ODBC_API
5051 : SQLTransact(SQLHENV henv, SQLHDBC hdbc, SQLUSMALLINT fType)
5052 : {
5053 0 : tdsdump_log(TDS_DBG_FUNC, "SQLTransact(%p, %p, %d)\n", henv, hdbc, fType);
5054 :
5055 0 : return odbc_SQLTransact(henv, hdbc, fType);
5056 : }
5057 :
5058 : #if ODBCVER >= 0x300
5059 : SQLRETURN ODBC_PUBLIC ODBC_API
5060 : SQLEndTran(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT completionType)
5061 : {
5062 : /*
5063 : * Do not call the exported SQLTransact(),
5064 : * because we may wind up calling a function with the same name implemented by the DM.
5065 : */
5066 760 : tdsdump_log(TDS_DBG_FUNC, "SQLEndTran(%d, %p, %d)\n", handleType, handle, completionType);
5067 :
5068 760 : switch (handleType) {
5069 0 : case SQL_HANDLE_ENV:
5070 0 : return odbc_SQLTransact(handle, NULL, completionType);
5071 760 : case SQL_HANDLE_DBC:
5072 760 : return odbc_SQLTransact(NULL, handle, completionType);
5073 : }
5074 : return SQL_ERROR;
5075 : }
5076 : #endif
5077 :
5078 : /* end of transaction support */
5079 :
5080 : SQLRETURN ODBC_PUBLIC ODBC_API
5081 : SQLSetParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLULEN cbParamDef,
5082 : SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN FAR * pcbValue)
5083 : {
5084 0 : tdsdump_log(TDS_DBG_FUNC, "SQLSetParam(%p, %d, %d, %d, %u, %d, %p, %p)\n",
5085 : hstmt, ipar, fCType, fSqlType, (unsigned)cbParamDef, ibScale, rgbValue, pcbValue);
5086 :
5087 0 : return odbc_SQLBindParameter(hstmt, ipar, SQL_PARAM_INPUT_OUTPUT, fCType, fSqlType, cbParamDef, ibScale, rgbValue,
5088 : SQL_SETPARAM_VALUE_MAX, pcbValue);
5089 : }
5090 :
5091 : /**
5092 : * SQLColumns
5093 : *
5094 : * Return column information for a table or view. This is
5095 : * mapped to a call to sp_columns which - lucky for us - returns
5096 : * the exact result set we need.
5097 : *
5098 : * exec sp_columns [ @table_name = ] object
5099 : * [ , [ @table_owner = ] owner ]
5100 : * [ , [ @table_qualifier = ] qualifier ]
5101 : * [ , [ @column_name = ] column ]
5102 : * [ , [ @ODBCVer = ] ODBCVer ]
5103 : *
5104 : */
5105 40 : ODBC_FUNC(SQLColumns, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT), /* object_qualifier */
5106 : PCHARIN(SchemaName,SQLSMALLINT), /* object_owner */
5107 : PCHARIN(TableName,SQLSMALLINT), /* object_name */
5108 : PCHARIN(ColumnName,SQLSMALLINT) /* column_name */
5109 : WIDE))
5110 : {
5111 : int retcode;
5112 40 : const char *proc = "sp_columns";
5113 :
5114 40 : ODBC_ENTER_HSTMT;
5115 :
5116 40 : if (odbc_get_string_size(cbCatalogName, szCatalogName _wide))
5117 20 : proc = "..sp_columns";
5118 :
5119 40 : retcode =
5120 40 : odbc_stat_execute(stmt _wide, proc, TDS_IS_MSSQL(stmt->dbc->tds_socket) ? 5 : 4,
5121 : "P@table_name", szTableName, cbTableName, "P@table_owner", szSchemaName,
5122 : cbSchemaName, "O@table_qualifier", szCatalogName, cbCatalogName, "P@column_name", szColumnName,
5123 : cbColumnName, "V@ODBCVer", (char*) NULL, 0);
5124 40 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
5125 20 : odbc_col_setname(stmt, 1, "TABLE_CAT");
5126 20 : odbc_col_setname(stmt, 2, "TABLE_SCHEM");
5127 20 : odbc_col_setname(stmt, 7, "COLUMN_SIZE");
5128 20 : odbc_col_setname(stmt, 8, "BUFFER_LENGTH");
5129 20 : odbc_col_setname(stmt, 9, "DECIMAL_DIGITS");
5130 20 : odbc_col_setname(stmt, 10, "NUM_PREC_RADIX");
5131 20 : if (TDS_IS_SYBASE(stmt->dbc->tds_socket))
5132 4 : stmt->special_row = ODBC_SPECIAL_COLUMNS;
5133 : }
5134 40 : ODBC_EXIT_(stmt);
5135 : }
5136 :
5137 78 : ODBC_FUNC(SQLGetConnectAttr, (P(SQLHDBC,hdbc), P(SQLINTEGER,Attribute), P(SQLPOINTER,Value), P(SQLINTEGER,BufferLength),
5138 : P(SQLINTEGER *,StringLength) WIDE))
5139 : {
5140 78 : const char *p = NULL;
5141 :
5142 78 : ODBC_ENTER_HDBC;
5143 :
5144 78 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLGetConnectAttr(%p, %d, %p, %d, %p)\n",
5145 : hdbc, (int)Attribute, Value, (int)BufferLength, StringLength);
5146 :
5147 78 : switch (Attribute) {
5148 0 : case SQL_ATTR_AUTOCOMMIT:
5149 0 : *((SQLUINTEGER *) Value) = dbc->attr.autocommit;
5150 : break;
5151 : #if defined(SQL_ATTR_CONNECTION_DEAD) && defined(SQL_CD_TRUE)
5152 0 : case SQL_ATTR_CONNECTION_DEAD:
5153 0 : *((SQLUINTEGER *) Value) = IS_TDSDEAD(dbc->tds_socket) ? SQL_CD_TRUE : SQL_CD_FALSE;
5154 : break;
5155 : #endif
5156 0 : case SQL_ATTR_CONNECTION_TIMEOUT:
5157 0 : *((SQLUINTEGER *) Value) = dbc->attr.connection_timeout;
5158 : break;
5159 0 : case SQL_ATTR_ACCESS_MODE:
5160 0 : *((SQLUINTEGER *) Value) = dbc->attr.access_mode;
5161 : break;
5162 68 : case SQL_ATTR_CURRENT_CATALOG:
5163 136 : p = tds_dstr_cstr(&dbc->attr.current_catalog);
5164 68 : break;
5165 0 : case SQL_ATTR_LOGIN_TIMEOUT:
5166 0 : *((SQLUINTEGER *) Value) = dbc->attr.login_timeout;
5167 : break;
5168 0 : case SQL_ATTR_ODBC_CURSORS:
5169 0 : *((SQLUINTEGER *) Value) = dbc->attr.odbc_cursors;
5170 : break;
5171 0 : case SQL_ATTR_PACKET_SIZE:
5172 0 : *((SQLUINTEGER *) Value) = dbc->attr.packet_size;
5173 : break;
5174 0 : case SQL_ATTR_QUIET_MODE:
5175 0 : *((SQLHWND *) Value) = dbc->attr.quite_mode;
5176 : break;
5177 : #ifdef TDS_NO_DM
5178 0 : case SQL_ATTR_TRACE:
5179 0 : *((SQLUINTEGER *) Value) = dbc->attr.trace;
5180 : break;
5181 0 : case SQL_ATTR_TRACEFILE:
5182 0 : p = tds_dstr_cstr(&dbc->attr.tracefile);
5183 0 : break;
5184 : #endif
5185 0 : case SQL_ATTR_TXN_ISOLATION:
5186 0 : *((SQLUINTEGER *) Value) = dbc->attr.txn_isolation;
5187 : break;
5188 10 : case SQL_COPT_SS_MARS_ENABLED:
5189 10 : *((SQLUINTEGER *) Value) = dbc->attr.mars_enabled;
5190 : break;
5191 0 : case SQL_ATTR_TRANSLATE_LIB:
5192 : case SQL_ATTR_TRANSLATE_OPTION:
5193 0 : odbc_errs_add(&dbc->errs, "HYC00", NULL);
5194 : break;
5195 0 : case SQL_COPT_SS_BCP:
5196 0 : *((SQLUINTEGER *) Value) = dbc->attr.bulk_enabled;
5197 : break;
5198 0 : default:
5199 0 : odbc_errs_add(&dbc->errs, "HY092", NULL);
5200 : break;
5201 : }
5202 :
5203 68 : if (p) {
5204 68 : SQLRETURN rc = odbc_set_string_oct(dbc, Value, BufferLength, StringLength, p, -1);
5205 68 : ODBC_EXIT(dbc, rc);
5206 : }
5207 10 : ODBC_EXIT_(dbc);
5208 : }
5209 :
5210 : SQLRETURN ODBC_PUBLIC ODBC_API
5211 : SQLGetConnectOption(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLPOINTER pvParam)
5212 : {
5213 0 : tdsdump_log(TDS_DBG_FUNC, "SQLGetConnectOption(%p, %u, %p)\n", hdbc, fOption, pvParam);
5214 :
5215 0 : return odbc_SQLGetConnectAttr(hdbc, (SQLINTEGER) fOption, pvParam, SQL_MAX_OPTION_STRING_LENGTH, NULL _wide0);
5216 : }
5217 :
5218 : #ifdef ENABLE_ODBC_WIDE
5219 : SQLRETURN ODBC_PUBLIC ODBC_API
5220 : SQLGetConnectOptionW(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLPOINTER pvParam)
5221 : {
5222 0 : tdsdump_log(TDS_DBG_FUNC, "SQLGetConnectOptionW(%p, %u, %p)\n", hdbc, fOption, pvParam);
5223 :
5224 0 : return odbc_SQLGetConnectAttr(hdbc, (SQLINTEGER) fOption, pvParam, SQL_MAX_OPTION_STRING_LENGTH, NULL, 1);
5225 : }
5226 : #endif
5227 :
5228 : SQLRETURN ODBC_PUBLIC ODBC_API
5229 : SQLGetData(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
5230 : {
5231 : /* TODO cursors fetch row if needed ?? */
5232 : TDSCOLUMN *colinfo;
5233 : TDSRESULTINFO *resinfo;
5234 : SQLLEN dummy_cb;
5235 :
5236 10532 : ODBC_ENTER_HSTMT;
5237 :
5238 10532 : tdsdump_log(TDS_DBG_FUNC, "SQLGetData(%p, %u, %d, %p, %d, %p)\n",
5239 : hstmt, icol, fCType, rgbValue, (int)cbValueMax, pcbValue);
5240 :
5241 10532 : if (cbValueMax < 0) {
5242 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
5243 0 : ODBC_EXIT_(stmt);
5244 : }
5245 :
5246 : /* read data from TDS only if current statement */
5247 10532 : if ((stmt->cursor == NULL && !stmt->tds)
5248 10460 : || stmt->row_status == PRE_NORMAL_ROW
5249 10128 : || stmt->row_status == NOT_IN_ROW)
5250 : {
5251 404 : odbc_errs_add(&stmt->errs, "24000", NULL);
5252 404 : ODBC_EXIT_(stmt);
5253 : }
5254 :
5255 10128 : IRD_CHECK;
5256 :
5257 10128 : if (!pcbValue)
5258 376 : pcbValue = &dummy_cb;
5259 :
5260 10128 : resinfo = stmt->cursor ? stmt->cursor->res_info : stmt->tds->current_results;
5261 10128 : if (!resinfo) {
5262 0 : odbc_errs_add(&stmt->errs, "HY010", NULL);
5263 0 : ODBC_EXIT_(stmt);
5264 : }
5265 10128 : if (icol <= 0 || icol > resinfo->num_cols) {
5266 0 : odbc_errs_add(&stmt->errs, "07009", "Column out of range");
5267 0 : ODBC_EXIT_(stmt);
5268 : }
5269 10128 : colinfo = resinfo->columns[icol - 1];
5270 :
5271 10128 : if (colinfo->column_cur_size < 0) {
5272 : /* TODO check what should happen if pcbValue was NULL */
5273 348 : *pcbValue = SQL_NULL_DATA;
5274 : } else {
5275 9780 : if (colinfo->column_text_sqlgetdatapos > 0
5276 2238 : && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size
5277 522 : && colinfo->column_iconv_left == 0)
5278 : /* TODO check if SQL_SUCCESS instead !! */
5279 460 : ODBC_EXIT(stmt, SQL_NO_DATA);
5280 :
5281 9320 : if (!is_variable_type(colinfo->column_type)) {
5282 580 : colinfo->column_text_sqlgetdatapos = 0;
5283 580 : colinfo->column_iconv_left = 0;
5284 : }
5285 :
5286 9320 : if (fCType == SQL_C_DEFAULT)
5287 0 : fCType = odbc_sql_to_c_type_default(stmt->ird->records[icol - 1].sql_desc_concise_type);
5288 9320 : if (fCType == SQL_ARD_TYPE) {
5289 10 : if (icol > stmt->ard->header.sql_desc_count) {
5290 10 : odbc_errs_add(&stmt->errs, "07009", NULL);
5291 10 : ODBC_EXIT_(stmt);
5292 : }
5293 0 : fCType = stmt->ard->records[icol - 1].sql_desc_concise_type;
5294 : }
5295 9310 : assert(fCType);
5296 :
5297 9310 : *pcbValue = odbc_tds2sql_col(stmt, colinfo, fCType, (TDS_CHAR *) rgbValue, cbValueMax, NULL);
5298 9310 : if (*pcbValue == SQL_NULL_DATA)
5299 40 : ODBC_EXIT(stmt, SQL_ERROR);
5300 :
5301 9270 : if (is_variable_type(colinfo->column_type)
5302 8690 : && (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR || fCType == SQL_C_BINARY)) {
5303 : /* avoid infinite SQL_SUCCESS on empty strings */
5304 8690 : if (colinfo->column_text_sqlgetdatapos == 0 && cbValueMax > 0)
5305 44 : ++colinfo->column_text_sqlgetdatapos;
5306 :
5307 8690 : if (colinfo->column_text_sqlgetdatapos < colinfo->column_cur_size || colinfo->column_iconv_left != 0) {
5308 : /* not all read ?? */
5309 1850 : odbc_errs_add(&stmt->errs, "01004", "String data, right truncated");
5310 1850 : ODBC_EXIT_(stmt);
5311 : }
5312 : } else {
5313 580 : int nSybType = tds_get_conversion_type(colinfo->on_server.column_type, colinfo->on_server.column_size);
5314 580 : colinfo->column_text_sqlgetdatapos = colinfo->column_cur_size;
5315 580 : if (is_fixed_type(nSybType) && (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR || fCType == SQL_C_BINARY)
5316 430 : && cbValueMax < *pcbValue) {
5317 18 : odbc_errs_add(&stmt->errs, "22003", NULL);
5318 18 : ODBC_EXIT_(stmt);
5319 : }
5320 : }
5321 : }
5322 7750 : ODBC_EXIT_(stmt);
5323 : }
5324 :
5325 : SQLRETURN ODBC_PUBLIC ODBC_API
5326 : SQLGetFunctions(SQLHDBC hdbc, SQLUSMALLINT fFunction, SQLUSMALLINT FAR * pfExists)
5327 : {
5328 : int i;
5329 :
5330 0 : ODBC_ENTER_HDBC;
5331 :
5332 0 : tdsdump_log(TDS_DBG_FUNC, "SQLGetFunctions: fFunction is %d\n", fFunction);
5333 0 : switch (fFunction) {
5334 : #if (ODBCVER >= 0x0300)
5335 : case SQL_API_ODBC3_ALL_FUNCTIONS:
5336 0 : for (i = 0; i < SQL_API_ODBC3_ALL_FUNCTIONS_SIZE; ++i) {
5337 0 : pfExists[i] = 0;
5338 : }
5339 :
5340 : /*
5341 : * every api available are contained in a macro
5342 : * all these macro begin with API followed by 2 letter
5343 : * first letter mean pre ODBC 3 (_) or ODBC 3 (3)
5344 : * second letter mean implemented (X) or unimplemented (_)
5345 : * You should copy these macro 3 times... not very good
5346 : * but works. Perhaps best method is build the bit array statically
5347 : * and then use it but I don't know how to build it...
5348 : */
5349 : #undef ODBC_ALL_API
5350 : #undef ODBC_COLATTRIBUTE
5351 :
5352 : #if SQL_API_SQLCOLATTRIBUTE != SQL_API_SQLCOLATTRIBUTES
5353 : #define ODBC_COLATTRIBUTE(s) s
5354 : #else
5355 : #define ODBC_COLATTRIBUTE(s)
5356 : #endif
5357 :
5358 : #define ODBC_ALL_API \
5359 : API_X(SQL_API_SQLALLOCCONNECT)\
5360 : API_X(SQL_API_SQLALLOCENV)\
5361 : API3X(SQL_API_SQLALLOCHANDLE)\
5362 : API_X(SQL_API_SQLALLOCSTMT)\
5363 : API_X(SQL_API_SQLBINDCOL)\
5364 : API_X(SQL_API_SQLBINDPARAM)\
5365 : API_X(SQL_API_SQLBINDPARAMETER)\
5366 : API__(SQL_API_SQLBROWSECONNECT)\
5367 : API3_(SQL_API_SQLBULKOPERATIONS)\
5368 : API_X(SQL_API_SQLCANCEL)\
5369 : API3X(SQL_API_SQLCLOSECURSOR)\
5370 : ODBC_COLATTRIBUTE(API3X(SQL_API_SQLCOLATTRIBUTE))\
5371 : API_X(SQL_API_SQLCOLATTRIBUTES)\
5372 : API_X(SQL_API_SQLCOLUMNPRIVILEGES)\
5373 : API_X(SQL_API_SQLCOLUMNS)\
5374 : API_X(SQL_API_SQLCONNECT)\
5375 : API3X(SQL_API_SQLCOPYDESC)\
5376 : API_X(SQL_API_SQLDESCRIBECOL)\
5377 : API_X(SQL_API_SQLDESCRIBEPARAM)\
5378 : API_X(SQL_API_SQLDISCONNECT)\
5379 : API_X(SQL_API_SQLDRIVERCONNECT)\
5380 : API3X(SQL_API_SQLENDTRAN)\
5381 : API_X(SQL_API_SQLERROR)\
5382 : API_X(SQL_API_SQLEXECDIRECT)\
5383 : API_X(SQL_API_SQLEXECUTE)\
5384 : API_X(SQL_API_SQLEXTENDEDFETCH)\
5385 : API_X(SQL_API_SQLFETCH)\
5386 : API3X(SQL_API_SQLFETCHSCROLL)\
5387 : API_X(SQL_API_SQLFOREIGNKEYS)\
5388 : API_X(SQL_API_SQLFREECONNECT)\
5389 : API_X(SQL_API_SQLFREEENV)\
5390 : API3X(SQL_API_SQLFREEHANDLE)\
5391 : API_X(SQL_API_SQLFREESTMT)\
5392 : API3X(SQL_API_SQLGETCONNECTATTR)\
5393 : API_X(SQL_API_SQLGETCONNECTOPTION)\
5394 : API_X(SQL_API_SQLGETCURSORNAME)\
5395 : API_X(SQL_API_SQLGETDATA)\
5396 : API3X(SQL_API_SQLGETDESCFIELD)\
5397 : API3X(SQL_API_SQLGETDESCREC)\
5398 : API3X(SQL_API_SQLGETDIAGFIELD)\
5399 : API3X(SQL_API_SQLGETDIAGREC)\
5400 : API3X(SQL_API_SQLGETENVATTR)\
5401 : API_X(SQL_API_SQLGETFUNCTIONS)\
5402 : API_X(SQL_API_SQLGETINFO)\
5403 : API3X(SQL_API_SQLGETSTMTATTR)\
5404 : API_X(SQL_API_SQLGETSTMTOPTION)\
5405 : API_X(SQL_API_SQLGETTYPEINFO)\
5406 : API_X(SQL_API_SQLMORERESULTS)\
5407 : API_X(SQL_API_SQLNATIVESQL)\
5408 : API_X(SQL_API_SQLNUMPARAMS)\
5409 : API_X(SQL_API_SQLNUMRESULTCOLS)\
5410 : API_X(SQL_API_SQLPARAMDATA)\
5411 : API_X(SQL_API_SQLPARAMOPTIONS)\
5412 : API_X(SQL_API_SQLPREPARE)\
5413 : API_X(SQL_API_SQLPRIMARYKEYS)\
5414 : API_X(SQL_API_SQLPROCEDURECOLUMNS)\
5415 : API_X(SQL_API_SQLPROCEDURES)\
5416 : API_X(SQL_API_SQLPUTDATA)\
5417 : API_X(SQL_API_SQLROWCOUNT)\
5418 : API3X(SQL_API_SQLSETCONNECTATTR)\
5419 : API_X(SQL_API_SQLSETCONNECTOPTION)\
5420 : API_X(SQL_API_SQLSETCURSORNAME)\
5421 : API3X(SQL_API_SQLSETDESCFIELD)\
5422 : API3X(SQL_API_SQLSETDESCREC)\
5423 : API3X(SQL_API_SQLSETENVATTR)\
5424 : API_X(SQL_API_SQLSETPARAM)\
5425 : API_X(SQL_API_SQLSETPOS)\
5426 : API_X(SQL_API_SQLSETSCROLLOPTIONS)\
5427 : API3X(SQL_API_SQLSETSTMTATTR)\
5428 : API_X(SQL_API_SQLSETSTMTOPTION)\
5429 : API_X(SQL_API_SQLSPECIALCOLUMNS)\
5430 : API_X(SQL_API_SQLSTATISTICS)\
5431 : API_X(SQL_API_SQLTABLEPRIVILEGES)\
5432 : API_X(SQL_API_SQLTABLES)\
5433 : API_X(SQL_API_SQLTRANSACT)
5434 :
5435 : #define API_X(n) if (n >= 0 && n < (16*SQL_API_ODBC3_ALL_FUNCTIONS_SIZE)) pfExists[n/16] |= (1 << n%16);
5436 : #define API__(n)
5437 : #define API3X(n) if (n >= 0 && n < (16*SQL_API_ODBC3_ALL_FUNCTIONS_SIZE)) pfExists[n/16] |= (1 << n%16);
5438 : #define API3_(n)
5439 0 : ODBC_ALL_API
5440 : #undef API_X
5441 : #undef API__
5442 : #undef API3X
5443 : #undef API3_
5444 : break;
5445 : #endif
5446 :
5447 0 : case SQL_API_ALL_FUNCTIONS:
5448 0 : tdsdump_log(TDS_DBG_FUNC, "SQLGetFunctions: " "fFunction is SQL_API_ALL_FUNCTIONS\n");
5449 0 : for (i = 0; i < 100; ++i) {
5450 0 : pfExists[i] = SQL_FALSE;
5451 : }
5452 :
5453 : #define API_X(n) if (n >= 0 && n < 100) pfExists[n] = SQL_TRUE;
5454 : #define API__(n)
5455 : #define API3X(n)
5456 : #define API3_(n)
5457 0 : ODBC_ALL_API
5458 : #undef API_X
5459 : #undef API__
5460 : #undef API3X
5461 : #undef API3_
5462 : break;
5463 : #define API_X(n) case n:
5464 : #define API__(n)
5465 : #if (ODBCVER >= 0x300)
5466 : #define API3X(n) case n:
5467 : #else
5468 : #define API3X(n)
5469 : #endif
5470 : #define API3_(n)
5471 0 : ODBC_ALL_API
5472 : #undef API_X
5473 : #undef API__
5474 : #undef API3X
5475 : #undef API3_
5476 0 : *pfExists = SQL_TRUE;
5477 0 : break;
5478 0 : default:
5479 0 : *pfExists = SQL_FALSE;
5480 0 : break;
5481 : }
5482 0 : ODBC_EXIT(dbc, SQL_SUCCESS);
5483 : #undef ODBC_ALL_API
5484 : }
5485 :
5486 :
5487 : static SQLRETURN
5488 974 : odbc_SQLGetInfo(TDS_DBC * dbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax,
5489 : SQLSMALLINT FAR * pcbInfoValue _WIDE)
5490 : {
5491 974 : const char *p = NULL;
5492 : char buf[32];
5493 : TDSSOCKET *tds;
5494 974 : int is_ms = -1;
5495 974 : unsigned int smajor = 6;
5496 974 : SQLUINTEGER mssql7plus_mask = 0;
5497 974 : int out_len = -1;
5498 :
5499 974 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLGetInfo(%p, %u, %p, %d, %p)\n",
5500 : dbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue);
5501 :
5502 : #define SIVAL out_len = sizeof(SQLSMALLINT), *((SQLSMALLINT *) rgbInfoValue)
5503 : #define USIVAL out_len = sizeof(SQLUSMALLINT), *((SQLUSMALLINT *) rgbInfoValue)
5504 : #define IVAL out_len = sizeof(SQLINTEGER), *((SQLINTEGER *) rgbInfoValue)
5505 : #define UIVAL out_len = sizeof(SQLUINTEGER), *((SQLUINTEGER *) rgbInfoValue)
5506 : #define ULVAL out_len = sizeof(SQLULEN), *((SQLULEN *) rgbInfoValue)
5507 :
5508 974 : if ((tds = dbc->tds_socket) != NULL) {
5509 934 : is_ms = TDS_IS_MSSQL(tds);
5510 934 : smajor = (tds->conn->product_version >> 24) & 0x7F;
5511 934 : if (is_ms && smajor >= 7)
5512 786 : mssql7plus_mask = ~((SQLUINTEGER) 0);
5513 : }
5514 :
5515 974 : switch (fInfoType) {
5516 : case SQL_ACCESSIBLE_PROCEDURES:
5517 : case SQL_ACCESSIBLE_TABLES:
5518 : p = "Y";
5519 : break;
5520 : /* SQL_ACTIVE_CONNECTIONS renamed to SQL_MAX_DRIVER_CONNECTIONS */
5521 : #if (ODBCVER >= 0x0300)
5522 0 : case SQL_ACTIVE_ENVIRONMENTS:
5523 0 : UIVAL = 0;
5524 0 : break;
5525 : #endif /* ODBCVER >= 0x0300 */
5526 : #if (ODBCVER >= 0x0300)
5527 0 : case SQL_AGGREGATE_FUNCTIONS:
5528 0 : UIVAL = SQL_AF_ALL;
5529 0 : break;
5530 0 : case SQL_ALTER_DOMAIN:
5531 0 : UIVAL = 0;
5532 0 : break;
5533 : #endif /* ODBCVER >= 0x0300 */
5534 0 : case SQL_ALTER_TABLE:
5535 0 : UIVAL = SQL_AT_ADD_COLUMN | SQL_AT_ADD_COLUMN_DEFAULT | SQL_AT_ADD_COLUMN_SINGLE | SQL_AT_ADD_CONSTRAINT |
5536 : SQL_AT_ADD_TABLE_CONSTRAINT | SQL_AT_CONSTRAINT_NAME_DEFINITION | SQL_AT_DROP_COLUMN_RESTRICT;
5537 0 : break;
5538 : #if (ODBCVER >= 0x0300)
5539 0 : case SQL_ASYNC_MODE:
5540 : /* TODO we hope so in a not-too-far future */
5541 : /* UIVAL = SQL_AM_STATEMENT; */
5542 0 : UIVAL = SQL_AM_NONE;
5543 0 : break;
5544 0 : case SQL_BATCH_ROW_COUNT:
5545 0 : UIVAL = SQL_BRC_EXPLICIT;
5546 0 : break;
5547 0 : case SQL_BATCH_SUPPORT:
5548 0 : UIVAL = SQL_BS_ROW_COUNT_EXPLICIT | SQL_BS_ROW_COUNT_PROC | SQL_BS_SELECT_EXPLICIT | SQL_BS_SELECT_PROC;
5549 0 : break;
5550 : #endif /* ODBCVER >= 0x0300 */
5551 0 : case SQL_BOOKMARK_PERSISTENCE:
5552 : /* TODO ??? */
5553 0 : UIVAL = SQL_BP_DELETE | SQL_BP_SCROLL | SQL_BP_UPDATE;
5554 0 : break;
5555 0 : case SQL_CATALOG_LOCATION:
5556 0 : SIVAL = SQL_CL_START;
5557 0 : break;
5558 : #if (ODBCVER >= 0x0300)
5559 : case SQL_CATALOG_NAME:
5560 : p = "Y";
5561 : break;
5562 : #endif /* ODBCVER >= 0x0300 */
5563 0 : case SQL_CATALOG_NAME_SEPARATOR:
5564 0 : p = ".";
5565 0 : break;
5566 0 : case SQL_CATALOG_TERM:
5567 0 : p = "database";
5568 0 : break;
5569 0 : case SQL_CATALOG_USAGE:
5570 0 : UIVAL = SQL_CU_DML_STATEMENTS | SQL_CU_PROCEDURE_INVOCATION | SQL_CU_TABLE_DEFINITION;
5571 0 : break;
5572 : /* TODO */
5573 : #if 0
5574 : case SQL_COLLATION_SEQ:
5575 : break;
5576 : #endif
5577 : case SQL_COLUMN_ALIAS:
5578 : p = "Y";
5579 : break;
5580 0 : case SQL_CONCAT_NULL_BEHAVIOR:
5581 0 : if (is_ms == -1)
5582 : return SQL_ERROR;
5583 : /* TODO a bit more complicate for mssql2k.. */
5584 0 : SIVAL = (!is_ms || smajor < 7) ? SQL_CB_NON_NULL : SQL_CB_NULL;
5585 0 : break;
5586 : /* TODO SQL_CONVERT_BIGINT SQL_CONVERT_GUID SQL_CONVERT_DATE SQL_CONVERT_TIME */
5587 : /* For Sybase/MSSql6.x we return 0 cause NativeSql is not so implemented */
5588 0 : case SQL_CONVERT_BINARY:
5589 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_VARCHAR |
5590 : SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_TINYINT | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR |
5591 0 : SQL_CVT_WVARCHAR) & mssql7plus_mask;
5592 0 : break;
5593 0 : case SQL_CONVERT_BIT:
5594 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5595 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5596 0 : SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5597 0 : break;
5598 0 : case SQL_CONVERT_CHAR:
5599 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5600 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT |
5601 : SQL_CVT_TINYINT | SQL_CVT_TIMESTAMP | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5602 0 : SQL_CVT_WVARCHAR) & mssql7plus_mask;
5603 0 : break;
5604 0 : case SQL_CONVERT_DECIMAL:
5605 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5606 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5607 0 : SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5608 0 : break;
5609 0 : case SQL_CONVERT_FLOAT:
5610 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5611 0 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) &
5612 : mssql7plus_mask;
5613 0 : break;
5614 0 : case SQL_CONVERT_INTEGER:
5615 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5616 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5617 0 : SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5618 0 : break;
5619 0 : case SQL_CONVERT_LONGVARCHAR:
5620 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5621 0 : SQL_CVT_WVARCHAR) & mssql7plus_mask;
5622 0 : break;
5623 0 : case SQL_CONVERT_NUMERIC:
5624 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5625 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5626 0 : SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5627 0 : break;
5628 0 : case SQL_CONVERT_REAL:
5629 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5630 0 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) &
5631 : mssql7plus_mask;
5632 0 : break;
5633 0 : case SQL_CONVERT_SMALLINT:
5634 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5635 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5636 0 : SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5637 0 : break;
5638 0 : case SQL_CONVERT_TIMESTAMP:
5639 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_TIMESTAMP | SQL_CVT_WCHAR |
5640 0 : SQL_CVT_WVARCHAR) & mssql7plus_mask;
5641 0 : break;
5642 0 : case SQL_CONVERT_TINYINT:
5643 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5644 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5645 0 : SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5646 0 : break;
5647 0 : case SQL_CONVERT_VARBINARY:
5648 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_VARCHAR |
5649 : SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_TINYINT | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR |
5650 0 : SQL_CVT_WVARCHAR) & mssql7plus_mask;
5651 0 : break;
5652 0 : case SQL_CONVERT_VARCHAR:
5653 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5654 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT |
5655 : SQL_CVT_TINYINT | SQL_CVT_TIMESTAMP | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5656 0 : SQL_CVT_WVARCHAR) & mssql7plus_mask;
5657 0 : break;
5658 0 : case SQL_CONVERT_LONGVARBINARY:
5659 0 : UIVAL = (SQL_CVT_BINARY | SQL_CVT_LONGVARBINARY | SQL_CVT_VARBINARY) & mssql7plus_mask;
5660 0 : break;
5661 0 : case SQL_CONVERT_WLONGVARCHAR:
5662 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5663 0 : SQL_CVT_WVARCHAR) & mssql7plus_mask;
5664 0 : break;
5665 : #if (ODBCVER >= 0x0300)
5666 0 : case SQL_CONVERT_WCHAR:
5667 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5668 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT |
5669 : SQL_CVT_TINYINT | SQL_CVT_TIMESTAMP | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5670 0 : SQL_CVT_WVARCHAR) & mssql7plus_mask;
5671 0 : break;
5672 0 : case SQL_CONVERT_WVARCHAR:
5673 0 : UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5674 : SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT |
5675 : SQL_CVT_TINYINT | SQL_CVT_TIMESTAMP | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5676 0 : SQL_CVT_WVARCHAR) & mssql7plus_mask;
5677 0 : break;
5678 : #endif /* ODBCVER >= 0x0300 */
5679 0 : case SQL_CONVERT_FUNCTIONS:
5680 : /* TODO no CAST for Sybase ?? */
5681 0 : UIVAL = SQL_FN_CVT_CONVERT | SQL_FN_CVT_CAST;
5682 0 : break;
5683 : #if (ODBCVER >= 0x0300)
5684 0 : case SQL_CREATE_ASSERTION:
5685 : case SQL_CREATE_CHARACTER_SET:
5686 : case SQL_CREATE_COLLATION:
5687 : case SQL_CREATE_DOMAIN:
5688 0 : UIVAL = 0;
5689 0 : break;
5690 0 : case SQL_CREATE_SCHEMA:
5691 0 : UIVAL = SQL_CS_AUTHORIZATION | SQL_CS_CREATE_SCHEMA;
5692 0 : break;
5693 0 : case SQL_CREATE_TABLE:
5694 0 : UIVAL = SQL_CT_CREATE_TABLE;
5695 0 : break;
5696 0 : case SQL_CREATE_TRANSLATION:
5697 0 : UIVAL = 0;
5698 0 : break;
5699 0 : case SQL_CREATE_VIEW:
5700 0 : UIVAL = SQL_CV_CHECK_OPTION | SQL_CV_CREATE_VIEW;
5701 0 : break;
5702 : #endif /* ODBCVER >= 0x0300 */
5703 0 : case SQL_CORRELATION_NAME:
5704 0 : USIVAL = SQL_CN_ANY;
5705 0 : break;
5706 0 : case SQL_CURSOR_COMMIT_BEHAVIOR:
5707 : /* currently cursors are not supported however sql server close automaticly cursors on commit */
5708 : /* TODO cursors test what happen if rollback, cursors get properly deleted ?? */
5709 0 : USIVAL = SQL_CB_CLOSE;
5710 0 : break;
5711 0 : case SQL_CURSOR_ROLLBACK_BEHAVIOR:
5712 0 : USIVAL = SQL_CB_CLOSE;
5713 0 : break;
5714 0 : case SQL_CURSOR_SENSITIVITY:
5715 0 : UIVAL = SQL_SENSITIVE;
5716 0 : break;
5717 0 : case SQL_DATABASE_NAME:
5718 0 : p = tds_dstr_cstr(&dbc->attr.current_catalog);
5719 0 : break;
5720 0 : case SQL_DATA_SOURCE_NAME:
5721 0 : p = tds_dstr_cstr(&dbc->dsn);
5722 0 : break;
5723 0 : case SQL_DATA_SOURCE_READ_ONLY:
5724 : /*
5725 : * TODO: determine the right answer from connection
5726 : * attribute SQL_ATTR_ACCESS_MODE
5727 : */
5728 0 : p = "N"; /* false, writable */
5729 0 : break;
5730 : #if (ODBCVER >= 0x0300)
5731 0 : case SQL_DATETIME_LITERALS:
5732 : /* TODO ok ?? */
5733 0 : UIVAL = 0;
5734 0 : break;
5735 : #endif /* ODBCVER >= 0x0300 */
5736 278 : case SQL_DBMS_NAME:
5737 278 : p = tds ? tds->conn->product_name : NULL;
5738 : break;
5739 106 : case SQL_DBMS_VER:
5740 106 : if (!dbc->tds_socket)
5741 : return SQL_ERROR;
5742 106 : odbc_rdbms_version(dbc->tds_socket, buf);
5743 106 : p = buf;
5744 106 : break;
5745 : #if (ODBCVER >= 0x0300)
5746 0 : case SQL_DDL_INDEX:
5747 0 : UIVAL = 0;
5748 0 : break;
5749 : #endif /* ODBCVER >= 0x0300 */
5750 0 : case SQL_DEFAULT_TXN_ISOLATION:
5751 0 : UIVAL = SQL_TXN_READ_COMMITTED;
5752 0 : break;
5753 : #if (ODBCVER >= 0x0300)
5754 : case SQL_DESCRIBE_PARAMETER:
5755 : p = "Y";
5756 : break;
5757 : #endif /* ODBCVER >= 0x0300 */
5758 10 : case SQL_DRIVER_HDBC:
5759 10 : ULVAL = (SQLULEN) dbc;
5760 10 : break;
5761 10 : case SQL_DRIVER_HENV:
5762 10 : ULVAL = (SQLULEN) dbc->env;
5763 10 : break;
5764 0 : case SQL_DRIVER_HSTMT: {
5765 0 : void *ptr = *((void**) rgbInfoValue);
5766 0 : if (SQL_NULL_HSTMT != ptr && !IS_HSTMT(ptr))
5767 0 : ULVAL = SQL_NULL_HSTMT;
5768 : }
5769 : break;
5770 0 : case SQL_DRIVER_HDESC: {
5771 0 : void *ptr = *((void**) rgbInfoValue);
5772 0 : if (SQL_NULL_HDESC != ptr && !IS_HDESC(ptr))
5773 0 : ULVAL = SQL_NULL_HDESC;
5774 : }
5775 : break;
5776 356 : case SQL_DRIVER_NAME: /* ODBC 2.0 */
5777 356 : p = "libtdsodbc.so";
5778 356 : break;
5779 0 : case SQL_DRIVER_ODBC_VER:
5780 0 : p = "03.50";
5781 0 : break;
5782 0 : case SQL_DRIVER_VER:
5783 0 : sprintf(buf, "%02d.%02d.%04d", TDS_VERSION_MAJOR,
5784 : TDS_VERSION_MINOR, TDS_VERSION_SUBVERSION);
5785 0 : p = buf;
5786 0 : break;
5787 : #if (ODBCVER >= 0x0300)
5788 0 : case SQL_DROP_ASSERTION:
5789 : case SQL_DROP_CHARACTER_SET:
5790 : case SQL_DROP_COLLATION:
5791 : case SQL_DROP_DOMAIN:
5792 : case SQL_DROP_SCHEMA:
5793 0 : UIVAL = 0;
5794 0 : break;
5795 0 : case SQL_DROP_TABLE:
5796 0 : UIVAL = SQL_DT_DROP_TABLE;
5797 0 : break;
5798 0 : case SQL_DROP_TRANSLATION:
5799 0 : UIVAL = 0;
5800 0 : break;
5801 0 : case SQL_DROP_VIEW:
5802 0 : UIVAL = SQL_DV_DROP_VIEW;
5803 0 : break;
5804 0 : case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
5805 0 : if (dbc->cursor_support)
5806 : /* TODO cursor SQL_CA1_BULK_ADD SQL_CA1_POS_REFRESH SQL_CA1_SELECT_FOR_UPDATE */
5807 0 : UIVAL = SQL_CA1_ABSOLUTE | SQL_CA1_NEXT | SQL_CA1_RELATIVE |
5808 : SQL_CA1_LOCK_NO_CHANGE |
5809 : SQL_CA1_POS_DELETE | SQL_CA1_POS_POSITION | SQL_CA1_POS_UPDATE |
5810 : SQL_CA1_POSITIONED_UPDATE | SQL_CA1_POSITIONED_DELETE;
5811 : else
5812 0 : UIVAL = 0;
5813 : break;
5814 0 : case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
5815 : /* TODO cursors */
5816 : /* Cursors not supported yet */
5817 : /*
5818 : * Should be SQL_CA2_LOCK_CONCURRENCY SQL_CA2_MAX_ROWS_CATALOG SQL_CA2_MAX_ROWS_DELETE
5819 : * SQL_CA2_MAX_ROWS_INSERT SQL_CA2_MAX_ROWS_SELECT SQL_CA2_MAX_ROWS_UPDATE SQL_CA2_OPT_ROWVER_CONCURRENCY
5820 : * SQL_CA2_OPT_VALUES_CONCURRENCY SQL_CA2_READ_ONLY_CONCURRENCY SQL_CA2_SENSITIVITY_ADDITIONS
5821 : * SQL_CA2_SENSITIVITY_UPDATES SQL_CA2_SIMULATE_UNIQUE
5822 : */
5823 0 : UIVAL = 0;
5824 0 : break;
5825 : #endif /* ODBCVER >= 0x0300 */
5826 : case SQL_EXPRESSIONS_IN_ORDERBY:
5827 : p = "Y";
5828 : break;
5829 0 : case SQL_FILE_USAGE:
5830 0 : USIVAL = SQL_FILE_NOT_SUPPORTED;
5831 0 : break;
5832 0 : case SQL_FETCH_DIRECTION:
5833 0 : if (dbc->cursor_support)
5834 : /* TODO cursors SQL_FD_FETCH_BOOKMARK */
5835 0 : UIVAL = SQL_FD_FETCH_ABSOLUTE|SQL_FD_FETCH_FIRST|SQL_FD_FETCH_LAST|SQL_FD_FETCH_NEXT
5836 : |SQL_FD_FETCH_PRIOR|SQL_FD_FETCH_RELATIVE;
5837 : else
5838 0 : UIVAL = 0;
5839 : break;
5840 : #if (ODBCVER >= 0x0300)
5841 0 : case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
5842 0 : if (dbc->cursor_support)
5843 : /* TODO cursors SQL_CA1_SELECT_FOR_UPDATE */
5844 0 : UIVAL = SQL_CA1_NEXT|SQL_CA1_POSITIONED_DELETE|SQL_CA1_POSITIONED_UPDATE;
5845 : else
5846 0 : UIVAL = 0;
5847 : break;
5848 0 : case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
5849 : /* TODO cursors */
5850 : /* Cursors not supported yet */
5851 : /*
5852 : * Should be SQL_CA2_LOCK_CONCURRENCY SQL_CA2_MAX_ROWS_CATALOG SQL_CA2_MAX_ROWS_DELETE
5853 : * SQL_CA2_MAX_ROWS_INSERT SQL_CA2_MAX_ROWS_SELECT SQL_CA2_MAX_ROWS_UPDATE SQL_CA2_OPT_ROWVER_CONCURRENCY
5854 : * SQL_CA2_OPT_VALUES_CONCURRENCY SQL_CA2_READ_ONLY_CONCURRENCY
5855 : */
5856 0 : UIVAL = 0;
5857 0 : break;
5858 : #endif /* ODBCVER >= 0x0300 */
5859 0 : case SQL_GETDATA_EXTENSIONS:
5860 : /* TODO FreeTDS support more ?? */
5861 0 : UIVAL = SQL_GD_BLOCK;
5862 0 : break;
5863 0 : case SQL_GROUP_BY:
5864 0 : USIVAL = SQL_GB_GROUP_BY_CONTAINS_SELECT;
5865 0 : break;
5866 0 : case SQL_IDENTIFIER_CASE:
5867 : /* TODO configuration dependend */
5868 0 : USIVAL = SQL_IC_MIXED;
5869 0 : break;
5870 0 : case SQL_IDENTIFIER_QUOTE_CHAR:
5871 0 : p = "\"";
5872 : /* TODO workaround for Sybase, use SET QUOTED_IDENTIFIER ON and fix unwanted quote */
5873 0 : if (!is_ms)
5874 0 : p = "";
5875 : break;
5876 : #if (ODBCVER >= 0x0300)
5877 0 : case SQL_INDEX_KEYWORDS:
5878 0 : UIVAL = SQL_IK_ASC | SQL_IK_DESC;
5879 0 : break;
5880 : #endif /* ODBCVER >= 0x0300 */
5881 0 : case SQL_INFO_SCHEMA_VIEWS:
5882 : /* TODO finish */
5883 0 : UIVAL = 0;
5884 0 : break;
5885 0 : case SQL_INSERT_STATEMENT:
5886 0 : UIVAL = 0;
5887 0 : break;
5888 : /* renamed from SQL_ODBC_SQL_OPT_IEF */
5889 : case SQL_INTEGRITY:
5890 : p = "Y";
5891 : break;
5892 0 : case SQL_KEYSET_CURSOR_ATTRIBUTES1:
5893 : case SQL_KEYSET_CURSOR_ATTRIBUTES2:
5894 : /* TODO cursors */
5895 0 : UIVAL = 0;
5896 0 : break;
5897 0 : case SQL_KEYWORDS:
5898 : /* TODO ok for Sybase ? */
5899 0 : p = "BREAK,BROWSE,BULK,CHECKPOINT,CLUSTERED,"
5900 : "COMMITTED,COMPUTE,CONFIRM,CONTROLROW,DATABASE,"
5901 : "DBCC,DISK,DISTRIBUTED,DUMMY,DUMP,ERRLVL,"
5902 : "ERROREXIT,EXIT,FILE,FILLFACTOR,FLOPPY,HOLDLOCK,"
5903 : "IDENTITY_INSERT,IDENTITYCOL,IF,KILL,LINENO,"
5904 : "LOAD,MIRROREXIT,NONCLUSTERED,OFF,OFFSETS,ONCE,"
5905 : "OVER,PERCENT,PERM,PERMANENT,PLAN,PRINT,PROC,"
5906 : "PROCESSEXIT,RAISERROR,READ,READTEXT,RECONFIGURE,"
5907 : "REPEATABLE,RETURN,ROWCOUNT,RULE,SAVE,SERIALIZABLE,"
5908 : "SETUSER,SHUTDOWN,STATISTICS,TAPE,TEMP,TEXTSIZE,"
5909 : "TRAN,TRIGGER,TRUNCATE,TSEQUEL,UNCOMMITTED," "UPDATETEXT,USE,WAITFOR,WHILE,WRITETEXT";
5910 0 : break;
5911 : case SQL_LIKE_ESCAPE_CLAUSE:
5912 : p = "Y";
5913 : break;
5914 0 : case SQL_LOCK_TYPES:
5915 0 : if (dbc->cursor_support)
5916 0 : IVAL = SQL_LCK_NO_CHANGE;
5917 : else
5918 0 : IVAL = 0;
5919 : break;
5920 : #if (ODBCVER >= 0x0300)
5921 0 : case SQL_MAX_ASYNC_CONCURRENT_STATEMENTS:
5922 0 : UIVAL = 1;
5923 0 : break;
5924 : #endif /* ODBCVER >= 0x0300 */
5925 : /* TODO same limits for Sybase ? */
5926 0 : case SQL_MAX_BINARY_LITERAL_LEN:
5927 0 : UIVAL = 131072;
5928 0 : break;
5929 0 : case SQL_MAX_CHAR_LITERAL_LEN:
5930 0 : UIVAL = 131072;
5931 0 : break;
5932 0 : case SQL_MAX_CONCURRENT_ACTIVITIES:
5933 0 : USIVAL = 1;
5934 0 : break;
5935 0 : case SQL_MAX_COLUMNS_IN_GROUP_BY:
5936 : case SQL_MAX_COLUMNS_IN_INDEX:
5937 : case SQL_MAX_COLUMNS_IN_ORDER_BY:
5938 : /* TODO Sybase ? */
5939 0 : USIVAL = 16;
5940 0 : break;
5941 0 : case SQL_MAX_COLUMNS_IN_SELECT:
5942 : /* TODO Sybase ? */
5943 0 : USIVAL = 4000;
5944 0 : break;
5945 0 : case SQL_MAX_COLUMNS_IN_TABLE:
5946 : /* TODO Sybase ? */
5947 0 : USIVAL = 250;
5948 0 : break;
5949 0 : case SQL_MAX_DRIVER_CONNECTIONS:
5950 0 : USIVAL = 0;
5951 0 : break;
5952 0 : case SQL_MAX_IDENTIFIER_LEN:
5953 0 : if (is_ms == -1)
5954 : return SQL_ERROR;
5955 0 : USIVAL = (!is_ms || smajor < 7) ? 30 : 128;
5956 0 : break;
5957 0 : case SQL_MAX_INDEX_SIZE:
5958 0 : UIVAL = 127;
5959 0 : break;
5960 0 : case SQL_MAX_PROCEDURE_NAME_LEN:
5961 0 : if (is_ms == -1)
5962 : return SQL_ERROR;
5963 : /* TODO Sybase ? */
5964 0 : USIVAL = (is_ms && smajor >= 7) ? 134 : 36;
5965 0 : break;
5966 0 : case SQL_MAX_ROW_SIZE:
5967 0 : if (is_ms == -1)
5968 : return SQL_ERROR;
5969 : /* TODO Sybase ? */
5970 0 : UIVAL = (is_ms && smajor >= 7) ? 8062 : 1962;
5971 0 : break;
5972 0 : case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
5973 0 : p = "N";
5974 0 : break;
5975 0 : case SQL_MAX_STATEMENT_LEN:
5976 : /* TODO Sybase ? */
5977 0 : UIVAL = 131072;
5978 0 : break;
5979 0 : case SQL_MAX_TABLES_IN_SELECT:
5980 : /* TODO Sybase ? */
5981 0 : USIVAL = 16;
5982 0 : break;
5983 0 : case SQL_MAX_USER_NAME_LEN:
5984 : /* TODO Sybase ? */
5985 0 : if (is_ms == -1)
5986 : return SQL_ERROR;
5987 0 : USIVAL = (is_ms && smajor >= 7) ? 128 : 30;
5988 0 : break;
5989 0 : case SQL_MAX_COLUMN_NAME_LEN:
5990 : case SQL_MAX_CURSOR_NAME_LEN:
5991 : case SQL_MAX_SCHEMA_NAME_LEN:
5992 : case SQL_MAX_CATALOG_NAME_LEN:
5993 : case SQL_MAX_TABLE_NAME_LEN:
5994 : /* TODO Sybase ? */
5995 0 : if (is_ms == -1)
5996 : return SQL_ERROR;
5997 0 : USIVAL = (is_ms && smajor >= 7) ? 128 : 30;
5998 0 : break;
5999 : case SQL_MULT_RESULT_SETS:
6000 : p = "Y";
6001 : break;
6002 : case SQL_MULTIPLE_ACTIVE_TXN:
6003 : p = "Y";
6004 : break;
6005 : case SQL_NEED_LONG_DATA_LEN:
6006 : /* current implementation do not require length, however future will, so is correct to return yes */
6007 : p = "Y";
6008 : break;
6009 0 : case SQL_NON_NULLABLE_COLUMNS:
6010 0 : USIVAL = SQL_NNC_NON_NULL;
6011 0 : break;
6012 0 : case SQL_NULL_COLLATION:
6013 0 : USIVAL = SQL_NC_LOW;
6014 0 : break;
6015 0 : case SQL_NUMERIC_FUNCTIONS:
6016 0 : UIVAL = (SQL_FN_NUM_ABS | SQL_FN_NUM_ACOS | SQL_FN_NUM_ASIN | SQL_FN_NUM_ATAN | SQL_FN_NUM_ATAN2 |
6017 : SQL_FN_NUM_CEILING | SQL_FN_NUM_COS | SQL_FN_NUM_COT | SQL_FN_NUM_DEGREES | SQL_FN_NUM_EXP |
6018 : SQL_FN_NUM_FLOOR | SQL_FN_NUM_LOG | SQL_FN_NUM_LOG10 | SQL_FN_NUM_MOD | SQL_FN_NUM_PI | SQL_FN_NUM_POWER |
6019 : SQL_FN_NUM_RADIANS | SQL_FN_NUM_RAND | SQL_FN_NUM_ROUND | SQL_FN_NUM_SIGN | SQL_FN_NUM_SIN |
6020 0 : SQL_FN_NUM_SQRT | SQL_FN_NUM_TAN) & mssql7plus_mask;
6021 0 : break;
6022 0 : case SQL_ODBC_API_CONFORMANCE:
6023 0 : SIVAL = SQL_OAC_LEVEL2;
6024 0 : break;
6025 : #if (ODBCVER >= 0x0300)
6026 0 : case SQL_ODBC_INTERFACE_CONFORMANCE:
6027 0 : UIVAL = SQL_OAC_LEVEL2;
6028 0 : break;
6029 : #endif /* ODBCVER >= 0x0300 */
6030 0 : case SQL_ODBC_SAG_CLI_CONFORMANCE:
6031 0 : SIVAL = SQL_OSCC_NOT_COMPLIANT;
6032 0 : break;
6033 0 : case SQL_ODBC_SQL_CONFORMANCE:
6034 0 : SIVAL = SQL_OSC_CORE;
6035 0 : break;
6036 : #ifdef TDS_NO_DM
6037 0 : case SQL_ODBC_VER:
6038 : /* TODO check format ##.##.0000 */
6039 0 : p = VERSION;
6040 0 : break;
6041 : #endif
6042 : #if (ODBCVER >= 0x0300)
6043 0 : case SQL_OJ_CAPABILITIES:
6044 0 : UIVAL = SQL_OJ_ALL_COMPARISON_OPS | SQL_OJ_FULL | SQL_OJ_INNER | SQL_OJ_LEFT | SQL_OJ_NESTED | SQL_OJ_NOT_ORDERED |
6045 : SQL_OJ_RIGHT;
6046 0 : break;
6047 : #endif /* ODBCVER >= 0x0300 */
6048 0 : case SQL_ORDER_BY_COLUMNS_IN_SELECT:
6049 0 : p = "N";
6050 0 : break;
6051 : case SQL_OUTER_JOINS:
6052 : p = "Y";
6053 : break;
6054 : #if (ODBCVER >= 0x0300)
6055 0 : case SQL_PARAM_ARRAY_ROW_COUNTS:
6056 0 : UIVAL = SQL_PARC_BATCH;
6057 0 : break;
6058 0 : case SQL_PARAM_ARRAY_SELECTS:
6059 0 : UIVAL = SQL_PAS_BATCH;
6060 0 : break;
6061 : #endif /* ODBCVER >= 0x0300 */
6062 0 : case SQL_POS_OPERATIONS:
6063 0 : if (dbc->cursor_support)
6064 : /* TODO cursors SQL_POS_ADD SQL_POS_REFRESH */
6065 : /* test REFRESH, ADD under mssql, under Sybase I don't know how to do it but dblib do */
6066 0 : IVAL = SQL_POS_DELETE | SQL_POS_POSITION | SQL_POS_UPDATE;
6067 : else
6068 0 : IVAL = 0;
6069 : break;
6070 0 : case SQL_POSITIONED_STATEMENTS:
6071 : /* TODO cursors SQL_PS_SELECT_FOR_UPDATE */
6072 0 : IVAL = SQL_PS_POSITIONED_DELETE | SQL_PS_POSITIONED_UPDATE;
6073 0 : break;
6074 0 : case SQL_PROCEDURE_TERM:
6075 0 : p = "stored procedure";
6076 0 : break;
6077 : case SQL_PROCEDURES:
6078 : p = "Y";
6079 : break;
6080 0 : case SQL_QUOTED_IDENTIFIER_CASE:
6081 : /* TODO usually insensitive */
6082 0 : USIVAL = SQL_IC_MIXED;
6083 0 : break;
6084 0 : case SQL_ROW_UPDATES:
6085 0 : p = "N";
6086 0 : break;
6087 : #if (ODBCVER >= 0x0300)
6088 0 : case SQL_SCHEMA_TERM:
6089 0 : p = "owner";
6090 0 : break;
6091 0 : case SQL_SCHEMA_USAGE:
6092 0 : UIVAL = SQL_OU_DML_STATEMENTS | SQL_OU_INDEX_DEFINITION | SQL_OU_PRIVILEGE_DEFINITION | SQL_OU_PROCEDURE_INVOCATION
6093 : | SQL_OU_TABLE_DEFINITION;
6094 0 : break;
6095 : #endif /* ODBCVER >= 0x0300 */
6096 0 : case SQL_SCROLL_CONCURRENCY:
6097 0 : if (dbc->cursor_support)
6098 : /* TODO cursors test them, Sybase support all ? */
6099 0 : IVAL = SQL_SCCO_LOCK | SQL_SCCO_OPT_ROWVER | SQL_SCCO_OPT_VALUES | SQL_SCCO_READ_ONLY;
6100 : else
6101 0 : IVAL = SQL_SCCO_READ_ONLY;
6102 : break;
6103 0 : case SQL_SCROLL_OPTIONS:
6104 0 : if (dbc->cursor_support)
6105 : /* TODO cursors test them, Sybase support all ?? */
6106 0 : UIVAL = SQL_SO_DYNAMIC | SQL_SO_FORWARD_ONLY | SQL_SO_KEYSET_DRIVEN | SQL_SO_STATIC;
6107 : else
6108 0 : UIVAL = SQL_SO_FORWARD_ONLY | SQL_SO_STATIC;
6109 : break;
6110 0 : case SQL_SEARCH_PATTERN_ESCAPE:
6111 0 : p = "\\";
6112 0 : break;
6113 0 : case SQL_SERVER_NAME:
6114 0 : p = dbc->tds_socket->conn->server;
6115 0 : break;
6116 0 : case SQL_SPECIAL_CHARACTERS:
6117 : /* TODO others ?? */
6118 0 : p = "\'\"[]{}";
6119 0 : break;
6120 : #if (ODBCVER >= 0x0300)
6121 0 : case SQL_SQL_CONFORMANCE:
6122 0 : UIVAL = SQL_SC_SQL92_ENTRY;
6123 0 : break;
6124 0 : case SQL_SQL92_DATETIME_FUNCTIONS:
6125 : case SQL_SQL92_FOREIGN_KEY_DELETE_RULE:
6126 : case SQL_SQL92_FOREIGN_KEY_UPDATE_RULE:
6127 0 : UIVAL = 0;
6128 0 : break;
6129 0 : case SQL_SQL92_GRANT:
6130 0 : UIVAL = SQL_SG_WITH_GRANT_OPTION;
6131 0 : break;
6132 0 : case SQL_SQL92_NUMERIC_VALUE_FUNCTIONS:
6133 0 : UIVAL = 0;
6134 0 : break;
6135 0 : case SQL_SQL92_PREDICATES:
6136 : /* TODO Sybase ?? */
6137 0 : UIVAL = SQL_SP_EXISTS | SQL_SP_ISNOTNULL | SQL_SP_ISNULL;
6138 0 : break;
6139 0 : case SQL_SQL92_RELATIONAL_JOIN_OPERATORS:
6140 : /* TODO Sybase ?? */
6141 0 : UIVAL = SQL_SRJO_CROSS_JOIN | SQL_SRJO_FULL_OUTER_JOIN | SQL_SRJO_INNER_JOIN | SQL_SRJO_LEFT_OUTER_JOIN |
6142 : SQL_SRJO_RIGHT_OUTER_JOIN | SQL_SRJO_UNION_JOIN;
6143 0 : break;
6144 0 : case SQL_SQL92_REVOKE:
6145 0 : UIVAL = SQL_SR_GRANT_OPTION_FOR;
6146 0 : break;
6147 0 : case SQL_SQL92_ROW_VALUE_CONSTRUCTOR:
6148 0 : UIVAL = SQL_SRVC_DEFAULT | SQL_SRVC_NULL | SQL_SRVC_ROW_SUBQUERY | SQL_SRVC_VALUE_EXPRESSION;
6149 0 : break;
6150 0 : case SQL_SQL92_STRING_FUNCTIONS:
6151 0 : UIVAL = SQL_SSF_LOWER | SQL_SSF_UPPER;
6152 0 : break;
6153 0 : case SQL_SQL92_VALUE_EXPRESSIONS:
6154 : /* TODO Sybase ? CAST supported ? */
6155 0 : UIVAL = SQL_SVE_CASE | SQL_SVE_CAST | SQL_SVE_COALESCE | SQL_SVE_NULLIF;
6156 0 : break;
6157 0 : case SQL_STANDARD_CLI_CONFORMANCE:
6158 0 : UIVAL = SQL_SCC_ISO92_CLI;
6159 0 : break;
6160 0 : case SQL_STATIC_SENSITIVITY:
6161 0 : IVAL = 0;
6162 0 : break;
6163 0 : case SQL_STATIC_CURSOR_ATTRIBUTES1:
6164 0 : if (dbc->cursor_support)
6165 : /* TODO cursors SQL_CA1_BOOKMARK SQL_CA1_BULK_FETCH_BY_BOOKMARK SQL_CA1_POS_REFRESH */
6166 0 : UIVAL = SQL_CA1_ABSOLUTE | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_NEXT | SQL_CA1_POS_POSITION | SQL_CA1_RELATIVE;
6167 : else
6168 0 : UIVAL = 0;
6169 : break;
6170 0 : case SQL_STATIC_CURSOR_ATTRIBUTES2:
6171 : /* TODO cursors */
6172 0 : UIVAL = 0;
6173 0 : break;
6174 : #endif /* ODBCVER >= 0x0300 */
6175 0 : case SQL_STRING_FUNCTIONS:
6176 0 : UIVAL = (SQL_FN_STR_ASCII | SQL_FN_STR_BIT_LENGTH | SQL_FN_STR_CHAR | SQL_FN_STR_CONCAT | SQL_FN_STR_DIFFERENCE |
6177 : SQL_FN_STR_INSERT | SQL_FN_STR_LCASE | SQL_FN_STR_LEFT | SQL_FN_STR_LENGTH | SQL_FN_STR_LOCATE_2 |
6178 : SQL_FN_STR_LTRIM | SQL_FN_STR_OCTET_LENGTH | SQL_FN_STR_REPEAT | SQL_FN_STR_RIGHT | SQL_FN_STR_RTRIM |
6179 0 : SQL_FN_STR_SOUNDEX | SQL_FN_STR_SPACE | SQL_FN_STR_SUBSTRING | SQL_FN_STR_UCASE) & mssql7plus_mask;
6180 0 : break;
6181 0 : case SQL_SUBQUERIES:
6182 0 : UIVAL = SQL_SQ_COMPARISON | SQL_SQ_CORRELATED_SUBQUERIES | SQL_SQ_EXISTS | SQL_SQ_IN | SQL_SQ_QUANTIFIED;
6183 0 : break;
6184 0 : case SQL_SYSTEM_FUNCTIONS:
6185 0 : UIVAL = SQL_FN_SYS_DBNAME | SQL_FN_SYS_IFNULL | SQL_FN_SYS_USERNAME;
6186 0 : break;
6187 0 : case SQL_TABLE_TERM:
6188 0 : p = "table";
6189 0 : break;
6190 0 : case SQL_TIMEDATE_ADD_INTERVALS:
6191 0 : UIVAL = (SQL_FN_TSI_DAY | SQL_FN_TSI_FRAC_SECOND | SQL_FN_TSI_HOUR | SQL_FN_TSI_MINUTE | SQL_FN_TSI_MONTH |
6192 0 : SQL_FN_TSI_QUARTER | SQL_FN_TSI_SECOND | SQL_FN_TSI_WEEK | SQL_FN_TSI_YEAR) & mssql7plus_mask;
6193 0 : break;
6194 0 : case SQL_TIMEDATE_DIFF_INTERVALS:
6195 0 : UIVAL = (SQL_FN_TSI_DAY | SQL_FN_TSI_FRAC_SECOND | SQL_FN_TSI_HOUR | SQL_FN_TSI_MINUTE | SQL_FN_TSI_MONTH |
6196 0 : SQL_FN_TSI_QUARTER | SQL_FN_TSI_SECOND | SQL_FN_TSI_WEEK | SQL_FN_TSI_YEAR) & mssql7plus_mask;
6197 0 : break;
6198 0 : case SQL_TIMEDATE_FUNCTIONS:
6199 0 : UIVAL = (SQL_FN_TD_CURDATE | SQL_FN_TD_CURRENT_DATE | SQL_FN_TD_CURRENT_TIME | SQL_FN_TD_CURRENT_TIMESTAMP |
6200 : SQL_FN_TD_CURTIME | SQL_FN_TD_DAYNAME | SQL_FN_TD_DAYOFMONTH | SQL_FN_TD_DAYOFWEEK | SQL_FN_TD_DAYOFYEAR |
6201 : SQL_FN_TD_EXTRACT | SQL_FN_TD_HOUR | SQL_FN_TD_MINUTE | SQL_FN_TD_MONTH | SQL_FN_TD_MONTHNAME |
6202 : SQL_FN_TD_NOW | SQL_FN_TD_QUARTER | SQL_FN_TD_SECOND | SQL_FN_TD_TIMESTAMPADD | SQL_FN_TD_TIMESTAMPDIFF |
6203 0 : SQL_FN_TD_WEEK | SQL_FN_TD_YEAR) & mssql7plus_mask;
6204 0 : break;
6205 0 : case SQL_TXN_CAPABLE:
6206 : /* transaction for DML and DDL */
6207 0 : SIVAL = SQL_TC_ALL;
6208 0 : break;
6209 0 : case SQL_TXN_ISOLATION_OPTION:
6210 0 : UIVAL = SQL_TXN_READ_COMMITTED | SQL_TXN_READ_UNCOMMITTED | SQL_TXN_REPEATABLE_READ | SQL_TXN_SERIALIZABLE;
6211 0 : break;
6212 0 : case SQL_UNION:
6213 0 : UIVAL = SQL_U_UNION | SQL_U_UNION_ALL;
6214 0 : break;
6215 : /* TODO finish */
6216 0 : case SQL_USER_NAME:
6217 : /* TODO this is not correct username */
6218 : /* p = tds_dstr_cstr(&dbc->tds_login->user_name); */
6219 : /* make OpenOffice happy :) */
6220 0 : p = "";
6221 0 : break;
6222 0 : case SQL_XOPEN_CLI_YEAR:
6223 : /* TODO check specifications */
6224 0 : p = "1995";
6225 0 : break;
6226 134 : case SQL_INFO_FREETDS_TDS_VERSION:
6227 134 : if (!dbc->tds_socket)
6228 : return SQL_ERROR;
6229 134 : UIVAL = TDS_MAJOR(dbc->tds_socket->conn) << 16 | TDS_MINOR(dbc->tds_socket->conn);
6230 134 : break;
6231 80 : case SQL_INFO_FREETDS_SOCKET:
6232 80 : if (IS_TDSDEAD(dbc->tds_socket))
6233 : return SQL_ERROR;
6234 80 : ULVAL = dbc->tds_socket->conn->s;
6235 80 : break;
6236 0 : default:
6237 0 : odbc_log_unimplemented_type("SQLGetInfo", fInfoType);
6238 0 : odbc_errs_add(&dbc->errs, "HY092", "Option not supported");
6239 0 : return SQL_ERROR;
6240 : }
6241 :
6242 : /* char data */
6243 974 : if (p) {
6244 740 : return odbc_set_string_oct(dbc, rgbInfoValue, cbInfoValueMax, pcbInfoValue, p, -1);
6245 : } else {
6246 234 : if (out_len > 0 && pcbInfoValue)
6247 214 : *pcbInfoValue = out_len;
6248 : }
6249 :
6250 : return SQL_SUCCESS;
6251 : #undef SIVAL
6252 : #undef USIVAL
6253 : #undef IVAL
6254 : #undef UIVAL
6255 : }
6256 :
6257 : SQLRETURN ODBC_PUBLIC ODBC_API
6258 : SQLGetInfo(SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax,
6259 : SQLSMALLINT FAR * pcbInfoValue)
6260 : {
6261 501 : ODBC_ENTER_HDBC;
6262 :
6263 501 : tdsdump_log(TDS_DBG_FUNC, "SQLGetInfo(%p, %d, %p, %d, %p)\n",
6264 : hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue);
6265 :
6266 501 : ODBC_EXIT(dbc, odbc_SQLGetInfo(dbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue _wide0));
6267 : }
6268 :
6269 : #ifdef ENABLE_ODBC_WIDE
6270 : SQLRETURN ODBC_PUBLIC ODBC_API
6271 : SQLGetInfoW(SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax,
6272 : SQLSMALLINT FAR * pcbInfoValue)
6273 : {
6274 473 : ODBC_ENTER_HDBC;
6275 :
6276 473 : tdsdump_log(TDS_DBG_FUNC, "SQLGetInfoW(%p, %d, %p, %d, %p)\n",
6277 : hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue);
6278 :
6279 473 : ODBC_EXIT(dbc, odbc_SQLGetInfo(dbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue, 1));
6280 : }
6281 : #endif
6282 :
6283 : static void
6284 336 : odbc_upper_column_names(TDS_STMT * stmt)
6285 : {
6286 : #if ENABLE_EXTRA_CHECKS
6287 : TDSSOCKET *tds;
6288 : #endif
6289 : int icol;
6290 : TDS_DESC *ird;
6291 :
6292 336 : IRD_CHECK;
6293 :
6294 : #if ENABLE_EXTRA_CHECKS
6295 336 : tds = stmt->dbc->tds_socket;
6296 336 : if (tds && tds->current_results) {
6297 : TDSRESULTINFO *const resinfo = tds->current_results;
6298 :
6299 4684 : for (icol = 0; icol < resinfo->num_cols; ++icol) {
6300 4684 : TDSCOLUMN *colinfo = resinfo->columns[icol];
6301 :
6302 : /* upper case */
6303 9368 : tds_ascii_strupr(tds_dstr_buf(&colinfo->column_name));
6304 : }
6305 : }
6306 : #endif
6307 :
6308 336 : ird = stmt->ird;
6309 5356 : for (icol = ird->header.sql_desc_count; --icol >= 0;) {
6310 4684 : struct _drecord *drec = &ird->records[icol];
6311 :
6312 : /* upper case */
6313 9368 : tds_ascii_strupr(tds_dstr_buf(&drec->sql_desc_label));
6314 9368 : tds_ascii_strupr(tds_dstr_buf(&drec->sql_desc_name));
6315 : }
6316 336 : }
6317 :
6318 : /**
6319 : * Change sql datatype to a specific version
6320 : * \param sql_type sql data type to change (any type)
6321 : * \param version ODBC version to change to, 2 for ODBC 2, 3 for ODBC 3, 0 swap
6322 : */
6323 : static SQLSMALLINT
6324 : odbc_swap_datetime_sql_type(SQLSMALLINT sql_type, int version)
6325 : {
6326 248 : switch (sql_type) {
6327 : case SQL_TYPE_TIMESTAMP:
6328 : if (version != 3)
6329 2 : sql_type = SQL_TIMESTAMP;
6330 : break;
6331 : case SQL_TIMESTAMP:
6332 : if (version != 2)
6333 18 : sql_type = SQL_TYPE_TIMESTAMP;
6334 : break;
6335 : case SQL_TYPE_DATE:
6336 : if (version != 3)
6337 2 : sql_type = SQL_DATE;
6338 : break;
6339 : case SQL_DATE:
6340 : if (version != 2)
6341 6 : sql_type = SQL_TYPE_DATE;
6342 : break;
6343 : case SQL_TYPE_TIME:
6344 : if (version != 3)
6345 2 : sql_type = SQL_TIME;
6346 : break;
6347 : case SQL_TIME:
6348 : if (version != 2)
6349 6 : sql_type = SQL_TYPE_TIME;
6350 : break;
6351 : }
6352 : return sql_type;
6353 : }
6354 :
6355 : SQLRETURN ODBC_PUBLIC ODBC_API
6356 : SQLGetTypeInfo(SQLHSTMT hstmt, SQLSMALLINT fSqlType)
6357 : {
6358 : SQLRETURN res;
6359 : TDSSOCKET *tds;
6360 : TDS_INT result_type;
6361 : TDS_INT compute_id;
6362 144 : int varchar_pos = -1, n;
6363 : static const char sql_templ_default[] = "sp_datatype_info %d";
6364 144 : const char *sql_templ = sql_templ_default;
6365 : char sql[sizeof(sql_templ_default) + 36];
6366 : int odbc3;
6367 :
6368 144 : ODBC_ENTER_HSTMT;
6369 :
6370 144 : tdsdump_log(TDS_DBG_FUNC, "SQLGetTypeInfo(%p, %d)\n", hstmt, fSqlType);
6371 :
6372 144 : tds = stmt->dbc->tds_socket;
6373 144 : odbc3 = (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3);
6374 :
6375 144 : if (IS_TDS73_PLUS(tds->conn))
6376 : sql_templ = "sp_datatype_info_100 %d";
6377 88 : else if (IS_TDS72_PLUS(tds->conn))
6378 0 : sql_templ = "sp_datatype_info_90 %d";
6379 :
6380 : /* For MSSQL6.5 and Sybase 11.9 sp_datatype_info work */
6381 : /* TODO what about early Sybase products ? */
6382 : /* TODO Does Sybase return all ODBC3 columns? Add them if not */
6383 : /* TODO ODBC3 convert type to ODBC version 2 (date) */
6384 144 : if (odbc3) {
6385 72 : if (TDS_IS_SYBASE(tds)) {
6386 16 : sprintf(sql, sql_templ, odbc_swap_datetime_sql_type(fSqlType, 0));
6387 16 : stmt->special_row = ODBC_SPECIAL_GETTYPEINFO;
6388 : } else {
6389 56 : sprintf(sql, sql_templ, fSqlType);
6390 56 : strcat(sql, ",3");
6391 : }
6392 : } else {
6393 : /* MS ODBC translate SQL_TIMESTAMP to SQL_TYPE_TIMESTAMP even for ODBC 2 apps
6394 : * other DM just pass value straight.
6395 : * Convert always to version 2 to make version 2 datatype works with all DMs
6396 : */
6397 72 : sprintf(sql, sql_templ, odbc_swap_datetime_sql_type(fSqlType, 2));
6398 : }
6399 144 : if (SQL_SUCCESS != odbc_set_stmt_query(stmt, (ODBC_CHAR*) sql, strlen(sql) _wide0))
6400 0 : ODBC_EXIT(stmt, SQL_ERROR);
6401 :
6402 148 : redo:
6403 148 : res = odbc_SQLExecute(stmt);
6404 :
6405 148 : odbc_upper_column_names(stmt);
6406 148 : if (odbc3) {
6407 74 : odbc_col_setname(stmt, 3, "COLUMN_SIZE");
6408 74 : odbc_col_setname(stmt, 11, "FIXED_PREC_SCALE");
6409 74 : odbc_col_setname(stmt, 12, "AUTO_UNIQUE_VALUE");
6410 : }
6411 :
6412 : /* workaround for a mispelled column name in Sybase */
6413 148 : if (TDS_IS_SYBASE(stmt->dbc->tds_socket) && !odbc3)
6414 18 : odbc_col_setname(stmt, 3, "PRECISION");
6415 :
6416 148 : if (TDS_IS_MSSQL(stmt->dbc->tds_socket) || fSqlType != SQL_VARCHAR || res != SQL_SUCCESS)
6417 140 : ODBC_EXIT(stmt, res);
6418 :
6419 : /*
6420 : * Sybase return first nvarchar for char... and without length !!!
6421 : * Some program use first entry so we discard all entry before varchar
6422 : */
6423 : n = 0;
6424 36 : while (tds->current_results) {
6425 : TDSRESULTINFO *resinfo;
6426 : TDSCOLUMN *colinfo;
6427 : char *name;
6428 :
6429 : /* if next is varchar leave next for SQLFetch */
6430 36 : if (n == (varchar_pos - 1))
6431 : break;
6432 :
6433 32 : switch (tds_process_tokens(stmt->dbc->tds_socket, &result_type, &compute_id, TDS_STOPAT_ROWFMT|TDS_RETURN_ROW)) {
6434 28 : case TDS_SUCCESS:
6435 28 : if (result_type == TDS_ROW_RESULT)
6436 : break;
6437 : case TDS_NO_MORE_RESULTS:
6438 : /* discard other tokens */
6439 4 : tds_process_simple_query(tds);
6440 4 : if (n >= varchar_pos && varchar_pos > 0)
6441 : goto redo;
6442 : break;
6443 0 : case TDS_CANCELLED:
6444 0 : odbc_errs_add(&stmt->errs, "HY008", NULL);
6445 0 : res = SQL_ERROR;
6446 0 : break;
6447 : }
6448 28 : if (!tds->current_results)
6449 : break;
6450 28 : ++n;
6451 :
6452 28 : resinfo = tds->current_results;
6453 28 : colinfo = resinfo->columns[0];
6454 28 : name = (char *) colinfo->column_data;
6455 28 : if (is_blob_col(colinfo))
6456 0 : name = (char*) ((TDSBLOB *) name)->textvalue;
6457 : /* skip nvarchar and sysname */
6458 28 : if (colinfo->column_cur_size == 7 && memcmp("varchar", name, 7) == 0) {
6459 4 : varchar_pos = n;
6460 : }
6461 : }
6462 4 : ODBC_EXIT(stmt, res);
6463 : }
6464 :
6465 : #ifdef ENABLE_ODBC_WIDE
6466 : SQLRETURN ODBC_PUBLIC ODBC_API
6467 : SQLGetTypeInfoW(SQLHSTMT hstmt, SQLSMALLINT fSqlType)
6468 : {
6469 72 : return SQLGetTypeInfo(hstmt, fSqlType);
6470 : }
6471 : #endif
6472 :
6473 : static SQLRETURN
6474 618 : odbc_SQLParamData(SQLHSTMT hstmt, SQLPOINTER FAR * prgbValue)
6475 : {
6476 618 : ODBC_ENTER_HSTMT;
6477 :
6478 618 : tdsdump_log(TDS_DBG_FUNC, "SQLParamData(%p, %p) [param_num %d, param_data_called = %d]\n",
6479 : hstmt, prgbValue, stmt->param_num, stmt->param_data_called);
6480 :
6481 618 : if (stmt->params && (unsigned int) stmt->param_num <= stmt->param_count) {
6482 : SQLRETURN res;
6483 :
6484 526 : if (stmt->param_num <= 0 || stmt->param_num > stmt->apd->header.sql_desc_count) {
6485 0 : tdsdump_log(TDS_DBG_FUNC, "SQLParamData: logic_error: parameter out of bounds: 0 <= %d < %d\n",
6486 : stmt->param_num, stmt->apd->header.sql_desc_count);
6487 0 : ODBC_EXIT(stmt, SQL_ERROR);
6488 : }
6489 :
6490 : /*
6491 : * TODO compute output value with this formula:
6492 : * Bound Address + Binding Offset + ((Row Number - 1) x Element Size)
6493 : * (see SQLParamData documentation)
6494 : * This is needed for updates using SQLBulkOperation (not currently supported)
6495 : */
6496 526 : if (!stmt->param_data_called) {
6497 194 : stmt->param_data_called = 1;
6498 194 : *prgbValue = stmt->apd->records[stmt->param_num - 1].sql_desc_data_ptr;
6499 194 : ODBC_EXIT(stmt, SQL_NEED_DATA);
6500 : }
6501 332 : ++stmt->param_num;
6502 332 : switch (res = parse_prepared_query(stmt, true)) {
6503 148 : case SQL_NEED_DATA:
6504 148 : *prgbValue = stmt->apd->records[stmt->param_num - 1].sql_desc_data_ptr;
6505 148 : ODBC_EXIT(stmt, SQL_NEED_DATA);
6506 184 : case SQL_SUCCESS:
6507 184 : ODBC_EXIT(stmt, odbc_SQLExecute(stmt));
6508 : }
6509 0 : ODBC_EXIT(stmt, res);
6510 : }
6511 :
6512 92 : odbc_errs_add(&stmt->errs, "HY010", NULL);
6513 92 : ODBC_EXIT_(stmt);
6514 : }
6515 :
6516 : SQLRETURN ODBC_PUBLIC ODBC_API
6517 : SQLParamData(SQLHSTMT hstmt, SQLPOINTER FAR * prgbValue)
6518 : {
6519 : ODBC_PRRET_BUF;
6520 618 : SQLRETURN ret = odbc_SQLParamData(hstmt, prgbValue);
6521 :
6522 618 : tdsdump_log(TDS_DBG_FUNC, "SQLParamData returns %s\n", odbc_prret(ret));
6523 :
6524 618 : return ret;
6525 : }
6526 :
6527 : SQLRETURN ODBC_PUBLIC ODBC_API
6528 : SQLPutData(SQLHSTMT hstmt, SQLPOINTER rgbValue, SQLLEN cbValue)
6529 : {
6530 : ODBC_PRRET_BUF;
6531 852 : ODBC_ENTER_HSTMT;
6532 :
6533 852 : tdsdump_log(TDS_DBG_FUNC, "SQLPutData(%p, %p, %i)\n", hstmt, rgbValue, (int)cbValue);
6534 :
6535 852 : if (stmt->param_data_called) {
6536 : SQLRETURN ret;
6537 852 : const TDSCOLUMN *curcol = stmt->params->columns[stmt->param_num - (stmt->prepared_query_is_func ? 2 : 1)];
6538 : /* TODO do some more tests before setting this flag */
6539 852 : stmt->param_data_called = 1;
6540 852 : ret = continue_parse_prepared_query(stmt, rgbValue, cbValue);
6541 852 : tdsdump_log(TDS_DBG_FUNC, "SQLPutData returns %s, %d bytes left\n",
6542 : odbc_prret(ret), curcol->column_size - curcol->column_cur_size);
6543 852 : ODBC_EXIT(stmt, ret);
6544 : }
6545 :
6546 0 : odbc_errs_add(&stmt->errs, "HY010", NULL);
6547 0 : ODBC_EXIT_(stmt);
6548 : }
6549 :
6550 :
6551 1901 : ODBC_FUNC(SQLSetConnectAttr, (P(SQLHDBC,hdbc), P(SQLINTEGER,Attribute), P(SQLPOINTER,ValuePtr), P(SQLINTEGER,StringLength) WIDE))
6552 : {
6553 1901 : SQLULEN u_value = (SQLULEN) (TDS_INTPTR) ValuePtr;
6554 :
6555 1901 : ODBC_ENTER_HDBC;
6556 :
6557 1901 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLSetConnectAttr(%p, %d, %p, %d)\n", hdbc, (int)Attribute, ValuePtr, (int)StringLength);
6558 :
6559 1901 : switch (Attribute) {
6560 218 : case SQL_ATTR_AUTOCOMMIT:
6561 : /* spinellia@acm.org */
6562 218 : change_autocommit(dbc, (int) u_value);
6563 218 : break;
6564 10 : case SQL_ATTR_CONNECTION_TIMEOUT:
6565 10 : dbc->attr.connection_timeout = (SQLUINTEGER) u_value;
6566 10 : break;
6567 0 : case SQL_ATTR_ACCESS_MODE:
6568 0 : dbc->attr.access_mode = (SQLUINTEGER) u_value;
6569 0 : break;
6570 80 : case SQL_ATTR_CURRENT_CATALOG:
6571 80 : if (!IS_VALID_LEN(StringLength)) {
6572 0 : odbc_errs_add(&dbc->errs, "HY090", NULL);
6573 0 : break;
6574 : }
6575 : {
6576 80 : DSTR s = DSTR_INITIALIZER;
6577 :
6578 80 : if (!odbc_dstr_copy_oct(dbc, &s, StringLength, (ODBC_CHAR*) ValuePtr)) {
6579 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
6580 0 : break;
6581 : }
6582 240 : change_database(dbc, tds_dstr_cstr(&s), tds_dstr_len(&s));
6583 80 : tds_dstr_free(&s);
6584 : }
6585 80 : break;
6586 0 : case SQL_ATTR_CURSOR_TYPE:
6587 0 : if (dbc->cursor_support)
6588 0 : dbc->attr.cursor_type = (SQLUINTEGER) u_value;
6589 : break;
6590 10 : case SQL_ATTR_LOGIN_TIMEOUT:
6591 10 : dbc->attr.login_timeout = (SQLUINTEGER) u_value;
6592 10 : break;
6593 0 : case SQL_ATTR_ODBC_CURSORS:
6594 : /* TODO cursors */
6595 0 : dbc->attr.odbc_cursors = (SQLUINTEGER) u_value;
6596 0 : break;
6597 0 : case SQL_ATTR_PACKET_SIZE:
6598 0 : dbc->attr.packet_size = (SQLUINTEGER) u_value;
6599 0 : break;
6600 0 : case SQL_ATTR_QUIET_MODE:
6601 0 : dbc->attr.quite_mode = (SQLHWND) (TDS_INTPTR) ValuePtr;
6602 0 : break;
6603 : #ifdef TDS_NO_DM
6604 0 : case SQL_ATTR_TRACE:
6605 0 : dbc->attr.trace = (SQLUINTEGER) u_value;
6606 0 : break;
6607 0 : case SQL_ATTR_TRACEFILE:
6608 0 : if (!IS_VALID_LEN(StringLength)) {
6609 0 : odbc_errs_add(&dbc->errs, "HY090", NULL);
6610 0 : break;
6611 : }
6612 0 : if (!odbc_dstr_copy(dbc, &dbc->attr.tracefile, StringLength, (ODBC_CHAR *) ValuePtr))
6613 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
6614 : break;
6615 : #endif
6616 104 : case SQL_ATTR_TXN_ISOLATION:
6617 104 : if (u_value != dbc->attr.txn_isolation) {
6618 92 : if (change_txn(dbc, (SQLUINTEGER) u_value) == SQL_SUCCESS)
6619 72 : dbc->attr.txn_isolation = (SQLUINTEGER)u_value;
6620 : }
6621 : break;
6622 553 : case SQL_COPT_SS_MARS_ENABLED:
6623 553 : dbc->attr.mars_enabled = (SQLUINTEGER) u_value;
6624 553 : break;
6625 0 : case SQL_ATTR_TRANSLATE_LIB:
6626 : case SQL_ATTR_TRANSLATE_OPTION:
6627 0 : odbc_errs_add(&dbc->errs, "HYC00", NULL);
6628 0 : break;
6629 2 : case SQL_COPT_SS_OLDPWD:
6630 2 : if (!IS_VALID_LEN(StringLength)) {
6631 0 : odbc_errs_add(&dbc->errs, "HY090", NULL);
6632 0 : break;
6633 : }
6634 2 : if (!odbc_dstr_copy_oct(dbc, &dbc->oldpwd, StringLength, (ODBC_CHAR *) ValuePtr))
6635 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
6636 : else
6637 2 : dbc->use_oldpwd = 1;
6638 : break;
6639 0 : case SQL_COPT_SS_ATTACHDBFILENAME:
6640 0 : if (!IS_VALID_LEN(StringLength)) {
6641 0 : odbc_errs_add(&dbc->errs, "HY090", NULL);
6642 0 : break;
6643 : }
6644 0 : if (!odbc_dstr_copy(dbc, &dbc->db_filename, StringLength, (ODBC_CHAR *) ValuePtr))
6645 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
6646 : break;
6647 10 : case SQL_COPT_SS_BCP:
6648 10 : dbc->attr.bulk_enabled = (SQLUINTEGER) u_value;
6649 10 : break;
6650 12 : case SQL_COPT_TDSODBC_IMPL_BCP_INITA:
6651 12 : if (!ValuePtr)
6652 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
6653 : else {
6654 12 : const struct tdsodbc_impl_bcp_init_params *params = (const struct tdsodbc_impl_bcp_init_params*)ValuePtr;
6655 24 : odbc_bcp_init(dbc, (const ODBC_CHAR *) params->tblname, (const ODBC_CHAR *) params->hfile,
6656 12 : (const ODBC_CHAR *) params->errfile, params->direction _wide0);
6657 : }
6658 : break;
6659 14 : case SQL_COPT_TDSODBC_DATETIME_FORMAT:
6660 14 : if (!odbc_dstr_copy(dbc, &dbc->datetime_fmt, StringLength, (ODBC_CHAR *) ValuePtr))
6661 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
6662 : break;
6663 4 : case SQL_COPT_TDSODBC_DATE_FORMAT:
6664 4 : if (!odbc_dstr_copy(dbc, &dbc->date_fmt, StringLength, (ODBC_CHAR *) ValuePtr))
6665 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
6666 : break;
6667 4 : case SQL_COPT_TDSODBC_TIME_FORMAT:
6668 4 : if (!odbc_dstr_copy(dbc, &dbc->time_fmt, StringLength, (ODBC_CHAR *) ValuePtr))
6669 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
6670 : break;
6671 : #ifdef ENABLE_ODBC_WIDE
6672 12 : case SQL_COPT_TDSODBC_IMPL_BCP_INITW:
6673 12 : if (!ValuePtr)
6674 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
6675 : else {
6676 12 : const struct tdsodbc_impl_bcp_init_params *params = (const struct tdsodbc_impl_bcp_init_params*)ValuePtr;
6677 24 : odbc_bcp_init(dbc, (const ODBC_CHAR *) params->tblname, (const ODBC_CHAR *) params->hfile,
6678 12 : (const ODBC_CHAR *) params->errfile, params->direction, 1);
6679 : }
6680 : break;
6681 : #endif
6682 0 : case SQL_COPT_TDSODBC_IMPL_BCP_CONTROL_OLD:
6683 0 : if (!ValuePtr)
6684 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
6685 : else {
6686 0 : const struct tdsodbc_impl_bcp_control_params *params =
6687 : (const struct tdsodbc_impl_bcp_control_params*)ValuePtr;
6688 0 : const int field = params->field == BCPHINTS_OLD ? BCPHINTSA : params->field;
6689 0 : odbc_bcp_control(dbc, field, params->value);
6690 : }
6691 : break;
6692 4 : case SQL_COPT_TDSODBC_IMPL_BCP_CONTROL:
6693 4 : if (!ValuePtr)
6694 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
6695 : else {
6696 4 : const struct tdsodbc_impl_bcp_control_params *params =
6697 : (const struct tdsodbc_impl_bcp_control_params*)ValuePtr;
6698 4 : odbc_bcp_control(dbc, params->field, params->value);
6699 : }
6700 : break;
6701 0 : case SQL_COPT_TDSODBC_IMPL_BCP_COLPTR:
6702 0 : if (!ValuePtr)
6703 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
6704 : else {
6705 0 : const struct tdsodbc_impl_bcp_colptr_params *params =
6706 : (const struct tdsodbc_impl_bcp_colptr_params*)ValuePtr;
6707 0 : odbc_bcp_colptr(dbc, params->colptr, params->table_column);
6708 : }
6709 : break;
6710 204 : case SQL_COPT_TDSODBC_IMPL_BCP_SENDROW:
6711 204 : if (ValuePtr)
6712 0 : odbc_errs_add(&dbc->errs, "HY000", NULL);
6713 : else
6714 204 : odbc_bcp_sendrow(dbc);
6715 : break;
6716 24 : case SQL_COPT_TDSODBC_IMPL_BCP_BATCH:
6717 24 : if (!ValuePtr)
6718 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
6719 : else {
6720 24 : struct tdsodbc_impl_bcp_batch_params *params = (struct tdsodbc_impl_bcp_batch_params*)ValuePtr;
6721 24 : params->rows = odbc_bcp_batch(dbc);
6722 : }
6723 : break;
6724 24 : case SQL_COPT_TDSODBC_IMPL_BCP_DONE:
6725 24 : if (!ValuePtr)
6726 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
6727 : else {
6728 24 : struct tdsodbc_impl_bcp_done_params *params = (struct tdsodbc_impl_bcp_done_params*)ValuePtr;
6729 24 : params->rows = odbc_bcp_done(dbc);
6730 : }
6731 : break;
6732 612 : case SQL_COPT_TDSODBC_IMPL_BCP_BIND:
6733 612 : if (!ValuePtr)
6734 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
6735 : else {
6736 612 : const struct tdsodbc_impl_bcp_bind_params *params = (const struct tdsodbc_impl_bcp_bind_params*)ValuePtr;
6737 1224 : odbc_bcp_bind(dbc, params->varaddr, params->prefixlen, params->varlen,
6738 612 : params->terminator, params->termlen, params->vartype, params->table_column);
6739 : }
6740 : break;
6741 0 : default:
6742 0 : odbc_errs_add(&dbc->errs, "HY092", NULL);
6743 0 : break;
6744 : }
6745 1901 : ODBC_EXIT_(dbc);
6746 : }
6747 :
6748 : SQLRETURN ODBC_PUBLIC ODBC_API
6749 : SQLSetConnectOption(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLULEN vParam)
6750 : {
6751 0 : tdsdump_log(TDS_DBG_FUNC, "SQLSetConnectOption(%p, %d, %p)\n", hdbc, fOption, (SQLPOINTER) (TDS_INTPTR) vParam);
6752 :
6753 0 : return odbc_SQLSetConnectAttr(hdbc, (SQLINTEGER) fOption, (SQLPOINTER) (TDS_INTPTR) vParam, SQL_NTS _wide0);
6754 : }
6755 :
6756 : #ifdef ENABLE_ODBC_WIDE
6757 : SQLRETURN ODBC_PUBLIC ODBC_API
6758 : SQLSetConnectOptionW(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLULEN vParam)
6759 : {
6760 0 : tdsdump_log(TDS_DBG_FUNC, "SQLSetConnectOptionW(%p, %d, %p)\n", hdbc, fOption, (SQLPOINTER) (TDS_INTPTR) vParam);
6761 :
6762 0 : return odbc_SQLSetConnectAttr(hdbc, (SQLINTEGER) fOption, (SQLPOINTER) (TDS_INTPTR) vParam, SQL_NTS, 1);
6763 : }
6764 : #endif
6765 :
6766 : static SQLRETURN
6767 6632 : odbc_SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength WIDE)
6768 : {
6769 6632 : SQLULEN ui = (SQLULEN) (TDS_INTPTR) ValuePtr;
6770 6632 : SQLUSMALLINT *usip = (SQLUSMALLINT *) ValuePtr;
6771 6632 : SQLLEN *lp = (SQLLEN *) ValuePtr;
6772 6632 : SQLULEN *ulp = (SQLULEN *) ValuePtr;
6773 :
6774 6632 : ODBC_ENTER_HSTMT;
6775 :
6776 6632 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLSetStmtAttr(%p, %d, %p, %d)\n", hstmt, (int)Attribute, ValuePtr, (int)StringLength);
6777 :
6778 : /* TODO - error checking and real functionality :-) */
6779 : /* TODO some setting set also other attribute, see documentation */
6780 6632 : switch (Attribute) {
6781 : /* TODO check SQLFreeHandle on descriptor. Is possible to free an associated descriptor ? */
6782 0 : case SQL_ATTR_APP_PARAM_DESC:
6783 : case SQL_ATTR_APP_ROW_DESC:
6784 : {
6785 : TDS_DESC *orig;
6786 : TDS_DESC **curr;
6787 0 : TDS_DESC *val = (TDS_DESC *) ValuePtr;
6788 :
6789 0 : if (Attribute == SQL_ATTR_APP_PARAM_DESC) {
6790 0 : orig = stmt->orig_apd;
6791 0 : curr = &stmt->apd;
6792 : } else {
6793 0 : orig = stmt->orig_ard;
6794 0 : curr = &stmt->ard;
6795 : }
6796 : /* if ValuePtr is NULL or original descriptor set original */
6797 0 : if (!val || val == orig) {
6798 0 : *curr = orig;
6799 0 : break;
6800 : }
6801 :
6802 : /* must be allocated by user, not implicit ones */
6803 0 : if (val->header.sql_desc_alloc_type != SQL_DESC_ALLOC_USER) {
6804 0 : odbc_errs_add(&stmt->errs, "HY017", NULL);
6805 0 : break;
6806 : }
6807 : /* TODO check HDESC (not associated, from DBC HY024) */
6808 0 : *curr = val;
6809 : }
6810 0 : break;
6811 0 : case SQL_ATTR_ASYNC_ENABLE:
6812 0 : if (stmt->attr.async_enable != ui) {
6813 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
6814 0 : break;
6815 : }
6816 0 : stmt->attr.async_enable = (SQLUINTEGER) ui;
6817 0 : break;
6818 298 : case SQL_ATTR_CONCURRENCY:
6819 298 : if (stmt->attr.concurrency != ui && !stmt->dbc->cursor_support) {
6820 26 : odbc_errs_add(&stmt->errs, "01S02", NULL);
6821 26 : break;
6822 : }
6823 :
6824 272 : if (stmt->cursor) {
6825 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
6826 0 : break;
6827 : }
6828 :
6829 272 : switch (ui) {
6830 72 : case SQL_CONCUR_READ_ONLY:
6831 72 : stmt->attr.cursor_sensitivity = SQL_INSENSITIVE;
6832 72 : break;
6833 200 : case SQL_CONCUR_LOCK:
6834 : case SQL_CONCUR_ROWVER:
6835 : case SQL_CONCUR_VALUES:
6836 200 : stmt->attr.cursor_sensitivity = SQL_SENSITIVE;
6837 200 : break;
6838 0 : default:
6839 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
6840 0 : ODBC_EXIT_(stmt);
6841 : }
6842 272 : stmt->attr.concurrency = (SQLUINTEGER) ui;
6843 272 : break;
6844 2098 : case SQL_ATTR_CURSOR_SCROLLABLE:
6845 2098 : if (stmt->attr.cursor_scrollable != ui && !stmt->dbc->cursor_support) {
6846 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
6847 0 : break;
6848 : }
6849 :
6850 2098 : switch (ui) {
6851 2050 : case SQL_SCROLLABLE:
6852 2050 : stmt->attr.cursor_type = SQL_CURSOR_KEYSET_DRIVEN;
6853 2050 : break;
6854 48 : case SQL_NONSCROLLABLE:
6855 48 : stmt->attr.cursor_type = SQL_CURSOR_FORWARD_ONLY;
6856 48 : break;
6857 0 : default:
6858 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
6859 0 : ODBC_EXIT_(stmt);
6860 : }
6861 2098 : stmt->attr.cursor_scrollable = (SQLUINTEGER) ui;
6862 2098 : break;
6863 72 : case SQL_ATTR_CURSOR_SENSITIVITY:
6864 : /* don't change anything */
6865 72 : if (ui == SQL_UNSPECIFIED)
6866 : break;
6867 72 : if (stmt->attr.cursor_sensitivity != ui && !stmt->dbc->cursor_support) {
6868 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
6869 0 : break;
6870 : }
6871 72 : switch (ui) {
6872 0 : case SQL_INSENSITIVE:
6873 0 : stmt->attr.concurrency = SQL_CONCUR_READ_ONLY;
6874 0 : stmt->attr.cursor_type = SQL_CURSOR_STATIC;
6875 0 : break;
6876 72 : case SQL_SENSITIVE:
6877 72 : stmt->attr.concurrency = SQL_CONCUR_ROWVER;
6878 72 : break;
6879 : }
6880 72 : stmt->attr.cursor_sensitivity = (SQLUINTEGER) ui;
6881 72 : break;
6882 2218 : case SQL_ATTR_CURSOR_TYPE:
6883 2218 : if (stmt->attr.cursor_type != ui && !stmt->dbc->cursor_support) {
6884 0 : odbc_errs_add(&stmt->errs, "01S02", NULL);
6885 0 : break;
6886 : }
6887 :
6888 2218 : if (stmt->cursor) {
6889 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
6890 0 : break;
6891 : }
6892 :
6893 2218 : switch (ui) {
6894 2138 : case SQL_CURSOR_DYNAMIC:
6895 : case SQL_CURSOR_KEYSET_DRIVEN:
6896 2138 : if (stmt->attr.concurrency != SQL_CONCUR_READ_ONLY)
6897 88 : stmt->attr.cursor_sensitivity = SQL_SENSITIVE;
6898 2138 : stmt->attr.cursor_scrollable = SQL_SCROLLABLE;
6899 2138 : break;
6900 80 : case SQL_CURSOR_STATIC:
6901 80 : if (stmt->attr.concurrency != SQL_CONCUR_READ_ONLY)
6902 0 : stmt->attr.cursor_sensitivity = SQL_SENSITIVE;
6903 : else
6904 80 : stmt->attr.cursor_sensitivity = SQL_INSENSITIVE;
6905 80 : stmt->attr.cursor_scrollable = SQL_SCROLLABLE;
6906 80 : break;
6907 0 : case SQL_CURSOR_FORWARD_ONLY:
6908 0 : stmt->attr.cursor_scrollable = SQL_NONSCROLLABLE;
6909 0 : break;
6910 0 : default:
6911 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
6912 0 : ODBC_EXIT_(stmt);
6913 : }
6914 2218 : stmt->attr.cursor_type = (SQLUINTEGER) ui;
6915 2218 : break;
6916 0 : case SQL_ATTR_ENABLE_AUTO_IPD:
6917 0 : if (stmt->attr.enable_auto_ipd != ui) {
6918 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
6919 0 : break;
6920 : }
6921 0 : stmt->attr.enable_auto_ipd = (SQLUINTEGER) ui;
6922 0 : break;
6923 0 : case SQL_ATTR_FETCH_BOOKMARK_PTR:
6924 0 : stmt->attr.fetch_bookmark_ptr = ValuePtr;
6925 0 : break;
6926 0 : case SQL_ATTR_IMP_ROW_DESC:
6927 : case SQL_ATTR_IMP_PARAM_DESC:
6928 0 : odbc_errs_add(&stmt->errs, "HY017", NULL);
6929 0 : break;
6930 : /* TODO what's is this ??? */
6931 0 : case SQL_ATTR_KEYSET_SIZE:
6932 0 : stmt->attr.keyset_size = ui;
6933 0 : break;
6934 : /* TODO max length of data returned. Use SQL TEXTSIZE or just truncate ?? */
6935 0 : case SQL_ATTR_MAX_LENGTH:
6936 0 : if (stmt->attr.max_length != ui) {
6937 0 : odbc_errs_add(&stmt->errs, "01S02", NULL);
6938 0 : break;
6939 : }
6940 0 : stmt->attr.max_length = ui;
6941 0 : break;
6942 : /* TODO max row returned. Use SET ROWCOUNT */
6943 0 : case SQL_ATTR_MAX_ROWS:
6944 0 : if (stmt->attr.max_rows != ui) {
6945 0 : odbc_errs_add(&stmt->errs, "01S02", NULL);
6946 0 : break;
6947 : }
6948 0 : stmt->attr.max_rows = ui;
6949 0 : break;
6950 0 : case SQL_ATTR_METADATA_ID:
6951 0 : stmt->attr.metadata_id = (SQLUINTEGER) ui;
6952 0 : break;
6953 : /* TODO use it !!! */
6954 0 : case SQL_ATTR_NOSCAN:
6955 0 : stmt->attr.noscan = (SQLUINTEGER) ui;
6956 0 : break;
6957 10 : case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
6958 10 : stmt->apd->header.sql_desc_bind_offset_ptr = lp;
6959 10 : break;
6960 124 : case SQL_ATTR_PARAM_BIND_TYPE:
6961 124 : stmt->apd->header.sql_desc_bind_type = (SQLUINTEGER) ui;
6962 124 : break;
6963 0 : case SQL_ATTR_PARAM_OPERATION_PTR:
6964 0 : stmt->apd->header.sql_desc_array_status_ptr = usip;
6965 0 : break;
6966 82 : case SQL_ATTR_PARAM_STATUS_PTR:
6967 82 : stmt->ipd->header.sql_desc_array_status_ptr = usip;
6968 82 : break;
6969 154 : case SQL_ATTR_PARAMS_PROCESSED_PTR:
6970 154 : stmt->ipd->header.sql_desc_rows_processed_ptr = ulp;
6971 154 : break;
6972 : /* allow to exec procedure multiple time */
6973 174 : case SQL_ATTR_PARAMSET_SIZE:
6974 174 : stmt->apd->header.sql_desc_array_size = ui;
6975 174 : break;
6976 136 : case SQL_ATTR_QUERY_TIMEOUT:
6977 : /* Microsoft allows a maximum value of 65534 */
6978 136 : if (ui > 65534) {
6979 8 : odbc_errs_add(&stmt->errs, "01S02", NULL);
6980 8 : ui = 65534;
6981 : }
6982 136 : stmt->attr.query_timeout = (SQLUINTEGER) ui;
6983 136 : break;
6984 : /* retrieve data after positioning the cursor */
6985 0 : case SQL_ATTR_RETRIEVE_DATA:
6986 : /* TODO cursors */
6987 0 : if (stmt->attr.retrieve_data != ui) {
6988 0 : odbc_errs_add(&stmt->errs, "01S02", NULL);
6989 0 : break;
6990 : }
6991 0 : stmt->attr.retrieve_data = (SQLUINTEGER) ui;
6992 0 : break;
6993 312 : case SQL_ATTR_ROW_ARRAY_SIZE:
6994 312 : stmt->ard->header.sql_desc_array_size = ui;
6995 312 : break;
6996 30 : case SQL_ATTR_ROW_BIND_OFFSET_PTR:
6997 : /* TODO test what happen with column-wise and row-wise bindings and SQLGetData */
6998 30 : stmt->ard->header.sql_desc_bind_offset_ptr = lp;
6999 30 : break;
7000 : #if SQL_BIND_TYPE != SQL_ATTR_ROW_BIND_TYPE
7001 : case SQL_BIND_TYPE: /* although this is ODBC2 we must support this attribute */
7002 : #endif
7003 234 : case SQL_ATTR_ROW_BIND_TYPE:
7004 234 : stmt->ard->header.sql_desc_bind_type = (SQLUINTEGER) ui;
7005 234 : break;
7006 0 : case SQL_ATTR_ROW_NUMBER:
7007 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
7008 0 : break;
7009 0 : case SQL_ATTR_ROW_OPERATION_PTR:
7010 0 : stmt->ard->header.sql_desc_array_status_ptr = usip;
7011 0 : break;
7012 264 : case SQL_ATTR_ROW_STATUS_PTR:
7013 264 : stmt->ird->header.sql_desc_array_status_ptr = usip;
7014 264 : break;
7015 292 : case SQL_ATTR_ROWS_FETCHED_PTR:
7016 292 : stmt->ird->header.sql_desc_rows_processed_ptr = ulp;
7017 292 : break;
7018 0 : case SQL_ATTR_SIMULATE_CURSOR:
7019 : /* TODO cursors */
7020 0 : if (stmt->cursor) {
7021 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
7022 0 : break;
7023 : }
7024 0 : if (stmt->attr.simulate_cursor != ui) {
7025 0 : odbc_errs_add(&stmt->errs, "01S02", NULL);
7026 0 : break;
7027 : }
7028 0 : stmt->attr.simulate_cursor = (SQLUINTEGER) ui;
7029 0 : break;
7030 0 : case SQL_ATTR_USE_BOOKMARKS:
7031 0 : if (stmt->cursor) {
7032 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
7033 0 : break;
7034 : }
7035 0 : stmt->attr.use_bookmarks = (SQLUINTEGER) ui;
7036 0 : break;
7037 66 : case SQL_ROWSET_SIZE: /* although this is ODBC2 we must support this attribute */
7038 66 : if (((TDS_INTPTR) ValuePtr) < 1) {
7039 30 : odbc_errs_add(&stmt->errs, "HY024", NULL);
7040 30 : break;
7041 : }
7042 36 : stmt->sql_rowset_size = ui;
7043 36 : break;
7044 4 : case SQL_SOPT_SS_QUERYNOTIFICATION_TIMEOUT:
7045 4 : if (ui < 1) {
7046 0 : odbc_errs_add(&stmt->errs, "HY024", NULL);
7047 0 : break;
7048 : }
7049 4 : stmt->attr.qn_timeout = (SQLUINTEGER) ui;
7050 4 : break;
7051 4 : case SQL_SOPT_SS_QUERYNOTIFICATION_MSGTEXT:
7052 4 : if (!IS_VALID_LEN(StringLength)) {
7053 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
7054 0 : break;
7055 : }
7056 4 : if (!odbc_dstr_copy_oct(stmt->dbc, &stmt->attr.qn_msgtext, StringLength, (ODBC_CHAR*) ValuePtr)) {
7057 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
7058 0 : break;
7059 : }
7060 : break;
7061 4 : case SQL_SOPT_SS_QUERYNOTIFICATION_OPTIONS:
7062 4 : if (!IS_VALID_LEN(StringLength)) {
7063 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
7064 0 : break;
7065 : }
7066 4 : if (!odbc_dstr_copy_oct(stmt->dbc, &stmt->attr.qn_options, StringLength, (ODBC_CHAR*) ValuePtr)) {
7067 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
7068 0 : break;
7069 : }
7070 : break;
7071 56 : case SQL_SOPT_SS_PARAM_FOCUS:
7072 56 : if (ui > 0 && (ui > stmt->apd->header.sql_desc_count
7073 32 : || stmt->ipd->records[ui - 1].sql_desc_concise_type != SQL_SS_TABLE)) {
7074 4 : odbc_errs_add(&stmt->errs, "IM020", NULL);
7075 4 : break;
7076 : }
7077 52 : stmt->attr.param_focus = (SQLUINTEGER) ui;
7078 52 : stmt->orig_apd->focus = (int) ui;
7079 52 : stmt->ipd->focus = (int) ui;
7080 52 : break;
7081 0 : default:
7082 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
7083 0 : break;
7084 : }
7085 6632 : ODBC_EXIT_(stmt);
7086 : }
7087 :
7088 : #if (ODBCVER >= 0x0300)
7089 : SQLRETURN ODBC_PUBLIC ODBC_API
7090 : SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength)
7091 : {
7092 3292 : tdsdump_log(TDS_DBG_FUNC, "SQLSetStmtAttr(%p, %d, %p, %d)\n",
7093 : hstmt, (int)Attribute, ValuePtr, (int)StringLength);
7094 :
7095 3292 : return odbc_SQLSetStmtAttr(hstmt, Attribute, ValuePtr, StringLength _wide0);
7096 : }
7097 :
7098 : #ifdef ENABLE_ODBC_WIDE
7099 : SQLRETURN ODBC_PUBLIC ODBC_API
7100 : SQLSetStmtAttrW(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength)
7101 : {
7102 3292 : tdsdump_log(TDS_DBG_FUNC, "SQLSetStmtAttr(%p, %d, %p, %d)\n",
7103 : hstmt, (int)Attribute, ValuePtr, (int)StringLength);
7104 :
7105 3292 : return odbc_SQLSetStmtAttr(hstmt, Attribute, ValuePtr, StringLength, 1);
7106 : }
7107 : #endif
7108 : #endif
7109 :
7110 : SQLRETURN ODBC_PUBLIC ODBC_API
7111 : SQLSetStmtOption(SQLHSTMT hstmt, SQLUSMALLINT fOption, SQLULEN vParam)
7112 : {
7113 8 : tdsdump_log(TDS_DBG_FUNC, "SQLSetStmtOption(%p, %u, %u)\n", hstmt, fOption, (unsigned)vParam);
7114 :
7115 : /* XXX: Lost precision */
7116 8 : return odbc_SQLSetStmtAttr(hstmt, (SQLINTEGER) fOption, (SQLPOINTER) (TDS_INTPTR) vParam, SQL_NTS _wide0);
7117 : }
7118 :
7119 0 : ODBC_FUNC(SQLSpecialColumns, (P(SQLHSTMT,hstmt), P(SQLUSMALLINT,fColType), PCHARIN(CatalogName,SQLSMALLINT),
7120 : PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT),
7121 : P(SQLUSMALLINT,fScope), P(SQLUSMALLINT,fNullable) WIDE))
7122 : {
7123 : int retcode;
7124 : char nullable, scope, col_type;
7125 :
7126 0 : ODBC_ENTER_HSTMT;
7127 :
7128 0 : tdsdump_log(TDS_DBG_FUNC, "SQLSpecialColumns(%p, %d, %p, %d, %p, %d, %p, %d, %d, %d)\n",
7129 : hstmt, fColType, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName,
7130 : fScope, fNullable);
7131 :
7132 : #ifdef TDS_NO_DM
7133 : /* Check column type */
7134 0 : if (fColType != SQL_BEST_ROWID && fColType != SQL_ROWVER) {
7135 0 : odbc_errs_add(&stmt->errs, "HY097", NULL);
7136 0 : ODBC_EXIT_(stmt);
7137 : }
7138 :
7139 : /* check our buffer lengths */
7140 0 : if (!IS_VALID_LEN(cbCatalogName) || !IS_VALID_LEN(cbSchemaName) || !IS_VALID_LEN(cbTableName)) {
7141 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
7142 0 : ODBC_EXIT_(stmt);
7143 : }
7144 :
7145 : /* Check nullable */
7146 0 : if (fNullable != SQL_NO_NULLS && fNullable != SQL_NULLABLE) {
7147 0 : odbc_errs_add(&stmt->errs, "HY099", NULL);
7148 0 : ODBC_EXIT_(stmt);
7149 : }
7150 :
7151 0 : if (!odbc_get_string_size(cbTableName, szTableName _wide)) {
7152 0 : odbc_errs_add(&stmt->errs, "HY009", "SQLSpecialColumns: The table name parameter is required");
7153 0 : ODBC_EXIT_(stmt);
7154 : }
7155 :
7156 0 : switch (fScope) {
7157 : case SQL_SCOPE_CURROW:
7158 : case SQL_SCOPE_TRANSACTION:
7159 : case SQL_SCOPE_SESSION:
7160 : break;
7161 0 : default:
7162 0 : odbc_errs_add(&stmt->errs, "HY098", NULL);
7163 0 : ODBC_EXIT_(stmt);
7164 : }
7165 : #endif
7166 :
7167 0 : if (fNullable == SQL_NO_NULLS)
7168 0 : nullable = 'O';
7169 : else
7170 0 : nullable = 'U';
7171 :
7172 0 : if (fScope == SQL_SCOPE_CURROW)
7173 0 : scope = 'C';
7174 : else
7175 0 : scope = 'T';
7176 :
7177 0 : if (fColType == SQL_BEST_ROWID)
7178 0 : col_type = 'R';
7179 : else
7180 0 : col_type = 'V';
7181 :
7182 0 : retcode =
7183 0 : odbc_stat_execute(stmt _wide, "sp_special_columns", TDS_IS_MSSQL(stmt->dbc->tds_socket) ? 7 : 4, "O", szTableName,
7184 : cbTableName, "O", szSchemaName, cbSchemaName, "O@qualifier", szCatalogName, cbCatalogName,
7185 : "!@col_type", &col_type, 1, "!@scope", &scope, 1, "!@nullable", &nullable, 1,
7186 : "V@ODBCVer", (char*) NULL, 0);
7187 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
7188 0 : odbc_col_setname(stmt, 5, "COLUMN_SIZE");
7189 0 : odbc_col_setname(stmt, 6, "BUFFER_LENGTH");
7190 0 : odbc_col_setname(stmt, 7, "DECIMAL_DIGITS");
7191 0 : if (TDS_IS_SYBASE(stmt->dbc->tds_socket))
7192 0 : stmt->special_row = ODBC_SPECIAL_SPECIALCOLUMNS;
7193 : }
7194 0 : ODBC_EXIT_(stmt);
7195 : }
7196 :
7197 0 : ODBC_FUNC(SQLStatistics, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
7198 : PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT), P(SQLUSMALLINT,fUnique),
7199 : P(SQLUSMALLINT,fAccuracy) WIDE))
7200 : {
7201 : int retcode;
7202 : char unique, accuracy;
7203 :
7204 0 : ODBC_ENTER_HSTMT;
7205 :
7206 0 : tdsdump_log(TDS_DBG_FUNC, "SQLStatistics(%p, %p, %d, %p, %d, %p, %d, %d, %d)\n",
7207 : hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName,
7208 : fUnique, fAccuracy);
7209 :
7210 : #ifdef TDS_NO_DM
7211 : /* check our buffer lengths */
7212 0 : if (!IS_VALID_LEN(cbCatalogName) || !IS_VALID_LEN(cbSchemaName) || !IS_VALID_LEN(cbTableName)) {
7213 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
7214 0 : ODBC_EXIT_(stmt);
7215 : }
7216 :
7217 : /* check our uniqueness value */
7218 0 : if (fUnique != SQL_INDEX_UNIQUE && fUnique != SQL_INDEX_ALL) {
7219 0 : odbc_errs_add(&stmt->errs, "HY100", NULL);
7220 0 : ODBC_EXIT_(stmt);
7221 : }
7222 :
7223 : /* check our accuracy value */
7224 0 : if (fAccuracy != SQL_QUICK && fAccuracy != SQL_ENSURE) {
7225 0 : odbc_errs_add(&stmt->errs, "HY101", NULL);
7226 0 : ODBC_EXIT_(stmt);
7227 : }
7228 :
7229 0 : if (!odbc_get_string_size(cbTableName, szTableName _wide)) {
7230 0 : odbc_errs_add(&stmt->errs, "HY009", NULL);
7231 0 : ODBC_EXIT_(stmt);
7232 : }
7233 : #endif
7234 :
7235 0 : if (fAccuracy == SQL_ENSURE)
7236 0 : accuracy = 'E';
7237 : else
7238 0 : accuracy = 'Q';
7239 :
7240 0 : if (fUnique == SQL_INDEX_UNIQUE)
7241 0 : unique = 'Y';
7242 : else
7243 0 : unique = 'N';
7244 :
7245 0 : retcode =
7246 0 : odbc_stat_execute(stmt _wide, "sp_statistics", TDS_IS_MSSQL(stmt->dbc->tds_socket) ? 5 : 4, "O@table_qualifier",
7247 : szCatalogName, cbCatalogName, "O@table_owner", szSchemaName, cbSchemaName, "O@table_name",
7248 : szTableName, cbTableName, "!@is_unique", &unique, 1, "!@accuracy", &accuracy, 1);
7249 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
7250 0 : odbc_col_setname(stmt, 1, "TABLE_CAT");
7251 0 : odbc_col_setname(stmt, 2, "TABLE_SCHEM");
7252 0 : odbc_col_setname(stmt, 8, "ORDINAL_POSITION");
7253 0 : odbc_col_setname(stmt, 10, "ASC_OR_DESC");
7254 : }
7255 0 : ODBC_EXIT_(stmt);
7256 : }
7257 :
7258 128 : ODBC_FUNC(SQLTables, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
7259 : PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT), PCHARIN(TableType,SQLSMALLINT) WIDE))
7260 : {
7261 : int retcode;
7262 128 : const char *proc = NULL;
7263 : int wildcards;
7264 : TDSSOCKET *tds;
7265 128 : DSTR schema_name = DSTR_INITIALIZER;
7266 128 : DSTR catalog_name = DSTR_INITIALIZER;
7267 128 : DSTR table_name = DSTR_INITIALIZER;
7268 128 : DSTR table_type = DSTR_INITIALIZER;
7269 :
7270 128 : ODBC_ENTER_HSTMT;
7271 :
7272 128 : tdsdump_log(TDS_DBG_FUNC, "SQLTables(%p, %p, %d, %p, %d, %p, %d, %p, %d)\n",
7273 : hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName,
7274 : szTableType, cbTableType);
7275 :
7276 128 : tds = stmt->dbc->tds_socket;
7277 :
7278 128 : if (!odbc_dstr_copy(stmt->dbc, &catalog_name, cbCatalogName, szCatalogName)
7279 128 : || !odbc_dstr_copy(stmt->dbc, &schema_name, cbSchemaName, szSchemaName)
7280 128 : || !odbc_dstr_copy(stmt->dbc, &table_name, cbTableName, szTableName)
7281 128 : || !odbc_dstr_copy(stmt->dbc, &table_type, cbTableType, szTableType))
7282 : goto memory_error;
7283 :
7284 128 : if (cbTableName == SQL_NTS)
7285 0 : cbTableName = tds_dstr_len(&table_name);
7286 128 : if (cbSchemaName == SQL_NTS)
7287 0 : cbSchemaName = tds_dstr_len(&schema_name);
7288 :
7289 : /* support wildcards on catalog (only odbc 3) */
7290 128 : wildcards = 0;
7291 176 : if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3 && stmt->dbc->attr.metadata_id == SQL_FALSE &&
7292 126 : (strchr(tds_dstr_cstr(&catalog_name), '%') || strchr(tds_dstr_cstr(&catalog_name), '_')))
7293 : wildcards = 1;
7294 :
7295 128 : proc = "sp_tables";
7296 256 : if (!tds_dstr_isempty(&catalog_name)) {
7297 18 : if (wildcards) {
7298 : /* if catalog specified and wildcards use sp_tableswc under mssql2k */
7299 18 : if (TDS_IS_MSSQL(tds) && tds->conn->product_version >= TDS_MS_VER(8,0,0)) {
7300 16 : proc = "sp_tableswc";
7301 32 : if (tds_dstr_isempty(&schema_name))
7302 16 : if (!tds_dstr_copy(&schema_name, "%"))
7303 : goto memory_error;
7304 : }
7305 : /*
7306 : * TODO support wildcards on catalog even for Sybase
7307 : * first execute a select name from master..sysdatabases where name like catalog quoted
7308 : * build a db1..sp_tables args db2..sp_tables args ... query
7309 : * collapse results in a single recordset (how??)
7310 : */
7311 : } else {
7312 : /* if catalog specified and not wildcards use catatog on name (catalog..sp_tables) */
7313 : proc = "..sp_tables";
7314 : }
7315 : }
7316 :
7317 : /* fix type if needed quoting it */
7318 256 : if (!tds_dstr_isempty(&table_type)) {
7319 80 : int to_fix = 0;
7320 80 : int elements = 0;
7321 160 : const char *p = tds_dstr_cstr(&table_type);
7322 80 : const char *const end = p + tds_dstr_len(&table_type);
7323 :
7324 30 : for (;;) {
7325 110 : const char *begin = p;
7326 :
7327 110 : p = (const char*) memchr(p, ',', end - p);
7328 110 : if (!p)
7329 80 : p = end;
7330 110 : ++elements;
7331 110 : if ((p - begin) < 2 || begin[0] != '\'' || p[-1] != '\'')
7332 50 : to_fix = 1;
7333 110 : if (p >= end)
7334 : break;
7335 30 : ++p;
7336 : }
7337 : /* fix it */
7338 80 : tdsdump_log(TDS_DBG_INFO1, "to_fix %d elements %d\n", to_fix, elements);
7339 80 : if (to_fix) {
7340 : char *dst, *type;
7341 :
7342 40 : tdsdump_log(TDS_DBG_INFO1, "fixing type elements\n");
7343 80 : type = tds_new(char, tds_dstr_len(&table_type) + elements * 2 + 3);
7344 40 : if (!type)
7345 : goto memory_error;
7346 :
7347 80 : p = tds_dstr_cstr(&table_type);
7348 40 : dst = type;
7349 30 : for (;;) {
7350 70 : const char *begin = p;
7351 :
7352 70 : p = (const char*) memchr(p, ',', end - p);
7353 70 : if (!p)
7354 40 : p = end;
7355 70 : if ((p - begin) < 2 || begin[0] != '\'' || p[-1] != '\'') {
7356 50 : *dst++ = '\'';
7357 50 : memcpy(dst, begin, p - begin);
7358 50 : dst += p - begin;
7359 50 : *dst++ = '\'';
7360 : } else {
7361 20 : memcpy(dst, begin, p - begin);
7362 20 : dst += p - begin;
7363 : }
7364 70 : if (p >= end)
7365 : break;
7366 30 : *dst++ = *p++;
7367 : }
7368 40 : *dst = 0;
7369 40 : if (!tds_dstr_set(&table_type, type)) {
7370 0 : free(type);
7371 0 : goto memory_error;
7372 : }
7373 : }
7374 : }
7375 :
7376 : /* special case for catalog list */
7377 256 : if (strcmp(tds_dstr_cstr(&catalog_name), "%") == 0 && cbTableName <= 0 && cbSchemaName <= 0) {
7378 10 : retcode =
7379 10 : odbc_stat_execute(stmt _wide, "sp_tables", 3, "$!P@table_name", "", 0,
7380 : "$!P@table_owner", "", 0, "!P@table_qualifier", "%", 1);
7381 : } else {
7382 118 : retcode =
7383 944 : odbc_stat_execute(stmt _wide, proc, 4,
7384 : "!P@table_name", tds_dstr_cstr(&table_name), tds_dstr_len(&table_name),
7385 : "!P@table_owner", tds_dstr_cstr(&schema_name), tds_dstr_len(&schema_name),
7386 : "!P@table_qualifier", tds_dstr_cstr(&catalog_name), tds_dstr_len(&catalog_name),
7387 : "!@table_type", tds_dstr_cstr(&table_type), tds_dstr_len(&table_type));
7388 : }
7389 128 : tds_dstr_free(&schema_name);
7390 128 : tds_dstr_free(&catalog_name);
7391 128 : tds_dstr_free(&table_name);
7392 128 : tds_dstr_free(&table_type);
7393 128 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
7394 48 : odbc_col_setname(stmt, 1, "TABLE_CAT");
7395 48 : odbc_col_setname(stmt, 2, "TABLE_SCHEM");
7396 : }
7397 128 : ODBC_EXIT_(stmt);
7398 :
7399 0 : memory_error:
7400 0 : tds_dstr_free(&schema_name);
7401 0 : tds_dstr_free(&catalog_name);
7402 0 : tds_dstr_free(&table_name);
7403 0 : tds_dstr_free(&table_type);
7404 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
7405 0 : ODBC_EXIT_(stmt);
7406 : }
7407 :
7408 : /**
7409 : * Log a useful message about unimplemented options
7410 : * Defying belief, Microsoft defines mutually exclusive options that
7411 : * some ODBC implementations #define as duplicate values (meaning, of course,
7412 : * that they couldn't be implemented in the same function because they're
7413 : * indistinguishable.
7414 : *
7415 : * Those duplicates are commented out below.
7416 : */
7417 : static void
7418 0 : odbc_log_unimplemented_type(const char function_name[], int fType)
7419 : {
7420 : const char *name, *category;
7421 :
7422 0 : switch (fType) {
7423 : #ifdef SQL_ALTER_SCHEMA
7424 : case SQL_ALTER_SCHEMA:
7425 : name = "SQL_ALTER_SCHEMA";
7426 : category = "Supported SQL";
7427 : break;
7428 : #endif
7429 : #ifdef SQL_ANSI_SQL_DATETIME_LITERALS
7430 : case SQL_ANSI_SQL_DATETIME_LITERALS:
7431 : name = "SQL_ANSI_SQL_DATETIME_LITERALS";
7432 : category = "Supported SQL";
7433 : break;
7434 : #endif
7435 : case SQL_COLLATION_SEQ:
7436 : name = "SQL_COLLATION_SEQ";
7437 : category = "Data Source Information";
7438 : break;
7439 0 : case SQL_CONVERT_BIGINT:
7440 0 : name = "SQL_CONVERT_BIGINT";
7441 0 : category = "Conversion Information";
7442 0 : break;
7443 0 : case SQL_CONVERT_DATE:
7444 0 : name = "SQL_CONVERT_DATE";
7445 0 : category = "Conversion Information";
7446 0 : break;
7447 0 : case SQL_CONVERT_DOUBLE:
7448 0 : name = "SQL_CONVERT_DOUBLE";
7449 0 : category = "Conversion Information";
7450 0 : break;
7451 0 : case SQL_CONVERT_INTERVAL_DAY_TIME:
7452 0 : name = "SQL_CONVERT_INTERVAL_DAY_TIME";
7453 0 : category = "Conversion Information";
7454 0 : break;
7455 0 : case SQL_CONVERT_INTERVAL_YEAR_MONTH:
7456 0 : name = "SQL_CONVERT_INTERVAL_YEAR_MONTH";
7457 0 : category = "Conversion Information";
7458 0 : break;
7459 0 : case SQL_DM_VER:
7460 0 : name = "SQL_DM_VER";
7461 0 : category = "Added for ODBC 3.x";
7462 0 : break;
7463 0 : case SQL_DRIVER_HLIB:
7464 0 : name = "SQL_DRIVER_HLIB";
7465 0 : category = "Driver Information";
7466 0 : break;
7467 : #ifdef SQL_ODBC_STANDARD_CLI_CONFORMANCE
7468 : case SQL_ODBC_STANDARD_CLI_CONFORMANCE:
7469 : name = "SQL_ODBC_STANDARD_CLI_CONFORMANCE";
7470 : category = "Driver Information";
7471 : break;
7472 : #endif
7473 0 : case SQL_USER_NAME:
7474 0 : name = "SQL_USER_NAME";
7475 0 : category = "Data Source Information";
7476 0 : break;
7477 : /* TODO extension SQL_INFO_SS_NETLIB_NAME ?? */
7478 0 : default:
7479 0 : name = "unknown";
7480 0 : category = "unknown";
7481 0 : break;
7482 : }
7483 :
7484 0 : tdsdump_log(TDS_DBG_INFO1, "not implemented: %s: option/type %d(%s) [category %s]\n", function_name, fType, name,
7485 : category);
7486 :
7487 0 : return;
7488 : }
7489 :
7490 : static size_t
7491 404 : odbc_quote_metadata(TDS_DBC * dbc, char type, char *dest, DSTR * dstr)
7492 : {
7493 404 : int unquote = 0;
7494 : char prev, buf[1200], *dst;
7495 808 : const char *s = tds_dstr_cstr(dstr);
7496 808 : ptrdiff_t len = tds_dstr_len(dstr);
7497 :
7498 : /* limit string/id lengths */
7499 404 : if (len > 384)
7500 0 : len = 384;
7501 :
7502 404 : if (!type || (type == 'O' && dbc->attr.metadata_id == SQL_FALSE)) {
7503 100 : if (dest)
7504 100 : memcpy(dest, s, len);
7505 100 : return len;
7506 : }
7507 :
7508 : /* where we can have ID or PV */
7509 304 : assert(type == 'P' || (type == 'O' && dbc->attr.metadata_id != SQL_FALSE));
7510 :
7511 : /* ID ? */
7512 304 : if (dbc->attr.metadata_id != SQL_FALSE) {
7513 : /* strip leading and trailing spaces */
7514 0 : while (len > 0 && *s == ' ')
7515 0 : ++s, --len;
7516 0 : while (len > 0 && s[len - 1] == ' ')
7517 0 : --len;
7518 : /* unquote if necessary */
7519 0 : if (len > 2 && *s == '\"' && s[len - 1] == '\"') {
7520 0 : ++s, len -= 2;
7521 0 : unquote = 1;
7522 : }
7523 : }
7524 :
7525 304 : if (!dest)
7526 0 : dest = buf;
7527 304 : dst = dest;
7528 :
7529 : /*
7530 : * handle patterns
7531 : * "'" -> "''" (normal string quoting)
7532 : *
7533 : * if metadata_id is FALSE
7534 : * "\_" -> "[_]"
7535 : * "\%" -> "[%]"
7536 : * "[" -> "[[]"
7537 : *
7538 : * if metadata_id is TRUE
7539 : * "\"\"" -> "\"" (if unquote id)
7540 : * "_" -> "[_]"
7541 : * "%" -> "[%]"
7542 : * "[" -> "[[]"
7543 : */
7544 304 : prev = 0;
7545 1890 : for (; --len >= 0; ++s) {
7546 1586 : switch (*s) {
7547 0 : case '\"':
7548 0 : if (unquote && prev == '\"') {
7549 0 : prev = 0; /* avoid "\"\"\"" -> "\"" */
7550 0 : --dst;
7551 0 : continue;
7552 : }
7553 : break;
7554 106 : case '_':
7555 : case '%':
7556 106 : if (dbc->attr.metadata_id == SQL_FALSE) {
7557 106 : if (prev != '\\')
7558 : break;
7559 0 : --dst;
7560 : }
7561 : case '[':
7562 0 : if (type != 'P')
7563 : break;
7564 : /* quote search string */
7565 0 : *dst++ = '[';
7566 0 : *dst++ = *s;
7567 0 : *dst++ = ']';
7568 0 : prev = 0;
7569 0 : continue;
7570 : }
7571 1586 : *dst++ = prev = *s;
7572 : }
7573 304 : return dst - dest;
7574 : }
7575 :
7576 : static TDSPARAMINFO*
7577 412 : odbc_add_char_param(TDSSOCKET *tds, TDSPARAMINFO *params, const char *name, const char *value, TDS_INT len)
7578 : {
7579 : TDSCOLUMN *col;
7580 :
7581 412 : params = tds_alloc_param_result(params);
7582 412 : if (!params)
7583 : return NULL;
7584 :
7585 412 : col = params->columns[params->num_cols-1];
7586 412 : if (!tds_dstr_copy(&col->column_name, name))
7587 : return NULL;
7588 412 : tds_set_param_type(tds->conn, col, IS_TDS7_PLUS(tds->conn) ? XSYBNVARCHAR : SYBVARCHAR);
7589 :
7590 412 : col->column_size = len;
7591 412 : if (!tds_alloc_param_data(col))
7592 : return NULL;
7593 :
7594 412 : memcpy(col->column_data, value, len);
7595 412 : col->column_cur_size = len;
7596 :
7597 412 : return params;
7598 : }
7599 :
7600 : static TDSPARAMINFO*
7601 48 : odbc_add_int_param(TDSSOCKET *tds, TDSPARAMINFO *params, const char *name, int value)
7602 : {
7603 : TDSCOLUMN *col;
7604 :
7605 48 : params = tds_alloc_param_result(params);
7606 48 : if (!params)
7607 : return NULL;
7608 :
7609 48 : col = params->columns[params->num_cols-1];
7610 48 : if (!tds_dstr_copy(&col->column_name, name))
7611 : return NULL;
7612 48 : tds_set_param_type(tds->conn, col, SYBINT4);
7613 :
7614 48 : if (!tds_alloc_param_data(col))
7615 : return NULL;
7616 :
7617 48 : *((TDS_INT*) col->column_data) = value;
7618 48 : col->column_cur_size = sizeof(TDS_INT);
7619 :
7620 48 : return params;
7621 : }
7622 :
7623 :
7624 : static SQLRETURN
7625 188 : odbc_stat_execute(TDS_STMT * stmt _WIDE, const char *begin, int nparams, ...)
7626 : {
7627 188 : int i, param_qualifier = -1;
7628 : size_t len;
7629 188 : char *proc = NULL, *p;
7630 : SQLRETURN retcode;
7631 : va_list marker;
7632 188 : DSTR qualifier = DSTR_INITIALIZER, value = DSTR_INITIALIZER;
7633 : TDSPARAMINFO *params;
7634 :
7635 : /* read all params and calc len required */
7636 188 : va_start(marker, nparams);
7637 188 : len = strlen(begin) + 3;
7638 188 : params = tds_alloc_results(0);
7639 188 : if (!params)
7640 : goto mem_error;
7641 790 : for (i = 0; i < nparams; ++i) {
7642 : int param_len;
7643 790 : bool convert TDS_UNUSED = true;
7644 790 : bool add_always = false;
7645 : DSTR *out;
7646 : const char *name;
7647 : char type;
7648 :
7649 790 : p = va_arg(marker, char *);
7650 :
7651 522 : for (; ; ++p) {
7652 1834 : switch (*p) {
7653 20 : case '$':
7654 20 : add_always = true;
7655 20 : continue;
7656 502 : case '!':
7657 502 : convert = false;
7658 502 : continue;
7659 672 : case 'V': /* ODBC version */
7660 : case 'O': /* ordinary arguments */
7661 : case 'P': /* pattern value arguments */
7662 672 : type = *p++;
7663 672 : break;
7664 : default:
7665 : type = 0; /* ordinary type */
7666 : break;
7667 : }
7668 : break;
7669 : }
7670 790 : name = p;
7671 :
7672 790 : p = va_arg(marker, char *);
7673 790 : param_len = va_arg(marker, int);
7674 :
7675 790 : if (type == 'V') {
7676 48 : int ver = (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) ? 3: 2;
7677 48 : if (!odbc_add_int_param(stmt->dbc->tds_socket, params, name, ver))
7678 : goto mem_error;
7679 48 : continue;
7680 : }
7681 :
7682 : #ifdef ENABLE_ODBC_WIDE
7683 742 : if (!convert)
7684 502 : out = tds_dstr_copyn(&value, p, param_len);
7685 : else
7686 240 : out = odbc_dstr_copy(stmt->dbc, &value, param_len, (ODBC_CHAR *) p);
7687 : #else
7688 : out = odbc_dstr_copy(stmt->dbc, &value, param_len, (ODBC_CHAR *) p);
7689 : #endif
7690 742 : if (!out)
7691 : goto mem_error;
7692 :
7693 1464 : if (add_always || !tds_dstr_isempty(&value)) {
7694 : char buf[1200];
7695 : int l;
7696 :
7697 404 : l = (int) odbc_quote_metadata(stmt->dbc, type, buf,
7698 : &value);
7699 404 : if (!odbc_add_char_param(stmt->dbc->tds_socket, params, name, buf, l))
7700 : goto mem_error;
7701 :
7702 404 : if (begin[0] == '.' && strstr(name, "qualifier")) {
7703 20 : if (!tds_dstr_dup(&qualifier, &value))
7704 : goto mem_error;
7705 40 : len += tds_quote_id_rpc(stmt->dbc->tds_socket, NULL,
7706 20 : tds_dstr_cstr(&qualifier), tds_dstr_len(&qualifier));
7707 20 : param_qualifier = i;
7708 : }
7709 : }
7710 : }
7711 188 : tds_dstr_free(&value);
7712 :
7713 : /* proc is neither mb or wide, is always utf encoded */
7714 188 : retcode = odbc_set_stmt_query(stmt, (ODBC_CHAR *) "-", 1 _wide0);
7715 188 : if (retcode != SQL_SUCCESS)
7716 : goto error;
7717 188 : stmt->prepared_query_is_rpc = 1;
7718 :
7719 : /* set params */
7720 188 : tds_free_param_results(stmt->params);
7721 188 : stmt->param_count = params->num_cols;
7722 188 : stmt->param_num = 1 + stmt->param_count;
7723 188 : stmt->params = params;
7724 188 : params = NULL;
7725 :
7726 : /* allocate space for string */
7727 188 : if (!tds_dstr_alloc(&stmt->query, len))
7728 : goto mem_error;
7729 376 : proc = tds_dstr_buf(&stmt->query);
7730 :
7731 : /* build query string */
7732 188 : p = proc;
7733 188 : if (param_qualifier >= 0)
7734 60 : p += tds_quote_id_rpc(stmt->dbc->tds_socket, p, tds_dstr_cstr(&qualifier), tds_dstr_len(&qualifier));
7735 188 : tds_dstr_free(&qualifier);
7736 188 : strcpy(p, begin);
7737 188 : p += strlen(begin);
7738 188 : tds_dstr_setlen(&stmt->query, p - proc);
7739 188 : assert(p + 1 <= proc + len);
7740 :
7741 : /* execute it */
7742 188 : retcode = odbc_SQLExecute(stmt);
7743 188 : if (SQL_SUCCEEDED(retcode))
7744 188 : odbc_upper_column_names(stmt);
7745 :
7746 188 : va_end(marker);
7747 188 : ODBC_RETURN(stmt, retcode);
7748 :
7749 0 : mem_error:
7750 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
7751 :
7752 0 : error:
7753 0 : tds_dstr_free(&value);
7754 0 : tds_dstr_free(&qualifier);
7755 0 : tds_free_results(params);
7756 0 : va_end(marker);
7757 0 : return SQL_ERROR;
7758 : }
7759 :
7760 : static SQLRETURN
7761 22028 : odbc_free_dynamic(TDS_STMT * stmt)
7762 : {
7763 : TDSSOCKET *tds;
7764 :
7765 22028 : if (!stmt->dyn)
7766 : return TDS_SUCCESS;
7767 :
7768 2232 : tds = stmt->dbc->tds_socket;
7769 2232 : if (!tds_needs_unprepare(tds->conn, stmt->dyn)) {
7770 92 : tds_release_dynamic(&stmt->dyn);
7771 92 : return SQL_SUCCESS;
7772 : }
7773 :
7774 2140 : if (odbc_lock_statement(stmt)) {
7775 2132 : if (TDS_SUCCEED(tds_submit_unprepare(stmt->tds, stmt->dyn))
7776 2132 : && TDS_SUCCEED(tds_process_simple_query(stmt->tds))) {
7777 2132 : odbc_unlock_statement(stmt);
7778 2132 : tds_release_dynamic(&stmt->dyn);
7779 2132 : return SQL_SUCCESS;
7780 : }
7781 : }
7782 :
7783 8 : if (TDS_SUCCEED(tds_deferred_unprepare(tds->conn, stmt->dyn))) {
7784 8 : tds_release_dynamic(&stmt->dyn);
7785 8 : return SQL_SUCCESS;
7786 : }
7787 :
7788 0 : ODBC_SAFE_ERROR(stmt);
7789 : return SQL_ERROR;
7790 : }
7791 :
7792 : /**
7793 : * Close server cursors
7794 : */
7795 : static SQLRETURN
7796 18491 : odbc_free_cursor(TDS_STMT * stmt)
7797 : {
7798 18491 : TDSCURSOR *cursor = stmt->cursor;
7799 : TDSSOCKET *tds;
7800 :
7801 18491 : if (!cursor)
7802 : return SQL_SUCCESS;
7803 :
7804 : /* if possible deallocate now */
7805 248 : if (odbc_lock_statement(stmt)) {
7806 248 : tds = stmt->tds;
7807 :
7808 248 : cursor->status.dealloc = TDS_CURSOR_STATE_REQUESTED;
7809 248 : if (TDS_SUCCEED(tds_cursor_close(tds, cursor))) {
7810 248 : if (TDS_SUCCEED(tds_process_simple_query(tds))) {
7811 : /* TODO check error */
7812 248 : tds_cursor_dealloc(tds, cursor);
7813 248 : tds_release_cursor(&stmt->cursor);
7814 248 : return SQL_SUCCESS;
7815 : }
7816 : }
7817 : }
7818 :
7819 0 : tds = stmt->dbc->tds_socket;
7820 0 : if (TDS_SUCCEED(tds_deferred_cursor_dealloc(tds->conn, cursor))) {
7821 0 : tds_release_cursor(&stmt->cursor);
7822 0 : return SQL_SUCCESS;
7823 : }
7824 :
7825 0 : ODBC_SAFE_ERROR(stmt);
7826 : return SQL_ERROR;
7827 : }
7828 :
7829 : SQLRETURN ODBC_PUBLIC ODBC_API
7830 : SQLSetScrollOptions(SQLHSTMT hstmt, SQLUSMALLINT fConcurrency, SQLLEN crowKeyset, SQLUSMALLINT crowRowset)
7831 : {
7832 : SQLUSMALLINT info;
7833 : SQLUINTEGER value, check;
7834 : SQLUINTEGER cursor_type;
7835 :
7836 0 : ODBC_ENTER_HSTMT;
7837 :
7838 0 : tdsdump_log(TDS_DBG_FUNC, "SQLSetScrollOptions(%p, %u, %ld, %u)\n",
7839 : hstmt, fConcurrency, (long int) crowKeyset, crowRowset);
7840 :
7841 0 : if (!stmt->dbc->cursor_support) {
7842 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
7843 0 : ODBC_EXIT_(stmt);
7844 : }
7845 :
7846 0 : if (stmt->cursor) {
7847 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
7848 0 : ODBC_EXIT_(stmt);
7849 : }
7850 :
7851 0 : switch (crowKeyset) {
7852 : case SQL_SCROLL_FORWARD_ONLY:
7853 : info = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
7854 : cursor_type = SQL_CURSOR_FORWARD_ONLY;
7855 : break;
7856 0 : case SQL_SCROLL_STATIC:
7857 0 : info = SQL_STATIC_CURSOR_ATTRIBUTES2;
7858 0 : cursor_type = SQL_CURSOR_STATIC;
7859 0 : break;
7860 0 : case SQL_SCROLL_KEYSET_DRIVEN:
7861 0 : info = SQL_KEYSET_CURSOR_ATTRIBUTES2;
7862 0 : cursor_type = SQL_CURSOR_KEYSET_DRIVEN;
7863 0 : break;
7864 0 : case SQL_SCROLL_DYNAMIC:
7865 0 : info = SQL_DYNAMIC_CURSOR_ATTRIBUTES2;
7866 0 : cursor_type = SQL_CURSOR_DYNAMIC;
7867 0 : break;
7868 0 : default:
7869 0 : if (crowKeyset > crowRowset) {
7870 : info = SQL_KEYSET_CURSOR_ATTRIBUTES2;
7871 : cursor_type = SQL_CURSOR_KEYSET_DRIVEN;
7872 : break;
7873 : }
7874 :
7875 0 : odbc_errs_add(&stmt->errs, "HY107", NULL);
7876 0 : ODBC_EXIT_(stmt);
7877 : }
7878 :
7879 0 : switch (fConcurrency) {
7880 : case SQL_CONCUR_READ_ONLY:
7881 : check = SQL_CA2_READ_ONLY_CONCURRENCY;
7882 : break;
7883 0 : case SQL_CONCUR_LOCK:
7884 0 : check = SQL_CA2_LOCK_CONCURRENCY;
7885 0 : break;
7886 0 : case SQL_CONCUR_ROWVER:
7887 0 : check = SQL_CA2_OPT_ROWVER_CONCURRENCY;
7888 0 : break;
7889 0 : case SQL_CONCUR_VALUES:
7890 0 : check = SQL_CA2_OPT_VALUES_CONCURRENCY;
7891 0 : break;
7892 0 : default:
7893 0 : odbc_errs_add(&stmt->errs, "HY108", NULL);
7894 0 : ODBC_EXIT_(stmt);
7895 : }
7896 :
7897 0 : value = 0;
7898 0 : odbc_SQLGetInfo(stmt->dbc, info, &value, sizeof(value), NULL _wide0);
7899 :
7900 0 : if ((value & check) == 0) {
7901 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
7902 0 : ODBC_EXIT_(stmt);
7903 : }
7904 :
7905 0 : odbc_SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) (TDS_INTPTR) cursor_type, 0 _wide0);
7906 0 : odbc_SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER) (TDS_INTPTR) fConcurrency, 0 _wide0);
7907 0 : odbc_SQLSetStmtAttr(hstmt, SQL_ATTR_KEYSET_SIZE, (SQLPOINTER) (TDS_INTPTR) crowKeyset, 0 _wide0);
7908 0 : odbc_SQLSetStmtAttr(hstmt, SQL_ROWSET_SIZE, (SQLPOINTER) (TDS_INTPTR) crowRowset, 0 _wide0);
7909 :
7910 0 : ODBC_EXIT_(stmt);
7911 : }
7912 :
7913 : static TDS_INT
7914 64 : get_int_col(TDSSOCKET *tds, TDSCOLUMN *col, TDS_INT default_value)
7915 : {
7916 64 : int srctype = tds_get_conversion_type(col->on_server.column_type, col->on_server.column_size);
7917 64 : TDS_CHAR *src = (TDS_CHAR *) col->column_data;
7918 64 : TDS_INT srclen = col->column_cur_size;
7919 : CONV_RESULT res;
7920 :
7921 64 : if (srclen < 0)
7922 : return default_value;
7923 :
7924 64 : if (is_blob_col(col))
7925 0 : src = ((TDSBLOB *) src)->textvalue;
7926 :
7927 64 : if (tds_convert(tds_get_ctx(tds), srctype, src, (TDS_UINT) srclen, SYBINT4, &res) < 0)
7928 : return default_value;
7929 :
7930 64 : return res.i;
7931 : }
7932 :
7933 : /**
7934 : * Replace placeholders ('?') inside query with @PRMxxx name.
7935 : * @param is_func Tell if query is a ODBC function call.
7936 : * @returns Converted string, NULL on memory error.
7937 : */
7938 : static char *
7939 8 : prepare_query_describing_params(const char *query, size_t *query_len, bool is_func)
7940 : {
7941 : #define PRM_FMT "@PRM%04d"
7942 8 : int i = 0;
7943 : size_t len, pos;
7944 : const char *e, *s;
7945 8 : size_t size = *query_len + 30;
7946 : char *out;
7947 :
7948 8 : if (is_func)
7949 2 : size += 10;
7950 :
7951 8 : out = tds_new(char, size);
7952 8 : if (!out)
7953 : goto memory_error;
7954 8 : pos = 0;
7955 8 : if (is_func)
7956 2 : pos += sprintf(out + pos, "exec " PRM_FMT "=", ++i);
7957 :
7958 : s = query;
7959 14 : for (;; ++i) {
7960 36 : e = tds_next_placeholder(s);
7961 22 : len = e ? e - s : strlen(s);
7962 22 : if (pos + len + 12 >= size) {
7963 2 : size = pos + len + 30;
7964 2 : if (!TDS_RESIZE(out, size))
7965 : goto memory_error;
7966 : }
7967 22 : memcpy(out + pos, s, len);
7968 22 : pos += len;
7969 22 : if (!e)
7970 : break;
7971 14 : pos += sprintf(out + pos, PRM_FMT, i + 1);
7972 :
7973 14 : s = e + 1;
7974 : }
7975 8 : out[pos] = 0;
7976 8 : *query_len = pos;
7977 8 : return out;
7978 :
7979 0 : memory_error:
7980 0 : free(out);
7981 0 : return NULL;
7982 : #undef PRM_FMT
7983 : }
7984 :
7985 : /**
7986 : * Parse UTF-16 name for parameter name in the form @PRMxxxx.
7987 : * @returns xxxx number or -1 if error.
7988 : */
7989 : static int
7990 16 : param_index_from_name(const TDSCOLUMN *const col)
7991 : {
7992 16 : const unsigned char *data = col->column_data;
7993 : int i;
7994 : unsigned n;
7995 : char name[9];
7996 :
7997 : /* should be in format @PRMxxxx */
7998 16 : if (col->column_cur_size != 8 * 2)
7999 : return -1;
8000 :
8001 : /* convert to ASCII and lower the case */
8002 144 : for (i = 0; i < 8; ++i) {
8003 128 : name[i] = data[i * 2];
8004 128 : if (data[i * 2 + 1])
8005 : return -1;
8006 : }
8007 16 : name[1] |= 0x20;
8008 16 : name[2] |= 0x20;
8009 16 : name[3] |= 0x20;
8010 16 : name[8] = 0;
8011 :
8012 : /* parse name */
8013 16 : i = -1;
8014 16 : if (sscanf(name, "@prm%u%n", &n, &i) < 1 || n < 1 || i != 8)
8015 : return -1;
8016 :
8017 16 : return (int) (n - 1);
8018 : }
8019 :
8020 : static bool
8021 9 : read_params(TDS_STMT *stmt)
8022 : {
8023 9 : bool ret = false;
8024 : TDSSOCKET *tds;
8025 9 : TDSPARAMINFO *params = NULL;
8026 9 : bool in_row = false;
8027 : enum {
8028 : COL_NAME,
8029 : COL_PRECISION,
8030 : COL_SCALE,
8031 : COL_TYPE,
8032 : COL_LENGTH,
8033 : NUM_COLUMNS
8034 : };
8035 : static const char *const column_names[NUM_COLUMNS] = {
8036 : "NAME",
8037 : "SUGGESTED_PRECISION",
8038 : "SUGGESTED_SCALE",
8039 : "SUGGESTED_TDS_TYPE_ID",
8040 : "SUGGESTED_TDS_LENGTH",
8041 : };
8042 : unsigned column_idx[NUM_COLUMNS];
8043 18 : const char *query = tds_dstr_cstr(&stmt->query);
8044 18 : size_t query_len = tds_dstr_len(&stmt->query);
8045 9 : unsigned num_params = tds_count_placeholders(query);
8046 9 : char *new_query = NULL;
8047 : TDSCOLUMN col[1];
8048 :
8049 : /* there should be not so many parameters, avoid client to mess around */
8050 9 : if (num_params >= 998) {
8051 0 : stmt->params_queried = 1;
8052 0 : return false;
8053 : }
8054 :
8055 : /* allocate tds */
8056 9 : if (!odbc_lock_statement(stmt)) {
8057 1 : odbc_errs_reset(&stmt->errs);
8058 1 : return false;
8059 : }
8060 :
8061 8 : tds = stmt->tds;
8062 8 : stmt->params_queried = 1;
8063 :
8064 : /* currently supported only by MSSQL 2012 */
8065 8 : if (!TDS_IS_MSSQL(tds) || tds->conn->product_version < TDS_MS_VER(11,0,0)) {
8066 0 : odbc_unlock_statement(stmt);
8067 0 : return false;
8068 : }
8069 :
8070 : /* replace parameters with names */
8071 8 : if (stmt->prepared_query_is_func)
8072 2 : ++num_params;
8073 8 : if (num_params) {
8074 8 : new_query = prepare_query_describing_params(query, &query_len, stmt->prepared_query_is_func);
8075 8 : if (!new_query)
8076 : goto memory_error;
8077 : query = new_query;
8078 : }
8079 :
8080 : /* send query */
8081 8 : params = odbc_add_char_param(tds, NULL, "", query, query_len);
8082 8 : if (!params)
8083 : goto memory_error;
8084 :
8085 8 : if (TDS_FAILED(tds_submit_rpc(tds, "sp_describe_undeclared_parameters", params, NULL)))
8086 : goto error;
8087 8 : tds_free_param_results(params);
8088 8 : params = NULL;
8089 :
8090 : /* clear IPD and APD */
8091 8 : desc_alloc_records(stmt->apd, 0);
8092 8 : desc_alloc_records(stmt->ipd, 0);
8093 : /* set IPD size */
8094 8 : desc_alloc_records(stmt->ipd, num_params);
8095 :
8096 8 : ret = true;
8097 : for (;;) {
8098 : TDS_INT result_type;
8099 : int done_flags;
8100 : TDSRESULTINFO *res_info;
8101 : ptrdiff_t i, j, num_cols;
8102 : struct _drecord *drec;
8103 : int idx, scale, precision, len, tds_type;
8104 :
8105 48 : switch (tds_process_tokens(tds, &result_type, &done_flags, TDS_RETURN_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW)) {
8106 40 : case TDS_SUCCESS:
8107 40 : switch (result_type) {
8108 16 : case TDS_DONE_RESULT:
8109 : case TDS_DONEPROC_RESULT:
8110 : case TDS_DONEINPROC_RESULT:
8111 16 : in_row = false;
8112 16 : break;
8113 :
8114 8 : case TDS_ROWFMT_RESULT:
8115 : /* parse results, scan all columns to find needed ones */
8116 : /* extract all column indexes */
8117 8 : res_info = tds->current_results;
8118 8 : num_cols = res_info->num_cols;
8119 :
8120 48 : for (i = 0; i < NUM_COLUMNS; i++)
8121 40 : column_idx[i] = ~0u;
8122 192 : for (i = 0; i < num_cols; i++) {
8123 : char *name;
8124 : TDSCOLUMN *col;
8125 :
8126 192 : col = res_info->columns[i];
8127 384 : name = tds_dstr_buf(&col->column_name);
8128 192 : tds_ascii_strupr(name);
8129 1152 : for (j = 0; j < NUM_COLUMNS; j++)
8130 960 : if (strcmp(name, column_names[j]) == 0)
8131 40 : column_idx[j] = i;
8132 : }
8133 : in_row = true;
8134 40 : for (i = 0; i < NUM_COLUMNS; i++)
8135 40 : if (column_idx[i] == ~0u)
8136 0 : in_row = false;
8137 : break;
8138 16 : case TDS_ROW_RESULT:
8139 16 : if (!in_row)
8140 : break;
8141 : /*
8142 : * convert type to SQL.
8143 : * Set precision (fixed on some types) and scale.
8144 : * Set length (based on type and fields).
8145 : */
8146 16 : res_info = tds->current_results;
8147 :
8148 16 : idx = param_index_from_name(res_info->columns[column_idx[COL_NAME]]);
8149 16 : if (idx < 0 || idx >= num_params)
8150 : break;
8151 16 : drec = &stmt->ipd->records[idx];
8152 16 : memset(col, 0, sizeof(col));
8153 16 : tds_type = get_int_col(tds, res_info->columns[column_idx[COL_TYPE]], -2);
8154 16 : len = get_int_col(tds, res_info->columns[column_idx[COL_LENGTH]], -2);
8155 16 : precision = get_int_col(tds, res_info->columns[column_idx[COL_PRECISION]], -2);
8156 16 : scale = get_int_col(tds, res_info->columns[column_idx[COL_SCALE]], -2);
8157 16 : if (tds_type < -1 || len < -1 || precision < -1 || scale < -1)
8158 : break;
8159 16 : tds_set_column_type(tds->conn, col, tds_type);
8160 16 : col->on_server.column_size = col->column_size = len;
8161 16 : col->column_prec = precision;
8162 16 : col->column_scale = scale;
8163 16 : drec->sql_desc_nullable = SQL_NULLABLE;
8164 16 : odbc_set_sql_type_info(col, drec, stmt->dbc);
8165 16 : break;
8166 : }
8167 40 : continue;
8168 : case TDS_NO_MORE_RESULTS:
8169 : break;
8170 0 : case TDS_CANCELLED:
8171 0 : odbc_errs_add(&stmt->errs, "HY008", NULL);
8172 0 : default:
8173 0 : stmt->errs.lastrc = SQL_ERROR;
8174 0 : ret = false;
8175 0 : break;
8176 : }
8177 8 : break;
8178 : }
8179 8 : odbc_unlock_statement(stmt);
8180 8 : free(new_query);
8181 8 : new_query = NULL;
8182 :
8183 : /* clear IPD on error */
8184 8 : if (!ret)
8185 0 : desc_alloc_records(stmt->ipd, 0);
8186 :
8187 : /* mark we have the information (we need to reset changing query) */
8188 8 : stmt->params_queried = 1;
8189 8 : return ret;
8190 :
8191 0 : memory_error:
8192 0 : free(new_query);
8193 0 : tds_free_param_results(params);
8194 0 : odbc_unlock_statement(stmt);
8195 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
8196 0 : return false;
8197 :
8198 0 : error:
8199 0 : free(new_query);
8200 0 : tds_free_param_results(params);
8201 0 : odbc_unlock_statement(stmt);
8202 0 : return false;
8203 : }
8204 :
8205 : #include "odbc_export.h"
8206 :
8207 : /* Under Windows driver exports functions */
8208 : /* The win_ prefix is to avoid clash with inline function.
8209 : * The prefix is removed from exported functions using definition file.
8210 : */
8211 : #ifdef _WIN32
8212 : RETCODE SQL_API win_bcp_initA(HDBC hdbc, const char *tblname, const char *hfile,
8213 : const char *errfile, int direction);
8214 : RETCODE SQL_API win_bcp_initW(HDBC hdbc, const SQLWCHAR *tblname, const SQLWCHAR *hfile,
8215 : const SQLWCHAR *errfile, int direction);
8216 : RETCODE SQL_API win_bcp_control(HDBC hdbc, int field, void *value);
8217 : RETCODE SQL_API win_bcp_colptr(HDBC hdbc, const unsigned char * colptr, int table_column);
8218 : RETCODE SQL_API win_bcp_sendrow(HDBC hdbc);
8219 : int SQL_API win_bcp_batch(HDBC hdbc);
8220 : int SQL_API win_bcp_done(HDBC hdbc);
8221 : RETCODE SQL_API win_bcp_bind(HDBC hdbc, const unsigned char * varaddr, int prefixlen, int varlen,
8222 : const unsigned char * terminator, int termlen, int vartype, int table_column);
8223 :
8224 : RETCODE SQL_API
8225 : win_bcp_initA(HDBC hdbc, const char *tblname, const char *hfile, const char *errfile, int direction)
8226 : {
8227 : return bcp_initA(hdbc, tblname, hfile, errfile, direction);
8228 : }
8229 :
8230 : #ifdef ENABLE_ODBC_WIDE
8231 : RETCODE SQL_API
8232 : win_bcp_initW(HDBC hdbc, const SQLWCHAR *tblname, const SQLWCHAR *hfile, const SQLWCHAR *errfile, int direction)
8233 : {
8234 : return bcp_initW(hdbc, tblname, hfile, errfile, direction);
8235 : }
8236 : #endif
8237 :
8238 : RETCODE SQL_API
8239 : win_bcp_control(HDBC hdbc, int field, void *value)
8240 : {
8241 : return bcp_control(hdbc, field, value);
8242 : }
8243 :
8244 : RETCODE SQL_API
8245 : win_bcp_colptr(HDBC hdbc, const unsigned char * colptr, int table_column)
8246 : {
8247 : return bcp_colptr(hdbc, colptr, table_column);
8248 : }
8249 :
8250 : RETCODE SQL_API
8251 : win_bcp_sendrow(HDBC hdbc)
8252 : {
8253 : return bcp_sendrow(hdbc);
8254 : }
8255 :
8256 : int SQL_API
8257 : win_bcp_batch(HDBC hdbc)
8258 : {
8259 : return bcp_batch(hdbc);
8260 : }
8261 :
8262 : int SQL_API
8263 : win_bcp_done(HDBC hdbc)
8264 : {
8265 : return bcp_done(hdbc);
8266 : }
8267 :
8268 : RETCODE SQL_API
8269 : win_bcp_bind(HDBC hdbc, const unsigned char * varaddr, int prefixlen, int varlen,
8270 : const unsigned char * terminator, int termlen, int vartype, int table_column)
8271 : {
8272 : return bcp_bind(hdbc, varaddr, prefixlen, varlen, terminator, termlen, vartype, table_column);
8273 : }
8274 : #endif
8275 :
|