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