NCBI C++ ToolKit
odbc.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 1998, 1999, 2000, 2001 Brian Bruns
3  * Copyright (C) 2002-2012 Frediano Ziglio
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 #include <config.h>
22 
23 #include <stdarg.h>
24 #include <stdio.h>
25 
26 #if HAVE_STDLIB_H
27 #include <stdlib.h>
28 #endif /* HAVE_STDLIB_H */
29 
30 #if HAVE_STRING_H
31 #include <string.h>
32 #endif /* HAVE_STRING_H */
33 
34 #include <assert.h>
35 #include <ctype.h>
36 
37 #include <freetds/odbc.h>
38 #include <freetds/iconv.h>
39 #include <freetds/string.h>
40 #include <freetds/convert.h>
41 #include "replacements.h"
42 #include "sqlwparams.h"
43 
44 /* Include odbcss.h with all bcp functions */
45 /* The define trick is to make inline functions calls internal
46  * _SQLSetConnectAttr instead of SQLSetConnectAttr */
47 ODBC_FUNC(SQLSetConnectAttr, (P(SQLHDBC,hdbc), P(SQLINTEGER,Attribute), P(SQLPOINTER,ValuePtr), P(SQLINTEGER,StringLength) WIDE));
48 #define TDSODBC_BCP
49 #undef SQLSetConnectAttr
50 #define SQLSetConnectAttr(h, n, p, t) _SQLSetConnectAttr(h, n, p, t _wide0)
51 #include <odbcss.h>
52 #undef SQLSetConnectAttr
53 
54 static SQLRETURN _SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc);
55 static SQLRETURN _SQLAllocEnv(SQLHENV FAR * phenv, SQLINTEGER odbc_version);
56 static SQLRETURN _SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt);
57 static SQLRETURN _SQLAllocDesc(SQLHDBC hdbc, SQLHDESC FAR * phdesc);
59 static SQLRETURN _SQLFreeEnv(SQLHENV henv);
60 static SQLRETURN _SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption, int force);
61 static SQLRETURN _SQLFreeDesc(SQLHDESC hdesc);
63 static SQLRETURN _SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength WIDE);
65  SQLINTEGER * StringLength WIDE);
66 static SQLRETURN _SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc,
67  SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc _WIDE);
68 static SQLRETURN _SQLFetch(TDS_STMT * stmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset);
70 static int odbc_errmsg_handler(const TDSCONTEXT * ctx, TDSSOCKET * tds, TDSMESSAGE * msg);
71 static void odbc_log_unimplemented_type(const char function_name[], int fType);
73 static void odbc_col_setname(TDS_STMT * stmt, int colpos, const char *name);
74 static SQLRETURN odbc_stat_execute(TDS_STMT * stmt _WIDE, const char *begin, int nparams, ...);
80 static int odbc_process_tokens(TDS_STMT * stmt, unsigned flag);
81 static int odbc_lock_statement(TDS_STMT* stmt);
82 static void odbc_unlock_statement(TDS_STMT* stmt);
83 
84 #if ENABLE_EXTRA_CHECKS
85 static void odbc_ird_check(TDS_STMT * stmt);
86 
87 #define IRD_CHECK odbc_ird_check(stmt)
88 #else
89 #define IRD_CHECK
90 #endif
91 
92 /**
93  * \defgroup odbc_api ODBC API
94  * Functions callable by \c ODBC client programs
95  */
96 
97 
98 /* utils to check handles */
99 #define INIT_HANDLE(t, n) \
100  TDS_##t *n = (TDS_##t*)h##n; \
101  if (SQL_NULL_H##t == h##n || !IS_H##t(h##n)) return SQL_INVALID_HANDLE; \
102  tds_mutex_lock(&n->mtx); \
103  CHECK_##t##_EXTRA(n); \
104  odbc_errs_reset(&n->errs);
105 
106 #define ODBC_ENTER_HSTMT INIT_HANDLE(STMT, stmt)
107 #define ODBC_ENTER_HDBC INIT_HANDLE(DBC, dbc)
108 #define ODBC_ENTER_HENV INIT_HANDLE(ENV, env)
109 #define ODBC_ENTER_HDESC INIT_HANDLE(DESC, desc)
110 
111 #define IS_VALID_LEN(len) ((len) >= 0 || (len) == SQL_NTS || (len) == SQL_NULL_DATA)
112 
113 #define ODBC_SAFE_ERROR(stmt) \
114  do { \
115  if (!stmt->errs.num_errors) \
116  odbc_errs_add(&stmt->errs, "HY000", "Unknown error"); \
117  } while(0)
118 
119 #define DEFAULT_QUERY_TIMEOUT (~((SQLUINTEGER) 0))
120 
121 /*
122  * Note: I *HATE* hungarian notation, it has to be the most idiotic thing
123  * I've ever seen. So, you will note it is avoided other than in the function
124  * declarations. "Gee, let's make our code totally hard to read and they'll
125  * beg for GUI tools"
126  * Bah!
127  */
128 
129 static const char *
130 odbc_prret(SQLRETURN ret, char *unknown, size_t unknown_size)
131 {
132  switch (ret) {
133  case SQL_ERROR: return "SQL_ERROR";
134  case SQL_INVALID_HANDLE: return "SQL_INVALID_HANDLE";
135  case SQL_SUCCESS: return "SQL_SUCCESS";
136  case SQL_SUCCESS_WITH_INFO: return "SQL_SUCCESS_WITH_INFO";
137 #if ODBCVER >= 0x0300
138  case SQL_NO_DATA: return "SQL_NO_DATA";
139 #endif
140  case SQL_STILL_EXECUTING: return "SQL_STILL_EXECUTING";
141  case SQL_NEED_DATA: return "SQL_NEED_DATA";
142  }
143 
144  snprintf(unknown, unknown_size, "unknown: %d", (int)ret);
145 
146  return unknown;
147 }
148 #define ODBC_PRRET_BUF char unknown_prret_buf[24]
149 #define odbc_prret(ret) odbc_prret(ret, unknown_prret_buf, sizeof(unknown_prret_buf))
150 
151 static void
152 odbc_col_setname(TDS_STMT * stmt, int colpos, const char *name)
153 {
154 #if ENABLE_EXTRA_CHECKS
155  TDSRESULTINFO *resinfo;
156 #endif
157 
158  IRD_CHECK;
159 
160 #if ENABLE_EXTRA_CHECKS
161  if (colpos > 0 && stmt->tds != NULL && (resinfo = stmt->tds->current_results) != NULL) {
162  if (colpos <= resinfo->num_cols) {
163  /* no overflow possible, name is always shorter */
164  if (!tds_dstr_copy(&resinfo->columns[colpos - 1]->column_name, name))
165  odbc_errs_add(&stmt->errs, "HY001", NULL);
166  tds_dstr_empty(&resinfo->columns[colpos - 1]->table_column_name);
167  }
168  }
169 #endif
170 
171  if (colpos > 0 && colpos <= stmt->ird->header.sql_desc_count) {
172  --colpos;
173  if (!tds_dstr_copy(&stmt->ird->records[colpos].sql_desc_label, name)
174  || !tds_dstr_copy(&stmt->ird->records[colpos].sql_desc_name, name))
175  odbc_errs_add(&stmt->errs, "HY001", NULL);
176  }
177 }
178 
179 /* spinellia@acm.org : copied shamelessly from change_database */
180 static SQLRETURN
182 {
183  TDSSOCKET *tds = dbc->tds_socket;
184  TDSRET ret;
185 
186  if (dbc->attr.autocommit == state)
187  return SQL_SUCCESS;
188 
189  /*
190  * We may not be connected yet and dbc->tds_socket
191  * may not initialized.
192  */
193  if (tds) {
194  /* TODO better idle check, not thread safe */
195  if (tds->state == TDS_IDLE)
196  tds->query_timeout = dbc->default_query_timeout;
197 
198  if (state == SQL_AUTOCOMMIT_ON)
199  ret = tds_submit_rollback(tds, 0);
200  else
201  ret = tds_submit_begin_tran(tds);
202 
203  if (TDS_FAILED(ret)) {
204  odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");
205  return SQL_ERROR;
206  }
208  odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");
209  return SQL_ERROR;
210  }
211  dbc->attr.autocommit = state;
212  } else {
213  /* if not connected we will change auto-commit after login */
214  dbc->attr.autocommit = state;
215  }
216  ODBC_RETURN_(dbc);
217 }
218 
219 static SQLRETURN
220 change_database(TDS_DBC * dbc, const char *database, size_t database_len)
221 {
222  TDSSOCKET *tds = dbc->tds_socket;
223 
224  /*
225  * We may not be connected yet and dbc->tds_socket
226  * may not initialized.
227  */
228  if (tds) {
229  /* build query */
230  char *query = tds_new(char, 6 + tds_quote_id(tds, NULL, database, database_len));
231 
232  if (!query) {
233  odbc_errs_add(&dbc->errs, "HY001", NULL);
234  return SQL_ERROR;
235  }
236  strcpy(query, "USE ");
237  tds_quote_id(tds, query + 4, database, database_len);
238 
239 
240  tdsdump_log(TDS_DBG_INFO1, "change_database: executing %s\n", query);
241 
242  /* TODO better idle check, not thread safe */
243  if (tds->state == TDS_IDLE)
244  tds->query_timeout = dbc->default_query_timeout;
246  free(query);
247  odbc_errs_add(&dbc->errs, "HY000", "Could not change database");
248  return SQL_ERROR;
249  }
250  free(query);
252  odbc_errs_add(&dbc->errs, "HY000", "Could not change database");
253  return SQL_ERROR;
254  }
255  } else {
256  if (!tds_dstr_copyn(&dbc->attr.current_catalog, database, database_len)) {
257  odbc_errs_add(&dbc->errs, "HY001", NULL);
258  return SQL_ERROR;
259  }
260  }
261  ODBC_RETURN_(dbc);
262 }
263 
264 static SQLRETURN
266 {
267  char query[64];
268  const char *level;
269  TDSSOCKET *tds = dbc->tds_socket;
270 
271  switch (txn_isolation) {
273  level = "READ COMMITTED";
274  break;
276  level = "READ UNCOMMITTED";
277  break;
279  level = "REPEATABLE READ";
280  break;
282  level = "SERIALIZABLE";
283  break;
284  default:
285  odbc_errs_add(&dbc->errs, "HY024", NULL);
286  return SQL_ERROR;
287  }
288 
289  /* if not connected return success, will be set after connection */
290  if (!tds)
291  return SQL_SUCCESS;
292 
293  if (tds->state != TDS_IDLE) {
294  odbc_errs_add(&dbc->errs, "HY011", NULL);
295  return SQL_ERROR;
296  }
297 
298  tds->query_timeout = dbc->default_query_timeout;
299  sprintf(query, "SET TRANSACTION ISOLATION LEVEL %s", level);
302  return SQL_ERROR;
303  }
306  return SQL_ERROR;
307  }
308 
309  return SQL_SUCCESS;
310 }
311 
312 static TDS_DBC*
314 {
316  if (!chk)
317  return NULL;
318  if (chk->htype == SQL_HANDLE_DBC)
319  return (TDS_DBC *) chk;
320  assert(chk->htype == SQL_HANDLE_STMT);
321  return ((TDS_STMT *) chk)->dbc;
322 }
323 
324 static TDS_STMT*
326 {
328  if (!chk || chk->htype != SQL_HANDLE_STMT)
329  return NULL;
330  return (TDS_STMT *) chk;
331 }
332 
333 
334 static void
335 odbc_env_change(TDSSOCKET * tds, int type, char *oldval, char *newval)
336 {
337  TDS_DBC *dbc;
338 
339  assert(tds);
340 
341  dbc = odbc_get_dbc(tds);
342  if (!dbc)
343  return;
344 
345  switch (type) {
346  case TDS_ENV_DATABASE:
347  tds_dstr_copy(&dbc->attr.current_catalog, newval);
348  break;
349  case TDS_ENV_PACKSIZE:
350  dbc->attr.packet_size = atoi(newval);
351  break;
352  }
353 }
354 
355 static SQLRETURN
357 {
358  TDS_ENV *env = dbc->env;
359 
360 #ifdef ENABLE_ODBC_WIDE
361  dbc->mb_conv = NULL;
362 #endif
363  dbc->tds_socket = tds_alloc_socket(env->tds_ctx, 512);
364  if (!dbc->tds_socket)
365  goto memory_error;
366 
367  dbc->tds_socket->conn->use_iconv = 0;
368  tds_set_parent(dbc->tds_socket, (void *) dbc);
369 
370  /* Set up our environment change hook */
371  dbc->tds_socket->env_chg_func = odbc_env_change;
372 
374 
375  /* use connection timeout if set */
376  if (dbc->attr.connection_timeout)
377  login->connect_timeout = dbc->attr.connection_timeout;
378 
379  if (dbc->attr.mars_enabled != SQL_MARS_ENABLED_NO)
380  login->mars = 1;
381  if (dbc->attr.bulk_enabled != SQL_BCP_OFF)
382  tds_set_bulk(login, 1);
383 
384 #ifdef ENABLE_ODBC_WIDE
385  /* force utf-8 in order to support wide characters */
386  if (!tds_dstr_dup(&dbc->original_charset, &login->client_charset)
387  || !tds_dstr_copy(&login->client_charset, "UTF-8"))
388  goto memory_error;
389 #endif
390 
391  /* replace password with old one */
392  if (dbc->use_oldpwd) {
394  || !tds_dstr_dup(&login->password, &dbc->oldpwd))
395  goto memory_error;
396  login->use_new_password = 1;
397  }
398 
399  if (TDS_FAILED(tds_connect_and_login(dbc->tds_socket, login))) {
400  tds_free_socket(dbc->tds_socket);
401  dbc->tds_socket = NULL;
402  odbc_errs_add(&dbc->errs, "08001", NULL);
403  return SQL_ERROR;
404  }
405 #ifdef ENABLE_ODBC_WIDE
406  dbc->mb_conv = tds_iconv_get(dbc->tds_socket->conn, tds_dstr_cstr(&dbc->original_charset), "UTF-8");
407 #endif
408 
409  dbc->default_query_timeout = dbc->tds_socket->query_timeout;
410 
411  if (IS_TDS7_PLUS(dbc->tds_socket->conn))
412  dbc->cursor_support = 1;
413 
414 #if ENABLE_ODBC_MARS
415  /* check if mars is enabled */
416  if (!IS_TDS72_PLUS(dbc->tds_socket->conn) || !dbc->tds_socket->conn->mars)
417  dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
418 #else
419  dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
420 #endif
421 
422  if (dbc->attr.txn_isolation != SQL_TXN_READ_COMMITTED) {
423  if (!SQL_SUCCEEDED(change_txn(dbc, dbc->attr.txn_isolation)))
424  ODBC_RETURN_(dbc);
425  }
426 
427  if (dbc->attr.autocommit != SQL_AUTOCOMMIT_ON) {
428  dbc->attr.autocommit = SQL_AUTOCOMMIT_ON;
430  ODBC_RETURN_(dbc);
431  }
432 
433  /* this overwrite any error arrived (wanted behavior, Sybase return error for conversion errors) */
435 
436 memory_error:
437  tds_free_socket(dbc->tds_socket);
438  dbc->tds_socket = NULL;
439  odbc_errs_add(&dbc->errs, "HY001", NULL);
440  ODBC_RETURN_(dbc);
441 }
442 
443 static SQLRETURN
445 {
446  SQLRETURN res;
447 
448  if (!stmt->need_reprepare || stmt->prepared_query_is_rpc
449  || !stmt->dbc || !IS_TDS7_PLUS(stmt->dbc->tds_socket->conn)) {
450  stmt->need_reprepare = 0;
451  return SQL_SUCCESS;
452  }
453 
454  /* FIXME where error are put ?? on stmt... */
457 
458  /* FIXME error */
460  if (res != SQL_SUCCESS) {
461  /* prepare with dummy parameters just to fill IRD */
462  tds_free_param_results(stmt->params);
463  stmt->params = NULL;
464  stmt->param_num = 0;
465  /*
466  * TODO
467  * we need to prepare again with parameters but need_reprepare
468  * flag is reset by odbc_prepare... perhaps should be checked
469  * later, not calling describeCol or similar
470  * we need prepare to get dynamic and cause we change parameters
471  */
472  }
473 
474  return odbc_prepare(stmt);
475 }
476 
477 static SQLRETURN
479 {
480  TDSSOCKET *tds = stmt->tds;
481  int in_row = 0;
482 
483  if (TDS_FAILED(tds_submit_prepare(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params))) {
485  return SQL_ERROR;
486  }
487 
488  /* try to go to the next recordset */
489  /* TODO merge with similar code */
490  desc_free_records(stmt->ird);
491  stmt->row_status = PRE_NORMAL_ROW;
492  for (;;) {
493  TDS_INT result_type;
494  int done_flags;
495 
496  switch (tds_process_tokens(tds, &result_type, &done_flags, TDS_RETURN_ROWFMT|TDS_RETURN_DONE)) {
497  case TDS_SUCCESS:
498  switch (result_type) {
499  case TDS_DONE_RESULT:
500  case TDS_DONEPROC_RESULT:
502  stmt->row_count = tds->rows_affected;
503  if (done_flags & TDS_DONE_ERROR && !stmt->dyn->emulated)
504  stmt->errs.lastrc = SQL_ERROR;
505  /* FIXME this row is used only as a flag for update binding, should be cleared if binding/result changed */
506  stmt->row = 0;
507  break;
508 
509  case TDS_ROWFMT_RESULT:
510  /* store first row informations */
511  if (!in_row)
513  stmt->row = 0;
514  stmt->row_count = TDS_NO_COUNT;
515  stmt->row_status = PRE_NORMAL_ROW;
516  in_row = 1;
517  break;
518  }
519  continue;
520  case TDS_NO_MORE_RESULTS:
521  break;
522  case TDS_CANCELLED:
523  odbc_errs_add(&stmt->errs, "HY008", NULL);
524  default:
525  stmt->errs.lastrc = SQL_ERROR;
526  break;
527  }
528  break;
529  }
530 
531  if (stmt->errs.lastrc == SQL_ERROR && !stmt->dyn->emulated) {
532  tds_release_dynamic(&stmt->dyn);
533  }
535  stmt->need_reprepare = 0;
537 }
538 
539 ODBC_FUNC(SQLDriverConnect, (P(SQLHDBC,hdbc), P(SQLHWND,hwnd), PCHARIN(ConnStrIn,SQLSMALLINT),
540  PCHAROUT(ConnStrOut,SQLSMALLINT), P(SQLUSMALLINT,fDriverCompletion) WIDE))
541 {
542  TDSLOGIN *login;
544  DSTR conn_str = DSTR_INITIALIZER;
545 
547 
548 #ifdef TDS_NO_DM
549  /* Check string length */
550  if (!IS_VALID_LEN(cbConnStrIn) || cbConnStrIn == 0) {
551  odbc_errs_add(&dbc->errs, "HY090", NULL);
552  ODBC_EXIT_(dbc);
553  }
554 
555  /* Check completion param */
556  switch (fDriverCompletion) {
557  case SQL_DRIVER_NOPROMPT:
558  case SQL_DRIVER_COMPLETE:
559  case SQL_DRIVER_PROMPT:
561  break;
562  default:
563  odbc_errs_add(&dbc->errs, "HY110", NULL);
564  ODBC_EXIT_(dbc);
565  }
566 #endif
567 
568  if (!odbc_dstr_copy(dbc, &conn_str, cbConnStrIn, szConnStrIn)) {
569  odbc_errs_add(&dbc->errs, "HY001", NULL);
570  ODBC_EXIT_(dbc);
571  }
572 
573  login = tds_alloc_login(0);
574  if (!login || !tds_init_login(login, dbc->env->tds_ctx->locale)) {
576  tds_dstr_free(&conn_str);
577  odbc_errs_add(&dbc->errs, "HY001", NULL);
578  ODBC_EXIT_(dbc);
579  }
580 
581  if (!tds_dstr_isempty(&dbc->attr.current_catalog))
582  if (!tds_dstr_dup(&login->database, &dbc->attr.current_catalog)) {
584  tds_dstr_free(&conn_str);
585  odbc_errs_add(&dbc->errs, "HY001", NULL);
586  ODBC_EXIT_(dbc);
587  }
588 
589  /* parse the DSN string */
590  if (!odbc_parse_connect_string(&dbc->errs, tds_dstr_buf(&conn_str), tds_dstr_buf(&conn_str) + tds_dstr_len(&conn_str),
591  login, params)) {
592  tds_dstr_free(&conn_str);
593  ODBC_EXIT_(dbc);
594  }
595 
596  odbc_set_string(dbc, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, tds_dstr_buf(&conn_str), tds_dstr_len(&conn_str));
597  tds_dstr_free(&conn_str);
598 
599  /* add login info */
600  if (hwnd && fDriverCompletion != SQL_DRIVER_NOPROMPT
601  && (fDriverCompletion == SQL_DRIVER_PROMPT || (!params[ODBC_PARAM_UID].p && !params[ODBC_PARAM_Trusted_Connection].p)
603 #ifdef _WIN32
604  char *out = NULL;
605 
606  /* prompt for login information */
607  if (!get_login_info(hwnd, login)) {
609  odbc_errs_add(&dbc->errs, "08001", "User canceled login");
610  ODBC_EXIT_(dbc);
611  }
613  params[ODBC_PARAM_UID].p = NULL;
614  params[ODBC_PARAM_PWD].p = NULL;
615  params[ODBC_PARAM_Trusted_Connection].p = "Yes";
617  } else {
623  }
624  if (!odbc_build_connect_string(&dbc->errs, params, &out))
625  ODBC_EXIT_(dbc);
626 
627  odbc_set_string(dbc, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, out, -1);
628  tdsdump_log(TDS_DBG_INFO1, "connection string is now: %s\n", out);
629  free(out);
630 #else
631  /* we dont support a dialog box */
632  odbc_errs_add(&dbc->errs, "HYC00", NULL);
633 #endif
634  }
635 
638  odbc_errs_add(&dbc->errs, "IM007", "Could not find Servername or server parameter");
639  ODBC_EXIT_(dbc);
640  }
641 
643 
645  ODBC_EXIT_(dbc);
646 }
647 
648 #if 0
650 SQLBrowseConnect(SQLHDBC hdbc, SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR FAR * szConnStrOut,
651  SQLSMALLINT cbConnStrOutMax, SQLSMALLINT FAR * pcbConnStrOut)
652 {
653  tdsdump_log(TDS_DBG_FUNC, "SQLBrowseConnect(%p, %s, %d, %p, %d, %p)\n",
654  hdbc, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut);
656  odbc_errs_add(&dbc->errs, "HYC00", "SQLBrowseConnect: function not implemented");
657  ODBC_EXIT_(dbc);
658 }
659 #endif
660 
661 
662 ODBC_FUNC(SQLColumnPrivileges, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT), PCHARIN(SchemaName,SQLSMALLINT),
663  PCHARIN(TableName,SQLSMALLINT), PCHARIN(ColumnName,SQLSMALLINT) WIDE))
664 {
665  int retcode;
666 
668 
669  retcode =
670  odbc_stat_execute(stmt _wide, "sp_column_privileges", 4, "O@table_qualifier", szCatalogName, cbCatalogName,
671  "O@table_owner", szSchemaName, cbSchemaName, "O@table_name", szTableName, cbTableName,
672  "P@column_name", szColumnName, cbColumnName);
673  if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
674  odbc_col_setname(stmt, 1, "TABLE_CAT");
675  odbc_col_setname(stmt, 2, "TABLE_SCHEM");
676  }
677  ODBC_EXIT_(stmt);
678 }
679 
680 #if 0
682 SQLDescribeParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT FAR * pfSqlType, SQLUINTEGER FAR * pcbParamDef,
683  SQLSMALLINT FAR * pibScale, SQLSMALLINT FAR * pfNullable)
684 {
685  tdsdump_log(TDS_DBG_FUNC, "SQLDescribeParam(%p, %d, %p, %p, %p, %p)\n",
686  hstmt, ipar, pfSqlType, pcbParamDef, pibScale, pfNullable);
688  odbc_errs_add(&stmt->errs, "HYC00", "SQLDescribeParam: function not implemented");
689  ODBC_EXIT_(stmt);
690 }
691 #endif
692 
693 
695 SQLExtendedFetch(SQLHSTMT hstmt, SQLUSMALLINT fFetchType, SQLROWOFFSET irow, SQLROWSETSIZE FAR * pcrow, SQLUSMALLINT FAR * rgfRowStatus)
696 {
697  SQLRETURN ret;
698  SQLULEN * tmp_rows;
699  SQLUSMALLINT * tmp_status;
700  SQLULEN tmp_size;
701  SQLLEN * tmp_offset;
702  SQLPOINTER tmp_bookmark;
703  SQLULEN bookmark;
704  SQLULEN out_len = 0;
705 
707 
708  tdsdump_log(TDS_DBG_FUNC, "SQLExtendedFetch(%p, %d, %d, %p, %p)\n",
709  hstmt, fFetchType, (int)irow, pcrow, rgfRowStatus);
710 
711  if (fFetchType != SQL_FETCH_NEXT && !stmt->dbc->cursor_support) {
712  odbc_errs_add(&stmt->errs, "HY106", NULL);
713  ODBC_EXIT_(stmt);
714  }
715 
716  /* save and change IRD/ARD state */
717  tmp_rows = stmt->ird->header.sql_desc_rows_processed_ptr;
718  stmt->ird->header.sql_desc_rows_processed_ptr = &out_len;
719  tmp_status = stmt->ird->header.sql_desc_array_status_ptr;
720  stmt->ird->header.sql_desc_array_status_ptr = rgfRowStatus;
721  tmp_size = stmt->ard->header.sql_desc_array_size;
722  stmt->ard->header.sql_desc_array_size = stmt->sql_rowset_size;
723  tmp_offset = stmt->ard->header.sql_desc_bind_offset_ptr;
724  stmt->ard->header.sql_desc_bind_offset_ptr = NULL;
725  tmp_bookmark = stmt->attr.fetch_bookmark_ptr;
726 
727  /* SQL_FETCH_BOOKMARK different */
728  if (fFetchType == SQL_FETCH_BOOKMARK) {
729  bookmark = irow;
730  irow = 0;
731  stmt->attr.fetch_bookmark_ptr = &bookmark;
732  }
733 
734  /* TODO errors are sligthly different ... perhaps it's better to leave DM do this job ?? */
735  /* TODO check fFetchType can be converted to USMALLINT */
736  ret = _SQLFetch(stmt, fFetchType, irow);
737 
738  /* restore IRD/ARD */
739  stmt->ird->header.sql_desc_rows_processed_ptr = tmp_rows;
740  if (pcrow)
741  *pcrow = out_len;
742  stmt->ird->header.sql_desc_array_status_ptr = tmp_status;
743  stmt->ard->header.sql_desc_array_size = tmp_size;
744  stmt->ard->header.sql_desc_bind_offset_ptr = tmp_offset;
745  stmt->attr.fetch_bookmark_ptr = tmp_bookmark;
746 
747  ODBC_EXIT(stmt, ret);
748 }
749 
750 ODBC_FUNC(SQLForeignKeys, (P(SQLHSTMT,hstmt), PCHARIN(PkCatalogName,SQLSMALLINT),
751  PCHARIN(PkSchemaName,SQLSMALLINT), PCHARIN(PkTableName,SQLSMALLINT),
752  PCHARIN(FkCatalogName,SQLSMALLINT), PCHARIN(FkSchemaName,SQLSMALLINT),
753  PCHARIN(FkTableName,SQLSMALLINT) WIDE))
754 {
755  int retcode;
756 
758 
759  retcode =
760  odbc_stat_execute(stmt _wide, "sp_fkeys", 6, "O@pktable_qualifier", szPkCatalogName, cbPkCatalogName, "O@pktable_owner",
761  szPkSchemaName, cbPkSchemaName, "O@pktable_name", szPkTableName, cbPkTableName,
762  "O@fktable_qualifier", szFkCatalogName, cbFkCatalogName, "O@fktable_owner", szFkSchemaName,
763  cbFkSchemaName, "O@fktable_name", szFkTableName, cbFkTableName);
764  if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
765  odbc_col_setname(stmt, 1, "PKTABLE_CAT");
766  odbc_col_setname(stmt, 2, "PKTABLE_SCHEM");
767  odbc_col_setname(stmt, 5, "FKTABLE_CAT");
768  odbc_col_setname(stmt, 6, "FKTABLE_SCHEM");
769  }
770  ODBC_EXIT_(stmt);
771 }
772 
773 static int
775 {
776 #if ENABLE_ODBC_MARS
777  TDSSOCKET *tds = stmt->tds;
778 
779 
780  /* we already own a socket, just use it */
781  if (!tds) {
782  /* try with one saved into DBC */
783  TDSSOCKET *dbc_tds = stmt->dbc->tds_socket;
784  tds_mutex_lock(&stmt->dbc->mtx);
785 
786  if (stmt->dbc->current_statement == NULL
787  || stmt->dbc->current_statement == stmt) {
788  tds = dbc_tds;
789  stmt->dbc->current_statement = stmt;
790  }
791 
792  /* try to grab current locked one */
793  if (!tds && dbc_tds->state == TDS_IDLE) {
794  stmt->dbc->current_statement->tds = NULL;
795  tds = dbc_tds;
796  stmt->dbc->current_statement = stmt;
797  }
798  tds_mutex_unlock(&stmt->dbc->mtx);
799 
800  /* try with MARS */
801  if (!tds)
803  }
804  if (tds) {
805  tds->query_timeout = (stmt->attr.query_timeout != DEFAULT_QUERY_TIMEOUT) ?
806  stmt->attr.query_timeout : stmt->dbc->default_query_timeout;
808  stmt->tds = tds;
809  return 1;
810  }
811  odbc_errs_add(&stmt->errs, "24000", NULL);
812  return 0;
813 #else
814  TDSSOCKET *tds = stmt->dbc->tds_socket;
815 
816  tds_mutex_lock(&stmt->dbc->mtx);
817  if (stmt->dbc->current_statement != NULL
818  && stmt->dbc->current_statement != stmt) {
819  if (!tds || tds->state != TDS_IDLE) {
820  tds_mutex_unlock(&stmt->dbc->mtx);
821  odbc_errs_add(&stmt->errs, "24000", NULL);
822  return 0;
823  }
824  stmt->dbc->current_statement->tds = NULL;
825  }
826  stmt->dbc->current_statement = stmt;
827  if (tds) {
828  tds->query_timeout = (stmt->attr.query_timeout != DEFAULT_QUERY_TIMEOUT) ?
829  stmt->attr.query_timeout : stmt->dbc->default_query_timeout;
831  stmt->tds = tds;
832  }
833  tds_mutex_unlock(&stmt->dbc->mtx);
834  return 1;
835 #endif
836 }
837 
838 static void
840 {
841  TDSSOCKET * tds;
842 
843  tds_mutex_lock(&stmt->dbc->mtx);
844  tds = stmt->tds;
845  if (stmt->dbc->current_statement == stmt) {
846  assert(tds == stmt->dbc->tds_socket);
847  if (tds->state == TDS_IDLE) {
848  stmt->dbc->current_statement = NULL;
849  tds_set_parent(tds, stmt->dbc);
850  stmt->tds = NULL;
851  }
852 #if ENABLE_ODBC_MARS
853  } else if (tds) {
854  if (tds->state == TDS_IDLE || tds->state == TDS_DEAD) {
855  assert(tds != stmt->dbc->tds_socket);
857  stmt->tds = NULL;
858  }
859 #endif
860  }
861  tds_mutex_unlock(&stmt->dbc->mtx);
862 }
863 
866 {
867  TDSSOCKET *tds;
868  TDS_INT result_type;
869  TDSRET tdsret;
870  int in_row = 0;
871  SQLUSMALLINT param_status;
872  int token_flags;
873 
875 
876  tdsdump_log(TDS_DBG_FUNC, "SQLMoreResults(%p)\n", hstmt);
877 
878  tds = stmt->tds;
879 
880  /* We already read all results... */
881  if (!tds)
883 
884  stmt->row_count = TDS_NO_COUNT;
885  stmt->special_row = ODBC_SPECIAL_NONE;
886 
887  /* TODO this code is TOO similar to _SQLExecute, merge it - freddy77 */
888  /* try to go to the next recordset */
889  if (stmt->row_status == IN_COMPUTE_ROW) {
890  /* FIXME doesn't seem so fine ... - freddy77 */
892  stmt->row_status = IN_COMPUTE_ROW;
893  in_row = 1;
894  }
895 
896  param_status = SQL_PARAM_SUCCESS;
898  if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
899  token_flags |= TDS_RETURN_MSG;
900  for (;;) {
901  result_type = odbc_process_tokens(stmt, token_flags);
902  tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: result_type=%d, row_count=%" PRId64 ", lastrc=%d\n",
903  result_type, stmt->row_count, stmt->errs.lastrc);
904  switch (result_type) {
905  case TDS_CMD_DONE:
906 #if 1 /* !UNIXODBC */
908 #endif
911  if (stmt->row_count == TDS_NO_COUNT && !in_row) {
912  stmt->row_status = NOT_IN_ROW;
913  tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: row_status=%d\n", stmt->row_status);
914  }
915  tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: row_count=%" PRId64 ", lastrc=%d\n", stmt->row_count, stmt->errs.lastrc);
916  if (stmt->row_count == TDS_NO_COUNT) {
917  if (stmt->errs.lastrc == SQL_SUCCESS || stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO)
919  }
920  ODBC_EXIT_(stmt);
921 
922  case TDS_CMD_FAIL:
924  ODBC_EXIT_(stmt);
925 
926  case TDS_COMPUTE_RESULT:
927  switch (stmt->row_status) {
928  /* skip this recordset */
929  case IN_COMPUTE_ROW:
930  /* TODO here we should set current_results to normal results */
931  in_row = 1;
932  /* fall through */
933  /* in normal row, put in compute status */
934  case AFTER_COMPUTE_ROW:
935  case IN_NORMAL_ROW:
936  case PRE_NORMAL_ROW:
937  stmt->row_status = IN_COMPUTE_ROW;
939  ODBC_EXIT_(stmt);
940  case NOT_IN_ROW:
941  /* this should never happen, protocol error */
943  ODBC_EXIT_(stmt);
944  break;
945  }
946  break;
947 
948  case TDS_ROW_RESULT:
949  if (in_row || (stmt->row_status != IN_NORMAL_ROW && stmt->row_status != PRE_NORMAL_ROW)) {
950  stmt->row_status = PRE_NORMAL_ROW;
952  ODBC_EXIT_(stmt);
953  }
954  /* Skipping current result set's rows to access next resultset or proc's retval */
956  /* TODO should we set in_row ?? */
957  switch (tdsret) {
958  case TDS_CANCELLED:
959  odbc_errs_add(&stmt->errs, "HY008", NULL);
960  default:
961  if (TDS_FAILED(tdsret)) {
963  ODBC_EXIT_(stmt);
964  }
965  }
966  break;
967 
968  case TDS_DONE_RESULT:
969  case TDS_DONEPROC_RESULT:
970  /* FIXME here ??? */
971  if (!in_row)
973  switch (stmt->errs.lastrc) {
974  case SQL_ERROR:
975  param_status = SQL_PARAM_ERROR;
976  break;
978  param_status = SQL_PARAM_SUCCESS_WITH_INFO;
979  break;
980  }
981  if (stmt->curr_param_row < stmt->num_param_rows) {
982  if (stmt->ipd->header.sql_desc_array_status_ptr)
983  stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
984  ++stmt->curr_param_row;
985  if (stmt->ipd->header.sql_desc_rows_processed_ptr)
986  *stmt->ipd->header.sql_desc_rows_processed_ptr = stmt->curr_param_row;
987  }
988  if (stmt->curr_param_row < stmt->num_param_rows) {
989 #if 0
990  if (stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO)
991  found_info = 1;
992  if (stmt->errs.lastrc == SQL_ERROR)
993  found_error = 1;
994 #endif
995  stmt->errs.lastrc = SQL_SUCCESS;
996  param_status = SQL_PARAM_SUCCESS;
997  break;
998  }
1000  ODBC_EXIT_(stmt);
1001  break;
1002 
1003  /*
1004  * TODO test flags ? check error and change result ?
1005  * see also other DONEINPROC handle (below)
1006  */
1007  case TDS_DONEINPROC_RESULT:
1008  if (in_row) {
1010  ODBC_EXIT_(stmt);
1011  }
1012  /* TODO perhaps it can be a problem if SET NOCOUNT ON, test it */
1015  break;
1016 
1017  /* do not stop at metadata, an error can follow... */
1018  case TDS_ROWFMT_RESULT:
1019  if (in_row) {
1021  ODBC_EXIT_(stmt);
1022  }
1023  stmt->row = 0;
1024  stmt->row_count = TDS_NO_COUNT;
1025  /* we expect a row */
1026  stmt->row_status = PRE_NORMAL_ROW;
1027  in_row = 1;
1028  break;
1029 
1030  case TDS_MSG_RESULT:
1031  if (!in_row) {
1034  }
1035  in_row = 1;
1036  break;
1037  }
1038  }
1040 }
1041 
1042 ODBC_FUNC(SQLNativeSql, (P(SQLHDBC,hdbc), PCHARIN(SqlStrIn,SQLINTEGER),
1044 {
1045  SQLRETURN ret = SQL_SUCCESS;
1047 
1049 
1050 #ifdef TDS_NO_DM
1051  if (!szSqlStrIn || !IS_VALID_LEN(cbSqlStrIn)) {
1052  odbc_errs_add(&dbc->errs, "HY009", NULL);
1053  ODBC_EXIT_(dbc);
1054  }
1055 #endif
1056 
1057  if (!odbc_dstr_copy(dbc, &query, cbSqlStrIn, szSqlStrIn)) {
1058  odbc_errs_add(&dbc->errs, "HY001", NULL);
1059  ODBC_EXIT_(dbc);
1060  }
1061 
1062  native_sql(dbc, &query);
1063 
1064  /* FIXME if error set some kind of error */
1065  ret = odbc_set_string(dbc, szSqlStr, cbSqlStrMax, pcbSqlStr, tds_dstr_cstr(&query), -1);
1066 
1067  tds_dstr_free(&query);
1068 
1069  ODBC_EXIT(dbc, ret);
1070 }
1071 
1074 {
1076  tdsdump_log(TDS_DBG_FUNC, "SQLNumParams(%p, %p)\n", hstmt, pcpar);
1077  *pcpar = stmt->param_count;
1078  ODBC_EXIT_(stmt);
1079 }
1080 
1083 {
1084  SQLRETURN res;
1085 
1086  tdsdump_log(TDS_DBG_FUNC, "SQLParamOptions(%p, %lu, %p)\n", hstmt, (unsigned long int)crow, pirow);
1087 
1088  /* emulate for ODBC 2 DM */
1089  res = _SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, pirow, 0 _wide0);
1090  if (res != SQL_SUCCESS)
1091  return res;
1093 }
1094 
1095 ODBC_FUNC(SQLPrimaryKeys, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
1096  PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT) WIDE))
1097 {
1098  int retcode;
1099 
1101 
1102  retcode =
1103  odbc_stat_execute(stmt _wide, "sp_pkeys", 3, "O@table_qualifier", szCatalogName, cbCatalogName, "O@table_owner",
1104  szSchemaName, cbSchemaName, "O@table_name", szTableName, cbTableName);
1105  if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1106  odbc_col_setname(stmt, 1, "TABLE_CAT");
1107  odbc_col_setname(stmt, 2, "TABLE_SCHEM");
1108  }
1109  ODBC_EXIT_(stmt);
1110 }
1111 
1113  PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(ProcName,SQLSMALLINT), PCHARIN(ColumnName,SQLSMALLINT) WIDE))
1114 {
1115  int retcode;
1116 
1118 
1119  retcode =
1120  odbc_stat_execute(stmt _wide, "sp_sproc_columns", TDS_IS_MSSQL(stmt->dbc->tds_socket) ? 5 : 4,
1121  "O@procedure_qualifier", szCatalogName, cbCatalogName,
1122  "P@procedure_owner", szSchemaName, cbSchemaName, "P@procedure_name", szProcName, cbProcName,
1123  "P@column_name", szColumnName, cbColumnName, "V@ODBCVer", (char*) NULL, 0);
1124  if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1125  odbc_col_setname(stmt, 1, "PROCEDURE_CAT");
1126  odbc_col_setname(stmt, 2, "PROCEDURE_SCHEM");
1127  odbc_col_setname(stmt, 8, "COLUMN_SIZE");
1128  odbc_col_setname(stmt, 9, "BUFFER_LENGTH");
1129  odbc_col_setname(stmt, 10, "DECIMAL_DIGITS");
1130  odbc_col_setname(stmt, 11, "NUM_PREC_RADIX");
1131  if (TDS_IS_SYBASE(stmt->dbc->tds_socket))
1132  stmt->special_row = ODBC_SPECIAL_PROCEDURECOLUMNS;
1133  }
1134  ODBC_EXIT_(stmt);
1135 }
1136 
1137 ODBC_FUNC(SQLProcedures, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
1138  PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(ProcName,SQLSMALLINT) WIDE))
1139 {
1140  int retcode;
1141 
1143 
1144  retcode =
1145  odbc_stat_execute(stmt _wide, "..sp_stored_procedures", 3, "P@sp_name", szProcName, cbProcName, "P@sp_owner", szSchemaName,
1146  cbSchemaName, "O@sp_qualifier", szCatalogName, cbCatalogName);
1147  if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1148  odbc_col_setname(stmt, 1, "PROCEDURE_CAT");
1149  odbc_col_setname(stmt, 2, "PROCEDURE_SCHEM");
1150  }
1151  ODBC_EXIT_(stmt);
1152 }
1153 
1154 static TDSPARAMINFO*
1156 {
1157  SQLSMALLINT n;
1158  TDSPARAMINFO * params = NULL;
1159  struct _drecord *drec_ird;
1160 
1161  for (n = 0; n < stmt->ird->header.sql_desc_count && n < stmt->ard->header.sql_desc_count; ++n) {
1162  TDSPARAMINFO *temp_params;
1163  TDSCOLUMN *curcol;
1164 
1165  drec_ird = &stmt->ird->records[n];
1166 
1167  if (drec_ird->sql_desc_updatable == SQL_FALSE)
1168  continue;
1169 
1170  /* we have certainly a parameter */
1171  if (!(temp_params = tds_alloc_param_result(params)))
1172  goto memory_error;
1173  params = temp_params;
1174 
1175  curcol = params->columns[params->num_cols - 1];
1176  if (!tds_dstr_dup(&curcol->column_name, &drec_ird->sql_desc_name))
1177  goto memory_error;
1178 
1179  /* TODO use all infos... */
1180  if (!tds_dstr_dup(&curcol->table_name, &drec_ird->sql_desc_base_table_name))
1181  goto memory_error;
1182 
1183  switch (odbc_sql2tds(stmt, drec_ird, &stmt->ard->records[n], curcol, 1, stmt->ard, n_row)) {
1184  case SQL_NEED_DATA:
1185  goto memory_error;
1186  case SQL_ERROR:
1187  tds_free_param_results(params);
1188  return NULL;
1189  }
1190  }
1191  return params;
1192 
1193 memory_error:
1194  tds_free_param_results(params);
1195  odbc_errs_add(&stmt->errs, "HY001", NULL);
1196  return NULL;
1197 }
1198 
1201 {
1202  TDSRET ret;
1203  TDSSOCKET *tds;
1205  TDSPARAMINFO *params = NULL;
1207 
1208  tdsdump_log(TDS_DBG_FUNC, "SQLSetPos(%p, %ld, %d, %d)\n",
1209  hstmt, (long) irow, fOption, fLock);
1210 
1211  if (!stmt->dbc->cursor_support) {
1212  odbc_errs_add(&stmt->errs, "HYC00", "SQLSetPos: function not implemented");
1213  ODBC_EXIT_(stmt);
1214  }
1215 
1216  /* TODO handle irow == 0 (all rows) */
1217 
1218  if (!stmt->cursor) {
1219  odbc_errs_add(&stmt->errs, "HY109", NULL);
1220  ODBC_EXIT_(stmt);
1221  }
1222 
1223  switch (fOption) {
1224  case SQL_POSITION:
1225  op = TDS_CURSOR_POSITION;
1226  break;
1227  /* TODO cursor support */
1228  case SQL_REFRESH:
1229  default:
1230  odbc_errs_add(&stmt->errs, "HY092", NULL);
1231  ODBC_EXIT_(stmt);
1232  break;
1233  case SQL_UPDATE:
1234  op = TDS_CURSOR_UPDATE;
1235  /* prepare paremeters for update */
1236  /* scan all columns and build parameter list */
1237  params = odbc_build_update_params(stmt, irow >= 1 ? irow - 1 : 0);
1238  if (!params) {
1240  ODBC_EXIT_(stmt);
1241  }
1242  break;
1243  case SQL_DELETE:
1244  op = TDS_CURSOR_DELETE;
1245  break;
1246  case SQL_ADD:
1247  op = TDS_CURSOR_INSERT;
1248  break;
1249  }
1250 
1251  if (!odbc_lock_statement(stmt)) {
1252  tds_free_param_results(params);
1253  ODBC_EXIT_(stmt);
1254  }
1255 
1256  tds = stmt->tds;
1257 
1258  if (TDS_FAILED(tds_cursor_update(tds, stmt->cursor, op, irow, params))) {
1259  tds_free_param_results(params);
1261  ODBC_EXIT_(stmt);
1262  }
1263  tds_free_param_results(params);
1264  params = NULL;
1265 
1268  if (TDS_FAILED(ret)) {
1270  ODBC_EXIT_(stmt);
1271  }
1272 
1273  ODBC_EXIT_(stmt);
1274 }
1275 
1276 ODBC_FUNC(SQLTablePrivileges, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
1277  PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT) WIDE))
1278 {
1279  int retcode;
1280 
1282 
1283  retcode =
1284  odbc_stat_execute(stmt _wide, "sp_table_privileges", 3, "O@table_qualifier", szCatalogName, cbCatalogName,
1285  "P@table_owner", szSchemaName, cbSchemaName, "P@table_name", szTableName, cbTableName);
1286  if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1287  odbc_col_setname(stmt, 1, "TABLE_CAT");
1288  odbc_col_setname(stmt, 2, "TABLE_SCHEM");
1289  }
1290  ODBC_EXIT_(stmt);
1291 }
1292 
1293 #if (ODBCVER >= 0x0300)
1296 {
1297  SQLINTEGER i_val = (SQLINTEGER) (TDS_INTPTR) Value;
1298 
1300 
1301  tdsdump_log(TDS_DBG_FUNC, "SQLSetEnvAttr(%p, %d, %p, %d)\n", henv, (int)Attribute, Value, (int)StringLength);
1302 
1303  switch (Attribute) {
1305  case SQL_ATTR_CP_MATCH:
1306  odbc_errs_add(&env->errs, "HYC00", NULL);
1307  break;
1308  case SQL_ATTR_ODBC_VERSION:
1309  switch (i_val) {
1310  case SQL_OV_ODBC3:
1311  case SQL_OV_ODBC2:
1312  env->attr.odbc_version = i_val;
1313  break;
1314  default:
1315  odbc_errs_add(&env->errs, "HY024", NULL);
1316  break;
1317  }
1318  break;
1319  case SQL_ATTR_OUTPUT_NTS:
1320  /* TODO - Make this really work */
1321  env->attr.output_nts = i_val;
1322  /* env->attr.output_nts = SQL_TRUE; */
1323  break;
1324  default:
1325  odbc_errs_add(&env->errs, "HY092", NULL);
1326  break;
1327  }
1328  ODBC_EXIT_(env);
1329 }
1330 
1332 SQLGetEnvAttr(SQLHENV henv, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
1333 {
1334  SQLINTEGER size;
1335  void *src;
1336 
1338 
1339  tdsdump_log(TDS_DBG_FUNC, "SQLGetEnvAttr(%p, %d, %p, %d, %p)\n",
1340  henv, (int)Attribute, Value, (int)BufferLength, StringLength);
1341 
1342  switch (Attribute) {
1344  src = &env->attr.connection_pooling;
1345  size = sizeof(env->attr.connection_pooling);
1346  break;
1347  case SQL_ATTR_CP_MATCH:
1348  src = &env->attr.cp_match;
1349  size = sizeof(env->attr.cp_match);
1350  break;
1351  case SQL_ATTR_ODBC_VERSION:
1352  src = &env->attr.odbc_version;
1353  size = sizeof(env->attr.odbc_version);
1354  break;
1355  case SQL_ATTR_OUTPUT_NTS:
1356  /* TODO handle output_nts flags */
1357  env->attr.output_nts = SQL_TRUE;
1358  src = &env->attr.output_nts;
1359  size = sizeof(env->attr.output_nts);
1360  break;
1361  default:
1362  odbc_errs_add(&env->errs, "HY092", NULL);
1363  ODBC_EXIT_(env);
1364  break;
1365  }
1366 
1367  if (StringLength) {
1368  *StringLength = size;
1369  }
1370  memcpy(Value, src, size);
1371 
1372  ODBC_EXIT_(env);
1373 }
1374 
1375 #endif
1376 
1377 #define IRD_UPDATE(desc, errs, exit) \
1378  do { \
1379  if (desc->type == DESC_IRD && ((TDS_STMT*)desc->parent)->need_reprepare && \
1380  odbc_update_ird((TDS_STMT*)desc->parent, errs) != SQL_SUCCESS) \
1381  exit; \
1382  } while(0)
1383 
1384 static SQLRETURN
1385 _SQLBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType,
1386  SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
1387 {
1388  TDS_DESC *apd, *ipd;
1389  struct _drecord *drec;
1390  SQLSMALLINT orig_apd_size, orig_ipd_size;
1391  int is_numeric = 0;
1392 
1394 
1395  tdsdump_log(TDS_DBG_FUNC, "_SQLBindParameter(%p, %u, %d, %d, %d, %u, %d, %p, %d, %p)\n",
1396  hstmt, (unsigned short)ipar, (int)fParamType, (int)fCType, (int)fSqlType, (unsigned int)cbColDef,
1397  (int)ibScale, rgbValue, (int)cbValueMax, pcbValue);
1398 
1399 #ifdef TDS_NO_DM
1400  /* TODO - more error checking ... XXX smurph */
1401 
1402  /* Check param type */
1403  switch (fParamType) {
1404  case SQL_PARAM_INPUT:
1406  case SQL_PARAM_OUTPUT:
1407  break;
1408  default:
1409  odbc_errs_add(&stmt->errs, "HY105", NULL);
1410  ODBC_EXIT_(stmt);
1411  }
1412 
1413  /* Check max buffer length */
1414  if (cbValueMax < 0) {
1415  odbc_errs_add(&stmt->errs, "HY090", NULL);
1416  ODBC_EXIT_(stmt);
1417  }
1418 #endif
1419 
1420  /* check cbColDef and ibScale */
1421  if (fSqlType == SQL_DECIMAL || fSqlType == SQL_NUMERIC) {
1422  is_numeric = 1;
1423  if (cbColDef < 1 || cbColDef > 38) {
1424  odbc_errs_add(&stmt->errs, "HY104", "Invalid precision value");
1425  ODBC_EXIT_(stmt);
1426  }
1427  if (ibScale < 0 || (SQLULEN)ibScale > cbColDef) {
1428  odbc_errs_add(&stmt->errs, "HY104", "Invalid scale value");
1429  ODBC_EXIT_(stmt);
1430  }
1431  }
1432 
1433  /* Check parameter number */
1434  if (ipar <= 0 || ipar > 4000) {
1435  odbc_errs_add(&stmt->errs, "07009", NULL);
1436  ODBC_EXIT_(stmt);
1437  }
1438 
1439  /* fill APD related fields */
1440  apd = stmt->apd;
1441  orig_apd_size = apd->header.sql_desc_count;
1442  if (ipar > apd->header.sql_desc_count && desc_alloc_records(apd, ipar) != SQL_SUCCESS) {
1443  odbc_errs_add(&stmt->errs, "HY001", NULL);
1444  ODBC_EXIT_(stmt);
1445  }
1446  drec = &apd->records[ipar - 1];
1447 
1448  if (odbc_set_concise_c_type(fCType, drec, 0) != SQL_SUCCESS) {
1449  desc_alloc_records(apd, orig_apd_size);
1450  odbc_errs_add(&stmt->errs, "HY004", NULL);
1451  ODBC_EXIT_(stmt);
1452  }
1453 
1454  stmt->need_reprepare = 1;
1455 
1456  /* TODO other types ?? handle SQL_C_DEFAULT */
1457  if (drec->sql_desc_type == SQL_C_CHAR || drec->sql_desc_type == SQL_C_WCHAR || drec->sql_desc_type == SQL_C_BINARY)
1458  drec->sql_desc_octet_length = cbValueMax;
1459  drec->sql_desc_indicator_ptr = pcbValue;
1460  drec->sql_desc_octet_length_ptr = pcbValue;
1461  drec->sql_desc_data_ptr = (char *) rgbValue;
1462 
1463  /* field IPD related fields */
1464  ipd = stmt->ipd;
1465  orig_ipd_size = ipd->header.sql_desc_count;
1466  if (ipar > ipd->header.sql_desc_count && desc_alloc_records(ipd, ipar) != SQL_SUCCESS) {
1467  desc_alloc_records(apd, orig_apd_size);
1468  odbc_errs_add(&stmt->errs, "HY001", NULL);
1469  ODBC_EXIT_(stmt);
1470  }
1471  drec = &ipd->records[ipar - 1];
1472 
1473  drec->sql_desc_parameter_type = fParamType;
1474  if (odbc_set_concise_sql_type(fSqlType, drec, 0) != SQL_SUCCESS) {
1475  desc_alloc_records(ipd, orig_ipd_size);
1476  desc_alloc_records(apd, orig_apd_size);
1477  odbc_errs_add(&stmt->errs, "HY004", NULL);
1478  ODBC_EXIT_(stmt);
1479  }
1480  if (is_numeric) {
1481  drec->sql_desc_precision = (SQLSMALLINT) cbColDef;
1482  drec->sql_desc_scale = ibScale;
1483  } else {
1484  drec->sql_desc_length = cbColDef;
1485  }
1486 
1487  ODBC_EXIT_(stmt);
1488 }
1489 
1491 SQLBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType,
1492  SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
1493 {
1494  tdsdump_log(TDS_DBG_FUNC, "SQLBindParameter(%p, %u, %d, %d, %d, %u, %d, %p, %d, %p)\n",
1495  hstmt, (unsigned)ipar, fParamType, fCType, (int)fSqlType, (unsigned)cbColDef, ibScale, rgbValue, (int)cbValueMax, pcbValue);
1496  return _SQLBindParameter(hstmt, ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, cbValueMax, pcbValue);
1497 }
1498 
1499 
1500 /* compatibility with X/Open */
1502 SQLBindParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLULEN cbColDef, SQLSMALLINT ibScale,
1503  SQLPOINTER rgbValue, SQLLEN FAR * pcbValue)
1504 {
1505  tdsdump_log(TDS_DBG_FUNC, "SQLBindParam(%p, %d, %d, %d, %u, %d, %p, %p)\n",
1506  hstmt, ipar, fCType, fSqlType, (unsigned)cbColDef, ibScale, rgbValue, pcbValue);
1507  return _SQLBindParameter(hstmt, ipar, SQL_PARAM_INPUT, fCType, fSqlType, cbColDef, ibScale, rgbValue, 0, pcbValue);
1508 }
1509 
1510 #if (ODBCVER >= 0x0300)
1512 SQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE * OutputHandle)
1513 {
1514  tdsdump_log(TDS_DBG_FUNC, "SQLAllocHandle(%d, %p, %p)\n", HandleType, InputHandle, OutputHandle);
1515 
1516  switch (HandleType) {
1517  case SQL_HANDLE_STMT:
1518  return _SQLAllocStmt(InputHandle, OutputHandle);
1519  break;
1520  case SQL_HANDLE_DBC:
1521  return _SQLAllocConnect(InputHandle, OutputHandle);
1522  break;
1523  case SQL_HANDLE_ENV:
1524  return _SQLAllocEnv(OutputHandle, SQL_OV_ODBC3);
1525  break;
1526  case SQL_HANDLE_DESC:
1527  return _SQLAllocDesc(InputHandle, OutputHandle);
1528  break;
1529  }
1530 
1531  /*
1532  * As the documentation puts it,
1533  * "There is no handle with which to associate additional diagnostic information."
1534  *
1535  * The DM must catch HY092 because the driver has no valid handle at this early stage in which
1536  * to store the error for later retrieval by the application.
1537  */
1538  tdsdump_log(TDS_DBG_FUNC, "SQLAllocHandle(): invalid HandleType, error HY092: should be caught by DM\n");
1539  return SQL_ERROR;
1540 }
1541 #endif
1542 
1543 static SQLRETURN
1545 {
1546  TDS_DBC *dbc;
1547 
1549 
1550  tdsdump_log(TDS_DBG_FUNC, "_SQLAllocConnect(%p, %p)\n", henv, phdbc);
1551 
1552  dbc = tds_new0(TDS_DBC, 1);
1553  if (!dbc) {
1554  odbc_errs_add(&env->errs, "HY001", NULL);
1555  ODBC_EXIT_(env);
1556  }
1557 
1558  dbc->htype = SQL_HANDLE_DBC;
1559  dbc->env = env;
1560  tds_dstr_init(&dbc->dsn);
1561 
1562  dbc->attr.cursor_type = SQL_CURSOR_FORWARD_ONLY;
1563  dbc->attr.access_mode = SQL_MODE_READ_WRITE;
1564  dbc->attr.async_enable = SQL_ASYNC_ENABLE_OFF;
1565  dbc->attr.auto_ipd = SQL_FALSE;
1566  /*
1567  * spinellia@acm.org
1568  * after login is enabled autocommit
1569  */
1570  dbc->attr.autocommit = SQL_AUTOCOMMIT_ON;
1571  dbc->attr.connection_dead = SQL_CD_TRUE; /* No connection yet */
1572  dbc->attr.connection_timeout = 0;
1573  /* This is set in the environment change function */
1574  tds_dstr_init(&dbc->attr.current_catalog);
1575  dbc->attr.login_timeout = 0; /* TODO */
1576  dbc->attr.metadata_id = SQL_FALSE;
1577  dbc->attr.odbc_cursors = SQL_CUR_USE_IF_NEEDED;
1578  dbc->attr.packet_size = 0;
1579  dbc->attr.quite_mode = NULL; /* We don't support GUI dialogs yet */
1580 #ifdef TDS_NO_DM
1581  dbc->attr.trace = SQL_OPT_TRACE_OFF;
1582  tds_dstr_init(&dbc->attr.tracefile);
1583 #endif
1584  tds_dstr_init(&dbc->attr.translate_lib);
1585 #ifdef ENABLE_ODBC_WIDE
1586  tds_dstr_init(&dbc->original_charset);
1587 #endif
1588  tds_dstr_init(&dbc->oldpwd);
1589  dbc->attr.translate_option = 0;
1590  dbc->attr.txn_isolation = SQL_TXN_READ_COMMITTED;
1591  dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
1592  dbc->attr.bulk_enabled = SQL_BCP_OFF;
1593 
1594  tds_mutex_init(&dbc->mtx);
1595  *phdbc = (SQLHDBC) dbc;
1596 
1597  ODBC_EXIT_(env);
1598 }
1599 
1602 {
1603  tdsdump_log(TDS_DBG_FUNC, "SQLAllocConnect(%p, %p)\n", henv, phdbc);
1604 
1605  return _SQLAllocConnect(henv, phdbc);
1606 }
1607 
1608 static SQLRETURN
1609 _SQLAllocEnv(SQLHENV FAR * phenv, SQLINTEGER odbc_version)
1610 {
1611  TDS_ENV *env;
1612  TDSCONTEXT *ctx;
1613 
1614  tdsdump_log(TDS_DBG_FUNC, "_SQLAllocEnv(%p, %d)\n",
1615  phenv, (int) odbc_version);
1616 
1617  env = tds_new0(TDS_ENV, 1);
1618  if (!env)
1619  return SQL_ERROR;
1620 
1621  env->htype = SQL_HANDLE_ENV;
1622  env->attr.odbc_version = odbc_version;
1623  /* TODO use it */
1624  env->attr.output_nts = SQL_TRUE;
1625 
1627  if (!ctx) {
1628  free(env);
1629  return SQL_ERROR;
1630  }
1631  env->tds_ctx = ctx;
1632  ctx->msg_handler = odbc_errmsg_handler;
1633  ctx->err_handler = odbc_errmsg_handler;
1634 
1635  /* ODBC has its own format */
1636  free(ctx->locale->date_fmt);
1637  ctx->locale->date_fmt = strdup("%Y-%m-%d %H:%M:%S.%z");
1638 
1639  tds_mutex_init(&env->mtx);
1640  *phenv = (SQLHENV) env;
1641 
1642  return SQL_SUCCESS;
1643 }
1644 
1647 {
1648  tdsdump_log(TDS_DBG_FUNC, "SQLAllocEnv(%p)\n", phenv);
1649 
1650  return _SQLAllocEnv(phenv, SQL_OV_ODBC2);
1651 }
1652 
1653 static SQLRETURN
1655 {
1656  int i;
1657 
1659 
1660  tdsdump_log(TDS_DBG_FUNC, "_SQLAllocDesc(%p, %p)\n", hdbc, phdesc);
1661 
1662  for (i = 0; ; ++i) {
1663  if (i >= TDS_MAX_APP_DESC) {
1664  odbc_errs_add(&dbc->errs, "HY014", NULL);
1665  break;
1666  }
1667  if (dbc->uad[i] == NULL) {
1669  if (desc == NULL) {
1670  odbc_errs_add(&dbc->errs, "HY001", NULL);
1671  break;
1672  }
1673  dbc->uad[i] = desc;
1674  *phdesc = (SQLHDESC) desc;
1675  break;
1676  }
1677  }
1678  ODBC_EXIT_(dbc);
1679 }
1680 
1681 static SQLRETURN
1683 {
1684  TDS_STMT *stmt;
1685  char *pstr;
1686 
1688 
1689  tdsdump_log(TDS_DBG_FUNC, "_SQLAllocStmt(%p, %p)\n", hdbc, phstmt);
1690 
1691  stmt = tds_new0(TDS_STMT, 1);
1692  if (!stmt) {
1693  odbc_errs_add(&dbc->errs, "HY001", NULL);
1694  ODBC_EXIT_(dbc);
1695  }
1696  tds_dstr_init(&stmt->cursor_name);
1697  tds_dstr_init(&stmt->query);
1698 
1699  stmt->htype = SQL_HANDLE_STMT;
1700  stmt->dbc = dbc;
1701  stmt->num_param_rows = 1;
1702  pstr = NULL;
1703  /* TODO test initial cursor ... */
1704  if (asprintf(&pstr, "SQL_CUR%p", stmt) < 0
1705  || !tds_dstr_set(&stmt->cursor_name, pstr)) {
1706  free(stmt);
1707  free(pstr);
1708  odbc_errs_add(&dbc->errs, "HY001", NULL);
1709  ODBC_EXIT_(dbc);
1710  }
1711  /* do not free pstr tds_dstr_set do it if necessary */
1712 
1713  /* allocate descriptors */
1718  if (!stmt->ird || !stmt->ard || !stmt->ipd || !stmt->apd) {
1719  tds_dstr_free(&stmt->cursor_name);
1720  desc_free(stmt->ird);
1721  desc_free(stmt->ard);
1722  desc_free(stmt->ipd);
1723  desc_free(stmt->apd);
1724  free(stmt);
1725  odbc_errs_add(&dbc->errs, "HY001", NULL);
1726  ODBC_EXIT_(dbc);
1727  }
1728 
1729  /* save original ARD and APD */
1730  stmt->orig_apd = stmt->apd;
1731  stmt->orig_ard = stmt->ard;
1732 
1733  /* set the default statement attributes */
1734 /* stmt->attr.app_param_desc = stmt->apd; */
1735 /* stmt->attr.app_row_desc = stmt->ard; */
1736  stmt->attr.async_enable = SQL_ASYNC_ENABLE_OFF;
1737  stmt->attr.concurrency = SQL_CONCUR_READ_ONLY;
1738  stmt->attr.cursor_scrollable = SQL_NONSCROLLABLE;
1739  stmt->attr.cursor_sensitivity = SQL_INSENSITIVE;
1740  stmt->attr.cursor_type = SQL_CURSOR_FORWARD_ONLY;
1741  /* TODO ?? why two attributes */
1742  stmt->attr.enable_auto_ipd = dbc->attr.auto_ipd = SQL_FALSE;
1743  stmt->attr.fetch_bookmark_ptr = NULL;
1744 /* stmt->attr.imp_param_desc = stmt->ipd; */
1745 /* stmt->attr.imp_row_desc = stmt->ird; */
1746  stmt->attr.keyset_size = 0;
1747  stmt->attr.max_length = 0;
1748  stmt->attr.max_rows = 0;
1749  stmt->attr.metadata_id = dbc->attr.metadata_id;
1750  /* TODO check this flag in prepare_call */
1751  stmt->attr.noscan = SQL_NOSCAN_OFF;
1752  assert(stmt->apd->header.sql_desc_bind_offset_ptr == NULL);
1753  assert(stmt->apd->header.sql_desc_bind_type == SQL_PARAM_BIND_BY_COLUMN);
1754  assert(stmt->apd->header.sql_desc_array_status_ptr == NULL);
1755  assert(stmt->ipd->header.sql_desc_array_status_ptr == NULL);
1756  assert(stmt->ipd->header.sql_desc_rows_processed_ptr == NULL);
1757  assert(stmt->apd->header.sql_desc_array_size == 1);
1758  stmt->attr.query_timeout = DEFAULT_QUERY_TIMEOUT;
1759  stmt->attr.retrieve_data = SQL_RD_ON;
1760  assert(stmt->ard->header.sql_desc_array_size == 1);
1761  assert(stmt->ard->header.sql_desc_bind_offset_ptr == NULL);
1762  assert(stmt->ard->header.sql_desc_bind_type == SQL_BIND_BY_COLUMN);
1763  stmt->attr.row_number = 0;
1764  assert(stmt->ard->header.sql_desc_array_status_ptr == NULL);
1765  assert(stmt->ird->header.sql_desc_array_status_ptr == NULL);
1766  assert(stmt->ird->header.sql_desc_rows_processed_ptr == NULL);
1767  stmt->attr.simulate_cursor = SQL_SC_NON_UNIQUE;
1768  stmt->attr.use_bookmarks = SQL_UB_OFF;
1769  tds_dstr_init(&stmt->attr.qn_msgtext);
1770  tds_dstr_init(&stmt->attr.qn_options);
1771  stmt->attr.qn_timeout = 432000;
1772 
1773  stmt->sql_rowset_size = 1;
1774 
1775  stmt->row_count = TDS_NO_COUNT;
1776  stmt->row_status = NOT_IN_ROW;
1777 
1778  /* insert into list */
1779  stmt->next = dbc->stmt_list;
1780  if (dbc->stmt_list)
1781  dbc->stmt_list->prev = stmt;
1782  dbc->stmt_list = stmt;
1783 
1784  tds_mutex_init(&stmt->mtx);
1785  *phstmt = (SQLHSTMT) stmt;
1786 
1787  if (dbc->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY)
1789 
1790  ODBC_EXIT_(dbc);
1791 }
1792 
1795 {
1796  tdsdump_log(TDS_DBG_FUNC, "SQLAllocStmt(%p, %p)\n", hdbc, phstmt);
1797 
1798  return _SQLAllocStmt(hdbc, phstmt);
1799 }
1800 
1802 SQLBindCol(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
1803 {
1804  TDS_DESC *ard;
1805  struct _drecord *drec;
1806  SQLSMALLINT orig_ard_size;
1807 
1809 
1810  tdsdump_log(TDS_DBG_FUNC, "SQLBindCol(%p, %d, %d, %p, %d, %p)\n",
1811  hstmt, icol, fCType, rgbValue, (int)cbValueMax, pcbValue);
1812 
1813  /* TODO - More error checking XXX smurph */
1814 
1815 #ifdef TDS_NO_DM
1816  /* check conversion type */
1817  switch (fCType) {
1818  case SQL_C_CHAR:
1819  case SQL_C_WCHAR:
1820  case SQL_C_BINARY:
1821  case SQL_C_DEFAULT:
1822  /* check max buffer length */
1823  if (!IS_VALID_LEN(cbValueMax)) {
1824  odbc_errs_add(&stmt->errs, "HY090", NULL);
1825  ODBC_EXIT_(stmt);
1826  }
1827  break;
1828  }
1829 #endif
1830 
1831  if (icol <= 0 || icol > 4000) {
1832  odbc_errs_add(&stmt->errs, "07009", NULL);
1833  ODBC_EXIT_(stmt);
1834  }
1835 
1836  ard = stmt->ard;
1837  orig_ard_size = ard->header.sql_desc_count;
1838  if (icol > ard->header.sql_desc_count && desc_alloc_records(ard, icol) != SQL_SUCCESS) {
1839  odbc_errs_add(&stmt->errs, "HY001", NULL);
1840  ODBC_EXIT_(stmt);
1841  }
1842 
1843  drec = &ard->records[icol - 1];
1844 
1845  if (odbc_set_concise_c_type(fCType, drec, 0) != SQL_SUCCESS) {
1846  desc_alloc_records(ard, orig_ard_size);
1847  odbc_errs_add(&stmt->errs, "HY003", NULL);
1848  ODBC_EXIT_(stmt);
1849  }
1850  drec->sql_desc_octet_length = cbValueMax;
1851  drec->sql_desc_octet_length_ptr = pcbValue;
1852  drec->sql_desc_indicator_ptr = pcbValue;
1853  drec->sql_desc_data_ptr = rgbValue;
1854 
1855  /* force rebind */
1856  stmt->row = 0;
1857 
1858  ODBC_EXIT_(stmt);
1859 }
1860 
1863 {
1864  TDSSOCKET *tds;
1865 
1866  /*
1867  * FIXME this function can be called from other thread, do not free
1868  * errors for this function
1869  * If function is called from another thread errors are not touched
1870  */
1871  /* TODO some tests required */
1872  TDS_STMT *stmt = (TDS_STMT*)hstmt;
1873  if (SQL_NULL_HSTMT == hstmt || !IS_HSTMT(hstmt))
1874  return SQL_INVALID_HANDLE;
1875 
1876  tdsdump_log(TDS_DBG_FUNC, "SQLCancel(%p)\n", hstmt);
1877 
1878  tds_mutex_lock(&stmt->dbc->mtx);
1879  tds = stmt->tds;
1880  tds_mutex_unlock(&stmt->dbc->mtx);
1881 
1882  /* cancelling an inactive statement ?? */
1883  if (!tds) {
1885  ODBC_EXIT_(stmt);
1886  }
1887  if (tds_mutex_trylock(&stmt->mtx) == 0) {
1889  odbc_errs_reset(&stmt->errs);
1890 
1891  /* FIXME test current statement */
1892  /* FIXME here we are unlocked */
1893 
1894  if (TDS_FAILED(tds_send_cancel(tds))) {
1896  ODBC_EXIT_(stmt);
1897  }
1898 
1901  ODBC_EXIT_(stmt);
1902  }
1903 
1904  /* only if we processed cancel reset statement */
1905  if (tds->state == TDS_IDLE)
1907 
1908  ODBC_EXIT_(stmt);
1909  }
1910 
1911  /* don't access error here, just return error */
1913  return SQL_ERROR;
1914  return SQL_SUCCESS;
1915 }
1916 
1919 {
1920  TDSLOGIN *login;
1921  DSTR *s;
1922 
1924 
1925 #ifdef TDS_NO_DM
1926  if (szDSN && !IS_VALID_LEN(cbDSN)) {
1927  odbc_errs_add(&dbc->errs, "HY090", "Invalid DSN buffer length");
1928  ODBC_EXIT_(dbc);
1929  }
1930 
1931  if (szUID && !IS_VALID_LEN(cbUID)) {
1932  odbc_errs_add(&dbc->errs, "HY090", "Invalid UID buffer length");
1933  ODBC_EXIT_(dbc);
1934  }
1935 
1936  if (szAuthStr && !IS_VALID_LEN(cbAuthStr)) {
1937  odbc_errs_add(&dbc->errs, "HY090", "Invalid PWD buffer length");
1938  ODBC_EXIT_(dbc);
1939  }
1940 #endif
1941 
1942  login = tds_alloc_login(0);
1943  if (!login || !tds_init_login(login, dbc->env->tds_ctx->locale))
1944  goto memory_error;
1945 
1946  /* data source name */
1947  if (odbc_get_string_size(cbDSN, szDSN _wide))
1948  s = odbc_dstr_copy(dbc, &dbc->dsn, cbDSN, szDSN);
1949  else
1950  s = tds_dstr_copy(&dbc->dsn, "DEFAULT");
1951  if (!s)
1952  goto memory_error;
1953 
1954 
1955  if (!odbc_get_dsn_info(&dbc->errs, tds_dstr_cstr(&dbc->dsn), login)) {
1957  ODBC_EXIT_(dbc);
1958  }
1959 
1960  if (!tds_dstr_isempty(&dbc->attr.current_catalog))
1961  if (!tds_dstr_dup(&login->database, &dbc->attr.current_catalog))
1962  goto memory_error;
1963 
1964  /*
1965  * username/password are never saved to ini file,
1966  * so you do not check in ini file
1967  */
1968  /* user id */
1969  if (odbc_get_string_size(cbUID, szUID _wide)) {
1970  if (!odbc_dstr_copy(dbc, &login->user_name, cbUID, szUID))
1971  goto memory_error;
1972  }
1973 
1974  /* password */
1975  if (szAuthStr && !tds_dstr_isempty(&login->user_name)) {
1976  if (!odbc_dstr_copy(dbc, &login->password, cbAuthStr, szAuthStr))
1977  goto memory_error;
1978  }
1979 
1980  /* DO IT */
1982 
1984  ODBC_EXIT_(dbc);
1985 
1986 memory_error:
1988  odbc_errs_add(&dbc->errs, "HY001", NULL);
1989  ODBC_EXIT_(dbc);
1990 }
1991 
1993  P(SQLSMALLINT FAR *,pfSqlType), P(SQLULEN FAR *,pcbColDef),
1994  P(SQLSMALLINT FAR *,pibScale), P(SQLSMALLINT FAR *,pfNullable) WIDE))
1995 {
1996  TDS_DESC *ird;
1997  struct _drecord *drec;
1998  SQLRETURN result;
1999 
2001 
2002  ird = stmt->ird;
2003  IRD_UPDATE(ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
2004 
2005  if (icol <= 0 || icol > ird->header.sql_desc_count) {
2006  odbc_errs_add(&stmt->errs, "07009", "Column out of range");
2007  ODBC_EXIT_(stmt);
2008  }
2009  /* check name length */
2010  if (cbColNameMax < 0) {
2011  odbc_errs_add(&stmt->errs, "HY090", NULL);
2012  ODBC_EXIT_(stmt);
2013  }
2014  drec = &ird->records[icol - 1];
2015 
2016  /* cbColNameMax can be 0 (to retrieve name length) */
2017  if (szColName == NULL)
2018  cbColNameMax = 0;
2019 
2020  /* straight copy column name up to cbColNameMax */
2021  result = odbc_set_string(stmt->dbc, szColName, cbColNameMax, pcbColName, tds_dstr_cstr(&drec->sql_desc_label), -1);
2022  if (szColName && result == SQL_SUCCESS_WITH_INFO)
2023  odbc_errs_add(&stmt->errs, "01004", NULL);
2024 
2025  if (pfSqlType) {
2026  /* TODO sure ? check documentation for date and intervals */
2027  *pfSqlType = drec->sql_desc_concise_type;
2028  }
2029 
2030  if (pcbColDef) {
2031  if (drec->sql_desc_type == SQL_NUMERIC || drec->sql_desc_type == SQL_DECIMAL) {
2032  *pcbColDef = drec->sql_desc_precision;
2033  } else {
2034  *pcbColDef = drec->sql_desc_length;
2035  }
2036  }
2037  if (pibScale) {
2038  *pibScale = drec->sql_desc_scale;
2039  }
2040  if (pfNullable) {
2041  *pfNullable = drec->sql_desc_nullable;
2042  }
2043  ODBC_EXIT_(stmt);
2044 }
2045 
2046 static SQLRETURN
2047 _SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax,
2048  SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc _WIDE)
2049 {
2050  TDS_DESC *ird;
2051  struct _drecord *drec;
2053 
2055 
2056  tdsdump_log(TDS_DBG_FUNC, "_SQLColAttribute(%p, %u, %u, %p, %d, %p, %p)\n",
2057  hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2058 
2059  ird = stmt->ird;
2060 
2061 #define COUT(src) result = odbc_set_string_oct(stmt->dbc, rgbDesc, cbDescMax, pcbDesc, src ? src : "", -1);
2062 #define SOUT(src) result = odbc_set_string_oct(stmt->dbc, rgbDesc, cbDescMax, pcbDesc, tds_dstr_cstr(&src), -1);
2063 
2064 /* SQLColAttribute returns always attributes using SQLINTEGER */
2065 #if ENABLE_EXTRA_CHECKS
2066 #define IOUT(type, src) do { \
2067  /* trick warning if type wrong */ \
2068  type *p_test = &src; p_test = p_test; \
2069  *pfDesc = src; } while(0)
2070 #else
2071 #define IOUT(type, src) *pfDesc = src
2072 #endif
2073 
2074  IRD_UPDATE(ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
2075 
2076  /* dont check column index for these */
2077  switch (fDescType) {
2078 #if SQL_COLUMN_COUNT != SQL_DESC_COUNT
2079  case SQL_COLUMN_COUNT:
2080 #endif
2081  case SQL_DESC_COUNT:
2084  break;
2085  }
2086 
2087  if (!ird->header.sql_desc_count) {
2088  odbc_errs_add(&stmt->errs, "07005", NULL);
2089  ODBC_EXIT_(stmt);
2090  }
2091 
2092  if (icol <= 0 || icol > ird->header.sql_desc_count) {
2093  odbc_errs_add(&stmt->errs, "07009", "Column out of range");
2094  ODBC_EXIT_(stmt);
2095  }
2096  drec = &ird->records[icol - 1];
2097 
2098  tdsdump_log(TDS_DBG_INFO1, "SQLColAttribute: fDescType is %d\n", fDescType);
2099 
2100  switch (fDescType) {
2103  break;
2106  break;
2109  break;
2112  break;
2113  case SQL_DESC_CATALOG_NAME:
2114  SOUT(drec->sql_desc_catalog_name);
2115  break;
2116 #if SQL_COLUMN_TYPE != SQL_DESC_CONCISE_TYPE
2117  case SQL_COLUMN_TYPE:
2118 #endif
2119  case SQL_DESC_CONCISE_TYPE:
2120  /* special case, get ODBC 2 type, not ODBC 3 SQL_DESC_CONCISE_TYPE (different for datetime) */
2121  if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
2123  break;
2124  }
2125 
2126  /* get type and convert it to ODBC 2 type */
2127  {
2129 
2130  switch (type) {
2131  case SQL_TYPE_DATE:
2132  type = SQL_DATE;
2133  break;
2134  case SQL_TYPE_TIME:
2135  type = SQL_TIME;
2136  break;
2137  case SQL_TYPE_TIMESTAMP:
2138  type = SQL_TIMESTAMP;
2139  break;
2140  }
2141  IOUT(SQLSMALLINT, type);
2142  }
2143  break;
2144  case SQL_DESC_DISPLAY_SIZE:
2146  break;
2149  break;
2150  case SQL_DESC_LABEL:
2151  SOUT(drec->sql_desc_label);
2152  break;
2153  /* FIXME special cases for SQL_COLUMN_LENGTH */
2154  case SQL_COLUMN_LENGTH:
2156  break;
2157  case SQL_DESC_LENGTH:
2158  IOUT(SQLULEN, drec->sql_desc_length);
2159  break;
2162  break;
2165  break;
2168  break;
2169 #if SQL_COLUMN_NAME != SQL_DESC_NAME
2170  case SQL_COLUMN_NAME:
2171 #endif
2172  case SQL_DESC_NAME:
2173  SOUT(drec->sql_desc_name);
2174  break;
2175 #if SQL_COLUMN_NULLABLE != SQL_DESC_NULLABLE
2176  case SQL_COLUMN_NULLABLE:
2177 #endif
2178  case SQL_DESC_NULLABLE:
2180  break;
2183  break;
2184  case SQL_DESC_OCTET_LENGTH:
2186  break;
2187  /* FIXME special cases for SQL_COLUMN_PRECISION */
2188  case SQL_COLUMN_PRECISION:
2189  if (drec->sql_desc_concise_type == SQL_REAL) {
2190  *pfDesc = 7;
2191  break;
2192  }
2193  if (drec->sql_desc_concise_type == SQL_DOUBLE) {
2194  *pfDesc = 15;
2195  break;
2196  }
2198  *pfDesc = drec->sql_desc_precision ? 23 : 16;
2199  break;
2200  }
2201  case SQL_DESC_PRECISION: /* this section may be wrong */
2209  else
2210  *pfDesc = drec->sql_desc_length;
2211  break;
2212  /* FIXME special cases for SQL_COLUMN_SCALE */
2213  case SQL_COLUMN_SCALE:
2214  case SQL_DESC_SCALE: /* this section may be wrong */
2219  || drec->sql_desc_concise_type == SQL_FLOAT
2223  else
2224  *pfDesc = 0;
2225  break;
2226  case SQL_DESC_SCHEMA_NAME:
2227  SOUT(drec->sql_desc_schema_name);
2228  break;
2229  case SQL_DESC_SEARCHABLE:
2231  break;
2232  case SQL_DESC_TABLE_NAME:
2233  SOUT(drec->sql_desc_table_name);
2234  break;
2235  case SQL_DESC_TYPE:
2236  IOUT(SQLSMALLINT, drec->sql_desc_type);
2237  break;
2238  case SQL_DESC_TYPE_NAME:
2239  COUT(drec->sql_desc_type_name);
2240  break;
2241  case SQL_DESC_UNNAMED:
2243  break;
2244  case SQL_DESC_UNSIGNED:
2246  break;
2247  case SQL_DESC_UPDATABLE:
2249  break;
2250  default:
2251  tdsdump_log(TDS_DBG_INFO2, "SQLColAttribute: fDescType %d not catered for...\n", fDescType);
2252  odbc_errs_add(&stmt->errs, "HY091", NULL);
2253  ODBC_EXIT_(stmt);
2254  break;
2255  }
2256 
2258  odbc_errs_add(&stmt->errs, "01004", NULL);
2259 
2260  ODBC_EXIT(stmt, result);
2261 
2262 #undef COUT
2263 #undef SOUT
2264 #undef IOUT
2265 }
2266 
2269  SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc)
2270 {
2271  tdsdump_log(TDS_DBG_FUNC, "SQLColAttributes(%p, %d, %d, %p, %d, %p, %p)\n",
2272  hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2273 
2274  return _SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc _wide0);
2275 }
2276 
2277 #if (ODBCVER >= 0x0300)
2279 SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType,
2280  SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc,
2281 #ifdef TDS_SQLCOLATTRIBUTE_SQLLEN
2282  SQLLEN FAR * pfDesc
2283 #else
2284  SQLPOINTER pfDesc
2285 #endif
2286  )
2287 {
2288 
2289  return _SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax,
2290  pcbDesc, (SQLLEN*) pfDesc _wide0);
2291 }
2292 
2293 #ifdef ENABLE_ODBC_WIDE
2295 SQLColAttributeW(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType,
2296  SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc,
2297 #ifdef TDS_SQLCOLATTRIBUTE_SQLLEN
2298  SQLLEN FAR * pfDesc
2299 #else
2300  SQLPOINTER pfDesc
2301 #endif
2302  )
2303 {
2304  tdsdump_log(TDS_DBG_FUNC, "SQLColAttributeW(%p, %u, %u, %p, %d, %p, %p)\n",
2305  hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2306 
2307  return _SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc, 1);
2308 }
2309 #endif
2310 #endif
2311 
2314 {
2315  int i;
2316  struct _hstmt *stmt, *next;
2317 
2319 
2320  tdsdump_log(TDS_DBG_FUNC, "SQLDisconnect(%p)\n", hdbc);
2321 
2322  /* free all associated statements */
2323  for (stmt = dbc->stmt_list; stmt != NULL; stmt = next) {
2324  next = stmt->next;
2325  tds_mutex_unlock(&dbc->mtx);
2326  _SQLFreeStmt(stmt, SQL_DROP, 1);
2327  tds_mutex_lock(&dbc->mtx);
2328  }
2329 
2330  /* free all associated descriptors */
2331  for (i = 0; i < TDS_MAX_APP_DESC; ++i) {
2332  if (dbc->uad[i]) {
2333  desc_free(dbc->uad[i]);
2334  dbc->uad[i] = NULL;
2335  }
2336  }
2337 
2338 #ifdef ENABLE_ODBC_WIDE
2339  dbc->mb_conv = NULL;
2340 #endif
2341  tds_close_socket(dbc->tds_socket);
2342  tds_free_socket(dbc->tds_socket);
2343  dbc->tds_socket = NULL;
2344  dbc->cursor_support = 0;
2345 
2346  ODBC_EXIT_(dbc);
2347 }
2348 
2349 static int
2351 {
2352  struct _sql_errors *errs = NULL;
2353  TDS_DBC *dbc = NULL;
2354  TDS_STMT *stmt = NULL;
2355 
2356  tdsdump_log(TDS_DBG_INFO1, "msgno %d %d\n", (int) msg->msgno, TDSETIME);
2357 
2358  if (msg->msgno == TDSETIME) {
2359 
2360  tdsdump_log(TDS_DBG_INFO1, "in timeout\n");
2361  if (!tds)
2362  return TDS_INT_CANCEL;
2363 
2364  if ((stmt = odbc_get_stmt(tds)) != NULL) {
2365  /* first time, try to send a cancel */
2366  if (!tds->in_cancel) {
2367  odbc_errs_add(&stmt->errs, "HYT00", "Timeout expired");
2368  tdsdump_log(TDS_DBG_INFO1, "returning from timeout\n");
2369  return TDS_INT_TIMEOUT;
2370  }
2371  } else if ((dbc = odbc_get_dbc(tds)) != NULL) {
2372  odbc_errs_add(&dbc->errs, "HYT00", "Timeout expired");
2373  }
2374 
2376  tdsdump_log(TDS_DBG_INFO1, "returning cancel from timeout\n");
2377  return TDS_INT_CANCEL;
2378  }
2379 
2380  if (tds && (dbc = odbc_get_dbc(tds)) != NULL) {
2381  errs = &dbc->errs;
2382  stmt = odbc_get_stmt(tds);
2383  if (stmt)
2384  errs = &stmt->errs;
2385  } else if (ctx->parent) {
2386  errs = &((TDS_ENV *) ctx->parent)->errs;
2387  }
2388  if (errs) {
2389  int severity = msg->severity;
2390  const char * state = msg->sql_state;
2391 
2392  /* fix severity for Sybase */
2393  if (severity <= 10 && dbc && !TDS_IS_MSSQL(dbc->tds_socket) && msg->sql_state && msg->sql_state[0]
2394  && strncmp(msg->sql_state, "00", 2) != 0) {
2395  if (strncmp(msg->sql_state, "01", 2) != 0 && strncmp(msg->sql_state, "IM", 2) != 0)
2396  severity = 11;
2397  }
2398 
2399  /* compute state if not available */
2400  if (!state)
2401  state = severity <= 10 ? "01000" : "42000";
2402  /* add error, do not overwrite connection timeout error */
2403  if (msg->msgno != TDSEFCON || errs->lastrc != SQL_ERROR || errs->num_errors < 1)
2404  odbc_errs_add_rdbms(errs, msg->msgno, state, msg->message, msg->line_number, msg->severity,
2405  msg->server, stmt ? stmt->curr_param_row + 1 : 0);
2406 
2407  /* set lastc according */
2408  if (severity <= 10) {
2409  if (errs->lastrc == SQL_SUCCESS)
2410  errs->lastrc = SQL_SUCCESS_WITH_INFO;
2411  } else {
2412  errs->lastrc = SQL_ERROR;
2413  }
2414  }
2415  return TDS_INT_CANCEL;
2416 }
2417 
2418 /* TODO optimize, change only if some data change (set same value should not set this flag) */
2419 #define DESC_SET_NEED_REPREPARE \
2420  do {\
2421  if (desc->type == DESC_IPD) {\
2422  assert(IS_HSTMT(desc->parent));\
2423  ((TDS_STMT *) desc->parent)->need_reprepare = 1;\
2424  }\
2425  } while(0)
2426 
2428 SQLSetDescRec(SQLHDESC hdesc, SQLSMALLINT nRecordNumber, SQLSMALLINT nType, SQLSMALLINT nSubType, SQLLEN nLength,
2429  SQLSMALLINT nPrecision, SQLSMALLINT nScale, SQLPOINTER pData, SQLLEN FAR * pnStringLength, SQLLEN FAR * pnIndicator)
2430 {
2431  struct _drecord *drec;
2432  SQLSMALLINT concise_type;
2433 
2435 
2436  tdsdump_log(TDS_DBG_FUNC, "SQLSetDescRec(%p, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n",
2437  hdesc, nRecordNumber, nType, nSubType, (int)nLength, nPrecision, nScale, pData, pnStringLength, pnIndicator);
2438 
2439  if (desc->type == DESC_IRD) {
2440  odbc_errs_add(&desc->errs, "HY016", NULL);
2441  ODBC_EXIT_(desc);
2442  }
2443 
2444  if (nRecordNumber > desc->header.sql_desc_count || nRecordNumber <= 0) {
2445  odbc_errs_add(&desc->errs, "07009", NULL);
2446  ODBC_EXIT_(desc);
2447  }
2448 
2449  drec = &desc->records[nRecordNumber - 1];
2450 
2451  /* check for valid types and return "HY021" if not */
2452  if (desc->type == DESC_IPD) {
2454  concise_type = odbc_get_concise_sql_type(nType, nSubType);
2455  } else {
2456  concise_type = odbc_get_concise_c_type(nType, nSubType);
2457  }
2458  if (nType == SQL_INTERVAL || nType == SQL_DATETIME) {
2459  if (!concise_type) {
2460  odbc_errs_add(&desc->errs, "HY021", NULL);
2461  ODBC_EXIT_(desc);
2462  }
2463  } else {
2464  if (concise_type != nType) {
2465  odbc_errs_add(&desc->errs, "HY021", NULL);
2466  ODBC_EXIT_(desc);
2467  }
2468  nSubType = 0;
2469  }
2470  drec->sql_desc_concise_type = concise_type;
2471  drec->sql_desc_type = nType;
2472  drec->sql_desc_datetime_interval_code = nSubType;
2473 
2474  drec->sql_desc_octet_length = nLength;
2475  drec->sql_desc_precision = nPrecision;
2476  drec->sql_desc_scale = nScale;
2477  drec->sql_desc_data_ptr = pData;
2478  drec->sql_desc_octet_length_ptr = pnStringLength;
2479  drec->sql_desc_indicator_ptr = pnIndicator;
2480 
2481  ODBC_EXIT_(desc);
2482 }
2483 
2484 ODBC_FUNC(SQLGetDescRec, (P(SQLHDESC,hdesc), P(SQLSMALLINT,RecordNumber), PCHAROUT(Name,SQLSMALLINT),
2485  P(SQLSMALLINT *,Type), P(SQLSMALLINT *,SubType), P(SQLLEN FAR *,Length),
2486  P(SQLSMALLINT *,Precision), P(SQLSMALLINT *,Scale), P(SQLSMALLINT *,Nullable) WIDE))
2487 {
2488  struct _drecord *drec = NULL;
2489  SQLRETURN rc = SQL_SUCCESS;
2490 
2492 
2493  if (RecordNumber <= 0) {
2494  odbc_errs_add(&desc->errs, "07009", NULL);
2495  ODBC_EXIT_(desc);
2496  }
2497 
2498  IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2499  if (RecordNumber > desc->header.sql_desc_count)
2500  ODBC_EXIT(desc, SQL_NO_DATA);
2501 
2502  if (desc->type == DESC_IRD && !desc->header.sql_desc_count) {
2503  odbc_errs_add(&desc->errs, "HY007", NULL);
2504  ODBC_EXIT_(desc);
2505  }
2506 
2507  drec = &desc->records[RecordNumber - 1];
2508 
2509  if ((rc = odbc_set_string(desc_get_dbc(desc), szName, cbNameMax, pcbName, tds_dstr_cstr(&drec->sql_desc_name), -1)) != SQL_SUCCESS)
2510  odbc_errs_add(&desc->errs, "01004", NULL);
2511 
2512  if (Type)
2513  *Type = drec->sql_desc_type;
2514  if (Length)
2515  *Length = drec->sql_desc_octet_length;
2516  if (Precision)
2517  *Precision = drec->sql_desc_precision;
2518  if (Scale)
2519  *Scale = drec->sql_desc_scale;
2520  if (SubType)
2521  *SubType = drec->sql_desc_datetime_interval_code;
2522  if (Nullable)
2523  *Nullable = drec->sql_desc_nullable;
2524 
2525  ODBC_EXIT(desc, rc);
2526 }
2527 
2529  P(SQLINTEGER,BufferLength), P(SQLINTEGER *,StringLength) WIDE))
2530 {
2531  struct _drecord *drec;
2533 
2535 
2536 #define COUT(src) result = odbc_set_string_oct(desc_get_dbc(desc), Value, BufferLength, StringLength, src, -1);
2537 #define SOUT(src) result = odbc_set_string_oct(desc_get_dbc(desc), Value, BufferLength, StringLength, tds_dstr_cstr(&src), -1);
2538 
2539 #if ENABLE_EXTRA_CHECKS
2540 #define IOUT(type, src) do { \
2541  /* trick warning if type wrong */ \
2542  type *p_test = &src; p_test = p_test; \
2543  *((type *)Value) = src; } while(0)
2544 #else
2545 #define IOUT(type, src) *((type *)Value) = src
2546 #endif
2547 
2548  /* dont check column index for these */
2549  switch (fDescType) {
2550  case SQL_DESC_ALLOC_TYPE:
2551  IOUT(SQLSMALLINT, desc->header.sql_desc_alloc_type);
2552  ODBC_EXIT_(desc);
2553  break;
2554  case SQL_DESC_ARRAY_SIZE:
2555  IOUT(SQLULEN, desc->header.sql_desc_array_size);
2556  ODBC_EXIT_(desc);
2557  break;
2559  IOUT(SQLUSMALLINT *, desc->header.sql_desc_array_status_ptr);
2560  ODBC_EXIT_(desc);
2561  break;
2563  IOUT(SQLLEN *, desc->header.sql_desc_bind_offset_ptr);
2564  ODBC_EXIT_(desc);
2565  break;
2566  case SQL_DESC_BIND_TYPE:
2567  IOUT(SQLINTEGER, desc->header.sql_desc_bind_type);
2568  ODBC_EXIT_(desc);
2569  break;
2570  case SQL_DESC_COUNT:
2571  IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2572  IOUT(SQLSMALLINT, desc->header.sql_desc_count);
2573  ODBC_EXIT_(desc);
2574  break;
2576  IOUT(SQLULEN *, desc->header.sql_desc_rows_processed_ptr);
2577  ODBC_EXIT_(desc);
2578  break;
2579  }
2580 
2581  IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2582  if (!desc->header.sql_desc_count) {
2583  odbc_errs_add(&desc->errs, "07005", NULL);
2584  ODBC_EXIT_(desc);
2585  }
2586 
2587  if (icol < 1) {
2588  odbc_errs_add(&desc->errs, "07009", "Column out of range");
2589  ODBC_EXIT_(desc);
2590  }
2591  if (icol > desc->header.sql_desc_count)
2592  ODBC_EXIT(desc, SQL_NO_DATA);
2593  drec = &desc->records[icol - 1];
2594 
2595  tdsdump_log(TDS_DBG_INFO1, "SQLGetDescField: fDescType is %d\n", fDescType);
2596 
2597  switch (fDescType) {
2600  break;
2603  break;
2606  break;
2609  break;
2610  case SQL_DESC_CATALOG_NAME:
2611  SOUT(drec->sql_desc_catalog_name);
2612  break;
2613  case SQL_DESC_CONCISE_TYPE:
2615  break;
2616  case SQL_DESC_DATA_PTR:
2618  break;
2621  break;
2624  break;
2625  case SQL_DESC_DISPLAY_SIZE:
2627  break;
2630  break;
2633  break;
2634  case SQL_DESC_LABEL:
2635  SOUT(drec->sql_desc_label);
2636  break;
2637  case SQL_DESC_LENGTH:
2638  IOUT(SQLULEN, drec->sql_desc_length);
2639  break;
2642  break;
2645  break;
2648  break;
2649  case SQL_DESC_NAME:
2650  SOUT(drec->sql_desc_name);
2651  break;
2652  case SQL_DESC_NULLABLE:
2654  break;
2657  break;
2658  case SQL_DESC_OCTET_LENGTH:
2660  break;
2663  break;
2666  break;
2667  case SQL_DESC_PRECISION:
2672  else
2673  /* TODO support date/time */
2674  *((SQLSMALLINT *) Value) = 0;
2675  break;
2676 #ifdef SQL_DESC_ROWVER
2677  case SQL_DESC_ROWVER:
2679  break;
2680 #endif
2681  case SQL_DESC_SCALE:
2685  || drec->sql_desc_concise_type == SQL_FLOAT)
2687  else
2688  *((SQLSMALLINT *) Value) = 0;
2689  break;
2690  case SQL_DESC_SCHEMA_NAME:
2691  SOUT(drec->sql_desc_schema_name);
2692  break;
2693  case SQL_DESC_SEARCHABLE:
2695  break;
2696  case SQL_DESC_TABLE_NAME:
2697  SOUT(drec->sql_desc_table_name);
2698  break;
2699  case SQL_DESC_TYPE:
2700  IOUT(SQLSMALLINT, drec->sql_desc_type);
2701  break;
2702  case SQL_DESC_TYPE_NAME:
2703  COUT(drec->sql_desc_type_name);
2704  break;
2705  case SQL_DESC_UNNAMED:
2707  break;
2708  case SQL_DESC_UNSIGNED:
2710  break;
2711  case SQL_DESC_UPDATABLE:
2713  break;
2714  default:
2715  odbc_errs_add(&desc->errs, "HY091", NULL);
2716  ODBC_EXIT_(desc);
2717  break;
2718  }
2719 
2721  odbc_errs_add(&desc->errs, "01004", NULL);
2722 
2723  ODBC_EXIT(desc, result);
2724 
2725 #undef COUT
2726 #undef SOUT
2727 #undef IOUT
2728 }
2729 
2730 ODBC_FUNC(SQLSetDescField, (P(SQLHDESC,hdesc), P(SQLSMALLINT,icol), P(SQLSMALLINT,fDescType),
2731  P(SQLPOINTER,Value), P(SQLINTEGER,BufferLength) WIDE))
2732 {
2733  struct _drecord *drec;
2735 
2737 
2738 #if ENABLE_EXTRA_CHECKS
2739 #define IIN(type, dest) do { \
2740  /* trick warning if type wrong */ \
2741  type *p_test = &dest; p_test = p_test; \
2742  dest = (type)(TDS_INTPTR)Value; } while(0)
2743 #define PIN(type, dest) do { \
2744  /* trick warning if type wrong */ \
2745  type *p_test = &dest; p_test = p_test; \
2746  dest = (type)Value; } while(0)
2747 #else
2748 #define IIN(type, dest) dest = (type)(TDS_INTPTR)Value
2749 #define PIN(type, dest) dest = (type)Value
2750 #endif
2751 
2752  /* special case for IRD */
2753  if (desc->type == DESC_IRD && fDescType != SQL_DESC_ARRAY_STATUS_PTR && fDescType != SQL_DESC_ROWS_PROCESSED_PTR) {
2754  odbc_errs_add(&desc->errs, "HY016", NULL);
2755  ODBC_EXIT_(desc);
2756  }
2757 
2758  /* dont check column index for these */
2759  switch (fDescType) {
2760  case SQL_DESC_ALLOC_TYPE:
2761  odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2762  ODBC_EXIT_(desc);
2763  break;
2764  case SQL_DESC_ARRAY_SIZE:
2765  IIN(SQLULEN, desc->header.sql_desc_array_size);
2766  ODBC_EXIT_(desc);
2767  break;
2769  PIN(SQLUSMALLINT *, desc->header.sql_desc_array_status_ptr);
2770  ODBC_EXIT_(desc);
2771  break;
2773  PIN(SQLULEN *, desc->header.sql_desc_rows_processed_ptr);
2774  ODBC_EXIT_(desc);
2775  break;
2776  case SQL_DESC_BIND_TYPE:
2777  IIN(SQLINTEGER, desc->header.sql_desc_bind_type);
2778  ODBC_EXIT_(desc);
2779  break;
2780  case SQL_DESC_COUNT:
2781  {
2782  int n = (int) (TDS_INTPTR) Value;
2783 
2784  if (n <= 0 || n > 4000) {
2785  odbc_errs_add(&desc->errs, "07009", NULL);
2786  ODBC_EXIT_(desc);
2787  }
2788  result = desc_alloc_records(desc, n);
2789  if (result == SQL_ERROR)
2790  odbc_errs_add(&desc->errs, "HY001", NULL);
2791  ODBC_EXIT(desc, result);
2792  }
2793  break;
2794  }
2795 
2796  if (!desc->header.sql_desc_count) {
2797  odbc_errs_add(&desc->errs, "07005", NULL);
2798  ODBC_EXIT_(desc);
2799  }
2800 
2801  if (icol <= 0 || icol > desc->header.sql_desc_count) {
2802  odbc_errs_add(&desc->errs, "07009", "Column out of range");
2803  ODBC_EXIT_(desc);
2804  }
2805  drec = &desc->records[icol - 1];
2806 
2807  tdsdump_log(TDS_DBG_INFO1, "SQLColAttributes: fDescType is %d\n", fDescType);
2808 
2809  switch (fDescType) {
2814  case SQL_DESC_CATALOG_NAME:
2815  odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2816  result = SQL_ERROR;
2817  break;
2818  case SQL_DESC_CONCISE_TYPE:
2820  if (desc->type == DESC_IPD)
2822  else
2824  if (result != SQL_SUCCESS)
2825  odbc_errs_add(&desc->errs, "HY021", NULL);
2826  break;
2827  case SQL_DESC_DATA_PTR:
2829  break;
2830  /* TODO SQL_DESC_DATETIME_INTERVAL_CODE remember to check sql_desc_type */
2831  /* TODO SQL_DESC_DATETIME_INTERVAL_PRECISION */
2832  case SQL_DESC_DISPLAY_SIZE:
2834  odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2835  result = SQL_ERROR;
2836  break;
2838  PIN(SQLLEN *, drec->sql_desc_indicator_ptr);
2839  break;
2840  case SQL_DESC_LABEL:
2841  odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2842  result = SQL_ERROR;
2843  break;
2844  case SQL_DESC_LENGTH:
2846  IIN(SQLULEN, drec->sql_desc_length);
2847  break;
2851  odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2852  result = SQL_ERROR;
2853  break;
2854  case SQL_DESC_NAME:
2855  if (!odbc_dstr_copy_oct(desc_get_dbc(desc), &drec->sql_desc_name, BufferLength, (ODBC_CHAR*) Value)) {
2856  odbc_errs_add(&desc->errs, "HY001", NULL);
2857  result = SQL_ERROR;
2858  }
2859  break;
2860  case SQL_DESC_NULLABLE:
2861  odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2862  result = SQL_ERROR;
2863  break;
2866  break;
2867  case SQL_DESC_OCTET_LENGTH:
2870  break;
2873  break;
2877  break;
2878  case SQL_DESC_PRECISION:
2880  /* TODO correct ?? */
2883  else
2884  IIN(SQLULEN, drec->sql_desc_length);
2885  break;
2886 #ifdef SQL_DESC_ROWVER
2887  case SQL_DESC_ROWVER:
2888  odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2889  result = SQL_ERROR;
2890  break;
2891 #endif
2892  case SQL_DESC_SCALE:
2895  IIN(SQLSMALLINT, drec->sql_desc_scale);
2896  else
2897  /* TODO even for datetime/money ?? */
2898  drec->sql_desc_scale = 0;
2899  break;
2900  case SQL_DESC_SCHEMA_NAME:
2901  case SQL_DESC_SEARCHABLE:
2902  case SQL_DESC_TABLE_NAME:
2903  odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2904  result = SQL_ERROR;
2905  break;
2906  case SQL_DESC_TYPE:
2908  IIN(SQLSMALLINT, drec->sql_desc_type);
2909  /* FIXME what happen for interval/datetime ?? */
2910  drec->sql_desc_concise_type = drec->sql_desc_type;
2911  break;
2912  case SQL_DESC_TYPE_NAME:
2913  odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2914  result = SQL_ERROR;
2915  break;
2916  case SQL_DESC_UNNAMED:
2918  break;
2919  case SQL_DESC_UNSIGNED:
2920  case SQL_DESC_UPDATABLE:
2921  odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2922  result = SQL_ERROR;
2923  break;
2924  default:
2925  odbc_errs_add(&desc->errs, "HY091", NULL);
2926  ODBC_EXIT_(desc);
2927  break;
2928  }
2929 
2930 #undef IIN
2931 
2932  ODBC_EXIT(desc, result);
2933 }
2934 
2937 {
2938  TDS_DESC *src;
2939 
2941 
2942  tdsdump_log(TDS_DBG_FUNC, "SQLCopyDesc(%p, %p)\n",
2943  hsrc, hdesc);
2944 
2945  if (SQL_NULL_HDESC == hsrc || !IS_HDESC(hsrc))
2946  return SQL_INVALID_HANDLE;
2947  src = (TDS_DESC *) hsrc;
2948  CHECK_DESC_EXTRA(src);
2949 
2950  /* do not write on IRD */
2951  if (desc->type == DESC_IRD) {
2952  odbc_errs_add(&desc->errs, "HY016", NULL);
2953  ODBC_EXIT_(desc);
2954  }
2955  IRD_UPDATE(src, &src->errs, ODBC_EXIT(desc, SQL_ERROR));
2956 
2957  ODBC_EXIT(desc, desc_copy(desc, src));
2958 }
2959 
2960 #if ENABLE_EXTRA_CHECKS
2961 static void
2962 odbc_ird_check(TDS_STMT * stmt)
2963 {
2964 #if !ENABLE_ODBC_MARS
2965  TDS_DESC *ird = stmt->ird;
2966  TDSRESULTINFO *res_info = NULL;
2967  int cols = 0, i;
2968 
2969  if (!stmt->tds)
2970  return;
2971  if (stmt->tds->current_results) {
2972  res_info = stmt->tds->current_results;
2973  cols = res_info->num_cols;
2974  }
2975  if (stmt->cursor != NULL)
2976  return;
2977 
2978  /* check columns number */
2979  assert(ird->header.sql_desc_count <= cols || ird->header.sql_desc_count == 0);
2980 
2981 
2982  /* check all columns */
2983  for (i = 0; i < ird->header.sql_desc_count; ++i) {
2984  struct _drecord *drec = &ird->records[i];
2985  TDSCOLUMN *col = res_info->columns[i];
2986 
2988  }
2989 #endif
2990 }
2991 #endif
2992 
2993 static void
2994 odbc_unquote(char *buf, size_t buf_len, const char *start, const char *end)
2995 {
2996  char quote;
2997  assert(buf_len > 0);
2998 
2999  /* empty string */
3000  if (start >= end) {
3001  buf[0] = 0;
3002  return;
3003  }
3004 
3005  /* not quoted */
3006  if (*start != '[' && *start != '\"') {
3007  --buf_len;
3008  if (end < start + buf_len)
3009  buf_len = end - start;
3010  memcpy(buf, start, buf_len);
3011  buf[buf_len] = 0;
3012  return;
3013  }
3014 
3015  /* quoted... unquote */
3016  quote = (*start == '[') ? ']' : *start;
3017  ++start;
3018  while (buf_len > 0 && start < end) {
3019  if (*start == quote)
3020  if (++start >= end)
3021  break;
3022  *buf++ = *start++;
3023  --buf_len;
3024  }
3025  *buf = 0;
3026 }
3027 
3028 /* FIXME check result !!! */
3029 static SQLRETURN
3031 {
3032  TDS_DESC *ird = stmt->ird;
3033  struct _drecord *drec;
3034  TDSCOLUMN *col;
3035  TDSRESULTINFO *res_info;
3036  int num_cols;
3037  int i;
3038 
3039  desc_free_records(ird);
3040  if (!stmt->tds || !(res_info = stmt->tds->current_results))
3041  return SQL_SUCCESS;
3042  if (res_info == stmt->tds->param_info)
3043  return SQL_SUCCESS;
3044  num_cols = res_info->num_cols;
3045 
3046  /* ignore hidden columns... TODO correct? */
3047  while (num_cols > 0 && res_info->columns[num_cols - 1]->column_hidden == 1)
3048  --num_cols;
3049 
3050  if (desc_alloc_records(ird, num_cols) != SQL_SUCCESS)
3051  goto memory_error;
3052 
3053  for (i = 0; i < num_cols; i++) {
3054  drec = &ird->records[i];
3055  col = res_info->columns[i];
3057  /* TODO SQL_FALSE ?? */
3059 
3060  /*
3061  * TODO how to handle when in datetime we change precision ??
3062  * should we change display size too ??
3063  * is formatting function correct ??
3064  * we should not convert to string with invalid precision!
3065  */
3066  odbc_set_sql_type_info(col, drec, stmt->dbc->env->attr.odbc_version);
3067 
3069  if (!tds_dstr_dup(&drec->sql_desc_label, &col->column_name))
3070  goto memory_error;
3071 
3072  if (tds_dstr_isempty(&col->table_column_name)) {
3073  if (!tds_dstr_dup(&drec->sql_desc_name, &col->column_name))
3074  goto memory_error;
3075  } else {
3076  if (!tds_dstr_dup(&drec->sql_desc_name, &col->table_column_name))
3077  goto memory_error;
3079  goto memory_error;
3080  }
3081 
3082  /* extract sql_desc_(catalog/schema/base_table)_name */
3083  /* TODO extract them dinamically (when needed) ? */
3084  /* TODO store in libTDS in different way (separately) ? */
3085  if (!tds_dstr_isempty(&col->table_name)) {
3086  struct {
3087  const char *start;
3088  const char *end;
3089  } partials[4];
3090  const char *p;
3091  char buf[256];
3092  int i;
3093 
3094  p = tds_dstr_cstr(&col->table_name);
3095  for (i = 0; ; ++i) {
3096  const char *pend;
3097 
3098  if (*p == '[' || *p == '\"') {
3099  pend = tds_skip_quoted(p);
3100  } else {
3101  pend = strchr(p, '.');
3102  if (!pend)
3103  pend = strchr(p, 0);
3104  }
3105  partials[i].start = p;
3106  partials[i].end = pend;
3107  p = pend;
3108  if (i == 3 || *p != '.')
3109  break;
3110  ++p;
3111  }
3112 
3113  /* here i points to last element */
3114  odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3116  goto memory_error;
3117 
3118  --i;
3119  if (i >= 0) {
3120  odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3121  if (!tds_dstr_copy(&drec->sql_desc_schema_name, buf))
3122  goto memory_error;
3123  }
3124 
3125  --i;
3126  if (i >= 0) {
3127  odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3128  if (!tds_dstr_copy(&drec->sql_desc_catalog_name, buf))
3129  goto memory_error;
3130  }
3131  }
3132 
3134  /* TODO use is_nullable_type ?? */
3136 
3138  /* TODO test timestamp from db, FOR BROWSE query */
3139  drec->sql_desc_rowver = SQL_FALSE;
3140  /* TODO seem not correct */
3143  }
3144  return SQL_SUCCESS;
3145 
3146 memory_error:
3147  odbc_errs_add(&stmt->errs, "HY001", NULL);
3148  return SQL_ERROR;
3149 }
3150 
3151 static TDSRET
3153 {
3154  TDSSOCKET *tds = stmt->tds;
3155  int send = 0, i;
3156  TDSRET ret;
3157  TDSCURSOR *cursor;
3158  TDSPARAMINFO *params = stmt->params;
3159 
3160  assert(tds);
3161  assert(stmt->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY || stmt->attr.concurrency != SQL_CONCUR_READ_ONLY);
3162 
3163  tds_release_cursor(&stmt->cursor);
3164  cursor = tds_alloc_cursor(tds, tds_dstr_cstr(&stmt->cursor_name), tds_dstr_len(&stmt->cursor_name),
3165  tds_dstr_cstr(&stmt->query), tds_dstr_len(&stmt->query));
3166  if (!cursor) {
3168 
3169  odbc_errs_add(&stmt->errs, "HY001", NULL);
3170  return TDS_FAIL;
3171  }
3172  stmt->cursor = cursor;
3173 
3174  /* TODO cursor add enums for tds7 */
3175  switch (stmt->attr.cursor_type) {
3176  default:
3179  break;
3180  case SQL_CURSOR_STATIC:
3182  break;
3185  break;
3186  case SQL_CURSOR_DYNAMIC:
3188  break;
3189  }
3190  cursor->type = i;
3191 
3192  switch (stmt->attr.concurrency) {
3193  default:
3194  case SQL_CONCUR_READ_ONLY:
3196  break;
3197  case SQL_CONCUR_LOCK:
3199  break;
3200  case SQL_CONCUR_ROWVER:
3202  break;
3203  case SQL_CONCUR_VALUES:
3205  break;
3206  }
3207  cursor->concurrency = 0x2000 | i;
3208 
3209  ret = tds_cursor_declare(tds, cursor, params, &send);
3210  if (TDS_FAILED(ret))
3211  return ret;
3212  ret = tds_cursor_open(tds, cursor, params, &send);
3213  if (TDS_FAILED(ret))
3214  return ret;
3215  /* TODO read results, set row count, check type and scroll returned */
3216  ret = tds_flush_packet(tds);
3218  /* set cursor name for TDS7+ */
3219  if (TDS_SUCCEED(ret) && IS_TDS7_PLUS(tds->conn) && !tds_dstr_isempty(&stmt->cursor_name)) {
3221  stmt->row_count = tds->rows_affected;
3222  if (ret == TDS_CMD_DONE && cursor->cursor_id != 0) {
3223  ret = tds_cursor_setname(tds, cursor);
3225  } else {
3226  ret = (ret == TDS_CMD_FAIL) ? TDS_FAIL : TDS_SUCCESS;
3227  }
3228  if (!cursor->cursor_id) {
3229  tds_cursor_dealloc(tds, cursor);
3230  tds_release_cursor(&stmt->cursor);
3231  }
3232  }
3233  return ret;
3234 }
3235 
3236 static TDSHEADERS *
3238 {
3239  if (tds_dstr_isempty(&stmt->attr.qn_msgtext) || tds_dstr_isempty(&stmt->attr.qn_options))
3240  return NULL;
3241 
3242  memset(head, 0, sizeof(*head));
3243  head->qn_timeout = stmt->attr.qn_timeout;
3244  head->qn_msgtext = tds_dstr_cstr(&stmt->attr.qn_msgtext);
3245  head->qn_options = tds_dstr_cstr(&stmt->attr.qn_options);
3246  return head;
3247 }
3248 
3249 static SQLRETURN
3251 {
3252  TDSRET ret;
3253  TDSSOCKET *tds;
3254  TDS_INT result_type;
3255  TDS_INT done = 0;
3256  int in_row = 0;
3257  SQLUSMALLINT param_status;
3258  int found_info = 0, found_error = 0;
3259  TDS_INT8 total_rows = TDS_NO_COUNT;
3260  TDSHEADERS head;
3261 
3262  tdsdump_log(TDS_DBG_FUNC, "_SQLExecute(%p)\n",
3263  stmt);
3264 
3265  stmt->row = 0;
3266 
3267 
3268  /* check parameters are all OK */
3269  if (stmt->params && stmt->param_num <= (int) stmt->param_count) {
3270  /* TODO what error ?? */
3272  return SQL_ERROR;
3273  }
3274 
3275  if (!odbc_lock_statement(stmt))
3276  return SQL_ERROR;
3277 
3278  tds = stmt->tds;
3279  tdsdump_log(TDS_DBG_FUNC, "_SQLExecute() starting with state %d\n", tds->state);
3280 
3281  if (tds->state != TDS_IDLE) {
3282  if (tds->state == TDS_DEAD) {
3283  odbc_errs_add(&stmt->errs, "08S01", NULL);
3284  } else {
3285  odbc_errs_add(&stmt->errs, "24000", NULL);
3286  }
3287  return SQL_ERROR;
3288  }
3289 
3290  stmt->curr_param_row = 0;
3291  stmt->num_param_rows = ODBC_MAX(1, stmt->apd->header.sql_desc_array_size);
3292 
3293  stmt->row_count = TDS_NO_COUNT;
3294 
3295  if (stmt->prepared_query_is_rpc) {
3296  /* TODO support stmt->apd->header.sql_desc_array_size for RPC */
3297  /* get rpc name */
3298  /* TODO change method */
3299  /* TODO cursor change way of calling */
3300  char *name = tds_dstr_buf(&stmt->query);
3301  char *end, tmp;
3302 
3303  end = name;
3304  end = (char *) odbc_skip_rpc_name(end);
3305  stmt->prepared_pos = end;
3306  tmp = *end;
3307  *end = 0;
3308  ret = tds_submit_rpc(tds, name, stmt->params, odbc_init_headers(stmt, &head));
3309  *end = tmp;
3310  } else if (stmt->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY || stmt->attr.concurrency != SQL_CONCUR_READ_ONLY) {
3311  ret = odbc_cursor_execute(stmt);
3312  } else if (!stmt->is_prepared_query) {
3313  /* not prepared query */
3314  /* TODO cursor change way of calling */
3315  /* SQLExecDirect */
3316  if (stmt->num_param_rows <= 1) {
3317  if (!stmt->params) {
3319  } else {
3321  }
3322  } else {
3323  /* pack multiple submit using language */
3324  TDSMULTIPLE multiple;
3325 
3327  for (stmt->curr_param_row = 0; TDS_SUCCEED(ret); ) {
3328  /* submit a query */
3329  ret = tds_multiple_query(tds, &multiple, tds_dstr_cstr(&stmt->query), stmt->params);
3330  if (++stmt->curr_param_row >= stmt->num_param_rows)
3331  break;
3332  /* than process others parameters */
3333  /* TODO handle all results*/
3335  break;
3336  }
3337  if (TDS_SUCCEED(ret))
3338  ret = tds_multiple_done(tds, &multiple);
3339  }
3340  } else if (stmt->num_param_rows <= 1 && IS_TDS71_PLUS(tds->conn) && (!stmt->dyn || stmt->need_reprepare)) {
3341  if (stmt->dyn) {
3344  }
3345  stmt->need_reprepare = 0;
3346  ret = tds71_submit_prepexec(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params);
3347  } else {
3348  /* TODO cursor change way of calling */
3349  /* SQLPrepare */
3350  TDSDYNAMIC *dyn;
3351 
3352  /* prepare dynamic query (only for first SQLExecute call) */
3353  if (!stmt->dyn || (stmt->need_reprepare && !stmt->dyn->emulated && IS_TDS7_PLUS(tds->conn))) {
3354 
3355  /* free previous prepared statement */
3356  if (stmt->dyn) {
3359  }
3360  stmt->need_reprepare = 0;
3361 
3362  tdsdump_log(TDS_DBG_INFO1, "Creating prepared statement\n");
3363  /* TODO use tds_submit_prepexec (mssql2k, tds71) */
3364  if (TDS_FAILED(tds_submit_prepare(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params))) {
3365  /* TODO ?? tds_free_param_results(params); */
3367  return SQL_ERROR;
3368  }
3370  tds_release_dynamic(&stmt->dyn);
3371  /* TODO ?? tds_free_param_results(params); */
3373  return SQL_ERROR;
3374  }
3375  }
3376  stmt->row_count = TDS_NO_COUNT;
3377  if (stmt->num_param_rows <= 1) {
3378  dyn = stmt->dyn;
3379  tds_free_input_params(dyn);
3380  dyn->params = stmt->params;
3381  /* prevent double free */
3382  stmt->params = NULL;
3383  tdsdump_log(TDS_DBG_INFO1, "End prepare, execute\n");
3384  /* TODO return error to client */
3385  ret = tds_submit_execute(tds, dyn);
3386  } else {
3387  TDSMULTIPLE multiple;
3388 
3389  ret = tds_multiple_init(tds, &multiple, TDS_MULTIPLE_EXECUTE, NULL);
3390  for (stmt->curr_param_row = 0; TDS_SUCCEED(ret); ) {
3391  dyn = stmt->dyn;
3392  tds_free_input_params(dyn);
3393  dyn->params = stmt->params;
3394  /* prevent double free */
3395  stmt->params = NULL;
3396  ret = tds_multiple_execute(tds, &multiple, dyn);
3397  if (++stmt->curr_param_row >= stmt->num_param_rows)
3398  break;
3399  /* than process others parameters */
3400  /* TODO handle all results*/
3402  break;
3403  }
3404  if (TDS_SUCCEED(ret))
3405  ret = tds_multiple_done(tds, &multiple);
3406  }
3407  }
3408  if (TDS_FAILED(ret)) {
3410  return SQL_ERROR;
3411  }
3412  /* catch all errors */
3413  if (!odbc_lock_statement(stmt))
3414  ODBC_RETURN_(stmt);
3415 
3416  stmt->row_status = PRE_NORMAL_ROW;
3417 
3418  stmt->curr_param_row = 0;
3419  param_status = SQL_PARAM_SUCCESS;
3420 
3421  /* TODO review this, ODBC return parameter in other way, for compute I don't know */
3422  /* TODO perhaps we should return SQL_NO_DATA if no data available... see old SQLExecute code */
3423  for (;;) {
3424  result_type = odbc_process_tokens(stmt, TDS_TOKEN_RESULTS);
3425  tdsdump_log(TDS_DBG_FUNC, "_SQLExecute: odbc_process_tokens returned result_type %d\n", result_type);
3426  switch (result_type) {
3427  case TDS_CMD_FAIL:
3428  case TDS_CMD_DONE:
3429  case TDS_COMPUTE_RESULT:
3430  case TDS_ROW_RESULT:
3431  done = 1;
3432  break;
3433 
3434  case TDS_DONE_RESULT:
3435  case TDS_DONEPROC_RESULT:
3436  switch (stmt->errs.lastrc) {
3437  case SQL_ERROR:
3438  found_error = 1;
3439  param_status = SQL_PARAM_ERROR;
3440  break;
3441  case SQL_SUCCESS_WITH_INFO:
3442  found_info = 1;
3443  param_status = SQL_PARAM_SUCCESS_WITH_INFO;
3444  break;
3445  }
3446  if (stmt->curr_param_row < stmt->num_param_rows && stmt->ipd->header.sql_desc_array_status_ptr)
3447  stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
3448  param_status = SQL_PARAM_SUCCESS;
3449  ++stmt->curr_param_row;
3450  /* actually is quite strange, if prepared always success with info or success
3451  * if not prepared return last one
3452  */
3453  if (stmt->curr_param_row < stmt->num_param_rows || result_type == TDS_DONEPROC_RESULT)
3454  stmt->errs.lastrc = SQL_SUCCESS;
3455  if (total_rows == TDS_NO_COUNT)
3456  total_rows = stmt->row_count;
3457  else if (stmt->row_count != TDS_NO_COUNT)
3458  total_rows += stmt->row_count;
3459  stmt->row_count = TDS_NO_COUNT;
3460  if (stmt->curr_param_row >= stmt->num_param_rows) {
3461  done = 1;
3462  break;
3463  }
3464  break;
3465 
3466  case TDS_DONEINPROC_RESULT:
3467  if (in_row)
3468  done = 1;
3469  break;
3470 
3471  /* ignore metadata, stop at done or row */
3472  case TDS_ROWFMT_RESULT:
3473  if (in_row) {
3474  done = 1;
3475  break;
3476  }
3477  stmt->row = 0;
3478  stmt->row_count = TDS_NO_COUNT;
3479  stmt->row_status = PRE_NORMAL_ROW;
3480  in_row = 1;
3481  break;
3482  }
3483  if (done)
3484  break;
3485  }
3486  if ((found_info || found_error) && stmt->errs.lastrc != SQL_ERROR)
3487  stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3488  if (tds_dstr_isempty(&stmt->attr.qn_msgtext) != tds_dstr_isempty(&stmt->attr.qn_options)) {
3489  odbc_errs_add(&stmt->errs, "HY000", "Attribute ignored");
3490  stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3491  }
3492  if (found_error && stmt->num_param_rows <= 1)
3493  stmt->errs.lastrc = SQL_ERROR;
3494  if (stmt->curr_param_row < stmt->num_param_rows) {
3495  if (stmt->ipd->header.sql_desc_array_status_ptr)
3496  stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
3497  ++stmt->curr_param_row;
3498  if (total_rows == TDS_NO_COUNT)
3499  total_rows = stmt->row_count;
3500  else if (stmt->row_count != TDS_NO_COUNT)
3501  total_rows += stmt->row_count;
3502  stmt->row_count = TDS_NO_COUNT;
3503  }
3504  if (stmt->ipd->header.sql_desc_rows_processed_ptr)
3505  *stmt->ipd->header.sql_desc_rows_processed_ptr = ODBC_MIN(stmt->curr_param_row, stmt->num_param_rows);
3506 
3507  if (total_rows != TDS_NO_COUNT)
3508  stmt->row_count = total_rows;
3509 
3511  switch (result_type) {
3512  case TDS_CMD_DONE:
3514  if (stmt->errs.lastrc == SQL_SUCCESS && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3
3515  && stmt->row_count == TDS_NO_COUNT && !stmt->cursor)
3517  break;
3518 
3519  case TDS_CMD_FAIL:
3520  /* TODO test what happened, report correct error to client */
3521  tdsdump_log(TDS_DBG_INFO1, "SQLExecute: bad results\n");
3523  return SQL_ERROR;
3524  }
3525  ODBC_RETURN_(stmt);
3526 }
3527 
3529 {
3530  SQLRETURN res;
3531 
3533 
3534  if (SQL_SUCCESS != odbc_set_stmt_query(stmt, szSqlStr, cbSqlStr _wide)) {
3535  odbc_errs_add(&stmt->errs, "HY001", NULL);
3536  ODBC_EXIT_(stmt);
3537  }
3538 
3539  /* count placeholders */
3540  /* note: szSqlStr can be no-null terminated, so first we set query and then count placeholders */
3541  stmt->param_count = tds_count_placeholders(tds_dstr_cstr(&stmt->query));
3542  stmt->param_data_called = 0;
3543 
3544  if (SQL_SUCCESS != prepare_call(stmt)) {
3545  /* TODO return another better error, prepare_call should set error ?? */
3546  odbc_errs_add(&stmt->errs, "HY000", "Could not prepare call");
3547  ODBC_EXIT_(stmt);
3548  }
3549 
3550  res = start_parse_prepared_query(stmt, 1);
3551  if (SQL_SUCCESS != res)
3552  ODBC_EXIT(stmt, res);
3553 
3555 }
3556 
3559 {
3561  SQLRETURN res;
3562 
3564 
3565  tdsdump_log(TDS_DBG_FUNC, "SQLExecute(%p)\n", hstmt);
3566 
3567  if (!stmt->is_prepared_query) {
3568  /* TODO error report, only without DM ?? */
3569  tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns SQL_ERROR (not prepared)\n");
3571  }
3572 
3573  /* TODO rebuild should be done for every bindings change, not every time */
3574  /* TODO free previous parameters */
3575  /* build parameters list */
3576  stmt->param_data_called = 0;
3577  stmt->curr_param_row = 0;
3578  if ((res = start_parse_prepared_query(stmt, 1)) != SQL_SUCCESS) {
3579  tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns %s (start_parse_prepared_query failed)\n", odbc_prret(res));
3580  ODBC_EXIT(stmt, res);
3581  }
3582 
3583  /* TODO test if two SQLPrepare on a statement */
3584  /* TODO test unprepare on statement free or connection close */
3585 
3586  res = _SQLExecute(stmt);
3587 
3588  tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns %s\n", odbc_prret(res));
3589 
3590  ODBC_EXIT(stmt, res);
3591 }
3592 
3593 static int
3595 {
3596  TDS_INT result_type;
3597  int done_flags = 0;
3598  TDSSOCKET * tds = stmt->tds;
3599 
3600  flag |= TDS_RETURN_DONE | TDS_RETURN_PROC;
3601  for (;;) {
3602  TDSRET retcode = tds_process_tokens(tds, &result_type, &done_flags, flag);
3603  tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: tds_process_tokens returned %d\n", retcode);
3604  tdsdump_log(TDS_DBG_FUNC, " result_type=%d, TDS_DONE_COUNT=%x, TDS_DONE_ERROR=%x\n",
3605  result_type, (done_flags & TDS_DONE_COUNT), (done_flags & TDS_DONE_ERROR));
3606  switch (retcode) {
3607  case TDS_SUCCESS:
3608  break;
3609  case TDS_NO_MORE_RESULTS:
3610  return TDS_CMD_DONE;
3611  case TDS_CANCELLED:
3612  odbc_errs_add(&stmt->errs, "HY008", NULL);
3613  default:
3614  return TDS_CMD_FAIL;
3615  }
3616 
3617  switch (result_type) {
3618  case TDS_STATUS_RESULT:
3619  odbc_set_return_status(stmt, ODBC_MIN(stmt->curr_param_row, stmt->num_param_rows - 1));
3620  break;
3621  case TDS_PARAM_RESULT:
3622  odbc_set_return_params(stmt, ODBC_MIN(stmt->curr_param_row, stmt->num_param_rows - 1));
3623  break;
3624 
3625  case TDS_DONE_RESULT:
3626  case TDS_DONEPROC_RESULT:
3627  if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3628  flag |= TDS_STOPAT_MSG;
3629  if (done_flags & TDS_DONE_COUNT) {
3630  /* correct ?? overwrite ?? */
3631  if (stmt->row_count == TDS_NO_COUNT)
3632  stmt->row_count = tds->rows_affected;
3633  }
3634  if (done_flags & TDS_DONE_ERROR)
3635  stmt->errs.lastrc = SQL_ERROR;
3636  /* test for internal_sp not very fine, used for param set -- freddy77 */
3637  if ((done_flags & (TDS_DONE_COUNT|TDS_DONE_ERROR)) != 0
3638  || (stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3639  || (result_type == TDS_DONEPROC_RESULT && tds->current_op == TDS_OP_EXECUTE)) {
3640  /* FIXME this row is used only as a flag for update binding, should be cleared if binding/result changed */
3641  stmt->row = 0;
3642 #if 0
3645 #endif
3646  tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: row_count=%" PRId64 "\n", stmt->row_count);
3647  return result_type;
3648  }
3649  tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: processed %s\n",
3650  result_type==TDS_DONE_RESULT? "TDS_DONE_RESULT" : "TDS_DONEPROC_RESULT");
3651  break;
3652 
3653  /*
3654  * TODO test flags ? check error and change result ?
3655  * see also other DONEINPROC handle (below)
3656  */
3657  case TDS_DONEINPROC_RESULT:
3658  if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3659  flag |= TDS_STOPAT_MSG;
3660  if (done_flags & TDS_DONE_COUNT) {
3661  stmt->row_count = tds->rows_affected;
3662  }
3663  if (done_flags & TDS_DONE_ERROR)
3664  stmt->errs.lastrc = SQL_ERROR;
3665  /* TODO perhaps it can be a problem if SET NOCOUNT ON, test it */
3666 #if 0
3669 #endif
3670  tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: processed TDS_DONEINPROC_RESULT\n");
3671  if (stmt->row_status == PRE_NORMAL_ROW)
3672  return result_type;
3673  break;
3674 
3675  default:
3676  tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: returning result_type %d\n", result_type);
3677  return result_type;
3678  }
3679  }
3680 }
3681 
3682 static void
3684 {
3685  TDSSOCKET *tds = stmt->tds;
3686  TDSRESULTINFO *resinfo;
3687  TDSCOLUMN *colinfo;
3688 
3689  if (!tds)
3690  return;
3691 
3692  resinfo = tds->current_results;
3693  if (!resinfo || resinfo->num_cols <= idx)
3694  return;
3695 
3696  colinfo = resinfo->columns[idx];
3697  if (colinfo->column_cur_size < 0)
3698  return;
3699 
3700  switch (tds_get_conversion_type(colinfo->column_type, colinfo->column_size)) {
3701  case SYBINT2: {
3702  TDS_SMALLINT *data = (TDS_SMALLINT *) colinfo->column_data;
3703  *data = odbc_swap_datetime_sql_type(*data, 0);
3704  }
3705  break;
3706  case SYBINT4: {
3707  TDS_INT *data = (TDS_INT *) colinfo->column_data;
3708  *data = odbc_swap_datetime_sql_type(*data, 0);
3709  }
3710  break;
3711  default:
3712  break;
3713  }
3714 }
3715 
3716 /*
3717  * - handle correctly SQLGetData (for forward cursors accept only row_size == 1
3718  * for other types application must use SQLSetPos)
3719  * - handle correctly results (SQL_SUCCESS_WITH_INFO if error on some rows,
3720  * SQL_ERROR for all rows, see doc)
3721  */
3722 static SQLRETURN
3723 _SQLFetch(TDS_STMT * stmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)
3724 {
3725  TDSSOCKET *tds;
3726  TDSRESULTINFO *resinfo;
3727  TDSCOLUMN *colinfo;
3728  int i;
3729  SQLULEN curr_row, num_rows;
3730  SQLLEN len = 0;
3731  TDS_CHAR *src;
3732  int srclen;
3733  struct _drecord *drec_ard;
3734  TDS_DESC *ard;
3735  SQLULEN dummy, *fetched_ptr;
3736  SQLUSMALLINT *status_ptr, row_status;
3737  TDS_INT result_type;
3738  int truncated = 0;
3739 
3740 #define AT_ROW(ptr, type) (row_offset ? (type*)(((char*)(ptr)) + row_offset) : &ptr[curr_row])
3741  SQLLEN row_offset = 0;
3742 
3743  tdsdump_log(TDS_DBG_FUNC, "_SQLFetch(%p, %d, %d)\n", stmt, (int)FetchOrientation, (int)FetchOffset);
3744 
3745  if (stmt->ard->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN && stmt->ard->header.sql_desc_bind_offset_ptr)
3746  row_offset = *stmt->ard->header.sql_desc_bind_offset_ptr;
3747 
3748  ard = stmt->ard;
3749 
3750  tds = stmt->tds;
3751  num_rows = ard->header.sql_desc_array_size;
3752 
3753  /* TODO cursor check also type of cursor (scrollable, not forward) */
3754  if (FetchOrientation != SQL_FETCH_NEXT && (!stmt->cursor || !stmt->dbc->cursor_support)) {
3755  odbc_errs_add(&stmt->errs, "HY106", NULL);
3756  return SQL_ERROR;
3757  }
3758 
3759  /* handle cursors, fetch wanted rows */
3760  if (stmt->cursor && odbc_lock_statement(stmt)) {
3761  TDSCURSOR *cursor = stmt->cursor;
3763 
3764  tds = stmt->tds;
3765 
3766  switch (FetchOrientation) {
3767  case SQL_FETCH_NEXT:
3768  break;
3769  case SQL_FETCH_FIRST:
3770  fetch_type = TDS_CURSOR_FETCH_FIRST;
3771  break;
3772  case SQL_FETCH_LAST:
3773  fetch_type = TDS_CURSOR_FETCH_LAST;
3774  break;
3775  case SQL_FETCH_PRIOR:
3776  fetch_type = TDS_CURSOR_FETCH_PREV;
3777  break;
3778  case SQL_FETCH_ABSOLUTE:
3779  fetch_type = TDS_CURSOR_FETCH_ABSOLUTE;
3780  break;
3781  case SQL_FETCH_RELATIVE:
3782  fetch_type = TDS_CURSOR_FETCH_RELATIVE;
3783  break;
3784  /* TODO cursor bookmark */
3785  default:
3786  odbc_errs_add(&stmt->errs, "HYC00", NULL);
3787  return SQL_ERROR;
3788  }
3789 
3790  if (cursor->cursor_rows != num_rows) {
3791  int send = 0;
3792  cursor->cursor_rows = num_rows;
3793  /* TODO handle change rows (tds5) */
3794  /*
3795  * TODO curerntly we support cursors only using tds7+
3796  * so this function can't fail but remember to add error
3797  * check when tds5 will be supported
3798  */
3799  tds_cursor_setrows(tds, cursor, &send);
3800  }
3801 
3802  if (TDS_FAILED(tds_cursor_fetch(tds, cursor, fetch_type, FetchOffset))) {
3803  /* TODO what kind of error ?? */
3805  return SQL_ERROR;
3806  }
3807 
3808  /* TODO handle errors in a better way */
3810  stmt->row_status = PRE_NORMAL_ROW;
3811  }
3812 
3813  if (!tds || stmt->row_status == NOT_IN_ROW) {
3814  odbc_errs_add(&stmt->errs, "24000", NULL);
3815  return SQL_ERROR;
3816  }
3817  IRD_CHECK;
3818 
3819  if (stmt->ird->header.sql_desc_count <= 0) {
3820  odbc_errs_add(&stmt->errs, "24000", NULL);
3821  return SQL_ERROR;
3822  }
3823 
3824  stmt->row++;
3825 
3826  fetched_ptr = &dummy;
3827  if (stmt->ird->header.sql_desc_rows_processed_ptr)
3828  fetched_ptr = stmt->ird->header.sql_desc_rows_processed_ptr;
3829  *fetched_ptr = 0;
3830 
3831  status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
3832  if (status_ptr) {
3833  for (i = 0; (SQLULEN) i < num_rows; ++i)
3834  *status_ptr++ = SQL_ROW_NOROW;
3835  status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
3836  }
3837 
3838  curr_row = 0;
3839  do {
3840  row_status = SQL_ROW_SUCCESS;
3841 
3842  /* do not get compute row if we are not expecting a compute row */
3843  switch (stmt->row_status) {
3844  case AFTER_COMPUTE_ROW:
3845  /* handle done if needed */
3846  /* FIXME doesn't seem so fine ... - freddy77 */
3847  tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
3848  goto all_done;
3849 
3850  case IN_COMPUTE_ROW:
3851  /* compute recorset contains only a row */
3852  /* we already fetched compute row in SQLMoreResults so do not fetch another one */
3853  num_rows = 1;
3854  stmt->row_status = AFTER_COMPUTE_ROW;
3855  break;
3856 
3857  default:
3858  /* FIXME stmt->row_count set correctly ?? TDS_DONE_COUNT not checked */
3860  case TDS_ROW_RESULT:
3861  break;
3862  default:
3863 #if 0
3864  stmt->row_count = tds->rows_affected;
3865 #endif
3866  /*
3867  * NOTE do not set row_status to NOT_IN_ROW,
3868  * if compute tds_process_tokens above returns TDS_NO_MORE_RESULTS
3869  */
3870  stmt->row_status = PRE_NORMAL_ROW;
3871  stmt->special_row = ODBC_SPECIAL_NONE;
3872 #if 0
3874 #endif
3875  tdsdump_log(TDS_DBG_INFO1, "SQLFetch: NO_DATA_FOUND\n");
3876  goto all_done;
3877  break;
3878  case TDS_CMD_FAIL:
3880  return SQL_ERROR;
3881  break;
3882  }
3883 
3884  stmt->row_status = IN_NORMAL_ROW;
3885 
3886  /* handle special row */
3887  switch (stmt->special_row) {
3890  break;
3891  case ODBC_SPECIAL_COLUMNS:
3893  odbc_fix_data_type_col(stmt, 13); /* TODO sure ?? */
3894  break;
3897  odbc_fix_data_type_col(stmt, 14); /* TODO sure ?? */
3898  break;
3901  break;
3902  case ODBC_SPECIAL_NONE:
3903  break;
3904  }
3905  }
3906 
3907  resinfo = tds->current_results;
3908  if (!resinfo) {
3909  tdsdump_log(TDS_DBG_INFO1, "SQLFetch: !resinfo\n");
3910  break;
3911  }
3912 
3913  /* we got a row, return a row readed even if error (for ODBC specifications) */
3914  ++(*fetched_ptr);
3915  for (i = 0; i < resinfo->num_cols; i++) {
3916  colinfo = resinfo->columns[i];
3917  colinfo->column_text_sqlgetdatapos = 0;
3918  drec_ard = (i < ard->header.sql_desc_count) ? &ard->records[i] : NULL;
3919  if (!drec_ard)
3920  continue;
3921  if (colinfo->column_cur_size < 0) {
3922  if (drec_ard->sql_desc_indicator_ptr) {
3924  } else if (drec_ard->sql_desc_data_ptr) {
3925  odbc_errs_add(&stmt->errs, "22002", NULL);
3926  row_status = SQL_ROW_ERROR;
3927  break;
3928  }
3929  continue;
3930  }
3931  /* set indicator to 0 if data is not null */
3932  if (drec_ard->sql_desc_indicator_ptr)
3933  *AT_ROW(drec_ard->sql_desc_indicator_ptr, SQLLEN) = 0;
3934 
3935  /* TODO what happen to length if no data is returned (drec->sql_desc_data_ptr == NULL) ?? */
3936  len = 0;
3937  if (drec_ard->sql_desc_data_ptr) {
3938  int c_type;
3939  TDS_CHAR *data_ptr = (TDS_CHAR *) drec_ard->sql_desc_data_ptr;
3940 
3941  src = (TDS_CHAR *) colinfo->column_data;
3942  srclen = colinfo->column_cur_size;
3943  colinfo->column_text_sqlgetdatapos = 0;
3944  c_type = drec_ard->sql_desc_concise_type;
3945  if (c_type == SQL_C_DEFAULT)
3946  c_type = odbc_sql_to_c_type_default(stmt->ird->records[i].sql_desc_concise_type);
3947  if (row_offset || curr_row == 0) {
3948  data_ptr += row_offset;
3949  } else {
3950  data_ptr += odbc_get_octet_len(c_type, drec_ard) * curr_row;
3951  }
3953  src, srclen, c_type, data_ptr, drec_ard->sql_desc_octet_length, drec_ard);
3954  if (len == SQL_NULL_DATA) {
3955  row_status = SQL_ROW_ERROR;
3956  break;
3957  }
3958  if ((c_type == SQL_C_CHAR && len >= drec_ard->sql_desc_octet_length)
3959  || (c_type == SQL_C_BINARY && len > drec_ard->sql_desc_octet_length)) {
3960  truncated = 1;
3961  stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3962  }
3963  }
3964  if (drec_ard->sql_desc_octet_length_ptr)
3965  *AT_ROW(drec_ard->sql_desc_octet_length_ptr, SQLLEN) = len;
3966  }
3967 
3968  if (status_ptr)
3969  *status_ptr++ = truncated ? SQL_ROW_ERROR : row_status;
3970  if (row_status == SQL_ROW_ERROR) {
3971  stmt->errs.lastrc = SQL_ERROR;
3972  break;
3973  }
3974 #if SQL_BIND_BY_COLUMN != 0
3975  if (stmt->ard->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN)
3976 #endif
3977  row_offset += stmt->ard->header.sql_desc_bind_type;
3978  } while (++curr_row < num_rows);
3979 
3980  if (truncated)
3981  odbc_errs_add(&stmt->errs, "01004", NULL);
3982 
3983  all_done:
3984  /* TODO cursor correct ?? */
3985  if (stmt->cursor) {
3986  tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
3988  }
3989  if (*fetched_ptr == 0 && (stmt->errs.lastrc == SQL_SUCCESS || stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO))
3991  if (stmt->errs.lastrc == SQL_ERROR && (*fetched_ptr > 1 || (*fetched_ptr == 1 && row_status != SQL_ROW_ERROR)))
3993  ODBC_RETURN_(stmt);
3994 }
3995 
3998 {
3999  SQLRETURN ret;
4000  struct {
4001  SQLULEN array_size;
4002  SQLULEN *rows_processed_ptr;
4003  SQLUSMALLINT *array_status_ptr;
4004  } keep;
4005 
4007 
4008  tdsdump_log(TDS_DBG_FUNC, "SQLFetch(%p)\n", hstmt);
4009 
4010  keep.array_size = stmt->ard->header.sql_desc_array_size;
4011  keep.rows_processed_ptr = stmt->ird->header.sql_desc_rows_processed_ptr;
4012  keep.array_status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
4013 
4014  if (stmt->dbc->env->attr.odbc_version != SQL_OV_ODBC3) {
4015  stmt->ard->header.sql_desc_array_size = 1;
4016  stmt->ird->header.sql_desc_rows_processed_ptr = NULL;
4017  stmt->ird->header.sql_desc_array_status_ptr = NULL;
4018  }
4019 
4020  ret = _SQLFetch(stmt, SQL_FETCH_NEXT, 0);
4021 
4022  if (stmt->dbc->env->attr.odbc_version != SQL_OV_ODBC3) {
4023  stmt->ard->header.sql_desc_array_size = keep.array_size;
4024  stmt->ird->header.sql_desc_rows_processed_ptr = keep.rows_processed_ptr;
4025  stmt->ird->header.sql_desc_array_status_ptr = keep.array_status_ptr;
4026  }
4027 
4028  ODBC_EXIT(stmt, ret);
4029 }
4030 
4031 #if (ODBCVER >= 0x0300)
4033 SQLFetchScroll(SQLHSTMT hstmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)
4034 {
4036 
4037  tdsdump_log(TDS_DBG_FUNC, "SQLFetchScroll(%p, %d, %d)\n", hstmt, FetchOrientation, (int)FetchOffset);
4038 
4039  if (FetchOrientation != SQL_FETCH_NEXT && !stmt->dbc->cursor_support) {
4040  odbc_errs_add(&stmt->errs, "HY106", NULL);
4041  ODBC_EXIT_(stmt);
4042  }
4043 
4044  ODBC_EXIT(stmt, _SQLFetch(stmt, FetchOrientation, FetchOffset));
4045 }
4046 #endif
4047 
4048 
4049 #if (ODBCVER >= 0x0300)
4052 {
4053  tdsdump_log(TDS_DBG_INFO1, "SQLFreeHandle(%d, %p)\n", HandleType, (void *) Handle);
4054 
4055  switch (HandleType) {
4056  case SQL_HANDLE_STMT:
4057  return _SQLFreeStmt(Handle, SQL_DROP, 0);
4058  break;
4059  case SQL_HANDLE_DBC:
4060  return _SQLFreeConnect(Handle);
4061  break;
4062  case SQL_HANDLE_ENV:
4063  return _SQLFreeEnv(Handle);
4064  break;
4065  case SQL_HANDLE_DESC:
4066  return _SQLFreeDesc(Handle);
4067  break;
4068  }
4069  return SQL_ERROR;
4070 }
4071 
4072 static SQLRETURN
4074 {
4075  int i;
4076 
4078 
4079  tdsdump_log(TDS_DBG_FUNC, "_SQLFreeConnect(%p)\n",
4080  hdbc);
4081 
4082  tds_close_socket(dbc->tds_socket);
4083 
4084  /* TODO if connected return error */
4085  tds_free_socket(dbc->tds_socket);
4086 
4088  /* free attributes */
4089 #ifdef TDS_NO_DM
4090  tds_dstr_free(&dbc->attr.tracefile);
4091 #endif
4092  tds_dstr_free(&dbc->attr.current_catalog);
4093  tds_dstr_free(&dbc->attr.translate_lib);
4094  tds_dstr_zero(&dbc->oldpwd);
4095  tds_dstr_free(&dbc->oldpwd);
4096 
4097 #ifdef ENABLE_ODBC_WIDE
4098  tds_dstr_free(&dbc->original_charset);
4099 #endif
4100  tds_dstr_free(&dbc->dsn);
4101 
4102  for (i = 0; i < TDS_MAX_APP_DESC; i++) {
4103  if (dbc->uad[i]) {
4104  desc_free(dbc->uad[i]);
4105  }
4106  }
4107  odbc_errs_reset(&dbc->errs);
4108  tds_mutex_unlock(&dbc->mtx);
4109  tds_mutex_free(&dbc->mtx);
4110 
4111  free(dbc);
4112 
4113  return SQL_SUCCESS;
4114 }
4115 
4117 SQLFreeConnect(SQLHDBC hdbc)
4118 {
4119  tdsdump_log(TDS_DBG_INFO2, "SQLFreeConnect(%p)\n", hdbc);
4120  return _SQLFreeConnect(hdbc);
4121 }
4122 #endif
4123 
4124 static SQLRETURN
4126 {
4128 
4129  tdsdump_log(TDS_DBG_FUNC, "_SQLFreeEnv(%p)\n",
4130  henv);
4131 
4132  odbc_errs_reset(&env->errs);
4133  tds_free_context(env->tds_ctx);
4134  tds_mutex_unlock(&env->mtx);
4135  tds_mutex_free(&env->mtx);
4136  free(env);
4137 
4138  return SQL_SUCCESS;
4139 }
4140 
4143 {
4144  tdsdump_log(TDS_DBG_FUNC, "SQLFreeEnv(%p)\n", henv);
4145 
4146  return _SQLFreeEnv(henv);
4147 }
4148 
4149 static SQLRETURN
4150 _SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption, int force)
4151 {
4152  TDSSOCKET *tds;
4153 
4155 
4156  tdsdump_log(TDS_DBG_FUNC, "_SQLFreeStmt(%p, %d, %d)\n", hstmt, fOption, force);
4157 
4158  /* check if option correct */
4159  if (fOption != SQL_DROP && fOption != SQL_CLOSE && fOption != SQL_UNBIND && fOption != SQL_RESET_PARAMS) {
4160  tdsdump_log(TDS_DBG_ERROR, "SQLFreeStmt: Unknown option %d\n", fOption);
4161  odbc_errs_add(&stmt->errs, "HY092", NULL);
4162  ODBC_EXIT_(stmt);
4163  }
4164 
4165  /* if we have bound columns, free the temporary list */
4166  if (fOption == SQL_DROP || fOption == SQL_UNBIND) {
4167  desc_free_records(stmt->ard);
4168  }
4169 
4170  /* do the same for bound parameters */
4171  if (fOption == SQL_DROP || fOption == SQL_RESET_PARAMS) {
4172  desc_free_records(stmt->apd);
4173  desc_free_records(stmt->ipd);
4174  }
4175 
4176  /* close statement */
4177  if (fOption == SQL_DROP || fOption == SQL_CLOSE) {
4178  SQLRETURN retcode;
4179 
4180  tds = stmt->tds;
4181  /*
4182  * FIXME -- otherwise make sure the current statement is complete
4183  */
4184  /* do not close other running query ! */
4185  if (tds && tds->state != TDS_IDLE && tds->state != TDS_DEAD) {
4188  }
4189 
4190  /* free cursor */
4191  retcode = odbc_free_cursor(stmt);
4192  if (!force && retcode != SQL_SUCCESS)
4193  ODBC_EXIT(stmt, retcode);
4194  }
4195 
4196  /* free it */
4197  if (fOption == SQL_DROP) {
4198  SQLRETURN retcode;
4199 
4200  /* close prepared statement or add to connection */
4201  retcode = odbc_free_dynamic(stmt);
4202  if (!force && retcode != SQL_SUCCESS)
4203  ODBC_EXIT(stmt, retcode);
4204 
4205  /* detatch from list */
4206  tds_mutex_lock(&stmt->dbc->mtx);
4207  if (stmt->next)
4208  stmt->next->prev = stmt->prev;
4209  if (stmt->prev)
4210  stmt->prev->next = stmt->next;
4211  if (stmt->dbc->stmt_list == stmt)
4212  stmt->dbc->stmt_list = stmt->next;
4213  tds_mutex_unlock(&stmt->dbc->mtx);
4214 
4215  tds_dstr_free(&stmt->query);
4216  tds_free_param_results(stmt->params);
4217  odbc_errs_reset(&stmt->errs);
4219  tds_dstr_free(&stmt->cursor_name);
4220  tds_dstr_free(&stmt->attr.qn_msgtext);
4221  tds_dstr_free(&stmt->attr.qn_options);
4222  desc_free(stmt->ird);
4223  desc_free(stmt->ipd);
4224  desc_free(stmt->orig_ard);
4225  desc_free(stmt->orig_apd);
4226  tds_mutex_unlock(&stmt->mtx);
4227  tds_mutex_free(&stmt->mtx);
4228  free(stmt);
4229 
4230  /* NOTE we freed stmt, do not use ODBC_EXIT */
4231  return SQL_SUCCESS;
4232  }
4233  ODBC_EXIT_(stmt);
4234 }
4235 
4238 {
4239  tdsdump_log(TDS_DBG_FUNC, "SQLFreeStmt(%p, %d)\n", hstmt, fOption);
4240  return _SQLFreeStmt(hstmt, fOption, 0);
4241 }
4242 
4243 
4246 {
4247  /* TODO cursors */
4248  /*
4249  * Basic implementation for when no driver manager is present.
4250  * - according to ODBC documentation SQLCloseCursor is more or less
4251  * equivalent to SQLFreeStmt(..., SQL_CLOSE).
4252  * - indeed that is what the DM does if it can't find the function
4253  * in the driver, so this is pretty close.
4254  */
4255  /* TODO remember to close cursors really when get implemented */
4256  /* TODO read all results and discard them or use cancellation ?? test behaviour */
4257 
4258  tdsdump_log(TDS_DBG_FUNC, "SQLCloseCursor(%p)\n", hstmt);
4259  return _SQLFreeStmt(hstmt, SQL_CLOSE, 0);
4260 }
4261 
4262 static SQLRETURN
4264 {
4266 
4267  tdsdump_log(TDS_DBG_FUNC, "_SQLFreeDesc(%p)\n",
4268  hdesc);
4269 
4270  if (desc->header.sql_desc_alloc_type != SQL_DESC_ALLOC_USER) {
4271  odbc_errs_add(&desc->errs, "HY017", NULL);
4272  ODBC_EXIT_(desc);
4273  }
4274 
4275  if (IS_HDBC(desc->parent)) {
4276  TDS_DBC *dbc = (TDS_DBC *) desc->parent;
4277  TDS_STMT *stmt;
4278  int i;
4279 
4280  /* freeing descriptors associated to statements revert state of statements */
4281  tds_mutex_lock(&dbc->mtx);
4282  for (stmt = dbc->stmt_list; stmt != NULL; stmt = stmt->next) {
4283  if (stmt->ard == desc)
4284  stmt->ard = stmt->orig_ard;
4285  if (stmt->apd == desc)
4286  stmt->apd = stmt->orig_apd;
4287  }
4288  tds_mutex_unlock(&dbc->mtx);
4289 
4290  for (i = 0; i < TDS_MAX_APP_DESC; ++i) {
4291  if (dbc->uad[i] == desc) {
4292  dbc->uad[i] = NULL;
4293  tds_mutex_unlock(&desc->mtx);
4294  desc_free(desc);
4295  break;
4296  }
4297  }
4298  }
4299  return SQL_SUCCESS;
4300 }
4301 
4302 static SQLRETURN
4304 {
4305  void *src;
4306  SQLINTEGER size;
4307 
4309 
4310  /* TODO assign directly, use macro for size */
4311  switch (Attribute) {
4313  size = sizeof(stmt->apd);
4314  src = &stmt->apd;
4315  break;
4316  case SQL_ATTR_APP_ROW_DESC:
4317  size = sizeof(stmt->ard);
4318  src = &stmt->ard;
4319  break;
4320  case SQL_ATTR_ASYNC_ENABLE:
4321  size = sizeof(stmt->attr.async_enable);
4322  src = &stmt->attr.async_enable;
4323  break;
4324  case SQL_ATTR_CONCURRENCY:
4325  size = sizeof(stmt->attr.concurrency);
4326  src = &stmt->attr.concurrency;
4327  break;
4328  case SQL_ATTR_CURSOR_TYPE:
4329  size = sizeof(stmt->attr.cursor_type);
4330  src = &stmt->attr.cursor_type;
4331  break;
4333  size = sizeof(stmt->attr.enable_auto_ipd);
4334  src = &stmt->attr.enable_auto_ipd;
4335  break;
4337  size = sizeof(stmt->attr.fetch_bookmark_ptr);
4338  src = &stmt->attr.fetch_bookmark_ptr;
4339  break;
4340  case SQL_ATTR_KEYSET_SIZE:
4341  size = sizeof(stmt->attr.keyset_size);
4342  src = &stmt->attr.keyset_size;
4343  break;
4344  case SQL_ATTR_MAX_LENGTH:
4345  size = sizeof(stmt->attr.max_length);
4346  src = &stmt->attr.max_length;
4347  break;
4348  case SQL_ATTR_MAX_ROWS:
4349  size = sizeof(stmt->attr.max_rows);
4350  src = &stmt->attr.max_rows;
4351  break;
4352  case SQL_ATTR_METADATA_ID:
4353  size = sizeof(stmt->attr.metadata_id);
4354  src = &stmt->attr.noscan;
4355  break;
4356  case SQL_ATTR_NOSCAN:
4357  size = sizeof(stmt->attr.noscan);
4358  src = &stmt->attr.noscan;
4359  break;
4361  size = sizeof(stmt->apd->header.sql_desc_bind_offset_ptr);
4362  src = &stmt->apd->header.sql_desc_bind_offset_ptr;
4363  break;
4365  size = sizeof(stmt->apd->header.sql_desc_bind_type);
4366  src = &stmt->apd->header.sql_desc_bind_type;
4367  break;
4369  size = sizeof(stmt->apd->header.sql_desc_array_status_ptr);
4370  src = &stmt->apd->header.sql_desc_array_status_ptr;
4371  break;
4373  size = sizeof(stmt->ipd->header.sql_desc_array_status_ptr);
4374  src = &stmt->ipd->header.sql_desc_array_status_ptr;
4375  break;
4377  size = sizeof(stmt->ipd->header.sql_desc_rows_processed_ptr);
4378  src = &stmt->ipd->header.sql_desc_rows_processed_ptr;
4379  break;
4381  size = sizeof(stmt->apd->header.sql_desc_array_size);
4382  src = &stmt->apd->header.sql_desc_array_size;
4383  break;
4385  size = sizeof(stmt->attr.query_timeout);
4386  src = &stmt->attr.query_timeout;
4387  break;
4389  size = sizeof(stmt->attr.retrieve_data);
4390  src = &stmt->attr.retrieve_data;
4391  break;
4393  size = sizeof(stmt->ard->header.sql_desc_bind_offset_ptr);
4394  src = &stmt->ard->header.sql_desc_bind_offset_ptr;
4395  break;
4396 #if SQL_BIND_TYPE != SQL_ATTR_ROW_BIND_TYPE
4397  case SQL_BIND_TYPE: /* although this is ODBC2 we must support this attribute */
4398 #endif
4400  size = sizeof(stmt->ard->header.sql_desc_bind_type);
4401  src = &stmt->ard->header.sql_desc_bind_type;
4402  break;
4403  case SQL_ATTR_ROW_NUMBER:
4404  /* TODO do not get info every time, cache somewhere */
4405  if (stmt->cursor && odbc_lock_statement(stmt)) {
4406  TDS_UINT row_number, row_count;
4407 
4408  tds_cursor_get_cursor_info(stmt->tds, stmt->cursor, &row_number, &row_count);
4409  stmt->attr.row_number = row_number;
4410  }
4411  size = sizeof(stmt->attr.row_number);
4412  src = &stmt->attr.row_number;
4413  break;
4415  size = sizeof(stmt->ard->header.sql_desc_array_status_ptr);
4416  src = &stmt->ard->header.sql_desc_array_status_ptr;
4417  break;
4419  size = sizeof(stmt->ird->header.sql_desc_array_status_ptr);
4420  src = &stmt->ird->header.sql_desc_array_status_ptr;
4421  break;
4423  size = sizeof(stmt->ird->header.sql_desc_rows_processed_ptr);
4424  src = &stmt->ird->header.sql_desc_rows_processed_ptr;
4425  break;
4427  size = sizeof(stmt->ard->header.sql_desc_array_size);
4428  src = &stmt->ard->header.sql_desc_array_size;
4429  break;
4431  size = sizeof(stmt->attr.simulate_cursor);
4432  src = &stmt->attr.simulate_cursor;
4433  break;
4435  size = sizeof(stmt->attr.use_bookmarks);
4436  src = &stmt->attr.use_bookmarks;
4437  break;
4439  size = sizeof(stmt->attr.cursor_scrollable);
4440  src = &stmt->attr.cursor_scrollable;
4441  break;
4443  size = sizeof(stmt->attr.cursor_sensitivity);
4444  src = &stmt->attr.cursor_sensitivity;
4445  break;
4446  case SQL_ATTR_IMP_ROW_DESC:
4447  size = sizeof(stmt->ird);
4448  src = &stmt->ird;
4449  break;
4451  size = sizeof(stmt->ipd);
4452  src = &stmt->ipd;
4453  break;
4454  case SQL_ROWSET_SIZE: /* although this is ODBC2 we must support this attribute */
4455  size = sizeof(stmt->sql_rowset_size);
4456  src = &stmt->sql_rowset_size;
4457  break;
4459  size = sizeof(stmt->attr.qn_timeout);
4460  src = &stmt->attr.qn_timeout;
4461  break;
4463  {
4464  SQLRETURN rc = odbc_set_string_oct(stmt->dbc, Value, BufferLength, StringLength, tds_dstr_cstr(&stmt->attr.qn_msgtext), tds_dstr_len(&stmt->attr.qn_msgtext));
4465  ODBC_EXIT(stmt, rc);
4466  }
4468  {
4469  SQLRETURN rc = odbc_set_string_oct(stmt->dbc, Value, BufferLength, StringLength, tds_dstr_cstr(&stmt->attr.qn_options), tds_dstr_len(&stmt->attr.qn_options));
4470  ODBC_EXIT(stmt, rc);
4471  }
4472  /* TODO SQL_COLUMN_SEARCHABLE, although ODBC2 */
4473  default:
4474  odbc_errs_add(&stmt->errs, "HY092", NULL);
4475  ODBC_EXIT_(stmt);
4476  }
4477 
4478  memcpy(Value, src, size);
4479  if (StringLength)
4480  *StringLength = size;
4481 
4482  ODBC_EXIT_(stmt);
4483 }
4484 
4485 #if (ODBCVER >= 0x0300)
4487 SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
4488 {
4489  tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtAttr(%p, %d, %p, %d, %p)\n",
4490  hstmt, (int)Attribute, Value, (int)BufferLength, StringLength);
4491 
4492  return _SQLGetStmtAttr(hstmt, Attribute, Value, BufferLength, StringLength _wide0);
4493 }
4494 
4495 #ifdef ENABLE_ODBC_WIDE
4497 SQLGetStmtAttrW(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
4498 {
4499  tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtAttr(%p, %d, %p, %d, %p)\n",
4500  hstmt, (int)Attribute, Value, (int)BufferLength, StringLength);
4501 
4502  return _SQLGetStmtAttr(hstmt, Attribute, Value, BufferLength, StringLength, 1);
4503 }
4504 #endif
4505 #endif
4506 
4509 {
4510  tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtOption(%p, %d, %p)\n",
4511  hstmt, fOption, pvParam);
4512 
4513  return _SQLGetStmtAttr(hstmt, (SQLINTEGER) fOption, pvParam, SQL_MAX_OPTION_STRING_LENGTH, NULL _wide0);
4514 }
4515 
4518 {
4520 
4521  tdsdump_log(TDS_DBG_FUNC, "SQLNumResultCols(%p, %p)\n",
4522  hstmt, pccol);
4523 
4524  /*
4525  * 3/15/2001 bsb - DBD::ODBC calls SQLNumResultCols on non-result
4526  * generating queries such as 'drop table'
4527  */
4528 #if 0
4529  if (stmt->row_status == NOT_IN_ROW) {
4530  odbc_errs_add(&stmt->errs, "24000", NULL);
4531  ODBC_EXIT_(stmt);
4532  }
4533 #endif
4534  IRD_UPDATE(stmt->ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
4535  *pccol = stmt->ird->header.sql_desc_count;
4536  ODBC_EXIT_(stmt);
4537 }
4538 
4540 {
4541  SQLRETURN retcode;
4542 
4544 
4545  /* try to free dynamic associated */
4546  retcode = odbc_free_dynamic(stmt);
4547  if (retcode != SQL_SUCCESS)
4548  ODBC_EXIT(stmt, retcode);
4549 
4550  if (SQL_SUCCESS != odbc_set_stmt_query(stmt, szSqlStr, cbSqlStr _wide))
4552  stmt->is_prepared_query = 1;
4553 
4554  /* count parameters */
4555  stmt->param_count = tds_count_placeholders(tds_dstr_cstr(&stmt->query));
4556 
4557  /* trasform to native (one time, not for every SQLExecute) */
4558  if (SQL_SUCCESS != prepare_call(stmt))
4560 
4561  /* TODO needed ?? */
4562  tds_release_dynamic(&stmt->dyn);
4563 
4564  /* try to prepare query */
4565  /* TODO support getting info for RPC */
4566  if (!stmt->prepared_query_is_rpc
4567  && (stmt->attr.cursor_type == SQL_CURSOR_FORWARD_ONLY && stmt->attr.concurrency == SQL_CONCUR_READ_ONLY)) {
4568 
4569  tds_free_param_results(stmt->params);
4570  stmt->params = NULL;
4571  stmt->param_num = 0;
4572  stmt->need_reprepare = 0;
4573  /*
4574  * using TDS7+ we need parameters to prepare a query so try
4575  * to get them
4576  * TDS5 do not need parameters type and we have always to
4577  * prepare sepatarely so this is not an issue
4578  */
4579  if (IS_TDS7_PLUS(stmt->dbc->tds_socket->conn)) {
4580  stmt->need_reprepare = 1;
4581  ODBC_EXIT_(stmt);
4582  }
4583 
4584  tdsdump_log(TDS_DBG_INFO1, "Creating prepared statement\n");
4586  odbc_prepare(stmt);
4587  }
4588 
4589  ODBC_EXIT_(stmt);
4590 }
4591 
4592 /* TDS_NO_COUNT must be -1 for SQLRowCount to return -1 when there is no rowcount */
4593 #if TDS_NO_COUNT != -1
4594 # error TDS_NO_COUNT != -1
4595 #endif
4596 
4597 SQLRETURN
4599 {
4601 
4602  tdsdump_log(TDS_DBG_FUNC, "_SQLRowCount(%p, %p), %ld rows \n", hstmt, pcrow, (long)stmt->row_count);
4603 
4604  *pcrow = stmt->row_count;
4605 
4606  ODBC_EXIT_(stmt);
4607 }
4608 
4611 {
4612  SQLRETURN rc = _SQLRowCount(hstmt, pcrow);
4613  tdsdump_log(TDS_DBG_INFO1, "SQLRowCount returns %d, row count %ld\n", rc, (long int) *pcrow);
4614  return rc;
4615 }
4616 
4618 {
4620 
4621  /* cursor already present, we cannot set name */
4622  if (stmt->cursor) {
4623  odbc_errs_add(&stmt->errs, "24000", NULL);
4624  ODBC_EXIT_(stmt);
4625  }
4626 
4627  if (!odbc_dstr_copy(stmt->dbc, &stmt->cursor_name, cbCursor, szCursor)) {
4628  odbc_errs_add(&stmt->errs, "HY001", NULL);
4629  ODBC_EXIT_(stmt);
4630  }
4631  ODBC_EXIT_(stmt);
4632 }
4633 
4635 {
4636  SQLRETURN rc;
4637 
4639 
4640  if ((rc = odbc_set_string(stmt->dbc, szCursor, cbCursorMax, pcbCursor, tds_dstr_cstr(&stmt->cursor_name), -1)))
4641  odbc_errs_add(&stmt->errs, "01004", NULL);
4642 
4643  ODBC_EXIT(stmt, rc);
4644 }
4645 
4646 /*
4647  * spinellia@acm.org : copied shamelessly from change_database
4648  * transaction support
4649  * 1 = commit, 0 = rollback
4650  */
4651 static SQLRETURN
4653 {
4654  TDSSOCKET *tds = dbc->tds_socket;
4655  int cont;
4656  TDSRET ret;
4657 
4658  tdsdump_log(TDS_DBG_INFO1, "change_transaction(0x%p,%d)\n", dbc, state);
4659 
4660  if (dbc->attr.autocommit == SQL_AUTOCOMMIT_ON)
4661  cont = 0;
4662  else
4663  cont = 1;
4664 
4665  /* if pending drop all recordset, don't issue cancel */
4666  if