LCOV - code coverage report
Current view: top level - src/odbc - odbc.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 2173 3226 67.4 %
Date: 2026-11-07 23:58:45 Functions: 57 60 95.0 %

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

Generated by: LCOV version 1.13