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