DON'T USE THIS REPO: IT'S OBSOLETE.
[versaplex.git] / vxodbc / execute.cc
blob292c83cdac7cbf1da4426a2bbcb37646c760fc90
1 /*
2 * Description: This module contains routines related to
3 * preparing and executing an SQL statement.
4 */
6 #include "psqlodbc.h"
7 #include "misc.h"
9 #include <stdio.h>
10 #include <string.h>
12 #include <ctype.h>
14 #include "environ.h"
15 #include "connection.h"
16 #include "statement.h"
17 #include "qresult.h"
18 #include "convert.h"
19 #include "bind.h"
20 #include "pgtypes.h"
21 #include "pgapifunc.h"
22 #include "vxhelpers.h"
24 /*extern GLOBAL_VALUES globals;*/
27 /* Perform a Prepare on the SQL statement */
28 RETCODE SQL_API
29 PGAPI_Prepare(HSTMT hstmt,
30 const SQLCHAR FAR * szSqlStr, SQLINTEGER cbSqlStr)
32 CSTR func = "PGAPI_Prepare";
33 StatementClass *self = (StatementClass *) hstmt;
34 RETCODE retval = SQL_SUCCESS;
36 mylog("%s: entering...\n", func);
38 #define return DONT_CALL_RETURN_FROM_HERE???
39 /* StartRollbackState(self); */
40 if (!self)
42 SC_log_error(func, "", NULL);
43 retval = SQL_INVALID_HANDLE;
44 goto cleanup;
48 * According to the ODBC specs it is valid to call SQLPrepare multiple
49 * times. In that case, the bound SQL statement is replaced by the new
50 * one
53 SC_set_prepared(self, NOT_YET_PREPARED);
54 switch (self->status)
56 case STMT_PREMATURE:
57 mylog("**** PGAPI_Prepare: STMT_PREMATURE, recycle\n");
58 SC_recycle_statement(self); /* recycle the statement, but do
59 * not remove parameter bindings */
60 break;
62 case STMT_FINISHED:
63 mylog("**** PGAPI_Prepare: STMT_FINISHED, recycle\n");
64 SC_recycle_statement(self); /* recycle the statement, but do
65 * not remove parameter bindings */
66 break;
68 case STMT_ALLOCATED:
69 mylog("**** PGAPI_Prepare: STMT_ALLOCATED, copy\n");
70 self->status = STMT_READY;
71 break;
73 case STMT_READY:
74 mylog("**** PGAPI_Prepare: STMT_READY, change SQL\n");
75 break;
77 case STMT_EXECUTING:
78 mylog("**** PGAPI_Prepare: STMT_EXECUTING, error!\n");
80 SC_set_error(self, STMT_SEQUENCE_ERROR,
81 "PGAPI_Prepare(): The handle does not point to a statement that is ready to be executed",
82 func);
84 retval = SQL_ERROR;
85 goto cleanup;
87 default:
88 SC_set_error(self, STMT_INTERNAL_ERROR,
89 "An Internal Error has occured -- Unknown statement status.",
90 func);
91 retval = SQL_ERROR;
92 goto cleanup;
95 SC_initialize_stmts(self, TRUE);
97 if (!szSqlStr)
99 SC_set_error(self, STMT_NO_MEMORY_ERROR, "the query is NULL",
100 func);
101 retval = SQL_ERROR;
102 goto cleanup;
104 if (!szSqlStr[0])
105 self->statement = strdup("");
106 else
107 self->statement = make_string(szSqlStr, cbSqlStr, NULL, 0);
108 if (!self->statement)
110 SC_set_error(self, STMT_NO_MEMORY_ERROR,
111 "No memory available to store statement", func);
112 retval = SQL_ERROR;
113 goto cleanup;
116 self->prepare = PREPARE_STATEMENT;
117 self->statement_type = statement_type(self->statement);
119 /* Check if connection is onlyread (only selects are allowed) */
120 if (CC_is_onlyread(SC_get_conn(self)) && STMT_UPDATE(self))
122 SC_set_error(self, STMT_EXEC_ERROR,
123 "Connection is readonly, only select statements are allowed.",
124 func);
125 retval = SQL_ERROR;
126 goto cleanup;
129 cleanup:
130 #undef return
131 inolog("SQLPrepare return=%d\n", retval);
132 if (self->internal)
133 retval = DiscardStatementSvp(self, retval, FALSE);
134 return retval;
139 // VX_CLEANUP: Anything calling this is obviously broken, but it's not so
140 // obvious whether the callers should be fixed to call PGAPI_ExecDirect_Vx or
141 // killed.
142 /* Performs the equivalent of SQLPrepare, followed by SQLExecute. */
143 RETCODE SQL_API
144 PGAPI_ExecDirect(HSTMT hstmt,
145 const SQLCHAR FAR * szSqlStr,
146 SQLINTEGER cbSqlStr, UWORD flag)
148 StatementClass *stmt = (StatementClass *) hstmt;
149 RETCODE result;
150 CSTR func = "PGAPI_ExecDirect";
151 SC_set_error(stmt, STMT_EXEC_ERROR,
152 "PGAPI_ExecDirect is not supported, call PGAPI_ExecDirect_Vx",
153 func);
154 return SQL_ERROR;
158 /* Performs the equivalent of SQLPrepare, followed by SQLExecute. */
159 RETCODE SQL_API
160 PGAPI_ExecDirect_Vx(HSTMT hstmt,
161 const SQLCHAR FAR * szSqlStr,
162 SQLINTEGER cbSqlStr, UWORD flag)
164 StatementClass *stmt = (StatementClass *)hstmt;
166 VxStatement st(stmt);
167 VxResultSet rs;
168 st.reinit();
169 st.runquery(rs, "ExecChunkRecordset", (const char *)szSqlStr);
170 st.set_result(rs);
171 stmt->statement = strdup((const char *)szSqlStr);
172 stmt->catalog_result = FALSE;
173 stmt->statement_type = STMT_TYPE_SELECT;
174 // SC_set_parse_forced(stmt);
176 cleanup:
177 return st.retcode();
181 /* Execute a prepared SQL statement */
182 RETCODE SQL_API PGAPI_Execute_Vx(HSTMT hstmt, UWORD flag)
184 StatementClass *stmt = (StatementClass *)hstmt;
186 VxStatement st(stmt);
187 VxResultSet rs;
188 st.runquery(rs, "ExecChunkRecordset", stmt->statement);
189 st.set_result(rs);
191 cleanup:
192 return st.retcode();
196 static int inquireHowToPrepare(const StatementClass * stmt)
198 ConnectionClass *conn;
199 ConnInfo *ci;
200 int ret = 0;
202 conn = SC_get_conn(stmt);
203 ci = &(conn->connInfo);
204 if (!ci->use_server_side_prepare || PG_VERSION_LT(conn, 7.3))
206 /* Do prepare operations by the driver itself */
207 return PREPARE_BY_THE_DRIVER;
209 if (NOT_YET_PREPARED == stmt->prepared)
211 SQLSMALLINT num_params;
213 if (STMT_TYPE_DECLARE == stmt->statement_type &&
214 PG_VERSION_LT(conn, 8.0))
216 return PREPARE_BY_THE_DRIVER;
218 if (stmt->multi_statement < 0)
219 PGAPI_NumParams((StatementClass *) stmt, &num_params);
220 if (stmt->multi_statement > 0) /* would divide the query into multiple commands and apply V3 parse requests for each of them */
221 ret = PARSE_REQ_FOR_INFO;
222 else if (PROTOCOL_74(ci))
224 if (STMT_TYPE_SELECT == stmt->statement_type)
226 if (SQL_CURSOR_FORWARD_ONLY !=
227 stmt->options.cursor_type)
228 ret = PARSE_REQ_FOR_INFO;
229 else
230 ret = PARSE_TO_EXEC_ONCE;
231 } else
232 ret = PARSE_TO_EXEC_ONCE;
233 } else
235 if (STMT_TYPE_SELECT == stmt->statement_type &&
236 (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type))
237 ret = PREPARE_BY_THE_DRIVER;
238 else
239 ret = USING_PREPARE_COMMAND;
242 if (SC_is_prepare_statement(stmt) && (PARSE_TO_EXEC_ONCE == ret))
243 ret = NAMED_PARSE_REQUEST;
245 return ret;
249 // VX_CLEANUP: This is called all over the place, it'll be a pain to extract.
250 int StartRollbackState(StatementClass * stmt)
252 CSTR func = "StartRollbackState";
253 return 1;
257 // VX_CLEANUP: SetStatementSvp was killed in or around r225; one might think
258 // that would make this function totally redundant, but it's still called all
259 // over the place, and breaks the unit tests if it returns an error.
260 RETCODE
261 DiscardStatementSvp(StatementClass * stmt, RETCODE ret, BOOL errorOnly)
263 CSTR func = "DiscardStatementSvp";
265 return ret;
268 void SC_setInsertedTable(StatementClass * stmt, RETCODE retval)
270 const char *cmd = stmt->statement, *ptr;
271 ConnectionClass *conn;
272 size_t len;
274 if (STMT_TYPE_INSERT != stmt->statement_type)
275 return;
276 if (SQL_NEED_DATA == retval)
277 return;
278 conn = SC_get_conn(stmt);
279 if (PG_VERSION_GE(conn, 8.1)) /* lastval() is available */
280 return;
281 /*if (!CC_fake_mss(conn))
282 return; */
283 while (isspace((UCHAR) * cmd))
284 cmd++;
285 if (!*cmd)
286 return;
287 len = 6;
288 if (strnicmp(cmd, "insert", len))
289 return;
290 cmd += len;
291 while (isspace((UCHAR) * (++cmd)));
292 if (!*cmd)
293 return;
294 len = 4;
295 if (strnicmp(cmd, "into", len))
296 return;
297 cmd += len;
298 while (isspace((UCHAR) * (++cmd)));
299 if (!*cmd)
300 return;
301 NULL_THE_NAME(conn->schemaIns);
302 NULL_THE_NAME(conn->tableIns);
303 if (!SQL_SUCCEEDED(retval))
304 return;
305 ptr = NULL;
306 if (IDENTIFIER_QUOTE == *cmd)
308 if (ptr = strchr(cmd + 1, IDENTIFIER_QUOTE), NULL == ptr)
309 return;
310 if ('.' == ptr[1])
312 len = ptr - cmd - 1;
313 STRN_TO_NAME(conn->schemaIns, cmd + 1, len);
314 cmd = ptr + 2;
315 ptr = NULL;
317 } else
319 if (ptr = strchr(cmd + 1, '.'), NULL != ptr)
321 len = ptr - cmd;
322 STRN_TO_NAME(conn->schemaIns, cmd, len);
323 cmd = ptr + 1;
324 ptr = NULL;
327 if (IDENTIFIER_QUOTE == *cmd && NULL == ptr)
329 if (ptr = strchr(cmd + 1, IDENTIFIER_QUOTE), NULL == ptr)
330 return;
332 if (IDENTIFIER_QUOTE == *cmd)
334 len = ptr - cmd - 1;
335 STRN_TO_NAME(conn->tableIns, cmd + 1, len);
336 } else
338 ptr = cmd;
339 while (*ptr && !isspace((UCHAR) * ptr))
340 ptr++;
341 len = ptr - cmd;
342 STRN_TO_NAME(conn->tableIns, cmd, len);
346 /* Execute a prepared SQL statement */
347 RETCODE SQL_API PGAPI_Execute(HSTMT hstmt, UWORD flag)
349 CSTR func = "PGAPI_Execute";
350 StatementClass *stmt = (StatementClass *) hstmt;
351 SC_set_error(stmt, STMT_EXEC_ERROR,
352 "PGAPI_Execute is not supported, call PGAPI_ExecDirect_Vx",
353 func);
354 return SQL_ERROR;
358 RETCODE SQL_API PGAPI_Transact(HENV henv, HDBC hdbc, SQLUSMALLINT fType)
360 CSTR func = "PGAPI_Transact";
362 CC_set_error((ConnectionClass *)hdbc, CONN_NOT_IMPLEMENTED_ERROR,
363 "PGAPI_Transact is not yet implemented",
364 func);
365 return SQL_ERROR;
369 // VX_CLEANUP: A lot of this is probably related to transactions, hence
370 // deletable
371 RETCODE SQL_API PGAPI_Cancel(HSTMT hstmt) /* Statement to cancel. */
373 CSTR func = "PGAPI_Cancel";
374 StatementClass *stmt = (StatementClass *) hstmt, *estmt;
375 ConnectionClass *conn;
376 RETCODE ret = SQL_SUCCESS;
377 BOOL entered_cs = FALSE;
378 ConnInfo *ci;
380 mylog("%s: entering...\n", func);
382 /* Check if this can handle canceling in the middle of a SQLPutData? */
383 if (!stmt)
385 SC_log_error(func, "", NULL);
386 return SQL_INVALID_HANDLE;
388 conn = SC_get_conn(stmt);
389 ci = &(conn->connInfo);
391 #define return DONT_CALL_RETURN_FROM_HERE???
392 /* StartRollbackState(stmt); */
394 if (stmt->execute_delegate)
395 estmt = stmt->execute_delegate;
396 else
397 estmt = stmt;
399 * Not in the middle of SQLParamData/SQLPutData so cancel like a
400 * close.
402 if (estmt->data_at_exec < 0)
405 * Tell the Backend that we're cancelling this request
407 mylog("Cancelling while in the middle of SQLParamData/SQLPutData not "
408 "yet supported\n");
409 ret = SQL_ERROR;
410 goto cleanup;
413 /* In the middle of SQLParamData/SQLPutData, so cancel that. */
415 * Note, any previous data-at-exec buffers will be freed in the
416 * recycle
418 /* if they call SQLExecDirect or SQLExecute again. */
420 ENTER_STMT_CS(stmt);
421 entered_cs = TRUE;
422 SC_clear_error(stmt);
423 estmt->data_at_exec = -1;
424 estmt->current_exec_param = -1;
425 estmt->put_data = FALSE;
426 cancelNeedDataState(estmt);
428 cleanup:
429 #undef return
430 if (entered_cs)
432 if (stmt->internal)
433 ret = DiscardStatementSvp(stmt, ret, FALSE);
434 LEAVE_STMT_CS(stmt);
436 return ret;
441 * Returns the SQL string as modified by the driver.
442 * Currently, just copy the input string without modification
443 * observing buffer limits and truncation.
445 RETCODE SQL_API
446 PGAPI_NativeSql(HDBC hdbc,
447 const SQLCHAR FAR * szSqlStrIn,
448 SQLINTEGER cbSqlStrIn,
449 SQLCHAR FAR * szSqlStr,
450 SQLINTEGER cbSqlStrMax, SQLINTEGER FAR * pcbSqlStr)
452 CSTR func = "PGAPI_NativeSql";
453 size_t len = 0;
454 char *ptr;
455 ConnectionClass *conn = (ConnectionClass *) hdbc;
456 RETCODE result;
458 mylog("%s: entering...cbSqlStrIn=%d\n", func, cbSqlStrIn);
460 ptr = (char *)(
461 (cbSqlStrIn == 0) ? "" : make_string(szSqlStrIn, cbSqlStrIn,
462 NULL, 0));
463 if (!ptr)
465 CC_set_error(conn, CONN_NO_MEMORY_ERROR,
466 "No memory available to store native sql string",
467 func);
468 return SQL_ERROR;
471 result = SQL_SUCCESS;
472 len = strlen(ptr);
474 if (szSqlStr)
476 strncpy_null((char *)szSqlStr, ptr, cbSqlStrMax);
478 if (len >= cbSqlStrMax)
480 result = SQL_SUCCESS_WITH_INFO;
481 CC_set_error(conn, CONN_TRUNCATED,
482 "The buffer was too small for the NativeSQL.",
483 func);
487 if (pcbSqlStr)
488 *pcbSqlStr = (SQLINTEGER) len;
490 if (cbSqlStrIn)
491 free(ptr);
493 return result;
498 * Supplies parameter data at execution time.
499 * Used in conjuction with SQLPutData.
501 RETCODE SQL_API PGAPI_ParamData(HSTMT hstmt, PTR FAR * prgbValue)
503 CSTR func = "PGAPI_ParamData";
504 StatementClass *stmt = (StatementClass *) hstmt, *estmt;
505 SC_log_error(func, "PGAPI_ParamData is not yet implemented", stmt);
506 return SQL_ERROR;
511 * Supplies parameter data at execution time.
512 * Used in conjunction with SQLParamData.
514 RETCODE SQL_API PGAPI_PutData(HSTMT hstmt, PTR rgbValue, SQLLEN cbValue)
516 CSTR func = "PGAPI_PutData";
517 StatementClass *stmt = (StatementClass *) hstmt, *estmt;
518 ConnectionClass *conn;
519 RETCODE retval = SQL_SUCCESS;
520 APDFields *apdopts;
521 IPDFields *ipdopts;
522 SQLLEN old_pos;
523 ParameterInfoClass *current_param;
524 ParameterImplClass *current_iparam;
525 PutDataClass *current_pdata;
526 char *buffer, *putbuf, *allocbuf = NULL;
527 Int2 ctype;
528 SQLLEN putlen;
529 BOOL lenset = FALSE;
531 mylog("%s: entering...\n", func);
533 #define return DONT_CALL_RETURN_FROM_HERE???
534 if (!stmt)
536 SC_log_error(func, "", NULL);
537 retval = SQL_INVALID_HANDLE;
538 goto cleanup;
540 if (SC_AcceptedCancelRequest(stmt))
542 SC_set_error(stmt, STMT_OPERATION_CANCELLED,
543 "Cancel the statement, sorry.", func);
544 retval = SQL_ERROR;
545 goto cleanup;
548 estmt = stmt->execute_delegate ? stmt->execute_delegate : stmt;
549 apdopts = SC_get_APDF(estmt);
550 if (estmt->current_exec_param < 0)
552 SC_set_error(stmt, STMT_SEQUENCE_ERROR,
553 "Previous call was not SQLPutData or SQLParamData",
554 func);
555 retval = SQL_ERROR;
556 goto cleanup;
559 current_param = &(apdopts->parameters[estmt->current_exec_param]);
560 ipdopts = SC_get_IPDF(estmt);
561 current_iparam = &(ipdopts->parameters[estmt->current_exec_param]);
562 ctype = current_param->CType;
564 conn = SC_get_conn(estmt);
565 if (ctype == SQL_C_DEFAULT)
567 ctype = sqltype_to_default_ctype(conn, current_iparam->SQLType);
568 if (SQL_C_WCHAR == ctype && CC_default_is_c(conn))
569 ctype = SQL_C_CHAR;
571 if (SQL_NTS == cbValue)
573 #ifdef UNICODE_SUPPORT
574 if (SQL_C_WCHAR == ctype)
576 putlen = WCLEN * ucs2strlen((SQLWCHAR *) rgbValue);
577 lenset = TRUE;
578 } else
579 #endif /* UNICODE_SUPPORT */
580 if (SQL_C_CHAR == ctype)
582 putlen = strlen((const char *)rgbValue);
583 lenset = TRUE;
586 if (!lenset)
588 if (cbValue < 0)
589 putlen = cbValue;
590 else
591 #ifdef UNICODE_SUPPORT
592 if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY
593 || ctype == SQL_C_WCHAR)
594 #else
595 if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY)
596 #endif /* UNICODE_SUPPORT */
597 putlen = cbValue;
598 else
599 putlen = ctype_length(ctype);
601 putbuf = (char *)rgbValue;
603 if (!estmt->put_data)
604 { /* first call */
605 mylog("PGAPI_PutData: (1) cbValue = %d\n", cbValue);
607 estmt->put_data = TRUE;
609 current_pdata->EXEC_used = (SQLLEN *) malloc(sizeof(SQLLEN));
610 if (!current_pdata->EXEC_used)
612 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
613 "Out of memory in PGAPI_PutData (1)", func);
614 retval = SQL_ERROR;
615 goto cleanup;
618 *current_pdata->EXEC_used = putlen;
620 if (cbValue == SQL_NULL_DATA)
622 retval = SQL_SUCCESS;
623 goto cleanup;
626 current_pdata->EXEC_buffer = (char *)malloc(putlen + 1);
627 if (!current_pdata->EXEC_buffer)
629 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
630 "Out of memory in PGAPI_PutData (2)",
631 func);
632 retval = SQL_ERROR;
633 goto cleanup;
635 memcpy(current_pdata->EXEC_buffer, putbuf, putlen);
636 current_pdata->EXEC_buffer[putlen] = '\0';
637 } else
639 /* calling SQLPutData more than once */
640 mylog("PGAPI_PutData: (>1) cbValue = %d\n", cbValue);
642 buffer = current_pdata->EXEC_buffer;
643 old_pos = *current_pdata->EXEC_used;
644 if (putlen > 0)
646 SQLLEN used =
647 *current_pdata->EXEC_used + putlen, allocsize;
648 for (allocsize = (1 << 4); allocsize <= used;
649 allocsize <<= 1);
650 mylog
651 (" cbValue = %d, old_pos = %d, *used = %d\n",
652 putlen, old_pos, used);
654 /* dont lose the old pointer in case out of memory */
655 buffer = (char *)realloc(current_pdata->EXEC_buffer, allocsize);
656 if (!buffer)
658 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
659 "Out of memory in PGAPI_PutData (3)",
660 func);
661 retval = SQL_ERROR;
662 goto cleanup;
665 memcpy(&buffer[old_pos], putbuf, putlen);
666 buffer[used] = '\0';
668 /* reassign buffer incase realloc moved it */
669 *current_pdata->EXEC_used = used;
670 current_pdata->EXEC_buffer = buffer;
671 } else
673 SC_set_error(stmt, STMT_INTERNAL_ERROR, "bad cbValue",
674 func);
675 retval = SQL_ERROR;
676 goto cleanup;
680 retval = SQL_SUCCESS;
681 cleanup:
682 #undef return
683 if (allocbuf)
684 free(allocbuf);
685 if (stmt->internal)
686 retval = DiscardStatementSvp(stmt, retval, TRUE);
688 return retval;