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