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 11:50:39 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       25542 : parse_prepared_query(struct _hstmt *stmt, bool compute_row)
     200             : {
     201             :         /* try setting this parameter */
     202             :         TDSPARAMINFO *temp_params;
     203       25542 :         int nparam = stmt->params ? stmt->params->num_cols : 0;
     204             : 
     205       25542 :         if (stmt->prepared_pos > 0)
     206         728 :                 return prepared_rpc(stmt, compute_row);
     207             : 
     208       24814 :         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       25282 : start_parse_prepared_query(struct _hstmt *stmt, bool compute_row)
     241             : {
     242             :         /* TODO should be NULL already ?? */
     243       25282 :         tds_free_param_results(stmt->params);
     244       25282 :         stmt->params = NULL;
     245             : 
     246       25282 :         stmt->param_num = stmt->prepared_query_is_func ? 2 : 1;
     247       25282 :         return parse_prepared_query(stmt, compute_row);
     248             : }
     249             : 
     250             : static TDS_INT
     251          48 : odbc_wchar2hex(TDS_CHAR *dest, TDS_UINT destlen, const SQLWCHAR * src, TDS_UINT srclen)
     252             : {
     253             :         unsigned int i;
     254          48 :         SQLWCHAR hex1, c = 0;
     255             : 
     256             :         /* if srclen if odd we must add a "0" before ... */
     257          48 :         i = 0;          /* number where to start converting */
     258          48 :         if (srclen & 1) {
     259           0 :                 ++srclen;
     260           0 :                 i = 1;
     261           0 :                 --src;
     262             :         }
     263      320016 :         for (; i < srclen; ++i) {
     264      320016 :                 hex1 = src[i];
     265             : 
     266      320016 :                 if ('0' <= hex1 && hex1 <= '9')
     267      276928 :                         hex1 &= 0x0f;
     268             :                 else {
     269       43088 :                         hex1 &= (SQLWCHAR) ~0x20u;  /* mask off 0x20 to ensure upper case */
     270       43088 :                         if ('A' <= hex1 && hex1 <= 'F') {
     271       43088 :                                 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      320016 :                 assert(hex1 < 0x10);
     279             : 
     280      320016 :                 if ((i/2u) >= destlen)
     281           0 :                         continue;
     282             : 
     283      320016 :                 if (i & 1)
     284      160008 :                         dest[i / 2u] = c | hex1;
     285             :                 else
     286      160008 :                         c = hex1 << 4;
     287             :         }
     288          48 :         return srclen / 2u;
     289             : }
     290             : 
     291             : 
     292             : int
     293         652 : 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         652 :         assert(stmt);
     303             : 
     304         652 :         tdsdump_log(TDS_DBG_FUNC, "continue_parse_prepared_query with parameter %d\n", stmt->param_num);
     305             : 
     306         652 :         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         652 :         if (stmt->param_num > stmt->apd->header.sql_desc_count || stmt->param_num > stmt->ipd->header.sql_desc_count)
     312             :                 return SQL_ERROR;
     313         652 :         drec_apd = &stmt->apd->records[stmt->param_num - 1];
     314         652 :         drec_ipd = &stmt->ipd->records[stmt->param_num - 1];
     315             : 
     316         652 :         curcol = stmt->params->columns[stmt->param_num - (stmt->prepared_query_is_func ? 2 : 1)];
     317         652 :         blob = NULL;
     318         652 :         if (is_blob_col(curcol))
     319         652 :                 blob = (TDSBLOB *) curcol->column_data;
     320         652 :         assert(curcol->column_cur_size <= curcol->column_size);
     321         652 :         need_bytes = curcol->column_size - curcol->column_cur_size;
     322             : 
     323         652 :         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         652 :         }
     333             : 
     334             :         /* get C type */
     335         652 :         sql_src_type = drec_apd->sql_desc_concise_type;
     336         652 :         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         652 :         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         652 :         default:
     354         652 :                 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         652 :         if (!blob && len > need_bytes)
     368           0 :                 len = need_bytes;
     369             : 
     370             :         /* copy to destination */
     371         652 :         if (blob) {
     372             :                 TDS_CHAR *p;
     373         652 :                 int binary_convert = 0;
     374         652 :                 SQLLEN orig_len = len;
     375             : 
     376         652 :                 if (sql_src_type == SQL_C_CHAR || sql_src_type == SQL_C_WCHAR) {
     377         512 :                         TDS_SERVER_TYPE type = tds_get_conversion_type(curcol->column_type, curcol->column_size);
     378         512 :                         if (is_binary_type(type)) {
     379          64 :                                 if (len && sql_src_type == SQL_C_CHAR && !*((char*)DataPtr+len-1))
     380           0 :                                         --len;
     381             : 
     382          64 :                                 if (sql_src_type == SQL_C_WCHAR)
     383          32 :                                         len /= sizeof(SQLWCHAR);
     384             : 
     385          64 :                                 if (!len)
     386             :                                         return SQL_SUCCESS;
     387             : 
     388          64 :                                 binary_convert = 1;
     389          64 :                                 orig_len = len;
     390          64 :                                 len = len / 2u + 1u;
     391             :                         }
     392             :                 }
     393             : 
     394         652 :                 if (!len)
     395             :                         return SQL_SUCCESS;
     396             : 
     397         628 :                 assert(blob->textvalue || curcol->column_cur_size == 0);
     398         628 :                 p = (TDS_CHAR *) TDS_RESIZE(blob->textvalue, len + curcol->column_cur_size);
     399         628 :                 if (!p) {
     400           0 :                         odbc_errs_add(&stmt->errs, "HY001", NULL); /* Memory allocation error */
     401           0 :                         return SQL_ERROR;
     402             :                 }
     403             : 
     404         628 :                 p += curcol->column_cur_size;
     405         628 :                 if (binary_convert) {
     406             :                         int res;
     407             : 
     408          64 :                         len = orig_len;
     409             : 
     410          64 :                         if (curcol->column_cur_size > 0
     411          32 :                         &&  curcol->column_text_sqlputdatainfo) {
     412             :                                 SQLWCHAR data[2];
     413          16 :                                 data[0] = curcol->column_text_sqlputdatainfo;
     414          16 :                                 data[1] = (sql_src_type == SQL_C_CHAR) ? *(unsigned char*)DataPtr : *(SQLWCHAR*)DataPtr;
     415             : 
     416          16 :                                 res = odbc_wchar2hex(p, 1, data, 2);
     417          16 :                                 if (res < 0) {
     418           0 :                                         odbc_convert_err_set(&stmt->errs, res);
     419           0 :                                         return SQL_ERROR;
     420             :                                 }
     421          16 :                                 p += res;
     422             : 
     423          16 :                                 DataPtr = (SQLPOINTER) (((char*)DataPtr) +
     424          16 :                                         (sql_src_type == SQL_C_CHAR ? 1 : sizeof(SQLWCHAR)));
     425          16 :                                 --len;
     426             :                         }
     427             : 
     428          64 :                         if (len&1) {
     429          16 :                                 --len;
     430          16 :                                 curcol->column_text_sqlputdatainfo = (sql_src_type == SQL_C_CHAR) ? ((char*)DataPtr)[len] : ((SQLWCHAR*)DataPtr)[len];
     431             :                         }
     432             : 
     433          64 :                         res = (sql_src_type == SQL_C_CHAR) ?
     434          96 :                                 tds_char2hex(p, len / 2u, (const TDS_CHAR*) DataPtr, len):
     435          32 :                                 odbc_wchar2hex(p, len / 2u, (const SQLWCHAR*) DataPtr, len);
     436          64 :                         if (res < 0) {
     437           0 :                                 odbc_convert_err_set(&stmt->errs, res);
     438           0 :                                 return SQL_ERROR;
     439             :                         }
     440          64 :                         p += res;
     441             : 
     442          64 :                         len = p - (blob->textvalue + curcol->column_cur_size);
     443             :                 } else {
     444         564 :                         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         628 :         curcol->column_cur_size += len;
     451             : 
     452         628 :         if (blob && curcol->column_cur_size > curcol->column_size)
     453         408 :                 curcol->column_size = curcol->column_cur_size;
     454             : 
     455             :         return SQL_SUCCESS;
     456             : }

Generated by: LCOV version 1.13