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