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