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