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-01-18 12:13:41 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         728 : prepared_rpc(struct _hstmt *stmt, bool compute_row)
      45             : {
      46         728 :         int nparam = stmt->params ? stmt->params->num_cols : 0;
      47             :         const char *p;
      48         728 :         TDSCONNECTION *conn = stmt->dbc->tds_socket->conn;
      49             : 
      50        1456 :         if (stmt->prepared_pos > tds_dstr_len(&stmt->query))
      51             :                 return SQL_ERROR;
      52             : 
      53        1456 :         p = tds_dstr_cstr(&stmt->query) + stmt->prepared_pos - 1;
      54             : 
      55         310 :         for (;;) {
      56             :                 TDSPARAMINFO *temp_params;
      57             :                 TDSCOLUMN *curcol;
      58             :                 TDS_SERVER_TYPE type;
      59             :                 const char *start;
      60             : 
      61        1868 :                 while (TDS_ISSPACE(*++p))
      62         830 :                         continue;
      63        1038 :                 if (!*p)
      64         728 :                         return SQL_SUCCESS;
      65             : 
      66             :                 /* we have certainly a parameter */
      67        1032 :                 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        1032 :                 stmt->params = temp_params;
      72        1032 :                 curcol = temp_params->columns[nparam];
      73             : 
      74        1032 :                 switch (*p) {
      75           8 :                 case ',':
      76           8 :                         if (IS_TDS7_PLUS(conn)) {
      77           6 :                                 tds_set_param_type(conn, curcol, SYBVOID);
      78           6 :                                 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           8 :                         if (compute_row)
      86           8 :                                 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          72 :                 default:
      93             :                         /* add next parameter to list */
      94          72 :                         start = p;
      95             : 
      96          72 :                         if (!(p = parse_const_param(p, &type))) {
      97           0 :                                 tds_free_param_result(temp_params);
      98           0 :                                 return SQL_ERROR;
      99             :                         }
     100          72 :                         tds_set_param_type(conn, curcol, type);
     101          72 :                         switch (type) {
     102          40 :                         case SYBVARCHAR:
     103          40 :                                 curcol->column_size = p - start;
     104          40 :                                 break;
     105           8 :                         case SYBVARBINARY:
     106           8 :                                 curcol->column_size = (p - start) / 2 -1;
     107           8 :                                 break;
     108             :                         default:
     109           0 :                                 assert(0);
     110             :                         case SYBINT4:
     111             :                         case SYBINT8:
     112             :                         case SYBFLT8:
     113          24 :                                 curcol->column_cur_size = curcol->column_size;
     114          24 :                                 break;
     115             :                         }
     116          72 :                         curcol->on_server.column_size = curcol->column_size;
     117             :                         /* TODO support other type other than VARCHAR, do not strip escape in prepare_call */
     118          72 :                         if (compute_row) {
     119             :                                 char *dest;
     120             :                                 int len;
     121             :                                 CONV_RESULT cr;
     122             : 
     123          72 :                                 if (!tds_alloc_param_data(curcol)) {
     124           0 :                                         tds_free_param_result(temp_params);
     125           0 :                                         return SQL_ERROR;
     126             :                                 }
     127          72 :                                 dest = (char *) curcol->column_data;
     128          72 :                                 switch (type) {
     129          40 :                                 case SYBVARCHAR:
     130          40 :                                         if (*start != '\'') {
     131           0 :                                                 memcpy(dest, start, p - start);
     132           0 :                                                 curcol->column_cur_size = p - start;
     133             :                                         } else {
     134          40 :                                                 ++start;
     135             :                                                 for (;;) {
     136         824 :                                                         if (*start == '\'')
     137          40 :                                                                 ++start;
     138         432 :                                                         if (start >= p)
     139             :                                                                 break;
     140         392 :                                                         *dest++ = *start++;
     141             :                                                 }
     142          40 :                                                 curcol->column_cur_size =
     143          40 :                                                         dest - (char *) curcol->column_data;
     144             :                                         }
     145             :                                         break;
     146           8 :                                 case SYBVARBINARY:
     147           8 :                                         cr.cb.len = curcol->column_size;
     148           8 :                                         cr.cb.ib = dest;
     149           8 :                                         len = tds_convert(NULL, SYBVARCHAR, start, p - start, TDS_CONVERT_BINARY, &cr);
     150           8 :                                         if (len >= 0 && len <= curcol->column_size)
     151           8 :                                                 curcol->column_cur_size = len;
     152             :                                         break;
     153           8 :                                 case SYBINT4:
     154           8 :                                         *((TDS_INT *) dest) = strtol(start, NULL, 10);
     155           8 :                                         break;
     156           8 :                                 case SYBINT8:
     157           8 :                                         *((TDS_INT8 *) dest) = tds_strtoll(start, NULL, 10);
     158           8 :                                         break;
     159           8 :                                 case SYBFLT8:
     160           8 :                                         *((TDS_FLOAT *) dest) = strtod(start, NULL);
     161           8 :                                         break;
     162             :                                 default:
     163             :                                         break;
     164             :                                 }
     165             :                         }
     166          72 :                         --p;
     167          72 :                         break;
     168         952 :                 case '?':
     169             :                         /* find bound parameter */
     170         952 :                         if (stmt->param_num > stmt->apd->header.sql_desc_count
     171         952 :                             || 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        1904 :                         switch (odbc_sql2tds
     178         952 :                                 (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         936 :                         ++stmt->param_num;
     186         936 :                         break;
     187             :                 }
     188        1016 :                 ++nparam;
     189             : 
     190        2760 :                 while (TDS_ISSPACE(*++p))
     191         728 :                         continue;
     192        1016 :                 if (!*p || *p != ',')
     193             :                         return SQL_SUCCESS;
     194         620 :                 stmt->prepared_pos = p + 1 - tds_dstr_cstr(&stmt->query);
     195             :         }
     196             : }
     197             : 
     198             : int
     199       25222 : parse_prepared_query(struct _hstmt *stmt, bool compute_row)
     200             : {
     201             :         /* try setting this parameter */
     202             :         TDSPARAMINFO *temp_params;
     203       25222 :         int nparam = stmt->params ? stmt->params->num_cols : 0;
     204             : 
     205       25222 :         if (stmt->prepared_pos > 0)
     206         728 :                 return prepared_rpc(stmt, compute_row);
     207             : 
     208       24494 :         tdsdump_log(TDS_DBG_FUNC, "parsing %d parameters\n", nparam);
     209             : 
     210        5588 :         for (; stmt->param_num <= stmt->param_count; ++nparam, ++stmt->param_num) {
     211             :                 /* find bound parameter */
     212        5854 :                 if (stmt->param_num > stmt->apd->header.sql_desc_count || stmt->param_num > stmt->ipd->header.sql_desc_count) {
     213           6 :                         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        5848 :                 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        5848 :                 stmt->params = temp_params;
     226             : 
     227       23392 :                 switch (odbc_sql2tds
     228        5848 :                         (stmt, &stmt->ipd->records[stmt->param_num - 1], &stmt->apd->records[stmt->param_num - 1],
     229       11696 :                          stmt->params->columns[nparam], compute_row, stmt->apd, stmt->curr_param_row)) {
     230             :                 case SQL_ERROR:
     231             :                         return SQL_ERROR;
     232         260 :                 case SQL_NEED_DATA:
     233         260 :                         return SQL_NEED_DATA;
     234             :                 }
     235             :         }
     236             :         return SQL_SUCCESS;
     237             : }
     238             : 
     239             : int
     240       24962 : start_parse_prepared_query(struct _hstmt *stmt, bool compute_row)
     241             : {
     242             :         /* TODO should be NULL already ?? */
     243       24962 :         tds_free_param_results(stmt->params);
     244       24962 :         stmt->params = NULL;
     245             :         stmt->param_num = 0;
     246             : 
     247       24962 :         stmt->param_num = stmt->prepared_query_is_func ? 2 : 1;
     248       24962 :         return parse_prepared_query(stmt, compute_row);
     249             : }
     250             : 
     251             : static TDS_INT
     252          48 : odbc_wchar2hex(TDS_CHAR *dest, TDS_UINT destlen, const SQLWCHAR * src, TDS_UINT srclen)
     253             : {
     254             :         unsigned int i;
     255          48 :         SQLWCHAR hex1, c = 0;
     256             : 
     257             :         /* if srclen if odd we must add a "0" before ... */
     258          48 :         i = 0;          /* number where to start converting */
     259          48 :         if (srclen & 1) {
     260           0 :                 ++srclen;
     261           0 :                 i = 1;
     262           0 :                 --src;
     263             :         }
     264      320016 :         for (; i < srclen; ++i) {
     265      320016 :                 hex1 = src[i];
     266             : 
     267      320016 :                 if ('0' <= hex1 && hex1 <= '9')
     268      276928 :                         hex1 &= 0x0f;
     269             :                 else {
     270       43088 :                         hex1 &= (SQLWCHAR) ~0x20u;  /* mask off 0x20 to ensure upper case */
     271       43088 :                         if ('A' <= hex1 && hex1 <= 'F') {
     272       43088 :                                 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      320016 :                 assert(hex1 < 0x10);
     280             : 
     281      320016 :                 if ((i/2u) >= destlen)
     282           0 :                         continue;
     283             : 
     284      320016 :                 if (i & 1)
     285      160008 :                         dest[i / 2u] = c | hex1;
     286             :                 else
     287      160008 :                         c = hex1 << 4;
     288             :         }
     289          48 :         return srclen / 2u;
     290             : }
     291             : 
     292             : 
     293             : int
     294         652 : 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         652 :         assert(stmt);
     304             : 
     305         652 :         tdsdump_log(TDS_DBG_FUNC, "continue_parse_prepared_query with parameter %d\n", stmt->param_num);
     306             : 
     307         652 :         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         652 :         if (stmt->param_num > stmt->apd->header.sql_desc_count || stmt->param_num > stmt->ipd->header.sql_desc_count)
     313             :                 return SQL_ERROR;
     314         652 :         drec_apd = &stmt->apd->records[stmt->param_num - 1];
     315         652 :         drec_ipd = &stmt->ipd->records[stmt->param_num - 1];
     316             : 
     317         652 :         curcol = stmt->params->columns[stmt->param_num - (stmt->prepared_query_is_func ? 2 : 1)];
     318         652 :         blob = NULL;
     319         652 :         if (is_blob_col(curcol))
     320         652 :                 blob = (TDSBLOB *) curcol->column_data;
     321         652 :         assert(curcol->column_cur_size <= curcol->column_size);
     322         652 :         need_bytes = curcol->column_size - curcol->column_cur_size;
     323             : 
     324         652 :         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         652 :         }
     334             : 
     335             :         /* get C type */
     336         652 :         sql_src_type = drec_apd->sql_desc_concise_type;
     337         652 :         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         652 :         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         652 :         default:
     355         652 :                 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         652 :         if (!blob && len > need_bytes)
     369           0 :                 len = need_bytes;
     370             : 
     371             :         /* copy to destination */
     372         652 :         if (blob) {
     373             :                 TDS_CHAR *p;
     374         652 :                 int binary_convert = 0;
     375         652 :                 SQLLEN orig_len = len;
     376             : 
     377         652 :                 if (sql_src_type == SQL_C_CHAR || sql_src_type == SQL_C_WCHAR) {
     378         512 :                         TDS_SERVER_TYPE type = tds_get_conversion_type(curcol->column_type, curcol->column_size);
     379         512 :                         if (is_binary_type(type)) {
     380          64 :                                 if (len && sql_src_type == SQL_C_CHAR && !*((char*)DataPtr+len-1))
     381           0 :                                         --len;
     382             : 
     383          64 :                                 if (sql_src_type == SQL_C_WCHAR)
     384          32 :                                         len /= sizeof(SQLWCHAR);
     385             : 
     386          64 :                                 if (!len)
     387             :                                         return SQL_SUCCESS;
     388             : 
     389          64 :                                 binary_convert = 1;
     390          64 :                                 orig_len = len;
     391          64 :                                 len = len / 2u + 1u;
     392             :                         }
     393             :                 }
     394             : 
     395         652 :                 if (!len)
     396             :                         return SQL_SUCCESS;
     397             : 
     398         628 :                 assert(blob->textvalue || curcol->column_cur_size == 0);
     399         628 :                 p = (TDS_CHAR *) TDS_RESIZE(blob->textvalue, len + curcol->column_cur_size);
     400         628 :                 if (!p) {
     401           0 :                         odbc_errs_add(&stmt->errs, "HY001", NULL); /* Memory allocation error */
     402           0 :                         return SQL_ERROR;
     403             :                 }
     404             : 
     405         628 :                 p += curcol->column_cur_size;
     406         628 :                 if (binary_convert) {
     407             :                         int res;
     408             : 
     409          64 :                         len = orig_len;
     410             : 
     411          64 :                         if (curcol->column_cur_size > 0
     412          32 :                         &&  curcol->column_text_sqlputdatainfo) {
     413             :                                 SQLWCHAR data[2];
     414          16 :                                 data[0] = curcol->column_text_sqlputdatainfo;
     415          16 :                                 data[1] = (sql_src_type == SQL_C_CHAR) ? *(unsigned char*)DataPtr : *(SQLWCHAR*)DataPtr;
     416             : 
     417          16 :                                 res = odbc_wchar2hex(p, 1, data, 2);
     418          16 :                                 if (res < 0) {
     419           0 :                                         odbc_convert_err_set(&stmt->errs, res);
     420           0 :                                         return SQL_ERROR;
     421             :                                 }
     422          16 :                                 p += res;
     423             : 
     424          16 :                                 DataPtr = (SQLPOINTER) (((char*)DataPtr) +
     425          16 :                                         (sql_src_type == SQL_C_CHAR ? 1 : sizeof(SQLWCHAR)));
     426          16 :                                 --len;
     427             :                         }
     428             : 
     429          64 :                         if (len&1) {
     430          16 :                                 --len;
     431          16 :                                 curcol->column_text_sqlputdatainfo = (sql_src_type == SQL_C_CHAR) ? ((char*)DataPtr)[len] : ((SQLWCHAR*)DataPtr)[len];
     432             :                         }
     433             : 
     434          64 :                         res = (sql_src_type == SQL_C_CHAR) ?
     435          96 :                                 tds_char2hex(p, len / 2u, (const TDS_CHAR*) DataPtr, len):
     436          32 :                                 odbc_wchar2hex(p, len / 2u, (const SQLWCHAR*) DataPtr, len);
     437          64 :                         if (res < 0) {
     438           0 :                                 odbc_convert_err_set(&stmt->errs, res);
     439           0 :                                 return SQL_ERROR;
     440             :                         }
     441          64 :                         p += res;
     442             : 
     443          64 :                         len = p - (blob->textvalue + curcol->column_cur_size);
     444             :                 } else {
     445         564 :                         memcpy(blob->textvalue + curcol->column_cur_size, DataPtr, len);
     446             :                 }
     447             :         } else {
     448           0 :                 memcpy(curcol->column_data + curcol->column_cur_size, DataPtr, len);
     449             :         }
     450             : 
     451         628 :         curcol->column_cur_size += len;
     452             : 
     453         628 :         if (blob && curcol->column_cur_size > curcol->column_size)
     454         408 :                 curcol->column_size = curcol->column_cur_size;
     455             : 
     456             :         return SQL_SUCCESS;
     457             : }

Generated by: LCOV version 1.13