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