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 (thats 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 109 : ODBCResetStmt(ODBCStmt *stmt)
39 : {
40 109 : MNDBFreeStmt(stmt, SQL_CLOSE);
41 109 : setODBCDescRecCount(stmt->ImplParamDescr, 0);
42 :
43 109 : if (stmt->queryid >= 0)
44 2 : mapi_release_id(stmt->Dbc->mid, stmt->queryid);
45 109 : stmt->queryid = -1;
46 109 : stmt->nparams = 0;
47 109 : stmt->State = INITED;
48 109 : }
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 0 : (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 349 : for (tp = ODBC_sql_types; tp->concise_type; tp++)
264 349 : 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 5 : && 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 : }
|