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

Generated by: LCOV version 1.13