LCOV - code coverage report
Current view: top level - src/odbc - prepare_query.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 182 230 79.1 %
Date: 2025-04-15 09:57:00 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004  Brian Bruns
       3             :  * Copyright (C) 2005-2008  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             : #include <assert.h>
      26             : 
      27             : #if HAVE_STDLIB_H
      28             : #include <stdlib.h>
      29             : #endif /* HAVE_STDLIB_H */
      30             : 
      31             : #if HAVE_STRING_H
      32             : #include <string.h>
      33             : #endif /* HAVE_STRING_H */
      34             : 
      35             : #include <ctype.h>
      36             : 
      37             : #include <freetds/odbc.h>
      38             : #include <freetds/convert.h>
      39             : #include <freetds/utils/string.h>
      40             : #include <freetds/checks.h>
      41             : 
      42             : #define TDS_ISSPACE(c) isspace((unsigned char) (c))
      43             : 
      44             : static int
      45         938 : prepared_rpc(struct _hstmt *stmt, bool compute_row)
      46             : {
      47         938 :         int nparam = stmt->params ? stmt->params->num_cols : 0;
      48             :         const char *p;
      49         938 :         TDSCONNECTION *conn = stmt->dbc->tds_socket->conn;
      50             : 
      51        1876 :         if (stmt->prepared_pos > tds_dstr_len(&stmt->query))
      52             :                 return SQL_ERROR;
      53             : 
      54        1876 :         p = tds_dstr_cstr(&stmt->query) + stmt->prepared_pos - 1;
      55             : 
      56         400 :         for (;;) {
      57             :                 TDSPARAMINFO *temp_params;
      58             :                 TDSCOLUMN *curcol;
      59             :                 TDS_SERVER_TYPE type;
      60             :                 const char *start;
      61             : 
      62        2404 :                 while (TDS_ISSPACE(*++p))
      63        1066 :                         continue;
      64        1338 :                 if (!*p)
      65         938 :                         return SQL_SUCCESS;
      66             : 
      67             :                 /* we have certainly a parameter */
      68        1330 :                 if (!(temp_params = tds_alloc_param_result(stmt->params))) {
      69           0 :                         odbc_errs_add(&stmt->errs, "HY001", NULL);
      70           0 :                         return SQL_ERROR;
      71             :                 }
      72        1330 :                 stmt->params = temp_params;
      73        1330 :                 curcol = temp_params->columns[nparam];
      74             : 
      75        1330 :                 switch (*p) {
      76          10 :                 case ',':
      77          10 :                         if (IS_TDS7_PLUS(conn)) {
      78           8 :                                 tds_set_param_type(conn, curcol, SYBVOID);
      79           8 :                                 curcol->column_size = curcol->column_cur_size = 0;
      80             :                         } else {
      81             :                                 /* TODO is there a better type ? */
      82           2 :                                 tds_set_param_type(conn, curcol, SYBINTN);
      83           2 :                                 curcol->column_size = curcol->on_server.column_size = 4;
      84           2 :                                 curcol->column_cur_size = -1;
      85             :                         }
      86          10 :                         if (compute_row)
      87          10 :                                 if (!tds_alloc_param_data(curcol)) {
      88           0 :                                         tds_free_param_result(temp_params);
      89           0 :                                         return SQL_ERROR;
      90             :                                 }
      91             :                         --p;
      92             :                         break;
      93          90 :                 default:
      94             :                         /* add next parameter to list */
      95          90 :                         start = p;
      96             : 
      97          90 :                         if (!(p = parse_const_param(p, &type))) {
      98           0 :                                 tds_free_param_result(temp_params);
      99           0 :                                 return SQL_ERROR;
     100             :                         }
     101          90 :                         tds_set_param_type(conn, curcol, type);
     102          90 :                         switch (type) {
     103          50 :                         case SYBVARCHAR:
     104          50 :                                 curcol->column_size = p - start;
     105          50 :                                 break;
     106          10 :                         case SYBVARBINARY:
     107          10 :                                 curcol->column_size = (p - start) / 2 -1;
     108          10 :                                 break;
     109             :                         default:
     110           0 :                                 assert(0);
     111             :                         case SYBINT4:
     112             :                         case SYBINT8:
     113             :                         case SYBFLT8:
     114          30 :                                 curcol->column_cur_size = curcol->column_size;
     115          30 :                                 break;
     116             :                         }
     117          90 :                         curcol->on_server.column_size = curcol->column_size;
     118             :                         /* TODO support other type other than VARCHAR, do not strip escape in prepare_call */
     119          90 :                         if (compute_row) {
     120             :                                 char *dest;
     121             :                                 int len;
     122             :                                 CONV_RESULT cr;
     123             : 
     124          90 :                                 if (!tds_alloc_param_data(curcol)) {
     125           0 :                                         tds_free_param_result(temp_params);
     126           0 :                                         return SQL_ERROR;
     127             :                                 }
     128          90 :                                 dest = (char *) curcol->column_data;
     129          90 :                                 switch (type) {
     130          50 :                                 case SYBVARCHAR:
     131          50 :                                         if (*start != '\'') {
     132           0 :                                                 memcpy(dest, start, p - start);
     133           0 :                                                 curcol->column_cur_size = p - start;
     134             :                                         } else {
     135          50 :                                                 ++start;
     136             :                                                 for (;;) {
     137        1030 :                                                         if (*start == '\'')
     138          50 :                                                                 ++start;
     139         540 :                                                         if (start >= p)
     140             :                                                                 break;
     141         490 :                                                         *dest++ = *start++;
     142             :                                                 }
     143          50 :                                                 curcol->column_cur_size =
     144          50 :                                                         dest - (char *) curcol->column_data;
     145             :                                         }
     146             :                                         break;
     147          10 :                                 case SYBVARBINARY:
     148          10 :                                         cr.cb.len = curcol->column_size;
     149          10 :                                         cr.cb.ib = dest;
     150          10 :                                         len = tds_convert(NULL, SYBVARCHAR, start, p - start, TDS_CONVERT_BINARY, &cr);
     151          10 :                                         if (len >= 0 && len <= curcol->column_size)
     152          10 :                                                 curcol->column_cur_size = len;
     153             :                                         break;
     154          10 :                                 case SYBINT4:
     155          10 :                                         *((TDS_INT *) dest) = atoi(start);
     156          10 :                                         break;
     157          10 :                                 case SYBINT8:
     158          10 :                                         *((TDS_INT8 *) dest) = tds_strtoll(start, NULL, 10);
     159          10 :                                         break;
     160          10 :                                 case SYBFLT8:
     161          10 :                                         *((TDS_FLOAT *) dest) = strtod(start, NULL);
     162          10 :                                         break;
     163             :                                 default:
     164             :                                         break;
     165             :                                 }
     166             :                         }
     167          90 :                         --p;
     168          90 :                         break;
     169        1230 :                 case '?':
     170             :                         /* find bound parameter */
     171        1230 :                         if (stmt->param_num > stmt->apd->header.sql_desc_count
     172        1230 :                             || stmt->param_num > stmt->ipd->header.sql_desc_count) {
     173           0 :                                 tds_free_param_result(temp_params);
     174             :                                 /* TODO set error */
     175           0 :                                 return SQL_ERROR;
     176             :                         }
     177             : 
     178        2460 :                         switch (odbc_sql2tds
     179        1230 :                                 (stmt, &stmt->ipd->records[stmt->param_num - 1], &stmt->apd->records[stmt->param_num - 1],
     180        1230 :                                  curcol, compute_row, stmt->apd, stmt->curr_param_row)) {
     181             :                         case SQL_ERROR:
     182             :                                 return SQL_ERROR;
     183           0 :                         case SQL_NEED_DATA:
     184           0 :                                 return SQL_NEED_DATA;
     185             :                         }
     186        1210 :                         ++stmt->param_num;
     187        1210 :                         break;
     188             :                 }
     189        1310 :                 ++nparam;
     190             : 
     191        3558 :                 while (TDS_ISSPACE(*++p))
     192         938 :                         continue;
     193        1310 :                 if (!*p || *p != ',')
     194             :                         return SQL_SUCCESS;
     195         800 :                 stmt->prepared_pos = p + 1 - tds_dstr_cstr(&stmt->query);
     196             :         }
     197             : }
     198             : 
     199             : int
     200       33913 : parse_prepared_query(struct _hstmt *stmt, bool compute_row)
     201             : {
     202             :         /* try setting this parameter */
     203             :         TDSPARAMINFO *temp_params;
     204       33913 :         int nparam = stmt->params ? stmt->params->num_cols : 0;
     205             : 
     206       33913 :         if (stmt->prepared_pos > 0)
     207         938 :                 return prepared_rpc(stmt, compute_row);
     208             : 
     209       32975 :         tdsdump_log(TDS_DBG_FUNC, "parsing %d parameters\n", nparam);
     210             : 
     211        7952 :         for (; stmt->param_num <= (int) stmt->param_count; ++nparam, ++stmt->param_num) {
     212             :                 /* find bound parameter */
     213        8292 :                 if (stmt->param_num > stmt->apd->header.sql_desc_count || stmt->param_num > stmt->ipd->header.sql_desc_count) {
     214           8 :                         tdsdump_log(TDS_DBG_FUNC, "parse_prepared_query: logic_error: parameter out of bounds: "
     215             :                                                   "%d > %d || %d > %d\n",
     216             :                                                    stmt->param_num, stmt->apd->header.sql_desc_count,
     217           0 :                                                    stmt->param_num, stmt->ipd->header.sql_desc_count);
     218             :                         return SQL_ERROR;
     219             :                 }
     220             : 
     221             :                 /* add a column to parameters */
     222        8284 :                 if (!(temp_params = tds_alloc_param_result(stmt->params))) {
     223           0 :                         odbc_errs_add(&stmt->errs, "HY001", NULL);
     224           0 :                         return SQL_ERROR;
     225             :                 }
     226        8284 :                 stmt->params = temp_params;
     227             : 
     228       33136 :                 switch (odbc_sql2tds
     229        8284 :                         (stmt, &stmt->ipd->records[stmt->param_num - 1], &stmt->apd->records[stmt->param_num - 1],
     230       24852 :                          stmt->params->columns[nparam], compute_row, stmt->apd, stmt->curr_param_row)) {
     231             :                 case SQL_ERROR:
     232             :                         return SQL_ERROR;
     233         332 :                 case SQL_NEED_DATA:
     234         332 :                         return SQL_NEED_DATA;
     235             :                 }
     236             :         }
     237             :         return SQL_SUCCESS;
     238             : }
     239             : 
     240             : int
     241       33581 : start_parse_prepared_query(struct _hstmt *stmt, bool compute_row)
     242             : {
     243             :         /* TODO should be NULL already ?? */
     244       33581 :         tds_free_param_results(stmt->params);
     245       33581 :         stmt->params = NULL;
     246             : 
     247       33581 :         stmt->param_num = stmt->prepared_query_is_func ? 2 : 1;
     248       33581 :         return parse_prepared_query(stmt, compute_row);
     249             : }
     250             : 
     251             : static ptrdiff_t
     252          60 : odbc_wchar2hex(TDS_CHAR *dest, size_t destlen, const SQLWCHAR * src, size_t srclen)
     253             : {
     254             :         size_t i;
     255          60 :         SQLWCHAR hex1, c = 0;
     256             : 
     257             :         /* if srclen if odd we must add a "0" before ... */
     258          60 :         i = 0;          /* number where to start converting */
     259          60 :         if (srclen & 1) {
     260           0 :                 ++srclen;
     261           0 :                 i = 1;
     262           0 :                 --src;
     263             :         }
     264      400020 :         for (; i < srclen; ++i) {
     265      400020 :                 hex1 = src[i];
     266             : 
     267      400020 :                 if ('0' <= hex1 && hex1 <= '9')
     268      346160 :                         hex1 &= 0x0f;
     269             :                 else {
     270       53860 :                         hex1 |= 0x20;   /* ensure lower case */
     271       53860 :                         if ('a' <= hex1 && hex1 <= 'f') {
     272       53860 :                                 hex1 -= ('a' - 10);
     273             :                         } else {
     274           0 :                                 tdsdump_log(TDS_DBG_INFO1,
     275             :                                             "error_handler:  attempt to convert data stopped by syntax error in source field \n");
     276             :                                 return TDS_CONVERT_SYNTAX;
     277             :                         }
     278             :                 }
     279      400020 :                 tds_extra_assert(hex1 < 0x10);
     280             : 
     281      400020 :                 if ((i/2u) >= destlen)
     282           0 :                         continue;
     283             : 
     284      400020 :                 if (i & 1)
     285      200010 :                         dest[i / 2u] = c | hex1;
     286             :                 else
     287      200010 :                         c = hex1 << 4;
     288             :         }
     289          60 :         return srclen / 2u;
     290             : }
     291             : 
     292             : 
     293             : int
     294         832 : continue_parse_prepared_query(struct _hstmt *stmt, SQLPOINTER DataPtr, SQLLEN StrLen_or_Ind)
     295             : {
     296             :         struct _drecord *drec_apd, *drec_ipd;
     297             :         SQLLEN len;
     298             :         int need_bytes;
     299             :         TDSCOLUMN *curcol;
     300             :         TDSBLOB *blob;
     301             :         int sql_src_type;
     302             : 
     303         832 :         assert(stmt);
     304             : 
     305         832 :         tdsdump_log(TDS_DBG_FUNC, "continue_parse_prepared_query with parameter %d\n", stmt->param_num);
     306             : 
     307         832 :         if (!stmt->params) {
     308           0 :                 tdsdump_log(TDS_DBG_FUNC, "error? continue_parse_prepared_query: no parameters provided");
     309             :                 return SQL_ERROR;
     310             :         }
     311             : 
     312         832 :         if (stmt->param_num > stmt->apd->header.sql_desc_count || stmt->param_num > stmt->ipd->header.sql_desc_count)
     313             :                 return SQL_ERROR;
     314         832 :         drec_apd = &stmt->apd->records[stmt->param_num - 1];
     315         832 :         drec_ipd = &stmt->ipd->records[stmt->param_num - 1];
     316             : 
     317         832 :         curcol = stmt->params->columns[stmt->param_num - (stmt->prepared_query_is_func ? 2 : 1)];
     318         832 :         blob = NULL;
     319         832 :         if (is_blob_col(curcol))
     320         832 :                 blob = (TDSBLOB *) curcol->column_data;
     321         832 :         assert(curcol->column_cur_size <= curcol->column_size);
     322         832 :         need_bytes = curcol->column_size - curcol->column_cur_size;
     323             : 
     324         832 :         if (DataPtr == NULL) {
     325           0 :                 switch(StrLen_or_Ind) {
     326             :                 case SQL_NULL_DATA:
     327             :                 case SQL_DEFAULT_PARAM:
     328             :                         break;  /* OK */
     329           0 :                 default:
     330           0 :                         odbc_errs_add(&stmt->errs, "HY009", NULL); /* Invalid use of null pointer */
     331           0 :                         return SQL_ERROR;
     332             :                 }
     333         832 :         }
     334             : 
     335             :         /* get C type */
     336         832 :         sql_src_type = drec_apd->sql_desc_concise_type;
     337         832 :         if (sql_src_type == SQL_C_DEFAULT)
     338           0 :                 sql_src_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type);
     339             : 
     340         832 :         switch(StrLen_or_Ind) {
     341           0 :         case SQL_NTS:
     342           0 :                 if (sql_src_type == SQL_C_WCHAR)
     343           0 :                         len = sqlwcslen((SQLWCHAR *) DataPtr);
     344             :                 else
     345           0 :                         len = strlen((char *) DataPtr);
     346             :                 break;
     347             :         case SQL_NULL_DATA:
     348             :                 len = 0;
     349             :                 break;
     350           0 :         case SQL_DEFAULT_PARAM:
     351             :                 /* FIXME: use the default if the parameter has one. */
     352           0 :                 odbc_errs_add(&stmt->errs, "07S01", NULL); /* Invalid use of default parameter */
     353           0 :                 return SQL_ERROR;
     354         832 :         default:
     355         832 :                 if (DataPtr && StrLen_or_Ind < 0) {
     356             :                         /*
     357             :                          * "The argument DataPtr was not a null pointer, and
     358             :                          * the argument StrLen_or_Ind was less than 0
     359             :                          * but not equal to SQL_NTS or SQL_NULL_DATA."
     360             :                          */
     361           0 :                         odbc_errs_add(&stmt->errs, "HY090", NULL);
     362           0 :                         return SQL_ERROR;
     363             :                 }
     364             :                 len = StrLen_or_Ind;
     365             :                 break;
     366             :         }
     367             : 
     368         832 :         if (!blob && len > need_bytes)
     369           0 :                 len = need_bytes;
     370             : 
     371             :         /* copy to destination */
     372         832 :         if (blob) {
     373             :                 TDS_CHAR *p;
     374         832 :                 int binary_convert = 0;
     375         832 :                 SQLLEN orig_len = len;
     376             : 
     377         832 :                 if (sql_src_type == SQL_C_CHAR || sql_src_type == SQL_C_WCHAR) {
     378         656 :                         TDS_SERVER_TYPE type = tds_get_conversion_type(curcol->column_type, curcol->column_size);
     379         656 :                         if (is_binary_type(type)) {
     380          80 :                                 if (len && sql_src_type == SQL_C_CHAR && !*((char*)DataPtr+len-1))
     381           0 :                                         --len;
     382             : 
     383          80 :                                 if (sql_src_type == SQL_C_WCHAR)
     384          40 :                                         len /= sizeof(SQLWCHAR);
     385             : 
     386          80 :                                 if (!len)
     387             :                                         return SQL_SUCCESS;
     388             : 
     389          80 :                                 binary_convert = 1;
     390          80 :                                 orig_len = len;
     391          80 :                                 len = len / 2u + 1u;
     392             :                         }
     393             :                 }
     394             : 
     395         832 :                 if (!len)
     396             :                         return SQL_SUCCESS;
     397             : 
     398         800 :                 assert(blob->textvalue || curcol->column_cur_size == 0);
     399         800 :                 p = (TDS_CHAR *) TDS_RESIZE(blob->textvalue, len + curcol->column_cur_size);
     400         800 :                 if (!p) {
     401           0 :                         odbc_errs_add(&stmt->errs, "HY001", NULL); /* Memory allocation error */
     402           0 :                         return SQL_ERROR;
     403             :                 }
     404             : 
     405         800 :                 p += curcol->column_cur_size;
     406         800 :                 if (binary_convert) {
     407             :                         ptrdiff_t res;
     408             : 
     409          80 :                         len = orig_len;
     410             : 
     411          80 :                         if (curcol->column_cur_size > 0
     412          40 :                         &&  curcol->column_text_sqlputdatainfo) {
     413             :                                 SQLWCHAR data[2];
     414          20 :                                 data[0] = curcol->column_text_sqlputdatainfo;
     415          20 :                                 data[1] = (sql_src_type == SQL_C_CHAR) ? *(unsigned char*)DataPtr : *(SQLWCHAR*)DataPtr;
     416             : 
     417          20 :                                 res = odbc_wchar2hex(p, 1, data, 2);
     418          20 :                                 if (res < 0) {
     419           0 :                                         odbc_convert_err_set(&stmt->errs, (TDS_INT) res);
     420           0 :                                         return SQL_ERROR;
     421             :                                 }
     422          20 :                                 p += res;
     423             : 
     424          20 :                                 DataPtr = (SQLPOINTER) (((char*)DataPtr) +
     425          20 :                                         (sql_src_type == SQL_C_CHAR ? 1 : sizeof(SQLWCHAR)));
     426          20 :                                 --len;
     427             :                         }
     428             : 
     429          80 :                         if (len&1) {
     430          20 :                                 --len;
     431          40 :                                 curcol->column_text_sqlputdatainfo =
     432          20 :                                         (sql_src_type == SQL_C_CHAR) ? ((char*)DataPtr)[len] : ((SQLWCHAR*)DataPtr)[len];
     433             :                         }
     434             : 
     435          80 :                         res = (sql_src_type == SQL_C_CHAR) ?
     436         120 :                                 tds_char2hex(p, len / 2u, (const TDS_CHAR*) DataPtr, len):
     437          40 :                                 odbc_wchar2hex(p, len / 2u, (const SQLWCHAR*) DataPtr, len);
     438          80 :                         if (res < 0) {
     439           0 :                                 odbc_convert_err_set(&stmt->errs, (TDS_INT) res);
     440           0 :                                 return SQL_ERROR;
     441             :                         }
     442          80 :                         p += res;
     443             : 
     444          80 :                         len = p - (blob->textvalue + curcol->column_cur_size);
     445             :                 } else {
     446         720 :                         memcpy(blob->textvalue + curcol->column_cur_size, DataPtr, len);
     447             :                 }
     448           0 :         } else if (len > 0) {
     449           0 :                 memcpy(curcol->column_data + curcol->column_cur_size, DataPtr, len);
     450             :         }
     451             : 
     452         800 :         curcol->column_cur_size += len;
     453             : 
     454         800 :         if (blob && curcol->column_cur_size > curcol->column_size)
     455         520 :                 curcol->column_size = curcol->column_cur_size;
     456             : 
     457             :         return SQL_SUCCESS;
     458             : }

Generated by: LCOV version 1.13