aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/odbc/statement.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/odbc/statement.c')
-rw-r--r--src/interfaces/odbc/statement.c264
1 files changed, 131 insertions, 133 deletions
diff --git a/src/interfaces/odbc/statement.c b/src/interfaces/odbc/statement.c
index b33ccc2cc95..f48a1724219 100644
--- a/src/interfaces/odbc/statement.c
+++ b/src/interfaces/odbc/statement.c
@@ -117,6 +117,10 @@ PGAPI_AllocStmt(HDBC hdbc,
/* Copy default statement options based from Connection options */
stmt->options = conn->stmtOptions;
+ stmt->ardopts = conn->ardOptions;
+ stmt->ardopts.bookmark = (BindInfoClass *) malloc(sizeof(BindInfoClass));
+ stmt->ardopts.bookmark->buffer = NULL;
+ stmt->ardopts.bookmark->used = NULL;
stmt->stmt_size_limit = CC_get_max_query_len(conn);
/* Save the handle for later */
@@ -205,17 +209,35 @@ void
InitializeStatementOptions(StatementOptions *opt)
{
memset(opt, 0, sizeof(StatementOptions));
- opt->maxRows = 0; /* driver returns all rows */
- opt->maxLength = 0; /* driver returns all data for char/binary */
- opt->rowset_size = 1;
+ opt->maxRows = 0; /* driver returns all rows */
+ opt->maxLength = 0; /* driver returns all data for char/binary */
opt->keyset_size = 0; /* fully keyset driven is the default */
opt->scroll_concurrency = SQL_CONCUR_READ_ONLY;
opt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
- opt->bind_size = 0; /* default is to bind by column */
opt->retrieve_data = SQL_RD_ON;
opt->use_bookmarks = SQL_UB_OFF;
+}
+
+
+/*
+ * ARDFields initialize
+ */
+void
+InitializeARDFields(ARDFields *opt)
+{
+ memset(opt, 0, sizeof(ARDFields));
+ opt->rowset_size = 1;
+ opt->bind_size = 0; /* default is to bind by column */
+}
+/*
+ * APDFields initialize
+ */
+void
+InitializeAPDFields(APDFields *opt)
+{
+ memset(opt, 0, sizeof(APDFields));
opt->paramset_size = 1;
- opt->param_bind_type = 0; /* default is column-wise binding */
+ opt->param_bind_type = 0; /* default is to bind by column */
}
@@ -246,15 +268,6 @@ SC_Constructor(void)
rv->stmt_size_limit = -1;
rv->statement_type = STMT_TYPE_UNKNOWN;
- rv->bindings = NULL;
- rv->bindings_allocated = 0;
-
- rv->bookmark.buffer = NULL;
- rv->bookmark.used = NULL;
-
- rv->parameters_allocated = 0;
- rv->parameters = 0;
-
rv->currTuple = -1;
rv->rowset_start = -1;
rv->current_col = -1;
@@ -274,22 +287,65 @@ SC_Constructor(void)
/* Parse Stuff */
rv->ti = NULL;
- rv->fi = NULL;
rv->ntab = 0;
- rv->nfld = 0;
rv->parse_status = STMT_PARSE_NONE;
/* Clear Statement Options -- defaults will be set in AllocStmt */
memset(&rv->options, 0, sizeof(StatementOptions));
+ memset(&rv->ardopts, 0, sizeof(ARDFields));
+ memset(&rv->apdopts, 0, sizeof(APDFields));
+ memset(&rv->irdopts, 0, sizeof(IRDFields));
+ memset(&rv->ipdopts, 0, sizeof(IPDFields));
rv->pre_executing = FALSE;
rv->inaccurate_result = FALSE;
rv->miscinfo = 0;
+ rv->updatable = FALSE;
}
return rv;
}
+void ARDFields_free(ARDFields * self)
+{
+ if (self->bookmark)
+ {
+ free(self->bookmark);
+ self->bookmark = NULL;
+ }
+ /*
+ * the memory pointed to by the bindings is not deallocated by the
+ * driver but by the application that uses that driver, so we don't
+ * have to care
+ */
+ ARD_unbind_cols(self, TRUE);
+}
+
+void APDFields_free(APDFields * self)
+{
+ /* param bindings */
+ APD_free_params(self, STMT_FREE_PARAMS_ALL);
+}
+
+void IRDFields_free(IRDFields * self)
+{
+ /* Free the parsed field information */
+ if (self->fi)
+ {
+ int i;
+
+ for (i = 0; i < (int) self->nfields; i++)
+ if (self->fi[i])
+ free(self->fi[i]);
+ free(self->fi);
+ self->fi = NULL;
+ }
+}
+
+void IPDFields_free(IPDFields * self)
+{
+}
+
char
SC_Destructor(StatementClass *self)
{
@@ -322,47 +378,25 @@ SC_Destructor(StatementClass *self)
if (self->load_statement)
free(self->load_statement);
- SC_free_params(self, STMT_FREE_PARAMS_ALL);
-
- /*
- * the memory pointed to by the bindings is not deallocated by the
- * driver but by the application that uses that driver, so we don't
- * have to care
- */
- /* about that here. */
- if (self->bindings)
- {
- int lf;
-
- for (lf = 0; lf < self->bindings_allocated; lf++)
- {
- if (self->bindings[lf].ttlbuf != NULL)
- free(self->bindings[lf].ttlbuf);
- }
- free(self->bindings);
- }
-
- /* Free the parsed table information */
+ /* Free the parsed table information */
if (self->ti)
{
- int i;
+ int i;
for (i = 0; i < self->ntab; i++)
- free(self->ti[i]);
+ if (self->ti[i]);
+ free(self->ti[i]);
free(self->ti);
+ self->ti = NULL;
}
/* Free the parsed field information */
- if (self->fi)
- {
- int i;
-
- for (i = 0; i < self->nfld; i++)
- free(self->fi[i]);
- free(self->fi);
- }
-
+ ARDFields_free(&(self->ardopts));
+ APDFields_free(&(self->apdopts));
+ IRDFields_free(&(self->irdopts));
+ IPDFields_free(&(self->ipdopts));
+
free(self);
mylog("SC_Destructor: EXIT\n");
@@ -378,46 +412,16 @@ SC_Destructor(StatementClass *self)
void
SC_free_params(StatementClass *self, char option)
{
- int i;
-
- mylog("SC_free_params: ENTER, self=%d\n", self);
-
- if (!self->parameters)
- return;
-
- for (i = 0; i < self->parameters_allocated; i++)
- {
- if (self->parameters[i].data_at_exec == TRUE)
- {
- if (self->parameters[i].EXEC_used)
- {
- free(self->parameters[i].EXEC_used);
- self->parameters[i].EXEC_used = NULL;
- }
-
- if (self->parameters[i].EXEC_buffer)
- {
- if (self->parameters[i].SQLType != SQL_LONGVARBINARY)
- free(self->parameters[i].EXEC_buffer);
- self->parameters[i].EXEC_buffer = NULL;
- }
- }
- }
+ APD_free_params(SC_get_APD(self), option);
self->data_at_exec = -1;
self->current_exec_param = -1;
self->put_data = FALSE;
-
if (option == STMT_FREE_PARAMS_ALL)
{
- free(self->parameters);
- self->parameters = NULL;
- self->parameters_allocated = 0;
self->exec_start_row = -1;
self->exec_end_row = -1;
self->exec_current_row = -1;
}
-
- mylog("SC_free_params: EXIT\n");
}
@@ -493,31 +497,22 @@ SC_recycle_statement(StatementClass *self)
return FALSE;
}
- /* Free the parsed table information */
+ /* Free the parsed table information */
if (self->ti)
{
- int i;
+ int i;
for (i = 0; i < self->ntab; i++)
- free(self->ti[i]);
-
- free(self->ti);
+ if (self->ti)
+ free(self->ti);
self->ti = NULL;
self->ntab = 0;
}
-
/* Free the parsed field information */
- if (self->fi)
- {
- int i;
+ IRDFields_free(SC_get_IRD(self));
- for (i = 0; i < self->nfld; i++)
- free(self->fi[i]);
- free(self->fi);
- self->fi = NULL;
- self->nfld = 0;
- }
self->parse_status = STMT_PARSE_NONE;
+ self->updatable = FALSE;
/* Free any cursors */
if (res = SC_get_Result(self), res)
@@ -605,19 +600,11 @@ SC_pre_execute(StatementClass *self)
char
SC_unbind_cols(StatementClass *self)
{
- Int2 lf;
-
- for (lf = 0; lf < self->bindings_allocated; lf++)
- {
- self->bindings[lf].data_left = -1;
- self->bindings[lf].buflen = 0;
- self->bindings[lf].buffer = NULL;
- self->bindings[lf].used = NULL;
- self->bindings[lf].returntype = SQL_C_CHAR;
- }
+ ARDFields *opts = SC_get_ARD(self);
- self->bookmark.buffer = NULL;
- self->bookmark.used = NULL;
+ ARD_unbind_cols(opts, FALSE);
+ opts->bookmark->buffer = NULL;
+ opts->bookmark->used = NULL;
return 1;
}
@@ -732,6 +719,7 @@ SC_fetch(StatementClass *self)
{
static char *func = "SC_fetch";
QResultClass *res = SC_get_Curres(self);
+ ARDFields *opts;
int retval,
result;
@@ -791,25 +779,26 @@ SC_fetch(StatementClass *self)
result = SQL_SUCCESS;
self->last_fetch_count = 1;
+ opts = SC_get_ARD(self);
/*
* If the bookmark column was bound then return a bookmark. Since this
* is used with SQLExtendedFetch, and the rowset size may be greater
* than 1, and an application can use row or column wise binding, use
* the code in copy_and_convert_field() to handle that.
*/
- if (self->bookmark.buffer)
+ if (opts->bookmark->buffer)
{
char buf[32];
- UInt4 offset = self->options.row_offset_ptr ? *self->options.row_offset_ptr : 0;
+ UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
sprintf(buf, "%ld", SC_get_bookmark(self));
result = copy_and_convert_field(self, 0, buf,
- SQL_C_ULONG, self->bookmark.buffer + offset, 0,
- self->bookmark.used ? self->bookmark.used + (offset >> 2) : NULL);
+ SQL_C_ULONG, opts->bookmark->buffer + offset, 0,
+ opts->bookmark->used ? opts->bookmark->used + (offset >> 2) : NULL);
}
#ifdef DRIVER_CURSOR_IMPLEMENT
- if (self->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
+ if (res->haskeyset)
{
num_cols -= 2;
}
@@ -818,12 +807,12 @@ SC_fetch(StatementClass *self)
return SQL_SUCCESS;
for (lf = 0; lf < num_cols; lf++)
{
- mylog("fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u\n", num_cols, lf, self, self->bindings, self->bindings[lf].buffer);
+ mylog("fetch: cols=%d, lf=%d, opts = %u, opts->bindings = %u, buffer[] = %u\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer);
/* reset for SQLGetData */
- self->bindings[lf].data_left = -1;
+ opts->bindings[lf].data_left = -1;
- if (self->bindings[lf].buffer != NULL)
+ if (opts->bindings[lf].buffer != NULL)
{
/* this column has a binding */
@@ -871,7 +860,7 @@ SC_fetch(StatementClass *self)
self->errornumber = STMT_TRUNCATED;
self->errormsg = "Fetched item was truncated.";
qlog("The %dth item was truncated\n", lf + 1);
- qlog("The buffer size = %d", self->bindings[lf].buflen);
+ qlog("The buffer size = %d", opts->bindings[lf].buflen);
qlog(" and the value is '%s'\n", value);
result = SQL_SUCCESS_WITH_INFO;
break;
@@ -905,12 +894,14 @@ SC_execute(StatementClass *self)
{
static char *func = "SC_execute";
ConnectionClass *conn;
+ APDFields *apdopts;
char was_ok, was_nonfatal;
QResultClass *res = NULL;
Int2 oldstatus,
numcols;
QueryInfo qi;
ConnInfo *ci;
+ UDWORD qflag = 0;
conn = SC_get_conn(self);
@@ -931,13 +922,15 @@ SC_execute(StatementClass *self)
(!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_OTHER)))
{
mylog(" about to begin a transaction on statement = %u\n", self);
- if (!CC_begin(conn))
- {
- self->errormsg = "Could not begin a transaction";
- self->errornumber = STMT_EXEC_ERROR;
- SC_log_error(func, "", self);
- return SQL_ERROR;
- }
+ if (PG_VERSION_GE(conn, 7.1))
+ qflag |= GO_INTO_TRANSACTION;
+ else if (!CC_begin(conn))
+ {
+ self->errormsg = "Could not begin a transaction";
+ self->errornumber = STMT_EXEC_ERROR;
+ SC_log_error(func, "", self);
+ return SQL_ERROR;
+ }
}
oldstatus = conn->status;
@@ -954,7 +947,7 @@ SC_execute(StatementClass *self)
if (self->statement_type == STMT_TYPE_SELECT)
{
char fetch[128];
- UDWORD qflag = (SQL_CONCUR_ROWVER == self->options.scroll_concurrency ? CREATE_KEYSET : 0);
+ qflag |= (SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency ? CREATE_KEYSET : 0);
mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name);
@@ -964,6 +957,7 @@ SC_execute(StatementClass *self)
QR_command_successful(res))
{
QR_Destructor(res);
+ qflag &= (~ GO_INTO_TRANSACTION);
/*
* That worked, so now send the fetch to start getting data
@@ -990,7 +984,7 @@ SC_execute(StatementClass *self)
{
/* not a SELECT statement so don't use a cursor */
mylog(" it's NOT a select statement: stmt=%u\n", self);
- res = CC_send_query(conn, self->stmt_with_params, NULL, 0);
+ res = CC_send_query(conn, self->stmt_with_params, NULL, qflag);
/*
* We shouldn't send COMMIT. Postgres backend does the autocommit
@@ -1037,8 +1031,9 @@ SC_execute(StatementClass *self)
/* now allocate the array to hold the binding info */
if (numcols > 0)
{
- extend_bindings(self, numcols);
- if (self->bindings == NULL)
+ ARDFields *opts = SC_get_ARD(self);
+ extend_column_bindings(opts, numcols);
+ if (opts->bindings == NULL)
{
QR_Destructor(res);
self->errornumber = STMT_NO_MEMORY_ERROR;
@@ -1083,12 +1078,13 @@ SC_execute(StatementClass *self)
last->next = res;
}
+ apdopts = SC_get_APD(self);
if (self->statement_type == STMT_TYPE_PROCCALL &&
(self->errornumber == STMT_OK ||
self->errornumber == STMT_INFO_ONLY) &&
- self->parameters &&
- self->parameters[0].buffer &&
- self->parameters[0].paramType == SQL_PARAM_OUTPUT)
+ apdopts->parameters &&
+ apdopts->parameters[0].buffer &&
+ apdopts->parameters[0].paramType == SQL_PARAM_OUTPUT)
{ /* get the return value of the procedure
* call */
RETCODE ret;
@@ -1097,7 +1093,7 @@ SC_execute(StatementClass *self)
ret = SC_fetch(hstmt);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
- ret = PGAPI_GetData(hstmt, 1, self->parameters[0].CType, self->parameters[0].buffer, self->parameters[0].buflen, self->parameters[0].used);
+ ret = PGAPI_GetData(hstmt, 1, apdopts->parameters[0].CType, apdopts->parameters[0].buffer, apdopts->parameters[0].buflen, apdopts->parameters[0].used);
if (ret != SQL_SUCCESS)
{
self->errornumber = STMT_EXEC_ERROR;
@@ -1133,19 +1129,21 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self)
if (self)
{
QResultClass *res = SC_get_Result(self);
+ const ARDFields *opts = SC_get_ARD(self);
+ const APDFields *apdopts = SC_get_APD(self);
qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
mylog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
qlog(" ------------------------------------------------------------\n");
qlog(" hdbc=%u, stmt=%u, result=%u\n", self->hdbc, self, res);
qlog(" manual_result=%d, prepare=%d, internal=%d\n", self->manual_result, self->prepare, self->internal);
- qlog(" bindings=%u, bindings_allocated=%d\n", self->bindings, self->bindings_allocated);
- qlog(" parameters=%u, parameters_allocated=%d\n", self->parameters, self->parameters_allocated);
+ qlog(" bindings=%u, bindings_allocated=%d\n", opts->bindings, opts->allocated);
+ qlog(" parameters=%u, parameters_allocated=%d\n", apdopts->parameters, apdopts->allocated);
qlog(" statement_type=%d, statement='%s'\n", self->statement_type, nullcheck(self->statement));
qlog(" stmt_with_params='%s'\n", nullcheck(self->stmt_with_params));
qlog(" data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data);
qlog(" currTuple=%d, current_col=%d, lobj_fd=%d\n", self->currTuple, self->current_col, self->lobj_fd);
- qlog(" maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, self->options.rowset_size, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
+ qlog(" maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, opts->rowset_size, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
qlog(" cursor_name='%s'\n", nullcheck(self->cursor_name));
qlog(" ----------------QResult Info -------------------------------\n");