Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001 Brian Bruns
3 : * Copyright (C) 2002-2012 Frediano Ziglio
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Library General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Library General Public
16 : * License along with this library; if not, write to the
17 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 : * Boston, MA 02111-1307, USA.
19 : */
20 :
21 : #include <config.h>
22 :
23 : #include <stdarg.h>
24 : #include <stdio.h>
25 :
26 : #if HAVE_STDLIB_H
27 : #include <stdlib.h>
28 : #endif /* HAVE_STDLIB_H */
29 :
30 : #if HAVE_STRING_H
31 : #include <string.h>
32 : #endif /* HAVE_STRING_H */
33 :
34 : #include <assert.h>
35 : #include <ctype.h>
36 :
37 : #include <freetds/utils.h>
38 : #include <freetds/odbc.h>
39 : #include <freetds/tds/iconv.h>
40 : #include <freetds/utils/string.h>
41 : #include <freetds/utils/ascii.h>
42 : #include <freetds/tds/convert.h>
43 : #include <freetds/encodings.h>
44 : #include <freetds/replacements.h>
45 : #include "sqlwparams.h"
46 :
47 : /* Include odbcss.h with all bcp functions */
48 : /* The define trick is to make inline functions calls internal
49 : * odbc_SQLSetConnectAttr instead of SQLSetConnectAttr */
50 : ODBC_FUNC(SQLSetConnectAttr, (P(SQLHDBC,hdbc), P(SQLINTEGER,Attribute), P(SQLPOINTER,ValuePtr), P(SQLINTEGER,StringLength) WIDE));
51 : #define TDSODBC_BCP
52 : #undef SQLSetConnectAttr
53 : #define SQLSetConnectAttr(h, n, p, t) odbc_SQLSetConnectAttr(h, n, p, t _wide0)
54 : #include <odbcss.h>
55 : #undef SQLSetConnectAttr
56 :
57 : static SQLRETURN odbc_SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc);
58 : static SQLRETURN odbc_SQLAllocEnv(SQLHENV FAR * phenv, SQLINTEGER odbc_version);
59 : static SQLRETURN odbc_SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt);
60 : static SQLRETURN odbc_SQLAllocDesc(SQLHDBC hdbc, SQLHDESC FAR * phdesc);
61 : static SQLRETURN odbc_SQLFreeConnect(SQLHDBC hdbc);
62 : static SQLRETURN odbc_SQLFreeEnv(SQLHENV henv);
63 : static SQLRETURN odbc_SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption, int force);
64 : static SQLRETURN odbc_SQLFreeDesc(SQLHDESC hdesc);
65 : static SQLRETURN odbc_SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength WIDE);
66 : static SQLRETURN odbc_SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength,
67 : SQLINTEGER * StringLength WIDE);
68 : static SQLRETURN odbc_SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc,
69 : SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc _WIDE);
70 : static SQLRETURN odbc_SQLFetch(TDS_STMT * stmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset);
71 : static SQLRETURN odbc_populate_ird(TDS_STMT * stmt);
72 : static int odbc_errmsg_handler(const TDSCONTEXT * ctx, TDSSOCKET * tds, TDSMESSAGE * msg);
73 : static SQLRETURN odbc_free_dynamic(TDS_STMT * stmt);
74 : static SQLRETURN odbc_free_cursor(TDS_STMT * stmt);
75 : static SQLRETURN odbc_update_ird(TDS_STMT * stmt, TDS_ERRS * errs);
76 : static SQLRETURN odbc_prepare(TDS_STMT * stmt);
77 : static int odbc_process_tokens(TDS_STMT * stmt, unsigned flag);
78 : static bool odbc_lock_statement(TDS_STMT * stmt);
79 : static void odbc_unlock_statement(TDS_STMT * stmt);
80 : static bool read_params(TDS_STMT * stmt);
81 :
82 : /**
83 : * \defgroup odbc_api ODBC API
84 : * Functions callable by \c ODBC client programs
85 : */
86 :
87 : #define ODBC_SAFE_ERROR(stmt) \
88 : do { \
89 : if (!stmt->errs.num_errors) \
90 : odbc_errs_add(&stmt->errs, "HY000", "Unknown error"); \
91 : } while(0)
92 :
93 : #define DEFAULT_QUERY_TIMEOUT (~((SQLUINTEGER) 0))
94 :
95 : /*
96 : * Note: I *HATE* hungarian notation, it has to be the most idiotic thing
97 : * I've ever seen. So, you will note it is avoided other than in the function
98 : * declarations. "Gee, let's make our code totally hard to read and they'll
99 : * beg for GUI tools"
100 : * Bah!
101 : */
102 :
103 : static const char *
104 0 : odbc_prret(SQLRETURN ret, char *unknown, size_t unknown_size)
105 : {
106 0 : switch (ret) {
107 : case SQL_ERROR: return "SQL_ERROR";
108 0 : case SQL_INVALID_HANDLE: return "SQL_INVALID_HANDLE";
109 0 : case SQL_SUCCESS: return "SQL_SUCCESS";
110 0 : case SQL_SUCCESS_WITH_INFO: return "SQL_SUCCESS_WITH_INFO";
111 : #if ODBCVER >= 0x0300
112 0 : case SQL_NO_DATA: return "SQL_NO_DATA";
113 : #endif
114 0 : case SQL_STILL_EXECUTING: return "SQL_STILL_EXECUTING";
115 0 : case SQL_NEED_DATA: return "SQL_NEED_DATA";
116 : }
117 :
118 0 : snprintf(unknown, unknown_size, "unknown: %d", (int)ret);
119 :
120 0 : return unknown;
121 : }
122 : #define ODBC_PRRET_BUF char unknown_prret_buf[24]
123 : #define odbc_prret(ret) odbc_prret(ret, unknown_prret_buf, sizeof(unknown_prret_buf))
124 :
125 : /* spinellia@acm.org : copied shamelessly from change_database */
126 : static SQLRETURN
127 260 : change_autocommit(TDS_DBC *dbc, int state)
128 : {
129 260 : TDSSOCKET *tds = dbc->tds_socket;
130 : TDSRET ret;
131 :
132 260 : tds_mutex_check_owned(&dbc->mtx);
133 260 : if (dbc->attr.autocommit == state)
134 : return SQL_SUCCESS;
135 :
136 : /*
137 : * We may not be connected yet and dbc->tds_socket
138 : * may not initialized.
139 : */
140 232 : if (tds) {
141 : /* TODO better idle check, not thread safe */
142 190 : if (tds->state == TDS_IDLE)
143 190 : tds->query_timeout = dbc->default_query_timeout;
144 :
145 190 : if (state == SQL_AUTOCOMMIT_ON)
146 58 : ret = tds_submit_rollback(tds, 0);
147 : else
148 132 : ret = tds_submit_begin_tran(tds);
149 :
150 190 : if (TDS_FAILED(ret)) {
151 0 : odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");
152 0 : return SQL_ERROR;
153 : }
154 190 : if (TDS_FAILED(tds_process_simple_query(tds))) {
155 0 : odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");
156 0 : return SQL_ERROR;
157 : }
158 190 : dbc->attr.autocommit = state;
159 : } else {
160 : /* if not connected we will change auto-commit after login */
161 42 : dbc->attr.autocommit = state;
162 : }
163 232 : ODBC_RETURN_(dbc);
164 : }
165 :
166 : static SQLRETURN
167 80 : change_database(TDS_DBC * dbc, const char *database, size_t database_len)
168 : {
169 80 : TDSSOCKET *tds = dbc->tds_socket;
170 80 : tds_mutex_check_owned(&dbc->mtx);
171 :
172 : /*
173 : * We may not be connected yet and dbc->tds_socket
174 : * may not initialized.
175 : */
176 80 : if (tds) {
177 : /* build query */
178 40 : char *query = tds_new(char, 6 + tds_quote_id(tds, NULL, database, database_len));
179 :
180 40 : if (!query) {
181 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
182 0 : return SQL_ERROR;
183 : }
184 40 : strcpy(query, "USE ");
185 40 : tds_quote_id(tds, query + 4, database, database_len);
186 :
187 :
188 40 : tdsdump_log(TDS_DBG_INFO1, "change_database: executing %s\n", query);
189 :
190 : /* TODO better idle check, not thread safe */
191 40 : if (tds->state == TDS_IDLE)
192 40 : tds->query_timeout = dbc->default_query_timeout;
193 40 : if (TDS_FAILED(tds_submit_query(tds, query))) {
194 0 : free(query);
195 0 : odbc_errs_add(&dbc->errs, "HY000", "Could not change database");
196 0 : return SQL_ERROR;
197 : }
198 40 : free(query);
199 40 : if (TDS_FAILED(tds_process_simple_query(tds))) {
200 10 : odbc_errs_add(&dbc->errs, "HY000", "Could not change database");
201 10 : return SQL_ERROR;
202 : }
203 : } else {
204 40 : if (!tds_dstr_copyn(&dbc->attr.current_catalog, database, database_len)) {
205 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
206 0 : return SQL_ERROR;
207 : }
208 : }
209 70 : ODBC_RETURN_(dbc);
210 : }
211 :
212 : static SQLRETURN
213 124 : change_txn(TDS_DBC * dbc, SQLUINTEGER txn_isolation)
214 : {
215 : char query[64];
216 : const char *level;
217 124 : TDSSOCKET *tds = dbc->tds_socket;
218 124 : tds_mutex_check_owned(&dbc->mtx);
219 :
220 124 : switch (txn_isolation) {
221 : case SQL_TXN_READ_COMMITTED:
222 : level = "READ COMMITTED";
223 : break;
224 30 : case SQL_TXN_READ_UNCOMMITTED:
225 30 : level = "READ UNCOMMITTED";
226 30 : break;
227 44 : case SQL_TXN_REPEATABLE_READ:
228 44 : level = "REPEATABLE READ";
229 44 : break;
230 30 : case SQL_TXN_SERIALIZABLE:
231 30 : level = "SERIALIZABLE";
232 30 : break;
233 10 : default:
234 10 : odbc_errs_add(&dbc->errs, "HY024", NULL);
235 10 : return SQL_ERROR;
236 : }
237 :
238 : /* if not connected return success, will be set after connection */
239 114 : if (!tds)
240 : return SQL_SUCCESS;
241 :
242 82 : if (tds->state != TDS_IDLE) {
243 10 : odbc_errs_add(&dbc->errs, "HY011", NULL);
244 10 : return SQL_ERROR;
245 : }
246 :
247 72 : tds->query_timeout = dbc->default_query_timeout;
248 72 : sprintf(query, "SET TRANSACTION ISOLATION LEVEL %s", level);
249 72 : if (TDS_FAILED(tds_submit_query(tds, query))) {
250 0 : ODBC_SAFE_ERROR(dbc);
251 : return SQL_ERROR;
252 : }
253 72 : if (TDS_FAILED(tds_process_simple_query(tds))) {
254 0 : ODBC_SAFE_ERROR(dbc);
255 : return SQL_ERROR;
256 : }
257 :
258 : return SQL_SUCCESS;
259 : }
260 :
261 : static TDS_DBC*
262 10988 : odbc_get_dbc(TDSSOCKET *tds)
263 : {
264 10988 : TDS_CHK *chk = (TDS_CHK *) tds_get_parent(tds);
265 10988 : if (!chk)
266 : return NULL;
267 10988 : if (chk->htype == SQL_HANDLE_DBC)
268 : return (TDS_DBC *) chk;
269 4602 : assert(chk->htype == SQL_HANDLE_STMT);
270 4602 : return ((TDS_STMT *) chk)->dbc;
271 : }
272 :
273 : static TDS_STMT*
274 : odbc_get_stmt(TDSSOCKET *tds)
275 : {
276 6299 : TDS_CHK *chk = (TDS_CHK *) tds_get_parent(tds);
277 6299 : if (!chk || chk->htype != SQL_HANDLE_STMT)
278 : return NULL;
279 : return (TDS_STMT *) chk;
280 : }
281 :
282 :
283 : static void
284 4885 : odbc_env_change(TDSSOCKET * tds, int type, char *oldval TDS_UNUSED, char *newval)
285 : {
286 : TDS_DBC *dbc;
287 :
288 4885 : assert(tds);
289 :
290 4885 : dbc = odbc_get_dbc(tds);
291 4885 : if (!dbc)
292 : return;
293 :
294 4885 : switch (type) {
295 2537 : case TDS_ENV_DATABASE:
296 2537 : tds_dstr_copy(&dbc->attr.current_catalog, newval);
297 2537 : break;
298 1174 : case TDS_ENV_PACKSIZE:
299 1174 : dbc->attr.packet_size = atoi(newval);
300 1174 : break;
301 : }
302 : }
303 :
304 : static SQLRETURN
305 1186 : odbc_connect(TDS_DBC * dbc, TDSLOGIN * login)
306 : {
307 1186 : TDS_ENV *env = dbc->env;
308 1186 : tds_mutex_check_owned(&dbc->mtx);
309 :
310 : #ifdef ENABLE_ODBC_WIDE
311 1186 : dbc->mb_conv = NULL;
312 : #endif
313 1186 : dbc->tds_socket = tds_alloc_socket(env->tds_ctx, 512);
314 1186 : if (!dbc->tds_socket)
315 : goto memory_error;
316 :
317 1186 : dbc->tds_socket->conn->use_iconv_in = 0;
318 1186 : tds_set_parent(dbc->tds_socket, (void *) dbc);
319 :
320 : /* Set up our environment change hook */
321 1186 : dbc->tds_socket->env_chg_func = odbc_env_change;
322 :
323 1186 : tds_fix_login(login);
324 :
325 : /* use connection timeout if set */
326 1186 : if (dbc->attr.connection_timeout)
327 10 : login->connect_timeout = dbc->attr.connection_timeout;
328 :
329 : /* but override with login timeout, if set */
330 1186 : if (dbc->attr.login_timeout)
331 10 : login->connect_timeout = dbc->attr.login_timeout;
332 :
333 1186 : if (dbc->attr.mars_enabled != SQL_MARS_ENABLED_NO)
334 553 : login->mars = 1;
335 1186 : if (dbc->attr.bulk_enabled != SQL_BCP_OFF)
336 10 : tds_set_bulk(login, true);
337 :
338 : #ifdef ENABLE_ODBC_WIDE
339 : /* force utf-8 in order to support wide characters */
340 2372 : dbc->original_charset_num = tds_canonical_charset(tds_dstr_cstr(&login->client_charset));
341 1186 : if (dbc->original_charset_num < 0) {
342 : char *msg;
343 :
344 0 : tds_free_socket(dbc->tds_socket);
345 0 : dbc->tds_socket = NULL;
346 :
347 0 : if (asprintf(&msg, "Invalid \"%s\" character set specified", tds_dstr_cstr(&login->client_charset)) > 0) {
348 0 : odbc_errs_add(&dbc->errs, "HY024", msg);
349 0 : free(msg);
350 : } else {
351 0 : odbc_errs_add(&dbc->errs, "HY024", "Invalid character set specified");
352 : }
353 0 : ODBC_RETURN_(dbc);
354 : }
355 1186 : if (!tds_dstr_copy(&login->client_charset, "UTF-8"))
356 : goto memory_error;
357 : #endif
358 :
359 : /* replace password with old one */
360 1186 : if (dbc->use_oldpwd) {
361 2 : if (!tds_dstr_dup(&login->new_password, &login->password)
362 2 : || !tds_dstr_dup(&login->password, &dbc->oldpwd))
363 : goto memory_error;
364 2 : login->use_new_password = 1;
365 : }
366 :
367 1186 : if (!tds_dstr_dup(&login->db_filename, &dbc->db_filename))
368 : goto memory_error;
369 :
370 1186 : if (TDS_FAILED(tds_connect_and_login(dbc->tds_socket, login))) {
371 12 : tds_free_socket(dbc->tds_socket);
372 12 : dbc->tds_socket = NULL;
373 12 : odbc_errs_add(&dbc->errs, "08001", NULL);
374 12 : return SQL_ERROR;
375 : }
376 : #ifdef ENABLE_ODBC_WIDE
377 1174 : dbc->mb_conv = tds_iconv_get_info(dbc->tds_socket->conn, dbc->original_charset_num, TDS_CHARSET_UTF_8);
378 : #endif
379 :
380 1174 : dbc->default_query_timeout = dbc->tds_socket->query_timeout;
381 :
382 1174 : if (IS_TDS7_PLUS(dbc->tds_socket->conn))
383 950 : dbc->cursor_support = 1;
384 :
385 : #if ENABLE_ODBC_MARS
386 : /* check if mars is enabled */
387 587 : if (!IS_TDS72_PLUS(dbc->tds_socket->conn) || !dbc->tds_socket->conn->mars)
388 368 : dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
389 : #else
390 587 : dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
391 : #endif
392 :
393 1174 : if (dbc->attr.txn_isolation != SQL_TXN_READ_COMMITTED) {
394 32 : if (!SQL_SUCCEEDED(change_txn(dbc, dbc->attr.txn_isolation)))
395 0 : ODBC_RETURN_(dbc);
396 : }
397 :
398 1174 : if (dbc->attr.autocommit != SQL_AUTOCOMMIT_ON) {
399 42 : dbc->attr.autocommit = SQL_AUTOCOMMIT_ON;
400 42 : if (!SQL_SUCCEEDED(change_autocommit(dbc, SQL_AUTOCOMMIT_OFF)))
401 0 : ODBC_RETURN_(dbc);
402 : }
403 :
404 : /* this overwrite any error arrived (wanted behavior, Sybase return error for conversion errors) */
405 1174 : ODBC_RETURN(dbc, SQL_SUCCESS);
406 :
407 0 : memory_error:
408 0 : tds_free_socket(dbc->tds_socket);
409 0 : dbc->tds_socket = NULL;
410 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
411 0 : ODBC_RETURN_(dbc);
412 : }
413 :
414 : /**
415 : * Update IRD information.
416 : * This is needed if the IRD is not updated as requires query to be prepared.
417 : * For instance calling SQLNumResultCols after SQLPrepare we need to
418 : * know how many rows the query could return.
419 : */
420 : static SQLRETURN
421 74 : odbc_update_ird(TDS_STMT *stmt, TDS_ERRS *errs TDS_UNUSED)
422 : {
423 : SQLRETURN res;
424 :
425 74 : if (!stmt->need_reprepare || stmt->prepared_query_is_rpc
426 66 : || !stmt->dbc || !IS_TDS7_PLUS(stmt->dbc->tds_socket->conn)) {
427 10 : stmt->need_reprepare = 0;
428 : return SQL_SUCCESS;
429 : }
430 :
431 : /* FIXME where error are put ?? on stmt... */
432 64 : if (!odbc_lock_statement(stmt))
433 0 : ODBC_RETURN_(stmt);
434 :
435 : /* FIXME error */
436 64 : res = start_parse_prepared_query(stmt, false);
437 64 : if (res != SQL_SUCCESS) {
438 : /* prepare with dummy parameters just to fill IRD */
439 8 : tds_free_param_results(stmt->params);
440 8 : stmt->params = NULL;
441 8 : stmt->param_num = 0;
442 : /*
443 : * TODO
444 : * we need to prepare again with parameters but need_reprepare
445 : * flag is reset by odbc_prepare... perhaps should be checked
446 : * later, not calling describeCol or similar
447 : * we need prepare to get dynamic and cause we change parameters
448 : */
449 : }
450 :
451 64 : return odbc_prepare(stmt);
452 : }
453 :
454 : static SQLRETURN
455 374 : odbc_prepare(TDS_STMT *stmt)
456 : {
457 374 : TDSSOCKET *tds = stmt->tds;
458 374 : bool in_row = false;
459 :
460 748 : if (TDS_FAILED(tds_submit_prepare(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params))) {
461 20 : ODBC_SAFE_ERROR(stmt);
462 : return SQL_ERROR;
463 : }
464 :
465 : /* try to go to the next recordset */
466 : /* TODO merge with similar code */
467 354 : desc_free_records(stmt->ird);
468 354 : stmt->row_status = PRE_NORMAL_ROW;
469 : for (;;) {
470 : TDS_INT result_type;
471 : int done_flags;
472 :
473 794 : switch (tds_process_tokens(tds, &result_type, &done_flags, TDS_RETURN_ROWFMT|TDS_RETURN_DONE)) {
474 440 : case TDS_SUCCESS:
475 440 : switch (result_type) {
476 344 : case TDS_DONE_RESULT:
477 : case TDS_DONEPROC_RESULT:
478 : case TDS_DONEINPROC_RESULT:
479 344 : stmt->row_count = tds->rows_affected;
480 344 : if (done_flags & TDS_DONE_ERROR && !stmt->dyn->emulated)
481 2 : stmt->errs.lastrc = SQL_ERROR;
482 : /* FIXME this row is used only as a flag for update binding,
483 : * should be cleared if binding/result changed */
484 344 : stmt->row = 0;
485 344 : break;
486 :
487 96 : case TDS_ROWFMT_RESULT:
488 : /* store first row information */
489 96 : if (!in_row)
490 80 : odbc_populate_ird(stmt);
491 96 : stmt->row = 0;
492 96 : stmt->row_count = TDS_NO_COUNT;
493 96 : stmt->row_status = PRE_NORMAL_ROW;
494 96 : in_row = true;
495 96 : break;
496 : }
497 440 : continue;
498 : case TDS_NO_MORE_RESULTS:
499 : break;
500 0 : case TDS_CANCELLED:
501 0 : odbc_errs_add(&stmt->errs, "HY008", NULL);
502 10 : default:
503 10 : stmt->errs.lastrc = SQL_ERROR;
504 10 : break;
505 : }
506 354 : break;
507 : }
508 :
509 354 : if (stmt->errs.lastrc == SQL_ERROR && !stmt->dyn->emulated) {
510 12 : tds_release_dynamic(&stmt->dyn);
511 : }
512 354 : odbc_unlock_statement(stmt);
513 354 : stmt->need_reprepare = 0;
514 354 : ODBC_RETURN_(stmt);
515 : }
516 :
517 168 : ODBC_FUNC(SQLDriverConnect, (P(SQLHDBC,hdbc), P(SQLHWND,hwnd), PCHARIN(ConnStrIn,SQLSMALLINT),
518 : PCHAROUT(ConnStrOut,SQLSMALLINT), P(SQLUSMALLINT,fDriverCompletion) WIDE))
519 : {
520 : TDSLOGIN *login;
521 : TDS_PARSED_PARAM params[ODBC_PARAM_SIZE];
522 168 : DSTR conn_str = DSTR_INITIALIZER;
523 :
524 168 : ODBC_ENTER_HDBC;
525 :
526 : #ifdef TDS_NO_DM
527 : /* Check string length */
528 168 : if (!IS_VALID_LEN(cbConnStrIn) || cbConnStrIn == 0) {
529 0 : odbc_errs_add(&dbc->errs, "HY090", NULL);
530 0 : ODBC_EXIT_(dbc);
531 : }
532 :
533 : /* Check completion param */
534 168 : switch (fDriverCompletion) {
535 : case SQL_DRIVER_NOPROMPT:
536 : case SQL_DRIVER_COMPLETE:
537 : case SQL_DRIVER_PROMPT:
538 : case SQL_DRIVER_COMPLETE_REQUIRED:
539 : break;
540 0 : default:
541 0 : odbc_errs_add(&dbc->errs, "HY110", NULL);
542 0 : ODBC_EXIT_(dbc);
543 : }
544 : #endif
545 :
546 168 : if (!odbc_dstr_copy(dbc, &conn_str, cbConnStrIn, szConnStrIn)) {
547 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
548 0 : ODBC_EXIT_(dbc);
549 : }
550 :
551 168 : login = tds_alloc_login(false);
552 168 : if (!login || !tds_init_login(login, dbc->env->tds_ctx->locale)) {
553 0 : tds_free_login(login);
554 0 : tds_dstr_free(&conn_str);
555 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
556 0 : ODBC_EXIT_(dbc);
557 : }
558 :
559 336 : if (!tds_dstr_isempty(&dbc->attr.current_catalog))
560 20 : if (!tds_dstr_dup(&login->database, &dbc->attr.current_catalog)) {
561 0 : tds_free_login(login);
562 0 : tds_dstr_free(&conn_str);
563 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
564 0 : ODBC_EXIT_(dbc);
565 : }
566 :
567 : /* parse the DSN string */
568 504 : if (!odbc_parse_connect_string(&dbc->errs, tds_dstr_buf(&conn_str), tds_dstr_buf(&conn_str) + tds_dstr_len(&conn_str),
569 : login, dbc, params)) {
570 10 : tds_free_login(login);
571 10 : tds_dstr_free(&conn_str);
572 10 : ODBC_EXIT_(dbc);
573 : }
574 :
575 474 : odbc_set_dstr(dbc, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, &conn_str);
576 158 : tds_dstr_free(&conn_str);
577 :
578 : /* add login info */
579 158 : if (hwnd && fDriverCompletion != SQL_DRIVER_NOPROMPT
580 0 : && (fDriverCompletion == SQL_DRIVER_PROMPT || (!params[ODBC_PARAM_UID].p && !params[ODBC_PARAM_Trusted_Connection].p)
581 0 : || tds_dstr_isempty(&login->server_name))) {
582 : #ifdef _WIN32
583 : char *out = NULL;
584 :
585 : /* prompt for login information */
586 : if (!get_login_info(hwnd, login)) {
587 : tds_free_login(login);
588 : odbc_errs_add(&dbc->errs, "08001", "User canceled login");
589 : ODBC_EXIT_(dbc);
590 : }
591 : if (tds_dstr_isempty(&login->user_name)) {
592 : params[ODBC_PARAM_UID].p = NULL;
593 : params[ODBC_PARAM_PWD].p = NULL;
594 : params[ODBC_PARAM_Trusted_Connection].p = "Yes";
595 : params[ODBC_PARAM_Trusted_Connection].len = 3;
596 : } else {
597 : params[ODBC_PARAM_UID].p = tds_dstr_cstr(&login->user_name);
598 : params[ODBC_PARAM_UID].len = tds_dstr_len(&login->user_name);
599 : params[ODBC_PARAM_PWD].p = tds_dstr_cstr(&login->password);
600 : params[ODBC_PARAM_PWD].len = tds_dstr_len(&login->password);
601 : params[ODBC_PARAM_Trusted_Connection].p = NULL;
602 : }
603 : if (!odbc_build_connect_string(&dbc->errs, params, &out))
604 : ODBC_EXIT_(dbc);
605 :
606 : odbc_set_string(dbc, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, out, -1);
607 : tdsdump_log(TDS_DBG_INFO1, "connection string is now: %s\n", out);
608 : free(out);
609 : #else
610 : /* we dont support a dialog box */
611 0 : odbc_errs_add(&dbc->errs, "HYC00", NULL);
612 : #endif
613 : }
614 :
615 316 : if (tds_dstr_isempty(&login->server_name)) {
616 0 : tds_free_login(login);
617 0 : odbc_errs_add(&dbc->errs, "IM007", "Could not find Servername or server parameter");
618 0 : ODBC_EXIT_(dbc);
619 : }
620 :
621 158 : odbc_connect(dbc, login);
622 :
623 158 : tds_free_login(login);
624 158 : ODBC_EXIT_(dbc);
625 : }
626 :
627 : #if 0
628 : SQLRETURN ODBC_PUBLIC ODBC_API
629 : SQLBrowseConnect(SQLHDBC hdbc, SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR FAR * szConnStrOut,
630 : SQLSMALLINT cbConnStrOutMax, SQLSMALLINT FAR * pcbConnStrOut)
631 : {
632 : ODBC_ENTER_HDBC;
633 :
634 : tdsdump_log(TDS_DBG_FUNC, "SQLBrowseConnect(%p, %s, %d, %p, %d, %p)\n",
635 : hdbc, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut);
636 : odbc_errs_add(&dbc->errs, "HYC00", "SQLBrowseConnect: function not implemented");
637 : ODBC_EXIT_(dbc);
638 : }
639 : #endif
640 :
641 :
642 : SQLRETURN ODBC_PUBLIC ODBC_API
643 : SQLDescribeParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT FAR *pfSqlType, SQLULEN FAR *pcbParamDef,
644 : SQLSMALLINT FAR *pibScale, SQLSMALLINT FAR *pfNullable)
645 : {
646 : TDS_DESC *ipd;
647 : struct _drecord *drec;
648 :
649 27 : ODBC_ENTER_HSTMT;
650 :
651 27 : tdsdump_log(TDS_DBG_FUNC, "SQLDescribeParam(%p, %d, %p, %p, %p, %p)\n",
652 : hstmt, ipar, pfSqlType, pcbParamDef, pibScale, pfNullable);
653 :
654 : /* Check if we need to ask server (not set params, we not asked before). */
655 : /* We need to reset set params resetting them. */
656 27 : if (!stmt->params_queried && !stmt->params_set && stmt->param_count > 0)
657 9 : read_params(stmt);
658 :
659 : /* return information from IPD */
660 27 : ipd = stmt->ipd;
661 27 : if (ipar < 1 || ipar > ipd->header.sql_desc_count) {
662 7 : odbc_errs_add(&stmt->errs, "07009", NULL);
663 7 : ODBC_EXIT_(stmt);
664 : }
665 20 : drec = &ipd->records[ipar - 1];
666 :
667 20 : if (pfSqlType)
668 20 : *pfSqlType = drec->sql_desc_type;
669 20 : if (pfNullable)
670 20 : *pfNullable = drec->sql_desc_nullable;
671 20 : switch (drec->sql_desc_type) {
672 2 : case SQL_DECIMAL:
673 : case SQL_NUMERIC:
674 2 : if (pcbParamDef)
675 2 : *pcbParamDef = drec->sql_desc_precision;
676 2 : if (pibScale)
677 2 : *pibScale = drec->sql_desc_scale;
678 : break;
679 18 : default:
680 18 : if (pcbParamDef)
681 18 : *pcbParamDef = drec->sql_desc_length;
682 18 : if (pibScale)
683 18 : *pibScale = 0;
684 : break;
685 : }
686 20 : ODBC_EXIT_(stmt);
687 : }
688 :
689 : SQLRETURN ODBC_PUBLIC ODBC_API
690 : SQLExtendedFetch(SQLHSTMT hstmt, SQLUSMALLINT fFetchType, SQLROWOFFSET irow,
691 : SQLROWSETSIZE FAR * pcrow, SQLUSMALLINT FAR * rgfRowStatus)
692 : {
693 : SQLRETURN ret;
694 : SQLULEN *tmp_rows;
695 : SQLUSMALLINT *tmp_status;
696 : SQLULEN tmp_size;
697 : SQLPOINTER tmp_bookmark;
698 : SQLULEN bookmark;
699 28 : SQLULEN out_len = 0;
700 :
701 28 : ODBC_ENTER_HSTMT;
702 :
703 28 : tdsdump_log(TDS_DBG_FUNC, "SQLExtendedFetch(%p, %d, %d, %p, %p)\n",
704 : hstmt, fFetchType, (int)irow, pcrow, rgfRowStatus);
705 :
706 28 : if (fFetchType != SQL_FETCH_NEXT && !stmt->dbc->cursor_support) {
707 0 : odbc_errs_add(&stmt->errs, "HY106", NULL);
708 0 : ODBC_EXIT_(stmt);
709 : }
710 :
711 : /* save and change IRD/ARD state */
712 28 : tmp_rows = stmt->ird->header.sql_desc_rows_processed_ptr;
713 28 : stmt->ird->header.sql_desc_rows_processed_ptr = &out_len;
714 28 : tmp_status = stmt->ird->header.sql_desc_array_status_ptr;
715 28 : stmt->ird->header.sql_desc_array_status_ptr = rgfRowStatus;
716 28 : tmp_size = stmt->ard->header.sql_desc_array_size;
717 28 : stmt->ard->header.sql_desc_array_size = stmt->sql_rowset_size;
718 28 : tmp_bookmark = stmt->attr.fetch_bookmark_ptr;
719 :
720 : /* SQL_FETCH_BOOKMARK different */
721 28 : if (fFetchType == SQL_FETCH_BOOKMARK) {
722 0 : bookmark = irow;
723 0 : irow = 0;
724 0 : stmt->attr.fetch_bookmark_ptr = &bookmark;
725 : }
726 :
727 : /* TODO errors are sligthly different ... perhaps it's better to leave DM do this job ?? */
728 : /* TODO check fFetchType can be converted to USMALLINT */
729 28 : ret = odbc_SQLFetch(stmt, fFetchType, irow);
730 :
731 : /* restore IRD/ARD */
732 28 : stmt->ird->header.sql_desc_rows_processed_ptr = tmp_rows;
733 28 : if (pcrow)
734 28 : *pcrow = out_len;
735 28 : stmt->ird->header.sql_desc_array_status_ptr = tmp_status;
736 28 : stmt->ard->header.sql_desc_array_size = tmp_size;
737 28 : stmt->attr.fetch_bookmark_ptr = tmp_bookmark;
738 :
739 28 : ODBC_EXIT(stmt, ret);
740 : }
741 :
742 : static bool
743 69981 : odbc_lock_statement(TDS_STMT *stmt)
744 : {
745 : #if ENABLE_ODBC_MARS
746 35164 : TDSSOCKET *tds = stmt->tds;
747 :
748 :
749 : /* we already own a socket, just use it */
750 35164 : if (!tds) {
751 : /* try with one saved into DBC */
752 16846 : TDSSOCKET *dbc_tds = stmt->dbc->tds_socket;
753 16846 : tds_mutex_lock(&stmt->dbc->mtx);
754 :
755 16846 : if (stmt->dbc->current_statement == NULL
756 54 : || stmt->dbc->current_statement == stmt) {
757 16792 : tds = dbc_tds;
758 16792 : stmt->dbc->current_statement = stmt;
759 : }
760 :
761 : /* try to grab current locked one */
762 16846 : if (!tds && dbc_tds->state == TDS_IDLE) {
763 40 : stmt->dbc->current_statement->tds = NULL;
764 40 : tds = dbc_tds;
765 40 : stmt->dbc->current_statement = stmt;
766 : }
767 16846 : tds_mutex_unlock(&stmt->dbc->mtx);
768 :
769 : /* try with MARS */
770 16846 : if (!tds) {
771 14 : tds = tds_alloc_additional_socket(dbc_tds->conn);
772 14 : if (tds)
773 8 : tdsdump_log(TDS_DBG_INFO1, "MARS SID %d allocated with new TDSSOCKET\n", tds->sid);
774 : }
775 : }
776 35164 : if (tds) {
777 70316 : tds->query_timeout = (stmt->attr.query_timeout != DEFAULT_QUERY_TIMEOUT) ?
778 35158 : stmt->attr.query_timeout : stmt->dbc->default_query_timeout;
779 35158 : tds_set_parent(tds, stmt);
780 35158 : stmt->tds = tds;
781 35158 : return true;
782 : }
783 6 : odbc_errs_add(&stmt->errs, "24000", NULL);
784 6 : return false;
785 : #else
786 34817 : TDSSOCKET *tds = stmt->dbc->tds_socket;
787 :
788 34817 : tds_mutex_lock(&stmt->dbc->mtx);
789 34817 : if (stmt->dbc->current_statement != NULL
790 18030 : && stmt->dbc->current_statement != stmt) {
791 51 : if (!tds || tds->state != TDS_IDLE) {
792 11 : tds_mutex_unlock(&stmt->dbc->mtx);
793 11 : odbc_errs_add(&stmt->errs, "24000", NULL);
794 11 : return false;
795 : }
796 40 : stmt->dbc->current_statement->tds = NULL;
797 : }
798 34806 : stmt->dbc->current_statement = stmt;
799 34806 : if (tds) {
800 69612 : tds->query_timeout = (stmt->attr.query_timeout != DEFAULT_QUERY_TIMEOUT) ?
801 34806 : stmt->attr.query_timeout : stmt->dbc->default_query_timeout;
802 34806 : tds_set_parent(tds, stmt);
803 34806 : stmt->tds = tds;
804 : }
805 34806 : tds_mutex_unlock(&stmt->dbc->mtx);
806 34806 : return true;
807 : #endif
808 : }
809 :
810 : static void
811 48856 : odbc_unlock_statement(TDS_STMT* stmt)
812 : {
813 : TDSSOCKET * tds;
814 :
815 48856 : tds_mutex_lock(&stmt->dbc->mtx);
816 48856 : tds = stmt->tds;
817 48856 : if (stmt->dbc->current_statement == stmt) {
818 33081 : assert(tds == stmt->dbc->tds_socket);
819 33081 : if (tds->state == TDS_IDLE || tds->state == TDS_DEAD) {
820 33081 : stmt->dbc->current_statement = NULL;
821 33081 : tds_set_parent(tds, stmt->dbc);
822 33081 : stmt->tds = NULL;
823 : }
824 : }
825 : /* NOTE: MARS socket now released when statement freed. */
826 48856 : tds_mutex_unlock(&stmt->dbc->mtx);
827 48856 : }
828 :
829 : SQLRETURN ODBC_PUBLIC ODBC_API
830 : SQLMoreResults(SQLHSTMT hstmt)
831 : {
832 : TDSSOCKET *tds;
833 : TDS_INT result_type;
834 : TDSRET tdsret;
835 10914 : bool in_row = false;
836 : SQLUSMALLINT param_status;
837 : unsigned int token_flags;
838 :
839 10914 : ODBC_ENTER_HSTMT;
840 :
841 10914 : tdsdump_log(TDS_DBG_FUNC, "SQLMoreResults(%p)\n", hstmt);
842 :
843 10914 : tds = stmt->tds;
844 :
845 : /* We already read all results... */
846 10914 : if (!tds)
847 785 : ODBC_EXIT(stmt, SQL_NO_DATA);
848 :
849 10129 : stmt->row_count = TDS_NO_COUNT;
850 10129 : stmt->special_row = ODBC_SPECIAL_NONE;
851 :
852 : /* TODO this code is TOO similar to odbc_SQLExecute, merge it - freddy77 */
853 : /* try to go to the next recordset */
854 10129 : if (stmt->row_status == IN_COMPUTE_ROW) {
855 : /* FIXME doesn't seem so fine ... - freddy77 */
856 16 : tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
857 16 : stmt->row_status = IN_COMPUTE_ROW;
858 16 : in_row = true;
859 : }
860 :
861 10129 : param_status = SQL_PARAM_SUCCESS;
862 10129 : token_flags = (TDS_TOKEN_RESULTS & (~TDS_STOPAT_COMPUTE)) | TDS_RETURN_COMPUTE;
863 10129 : if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
864 8307 : token_flags |= TDS_RETURN_MSG;
865 : for (;;) {
866 10672 : result_type = odbc_process_tokens(stmt, token_flags);
867 10672 : tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: result_type=%d, row_count=%" PRId64 ", lastrc=%d\n",
868 : result_type, stmt->row_count, stmt->errs.lastrc);
869 10672 : switch (result_type) {
870 8969 : case TDS_CMD_DONE:
871 : #if 1 /* !UNIXODBC */
872 8969 : tds_free_all_results(tds);
873 : #endif
874 8969 : odbc_populate_ird(stmt);
875 8969 : odbc_unlock_statement(stmt);
876 8969 : if (stmt->row_count == TDS_NO_COUNT && !in_row) {
877 8911 : stmt->row_status = NOT_IN_ROW;
878 8911 : tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: row_status=%d\n", stmt->row_status);
879 : }
880 8969 : tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: row_count=%" PRId64 ", lastrc=%d\n", stmt->row_count,
881 : stmt->errs.lastrc);
882 8969 : if (stmt->row_count == TDS_NO_COUNT) {
883 8923 : if (stmt->errs.lastrc == SQL_SUCCESS || stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO)
884 8919 : ODBC_EXIT(stmt, SQL_NO_DATA);
885 : }
886 50 : ODBC_EXIT_(stmt);
887 :
888 0 : case TDS_CMD_FAIL:
889 0 : ODBC_SAFE_ERROR(stmt);
890 0 : ODBC_EXIT_(stmt);
891 :
892 48 : case TDS_COMPUTE_RESULT:
893 48 : switch (stmt->row_status) {
894 : /* skip this recordset */
895 : case IN_COMPUTE_ROW:
896 : /* TODO here we should set current_results to normal results */
897 : in_row = true;
898 : /* fall through */
899 : /* in normal row, put in compute status */
900 48 : case AFTER_COMPUTE_ROW:
901 : case IN_NORMAL_ROW:
902 : case PRE_NORMAL_ROW:
903 48 : stmt->row_status = IN_COMPUTE_ROW;
904 48 : odbc_populate_ird(stmt);
905 48 : ODBC_EXIT_(stmt);
906 0 : case NOT_IN_ROW:
907 : /* this should never happen, protocol error */
908 0 : ODBC_SAFE_ERROR(stmt);
909 0 : ODBC_EXIT_(stmt);
910 : break;
911 : }
912 : break;
913 :
914 389 : case TDS_ROW_RESULT:
915 389 : if (in_row || (stmt->row_status != IN_NORMAL_ROW && stmt->row_status != PRE_NORMAL_ROW)) {
916 158 : stmt->row_status = PRE_NORMAL_ROW;
917 158 : odbc_populate_ird(stmt);
918 158 : ODBC_EXIT_(stmt);
919 : }
920 : /* Skipping current result set's rows to access next resultset or proc's retval */
921 231 : tdsret = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_STOPAT_COMPUTE);
922 : /* TODO should we set in_row ?? */
923 231 : switch (tdsret) {
924 0 : case TDS_CANCELLED:
925 0 : odbc_errs_add(&stmt->errs, "HY008", NULL);
926 231 : default:
927 231 : if (TDS_FAILED(tdsret)) {
928 0 : ODBC_SAFE_ERROR(stmt);
929 0 : ODBC_EXIT_(stmt);
930 : }
931 : }
932 : break;
933 :
934 872 : case TDS_DONE_RESULT:
935 : case TDS_DONEPROC_RESULT:
936 : /* FIXME here ??? */
937 872 : if (!in_row)
938 804 : tds_free_all_results(tds);
939 872 : switch (stmt->errs.lastrc) {
940 70 : case SQL_ERROR:
941 70 : param_status = SQL_PARAM_ERROR;
942 70 : break;
943 58 : case SQL_SUCCESS_WITH_INFO:
944 58 : param_status = SQL_PARAM_SUCCESS_WITH_INFO;
945 58 : break;
946 : }
947 872 : if (stmt->curr_param_row < stmt->num_param_rows) {
948 0 : if (stmt->ipd->header.sql_desc_array_status_ptr)
949 0 : stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
950 0 : ++stmt->curr_param_row;
951 0 : if (stmt->ipd->header.sql_desc_rows_processed_ptr)
952 0 : *stmt->ipd->header.sql_desc_rows_processed_ptr = stmt->curr_param_row;
953 : }
954 872 : if (stmt->curr_param_row < stmt->num_param_rows) {
955 : #if 0
956 : if (stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO)
957 : found_info = 1;
958 : if (stmt->errs.lastrc == SQL_ERROR)
959 : found_error = 1;
960 : #endif
961 0 : stmt->errs.lastrc = SQL_SUCCESS;
962 0 : param_status = SQL_PARAM_SUCCESS;
963 0 : break;
964 : }
965 872 : odbc_populate_ird(stmt);
966 872 : ODBC_EXIT_(stmt);
967 : break;
968 :
969 : /*
970 : * TODO test flags ? check error and change result ?
971 : * see also other DONEINPROC handle (below)
972 : */
973 86 : case TDS_DONEINPROC_RESULT:
974 86 : if (in_row) {
975 70 : odbc_populate_ird(stmt);
976 70 : ODBC_EXIT_(stmt);
977 : }
978 : /* TODO perhaps it can be a problem if SET NOCOUNT ON, test it */
979 16 : tds_free_all_results(tds);
980 16 : odbc_populate_ird(stmt);
981 16 : break;
982 :
983 : /* do not stop at metadata, an error can follow... */
984 194 : case TDS_ROWFMT_RESULT:
985 194 : if (in_row) {
986 12 : odbc_populate_ird(stmt);
987 12 : ODBC_EXIT_(stmt);
988 : }
989 182 : stmt->row = 0;
990 182 : stmt->row_count = TDS_NO_COUNT;
991 : /* we expect a row */
992 182 : stmt->row_status = PRE_NORMAL_ROW;
993 182 : in_row = true;
994 182 : break;
995 :
996 114 : case TDS_MSG_RESULT:
997 114 : if (!in_row) {
998 114 : tds_free_all_results(tds);
999 114 : odbc_populate_ird(stmt);
1000 : }
1001 : in_row = true;
1002 : break;
1003 : }
1004 : }
1005 : ODBC_EXIT(stmt, SQL_ERROR);
1006 : }
1007 :
1008 0 : ODBC_FUNC(SQLNativeSql, (P(SQLHDBC,hdbc), PCHARIN(SqlStrIn,SQLINTEGER),
1009 : PCHAROUT(SqlStr,SQLINTEGER) WIDE))
1010 : {
1011 0 : SQLRETURN ret = SQL_SUCCESS;
1012 0 : DSTR query = DSTR_INITIALIZER;
1013 :
1014 0 : ODBC_ENTER_HDBC;
1015 :
1016 : #ifdef TDS_NO_DM
1017 0 : if (!szSqlStrIn || !IS_VALID_LEN(cbSqlStrIn)) {
1018 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
1019 0 : ODBC_EXIT_(dbc);
1020 : }
1021 : #endif
1022 :
1023 0 : if (!odbc_dstr_copy(dbc, &query, cbSqlStrIn, szSqlStrIn)) {
1024 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1025 0 : ODBC_EXIT_(dbc);
1026 : }
1027 :
1028 0 : native_sql(dbc, &query);
1029 :
1030 : /* FIXME if error set some kind of error */
1031 0 : ret = odbc_set_dstr(dbc, szSqlStr, cbSqlStrMax, pcbSqlStr, &query);
1032 :
1033 0 : tds_dstr_free(&query);
1034 :
1035 0 : ODBC_EXIT(dbc, ret);
1036 : }
1037 :
1038 : SQLRETURN ODBC_PUBLIC ODBC_API
1039 : SQLNumParams(SQLHSTMT hstmt, SQLSMALLINT FAR * pcpar)
1040 : {
1041 46 : ODBC_ENTER_HSTMT;
1042 46 : tdsdump_log(TDS_DBG_FUNC, "SQLNumParams(%p, %p)\n", hstmt, pcpar);
1043 46 : *pcpar = stmt->param_count;
1044 46 : ODBC_EXIT_(stmt);
1045 : }
1046 :
1047 : SQLRETURN ODBC_PUBLIC ODBC_API
1048 : SQLParamOptions(SQLHSTMT hstmt, SQLULEN crow, SQLULEN FAR * pirow)
1049 : {
1050 : SQLRETURN res;
1051 :
1052 20 : tdsdump_log(TDS_DBG_FUNC, "SQLParamOptions(%p, %lu, %p)\n", hstmt, (unsigned long int)crow, pirow);
1053 :
1054 : /* emulate for ODBC 2 DM */
1055 20 : res = odbc_SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, pirow, 0 _wide0);
1056 20 : if (res != SQL_SUCCESS)
1057 : return res;
1058 20 : return odbc_SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) (TDS_INTPTR) crow, 0 _wide0);
1059 : }
1060 :
1061 : static TDSPARAMINFO *
1062 80 : odbc_build_update_params(TDS_STMT *stmt, SQLSETPOSIROW n_row)
1063 : {
1064 : SQLSMALLINT n;
1065 80 : TDSPARAMINFO * params = NULL;
1066 : struct _drecord *drec_ird;
1067 :
1068 240 : for (n = 0; n < stmt->ird->header.sql_desc_count && n < stmt->ard->header.sql_desc_count; ++n) {
1069 : TDSPARAMINFO *temp_params;
1070 : TDSCOLUMN *curcol;
1071 :
1072 160 : drec_ird = &stmt->ird->records[n];
1073 :
1074 160 : if (drec_ird->sql_desc_updatable == SQL_FALSE)
1075 16 : continue;
1076 :
1077 : /* we have certainly a parameter */
1078 144 : if (!(temp_params = tds_alloc_param_result(params)))
1079 : goto memory_error;
1080 144 : params = temp_params;
1081 :
1082 144 : curcol = params->columns[params->num_cols - 1];
1083 144 : if (!tds_dstr_dup(&curcol->column_name, &drec_ird->sql_desc_name))
1084 : goto memory_error;
1085 :
1086 : /* TODO use all infos... */
1087 144 : if (!tds_dstr_dup(&curcol->table_name, &drec_ird->sql_desc_base_table_name))
1088 : goto memory_error;
1089 :
1090 144 : switch (odbc_sql2tds(stmt, drec_ird, &stmt->ard->records[n], curcol, true, stmt->ard, n_row)) {
1091 : case SQL_NEED_DATA:
1092 : goto memory_error;
1093 0 : case SQL_ERROR:
1094 0 : tds_free_param_results(params);
1095 0 : return NULL;
1096 : }
1097 : }
1098 : return params;
1099 :
1100 0 : memory_error:
1101 0 : tds_free_param_results(params);
1102 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
1103 0 : return NULL;
1104 : }
1105 :
1106 : SQLRETURN ODBC_PUBLIC ODBC_API
1107 : SQLSetPos(SQLHSTMT hstmt, SQLSETPOSIROW irow, SQLUSMALLINT fOption, SQLUSMALLINT fLock)
1108 : {
1109 : TDSRET ret;
1110 : TDSSOCKET *tds;
1111 : TDS_CURSOR_OPERATION op;
1112 320 : TDSPARAMINFO *params = NULL;
1113 320 : ODBC_ENTER_HSTMT;
1114 :
1115 320 : tdsdump_log(TDS_DBG_FUNC, "SQLSetPos(%p, %ld, %d, %d)\n",
1116 : hstmt, (long) irow, fOption, fLock);
1117 :
1118 320 : if (!stmt->dbc->cursor_support) {
1119 0 : odbc_errs_add(&stmt->errs, "HYC00", "SQLSetPos: function not implemented");
1120 0 : ODBC_EXIT_(stmt);
1121 : }
1122 :
1123 : /* TODO handle irow == 0 (all rows) */
1124 :
1125 320 : if (!stmt->cursor) {
1126 0 : odbc_errs_add(&stmt->errs, "HY109", NULL);
1127 0 : ODBC_EXIT_(stmt);
1128 : }
1129 :
1130 320 : switch (fOption) {
1131 : case SQL_POSITION:
1132 : op = TDS_CURSOR_POSITION;
1133 : break;
1134 : /* TODO cursor support */
1135 0 : case SQL_REFRESH:
1136 : default:
1137 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
1138 0 : ODBC_EXIT_(stmt);
1139 : break;
1140 80 : case SQL_UPDATE:
1141 80 : op = TDS_CURSOR_UPDATE;
1142 : /* prepare paremeters for update */
1143 : /* scan all columns and build parameter list */
1144 80 : params = odbc_build_update_params(stmt, irow >= 1 ? irow - 1 : 0);
1145 80 : if (!params) {
1146 0 : ODBC_SAFE_ERROR(stmt);
1147 0 : ODBC_EXIT_(stmt);
1148 : }
1149 : break;
1150 80 : case SQL_DELETE:
1151 80 : op = TDS_CURSOR_DELETE;
1152 80 : break;
1153 0 : case SQL_ADD:
1154 0 : op = TDS_CURSOR_INSERT;
1155 0 : break;
1156 : }
1157 :
1158 320 : if (!odbc_lock_statement(stmt)) {
1159 0 : tds_free_param_results(params);
1160 0 : ODBC_EXIT_(stmt);
1161 : }
1162 :
1163 320 : tds = stmt->tds;
1164 :
1165 320 : if (TDS_FAILED(tds_cursor_update(tds, stmt->cursor, op, irow, params))) {
1166 0 : tds_free_param_results(params);
1167 0 : ODBC_SAFE_ERROR(stmt);
1168 0 : ODBC_EXIT_(stmt);
1169 : }
1170 320 : tds_free_param_results(params);
1171 320 : params = NULL;
1172 :
1173 320 : ret = tds_process_simple_query(tds);
1174 320 : odbc_unlock_statement(stmt);
1175 320 : if (TDS_FAILED(ret)) {
1176 0 : ODBC_SAFE_ERROR(stmt);
1177 0 : ODBC_EXIT_(stmt);
1178 : }
1179 :
1180 320 : ODBC_EXIT_(stmt);
1181 : }
1182 :
1183 : #if (ODBCVER >= 0x0300)
1184 : SQLRETURN ODBC_PUBLIC ODBC_API
1185 : SQLSetEnvAttr(SQLHENV henv, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength)
1186 : {
1187 618 : SQLINTEGER i_val = (SQLINTEGER) (TDS_INTPTR) Value;
1188 :
1189 618 : ODBC_ENTER_HENV;
1190 :
1191 618 : tdsdump_log(TDS_DBG_FUNC, "SQLSetEnvAttr(%p, %d, %p, %d)\n", henv, (int)Attribute, Value, (int)StringLength);
1192 :
1193 618 : switch (Attribute) {
1194 0 : case SQL_ATTR_CONNECTION_POOLING:
1195 : case SQL_ATTR_CP_MATCH:
1196 0 : odbc_errs_add(&env->errs, "HYC00", NULL);
1197 0 : break;
1198 618 : case SQL_ATTR_ODBC_VERSION:
1199 618 : switch (i_val) {
1200 618 : case SQL_OV_ODBC3:
1201 : case SQL_OV_ODBC2:
1202 618 : env->attr.odbc_version = i_val;
1203 618 : break;
1204 0 : default:
1205 0 : odbc_errs_add(&env->errs, "HY024", NULL);
1206 0 : break;
1207 : }
1208 : break;
1209 0 : case SQL_ATTR_OUTPUT_NTS:
1210 : /* TODO - Make this really work */
1211 : /* env->attr.output_nts = i_val; */
1212 0 : env->attr.output_nts = SQL_TRUE;
1213 0 : break;
1214 0 : default:
1215 0 : odbc_errs_add(&env->errs, "HY092", NULL);
1216 0 : break;
1217 : }
1218 618 : ODBC_EXIT_(env);
1219 : }
1220 :
1221 : SQLRETURN ODBC_PUBLIC ODBC_API
1222 : SQLGetEnvAttr(SQLHENV henv, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
1223 : {
1224 : static const SQLINTEGER unicode_type =
1225 : sizeof(SQLWCHAR) == 4 ? SQL_DM_CP_UCS4 : SQL_DM_CP_UTF16;
1226 : SQLINTEGER size;
1227 : const void *src;
1228 :
1229 0 : ODBC_ENTER_HENV;
1230 :
1231 0 : tdsdump_log(TDS_DBG_FUNC, "SQLGetEnvAttr(%p, %d, %p, %d, %p)\n",
1232 : henv, (int)Attribute, Value, (int)BufferLength, StringLength);
1233 :
1234 0 : switch (Attribute) {
1235 0 : case SQL_ATTR_CONNECTION_POOLING:
1236 0 : src = &env->attr.connection_pooling;
1237 0 : size = sizeof(env->attr.connection_pooling);
1238 0 : break;
1239 0 : case SQL_ATTR_CP_MATCH:
1240 0 : src = &env->attr.cp_match;
1241 0 : size = sizeof(env->attr.cp_match);
1242 0 : break;
1243 0 : case SQL_ATTR_ODBC_VERSION:
1244 0 : src = &env->attr.odbc_version;
1245 0 : size = sizeof(env->attr.odbc_version);
1246 0 : break;
1247 0 : case SQL_ATTR_OUTPUT_NTS:
1248 : /* TODO handle output_nts flags */
1249 0 : env->attr.output_nts = SQL_TRUE;
1250 0 : src = &env->attr.output_nts;
1251 0 : size = sizeof(env->attr.output_nts);
1252 0 : break;
1253 : case SQL_ATTR_DRIVER_UNICODE_TYPE:
1254 : /* iODBC extension, tell which Unicode encoding we support */
1255 : src = &unicode_type;
1256 : size = sizeof(unicode_type);
1257 : break;
1258 0 : default:
1259 0 : odbc_errs_add(&env->errs, "HY092", NULL);
1260 0 : ODBC_EXIT_(env);
1261 : break;
1262 : }
1263 :
1264 0 : if (StringLength) {
1265 0 : *StringLength = size;
1266 : }
1267 0 : memcpy(Value, src, size);
1268 :
1269 0 : ODBC_EXIT_(env);
1270 : }
1271 :
1272 : #endif
1273 :
1274 : #define IRD_UPDATE(desc, errs, exit) \
1275 : do { \
1276 : if (desc->type == DESC_IRD && ((TDS_STMT*)desc->parent)->need_reprepare && \
1277 : odbc_update_ird((TDS_STMT*)desc->parent, errs) != SQL_SUCCESS) \
1278 : exit; \
1279 : } while(0)
1280 :
1281 : static SQLRETURN
1282 15182 : odbc_SQLBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType,
1283 : SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
1284 : {
1285 : TDS_DESC *apd, *ipd;
1286 : struct _drecord *drec;
1287 : SQLSMALLINT orig_apd_size, orig_ipd_size;
1288 15182 : bool is_numeric = false;
1289 :
1290 15182 : ODBC_ENTER_HSTMT;
1291 :
1292 15182 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLBindParameter(%p, %u, %d, %d, %d, %u, %d, %p, %d, %p)\n",
1293 : hstmt, (unsigned)ipar, (int)fParamType, (int)fCType, (int)fSqlType, (unsigned int)cbColDef,
1294 : (int)ibScale, rgbValue, (int)cbValueMax, pcbValue);
1295 :
1296 : #ifdef TDS_NO_DM
1297 : /* TODO - more error checking ... XXX smurph */
1298 :
1299 : /* Check param type */
1300 : switch (fParamType) {
1301 : case SQL_PARAM_INPUT:
1302 : case SQL_PARAM_INPUT_OUTPUT:
1303 : case SQL_PARAM_OUTPUT:
1304 : break;
1305 0 : default:
1306 0 : odbc_errs_add(&stmt->errs, "HY105", NULL);
1307 0 : ODBC_EXIT_(stmt);
1308 : }
1309 :
1310 : /* Check max buffer length */
1311 15182 : if (cbValueMax < 0 && cbValueMax != SQL_NTS) {
1312 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
1313 0 : ODBC_EXIT_(stmt);
1314 : }
1315 : #endif
1316 :
1317 : /* check cbColDef and ibScale */
1318 15182 : if (fSqlType == SQL_DECIMAL || fSqlType == SQL_NUMERIC) {
1319 220 : is_numeric = true;
1320 220 : if (cbColDef < 1 || cbColDef > 38) {
1321 0 : odbc_errs_add(&stmt->errs, "HY104", "Invalid precision value");
1322 0 : ODBC_EXIT_(stmt);
1323 : }
1324 220 : if (ibScale < 0 || (SQLULEN) ibScale > cbColDef) {
1325 0 : odbc_errs_add(&stmt->errs, "HY104", "Invalid scale value");
1326 0 : ODBC_EXIT_(stmt);
1327 : }
1328 : }
1329 :
1330 : /* Check parameter number */
1331 15182 : if (ipar <= 0 || ipar > 4000) {
1332 0 : odbc_errs_add(&stmt->errs, "07009", NULL);
1333 0 : ODBC_EXIT_(stmt);
1334 : }
1335 :
1336 : /* special checks for table type */
1337 15182 : if (fSqlType == SQL_SS_TABLE) {
1338 : /* Table types are strictly read-only */
1339 4152 : if (fParamType != SQL_PARAM_INPUT) {
1340 12 : odbc_errs_add(&stmt->errs, "HY105", NULL);
1341 12 : ODBC_EXIT_(stmt);
1342 : }
1343 :
1344 : /* Only SQL_C_DEFAULT is accepted */
1345 4140 : if (fCType != SQL_C_DEFAULT) {
1346 4 : odbc_errs_add(&stmt->errs, "07006", NULL);
1347 4 : ODBC_EXIT_(stmt);
1348 : }
1349 : fCType = SQL_C_BINARY;
1350 : }
1351 :
1352 15166 : apd = stmt->apd;
1353 15166 : ipd = stmt->ipd;
1354 :
1355 : /* If the parameter focus is set to 0, bind values as arguments */
1356 : /* Otherwise, bind values as the columns of a table-valued parameter */
1357 15166 : if (stmt->attr.param_focus != 0) {
1358 : SQLTVP *tvp;
1359 :
1360 : /* a table type cannot contain a table type */
1361 4148 : if (fSqlType == SQL_SS_TABLE) {
1362 8 : odbc_errs_add(&stmt->errs, "HY004", NULL);
1363 8 : ODBC_EXIT_(stmt);
1364 : }
1365 :
1366 : /* Columns of table types are strictly read-only */
1367 4140 : if (fParamType != SQL_PARAM_INPUT) {
1368 0 : odbc_errs_add(&stmt->errs, "HY105", NULL);
1369 0 : ODBC_EXIT_(stmt);
1370 : }
1371 :
1372 : /* check index */
1373 4140 : if (stmt->attr.param_focus > ipd->header.sql_desc_count) {
1374 0 : odbc_errs_add(&stmt->errs, "IM020", NULL);
1375 0 : ODBC_EXIT_(stmt);
1376 : }
1377 :
1378 4140 : drec = &ipd->records[stmt->attr.param_focus - 1];
1379 :
1380 : /* check ipd type */
1381 4140 : if (drec->sql_desc_concise_type != SQL_SS_TABLE) {
1382 0 : odbc_errs_add(&stmt->errs, "IM020", NULL);
1383 0 : ODBC_EXIT_(stmt);
1384 : }
1385 :
1386 4140 : tvp = (SQLTVP *) drec->sql_desc_data_ptr;
1387 4140 : apd = tvp->apd;
1388 4140 : ipd = tvp->ipd;
1389 : }
1390 :
1391 : /* fill APD related fields */
1392 15158 : orig_apd_size = apd->header.sql_desc_count;
1393 15158 : if (ipar > apd->header.sql_desc_count && desc_alloc_records(apd, ipar) != SQL_SUCCESS) {
1394 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
1395 0 : ODBC_EXIT_(stmt);
1396 : }
1397 15158 : drec = &apd->records[ipar - 1];
1398 :
1399 15158 : if (odbc_set_concise_c_type(fCType, drec, 0) != SQL_SUCCESS) {
1400 70 : desc_alloc_records(apd, orig_apd_size);
1401 70 : odbc_errs_add(&stmt->errs, "HY004", NULL);
1402 70 : ODBC_EXIT_(stmt);
1403 : }
1404 :
1405 15088 : stmt->need_reprepare = 1;
1406 :
1407 : /* TODO other types ?? handle SQL_C_DEFAULT */
1408 15088 : if (drec->sql_desc_type == SQL_C_CHAR || drec->sql_desc_type == SQL_C_WCHAR || drec->sql_desc_type == SQL_C_BINARY)
1409 7478 : drec->sql_desc_octet_length = cbValueMax;
1410 15088 : drec->sql_desc_indicator_ptr = pcbValue;
1411 15088 : drec->sql_desc_octet_length_ptr = pcbValue;
1412 15088 : drec->sql_desc_data_ptr = (char *) rgbValue;
1413 :
1414 15088 : if (fSqlType == SQL_SS_TABLE)
1415 4128 : drec->sql_desc_length = 1;
1416 :
1417 : /* field IPD related fields */
1418 15088 : orig_ipd_size = ipd->header.sql_desc_count;
1419 15088 : if (ipar > ipd->header.sql_desc_count && desc_alloc_records(ipd, ipar) != SQL_SUCCESS) {
1420 0 : desc_alloc_records(apd, orig_apd_size);
1421 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
1422 0 : ODBC_EXIT_(stmt);
1423 : }
1424 15088 : drec = &ipd->records[ipar - 1];
1425 :
1426 15088 : drec->sql_desc_parameter_type = fParamType;
1427 :
1428 15088 : if (odbc_set_concise_sql_type(fSqlType, drec, 0) != SQL_SUCCESS) {
1429 0 : desc_alloc_records(ipd, orig_ipd_size);
1430 0 : desc_alloc_records(apd, orig_apd_size);
1431 0 : odbc_errs_add(&stmt->errs, "HY004", NULL);
1432 0 : ODBC_EXIT_(stmt);
1433 : }
1434 15088 : if (is_numeric) {
1435 220 : drec->sql_desc_precision = (SQLSMALLINT) cbColDef;
1436 220 : drec->sql_desc_scale = ibScale;
1437 : } else {
1438 14868 : drec->sql_desc_length = cbColDef;
1439 : }
1440 :
1441 15088 : if (fSqlType == SQL_SS_TABLE) {
1442 : SQLTVP *tvp;
1443 4128 : int wide TDS_UNUSED = 1;
1444 :
1445 4128 : tvp = tvp_alloc(stmt);
1446 4128 : if (tvp == NULL) {
1447 0 : desc_alloc_records(ipd, orig_ipd_size);
1448 0 : desc_alloc_records(apd, orig_apd_size);
1449 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
1450 0 : ODBC_EXIT_(stmt);
1451 : }
1452 4128 : tvp->apd->header.sql_desc_array_size = cbColDef;
1453 :
1454 4128 : if (!odbc_dstr_copy_oct(stmt->dbc, &tvp->type_name, cbValueMax, (ODBC_CHAR *) rgbValue)) {
1455 0 : free(tvp);
1456 0 : desc_alloc_records(ipd, orig_ipd_size);
1457 0 : desc_alloc_records(apd, orig_apd_size);
1458 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
1459 0 : ODBC_EXIT_(stmt);
1460 : }
1461 :
1462 : /* Use this the column type as a marker for us */
1463 : /* to free up memory allocated with odbc_alloc_table() */
1464 4128 : drec->sql_desc_type = drec->sql_desc_concise_type = SQL_SS_TABLE;
1465 :
1466 4128 : drec->sql_desc_data_ptr = tvp;
1467 :
1468 4128 : drec->sql_desc_length = 0;
1469 : }
1470 :
1471 15088 : stmt->params_set = 1;
1472 15088 : ODBC_EXIT_(stmt);
1473 : }
1474 :
1475 : SQLRETURN ODBC_PUBLIC ODBC_API
1476 : SQLBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType,
1477 : SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
1478 : {
1479 15182 : tdsdump_log(TDS_DBG_FUNC, "SQLBindParameter(%p, %u, %d, %d, %d, %u, %d, %p, %d, %p)\n",
1480 : hstmt, (unsigned)ipar, fParamType, fCType, (int)fSqlType, (unsigned)cbColDef, ibScale,
1481 : rgbValue, (int)cbValueMax, pcbValue);
1482 15182 : return odbc_SQLBindParameter(hstmt, ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, cbValueMax, pcbValue);
1483 : }
1484 :
1485 :
1486 : /* compatibility with X/Open */
1487 : SQLRETURN ODBC_PUBLIC ODBC_API
1488 : SQLBindParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLULEN cbColDef, SQLSMALLINT ibScale,
1489 : SQLPOINTER rgbValue, SQLLEN FAR * pcbValue)
1490 : {
1491 0 : tdsdump_log(TDS_DBG_FUNC, "SQLBindParam(%p, %d, %d, %d, %u, %d, %p, %p)\n",
1492 : hstmt, ipar, fCType, fSqlType, (unsigned)cbColDef, ibScale, rgbValue, pcbValue);
1493 0 : return odbc_SQLBindParameter(hstmt, ipar, SQL_PARAM_INPUT, fCType, fSqlType, cbColDef, ibScale, rgbValue, 0, pcbValue);
1494 : }
1495 :
1496 : #if (ODBCVER >= 0x0300)
1497 : SQLRETURN ODBC_PUBLIC ODBC_API
1498 : SQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE * OutputHandle)
1499 : {
1500 1356 : tdsdump_log(TDS_DBG_FUNC, "SQLAllocHandle(%d, %p, %p)\n", HandleType, InputHandle, OutputHandle);
1501 :
1502 1356 : if (OutputHandle)
1503 1356 : *OutputHandle = SQL_NULL_HANDLE;
1504 :
1505 1356 : switch (HandleType) {
1506 120 : case SQL_HANDLE_STMT:
1507 120 : return odbc_SQLAllocStmt(InputHandle, OutputHandle);
1508 : break;
1509 608 : case SQL_HANDLE_DBC:
1510 608 : return odbc_SQLAllocConnect(InputHandle, OutputHandle);
1511 : break;
1512 608 : case SQL_HANDLE_ENV:
1513 608 : return odbc_SQLAllocEnv(OutputHandle, SQL_OV_ODBC3);
1514 : break;
1515 20 : case SQL_HANDLE_DESC:
1516 20 : return odbc_SQLAllocDesc(InputHandle, OutputHandle);
1517 : break;
1518 : }
1519 :
1520 : /*
1521 : * As the documentation puts it,
1522 : * "There is no handle with which to associate additional diagnostic information."
1523 : *
1524 : * The DM must catch HY092 because the driver has no valid handle at this early stage in which
1525 : * to store the error for later retrieval by the application.
1526 : */
1527 0 : tdsdump_log(TDS_DBG_FUNC, "SQLAllocHandle(): invalid HandleType, error HY092: should be caught by DM\n");
1528 : return SQL_ERROR;
1529 : }
1530 : #endif
1531 :
1532 : static SQLRETURN
1533 1216 : odbc_SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc)
1534 : {
1535 : TDS_DBC *dbc;
1536 :
1537 1216 : ODBC_ENTER_HENV;
1538 :
1539 1216 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLAllocConnect(%p, %p)\n", henv, phdbc);
1540 :
1541 1216 : if (!phdbc) {
1542 0 : odbc_errs_add(&env->errs, "HY009", NULL);
1543 0 : ODBC_EXIT_(env);
1544 : }
1545 :
1546 1216 : dbc = tds_new0(TDS_DBC, 1);
1547 1216 : if (!dbc) {
1548 0 : odbc_errs_add(&env->errs, "HY001", NULL);
1549 0 : ODBC_EXIT_(env);
1550 : }
1551 :
1552 1216 : dbc->htype = SQL_HANDLE_DBC;
1553 1216 : dbc->env = env;
1554 2432 : tds_dstr_init(&dbc->dsn);
1555 :
1556 1216 : dbc->attr.cursor_type = SQL_CURSOR_FORWARD_ONLY;
1557 1216 : dbc->attr.access_mode = SQL_MODE_READ_WRITE;
1558 1216 : dbc->attr.async_enable = SQL_ASYNC_ENABLE_OFF;
1559 1216 : dbc->attr.auto_ipd = SQL_FALSE;
1560 : /*
1561 : * spinellia@acm.org
1562 : * after login is enabled autocommit
1563 : */
1564 1216 : dbc->attr.autocommit = SQL_AUTOCOMMIT_ON;
1565 1216 : dbc->attr.connection_dead = SQL_CD_TRUE; /* No connection yet */
1566 1216 : dbc->attr.connection_timeout = 0;
1567 : /* This is set in the environment change function */
1568 2432 : tds_dstr_init(&dbc->attr.current_catalog);
1569 1216 : dbc->attr.login_timeout = 0; /* TODO */
1570 1216 : dbc->attr.metadata_id = SQL_FALSE;
1571 1216 : dbc->attr.odbc_cursors = SQL_CUR_USE_DRIVER;
1572 1216 : dbc->attr.packet_size = 0;
1573 1216 : dbc->attr.quite_mode = NULL; /* We don't support GUI dialogs yet */
1574 : #ifdef TDS_NO_DM
1575 1216 : dbc->attr.trace = SQL_OPT_TRACE_OFF;
1576 2432 : tds_dstr_init(&dbc->attr.tracefile);
1577 : #endif
1578 2432 : tds_dstr_init(&dbc->attr.translate_lib);
1579 : #ifdef ENABLE_ODBC_WIDE
1580 1216 : dbc->original_charset_num = TDS_CHARSET_UTF_8;
1581 : #endif
1582 2432 : tds_dstr_init(&dbc->oldpwd);
1583 2432 : tds_dstr_init(&dbc->db_filename);
1584 1216 : dbc->attr.translate_option = 0;
1585 1216 : dbc->attr.txn_isolation = SQL_TXN_READ_COMMITTED;
1586 1216 : dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
1587 1216 : dbc->attr.bulk_enabled = SQL_BCP_OFF;
1588 :
1589 : /* Initial values of DBC date formats taken from environment context.
1590 : * odbc_SQLAllocEnv() always initializes that. */
1591 2432 : tds_dstr_init(&dbc->datetime_fmt);
1592 2432 : tds_dstr_init(&dbc->date_fmt);
1593 2432 : tds_dstr_init(&dbc->time_fmt);
1594 :
1595 2432 : if (!tds_dstr_copy(&dbc->datetime_fmt, env->tds_ctx->locale->datetime_fmt) ||
1596 2432 : !tds_dstr_copy(&dbc->date_fmt, env->tds_ctx->locale->date_fmt) ||
1597 1216 : !tds_dstr_copy(&dbc->time_fmt, env->tds_ctx->locale->time_fmt)) {
1598 0 : tds_dstr_free(&dbc->datetime_fmt);
1599 0 : tds_dstr_free(&dbc->date_fmt);
1600 0 : tds_dstr_free(&dbc->time_fmt);
1601 0 : free(dbc);
1602 0 : odbc_errs_add(&env->errs, "HY001", NULL);
1603 0 : ODBC_EXIT_(env);
1604 : }
1605 :
1606 2432 : tds_mutex_init(&dbc->mtx);
1607 1216 : *phdbc = (SQLHDBC) dbc;
1608 :
1609 1216 : ODBC_EXIT_(env);
1610 : }
1611 :
1612 : SQLRETURN ODBC_PUBLIC ODBC_API
1613 : SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc)
1614 : {
1615 608 : tdsdump_log(TDS_DBG_FUNC, "SQLAllocConnect(%p, %p)\n", henv, phdbc);
1616 :
1617 608 : return odbc_SQLAllocConnect(henv, phdbc);
1618 : }
1619 :
1620 : static SQLRETURN
1621 1216 : odbc_SQLAllocEnv(SQLHENV FAR * phenv, SQLINTEGER odbc_version)
1622 : {
1623 : TDS_ENV *env;
1624 : TDSCONTEXT *ctx;
1625 :
1626 1216 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLAllocEnv(%p, %d)\n",
1627 : phenv, (int) odbc_version);
1628 :
1629 1216 : if (!phenv)
1630 : return SQL_ERROR;
1631 :
1632 1216 : env = tds_new0(TDS_ENV, 1);
1633 1216 : if (!env)
1634 : return SQL_ERROR;
1635 :
1636 1216 : env->htype = SQL_HANDLE_ENV;
1637 1216 : env->attr.odbc_version = odbc_version;
1638 : /* TODO use it */
1639 1216 : env->attr.output_nts = SQL_TRUE;
1640 :
1641 1216 : ctx = tds_alloc_context(env);
1642 1216 : if (!ctx) {
1643 0 : free(env);
1644 0 : return SQL_ERROR;
1645 : }
1646 1216 : env->tds_ctx = ctx;
1647 1216 : ctx->msg_handler = odbc_errmsg_handler;
1648 1216 : ctx->err_handler = odbc_errmsg_handler;
1649 :
1650 : /* ODBC driver date-to-char conversion: mimic MS client */
1651 1216 : free(ctx->locale->datetime_fmt);
1652 1216 : ctx->locale->datetime_fmt = strdup("%Y-%m-%d %H:%M:%S.%z");
1653 1216 : free(ctx->locale->date_fmt);
1654 1216 : ctx->locale->date_fmt = strdup("%Y-%m-%d");
1655 1216 : free(ctx->locale->time_fmt);
1656 1216 : ctx->locale->time_fmt = strdup("%H:%M:%S.%z");
1657 :
1658 2432 : tds_mutex_init(&env->mtx);
1659 1216 : *phenv = (SQLHENV) env;
1660 :
1661 1216 : return SQL_SUCCESS;
1662 : }
1663 :
1664 : SQLRETURN ODBC_PUBLIC ODBC_API
1665 : SQLAllocEnv(SQLHENV FAR * phenv)
1666 : {
1667 608 : tdsdump_log(TDS_DBG_FUNC, "SQLAllocEnv(%p)\n", phenv);
1668 :
1669 608 : return odbc_SQLAllocEnv(phenv, SQL_OV_ODBC2);
1670 : }
1671 :
1672 : static SQLRETURN
1673 20 : odbc_SQLAllocDesc(SQLHDBC hdbc, SQLHDESC FAR * phdesc)
1674 : {
1675 : int i;
1676 :
1677 20 : ODBC_ENTER_HDBC;
1678 :
1679 20 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLAllocDesc(%p, %p)\n", hdbc, phdesc);
1680 :
1681 20 : if (!phdesc) {
1682 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
1683 0 : ODBC_EXIT_(dbc);
1684 : }
1685 :
1686 10 : for (i = 0; ; ++i) {
1687 40 : if (i >= TDS_MAX_APP_DESC) {
1688 0 : odbc_errs_add(&dbc->errs, "HY014", NULL);
1689 0 : break;
1690 : }
1691 30 : if (dbc->uad[i] == NULL) {
1692 20 : TDS_DESC *desc = desc_alloc(dbc, DESC_ARD, SQL_DESC_ALLOC_USER);
1693 20 : if (desc == NULL) {
1694 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1695 0 : break;
1696 : }
1697 20 : dbc->uad[i] = desc;
1698 20 : *phdesc = (SQLHDESC) desc;
1699 20 : break;
1700 : }
1701 : }
1702 20 : ODBC_EXIT_(dbc);
1703 : }
1704 :
1705 : static SQLRETURN
1706 17805 : odbc_SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt)
1707 : {
1708 : TDS_STMT *stmt;
1709 : char *pstr;
1710 :
1711 17805 : ODBC_ENTER_HDBC;
1712 :
1713 17805 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLAllocStmt(%p, %p)\n", hdbc, phstmt);
1714 :
1715 17805 : if (!phstmt) {
1716 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
1717 0 : ODBC_EXIT_(dbc);
1718 : }
1719 :
1720 17805 : stmt = tds_new0(TDS_STMT, 1);
1721 17805 : if (!stmt) {
1722 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1723 0 : ODBC_EXIT_(dbc);
1724 : }
1725 35610 : tds_dstr_init(&stmt->cursor_name);
1726 35610 : tds_dstr_init(&stmt->query);
1727 :
1728 17805 : stmt->htype = SQL_HANDLE_STMT;
1729 17805 : stmt->dbc = dbc;
1730 17805 : stmt->num_param_rows = 1;
1731 17805 : pstr = NULL;
1732 : /* TODO test initial cursor ... */
1733 17805 : if (asprintf(&pstr, "SQL_CUR%p", stmt) < 0 || !tds_dstr_set(&stmt->cursor_name, pstr)) {
1734 0 : free(stmt);
1735 0 : free(pstr);
1736 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1737 0 : ODBC_EXIT_(dbc);
1738 : }
1739 : /* do not free pstr tds_dstr_set do it if necessary */
1740 :
1741 : /* allocate descriptors */
1742 17805 : stmt->ird = desc_alloc(stmt, DESC_IRD, SQL_DESC_ALLOC_AUTO);
1743 17805 : stmt->ard = desc_alloc(stmt, DESC_ARD, SQL_DESC_ALLOC_AUTO);
1744 17805 : stmt->ipd = desc_alloc(stmt, DESC_IPD, SQL_DESC_ALLOC_AUTO);
1745 17805 : stmt->apd = desc_alloc(stmt, DESC_APD, SQL_DESC_ALLOC_AUTO);
1746 17805 : if (!stmt->ird || !stmt->ard || !stmt->ipd || !stmt->apd) {
1747 0 : tds_dstr_free(&stmt->cursor_name);
1748 0 : desc_free(stmt->ird);
1749 0 : desc_free(stmt->ard);
1750 0 : desc_free(stmt->ipd);
1751 0 : desc_free(stmt->apd);
1752 0 : free(stmt);
1753 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1754 0 : ODBC_EXIT_(dbc);
1755 : }
1756 :
1757 : /* save original ARD and APD */
1758 17805 : stmt->orig_apd = stmt->apd;
1759 17805 : stmt->orig_ard = stmt->ard;
1760 :
1761 : /* set the default statement attributes */
1762 : /* stmt->attr.app_param_desc = stmt->apd; */
1763 : /* stmt->attr.app_row_desc = stmt->ard; */
1764 17805 : stmt->attr.async_enable = SQL_ASYNC_ENABLE_OFF;
1765 17805 : stmt->attr.concurrency = SQL_CONCUR_READ_ONLY;
1766 17805 : stmt->attr.cursor_scrollable = SQL_NONSCROLLABLE;
1767 17805 : stmt->attr.cursor_sensitivity = SQL_INSENSITIVE;
1768 17805 : stmt->attr.cursor_type = SQL_CURSOR_FORWARD_ONLY;
1769 : /* TODO ?? why two attributes */
1770 17805 : stmt->attr.enable_auto_ipd = dbc->attr.auto_ipd = SQL_FALSE;
1771 17805 : stmt->attr.fetch_bookmark_ptr = NULL;
1772 : /* stmt->attr.imp_param_desc = stmt->ipd; */
1773 : /* stmt->attr.imp_row_desc = stmt->ird; */
1774 17805 : stmt->attr.keyset_size = 0;
1775 17805 : stmt->attr.max_length = 0;
1776 17805 : stmt->attr.max_rows = 0;
1777 17805 : stmt->attr.metadata_id = dbc->attr.metadata_id;
1778 : /* TODO check this flag in prepare_call */
1779 17805 : stmt->attr.noscan = SQL_NOSCAN_OFF;
1780 17805 : assert(stmt->apd->header.sql_desc_bind_offset_ptr == NULL);
1781 17805 : assert(stmt->apd->header.sql_desc_bind_type == SQL_PARAM_BIND_BY_COLUMN);
1782 17805 : assert(stmt->apd->header.sql_desc_array_status_ptr == NULL);
1783 17805 : assert(stmt->ipd->header.sql_desc_array_status_ptr == NULL);
1784 17805 : assert(stmt->ipd->header.sql_desc_rows_processed_ptr == NULL);
1785 17805 : assert(stmt->apd->header.sql_desc_array_size == 1);
1786 17805 : stmt->attr.query_timeout = DEFAULT_QUERY_TIMEOUT;
1787 17805 : stmt->attr.retrieve_data = SQL_RD_ON;
1788 17805 : assert(stmt->ard->header.sql_desc_array_size == 1);
1789 17805 : assert(stmt->ard->header.sql_desc_bind_offset_ptr == NULL);
1790 17805 : assert(stmt->ard->header.sql_desc_bind_type == SQL_BIND_BY_COLUMN);
1791 17805 : stmt->attr.row_number = 0;
1792 17805 : assert(stmt->ard->header.sql_desc_array_status_ptr == NULL);
1793 17805 : assert(stmt->ird->header.sql_desc_array_status_ptr == NULL);
1794 17805 : assert(stmt->ird->header.sql_desc_rows_processed_ptr == NULL);
1795 17805 : stmt->attr.simulate_cursor = SQL_SC_NON_UNIQUE;
1796 17805 : stmt->attr.use_bookmarks = SQL_UB_OFF;
1797 35610 : tds_dstr_init(&stmt->attr.qn_msgtext);
1798 35610 : tds_dstr_init(&stmt->attr.qn_options);
1799 17805 : stmt->attr.qn_timeout = 432000;
1800 :
1801 17805 : stmt->sql_rowset_size = 1;
1802 :
1803 17805 : stmt->row_count = TDS_NO_COUNT;
1804 17805 : stmt->row_status = NOT_IN_ROW;
1805 :
1806 : /* insert into list */
1807 17805 : stmt->next = dbc->stmt_list;
1808 17805 : if (dbc->stmt_list)
1809 349 : dbc->stmt_list->prev = stmt;
1810 17805 : dbc->stmt_list = stmt;
1811 :
1812 35610 : tds_mutex_init(&stmt->mtx);
1813 17805 : *phstmt = (SQLHSTMT) stmt;
1814 :
1815 17805 : if (dbc->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY)
1816 0 : odbc_SQLSetStmtAttr(stmt, SQL_CURSOR_TYPE, (SQLPOINTER) (TDS_INTPTR) dbc->attr.cursor_type, SQL_IS_INTEGER _wide0);
1817 :
1818 17805 : stmt->attr.param_focus = 0;
1819 :
1820 17805 : ODBC_EXIT_(dbc);
1821 : }
1822 :
1823 : SQLRETURN ODBC_PUBLIC ODBC_API
1824 : SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt)
1825 : {
1826 17685 : tdsdump_log(TDS_DBG_FUNC, "SQLAllocStmt(%p, %p)\n", hdbc, phstmt);
1827 :
1828 17685 : return odbc_SQLAllocStmt(hdbc, phstmt);
1829 : }
1830 :
1831 : SQLRETURN ODBC_PUBLIC ODBC_API
1832 : SQLBindCol(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
1833 : {
1834 : TDS_DESC *ard;
1835 : struct _drecord *drec;
1836 : SQLSMALLINT orig_ard_size;
1837 :
1838 6120 : ODBC_ENTER_HSTMT;
1839 :
1840 6120 : tdsdump_log(TDS_DBG_FUNC, "SQLBindCol(%p, %d, %d, %p, %d, %p)\n",
1841 : hstmt, icol, fCType, rgbValue, (int)cbValueMax, pcbValue);
1842 :
1843 : /* TODO - More error checking XXX smurph */
1844 :
1845 : #ifdef TDS_NO_DM
1846 : /* check conversion type */
1847 6120 : switch (fCType) {
1848 3158 : case SQL_C_CHAR:
1849 : case SQL_C_WCHAR:
1850 : case SQL_C_BINARY:
1851 : case SQL_C_DEFAULT:
1852 : /* check max buffer length */
1853 3158 : if (!IS_VALID_LEN(cbValueMax)) {
1854 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
1855 0 : ODBC_EXIT_(stmt);
1856 : }
1857 : break;
1858 : }
1859 : #endif
1860 :
1861 6120 : if (icol <= 0 || icol > 4000) {
1862 0 : odbc_errs_add(&stmt->errs, "07009", NULL);
1863 0 : ODBC_EXIT_(stmt);
1864 : }
1865 :
1866 6120 : ard = stmt->ard;
1867 6120 : orig_ard_size = ard->header.sql_desc_count;
1868 6120 : if (icol > ard->header.sql_desc_count && desc_alloc_records(ard, icol) != SQL_SUCCESS) {
1869 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
1870 0 : ODBC_EXIT_(stmt);
1871 : }
1872 :
1873 6120 : drec = &ard->records[icol - 1];
1874 :
1875 6120 : if (odbc_set_concise_c_type(fCType, drec, 0) != SQL_SUCCESS) {
1876 0 : desc_alloc_records(ard, orig_ard_size);
1877 0 : odbc_errs_add(&stmt->errs, "HY003", NULL);
1878 0 : ODBC_EXIT_(stmt);
1879 : }
1880 6120 : drec->sql_desc_octet_length = cbValueMax;
1881 6120 : drec->sql_desc_octet_length_ptr = pcbValue;
1882 6120 : drec->sql_desc_indicator_ptr = pcbValue;
1883 6120 : drec->sql_desc_data_ptr = rgbValue;
1884 :
1885 : /* force rebind */
1886 6120 : stmt->row = 0;
1887 :
1888 6120 : ODBC_EXIT_(stmt);
1889 : }
1890 :
1891 : SQLRETURN ODBC_PUBLIC ODBC_API
1892 : SQLCancel(SQLHSTMT hstmt)
1893 : {
1894 : TDSSOCKET *tds;
1895 :
1896 : /*
1897 : * FIXME this function can be called from other thread, do not free
1898 : * errors for this function
1899 : * If function is called from another thread errors are not touched
1900 : */
1901 : /* TODO some tests required */
1902 80 : TDS_STMT *stmt = (TDS_STMT*)hstmt;
1903 80 : if (SQL_NULL_HSTMT == hstmt || !IS_HSTMT(hstmt))
1904 : return SQL_INVALID_HANDLE;
1905 :
1906 80 : tdsdump_log(TDS_DBG_FUNC, "SQLCancel(%p)\n", hstmt);
1907 :
1908 80 : tds = stmt->tds;
1909 :
1910 : /* cancelling an inactive statement */
1911 80 : if (!tds)
1912 : /* Just return success */
1913 : /* Note that we don't own locks so don't use ODBC_EXIT here. */
1914 : return SQL_SUCCESS;
1915 :
1916 50 : if (tds_mutex_trylock(&stmt->mtx) == 0) {
1917 10 : CHECK_STMT_EXTRA(stmt);
1918 10 : odbc_errs_reset(&stmt->errs);
1919 :
1920 : /* FIXME test current statement */
1921 : /* FIXME here we are unlocked */
1922 :
1923 10 : if (TDS_FAILED(tds_send_cancel(tds))) {
1924 0 : ODBC_SAFE_ERROR(stmt);
1925 0 : ODBC_EXIT_(stmt);
1926 : }
1927 :
1928 10 : if (TDS_FAILED(tds_process_cancel(tds))) {
1929 0 : ODBC_SAFE_ERROR(stmt);
1930 0 : ODBC_EXIT_(stmt);
1931 : }
1932 :
1933 : /* only if we processed cancel reset statement */
1934 10 : if (tds->state == TDS_IDLE)
1935 10 : odbc_unlock_statement(stmt);
1936 :
1937 10 : ODBC_EXIT_(stmt);
1938 : }
1939 :
1940 : /* don't access error here, just return error */
1941 40 : if (TDS_FAILED(tds_send_cancel(tds)))
1942 : return SQL_ERROR;
1943 40 : return SQL_SUCCESS;
1944 : }
1945 :
1946 1028 : ODBC_FUNC(SQLConnect, (P(SQLHDBC,hdbc), PCHARIN(DSN,SQLSMALLINT), PCHARIN(UID,SQLSMALLINT),
1947 : PCHARIN(AuthStr,SQLSMALLINT) WIDE))
1948 : {
1949 : TDSLOGIN *login;
1950 : DSTR *s;
1951 :
1952 1028 : ODBC_ENTER_HDBC;
1953 :
1954 : #ifdef TDS_NO_DM
1955 1028 : if (szDSN && !IS_VALID_LEN(cbDSN)) {
1956 0 : odbc_errs_add(&dbc->errs, "HY090", "Invalid DSN buffer length");
1957 0 : ODBC_EXIT_(dbc);
1958 : }
1959 :
1960 1028 : if (szUID && !IS_VALID_LEN(cbUID)) {
1961 0 : odbc_errs_add(&dbc->errs, "HY090", "Invalid UID buffer length");
1962 0 : ODBC_EXIT_(dbc);
1963 : }
1964 :
1965 1028 : if (szAuthStr && !IS_VALID_LEN(cbAuthStr)) {
1966 0 : odbc_errs_add(&dbc->errs, "HY090", "Invalid PWD buffer length");
1967 0 : ODBC_EXIT_(dbc);
1968 : }
1969 : #endif
1970 :
1971 1028 : login = tds_alloc_login(false);
1972 1028 : if (!login || !tds_init_login(login, dbc->env->tds_ctx->locale))
1973 : goto memory_error;
1974 :
1975 : /* data source name */
1976 1028 : if (odbc_get_string_size(cbDSN, szDSN _wide))
1977 1028 : s = odbc_dstr_copy(dbc, &dbc->dsn, cbDSN, szDSN);
1978 : else
1979 0 : s = tds_dstr_copy(&dbc->dsn, "DEFAULT");
1980 1028 : if (!s)
1981 : goto memory_error;
1982 :
1983 :
1984 2056 : if (!odbc_get_dsn_info(&dbc->errs, tds_dstr_cstr(&dbc->dsn), login)) {
1985 0 : tds_free_login(login);
1986 0 : ODBC_EXIT_(dbc);
1987 : }
1988 :
1989 2056 : if (!tds_dstr_isempty(&dbc->attr.current_catalog))
1990 20 : if (!tds_dstr_dup(&login->database, &dbc->attr.current_catalog))
1991 : goto memory_error;
1992 :
1993 : /*
1994 : * username/password are never saved to ini file,
1995 : * so you do not check in ini file
1996 : */
1997 : /* user id */
1998 1028 : if (odbc_get_string_size(cbUID, szUID _wide)) {
1999 1028 : if (!odbc_dstr_copy(dbc, &login->user_name, cbUID, szUID))
2000 : goto memory_error;
2001 : }
2002 :
2003 : /* password */
2004 2056 : if (szAuthStr && !tds_dstr_isempty(&login->user_name)) {
2005 1028 : if (!odbc_dstr_copy(dbc, &login->password, cbAuthStr, szAuthStr))
2006 : goto memory_error;
2007 : }
2008 :
2009 : /* DO IT */
2010 1028 : odbc_connect(dbc, login);
2011 :
2012 1028 : tds_free_login(login);
2013 1028 : ODBC_EXIT_(dbc);
2014 :
2015 0 : memory_error:
2016 0 : tds_free_login(login);
2017 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
2018 0 : ODBC_EXIT_(dbc);
2019 : }
2020 :
2021 2354 : ODBC_FUNC(SQLDescribeCol, (P(SQLHSTMT,hstmt), P(SQLUSMALLINT,icol), PCHAROUT(ColName,SQLSMALLINT),
2022 : P(SQLSMALLINT FAR *,pfSqlType), P(SQLULEN FAR *,pcbColDef),
2023 : P(SQLSMALLINT FAR *,pibScale), P(SQLSMALLINT FAR *,pfNullable) WIDE))
2024 : {
2025 : TDS_DESC *ird;
2026 : struct _drecord *drec;
2027 : SQLRETURN result;
2028 :
2029 2354 : ODBC_ENTER_HSTMT;
2030 :
2031 2354 : ird = stmt->ird;
2032 2354 : IRD_UPDATE(ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
2033 :
2034 2354 : if (icol <= 0 || icol > ird->header.sql_desc_count) {
2035 0 : odbc_errs_add(&stmt->errs, "07009", "Column out of range");
2036 0 : ODBC_EXIT_(stmt);
2037 : }
2038 : /* check name length */
2039 2354 : if (cbColNameMax < 0) {
2040 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
2041 0 : ODBC_EXIT_(stmt);
2042 : }
2043 2354 : drec = &ird->records[icol - 1];
2044 :
2045 : /* cbColNameMax can be 0 (to retrieve name length) */
2046 2354 : if (szColName == NULL)
2047 1052 : cbColNameMax = 0;
2048 :
2049 : /* straight copy column name up to cbColNameMax */
2050 7062 : result = odbc_set_dstr(stmt->dbc, szColName, cbColNameMax, pcbColName, &drec->sql_desc_label);
2051 2354 : if (szColName && result == SQL_SUCCESS_WITH_INFO)
2052 30 : odbc_errs_add(&stmt->errs, "01004", NULL);
2053 :
2054 2354 : if (pfSqlType) {
2055 : /* TODO sure ? check documentation for date and intervals */
2056 2354 : *pfSqlType = drec->sql_desc_concise_type;
2057 : }
2058 :
2059 2354 : if (pcbColDef) {
2060 1226 : if (drec->sql_desc_type == SQL_NUMERIC || drec->sql_desc_type == SQL_DECIMAL) {
2061 180 : *pcbColDef = drec->sql_desc_precision;
2062 : } else {
2063 1046 : *pcbColDef = drec->sql_desc_length;
2064 : }
2065 : }
2066 2354 : if (pibScale) {
2067 1226 : *pibScale = drec->sql_desc_scale;
2068 : }
2069 2354 : if (pfNullable) {
2070 1226 : *pfNullable = drec->sql_desc_nullable;
2071 : }
2072 2354 : ODBC_EXIT_(stmt);
2073 : }
2074 :
2075 : static SQLRETURN
2076 6572 : odbc_SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax,
2077 : SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc _WIDE)
2078 : {
2079 : TDS_DESC *ird;
2080 : struct _drecord *drec;
2081 6572 : SQLRETURN result = SQL_SUCCESS;
2082 :
2083 6572 : ODBC_ENTER_HSTMT;
2084 :
2085 6572 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLColAttribute(%p, %u, %u, %p, %d, %p, %p)\n",
2086 : hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2087 :
2088 6572 : ird = stmt->ird;
2089 :
2090 : #define COUT(src) result = odbc_set_string_oct(stmt->dbc, rgbDesc, cbDescMax, pcbDesc, src ? src : "", -1);
2091 : #define SOUT(src) result = odbc_set_dstr_oct(stmt->dbc, rgbDesc, cbDescMax, pcbDesc, &src);
2092 :
2093 : /* SQLColAttribute returns always attributes using SQLINTEGER */
2094 : #if ENABLE_EXTRA_CHECKS
2095 : #define IOUT(type, src) do { \
2096 : /* trick warning if type wrong */ \
2097 : type *p_test = &src; p_test = p_test; \
2098 : *pfDesc = src; } while(0)
2099 : #else
2100 : #define IOUT(type, src) *pfDesc = src
2101 : #endif
2102 :
2103 6572 : IRD_UPDATE(ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
2104 :
2105 : /* dont check column index for these */
2106 6572 : switch (fDescType) {
2107 : #if SQL_COLUMN_COUNT != SQL_DESC_COUNT
2108 0 : case SQL_COLUMN_COUNT:
2109 : #endif
2110 : case SQL_DESC_COUNT:
2111 0 : IOUT(SQLSMALLINT, ird->header.sql_desc_count);
2112 0 : ODBC_EXIT(stmt, SQL_SUCCESS);
2113 : break;
2114 : }
2115 :
2116 6572 : if (!ird->header.sql_desc_count) {
2117 0 : odbc_errs_add(&stmt->errs, "07005", NULL);
2118 0 : ODBC_EXIT_(stmt);
2119 : }
2120 :
2121 6572 : if (icol <= 0 || icol > ird->header.sql_desc_count) {
2122 0 : odbc_errs_add(&stmt->errs, "07009", "Column out of range");
2123 0 : ODBC_EXIT_(stmt);
2124 : }
2125 6572 : drec = &ird->records[icol - 1];
2126 :
2127 6572 : tdsdump_log(TDS_DBG_INFO1, "SQLColAttribute: fDescType is %d\n", fDescType);
2128 :
2129 6572 : switch (fDescType) {
2130 0 : case SQL_DESC_AUTO_UNIQUE_VALUE:
2131 0 : IOUT(SQLUINTEGER, drec->sql_desc_auto_unique_value);
2132 : break;
2133 0 : case SQL_DESC_BASE_COLUMN_NAME:
2134 0 : SOUT(drec->sql_desc_base_column_name);
2135 0 : break;
2136 0 : case SQL_DESC_BASE_TABLE_NAME:
2137 0 : SOUT(drec->sql_desc_base_table_name);
2138 0 : break;
2139 0 : case SQL_DESC_CASE_SENSITIVE:
2140 0 : IOUT(SQLINTEGER, drec->sql_desc_case_sensitive);
2141 : break;
2142 0 : case SQL_DESC_CATALOG_NAME:
2143 0 : SOUT(drec->sql_desc_catalog_name);
2144 0 : break;
2145 : #if SQL_COLUMN_TYPE != SQL_DESC_CONCISE_TYPE
2146 : case SQL_COLUMN_TYPE:
2147 : #endif
2148 152 : case SQL_DESC_CONCISE_TYPE:
2149 : /* special case, get ODBC 2 type, not ODBC 3 SQL_DESC_CONCISE_TYPE (different for datetime) */
2150 152 : if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
2151 112 : IOUT(SQLSMALLINT, drec->sql_desc_concise_type);
2152 : break;
2153 : }
2154 :
2155 : /* get type and convert it to ODBC 2 type */
2156 : {
2157 40 : SQLSMALLINT type = drec->sql_desc_concise_type;
2158 :
2159 40 : switch (type) {
2160 0 : case SQL_TYPE_DATE:
2161 0 : type = SQL_DATE;
2162 0 : break;
2163 0 : case SQL_TYPE_TIME:
2164 0 : type = SQL_TIME;
2165 0 : break;
2166 20 : case SQL_TYPE_TIMESTAMP:
2167 20 : type = SQL_TIMESTAMP;
2168 20 : break;
2169 : }
2170 40 : IOUT(SQLSMALLINT, type);
2171 : }
2172 : break;
2173 516 : case SQL_DESC_DISPLAY_SIZE:
2174 516 : IOUT(SQLLEN, drec->sql_desc_display_size);
2175 : break;
2176 0 : case SQL_DESC_FIXED_PREC_SCALE:
2177 0 : IOUT(SQLSMALLINT, drec->sql_desc_fixed_prec_scale);
2178 : break;
2179 1068 : case SQL_DESC_LABEL:
2180 3204 : SOUT(drec->sql_desc_label);
2181 1068 : break;
2182 : /* FIXME special cases for SQL_COLUMN_LENGTH */
2183 460 : case SQL_COLUMN_LENGTH:
2184 460 : IOUT(SQLLEN, drec->sql_desc_octet_length);
2185 : break;
2186 516 : case SQL_DESC_LENGTH:
2187 516 : IOUT(SQLULEN, drec->sql_desc_length);
2188 : break;
2189 0 : case SQL_DESC_LITERAL_PREFIX:
2190 0 : COUT(drec->sql_desc_literal_prefix);
2191 0 : break;
2192 0 : case SQL_DESC_LITERAL_SUFFIX:
2193 0 : COUT(drec->sql_desc_literal_suffix);
2194 0 : break;
2195 0 : case SQL_DESC_LOCAL_TYPE_NAME:
2196 0 : SOUT(drec->sql_desc_local_type_name);
2197 0 : break;
2198 : #if SQL_COLUMN_NAME != SQL_DESC_NAME
2199 1068 : case SQL_COLUMN_NAME:
2200 : #endif
2201 : case SQL_DESC_NAME:
2202 3204 : SOUT(drec->sql_desc_name);
2203 1068 : break;
2204 : #if SQL_COLUMN_NULLABLE != SQL_DESC_NULLABLE
2205 0 : case SQL_COLUMN_NULLABLE:
2206 : #endif
2207 : case SQL_DESC_NULLABLE:
2208 0 : IOUT(SQLSMALLINT, drec->sql_desc_nullable);
2209 : break;
2210 0 : case SQL_DESC_NUM_PREC_RADIX:
2211 0 : IOUT(SQLINTEGER, drec->sql_desc_num_prec_radix);
2212 : break;
2213 516 : case SQL_DESC_OCTET_LENGTH:
2214 516 : IOUT(SQLLEN, drec->sql_desc_octet_length);
2215 : break;
2216 : /* FIXME special cases for SQL_COLUMN_PRECISION */
2217 460 : case SQL_COLUMN_PRECISION:
2218 460 : if (drec->sql_desc_concise_type == SQL_REAL) {
2219 20 : *pfDesc = 7;
2220 : break;
2221 : }
2222 440 : if (drec->sql_desc_concise_type == SQL_DOUBLE) {
2223 20 : *pfDesc = 15;
2224 : break;
2225 : }
2226 420 : if (drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP || drec->sql_desc_concise_type == SQL_TIMESTAMP) {
2227 40 : *pfDesc = drec->sql_desc_precision ? 23 : 16;
2228 : break;
2229 : }
2230 : case SQL_DESC_PRECISION: /* this section may be wrong */
2231 1792 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2232 896 : || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP
2233 684 : || drec->sql_desc_concise_type == SQL_TYPE_DATE
2234 678 : || drec->sql_desc_concise_type == SQL_TYPE_TIME
2235 678 : || drec->sql_desc_concise_type == SQL_TIMESTAMP
2236 678 : || drec->sql_desc_concise_type == SQL_SS_TIME2
2237 668 : || drec->sql_desc_concise_type == SQL_SS_TIMESTAMPOFFSET)
2238 236 : IOUT(SQLSMALLINT, drec->sql_desc_precision);
2239 : else
2240 660 : *pfDesc = drec->sql_desc_length;
2241 : break;
2242 : /* FIXME special cases for SQL_COLUMN_SCALE */
2243 980 : case SQL_COLUMN_SCALE:
2244 : case SQL_DESC_SCALE: /* this section may be wrong */
2245 1960 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2246 980 : || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP
2247 728 : || drec->sql_desc_concise_type == SQL_TYPE_DATE
2248 720 : || drec->sql_desc_concise_type == SQL_TYPE_TIME
2249 720 : || drec->sql_desc_concise_type == SQL_TIMESTAMP
2250 720 : || drec->sql_desc_concise_type == SQL_FLOAT
2251 720 : || drec->sql_desc_concise_type == SQL_SS_TIME2
2252 708 : || drec->sql_desc_concise_type == SQL_SS_TIMESTAMPOFFSET)
2253 280 : IOUT(SQLSMALLINT, drec->sql_desc_scale);
2254 : else
2255 700 : *pfDesc = 0;
2256 : break;
2257 0 : case SQL_DESC_SCHEMA_NAME:
2258 0 : SOUT(drec->sql_desc_schema_name);
2259 0 : break;
2260 0 : case SQL_DESC_SEARCHABLE:
2261 0 : IOUT(SQLSMALLINT, drec->sql_desc_searchable);
2262 : break;
2263 0 : case SQL_DESC_TABLE_NAME:
2264 0 : SOUT(drec->sql_desc_table_name);
2265 0 : break;
2266 60 : case SQL_DESC_TYPE:
2267 60 : IOUT(SQLSMALLINT, drec->sql_desc_type);
2268 : break;
2269 144 : case SQL_DESC_TYPE_NAME:
2270 144 : COUT(drec->sql_desc_type_name);
2271 144 : break;
2272 0 : case SQL_DESC_UNNAMED:
2273 0 : IOUT(SQLSMALLINT, drec->sql_desc_unnamed);
2274 : break;
2275 116 : case SQL_DESC_UNSIGNED:
2276 116 : IOUT(SQLSMALLINT, drec->sql_desc_unsigned);
2277 : break;
2278 0 : case SQL_DESC_UPDATABLE:
2279 0 : IOUT(SQLSMALLINT, drec->sql_desc_updatable);
2280 : break;
2281 0 : default:
2282 0 : tdsdump_log(TDS_DBG_INFO2, "SQLColAttribute: fDescType %d not catered for...\n", fDescType);
2283 0 : odbc_errs_add(&stmt->errs, "HY091", NULL);
2284 0 : ODBC_EXIT_(stmt);
2285 : break;
2286 : }
2287 :
2288 2280 : if (result == SQL_SUCCESS_WITH_INFO)
2289 0 : odbc_errs_add(&stmt->errs, "01004", NULL);
2290 :
2291 6572 : ODBC_EXIT(stmt, result);
2292 :
2293 : #undef COUT
2294 : #undef SOUT
2295 : #undef IOUT
2296 : }
2297 :
2298 : SQLRETURN ODBC_PUBLIC ODBC_API
2299 : SQLColAttributes(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType,
2300 : SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc)
2301 : {
2302 0 : tdsdump_log(TDS_DBG_FUNC, "SQLColAttributes(%p, %d, %d, %p, %d, %p, %p)\n",
2303 : hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2304 :
2305 0 : return odbc_SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc _wide0);
2306 : }
2307 :
2308 : #if (ODBCVER >= 0x0300)
2309 : SQLRETURN ODBC_PUBLIC ODBC_API
2310 : SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType,
2311 : SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc,
2312 : #ifdef TDS_SQLCOLATTRIBUTE_SQLLEN
2313 : SQLLEN FAR * pfDesc
2314 : #else
2315 : SQLPOINTER pfDesc
2316 : #endif
2317 : )
2318 : {
2319 :
2320 3286 : return odbc_SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, (SQLLEN*) pfDesc _wide0);
2321 : }
2322 :
2323 : #ifdef ENABLE_ODBC_WIDE
2324 : SQLRETURN ODBC_PUBLIC ODBC_API
2325 : SQLColAttributeW(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType,
2326 : SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc,
2327 : #ifdef TDS_SQLCOLATTRIBUTE_SQLLEN
2328 : SQLLEN FAR * pfDesc
2329 : #else
2330 : SQLPOINTER pfDesc
2331 : #endif
2332 : )
2333 : {
2334 3286 : tdsdump_log(TDS_DBG_FUNC, "SQLColAttributeW(%p, %u, %u, %p, %d, %p, %p)\n",
2335 : hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2336 :
2337 3286 : return odbc_SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc, 1);
2338 : }
2339 : #endif
2340 : #endif
2341 :
2342 : SQLRETURN ODBC_PUBLIC ODBC_API
2343 : SQLDisconnect(SQLHDBC hdbc)
2344 : {
2345 : int i;
2346 :
2347 1216 : ODBC_ENTER_HDBC;
2348 :
2349 1216 : tdsdump_log(TDS_DBG_FUNC, "SQLDisconnect(%p)\n", hdbc);
2350 :
2351 : /* free all associated statements */
2352 1252 : while (dbc->stmt_list) {
2353 36 : tds_mutex_unlock(&dbc->mtx);
2354 36 : odbc_SQLFreeStmt(dbc->stmt_list, SQL_DROP, 1);
2355 36 : tds_mutex_lock(&dbc->mtx);
2356 : }
2357 :
2358 : /* free all associated descriptors */
2359 121600 : for (i = 0; i < TDS_MAX_APP_DESC; ++i) {
2360 121600 : if (dbc->uad[i]) {
2361 10 : desc_free(dbc->uad[i]);
2362 10 : dbc->uad[i] = NULL;
2363 : }
2364 : }
2365 :
2366 : #ifdef ENABLE_ODBC_WIDE
2367 1216 : dbc->mb_conv = NULL;
2368 : #endif
2369 1216 : tds_close_socket(dbc->tds_socket);
2370 1216 : tds_free_socket(dbc->tds_socket);
2371 1216 : dbc->tds_socket = NULL;
2372 1216 : dbc->cursor_support = 0;
2373 :
2374 1216 : ODBC_EXIT_(dbc);
2375 : }
2376 :
2377 : static int
2378 6299 : odbc_errmsg_handler(const TDSCONTEXT * ctx, TDSSOCKET * tds, TDSMESSAGE * msg)
2379 : {
2380 6299 : struct _sql_errors *errs = NULL;
2381 6299 : TDS_DBC *dbc = NULL;
2382 6299 : TDS_STMT *stmt = NULL;
2383 :
2384 6299 : tdsdump_log(TDS_DBG_INFO1, "msgno %d %d\n", (int) msg->msgno, TDSETIME);
2385 :
2386 6299 : if (msg->msgno == TDSETIME) {
2387 :
2388 206 : tdsdump_log(TDS_DBG_INFO1, "in timeout\n");
2389 206 : if (!tds)
2390 : return TDS_INT_CANCEL;
2391 :
2392 196 : if ((stmt = odbc_get_stmt(tds)) != NULL) {
2393 : /* first time, try to send a cancel */
2394 196 : if (!tds->in_cancel) {
2395 176 : odbc_errs_add(&stmt->errs, "HYT00", "Timeout expired");
2396 176 : tdsdump_log(TDS_DBG_INFO1, "returning from timeout\n");
2397 : return TDS_INT_TIMEOUT;
2398 : }
2399 10 : } else if ((dbc = odbc_get_dbc(tds)) != NULL) {
2400 10 : odbc_errs_add(&dbc->errs, "HYT00", "Timeout expired");
2401 : }
2402 :
2403 30 : tds_close_socket(tds);
2404 30 : tdsdump_log(TDS_DBG_INFO1, "returning cancel from timeout\n");
2405 : return TDS_INT_CANCEL;
2406 : }
2407 :
2408 6093 : if (tds && (dbc = odbc_get_dbc(tds)) != NULL) {
2409 6093 : errs = &dbc->errs;
2410 3474 : stmt = odbc_get_stmt(tds);
2411 : if (stmt)
2412 3474 : errs = &stmt->errs;
2413 0 : } else if (ctx->parent) {
2414 0 : errs = &((TDS_ENV *) ctx->parent)->errs;
2415 : }
2416 6093 : if (errs) {
2417 6093 : int severity = msg->severity;
2418 6093 : const char * state = msg->sql_state;
2419 :
2420 : /* fix severity for Sybase */
2421 6093 : if (severity <= 10 && dbc && !TDS_IS_MSSQL(dbc->tds_socket) && msg->sql_state && msg->sql_state[0]
2422 15 : && strncmp(msg->sql_state, "00", 2) != 0) {
2423 15 : if (strncmp(msg->sql_state, "01", 2) != 0 && strncmp(msg->sql_state, "IM", 2) != 0)
2424 11 : severity = 11;
2425 : }
2426 :
2427 : /* compute state if not available */
2428 6093 : if (!state)
2429 4186 : state = severity <= 10 ? "01000" : "42000";
2430 : /* add error, do not overwrite connection timeout error */
2431 6093 : if (msg->msgno != TDSEFCON || errs->lastrc != SQL_ERROR || errs->num_errors < 1)
2432 15636 : odbc_errs_add_rdbms(errs, msg->msgno, state, msg->message, msg->line_number, msg->severity,
2433 9555 : msg->server, stmt ? stmt->curr_param_row + 1 : 0);
2434 :
2435 : /* set lastrc according */
2436 6093 : if (severity <= 10) {
2437 4787 : if (errs->lastrc == SQL_SUCCESS)
2438 2622 : errs->lastrc = SQL_SUCCESS_WITH_INFO;
2439 : } else {
2440 1306 : errs->lastrc = SQL_ERROR;
2441 : }
2442 : }
2443 : return TDS_INT_CANCEL;
2444 : }
2445 :
2446 : /* TODO optimize, change only if some data change (set same value should not set this flag) */
2447 : #define DESC_SET_NEED_REPREPARE \
2448 : do {\
2449 : if (desc->type == DESC_IPD) {\
2450 : assert(IS_HSTMT(desc->parent));\
2451 : ((TDS_STMT *) desc->parent)->need_reprepare = 1;\
2452 : }\
2453 : } while(0)
2454 :
2455 : SQLRETURN ODBC_PUBLIC ODBC_API
2456 : SQLSetDescRec(SQLHDESC hdesc, SQLSMALLINT nRecordNumber, SQLSMALLINT nType, SQLSMALLINT nSubType, SQLLEN nLength,
2457 : SQLSMALLINT nPrecision, SQLSMALLINT nScale, SQLPOINTER pData, SQLLEN FAR * pnStringLength, SQLLEN FAR * pnIndicator)
2458 : {
2459 : struct _drecord *drec;
2460 : SQLSMALLINT concise_type;
2461 :
2462 0 : ODBC_ENTER_HDESC;
2463 :
2464 0 : tdsdump_log(TDS_DBG_FUNC, "SQLSetDescRec(%p, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n",
2465 : hdesc, nRecordNumber, nType, nSubType, (int)nLength, nPrecision, nScale,
2466 : pData, pnStringLength, pnIndicator);
2467 :
2468 0 : if (desc->type == DESC_IRD) {
2469 0 : odbc_errs_add(&desc->errs, "HY016", NULL);
2470 0 : ODBC_EXIT_(desc);
2471 : }
2472 :
2473 0 : if (nRecordNumber > desc->header.sql_desc_count || nRecordNumber <= 0) {
2474 0 : odbc_errs_add(&desc->errs, "07009", NULL);
2475 0 : ODBC_EXIT_(desc);
2476 : }
2477 :
2478 0 : drec = &desc->records[nRecordNumber - 1];
2479 :
2480 : /* check for valid types and return "HY021" if not */
2481 0 : if (desc->type == DESC_IPD) {
2482 0 : DESC_SET_NEED_REPREPARE;
2483 0 : concise_type = odbc_get_concise_sql_type(nType, nSubType);
2484 : } else {
2485 0 : concise_type = odbc_get_concise_c_type(nType, nSubType);
2486 : }
2487 0 : if (nType == SQL_INTERVAL || nType == SQL_DATETIME) {
2488 0 : if (!concise_type) {
2489 0 : odbc_errs_add(&desc->errs, "HY021", NULL);
2490 0 : ODBC_EXIT_(desc);
2491 : }
2492 : } else {
2493 0 : if (concise_type != nType) {
2494 0 : odbc_errs_add(&desc->errs, "HY021", NULL);
2495 0 : ODBC_EXIT_(desc);
2496 : }
2497 : nSubType = 0;
2498 : }
2499 0 : drec->sql_desc_concise_type = concise_type;
2500 0 : drec->sql_desc_type = nType;
2501 0 : drec->sql_desc_datetime_interval_code = nSubType;
2502 :
2503 0 : drec->sql_desc_octet_length = nLength;
2504 0 : drec->sql_desc_precision = nPrecision;
2505 0 : drec->sql_desc_scale = nScale;
2506 0 : drec->sql_desc_data_ptr = pData;
2507 0 : drec->sql_desc_octet_length_ptr = pnStringLength;
2508 0 : drec->sql_desc_indicator_ptr = pnIndicator;
2509 :
2510 0 : ODBC_EXIT_(desc);
2511 : }
2512 :
2513 30 : ODBC_FUNC(SQLGetDescRec, (P(SQLHDESC,hdesc), P(SQLSMALLINT,RecordNumber), PCHAROUT(Name,SQLSMALLINT),
2514 : P(SQLSMALLINT *,Type), P(SQLSMALLINT *,SubType), P(SQLLEN FAR *,Length),
2515 : P(SQLSMALLINT *,Precision), P(SQLSMALLINT *,Scale), P(SQLSMALLINT *,Nullable) WIDE))
2516 : {
2517 30 : struct _drecord *drec = NULL;
2518 30 : SQLRETURN rc = SQL_SUCCESS;
2519 :
2520 30 : ODBC_ENTER_HDESC;
2521 :
2522 30 : if (RecordNumber <= 0) {
2523 10 : odbc_errs_add(&desc->errs, "07009", NULL);
2524 10 : ODBC_EXIT_(desc);
2525 : }
2526 :
2527 20 : IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2528 20 : if (RecordNumber > desc->header.sql_desc_count)
2529 10 : ODBC_EXIT(desc, SQL_NO_DATA);
2530 :
2531 : if (desc->type == DESC_IRD && !desc->header.sql_desc_count) {
2532 : odbc_errs_add(&desc->errs, "HY007", NULL);
2533 : ODBC_EXIT_(desc);
2534 : }
2535 :
2536 10 : drec = &desc->records[RecordNumber - 1];
2537 :
2538 30 : if ((rc = odbc_set_dstr(desc_get_dbc(desc), szName, cbNameMax, pcbName, &drec->sql_desc_name)) != SQL_SUCCESS)
2539 0 : odbc_errs_add(&desc->errs, "01004", NULL);
2540 :
2541 10 : if (Type)
2542 0 : *Type = drec->sql_desc_type;
2543 10 : if (Length)
2544 0 : *Length = drec->sql_desc_octet_length;
2545 10 : if (Precision)
2546 0 : *Precision = drec->sql_desc_precision;
2547 10 : if (Scale)
2548 0 : *Scale = drec->sql_desc_scale;
2549 10 : if (SubType)
2550 0 : *SubType = drec->sql_desc_datetime_interval_code;
2551 10 : if (Nullable)
2552 0 : *Nullable = drec->sql_desc_nullable;
2553 :
2554 10 : ODBC_EXIT(desc, rc);
2555 : }
2556 :
2557 : static TDS_DESC*
2558 2852 : desc_get_focused(TDS_DESC *desc)
2559 : {
2560 : struct _drecord *drec;
2561 2852 : int focus = desc->focus;
2562 2852 : bool was_apd = false;
2563 :
2564 2852 : if (focus <= 0)
2565 : return desc;
2566 20 : if (desc->type != DESC_IPD && IS_HSTMT(desc->parent)) {
2567 12 : desc = ((TDS_STMT *) desc->parent)->ipd;
2568 12 : was_apd = true;
2569 : }
2570 20 : if (desc->type == DESC_IPD) {
2571 20 : if (focus > desc->header.sql_desc_count)
2572 : return desc;
2573 :
2574 20 : drec = &desc->records[focus - 1];
2575 20 : if (drec->sql_desc_concise_type != SQL_SS_TABLE)
2576 : return desc;
2577 20 : if (was_apd)
2578 12 : return ((SQLTVP *) drec->sql_desc_data_ptr)->apd;
2579 8 : return ((SQLTVP *) drec->sql_desc_data_ptr)->ipd;
2580 : }
2581 : return desc;
2582 : }
2583 :
2584 2142 : ODBC_FUNC(SQLGetDescField, (P(SQLHDESC,hdesc), P(SQLSMALLINT,icol), P(SQLSMALLINT,fDescType), P(SQLPOINTER,Value),
2585 : P(SQLINTEGER,BufferLength), P(SQLINTEGER *,StringLength) WIDE))
2586 : {
2587 : struct _drecord *drec;
2588 2142 : SQLRETURN result = SQL_SUCCESS;
2589 : SQLINTEGER dummy_size;
2590 : TDS_DESC *fdesc;
2591 :
2592 2142 : ODBC_ENTER_HDESC;
2593 :
2594 : #define COUT(src) result = odbc_set_string_oct(desc_get_dbc(desc), Value, BufferLength, StringLength, src, -1);
2595 : #define SOUT(src) result = odbc_set_dstr_oct(desc_get_dbc(desc), Value, BufferLength, StringLength, &src);
2596 :
2597 : #if ENABLE_EXTRA_CHECKS
2598 : #define IOUT(type, src) do { \
2599 : /* trick warning if type wrong */ \
2600 : type *p_test = &src; p_test = p_test; \
2601 : *((type *)Value) = src; \
2602 : *StringLength = sizeof(type); } while(0)
2603 : #else
2604 : #define IOUT(type, src) do { \
2605 : *((type *)Value) = src; \
2606 : *StringLength = sizeof(type); } while(0)
2607 : #endif
2608 :
2609 2142 : if (!StringLength)
2610 0 : StringLength = &dummy_size;
2611 :
2612 2142 : fdesc = desc_get_focused(desc);
2613 :
2614 : /* dont check column index for these */
2615 2142 : switch (fDescType) {
2616 40 : case SQL_DESC_ALLOC_TYPE:
2617 40 : IOUT(SQLSMALLINT, fdesc->header.sql_desc_alloc_type);
2618 40 : ODBC_EXIT_(desc);
2619 : break;
2620 8 : case SQL_DESC_ARRAY_SIZE:
2621 8 : IOUT(SQLULEN, fdesc->header.sql_desc_array_size);
2622 8 : ODBC_EXIT_(desc);
2623 : break;
2624 0 : case SQL_DESC_ARRAY_STATUS_PTR:
2625 0 : IOUT(SQLUSMALLINT *, fdesc->header.sql_desc_array_status_ptr);
2626 0 : ODBC_EXIT_(desc);
2627 : break;
2628 0 : case SQL_DESC_BIND_OFFSET_PTR:
2629 0 : IOUT(const SQLLEN *, fdesc->header.sql_desc_bind_offset_ptr);
2630 0 : ODBC_EXIT_(desc);
2631 : break;
2632 0 : case SQL_DESC_BIND_TYPE:
2633 0 : IOUT(SQLINTEGER, fdesc->header.sql_desc_bind_type);
2634 0 : ODBC_EXIT_(desc);
2635 : break;
2636 118 : case SQL_DESC_COUNT:
2637 118 : IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2638 118 : IOUT(SQLSMALLINT, fdesc->header.sql_desc_count);
2639 118 : ODBC_EXIT_(desc);
2640 : break;
2641 110 : case SQL_DESC_ROWS_PROCESSED_PTR:
2642 110 : IOUT(SQLULEN *, fdesc->header.sql_desc_rows_processed_ptr);
2643 110 : ODBC_EXIT_(desc);
2644 : break;
2645 : }
2646 :
2647 1866 : IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2648 1866 : if (!fdesc->header.sql_desc_count) {
2649 0 : odbc_errs_add(&desc->errs, "07005", NULL);
2650 0 : ODBC_EXIT_(desc);
2651 : }
2652 :
2653 1866 : if (icol < 1) {
2654 0 : odbc_errs_add(&desc->errs, "07009", "Column out of range");
2655 0 : ODBC_EXIT_(desc);
2656 : }
2657 1866 : if (icol > fdesc->header.sql_desc_count)
2658 0 : ODBC_EXIT(desc, SQL_NO_DATA);
2659 1866 : drec = &fdesc->records[icol - 1];
2660 :
2661 1866 : tdsdump_log(TDS_DBG_INFO1, "SQLGetDescField: fDescType is %d\n", fDescType);
2662 :
2663 1866 : switch (fDescType) {
2664 0 : case SQL_DESC_AUTO_UNIQUE_VALUE:
2665 0 : IOUT(SQLUINTEGER, drec->sql_desc_auto_unique_value);
2666 : break;
2667 0 : case SQL_DESC_BASE_COLUMN_NAME:
2668 0 : SOUT(drec->sql_desc_base_column_name);
2669 0 : break;
2670 0 : case SQL_DESC_BASE_TABLE_NAME:
2671 0 : SOUT(drec->sql_desc_base_table_name);
2672 0 : break;
2673 0 : case SQL_DESC_CASE_SENSITIVE:
2674 0 : IOUT(SQLINTEGER, drec->sql_desc_case_sensitive);
2675 : break;
2676 0 : case SQL_DESC_CATALOG_NAME:
2677 0 : SOUT(drec->sql_desc_catalog_name);
2678 0 : break;
2679 604 : case SQL_DESC_CONCISE_TYPE:
2680 604 : IOUT(SQLSMALLINT, drec->sql_desc_concise_type);
2681 : break;
2682 16 : case SQL_DESC_DATA_PTR:
2683 16 : IOUT(SQLPOINTER, drec->sql_desc_data_ptr);
2684 : break;
2685 590 : case SQL_DESC_DATETIME_INTERVAL_CODE:
2686 590 : IOUT(SQLSMALLINT, drec->sql_desc_datetime_interval_code);
2687 : break;
2688 0 : case SQL_DESC_DATETIME_INTERVAL_PRECISION:
2689 0 : IOUT(SQLINTEGER, drec->sql_desc_datetime_interval_precision);
2690 : break;
2691 0 : case SQL_DESC_DISPLAY_SIZE:
2692 0 : IOUT(SQLLEN, drec->sql_desc_display_size);
2693 : break;
2694 0 : case SQL_DESC_FIXED_PREC_SCALE:
2695 0 : IOUT(SQLSMALLINT, drec->sql_desc_fixed_prec_scale);
2696 : break;
2697 8 : case SQL_DESC_INDICATOR_PTR:
2698 8 : IOUT(SQLLEN *, drec->sql_desc_indicator_ptr);
2699 : break;
2700 0 : case SQL_DESC_LABEL:
2701 0 : SOUT(drec->sql_desc_label);
2702 0 : break;
2703 14 : case SQL_DESC_LENGTH:
2704 14 : IOUT(SQLULEN, drec->sql_desc_length);
2705 : break;
2706 0 : case SQL_DESC_LITERAL_PREFIX:
2707 0 : COUT(drec->sql_desc_literal_prefix);
2708 0 : break;
2709 0 : case SQL_DESC_LITERAL_SUFFIX:
2710 0 : COUT(drec->sql_desc_literal_suffix);
2711 0 : break;
2712 0 : case SQL_DESC_LOCAL_TYPE_NAME:
2713 0 : SOUT(drec->sql_desc_local_type_name);
2714 0 : break;
2715 0 : case SQL_DESC_NAME:
2716 0 : SOUT(drec->sql_desc_name);
2717 0 : break;
2718 0 : case SQL_DESC_NULLABLE:
2719 0 : IOUT(SQLSMALLINT, drec->sql_desc_nullable);
2720 : break;
2721 0 : case SQL_DESC_NUM_PREC_RADIX:
2722 0 : IOUT(SQLINTEGER, drec->sql_desc_num_prec_radix);
2723 : break;
2724 8 : case SQL_DESC_OCTET_LENGTH:
2725 8 : IOUT(SQLLEN, drec->sql_desc_octet_length);
2726 : break;
2727 8 : case SQL_DESC_OCTET_LENGTH_PTR:
2728 8 : IOUT(SQLLEN *, drec->sql_desc_octet_length_ptr);
2729 : break;
2730 0 : case SQL_DESC_PARAMETER_TYPE:
2731 0 : IOUT(SQLSMALLINT, drec->sql_desc_parameter_type);
2732 : break;
2733 6 : case SQL_DESC_PRECISION:
2734 12 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2735 6 : || drec->sql_desc_concise_type == SQL_TIMESTAMP
2736 4 : || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP)
2737 2 : IOUT(SQLSMALLINT, drec->sql_desc_precision);
2738 : else
2739 : /* TODO support date/time */
2740 4 : *((SQLSMALLINT *) Value) = 0;
2741 : break;
2742 : #ifdef SQL_DESC_ROWVER
2743 0 : case SQL_DESC_ROWVER:
2744 0 : IOUT(SQLSMALLINT, drec->sql_desc_rowver);
2745 : break;
2746 : #endif
2747 6 : case SQL_DESC_SCALE:
2748 12 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2749 6 : || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP
2750 4 : || drec->sql_desc_concise_type == SQL_TIMESTAMP
2751 4 : || drec->sql_desc_concise_type == SQL_FLOAT)
2752 2 : IOUT(SQLSMALLINT, drec->sql_desc_scale);
2753 : else
2754 4 : *((SQLSMALLINT *) Value) = 0;
2755 : break;
2756 0 : case SQL_DESC_SCHEMA_NAME:
2757 0 : SOUT(drec->sql_desc_schema_name);
2758 0 : break;
2759 0 : case SQL_DESC_SEARCHABLE:
2760 0 : IOUT(SQLSMALLINT, drec->sql_desc_searchable);
2761 : break;
2762 0 : case SQL_DESC_TABLE_NAME:
2763 0 : SOUT(drec->sql_desc_table_name);
2764 0 : break;
2765 606 : case SQL_DESC_TYPE:
2766 606 : IOUT(SQLSMALLINT, drec->sql_desc_type);
2767 : break;
2768 0 : case SQL_DESC_TYPE_NAME:
2769 0 : COUT(drec->sql_desc_type_name);
2770 0 : break;
2771 0 : case SQL_DESC_UNNAMED:
2772 0 : IOUT(SQLSMALLINT, drec->sql_desc_unnamed);
2773 : break;
2774 0 : case SQL_DESC_UNSIGNED:
2775 0 : IOUT(SQLSMALLINT, drec->sql_desc_unsigned);
2776 : break;
2777 0 : case SQL_DESC_UPDATABLE:
2778 0 : IOUT(SQLSMALLINT, drec->sql_desc_updatable);
2779 : break;
2780 0 : default:
2781 0 : odbc_errs_add(&desc->errs, "HY091", NULL);
2782 0 : ODBC_EXIT_(desc);
2783 : break;
2784 : }
2785 :
2786 0 : if (result == SQL_SUCCESS_WITH_INFO)
2787 0 : odbc_errs_add(&desc->errs, "01004", NULL);
2788 :
2789 1866 : ODBC_EXIT(desc, result);
2790 :
2791 : #undef COUT
2792 : #undef SOUT
2793 : #undef IOUT
2794 : }
2795 :
2796 : static SQLRETURN
2797 12 : resize_desc(TDS_DESC *desc, struct _sql_errors *errs, int n)
2798 : {
2799 12 : if (n < 0 || n > 4000) {
2800 0 : odbc_errs_add(errs, "07009", NULL);
2801 0 : return SQL_ERROR;
2802 : }
2803 12 : if (desc_alloc_records(desc, n) != SQL_SUCCESS) {
2804 0 : odbc_errs_add(errs, "HY001", NULL);
2805 0 : return SQL_ERROR;
2806 : }
2807 : return SQL_SUCCESS;
2808 : }
2809 :
2810 : static struct _drecord *
2811 658 : get_drec(TDS_DESC *desc, struct _sql_errors *errs, SQLSMALLINT icol)
2812 : {
2813 658 : if (icol > 0 && (icol <= desc->header.sql_desc_count || resize_desc(desc, errs, icol) == SQL_SUCCESS))
2814 658 : return &desc->records[icol - 1];
2815 :
2816 : return NULL;
2817 : }
2818 :
2819 710 : ODBC_FUNC(SQLSetDescField, (P(SQLHDESC,hdesc), P(SQLSMALLINT,icol), P(SQLSMALLINT,fDescType),
2820 : P(SQLPOINTER,Value), P(SQLINTEGER,BufferLength) WIDE))
2821 : {
2822 : struct _drecord *drec;
2823 710 : SQLRETURN result = SQL_SUCCESS;
2824 : TDS_DESC *fdesc;
2825 :
2826 710 : ODBC_ENTER_HDESC;
2827 :
2828 : #if ENABLE_EXTRA_CHECKS
2829 : #define IIN(type, dest) do { \
2830 : /* trick warning if type wrong */ \
2831 : type *p_test = &dest; p_test = p_test; \
2832 : dest = (type)(TDS_INTPTR)Value; } while(0)
2833 : #define PIN(type, dest) do { \
2834 : /* trick warning if type wrong */ \
2835 : type *p_test = &dest; p_test = p_test; \
2836 : dest = (type)Value; } while(0)
2837 : #else
2838 : #define IIN(type, dest) dest = (type)(TDS_INTPTR)Value
2839 : #define PIN(type, dest) dest = (type)Value
2840 : #endif
2841 : #define GET_DREC do { \
2842 : drec = get_drec(fdesc, &desc->errs, icol); \
2843 : if (!drec) goto default_err; \
2844 : } while(0)
2845 :
2846 : /* special case for IRD */
2847 710 : if (desc->type == DESC_IRD && fDescType != SQL_DESC_ARRAY_STATUS_PTR && fDescType != SQL_DESC_ROWS_PROCESSED_PTR) {
2848 0 : odbc_errs_add(&desc->errs, "HY016", NULL);
2849 0 : ODBC_EXIT_(desc);
2850 : }
2851 :
2852 710 : fdesc = desc_get_focused(desc);
2853 :
2854 : /* dont check column index for these */
2855 710 : switch (fDescType) {
2856 0 : case SQL_DESC_ALLOC_TYPE:
2857 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2858 0 : ODBC_EXIT_(desc);
2859 : break;
2860 0 : case SQL_DESC_ARRAY_SIZE:
2861 0 : IIN(SQLULEN, fdesc->header.sql_desc_array_size);
2862 0 : ODBC_EXIT_(desc);
2863 : break;
2864 0 : case SQL_DESC_ARRAY_STATUS_PTR:
2865 0 : PIN(SQLUSMALLINT *, fdesc->header.sql_desc_array_status_ptr);
2866 0 : ODBC_EXIT_(desc);
2867 : break;
2868 40 : case SQL_DESC_ROWS_PROCESSED_PTR:
2869 40 : PIN(SQLULEN *, fdesc->header.sql_desc_rows_processed_ptr);
2870 40 : ODBC_EXIT_(desc);
2871 : break;
2872 0 : case SQL_DESC_BIND_TYPE:
2873 0 : IIN(SQLINTEGER, fdesc->header.sql_desc_bind_type);
2874 0 : ODBC_EXIT_(desc);
2875 : break;
2876 2 : case SQL_DESC_COUNT:
2877 2 : resize_desc(fdesc, &desc->errs, (int) (TDS_INTPTR) Value);
2878 2 : ODBC_EXIT_(desc);
2879 : break;
2880 : }
2881 :
2882 668 : if (icol <= 0) {
2883 0 : odbc_errs_add(&desc->errs, "07009", "Column out of range");
2884 0 : ODBC_EXIT_(desc);
2885 : }
2886 :
2887 668 : tdsdump_log(TDS_DBG_INFO1, "SQLSetDescField: fDescType is %d\n", fDescType);
2888 :
2889 668 : switch (fDescType) {
2890 10 : case SQL_DESC_AUTO_UNIQUE_VALUE:
2891 : case SQL_DESC_BASE_COLUMN_NAME:
2892 : case SQL_DESC_BASE_TABLE_NAME:
2893 : case SQL_DESC_CASE_SENSITIVE:
2894 : case SQL_DESC_CATALOG_NAME:
2895 10 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2896 10 : result = SQL_ERROR;
2897 10 : break;
2898 544 : case SQL_DESC_CONCISE_TYPE:
2899 544 : GET_DREC;
2900 544 : DESC_SET_NEED_REPREPARE;
2901 544 : if (fdesc->type == DESC_IPD)
2902 450 : result = odbc_set_concise_sql_type((SQLSMALLINT) (TDS_INTPTR) Value, drec, 0);
2903 : else
2904 94 : result = odbc_set_concise_c_type((SQLSMALLINT) (TDS_INTPTR) Value, drec, 0);
2905 544 : if (result != SQL_SUCCESS)
2906 310 : odbc_errs_add(&desc->errs, "HY021", NULL);
2907 : break;
2908 0 : case SQL_DESC_DATA_PTR:
2909 0 : GET_DREC;
2910 0 : PIN(SQLPOINTER, drec->sql_desc_data_ptr);
2911 0 : break;
2912 : /* TODO SQL_DESC_DATETIME_INTERVAL_CODE remember to check sql_desc_type */
2913 : /* TODO SQL_DESC_DATETIME_INTERVAL_PRECISION */
2914 0 : case SQL_DESC_DISPLAY_SIZE:
2915 : case SQL_DESC_FIXED_PREC_SCALE:
2916 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2917 0 : result = SQL_ERROR;
2918 0 : break;
2919 0 : case SQL_DESC_INDICATOR_PTR:
2920 0 : GET_DREC;
2921 0 : PIN(SQLLEN *, drec->sql_desc_indicator_ptr);
2922 0 : break;
2923 0 : case SQL_DESC_LABEL:
2924 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2925 0 : result = SQL_ERROR;
2926 0 : break;
2927 0 : case SQL_DESC_LENGTH:
2928 0 : GET_DREC;
2929 0 : DESC_SET_NEED_REPREPARE;
2930 0 : IIN(SQLULEN, drec->sql_desc_length);
2931 0 : break;
2932 0 : case SQL_DESC_LITERAL_PREFIX:
2933 : case SQL_DESC_LITERAL_SUFFIX:
2934 : case SQL_DESC_LOCAL_TYPE_NAME:
2935 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2936 0 : result = SQL_ERROR;
2937 0 : break;
2938 0 : case SQL_DESC_NAME:
2939 0 : GET_DREC;
2940 0 : if (!odbc_dstr_copy_oct(desc_get_dbc(fdesc), &drec->sql_desc_name, BufferLength, (ODBC_CHAR *) Value)) {
2941 0 : odbc_errs_add(&desc->errs, "HY001", NULL);
2942 0 : result = SQL_ERROR;
2943 : }
2944 : break;
2945 0 : case SQL_DESC_NULLABLE:
2946 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2947 0 : result = SQL_ERROR;
2948 0 : break;
2949 0 : case SQL_DESC_NUM_PREC_RADIX:
2950 0 : GET_DREC;
2951 0 : IIN(SQLINTEGER, drec->sql_desc_num_prec_radix);
2952 0 : break;
2953 0 : case SQL_DESC_OCTET_LENGTH:
2954 0 : GET_DREC;
2955 0 : DESC_SET_NEED_REPREPARE;
2956 0 : IIN(SQLLEN, drec->sql_desc_octet_length);
2957 0 : break;
2958 4 : case SQL_DESC_OCTET_LENGTH_PTR:
2959 4 : GET_DREC;
2960 4 : PIN(SQLLEN *, drec->sql_desc_octet_length_ptr);
2961 4 : break;
2962 0 : case SQL_DESC_PARAMETER_TYPE:
2963 0 : GET_DREC;
2964 0 : DESC_SET_NEED_REPREPARE;
2965 0 : IIN(SQLSMALLINT, drec->sql_desc_parameter_type);
2966 0 : break;
2967 50 : case SQL_DESC_PRECISION:
2968 50 : GET_DREC;
2969 50 : DESC_SET_NEED_REPREPARE;
2970 : /* TODO correct ?? */
2971 50 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL)
2972 10 : IIN(SQLSMALLINT, drec->sql_desc_precision);
2973 : else
2974 40 : IIN(SQLULEN, drec->sql_desc_length);
2975 : break;
2976 : #ifdef SQL_DESC_ROWVER
2977 0 : case SQL_DESC_ROWVER:
2978 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2979 0 : result = SQL_ERROR;
2980 0 : break;
2981 : #endif
2982 60 : case SQL_DESC_SCALE:
2983 60 : GET_DREC;
2984 60 : DESC_SET_NEED_REPREPARE;
2985 60 : if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL)
2986 10 : IIN(SQLSMALLINT, drec->sql_desc_scale);
2987 : else
2988 : /* TODO even for datetime/money ?? */
2989 50 : drec->sql_desc_scale = 0;
2990 : break;
2991 0 : case SQL_DESC_SCHEMA_NAME:
2992 : case SQL_DESC_SEARCHABLE:
2993 : case SQL_DESC_TABLE_NAME:
2994 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2995 0 : result = SQL_ERROR;
2996 0 : break;
2997 0 : case SQL_DESC_TYPE:
2998 0 : GET_DREC;
2999 0 : DESC_SET_NEED_REPREPARE;
3000 0 : IIN(SQLSMALLINT, drec->sql_desc_type);
3001 : /* FIXME what happen for interval/datetime ?? */
3002 0 : drec->sql_desc_concise_type = drec->sql_desc_type;
3003 0 : break;
3004 0 : case SQL_DESC_TYPE_NAME:
3005 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3006 0 : result = SQL_ERROR;
3007 0 : break;
3008 0 : case SQL_DESC_UNNAMED:
3009 0 : GET_DREC;
3010 0 : IIN(SQLSMALLINT, drec->sql_desc_unnamed);
3011 0 : break;
3012 0 : case SQL_DESC_UNSIGNED:
3013 : case SQL_DESC_UPDATABLE:
3014 0 : odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
3015 0 : result = SQL_ERROR;
3016 0 : break;
3017 0 : default:
3018 0 : odbc_errs_add(&desc->errs, "HY091", NULL);
3019 0 : ODBC_EXIT_(desc);
3020 : break;
3021 : }
3022 :
3023 : #undef IIN
3024 :
3025 668 : ODBC_EXIT(desc, result);
3026 :
3027 0 : default_err:
3028 0 : ODBC_EXIT_(desc);
3029 : }
3030 :
3031 : SQLRETURN ODBC_PUBLIC ODBC_API
3032 : SQLCopyDesc(SQLHDESC hsrc, SQLHDESC hdesc)
3033 : {
3034 : TDS_DESC *src;
3035 :
3036 50 : ODBC_ENTER_HDESC;
3037 :
3038 30 : tdsdump_log(TDS_DBG_FUNC, "SQLCopyDesc(%p, %p)\n",
3039 : hsrc, hdesc);
3040 :
3041 : /* check source descriptor handle, destination one was already checked */
3042 30 : if (SQL_NULL_HDESC == hsrc || !IS_HDESC(hsrc)) {
3043 20 : tds_mutex_unlock(&desc->mtx);
3044 20 : return SQL_INVALID_HANDLE;
3045 : }
3046 :
3047 10 : src = (TDS_DESC *) hsrc;
3048 10 : CHECK_DESC_EXTRA(src);
3049 :
3050 : /* do not write on IRD */
3051 10 : if (desc->type == DESC_IRD) {
3052 0 : odbc_errs_add(&desc->errs, "HY016", NULL);
3053 0 : ODBC_EXIT_(desc);
3054 : }
3055 10 : IRD_UPDATE(src, &src->errs, ODBC_EXIT(desc, SQL_ERROR));
3056 :
3057 10 : ODBC_EXIT(desc, desc_copy(desc, src));
3058 : }
3059 :
3060 : #if ENABLE_EXTRA_CHECKS
3061 : void
3062 19852 : odbc_ird_check(TDS_STMT *stmt TDS_UNUSED)
3063 : {
3064 : #if !ENABLE_ODBC_MARS
3065 19426 : TDS_DESC *ird = stmt->ird;
3066 19426 : TDSRESULTINFO *res_info = NULL;
3067 19426 : int cols = 0, i;
3068 :
3069 19426 : if (!stmt->tds)
3070 : return;
3071 18446 : if (stmt->tds->current_results) {
3072 18425 : res_info = stmt->tds->current_results;
3073 18425 : cols = res_info->num_cols;
3074 : }
3075 18446 : if (stmt->cursor != NULL)
3076 : return;
3077 :
3078 : /* check columns number */
3079 18098 : assert(ird->header.sql_desc_count <= cols || ird->header.sql_desc_count == 0);
3080 :
3081 :
3082 : /* check all columns */
3083 74673 : for (i = 0; i < ird->header.sql_desc_count; ++i) {
3084 74673 : struct _drecord *drec = &ird->records[i];
3085 74673 : TDSCOLUMN *col = res_info->columns[i];
3086 :
3087 224019 : assert(strcmp(tds_dstr_cstr(&drec->sql_desc_label), tds_dstr_cstr(&col->column_name)) == 0);
3088 : }
3089 : #endif
3090 426 : }
3091 : #endif
3092 :
3093 : static void
3094 3710 : odbc_unquote(char *buf, size_t buf_len, const char *start, const char *end)
3095 : {
3096 : char quote;
3097 3710 : assert(buf_len > 0);
3098 :
3099 : /* empty string */
3100 3710 : if (start >= end) {
3101 0 : buf[0] = 0;
3102 0 : return;
3103 : }
3104 :
3105 : /* not quoted */
3106 3710 : if (*start != '[' && *start != '\"') {
3107 2622 : --buf_len;
3108 2622 : if (end < start + buf_len)
3109 2622 : buf_len = end - start;
3110 2622 : memcpy(buf, start, buf_len);
3111 2622 : buf[buf_len] = 0;
3112 2622 : return;
3113 : }
3114 :
3115 : /* quoted... unquote */
3116 1088 : quote = (*start == '[') ? ']' : *start;
3117 1088 : ++start;
3118 7856 : while (buf_len > 0 && start < end) {
3119 6768 : if (*start == quote)
3120 1088 : if (++start >= end)
3121 : break;
3122 5680 : *buf++ = *start++;
3123 5680 : --buf_len;
3124 : }
3125 1088 : *buf = 0;
3126 : }
3127 :
3128 : /* FIXME check result !!! */
3129 : static SQLRETURN
3130 43400 : odbc_populate_ird(TDS_STMT * stmt)
3131 : {
3132 43400 : TDS_DESC *ird = stmt->ird;
3133 : struct _drecord *drec;
3134 : TDSCOLUMN *col;
3135 : TDSRESULTINFO *res_info;
3136 : int num_cols;
3137 : int i;
3138 :
3139 43400 : desc_free_records(ird);
3140 43400 : if (!stmt->tds || !(res_info = stmt->tds->current_results))
3141 : return SQL_SUCCESS;
3142 12073 : if (res_info == stmt->tds->param_info)
3143 : return SQL_SUCCESS;
3144 11337 : num_cols = res_info->num_cols;
3145 :
3146 : /* ignore hidden columns... TODO correct? */
3147 23106 : while (num_cols > 0 && res_info->columns[num_cols - 1]->column_hidden == 1)
3148 432 : --num_cols;
3149 :
3150 11337 : if (desc_alloc_records(ird, num_cols) != SQL_SUCCESS)
3151 : goto memory_error;
3152 :
3153 18331 : for (i = 0; i < num_cols; i++) {
3154 18331 : drec = &ird->records[i];
3155 18331 : col = res_info->columns[i];
3156 18331 : drec->sql_desc_auto_unique_value = col->column_identity ? SQL_TRUE : SQL_FALSE;
3157 : /* TODO SQL_FALSE ?? */
3158 18331 : drec->sql_desc_case_sensitive = SQL_TRUE;
3159 :
3160 : /*
3161 : * TODO how to handle when in datetime we change precision ??
3162 : * should we change display size too ??
3163 : * is formatting function correct ??
3164 : * we should not convert to string with invalid precision!
3165 : */
3166 18331 : odbc_set_sql_type_info(col, drec, stmt->dbc);
3167 :
3168 18331 : drec->sql_desc_fixed_prec_scale = (col->column_prec && col->column_scale) ? SQL_TRUE : SQL_FALSE;
3169 18331 : if (!tds_dstr_dup(&drec->sql_desc_label, &col->column_name))
3170 : goto memory_error;
3171 :
3172 36662 : if (tds_dstr_isempty(&col->table_column_name)) {
3173 16063 : if (!tds_dstr_dup(&drec->sql_desc_name, &col->column_name))
3174 : goto memory_error;
3175 : } else {
3176 2268 : if (!tds_dstr_dup(&drec->sql_desc_name, &col->table_column_name))
3177 : goto memory_error;
3178 2268 : if (!tds_dstr_dup(&drec->sql_desc_base_column_name, &col->table_column_name))
3179 : goto memory_error;
3180 : }
3181 :
3182 : /* extract sql_desc_(catalog/schema/base_table)_name */
3183 : /* TODO extract them dinamically (when needed) ? */
3184 : /* TODO store in libTDS in different way (separately) ? */
3185 36662 : if (!tds_dstr_isempty(&col->table_name)) {
3186 : struct {
3187 : const char *start;
3188 : const char *end;
3189 : } partials[4];
3190 : const char *p;
3191 : char buf[256];
3192 : int i;
3193 :
3194 7420 : p = tds_dstr_cstr(&col->table_name);
3195 3710 : for (i = 0; ; ++i) {
3196 : const char *pend;
3197 :
3198 3710 : if (*p == '[' || *p == '\"') {
3199 1088 : pend = tds_skip_quoted(p);
3200 : } else {
3201 2622 : pend = strchr(p, '.');
3202 2622 : if (!pend)
3203 2622 : pend = strchr(p, 0);
3204 : }
3205 3710 : partials[i].start = p;
3206 3710 : partials[i].end = pend;
3207 3710 : p = pend;
3208 3710 : if (i == 3 || *p != '.')
3209 : break;
3210 0 : ++p;
3211 : }
3212 :
3213 : /* here i points to last element */
3214 3710 : odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3215 3710 : if (!tds_dstr_copy(&drec->sql_desc_base_table_name, buf))
3216 : goto memory_error;
3217 :
3218 3710 : --i;
3219 3710 : if (i >= 0) {
3220 0 : odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3221 0 : if (!tds_dstr_copy(&drec->sql_desc_schema_name, buf))
3222 : goto memory_error;
3223 : }
3224 :
3225 3710 : --i;
3226 3710 : if (i >= 0) {
3227 0 : odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3228 0 : if (!tds_dstr_copy(&drec->sql_desc_catalog_name, buf))
3229 : goto memory_error;
3230 : }
3231 : }
3232 :
3233 36662 : drec->sql_desc_unnamed = tds_dstr_isempty(&drec->sql_desc_name) ? SQL_UNNAMED : SQL_NAMED;
3234 : /* TODO use is_nullable_type ?? */
3235 18331 : drec->sql_desc_nullable = col->column_nullable ? SQL_TRUE : SQL_FALSE;
3236 :
3237 18331 : drec->sql_desc_octet_length_ptr = NULL;
3238 : /* TODO test timestamp from db, FOR BROWSE query */
3239 18331 : drec->sql_desc_rowver = SQL_FALSE;
3240 : /* TODO seem not correct */
3241 18331 : drec->sql_desc_searchable = (drec->sql_desc_unnamed == SQL_NAMED) ? SQL_PRED_SEARCHABLE : SQL_UNSEARCHABLE;
3242 18331 : drec->sql_desc_updatable = col->column_writeable && !col->column_identity ? SQL_TRUE : SQL_FALSE;
3243 : }
3244 : return SQL_SUCCESS;
3245 :
3246 0 : memory_error:
3247 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
3248 0 : return SQL_ERROR;
3249 : }
3250 :
3251 : static TDSRET
3252 2314 : odbc_cursor_execute(TDS_STMT * stmt)
3253 : {
3254 2314 : TDSSOCKET *tds = stmt->tds;
3255 : int i;
3256 2314 : bool send = false;
3257 : TDSRET ret;
3258 : TDSCURSOR *cursor;
3259 2314 : TDSPARAMINFO *params = stmt->params;
3260 :
3261 2314 : assert(tds);
3262 2314 : assert(stmt->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY || stmt->attr.concurrency != SQL_CONCUR_READ_ONLY);
3263 :
3264 2314 : tds_release_cursor(&stmt->cursor);
3265 11570 : cursor = tds_alloc_cursor(tds, tds_dstr_cstr(&stmt->cursor_name), tds_dstr_len(&stmt->cursor_name),
3266 4628 : tds_dstr_cstr(&stmt->query), tds_dstr_len(&stmt->query));
3267 2314 : if (!cursor) {
3268 0 : odbc_unlock_statement(stmt);
3269 :
3270 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
3271 0 : return TDS_FAIL;
3272 : }
3273 2314 : stmt->cursor = cursor;
3274 :
3275 : /* TODO cursor add enums for tds7 */
3276 2314 : switch (stmt->attr.cursor_type) {
3277 : default:
3278 : case SQL_CURSOR_FORWARD_ONLY:
3279 : i = TDS_CUR_TYPE_FORWARD;
3280 : break;
3281 : case SQL_CURSOR_STATIC:
3282 : i = TDS_CUR_TYPE_STATIC;
3283 : break;
3284 : case SQL_CURSOR_KEYSET_DRIVEN:
3285 : i = TDS_CUR_TYPE_KEYSET;
3286 : break;
3287 : case SQL_CURSOR_DYNAMIC:
3288 : i = TDS_CUR_TYPE_DYNAMIC;
3289 : break;
3290 : }
3291 2314 : cursor->type = i;
3292 :
3293 2314 : switch (stmt->attr.concurrency) {
3294 : default:
3295 : case SQL_CONCUR_READ_ONLY:
3296 : i = TDS_CUR_CONCUR_READ_ONLY;
3297 : break;
3298 : case SQL_CONCUR_LOCK:
3299 : i = TDS_CUR_CONCUR_SCROLL_LOCKS;
3300 : break;
3301 : case SQL_CONCUR_ROWVER:
3302 : i = TDS_CUR_CONCUR_OPTIMISTIC;
3303 : break;
3304 : case SQL_CONCUR_VALUES:
3305 : i = TDS_CUR_CONCUR_OPTIMISTIC_VALUES;
3306 : break;
3307 : }
3308 2314 : cursor->concurrency = TDS_CUR_CONCUR_ALLOW_DIRECT | i;
3309 :
3310 2314 : ret = tds_cursor_declare(tds, cursor, &send);
3311 2314 : if (TDS_FAILED(ret))
3312 : return ret;
3313 2314 : ret = tds_cursor_open(tds, cursor, params, &send);
3314 2314 : if (TDS_FAILED(ret))
3315 : return ret;
3316 : /* TODO read results, set row count, check type and scroll returned */
3317 2314 : ret = tds_flush_packet(tds);
3318 2314 : tds_set_state(tds, TDS_PENDING);
3319 : /* set cursor name for TDS7+ */
3320 4628 : if (TDS_SUCCEED(ret) && IS_TDS7_PLUS(tds->conn) && !tds_dstr_isempty(&stmt->cursor_name)) {
3321 2314 : ret = odbc_process_tokens(stmt, TDS_RETURN_DONE|TDS_STOPAT_ROW|TDS_STOPAT_COMPUTE);
3322 2314 : stmt->row_count = tds->rows_affected;
3323 2314 : if (ret == TDS_CMD_DONE && cursor->cursor_id != 0) {
3324 248 : ret = tds_cursor_setname(tds, cursor);
3325 248 : tds_set_state(tds, TDS_PENDING);
3326 : } else {
3327 2066 : ret = (ret == TDS_CMD_FAIL) ? TDS_FAIL : TDS_SUCCESS;
3328 : }
3329 2314 : if (!cursor->cursor_id) {
3330 2058 : tds_cursor_dealloc(tds, cursor);
3331 2058 : tds_release_cursor(&stmt->cursor);
3332 : }
3333 : }
3334 : return ret;
3335 : }
3336 :
3337 : static TDSHEADERS *
3338 27953 : odbc_init_headers(TDS_STMT * stmt, TDSHEADERS * head)
3339 : {
3340 55910 : if (tds_dstr_isempty(&stmt->attr.qn_msgtext) || tds_dstr_isempty(&stmt->attr.qn_options))
3341 : return NULL;
3342 :
3343 4 : memset(head, 0, sizeof(*head));
3344 4 : head->qn_timeout = stmt->attr.qn_timeout;
3345 8 : head->qn_msgtext = tds_dstr_cstr(&stmt->attr.qn_msgtext);
3346 8 : head->qn_options = tds_dstr_cstr(&stmt->attr.qn_options);
3347 4 : return head;
3348 : }
3349 :
3350 : SQLRETURN
3351 33089 : odbc_SQLExecute(TDS_STMT *stmt)
3352 : {
3353 : TDSRET ret;
3354 : TDSSOCKET *tds;
3355 : TDS_INT result_type;
3356 33089 : TDS_INT done = 0;
3357 33089 : bool in_row = false;
3358 : SQLUSMALLINT param_status;
3359 33089 : int found_info = 0, found_error = 0;
3360 33089 : TDS_INT8 total_rows = TDS_NO_COUNT;
3361 : TDSHEADERS head;
3362 :
3363 33089 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLExecute(%p)\n",
3364 : stmt);
3365 :
3366 33089 : stmt->row = 0;
3367 :
3368 :
3369 : /* check parameters are all OK */
3370 33089 : if (stmt->params && stmt->param_num <= (int) stmt->param_count) {
3371 : /* TODO what error ?? */
3372 0 : ODBC_SAFE_ERROR(stmt);
3373 : return SQL_ERROR;
3374 : }
3375 :
3376 33089 : if (!odbc_lock_statement(stmt))
3377 : return SQL_ERROR;
3378 :
3379 33081 : tds = stmt->tds;
3380 33081 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLExecute() starting with state %d\n", tds->state);
3381 :
3382 33081 : if (tds->state != TDS_IDLE) {
3383 0 : if (tds->state == TDS_DEAD) {
3384 0 : odbc_errs_add(&stmt->errs, "08S01", NULL);
3385 : } else {
3386 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
3387 : }
3388 : return SQL_ERROR;
3389 : }
3390 :
3391 33081 : stmt->curr_param_row = 0;
3392 33081 : stmt->num_param_rows = TDS_MAX(1, stmt->apd->header.sql_desc_array_size);
3393 :
3394 33081 : stmt->row_count = TDS_NO_COUNT;
3395 :
3396 33081 : if (stmt->prepared_query_is_rpc) {
3397 : /* TODO support stmt->apd->header.sql_desc_array_size for RPC */
3398 : /* get rpc name */
3399 : /* TODO change method */
3400 : /* TODO cursor change way of calling */
3401 2212 : char *name = tds_dstr_buf(&stmt->query);
3402 : char *end, tmp;
3403 :
3404 1106 : end = name;
3405 1106 : end = (char *) odbc_skip_rpc_name(end);
3406 1106 : stmt->prepared_pos = end - name;
3407 1106 : tmp = *end;
3408 1106 : *end = 0;
3409 1106 : ret = tds_submit_rpc(tds, name, stmt->params, odbc_init_headers(stmt, &head));
3410 1106 : *end = tmp;
3411 31975 : } else if (stmt->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY || stmt->attr.concurrency != SQL_CONCUR_READ_ONLY) {
3412 2314 : ret = odbc_cursor_execute(stmt);
3413 29661 : } else if (!stmt->is_prepared_query) {
3414 : /* not prepared query */
3415 : /* TODO cursor change way of calling */
3416 : /* SQLExecDirect */
3417 26847 : if (stmt->num_param_rows <= 1) {
3418 26759 : if (!stmt->params) {
3419 51890 : ret = tds_submit_query_params(tds, tds_dstr_cstr(&stmt->query), NULL,
3420 : odbc_init_headers(stmt, &head));
3421 : } else {
3422 1628 : ret = tds_submit_execdirect(tds, tds_dstr_cstr(&stmt->query), stmt->params,
3423 : odbc_init_headers(stmt, &head));
3424 : }
3425 : } else {
3426 : /* pack multiple submit using language */
3427 : TDSMULTIPLE multiple;
3428 :
3429 88 : ret = tds_multiple_init(tds, &multiple, TDS_MULTIPLE_QUERY, odbc_init_headers(stmt, &head));
3430 728 : for (stmt->curr_param_row = 0; TDS_SUCCEED(ret); ) {
3431 : /* submit a query */
3432 1280 : ret = tds_multiple_query(tds, &multiple, tds_dstr_cstr(&stmt->query), stmt->params);
3433 640 : if (++stmt->curr_param_row >= stmt->num_param_rows)
3434 : break;
3435 : /* than process others parameters */
3436 : /* TODO handle all results*/
3437 552 : if (start_parse_prepared_query(stmt, true) != SQL_SUCCESS)
3438 : break;
3439 : }
3440 88 : if (TDS_SUCCEED(ret))
3441 88 : ret = tds_multiple_done(tds, &multiple);
3442 : }
3443 2814 : } else if (stmt->num_param_rows <= 1 && IS_TDS71_PLUS(tds->conn)
3444 2328 : && (!stmt->dyn || stmt->need_reprepare || !stmt->dyn->num_id)) {
3445 1846 : if (stmt->dyn) {
3446 86 : tdsdump_log(TDS_DBG_INFO1, "Re-prepare dynamic statement (num_id was %d)\n", stmt->dyn->num_id);
3447 86 : if (odbc_free_dynamic(stmt) != SQL_SUCCESS)
3448 0 : ODBC_RETURN(stmt, SQL_ERROR);
3449 : }
3450 1846 : stmt->need_reprepare = 0;
3451 3692 : ret = tds71_submit_prepexec(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params);
3452 : } else {
3453 : /* TODO cursor change way of calling */
3454 : /* SQLPrepare */
3455 : TDSDYNAMIC *dyn;
3456 :
3457 : /* prepare dynamic query (only for first SQLExecute call) */
3458 968 : if (!stmt->dyn || (stmt->need_reprepare && !stmt->dyn->emulated && IS_TDS7_PLUS(tds->conn))) {
3459 :
3460 : /* free previous prepared statement */
3461 64 : if (stmt->dyn) {
3462 0 : if (odbc_free_dynamic(stmt) != SQL_SUCCESS)
3463 0 : ODBC_RETURN(stmt, SQL_ERROR);
3464 : }
3465 64 : stmt->need_reprepare = 0;
3466 :
3467 64 : tdsdump_log(TDS_DBG_INFO1, "Creating prepared statement\n");
3468 : /* TODO use tds_submit_prepexec (mssql2k, tds71) */
3469 128 : if (TDS_FAILED(tds_submit_prepare(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params))) {
3470 : /* TODO ?? tds_free_param_results(params); */
3471 0 : ODBC_SAFE_ERROR(stmt);
3472 : return SQL_ERROR;
3473 : }
3474 64 : if (TDS_FAILED(tds_process_simple_query(tds))) {
3475 0 : tds_release_dynamic(&stmt->dyn);
3476 : /* TODO ?? tds_free_param_results(params); */
3477 0 : ODBC_SAFE_ERROR(stmt);
3478 : return SQL_ERROR;
3479 : }
3480 : }
3481 968 : stmt->row_count = TDS_NO_COUNT;
3482 968 : if (stmt->num_param_rows <= 1) {
3483 902 : dyn = stmt->dyn;
3484 902 : tds_free_input_params(dyn);
3485 902 : dyn->params = stmt->params;
3486 : /* prevent double free */
3487 902 : stmt->params = NULL;
3488 902 : tdsdump_log(TDS_DBG_INFO1, "End prepare, execute\n");
3489 : /* TODO return error to client */
3490 902 : ret = tds_submit_execute(tds, dyn);
3491 : } else {
3492 : TDSMULTIPLE multiple;
3493 :
3494 66 : ret = tds_multiple_init(tds, &multiple, TDS_MULTIPLE_EXECUTE, NULL);
3495 656 : for (stmt->curr_param_row = 0; TDS_SUCCEED(ret); ) {
3496 590 : dyn = stmt->dyn;
3497 590 : tds_free_input_params(dyn);
3498 590 : dyn->params = stmt->params;
3499 : /* prevent double free */
3500 590 : stmt->params = NULL;
3501 590 : ret = tds_multiple_execute(tds, &multiple, dyn);
3502 590 : if (++stmt->curr_param_row >= stmt->num_param_rows)
3503 : break;
3504 : /* than process others parameters */
3505 : /* TODO handle all results*/
3506 524 : if (start_parse_prepared_query(stmt, true) != SQL_SUCCESS)
3507 : break;
3508 : }
3509 66 : if (TDS_SUCCEED(ret))
3510 66 : ret = tds_multiple_done(tds, &multiple);
3511 : }
3512 : }
3513 33081 : if (TDS_FAILED(ret)) {
3514 20 : ODBC_SAFE_ERROR(stmt);
3515 : return SQL_ERROR;
3516 : }
3517 : /* catch all errors */
3518 33061 : if (!odbc_lock_statement(stmt))
3519 0 : ODBC_RETURN_(stmt);
3520 :
3521 33061 : stmt->row_status = PRE_NORMAL_ROW;
3522 :
3523 33061 : stmt->curr_param_row = 0;
3524 33061 : param_status = SQL_PARAM_SUCCESS;
3525 :
3526 : /* TODO review this, ODBC return parameter in other way, for compute I don't know */
3527 : /* TODO perhaps we should return SQL_NO_DATA if no data available... see old SQLExecute code */
3528 : for (;;) {
3529 54562 : result_type = odbc_process_tokens(stmt, TDS_TOKEN_RESULTS);
3530 54562 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLExecute: odbc_process_tokens returned result_type %d\n", result_type);
3531 54562 : switch (result_type) {
3532 28995 : case TDS_CMD_FAIL:
3533 : case TDS_CMD_DONE:
3534 : case TDS_COMPUTE_RESULT:
3535 : case TDS_ROW_RESULT:
3536 28995 : done = 1;
3537 28995 : break;
3538 :
3539 5064 : case TDS_DONE_RESULT:
3540 : case TDS_DONEPROC_RESULT:
3541 5064 : switch (stmt->errs.lastrc) {
3542 968 : case SQL_ERROR:
3543 968 : found_error = 1;
3544 968 : param_status = SQL_PARAM_ERROR;
3545 968 : break;
3546 634 : case SQL_SUCCESS_WITH_INFO:
3547 634 : found_info = 1;
3548 634 : param_status = SQL_PARAM_SUCCESS_WITH_INFO;
3549 634 : break;
3550 : }
3551 5064 : if (stmt->curr_param_row < stmt->num_param_rows && stmt->ipd->header.sql_desc_array_status_ptr)
3552 820 : stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
3553 5064 : param_status = SQL_PARAM_SUCCESS;
3554 5064 : ++stmt->curr_param_row;
3555 : /* actually is quite strange, if prepared always success with info or success
3556 : * if not prepared return last one
3557 : */
3558 5064 : if (stmt->curr_param_row < stmt->num_param_rows || result_type == TDS_DONEPROC_RESULT)
3559 1614 : stmt->errs.lastrc = SQL_SUCCESS;
3560 5064 : if (total_rows == TDS_NO_COUNT)
3561 4180 : total_rows = stmt->row_count;
3562 884 : else if (stmt->row_count != TDS_NO_COUNT)
3563 674 : total_rows += stmt->row_count;
3564 5064 : stmt->row_count = TDS_NO_COUNT;
3565 5064 : if (stmt->curr_param_row >= stmt->num_param_rows) {
3566 3988 : done = 1;
3567 3988 : break;
3568 : }
3569 : break;
3570 :
3571 9988 : case TDS_DONEINPROC_RESULT:
3572 9988 : if (in_row)
3573 78 : done = 1;
3574 : break;
3575 :
3576 : /* ignore metadata, stop at done or row */
3577 10479 : case TDS_ROWFMT_RESULT:
3578 10479 : if (in_row) {
3579 : done = 1;
3580 : break;
3581 : }
3582 10479 : stmt->row = 0;
3583 10479 : stmt->row_count = TDS_NO_COUNT;
3584 10479 : stmt->row_status = PRE_NORMAL_ROW;
3585 10479 : in_row = true;
3586 10479 : break;
3587 : }
3588 54562 : if (done)
3589 : break;
3590 : }
3591 33061 : if (found_error) {
3592 : /* if the application uses status array it can examine it to determine
3593 : which rows resulted in errors, but if it doesn't, it has no way to
3594 : do it and we must return an error and not success with info to it */
3595 432 : if (stmt->ipd->header.sql_desc_array_status_ptr)
3596 64 : stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3597 : else
3598 368 : stmt->errs.lastrc = SQL_ERROR;
3599 32629 : } else if (found_info && stmt->errs.lastrc != SQL_ERROR)
3600 634 : stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3601 :
3602 99183 : if (tds_dstr_isempty(&stmt->attr.qn_msgtext) != tds_dstr_isempty(&stmt->attr.qn_options)) {
3603 0 : odbc_errs_add(&stmt->errs, "HY000", "Attribute ignored");
3604 0 : stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3605 : }
3606 33061 : if (found_error && stmt->num_param_rows <= 1)
3607 352 : stmt->errs.lastrc = SQL_ERROR;
3608 33061 : if (stmt->curr_param_row < stmt->num_param_rows) {
3609 29073 : if (stmt->ipd->header.sql_desc_array_status_ptr)
3610 0 : stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
3611 29073 : ++stmt->curr_param_row;
3612 29073 : if (total_rows == TDS_NO_COUNT)
3613 29073 : total_rows = stmt->row_count;
3614 0 : else if (stmt->row_count != TDS_NO_COUNT)
3615 0 : total_rows += stmt->row_count;
3616 29073 : stmt->row_count = TDS_NO_COUNT;
3617 : }
3618 33061 : if (stmt->ipd->header.sql_desc_rows_processed_ptr)
3619 144 : *stmt->ipd->header.sql_desc_rows_processed_ptr = TDS_MIN(stmt->curr_param_row, stmt->num_param_rows);
3620 :
3621 33061 : if (total_rows != TDS_NO_COUNT)
3622 8378 : stmt->row_count = total_rows;
3623 :
3624 33061 : odbc_populate_ird(stmt);
3625 33061 : switch (result_type) {
3626 18542 : case TDS_CMD_DONE:
3627 18542 : odbc_unlock_statement(stmt);
3628 18542 : if (stmt->errs.lastrc == SQL_SUCCESS && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3
3629 15718 : && stmt->row_count == TDS_NO_COUNT && !stmt->cursor && stmt->ird->header.sql_desc_count <= 0)
3630 10914 : ODBC_RETURN(stmt, SQL_NO_DATA);
3631 : break;
3632 :
3633 206 : case TDS_CMD_FAIL:
3634 : /* TODO test what happened, report correct error to client */
3635 206 : tdsdump_log(TDS_DBG_INFO1, "SQLExecute: bad results\n");
3636 206 : ODBC_SAFE_ERROR(stmt);
3637 : return SQL_ERROR;
3638 : }
3639 21941 : ODBC_RETURN_(stmt);
3640 : }
3641 :
3642 28015 : ODBC_FUNC(SQLExecDirect, (P(SQLHSTMT,hstmt), PCHARIN(SqlStr,SQLINTEGER) WIDE))
3643 : {
3644 : SQLRETURN res;
3645 :
3646 28015 : ODBC_ENTER_HSTMT;
3647 :
3648 28015 : if (SQL_SUCCESS != odbc_set_stmt_query(stmt, szSqlStr, cbSqlStr _wide)) {
3649 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
3650 0 : ODBC_EXIT_(stmt);
3651 : }
3652 :
3653 : /* count placeholders */
3654 : /* note: szSqlStr can be no-null terminated, so first we set query and then count placeholders */
3655 56030 : stmt->param_count = tds_count_placeholders(tds_dstr_cstr(&stmt->query));
3656 28015 : stmt->param_data_called = 0;
3657 :
3658 28015 : if (SQL_SUCCESS != prepare_call(stmt)) {
3659 : /* TODO return another better error, prepare_call should set error ?? */
3660 0 : odbc_errs_add(&stmt->errs, "HY000", "Could not prepare call");
3661 0 : ODBC_EXIT_(stmt);
3662 : }
3663 :
3664 28015 : res = start_parse_prepared_query(stmt, true);
3665 28015 : if (SQL_SUCCESS != res)
3666 102 : ODBC_EXIT(stmt, res);
3667 :
3668 27913 : ODBC_EXIT(stmt, odbc_SQLExecute(stmt));
3669 : }
3670 :
3671 : SQLRETURN ODBC_PUBLIC ODBC_API
3672 : SQLExecute(SQLHSTMT hstmt)
3673 : {
3674 : ODBC_PRRET_BUF;
3675 : SQLRETURN res;
3676 :
3677 4768 : ODBC_ENTER_HSTMT;
3678 :
3679 4768 : tdsdump_log(TDS_DBG_FUNC, "SQLExecute(%p)\n", hstmt);
3680 :
3681 4768 : if (!stmt->is_prepared_query) {
3682 : /* TODO error report, only without DM ?? */
3683 0 : tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns SQL_ERROR (not prepared)\n");
3684 0 : ODBC_EXIT(stmt, SQL_ERROR);
3685 : }
3686 :
3687 : /* TODO rebuild should be done for every bindings change, not every time */
3688 : /* TODO free previous parameters */
3689 : /* build parameters list */
3690 4768 : stmt->param_data_called = 0;
3691 4768 : stmt->curr_param_row = 0;
3692 4768 : if ((res = start_parse_prepared_query(stmt, true)) != SQL_SUCCESS) {
3693 112 : tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns %s (start_parse_prepared_query failed)\n", odbc_prret(res));
3694 112 : ODBC_EXIT(stmt, res);
3695 : }
3696 :
3697 : /* TODO test if two SQLPrepare on a statement */
3698 : /* TODO test unprepare on statement free or connection close */
3699 :
3700 4656 : res = odbc_SQLExecute(stmt);
3701 :
3702 4656 : tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns %s\n", odbc_prret(res));
3703 :
3704 4656 : ODBC_EXIT(stmt, res);
3705 : }
3706 :
3707 : static int
3708 98228 : odbc_process_tokens(TDS_STMT * stmt, unsigned flag)
3709 : {
3710 : TDS_INT result_type;
3711 98228 : int done_flags = 0;
3712 98228 : TDSSOCKET * tds = stmt->tds;
3713 :
3714 98228 : flag |= TDS_RETURN_DONE | TDS_RETURN_PROC;
3715 : for (;;) {
3716 217244 : TDSRET retcode = tds_process_tokens(tds, &result_type, &done_flags, flag);
3717 217244 : tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: tds_process_tokens returned %d\n", retcode);
3718 217244 : tdsdump_log(TDS_DBG_FUNC, " result_type=%d, TDS_DONE_COUNT=%x, TDS_DONE_ERROR=%x\n",
3719 : result_type, (done_flags & TDS_DONE_COUNT), (done_flags & TDS_DONE_ERROR));
3720 217244 : switch (retcode) {
3721 : case TDS_SUCCESS:
3722 : break;
3723 : case TDS_NO_MORE_RESULTS:
3724 : return TDS_CMD_DONE;
3725 196 : case TDS_CANCELLED:
3726 196 : odbc_errs_add(&stmt->errs, "HY008", NULL);
3727 : default:
3728 : return TDS_CMD_FAIL;
3729 : }
3730 :
3731 186287 : switch (result_type) {
3732 1225 : case TDS_STATUS_RESULT:
3733 1225 : odbc_set_return_status(stmt, TDS_MIN(stmt->curr_param_row, stmt->num_param_rows - 1));
3734 1225 : break;
3735 834 : case TDS_PARAM_RESULT:
3736 834 : odbc_set_return_params(stmt, TDS_MIN(stmt->curr_param_row, stmt->num_param_rows - 1));
3737 834 : break;
3738 :
3739 130265 : case TDS_DONE_RESULT:
3740 : case TDS_DONEPROC_RESULT:
3741 130265 : if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3742 91682 : flag |= TDS_STOPAT_MSG;
3743 130265 : if (done_flags & TDS_DONE_COUNT) {
3744 11962 : stmt->row_count = tds->rows_affected;
3745 : }
3746 130265 : if (done_flags & TDS_DONE_ERROR)
3747 690 : stmt->errs.lastrc = SQL_ERROR;
3748 : /* test for internal_sp not very fine, used for param set -- freddy77 */
3749 130265 : if ((done_flags & (TDS_DONE_COUNT|TDS_DONE_ERROR)) != 0
3750 117733 : || (stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3751 117073 : || (result_type == TDS_DONEPROC_RESULT && tds->current_op == TDS_OP_EXECUTE)) {
3752 : /* FIXME this row is used only as a flag for update binding,
3753 : * should be cleared if binding/result changed */
3754 14256 : stmt->row = 0;
3755 : #if 0
3756 : tds_free_all_results(tds);
3757 : odbc_populate_ird(stmt);
3758 : #endif
3759 14256 : tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: row_count=%" PRId64 "\n", stmt->row_count);
3760 14256 : return result_type;
3761 : }
3762 116009 : tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: processed %s\n",
3763 : result_type==TDS_DONE_RESULT? "TDS_DONE_RESULT" : "TDS_DONEPROC_RESULT");
3764 : break;
3765 :
3766 : /*
3767 : * TODO test flags ? check error and change result ?
3768 : * see also other DONEINPROC handle (below)
3769 : */
3770 11034 : case TDS_DONEINPROC_RESULT:
3771 11034 : if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3772 6342 : flag |= TDS_STOPAT_MSG;
3773 11034 : if (done_flags & TDS_DONE_COUNT) {
3774 7182 : stmt->row_count = tds->rows_affected;
3775 : }
3776 11034 : if (done_flags & TDS_DONE_ERROR)
3777 448 : stmt->errs.lastrc = SQL_ERROR;
3778 : /* TODO perhaps it can be a problem if SET NOCOUNT ON, test it */
3779 : #if 0
3780 : tds_free_all_results(tds);
3781 : odbc_populate_ird(stmt);
3782 : #endif
3783 11034 : tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: processed TDS_DONEINPROC_RESULT\n");
3784 11034 : if (stmt->row_status == PRE_NORMAL_ROW)
3785 10086 : return result_type;
3786 : break;
3787 :
3788 42929 : default:
3789 42929 : tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: returning result_type %d\n", result_type);
3790 42929 : return result_type;
3791 : }
3792 : }
3793 : }
3794 :
3795 : static void
3796 160 : odbc_fix_data_type_col(TDS_STMT *stmt, int idx)
3797 : {
3798 160 : TDSSOCKET *tds = stmt->tds;
3799 : TDSRESULTINFO *resinfo;
3800 : TDSCOLUMN *colinfo;
3801 :
3802 160 : if (!tds)
3803 : return;
3804 :
3805 160 : resinfo = tds->current_results;
3806 160 : if (!resinfo || resinfo->num_cols <= idx)
3807 : return;
3808 :
3809 160 : colinfo = resinfo->columns[idx];
3810 160 : if (colinfo->column_cur_size < 0)
3811 : return;
3812 :
3813 160 : switch (tds_get_conversion_type(colinfo->column_type, colinfo->column_size)) {
3814 160 : case SYBINT2: {
3815 160 : TDS_SMALLINT *data = (TDS_SMALLINT *) colinfo->column_data;
3816 160 : *data = odbc_swap_datetime_sql_type(*data, 0);
3817 : }
3818 160 : break;
3819 0 : case SYBINT4: {
3820 0 : TDS_INT *data = (TDS_INT *) colinfo->column_data;
3821 0 : *data = odbc_swap_datetime_sql_type(*data, 0);
3822 : }
3823 0 : break;
3824 : default:
3825 : break;
3826 : }
3827 : }
3828 :
3829 : static SQLUSMALLINT
3830 20688 : copy_row(TDS_STMT * const stmt, const SQLLEN row_offset, const SQLULEN curr_row)
3831 : {
3832 20688 : const TDS_DESC *const ard = stmt->ard;
3833 20688 : TDSRESULTINFO *const resinfo = stmt->tds->current_results;
3834 : int i;
3835 20688 : bool truncated = false;
3836 :
3837 : #define AT_ROW(ptr, type) (row_offset ? (type*)(((char*)(ptr)) + row_offset) : &ptr[curr_row])
3838 :
3839 99958 : for (i = 0; i < resinfo->num_cols; i++) {
3840 : TDSCOLUMN *colinfo;
3841 : struct _drecord *drec_ard;
3842 : SQLLEN len;
3843 :
3844 79270 : colinfo = resinfo->columns[i];
3845 79270 : colinfo->column_text_sqlgetdatapos = 0;
3846 79270 : colinfo->column_iconv_left = 0;
3847 79270 : drec_ard = (i < ard->header.sql_desc_count) ? &ard->records[i] : NULL;
3848 19678 : if (!drec_ard)
3849 59592 : continue;
3850 19678 : if (colinfo->column_cur_size < 0) {
3851 2410 : if (drec_ard->sql_desc_indicator_ptr) {
3852 1294 : *AT_ROW(drec_ard->sql_desc_indicator_ptr, SQLLEN) = SQL_NULL_DATA;
3853 1116 : } else if (drec_ard->sql_desc_data_ptr) {
3854 0 : odbc_errs_add(&stmt->errs, "22002", NULL);
3855 0 : return SQL_ROW_ERROR;
3856 : }
3857 2410 : continue;
3858 : }
3859 : /* set indicator to 0 if data is not null */
3860 17268 : if (drec_ard->sql_desc_indicator_ptr)
3861 12272 : *AT_ROW(drec_ard->sql_desc_indicator_ptr, SQLLEN) = 0;
3862 :
3863 : /* TODO what happen to length if no data is returned (drec->sql_desc_data_ptr == NULL) ?? */
3864 17268 : len = 0;
3865 17268 : if (drec_ard->sql_desc_data_ptr) {
3866 : int c_type;
3867 11936 : TDS_CHAR *data_ptr = (TDS_CHAR *) drec_ard->sql_desc_data_ptr;
3868 :
3869 11936 : colinfo->column_text_sqlgetdatapos = 0;
3870 11936 : colinfo->column_iconv_left = 0;
3871 11936 : c_type = drec_ard->sql_desc_concise_type;
3872 11936 : if (c_type == SQL_C_DEFAULT)
3873 10 : c_type = odbc_sql_to_c_type_default(stmt->ird->records[i].sql_desc_concise_type);
3874 11936 : if (row_offset || curr_row == 0) {
3875 10778 : data_ptr += row_offset;
3876 : } else {
3877 1158 : data_ptr += odbc_get_octet_len(c_type, drec_ard) * curr_row;
3878 : }
3879 11936 : len = odbc_tds2sql_col(stmt, colinfo, c_type, data_ptr, drec_ard->sql_desc_octet_length, drec_ard);
3880 11936 : if (len == SQL_NULL_DATA)
3881 : return SQL_ROW_ERROR;
3882 :
3883 11936 : if ((c_type == SQL_C_CHAR && len >= drec_ard->sql_desc_octet_length)
3884 11748 : || (c_type == SQL_C_BINARY && len > drec_ard->sql_desc_octet_length)) {
3885 188 : truncated = true;
3886 188 : stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3887 : }
3888 : }
3889 17268 : if (drec_ard->sql_desc_octet_length_ptr)
3890 12272 : *AT_ROW(drec_ard->sql_desc_octet_length_ptr, SQLLEN) = len;
3891 : }
3892 :
3893 20688 : return truncated ? SQL_ROW_SUCCESS_WITH_INFO : SQL_ROW_SUCCESS;
3894 : #undef AT_ROW
3895 : }
3896 :
3897 : /*
3898 : * - handle correctly SQLGetData (for forward cursors accept only row_size == 1
3899 : * for other types application must use SQLSetPos)
3900 : * - handle correctly results (SQL_SUCCESS_WITH_INFO if error on some rows,
3901 : * SQL_ERROR for all rows, see doc)
3902 : */
3903 : static SQLRETURN
3904 28302 : odbc_SQLFetch(TDS_STMT * stmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)
3905 : {
3906 : TDSSOCKET *tds;
3907 : TDSRESULTINFO *resinfo;
3908 : int i;
3909 : SQLULEN curr_row, num_rows;
3910 28302 : const TDS_DESC *const ard = stmt->ard;
3911 : SQLULEN dummy, *fetched_ptr;
3912 28302 : SQLUSMALLINT *status_ptr, row_status = SQL_ROW_SUCCESS;
3913 : TDS_INT result_type;
3914 28302 : bool truncated = false;
3915 :
3916 28302 : SQLLEN row_offset = 0;
3917 :
3918 28302 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLFetch(%p, %d, %d)\n", stmt, (int) FetchOrientation, (int) FetchOffset);
3919 :
3920 28302 : if (ard->header.sql_desc_bind_offset_ptr)
3921 30 : row_offset = *ard->header.sql_desc_bind_offset_ptr;
3922 :
3923 28302 : tds = stmt->tds;
3924 28302 : num_rows = ard->header.sql_desc_array_size;
3925 :
3926 : /* TODO cursor check also type of cursor (scrollable, not forward) */
3927 28302 : if (FetchOrientation != SQL_FETCH_NEXT && (!stmt->cursor || !stmt->dbc->cursor_support)) {
3928 0 : odbc_errs_add(&stmt->errs, "HY106", NULL);
3929 0 : return SQL_ERROR;
3930 : }
3931 :
3932 : /* handle cursors, fetch wanted rows */
3933 28302 : if (stmt->cursor && odbc_lock_statement(stmt)) {
3934 696 : TDSCURSOR *cursor = stmt->cursor;
3935 696 : TDS_CURSOR_FETCH fetch_type = TDS_CURSOR_FETCH_NEXT;
3936 :
3937 696 : tds = stmt->tds;
3938 :
3939 696 : switch (FetchOrientation) {
3940 : case SQL_FETCH_NEXT:
3941 : break;
3942 16 : case SQL_FETCH_FIRST:
3943 16 : fetch_type = TDS_CURSOR_FETCH_FIRST;
3944 16 : break;
3945 24 : case SQL_FETCH_LAST:
3946 24 : fetch_type = TDS_CURSOR_FETCH_LAST;
3947 24 : break;
3948 32 : case SQL_FETCH_PRIOR:
3949 32 : fetch_type = TDS_CURSOR_FETCH_PREV;
3950 32 : break;
3951 16 : case SQL_FETCH_ABSOLUTE:
3952 16 : fetch_type = TDS_CURSOR_FETCH_ABSOLUTE;
3953 16 : break;
3954 56 : case SQL_FETCH_RELATIVE:
3955 56 : fetch_type = TDS_CURSOR_FETCH_RELATIVE;
3956 56 : break;
3957 : /* TODO cursor bookmark */
3958 0 : default:
3959 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
3960 0 : return SQL_ERROR;
3961 : }
3962 :
3963 696 : if (cursor->cursor_rows != num_rows) {
3964 248 : bool send = false;
3965 248 : cursor->cursor_rows = num_rows;
3966 : /* TODO handle change rows (tds5) */
3967 : /*
3968 : * TODO curerntly we support cursors only using tds7+
3969 : * so this function can't fail but remember to add error
3970 : * check when tds5 will be supported
3971 : */
3972 248 : tds_cursor_setrows(tds, cursor, &send);
3973 : }
3974 :
3975 696 : if (TDS_FAILED(tds_cursor_fetch(tds, cursor, fetch_type, FetchOffset))) {
3976 : /* TODO what kind of error ?? */
3977 0 : ODBC_SAFE_ERROR(stmt);
3978 : return SQL_ERROR;
3979 : }
3980 :
3981 : /* TODO handle errors in a better way */
3982 696 : odbc_process_tokens(stmt, TDS_RETURN_ROW|TDS_STOPAT_COMPUTE|TDS_STOPAT_ROW);
3983 696 : stmt->row_status = PRE_NORMAL_ROW;
3984 : }
3985 :
3986 28302 : if (!tds && stmt->row_status == PRE_NORMAL_ROW && stmt->ird->header.sql_desc_count > 0)
3987 10 : ODBC_RETURN(stmt, SQL_NO_DATA);
3988 28292 : if (!tds || stmt->row_status == NOT_IN_ROW) {
3989 30 : odbc_errs_add(&stmt->errs, "24000", NULL);
3990 30 : return SQL_ERROR;
3991 : }
3992 28262 : IRD_CHECK;
3993 :
3994 28262 : if (stmt->ird->header.sql_desc_count <= 0) {
3995 34 : odbc_errs_add(&stmt->errs, "24000", NULL);
3996 34 : return SQL_ERROR;
3997 : }
3998 :
3999 28228 : stmt->row++;
4000 :
4001 28228 : fetched_ptr = &dummy;
4002 28228 : if (stmt->ird->header.sql_desc_rows_processed_ptr)
4003 640 : fetched_ptr = stmt->ird->header.sql_desc_rows_processed_ptr;
4004 28228 : *fetched_ptr = 0;
4005 :
4006 28228 : status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
4007 28228 : if (status_ptr) {
4008 2704 : for (i = 0; (SQLULEN) i < num_rows; ++i)
4009 2704 : *status_ptr++ = SQL_ROW_NOROW;
4010 : status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
4011 : }
4012 :
4013 : curr_row = 0;
4014 : do {
4015 30048 : row_status = SQL_ROW_SUCCESS;
4016 :
4017 : /* do not get compute row if we are not expecting a compute row */
4018 30048 : switch (stmt->row_status) {
4019 32 : case AFTER_COMPUTE_ROW:
4020 : /* handle done if needed */
4021 : /* FIXME doesn't seem so fine ... - freddy77 */
4022 32 : tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
4023 32 : goto all_done;
4024 :
4025 32 : case IN_COMPUTE_ROW:
4026 : /* compute recorset contains only a row */
4027 : /* we already fetched compute row in SQLMoreResults so do not fetch another one */
4028 32 : num_rows = 1;
4029 32 : stmt->row_status = AFTER_COMPUTE_ROW;
4030 32 : break;
4031 :
4032 29984 : default:
4033 : /* FIXME stmt->row_count set correctly ?? TDS_DONE_COUNT not checked */
4034 29984 : switch (odbc_process_tokens(stmt, TDS_STOPAT_ROWFMT|TDS_RETURN_ROW|TDS_STOPAT_COMPUTE)) {
4035 : case TDS_ROW_RESULT:
4036 : break;
4037 9328 : default:
4038 : #if 0
4039 : stmt->row_count = tds->rows_affected;
4040 : #endif
4041 : /*
4042 : * NOTE do not set row_status to NOT_IN_ROW,
4043 : * if compute tds_process_tokens above returns TDS_NO_MORE_RESULTS
4044 : */
4045 9328 : stmt->row_status = PRE_NORMAL_ROW;
4046 9328 : stmt->special_row = ODBC_SPECIAL_NONE;
4047 : #if 0
4048 : odbc_populate_ird(stmt);
4049 : #endif
4050 9328 : tdsdump_log(TDS_DBG_INFO1, "SQLFetch: NO_DATA_FOUND\n");
4051 : goto all_done;
4052 : break;
4053 0 : case TDS_CMD_FAIL:
4054 0 : ODBC_SAFE_ERROR(stmt);
4055 : return SQL_ERROR;
4056 : break;
4057 : }
4058 :
4059 20656 : stmt->row_status = IN_NORMAL_ROW;
4060 :
4061 : /* handle special row */
4062 20656 : switch (stmt->special_row) {
4063 148 : case ODBC_SPECIAL_GETTYPEINFO:
4064 148 : odbc_fix_data_type_col(stmt, 1);
4065 148 : break;
4066 4 : case ODBC_SPECIAL_COLUMNS:
4067 4 : odbc_fix_data_type_col(stmt, 4);
4068 4 : odbc_fix_data_type_col(stmt, 13); /* TODO sure ?? */
4069 4 : break;
4070 2 : case ODBC_SPECIAL_PROCEDURECOLUMNS:
4071 2 : odbc_fix_data_type_col(stmt, 5);
4072 2 : odbc_fix_data_type_col(stmt, 14); /* TODO sure ?? */
4073 2 : break;
4074 0 : case ODBC_SPECIAL_SPECIALCOLUMNS:
4075 0 : odbc_fix_data_type_col(stmt, 2);
4076 0 : break;
4077 : case ODBC_SPECIAL_NONE:
4078 : break;
4079 : }
4080 : }
4081 :
4082 20688 : resinfo = tds->current_results;
4083 20688 : if (!resinfo) {
4084 0 : tdsdump_log(TDS_DBG_INFO1, "SQLFetch: !resinfo\n");
4085 : break;
4086 : }
4087 :
4088 : /* we got a row, return a row readed even if error (for ODBC specifications) */
4089 20688 : ++(*fetched_ptr);
4090 20688 : row_status = copy_row(stmt, row_offset, curr_row);
4091 20688 : if (row_status == SQL_ROW_SUCCESS_WITH_INFO)
4092 188 : truncated = true;
4093 :
4094 20688 : if (status_ptr)
4095 2096 : *status_ptr++ = truncated ? SQL_ROW_ERROR : row_status;
4096 20688 : if (row_status == SQL_ROW_ERROR) {
4097 0 : stmt->errs.lastrc = SQL_ERROR;
4098 0 : break;
4099 : }
4100 : #if SQL_BIND_BY_COLUMN != 0
4101 : if (ard->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN)
4102 : #endif
4103 20688 : row_offset += ard->header.sql_desc_bind_type;
4104 20688 : } while (++curr_row < num_rows);
4105 :
4106 18868 : if (truncated)
4107 98 : odbc_errs_add(&stmt->errs, "01004", NULL);
4108 :
4109 46998 : all_done:
4110 : /* TODO cursor correct ?? */
4111 28228 : if (stmt->cursor) {
4112 696 : tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
4113 696 : odbc_unlock_statement(stmt);
4114 : }
4115 28228 : if (*fetched_ptr == 0 && (stmt->errs.lastrc == SQL_SUCCESS || stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO))
4116 9142 : ODBC_RETURN(stmt, SQL_NO_DATA);
4117 19086 : if (stmt->errs.lastrc == SQL_ERROR && (*fetched_ptr > 1 || (*fetched_ptr == 1 && row_status != SQL_ROW_ERROR)))
4118 0 : ODBC_RETURN(stmt, SQL_SUCCESS_WITH_INFO);
4119 19086 : ODBC_RETURN_(stmt);
4120 : }
4121 :
4122 : SQLRETURN ODBC_PUBLIC ODBC_API
4123 : SQLFetch(SQLHSTMT hstmt)
4124 : {
4125 : SQLRETURN ret;
4126 : struct {
4127 : SQLULEN array_size;
4128 : SQLULEN *rows_processed_ptr;
4129 : SQLUSMALLINT *array_status_ptr;
4130 : } keep;
4131 :
4132 27632 : ODBC_ENTER_HSTMT;
4133 :
4134 27632 : tdsdump_log(TDS_DBG_FUNC, "SQLFetch(%p)\n", hstmt);
4135 :
4136 27632 : keep.array_size = stmt->ard->header.sql_desc_array_size;
4137 27632 : keep.rows_processed_ptr = stmt->ird->header.sql_desc_rows_processed_ptr;
4138 27632 : keep.array_status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
4139 :
4140 27632 : if (stmt->dbc->env->attr.odbc_version != SQL_OV_ODBC3) {
4141 4762 : stmt->ard->header.sql_desc_array_size = 1;
4142 4762 : stmt->ird->header.sql_desc_rows_processed_ptr = NULL;
4143 4762 : stmt->ird->header.sql_desc_array_status_ptr = NULL;
4144 : }
4145 :
4146 27632 : ret = odbc_SQLFetch(stmt, SQL_FETCH_NEXT, 0);
4147 :
4148 27632 : if (stmt->dbc->env->attr.odbc_version != SQL_OV_ODBC3) {
4149 4762 : stmt->ard->header.sql_desc_array_size = keep.array_size;
4150 4762 : stmt->ird->header.sql_desc_rows_processed_ptr = keep.rows_processed_ptr;
4151 4762 : stmt->ird->header.sql_desc_array_status_ptr = keep.array_status_ptr;
4152 : }
4153 :
4154 27632 : ODBC_EXIT(stmt, ret);
4155 : }
4156 :
4157 : #if (ODBCVER >= 0x0300)
4158 : SQLRETURN ODBC_PUBLIC ODBC_API
4159 : SQLFetchScroll(SQLHSTMT hstmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)
4160 : {
4161 642 : ODBC_ENTER_HSTMT;
4162 :
4163 642 : tdsdump_log(TDS_DBG_FUNC, "SQLFetchScroll(%p, %d, %d)\n", hstmt, FetchOrientation, (int)FetchOffset);
4164 :
4165 642 : if (FetchOrientation != SQL_FETCH_NEXT && !stmt->dbc->cursor_support) {
4166 0 : odbc_errs_add(&stmt->errs, "HY106", NULL);
4167 0 : ODBC_EXIT_(stmt);
4168 : }
4169 :
4170 642 : ODBC_EXIT(stmt, odbc_SQLFetch(stmt, FetchOrientation, FetchOffset));
4171 : }
4172 : #endif
4173 :
4174 :
4175 : #if (ODBCVER >= 0x0300)
4176 : SQLRETURN ODBC_PUBLIC ODBC_API
4177 : SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle)
4178 : {
4179 138 : tdsdump_log(TDS_DBG_INFO1, "SQLFreeHandle(%d, %p)\n", HandleType, (void *) Handle);
4180 :
4181 138 : switch (HandleType) {
4182 128 : case SQL_HANDLE_STMT:
4183 128 : return odbc_SQLFreeStmt(Handle, SQL_DROP, 0);
4184 : break;
4185 0 : case SQL_HANDLE_DBC:
4186 0 : return odbc_SQLFreeConnect(Handle);
4187 : break;
4188 0 : case SQL_HANDLE_ENV:
4189 0 : return odbc_SQLFreeEnv(Handle);
4190 : break;
4191 10 : case SQL_HANDLE_DESC:
4192 10 : return odbc_SQLFreeDesc(Handle);
4193 : break;
4194 : }
4195 : return SQL_ERROR;
4196 : }
4197 :
4198 : static SQLRETURN
4199 1216 : odbc_SQLFreeConnect(SQLHDBC hdbc)
4200 : {
4201 : int i;
4202 :
4203 1216 : ODBC_ENTER_HDBC;
4204 :
4205 1216 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLFreeConnect(%p)\n",
4206 : hdbc);
4207 :
4208 1216 : tds_close_socket(dbc->tds_socket);
4209 :
4210 : /* TODO if connected return error */
4211 1216 : tds_free_socket(dbc->tds_socket);
4212 :
4213 1216 : odbc_bcp_free_storage(dbc);
4214 :
4215 1216 : tds_dstr_free(&dbc->datetime_fmt);
4216 1216 : tds_dstr_free(&dbc->date_fmt);
4217 1216 : tds_dstr_free(&dbc->time_fmt);
4218 :
4219 : /* free attributes */
4220 : #ifdef TDS_NO_DM
4221 1216 : tds_dstr_free(&dbc->attr.tracefile);
4222 : #endif
4223 1216 : tds_dstr_free(&dbc->attr.current_catalog);
4224 1216 : tds_dstr_free(&dbc->attr.translate_lib);
4225 1216 : tds_dstr_zero(&dbc->oldpwd);
4226 1216 : tds_dstr_free(&dbc->oldpwd);
4227 1216 : tds_dstr_free(&dbc->db_filename);
4228 :
4229 1216 : tds_dstr_free(&dbc->dsn);
4230 :
4231 122816 : for (i = 0; i < TDS_MAX_APP_DESC; i++) {
4232 121600 : if (dbc->uad[i]) {
4233 0 : desc_free(dbc->uad[i]);
4234 : }
4235 : }
4236 1216 : odbc_errs_reset(&dbc->errs);
4237 1216 : tds_mutex_unlock(&dbc->mtx);
4238 1216 : tds_mutex_free(&dbc->mtx);
4239 :
4240 1216 : free(dbc);
4241 :
4242 1216 : return SQL_SUCCESS;
4243 : }
4244 :
4245 : SQLRETURN ODBC_PUBLIC ODBC_API
4246 : SQLFreeConnect(SQLHDBC hdbc)
4247 : {
4248 1216 : tdsdump_log(TDS_DBG_INFO2, "SQLFreeConnect(%p)\n", hdbc);
4249 1216 : return odbc_SQLFreeConnect(hdbc);
4250 : }
4251 : #endif
4252 :
4253 : static SQLRETURN
4254 1216 : odbc_SQLFreeEnv(SQLHENV henv)
4255 : {
4256 1216 : ODBC_ENTER_HENV;
4257 :
4258 1216 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLFreeEnv(%p)\n",
4259 : henv);
4260 :
4261 1216 : odbc_errs_reset(&env->errs);
4262 1216 : tds_free_context(env->tds_ctx);
4263 1216 : tds_mutex_unlock(&env->mtx);
4264 1216 : tds_mutex_free(&env->mtx);
4265 1216 : free(env);
4266 :
4267 1216 : return SQL_SUCCESS;
4268 : }
4269 :
4270 : SQLRETURN ODBC_PUBLIC ODBC_API
4271 : SQLFreeEnv(SQLHENV henv)
4272 : {
4273 1216 : tdsdump_log(TDS_DBG_FUNC, "SQLFreeEnv(%p)\n", henv);
4274 :
4275 1216 : return odbc_SQLFreeEnv(henv);
4276 : }
4277 :
4278 : static SQLRETURN
4279 20181 : odbc_SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption, int force)
4280 : {
4281 20181 : ODBC_ENTER_HSTMT;
4282 :
4283 20181 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLFreeStmt(%p, %d, %d)\n", hstmt, fOption, force);
4284 :
4285 : /* check if option correct */
4286 20181 : if (fOption != SQL_DROP && fOption != SQL_CLOSE && fOption != SQL_UNBIND && fOption != SQL_RESET_PARAMS) {
4287 0 : tdsdump_log(TDS_DBG_ERROR, "SQLFreeStmt: Unknown option %d\n", fOption);
4288 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
4289 0 : ODBC_EXIT_(stmt);
4290 : }
4291 :
4292 : /* if we have bound columns, free the temporary list */
4293 20181 : if (fOption == SQL_DROP || fOption == SQL_UNBIND) {
4294 18639 : desc_free_records(stmt->ard);
4295 : }
4296 :
4297 : /* do the same for bound parameters */
4298 20181 : if (fOption == SQL_DROP || fOption == SQL_RESET_PARAMS) {
4299 18651 : desc_free_records(stmt->apd);
4300 18651 : desc_free_records(stmt->ipd);
4301 18651 : stmt->params_set = 0;
4302 : }
4303 :
4304 : /* close statement */
4305 20181 : if (fOption == SQL_DROP || fOption == SQL_CLOSE) {
4306 : SQLRETURN retcode;
4307 : TDSSOCKET *tds;
4308 :
4309 18501 : tds = stmt->tds;
4310 : /*
4311 : * FIXME -- otherwise make sure the current statement is complete
4312 : */
4313 : /* do not close other running query ! */
4314 18501 : if (tds && tds->state != TDS_IDLE && tds->state != TDS_DEAD) {
4315 602 : if (TDS_SUCCEED(tds_send_cancel(tds)))
4316 602 : tds_process_cancel(tds);
4317 : }
4318 :
4319 : /* free cursor */
4320 18501 : retcode = odbc_free_cursor(stmt);
4321 18501 : if (!force && retcode != SQL_SUCCESS)
4322 0 : ODBC_EXIT(stmt, retcode);
4323 : }
4324 :
4325 : /* free it */
4326 20181 : if (fOption == SQL_DROP) {
4327 : #if ENABLE_ODBC_MARS
4328 : TDSSOCKET *tds;
4329 : #endif
4330 : SQLRETURN retcode;
4331 :
4332 : /* close prepared statement or add to connection */
4333 17805 : retcode = odbc_free_dynamic(stmt);
4334 17805 : if (!force && retcode != SQL_SUCCESS)
4335 0 : ODBC_EXIT(stmt, retcode);
4336 :
4337 : /* detatch from list */
4338 17805 : tds_mutex_lock(&stmt->dbc->mtx);
4339 17805 : if (stmt->next)
4340 333 : stmt->next->prev = stmt->prev;
4341 17805 : if (stmt->prev)
4342 24 : stmt->prev->next = stmt->next;
4343 17805 : if (stmt->dbc->stmt_list == stmt)
4344 17781 : stmt->dbc->stmt_list = stmt->next;
4345 17805 : tds_mutex_unlock(&stmt->dbc->mtx);
4346 :
4347 17805 : tds_dstr_free(&stmt->query);
4348 17805 : tds_free_param_results(stmt->params);
4349 17805 : odbc_errs_reset(&stmt->errs);
4350 17805 : odbc_unlock_statement(stmt);
4351 : #if ENABLE_ODBC_MARS
4352 8907 : tds = stmt->tds;
4353 8907 : if (tds && tds != stmt->dbc->tds_socket) {
4354 8 : if (tds->state != TDS_IDLE && tds->state != TDS_DEAD)
4355 0 : tdsdump_log(TDS_DBG_WARN, "MARS SID %d was not idle/dead\n", tds->sid);
4356 :
4357 8 : tdsdump_log(TDS_DBG_INFO1, "MARS SID %d socket freeing\n", tds->sid);
4358 8 : tds_free_socket(tds);
4359 8 : stmt->tds = NULL;
4360 : }
4361 : #endif
4362 17805 : tds_dstr_free(&stmt->cursor_name);
4363 17805 : tds_dstr_free(&stmt->attr.qn_msgtext);
4364 17805 : tds_dstr_free(&stmt->attr.qn_options);
4365 17805 : desc_free(stmt->ird);
4366 17805 : desc_free(stmt->ipd);
4367 17805 : desc_free(stmt->orig_ard);
4368 17805 : desc_free(stmt->orig_apd);
4369 17805 : tds_mutex_unlock(&stmt->mtx);
4370 17805 : tds_mutex_free(&stmt->mtx);
4371 17805 : free(stmt);
4372 :
4373 : /* NOTE we freed stmt, do not use ODBC_EXIT */
4374 17805 : return SQL_SUCCESS;
4375 : }
4376 2376 : ODBC_EXIT_(stmt);
4377 : }
4378 :
4379 : SQLRETURN ODBC_PUBLIC ODBC_API
4380 : SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption)
4381 : {
4382 19549 : tdsdump_log(TDS_DBG_FUNC, "SQLFreeStmt(%p, %d)\n", hstmt, fOption);
4383 19549 : return odbc_SQLFreeStmt(hstmt, fOption, 0);
4384 : }
4385 :
4386 :
4387 : SQLRETURN ODBC_PUBLIC ODBC_API
4388 : SQLCloseCursor(SQLHSTMT hstmt)
4389 : {
4390 : /* TODO cursors */
4391 : /*
4392 : * Basic implementation for when no driver manager is present.
4393 : * - according to ODBC documentation SQLCloseCursor is more or less
4394 : * equivalent to SQLFreeStmt(..., SQL_CLOSE).
4395 : * - indeed that is what the DM does if it can't find the function
4396 : * in the driver, so this is pretty close.
4397 : */
4398 : /* TODO remember to close cursors really when get implemented */
4399 : /* TODO read all results and discard them or use cancellation ?? test behaviour */
4400 :
4401 468 : tdsdump_log(TDS_DBG_FUNC, "SQLCloseCursor(%p)\n", hstmt);
4402 468 : return odbc_SQLFreeStmt(hstmt, SQL_CLOSE, 0);
4403 : }
4404 :
4405 : static SQLRETURN
4406 10 : odbc_SQLFreeDesc(SQLHDESC hdesc)
4407 : {
4408 10 : ODBC_ENTER_HDESC;
4409 :
4410 10 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLFreeDesc(%p)\n",
4411 : hdesc);
4412 :
4413 10 : if (desc->header.sql_desc_alloc_type != SQL_DESC_ALLOC_USER) {
4414 0 : odbc_errs_add(&desc->errs, "HY017", NULL);
4415 0 : ODBC_EXIT_(desc);
4416 : }
4417 :
4418 10 : if (IS_HDBC(desc->parent)) {
4419 10 : TDS_DBC *dbc = (TDS_DBC *) desc->parent;
4420 : TDS_STMT *stmt;
4421 : int i;
4422 :
4423 : /* freeing descriptors associated to statements revert state of statements */
4424 10 : tds_mutex_lock(&dbc->mtx);
4425 20 : for (stmt = dbc->stmt_list; stmt != NULL; stmt = stmt->next) {
4426 10 : if (stmt->ard == desc)
4427 0 : stmt->ard = stmt->orig_ard;
4428 10 : if (stmt->apd == desc)
4429 0 : stmt->apd = stmt->orig_apd;
4430 : }
4431 10 : tds_mutex_unlock(&dbc->mtx);
4432 :
4433 20 : for (i = 0; i < TDS_MAX_APP_DESC; ++i) {
4434 20 : if (dbc->uad[i] == desc) {
4435 10 : dbc->uad[i] = NULL;
4436 10 : tds_mutex_unlock(&desc->mtx);
4437 10 : desc_free(desc);
4438 10 : break;
4439 : }
4440 : }
4441 : }
4442 : return SQL_SUCCESS;
4443 : }
4444 :
4445 : static SQLRETURN
4446 1140 : odbc_SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value,
4447 : SQLINTEGER BufferLength, SQLINTEGER * StringLength WIDE)
4448 : {
4449 : static const SQLUINTEGER zero_ui = 0;
4450 : const void *src;
4451 : SQLINTEGER size;
4452 :
4453 1140 : ODBC_ENTER_HSTMT;
4454 :
4455 : /* TODO assign directly, use macro for size */
4456 1140 : switch (Attribute) {
4457 524 : case SQL_ATTR_APP_PARAM_DESC:
4458 524 : size = sizeof(stmt->apd);
4459 524 : src = &stmt->apd;
4460 524 : break;
4461 150 : case SQL_ATTR_APP_ROW_DESC:
4462 150 : size = sizeof(stmt->ard);
4463 150 : src = &stmt->ard;
4464 150 : break;
4465 0 : case SQL_ATTR_ASYNC_ENABLE:
4466 0 : size = sizeof(stmt->attr.async_enable);
4467 0 : src = &stmt->attr.async_enable;
4468 0 : break;
4469 16 : case SQL_ATTR_CONCURRENCY:
4470 16 : size = sizeof(stmt->attr.concurrency);
4471 16 : src = &stmt->attr.concurrency;
4472 16 : break;
4473 16 : case SQL_ATTR_CURSOR_TYPE:
4474 16 : size = sizeof(stmt->attr.cursor_type);
4475 16 : src = &stmt->attr.cursor_type;
4476 16 : break;
4477 0 : case SQL_ATTR_ENABLE_AUTO_IPD:
4478 0 : size = sizeof(stmt->attr.enable_auto_ipd);
4479 0 : src = &stmt->attr.enable_auto_ipd;
4480 0 : break;
4481 0 : case SQL_ATTR_FETCH_BOOKMARK_PTR:
4482 0 : size = sizeof(stmt->attr.fetch_bookmark_ptr);
4483 0 : src = &stmt->attr.fetch_bookmark_ptr;
4484 0 : break;
4485 0 : case SQL_ATTR_KEYSET_SIZE:
4486 0 : size = sizeof(stmt->attr.keyset_size);
4487 0 : src = &stmt->attr.keyset_size;
4488 0 : break;
4489 0 : case SQL_ATTR_MAX_LENGTH:
4490 0 : size = sizeof(stmt->attr.max_length);
4491 0 : src = &stmt->attr.max_length;
4492 0 : break;
4493 0 : case SQL_ATTR_MAX_ROWS:
4494 0 : size = sizeof(stmt->attr.max_rows);
4495 0 : src = &stmt->attr.max_rows;
4496 0 : break;
4497 0 : case SQL_ATTR_METADATA_ID:
4498 0 : size = sizeof(stmt->attr.metadata_id);
4499 0 : src = &stmt->attr.metadata_id;
4500 0 : break;
4501 0 : case SQL_ATTR_NOSCAN:
4502 0 : size = sizeof(stmt->attr.noscan);
4503 0 : src = &stmt->attr.noscan;
4504 0 : break;
4505 0 : case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
4506 0 : size = sizeof(stmt->apd->header.sql_desc_bind_offset_ptr);
4507 0 : src = &stmt->apd->header.sql_desc_bind_offset_ptr;
4508 0 : break;
4509 0 : case SQL_ATTR_PARAM_BIND_TYPE:
4510 0 : size = sizeof(stmt->apd->header.sql_desc_bind_type);
4511 0 : src = &stmt->apd->header.sql_desc_bind_type;
4512 0 : break;
4513 0 : case SQL_ATTR_PARAM_OPERATION_PTR:
4514 0 : size = sizeof(stmt->apd->header.sql_desc_array_status_ptr);
4515 0 : src = &stmt->apd->header.sql_desc_array_status_ptr;
4516 0 : break;
4517 0 : case SQL_ATTR_PARAM_STATUS_PTR:
4518 0 : size = sizeof(stmt->ipd->header.sql_desc_array_status_ptr);
4519 0 : src = &stmt->ipd->header.sql_desc_array_status_ptr;
4520 0 : break;
4521 60 : case SQL_ATTR_PARAMS_PROCESSED_PTR:
4522 60 : size = sizeof(stmt->ipd->header.sql_desc_rows_processed_ptr);
4523 60 : src = &stmt->ipd->header.sql_desc_rows_processed_ptr;
4524 60 : break;
4525 0 : case SQL_ATTR_PARAMSET_SIZE:
4526 0 : size = sizeof(stmt->apd->header.sql_desc_array_size);
4527 0 : src = &stmt->apd->header.sql_desc_array_size;
4528 0 : break;
4529 32 : case SQL_ATTR_QUERY_TIMEOUT:
4530 32 : size = sizeof(stmt->attr.query_timeout);
4531 32 : src = (stmt->attr.query_timeout != DEFAULT_QUERY_TIMEOUT) ? &stmt->attr.query_timeout : &zero_ui;
4532 : break;
4533 0 : case SQL_ATTR_RETRIEVE_DATA:
4534 0 : size = sizeof(stmt->attr.retrieve_data);
4535 0 : src = &stmt->attr.retrieve_data;
4536 0 : break;
4537 0 : case SQL_ATTR_ROW_BIND_OFFSET_PTR:
4538 0 : size = sizeof(stmt->ard->header.sql_desc_bind_offset_ptr);
4539 0 : src = &stmt->ard->header.sql_desc_bind_offset_ptr;
4540 0 : break;
4541 : #if SQL_BIND_TYPE != SQL_ATTR_ROW_BIND_TYPE
4542 : case SQL_BIND_TYPE: /* although this is ODBC2 we must support this attribute */
4543 : #endif
4544 0 : case SQL_ATTR_ROW_BIND_TYPE:
4545 0 : size = sizeof(stmt->ard->header.sql_desc_bind_type);
4546 0 : src = &stmt->ard->header.sql_desc_bind_type;
4547 0 : break;
4548 24 : case SQL_ATTR_ROW_NUMBER:
4549 : /* TODO do not get info every time, cache somewhere */
4550 24 : if (stmt->cursor && odbc_lock_statement(stmt)) {
4551 : TDS_UINT row_number, row_count;
4552 :
4553 24 : tds_cursor_get_cursor_info(stmt->tds, stmt->cursor, &row_number, &row_count);
4554 24 : stmt->attr.row_number = row_number;
4555 : }
4556 24 : size = sizeof(stmt->attr.row_number);
4557 24 : src = &stmt->attr.row_number;
4558 24 : break;
4559 0 : case SQL_ATTR_ROW_OPERATION_PTR:
4560 0 : size = sizeof(stmt->ard->header.sql_desc_array_status_ptr);
4561 0 : src = &stmt->ard->header.sql_desc_array_status_ptr;
4562 0 : break;
4563 0 : case SQL_ATTR_ROW_STATUS_PTR:
4564 0 : size = sizeof(stmt->ird->header.sql_desc_array_status_ptr);
4565 0 : src = &stmt->ird->header.sql_desc_array_status_ptr;
4566 0 : break;
4567 50 : case SQL_ATTR_ROWS_FETCHED_PTR:
4568 50 : size = sizeof(stmt->ird->header.sql_desc_rows_processed_ptr);
4569 50 : src = &stmt->ird->header.sql_desc_rows_processed_ptr;
4570 50 : break;
4571 0 : case SQL_ATTR_ROW_ARRAY_SIZE:
4572 0 : size = sizeof(stmt->ard->header.sql_desc_array_size);
4573 0 : src = &stmt->ard->header.sql_desc_array_size;
4574 0 : break;
4575 0 : case SQL_ATTR_SIMULATE_CURSOR:
4576 0 : size = sizeof(stmt->attr.simulate_cursor);
4577 0 : src = &stmt->attr.simulate_cursor;
4578 0 : break;
4579 0 : case SQL_ATTR_USE_BOOKMARKS:
4580 0 : size = sizeof(stmt->attr.use_bookmarks);
4581 0 : src = &stmt->attr.use_bookmarks;
4582 0 : break;
4583 16 : case SQL_ATTR_CURSOR_SCROLLABLE:
4584 16 : size = sizeof(stmt->attr.cursor_scrollable);
4585 16 : src = &stmt->attr.cursor_scrollable;
4586 16 : break;
4587 16 : case SQL_ATTR_CURSOR_SENSITIVITY:
4588 16 : size = sizeof(stmt->attr.cursor_sensitivity);
4589 16 : src = &stmt->attr.cursor_sensitivity;
4590 16 : break;
4591 90 : case SQL_ATTR_IMP_ROW_DESC:
4592 90 : size = sizeof(stmt->ird);
4593 90 : src = &stmt->ird;
4594 90 : break;
4595 136 : case SQL_ATTR_IMP_PARAM_DESC:
4596 136 : size = sizeof(stmt->ipd);
4597 136 : src = &stmt->ipd;
4598 136 : break;
4599 10 : case SQL_ROWSET_SIZE: /* although this is ODBC2 we must support this attribute */
4600 10 : size = sizeof(stmt->sql_rowset_size);
4601 10 : src = &stmt->sql_rowset_size;
4602 10 : break;
4603 0 : case SQL_SOPT_SS_QUERYNOTIFICATION_TIMEOUT:
4604 0 : size = sizeof(stmt->attr.qn_timeout);
4605 0 : src = &stmt->attr.qn_timeout;
4606 0 : break;
4607 0 : case SQL_SOPT_SS_QUERYNOTIFICATION_MSGTEXT:
4608 : {
4609 0 : SQLRETURN rc = odbc_set_dstr_oct(stmt->dbc, Value, BufferLength, StringLength, &stmt->attr.qn_msgtext);
4610 0 : ODBC_EXIT(stmt, rc);
4611 : }
4612 0 : case SQL_SOPT_SS_QUERYNOTIFICATION_OPTIONS:
4613 : {
4614 0 : SQLRETURN rc = odbc_set_dstr_oct(stmt->dbc, Value, BufferLength, StringLength, &stmt->attr.qn_options);
4615 0 : ODBC_EXIT(stmt, rc);
4616 : }
4617 : /* TODO SQL_COLUMN_SEARCHABLE, although ODBC2 */
4618 0 : default:
4619 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
4620 0 : ODBC_EXIT_(stmt);
4621 : }
4622 :
4623 1140 : memcpy(Value, src, size);
4624 1140 : if (StringLength)
4625 978 : *StringLength = size;
4626 :
4627 1140 : ODBC_EXIT_(stmt);
4628 : }
4629 :
4630 : #if (ODBCVER >= 0x0300)
4631 : SQLRETURN ODBC_PUBLIC ODBC_API
4632 : SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
4633 : {
4634 570 : tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtAttr(%p, %d, %p, %d, %p)\n",
4635 : hstmt, (int)Attribute, Value, (int)BufferLength, StringLength);
4636 :
4637 570 : return odbc_SQLGetStmtAttr(hstmt, Attribute, Value, BufferLength, StringLength _wide0);
4638 : }
4639 :
4640 : #ifdef ENABLE_ODBC_WIDE
4641 : SQLRETURN ODBC_PUBLIC ODBC_API
4642 : SQLGetStmtAttrW(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
4643 : {
4644 570 : tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtAttr(%p, %d, %p, %d, %p)\n",
4645 : hstmt, (int)Attribute, Value, (int)BufferLength, StringLength);
4646 :
4647 570 : return odbc_SQLGetStmtAttr(hstmt, Attribute, Value, BufferLength, StringLength, 1);
4648 : }
4649 : #endif
4650 : #endif
4651 :
4652 : SQLRETURN ODBC_PUBLIC ODBC_API
4653 : SQLGetStmtOption(SQLHSTMT hstmt, SQLUSMALLINT fOption, SQLPOINTER pvParam)
4654 : {
4655 0 : tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtOption(%p, %d, %p)\n",
4656 : hstmt, fOption, pvParam);
4657 :
4658 0 : return odbc_SQLGetStmtAttr(hstmt, (SQLINTEGER) fOption, pvParam, SQL_MAX_OPTION_STRING_LENGTH, NULL _wide0);
4659 : }
4660 :
4661 : SQLRETURN ODBC_PUBLIC ODBC_API
4662 : SQLNumResultCols(SQLHSTMT hstmt, SQLSMALLINT FAR * pccol)
4663 : {
4664 838 : ODBC_ENTER_HSTMT;
4665 :
4666 838 : tdsdump_log(TDS_DBG_FUNC, "SQLNumResultCols(%p, %p)\n",
4667 : hstmt, pccol);
4668 :
4669 : /*
4670 : * 3/15/2001 bsb - DBD::ODBC calls SQLNumResultCols on non-result
4671 : * generating queries such as 'drop table'
4672 : */
4673 : #if 0
4674 : if (stmt->row_status == NOT_IN_ROW) {
4675 : odbc_errs_add(&stmt->errs, "24000", NULL);
4676 : ODBC_EXIT_(stmt);
4677 : }
4678 : #endif
4679 838 : IRD_UPDATE(stmt->ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
4680 814 : *pccol = stmt->ird->header.sql_desc_count;
4681 814 : ODBC_EXIT_(stmt);
4682 : }
4683 :
4684 4167 : ODBC_FUNC(SQLPrepare, (P(SQLHSTMT,hstmt), PCHARIN(SqlStr,SQLINTEGER) WIDE))
4685 : {
4686 : SQLRETURN retcode;
4687 :
4688 4167 : ODBC_ENTER_HSTMT;
4689 :
4690 : /* try to free dynamic associated */
4691 4167 : retcode = odbc_free_dynamic(stmt);
4692 4167 : if (retcode != SQL_SUCCESS)
4693 0 : ODBC_EXIT(stmt, retcode);
4694 :
4695 4167 : if (SQL_SUCCESS != odbc_set_stmt_query(stmt, szSqlStr, cbSqlStr _wide))
4696 0 : ODBC_EXIT(stmt, SQL_ERROR);
4697 4167 : stmt->is_prepared_query = 1;
4698 :
4699 : /* count parameters */
4700 8334 : stmt->param_count = tds_count_placeholders(tds_dstr_cstr(&stmt->query));
4701 :
4702 : /* reset IPD and APD */
4703 4167 : if (!stmt->params_set) {
4704 2249 : desc_alloc_records(stmt->ipd, 0);
4705 2249 : desc_alloc_records(stmt->apd, 0);
4706 : }
4707 :
4708 : /* trasform to native (one time, not for every SQLExecute) */
4709 4167 : if (SQL_SUCCESS != prepare_call(stmt))
4710 0 : ODBC_EXIT(stmt, SQL_ERROR);
4711 :
4712 : /* TODO needed ?? */
4713 4167 : tds_release_dynamic(&stmt->dyn);
4714 :
4715 : /* try to prepare query */
4716 : /* TODO support getting info for RPC */
4717 4167 : if (!stmt->prepared_query_is_rpc
4718 3519 : && (stmt->attr.cursor_type == SQL_CURSOR_FORWARD_ONLY && stmt->attr.concurrency == SQL_CONCUR_READ_ONLY)) {
4719 :
4720 2211 : tds_free_param_results(stmt->params);
4721 2211 : stmt->params = NULL;
4722 2211 : stmt->param_num = 0;
4723 2211 : stmt->need_reprepare = 0;
4724 : /*
4725 : * using TDS7+ we need parameters to prepare a query so try
4726 : * to get them
4727 : * TDS5 do not need parameters type and we have always to
4728 : * prepare sepatately so this is not an issue
4729 : */
4730 2211 : if (IS_TDS7_PLUS(stmt->dbc->tds_socket->conn)) {
4731 1901 : stmt->need_reprepare = 1;
4732 1901 : ODBC_EXIT_(stmt);
4733 : }
4734 :
4735 310 : tdsdump_log(TDS_DBG_INFO1, "Creating prepared statement\n");
4736 310 : if (odbc_lock_statement(stmt))
4737 310 : odbc_prepare(stmt);
4738 : }
4739 :
4740 2266 : ODBC_EXIT_(stmt);
4741 : }
4742 :
4743 : /* TDS_NO_COUNT must be -1 for SQLRowCount to return -1 when there is no rowcount */
4744 : #if TDS_NO_COUNT != -1
4745 : # error TDS_NO_COUNT != -1
4746 : #endif
4747 :
4748 : SQLRETURN
4749 736 : odbc_SQLRowCount(SQLHSTMT hstmt, SQLLEN FAR * pcrow)
4750 : {
4751 736 : ODBC_ENTER_HSTMT;
4752 :
4753 736 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLRowCount(%p, %p), %ld rows \n", hstmt, pcrow, (long)stmt->row_count);
4754 :
4755 736 : *pcrow = stmt->row_count;
4756 :
4757 736 : ODBC_EXIT_(stmt);
4758 : }
4759 :
4760 : SQLRETURN ODBC_PUBLIC ODBC_API
4761 : SQLRowCount(SQLHSTMT hstmt, SQLLEN FAR * pcrow)
4762 : {
4763 736 : SQLRETURN rc = odbc_SQLRowCount(hstmt, pcrow);
4764 736 : tdsdump_log(TDS_DBG_INFO1, "SQLRowCount returns %d, row count %ld\n", rc, (long int) *pcrow);
4765 736 : return rc;
4766 : }
4767 :
4768 104 : ODBC_FUNC(SQLSetCursorName, (P(SQLHSTMT,hstmt), PCHARIN(Cursor,SQLSMALLINT) WIDE))
4769 : {
4770 104 : ODBC_ENTER_HSTMT;
4771 :
4772 : /* cursor already present, we cannot set name */
4773 104 : if (stmt->cursor) {
4774 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
4775 0 : ODBC_EXIT_(stmt);
4776 : }
4777 :
4778 104 : if (!odbc_dstr_copy(stmt->dbc, &stmt->cursor_name, cbCursor, szCursor)) {
4779 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
4780 0 : ODBC_EXIT_(stmt);
4781 : }
4782 104 : ODBC_EXIT_(stmt);
4783 : }
4784 :
4785 0 : ODBC_FUNC(SQLGetCursorName, (P(SQLHSTMT,hstmt), PCHAROUT(Cursor,SQLSMALLINT) WIDE))
4786 : {
4787 : SQLRETURN rc;
4788 :
4789 0 : ODBC_ENTER_HSTMT;
4790 :
4791 0 : if ((rc = odbc_set_dstr(stmt->dbc, szCursor, cbCursorMax, pcbCursor, &stmt->cursor_name)))
4792 0 : odbc_errs_add(&stmt->errs, "01004", NULL);
4793 :
4794 0 : ODBC_EXIT(stmt, rc);
4795 : }
4796 :
4797 : /*
4798 : * spinellia@acm.org : copied shamelessly from change_database
4799 : * transaction support
4800 : * 1 = commit, 0 = rollback
4801 : */
4802 : static SQLRETURN
4803 760 : change_transaction(TDS_DBC * dbc, int state)
4804 : {
4805 760 : TDSSOCKET *tds = dbc->tds_socket;
4806 : int cont;
4807 : TDSRET ret;
4808 :
4809 760 : tdsdump_log(TDS_DBG_INFO1, "change_transaction(0x%p,%d)\n", dbc, state);
4810 760 : tds_mutex_check_owned(&dbc->mtx);
4811 :
4812 760 : if (dbc->attr.autocommit == SQL_AUTOCOMMIT_ON)
4813 : return SQL_SUCCESS;
4814 740 : cont = 1;
4815 :
4816 : /* if pending drop all recordset, don't issue cancel */
4817 740 : if (tds->state == TDS_PENDING && dbc->current_statement != NULL) {
4818 : /* TODO what happen on multiple errors ?? discard all ?? */
4819 20 : if (TDS_FAILED(tds_process_simple_query(tds)))
4820 : return SQL_ERROR;
4821 : }
4822 :
4823 : /* TODO better idle check, not thread safe */
4824 740 : if (tds->state == TDS_IDLE)
4825 740 : tds->query_timeout = dbc->default_query_timeout;
4826 :
4827 : /* reset statement so errors will be reported on connection.
4828 : * Note that we own the connection lock */
4829 740 : if (dbc->current_statement) {
4830 498 : dbc->current_statement->tds = NULL;
4831 498 : dbc->current_statement = NULL;
4832 : }
4833 740 : tds_set_parent(tds, dbc);
4834 :
4835 740 : if (state)
4836 282 : ret = tds_submit_commit(tds, cont);
4837 : else
4838 458 : ret = tds_submit_rollback(tds, cont);
4839 :
4840 740 : if (TDS_FAILED(ret)) {
4841 10 : odbc_errs_add(&dbc->errs, "HY000", "Could not perform COMMIT or ROLLBACK");
4842 10 : return SQL_ERROR;
4843 : }
4844 :
4845 730 : if (TDS_FAILED(tds_process_simple_query(tds)))
4846 : return SQL_ERROR;
4847 :
4848 : /* TODO some query can collect errors so perhaps it's better to return SUCCES_WITH_INFO in such case... */
4849 730 : return SQL_SUCCESS;
4850 : }
4851 :
4852 : static SQLRETURN
4853 760 : odbc_SQLTransact(SQLHENV henv, SQLHDBC hdbc, SQLUSMALLINT fType)
4854 : {
4855 760 : int op = (fType == SQL_COMMIT ? 1 : 0);
4856 :
4857 : /* I may live without a HENV */
4858 : /* CHECK_HENV; */
4859 : /* ..but not without a HDBC! */
4860 760 : ODBC_ENTER_HDBC;
4861 :
4862 760 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLTransact(%p, %p, %d)\n",
4863 : henv, hdbc, fType);
4864 :
4865 760 : ODBC_EXIT(dbc, change_transaction(dbc, op));
4866 : }
4867 :
4868 : SQLRETURN ODBC_PUBLIC ODBC_API
4869 : SQLTransact(SQLHENV henv, SQLHDBC hdbc, SQLUSMALLINT fType)
4870 : {
4871 0 : tdsdump_log(TDS_DBG_FUNC, "SQLTransact(%p, %p, %d)\n", henv, hdbc, fType);
4872 :
4873 0 : return odbc_SQLTransact(henv, hdbc, fType);
4874 : }
4875 :
4876 : #if ODBCVER >= 0x300
4877 : SQLRETURN ODBC_PUBLIC ODBC_API
4878 : SQLEndTran(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT completionType)
4879 : {
4880 : /*
4881 : * Do not call the exported SQLTransact(),
4882 : * because we may wind up calling a function with the same name implemented by the DM.
4883 : */
4884 760 : tdsdump_log(TDS_DBG_FUNC, "SQLEndTran(%d, %p, %d)\n", handleType, handle, completionType);
4885 :
4886 760 : switch (handleType) {
4887 0 : case SQL_HANDLE_ENV:
4888 0 : return odbc_SQLTransact(handle, NULL, completionType);
4889 760 : case SQL_HANDLE_DBC:
4890 760 : return odbc_SQLTransact(NULL, handle, completionType);
4891 : }
4892 : return SQL_ERROR;
4893 : }
4894 : #endif
4895 :
4896 : /* end of transaction support */
4897 :
4898 : SQLRETURN ODBC_PUBLIC ODBC_API
4899 : SQLSetParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLULEN cbParamDef,
4900 : SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN FAR * pcbValue)
4901 : {
4902 0 : tdsdump_log(TDS_DBG_FUNC, "SQLSetParam(%p, %d, %d, %d, %u, %d, %p, %p)\n",
4903 : hstmt, ipar, fCType, fSqlType, (unsigned)cbParamDef, ibScale, rgbValue, pcbValue);
4904 :
4905 0 : return odbc_SQLBindParameter(hstmt, ipar, SQL_PARAM_INPUT_OUTPUT, fCType, fSqlType, cbParamDef, ibScale, rgbValue,
4906 : SQL_SETPARAM_VALUE_MAX, pcbValue);
4907 : }
4908 :
4909 78 : ODBC_FUNC(SQLGetConnectAttr, (P(SQLHDBC, hdbc), P(SQLINTEGER, Attribute), P(SQLPOINTER, Value), P(SQLINTEGER, BufferLength),
4910 : P(SQLINTEGER *, StringLength) WIDE))
4911 : {
4912 78 : const char *p = NULL;
4913 :
4914 78 : ODBC_ENTER_HDBC;
4915 :
4916 78 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLGetConnectAttr(%p, %d, %p, %d, %p)\n",
4917 : hdbc, (int)Attribute, Value, (int)BufferLength, StringLength);
4918 :
4919 78 : switch (Attribute) {
4920 0 : case SQL_ATTR_AUTOCOMMIT:
4921 0 : *((SQLUINTEGER *) Value) = dbc->attr.autocommit;
4922 : break;
4923 : #if defined(SQL_ATTR_CONNECTION_DEAD) && defined(SQL_CD_TRUE)
4924 0 : case SQL_ATTR_CONNECTION_DEAD:
4925 0 : *((SQLUINTEGER *) Value) = IS_TDSDEAD(dbc->tds_socket) ? SQL_CD_TRUE : SQL_CD_FALSE;
4926 : break;
4927 : #endif
4928 0 : case SQL_ATTR_CONNECTION_TIMEOUT:
4929 0 : *((SQLUINTEGER *) Value) = dbc->attr.connection_timeout;
4930 : break;
4931 0 : case SQL_ATTR_ACCESS_MODE:
4932 0 : *((SQLUINTEGER *) Value) = dbc->attr.access_mode;
4933 : break;
4934 68 : case SQL_ATTR_CURRENT_CATALOG:
4935 136 : p = tds_dstr_cstr(&dbc->attr.current_catalog);
4936 68 : break;
4937 0 : case SQL_ATTR_LOGIN_TIMEOUT:
4938 0 : *((SQLUINTEGER *) Value) = dbc->attr.login_timeout;
4939 : break;
4940 0 : case SQL_ATTR_ODBC_CURSORS:
4941 0 : *((SQLUINTEGER *) Value) = dbc->attr.odbc_cursors;
4942 : break;
4943 0 : case SQL_ATTR_PACKET_SIZE:
4944 0 : *((SQLUINTEGER *) Value) = dbc->attr.packet_size;
4945 : break;
4946 0 : case SQL_ATTR_QUIET_MODE:
4947 0 : *((SQLHWND *) Value) = dbc->attr.quite_mode;
4948 : break;
4949 : #ifdef TDS_NO_DM
4950 0 : case SQL_ATTR_TRACE:
4951 0 : *((SQLUINTEGER *) Value) = dbc->attr.trace;
4952 : break;
4953 0 : case SQL_ATTR_TRACEFILE:
4954 0 : p = tds_dstr_cstr(&dbc->attr.tracefile);
4955 0 : break;
4956 : #endif
4957 0 : case SQL_ATTR_TXN_ISOLATION:
4958 0 : *((SQLUINTEGER *) Value) = dbc->attr.txn_isolation;
4959 : break;
4960 10 : case SQL_COPT_SS_MARS_ENABLED:
4961 10 : *((SQLUINTEGER *) Value) = dbc->attr.mars_enabled;
4962 : break;
4963 0 : case SQL_ATTR_TRANSLATE_LIB:
4964 : case SQL_ATTR_TRANSLATE_OPTION:
4965 0 : odbc_errs_add(&dbc->errs, "HYC00", NULL);
4966 : break;
4967 0 : case SQL_COPT_SS_BCP:
4968 0 : *((SQLUINTEGER *) Value) = dbc->attr.bulk_enabled;
4969 : break;
4970 0 : default:
4971 0 : odbc_errs_add(&dbc->errs, "HY092", NULL);
4972 : break;
4973 : }
4974 :
4975 68 : if (p) {
4976 68 : SQLRETURN rc = odbc_set_string_oct(dbc, Value, BufferLength, StringLength, p, -1);
4977 68 : ODBC_EXIT(dbc, rc);
4978 : }
4979 10 : ODBC_EXIT_(dbc);
4980 : }
4981 :
4982 : SQLRETURN ODBC_PUBLIC ODBC_API
4983 : SQLGetConnectOption(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLPOINTER pvParam)
4984 : {
4985 0 : tdsdump_log(TDS_DBG_FUNC, "SQLGetConnectOption(%p, %u, %p)\n", hdbc, fOption, pvParam);
4986 :
4987 0 : return odbc_SQLGetConnectAttr(hdbc, (SQLINTEGER) fOption, pvParam, SQL_MAX_OPTION_STRING_LENGTH, NULL _wide0);
4988 : }
4989 :
4990 : #ifdef ENABLE_ODBC_WIDE
4991 : SQLRETURN ODBC_PUBLIC ODBC_API
4992 : SQLGetConnectOptionW(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLPOINTER pvParam)
4993 : {
4994 0 : tdsdump_log(TDS_DBG_FUNC, "SQLGetConnectOptionW(%p, %u, %p)\n", hdbc, fOption, pvParam);
4995 :
4996 0 : return odbc_SQLGetConnectAttr(hdbc, (SQLINTEGER) fOption, pvParam, SQL_MAX_OPTION_STRING_LENGTH, NULL, 1);
4997 : }
4998 : #endif
4999 :
5000 : SQLRETURN ODBC_PUBLIC ODBC_API
5001 : SQLGetData(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
5002 : {
5003 : /* TODO cursors fetch row if needed ?? */
5004 : TDSCOLUMN *colinfo;
5005 : TDSRESULTINFO *resinfo;
5006 : SQLLEN dummy_cb;
5007 :
5008 10536 : ODBC_ENTER_HSTMT;
5009 :
5010 10536 : tdsdump_log(TDS_DBG_FUNC, "SQLGetData(%p, %u, %d, %p, %d, %p)\n",
5011 : hstmt, icol, fCType, rgbValue, (int)cbValueMax, pcbValue);
5012 :
5013 10536 : if (cbValueMax < 0) {
5014 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
5015 0 : ODBC_EXIT_(stmt);
5016 : }
5017 :
5018 : /* read data from TDS only if current statement */
5019 10536 : if ((stmt->cursor == NULL && !stmt->tds)
5020 10464 : || stmt->row_status == PRE_NORMAL_ROW
5021 10132 : || stmt->row_status == NOT_IN_ROW)
5022 : {
5023 404 : odbc_errs_add(&stmt->errs, "24000", NULL);
5024 404 : ODBC_EXIT_(stmt);
5025 : }
5026 :
5027 10132 : IRD_CHECK;
5028 :
5029 10132 : if (!pcbValue)
5030 376 : pcbValue = &dummy_cb;
5031 :
5032 10132 : resinfo = stmt->cursor ? stmt->cursor->res_info : stmt->tds->current_results;
5033 10132 : if (!resinfo) {
5034 0 : odbc_errs_add(&stmt->errs, "HY010", NULL);
5035 0 : ODBC_EXIT_(stmt);
5036 : }
5037 10132 : if (icol <= 0 || icol > resinfo->num_cols) {
5038 0 : odbc_errs_add(&stmt->errs, "07009", "Column out of range");
5039 0 : ODBC_EXIT_(stmt);
5040 : }
5041 10132 : colinfo = resinfo->columns[icol - 1];
5042 :
5043 10132 : if (colinfo->column_cur_size < 0) {
5044 : /* TODO check what should happen if pcbValue was NULL */
5045 348 : *pcbValue = SQL_NULL_DATA;
5046 : } else {
5047 9784 : if (colinfo->column_text_sqlgetdatapos > 0
5048 2238 : && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size
5049 522 : && colinfo->column_iconv_left == 0)
5050 : /* TODO check if SQL_SUCCESS instead !! */
5051 460 : ODBC_EXIT(stmt, SQL_NO_DATA);
5052 :
5053 9324 : if (!is_variable_type(colinfo->column_type)) {
5054 580 : colinfo->column_text_sqlgetdatapos = 0;
5055 580 : colinfo->column_iconv_left = 0;
5056 : }
5057 :
5058 9324 : if (fCType == SQL_C_DEFAULT)
5059 0 : fCType = odbc_sql_to_c_type_default(stmt->ird->records[icol - 1].sql_desc_concise_type);
5060 9324 : if (fCType == SQL_ARD_TYPE) {
5061 10 : if (icol > stmt->ard->header.sql_desc_count) {
5062 10 : odbc_errs_add(&stmt->errs, "07009", NULL);
5063 10 : ODBC_EXIT_(stmt);
5064 : }
5065 0 : fCType = stmt->ard->records[icol - 1].sql_desc_concise_type;
5066 : }
5067 9314 : assert(fCType);
5068 :
5069 9314 : *pcbValue = odbc_tds2sql_col(stmt, colinfo, fCType, (TDS_CHAR *) rgbValue, cbValueMax, NULL);
5070 9314 : if (*pcbValue == SQL_NULL_DATA)
5071 40 : ODBC_EXIT(stmt, SQL_ERROR);
5072 :
5073 9274 : if (is_variable_type(colinfo->column_type)
5074 8694 : && (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR || fCType == SQL_C_BINARY)) {
5075 : /* avoid infinite SQL_SUCCESS on empty strings */
5076 8694 : if (colinfo->column_text_sqlgetdatapos == 0 && cbValueMax > 0)
5077 44 : ++colinfo->column_text_sqlgetdatapos;
5078 :
5079 8694 : if (colinfo->column_text_sqlgetdatapos < colinfo->column_cur_size || colinfo->column_iconv_left != 0) {
5080 : /* not all read ?? */
5081 1850 : odbc_errs_add(&stmt->errs, "01004", "String data, right truncated");
5082 1850 : ODBC_EXIT_(stmt);
5083 : }
5084 : } else {
5085 580 : int nSybType = tds_get_conversion_type(colinfo->on_server.column_type, colinfo->on_server.column_size);
5086 580 : colinfo->column_text_sqlgetdatapos = colinfo->column_cur_size;
5087 580 : if (is_fixed_type(nSybType) && (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR || fCType == SQL_C_BINARY)
5088 430 : && cbValueMax < *pcbValue) {
5089 18 : odbc_errs_add(&stmt->errs, "22003", NULL);
5090 18 : ODBC_EXIT_(stmt);
5091 : }
5092 : }
5093 : }
5094 7754 : ODBC_EXIT_(stmt);
5095 : }
5096 :
5097 : static SQLRETURN
5098 618 : odbc_SQLParamData(SQLHSTMT hstmt, SQLPOINTER FAR *prgbValue)
5099 : {
5100 618 : ODBC_ENTER_HSTMT;
5101 :
5102 618 : tdsdump_log(TDS_DBG_FUNC, "SQLParamData(%p, %p) [param_num %d, param_data_called = %d]\n",
5103 : hstmt, prgbValue, stmt->param_num, stmt->param_data_called);
5104 :
5105 618 : if (stmt->params && (unsigned int) stmt->param_num <= stmt->param_count) {
5106 : SQLRETURN res;
5107 :
5108 526 : if (stmt->param_num <= 0 || stmt->param_num > stmt->apd->header.sql_desc_count) {
5109 0 : tdsdump_log(TDS_DBG_FUNC, "SQLParamData: logic_error: parameter out of bounds: 0 <= %d < %d\n",
5110 : stmt->param_num, stmt->apd->header.sql_desc_count);
5111 0 : ODBC_EXIT(stmt, SQL_ERROR);
5112 : }
5113 :
5114 : /*
5115 : * TODO compute output value with this formula:
5116 : * Bound Address + Binding Offset + ((Row Number - 1) x Element Size)
5117 : * (see SQLParamData documentation)
5118 : * This is needed for updates using SQLBulkOperation (not currently supported)
5119 : */
5120 526 : if (!stmt->param_data_called) {
5121 194 : stmt->param_data_called = 1;
5122 194 : *prgbValue = stmt->apd->records[stmt->param_num - 1].sql_desc_data_ptr;
5123 194 : ODBC_EXIT(stmt, SQL_NEED_DATA);
5124 : }
5125 332 : ++stmt->param_num;
5126 332 : switch (res = parse_prepared_query(stmt, true)) {
5127 148 : case SQL_NEED_DATA:
5128 148 : *prgbValue = stmt->apd->records[stmt->param_num - 1].sql_desc_data_ptr;
5129 148 : ODBC_EXIT(stmt, SQL_NEED_DATA);
5130 184 : case SQL_SUCCESS:
5131 184 : ODBC_EXIT(stmt, odbc_SQLExecute(stmt));
5132 : }
5133 0 : ODBC_EXIT(stmt, res);
5134 : }
5135 :
5136 92 : odbc_errs_add(&stmt->errs, "HY010", NULL);
5137 92 : ODBC_EXIT_(stmt);
5138 : }
5139 :
5140 : SQLRETURN ODBC_PUBLIC ODBC_API
5141 : SQLParamData(SQLHSTMT hstmt, SQLPOINTER FAR * prgbValue)
5142 : {
5143 : ODBC_PRRET_BUF;
5144 618 : SQLRETURN ret = odbc_SQLParamData(hstmt, prgbValue);
5145 :
5146 618 : tdsdump_log(TDS_DBG_FUNC, "SQLParamData returns %s\n", odbc_prret(ret));
5147 :
5148 618 : return ret;
5149 : }
5150 :
5151 : SQLRETURN ODBC_PUBLIC ODBC_API
5152 : SQLPutData(SQLHSTMT hstmt, SQLPOINTER rgbValue, SQLLEN cbValue)
5153 : {
5154 : ODBC_PRRET_BUF;
5155 852 : ODBC_ENTER_HSTMT;
5156 :
5157 852 : tdsdump_log(TDS_DBG_FUNC, "SQLPutData(%p, %p, %i)\n", hstmt, rgbValue, (int)cbValue);
5158 :
5159 852 : if (stmt->param_data_called) {
5160 : SQLRETURN ret;
5161 852 : const TDSCOLUMN *curcol = stmt->params->columns[stmt->param_num - (stmt->prepared_query_is_func ? 2 : 1)];
5162 : /* TODO do some more tests before setting this flag */
5163 852 : stmt->param_data_called = 1;
5164 852 : ret = continue_parse_prepared_query(stmt, rgbValue, cbValue);
5165 852 : tdsdump_log(TDS_DBG_FUNC, "SQLPutData returns %s, %d bytes left\n",
5166 : odbc_prret(ret), curcol->column_size - curcol->column_cur_size);
5167 852 : ODBC_EXIT(stmt, ret);
5168 : }
5169 :
5170 0 : odbc_errs_add(&stmt->errs, "HY010", NULL);
5171 0 : ODBC_EXIT_(stmt);
5172 : }
5173 :
5174 :
5175 1906 : ODBC_FUNC(SQLSetConnectAttr, (P(SQLHDBC,hdbc), P(SQLINTEGER,Attribute), P(SQLPOINTER,ValuePtr), P(SQLINTEGER,StringLength) WIDE))
5176 : {
5177 1906 : SQLULEN u_value = (SQLULEN) (TDS_INTPTR) ValuePtr;
5178 :
5179 1906 : ODBC_ENTER_HDBC;
5180 :
5181 1906 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLSetConnectAttr(%p, %d, %p, %d)\n", hdbc, (int)Attribute, ValuePtr, (int)StringLength);
5182 :
5183 1906 : switch (Attribute) {
5184 218 : case SQL_ATTR_AUTOCOMMIT:
5185 : /* spinellia@acm.org */
5186 218 : change_autocommit(dbc, (int) u_value);
5187 218 : break;
5188 10 : case SQL_ATTR_CONNECTION_TIMEOUT:
5189 10 : dbc->attr.connection_timeout = (SQLUINTEGER) u_value;
5190 10 : break;
5191 0 : case SQL_ATTR_ACCESS_MODE:
5192 0 : dbc->attr.access_mode = (SQLUINTEGER) u_value;
5193 0 : break;
5194 80 : case SQL_ATTR_CURRENT_CATALOG:
5195 80 : if (!IS_VALID_LEN(StringLength)) {
5196 0 : odbc_errs_add(&dbc->errs, "HY090", NULL);
5197 0 : break;
5198 : }
5199 : {
5200 80 : DSTR s = DSTR_INITIALIZER;
5201 :
5202 80 : if (!odbc_dstr_copy_oct(dbc, &s, StringLength, (ODBC_CHAR*) ValuePtr)) {
5203 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
5204 0 : break;
5205 : }
5206 240 : change_database(dbc, tds_dstr_cstr(&s), tds_dstr_len(&s));
5207 80 : tds_dstr_free(&s);
5208 : }
5209 80 : break;
5210 0 : case SQL_ATTR_CURSOR_TYPE:
5211 0 : if (dbc->cursor_support)
5212 0 : dbc->attr.cursor_type = (SQLUINTEGER) u_value;
5213 : break;
5214 10 : case SQL_ATTR_LOGIN_TIMEOUT:
5215 10 : dbc->attr.login_timeout = (SQLUINTEGER) u_value;
5216 10 : break;
5217 0 : case SQL_ATTR_ODBC_CURSORS:
5218 : /* TODO cursors */
5219 0 : dbc->attr.odbc_cursors = (SQLUINTEGER) u_value;
5220 0 : break;
5221 0 : case SQL_ATTR_PACKET_SIZE:
5222 0 : dbc->attr.packet_size = (SQLUINTEGER) u_value;
5223 0 : break;
5224 0 : case SQL_ATTR_QUIET_MODE:
5225 0 : dbc->attr.quite_mode = (SQLHWND) (TDS_INTPTR) ValuePtr;
5226 0 : break;
5227 : #ifdef TDS_NO_DM
5228 0 : case SQL_ATTR_TRACE:
5229 0 : dbc->attr.trace = (SQLUINTEGER) u_value;
5230 0 : break;
5231 0 : case SQL_ATTR_TRACEFILE:
5232 0 : if (!IS_VALID_LEN(StringLength)) {
5233 0 : odbc_errs_add(&dbc->errs, "HY090", NULL);
5234 0 : break;
5235 : }
5236 0 : if (!odbc_dstr_copy(dbc, &dbc->attr.tracefile, StringLength, (ODBC_CHAR *) ValuePtr))
5237 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
5238 : break;
5239 : #endif
5240 104 : case SQL_ATTR_TXN_ISOLATION:
5241 104 : if (u_value != dbc->attr.txn_isolation) {
5242 92 : if (change_txn(dbc, (SQLUINTEGER) u_value) == SQL_SUCCESS)
5243 72 : dbc->attr.txn_isolation = (SQLUINTEGER)u_value;
5244 : }
5245 : break;
5246 558 : case SQL_COPT_SS_MARS_ENABLED:
5247 558 : dbc->attr.mars_enabled = (SQLUINTEGER) u_value;
5248 558 : break;
5249 0 : case SQL_ATTR_TRANSLATE_LIB:
5250 : case SQL_ATTR_TRANSLATE_OPTION:
5251 0 : odbc_errs_add(&dbc->errs, "HYC00", NULL);
5252 0 : break;
5253 2 : case SQL_COPT_SS_OLDPWD:
5254 2 : if (!IS_VALID_LEN(StringLength)) {
5255 0 : odbc_errs_add(&dbc->errs, "HY090", NULL);
5256 0 : break;
5257 : }
5258 2 : if (!odbc_dstr_copy_oct(dbc, &dbc->oldpwd, StringLength, (ODBC_CHAR *) ValuePtr))
5259 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
5260 : else
5261 2 : dbc->use_oldpwd = 1;
5262 : break;
5263 0 : case SQL_COPT_SS_ATTACHDBFILENAME:
5264 0 : if (!IS_VALID_LEN(StringLength)) {
5265 0 : odbc_errs_add(&dbc->errs, "HY090", NULL);
5266 0 : break;
5267 : }
5268 0 : if (!odbc_dstr_copy(dbc, &dbc->db_filename, StringLength, (ODBC_CHAR *) ValuePtr))
5269 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
5270 : break;
5271 10 : case SQL_COPT_SS_BCP:
5272 10 : dbc->attr.bulk_enabled = (SQLUINTEGER) u_value;
5273 10 : break;
5274 12 : case SQL_COPT_TDSODBC_IMPL_BCP_INITA:
5275 12 : if (!ValuePtr)
5276 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
5277 : else {
5278 12 : const struct tdsodbc_impl_bcp_init_params *params = (const struct tdsodbc_impl_bcp_init_params*)ValuePtr;
5279 24 : odbc_bcp_init(dbc, (const ODBC_CHAR *) params->tblname, (const ODBC_CHAR *) params->hfile,
5280 12 : (const ODBC_CHAR *) params->errfile, params->direction _wide0);
5281 : }
5282 : break;
5283 14 : case SQL_COPT_TDSODBC_DATETIME_FORMAT:
5284 14 : if (!odbc_dstr_copy(dbc, &dbc->datetime_fmt, StringLength, (ODBC_CHAR *) ValuePtr))
5285 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
5286 : break;
5287 4 : case SQL_COPT_TDSODBC_DATE_FORMAT:
5288 4 : if (!odbc_dstr_copy(dbc, &dbc->date_fmt, StringLength, (ODBC_CHAR *) ValuePtr))
5289 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
5290 : break;
5291 4 : case SQL_COPT_TDSODBC_TIME_FORMAT:
5292 4 : if (!odbc_dstr_copy(dbc, &dbc->time_fmt, StringLength, (ODBC_CHAR *) ValuePtr))
5293 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
5294 : break;
5295 : #ifdef ENABLE_ODBC_WIDE
5296 12 : case SQL_COPT_TDSODBC_IMPL_BCP_INITW:
5297 12 : if (!ValuePtr)
5298 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
5299 : else {
5300 12 : const struct tdsodbc_impl_bcp_init_params *params = (const struct tdsodbc_impl_bcp_init_params*)ValuePtr;
5301 24 : odbc_bcp_init(dbc, (const ODBC_CHAR *) params->tblname, (const ODBC_CHAR *) params->hfile,
5302 12 : (const ODBC_CHAR *) params->errfile, params->direction, 1);
5303 : }
5304 : break;
5305 : #endif
5306 0 : case SQL_COPT_TDSODBC_IMPL_BCP_CONTROL_OLD:
5307 0 : if (!ValuePtr)
5308 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
5309 : else {
5310 0 : const struct tdsodbc_impl_bcp_control_params *params =
5311 : (const struct tdsodbc_impl_bcp_control_params*)ValuePtr;
5312 0 : const int field = params->field == BCPHINTS_OLD ? BCPHINTSA : params->field;
5313 0 : odbc_bcp_control(dbc, field, params->value);
5314 : }
5315 : break;
5316 4 : case SQL_COPT_TDSODBC_IMPL_BCP_CONTROL:
5317 4 : if (!ValuePtr)
5318 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
5319 : else {
5320 4 : const struct tdsodbc_impl_bcp_control_params *params =
5321 : (const struct tdsodbc_impl_bcp_control_params*)ValuePtr;
5322 4 : odbc_bcp_control(dbc, params->field, params->value);
5323 : }
5324 : break;
5325 0 : case SQL_COPT_TDSODBC_IMPL_BCP_COLPTR:
5326 0 : if (!ValuePtr)
5327 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
5328 : else {
5329 0 : const struct tdsodbc_impl_bcp_colptr_params *params =
5330 : (const struct tdsodbc_impl_bcp_colptr_params*)ValuePtr;
5331 0 : odbc_bcp_colptr(dbc, params->colptr, params->table_column);
5332 : }
5333 : break;
5334 204 : case SQL_COPT_TDSODBC_IMPL_BCP_SENDROW:
5335 204 : if (ValuePtr)
5336 0 : odbc_errs_add(&dbc->errs, "HY000", NULL);
5337 : else
5338 204 : odbc_bcp_sendrow(dbc);
5339 : break;
5340 24 : case SQL_COPT_TDSODBC_IMPL_BCP_BATCH:
5341 24 : if (!ValuePtr)
5342 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
5343 : else {
5344 24 : struct tdsodbc_impl_bcp_batch_params *params = (struct tdsodbc_impl_bcp_batch_params*)ValuePtr;
5345 24 : params->rows = odbc_bcp_batch(dbc);
5346 : }
5347 : break;
5348 24 : case SQL_COPT_TDSODBC_IMPL_BCP_DONE:
5349 24 : if (!ValuePtr)
5350 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
5351 : else {
5352 24 : struct tdsodbc_impl_bcp_done_params *params = (struct tdsodbc_impl_bcp_done_params*)ValuePtr;
5353 24 : params->rows = odbc_bcp_done(dbc);
5354 : }
5355 : break;
5356 612 : case SQL_COPT_TDSODBC_IMPL_BCP_BIND:
5357 612 : if (!ValuePtr)
5358 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
5359 : else {
5360 612 : const struct tdsodbc_impl_bcp_bind_params *params = (const struct tdsodbc_impl_bcp_bind_params*)ValuePtr;
5361 1224 : odbc_bcp_bind(dbc, params->varaddr, params->prefixlen, params->varlen,
5362 612 : params->terminator, params->termlen, params->vartype, params->table_column);
5363 : }
5364 : break;
5365 0 : default:
5366 0 : odbc_errs_add(&dbc->errs, "HY092", NULL);
5367 0 : break;
5368 : }
5369 1906 : ODBC_EXIT_(dbc);
5370 : }
5371 :
5372 : SQLRETURN ODBC_PUBLIC ODBC_API
5373 : SQLSetConnectOption(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLULEN vParam)
5374 : {
5375 0 : tdsdump_log(TDS_DBG_FUNC, "SQLSetConnectOption(%p, %d, %p)\n", hdbc, fOption, (SQLPOINTER) (TDS_INTPTR) vParam);
5376 :
5377 0 : return odbc_SQLSetConnectAttr(hdbc, (SQLINTEGER) fOption, (SQLPOINTER) (TDS_INTPTR) vParam, SQL_NTS _wide0);
5378 : }
5379 :
5380 : #ifdef ENABLE_ODBC_WIDE
5381 : SQLRETURN ODBC_PUBLIC ODBC_API
5382 : SQLSetConnectOptionW(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLULEN vParam)
5383 : {
5384 0 : tdsdump_log(TDS_DBG_FUNC, "SQLSetConnectOptionW(%p, %d, %p)\n", hdbc, fOption, (SQLPOINTER) (TDS_INTPTR) vParam);
5385 :
5386 0 : return odbc_SQLSetConnectAttr(hdbc, (SQLINTEGER) fOption, (SQLPOINTER) (TDS_INTPTR) vParam, SQL_NTS, 1);
5387 : }
5388 : #endif
5389 :
5390 : static SQLRETURN
5391 6632 : odbc_SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength WIDE)
5392 : {
5393 6632 : SQLULEN ui = (SQLULEN) (TDS_INTPTR) ValuePtr;
5394 6632 : SQLUSMALLINT *usip = (SQLUSMALLINT *) ValuePtr;
5395 6632 : SQLLEN *lp = (SQLLEN *) ValuePtr;
5396 6632 : SQLULEN *ulp = (SQLULEN *) ValuePtr;
5397 :
5398 6632 : ODBC_ENTER_HSTMT;
5399 :
5400 6632 : tdsdump_log(TDS_DBG_FUNC, "odbc_SQLSetStmtAttr(%p, %d, %p, %d)\n", hstmt, (int)Attribute, ValuePtr, (int)StringLength);
5401 :
5402 : /* TODO - error checking and real functionality :-) */
5403 : /* TODO some setting set also other attribute, see documentation */
5404 6632 : switch (Attribute) {
5405 : /* TODO check SQLFreeHandle on descriptor. Is possible to free an associated descriptor ? */
5406 0 : case SQL_ATTR_APP_PARAM_DESC:
5407 : case SQL_ATTR_APP_ROW_DESC:
5408 : {
5409 : TDS_DESC *orig;
5410 : TDS_DESC **curr;
5411 0 : TDS_DESC *val = (TDS_DESC *) ValuePtr;
5412 :
5413 0 : if (Attribute == SQL_ATTR_APP_PARAM_DESC) {
5414 0 : orig = stmt->orig_apd;
5415 0 : curr = &stmt->apd;
5416 : } else {
5417 0 : orig = stmt->orig_ard;
5418 0 : curr = &stmt->ard;
5419 : }
5420 : /* if ValuePtr is NULL or original descriptor set original */
5421 0 : if (!val || val == orig) {
5422 0 : *curr = orig;
5423 0 : break;
5424 : }
5425 :
5426 : /* must be allocated by user, not implicit ones */
5427 0 : if (val->header.sql_desc_alloc_type != SQL_DESC_ALLOC_USER) {
5428 0 : odbc_errs_add(&stmt->errs, "HY017", NULL);
5429 0 : break;
5430 : }
5431 : /* TODO check HDESC (not associated, from DBC HY024) */
5432 0 : *curr = val;
5433 : }
5434 0 : break;
5435 0 : case SQL_ATTR_ASYNC_ENABLE:
5436 0 : if (stmt->attr.async_enable != ui) {
5437 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
5438 0 : break;
5439 : }
5440 0 : stmt->attr.async_enable = (SQLUINTEGER) ui;
5441 0 : break;
5442 298 : case SQL_ATTR_CONCURRENCY:
5443 298 : if (stmt->attr.concurrency != ui && !stmt->dbc->cursor_support) {
5444 26 : odbc_errs_add(&stmt->errs, "01S02", NULL);
5445 26 : break;
5446 : }
5447 :
5448 272 : if (stmt->cursor) {
5449 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
5450 0 : break;
5451 : }
5452 :
5453 272 : switch (ui) {
5454 72 : case SQL_CONCUR_READ_ONLY:
5455 72 : stmt->attr.cursor_sensitivity = SQL_INSENSITIVE;
5456 72 : break;
5457 200 : case SQL_CONCUR_LOCK:
5458 : case SQL_CONCUR_ROWVER:
5459 : case SQL_CONCUR_VALUES:
5460 200 : stmt->attr.cursor_sensitivity = SQL_SENSITIVE;
5461 200 : break;
5462 0 : default:
5463 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
5464 0 : ODBC_EXIT_(stmt);
5465 : }
5466 272 : stmt->attr.concurrency = (SQLUINTEGER) ui;
5467 272 : break;
5468 2098 : case SQL_ATTR_CURSOR_SCROLLABLE:
5469 2098 : if (stmt->attr.cursor_scrollable != ui && !stmt->dbc->cursor_support) {
5470 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
5471 0 : break;
5472 : }
5473 :
5474 2098 : switch (ui) {
5475 2050 : case SQL_SCROLLABLE:
5476 2050 : stmt->attr.cursor_type = SQL_CURSOR_KEYSET_DRIVEN;
5477 2050 : break;
5478 48 : case SQL_NONSCROLLABLE:
5479 48 : stmt->attr.cursor_type = SQL_CURSOR_FORWARD_ONLY;
5480 48 : break;
5481 0 : default:
5482 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
5483 0 : ODBC_EXIT_(stmt);
5484 : }
5485 2098 : stmt->attr.cursor_scrollable = (SQLUINTEGER) ui;
5486 2098 : break;
5487 72 : case SQL_ATTR_CURSOR_SENSITIVITY:
5488 : /* don't change anything */
5489 72 : if (ui == SQL_UNSPECIFIED)
5490 : break;
5491 72 : if (stmt->attr.cursor_sensitivity != ui && !stmt->dbc->cursor_support) {
5492 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
5493 0 : break;
5494 : }
5495 72 : switch (ui) {
5496 0 : case SQL_INSENSITIVE:
5497 0 : stmt->attr.concurrency = SQL_CONCUR_READ_ONLY;
5498 0 : stmt->attr.cursor_type = SQL_CURSOR_STATIC;
5499 0 : break;
5500 72 : case SQL_SENSITIVE:
5501 72 : stmt->attr.concurrency = SQL_CONCUR_ROWVER;
5502 72 : break;
5503 : }
5504 72 : stmt->attr.cursor_sensitivity = (SQLUINTEGER) ui;
5505 72 : break;
5506 2218 : case SQL_ATTR_CURSOR_TYPE:
5507 2218 : if (stmt->attr.cursor_type != ui && !stmt->dbc->cursor_support) {
5508 0 : odbc_errs_add(&stmt->errs, "01S02", NULL);
5509 0 : break;
5510 : }
5511 :
5512 2218 : if (stmt->cursor) {
5513 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
5514 0 : break;
5515 : }
5516 :
5517 2218 : switch (ui) {
5518 2138 : case SQL_CURSOR_DYNAMIC:
5519 : case SQL_CURSOR_KEYSET_DRIVEN:
5520 2138 : if (stmt->attr.concurrency != SQL_CONCUR_READ_ONLY)
5521 88 : stmt->attr.cursor_sensitivity = SQL_SENSITIVE;
5522 2138 : stmt->attr.cursor_scrollable = SQL_SCROLLABLE;
5523 2138 : break;
5524 80 : case SQL_CURSOR_STATIC:
5525 80 : if (stmt->attr.concurrency != SQL_CONCUR_READ_ONLY)
5526 0 : stmt->attr.cursor_sensitivity = SQL_SENSITIVE;
5527 : else
5528 80 : stmt->attr.cursor_sensitivity = SQL_INSENSITIVE;
5529 80 : stmt->attr.cursor_scrollable = SQL_SCROLLABLE;
5530 80 : break;
5531 0 : case SQL_CURSOR_FORWARD_ONLY:
5532 0 : stmt->attr.cursor_scrollable = SQL_NONSCROLLABLE;
5533 0 : break;
5534 0 : default:
5535 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
5536 0 : ODBC_EXIT_(stmt);
5537 : }
5538 2218 : stmt->attr.cursor_type = (SQLUINTEGER) ui;
5539 2218 : break;
5540 0 : case SQL_ATTR_ENABLE_AUTO_IPD:
5541 0 : if (stmt->attr.enable_auto_ipd != ui) {
5542 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
5543 0 : break;
5544 : }
5545 0 : stmt->attr.enable_auto_ipd = (SQLUINTEGER) ui;
5546 0 : break;
5547 0 : case SQL_ATTR_FETCH_BOOKMARK_PTR:
5548 0 : stmt->attr.fetch_bookmark_ptr = ValuePtr;
5549 0 : break;
5550 0 : case SQL_ATTR_IMP_ROW_DESC:
5551 : case SQL_ATTR_IMP_PARAM_DESC:
5552 0 : odbc_errs_add(&stmt->errs, "HY017", NULL);
5553 0 : break;
5554 : /* TODO what's is this ??? */
5555 0 : case SQL_ATTR_KEYSET_SIZE:
5556 0 : stmt->attr.keyset_size = ui;
5557 0 : break;
5558 : /* TODO max length of data returned. Use SQL TEXTSIZE or just truncate ?? */
5559 0 : case SQL_ATTR_MAX_LENGTH:
5560 0 : if (stmt->attr.max_length != ui) {
5561 0 : odbc_errs_add(&stmt->errs, "01S02", NULL);
5562 0 : break;
5563 : }
5564 0 : stmt->attr.max_length = ui;
5565 0 : break;
5566 : /* TODO max row returned. Use SET ROWCOUNT */
5567 0 : case SQL_ATTR_MAX_ROWS:
5568 0 : if (stmt->attr.max_rows != ui) {
5569 0 : odbc_errs_add(&stmt->errs, "01S02", NULL);
5570 0 : break;
5571 : }
5572 0 : stmt->attr.max_rows = ui;
5573 0 : break;
5574 0 : case SQL_ATTR_METADATA_ID:
5575 0 : stmt->attr.metadata_id = (SQLUINTEGER) ui;
5576 0 : break;
5577 : /* TODO use it !!! */
5578 0 : case SQL_ATTR_NOSCAN:
5579 0 : stmt->attr.noscan = (SQLUINTEGER) ui;
5580 0 : break;
5581 10 : case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
5582 10 : stmt->apd->header.sql_desc_bind_offset_ptr = lp;
5583 10 : break;
5584 124 : case SQL_ATTR_PARAM_BIND_TYPE:
5585 124 : stmt->apd->header.sql_desc_bind_type = (SQLUINTEGER) ui;
5586 124 : break;
5587 0 : case SQL_ATTR_PARAM_OPERATION_PTR:
5588 0 : stmt->apd->header.sql_desc_array_status_ptr = usip;
5589 0 : break;
5590 82 : case SQL_ATTR_PARAM_STATUS_PTR:
5591 82 : stmt->ipd->header.sql_desc_array_status_ptr = usip;
5592 82 : break;
5593 154 : case SQL_ATTR_PARAMS_PROCESSED_PTR:
5594 154 : stmt->ipd->header.sql_desc_rows_processed_ptr = ulp;
5595 154 : break;
5596 : /* allow to exec procedure multiple time */
5597 174 : case SQL_ATTR_PARAMSET_SIZE:
5598 174 : stmt->apd->header.sql_desc_array_size = ui;
5599 174 : break;
5600 136 : case SQL_ATTR_QUERY_TIMEOUT:
5601 : /* Microsoft allows a maximum value of 65534 */
5602 136 : if (ui > 65534) {
5603 8 : odbc_errs_add(&stmt->errs, "01S02", NULL);
5604 8 : ui = 65534;
5605 : }
5606 136 : stmt->attr.query_timeout = (SQLUINTEGER) ui;
5607 136 : break;
5608 : /* retrieve data after positioning the cursor */
5609 0 : case SQL_ATTR_RETRIEVE_DATA:
5610 : /* TODO cursors */
5611 0 : if (stmt->attr.retrieve_data != ui) {
5612 0 : odbc_errs_add(&stmt->errs, "01S02", NULL);
5613 0 : break;
5614 : }
5615 0 : stmt->attr.retrieve_data = (SQLUINTEGER) ui;
5616 0 : break;
5617 312 : case SQL_ATTR_ROW_ARRAY_SIZE:
5618 312 : stmt->ard->header.sql_desc_array_size = ui;
5619 312 : break;
5620 30 : case SQL_ATTR_ROW_BIND_OFFSET_PTR:
5621 : /* TODO test what happen with column-wise and row-wise bindings and SQLGetData */
5622 30 : stmt->ard->header.sql_desc_bind_offset_ptr = lp;
5623 30 : break;
5624 : #if SQL_BIND_TYPE != SQL_ATTR_ROW_BIND_TYPE
5625 : case SQL_BIND_TYPE: /* although this is ODBC2 we must support this attribute */
5626 : #endif
5627 234 : case SQL_ATTR_ROW_BIND_TYPE:
5628 234 : stmt->ard->header.sql_desc_bind_type = (SQLUINTEGER) ui;
5629 234 : break;
5630 0 : case SQL_ATTR_ROW_NUMBER:
5631 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
5632 0 : break;
5633 0 : case SQL_ATTR_ROW_OPERATION_PTR:
5634 0 : stmt->ard->header.sql_desc_array_status_ptr = usip;
5635 0 : break;
5636 264 : case SQL_ATTR_ROW_STATUS_PTR:
5637 264 : stmt->ird->header.sql_desc_array_status_ptr = usip;
5638 264 : break;
5639 292 : case SQL_ATTR_ROWS_FETCHED_PTR:
5640 292 : stmt->ird->header.sql_desc_rows_processed_ptr = ulp;
5641 292 : break;
5642 0 : case SQL_ATTR_SIMULATE_CURSOR:
5643 : /* TODO cursors */
5644 0 : if (stmt->cursor) {
5645 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
5646 0 : break;
5647 : }
5648 0 : if (stmt->attr.simulate_cursor != ui) {
5649 0 : odbc_errs_add(&stmt->errs, "01S02", NULL);
5650 0 : break;
5651 : }
5652 0 : stmt->attr.simulate_cursor = (SQLUINTEGER) ui;
5653 0 : break;
5654 0 : case SQL_ATTR_USE_BOOKMARKS:
5655 0 : if (stmt->cursor) {
5656 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
5657 0 : break;
5658 : }
5659 0 : stmt->attr.use_bookmarks = (SQLUINTEGER) ui;
5660 0 : break;
5661 66 : case SQL_ROWSET_SIZE: /* although this is ODBC2 we must support this attribute */
5662 66 : if (((TDS_INTPTR) ValuePtr) < 1) {
5663 30 : odbc_errs_add(&stmt->errs, "HY024", NULL);
5664 30 : break;
5665 : }
5666 36 : stmt->sql_rowset_size = ui;
5667 36 : break;
5668 4 : case SQL_SOPT_SS_QUERYNOTIFICATION_TIMEOUT:
5669 4 : if (ui < 1) {
5670 0 : odbc_errs_add(&stmt->errs, "HY024", NULL);
5671 0 : break;
5672 : }
5673 4 : stmt->attr.qn_timeout = (SQLUINTEGER) ui;
5674 4 : break;
5675 4 : case SQL_SOPT_SS_QUERYNOTIFICATION_MSGTEXT:
5676 4 : if (!IS_VALID_LEN(StringLength)) {
5677 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
5678 0 : break;
5679 : }
5680 4 : if (!odbc_dstr_copy_oct(stmt->dbc, &stmt->attr.qn_msgtext, StringLength, (ODBC_CHAR*) ValuePtr)) {
5681 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
5682 0 : break;
5683 : }
5684 : break;
5685 4 : case SQL_SOPT_SS_QUERYNOTIFICATION_OPTIONS:
5686 4 : if (!IS_VALID_LEN(StringLength)) {
5687 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
5688 0 : break;
5689 : }
5690 4 : if (!odbc_dstr_copy_oct(stmt->dbc, &stmt->attr.qn_options, StringLength, (ODBC_CHAR*) ValuePtr)) {
5691 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
5692 0 : break;
5693 : }
5694 : break;
5695 56 : case SQL_SOPT_SS_PARAM_FOCUS:
5696 56 : if (ui > 0 && (ui > stmt->apd->header.sql_desc_count
5697 32 : || stmt->ipd->records[ui - 1].sql_desc_concise_type != SQL_SS_TABLE)) {
5698 4 : odbc_errs_add(&stmt->errs, "IM020", NULL);
5699 4 : break;
5700 : }
5701 52 : stmt->attr.param_focus = (SQLUINTEGER) ui;
5702 52 : stmt->orig_apd->focus = (int) ui;
5703 52 : stmt->ipd->focus = (int) ui;
5704 52 : break;
5705 0 : default:
5706 0 : odbc_errs_add(&stmt->errs, "HY092", NULL);
5707 0 : break;
5708 : }
5709 6632 : ODBC_EXIT_(stmt);
5710 : }
5711 :
5712 : #if (ODBCVER >= 0x0300)
5713 : SQLRETURN ODBC_PUBLIC ODBC_API
5714 : SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength)
5715 : {
5716 3292 : tdsdump_log(TDS_DBG_FUNC, "SQLSetStmtAttr(%p, %d, %p, %d)\n",
5717 : hstmt, (int)Attribute, ValuePtr, (int)StringLength);
5718 :
5719 3292 : return odbc_SQLSetStmtAttr(hstmt, Attribute, ValuePtr, StringLength _wide0);
5720 : }
5721 :
5722 : #ifdef ENABLE_ODBC_WIDE
5723 : SQLRETURN ODBC_PUBLIC ODBC_API
5724 : SQLSetStmtAttrW(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength)
5725 : {
5726 3292 : tdsdump_log(TDS_DBG_FUNC, "SQLSetStmtAttr(%p, %d, %p, %d)\n",
5727 : hstmt, (int)Attribute, ValuePtr, (int)StringLength);
5728 :
5729 3292 : return odbc_SQLSetStmtAttr(hstmt, Attribute, ValuePtr, StringLength, 1);
5730 : }
5731 : #endif
5732 : #endif
5733 :
5734 : SQLRETURN ODBC_PUBLIC ODBC_API
5735 : SQLSetStmtOption(SQLHSTMT hstmt, SQLUSMALLINT fOption, SQLULEN vParam)
5736 : {
5737 8 : tdsdump_log(TDS_DBG_FUNC, "SQLSetStmtOption(%p, %u, %u)\n", hstmt, fOption, (unsigned)vParam);
5738 :
5739 : /* XXX: Lost precision */
5740 8 : return odbc_SQLSetStmtAttr(hstmt, (SQLINTEGER) fOption, (SQLPOINTER) (TDS_INTPTR) vParam, SQL_NTS _wide0);
5741 : }
5742 :
5743 : static SQLRETURN
5744 22058 : odbc_free_dynamic(TDS_STMT *stmt)
5745 : {
5746 : TDSSOCKET *tds;
5747 :
5748 22058 : if (!stmt->dyn)
5749 : return TDS_SUCCESS;
5750 :
5751 2252 : tds = stmt->dbc->tds_socket;
5752 2252 : if (!tds_needs_unprepare(tds->conn, stmt->dyn)) {
5753 92 : tds_release_dynamic(&stmt->dyn);
5754 92 : return SQL_SUCCESS;
5755 : }
5756 :
5757 2160 : if (odbc_lock_statement(stmt)) {
5758 2152 : if (TDS_SUCCEED(tds_submit_unprepare(stmt->tds, stmt->dyn))
5759 2152 : && TDS_SUCCEED(tds_process_simple_query(stmt->tds))) {
5760 2152 : odbc_unlock_statement(stmt);
5761 2152 : tds_release_dynamic(&stmt->dyn);
5762 2152 : return SQL_SUCCESS;
5763 : }
5764 : }
5765 :
5766 8 : if (TDS_SUCCEED(tds_deferred_unprepare(tds->conn, stmt->dyn))) {
5767 8 : tds_release_dynamic(&stmt->dyn);
5768 8 : return SQL_SUCCESS;
5769 : }
5770 :
5771 0 : ODBC_SAFE_ERROR(stmt);
5772 : return SQL_ERROR;
5773 : }
5774 :
5775 : /**
5776 : * Close server cursors
5777 : */
5778 : static SQLRETURN
5779 18501 : odbc_free_cursor(TDS_STMT * stmt)
5780 : {
5781 18501 : TDSCURSOR *cursor = stmt->cursor;
5782 : TDSSOCKET *tds;
5783 :
5784 18501 : if (!cursor)
5785 : return SQL_SUCCESS;
5786 :
5787 : /* if possible deallocate now */
5788 248 : if (odbc_lock_statement(stmt)) {
5789 248 : tds = stmt->tds;
5790 :
5791 248 : cursor->status.dealloc = TDS_CURSOR_STATE_REQUESTED;
5792 248 : if (TDS_SUCCEED(tds_cursor_close(tds, cursor))) {
5793 248 : if (TDS_SUCCEED(tds_process_simple_query(tds))) {
5794 : /* TODO check error */
5795 248 : tds_cursor_dealloc(tds, cursor);
5796 248 : tds_release_cursor(&stmt->cursor);
5797 248 : return SQL_SUCCESS;
5798 : }
5799 : }
5800 : }
5801 :
5802 0 : tds = stmt->dbc->tds_socket;
5803 0 : if (TDS_SUCCEED(tds_deferred_cursor_dealloc(tds->conn, cursor))) {
5804 0 : tds_release_cursor(&stmt->cursor);
5805 0 : return SQL_SUCCESS;
5806 : }
5807 :
5808 0 : ODBC_SAFE_ERROR(stmt);
5809 : return SQL_ERROR;
5810 : }
5811 :
5812 : SQLRETURN ODBC_PUBLIC ODBC_API
5813 : SQLSetScrollOptions(SQLHSTMT hstmt, SQLUSMALLINT fConcurrency, SQLLEN crowKeyset, SQLUSMALLINT crowRowset)
5814 : {
5815 : SQLUSMALLINT info;
5816 : SQLUINTEGER value, check;
5817 : SQLUINTEGER cursor_type;
5818 :
5819 0 : ODBC_ENTER_HSTMT;
5820 :
5821 0 : tdsdump_log(TDS_DBG_FUNC, "SQLSetScrollOptions(%p, %u, %ld, %u)\n",
5822 : hstmt, fConcurrency, (long int) crowKeyset, crowRowset);
5823 :
5824 0 : if (!stmt->dbc->cursor_support) {
5825 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
5826 0 : ODBC_EXIT_(stmt);
5827 : }
5828 :
5829 0 : if (stmt->cursor) {
5830 0 : odbc_errs_add(&stmt->errs, "24000", NULL);
5831 0 : ODBC_EXIT_(stmt);
5832 : }
5833 :
5834 0 : switch (crowKeyset) {
5835 : case SQL_SCROLL_FORWARD_ONLY:
5836 : info = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
5837 : cursor_type = SQL_CURSOR_FORWARD_ONLY;
5838 : break;
5839 0 : case SQL_SCROLL_STATIC:
5840 0 : info = SQL_STATIC_CURSOR_ATTRIBUTES2;
5841 0 : cursor_type = SQL_CURSOR_STATIC;
5842 0 : break;
5843 0 : case SQL_SCROLL_KEYSET_DRIVEN:
5844 0 : info = SQL_KEYSET_CURSOR_ATTRIBUTES2;
5845 0 : cursor_type = SQL_CURSOR_KEYSET_DRIVEN;
5846 0 : break;
5847 0 : case SQL_SCROLL_DYNAMIC:
5848 0 : info = SQL_DYNAMIC_CURSOR_ATTRIBUTES2;
5849 0 : cursor_type = SQL_CURSOR_DYNAMIC;
5850 0 : break;
5851 0 : default:
5852 0 : if (crowKeyset > crowRowset) {
5853 : info = SQL_KEYSET_CURSOR_ATTRIBUTES2;
5854 : cursor_type = SQL_CURSOR_KEYSET_DRIVEN;
5855 : break;
5856 : }
5857 :
5858 0 : odbc_errs_add(&stmt->errs, "HY107", NULL);
5859 0 : ODBC_EXIT_(stmt);
5860 : }
5861 :
5862 0 : switch (fConcurrency) {
5863 : case SQL_CONCUR_READ_ONLY:
5864 : check = SQL_CA2_READ_ONLY_CONCURRENCY;
5865 : break;
5866 0 : case SQL_CONCUR_LOCK:
5867 0 : check = SQL_CA2_LOCK_CONCURRENCY;
5868 0 : break;
5869 0 : case SQL_CONCUR_ROWVER:
5870 0 : check = SQL_CA2_OPT_ROWVER_CONCURRENCY;
5871 0 : break;
5872 0 : case SQL_CONCUR_VALUES:
5873 0 : check = SQL_CA2_OPT_VALUES_CONCURRENCY;
5874 0 : break;
5875 0 : default:
5876 0 : odbc_errs_add(&stmt->errs, "HY108", NULL);
5877 0 : ODBC_EXIT_(stmt);
5878 : }
5879 :
5880 0 : value = 0;
5881 0 : odbc_SQLGetInfo(stmt->dbc, info, &value, sizeof(value), NULL _wide0);
5882 :
5883 0 : if ((value & check) == 0) {
5884 0 : odbc_errs_add(&stmt->errs, "HYC00", NULL);
5885 0 : ODBC_EXIT_(stmt);
5886 : }
5887 :
5888 0 : odbc_SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) (TDS_INTPTR) cursor_type, 0 _wide0);
5889 0 : odbc_SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER) (TDS_INTPTR) fConcurrency, 0 _wide0);
5890 0 : odbc_SQLSetStmtAttr(hstmt, SQL_ATTR_KEYSET_SIZE, (SQLPOINTER) (TDS_INTPTR) crowKeyset, 0 _wide0);
5891 0 : odbc_SQLSetStmtAttr(hstmt, SQL_ROWSET_SIZE, (SQLPOINTER) (TDS_INTPTR) crowRowset, 0 _wide0);
5892 :
5893 0 : ODBC_EXIT_(stmt);
5894 : }
5895 :
5896 : /**
5897 : * Replace placeholders ('?') inside query with @PRMxxx name.
5898 : * @param is_func Tell if query is a ODBC function call.
5899 : * @returns Converted string, NULL on memory error.
5900 : */
5901 : static char *
5902 8 : prepare_query_describing_params(const char *query, size_t *query_len, bool is_func)
5903 : {
5904 : #define PRM_FMT "@PRM%04d"
5905 8 : int i = 0;
5906 : size_t len, pos;
5907 : const char *e, *s;
5908 8 : size_t size = *query_len + 30;
5909 : char *out;
5910 :
5911 8 : if (is_func)
5912 2 : size += 10;
5913 :
5914 8 : out = tds_new(char, size);
5915 8 : if (!out)
5916 : goto memory_error;
5917 8 : pos = 0;
5918 8 : if (is_func)
5919 2 : pos += sprintf(out + pos, "exec " PRM_FMT "=", ++i);
5920 :
5921 : s = query;
5922 14 : for (;; ++i) {
5923 36 : e = tds_next_placeholder(s);
5924 22 : len = e ? e - s : strlen(s);
5925 22 : if (pos + len + 12 >= size) {
5926 2 : size = pos + len + 30;
5927 2 : if (!TDS_RESIZE(out, size))
5928 : goto memory_error;
5929 : }
5930 22 : memcpy(out + pos, s, len);
5931 22 : pos += len;
5932 22 : if (!e)
5933 : break;
5934 14 : pos += sprintf(out + pos, PRM_FMT, i + 1);
5935 :
5936 14 : s = e + 1;
5937 : }
5938 8 : out[pos] = 0;
5939 8 : *query_len = pos;
5940 8 : return out;
5941 :
5942 0 : memory_error:
5943 0 : free(out);
5944 0 : return NULL;
5945 : #undef PRM_FMT
5946 : }
5947 :
5948 : /**
5949 : * Parse UTF-16 name for parameter name in the form @PRMxxxx.
5950 : * @returns xxxx number or -1 if error.
5951 : */
5952 : static int
5953 16 : param_index_from_name(const TDSCOLUMN *const col)
5954 : {
5955 16 : const unsigned char *data = col->column_data;
5956 : int i;
5957 : unsigned n;
5958 : char name[9];
5959 :
5960 : /* should be in format @PRMxxxx */
5961 16 : if (col->column_cur_size != 8 * 2)
5962 : return -1;
5963 :
5964 : /* convert to ASCII and lower the case */
5965 144 : for (i = 0; i < 8; ++i) {
5966 128 : name[i] = data[i * 2];
5967 128 : if (data[i * 2 + 1])
5968 : return -1;
5969 : }
5970 16 : name[1] |= 0x20;
5971 16 : name[2] |= 0x20;
5972 16 : name[3] |= 0x20;
5973 16 : name[8] = 0;
5974 :
5975 : /* parse name */
5976 16 : i = -1;
5977 16 : if (sscanf(name, "@prm%u%n", &n, &i) < 1 || n < 1 || i != 8)
5978 : return -1;
5979 :
5980 16 : return (int) (n - 1);
5981 : }
5982 :
5983 : static bool
5984 9 : read_params(TDS_STMT *stmt)
5985 : {
5986 9 : bool ret = false;
5987 : TDSSOCKET *tds;
5988 9 : TDSPARAMINFO *params = NULL;
5989 9 : bool in_row = false;
5990 : enum {
5991 : COL_NAME,
5992 : COL_PRECISION,
5993 : COL_SCALE,
5994 : COL_TYPE,
5995 : COL_LENGTH,
5996 : NUM_COLUMNS
5997 : };
5998 : static const char *const column_names[NUM_COLUMNS] = {
5999 : "NAME",
6000 : "SUGGESTED_PRECISION",
6001 : "SUGGESTED_SCALE",
6002 : "SUGGESTED_TDS_TYPE_ID",
6003 : "SUGGESTED_TDS_LENGTH",
6004 : };
6005 : unsigned column_idx[NUM_COLUMNS];
6006 18 : const char *query = tds_dstr_cstr(&stmt->query);
6007 18 : size_t query_len = tds_dstr_len(&stmt->query);
6008 9 : unsigned num_params = tds_count_placeholders(query);
6009 9 : char *new_query = NULL;
6010 : TDSCOLUMN col[1];
6011 :
6012 : /* there should be not so many parameters, avoid client to mess around */
6013 9 : if (num_params >= 998) {
6014 0 : stmt->params_queried = 1;
6015 0 : return false;
6016 : }
6017 :
6018 : /* allocate tds */
6019 9 : if (!odbc_lock_statement(stmt)) {
6020 1 : odbc_errs_reset(&stmt->errs);
6021 1 : return false;
6022 : }
6023 :
6024 8 : tds = stmt->tds;
6025 8 : stmt->params_queried = 1;
6026 :
6027 : /* currently supported only by MSSQL 2012 */
6028 8 : if (!TDS_IS_MSSQL(tds) || tds->conn->product_version < TDS_MS_VER(11,0,0)) {
6029 0 : odbc_unlock_statement(stmt);
6030 0 : return false;
6031 : }
6032 :
6033 : /* replace parameters with names */
6034 8 : if (stmt->prepared_query_is_func)
6035 2 : ++num_params;
6036 8 : if (num_params) {
6037 8 : new_query = prepare_query_describing_params(query, &query_len, stmt->prepared_query_is_func);
6038 8 : if (!new_query)
6039 : goto memory_error;
6040 : query = new_query;
6041 : }
6042 :
6043 : /* send query */
6044 8 : params = odbc_add_char_param(tds, NULL, "", query, query_len);
6045 8 : if (!params)
6046 : goto memory_error;
6047 :
6048 8 : if (TDS_FAILED(tds_submit_rpc(tds, "sp_describe_undeclared_parameters", params, NULL)))
6049 : goto error;
6050 8 : tds_free_param_results(params);
6051 8 : params = NULL;
6052 :
6053 : /* clear IPD and APD */
6054 8 : desc_alloc_records(stmt->apd, 0);
6055 8 : desc_alloc_records(stmt->ipd, 0);
6056 : /* set IPD size */
6057 8 : desc_alloc_records(stmt->ipd, num_params);
6058 :
6059 8 : ret = true;
6060 : for (;;) {
6061 : TDS_INT result_type;
6062 : int done_flags;
6063 : TDSRESULTINFO *res_info;
6064 : ptrdiff_t i, j, num_cols;
6065 : struct _drecord *drec;
6066 : int idx, scale, precision, len, tds_type;
6067 :
6068 48 : switch (tds_process_tokens(tds, &result_type, &done_flags, TDS_RETURN_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW)) {
6069 40 : case TDS_SUCCESS:
6070 40 : switch (result_type) {
6071 16 : case TDS_DONE_RESULT:
6072 : case TDS_DONEPROC_RESULT:
6073 : case TDS_DONEINPROC_RESULT:
6074 16 : in_row = false;
6075 16 : break;
6076 :
6077 8 : case TDS_ROWFMT_RESULT:
6078 : /* parse results, scan all columns to find needed ones */
6079 : /* extract all column indexes */
6080 8 : res_info = tds->current_results;
6081 8 : num_cols = res_info->num_cols;
6082 :
6083 48 : for (i = 0; i < NUM_COLUMNS; i++)
6084 40 : column_idx[i] = ~0u;
6085 192 : for (i = 0; i < num_cols; i++) {
6086 : char *name;
6087 : TDSCOLUMN *col;
6088 :
6089 192 : col = res_info->columns[i];
6090 384 : name = tds_dstr_buf(&col->column_name);
6091 192 : tds_ascii_strupr(name);
6092 1152 : for (j = 0; j < NUM_COLUMNS; j++)
6093 960 : if (strcmp(name, column_names[j]) == 0)
6094 40 : column_idx[j] = i;
6095 : }
6096 : in_row = true;
6097 40 : for (i = 0; i < NUM_COLUMNS; i++)
6098 40 : if (column_idx[i] == ~0u)
6099 0 : in_row = false;
6100 : break;
6101 16 : case TDS_ROW_RESULT:
6102 16 : if (!in_row)
6103 : break;
6104 : /*
6105 : * convert type to SQL.
6106 : * Set precision (fixed on some types) and scale.
6107 : * Set length (based on type and fields).
6108 : */
6109 16 : res_info = tds->current_results;
6110 :
6111 16 : idx = param_index_from_name(res_info->columns[column_idx[COL_NAME]]);
6112 16 : if (idx < 0 || idx >= num_params)
6113 : break;
6114 16 : drec = &stmt->ipd->records[idx];
6115 16 : memset(col, 0, sizeof(col));
6116 16 : tds_type = tds_get_int_col(tds, res_info->columns[column_idx[COL_TYPE]], -2);
6117 16 : len = tds_get_int_col(tds, res_info->columns[column_idx[COL_LENGTH]], -2);
6118 16 : precision = tds_get_int_col(tds, res_info->columns[column_idx[COL_PRECISION]], -2);
6119 16 : scale = tds_get_int_col(tds, res_info->columns[column_idx[COL_SCALE]], -2);
6120 16 : if (tds_type < -1 || len < -1 || precision < -1 || scale < -1)
6121 : break;
6122 16 : tds_set_column_type(tds->conn, col, tds_type);
6123 16 : col->on_server.column_size = col->column_size = len;
6124 16 : col->column_prec = precision;
6125 16 : col->column_scale = scale;
6126 16 : drec->sql_desc_nullable = SQL_NULLABLE;
6127 16 : odbc_set_sql_type_info(col, drec, stmt->dbc);
6128 16 : break;
6129 : }
6130 40 : continue;
6131 : case TDS_NO_MORE_RESULTS:
6132 : break;
6133 0 : case TDS_CANCELLED:
6134 0 : odbc_errs_add(&stmt->errs, "HY008", NULL);
6135 0 : default:
6136 0 : stmt->errs.lastrc = SQL_ERROR;
6137 0 : ret = false;
6138 0 : break;
6139 : }
6140 8 : break;
6141 : }
6142 8 : odbc_unlock_statement(stmt);
6143 8 : free(new_query);
6144 8 : new_query = NULL;
6145 :
6146 : /* clear IPD on error */
6147 8 : if (!ret)
6148 0 : desc_alloc_records(stmt->ipd, 0);
6149 :
6150 : /* mark we have the information (we need to reset changing query) */
6151 8 : stmt->params_queried = 1;
6152 8 : return ret;
6153 :
6154 0 : memory_error:
6155 0 : free(new_query);
6156 0 : tds_free_param_results(params);
6157 0 : odbc_unlock_statement(stmt);
6158 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
6159 0 : return false;
6160 :
6161 0 : error:
6162 0 : free(new_query);
6163 0 : tds_free_param_results(params);
6164 0 : odbc_unlock_statement(stmt);
6165 0 : return false;
6166 : }
6167 :
6168 : #include "odbc_export.h"
6169 :
6170 : /* Under Windows driver exports functions */
6171 : /* The win_ prefix is to avoid clash with inline function.
6172 : * The prefix is removed from exported functions using definition file.
6173 : */
6174 : #ifdef _WIN32
6175 : RETCODE SQL_API win_bcp_initA(HDBC hdbc, const char *tblname, const char *hfile,
6176 : const char *errfile, int direction);
6177 : RETCODE SQL_API win_bcp_initW(HDBC hdbc, const SQLWCHAR *tblname, const SQLWCHAR *hfile,
6178 : const SQLWCHAR *errfile, int direction);
6179 : RETCODE SQL_API win_bcp_control(HDBC hdbc, int field, void *value);
6180 : RETCODE SQL_API win_bcp_colptr(HDBC hdbc, const unsigned char * colptr, int table_column);
6181 : RETCODE SQL_API win_bcp_sendrow(HDBC hdbc);
6182 : int SQL_API win_bcp_batch(HDBC hdbc);
6183 : int SQL_API win_bcp_done(HDBC hdbc);
6184 : RETCODE SQL_API win_bcp_bind(HDBC hdbc, const unsigned char * varaddr, int prefixlen, int varlen,
6185 : const unsigned char * terminator, int termlen, int vartype, int table_column);
6186 :
6187 : RETCODE SQL_API
6188 : win_bcp_initA(HDBC hdbc, const char *tblname, const char *hfile, const char *errfile, int direction)
6189 : {
6190 : return bcp_initA(hdbc, tblname, hfile, errfile, direction);
6191 : }
6192 :
6193 : #ifdef ENABLE_ODBC_WIDE
6194 : RETCODE SQL_API
6195 : win_bcp_initW(HDBC hdbc, const SQLWCHAR *tblname, const SQLWCHAR *hfile, const SQLWCHAR *errfile, int direction)
6196 : {
6197 : return bcp_initW(hdbc, tblname, hfile, errfile, direction);
6198 : }
6199 : #endif
6200 :
6201 : RETCODE SQL_API
6202 : win_bcp_control(HDBC hdbc, int field, void *value)
6203 : {
6204 : return bcp_control(hdbc, field, value);
6205 : }
6206 :
6207 : RETCODE SQL_API
6208 : win_bcp_colptr(HDBC hdbc, const unsigned char * colptr, int table_column)
6209 : {
6210 : return bcp_colptr(hdbc, colptr, table_column);
6211 : }
6212 :
6213 : RETCODE SQL_API
6214 : win_bcp_sendrow(HDBC hdbc)
6215 : {
6216 : return bcp_sendrow(hdbc);
6217 : }
6218 :
6219 : int SQL_API
6220 : win_bcp_batch(HDBC hdbc)
6221 : {
6222 : return bcp_batch(hdbc);
6223 : }
6224 :
6225 : int SQL_API
6226 : win_bcp_done(HDBC hdbc)
6227 : {
6228 : return bcp_done(hdbc);
6229 : }
6230 :
6231 : RETCODE SQL_API
6232 : win_bcp_bind(HDBC hdbc, const unsigned char * varaddr, int prefixlen, int varlen,
6233 : const unsigned char * terminator, int termlen, int vartype, int table_column)
6234 : {
6235 : return bcp_bind(hdbc, varaddr, prefixlen, varlen, terminator, termlen, vartype, table_column);
6236 : }
6237 : #endif
6238 :
|