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 : * SQLExecute()
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 : #include <limits.h>
36 :
37 : static struct msql_types {
38 : char *name;
39 : int concise_type;
40 : } msql_types[] = {
41 : {"bigint", SQL_BIGINT},
42 : {"blob", SQL_LONGVARBINARY},
43 : {"boolean", SQL_BIT},
44 : {"char", SQL_WCHAR},
45 : {"clob", SQL_WLONGVARCHAR},
46 : {"date", SQL_TYPE_DATE},
47 : {"day_interval", SQL_INTERVAL_SECOND},
48 : {"decimal", SQL_DECIMAL},
49 : {"double", SQL_DOUBLE},
50 : {"hugeint", SQL_HUGEINT},
51 : /* {"inet", SQL_WCHAR}, */
52 : {"int", SQL_INTEGER},
53 : /* {"json", SQL_WVARCHAR}, */
54 : {"month_interval", SQL_INTERVAL_MONTH},
55 : {"oid", SQL_BIGINT},
56 : {"real", SQL_REAL},
57 : {"sec_interval", SQL_INTERVAL_SECOND},
58 : {"smallint", SQL_SMALLINT},
59 : {"table", 0},
60 : {"time", SQL_TYPE_TIME},
61 : {"timetz", SQL_TYPE_TIME},
62 : {"timestamp", SQL_TYPE_TIMESTAMP},
63 : {"timestamptz", SQL_TYPE_TIMESTAMP},
64 : {"tinyint", SQL_TINYINT},
65 : /* {"url", SQL_WVARCHAR}, */
66 : {"uuid", SQL_GUID},
67 : {"varchar", SQL_WVARCHAR},
68 : {0, 0}, /* sentinel */
69 : };
70 :
71 : int
72 944 : ODBCConciseType(const char *name)
73 : {
74 944 : struct msql_types *p;
75 :
76 16640 : for (p = msql_types; p->name; p++)
77 16640 : if (strcmp(p->name, name) == 0)
78 944 : return p->concise_type;
79 : return 0;
80 : }
81 :
82 : #ifdef ODBCDEBUG
83 : static char *
84 0 : translatequerytype(int querytype)
85 : {
86 0 : switch (querytype) {
87 : case Q_PARSE:
88 : return "Q_PARSE";
89 0 : case Q_TABLE:
90 0 : return "Q_TABLE";
91 0 : case Q_UPDATE:
92 0 : return "Q_UPDATE";
93 0 : case Q_SCHEMA:
94 0 : return "Q_SCHEMA";
95 0 : case Q_TRANS:
96 0 : return "Q_TRANS";
97 0 : case Q_PREPARE:
98 0 : return "Q_PREPARE";
99 0 : case Q_BLOCK:
100 0 : return "Q_BLOCK";
101 0 : default:
102 0 : return "unknown";
103 : }
104 : }
105 : #endif
106 :
107 : SQLRETURN
108 2106 : ODBCInitResult(ODBCStmt *stmt)
109 : {
110 2106 : int i = 0;
111 2106 : int nrCols;
112 2106 : ODBCDescRec *rec;
113 2106 : MapiHdl hdl;
114 2106 : const char *errstr;
115 :
116 2106 : hdl = stmt->hdl;
117 :
118 : /* initialize the Result meta data values */
119 2106 : stmt->currentRow = 0;
120 2106 : stmt->startRow = 0;
121 2106 : stmt->rowSetSize = 0;
122 2106 : stmt->retrieved = 0;
123 2106 : stmt->currentCol = 0;
124 :
125 2158 : repeat:
126 2158 : errstr = mapi_result_error(hdl);
127 2158 : if (errstr) {
128 0 : const char *sqlstate;
129 :
130 0 : if ((sqlstate = mapi_result_errorcode(hdl)) != NULL)
131 0 : addStmtError(stmt, sqlstate, errstr, 0);
132 : else {
133 : /* Syntax error or access violation */
134 0 : addStmtError(stmt, "42000", errstr, 0);
135 : }
136 0 : return SQL_ERROR;
137 : }
138 2158 : nrCols = mapi_get_field_count(hdl);
139 2158 : stmt->querytype = mapi_get_querytype(hdl);
140 : #if SIZEOF_SIZE_T == SIZEOF_INT
141 : if (mapi_rows_affected(hdl) >= (int64_t) 1 << (sizeof(int) * CHAR_BIT)) {
142 : /* General error */
143 : addStmtError(stmt, "HY000", "Too many rows to handle", 0);
144 : return SQL_ERROR;
145 : }
146 : #endif
147 2158 : stmt->rowcount = (SQLULEN) mapi_rows_affected(hdl);
148 :
149 : #ifdef ODBCDEBUG
150 2158 : ODBCLOG("ODBCInitResult: querytype %s, rowcount %lu\n",
151 : translatequerytype(stmt->querytype),
152 : (unsigned long) stmt->rowcount);
153 : #endif
154 :
155 2158 : switch (stmt->querytype) {
156 94 : case Q_TABLE: /* Q_TABLE */
157 : /* result set generating query */
158 94 : assert(nrCols > 0);
159 94 : stmt->State = EXECUTED1;
160 94 : break;
161 2000 : case Q_UPDATE: /* Q_UPDATE */
162 : /* result count generating query */
163 2000 : assert(nrCols == 0);
164 2000 : stmt->State = EXECUTED0;
165 2000 : break;
166 64 : default:
167 : /* resultless query */
168 64 : if (mapi_result_error(hdl) == NULL && mapi_next_result(hdl) == 1)
169 52 : goto repeat;
170 12 : stmt->State = EXECUTED0;
171 12 : stmt->rowcount = 0;
172 12 : nrCols = 0;
173 12 : break;
174 : }
175 :
176 : #if 0
177 : /* XXX is this correct? */
178 : assert(stmt->ImplRowDescr == NULL ||
179 : stmt->ImplRowDescr->sql_desc_count == nrCols ||
180 : stmt->ImplRowDescr->sql_desc_count == 0);
181 : #endif
182 2106 : setODBCDescRecCount(stmt->ImplRowDescr, nrCols);
183 :
184 2106 : if (nrCols == 0)
185 : return SQL_SUCCESS;
186 94 : if (stmt->ImplRowDescr->descRec == NULL) {
187 0 : stmt->State = stmt->queryid >= 0 ? (stmt->State == EXECUTED0 ? PREPARED0 : PREPARED1) : INITED;
188 :
189 : /* Memory allocation error */
190 0 : addStmtError(stmt, "HY001", NULL, 0);
191 0 : return SQL_ERROR;
192 : }
193 :
194 94 : rec = stmt->ImplRowDescr->descRec + 1;
195 :
196 1011 : for (i = 0; i < nrCols; i++) {
197 917 : struct sql_types *tp;
198 917 : int concise_type;
199 917 : char *s;
200 :
201 917 : rec->sql_desc_auto_unique_value = SQL_FALSE;
202 917 : rec->sql_desc_nullable = SQL_NULLABLE_UNKNOWN;
203 917 : rec->sql_desc_rowver = SQL_FALSE;
204 917 : rec->sql_desc_searchable = SQL_PRED_SEARCHABLE;
205 917 : rec->sql_desc_updatable = SQL_ATTR_READONLY;
206 :
207 917 : s = mapi_get_name(hdl, i);
208 : /* HACK to compensate for generated column names */
209 917 : if (s == NULL || strcmp(s, "single_value") == 0)
210 0 : s = "";
211 917 : if (*s) {
212 917 : rec->sql_desc_unnamed = SQL_NAMED;
213 917 : if (rec->sql_desc_label)
214 22 : free(rec->sql_desc_label);
215 917 : rec->sql_desc_label = (SQLCHAR *) strdup(s);
216 917 : if (rec->sql_desc_label == NULL)
217 0 : goto nomem;
218 917 : if (rec->sql_desc_name)
219 22 : free(rec->sql_desc_name);
220 917 : rec->sql_desc_name = (SQLCHAR *) strdup(s);
221 917 : if (rec->sql_desc_name == NULL)
222 0 : goto nomem;
223 : } else {
224 0 : rec->sql_desc_unnamed = SQL_UNNAMED;
225 0 : rec->sql_desc_label = NULL;
226 0 : rec->sql_desc_name = NULL;
227 : }
228 917 : if (rec->sql_desc_base_column_name)
229 2 : free(rec->sql_desc_base_column_name);
230 917 : rec->sql_desc_base_column_name = NULL; /* see below */
231 :
232 917 : s = mapi_get_type(hdl, i);
233 917 : if (s == NULL) /* shouldn't happen */
234 0 : s = "";
235 917 : if (!stmt->Dbc->allow_hugeint && strcmp(s, "hugeint") == 0)
236 917 : s = "bigint";
237 917 : if (rec->sql_desc_type_name)
238 22 : free(rec->sql_desc_type_name);
239 917 : rec->sql_desc_type_name = (SQLCHAR *) strdup(s);
240 917 : if (rec->sql_desc_type_name == NULL)
241 0 : goto nomem;
242 917 : concise_type = ODBCConciseType(s);
243 917 : if (concise_type == SQL_INTERVAL_MONTH) {
244 0 : switch (mapi_get_digits(hdl, i)) {
245 : case 1:
246 : concise_type = SQL_INTERVAL_YEAR;
247 : break;
248 : case 2:
249 : concise_type = SQL_INTERVAL_YEAR_TO_MONTH;
250 : break;
251 : case 3:
252 : concise_type = SQL_INTERVAL_MONTH;
253 : break;
254 : default:
255 0 : assert(0);
256 : }
257 917 : } else if (concise_type == SQL_INTERVAL_SECOND) {
258 0 : switch (mapi_get_digits(hdl, i)) {
259 : case 4:
260 : concise_type = SQL_INTERVAL_DAY;
261 : break;
262 : case 5:
263 : concise_type = SQL_INTERVAL_DAY_TO_HOUR;
264 : break;
265 : case 6:
266 : concise_type = SQL_INTERVAL_DAY_TO_MINUTE;
267 : break;
268 : case 7:
269 : concise_type = SQL_INTERVAL_DAY_TO_SECOND;
270 : break;
271 : case 8:
272 : concise_type = SQL_INTERVAL_HOUR;
273 : break;
274 : case 9:
275 : concise_type = SQL_INTERVAL_HOUR_TO_MINUTE;
276 : break;
277 : case 10:
278 : concise_type = SQL_INTERVAL_HOUR_TO_SECOND;
279 : break;
280 : case 11:
281 : concise_type = SQL_INTERVAL_MINUTE;
282 : break;
283 : case 12:
284 : concise_type = SQL_INTERVAL_MINUTE_TO_SECOND;
285 : break;
286 : case 13:
287 : concise_type = SQL_INTERVAL_SECOND;
288 : break;
289 : default:
290 0 : assert(0);
291 : }
292 : }
293 6975 : for (tp = ODBC_sql_types; tp->concise_type; tp++)
294 6975 : if (concise_type == tp->concise_type)
295 : break;
296 917 : rec->sql_desc_concise_type = tp->concise_type;
297 917 : rec->sql_desc_type = tp->type;
298 917 : rec->sql_desc_datetime_interval_code = tp->code;
299 917 : switch (concise_type) {
300 2 : case SQL_DECIMAL:
301 : case SQL_NUMERIC:
302 2 : rec->sql_desc_precision = mapi_get_digits(hdl, i);
303 2 : rec->sql_desc_scale = mapi_get_scale(hdl, i);
304 2 : break;
305 915 : default:
306 915 : if (tp->precision != UNAFFECTED)
307 6 : rec->sql_desc_precision = tp->precision;
308 915 : if (tp->scale != UNAFFECTED)
309 0 : rec->sql_desc_scale = tp->scale;
310 : break;
311 : }
312 917 : if (tp->datetime_interval_precision != UNAFFECTED)
313 0 : rec->sql_desc_datetime_interval_precision = tp->datetime_interval_precision;
314 917 : rec->sql_desc_fixed_prec_scale = tp->fixed;
315 917 : rec->sql_desc_num_prec_radix = tp->radix;
316 917 : rec->sql_desc_unsigned = tp->radix == 0 ? SQL_TRUE : SQL_FALSE;
317 :
318 917 : if (rec->sql_desc_concise_type == SQL_CHAR ||
319 : rec->sql_desc_concise_type == SQL_VARCHAR ||
320 : rec->sql_desc_concise_type == SQL_LONGVARCHAR ||
321 : rec->sql_desc_concise_type == SQL_WCHAR ||
322 : rec->sql_desc_concise_type == SQL_WVARCHAR ||
323 : rec->sql_desc_concise_type == SQL_WLONGVARCHAR)
324 528 : rec->sql_desc_case_sensitive = SQL_TRUE;
325 : else
326 389 : rec->sql_desc_case_sensitive = SQL_FALSE;
327 :
328 917 : s = mapi_get_table(hdl, i);
329 917 : if (s) {
330 917 : char *p = strchr(s, '.');
331 917 : if (rec->sql_desc_table_name)
332 22 : free(rec->sql_desc_table_name);
333 917 : if (p) {
334 917 : if (rec->sql_desc_schema_name)
335 2 : free(rec->sql_desc_schema_name);
336 917 : rec->sql_desc_schema_name = (SQLCHAR *) dupODBCstring((SQLCHAR *) s, p - s);
337 917 : if (rec->sql_desc_schema_name == NULL)
338 0 : goto nomem;
339 917 : rec->sql_desc_table_name = (SQLCHAR *) strdup(p + 1);
340 917 : if (rec->sql_desc_table_name == NULL)
341 0 : goto nomem;
342 917 : if (p != s) {
343 : /* base table name and base
344 : * column name exist if there
345 : * is a schema name */
346 54 : if (rec->sql_desc_base_table_name)
347 0 : free(rec->sql_desc_base_table_name);
348 54 : rec->sql_desc_base_table_name = (SQLCHAR *) strdup(p + 1);
349 54 : if (rec->sql_desc_base_table_name == NULL)
350 0 : goto nomem;
351 54 : if (rec->sql_desc_name) {
352 54 : rec->sql_desc_base_column_name = (SQLCHAR *) strdup((char *) rec->sql_desc_name);
353 54 : if (rec->sql_desc_base_column_name == NULL)
354 0 : goto nomem;
355 : }
356 : }
357 : } else {
358 0 : rec->sql_desc_table_name = (SQLCHAR *) strdup(s);
359 0 : if (rec->sql_desc_table_name == NULL)
360 0 : goto nomem;
361 : }
362 : }
363 :
364 917 : if (rec->sql_desc_type != SQL_INTERVAL &&
365 917 : (rec->sql_desc_length = mapi_get_digits(hdl, i)) == 0)
366 22 : rec->sql_desc_length = mapi_get_len(hdl, i);
367 :
368 917 : rec->sql_desc_local_type_name = NULL;
369 917 : rec->sql_desc_catalog_name = NULL;
370 917 : rec->sql_desc_literal_prefix = NULL;
371 917 : rec->sql_desc_literal_suffix = NULL;
372 :
373 : /* unused fields */
374 917 : rec->sql_desc_data_ptr = NULL;
375 917 : rec->sql_desc_indicator_ptr = NULL;
376 917 : rec->sql_desc_octet_length_ptr = NULL;
377 917 : rec->sql_desc_parameter_type = 0;
378 :
379 : /* this must come after other fields have been
380 : * initialized */
381 917 : if (rec->sql_desc_concise_type == SQL_CHAR ||
382 : rec->sql_desc_concise_type == SQL_VARCHAR ||
383 : rec->sql_desc_concise_type == SQL_LONGVARCHAR ||
384 : rec->sql_desc_concise_type == SQL_WCHAR ||
385 : rec->sql_desc_concise_type == SQL_WVARCHAR ||
386 : rec->sql_desc_concise_type == SQL_WLONGVARCHAR) {
387 : /* for strings, get the display size from what
388 : * the server told us the size is for this
389 : * column, and derive the octet length from
390 : * that */
391 528 : rec->sql_desc_display_size = mapi_get_len(hdl, i);
392 528 : rec->sql_desc_octet_length = 4 * rec->sql_desc_display_size;
393 :
394 : /* For large varchar column definitions conditionally
395 : * change type to SQL_WLONGVARCHAR when mapToLongVarchar is set (e.g. to 4000)
396 : * This is a workaround for MS SQL Server linked server
397 : * which can not handle large varchars (ref: SUPPORT-747) */
398 528 : if (rec->sql_desc_concise_type == SQL_WVARCHAR
399 425 : && stmt->Dbc->mapToLongVarchar > 0
400 0 : && rec->sql_desc_length > (SQLULEN) stmt->Dbc->mapToLongVarchar)
401 0 : rec->sql_desc_concise_type = SQL_WLONGVARCHAR;
402 : } else {
403 389 : rec->sql_desc_length = ODBCLength(rec, SQL_DESC_LENGTH);
404 389 : rec->sql_desc_display_size = ODBCLength(rec, SQL_DESC_DISPLAY_SIZE);
405 389 : rec->sql_desc_octet_length = ODBCLength(rec, SQL_DESC_OCTET_LENGTH);
406 : }
407 917 : if (rec->sql_desc_length == 0) {
408 5 : rec->sql_desc_length = SQL_NO_TOTAL;
409 5 : rec->sql_desc_display_size = SQL_NO_TOTAL;
410 5 : rec->sql_desc_octet_length = SQL_NO_TOTAL;
411 : }
412 :
413 917 : rec++;
414 : }
415 :
416 94 : return stmt->Error ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
417 :
418 0 : nomem:
419 : /* Memory allocation error */
420 0 : addStmtError(stmt, "HY001", NULL, 0);
421 0 : return SQL_ERROR;
422 : }
423 :
424 : SQLRETURN
425 2004 : MNDBExecute(ODBCStmt *stmt)
426 : {
427 2004 : MapiHdl hdl;
428 2004 : MapiMsg msg;
429 2004 : char *query;
430 2004 : const char *errstr;
431 2004 : char *sep;
432 2004 : size_t querylen;
433 2004 : size_t querypos;
434 2004 : int i;
435 2004 : ODBCDesc *desc;
436 2004 : SQLLEN offset;
437 :
438 : /* check statement cursor state, query should be prepared */
439 2004 : if (stmt->State == INITED ||
440 1999 : (stmt->State >= EXECUTED0 && stmt->queryid < 0)) {
441 : /* Function sequence error */
442 0 : addStmtError(stmt, "HY010", NULL, 0);
443 0 : return SQL_ERROR;
444 : }
445 2004 : if (stmt->State >= EXECUTED1 ||
446 1999 : (stmt->State == EXECUTED0 && mapi_more_results(stmt->hdl))) {
447 : /* Invalid cursor state */
448 0 : addStmtError(stmt, "24000", NULL, 0);
449 0 : return SQL_ERROR;
450 : }
451 :
452 2004 : assert(stmt->Dbc);
453 2004 : assert(stmt->Dbc->mid);
454 2004 : hdl = stmt->hdl;
455 :
456 2004 : assert(hdl);
457 :
458 2004 : desc = stmt->ApplParamDescr;
459 :
460 2004 : if (desc->sql_desc_count < stmt->nparams ||
461 2004 : stmt->ImplParamDescr->sql_desc_count < stmt->nparams) {
462 : /* COUNT field incorrect */
463 0 : addStmtError(stmt, "07002", NULL, 0);
464 0 : return SQL_ERROR;
465 : }
466 :
467 2004 : querylen = 1024;
468 2004 : query = malloc(querylen); /* XXX allocate space for parameters */
469 2004 : if (query == NULL) {
470 : /* Memory allocation error */
471 0 : addStmtError(stmt, "HY001", NULL, 0);
472 0 : return SQL_ERROR;
473 : }
474 2004 : if (stmt->qtimeout != stmt->Dbc->qtimeout) {
475 0 : snprintf(query, querylen, "call sys.%s(%" PRIu64 ")",
476 0 : (stmt->Dbc->major == 11 && stmt->Dbc->minor >= 37)
477 : ? "setquerytimeout" : "settimeout",
478 : (uint64_t) stmt->qtimeout);
479 0 : if (mapi_query_handle(hdl, query) == MOK)
480 0 : stmt->Dbc->qtimeout = stmt->qtimeout;
481 : }
482 2004 : querypos = snprintf(query, querylen, "execute %d (", stmt->queryid);
483 : /* XXX fill in parameter values */
484 2004 : if (desc->sql_desc_bind_offset_ptr)
485 0 : offset = *desc->sql_desc_bind_offset_ptr;
486 : else
487 : offset = 0;
488 2004 : sep = "";
489 12008 : for (i = 1; i <= stmt->nparams; i++) {
490 10004 : if (ODBCStore(stmt, i, offset, 0, &query, &querypos, &querylen, sep) == SQL_ERROR) {
491 0 : if (query)
492 0 : free(query);
493 0 : return SQL_ERROR;
494 : }
495 10004 : sep = ",";
496 : }
497 2004 : if (querypos + 1 >= querylen) {
498 0 : char *q = realloc(query, querylen += 10);
499 0 : if (q == NULL) {
500 0 : free(query);
501 0 : addStmtError(stmt, "HY001", NULL, 0);
502 0 : return SQL_ERROR;
503 : }
504 0 : query = q;
505 : }
506 2004 : query[querypos++] = ')';
507 2004 : query[querypos] = 0;
508 :
509 : #ifdef ODBCDEBUG
510 2004 : ODBCLOG("SQLExecute %p %s\n", stmt, query);
511 : #endif
512 :
513 : /* Have the server execute the query */
514 2004 : if (stmt->next == NULL && stmt->Dbc->FirstStmt == stmt &&
515 2003 : stmt->cursorType == SQL_CURSOR_FORWARD_ONLY) {
516 : /* we're the only Stmt handle, and we're only going forward */
517 2003 : if (stmt->Dbc->cachelimit != 10000)
518 3 : mapi_cache_limit(stmt->Dbc->mid, 10000);
519 2003 : stmt->Dbc->cachelimit = 10000;
520 : } else {
521 1 : if (stmt->Dbc->cachelimit != 100)
522 1 : mapi_cache_limit(stmt->Dbc->mid, 100);
523 1 : stmt->Dbc->cachelimit = 100;
524 : }
525 2004 : msg = mapi_query_handle(hdl, query);
526 2004 : free(query);
527 2004 : switch (msg) {
528 : case MOK:
529 2004 : break;
530 0 : case MTIMEOUT:
531 : /* Timeout expired / Communication link failure */
532 0 : addStmtError(stmt, stmt->Dbc->sql_attr_connection_timeout ? "HYT00" : "08S01", mapi_error_str(stmt->Dbc->mid), 0);
533 0 : return SQL_ERROR;
534 0 : default:
535 0 : errstr = mapi_result_error(hdl);
536 0 : if (errstr == NULL)
537 0 : errstr = mapi_error_str(stmt->Dbc->mid);
538 0 : if (errstr) {
539 0 : const char *sqlstate;
540 :
541 0 : if ((sqlstate = mapi_result_errorcode(hdl)) != NULL) {
542 0 : addStmtError(stmt, sqlstate, errstr, 0);
543 0 : return SQL_ERROR;
544 : }
545 : }
546 : /* General error */
547 0 : addStmtError(stmt, "HY000", errstr, 0);
548 0 : return SQL_ERROR;
549 : }
550 :
551 : /* now get the result data and store it to our internal data structure */
552 :
553 2004 : return ODBCInitResult(stmt);
554 : }
555 :
556 : SQLRETURN SQL_API
557 : SQLExecute(SQLHSTMT StatementHandle)
558 : {
559 : #ifdef ODBCDEBUG
560 2004 : ODBCLOG("SQLExecute %p\n", StatementHandle);
561 : #endif
562 :
563 2004 : if (!isValidStmt((ODBCStmt *) StatementHandle))
564 : return SQL_INVALID_HANDLE;
565 :
566 2004 : clearStmtErrors((ODBCStmt *) StatementHandle);
567 :
568 2004 : return MNDBExecute((ODBCStmt *) StatementHandle);
569 : }
|