LCOV - code coverage report
Current view: top level - clients/odbc/driver - SQLPrepare.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 150 184 81.5 %
Date: 2024-12-19 23:10:26 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * This code was created by Peter Harvey (mostly during Christmas 98/99).
      15             :  * This code is LGPL. Please ensure that this message remains in future
      16             :  * distributions and uses of this code (that's about all I get out of it).
      17             :  * - Peter Harvey pharvey@codebydesign.com
      18             :  *
      19             :  * This file has been modified for the MonetDB project.  See the file
      20             :  * Copyright in this directory for more information.
      21             :  */
      22             : 
      23             : /**********************************************************************
      24             :  * SQLPrepare
      25             :  * CLI Compliance: ISO 92
      26             :  *
      27             :  * Author: Martin van Dinther, Sjoerd Mullender
      28             :  * Date  : 30 aug 2002
      29             :  *
      30             :  **********************************************************************/
      31             : 
      32             : #include "ODBCGlobal.h"
      33             : #include "ODBCStmt.h"
      34             : #include "ODBCUtil.h"
      35             : 
      36             : 
      37             : void
      38         112 : ODBCResetStmt(ODBCStmt *stmt)
      39             : {
      40         112 :         MNDBFreeStmt(stmt, SQL_CLOSE);
      41         112 :         setODBCDescRecCount(stmt->ImplParamDescr, 0);
      42             : 
      43         112 :         if (stmt->queryid >= 0)
      44           2 :                 mapi_release_id(stmt->Dbc->mid, stmt->queryid);
      45         112 :         stmt->queryid = -1;
      46         112 :         stmt->nparams = 0;
      47         112 :         stmt->State = INITED;
      48         112 : }
      49             : 
      50             : SQLRETURN
      51           4 : MNDBPrepare(ODBCStmt *stmt,
      52             :             const SQLCHAR *StatementText,
      53             :             SQLINTEGER TextLength)
      54             : {
      55           4 :         char *query, *s;
      56           4 :         MapiMsg ret;
      57           4 :         MapiHdl hdl;
      58           4 :         int nrows;
      59           4 :         int ncols;
      60           4 :         ODBCDescRec *prec, *rrec; /* param and row descriptors */
      61           4 :         ODBCDescRec *rec;
      62           4 :         int i;
      63             : 
      64           4 :         hdl = stmt->hdl;
      65             : 
      66           4 :         if (stmt->State >= EXECUTED1 ||
      67           1 :             (stmt->State == EXECUTED0 && mapi_more_results(hdl))) {
      68             :                 /* Invalid cursor state */
      69           0 :                 addStmtError(stmt, "24000", NULL, 0);
      70           0 :                 return SQL_ERROR;
      71             :         }
      72             : 
      73             :         /* check input parameter */
      74           4 :         if (StatementText == NULL) {
      75             :                 /* Invalid use of null pointer */
      76           0 :                 addStmtError(stmt, "HY009", NULL, 0);
      77           0 :                 return SQL_ERROR;
      78             :         }
      79             : 
      80           4 :         fixODBCstring(StatementText, TextLength, SQLINTEGER, addStmtError, stmt, return SQL_ERROR);
      81           4 :         query = ODBCTranslateSQL(stmt->Dbc, StatementText, (size_t) TextLength,
      82             :                                  stmt->noScan);
      83           4 :         if (query == NULL) {
      84             :                 /* Memory allocation error */
      85           0 :                 addStmtError(stmt, "HY001", NULL, 0);
      86           0 :                 return SQL_ERROR;
      87             :         }
      88             : #ifdef ODBCDEBUG
      89           4 :         ODBCLOG("SQLPrepare: \"%s\"\n", query);
      90             : #endif
      91           4 :         size_t querylen = strlen(query) + 9;
      92           4 :         s = malloc(querylen);
      93           4 :         if (s == NULL) {
      94           0 :                 free(query);
      95             :                 /* Memory allocation error */
      96           0 :                 addStmtError(stmt, "HY001", NULL, 0);
      97           0 :                 return SQL_ERROR;
      98             :         }
      99           4 :         strconcat_len(s, querylen, "prepare ", query, NULL);
     100           4 :         free(query);
     101             : 
     102           4 :         ODBCResetStmt(stmt);
     103             : 
     104           4 :         if (stmt->Dbc->cachelimit != -1) {
     105           4 :                 mapi_cache_limit(stmt->Dbc->mid, -1);
     106           4 :                 stmt->Dbc->cachelimit = -1;
     107             :         }
     108             : 
     109           4 :         ret = mapi_query_handle(hdl, s);
     110           4 :         free(s);
     111           4 :         s = NULL;
     112           4 :         if (ret != MOK) {
     113           0 :                 const char *e, *m;
     114             : 
     115             :                 /* XXX more fine-grained control required */
     116             :                 /* Syntax error or access violation */
     117           0 :                 if ((m = mapi_result_error(hdl)) == NULL)
     118           0 :                         m = mapi_error_str(stmt->Dbc->mid);
     119           0 :                 if (m && (e = mapi_result_errorcode(hdl)) != NULL)
     120           0 :                         addStmtError(stmt, e, m, 0);
     121             :                 else
     122           0 :                         addStmtError(stmt, "42000", m, 0);
     123           0 :                 return SQL_ERROR;
     124             :         }
     125           4 :         if (mapi_rows_affected(hdl) > ((int64_t) 1 << 16)) {
     126             :                 /* arbitrarily limit the number of parameters */
     127             :                 /* Memory allocation error */
     128           0 :                 addStmtError(stmt, "HY001", 0, 0);
     129           0 :                 return SQL_ERROR;
     130             :         }
     131           4 :         nrows = (int) mapi_rows_affected(hdl);
     132           4 :         ncols = mapi_get_field_count(hdl);
     133             :         /* these two will be adjusted later */
     134           4 :         setODBCDescRecCount(stmt->ImplParamDescr, nrows);
     135           4 :         setODBCDescRecCount(stmt->ImplRowDescr, nrows);
     136           4 :         prec = stmt->ImplParamDescr->descRec + 1;
     137           4 :         rrec = stmt->ImplRowDescr->descRec + 1;
     138           4 :         stmt->nparams = 0;
     139          31 :         for (i = 0; i < nrows; i++) {
     140          27 :                 struct sql_types *tp;
     141          27 :                 int concise_type;
     142          27 :                 int length, scale;
     143             : 
     144          27 :                 if (mapi_fetch_row(hdl) == 0) {
     145             :                         /* Memory allocation error (or maybe something else) */
     146           0 :                         addStmtError(stmt, "HY001", 0, 0);
     147           0 :                         return SQL_ERROR;
     148             :                 }
     149          27 :                 if (ncols == 3 ||
     150          27 :                     (s = mapi_fetch_field(hdl, 5)) == NULL) {
     151             :                         /* either old prepare (i.e. old server) or no
     152             :                          * column name: either way, this describes a
     153             :                          * parameter */
     154           7 :                         stmt->nparams++;
     155           7 :                         rec = prec++;
     156           7 :                         rec->sql_desc_nullable = SQL_NULLABLE;
     157           7 :                         rec->sql_desc_searchable = SQL_UNSEARCHABLE;
     158           7 :                         rec->sql_desc_unnamed = SQL_UNNAMED;
     159           7 :                         rec->sql_desc_label = NULL;
     160           7 :                         rec->sql_desc_name = NULL;
     161           7 :                         rec->sql_desc_schema_name = NULL;
     162           7 :                         rec->sql_desc_table_name = NULL;
     163           7 :                         rec->sql_desc_base_table_name = NULL;
     164           7 :                         rec->sql_desc_base_column_name = NULL;
     165           7 :                         rec->sql_desc_parameter_type = SQL_PARAM_INPUT;
     166             :                 } else {
     167          20 :                         rec = rrec++;
     168          20 :                         rec->sql_desc_nullable = SQL_NULLABLE_UNKNOWN;
     169          20 :                         rec->sql_desc_searchable = SQL_PRED_SEARCHABLE;
     170          20 :                         rec->sql_desc_unnamed = SQL_NAMED;
     171          20 :                         rec->sql_desc_label = (SQLCHAR *) strdup(s);
     172          20 :                         rec->sql_desc_name = (SQLCHAR *) strdup(s);
     173          20 :                         s = mapi_fetch_field(hdl, 3); /* schema name */
     174          20 :                         rec->sql_desc_schema_name = s && *s ? (SQLCHAR *) strdup(s) : NULL;
     175          20 :                         s = mapi_fetch_field(hdl, 4); /* table name */
     176          20 :                         rec->sql_desc_table_name = s && *s ? (SQLCHAR *) strdup(s) : NULL;
     177          20 :                         if (rec->sql_desc_schema_name) {
     178             :                                 /* base table name and base column
     179             :                                  * name exist if there is a schema
     180             :                                  * name; the extra check is for static
     181             :                                  * code analyzers and robustness */
     182           0 :                                 rec->sql_desc_base_table_name = rec->sql_desc_table_name ? (SQLCHAR *) strdup((char *) rec->sql_desc_table_name) : NULL;
     183           0 :                                 rec->sql_desc_base_column_name = (SQLCHAR *) strdup((char *) rec->sql_desc_name);
     184             :                         } else {
     185          20 :                                 rec->sql_desc_base_table_name = NULL;
     186          20 :                                 rec->sql_desc_base_column_name = NULL;
     187             :                         }
     188          20 :                         rec->sql_desc_parameter_type = 0;
     189             :                 }
     190             : 
     191          27 :                 s = mapi_fetch_field(hdl, 0); /* type */
     192          27 :                 if (!stmt->Dbc->allow_hugeint && strcmp(s, "hugeint") == 0)
     193          27 :                         s = "bigint";
     194          27 :                 rec->sql_desc_type_name = (SQLCHAR *) strdup(s);
     195          27 :                 concise_type = ODBCConciseType(s);
     196             : 
     197          27 :                 s = mapi_fetch_field(hdl, 1); /* digits */
     198          27 :                 length = atoi(s);
     199             : 
     200          27 :                 s = mapi_fetch_field(hdl, 2); /* scale */
     201          27 :                 scale = atoi(s);
     202             : 
     203             :                 /* for interval types, length and scale are used
     204             :                  * differently */
     205          27 :                 if (concise_type == SQL_INTERVAL_MONTH) {
     206           0 :                         switch (length) {
     207             :                         case 1:
     208             :                                 concise_type = SQL_INTERVAL_YEAR;
     209             :                                 break;
     210             :                         case 2:
     211             :                                 concise_type = SQL_INTERVAL_YEAR_TO_MONTH;
     212             :                                 break;
     213             :                         case 3:
     214             :                                 concise_type = SQL_INTERVAL_MONTH;
     215             :                                 break;
     216             :                         default:
     217           0 :                                 assert(0);
     218             :                         }
     219           0 :                         rec->sql_desc_scale = 0;
     220           0 :                         rec->sql_desc_length = 0;
     221          27 :                 } else if (concise_type == SQL_INTERVAL_SECOND) {
     222           0 :                         switch (length) {
     223             :                         case 4:
     224             :                                 concise_type = SQL_INTERVAL_DAY;
     225             :                                 break;
     226             :                         case 5:
     227             :                                 concise_type = SQL_INTERVAL_DAY_TO_HOUR;
     228             :                                 break;
     229             :                         case 6:
     230             :                                 concise_type = SQL_INTERVAL_DAY_TO_MINUTE;
     231             :                                 break;
     232             :                         case 7:
     233             :                                 concise_type = SQL_INTERVAL_DAY_TO_SECOND;
     234             :                                 break;
     235             :                         case 8:
     236             :                                 concise_type = SQL_INTERVAL_HOUR;
     237             :                                 break;
     238             :                         case 9:
     239             :                                 concise_type = SQL_INTERVAL_HOUR_TO_MINUTE;
     240             :                                 break;
     241             :                         case 10:
     242             :                                 concise_type = SQL_INTERVAL_HOUR_TO_SECOND;
     243             :                                 break;
     244             :                         case 11:
     245             :                                 concise_type = SQL_INTERVAL_MINUTE;
     246             :                                 break;
     247             :                         case 12:
     248             :                                 concise_type = SQL_INTERVAL_MINUTE_TO_SECOND;
     249             :                                 break;
     250             :                         case 13:
     251             :                                 concise_type = SQL_INTERVAL_SECOND;
     252             :                                 break;
     253             :                         default:
     254           0 :                                 assert(0);
     255             :                         }
     256           0 :                         rec->sql_desc_scale = 0;
     257           0 :                         rec->sql_desc_length = 0;
     258             :                 } else {
     259          27 :                         rec->sql_desc_scale = scale;
     260          27 :                         rec->sql_desc_length = length;
     261             :                 }
     262             : 
     263         347 :                 for (tp = ODBC_sql_types; tp->concise_type; tp++)
     264         347 :                         if (concise_type == tp->concise_type)
     265             :                                 break;
     266          27 :                 rec->sql_desc_concise_type = tp->concise_type;
     267          27 :                 rec->sql_desc_type = tp->type;
     268          27 :                 rec->sql_desc_datetime_interval_code = tp->code;
     269          27 :                 if (tp->precision != UNAFFECTED)
     270           9 :                         rec->sql_desc_precision = tp->precision;
     271          27 :                 if (tp->datetime_interval_precision != UNAFFECTED)
     272           0 :                         rec->sql_desc_datetime_interval_precision = tp->datetime_interval_precision;
     273          27 :                 rec->sql_desc_fixed_prec_scale = tp->fixed;
     274          27 :                 rec->sql_desc_num_prec_radix = tp->radix;
     275          27 :                 rec->sql_desc_unsigned = tp->radix == 0 ? SQL_TRUE : SQL_FALSE;
     276             : 
     277          27 :                 if (rec->sql_desc_concise_type == SQL_CHAR ||
     278             :                     rec->sql_desc_concise_type == SQL_VARCHAR ||
     279             :                     rec->sql_desc_concise_type == SQL_LONGVARCHAR ||
     280             :                     rec->sql_desc_concise_type == SQL_WCHAR ||
     281             :                     rec->sql_desc_concise_type == SQL_WVARCHAR ||
     282             :                     rec->sql_desc_concise_type == SQL_WLONGVARCHAR) {
     283           7 :                         rec->sql_desc_case_sensitive = SQL_TRUE;
     284             : 
     285             :                         /* For large varchar column definitions conditionally
     286             :                          * change type to SQL_WLONGVARCHAR when mapToLongVarchar is set (e.g. to 4000)
     287             :                          * This is a workaround for MS SQL Server linked server
     288             :                          * which can not handle large varchars (ref: SUPPORT-747) */
     289           7 :                         if (rec->sql_desc_concise_type == SQL_WVARCHAR
     290           7 :                          && stmt->Dbc->mapToLongVarchar > 0
     291           0 :                          && rec->sql_desc_length > (SQLULEN) stmt->Dbc->mapToLongVarchar)
     292           0 :                                 rec->sql_desc_concise_type = SQL_WLONGVARCHAR;
     293             :                 } else
     294          20 :                         rec->sql_desc_case_sensitive = SQL_FALSE;
     295             : 
     296          27 :                 rec->sql_desc_local_type_name = NULL;
     297          27 :                 rec->sql_desc_rowver = SQL_FALSE;
     298             : 
     299             :                 /* unused fields */
     300          27 :                 rec->sql_desc_auto_unique_value = SQL_FALSE;
     301          27 :                 rec->sql_desc_data_ptr = NULL;
     302          27 :                 rec->sql_desc_display_size = 0;
     303          27 :                 rec->sql_desc_indicator_ptr = NULL;
     304          27 :                 rec->sql_desc_literal_prefix = NULL;
     305          27 :                 rec->sql_desc_literal_suffix = NULL;
     306          27 :                 rec->sql_desc_octet_length_ptr = NULL;
     307          27 :                 rec->sql_desc_catalog_name = NULL;
     308          27 :                 rec->sql_desc_schema_name = NULL;
     309          27 :                 rec->sql_desc_updatable = SQL_ATTR_READONLY;
     310             : 
     311             :                 /* this must come after other fields have been
     312             :                  * initialized */
     313          27 :                 rec->sql_desc_length = ODBCLength(rec, SQL_DESC_LENGTH);
     314          27 :                 rec->sql_desc_display_size = ODBCLength(rec, SQL_DESC_DISPLAY_SIZE);
     315          27 :                 rec->sql_desc_octet_length = ODBCLength(rec, SQL_DESC_OCTET_LENGTH);
     316          27 :                 if (rec->sql_desc_length == 0) {
     317           2 :                         rec->sql_desc_length = SQL_NO_TOTAL;
     318           2 :                         rec->sql_desc_display_size = SQL_NO_TOTAL;
     319           2 :                         rec->sql_desc_octet_length = SQL_NO_TOTAL;
     320             :                 }
     321             :         }
     322             : 
     323           4 :         assert(prec - stmt->ImplParamDescr->descRec == stmt->nparams + 1);
     324           4 :         assert(rrec - stmt->ImplRowDescr->descRec == nrows - stmt->nparams + 1);
     325           4 :         setODBCDescRecCount(stmt->ImplParamDescr, stmt->nparams);
     326           4 :         setODBCDescRecCount(stmt->ImplRowDescr, nrows - stmt->nparams);
     327             : 
     328             :         /* update the internal state */
     329           4 :         stmt->queryid = mapi_get_tableid(hdl);
     330           4 :         if (stmt->ImplRowDescr->sql_desc_count == 0)
     331           1 :                 stmt->State = PREPARED0; /* no columns: no result set */
     332             :         else
     333           3 :                 stmt->State = PREPARED1;
     334             : 
     335             :         return SQL_SUCCESS;
     336             : }
     337             : 
     338             : SQLRETURN SQL_API
     339             : SQLPrepare(SQLHSTMT StatementHandle,
     340             :            SQLCHAR *StatementText,
     341             :            SQLINTEGER TextLength)
     342             : {
     343             : #ifdef ODBCDEBUG
     344           3 :         ODBCLOG("SQLPrepare %p\n", StatementHandle);
     345             : #endif
     346             : 
     347           3 :         if (!isValidStmt((ODBCStmt *) StatementHandle))
     348             :                 return SQL_INVALID_HANDLE;
     349             : 
     350           3 :         clearStmtErrors((ODBCStmt *) StatementHandle);
     351             : 
     352           3 :         return MNDBPrepare((ODBCStmt *) StatementHandle,
     353             :                            StatementText,
     354             :                            TextLength);
     355             : }
     356             : 
     357             : SQLRETURN SQL_API
     358             : SQLPrepareA(SQLHSTMT StatementHandle,
     359             :             SQLCHAR *StatementText,
     360             :             SQLINTEGER TextLength)
     361             : {
     362           0 :         return SQLPrepare(StatementHandle, StatementText, TextLength);
     363             : }
     364             : 
     365             : SQLRETURN SQL_API
     366             : SQLPrepareW(SQLHSTMT StatementHandle,
     367             :             SQLWCHAR *StatementText,
     368             :             SQLINTEGER TextLength)
     369             : {
     370           1 :         ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
     371           1 :         SQLCHAR *sql;
     372           1 :         SQLRETURN rc;
     373             : 
     374             : #ifdef ODBCDEBUG
     375           1 :         ODBCLOG("SQLPrepareW %p\n", StatementHandle);
     376             : #endif
     377             : 
     378           1 :         if (!isValidStmt(stmt))
     379             :                  return SQL_INVALID_HANDLE;
     380             : 
     381           1 :         clearStmtErrors(stmt);
     382             : 
     383           1 :         fixWcharIn(StatementText, TextLength, SQLCHAR, sql,
     384             :                    addStmtError, stmt, return SQL_ERROR);
     385             : 
     386           1 :         rc = MNDBPrepare(stmt, sql, SQL_NTS);
     387             : 
     388           1 :         if (sql)
     389           1 :                 free(sql);
     390             : 
     391             :         return rc;
     392             : }

Generated by: LCOV version 1.14