aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interfaces/odbc/bind.c347
-rw-r--r--src/interfaces/odbc/bind.h5
-rw-r--r--src/interfaces/odbc/connection.c89
-rw-r--r--src/interfaces/odbc/connection.h6
-rw-r--r--src/interfaces/odbc/convert.c143
-rw-r--r--src/interfaces/odbc/descriptor.h96
-rw-r--r--src/interfaces/odbc/dlg_specific.c17
-rw-r--r--src/interfaces/odbc/dlg_specific.h4
-rw-r--r--src/interfaces/odbc/environ.c11
-rw-r--r--src/interfaces/odbc/execute.c98
-rw-r--r--src/interfaces/odbc/info.c203
-rw-r--r--src/interfaces/odbc/info30.c26
-rw-r--r--src/interfaces/odbc/misc.c5
-rw-r--r--src/interfaces/odbc/misc.h12
-rw-r--r--src/interfaces/odbc/multibyte.c6
-rw-r--r--src/interfaces/odbc/multibyte.h3
-rw-r--r--src/interfaces/odbc/odbcapi.c5
-rw-r--r--src/interfaces/odbc/odbcapi30.c267
-rw-r--r--src/interfaces/odbc/odbcapi30w.c62
-rw-r--r--src/interfaces/odbc/options.c18
-rw-r--r--src/interfaces/odbc/parse.c157
-rw-r--r--src/interfaces/odbc/pgapi30.c905
-rw-r--r--src/interfaces/odbc/pgapifunc.h3
-rw-r--r--src/interfaces/odbc/pgtypes.c246
-rw-r--r--src/interfaces/odbc/pgtypes.h14
-rw-r--r--src/interfaces/odbc/psqlodbc.h27
-rw-r--r--src/interfaces/odbc/psqlodbc.rc56
-rw-r--r--src/interfaces/odbc/psqlodbc30w.reg16
-rwxr-xr-xsrc/interfaces/odbc/psqlodbc_api30.def2
-rw-r--r--src/interfaces/odbc/psqlodbc_api30w.def3
-rw-r--r--src/interfaces/odbc/qresult.c107
-rw-r--r--src/interfaces/odbc/qresult.h5
-rw-r--r--src/interfaces/odbc/resource.h3
-rw-r--r--src/interfaces/odbc/results.c657
-rw-r--r--src/interfaces/odbc/setup.c4
-rw-r--r--src/interfaces/odbc/statement.c264
-rw-r--r--src/interfaces/odbc/statement.h54
-rw-r--r--src/interfaces/odbc/tuple.h19
-rw-r--r--src/interfaces/odbc/win32.mak4
-rw-r--r--src/interfaces/odbc/win32_30w.mak18
40 files changed, 2696 insertions, 1291 deletions
diff --git a/src/interfaces/odbc/bind.c b/src/interfaces/odbc/bind.c
index 4635706a866..397d984ec6c 100644
--- a/src/interfaces/odbc/bind.c
+++ b/src/interfaces/odbc/bind.c
@@ -17,6 +17,7 @@
#include "environ.h"
#include "statement.h"
+#include "descriptor.h"
#include "qresult.h"
#include "pgtypes.h"
#include <stdlib.h>
@@ -41,6 +42,7 @@ PGAPI_BindParameter(
{
StatementClass *stmt = (StatementClass *) hstmt;
static char *func = "PGAPI_BindParameter";
+ APDFields *opts;
mylog("%s: entering...\n", func);
@@ -51,103 +53,54 @@ PGAPI_BindParameter(
}
SC_clear_error(stmt);
- if (stmt->parameters_allocated < ipar)
- {
- ParameterInfoClass *old_parameters;
- int i,
- old_parameters_allocated;
-
- old_parameters = stmt->parameters;
- old_parameters_allocated = stmt->parameters_allocated;
-
- stmt->parameters = (ParameterInfoClass *) malloc(sizeof(ParameterInfoClass) * (ipar));
- if (!stmt->parameters)
- {
- stmt->errornumber = STMT_NO_MEMORY_ERROR;
- stmt->errormsg = "Could not allocate memory for statement parameters";
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
- }
-
- stmt->parameters_allocated = ipar;
-
- /* copy the old parameters over */
- for (i = 0; i < old_parameters_allocated; i++)
- {
- /* a structure copy should work */
- stmt->parameters[i] = old_parameters[i];
- }
-
- /* get rid of the old parameters, if there were any */
- if (old_parameters)
- free(old_parameters);
-
- /*
- * zero out the newly allocated parameters (in case they skipped
- * some,
- */
- /* so we don't accidentally try to use them later) */
- for (; i < stmt->parameters_allocated; i++)
- {
- stmt->parameters[i].buflen = 0;
- stmt->parameters[i].buffer = 0;
- stmt->parameters[i].used = 0;
- stmt->parameters[i].paramType = 0;
- stmt->parameters[i].CType = 0;
- stmt->parameters[i].SQLType = 0;
- stmt->parameters[i].precision = 0;
- stmt->parameters[i].scale = 0;
- stmt->parameters[i].data_at_exec = FALSE;
- stmt->parameters[i].lobj_oid = 0;
- stmt->parameters[i].EXEC_used = NULL;
- stmt->parameters[i].EXEC_buffer = NULL;
- }
- }
+ opts = SC_get_APD(stmt);
+ if (opts->allocated < ipar)
+ extend_parameter_bindings(opts, ipar);
/* use zero based column numbers for the below part */
ipar--;
/* store the given info */
- stmt->parameters[ipar].buflen = cbValueMax;
- stmt->parameters[ipar].buffer = rgbValue;
- stmt->parameters[ipar].used = pcbValue;
- stmt->parameters[ipar].paramType = fParamType;
- stmt->parameters[ipar].CType = fCType;
- stmt->parameters[ipar].SQLType = fSqlType;
- stmt->parameters[ipar].precision = cbColDef;
- stmt->parameters[ipar].scale = ibScale;
+ opts->parameters[ipar].buflen = cbValueMax;
+ opts->parameters[ipar].buffer = rgbValue;
+ opts->parameters[ipar].used = pcbValue;
+ opts->parameters[ipar].paramType = fParamType;
+ opts->parameters[ipar].CType = fCType;
+ opts->parameters[ipar].SQLType = fSqlType;
+ opts->parameters[ipar].precision = cbColDef;
+ opts->parameters[ipar].scale = ibScale;
/*
* If rebinding a parameter that had data-at-exec stuff in it, then
* free that stuff
*/
- if (stmt->parameters[ipar].EXEC_used)
+ if (opts->parameters[ipar].EXEC_used)
{
- free(stmt->parameters[ipar].EXEC_used);
- stmt->parameters[ipar].EXEC_used = NULL;
+ free(opts->parameters[ipar].EXEC_used);
+ opts->parameters[ipar].EXEC_used = NULL;
}
- if (stmt->parameters[ipar].EXEC_buffer)
+ if (opts->parameters[ipar].EXEC_buffer)
{
- if (stmt->parameters[ipar].SQLType != SQL_LONGVARBINARY)
- free(stmt->parameters[ipar].EXEC_buffer);
- stmt->parameters[ipar].EXEC_buffer = NULL;
+ if (opts->parameters[ipar].SQLType != SQL_LONGVARBINARY)
+ free(opts->parameters[ipar].EXEC_buffer);
+ opts->parameters[ipar].EXEC_buffer = NULL;
}
- if (pcbValue && stmt->options.param_offset_ptr)
- pcbValue += (*stmt->options.param_offset_ptr >> 2);
+ if (pcbValue && opts->param_offset_ptr)
+ pcbValue += (*opts->param_offset_ptr >> 2);
/* Data at exec macro only valid for C char/binary data */
if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC ||
*pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET))
- stmt->parameters[ipar].data_at_exec = TRUE;
+ opts->parameters[ipar].data_at_exec = TRUE;
else
- stmt->parameters[ipar].data_at_exec = FALSE;
+ opts->parameters[ipar].data_at_exec = FALSE;
/* Clear premature result */
if (stmt->status == STMT_PREMATURE)
SC_recycle_statement(stmt);
- mylog("PGAPI_BindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, stmt->parameters[ipar].data_at_exec);
+ mylog("PGAPI_BindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, opts->parameters[ipar].data_at_exec);
return SQL_SUCCESS;
}
@@ -165,6 +118,7 @@ PGAPI_BindCol(
{
StatementClass *stmt = (StatementClass *) hstmt;
static char *func = "PGAPI_BindCol";
+ ARDFields *opts;
mylog("%s: entering...\n", func);
@@ -178,8 +132,8 @@ PGAPI_BindCol(
}
- SC_clear_error(stmt);
+ opts = SC_get_ARD(stmt);
if (stmt->status == STMT_EXECUTING)
{
stmt->errormsg = "Can't bind columns while statement is still executing.";
@@ -188,13 +142,14 @@ PGAPI_BindCol(
return SQL_ERROR;
}
+ SC_clear_error(stmt);
/* If the bookmark column is being bound, then just save it */
if (icol == 0)
{
if (rgbValue == NULL)
{
- stmt->bookmark.buffer = NULL;
- stmt->bookmark.used = NULL;
+ opts->bookmark->buffer = NULL;
+ opts->bookmark->used = NULL;
}
else
{
@@ -215,8 +170,8 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
return SQL_ERROR;
}
- stmt->bookmark.buffer = rgbValue;
- stmt->bookmark.used = pcbValue;
+ opts->bookmark->buffer = rgbValue;
+ opts->bookmark->used = pcbValue;
}
return SQL_SUCCESS;
}
@@ -226,11 +181,11 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
* execution of a statement would have setup the necessary bindings.
* But some apps call BindCol before any statement is executed.
*/
- if (icol > stmt->bindings_allocated)
- extend_bindings(stmt, icol);
+ if (icol > opts->allocated)
+ extend_column_bindings(opts, icol);
/* check to see if the bindings were allocated */
- if (!stmt->bindings)
+ if (!opts->bindings)
{
stmt->errormsg = "Could not allocate memory for bindings.";
stmt->errornumber = STMT_NO_MEMORY_ERROR;
@@ -242,25 +197,29 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
icol--;
/* Reset for SQLGetData */
- stmt->bindings[icol].data_left = -1;
+ opts->bindings[icol].data_left = -1;
if (rgbValue == NULL)
{
/* we have to unbind the column */
- stmt->bindings[icol].buflen = 0;
- stmt->bindings[icol].buffer = NULL;
- stmt->bindings[icol].used = NULL;
- stmt->bindings[icol].returntype = SQL_C_CHAR;
+ opts->bindings[icol].buflen = 0;
+ opts->bindings[icol].buffer = NULL;
+ opts->bindings[icol].used = NULL;
+ opts->bindings[icol].returntype = SQL_C_CHAR;
+ if (opts->bindings[icol].ttlbuf)
+ free(opts->bindings[icol].ttlbuf);
+ opts->bindings[icol].ttlbuf = NULL;
+ opts->bindings[icol].ttlbuflen = 0;
}
else
{
/* ok, bind that column */
- stmt->bindings[icol].buflen = cbValueMax;
- stmt->bindings[icol].buffer = rgbValue;
- stmt->bindings[icol].used = pcbValue;
- stmt->bindings[icol].returntype = fCType;
+ opts->bindings[icol].buflen = cbValueMax;
+ opts->bindings[icol].buffer = rgbValue;
+ opts->bindings[icol].used = pcbValue;
+ opts->bindings[icol].returntype = fCType;
- mylog(" bound buffer[%d] = %u\n", icol, stmt->bindings[icol].buffer);
+ mylog(" bound buffer[%d] = %u\n", icol, opts->bindings[icol].buffer);
}
return SQL_SUCCESS;
@@ -286,6 +245,7 @@ PGAPI_DescribeParam(
{
StatementClass *stmt = (StatementClass *) hstmt;
static char *func = "PGAPI_DescribeParam";
+ APDFields *opts;
mylog("%s: entering...\n", func);
@@ -296,7 +256,8 @@ PGAPI_DescribeParam(
}
SC_clear_error(stmt);
- if ((ipar < 1) || (ipar > stmt->parameters_allocated))
+ opts = SC_get_APD(stmt);
+ if ((ipar < 1) || (ipar > opts->allocated))
{
stmt->errormsg = "Invalid parameter number for PGAPI_DescribeParam.";
stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR;
@@ -312,16 +273,16 @@ PGAPI_DescribeParam(
*/
/* parameter markers, not bound parameters. */
if (pfSqlType)
- *pfSqlType = stmt->parameters[ipar].SQLType;
+ *pfSqlType = opts->parameters[ipar].SQLType;
if (pcbColDef)
- *pcbColDef = stmt->parameters[ipar].precision;
+ *pcbColDef = opts->parameters[ipar].precision;
if (pibScale)
- *pibScale = stmt->parameters[ipar].scale;
+ *pibScale = opts->parameters[ipar].scale;
if (pfNullable)
- *pfNullable = pgtype_nullable(stmt, stmt->parameters[ipar].paramType);
+ *pfNullable = pgtype_nullable(stmt, opts->parameters[ipar].paramType);
return SQL_SUCCESS;
}
@@ -336,11 +297,13 @@ PGAPI_ParamOptions(
{
static char *func = "PGAPI_ParamOptions";
StatementClass *stmt = (StatementClass *) hstmt;
+ APDFields *opts;
mylog("%s: entering... %d %x\n", func, crow, pirow);
- stmt->options.paramset_size = crow;
- stmt->options.param_processed_ptr = (SQLUINTEGER *)pirow;
+ opts = SC_get_APD(stmt);
+ opts->paramset_size = crow;
+ SC_get_IPD(stmt)->param_processed_ptr = (UInt4 *) pirow;
return SQL_SUCCESS;
}
@@ -433,46 +396,156 @@ create_empty_bindings(int num_columns)
return new_bindings;
}
+void
+extend_parameter_bindings(APDFields *self, int num_params)
+{
+ static char *func = "extend_parameter_bindings";
+ ParameterInfoClass *new_bindings;
+
+ mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
+
+ /*
+ * if we have too few, allocate room for more, and copy the old
+ * entries into the new structure
+ */
+ if (self->allocated < num_params)
+ {
+ new_bindings = (ParameterInfoClass *) realloc(self->parameters, sizeof(ParameterInfoClass) * num_params);
+ if (!new_bindings)
+ {
+ mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_params, self->allocated);
+
+ self->parameters = NULL;
+ self->allocated = 0;
+ return;
+ }
+ memset(&new_bindings[self->allocated], 0,
+ sizeof(ParameterInfoClass) * (num_params - self->allocated));
+
+ self->parameters = new_bindings;
+ self->allocated = num_params;
+ }
+
+ mylog("exit extend_parameter_bindings\n");
+}
+
+void
+reset_a_parameter_binding(APDFields *self, int ipar)
+{
+ static char *func = "reset_a_parameter_binding";
+
+ mylog("%s: entering ... self=%u, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
+
+ if (ipar < 1 || ipar > self->allocated)
+ return;
+
+ ipar--;
+ self->parameters[ipar].buflen = 0;
+ self->parameters[ipar].buffer = 0;
+ self->parameters[ipar].used = 0;
+ self->parameters[ipar].paramType = 0;
+ self->parameters[ipar].CType = 0;
+ if (self->parameters[ipar].EXEC_used)
+ {
+ free(self->parameters[ipar].EXEC_used);
+ self->parameters[ipar].EXEC_used = NULL;
+ }
+
+ if (self->parameters[ipar].EXEC_buffer)
+ {
+ if (self->parameters[ipar].SQLType != SQL_LONGVARBINARY)
+ free(self->parameters[ipar].EXEC_buffer);
+ self->parameters[ipar].EXEC_buffer = NULL;
+ }
+ self->parameters[ipar].SQLType = 0;
+ self->parameters[ipar].precision = 0;
+ self->parameters[ipar].scale = 0;
+ self->parameters[ipar].data_at_exec = FALSE;
+ self->parameters[ipar].lobj_oid = 0;
+}
+
+/*
+ * Free parameters and free the memory.
+ */
+void
+APD_free_params(APDFields *self, char option)
+{
+ int i;
+
+ mylog("APD_free_params: ENTER, self=%d\n", self);
+
+ if (!self->parameters)
+ return;
+
+ for (i = 0; i < self->allocated; i++)
+ {
+ if (self->parameters[i].data_at_exec)
+ {
+ 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;
+ }
+ }
+ }
+
+ if (option == STMT_FREE_PARAMS_ALL)
+ {
+ if (self->parameters);
+ free(self->parameters);
+ self->parameters = NULL;
+ self->allocated = 0;
+ }
+
+ mylog("APD_free_params: EXIT\n");
+}
void
-extend_bindings(StatementClass *stmt, int num_columns)
+extend_column_bindings(ARDFields *self, int num_columns)
{
- static char *func = "extend_bindings";
+ static char *func = "extend_column_bindings";
BindInfoClass *new_bindings;
int i;
- mylog("%s: entering ... stmt=%u, bindings_allocated=%d, num_columns=%d\n", func, stmt, stmt->bindings_allocated, num_columns);
+ mylog("%s: entering ... self=%u, bindings_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns);
/*
* if we have too few, allocate room for more, and copy the old
* entries into the new structure
*/
- if (stmt->bindings_allocated < num_columns)
+ if (self->allocated < num_columns)
{
new_bindings = create_empty_bindings(num_columns);
if (!new_bindings)
{
- mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, stmt->bindings_allocated);
+ mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, self->allocated);
- if (stmt->bindings)
+ if (self->bindings)
{
- free(stmt->bindings);
- stmt->bindings = NULL;
+ free(self->bindings);
+ self->bindings = NULL;
}
- stmt->bindings_allocated = 0;
+ self->allocated = 0;
return;
}
- if (stmt->bindings)
+ if (self->bindings)
{
- for (i = 0; i < stmt->bindings_allocated; i++)
- new_bindings[i] = stmt->bindings[i];
+ for (i = 0; i < self->allocated; i++)
+ new_bindings[i] = self->bindings[i];
- free(stmt->bindings);
+ free(self->bindings);
}
- stmt->bindings = new_bindings;
- stmt->bindings_allocated = num_columns;
+ self->bindings = new_bindings;
+ self->allocated = num_columns;
}
/*
@@ -485,5 +558,53 @@ extend_bindings(StatementClass *stmt, int num_columns)
/* SQLExecDirect(...) # returns 5 cols */
/* SQLExecDirect(...) # returns 10 cols (now OK) */
- mylog("exit extend_bindings\n");
+ mylog("exit extend_column_bindings\n");
+}
+
+void
+reset_a_column_binding(ARDFields *self, int icol)
+{
+ static char *func = "reset_a_column_binding";
+
+ mylog("%s: entering ... self=%u, bindings_allocated=%d, icol=%d\n", func, self, self->allocated, icol);
+
+ if (icol > self->allocated)
+ return;
+
+ /* use zero based col numbers from here out */
+ if (0 == icol)
+ {
+ self->bookmark->buffer = NULL;
+ self->bookmark->used = NULL;
+ }
+ else
+ {
+ icol--;
+
+ /* we have to unbind the column */
+ self->bindings[icol].buflen = 0;
+ self->bindings[icol].buffer = NULL;
+ self->bindings[icol].used = NULL;
+ self->bindings[icol].data_left = -1;
+ self->bindings[icol].returntype = SQL_C_CHAR;
+ if (self->bindings[icol].ttlbuf)
+ free(self->bindings[icol].ttlbuf);
+ self->bindings[icol].ttlbuf = NULL;
+ self->bindings[icol].ttlbuflen = 0;
+ }
}
+
+void ARD_unbind_cols(ARDFields *self, BOOL freeall)
+{
+ Int2 lf;
+
+ for (lf = 1; lf <= self->allocated; lf++)
+ reset_a_column_binding(self, lf);
+ if (freeall)
+ {
+ if (self->bindings)
+ free(self->bindings);
+ self->bindings = NULL;
+ self->allocated = 0;
+ }
+}
diff --git a/src/interfaces/odbc/bind.h b/src/interfaces/odbc/bind.h
index 34b9e1d399b..16d9f84b6e6 100644
--- a/src/interfaces/odbc/bind.h
+++ b/src/interfaces/odbc/bind.h
@@ -50,6 +50,9 @@ struct ParameterInfoClass_
};
BindInfoClass *create_empty_bindings(int num_columns);
-void extend_bindings(StatementClass *stmt, int num_columns);
+void extend_column_bindings(ARDFields *opts, int num_columns);
+void reset_a_column_binding(ARDFields *opts, int icol);
+void extend_parameter_bindings(APDFields *opts, int num_columns);
+void reset_a_parameter_binding(APDFields *opts, int ipar);
#endif
diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c
index a26913db767..db237b3f952 100644
--- a/src/interfaces/odbc/connection.c
+++ b/src/interfaces/odbc/connection.c
@@ -298,8 +298,8 @@ CC_Constructor()
/* Statements under this conn will inherit these options */
InitializeStatementOptions(&rv->stmtOptions);
-
-
+ InitializeARDFields(&rv->ardOptions);
+ InitializeAPDFields(&rv->apdOptions);
}
return rv;
}
@@ -381,8 +381,6 @@ CC_begin(ConnectionClass *self)
{
ret = QR_command_successful(res);
QR_Destructor(res);
- if (ret)
- CC_set_in_trans(self);
}
else
return FALSE;
@@ -403,9 +401,6 @@ CC_commit(ConnectionClass *self)
{
QResultClass *res = CC_send_query(self, "COMMIT", NULL, CLEAR_RESULT_ON_ABORT);
mylog("CC_commit: sending COMMIT!\n");
-
- CC_set_no_trans(self);
-
if (res != NULL)
{
ret = QR_command_successful(res);
@@ -429,9 +424,6 @@ CC_abort(ConnectionClass *self)
{
QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, CLEAR_RESULT_ON_ABORT);
mylog("CC_abort: sending ABORT!\n");
-
- CC_set_no_trans(self);
-
if (res != NULL)
QR_Destructor(res);
else
@@ -1118,6 +1110,23 @@ CC_get_error(ConnectionClass *self, int *number, char **message)
}
+void CC_on_commit(ConnectionClass *conn, BOOL set_no_trans)
+{
+ if (CC_is_in_trans(conn))
+ {
+ if (set_no_trans)
+ CC_set_no_trans(conn);
+ }
+}
+void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans)
+{
+ if (CC_is_in_trans(conn))
+ {
+ if (set_no_trans)
+ CC_set_no_trans(conn);
+ }
+}
+
/*
* The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
* the same existing QResultClass (this occurs when the tuple cache is depleted and
@@ -1134,7 +1143,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
*retres = NULL,
*res = NULL;
BOOL clear_result_on_abort = ((flag & CLEAR_RESULT_ON_ABORT) != 0),
- create_keyset = ((flag & CREATE_KEYSET) != 0);
+ create_keyset = ((flag & CREATE_KEYSET) != 0),
+ issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self));
char swallow,
*wq;
int id;
@@ -1146,7 +1156,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
query_completed = FALSE,
before_64 = PG_VERSION_LT(self, 6.4),
aborted = FALSE,
- used_passed_result_object = FALSE;
+ used_passed_result_object = FALSE,
+ set_no_trans;
/* ERROR_MSG_LENGTH is suffcient */
static char msgbuffer[ERROR_MSG_LENGTH + 1];
@@ -1173,7 +1184,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
{
self->errornumber = CONNECTION_COULD_NOT_SEND;
self->errormsg = "Could not send Query to backend";
- CC_set_no_trans(self);
+ CC_on_abort(self, TRUE);
return NULL;
}
@@ -1182,10 +1193,12 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
{
self->errornumber = CONNECTION_COULD_NOT_SEND;
self->errormsg = "Could not send Query to backend";
- CC_set_no_trans(self);
+ CC_on_abort(self, TRUE);
return NULL;
}
+ if (issue_begin)
+ SOCK_put_n_char(sock, "begin;", 6);
SOCK_put_string(sock, query);
SOCK_flush_output(sock);
@@ -1193,7 +1206,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
{
self->errornumber = CONNECTION_COULD_NOT_SEND;
self->errormsg = "Could not send Query to backend";
- CC_set_no_trans(self);
+ CC_on_abort(self, TRUE);
return NULL;
}
@@ -1230,7 +1243,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
self->errormsg = "No response from the backend";
mylog("send_query: 'id' - %s\n", self->errormsg);
- CC_set_no_trans(self);
+ CC_on_abort(self, TRUE);
ReadyToReturn = TRUE;
retres = NULL;
break;
@@ -1254,7 +1267,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
self->errornumber = CONNECTION_NO_RESPONSE;
self->errormsg = "No response from backend while receiving a portal query command";
mylog("send_query: 'C' - %s\n", self->errormsg);
- CC_set_no_trans(self);
+ CC_on_abort(self, TRUE);
ReadyToReturn = TRUE;
retres = NULL;
}
@@ -1270,6 +1283,24 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
mylog("send_query: setting cmdbuffer = '%s'\n", cmdbuffer);
+ if (strnicmp(cmdbuffer, "BEGIN", 5) == 0)
+ {
+ CC_set_in_trans(self);
+ if (issue_begin)
+ {
+ issue_begin = FALSE;
+ continue;
+ }
+ }
+ else if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
+ CC_on_commit(self, TRUE);
+ else if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0)
+ CC_on_abort(self, TRUE);
+ else if (strnicmp(cmdbuffer, "END", 3) == 0)
+ CC_on_commit(self, TRUE);
+ else if (strnicmp(cmdbuffer, "ABORT", 5) == 0)
+ CC_on_abort(self, TRUE);
+
if (QR_command_successful(res))
QR_set_status(res, PGRES_COMMAND_OK);
QR_set_command(res, cmdbuffer);
@@ -1352,14 +1383,15 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
qlog("ERROR from backend during send_query: '%s'\n", msgbuffer);
/* We should report that an error occured. Zoltan */
-
+ set_no_trans = FALSE;
if (!strncmp(msgbuffer, "FATAL", 5))
{
self->errornumber = CONNECTION_SERVER_REPORTED_ERROR;
- CC_set_no_trans(self);
+ set_no_trans = TRUE;
}
else
self->errornumber = CONNECTION_SERVER_REPORTED_WARNING;
+ CC_on_abort(self, set_no_trans);
QR_set_status(res, PGRES_FATAL_ERROR);
QR_set_message(res, msgbuffer);
QR_set_aborted(res, TRUE);
@@ -1377,9 +1409,6 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
if (query_completed)
{
res->next = QR_Constructor();
- if (create_keyset)
- QR_set_haskeyset(res->next);
- mylog("send_query: 'T' no result_in: res = %u\n", res->next);
if (!res->next)
{
self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
@@ -1388,6 +1417,9 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
retres = NULL;
break;
}
+ if (create_keyset)
+ QR_set_haskeyset(res->next);
+ mylog("send_query: 'T' no result_in: res = %u\n", res->next);
res = res->next;
if (qi)
@@ -1448,7 +1480,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
default:
self->errornumber = CONNECTION_BACKEND_CRAZY;
self->errormsg = "Unexpected protocol character from backend (send_query)";
- CC_set_no_trans(self);
+ CC_on_abort(self, TRUE);
mylog("send_query: error - %s\n", self->errormsg);
ReadyToReturn = TRUE;
@@ -1536,7 +1568,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
{
self->errornumber = CONNECTION_COULD_NOT_SEND;
self->errormsg = "Could not send function to backend";
- CC_set_no_trans(self);
+ CC_on_abort(self, TRUE);
return FALSE;
}
@@ -1545,7 +1577,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
{
self->errornumber = CONNECTION_COULD_NOT_SEND;
self->errormsg = "Could not send function to backend";
- CC_set_no_trans(self);
+ CC_on_abort(self, TRUE);
return FALSE;
}
@@ -1594,6 +1626,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
case 'E':
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
self->errormsg = msgbuffer;
+ CC_on_abort(self, FALSE);
mylog("send_function(V): 'E' - %s\n", self->errormsg);
qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
@@ -1606,7 +1639,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
default:
self->errornumber = CONNECTION_BACKEND_CRAZY;
self->errormsg = "Unexpected protocol character from backend (send_function, args)";
- CC_set_no_trans(self);
+ CC_on_abort(self, TRUE);
mylog("send_function: error - %s\n", self->errormsg);
return FALSE;
@@ -1640,7 +1673,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
case 'E':
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
self->errormsg = msgbuffer;
-
+ CC_on_abort(self, FALSE);
mylog("send_function(G): 'E' - %s\n", self->errormsg);
qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
@@ -1661,7 +1694,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
default:
self->errornumber = CONNECTION_BACKEND_CRAZY;
self->errormsg = "Unexpected protocol character from backend (send_function, result)";
- CC_set_no_trans(self);
+ CC_on_abort(self, TRUE);
mylog("send_function: error - %s\n", self->errormsg);
return FALSE;
diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h
index ee19d27dcb7..67411edd67a 100644
--- a/src/interfaces/odbc/connection.h
+++ b/src/interfaces/odbc/connection.h
@@ -13,6 +13,7 @@
#include <stdlib.h>
#include <string.h>
+#include "descriptor.h"
typedef enum
@@ -242,6 +243,8 @@ struct ConnectionClass_
HENV henv; /* environment this connection was created
* on */
StatementOptions stmtOptions;
+ ARDFields ardOptions;
+ APDFields apdOptions;
char *errormsg;
int errornumber;
CONN_Status status;
@@ -315,8 +318,11 @@ void CC_lookup_pg_version(ConnectionClass *conn);
void CC_initialize_pg_version(ConnectionClass *conn);
void CC_log_error(const char *func, const char *desc, const ConnectionClass *self);
int CC_get_max_query_len(const ConnectionClass *self);
+void CC_on_commit(ConnectionClass *conn, BOOL set_no_trans);
+void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans);
/* CC_send_query_options */
#define CLEAR_RESULT_ON_ABORT 1L
#define CREATE_KEYSET (1L << 1) /* create keyset for updatable curosrs */
+#define GO_INTO_TRANSACTION (1L << 2) /* issue begin in advance */
#endif
diff --git a/src/interfaces/odbc/convert.c b/src/interfaces/odbc/convert.c
index 94cd26c918e..c0a2706ef61 100644
--- a/src/interfaces/odbc/convert.c
+++ b/src/interfaces/odbc/convert.c
@@ -107,7 +107,7 @@ char *mapFuncs[][2] = {
{"DAYNAME", "to_char($1, 'Day')" },
{"DAYOFMONTH", "cast(extract(day from $1) as integer)" },
{"DAYOFWEEK", "(cast(extract(dow from $1) as integer) + 1)" },
- {"DAYOFYEAR", "cast(extract(doy from $1) as integer)" },
+ {"DAYOFYEAR", "cast(extract(doy from $1) as integer)" },
{"HOUR", "cast(extract(hour from $1) as integer)" },
{"MINUTE", "cast(extract(minute from $1) as integer)" },
{"MONTH", "cast(extract(month from $1) as integer)" },
@@ -311,8 +311,9 @@ stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision)
int
copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col)
{
- BindInfoClass *bic = &(stmt->bindings[col]);
- UInt4 offset = stmt->options.row_offset_ptr ? *stmt->options.row_offset_ptr : 0;
+ ARDFields *opts = SC_get_ARD(stmt);
+ BindInfoClass *bic = &(opts->bindings[col]);
+ UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
return copy_and_convert_field(stmt, field_type, value, (Int2) bic->returntype, (PTR) (bic->buffer + offset),
(SDWORD) bic->buflen, (SDWORD *) (bic->used + (offset >> 2)));
@@ -325,6 +326,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue)
{
static char *func = "copy_and_convert_field";
+ ARDFields *opts = SC_get_ARD(stmt);
Int4 len = 0,
copy_len = 0;
SIMPLE_TIME st;
@@ -335,7 +337,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
char *rgbValueBindRow;
const char *ptr;
int bind_row = stmt->bind_row;
- int bind_size = stmt->options.bind_size;
+ int bind_size = opts->bind_size;
int result = COPY_OK;
BOOL changed, true_is_minus1 = FALSE;
const char *neut_str = value;
@@ -349,7 +351,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
if (stmt->current_col >= 0)
{
- pbic = &stmt->bindings[stmt->current_col];
+ pbic = &opts->bindings[stmt->current_col];
if (pbic->data_left == -2)
pbic->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be *
* needed for ADO ? */
@@ -404,7 +406,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
else
{
stmt->errornumber = STMT_RETURN_NULL_WITHOUT_INDICATOR;
- stmt->errormsg = "StrLen_or_IndPtr was a null pointer and NULL data was retrieved";
+ stmt->errormsg = "StrLen_or_IndPtr was a null pointer and NULL data was retrieved";
SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -651,7 +653,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
pbic->data_left = -1;
}
else
- pbic = &stmt->bindings[stmt->current_col];
+ pbic = &opts->bindings[stmt->current_col];
if (pbic->data_left < 0)
{
BOOL lf_conv = SC_get_conn(stmt)->connInfo.lf_conversion;
@@ -759,7 +761,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
if (cbValueMax < 2 * (SDWORD) ucount)
result = COPY_RESULT_TRUNCATED;
len = ucount * 2;
- free(str);
+ free(str);
}
else
{
@@ -923,6 +925,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
case SQL_C_ULONG:
len = 4;
+inolog("rgb=%x + %d, pcb=%x, set %s\n", rgbValue, bind_row * bind_size, pcbValue, neut_str);
if (bind_size > 0)
*(UDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(neut_str);
else
@@ -960,7 +963,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
pbic->data_left = -1;
}
else
- pbic = &stmt->bindings[stmt->current_col];
+ pbic = &opts->bindings[stmt->current_col];
if (!pbic->ttlbuf)
pbic->ttlbuflen = 0;
if (len = strlen(neut_str), len >= (int) pbic->ttlbuflen)
@@ -1026,7 +1029,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
*(SDWORD *) ((char *) pcbValue + pcbValueOffset) = len;
if (result == COPY_OK && stmt->current_col >= 0)
- stmt->bindings[stmt->current_col].data_left = 0;
+ opts->bindings[stmt->current_col].data_left = 0;
return result;
}
@@ -1283,16 +1286,14 @@ copy_statement_with_parameters(StatementClass *stmt)
char token_save[64];
int token_len;
BOOL prev_token_end;
- UInt4 offset = stmt->options.param_offset_ptr ? *stmt->options.param_offset_ptr : 0;
+ APDFields *opts = SC_get_APD(stmt);
+ UInt4 offset = opts->param_offset_ptr ? *opts->param_offset_ptr : 0;
UInt4 current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
BOOL lf_conv = ci->lf_conversion;
#ifdef MULTIBYTE
encoded_str encstr;
#endif /* MULTIBYTE */
-#ifdef DRIVER_CURSOR_IMPLEMENT
- BOOL search_from_pos = FALSE;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
Int4 from_pos = -1, where_pos = -1;
if (ci->disallow_premature)
@@ -1324,17 +1325,20 @@ copy_statement_with_parameters(StatementClass *stmt)
{
if (stmt->parse_status == STMT_PARSE_NONE)
parse_statement(stmt);
- if (stmt->parse_status != STMT_PARSE_COMPLETE)
+ /*if (stmt->parse_status != STMT_PARSE_COMPLETE)
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
- else if (!stmt->ti || stmt->ntab != 1)
+ else*/ if (!stmt->updatable)
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
else
{
- /** search_from_pos = TRUE; **/
from_pos = stmt->from_pos;
where_pos = stmt->where_pos;
}
}
+#else
+ stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
+ if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
+ stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;
#endif /* DRIVER_CURSOR_IMPLEMENT */
/* If the application hasn't set a cursor name, then generate one */
@@ -1433,8 +1437,7 @@ copy_statement_with_parameters(StatementClass *stmt)
*/
else if (oldchar == '{')
{
- char *begin = &old_statement[opos];
- const char *end;
+ const char *begin = &old_statement[opos], *end;
/* procedure calls */
if (stmt->statement_type == STMT_TYPE_PROCCALL)
@@ -1466,8 +1469,8 @@ copy_statement_with_parameters(StatementClass *stmt)
proc_no_param = FALSE;
continue;
}
- if (convert_escape(begin, stmt, &npos, &new_stsize, &end) !=
- CONVERT_ESCAPE_OK)
+ if (convert_escape(begin, stmt, &npos, &new_stsize, &end
+) != CONVERT_ESCAPE_OK)
{
stmt->errormsg = "ODBC escape convert error";
stmt->errornumber = STMT_EXEC_ERROR;
@@ -1522,15 +1525,6 @@ copy_statement_with_parameters(StatementClass *stmt)
memmove(new_statement, new_statement + declare_pos, npos - declare_pos);
npos -= declare_pos;
}
-#ifdef DRIVER_CURSOR_IMPLEMENT
- else if (search_from_pos && /* where's from clause */
- strnicmp(token_save, "from", 4) == 0)
- {
- search_from_pos = FALSE;
- npos -= 5;
- CVT_APPEND_STR(", CTID, OID from");
- }
-#endif /* DRIVER_CURSOR_IMPLEMENT */
}
if (token_len == 3)
{
@@ -1574,7 +1568,7 @@ copy_statement_with_parameters(StatementClass *stmt)
*/
param_number++;
- if (param_number >= stmt->parameters_allocated)
+ if (param_number >= opts->allocated)
{
if (stmt->pre_executing)
{
@@ -1590,34 +1584,34 @@ copy_statement_with_parameters(StatementClass *stmt)
}
/* Assign correct buffers based on data at exec param or not */
- if (stmt->parameters[param_number].data_at_exec)
+ if (opts->parameters[param_number].data_at_exec)
{
- used = stmt->parameters[param_number].EXEC_used ? *stmt->parameters[param_number].EXEC_used : SQL_NTS;
- buffer = stmt->parameters[param_number].EXEC_buffer;
+ used = opts->parameters[param_number].EXEC_used ? *opts->parameters[param_number].EXEC_used : SQL_NTS;
+ buffer = opts->parameters[param_number].EXEC_buffer;
}
else
{
- UInt4 bind_size = stmt->options.param_bind_type;
+ UInt4 bind_size = opts->param_bind_type;
UInt4 ctypelen;
- buffer = stmt->parameters[param_number].buffer + offset;
+ buffer = opts->parameters[param_number].buffer + offset;
if (current_row > 0)
{
if (bind_size > 0)
buffer += (bind_size * current_row);
- else if (ctypelen = ctype_length(stmt->parameters[param_number].CType), ctypelen > 0)
+ else if (ctypelen = ctype_length(opts->parameters[param_number].CType), ctypelen > 0)
buffer += current_row * ctypelen;
- else
- buffer += current_row * stmt->parameters[param_number].buflen;
+ else
+ buffer += current_row * opts->parameters[param_number].buflen;
}
- if (stmt->parameters[param_number].used)
+ if (opts->parameters[param_number].used)
{
UInt4 p_offset = offset;
if (bind_size > 0)
p_offset = offset + bind_size * current_row;
else
p_offset = offset + sizeof(SDWORD) * current_row;
- used = *(SDWORD *)((char *)stmt->parameters[param_number].used + p_offset);
+ used = *(SDWORD *)((char *)opts->parameters[param_number].used + p_offset);
}
else
used = SQL_NTS;
@@ -1649,8 +1643,8 @@ copy_statement_with_parameters(StatementClass *stmt)
}
}
- param_ctype = stmt->parameters[param_number].CType;
- param_sqltype = stmt->parameters[param_number].SQLType;
+ param_ctype = opts->parameters[param_number].CType;
+ param_sqltype = opts->parameters[param_number].SQLType;
mylog("copy_statement_with_params: from(fcType)=%d, to(fSqlType)=%d\n", param_ctype, param_sqltype);
@@ -1907,8 +1901,8 @@ copy_statement_with_parameters(StatementClass *stmt)
case SQL_LONGVARBINARY:
- if (stmt->parameters[param_number].data_at_exec)
- lobj_oid = stmt->parameters[param_number].lobj_oid;
+ if (opts->parameters[param_number].data_at_exec)
+ lobj_oid = opts->parameters[param_number].lobj_oid;
else
{
/* begin transaction if needed */
@@ -2048,13 +2042,14 @@ copy_statement_with_parameters(StatementClass *stmt)
}
#ifdef DRIVER_CURSOR_IMPLEMENT
- if (search_from_pos)
- stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
if (!stmt->load_statement && from_pos >=0)
{
stmt->load_statement = malloc(npos + 1);
memcpy(stmt->load_statement, new_statement, npos);
- stmt->load_statement[npos] = '\0';
+ if (stmt->load_statement[npos - 1] == ';')
+ stmt->load_statement[npos - 1] = '\0';
+ else
+ stmt->load_statement[npos] = '\0';
}
#endif /* DRIVER_CURSOR_IMPLEMENT */
if (prepare_dummy_cursor && SC_is_pre_executable(stmt))
@@ -2083,7 +2078,7 @@ mapFunction(const char *func, int param_count)
if (mapFuncs[i][0][0] == '%')
{
if (mapFuncs[i][0][1] - '0' == param_count &&
- !stricmp(mapFuncs[i][0] + 2, func))
+ !stricmp(mapFuncs[i][0] + 2, func))
return mapFuncs[i][1];
}
else if (!stricmp(mapFuncs[i][0], func))
@@ -2101,7 +2096,7 @@ static int processParameters(const ConnectionClass *conn, const char *value, cha
* inner_convert_escape()
* work with embedded escapes sequences
*/
-
+
static
int inner_convert_escape(const ConnectionClass *conn, const char *value,
char *result, UInt4 maxLen, const char **input_resume,
@@ -2114,7 +2109,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
const char *valptr;
UInt4 vlen, prtlen, input_consumed, param_consumed, extra_len;
Int4 param_pos[16][2];
-
+
valptr = value;
if (*valptr == '{') /* skip the first { */
valptr++;
@@ -2126,7 +2121,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
valptr++;
while ((*valptr != '\0') && isspace((unsigned char) *valptr))
valptr++;
-
+
if (end = my_strchr(conn, valptr, '}'), NULL == end)
{
mylog("%s couldn't find the ending }\n",func);
@@ -2138,7 +2133,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
valnts[vlen] = '\0';
*input_resume = valptr + vlen; /* resume from the last } */
mylog("%s: key='%s', val='%s'\n", func, key, valnts);
-
+
extra_len = 0;
if (isalnum(result[-1])) /* Avoid the concatenation of the function name with the previous word. Aceto */
{
@@ -2175,7 +2170,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
{
/* Literal; return the escape part as-is */
strncpy(result, valnts, maxLen);
- prtlen = vlen;
+ prtlen = vlen;
}
else if (strcmp(key, "fn") == 0)
{
@@ -2186,7 +2181,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
char *funcEnd = valnts;
char svchar;
const char *mapExpr;
-
+
params[sizeof(params)-1] = '\0';
while ((*funcEnd != '\0') && (*funcEnd != '(') &&
@@ -2200,7 +2195,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
funcEnd++;
/*
- * We expect left parenthesis here, else return fn body as-is
+ * We expect left parenthesis here, else return fn body as-is
* since it is one of those "function constants".
*/
if (*funcEnd != '(')
@@ -2216,7 +2211,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
*/
valptr += (UInt4)(funcEnd - valnts);
- if (subret = processParameters(conn, valptr, params, sizeof(params) - 1, &input_consumed, &param_consumed, param_pos), CONVERT_ESCAPE_OK != subret)
+ if (subret = processParameters(conn, valptr, params, sizeof(params) - 1, &input_consumed, &param_consumed, param_pos), CONVERT_ESCAPE_OK != subret)
return CONVERT_ESCAPE_ERROR;
for (param_count = 0;; param_count++)
@@ -2225,9 +2220,9 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
break;
}
if (param_count == 1 &&
- param_pos[0][1] < param_pos[0][0])
+ param_pos[0][1] < param_pos[0][0])
param_count = 0;
-
+
mapExpr = mapFunction(key, param_count);
if (mapExpr == NULL)
prtlen = snprintf(result, maxLen, "%s%s", key, params);
@@ -2259,7 +2254,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
{
pidx = *mapptr - '0' - 1;
if (pidx < 0 ||
- param_pos[pidx][0] <0)
+ param_pos[pidx][0] < 0)
{
qlog("%s %dth param not found for the expression %s\n", pidx + 1, mapExpr);
return CONVERT_ESCAPE_ERROR;
@@ -2294,7 +2289,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
/* Bogus key, leave untranslated */
return CONVERT_ESCAPE_ERROR;
}
-
+
if (count)
*count = prtlen + extra_len;
if (prtlen < 0 || prtlen >= maxLen) /* buffer overflow */
@@ -2304,12 +2299,12 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
}
return CONVERT_ESCAPE_OK;
}
-
+
/*
* processParameters()
* Process function parameters and work with embedded escapes sequences.
*/
-
+
static
int processParameters(const ConnectionClass *conn, const char *value,
char *result, UInt4 maxLen, UInt4 *input_consumed,
@@ -2324,7 +2319,7 @@ int processParameters(const ConnectionClass *conn, const char *value,
#ifdef MULTIBYTE
encoded_str encstr;
#endif /* MULTIBYTE */
-
+
buf[sizeof(buf)-1] = '\0';
innerParenthesis = 0;
in_quote = in_dquote = in_escape = leadingSpace = FALSE;
@@ -2403,7 +2398,7 @@ int processParameters(const ConnectionClass *conn, const char *value,
}
innerParenthesis++;
break;
-
+
case ')':
innerParenthesis--;
if (0 == innerParenthesis)
@@ -2414,18 +2409,18 @@ int processParameters(const ConnectionClass *conn, const char *value,
param_pos[param_count][1] = -1;
}
break;
-
+
case '}':
stop = TRUE;
break;
-
+
case '{':
if (subret = inner_convert_escape(conn, valptr, buf, sizeof(buf) - 1, &valptr, &inner_count), CONVERT_ESCAPE_OK != subret)
return CONVERT_ESCAPE_ERROR;
-
+
if (inner_count + count >= maxLen)
return CONVERT_ESCAPE_OVERFLOW;
- memcpy(&result[count], buf, inner_count);
+ memcpy(&result[count], buf, inner_count);
count += inner_count;
ipos = (UInt4) (valptr - value);
continue;
@@ -2445,15 +2440,14 @@ int processParameters(const ConnectionClass *conn, const char *value,
*output_count = count;
return CONVERT_ESCAPE_OK;
}
-
+
/*
* convert_escape()
* This function returns a pointer to static memory!
*/
-
+
int
-convert_escape(const char *value, StatementClass *stmt, int *npos, int *stsize,
- const char **val_resume)
+convert_escape(const char *value, StatementClass *stmt, int *npos, int *stsize, const char **val_resume)
{
int ret, pos = *npos;
UInt4 count;
@@ -2920,12 +2914,13 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
BindInfoClass *bindInfo = NULL;
ConnectionClass *conn = SC_get_conn(stmt);
ConnInfo *ci = &(conn->connInfo);
+ ARDFields *opts = SC_get_ARD(stmt);
int factor = (fCType == SQL_C_CHAR ? 2 : 1);
/* If using SQLGetData, then current_col will be set */
if (stmt->current_col >= 0)
{
- bindInfo = &stmt->bindings[stmt->current_col];
+ bindInfo = &opts->bindings[stmt->current_col];
left = bindInfo->data_left;
}
diff --git a/src/interfaces/odbc/descriptor.h b/src/interfaces/odbc/descriptor.h
new file mode 100644
index 00000000000..58036914ada
--- /dev/null
+++ b/src/interfaces/odbc/descriptor.h
@@ -0,0 +1,96 @@
+/* File: descriptor.h
+ *
+ * Description: This file contains defines and declarations that are related to
+ * the entire driver.
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *
+ * $Id: descriptor.h,v 1.1 2002/03/28 08:08:02 inoue Exp $
+ *
+ */
+
+#ifndef __DESCRIPTOR_H__
+#define __DESCRIPTOR_H__
+
+#include "psqlodbc.h"
+
+typedef struct
+{
+ COL_INFO *col_info; /* cached SQLColumns info for this table */
+ char name[MAX_TABLE_LEN + 1];
+ char alias[MAX_TABLE_LEN + 1];
+} TABLE_INFO;
+
+typedef struct
+{
+ TABLE_INFO *ti; /* resolve to explicit table names */
+ int column_size; /* precision in 2.x */
+ int decimal_digits; /* scale in 2.x */
+ int display_size;
+ int length;
+ int type;
+ char nullable;
+ char func;
+ char expr;
+ char quote;
+ char dquote;
+ char numeric;
+ char updatable;
+ char dot[MAX_TABLE_LEN + 1];
+ char name[MAX_COLUMN_LEN + 1];
+ char alias[MAX_COLUMN_LEN + 1];
+} FIELD_INFO;
+
+struct ARDFields_
+{
+ StatementClass *stmt;
+ int rowset_size;
+ int bind_size; /* size of each structure if using Row
+ * Binding */
+ UInt2 *row_operation_ptr;
+ UInt4 *row_offset_ptr;
+ BindInfoClass *bookmark;
+ BindInfoClass *bindings;
+ int allocated;
+};
+
+struct APDFields_
+{
+ StatementClass *stmt;
+ int paramset_size;
+ int param_bind_type; /* size of each structure if using Param
+ * Binding */
+ UInt2 *param_operation_ptr;
+ UInt4 *param_offset_ptr;
+ ParameterInfoClass *parameters;
+ int allocated;
+};
+
+struct IRDFields_
+{
+ StatementClass *stmt;
+ UInt4 *rowsFetched;
+ UInt2 *rowStatusArray;
+ UInt4 nfields;
+ FIELD_INFO **fi;
+};
+
+struct IPDFields_
+{
+ StatementClass *stmt;
+ UInt4 *param_processed_ptr;
+ UInt2 *param_status_ptr;
+};
+
+void InitializeARDFields(ARDFields *self);
+void InitializeAPDFields(APDFields *self);
+/* void InitializeIRDFields(IRDFields *self);
+void InitializeIPDFiedls(IPDFields *self); */
+void ARDFields_free(ARDFields *self);
+void APDFields_free(APDFields *self);
+void IRDFields_free(IRDFields *self);
+void IPDFields_free(IPDFields *self);
+void ARD_unbind_cols(ARDFields *self, BOOL freeall);
+void APD_free_params(APDFields *self, char option);
+
+#endif
diff --git a/src/interfaces/odbc/dlg_specific.c b/src/interfaces/odbc/dlg_specific.c
index a95c67634c0..a4423e43b41 100644
--- a/src/interfaces/odbc/dlg_specific.c
+++ b/src/interfaces/odbc/dlg_specific.c
@@ -120,6 +120,9 @@ driver_optionsDraw(HWND hdlg, const ConnInfo *ci, int src, BOOL enable)
}
CheckDlgButton(hdlg, DRV_COMMLOG, comval->commlog);
+#ifndef Q_LOG
+ EnableWindow(GetDlgItem(hdlg, DRV_COMMLOG), FALSE);
+#endif /* Q_LOG */
CheckDlgButton(hdlg, DRV_OPTIMIZER, comval->disable_optimizer);
CheckDlgButton(hdlg, DRV_KSQO, comval->ksqo);
CheckDlgButton(hdlg, DRV_UNIQUEINDEX, comval->unique_index);
@@ -153,6 +156,9 @@ driver_optionsDraw(HWND hdlg, const ConnInfo *ci, int src, BOOL enable)
CheckDlgButton(hdlg, DRV_PARSE, comval->parse);
CheckDlgButton(hdlg, DRV_CANCELASFREESTMT, comval->cancel_as_freestmt);
CheckDlgButton(hdlg, DRV_DEBUG, comval->debug);
+#ifndef MY_LOG
+ EnableWindow(GetDlgItem(hdlg, DRV_DEBUG), FALSE);
+#endif /* MY_LOG */
SetDlgItemInt(hdlg, DRV_CACHE_SIZE, comval->fetch_max, FALSE);
SetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, comval->max_varchar_size, FALSE);
SetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, comval->max_longvarchar_size, TRUE);
@@ -221,7 +227,7 @@ driver_options_update(HWND hdlg, ConnInfo *ci, BOOL updateProfile)
int CALLBACK
driver_optionsProc(HWND hdlg,
- WORD wMsg,
+ UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
@@ -293,7 +299,7 @@ driver_optionsProc(HWND hdlg,
int CALLBACK
ds_optionsProc(HWND hdlg,
- WORD wMsg,
+ UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
@@ -334,6 +340,10 @@ ds_optionsProc(HWND hdlg,
CheckDlgButton(hdlg, DS_DISALLOWPREMATURE, ci->disallow_premature);
CheckDlgButton(hdlg, DS_LFCONVERSION, ci->lf_conversion);
CheckDlgButton(hdlg, DS_TRUEISMINUS1, ci->true_is_minus1);
+ CheckDlgButton(hdlg, DS_UPDATABLECURSORS, ci->updatable_cursors);
+#ifndef DRIVER_CURSOR_IMPLEMENT
+ EnableWindow(GetDlgItem(hdlg, DS_UPDATABLECURSORS), FALSE);
+#endif /* DRIVER_CURSOR_IMPLEMENT */
EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), atoi(ci->show_oid_column));
@@ -371,6 +381,9 @@ ds_optionsProc(HWND hdlg,
ci->disallow_premature = IsDlgButtonChecked(hdlg, DS_DISALLOWPREMATURE);
ci->lf_conversion = IsDlgButtonChecked(hdlg, DS_LFCONVERSION);
ci->true_is_minus1 = IsDlgButtonChecked(hdlg, DS_TRUEISMINUS1);
+#ifdef DRIVER_CURSOR_IMPLEMENT
+ ci->updatable_cursors = IsDlgButtonChecked(hdlg, DS_UPDATABLECURSORS);
+#endif /* DRIVER_CURSOR_IMPLEMENT */
/* OID Options */
sprintf(ci->fake_oid_index, "%d", IsDlgButtonChecked(hdlg, DS_FAKEOIDINDEX));
diff --git a/src/interfaces/odbc/dlg_specific.h b/src/interfaces/odbc/dlg_specific.h
index f293079d35f..98ecac0bbcf 100644
--- a/src/interfaces/odbc/dlg_specific.h
+++ b/src/interfaces/odbc/dlg_specific.h
@@ -169,11 +169,11 @@ void SetDlgStuff(HWND hdlg, const ConnInfo *ci);
void GetDlgStuff(HWND hdlg, ConnInfo *ci);
int CALLBACK driver_optionsProc(HWND hdlg,
- WORD wMsg,
+ UINT wMsg,
WPARAM wParam,
LPARAM lParam);
int CALLBACK ds_optionsProc(HWND hdlg,
- WORD wMsg,
+ UINT wMsg,
WPARAM wParam,
LPARAM lParam);
#endif /* WIN32 */
diff --git a/src/interfaces/odbc/environ.c b/src/interfaces/odbc/environ.c
index 618c5ef003b..4fdfe74c9d4 100644
--- a/src/interfaces/odbc/environ.c
+++ b/src/interfaces/odbc/environ.c
@@ -94,7 +94,7 @@ PGAPI_StmtError( HSTMT hstmt,
StatementClass *stmt = (StatementClass *) hstmt;
char *msg;
int status;
- BOOL partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
+ BOOL partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
SWORD msglen, stapos, wrtlen, pcblen;
@@ -275,6 +275,9 @@ PGAPI_StmtError( HSTMT hstmt,
case STMT_OPERATION_INVALID:
strcpy(szSqlState, "S1011");
break;
+ case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
+ strcpy(szSqlState, "HY091");
+ break;
case STMT_INVALID_OPTION_IDENTIFIER:
strcpy(szSqlState, "HY092");
break;
@@ -313,6 +316,7 @@ PGAPI_ConnectError( HDBC hdbc,
BOOL once_again = FALSE;
SWORD msglen;
+ mylog("**** PGAPI_ConnectError: hdbc=%u <%d>\n", hdbc, cbErrorMsgMax);
if (RecNumber != 1)
return SQL_NO_DATA_FOUND;
if (cbErrorMsgMax < 0)
@@ -361,6 +365,7 @@ PGAPI_ConnectError( HDBC hdbc,
strcpy(szSqlState, "IM002");
/* data source not found */
break;
+ case CONNECTION_SERVER_NOT_REACHED:
case CONN_OPENDB_ERROR:
strcpy(szSqlState, "08001");
/* unable to connect to data source */
@@ -413,6 +418,7 @@ PGAPI_ConnectError( HDBC hdbc,
break;
}
+ mylog(" szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, msglen, szErrorMsg);
if (once_again)
{
conn->errornumber = status;
@@ -436,6 +442,7 @@ PGAPI_EnvError( HENV henv,
char *msg;
int status;
+ mylog("**** PGAPI_EnvError: henv=%u <%d>\n", henv, cbErrorMsgMax);
if (RecNumber != 1)
return SQL_NO_DATA_FOUND;
if (cbErrorMsgMax < 0)
@@ -567,7 +574,7 @@ EN_Destructor(EnvironmentClass *self)
mylog("exit EN_Destructor: rv = %d\n", rv);
#ifdef _MEMORY_DEBUG_
- debug_memory_inouecheck();
+ debug_memory_check();
#endif /* _MEMORY_DEBUG_ */
return rv;
}
diff --git a/src/interfaces/odbc/execute.c b/src/interfaces/odbc/execute.c
index 8f05024f454..11893321f84 100644
--- a/src/interfaces/odbc/execute.c
+++ b/src/interfaces/odbc/execute.c
@@ -206,9 +206,12 @@ PGAPI_Execute(
{
static char *func = "PGAPI_Execute";
StatementClass *stmt = (StatementClass *) hstmt;
+ APDFields *opts;
+ IPDFields *ipdopts;
ConnectionClass *conn;
int i,
retval, start_row, end_row;
+ int cursor_type, scroll_concurrency;
mylog("%s: entering...\n", func);
@@ -219,6 +222,9 @@ PGAPI_Execute(
return SQL_INVALID_HANDLE;
}
+ opts = SC_get_APD(stmt);
+ cursor_type = stmt->options.cursor_type;
+ scroll_concurrency = stmt->options.scroll_concurrency;
/*
* If the statement is premature, it means we already executed it from
* an SQLPrepare/SQLDescribeCol type of scenario. So just return
@@ -297,24 +303,25 @@ PGAPI_Execute(
if (start_row = stmt->exec_start_row, start_row < 0)
start_row = 0;
if (end_row = stmt->exec_end_row, end_row < 0)
- end_row = stmt->options.paramset_size - 1;
+ end_row = opts->paramset_size - 1;
if (stmt->exec_current_row < 0)
stmt->exec_current_row = start_row;
+ ipdopts = SC_get_IPD(stmt);
if (stmt->exec_current_row == start_row)
{
- if (stmt->options.param_processed_ptr)
- *stmt->options.param_processed_ptr = 0;
+ if (ipdopts->param_processed_ptr)
+ *ipdopts->param_processed_ptr = 0;
SC_recycle_statement(stmt);
}
next_param_row:
#if (ODBCVER >= 0x0300)
- if (stmt->options.param_operation_ptr)
+ if (opts->param_operation_ptr)
{
- while (stmt->options.param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE)
+ while (opts->param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE)
{
- if (stmt->options.param_status_ptr)
- stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_UNUSED;
+ if (ipdopts->param_status_ptr)
+ ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_UNUSED;
if (stmt->exec_current_row >= end_row)
{
stmt->exec_current_row = -1;
@@ -335,16 +342,16 @@ next_param_row:
* execute of this statement? Therefore check for params and
* re-copy.
*/
- UInt4 offset = stmt->options.param_offset_ptr ? *stmt->options.param_offset_ptr : 0;
- Int4 bind_size = stmt->options.param_bind_type;
+ UInt4 offset = opts->param_offset_ptr ? *opts->param_offset_ptr : 0;
+ Int4 bind_size = opts->param_bind_type;
Int4 current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
stmt->data_at_exec = -1;
- for (i = 0; i < stmt->parameters_allocated; i++)
+ for (i = 0; i < opts->allocated; i++)
{
- Int4 *pcVal = stmt->parameters[i].used;
+ Int4 *pcVal = opts->parameters[i].used;
- stmt->parameters[i].data_at_exec = FALSE;
+ opts->parameters[i].data_at_exec = FALSE;
if (pcVal)
{
if (bind_size > 0)
@@ -352,10 +359,10 @@ next_param_row:
else
pcVal = (Int4 *)((char *)pcVal + offset + sizeof(SDWORD) * current_row);
if (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET)
- stmt->parameters[i].data_at_exec = TRUE;
+ opts->parameters[i].data_at_exec = TRUE;
}
/* Check for data at execution parameters */
- if (stmt->parameters[i].data_at_exec)
+ if (opts->parameters[i].data_at_exec)
{
if (stmt->data_at_exec < 0)
stmt->data_at_exec = 1;
@@ -394,22 +401,22 @@ next_param_row:
retval = SC_execute(stmt);
if (retval != SQL_ERROR)
{
- if (stmt->options.param_processed_ptr)
- (*stmt->options.param_processed_ptr)++;
+ if (ipdopts->param_processed_ptr)
+ (*ipdopts->param_processed_ptr)++;
}
#if (ODBCVER >= 0x0300)
- if (stmt->options.param_status_ptr)
+ if (ipdopts->param_status_ptr)
{
switch (retval)
{
case SQL_SUCCESS:
- stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
+ ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
break;
case SQL_SUCCESS_WITH_INFO:
- stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
+ ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
break;
default:
- stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
+ ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
break;
}
}
@@ -447,7 +454,6 @@ next_param_row:
}
}
/* we are now in a transaction */
- CC_set_in_trans(conn);
res = CC_send_query(conn, stmt->stmt_with_params, NULL, CLEAR_RESULT_ON_ABORT);
if (!res)
{
@@ -464,13 +470,18 @@ next_param_row:
{
if (issued_begin)
CC_commit(conn);
- else if (!in_trans && begin_included)
- CC_set_no_trans(conn);
}
stmt->status = STMT_FINISHED;
return SQL_SUCCESS;
}
- else
+ else if (stmt->options.cursor_type != cursor_type ||
+ stmt->options.scroll_concurrency != scroll_concurrency)
+ {
+ stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
+ stmt->errormsg = "cursor updatability changed";
+ return SQL_SUCCESS_WITH_INFO;
+ }
+ else
return SQL_SUCCESS;
}
@@ -534,11 +545,10 @@ PGAPI_Transact(
mylog("PGAPI_Transact: sending on conn %d '%s'\n", conn, stmt_string);
res = CC_send_query(conn, stmt_string, NULL, CLEAR_RESULT_ON_ABORT);
- CC_set_no_trans(conn);
-
if (!res)
{
/* error msg will be in the connection */
+ CC_on_abort(conn, TRUE);
CC_log_error(func, "", conn);
return SQL_ERROR;
}
@@ -548,6 +558,7 @@ PGAPI_Transact(
if (!ok)
{
+ CC_on_abort(conn, TRUE);
CC_log_error(func, "", conn);
return SQL_ERROR;
}
@@ -697,6 +708,8 @@ PGAPI_ParamData(
{
static char *func = "PGAPI_ParamData";
StatementClass *stmt = (StatementClass *) hstmt;
+ APDFields *opts;
+ IPDFields *ipdopts;
int i,
retval;
ConnInfo *ci;
@@ -709,8 +722,9 @@ PGAPI_ParamData(
return SQL_INVALID_HANDLE;
}
ci = &(SC_get_conn(stmt)->connInfo);
+ opts = SC_get_APD(stmt);
- mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, stmt->data_at_exec, stmt->parameters_allocated);
+ mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, stmt->data_at_exec, opts->allocated);
if (stmt->data_at_exec < 0)
{
@@ -720,7 +734,7 @@ PGAPI_ParamData(
return SQL_ERROR;
}
- if (stmt->data_at_exec > stmt->parameters_allocated)
+ if (stmt->data_at_exec > opts->allocated)
{
stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "Too many execution-time parameters were present";
@@ -748,6 +762,7 @@ PGAPI_ParamData(
}
/* Done, now copy the params and then execute the statement */
+ ipdopts = SC_get_IPD(stmt);
if (stmt->data_at_exec == 0)
{
int end_row;
@@ -761,28 +776,29 @@ PGAPI_ParamData(
retval = SC_execute(stmt);
if (retval != SQL_ERROR)
{
- if (stmt->options.param_processed_ptr)
- (*stmt->options.param_processed_ptr)++;
+ if (ipdopts->param_processed_ptr)
+ (*ipdopts->param_processed_ptr)++;
}
#if (ODBCVER >= 0x0300)
- if (stmt->options.param_status_ptr)
+ if (ipdopts->param_status_ptr)
{
switch (retval)
{
case SQL_SUCCESS:
- stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
+ ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
break;
case SQL_SUCCESS_WITH_INFO:
- stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
+ ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
break;
default:
- stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
+ ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
break;
}
}
#endif /* ODBCVER */
- if (stmt->exec_end_row < 0)
- end_row = stmt->options.paramset_size - 1;
+ end_row = stmt->exec_end_row;
+ if (end_row < 0)
+ end_row = opts->paramset_size - 1;
if (retval == SQL_ERROR ||
stmt->exec_current_row >= end_row)
{
@@ -800,14 +816,14 @@ PGAPI_ParamData(
i = stmt->current_exec_param >= 0 ? stmt->current_exec_param + 1 : 0;
/* At least 1 data at execution parameter, so Fill in the token value */
- for (; i < stmt->parameters_allocated; i++)
+ for (; i < opts->allocated; i++)
{
- if (stmt->parameters[i].data_at_exec)
+ if (opts->parameters[i].data_at_exec)
{
stmt->data_at_exec--;
stmt->current_exec_param = i;
stmt->put_data = FALSE;
- *prgbValue = stmt->parameters[i].buffer; /* token */
+ *prgbValue = opts->parameters[i].buffer; /* token */
break;
}
}
@@ -828,6 +844,7 @@ PGAPI_PutData(
{
static char *func = "PGAPI_PutData";
StatementClass *stmt = (StatementClass *) hstmt;
+ APDFields *opts;
int old_pos,
retval;
ParameterInfoClass *current_param;
@@ -841,6 +858,7 @@ PGAPI_PutData(
return SQL_INVALID_HANDLE;
}
+ opts = SC_get_APD(stmt);
if (stmt->current_exec_param < 0)
{
stmt->errornumber = STMT_SEQUENCE_ERROR;
@@ -849,7 +867,7 @@ PGAPI_PutData(
return SQL_ERROR;
}
- current_param = &(stmt->parameters[stmt->current_exec_param]);
+ current_param = &(opts->parameters[stmt->current_exec_param]);
if (!stmt->put_data)
{ /* first call */
diff --git a/src/interfaces/odbc/info.c b/src/interfaces/odbc/info.c
index 99b1420ed2f..a2aba6cf1ef 100644
--- a/src/interfaces/odbc/info.c
+++ b/src/interfaces/odbc/info.c
@@ -107,7 +107,7 @@ PGAPI_GetInfo(
case SQL_BOOKMARK_PERSISTENCE: /* ODBC 2.0 */
/* very simple bookmark support */
len = 4;
- value = ci->drivers.use_declarefetch ? 0 : (SQL_BP_SCROLL);
+ value = ci->drivers.use_declarefetch ? 0 : (SQL_BP_SCROLL | SQL_BP_DELETE | SQL_BP_UPDATE | SQL_BP_TRANSACTION);
break;
case SQL_COLUMN_ALIAS: /* ODBC 2.0 */
@@ -495,8 +495,10 @@ PGAPI_GetInfo(
case SQL_POS_OPERATIONS: /* ODBC 2.0 */
len = 4;
value = ci->drivers.lie ? (SQL_POS_POSITION | SQL_POS_REFRESH | SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD) : (SQL_POS_POSITION | SQL_POS_REFRESH);
+#ifdef DRIVER_CURSOR_IMPLEMENT
if (ci->updatable_cursors)
value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD);
+#endif /* DRIVER_CURSOR_IMPLEMENT */
break;
case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */
@@ -554,8 +556,10 @@ PGAPI_GetInfo(
SQL_SCCO_OPT_ROWVER |
SQL_SCCO_OPT_VALUES) :
(SQL_SCCO_READ_ONLY);
+#ifdef DRIVER_CURSOR_IMPLEMENT
if (ci->updatable_cursors)
value |= SQL_SCCO_OPT_ROWVER;
+#endif /* DRIVER_CURSOR_IMPLEMENT */
break;
case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */
@@ -588,8 +592,10 @@ PGAPI_GetInfo(
case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */
len = 4;
value = ci->drivers.lie ? (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES) : 0;
+#ifdef DRIVER_CURSOR_IMPLEMENT
if (ci->updatable_cursors)
value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES);
+#endif /* DRIVER_CURSOR_IMPLEMENT */
break;
case SQL_STRING_FUNCTIONS: /* ODBC 1.0 */
@@ -753,7 +759,11 @@ PGAPI_GetTypeInfo(
}
SC_set_Result(stmt, res);
- extend_bindings(stmt, 15);
+#if (ODBCVER >= 0x0399)
+ extend_column_bindings(SC_get_ARD(stmt), 19);
+#else
+ extend_column_bindings(SC_get_ARD(stmt), 15);
+#endif /* ODBCVER */
QR_set_num_fields(res, 15);
QR_set_field_info(res, 0, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
@@ -771,6 +781,12 @@ PGAPI_GetTypeInfo(
QR_set_field_info(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
QR_set_field_info(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
QR_set_field_info(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
+#if (ODBCVER >=0x0399)
+ QR_set_field_info(res, 15, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
+ QR_set_field_info(res, 16, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2);
+ QR_set_field_info(res, 17, "NUM_PREC_RADIX", PG_TYPE_INT4, 4);
+ QR_set_field_info(res, 18, "INTERVAL_PRECISION", PG_TYPE_INT2, 2);
+#endif /* ODBCVER */
for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
{
@@ -795,7 +811,7 @@ PGAPI_GetTypeInfo(
set_tuplefield_null(&row->tuple[12]);
/* These values can be NULL */
- set_nullfield_int4(&row->tuple[2], pgtype_precision(stmt, pgType, PG_STATIC, PG_STATIC));
+ set_nullfield_int4(&row->tuple[2], pgtype_column_size(stmt, pgType, PG_STATIC, PG_STATIC));
set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(stmt, pgType));
set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(stmt, pgType));
set_nullfield_string(&row->tuple[5], pgtype_create_params(stmt, pgType));
@@ -803,6 +819,12 @@ PGAPI_GetTypeInfo(
set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(stmt, pgType));
set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, pgType, PG_STATIC));
set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, pgType, PG_STATIC));
+#if (ODBCVER >=0x0399)
+ set_nullfield_int2(&row->tuple[15], pgtype_sqldesctype(stmt, pgType));
+ set_nullfield_int2(&row->tuple[16], pgtype_datetime_sub(stmt, pgType));
+ set_nullfield_int4(&row->tuple[17], pgtype_radix(stmt, pgType));
+ set_nullfield_int4(&row->tuple[18], 0);
+#endif /* ODBCVER */
QR_add_tuple(res, row);
}
@@ -1317,7 +1339,7 @@ PGAPI_Tables(
* a statement is actually executed, so we'll have to do this
* ourselves.
*/
- extend_bindings(stmt, 5);
+ extend_column_bindings(SC_get_ARD(stmt), 5);
/* set the field names */
QR_set_num_fields(res, 5);
@@ -1523,13 +1545,15 @@ PGAPI_Columns(
field_name[MAX_INFO_STRING],
field_type_name[MAX_INFO_STRING];
Int2 field_number, sqltype,
+ reserved_cols,
result_cols,
- scale;
+ decimal_digits;
Int4 field_type,
the_type,
field_length,
mod_length,
- precision;
+ column_size,
+ ordinal;
char useStaticPrecision;
char not_null[MAX_INFO_STRING],
relhasrules[MAX_INFO_STRING];
@@ -1735,11 +1759,12 @@ PGAPI_Columns(
* ourselves.
*/
#if (ODBCVER >= 0x0300)
- result_cols = 18;
+ reserved_cols = 18;
#else
- result_cols = 14;
+ reserved_cols = 12;
#endif /* ODBCVER */
- extend_bindings(stmt, result_cols);
+ result_cols = reserved_cols + 2;
+ extend_column_bindings(SC_get_ARD(stmt), result_cols);
/* set the field names */
QR_set_num_fields(res, result_cols);
@@ -1749,9 +1774,9 @@ PGAPI_Columns(
QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
QR_set_field_info(res, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
QR_set_field_info(res, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
- QR_set_field_info(res, 6, "PRECISION", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 7, "LENGTH", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 8, "SCALE", PG_TYPE_INT2, 2);
+ QR_set_field_info(res, 6, "PRECISION", PG_TYPE_INT4, 4); /* COLUMN_SIZE */
+ QR_set_field_info(res, 7, "LENGTH", PG_TYPE_INT4, 4); /* BUFFER_LENGTH */
+ QR_set_field_info(res, 8, "SCALE", PG_TYPE_INT2, 2); /* DECIMAL_DIGITS ***/
QR_set_field_info(res, 9, "RADIX", PG_TYPE_INT2, 2);
QR_set_field_info(res, 10, "NULLABLE", PG_TYPE_INT2, 2);
QR_set_field_info(res, 11, "REMARKS", PG_TYPE_TEXT, 254);
@@ -1764,11 +1789,11 @@ PGAPI_Columns(
QR_set_field_info(res, 15, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
QR_set_field_info(res, 16, "ORDINAL_POSITION", PG_TYPE_INT4, 4);
QR_set_field_info(res, 17, "IS_NULLABLE", PG_TYPE_TEXT, 254);
-#else
- QR_set_field_info(res, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
#endif /* ODBCVER */
+ QR_set_field_info(res, reserved_cols, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
+ QR_set_field_info(res, reserved_cols + 1, "FIELD_TYPE", PG_TYPE_INT4, 4);
+ ordinal = 1;
result = PGAPI_Fetch(hcol_stmt);
/*
@@ -1794,14 +1819,13 @@ PGAPI_Columns(
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], "oid");
- sqltype = pgtype_to_sqltype(stmt, the_type);
+ sqltype = pgtype_to_concise_type(stmt, the_type);
set_tuplefield_int2(&row->tuple[4], sqltype);
set_tuplefield_string(&row->tuple[5], "OID");
- set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
-
- set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, the_type, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
set_tuplefield_string(&row->tuple[11], "");
@@ -1810,15 +1834,15 @@ PGAPI_Columns(
set_tuplefield_null(&row->tuple[12]);
set_tuplefield_int2(&row->tuple[13], sqltype);
set_tuplefield_null(&row->tuple[14]);
- set_tuplefield_int4(&row->tuple[15], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[16], 0);
+ set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[16], ordinal);
set_tuplefield_string(&row->tuple[17], "No");
-#else
- set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[13], the_type);
#endif /* ODBCVER */
+ set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[reserved_cols + 1], the_type);
QR_add_tuple(res, row);
+ ordinal++;
}
}
@@ -1834,7 +1858,7 @@ PGAPI_Columns(
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], field_name);
- sqltype = pgtype_to_sqltype(stmt, field_type);
+ sqltype = pgtype_to_concise_type(stmt, field_type);
set_tuplefield_int2(&row->tuple[4], sqltype);
set_tuplefield_string(&row->tuple[5], field_type_name);
@@ -1845,15 +1869,15 @@ PGAPI_Columns(
* VARCHAR - the length is stored in the pg_attribute.atttypmod field
* BPCHAR - the length is also stored as varchar is
*
- * NUMERIC - the scale is stored in atttypmod as follows:
+ * NUMERIC - the decimal_digits is stored in atttypmod as follows:
*
- * precision =((atttypmod - VARHDRSZ) >> 16) & 0xffff
- * scale = (atttypmod - VARHDRSZ) & 0xffff
+ * column_size =((atttypmod - VARHDRSZ) >> 16) & 0xffff
+ * decimal_digits = (atttypmod - VARHDRSZ) & 0xffff
*
*----------
*/
- qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,sqltype=%d,name='%s'\n",
- table_name, field_name, field_type, pgtype_to_sqltype, field_type_name);
+ qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,name='%s'\n",
+ table_name, field_name, field_type, field_type_name);
useStaticPrecision = TRUE;
@@ -1866,15 +1890,18 @@ PGAPI_Columns(
{
useStaticPrecision = FALSE;
- precision = (mod_length >> 16) & 0xffff;
- scale = mod_length & 0xffff;
+ column_size = (mod_length >> 16) & 0xffff;
+ decimal_digits = mod_length & 0xffff;
- mylog("%s: field type is NUMERIC: field_type = %d, mod_length=%d, precision=%d, scale=%d\n", func, field_type, mod_length, precision, scale);
+ mylog("%s: field type is NUMERIC: field_type = %d, mod_length=%d, precision=%d, scale=%d\n", func, field_type, mod_length, column_size, decimal_digits);
- set_tuplefield_int4(&row->tuple[7], precision + 2); /* sign+dec.point */
- set_tuplefield_int4(&row->tuple[6], precision);
- set_tuplefield_int4(&row->tuple[12], precision + 2); /* sign+dec.point */
- set_nullfield_int2(&row->tuple[8], scale);
+ set_tuplefield_int4(&row->tuple[6], column_size);
+ set_tuplefield_int4(&row->tuple[7], column_size + 2); /* sign+dec.point */
+ set_nullfield_int2(&row->tuple[8], decimal_digits);
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_null(&row->tuple[15]);
+#endif /* ODBCVER */
+ set_tuplefield_int4(&row->tuple[reserved_cols], column_size + 2); /* sign+dec.point */
}
}
@@ -1891,54 +1918,42 @@ PGAPI_Columns(
mylog("%s: field type is VARCHAR,BPCHAR: field_type = %d, mod_length = %d\n", func, field_type, mod_length);
- set_tuplefield_int4(&row->tuple[7], mod_length);
set_tuplefield_int4(&row->tuple[6], mod_length);
- set_tuplefield_int4(&row->tuple[12], mod_length);
- set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, field_type, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[7], mod_length);
+ set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, field_type, PG_STATIC, PG_STATIC));
+#endif /* ODBCVER */
+ set_tuplefield_int4(&row->tuple[reserved_cols], mod_length);
}
if (useStaticPrecision)
{
- mylog("%s: field type is OTHER: field_type = %d, pgtype_length = %d\n", func, field_type, pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
+ mylog("%s: field type is OTHER: field_type = %d, pgtype_length = %d\n", func, field_type, pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, field_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
- set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, field_type, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, field_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC));
+ set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_null(&row->tuple[15]);
+#endif /* ODBCVER */
+ set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
}
set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, field_type));
set_tuplefield_int2(&row->tuple[10], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type)));
set_tuplefield_string(&row->tuple[11], "");
#if (ODBCVER >= 0x0300)
- switch (sqltype)
- {
- case SQL_TYPE_DATE:
- set_tuplefield_int2(&row->tuple[13], SQL_DATETIME);
- set_tuplefield_int2(&row->tuple[14], SQL_CODE_DATE);
- break;
- case SQL_TYPE_TIME:
- set_tuplefield_int2(&row->tuple[13], SQL_DATETIME);
- set_tuplefield_int2(&row->tuple[14], SQL_CODE_TIME);
- break;
- case SQL_TYPE_TIMESTAMP:
- set_tuplefield_int2(&row->tuple[13], SQL_DATETIME);
- set_tuplefield_int2(&row->tuple[14], SQL_CODE_TIMESTAMP);
- break;
- default:
- set_tuplefield_int2(&row->tuple[13], sqltype);
- set_tuplefield_null(&row->tuple[14]);
- break;
- }
- set_tuplefield_int4(&row->tuple[15], pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[16], field_number);
+ set_tuplefield_null(&row->tuple[12]);
+ set_tuplefield_int2(&row->tuple[13], pgtype_to_sqldesctype(stmt, field_type));
+ set_nullfield_int2(&row->tuple[14], pgtype_to_datetime_sub(stmt, field_type));
+ set_tuplefield_int4(&row->tuple[16], ordinal);
set_tuplefield_null(&row->tuple[17]);
-#else
- set_tuplefield_int4(&row->tuple[13], field_type);
#endif /* ODBCVER */
+ set_tuplefield_int4(&row->tuple[reserved_cols + 1], field_type);
QR_add_tuple(res, row);
-
+ ordinal++;
result = PGAPI_Fetch(hcol_stmt);
@@ -1968,12 +1983,12 @@ PGAPI_Columns(
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], "xmin");
- sqltype = pgtype_to_sqltype(stmt, the_type);
+ sqltype = pgtype_to_concise_type(stmt, the_type);
set_tuplefield_int2(&row->tuple[4], sqltype);
set_tuplefield_string(&row->tuple[5], pgtype_to_name(stmt, the_type));
- set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
- set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, the_type, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
set_tuplefield_string(&row->tuple[11], "");
@@ -1981,15 +1996,15 @@ PGAPI_Columns(
set_tuplefield_null(&row->tuple[12]);
set_tuplefield_int2(&row->tuple[13], sqltype);
set_tuplefield_null(&row->tuple[14]);
- set_tuplefield_int4(&row->tuple[15], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[16], 0);
+ set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[16], ordinal);
set_tuplefield_string(&row->tuple[17], "No");
-#else
- set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[13], the_type);
#endif /* ODBCVER */
+ set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[reserved_cols + 1], the_type);
QR_add_tuple(res, row);
+ ordinal++;
}
/*
@@ -2096,7 +2111,7 @@ PGAPI_SpecialColumns(
res = QR_Constructor();
SC_set_Result(stmt, res);
- extend_bindings(stmt, 8);
+ extend_column_bindings(SC_get_ARD(stmt), 8);
QR_set_num_fields(res, 8);
QR_set_field_info(res, 0, "SCOPE", PG_TYPE_INT2, 2);
@@ -2117,11 +2132,11 @@ PGAPI_SpecialColumns(
set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION);
set_tuplefield_string(&row->tuple[1], "oid");
- set_tuplefield_int2(&row->tuple[2], pgtype_to_sqltype(stmt, PG_TYPE_OID));
+ set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID));
set_tuplefield_string(&row->tuple[3], "OID");
- set_tuplefield_int4(&row->tuple[4], pgtype_precision(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[5], pgtype_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
- set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, PG_TYPE_OID, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
+ set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, PG_TYPE_OID, PG_STATIC));
set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
QR_add_tuple(res, row);
@@ -2137,11 +2152,11 @@ PGAPI_SpecialColumns(
set_tuplefield_null(&row->tuple[0]);
set_tuplefield_string(&row->tuple[1], "xmin");
- set_tuplefield_int2(&row->tuple[2], pgtype_to_sqltype(stmt, the_type));
+ set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type));
set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
- set_tuplefield_int4(&row->tuple[4], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[5], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, the_type, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
QR_add_tuple(res, row);
@@ -2227,7 +2242,7 @@ PGAPI_Statistics(
* a statement is actually executed, so we'll have to do this
* ourselves.
*/
- extend_bindings(stmt, 13);
+ extend_column_bindings(SC_get_ARD(stmt), 13);
/* set the field names */
QR_set_num_fields(res, 13);
@@ -2671,7 +2686,7 @@ PGAPI_PrimaryKeys(
* ourselves.
*/
result_cols = 6;
- extend_bindings(stmt, result_cols);
+ extend_column_bindings(SC_get_ARD(stmt), result_cols);
/* set the field names */
QR_set_num_fields(res, result_cols);
@@ -3067,7 +3082,7 @@ PGAPI_ForeignKeys(
* ourselves.
*/
result_cols = 14;
- extend_bindings(stmt, result_cols);
+ extend_column_bindings(SC_get_ARD(stmt), result_cols);
/* set the field names */
QR_set_num_fields(res, result_cols);
@@ -3803,7 +3818,7 @@ PGAPI_Procedures(
* results can be retrieved.
*/
stmt->status = STMT_FINISHED;
- extend_bindings(stmt, 8);
+ extend_column_bindings(SC_get_ARD(stmt), 8);
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
stmt->rowset_start = -1;
@@ -3891,7 +3906,7 @@ PGAPI_TablePrivileges(
* ourselves.
*/
result_cols = 7;
- extend_bindings(stmt, result_cols);
+ extend_column_bindings(SC_get_ARD(stmt), result_cols);
/* set the field names */
stmt->manual_result = TRUE;
@@ -3983,7 +3998,7 @@ PGAPI_TablePrivileges(
char *grolist, *uid, *delm;
snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user);
- if ((gres = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT)))
+ if (gres = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), gres != NULL)
{
grolist = QR_get_value_backend_row(gres, 0, 0);
if (grolist && grolist[0] == '{')
diff --git a/src/interfaces/odbc/info30.c b/src/interfaces/odbc/info30.c
index 414110b8938..c1c2c63d066 100644
--- a/src/interfaces/odbc/info30.c
+++ b/src/interfaces/odbc/info30.c
@@ -53,14 +53,13 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
| SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
| SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
| SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
- | SQL_CA1_POS_REFRESH);
- if (ci->drivers.lie)
- value |= (SQL_CA1_BULK_ADD
+ | SQL_CA1_POS_REFRESH | SQL_CA1_BULK_ADD
| SQL_CA1_BULK_UPDATE_BY_BOOKMARK
| SQL_CA1_BULK_DELETE_BY_BOOKMARK
| SQL_CA1_BULK_FETCH_BY_BOOKMARK
-
- | SQL_CA1_LOCK_EXCLUSIVE
+ );
+ if (ci->drivers.lie)
+ value |= (SQL_CA1_LOCK_EXCLUSIVE
| SQL_CA1_LOCK_UNLOCK
| SQL_CA1_POSITIONED_UPDATE
| SQL_CA1_POSITIONED_DELETE
@@ -72,9 +71,10 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
value = 0;
if (ci->updatable_cursors || ci->drivers.lie)
value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
- | SQL_CA2_SENSITIVITY_ADDITIONS
| SQL_CA2_SENSITIVITY_DELETIONS
- | SQL_CA2_SENSITIVITY_UPDATES);
+ | SQL_CA2_SENSITIVITY_UPDATES
+ /* | SQL_CA2_SENSITIVITY_ADDITIONS */
+ );
if (ci->drivers.lie)
value |= (SQL_CA2_READ_ONLY_CONCURRENCY
| SQL_CA2_LOCK_CONCURRENCY
@@ -97,19 +97,21 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
len = 4;
value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE
| SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
- | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION;
+ | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
+ | SQL_CA1_POS_REFRESH;
if (ci->updatable_cursors)
value |= (SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
- | SQL_CA1_POS_REFRESH);
+ );
break;
case SQL_STATIC_CURSOR_ATTRIBUTES2:
len = 4;
- value = 0;
+ value = SQL_CA2_READ_ONLY_CONCURRENCY;
if (ci->updatable_cursors)
value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
- | SQL_CA2_SENSITIVITY_ADDITIONS
+ /* | SQL_CA2_SENSITIVITY_ADDITIONS
| SQL_CA2_SENSITIVITY_DELETIONS
- | SQL_CA2_SENSITIVITY_UPDATES);
+ | SQL_CA2_SENSITIVITY_UPDATES */
+ );
break;
case SQL_ODBC_INTERFACE_CONFORMANCE:
diff --git a/src/interfaces/odbc/misc.c b/src/interfaces/odbc/misc.c
index 443d1f47b3c..a7bcaca8d97 100644
--- a/src/interfaces/odbc/misc.c
+++ b/src/interfaces/odbc/misc.c
@@ -115,6 +115,11 @@ mylog(char *fmt,...)
va_end(args);
}
}
+#else
+void
+MyLog(char *fmt,...)
+{
+}
#endif
diff --git a/src/interfaces/odbc/misc.h b/src/interfaces/odbc/misc.h
index b658ed7c91e..cba7f2bfede 100644
--- a/src/interfaces/odbc/misc.h
+++ b/src/interfaces/odbc/misc.h
@@ -36,17 +36,18 @@
#define MYLOGDIR "/tmp"
#else
#define MYLOGDIR "c:"
-#endif
+#endif /* WIN32 */
extern void mylog(char *fmt,...);
-#define inolog mylog /* for really temporary debug */
#else
#ifndef WIN32
#define mylog(args...) /* GNU convention for variable arguments */
#else
-#define mylog /* mylog */
-#endif
-#endif
+extern void MyLog(char *fmt,...);
+#define mylog if (0) MyLog /* mylog */
+#endif /* WIN32 */
+#endif /* MY_LOG */
+#define inolog mylog /* for really temporary debug */
#ifdef Q_LOG
#define QLOGFILE "psqlodbc_"
@@ -64,6 +65,7 @@ extern void qlog(char *fmt,...);
#define qlog /* qlog */
#endif
#endif
+#define inoqlog qlog
#ifndef WIN32
#define DIRSEPARATOR "/"
diff --git a/src/interfaces/odbc/multibyte.c b/src/interfaces/odbc/multibyte.c
index 362916da2cd..9c8c7dae6a1 100644
--- a/src/interfaces/odbc/multibyte.c
+++ b/src/interfaces/odbc/multibyte.c
@@ -59,7 +59,7 @@ pg_CS CS_Table[] =
{ "OTHER", OTHER }
};
-int
+static int
pg_ismb(int characterset_code)
{
int i=0,MB_CHARACTERSET[]={EUC_JP,EUC_CN,EUC_KR,EUC_TW,UTF8,MULE_INTERNAL,SJIS,BIG5,GBK,UHC,JOHAB};
@@ -228,8 +228,8 @@ pg_CS_stat(int stat,unsigned int character,int characterset_code)
character > 0xa0)
stat = 3;
else if (stat == 3 ||
- (stat < 2 &&
- character > 0xa0))
+ stat < 2 &&
+ character > 0xa0)
stat = 2;
else if (stat == 2)
stat = 1;
diff --git a/src/interfaces/odbc/multibyte.h b/src/interfaces/odbc/multibyte.h
index 8c9b4cce025..47a57b0ade6 100644
--- a/src/interfaces/odbc/multibyte.h
+++ b/src/interfaces/odbc/multibyte.h
@@ -86,7 +86,4 @@ void encoded_str_constr(encoded_str *encstr, int ccsc, const char *str);
#define make_encoded_str(encstr, conn, str) encoded_str_constr(encstr, conn->ccsc, str)
extern int encoded_nextchar(encoded_str *encstr);
extern int encoded_byte_check(encoded_str *encstr, int abspos);
-
-/* This doesn't seem to be called by anyone, bjm 2002-03-24 */
-extern int pg_ismb(int characterset_code);
#define check_client_encoding(X) pg_CS_name(pg_CS_code(X))
diff --git a/src/interfaces/odbc/odbcapi.c b/src/interfaces/odbc/odbcapi.c
index cbb31dad0a7..d116d00006c 100644
--- a/src/interfaces/odbc/odbcapi.c
+++ b/src/interfaces/odbc/odbcapi.c
@@ -204,8 +204,9 @@ SQLFetch(HSTMT StatementHandle)
if (conn->driver_version >= 0x0300)
{
- SQLUSMALLINT *rowStatusArray = stmt->options.rowStatusArray;
- SQLINTEGER *pcRow = stmt->options.rowsFetched;
+ IRDFields *irdopts = SC_get_IRD(stmt);
+ SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray;
+ SQLINTEGER *pcRow = irdopts->rowsFetched;
mylog("[[%s]]", func);
return PGAPI_ExtendedFetch(StatementHandle, SQL_FETCH_NEXT, 0,
diff --git a/src/interfaces/odbc/odbcapi30.c b/src/interfaces/odbc/odbcapi30.c
index c4efdd56e52..0e9b63a3049 100644
--- a/src/interfaces/odbc/odbcapi30.c
+++ b/src/interfaces/odbc/odbcapi30.c
@@ -155,8 +155,9 @@ SQLFetchScroll(HSTMT StatementHandle,
static char *func = "SQLFetchScroll";
StatementClass *stmt = (StatementClass *) StatementHandle;
RETCODE ret;
- SQLUSMALLINT *rowStatusArray = stmt->options.rowStatusArray;
- SQLINTEGER *pcRow = stmt->options.rowsFetched;
+ IRDFields *irdopts = SC_get_IRD(stmt);
+ SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray;
+ SQLINTEGER *pcRow = irdopts->rowsFetched;
mylog("[[%s]] %d,%d\n", func, FetchOrientation, FetchOffset);
if (FetchOrientation == SQL_FETCH_BOOKMARK)
@@ -208,8 +209,8 @@ SQLGetDescField(SQLHDESC DescriptorHandle,
SQLINTEGER *StringLength)
{
mylog("[[SQLGetDescField]]\n");
- mylog("Error not implemented\n");
- return SQL_ERROR;
+ return PGAPI_GetDescField(DescriptorHandle, RecNumber, FieldIdentifier,
+ Value, BufferLength, StringLength);
}
/* new function */
@@ -233,7 +234,7 @@ SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
PTR DiagInfo, SQLSMALLINT BufferLength,
SQLSMALLINT *StringLength)
{
- mylog("[[SQLGetDiagField]]\n");
+ mylog("[[SQLGetDiagField]] Handle=(%u,%x) Rec=%d Id=%d\n", HandleType, Handle, RecNumber, DiagIdentifier);
return SQL_ERROR;
}
@@ -285,21 +286,9 @@ SQLGetConnectAttr(HDBC ConnectionHandle,
SQLINTEGER Attribute, PTR Value,
SQLINTEGER BufferLength, SQLINTEGER *StringLength)
{
- ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
-
mylog("[[SQLGetConnectAttr]] %d\n", Attribute);
- switch (Attribute)
- {
- case SQL_ATTR_ASYNC_ENABLE:
- case SQL_ATTR_AUTO_IPD:
- case SQL_ATTR_CONNECTION_DEAD:
- case SQL_ATTR_CONNECTION_TIMEOUT:
- case SQL_ATTR_METADATA_ID:
- conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
- conn->errormsg = "Unsupported connection option (Set)";
- return SQL_ERROR;
- }
- return PGAPI_GetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
+ return PGAPI_GetConnectAttr(ConnectionHandle, Attribute,Value,
+ BufferLength, StringLength);
}
/* SQLGetStmtOption -> SQLGetStmtAttr */
@@ -309,91 +298,10 @@ SQLGetStmtAttr(HSTMT StatementHandle,
SQLINTEGER BufferLength, SQLINTEGER *StringLength)
{
static char *func = "SQLGetStmtAttr";
- StatementClass *stmt = (StatementClass *) StatementHandle;
- RETCODE ret = SQL_SUCCESS;
- int len = 0;
mylog("[[%s]] Handle=%u %d\n", func, StatementHandle, Attribute);
- switch (Attribute)
- {
- case SQL_ATTR_FETCH_BOOKMARK_PTR: /* 16 */
- Value = stmt->options.bookmark_ptr;
- len = 4;
- break;
- case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */
- Value = stmt->options.param_offset_ptr;
- len = 4;
- break;
- case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */
- *((SQLUINTEGER *) Value) = stmt->options.param_bind_type;
- len = 4;
- break;
- case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */
- Value = stmt->options.param_operation_ptr;
- len = 4;
- break;
- case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
- Value = stmt->options.param_status_ptr;
- len = 4;
- break;
- case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */
- Value = stmt->options.param_processed_ptr;
- len = 4;
- break;
- case SQL_ATTR_PARAMSET_SIZE: /* 22 */
- *((SQLUINTEGER *) Value) = stmt->options.paramset_size;
- len = 4;
- break;
- case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */
- Value = stmt->options.row_offset_ptr;
- len = 4;
- break;
- case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */
- Value = stmt->options.row_operation_ptr;
- len = 4;
- break;
- case SQL_ATTR_ROW_STATUS_PTR: /* 25 */
- Value = stmt->options.rowStatusArray;
- len = 4;
- break;
- case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
- Value = stmt->options.rowsFetched;
- len = 4;
- break;
- case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */
- *((SQLUINTEGER *) Value) = stmt->options.rowset_size;
- len = 4;
- break;
- case SQL_ATTR_APP_ROW_DESC: /* 10010 */
- case SQL_ATTR_APP_PARAM_DESC: /* 10011 */
- case SQL_ATTR_IMP_ROW_DESC: /* 10012 */
- case SQL_ATTR_IMP_PARAM_DESC: /* 10013 */
- len = 4;
- *((HSTMT *) Value) = descHandleFromStatementHandle(StatementHandle, Attribute);
- break;
- case SQL_ATTR_AUTO_IPD: /* 10001 */
- /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
-
- case SQL_ATTR_CURSOR_SCROLLABLE: /* -1 */
- case SQL_ATTR_CURSOR_SENSITIVITY: /* -2 */
- case SQL_ATTR_ENABLE_AUTO_IPD: /* 15 */
- case SQL_ATTR_METADATA_ID: /* 10014 */
-
- /*
- * case SQL_ATTR_PREDICATE_PTR: case
- * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
- */
- stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
- stmt->errormsg = "Unsupported statement option (Get)";
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
- default:
- len = 4;
- ret = PGAPI_GetStmtOption(StatementHandle, (UWORD) Attribute, Value);
- }
- if (ret == SQL_SUCCESS && StringLength)
- *StringLength = len;
- return ret;
+ return PGAPI_GetStmtAttr(StatementHandle, Attribute, Value,
+ BufferLength, StringLength);
}
/* SQLSetConnectOption -> SQLSetConnectAttr */
@@ -405,18 +313,8 @@ SQLSetConnectAttr(HDBC ConnectionHandle,
ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
mylog("[[SQLSetConnectAttr]] %d\n", Attribute);
- switch (Attribute)
- {
- case SQL_ATTR_ASYNC_ENABLE:
- case SQL_ATTR_AUTO_IPD:
- case SQL_ATTR_CONNECTION_DEAD:
- case SQL_ATTR_CONNECTION_TIMEOUT:
- case SQL_ATTR_METADATA_ID:
- conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
- conn->errormsg = "Unsupported connection option (Set)";
- return SQL_ERROR;
- }
- return PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
+ return PGAPI_SetConnectAttr(ConnectionHandle, Attribute, Value,
+ StringLength);
}
/* new function */
@@ -497,70 +395,7 @@ SQLSetStmtAttr(HSTMT StatementHandle,
StatementClass *stmt = (StatementClass *) StatementHandle;
mylog("[[%s]] Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
- switch (Attribute)
- {
- case SQL_ATTR_CURSOR_SCROLLABLE: /* -1 */
- case SQL_ATTR_CURSOR_SENSITIVITY: /* -2 */
-
- case SQL_ATTR_ENABLE_AUTO_IPD: /* 15 */
-
- case SQL_ATTR_APP_ROW_DESC: /* 10010 */
- case SQL_ATTR_APP_PARAM_DESC: /* 10011 */
- case SQL_ATTR_AUTO_IPD: /* 10001 */
- /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
- case SQL_ATTR_IMP_ROW_DESC: /* 10012 (read-only) */
- case SQL_ATTR_IMP_PARAM_DESC: /* 10013 (read-only) */
- case SQL_ATTR_METADATA_ID: /* 10014 */
-
- /*
- * case SQL_ATTR_PREDICATE_PTR: case
- * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
- */
- stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
- stmt->errormsg = "Unsupported statement option (Set)";
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
-
- case SQL_ATTR_FETCH_BOOKMARK_PTR: /* 16 */
- stmt->options.bookmark_ptr = Value;
- break;
- case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */
- stmt->options.param_offset_ptr = (SQLUINTEGER *) Value;
- break;
- case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */
- stmt->options.param_bind_type = (SQLUINTEGER) Value;
- break;
- case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */
- stmt->options.param_operation_ptr = Value;
- break;
- case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
- stmt->options.param_status_ptr = (SQLUSMALLINT *) Value;
- break;
- case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */
- stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
- break;
- case SQL_ATTR_PARAMSET_SIZE: /* 22 */
- stmt->options.paramset_size = (SQLUINTEGER) Value;
- break;
- case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */
- stmt->options.row_offset_ptr = (SQLUINTEGER *) Value;
- break;
- case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */
- stmt->options.row_operation_ptr = Value;
- break;
- case SQL_ATTR_ROW_STATUS_PTR: /* 25 */
- stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
- break;
- case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
- stmt->options.rowsFetched = (SQLUINTEGER *) Value;
- break;
- case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */
- stmt->options.rowset_size = (SQLUINTEGER) Value;
- break;
- default:
- return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) Value);
- }
- return SQL_SUCCESS;
+ return PGAPI_SetStmtAttr(StatementHandle, Attribute, Value, StringLength);
}
#define SQL_FUNC_ESET(pfExists, uwAPI) \
@@ -630,8 +465,9 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
if (ci->drivers.lie)
SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); /* 56 not implemented yet */
SQL_FUNC_ESET(pfExists, SQL_API_SQLDATASOURCES); /* 57 */
- SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBEPARAM); /* 58 */
- /* SQL_FUNC_ESET(pfExists, SQL_API_SQLEXTENDEDFETCH); 59 deprecated */
+ if (ci->drivers.lie)
+ SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBEPARAM); /* 58 not properly implemented */
+ SQL_FUNC_ESET(pfExists, SQL_API_SQLEXTENDEDFETCH); /* 59 deprecated ? */
/*
* for (++i; i < SQL_API_SQLBINDPARAMETER; i++)
@@ -678,8 +514,75 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
SQL_FUNC_ESET(pfExists, SQL_API_SQLSETENVATTR); /* 1019 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSTMTATTR); /* 1020 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLFETCHSCROLL); /* 1021 */
- if (ci->drivers.lie)
- SQL_FUNC_ESET(pfExists, SQL_API_SQLBULKOPERATIONS); /* 24 not implemented yet */
+ if (ci->updatable_cursors)
+ SQL_FUNC_ESET(pfExists, SQL_API_SQLBULKOPERATIONS); /* 24 */
return SQL_SUCCESS;
}
+
+RETCODE SQL_API
+SQLBulkOperations(HSTMT hstmt, SQLSMALLINT operation)
+{
+ static char *func = "SQLBulkOperations";
+ StatementClass *stmt = (StatementClass *) hstmt;
+ ARDFields *opts = SC_get_ARD(stmt);
+ RETCODE ret;
+ UInt4 offset, bind_size = opts->bind_size, *bmark;
+ int i, processed;
+ ConnectionClass *conn;
+ BOOL auto_commit_needed = FALSE;
+
+ mylog("[[%s]] operation = %d\n", func, operation);
+ offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
+ switch (operation)
+ {
+ case SQL_ADD:
+ ret = PGAPI_SetPos(hstmt, 0, operation, SQL_LOCK_NO_CHANGE);
+ break;
+ default:
+ if (SQL_FETCH_BY_BOOKMARK != operation)
+ {
+ conn = SC_get_conn(stmt);
+ if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed)
+ PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT,
+SQL_AUTOCOMMIT_OFF);
+ }
+ if (bmark = (UInt4 *) opts->bookmark->buffer, !bmark)
+ {
+ stmt->errormsg = "bookmark isn't specified";
+ return SQL_ERROR;
+ }
+ bmark += (offset >> 4);
+ for (i = 0, processed = 0; i < opts->rowset_size; i++)
+ {
+ if (!opts->row_operation_ptr || SQL_ROW_PROCEED == opts->row_operation_ptr[i])
+ {
+ switch (operation)
+ {
+ case SQL_UPDATE_BY_BOOKMARK:
+ ret = SC_pos_update(stmt, (UWORD) i, *bmark);
+ break;
+ case SQL_DELETE_BY_BOOKMARK:
+ ret = SC_pos_delete(stmt, (UWORD) i, *bmark);
+ break;
+ case SQL_FETCH_BY_BOOKMARK:
+ ret = SC_pos_refresh(stmt, (UWORD) i, *bmark);
+ break;
+ }
+ processed++;
+ if (SQL_ERROR == ret)
+ break;
+ if (bind_size > 0)
+ bmark += (bind_size >> 2);
+ else
+ bmark++;
+ }
+ }
+ if (auto_commit_needed)
+ PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
+ if (SC_get_IRD(stmt)->rowsFetched)
+ *SC_get_IRD(stmt)->rowsFetched = processed;
+ break;
+ }
+ return ret;
+}
diff --git a/src/interfaces/odbc/odbcapi30w.c b/src/interfaces/odbc/odbcapi30w.c
index 35237202faa..0273f97b6b9 100644
--- a/src/interfaces/odbc/odbcapi30w.c
+++ b/src/interfaces/odbc/odbcapi30w.c
@@ -5,7 +5,7 @@
*
* Classes: n/a
*
- * API functions: SQLColAttributeW, SQLGetStmtW, SQLSetStmtW,
+ * API functions: SQLColAttributeW, SQLGetStmtAttrW, SQLSetStmtAttrW,
SQLSetConnectAttrW, SQLGetConnectAttrW,
SQLGetDescFieldW, SQLGetDescRecW, SQLGetDiagFieldW,
SQLGetDiagRecW,
@@ -75,6 +75,48 @@ RETCODE SQL_API SQLSetConnectAttrW(HDBC hdbc,
return ret;
}
+/* new function */
+RETCODE SQL_API
+SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber,
+ SQLSMALLINT FieldIdentifier, PTR Value,
+ SQLINTEGER BufferLength)
+{
+ RETCODE ret;
+ UInt4 vallen;
+ char *uval = NULL;
+ BOOL val_alloced = FALSE;
+
+ mylog("[SQLSetDescFieldW]");
+ if (BufferLength > 0)
+ {
+ uval = ucs2_to_utf8(Value, BufferLength / 2, &vallen);
+ val_alloced = TRUE;
+ }
+ else
+ {
+ uval = Value;
+ vallen = BufferLength;
+ }
+ ret = PGAPI_SetDescField(DescriptorHandle, RecNumber, FieldIdentifier,
+ uval, vallen);
+ if (val_alloced)
+ free(uval);
+ return ret;
+}
+RETCODE SQL_API
+SQLGetDescFieldW(SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField,
+ PTR rgbValue, SQLINTEGER cbValueMax,
+ SQLINTEGER *pcbValue)
+{
+ RETCODE ret;
+ char *qstr = NULL, *mtxt = NULL;
+
+ mylog("[SQLGetDescFieldW]");
+ ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbValue,
+ cbValueMax, pcbValue);
+ return ret;
+}
+
RETCODE SQL_API SQLGetDiagRecW(SWORD fHandleType,
SQLHANDLE handle,
SQLSMALLINT iRecord,
@@ -131,7 +173,25 @@ RETCODE SQL_API SQLColAttributeW(
RETCODE ret;
mylog("[SQLColAttributeW]");
+ switch (fDescType)
+ {
+ case SQL_DESC_BASE_COLUMN_NAME:
+ case SQL_DESC_BASE_TABLE_NAME:
+ case SQL_DESC_CATALOG_NAME:
+ case SQL_DESC_LABEL:
+ case SQL_DESC_LITERAL_PREFIX:
+ case SQL_DESC_LITERAL_SUFFIX:
+ case SQL_DESC_LOCAL_TYPE_NAME:
+ case SQL_DESC_NAME:
+ case SQL_DESC_SCHEMA_NAME:
+ case SQL_DESC_TABLE_NAME:
+ case SQL_DESC_TYPE_NAME:
+ case SQL_COLUMN_NAME:
+ break;
+ }
+
ret = PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
cbDescMax, pcbDesc, pfDesc);
+
return ret;
}
diff --git a/src/interfaces/odbc/options.c b/src/interfaces/odbc/options.c
index ea11fae76be..d560ff46705 100644
--- a/src/interfaces/odbc/options.c
+++ b/src/interfaces/odbc/options.c
@@ -53,9 +53,9 @@ set_statement_option(ConnectionClass *conn,
case SQL_BIND_TYPE:
/* now support multi-column and multi-row binding */
if (conn)
- conn->stmtOptions.bind_size = vParam;
+ conn->ardOptions.bind_size = vParam;
if (stmt)
- stmt->options.bind_size = vParam;
+ SC_get_ARD(stmt)->bind_size = vParam;
break;
case SQL_CONCURRENCY:
@@ -173,7 +173,7 @@ set_statement_option(ConnectionClass *conn,
*/
if (stmt && stmt->save_rowset_size <= 0 && stmt->last_fetch_count > 0)
- stmt->save_rowset_size = stmt->options.rowset_size;
+ stmt->save_rowset_size = SC_get_ARD(stmt)->rowset_size;
if (vParam < 1)
{
@@ -182,9 +182,9 @@ set_statement_option(ConnectionClass *conn,
}
if (conn)
- conn->stmtOptions.rowset_size = vParam;
+ conn->ardOptions.rowset_size = vParam;
if (stmt)
- stmt->options.rowset_size = vParam;
+ SC_get_ARD(stmt)->rowset_size = vParam;
break;
case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */
@@ -590,16 +590,16 @@ PGAPI_GetStmtOption(
break;
case SQL_BIND_TYPE:
- *((SDWORD *) pvParam) = stmt->options.bind_size;
+ *((SDWORD *) pvParam) = SC_get_ARD(stmt)->bind_size;
break;
case SQL_CONCURRENCY: /* NOT REALLY SUPPORTED */
- mylog("GetStmtOption(): SQL_CONCURRENCY\n");
+ mylog("GetStmtOption(): SQL_CONCURRENCY %d\n", stmt->options.scroll_concurrency);
*((SDWORD *) pvParam) = stmt->options.scroll_concurrency;
break;
case SQL_CURSOR_TYPE: /* PARTIAL SUPPORT */
- mylog("GetStmtOption(): SQL_CURSOR_TYPE\n");
+ mylog("GetStmtOption(): SQL_CURSOR_TYPE %d\n", stmt->options.cursor_type);
*((SDWORD *) pvParam) = stmt->options.cursor_type;
break;
@@ -630,7 +630,7 @@ PGAPI_GetStmtOption(
break;
case SQL_ROWSET_SIZE:
- *((SDWORD *) pvParam) = stmt->options.rowset_size;
+ *((SDWORD *) pvParam) = SC_get_ARD(stmt)->rowset_size;
break;
case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */
diff --git a/src/interfaces/odbc/parse.c b/src/interfaces/odbc/parse.c
index 8a7e6d7415c..3549ff2ef7a 100644
--- a/src/interfaces/odbc/parse.c
+++ b/src/interfaces/odbc/parse.c
@@ -236,19 +236,25 @@ void
getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
{
char *str;
+ Int2 reserved_cols;
+#if (ODBCVER >= 0x0300)
+ reserved_cols = 18;
+#else
+ reserved_cols = 12;
+#endif /* ODBCVER */
if (fi->name[0] == '\0')
strcpy(fi->name, QR_get_value_manual(col_info->result, k, 3));
- fi->type = atoi(QR_get_value_manual(col_info->result, k, 13));
- fi->precision = atoi(QR_get_value_manual(col_info->result, k, 6));
+ fi->type = atoi(QR_get_value_manual(col_info->result, k, (Int2)(reserved_cols + 1)));
+ fi->column_size = atoi(QR_get_value_manual(col_info->result, k, 6));
fi->length = atoi(QR_get_value_manual(col_info->result, k, 7));
if (str = QR_get_value_manual(col_info->result, k, 8), str)
- fi->scale = atoi(str);
+ fi->decimal_digits = atoi(str);
else
- fi->scale = -1;
+ fi->decimal_digits = -1;
fi->nullable = atoi(QR_get_value_manual(col_info->result, k, 10));
- fi->display_size = atoi(QR_get_value_manual(col_info->result, k, 12));
+ fi->display_size = atoi(QR_get_value_manual(col_info->result, k, reserved_cols));
}
@@ -315,16 +321,17 @@ parse_statement(StatementClass *stmt)
ConnectionClass *conn = stmt->hdbc;
HSTMT hcol_stmt;
StatementClass *col_stmt;
+ IRDFields *irdflds = SC_get_IRD(stmt);
RETCODE result;
BOOL updatable = TRUE;
mylog("%s: entering...\n", func);
ptr = stmt->statement;
- fi = stmt->fi;
+ fi = irdflds->fi;
ti = stmt->ti;
- stmt->nfld = 0;
+ irdflds->nfields = 0;
stmt->ntab = 0;
stmt->from_pos = -1;
stmt->where_pos = -1;
@@ -371,7 +378,7 @@ parse_statement(StatementClass *stmt)
mylog("FROM\n");
continue;
}
- }
+ } /* in_select && unquoted && blevel == 0 */
if (unquoted && blevel == 0)
{
if ((!stricmp(token, "where") ||
@@ -386,18 +393,18 @@ parse_statement(StatementClass *stmt)
in_from = FALSE;
in_where = TRUE;
- if (!stricmp(token, "where"))
+ if (stmt->where_pos < 0)
+ stmt->where_pos = pptr - stmt->statement;
+ mylog("%s...\n", token);
+ if (stricmp(token, "where") &&
+ stricmp(token, "order"))
{
- if (stmt->where_pos < 0)
- stmt->where_pos = pptr - stmt->statement;
- }
- else if (stricmp(token, "order"))
updatable = FALSE;
-
- mylog("WHERE...\n");
- break;
+ break;
+ }
+ continue;
}
- }
+ } /* unquoted && blevel == 0 */
if (in_select && (in_expr || in_func))
{
/* just eat the expression */
@@ -435,7 +442,7 @@ parse_statement(StatementClass *stmt)
}
}
continue;
- }
+ } /* in_select && (in_expr || in_func) */
if (unquoted && !stricmp(token, "select"))
{
@@ -464,81 +471,81 @@ parse_statement(StatementClass *stmt)
}
mylog("done distinct\n");
in_distinct = FALSE;
- }
+ } /* in_distinct */
if (!in_field)
{
if (!token[0])
continue;
- if (!(stmt->nfld % FLD_INCR))
+ if (!(irdflds->nfields % FLD_INCR))
{
- mylog("reallocing at nfld=%d\n", stmt->nfld);
- fi = (FIELD_INFO **) realloc(fi, (stmt->nfld + FLD_INCR) * sizeof(FIELD_INFO *));
+ mylog("reallocing at nfld=%d\n", irdflds->nfields);
+ fi = (FIELD_INFO **) realloc(fi, (irdflds->nfields + FLD_INCR) * sizeof(FIELD_INFO *));
if (!fi)
{
stmt->parse_status = STMT_PARSE_FATAL;
return FALSE;
}
- stmt->fi = fi;
+ irdflds->fi = fi;
}
- fi[stmt->nfld] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
- if (fi[stmt->nfld] == NULL)
+ fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
+ if (fi[irdflds->nfields] == NULL)
{
stmt->parse_status = STMT_PARSE_FATAL;
return FALSE;
}
/* Initialize the field info */
- memset(fi[stmt->nfld], 0, sizeof(FIELD_INFO));
+ memset(fi[irdflds->nfields], 0, sizeof(FIELD_INFO));
/* double quotes are for qualifiers */
if (dquote)
- fi[stmt->nfld]->dquote = TRUE;
+ fi[irdflds->nfields]->dquote = TRUE;
if (quote)
{
- fi[stmt->nfld]->quote = TRUE;
- fi[stmt->nfld]->precision = strlen(token);
+ fi[irdflds->nfields]->quote = TRUE;
+ fi[irdflds->nfields]->column_size = strlen(token);
}
else if (numeric)
{
- mylog("**** got numeric: nfld = %d\n", stmt->nfld);
- fi[stmt->nfld]->numeric = TRUE;
+ mylog("**** got numeric: nfld = %d\n", irdflds->nfields);
+ fi[irdflds->nfields]->numeric = TRUE;
}
else if (token[0] == '(')
{ /* expression */
mylog("got EXPRESSION\n");
- fi[stmt->nfld++]->expr = TRUE;
+ fi[irdflds->nfields++]->expr = TRUE;
in_expr = TRUE;
blevel = 1;
continue;
}
else
{
- strcpy(fi[stmt->nfld]->name, token);
- fi[stmt->nfld]->dot[0] = '\0';
+ strcpy(fi[irdflds->nfields]->name, token);
+ fi[irdflds->nfields]->dot[0] = '\0';
}
- mylog("got field='%s', dot='%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->dot);
+ mylog("got field='%s', dot='%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->dot);
if (delim == ',')
mylog("comma (1)\n");
else
in_field = TRUE;
- stmt->nfld++;
+ irdflds->nfields++;
continue;
- }
+ } /* !in_field */
/*
* We are in a field now
*/
if (in_dot)
{
- stmt->nfld--;
- strcpy(fi[stmt->nfld]->dot, fi[stmt->nfld]->name);
- strcpy(fi[stmt->nfld]->name, token);
- stmt->nfld++;
+ irdflds->nfields--;
+ strcpy(fi[irdflds->nfields]->dot, fi[irdflds->nfields]->name);
+ strcpy(fi[irdflds->nfields]->name, token);
+ irdflds->nfields++;
in_dot = FALSE;
if (delim == ',')
@@ -551,13 +558,13 @@ parse_statement(StatementClass *stmt)
if (in_as)
{
- stmt->nfld--;
- strcpy(fi[stmt->nfld]->alias, token);
- mylog("alias for field '%s' is '%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->alias);
+ irdflds->nfields--;
+ strcpy(fi[irdflds->nfields]->alias, token);
+ mylog("alias for field '%s' is '%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->alias);
in_as = FALSE;
in_field = FALSE;
- stmt->nfld++;
+ irdflds->nfields++;
if (delim == ',')
mylog("comma(2)\n");
@@ -569,13 +576,13 @@ parse_statement(StatementClass *stmt)
{
in_func = TRUE;
blevel = 1;
- fi[stmt->nfld - 1]->func = TRUE;
+ fi[irdflds->nfields - 1]->func = TRUE;
/*
* name will have the function name -- maybe useful some
* day
*/
- mylog("**** got function = '%s'\n", fi[stmt->nfld - 1]->name);
+ mylog("**** got function = '%s'\n", fi[irdflds->nfields - 1]->name);
continue;
}
@@ -595,11 +602,11 @@ parse_statement(StatementClass *stmt)
/* otherwise, it's probably an expression */
in_expr = TRUE;
- fi[stmt->nfld - 1]->expr = TRUE;
- fi[stmt->nfld - 1]->name[0] = '\0';
- fi[stmt->nfld - 1]->precision = 0;
+ fi[irdflds->nfields - 1]->expr = TRUE;
+ fi[irdflds->nfields - 1]->name[0] = '\0';
+ fi[irdflds->nfields - 1]->column_size = 0;
mylog("*** setting expression\n");
- }
+ } /* in_select end */
if (in_from)
{
@@ -607,6 +614,8 @@ parse_statement(StatementClass *stmt)
{
if (!token[0])
continue;
+ if (token[0] == ';')
+ break;
if (!(stmt->ntab % TAB_INCR))
{
@@ -658,12 +667,17 @@ parse_statement(StatementClass *stmt)
continue;
}
- strcpy(ti[stmt->ntab - 1]->alias, token);
- mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias);
- in_table = FALSE;
- if (delim == ',')
- mylog("more than 1 tables\n");
- }
+ if (token[0] == ';')
+ break;
+ if (stricmp(token, "as"))
+ {
+ strcpy(ti[stmt->ntab - 1]->alias, token);
+ mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias);
+ in_table = FALSE;
+ if (delim == ',')
+ mylog("more than 1 tables\n");
+ }
+ } /* in_from */
}
/*
@@ -673,7 +687,7 @@ parse_statement(StatementClass *stmt)
parse = TRUE;
/* Resolve field names with tables */
- for (i = 0; i < stmt->nfld; i++)
+ for (i = 0; i < (int) irdflds->nfields; i++)
{
if (fi[i]->func || fi[i]->expr || fi[i]->numeric)
{
@@ -687,16 +701,16 @@ parse_statement(StatementClass *stmt)
fi[i]->ti = NULL;
/*
- * fi[i]->type = PG_TYPE_TEXT; fi[i]->precision = 0; the
+ * fi[i]->type = PG_TYPE_TEXT; fi[i]->column_size = 0; the
* following may be better
*/
fi[i]->type = PG_TYPE_UNKNOWN;
- if (fi[i]->precision == 0)
+ if (fi[i]->column_size == 0)
{
fi[i]->type = PG_TYPE_VARCHAR;
- fi[i]->precision = 254;
+ fi[i]->column_size = 254;
}
- fi[i]->length = fi[i]->precision;
+ fi[i]->length = fi[i]->column_size;
continue;
}
/* it's a dot, resolve to table or alias */
@@ -721,9 +735,9 @@ parse_statement(StatementClass *stmt)
}
mylog("--------------------------------------------\n");
- mylog("nfld=%d, ntab=%d\n", stmt->nfld, stmt->ntab);
+ mylog("nfld=%d, ntab=%d\n", irdflds->nfields, stmt->ntab);
- for (i = 0; i < stmt->nfld; i++)
+ for (i = 0; i < (int) irdflds->nfields; i++)
{
mylog("Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, fi[i]->expr, fi[i]->func, fi[i]->quote, fi[i]->dquote, fi[i]->numeric, fi[i]->name, fi[i]->alias, fi[i]->dot);
if (fi[i]->ti)
@@ -836,7 +850,7 @@ parse_statement(StatementClass *stmt)
/*
* Now resolve the fields to point to column info
*/
- for (i = 0; i < stmt->nfld;)
+ for (i = 0; i < (int) irdflds->nfields;)
{
fi[i]->updatable = updatable;
/* Dont worry about functions or quotes */
@@ -875,8 +889,8 @@ parse_statement(StatementClass *stmt)
increased_cols = total_cols - 1;
/* Allocate some more field pointers if necessary */
- old_alloc = ((stmt->nfld - 1) / FLD_INCR + 1) * FLD_INCR;
- new_size = stmt->nfld + increased_cols;
+ old_alloc = ((irdflds->nfields - 1) / FLD_INCR + 1) * FLD_INCR;
+ new_size = irdflds->nfields + increased_cols;
mylog("k=%d, increased_cols=%d, old_alloc=%d, new_size=%d\n", k, increased_cols, old_alloc, new_size);
@@ -891,14 +905,14 @@ parse_statement(StatementClass *stmt)
stmt->parse_status = STMT_PARSE_FATAL;
return FALSE;
}
- stmt->fi = fi;
+ irdflds->fi = fi;
}
/*
* copy any other fields (if there are any) up past the
* expansion
*/
- for (j = stmt->nfld - 1; j > i; j--)
+ for (j = irdflds->nfields - 1; j > i; j--)
{
mylog("copying field %d to %d\n", j, increased_cols + j);
fi[increased_cols + j] = fi[j];
@@ -906,8 +920,8 @@ parse_statement(StatementClass *stmt)
mylog("done copying fields\n");
/* Set the new number of fields */
- stmt->nfld += increased_cols;
- mylog("stmt->nfld now at %d\n", stmt->nfld);
+ irdflds->nfields += increased_cols;
+ mylog("irdflds->nfields now at %d\n", irdflds->nfields);
/* copy the new field info */
@@ -990,6 +1004,7 @@ parse_statement(StatementClass *stmt)
else
stmt->parse_status = STMT_PARSE_COMPLETE;
+ stmt->updatable = updatable;
mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status);
return parse;
}
diff --git a/src/interfaces/odbc/pgapi30.c b/src/interfaces/odbc/pgapi30.c
index 6e4c575e31e..a67cc434fab 100644
--- a/src/interfaces/odbc/pgapi30.c
+++ b/src/interfaces/odbc/pgapi30.c
@@ -24,8 +24,10 @@
#include "environ.h"
#include "connection.h"
#include "statement.h"
+#include "descriptor.h"
#include "pgapifunc.h"
+static HSTMT statementHandleFromDescHandle(HSTMT, SQLINTEGER *descType);
/* SQLError -> SQLDiagRec */
RETCODE SQL_API
PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
@@ -54,6 +56,12 @@ PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
NativeError, MessageText, BufferLength,
TextLength, 0);
break;
+ case SQL_HANDLE_DESC:
+ ret = PGAPI_StmtError(statementHandleFromDescHandle(Handle, NULL),
+ RecNumber, Sqlstate, NativeError,
+ MessageText, BufferLength,
+ TextLength, 0);
+ break;
default:
ret = SQL_ERROR;
}
@@ -131,21 +139,37 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
SQLINTEGER Attribute, PTR Value,
SQLINTEGER BufferLength, SQLINTEGER *StringLength)
{
+ static const char *func = "PGAPI_GetConnectAttr";
ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+ RETCODE ret = SQL_SUCCESS;
+ SQLINTEGER len = 4;
mylog("PGAPI_GetConnectAttr %d\n", Attribute);
switch (Attribute)
{
case SQL_ATTR_ASYNC_ENABLE:
+ *((SQLUINTEGER *) Value) = SQL_ASYNC_ENABLE_OFF;
+ break;
case SQL_ATTR_AUTO_IPD:
+ *((SQLUINTEGER *) Value) = SQL_FALSE;
+ break;
case SQL_ATTR_CONNECTION_DEAD:
+ *((SQLUINTEGER *) Value) = SQL_CD_FALSE;
+ break;
case SQL_ATTR_CONNECTION_TIMEOUT:
+ *((SQLUINTEGER *) Value) = 0;
+ break;
case SQL_ATTR_METADATA_ID:
conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
conn->errormsg = "Unsupported connect attribute (Get)";
+ CC_log_error(func, "", conn);
return SQL_ERROR;
+ default:
+ ret = PGAPI_GetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
}
- return PGAPI_GetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
+ if (StringLength)
+ *StringLength = len;
+ return ret;
}
static HSTMT
@@ -168,113 +192,263 @@ static HSTMT
statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType)
{
SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4;
- switch (res)
+ if (descType)
{
- case 0: *descType = SQL_ATTR_APP_ROW_DESC; /* 10010 */
- break;
- case 1: *descType = SQL_ATTR_APP_PARAM_DESC; /* 10011 */
- break;
- case 2: *descType = SQL_ATTR_IMP_ROW_DESC; /* 10012 */
- break;
- case 3: *descType = SQL_ATTR_IMP_PARAM_DESC; /* 10013 */
- break;
+ switch (res)
+ {
+ case 0: *descType = SQL_ATTR_APP_ROW_DESC; /* 10010 */
+ break;
+ case 1: *descType = SQL_ATTR_APP_PARAM_DESC; /* 10011 */
+ break;
+ case 2: *descType = SQL_ATTR_IMP_ROW_DESC; /* 10012 */
+ break;
+ case 3: *descType = SQL_ATTR_IMP_PARAM_DESC; /* 10013 */
+ break;
+ }
}
return (HSTMT) ((SQLUINTEGER) DescHandle - res);
}
+static void column_bindings_set(ARDFields *opts, int cols, BOOL maxset)
+{
+ int i;
+
+ if (cols == opts->allocated)
+ return;
+ if (cols > opts->allocated)
+ {
+ extend_column_bindings(opts, cols);
+ return;
+ }
+ if (maxset) return;
+
+ for (i = opts->allocated; i > cols; i--)
+ reset_a_column_binding(opts, i);
+ opts->allocated = cols;
+ if (0 == cols)
+ {
+ free(opts->bindings);
+ opts->bindings = NULL;
+ }
+}
+
static RETCODE SQL_API
ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
{
RETCODE ret = SQL_SUCCESS;
PTR tptr;
+ ARDFields *opts = SC_get_ARD(stmt);
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_SIZE:
- stmt->options.rowset_size = (SQLUINTEGER) Value;
+ opts->rowset_size = (SQLUINTEGER) Value;
break;
case SQL_DESC_ARRAY_STATUS_PTR:
- stmt->options.row_operation_ptr = Value;
+ opts->row_operation_ptr = Value;
break;
case SQL_DESC_BIND_OFFSET_PTR:
- stmt->options.row_offset_ptr = Value;
+ opts->row_offset_ptr = Value;
break;
case SQL_DESC_BIND_TYPE:
- stmt->options.bind_size = (SQLUINTEGER) Value;
+ opts->bind_size = (SQLUINTEGER) Value;
break;
+ case SQL_DESC_TYPE:
+ column_bindings_set(opts, RecNumber, TRUE);
+ reset_a_column_binding(opts, RecNumber);
+ opts->bindings[RecNumber - 1].returntype = (Int4) Value;
+ break;
+ case SQL_DESC_DATETIME_INTERVAL_CODE:
+ column_bindings_set(opts, RecNumber, TRUE);
+ switch (opts->bindings[RecNumber - 1].returntype)
+ {
+ case SQL_DATETIME:
+ case SQL_C_TYPE_DATE:
+ case SQL_C_TYPE_TIME:
+ case SQL_C_TYPE_TIMESTAMP:
+ switch ((Int4) Value)
+ {
+ case SQL_CODE_DATE:
+ opts->bindings[RecNumber - 1].returntype = SQL_C_TYPE_DATE;
+ break;
+ case SQL_CODE_TIME:
+ opts->bindings[RecNumber - 1].returntype = SQL_C_TYPE_TIME;
+ break;
+ case SQL_CODE_TIMESTAMP:
+ opts->bindings[RecNumber - 1].returntype = SQL_C_TYPE_TIMESTAMP;
+ break;
+ }
+ break;
+ }
+ break;
+ case SQL_DESC_CONCISE_TYPE:
+ column_bindings_set(opts, RecNumber, TRUE);
+ opts->bindings[RecNumber - 1].returntype = (Int4) Value;
+ break;
case SQL_DESC_DATA_PTR:
if (!RecNumber)
- stmt->bookmark.buffer = Value;
+ opts->bookmark->buffer = Value;
else
- stmt->bindings[RecNumber - 1].buffer = Value;
+ {
+ column_bindings_set(opts, RecNumber, TRUE);
+ opts->bindings[RecNumber - 1].buffer = Value;
+ }
break;
case SQL_DESC_INDICATOR_PTR:
if (!RecNumber)
- tptr = stmt->bookmark.used;
+ tptr = opts->bookmark->used;
else
- tptr = stmt->bindings[RecNumber - 1].used;
+ {
+ column_bindings_set(opts, RecNumber, TRUE);
+ tptr = opts->bindings[RecNumber - 1].used;
+ }
if (Value != tptr)
{
ret = SQL_ERROR;
- stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
+ stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
stmt->errormsg = "INDICATOR != OCTET_LENGTH_PTR";
}
break;
case SQL_DESC_OCTET_LENGTH_PTR:
if (!RecNumber)
- stmt->bookmark.used = Value;
+ opts->bookmark->used = Value;
else
- stmt->bindings[RecNumber - 1].used = Value;
+ {
+ column_bindings_set(opts, RecNumber, TRUE);
+ opts->bindings[RecNumber - 1].used = Value;
+ }
+ break;
+ case SQL_DESC_COUNT:
+ column_bindings_set(opts, (SQLUINTEGER) Value, FALSE);
+ break;
+ case SQL_DESC_OCTET_LENGTH:
+ if (RecNumber)
+ {
+ column_bindings_set(opts, RecNumber, TRUE);
+ opts->bindings[RecNumber - 1].buflen = (Int4) Value;
+ }
break;
+ case SQL_DESC_ALLOC_TYPE: /* read-only */
+ case SQL_DESC_DATETIME_INTERVAL_PRECISION:
+ case SQL_DESC_LENGTH:
+ case SQL_DESC_NUM_PREC_RADIX:
+ case SQL_DESC_PRECISION:
+ case SQL_DESC_SCALE:
default:ret = SQL_ERROR;
- stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
- stmt->errormsg = "not implemedted yet";
+ stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
}
return ret;
}
+static void parameter_bindings_set(APDFields *opts, int params, BOOL maxset)
+{
+ int i;
+
+ if (params == opts->allocated)
+ return;
+ if (params > opts->allocated)
+ {
+ extend_parameter_bindings(opts, params);
+ return;
+ }
+ if (maxset) return;
+
+ for (i = opts->allocated; i > params; i--)
+ reset_a_parameter_binding(opts, i);
+ opts->allocated = params;
+ if (0 == params)
+ {
+ free(opts->parameters);
+ opts->parameters = NULL;
+ }
+}
+
static RETCODE SQL_API
APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
{
RETCODE ret = SQL_SUCCESS;
+ APDFields *opts = SC_get_APD(stmt);
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_SIZE:
- stmt->options.paramset_size = (SQLUINTEGER) Value;
+ opts->paramset_size = (SQLUINTEGER) Value;
break;
case SQL_DESC_ARRAY_STATUS_PTR:
- stmt->options.param_operation_ptr = Value;
+ opts->param_operation_ptr = Value;
break;
case SQL_DESC_BIND_OFFSET_PTR:
- stmt->options.param_offset_ptr = Value;
+ opts->param_offset_ptr = Value;
break;
case SQL_DESC_BIND_TYPE:
- stmt->options.param_bind_type = (SQLUINTEGER) Value;
+ opts->param_bind_type = (SQLUINTEGER) Value;
break;
+ case SQL_DESC_TYPE:
+ parameter_bindings_set(opts, RecNumber, TRUE);
+ reset_a_parameter_binding(opts, RecNumber);
+ opts->parameters[RecNumber - 1].CType = (Int4) Value;
+ break;
+ case SQL_DESC_DATETIME_INTERVAL_CODE:
+ parameter_bindings_set(opts, RecNumber, TRUE);
+ switch (opts->parameters[RecNumber - 1].CType)
+ {
+ case SQL_DATETIME:
+ case SQL_C_TYPE_DATE:
+ case SQL_C_TYPE_TIME:
+ case SQL_C_TYPE_TIMESTAMP:
+ switch ((Int4) Value)
+ {
+ case SQL_CODE_DATE:
+ opts->parameters[RecNumber - 1].CType = SQL_C_TYPE_DATE;
+ break;
+ case SQL_CODE_TIME:
+ opts->parameters[RecNumber - 1].CType = SQL_C_TYPE_TIME;
+ break;
+ case SQL_CODE_TIMESTAMP:
+ opts->parameters[RecNumber - 1].CType = SQL_C_TYPE_TIMESTAMP;
+ break;
+ }
+ break;
+ }
+ break;
+ case SQL_DESC_CONCISE_TYPE:
+ parameter_bindings_set(opts, RecNumber, TRUE);
+ opts->parameters[RecNumber - 1].CType = (Int4) Value;
+ break;
case SQL_DESC_DATA_PTR:
- if (stmt->parameters_allocated < RecNumber)
- PGAPI_BindParameter(stmt, RecNumber, 0, 0, 0, 0, 0, 0, 0, 0);
- stmt->parameters[RecNumber - 1].buffer = Value;
+ parameter_bindings_set(opts, RecNumber, TRUE);
+ opts->parameters[RecNumber - 1].buffer = Value;
break;
case SQL_DESC_INDICATOR_PTR:
- if (stmt->parameters_allocated < RecNumber ||
- Value != stmt->parameters[RecNumber - 1].used)
+ if (opts->allocated < RecNumber ||
+ Value != opts->parameters[RecNumber - 1].used)
{
ret = SQL_ERROR;
- stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
+ stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
stmt->errormsg = "INDICATOR != OCTET_LENGTH_PTR";
}
break;
+ case SQL_DESC_OCTET_LENGTH:
+ parameter_bindings_set(opts, RecNumber, TRUE);
+ opts->parameters[RecNumber - 1].buflen = (Int4) Value;
+ break;
case SQL_DESC_OCTET_LENGTH_PTR:
- if (stmt->parameters_allocated < RecNumber)
- PGAPI_BindParameter(stmt, RecNumber, 0, 0, 0, 0, 0, 0, 0, 0);
- stmt->parameters[RecNumber - 1].used = Value;
+ parameter_bindings_set(opts, RecNumber, TRUE);
+ opts->parameters[RecNumber - 1].used = Value;
break;
+ case SQL_DESC_COUNT:
+ parameter_bindings_set(opts, (SQLUINTEGER) Value, FALSE);
+ break;
+ case SQL_DESC_ALLOC_TYPE: /* read-only */
+ case SQL_DESC_DATETIME_INTERVAL_PRECISION:
+ case SQL_DESC_LENGTH:
+ case SQL_DESC_NUM_PREC_RADIX:
+ case SQL_DESC_PRECISION:
+ case SQL_DESC_SCALE:
default:ret = SQL_ERROR;
- stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
+ stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
}
return ret;
}
@@ -284,16 +458,51 @@ IRDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
{
RETCODE ret = SQL_SUCCESS;
+ IRDFields *opts = SC_get_IRD(stmt);
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_STATUS_PTR:
- stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
+ opts->rowStatusArray = (SQLUSMALLINT *) Value;
break;
case SQL_DESC_ROWS_PROCESSED_PTR:
- stmt->options.rowsFetched = (SQLUINTEGER *) Value;
+ opts->rowsFetched = (SQLUINTEGER *) Value;
break;
+ case SQL_DESC_ALLOC_TYPE: /* read-only */
+ case SQL_DESC_COUNT: /* read-only */
+ case SQL_DESC_AUTO_UNIQUE_VALUE: /* read-only */
+ case SQL_DESC_BASE_COLUMN_NAME: /* read-only */
+ case SQL_DESC_BASE_TABLE_NAME: /* read-only */
+ case SQL_DESC_CASE_SENSITIVE: /* read-only */
+ case SQL_DESC_CATALOG_NAME: /* read-only */
+ case SQL_DESC_CONCISE_TYPE: /* read-only */
+ case SQL_DESC_DATETIME_INTERVAL_CODE: /* read-only */
+ case SQL_DESC_DATETIME_INTERVAL_PRECISION: /* read-only */
+ case SQL_DESC_DISPLAY_SIZE: /* read-only */
+ case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
+ case SQL_DESC_LABEL: /* read-only */
+ case SQL_DESC_LENGTH: /* read-only */
+ case SQL_DESC_LITERAL_PREFIX: /* read-only */
+ case SQL_DESC_LITERAL_SUFFIX: /* read-only */
+ case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
+ case SQL_DESC_NAME: /* read-only */
+ case SQL_DESC_NULLABLE: /* read-only */
+ case SQL_DESC_NUM_PREC_RADIX: /* read-only */
+ case SQL_DESC_OCTET_LENGTH: /* read-only */
+ case SQL_DESC_PRECISION: /* read-only */
+#if (ODBCVER >= 0x0350)
+ case SQL_DESC_ROWVER: /* read-only */
+#endif /* ODBCVER */
+ case SQL_DESC_SCALE: /* read-only */
+ case SQL_DESC_SCHEMA_NAME: /* read-only */
+ case SQL_DESC_SEARCHABLE: /* read-only */
+ case SQL_DESC_TABLE_NAME: /* read-only */
+ case SQL_DESC_TYPE: /* read-only */
+ case SQL_DESC_TYPE_NAME: /* read-only */
+ case SQL_DESC_UNNAMED: /* read-only */
+ case SQL_DESC_UNSIGNED: /* read-only */
+ case SQL_DESC_UPDATABLE: /* read-only */
default:ret = SQL_ERROR;
- stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
+ stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
}
return ret;
}
@@ -303,17 +512,526 @@ IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
{
RETCODE ret = SQL_SUCCESS;
+ IPDFields *ipdopts = SC_get_IPD(stmt);
+ APDFields *apdopts = SC_get_APD(stmt);
+
+ switch (FieldIdentifier)
+ {
+ case SQL_DESC_ARRAY_STATUS_PTR:
+ ipdopts->param_status_ptr = (SQLUSMALLINT *) Value;
+ break;
+ case SQL_DESC_ROWS_PROCESSED_PTR:
+ ipdopts->param_processed_ptr = (SQLUINTEGER *) Value;
+ break;
+ case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
+ if (SQL_UNNAMED != (SQLUINTEGER) Value)
+ {
+ ret = SQL_ERROR;
+ stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
+ }
+ break;
+ case SQL_DESC_TYPE:
+ parameter_bindings_set(apdopts, RecNumber, TRUE);
+ apdopts->parameters[RecNumber - 1].SQLType = (Int4) Value;
+ break;
+ case SQL_DESC_DATETIME_INTERVAL_CODE:
+ parameter_bindings_set(apdopts, RecNumber, TRUE);
+ switch (apdopts->parameters[RecNumber - 1].SQLType)
+ {
+ case SQL_DATETIME:
+ case SQL_TYPE_DATE:
+ case SQL_TYPE_TIME:
+ case SQL_TYPE_TIMESTAMP:
+ switch ((Int4) Value)
+ {
+ case SQL_CODE_DATE:
+ apdopts->parameters[RecNumber - 1].SQLType = SQL_TYPE_DATE;
+ break;
+ case SQL_CODE_TIME:
+ apdopts->parameters[RecNumber - 1].SQLType = SQL_TYPE_TIME;
+ break;
+ case SQL_CODE_TIMESTAMP:
+ apdopts->parameters[RecNumber - 1].SQLType = SQL_TYPE_TIMESTAMP;
+ break;
+ }
+ break;
+ }
+ break;
+ case SQL_DESC_CONCISE_TYPE:
+ parameter_bindings_set(apdopts, RecNumber, TRUE);
+ apdopts->parameters[RecNumber - 1].SQLType = (Int4) Value;
+ break;
+ case SQL_DESC_COUNT:
+ parameter_bindings_set(apdopts, (SQLUINTEGER) Value, FALSE);
+ break;
+ case SQL_DESC_PARAMETER_TYPE:
+ apdopts->parameters[RecNumber - 1].paramType = (Int2) Value;
+ break;
+ case SQL_DESC_SCALE:
+ apdopts->parameters[RecNumber - 1].scale = (Int2) Value;
+ break;
+ case SQL_DESC_ALLOC_TYPE: /* read-only */
+ case SQL_DESC_CASE_SENSITIVE: /* read-only */
+ case SQL_DESC_DATETIME_INTERVAL_PRECISION:
+ case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
+ case SQL_DESC_LENGTH:
+ case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
+ case SQL_DESC_NAME:
+ case SQL_DESC_NULLABLE: /* read-only */
+ case SQL_DESC_NUM_PREC_RADIX:
+ case SQL_DESC_OCTET_LENGTH:
+ case SQL_DESC_PRECISION:
+#if (ODBCVER >= 0x0350)
+ case SQL_DESC_ROWVER: /* read-only */
+#endif /* ODBCVER */
+ case SQL_DESC_TYPE_NAME: /* read-only */
+ case SQL_DESC_UNSIGNED: /* read-only */
+ default:ret = SQL_ERROR;
+ stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
+ }
+ return ret;
+}
+
+
+static RETCODE SQL_API
+ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+ SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
+ SQLINTEGER *StringLength)
+{
+ RETCODE ret = SQL_SUCCESS;
+ SQLINTEGER len, ival;
+ PTR ptr = NULL;
+ const ARDFields *opts = SC_get_ARD(stmt);
+
+ len = 4;
+ switch (FieldIdentifier)
+ {
+ case SQL_DESC_ARRAY_SIZE:
+ ival = opts->rowset_size;
+ break;
+ case SQL_DESC_ARRAY_STATUS_PTR:
+ ptr = opts->row_operation_ptr;
+ break;
+ case SQL_DESC_BIND_OFFSET_PTR:
+ ptr = opts->row_offset_ptr;
+ break;
+ case SQL_DESC_BIND_TYPE:
+ ival = opts->bind_size;
+ break;
+ case SQL_DESC_TYPE:
+ switch (opts->bindings[RecNumber - 1].returntype)
+ {
+ case SQL_C_TYPE_DATE:
+ case SQL_C_TYPE_TIME:
+ case SQL_C_TYPE_TIMESTAMP:
+ ival = SQL_DATETIME;
+ break;
+ default:
+ ival = opts->bindings[RecNumber - 1].returntype;
+ }
+ break;
+ case SQL_DESC_DATETIME_INTERVAL_CODE:
+ switch (opts->bindings[RecNumber - 1].returntype)
+ {
+ case SQL_C_TYPE_DATE:
+ ival = SQL_CODE_DATE;
+ break;
+ case SQL_C_TYPE_TIME:
+ ival = SQL_CODE_TIME;
+ break;
+ case SQL_C_TYPE_TIMESTAMP:
+ ival = SQL_CODE_TIMESTAMP;
+ break;
+ default:
+ ival = 0;
+ break;
+ }
+ break;
+ case SQL_DESC_CONCISE_TYPE:
+ ival = opts->bindings[RecNumber - 1].returntype;
+ break;
+ case SQL_DESC_DATA_PTR:
+ if (!RecNumber)
+ ptr = opts->bookmark->buffer;
+ else
+ {
+ ptr = opts->bindings[RecNumber - 1].buffer;
+ }
+ break;
+ case SQL_DESC_INDICATOR_PTR:
+ if (!RecNumber)
+ ptr = opts->bookmark->used;
+ else
+ {
+ ptr = opts->bindings[RecNumber - 1].used;
+ }
+ break;
+ case SQL_DESC_OCTET_LENGTH_PTR:
+ if (!RecNumber)
+ ptr = opts->bookmark->used;
+ else
+ {
+ ptr = opts->bindings[RecNumber - 1].used;
+ }
+ break;
+ case SQL_DESC_COUNT:
+ ival = opts->allocated;
+ break;
+ case SQL_DESC_OCTET_LENGTH:
+ if (RecNumber)
+ {
+ ival = opts->bindings[RecNumber - 1].buflen;
+ }
+ break;
+ case SQL_DESC_ALLOC_TYPE: /* read-only */
+ ival = SQL_DESC_ALLOC_AUTO;
+ break;
+ case SQL_DESC_DATETIME_INTERVAL_PRECISION:
+ case SQL_DESC_LENGTH:
+ case SQL_DESC_NUM_PREC_RADIX:
+ case SQL_DESC_PRECISION:
+ case SQL_DESC_SCALE:
+ default:ret = SQL_ERROR;
+ stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
+ }
+ switch (BufferLength)
+ {
+ case 0:
+ case SQL_IS_INTEGER:
+ len = 4;
+ *((SQLINTEGER *) Value) = ival;
+ break;
+ case SQL_IS_UINTEGER:
+ len = 4;
+ *((UInt4 *) Value) = ival;
+ break;
+ case SQL_IS_SMALLINT:
+ len = 2;
+ *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
+ break;
+ case SQL_IS_USMALLINT:
+ len = 2;
+ *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
+ break;
+ case SQL_IS_POINTER:
+ len = 4;
+ *((void **) Value) = ptr;
+ break;
+ }
+
+ if (StringLength)
+ *StringLength = len;
+ return ret;
+}
+
+static RETCODE SQL_API
+APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+ SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
+ SQLINTEGER *StringLength)
+{
+ RETCODE ret = SQL_SUCCESS;
+ SQLINTEGER ival = 0, len;
+ PTR ptr = NULL;
+ const APDFields *opts = SC_get_APD(stmt);
+
+ len = 4;
+ switch (FieldIdentifier)
+ {
+ case SQL_DESC_ARRAY_SIZE:
+ ival = opts->paramset_size;
+ break;
+ case SQL_DESC_ARRAY_STATUS_PTR:
+ ptr = opts->param_operation_ptr;
+ break;
+ case SQL_DESC_BIND_OFFSET_PTR:
+ ptr = opts->param_offset_ptr;
+ break;
+ case SQL_DESC_BIND_TYPE:
+ ival = opts->param_bind_type;
+ break;
+
+ case SQL_DESC_TYPE:
+ switch (opts->parameters[RecNumber - 1].CType)
+ {
+ case SQL_C_TYPE_DATE:
+ case SQL_C_TYPE_TIME:
+ case SQL_C_TYPE_TIMESTAMP:
+ ival = SQL_DATETIME;
+ break;
+ default:
+ ival = opts->parameters[RecNumber - 1].CType;
+ }
+ break;
+ case SQL_DESC_DATETIME_INTERVAL_CODE:
+ switch (opts->parameters[RecNumber - 1].CType)
+ {
+ case SQL_C_TYPE_DATE:
+ ival = SQL_CODE_DATE;
+ break;
+ case SQL_C_TYPE_TIME:
+ ival = SQL_CODE_TIME;
+ break;
+ case SQL_C_TYPE_TIMESTAMP:
+ ival = SQL_CODE_TIMESTAMP;
+ break;
+ default:
+ ival = 0;
+ break;
+ }
+ break;
+ case SQL_DESC_CONCISE_TYPE:
+ ival = opts->parameters[RecNumber - 1].CType;
+ break;
+ case SQL_DESC_DATA_PTR:
+ ptr = opts->parameters[RecNumber - 1].buffer;
+ break;
+ case SQL_DESC_INDICATOR_PTR:
+ ptr = opts->parameters[RecNumber - 1].used;
+ break;
+ case SQL_DESC_OCTET_LENGTH:
+ ival = opts->parameters[RecNumber - 1].buflen;
+ break;
+ case SQL_DESC_OCTET_LENGTH_PTR:
+ ptr = opts->parameters[RecNumber - 1].used;
+ break;
+ case SQL_DESC_COUNT:
+ ival = opts->allocated;
+ break;
+ case SQL_DESC_ALLOC_TYPE: /* read-only */
+ ival = SQL_DESC_ALLOC_AUTO;
+ break;
+ case SQL_DESC_DATETIME_INTERVAL_PRECISION:
+ case SQL_DESC_LENGTH:
+ case SQL_DESC_NUM_PREC_RADIX:
+ case SQL_DESC_PRECISION:
+ case SQL_DESC_SCALE:
+ default:ret = SQL_ERROR;
+ stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
+ }
+ switch (BufferLength)
+ {
+ case 0:
+ case SQL_IS_INTEGER:
+ len = 4;
+ *((Int4 *) Value) = ival;
+ break;
+ case SQL_IS_UINTEGER:
+ len = 4;
+ *((UInt4 *) Value) = ival;
+ break;
+ case SQL_IS_SMALLINT:
+ len = 2;
+ *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
+ break;
+ case SQL_IS_USMALLINT:
+ len = 2;
+ *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
+ break;
+ case SQL_IS_POINTER:
+ len = 4;
+ *((void **) Value) = ptr;
+ break;
+ }
+
+ if (StringLength)
+ *StringLength = len;
+ return ret;
+}
+
+static RETCODE SQL_API
+IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+ SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
+ SQLINTEGER *StringLength)
+{
+ RETCODE ret = SQL_SUCCESS;
+ SQLINTEGER ival = 0, len;
+ PTR ptr = NULL;
+ const IRDFields *opts = SC_get_IRD(stmt);
+
+ switch (FieldIdentifier)
+ {
+ case SQL_DESC_ARRAY_STATUS_PTR:
+ ptr = opts->rowStatusArray;
+ break;
+ case SQL_DESC_ROWS_PROCESSED_PTR:
+ ptr = opts->rowsFetched;
+ break;
+ case SQL_DESC_ALLOC_TYPE: /* read-only */
+ case SQL_DESC_COUNT: /* read-only */
+ case SQL_DESC_AUTO_UNIQUE_VALUE: /* read-only */
+ case SQL_DESC_BASE_COLUMN_NAME: /* read-only */
+ case SQL_DESC_BASE_TABLE_NAME: /* read-only */
+ case SQL_DESC_CASE_SENSITIVE: /* read-only */
+ case SQL_DESC_CATALOG_NAME: /* read-only */
+ case SQL_DESC_CONCISE_TYPE: /* read-only */
+ case SQL_DESC_DATETIME_INTERVAL_CODE: /* read-only */
+ case SQL_DESC_DATETIME_INTERVAL_PRECISION: /* read-only */
+ case SQL_DESC_DISPLAY_SIZE: /* read-only */
+ case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
+ case SQL_DESC_LABEL: /* read-only */
+ case SQL_DESC_LENGTH: /* read-only */
+ case SQL_DESC_LITERAL_PREFIX: /* read-only */
+ case SQL_DESC_LITERAL_SUFFIX: /* read-only */
+ case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
+ case SQL_DESC_NAME: /* read-only */
+ case SQL_DESC_NULLABLE: /* read-only */
+ case SQL_DESC_NUM_PREC_RADIX: /* read-only */
+ case SQL_DESC_OCTET_LENGTH: /* read-only */
+ case SQL_DESC_PRECISION: /* read-only */
+#if (ODBCVER >= 0x0350)
+ case SQL_DESC_ROWVER: /* read-only */
+#endif /* ODBCVER */
+ case SQL_DESC_SCALE: /* read-only */
+ case SQL_DESC_SCHEMA_NAME: /* read-only */
+ case SQL_DESC_SEARCHABLE: /* read-only */
+ case SQL_DESC_TABLE_NAME: /* read-only */
+ case SQL_DESC_TYPE: /* read-only */
+ case SQL_DESC_TYPE_NAME: /* read-only */
+ case SQL_DESC_UNNAMED: /* read-only */
+ case SQL_DESC_UNSIGNED: /* read-only */
+ case SQL_DESC_UPDATABLE: /* read-only */
+ default:ret = SQL_ERROR;
+ stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
+ }
+ switch (BufferLength)
+ {
+ case 0:
+ case SQL_IS_INTEGER:
+ len = 4;
+ *((Int4 *) Value) = ival;
+ break;
+ case SQL_IS_UINTEGER:
+ len = 4;
+ *((UInt4 *) Value) = ival;
+ break;
+ case SQL_IS_SMALLINT:
+ len = 2;
+ *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
+ break;
+ case SQL_IS_USMALLINT:
+ len = 2;
+ *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
+ break;
+ case SQL_IS_POINTER:
+ len = 4;
+ *((void **) Value) = ptr;
+ break;
+ }
+
+ if (StringLength)
+ *StringLength = len;
+ return ret;
+}
+
+static RETCODE SQL_API
+IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+ SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
+ SQLINTEGER *StringLength)
+{
+ RETCODE ret = SQL_SUCCESS;
+ SQLINTEGER ival = 0, len;
+ PTR ptr = NULL;
+ const IPDFields *ipdopts = SC_get_IPD(stmt);
+ const APDFields *apdopts = SC_get_APD(stmt);
+
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_STATUS_PTR:
- stmt->options.param_status_ptr = (SQLUSMALLINT *) Value;
+ ptr = ipdopts->param_status_ptr;
break;
case SQL_DESC_ROWS_PROCESSED_PTR:
- stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
+ ptr = ipdopts->param_processed_ptr;
+ break;
+ case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
+ ival = SQL_UNNAMED;
+ break;
+ case SQL_DESC_TYPE:
+ switch (apdopts->parameters[RecNumber - 1].SQLType)
+ {
+ case SQL_TYPE_DATE:
+ case SQL_TYPE_TIME:
+ case SQL_TYPE_TIMESTAMP:
+ ival = SQL_DATETIME;
+ break;
+ default:
+ ival = apdopts->parameters[RecNumber - 1].SQLType;
+ }
+ break;
+ case SQL_DESC_DATETIME_INTERVAL_CODE:
+ switch (apdopts->parameters[RecNumber - 1].SQLType)
+ {
+ case SQL_TYPE_DATE:
+ ival = SQL_CODE_DATE;
+ case SQL_TYPE_TIME:
+ ival = SQL_CODE_TIME;
+ break;
+ case SQL_TYPE_TIMESTAMP:
+ ival = SQL_CODE_TIMESTAMP;
+ break;
+ default:
+ ival = 0;
+ }
+ break;
+ case SQL_DESC_CONCISE_TYPE:
+ ival = apdopts->parameters[RecNumber - 1].SQLType;
+ break;
+ case SQL_DESC_COUNT:
+ ival = apdopts->allocated;
+ break;
+ case SQL_DESC_PARAMETER_TYPE:
+ ival = apdopts->parameters[RecNumber - 1].paramType;
+ break;
+ case SQL_DESC_SCALE:
+ ival = apdopts->parameters[RecNumber - 1].scale ;
break;
+ case SQL_DESC_ALLOC_TYPE: /* read-only */
+ ival = SQL_DESC_ALLOC_AUTO;
+ break;
+ case SQL_DESC_CASE_SENSITIVE: /* read-only */
+ case SQL_DESC_DATETIME_INTERVAL_PRECISION:
+ case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
+ case SQL_DESC_LENGTH:
+ case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
+ case SQL_DESC_NAME:
+ case SQL_DESC_NULLABLE: /* read-only */
+ case SQL_DESC_NUM_PREC_RADIX:
+ case SQL_DESC_OCTET_LENGTH:
+ case SQL_DESC_PRECISION:
+#if (ODBCVER >= 0x0350)
+ case SQL_DESC_ROWVER: /* read-only */
+#endif /* ODBCVER */
+ case SQL_DESC_TYPE_NAME: /* read-only */
+ case SQL_DESC_UNSIGNED: /* read-only */
default:ret = SQL_ERROR;
- stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
+ stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
+ }
+ switch (BufferLength)
+ {
+ case 0:
+ case SQL_IS_INTEGER:
+ len = 4;
+ *((Int4 *) Value) = ival;
+ break;
+ case SQL_IS_UINTEGER:
+ len = 4;
+ *((UInt4 *) Value) = ival;
+ break;
+ case SQL_IS_SMALLINT:
+ len = 2;
+ *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
+ break;
+ case SQL_IS_USMALLINT:
+ len = 2;
+ *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
+ break;
+ case SQL_IS_POINTER:
+ len = 4;
+ *((void **)Value) = ptr;
+ break;
}
+
+ if (StringLength)
+ *StringLength = len;
return ret;
}
@@ -332,51 +1050,51 @@ PGAPI_GetStmtAttr(HSTMT StatementHandle,
switch (Attribute)
{
case SQL_ATTR_FETCH_BOOKMARK_PTR: /* 16 */
- Value = stmt->options.bookmark_ptr;
+ *((void **) Value) = stmt->options.bookmark_ptr;
len = 4;
break;
case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */
- Value = stmt->options.param_offset_ptr;
+ *((SQLUINTEGER **) Value) = SC_get_APD(stmt)->param_offset_ptr;
len = 4;
break;
case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */
- *((SQLUINTEGER *) Value) = stmt->options.param_bind_type;
+ *((SQLUINTEGER *) Value) = SC_get_APD(stmt)->param_bind_type;
len = 4;
break;
case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */
- Value = stmt->options.param_operation_ptr;
+ *((SQLUSMALLINT **) Value) = SC_get_APD(stmt)->param_operation_ptr;
len = 4;
break;
case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
- Value = stmt->options.param_status_ptr;
+ *((SQLUSMALLINT **) Value) = SC_get_IPD(stmt)->param_status_ptr;
len = 4;
break;
case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */
- Value = stmt->options.param_processed_ptr;
+ *((SQLUINTEGER **) Value) = SC_get_IPD(stmt)->param_processed_ptr;
len = 4;
break;
case SQL_ATTR_PARAMSET_SIZE: /* 22 */
- *((SQLUINTEGER *) Value) = stmt->options.paramset_size;
+ *((SQLUINTEGER *) Value) = SC_get_APD(stmt)->paramset_size;
len = 4;
break;
case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */
- Value = stmt->options.row_offset_ptr;
+ *((SQLUINTEGER **) Value) = SC_get_ARD(stmt)->row_offset_ptr;
len = 4;
break;
case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */
- Value = stmt->options.row_operation_ptr;
+ *((SQLUSMALLINT **) Value) = SC_get_ARD(stmt)->row_operation_ptr;
len = 4;
break;
case SQL_ATTR_ROW_STATUS_PTR: /* 25 */
- Value = stmt->options.rowStatusArray;
+ *((SQLUSMALLINT **) Value) = SC_get_IRD(stmt)->rowStatusArray;
len = 4;
break;
case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
- Value = stmt->options.rowsFetched;
+ *((SQLUINTEGER **) Value) = SC_get_IRD(stmt)->rowsFetched;
len = 4;
break;
case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */
- *((SQLUINTEGER *) Value) = stmt->options.rowset_size;
+ *((SQLUINTEGER *) Value) = SC_get_ARD(stmt)->rowset_size;
len = 4;
break;
case SQL_ATTR_APP_ROW_DESC: /* 10010 */
@@ -418,6 +1136,7 @@ PGAPI_SetConnectAttr(HDBC ConnectionHandle,
SQLINTEGER StringLength)
{
ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+ RETCODE ret = SQL_SUCCESS;
mylog("PGAPI_SetConnectAttr %d\n", Attribute);
switch (Attribute)
@@ -430,8 +1149,54 @@ PGAPI_SetConnectAttr(HDBC ConnectionHandle,
conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
conn->errormsg = "Unsupported connect attribute (Set)";
return SQL_ERROR;
+ default:
+ ret = PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
}
- return PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
+ return ret;
+}
+
+/* new function */
+RETCODE SQL_API
+PGAPI_GetDescField(SQLHDESC DescriptorHandle,
+ SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
+ PTR Value, SQLINTEGER BufferLength,
+ SQLINTEGER *StringLength)
+{
+ RETCODE ret = SQL_SUCCESS;
+ HSTMT hstmt;
+ SQLUINTEGER descType;
+ StatementClass *stmt;
+ static const char *func = "PGAPI_GetDescField";
+
+ mylog("%s h=%u rec=%d field=%d blen=%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, BufferLength);
+ hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType);
+ mylog("stmt=%x type=%d\n", hstmt, descType);
+ stmt = (StatementClass *) hstmt;
+ switch (descType)
+ {
+ case SQL_ATTR_APP_ROW_DESC:
+ ret = ARDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+ break;
+ case SQL_ATTR_APP_PARAM_DESC:
+ ret = APDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+ break;
+ case SQL_ATTR_IMP_ROW_DESC:
+ ret = IRDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+ break;
+ case SQL_ATTR_IMP_PARAM_DESC:
+ ret = IPDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+ break;
+ default:ret = SQL_ERROR;
+ stmt->errornumber = STMT_INTERNAL_ERROR;
+ stmt->errormsg = "Error not implemented";
+ }
+ if (ret == SQL_ERROR)
+ {
+ if (!stmt->errormsg && stmt->errornumber == STMT_INVALID_DESCRIPTOR_IDENTIFIER)
+ stmt->errormsg = "can't SQLGetDescField for this descriptor identifier";
+ SC_log_error(func, "", stmt);
+ }
+ return ret;
}
/* new function */
@@ -446,7 +1211,7 @@ PGAPI_SetDescField(SQLHDESC DescriptorHandle,
StatementClass *stmt;
static const char *func = "PGAPI_SetDescField";
- mylog("%s h=%u rec=%d field=%d val=%x\n", func, DescriptorHandle, RecNumber, FieldIdentifier, Value);
+ mylog("%s h=%u rec=%d field=%d val=%x,%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength);
hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType);
mylog("stmt=%x type=%d\n", hstmt, descType);
stmt = (StatementClass *) hstmt;
@@ -469,7 +1234,11 @@ PGAPI_SetDescField(SQLHDESC DescriptorHandle,
stmt->errormsg = "Error not implemented";
}
if (ret == SQL_ERROR)
+ {
+ if (!stmt->errormsg && stmt->errornumber == STMT_INVALID_DESCRIPTOR_IDENTIFIER)
+ stmt->errormsg = "can't SQLSetDescField for this descriptor identifier";
SC_log_error(func, "", stmt);
+ }
return ret;
}
@@ -511,37 +1280,37 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle,
stmt->options.bookmark_ptr = Value;
break;
case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */
- stmt->options.param_offset_ptr = (SQLUINTEGER *) Value;
+ SC_get_APD(stmt)->param_offset_ptr = (SQLUINTEGER *) Value;
break;
case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */
- stmt->options.param_bind_type = (SQLUINTEGER) Value;
+ SC_get_APD(stmt)->param_bind_type = (SQLUINTEGER) Value;
break;
case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */
- stmt->options.param_operation_ptr = Value;
+ SC_get_APD(stmt)->param_operation_ptr = Value;
break;
case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
- stmt->options.param_status_ptr = (SQLUSMALLINT *) Value;
+ SC_get_IPD(stmt)->param_status_ptr = (SQLUSMALLINT *) Value;
break;
case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */
- stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
+ SC_get_IPD(stmt)->param_processed_ptr = (SQLUINTEGER *) Value;
break;
case SQL_ATTR_PARAMSET_SIZE: /* 22 */
- stmt->options.paramset_size = (SQLUINTEGER) Value;
+ SC_get_APD(stmt)->paramset_size = (SQLUINTEGER) Value;
break;
case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */
- stmt->options.row_offset_ptr = (SQLUINTEGER *) Value;
+ SC_get_ARD(stmt)->row_offset_ptr = (SQLUINTEGER *) Value;
break;
case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */
- stmt->options.row_operation_ptr = Value;
+ SC_get_ARD(stmt)->row_operation_ptr = Value;
break;
case SQL_ATTR_ROW_STATUS_PTR: /* 25 */
- stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
+ SC_get_IRD(stmt)->rowStatusArray = (SQLUSMALLINT *) Value;
break;
case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
- stmt->options.rowsFetched = (SQLUINTEGER *) Value;
+ SC_get_IRD(stmt)->rowsFetched = (SQLUINTEGER *) Value;
break;
case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */
- stmt->options.rowset_size = (SQLUINTEGER) Value;
+ SC_get_ARD(stmt)->rowset_size = (SQLUINTEGER) Value;
break;
default:
return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) Value);
diff --git a/src/interfaces/odbc/pgapifunc.h b/src/interfaces/odbc/pgapifunc.h
index f7a72a28e43..a906a311deb 100644
--- a/src/interfaces/odbc/pgapifunc.h
+++ b/src/interfaces/odbc/pgapifunc.h
@@ -280,5 +280,8 @@ RETCODE SQL_API PGAPI_SetStmtAttr(HSTMT StatementHandle,
RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle,
SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
PTR Value, SQLINTEGER BufferLength);
+RETCODE SQL_API PGAPI_GetDescField(SQLHDESC DescriptorHandle,
+ SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
+ PTR Value, SQLINTEGER BufferLength, SQLINTEGER *StringLength);
#endif /* ODBCVER */
#endif /* define_PG_API_FUNC_H__ */
diff --git a/src/interfaces/odbc/pgtypes.c b/src/interfaces/odbc/pgtypes.c
index b40985866e6..691fd92c53a 100644
--- a/src/interfaces/odbc/pgtypes.c
+++ b/src/interfaces/odbc/pgtypes.c
@@ -26,7 +26,7 @@
-Int4 getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
+Int4 getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
/*
* these are the types we support. all of the pgtype_ functions should
@@ -230,13 +230,13 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
* types that are unknown. All other pg routines in here return a suitable default.
*/
Int2
-pgtype_to_sqltype(StatementClass *stmt, Int4 type)
+pgtype_to_concise_type(StatementClass *stmt, Int4 type)
{
ConnectionClass *conn = SC_get_conn(stmt);
ConnInfo *ci = &(conn->connInfo);
#if (ODBCVER >= 0x0300)
EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
-#endif
+#endif /* ODBCVER */
switch (type)
{
@@ -289,7 +289,7 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
if (!conn->ms_jet)
return SQL_BIGINT;
#endif /* ODBCVER */
- return SQL_CHAR;
+ return SQL_VARCHAR;
case PG_TYPE_NUMERIC:
return SQL_NUMERIC;
@@ -338,6 +338,40 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
}
}
+Int2
+pgtype_to_sqldesctype(StatementClass *stmt, Int4 type)
+{
+ Int2 rettype;
+
+ switch (rettype = pgtype_to_concise_type(stmt, type))
+ {
+#if (ODBCVER >= 0x0300)
+ case SQL_TYPE_DATE:
+ case SQL_TYPE_TIME:
+ case SQL_TYPE_TIMESTAMP:
+ return SQL_DATETIME;
+#endif /* ODBCVER */
+ }
+ return rettype;
+}
+
+Int2
+pgtype_to_datetime_sub(StatementClass *stmt, Int4 type)
+{
+ switch (pgtype_to_concise_type(stmt, type))
+ {
+#if (ODBCVER >= 0x0300)
+ case SQL_TYPE_DATE:
+ return SQL_CODE_DATE;
+ case SQL_TYPE_TIME:
+ return SQL_CODE_TIME;
+ case SQL_TYPE_TIMESTAMP:
+ return SQL_CODE_TIMESTAMP;
+#endif /* ODBCVER */
+ }
+ return -1;
+}
+
Int2
pgtype_to_ctype(StatementClass *stmt, Int4 type)
@@ -346,7 +380,7 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
ConnInfo *ci = &(conn->connInfo);
#if (ODBCVER >= 0x0300)
EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
-#endif
+#endif /* ODBCVER */
switch (type)
{
@@ -484,13 +518,13 @@ pgtype_to_name(StatementClass *stmt, Int4 type)
static Int2
-getNumericScale(StatementClass *stmt, Int4 type, int col)
+getNumericDecimalDigits(StatementClass *stmt, Int4 type, int col)
{
Int4 atttypmod = -1;
QResultClass *result;
ColumnInfoClass *flds;
- mylog("getNumericScale: type=%d, col=%d\n", type, col);
+ mylog("getNumericDecimalDigits: type=%d, col=%d\n", type, col);
if (col < 0)
return PG_NUMERIC_MAX_SCALE;
@@ -525,13 +559,13 @@ getNumericScale(StatementClass *stmt, Int4 type, int col)
static Int4
-getNumericPrecision(StatementClass *stmt, Int4 type, int col)
+getNumericColumnSize(StatementClass *stmt, Int4 type, int col)
{
Int4 atttypmod = -1;
QResultClass *result;
ColumnInfoClass *flds;
- mylog("getNumericPrecision: type=%d, col=%d\n", type, col);
+ mylog("getNumericColumnSize: type=%d, col=%d\n", type, col);
if (col < 0)
return PG_NUMERIC_MAX_PRECISION;
@@ -566,15 +600,15 @@ getNumericPrecision(StatementClass *stmt, Int4 type, int col)
Int4
-getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
{
- int p = -1,
+ int p = -1, attlen = -1,
maxsize;
QResultClass *result;
ColumnInfoClass *flds;
ConnInfo *ci = &(SC_get_conn(stmt)->connInfo);
- mylog("getCharPrecision: type=%d, col=%d, unknown = %d\n", type, col, handle_unknown_size_as);
+ mylog("getCharColumnSize: type=%d, col=%d, unknown = %d\n", type, col, handle_unknown_size_as);
/* Assign Maximum size based on parameters */
switch (type)
@@ -607,7 +641,7 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
maxsize = TEXT_FIELD_SIZE;
}
/*
- * Static Precision (i.e., the Maximum Precision of the datatype) This
+ * Static ColumnSize (i.e., the Maximum ColumnSize of the datatype) This
* has nothing to do with a result set.
*/
if (col < 0)
@@ -628,35 +662,37 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
return maxsize;
}
+ p = QR_get_display_size(result, col); /* longest */
+ attlen = QR_get_atttypmod(result, col);
/* Size is unknown -- handle according to parameter */
- if (QR_get_atttypmod(result, col) > -1)
- return QR_get_atttypmod(result, col);
+ if (attlen > p) /* maybe the length is known */
+ return attlen;
/* The type is really unknown */
if (type == PG_TYPE_BPCHAR || handle_unknown_size_as == UNKNOWNS_AS_LONGEST)
{
- p = QR_get_display_size(result, col);
- mylog("getCharPrecision: LONGEST: p = %d\n", p);
+ mylog("getCharColumnSize: LONGEST: p = %d\n", p);
if (p >= 0)
return p;
}
+ if (p > maxsize)
+ maxsize = p;
if (handle_unknown_size_as == UNKNOWNS_AS_MAX)
return maxsize;
else /* handle_unknown_size_as == DONT_KNOW */
return -1;
-
}
static Int2
-getTimestampScale(StatementClass *stmt, Int4 type, int col)
+getTimestampDecimalDigits(StatementClass *stmt, Int4 type, int col)
{
ConnectionClass *conn = SC_get_conn(stmt);
Int4 atttypmod;
QResultClass *result;
ColumnInfoClass *flds;
- mylog("getTimestampScale: type=%d, col=%d\n", type, col);
+ mylog("getTimestampDecimalDigits: type=%d, col=%d\n", type, col);
if (col < 0)
return 0;
@@ -685,12 +721,12 @@ getTimestampScale(StatementClass *stmt, Int4 type, int col)
static Int4
-getTimestampPrecision(StatementClass *stmt, Int4 type, int col)
+getTimestampColumnSize(StatementClass *stmt, Int4 type, int col)
{
Int4 fixed,
scale;
- mylog("getTimestampPrecision: type=%d, col=%d\n", type, col);
+ mylog("getTimestampColumnSize: type=%d, col=%d\n", type, col);
switch (type)
{
@@ -710,11 +746,13 @@ getTimestampPrecision(StatementClass *stmt, Int4 type, int col)
fixed = 19;
break;
}
- scale = getTimestampScale(stmt, type, col);
+ scale = getTimestampDecimalDigits(stmt, type, col);
return (scale > 0) ? fixed + 1 + scale : fixed;
}
/*
+ * This corresponds to "precision" in ODBC 2.x.
+ *
* For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, PG_TYPE_NUMERIC, SQLColumns will
* override this length with the atttypmod length from pg_attribute .
*
@@ -722,7 +760,7 @@ getTimestampPrecision(StatementClass *stmt, Int4 type, int col)
* This is used for functions SQLDescribeCol and SQLColAttributes.
*/
Int4
-pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
{
switch (type)
{
@@ -750,7 +788,7 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
return 19; /* signed */
case PG_TYPE_NUMERIC:
- return getNumericPrecision(stmt, type, col);
+ return getNumericColumnSize(stmt, type, col);
case PG_TYPE_FLOAT4:
case PG_TYPE_MONEY:
@@ -769,7 +807,7 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
return 22;
case PG_TYPE_DATETIME:
/* return 22; */
- return getTimestampPrecision(stmt, type, col);
+ return getTimestampColumnSize(stmt, type, col);
case PG_TYPE_BOOL:
{
@@ -787,8 +825,24 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
return SQL_NO_TOTAL;
/* Handle Character types and unknown types */
- return getCharPrecision(stmt, type, col, handle_unknown_size_as);
+ return getCharColumnSize(stmt, type, col, handle_unknown_size_as);
+ }
+}
+
+/*
+ * "precision in ODBC 3.x.
+ */
+Int4
+pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+{
+ switch (type)
+ {
+ case PG_TYPE_NUMERIC:
+ return getNumericColumnSize(stmt, type, col);
+ case PG_TYPE_DATETIME:
+ return getTimestampDecimalDigits(stmt, type, col);
}
+ return -1;
}
@@ -813,7 +867,7 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown
return 20; /* signed: 19 digits + sign */
case PG_TYPE_NUMERIC:
- dsize = getNumericPrecision(stmt, type, col);
+ dsize = getNumericColumnSize(stmt, type, col);
return dsize < 0 ? dsize : dsize + 2;
case PG_TYPE_MONEY:
@@ -827,60 +881,62 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown
/* Character types use regular precision */
default:
- return pgtype_precision(stmt, type, col, handle_unknown_size_as);
+ return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
}
}
/*
- * For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, SQLColumns will
- * override this length with the atttypmod length from pg_attribute
+ * The length in bytes of data transferred on an SQLGetData, SQLFetch,
+ * or SQLFetchScroll operation if SQL_C_DEFAULT is specified.
*/
Int4
-pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+pgtype_buffer_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
{
ConnectionClass *conn = SC_get_conn(stmt);
switch (type)
{
case PG_TYPE_INT2:
- return 2;
+ return 2; /* sizeof(SQLSMALLINT) */
case PG_TYPE_OID:
case PG_TYPE_XID:
case PG_TYPE_INT4:
- return 4;
+ return 4; /* sizeof(SQLINTEGER) */
case PG_TYPE_INT8:
- return 20; /* signed: 19 digits + sign */
+ if (SQL_C_CHAR == pgtype_to_ctype(stmt, type))
+ return 20; /* signed: 19 digits + sign */
+ return 8; /* sizeof(SQLSBININT) */
case PG_TYPE_NUMERIC:
- return getNumericPrecision(stmt, type, col) + 2;
+ return getNumericColumnSize(stmt, type, col) + 2;
case PG_TYPE_FLOAT4:
case PG_TYPE_MONEY:
- return 4;
+ return 4; /* sizeof(SQLREAL) */
case PG_TYPE_FLOAT8:
- return 8;
+ return 8; /* sizeof(SQLFLOAT) */
case PG_TYPE_DATE:
case PG_TYPE_TIME:
- return 6; /* sizeof(DATE(TIME)_STRUCT) */
+ return 6; /* sizeof(DATE(TIME)_STRUCT) */
case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP:
- return 16; /* sizeof(TIMESTAMP_STRUCT) */
+ return 16; /* sizeof(TIMESTAMP_STRUCT) */
- /* Character types (and NUMERIC) use the default precision */
+ /* Character types use the default precision */
case PG_TYPE_VARCHAR:
case PG_TYPE_BPCHAR:
{
int coef = 1;
- Int4 prec = pgtype_precision(stmt, type, col, handle_unknown_size_as), maxvarc;
+ Int4 prec = pgtype_column_size(stmt, type, col, handle_unknown_size_as), maxvarc;
if (conn->unicode)
- return (prec + 1) * 2;
+ return prec * 2;
#ifdef MULTIBYTE
/* after 7.2 */
if (PG_VERSION_GE(conn, 7.2))
@@ -891,20 +947,100 @@ pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_
/* CR -> CR/LF */
coef = 2;
if (coef == 1)
- return prec + 1;
+ return prec;
maxvarc = conn->connInfo.drivers.max_varchar_size;
if (prec <= maxvarc && prec * coef > maxvarc)
return maxvarc;
return coef * prec;
}
default:
- return pgtype_precision(stmt, type, col, handle_unknown_size_as);
+ return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
}
}
+/*
+ */
+Int4
+pgtype_desclength(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+{
+ switch (type)
+ {
+ case PG_TYPE_INT2:
+ return 2;
+
+ case PG_TYPE_OID:
+ case PG_TYPE_XID:
+ case PG_TYPE_INT4:
+ return 4;
+
+ case PG_TYPE_INT8:
+ return 20; /* signed: 19 digits + sign */
+ case PG_TYPE_NUMERIC:
+ return getNumericColumnSize(stmt, type, col) + 2;
+
+ case PG_TYPE_FLOAT4:
+ case PG_TYPE_MONEY:
+ return 4;
+
+ case PG_TYPE_FLOAT8:
+ return 8;
+
+ case PG_TYPE_DATE:
+ case PG_TYPE_TIME:
+ case PG_TYPE_ABSTIME:
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP:
+ case PG_TYPE_VARCHAR:
+ case PG_TYPE_BPCHAR:
+ return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
+ default:
+ return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
+ }
+}
+
+/*
+ * Transfer octet length.
+ */
+Int4
+pgtype_transfer_octet_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+{
+ ConnectionClass *conn = SC_get_conn(stmt);
+
+ int coef = 1;
+ Int4 prec = pgtype_column_size(stmt, type, col, handle_unknown_size_as), maxvarc;
+ switch (type)
+ {
+ case PG_TYPE_VARCHAR:
+ case PG_TYPE_BPCHAR:
+ if (conn->unicode)
+ return prec * 2;
+#ifdef MULTIBYTE
+ /* after 7.2 */
+ if (PG_VERSION_GE(conn, 7.2))
+ coef = 3;
+ else
+#endif /* MULTIBYTE */
+ if ((conn->connInfo).lf_conversion)
+ /* CR -> CR/LF */
+ coef = 2;
+ if (coef == 1)
+ return prec;
+ maxvarc = conn->connInfo.drivers.max_varchar_size;
+ if (prec <= maxvarc && prec * coef > maxvarc)
+ return maxvarc;
+ return coef * prec;
+ case PG_TYPE_BYTEA:
+ return prec;
+ }
+ return -1;
+}
+
+/*
+ * corrsponds to "scale" in ODBC 2.x.
+ */
Int2
-pgtype_scale(StatementClass *stmt, Int4 type, int col)
+pgtype_decimal_digits(StatementClass *stmt, Int4 type, int col)
{
switch (type)
{
@@ -927,16 +1063,30 @@ pgtype_scale(StatementClass *stmt, Int4 type, int col)
return 0;
case PG_TYPE_DATETIME:
/* return 0; */
- return getTimestampScale(stmt, type, col);
+ return getTimestampDecimalDigits(stmt, type, col);
case PG_TYPE_NUMERIC:
- return getNumericScale(stmt, type, col);
+ return getNumericDecimalDigits(stmt, type, col);
default:
return -1;
}
}
+/*
+ * "scale" in ODBC 3.x.
+ */
+Int2
+pgtype_scale(StatementClass *stmt, Int4 type, int col)
+{
+ switch (type)
+ {
+ case PG_TYPE_NUMERIC:
+ return getNumericDecimalDigits(stmt, type, col);
+ }
+ return -1;
+}
+
Int2
pgtype_radix(StatementClass *stmt, Int4 type)
diff --git a/src/interfaces/odbc/pgtypes.h b/src/interfaces/odbc/pgtypes.h
index 651817921fe..cef2362ddfe 100644
--- a/src/interfaces/odbc/pgtypes.h
+++ b/src/interfaces/odbc/pgtypes.h
@@ -72,16 +72,22 @@ extern Int2 sqlTypes[];
Int4 sqltype_to_pgtype(StatementClass *stmt, Int2 fSqlType);
-Int2 pgtype_to_sqltype(StatementClass *stmt, Int4 type);
+Int2 pgtype_to_concise_type(StatementClass *stmt, Int4 type);
+Int2 pgtype_to_sqldesctype(StatementClass *stmt, Int4 type);
+Int2 pgtype_to_datetime_sub(StatementClass *stmt, Int4 type);
Int2 pgtype_to_ctype(StatementClass *stmt, Int4 type);
char *pgtype_to_name(StatementClass *stmt, Int4 type);
/* These functions can use static numbers or result sets(col parameter) */
-Int4 pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
+Int4 pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as); /* corresponds to "precision" in ODBC 2.x */
+Int4 pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as); /* "precsion in ODBC 3.x */
Int4 pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
-Int4 pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
+Int4 pgtype_buffer_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
+Int4 pgtype_desclength(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
+Int4 pgtype_transfer_octet_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
-Int2 pgtype_scale(StatementClass *stmt, Int4 type, int col);
+Int2 pgtype_decimal_digits(StatementClass *stmt, Int4 type, int col); /* corresponds to "scale" in ODBC 2.x */
+Int2 pgtype_scale(StatementClass *stmt, Int4 type, int col); /* ODBC 3.x " */
Int2 pgtype_radix(StatementClass *stmt, Int4 type);
Int2 pgtype_nullable(StatementClass *stmt, Int4 type);
Int2 pgtype_auto_increment(StatementClass *stmt, Int4 type);
diff --git a/src/interfaces/odbc/psqlodbc.h b/src/interfaces/odbc/psqlodbc.h
index 958a3b6b102..a0d4be134b1 100644
--- a/src/interfaces/odbc/psqlodbc.h
+++ b/src/interfaces/odbc/psqlodbc.h
@@ -5,7 +5,7 @@
*
* Comments: See "notice.txt" for copyright and license information.
*
- * $Id: psqlodbc.h,v 1.60 2002/03/14 05:42:03 inoue Exp $
+ * $Id: psqlodbc.h,v 1.61 2002/03/28 08:08:06 inoue Exp $
*
*/
@@ -91,7 +91,11 @@ typedef UInt4 Oid;
#ifdef WIN32
#if (ODBCVER >= 0x0300)
+#ifdef UNICODE_SUPPORT
+#define DRIVER_FILE_NAME "PSQLODBC30W.DLL"
+#else
#define DRIVER_FILE_NAME "PSQLODBC30.DLL"
+#endif /* UNICODE_SUPPORT */
#else
#define DRIVER_FILE_NAME "PSQLODBC.DLL"
#endif /* ODBCVER */
@@ -167,6 +171,11 @@ typedef struct EnvironmentClass_ EnvironmentClass;
typedef struct TupleNode_ TupleNode;
typedef struct TupleField_ TupleField;
typedef struct KeySet_ KeySet;
+typedef struct Rollback_ Rollback;
+typedef struct ARDFields_ ARDFields;
+typedef struct APDFields_ APDFields;
+typedef struct IRDFields_ IRDFields;
+typedef struct IPDFields_ IPDFields;
typedef struct col_info COL_INFO;
typedef struct lo_arg LO_ARG;
@@ -201,25 +210,12 @@ typedef struct StatementOptions_
{
int maxRows;
int maxLength;
- int rowset_size;
int keyset_size;
int cursor_type;
int scroll_concurrency;
int retrieve_data;
- int bind_size; /* size of each structure if using Row
- * Binding */
int use_bookmarks;
- UInt4 *rowsFetched;
- UInt2 *rowStatusArray;
- void *bookmark_ptr;
- UInt2 *row_operation_ptr;
- UInt4 *row_offset_ptr;
- UInt4 paramset_size;
- UInt4 param_bind_type;
- UInt4 *param_processed_ptr;
- UInt2 *param_status_ptr;
- UInt2 *param_operation_ptr;
- UInt4 *param_offset_ptr;
+ void *bookmark_ptr;
} StatementOptions;
/* Used to pass extra query info to send_query */
@@ -260,6 +256,7 @@ UInt4 ucs2strlen(const SQLWCHAR *ucs2str);
char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen);
UInt4 utf8_to_ucs2(const char * utf8str, Int4 ilen, SQLWCHAR *ucs2str, UInt4 buflen);
#endif /* UNICODE_SUPPORT */
+/*#define _MEMORY_DEBUG_ */
#ifdef _MEMORY_DEBUG_
void *debug_alloc(size_t);
void *debug_realloc(void *, size_t);
diff --git a/src/interfaces/odbc/psqlodbc.rc b/src/interfaces/odbc/psqlodbc.rc
index 698bd6c74fe..7c99c038e20 100644
--- a/src/interfaces/odbc/psqlodbc.rc
+++ b/src/interfaces/odbc/psqlodbc.rc
@@ -138,7 +138,7 @@ BEGIN
BS_NOTIFY | WS_TABSTOP,247,205,40,10
END
-DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 267, 176
+DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 267, 196
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Advanced Options (DataSource)"
FONT 10, "Terminal"
@@ -155,23 +155,25 @@ BEGIN
BS_AUTOCHECKBOX | WS_TABSTOP,45,43,92,10
CONTROL "True is -1",DS_TRUEISMINUS1,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,149,43,86,10
- GROUPBOX "Protocol",IDC_STATIC,43,59,180,25
+ CONTROL "(Trial) Updatable cursors",DS_UPDATABLECURSORS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,45,58,112,10
+ GROUPBOX "Protocol",IDC_STATIC,43,74,180,25
CONTROL "7.X,6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON |
- WS_GROUP,53,69,47,10
+ WS_GROUP,53,84,47,10
CONTROL "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
- 131,69,26,10
+ 131,84,26,10
CONTROL "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
- 187,69,26,10
- GROUPBOX "OID Options",IDC_STATIC,43,89,180,25
+ 187,84,26,10
+ GROUPBOX "OID Options",IDC_STATIC,43,104,180,25
CONTROL "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX |
- WS_GROUP | WS_TABSTOP,53,100,59,10
+ WS_GROUP | WS_TABSTOP,53,115,59,10
CONTROL "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX |
- WS_GROUP | WS_TABSTOP,161,100,55,10
- LTEXT "Connect &Settings:",IDC_STATIC,10,120,35,25
- EDITTEXT DS_CONNSETTINGS,50,120,200,20,ES_MULTILINE |
+ WS_GROUP | WS_TABSTOP,161,115,55,10
+ LTEXT "Connect &Settings:",IDC_STATIC,10,135,35,25
+ EDITTEXT DS_CONNSETTINGS,50,135,200,20,ES_MULTILINE |
ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
- DEFPUSHBUTTON "OK",IDOK,71,150,50,14,WS_GROUP
- PUSHBUTTON "Cancel",IDCANCEL,146,150,50,14
+ DEFPUSHBUTTON "OK",IDOK,71,165,50,14,WS_GROUP
+ PUSHBUTTON "Cancel",IDCANCEL,146,165,50,14
END
#else
DLG_CONFIG DIALOG DISCARDABLE 65, 43, 292, 116
@@ -259,7 +261,7 @@ BEGIN
BS_NOTIFY | WS_TABSTOP,233,224,40,10
END
-DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 267, 176
+DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 267, 186
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Advanced Options (DataSource)"
FONT 8, "MS Sans Serif"
@@ -273,26 +275,28 @@ BEGIN
CONTROL "Disallow &Premature",DS_DISALLOWPREMATURE,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,130,25,85,10
CONTROL "LF <-> CR/LF convert",DS_LFCONVERSION,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,45,40,92,10
+ BS_AUTOCHECKBOX | WS_TABSTOP,25,40,92,10
CONTROL "True is -1",DS_TRUEISMINUS1,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,149,40,86,10
- GROUPBOX "Protocol",IDC_STATIC,15,55,180,25
+ BS_AUTOCHECKBOX | WS_TABSTOP,130,40,86,10
+ CONTROL "(Trial) Updatable Cursors",DS_UPDATABLECURSORS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,25,55,102,10
+ GROUPBOX "Protocol",IDC_STATIC,15,70,180,25
CONTROL "7.X,6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | WS_GROUP,25,
- 65,35,10
+ 80,35,10
CONTROL "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
- 75,65,26,10
+ 75,80,26,10
CONTROL "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
- 130,65,26,10
- GROUPBOX "OID Options",IDC_STATIC,15,86,180,25
+ 130,80,26,10
+ GROUPBOX "OID Options",IDC_STATIC,15,101,180,25
CONTROL "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX |
- WS_GROUP | WS_TABSTOP,25,96,59,10
+ WS_GROUP | WS_TABSTOP,25,111,59,10
CONTROL "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX |
- WS_GROUP | WS_TABSTOP,115,96,51,10
- RTEXT "Connect &Settings:",IDC_STATIC,10,120,35,25
- EDITTEXT DS_CONNSETTINGS,50,120,200,20,ES_MULTILINE |
+ WS_GROUP | WS_TABSTOP,115,111,51,10
+ RTEXT "Connect &Settings:",IDC_STATIC,10,135,35,25
+ EDITTEXT DS_CONNSETTINGS,50,135,200,20,ES_MULTILINE |
ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
- DEFPUSHBUTTON "OK",IDOK,71,150,50,14,WS_GROUP
- PUSHBUTTON "Cancel",IDCANCEL,146,150,50,14
+ DEFPUSHBUTTON "OK",IDOK,71,165,50,14,WS_GROUP
+ PUSHBUTTON "Cancel",IDCANCEL,146,165,50,14
END
#endif
diff --git a/src/interfaces/odbc/psqlodbc30w.reg b/src/interfaces/odbc/psqlodbc30w.reg
new file mode 100644
index 00000000000..81fd93e15c9
--- /dev/null
+++ b/src/interfaces/odbc/psqlodbc30w.reg
@@ -0,0 +1,16 @@
+REGEDIT4
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI]
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers]
+"PostgreSQL30W"="Installed"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\PostgreSQL30W]
+"APILevel"="1"
+"ConnectFunctions"="YYN"
+"Driver"="PSQLODBC30W.DLL"
+"DriverODBCVer"="03.00"
+"FileUsage"="0"
+"Setup"="PSQLODBC30W.DLL"
+"SQLLevel"="1"
+"UsageCount"=dword:00000001
diff --git a/src/interfaces/odbc/psqlodbc_api30.def b/src/interfaces/odbc/psqlodbc_api30.def
index a2031c7aba6..ddc78062e62 100755
--- a/src/interfaces/odbc/psqlodbc_api30.def
+++ b/src/interfaces/odbc/psqlodbc_api30.def
@@ -74,9 +74,9 @@ SQLSetDescField @96
SQLSetDescRec @97
SQLSetEnvAttr @98
SQLSetStmtAttr @99
+SQLBulkOperations @100
SQLDummyOrdinal @199
dconn_FDriverConnectProc @200
DllMain @201
ConfigDSN @202
-
diff --git a/src/interfaces/odbc/psqlodbc_api30w.def b/src/interfaces/odbc/psqlodbc_api30w.def
index ef7cdfdf33d..86dedae64c6 100644
--- a/src/interfaces/odbc/psqlodbc_api30w.def
+++ b/src/interfaces/odbc/psqlodbc_api30w.def
@@ -1,4 +1,4 @@
-LIBRARY psqlodbc30
+LIBRARY psqlodbc30w
EXPORTS
SQLAllocConnect @1
SQLAllocEnv @2
@@ -71,6 +71,7 @@ SQLSetDescField @96
SQLSetDescRec @97
SQLSetEnvAttr @98
SQLSetStmtAttr @99
+SQLBulkOperations @100
SQLDummyOrdinal @199
dconn_FDriverConnectProc @200
diff --git a/src/interfaces/odbc/qresult.c b/src/interfaces/odbc/qresult.c
index 89ce0396eca..923448abeba 100644
--- a/src/interfaces/odbc/qresult.c
+++ b/src/interfaces/odbc/qresult.c
@@ -123,6 +123,8 @@ QR_Constructor()
rv->rowset_size = 1;
rv->haskeyset = 0;
rv->keyset = NULL;
+ rv->rb_count = 0;
+ rv->rollback = NULL;
}
mylog("exit QR_Constructor\n");
@@ -228,6 +230,12 @@ QR_free_memory(QResultClass *self)
free(self->keyset);
self->keyset = NULL;
}
+ if (self->rollback)
+ {
+ free(self->rollback);
+ self->rb_count = 0;
+ self->rollback = NULL;
+ }
self->fcount = 0;
@@ -280,6 +288,8 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
{
self->status = PGRES_FIELDS_OK;
self->num_fields = CI_get_num_fields(self->fields);
+ if (self->haskeyset)
+ self->num_fields -= 2;
}
else
{
@@ -302,15 +312,18 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
/* allocate memory for the tuple cache */
mylog("MALLOC: tuple_size = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
self->count_allocated = 0;
- self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
- if (self->haskeyset)
- self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size);
- if (!self->backend_tuples)
+ if (self->num_fields > 0)
{
- self->status = PGRES_FATAL_ERROR;
- QR_set_message(self, "Could not get memory for tuple cache.");
- return FALSE;
+ self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
+ if (!self->backend_tuples)
+ {
+ self->status = PGRES_FATAL_ERROR;
+ QR_set_message(self, "Could not get memory for tuple cache.");
+ return FALSE;
+ }
}
+ if (self->haskeyset)
+ self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size);
self->count_allocated = tuple_size;
self->inTuples = TRUE;
@@ -415,6 +428,7 @@ QR_next_tuple(QResultClass *self)
char fetch[128];
QueryInfo qi;
ConnInfo *ci = NULL;
+ BOOL set_no_trans;
if (fetch_count < fcount)
{
@@ -484,12 +498,16 @@ QR_next_tuple(QResultClass *self)
if (!self->backend_tuples || self->cache_size > self->count_allocated)
{
self->count_allocated = 0;
- self->backend_tuples = (TupleField *) realloc(self->backend_tuples, self->num_fields * sizeof(TupleField) * self->cache_size);
- if (!self->backend_tuples)
+ if (self->num_fields > 0)
{
- self->status = PGRES_FATAL_ERROR;
- QR_set_message(self, "Out of memory while reading tuples.");
- return FALSE;
+ self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
+ self->num_fields * sizeof(TupleField) * self->cache_size);
+ if (!self->backend_tuples)
+ {
+ self->status = PGRES_FATAL_ERROR;
+ QR_set_message(self, "Out of memory while reading tuples.");
+ return FALSE;
+ }
}
if (self->haskeyset)
self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * self->cache_size);
@@ -555,13 +573,16 @@ QR_next_tuple(QResultClass *self)
mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
tuple_size *= 2;
- self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
- tuple_size * self->num_fields * sizeof(TupleField));
- if (!self->backend_tuples)
+ if (self->num_fields > 0)
{
- self->status = PGRES_FATAL_ERROR;
- QR_set_message(self, "Out of memory while reading tuples.");
- return FALSE;
+ self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
+ tuple_size * self->num_fields * sizeof(TupleField));
+ if (!self->backend_tuples)
+ {
+ self->status = PGRES_FATAL_ERROR;
+ QR_set_message(self, "Out of memory while reading tuples.");
+ return FALSE;
+ }
}
if (self->haskeyset)
self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * tuple_size);
@@ -606,8 +627,10 @@ QR_next_tuple(QResultClass *self)
QR_set_message(self, msgbuffer);
self->status = PGRES_FATAL_ERROR;
+ set_no_trans = FALSE;
if (!strncmp(msgbuffer, "FATAL", 5))
- CC_set_no_trans(self->conn);
+ set_no_trans = TRUE;
+ CC_on_abort(self->conn, set_no_trans);
qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
@@ -626,7 +649,7 @@ QR_next_tuple(QResultClass *self)
qlog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id);
QR_set_message(self, "Unexpected result from backend. It probably crashed");
self->status = PGRES_FATAL_ERROR;
- CC_set_no_trans(self->conn);
+ CC_on_abort(self->conn, TRUE);
return FALSE;
}
}
@@ -647,16 +670,21 @@ QR_read_tuple(QResultClass *self, char binary)
Int2 bitcnt;
Int4 len;
char *buffer;
- int num_fields = self->num_fields; /* speed up access */
+ int ci_num_fields = QR_NumResultCols(self); /* speed up access */
+ int num_fields = self->num_fields; /* speed up access */
SocketClass *sock = CC_get_socket(self->conn);
ColumnInfoClass *flds;
+ int effective_cols;
+ char tidoidbuf[32];
/* set the current row to read the fields into */
+ effective_cols = ci_num_fields;
this_tuplefield = self->backend_tuples + (self->fcount * num_fields);
if (self->haskeyset)
{
this_keyset = self->keyset + self->fcount;
this_keyset->status = 0;
+ effective_cols -= 2;
}
bitmaplen = (Int2) num_fields / BYTELEN;
@@ -672,8 +700,9 @@ QR_read_tuple(QResultClass *self, char binary)
bitmap_pos = 0;
bitcnt = 0;
bmp = bitmap[bitmap_pos];
+ flds = self->fields;
- for (field_lf = 0; field_lf < num_fields; field_lf++)
+ for (field_lf = 0; field_lf < ci_num_fields; field_lf++)
{
/* Check if the current field is NULL */
if (!(bmp & 0200))
@@ -692,14 +721,27 @@ QR_read_tuple(QResultClass *self, char binary)
if (!binary)
len -= VARHDRSZ;
- buffer = (char *) malloc(len + 1);
+ if (field_lf >= effective_cols)
+ buffer = tidoidbuf;
+ else
+ buffer = (char *) malloc(len + 1);
SOCK_get_n_char(sock, buffer, len);
buffer[len] = '\0';
mylog("qresult: len=%d, buffer='%s'\n", len, buffer);
- this_tuplefield[field_lf].len = len;
- this_tuplefield[field_lf].value = buffer;
+ if (field_lf >= effective_cols)
+ {
+ if (field_lf == effective_cols)
+ sscanf(buffer, "(%lu,%hu)",
+ &this_keyset->blocknum, &this_keyset->offset);
+ else
+ this_keyset->oid = strtoul(buffer, NULL, 10);
+ }
+ else
+ {
+ this_tuplefield[field_lf].len = len;
+ this_tuplefield[field_lf].value = buffer;
/*
* This can be used to set the longest length of the column
@@ -710,9 +752,9 @@ QR_read_tuple(QResultClass *self, char binary)
* row!
*/
- flds = self->fields;
- if (flds && flds->display_size && flds->display_size[field_lf] < len)
- flds->display_size[field_lf] = len;
+ if (flds && flds->display_size && flds->display_size[field_lf] < len)
+ flds->display_size[field_lf] = len;
+ }
}
/*
@@ -728,15 +770,6 @@ QR_read_tuple(QResultClass *self, char binary)
else
bmp <<= 1;
}
- if (this_keyset)
- {
- if (this_tuplefield[num_fields - 2].value)
- sscanf(this_tuplefield[num_fields - 2].value, "(%lu,%hu)",
- &this_keyset->blocknum, &this_keyset->offset);
- if (this_tuplefield[num_fields - 1].value)
- sscanf(this_tuplefield[num_fields - 1].value, "%lu",
- &this_keyset->oid);
- }
self->currTuple++;
return TRUE;
}
diff --git a/src/interfaces/odbc/qresult.h b/src/interfaces/odbc/qresult.h
index dbb6f46901e..a7291c43a6f 100644
--- a/src/interfaces/odbc/qresult.h
+++ b/src/interfaces/odbc/qresult.h
@@ -73,8 +73,9 @@ struct QResultClass_
* progress? */
char aborted; /* was aborted? */
char haskeyset; /* this result contains keyset ? */
- KeySet *keyset;
-
+ KeySet *keyset;
+ UInt4 rb_count; /* count of rollback info */
+ Rollback *rollback;
};
#define QR_get_fields(self) (self->fields)
diff --git a/src/interfaces/odbc/resource.h b/src/interfaces/odbc/resource.h
index 4cd1639887b..ac67ad5a5eb 100644
--- a/src/interfaces/odbc/resource.h
+++ b/src/interfaces/odbc/resource.h
@@ -54,6 +54,7 @@
#define DS_DISALLOWPREMATURE 1061
#define DS_LFCONVERSION 1062
#define DS_TRUEISMINUS1 1063
+#define DS_UPDATABLECURSORS 1064
/* Next default values for new objects */
/* */
@@ -61,7 +62,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1062
+#define _APS_NEXT_CONTROL_VALUE 1065
#define _APS_NEXT_SYMED_VALUE 101
#endif /* */
diff --git a/src/interfaces/odbc/results.c b/src/interfaces/odbc/results.c
index af7c8b30f8b..6d20bbaad59 100644
--- a/src/interfaces/odbc/results.c
+++ b/src/interfaces/odbc/results.c
@@ -138,7 +138,7 @@ PGAPI_NumResultCols(
if (stmt->parse_status != STMT_PARSE_FATAL)
{
parse_ok = TRUE;
- *pccol = stmt->nfld;
+ *pccol = SC_get_IRD(stmt)->nfields;
mylog("PARSE: PGAPI_NumResultCols: *pccol = %d\n", *pccol);
}
}
@@ -189,11 +189,12 @@ PGAPI_DescribeCol(
/* gets all the information about a specific column */
StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
+ IRDFields *irdflds;
QResultClass *res;
char *col_name = NULL;
Int4 fieldtype = 0;
- int precision = 0,
- scale = 0;
+ int column_size = 0,
+ decimal_digits = 0;
ConnInfo *ci;
char parse_ok;
char buf[255];
@@ -213,6 +214,7 @@ PGAPI_DescribeCol(
SC_clear_error(stmt);
+ irdflds = SC_get_IRD(stmt);
#if (ODBCVER >= 0x0300)
if (0 == icol) /* bookmark column */
{
@@ -249,11 +251,11 @@ PGAPI_DescribeCol(
parse_statement(stmt);
}
- mylog("PARSE: DescribeCol: icol=%d, stmt=%u, stmt->nfld=%d, stmt->fi=%u\n", icol, stmt, stmt->nfld, stmt->fi);
+ mylog("PARSE: DescribeCol: icol=%d, stmt=%u, stmt->nfld=%d, stmt->fi=%u\n", icol, stmt, irdflds->nfields, irdflds->fi);
- if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[icol])
+ if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[icol])
{
- if (icol >= stmt->nfld)
+ if (icol >= irdflds->nfields)
{
stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
stmt->errormsg = "Invalid column number in DescribeCol.";
@@ -262,15 +264,15 @@ PGAPI_DescribeCol(
}
mylog("DescribeCol: getting info for icol=%d\n", icol);
- fieldtype = stmt->fi[icol]->type;
- if (stmt->fi[icol]->alias[0])
- col_name = stmt->fi[icol]->alias;
+ fieldtype = irdflds->fi[icol]->type;
+ if (irdflds->fi[icol]->alias[0])
+ col_name = irdflds->fi[icol]->alias;
else
- col_name = stmt->fi[icol]->name;
- precision = stmt->fi[icol]->precision;
- scale = stmt->fi[icol]->scale;
+ col_name = irdflds->fi[icol]->name;
+ column_size = irdflds->fi[icol]->column_size;
+ decimal_digits = irdflds->fi[icol]->decimal_digits;
- mylog("PARSE: fieldtype=%d, col_name='%s', precision=%d\n", fieldtype, col_name, precision);
+ mylog("PARSE: fieldtype=%d, col_name='%s', column_size=%d\n", fieldtype, col_name, column_size);
if (fieldtype > 0)
parse_ok = TRUE;
}
@@ -310,13 +312,13 @@ PGAPI_DescribeCol(
fieldtype = QR_get_field_type(res, icol);
/* atoi(ci->unknown_sizes) */
- precision = pgtype_precision(stmt, fieldtype, icol, ci->drivers.unknown_sizes);
- scale = pgtype_scale(stmt, fieldtype, icol);
+ column_size = pgtype_column_size(stmt, fieldtype, icol, ci->drivers.unknown_sizes);
+ decimal_digits = pgtype_decimal_digits(stmt, fieldtype, icol);
}
mylog("describeCol: col %d fieldname = '%s'\n", icol, col_name);
mylog("describeCol: col %d fieldtype = %d\n", icol, fieldtype);
- mylog("describeCol: col %d precision = %d\n", icol, precision);
+ mylog("describeCol: col %d column_size = %d\n", icol, column_size);
result = SQL_SUCCESS;
@@ -341,37 +343,37 @@ PGAPI_DescribeCol(
}
/*
- * SQL TYPE
+ * CONCISE(SQL) TYPE
*/
if (pfSqlType)
{
- *pfSqlType = pgtype_to_sqltype(stmt, fieldtype);
+ *pfSqlType = pgtype_to_concise_type(stmt, fieldtype);
mylog("describeCol: col %d *pfSqlType = %d\n", icol, *pfSqlType);
}
/*
- * PRECISION
+ * COLUMN SIZE(PRECISION in 2.x)
*/
if (pcbColDef)
{
- if (precision < 0)
- precision = 0; /* "I dont know" */
+ if (column_size < 0)
+ column_size = 0; /* "I dont know" */
- *pcbColDef = precision;
+ *pcbColDef = column_size;
mylog("describeCol: col %d *pcbColDef = %d\n", icol, *pcbColDef);
}
/*
- * SCALE
+ * DECIMAL DIGITS(SCALE in 2.x)
*/
if (pibScale)
{
- if (scale < 0)
- scale = 0;
+ if (decimal_digits < 0)
+ decimal_digits = 0;
- *pibScale = scale;
+ *pibScale = decimal_digits;
mylog("describeCol: col %d *pibScale = %d\n", icol, *pibScale);
}
@@ -380,7 +382,7 @@ PGAPI_DescribeCol(
*/
if (pfNullable)
{
- *pfNullable = (parse_ok) ? stmt->fi[icol]->nullable : pgtype_nullable(stmt, fieldtype);
+ *pfNullable = (parse_ok) ? irdflds->fi[icol]->nullable : pgtype_nullable(stmt, fieldtype);
mylog("describeCol: col %d *pfNullable = %d\n", icol, *pfNullable);
}
@@ -402,6 +404,7 @@ PGAPI_ColAttributes(
{
static char *func = "PGAPI_ColAttributes";
StatementClass *stmt = (StatementClass *) hstmt;
+ IRDFields *irdflds;
Int4 col_idx, field_type = 0;
ConnectionClass *conn;
ConnInfo *ci;
@@ -414,7 +417,8 @@ PGAPI_ColAttributes(
value = 0;
const FIELD_INFO *fi = NULL;
- mylog("%s: entering..col=%d %d.\n", func, icol, fDescType);
+ mylog("%s: entering..col=%d %d len=%d.\n", func, icol, fDescType,
+ cbDescMax);
if (!stmt)
{
@@ -422,6 +426,9 @@ PGAPI_ColAttributes(
return SQL_INVALID_HANDLE;
}
+ if (pcbDesc)
+ *pcbDesc = 0;
+ irdflds = SC_get_IRD(stmt);
conn = SC_get_conn(stmt);
ci = &(conn->connInfo);
@@ -466,7 +473,7 @@ PGAPI_ColAttributes(
parse_statement(stmt);
}
- cols = stmt->nfld;
+ cols = irdflds->nfields;
/*
* Column Count is a special case. The Column number is ignored
@@ -484,7 +491,7 @@ PGAPI_ColAttributes(
return SQL_SUCCESS;
}
- if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[col_idx])
+ if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[col_idx])
{
if (col_idx >= cols)
{
@@ -493,14 +500,14 @@ PGAPI_ColAttributes(
SC_log_error(func, "", stmt);
return SQL_ERROR;
}
- field_type = stmt->fi[col_idx]->type;
+ field_type = irdflds->fi[col_idx]->type;
if (field_type > 0)
parse_ok = TRUE;
}
}
if (parse_ok)
- fi = stmt->fi[col_idx];
+ fi = irdflds->fi[col_idx];
else
{
SC_pre_execute(stmt);
@@ -542,8 +549,8 @@ PGAPI_ColAttributes(
}
field_type = QR_get_field_type(SC_get_Curres(stmt), col_idx);
- if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[col_idx])
- fi = stmt->fi[col_idx];
+ if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[col_idx])
+ fi = irdflds->fi[col_idx];
}
mylog("colAttr: col %d field_type = %d\n", col_idx, field_type);
@@ -587,15 +594,18 @@ inolog("AUTO_INCREMENT=%d\n", value);
#if (ODBCVER >= 0x0300)
case SQL_DESC_NAME:
-#endif /* ODBCVER */
+#else
case SQL_COLUMN_NAME:
+#endif /* ODBCVER */
p = fi ? (fi->alias[0] ? fi->alias : fi->name) : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
mylog("PGAPI_ColAttr: COLUMN_NAME = '%s'\n", p);
break;
case SQL_COLUMN_LENGTH:
- value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes);
+ value = (fi && fi->length > 0) ? fi->length : pgtype_buffer_length(stmt, field_type, col_idx, unknown_sizes);
+ if (value < 0)
+ value = 0;
mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
break;
@@ -607,8 +617,9 @@ inolog("COLUMN_MONEY=%d\n", value);
#if (ODBCVER >= 0x0300)
case SQL_DESC_NULLABLE:
-#endif /* ODBCVER */
+#else
case SQL_COLUMN_NULLABLE:
+#endif /* ODBCVER */
value = fi ? fi->nullable : pgtype_nullable(stmt, field_type);
inolog("COLUMN_NULLABLE=%d\n", value);
break;
@@ -617,19 +628,23 @@ inolog("COLUMN_NULLABLE=%d\n", value);
p = "";
break;
- case SQL_COLUMN_PRECISION:
- value = fi ? fi->precision : pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
+ case SQL_COLUMN_PRECISION: /* in 2.x */
+ value = (fi && fi->column_size > 0) ? fi->column_size : pgtype_column_size(stmt, field_type, col_idx, unknown_sizes);
+ if (value < 0)
+ value = 0;
- mylog("PGAPI_ColAttributes: col %d, precision = %d\n", col_idx, value);
+ mylog("PGAPI_ColAttributes: col %d, column_size = %d\n", col_idx, value);
break;
case SQL_COLUMN_QUALIFIER_NAME: /* == SQL_DESC_CATALOG_NAME */
p = "";
break;
- case SQL_COLUMN_SCALE:
- value = pgtype_scale(stmt, field_type, col_idx);
+ case SQL_COLUMN_SCALE: /* in 2.x */
+ value = pgtype_decimal_digits(stmt, field_type, col_idx);
inolog("COLUMN_SCALE=%d\n", value);
+ if (value < 0)
+ value = 0;
break;
case SQL_COLUMN_SEARCHABLE: /* SQL_DESC_SEARCHABLE */
@@ -643,7 +658,7 @@ inolog("COLUMN_SCALE=%d\n", value);
break;
case SQL_COLUMN_TYPE: /* == SQL_DESC_CONCISE_TYPE */
- value = pgtype_to_sqltype(stmt, field_type);
+ value = pgtype_to_concise_type(stmt, field_type);
inolog("COLUMN_TYPE=%d\n", value);
break;
@@ -678,46 +693,53 @@ inolog("COLUMN_TYPE=%d\n", value);
mylog("PGAPI_ColAttr: BASE_COLUMN_NAME = '%s'\n", p);
break;
case SQL_DESC_BASE_TABLE_NAME: /* the same as TABLE_NAME ok ? */
- p = fi && (fi->ti) ? fi->ti->name : "";
+ p = (fi && (fi->ti)) ? fi->ti->name : "";
mylog("PGAPI_ColAttr: BASE_TABLE_NAME = '%s'\n", p);
break;
case SQL_DESC_LENGTH: /* different from SQL_COLUMN_LENGTH */
- value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes);
+ value = (fi && fi->length > 0) ? fi->length : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
+ if (value < 0)
+ value = 0;
mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
break;
case SQL_DESC_OCTET_LENGTH:
- value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes);
-
+ value = (fi && fi->length > 0) ? fi->length : pgtype_transfer_octet_length(stmt, field_type, col_idx, unknown_sizes);
+ if (value < 0)
+ value = 0;
mylog("PGAPI_ColAttributes: col %d, octet_length = %d\n", col_idx, value);
break;
case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */
- value = fi ? fi->precision : pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
+ value = (fi && fi->column_size > 0) ? fi->column_size : pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
+ if (value < 0)
+ value = 0;
mylog("PGAPI_ColAttributes: col %d, desc_precision = %d\n", col_idx, value);
break;
case SQL_DESC_SCALE: /* different from SQL_COLUMN_SCALE */
value = pgtype_scale(stmt, field_type, col_idx);
+ if (value < 0)
+ value = 0;
break;
case SQL_DESC_LOCAL_TYPE_NAME:
p = pgtype_to_name(stmt, field_type);
break;
case SQL_DESC_TYPE:
- value = pgtype_to_sqltype(stmt, field_type);
- switch (value)
- {
- case SQL_TYPE_DATE:
- case SQL_TYPE_TIME:
- case SQL_TYPE_TIMESTAMP:
- value = SQL_DATETIME;
- break;
- }
+ value = pgtype_to_sqldesctype(stmt, field_type);
+ break;
+ case SQL_DESC_NUM_PREC_RADIX:
+ value = pgtype_radix(stmt, field_type);
break;
case SQL_DESC_LITERAL_PREFIX:
+ p = pgtype_literal_prefix(stmt, field_type);
+ break;
case SQL_DESC_LITERAL_SUFFIX:
- case SQL_DESC_NUM_PREC_RADIX:
+ p = pgtype_literal_suffix(stmt, field_type);
+ break;
case SQL_DESC_UNNAMED:
+ value = (fi && !fi->name[0] && !fi->alias[0]) ? SQL_UNNAMED : SQL_NAMED;
+ break;
#endif /* ODBCVER */
default:
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
@@ -967,6 +989,7 @@ PGAPI_Fetch(
{
static char *func = "PGAPI_Fetch";
StatementClass *stmt = (StatementClass *) hstmt;
+ ARDFields *opts;
QResultClass *res;
mylog("PGAPI_Fetch: stmt = %u, stmt->result= %u\n", stmt, SC_get_Curres(stmt));
@@ -988,7 +1011,8 @@ PGAPI_Fetch(
}
/* Not allowed to bind a bookmark column when using SQLFetch. */
- if (stmt->bookmark.buffer)
+ opts = SC_get_ARD(stmt);
+ if (opts->bookmark->buffer)
{
stmt->errornumber = STMT_COLNUM_ERROR;
stmt->errormsg = "Not allowed to bind a bookmark column when using PGAPI_Fetch";
@@ -1012,7 +1036,7 @@ PGAPI_Fetch(
return SQL_ERROR;
}
- if (stmt->bindings == NULL)
+ if (opts->bindings == NULL)
{
/* just to avoid a crash if the user insists on calling this */
/* function even if SQL_ExecDirect has reported an Error */
@@ -1040,6 +1064,7 @@ PGAPI_ExtendedFetch(
{
static char *func = "PGAPI_ExtendedFetch";
StatementClass *stmt = (StatementClass *) hstmt;
+ ARDFields *opts;
QResultClass *res;
int num_tuples,
i,
@@ -1078,11 +1103,12 @@ PGAPI_ExtendedFetch(
return SQL_ERROR;
}
+ opts = SC_get_ARD(stmt);
/*
* If a bookmark colunmn is bound but bookmark usage is off, then
* error
*/
- if (stmt->bookmark.buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
+ if (opts->bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
{
stmt->errornumber = STMT_COLNUM_ERROR;
stmt->errormsg = "Attempt to retrieve bookmark with bookmark usage disabled";
@@ -1106,7 +1132,7 @@ PGAPI_ExtendedFetch(
return SQL_ERROR;
}
- if (stmt->bindings == NULL)
+ if (opts->bindings == NULL)
{
/* just to avoid a crash if the user insists on calling this */
/* function even if SQL_ExecDirect has reported an Error */
@@ -1118,7 +1144,7 @@ PGAPI_ExtendedFetch(
/* Initialize to no rows fetched */
if (rgfRowStatus)
- for (i = 0; i < stmt->options.rowset_size; i++)
+ for (i = 0; i < opts->rowset_size; i++)
*(rgfRowStatus + i) = SQL_ROW_NOROW;
if (pcrow)
@@ -1144,7 +1170,7 @@ PGAPI_ExtendedFetch(
stmt->rowset_start = 0;
else
- stmt->rowset_start += (save_rowset_size > 0 ? save_rowset_size : stmt->options.rowset_size);
+ stmt->rowset_start += (save_rowset_size > 0 ? save_rowset_size : opts->rowset_size);
mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
break;
@@ -1159,22 +1185,22 @@ PGAPI_ExtendedFetch(
*/
if (stmt->rowset_start >= num_tuples)
{
- if (stmt->options.rowset_size > num_tuples)
+ if (opts->rowset_size > num_tuples)
{
stmt->errornumber = STMT_POS_BEFORE_RECORDSET;
stmt->errormsg = "fetch prior from eof and before the beggining";
}
- stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - stmt->options.rowset_size);
+ stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - opts->rowset_size);
}
else
{
- if (stmt->rowset_start < stmt->options.rowset_size)
+ if (stmt->rowset_start < opts->rowset_size)
{
stmt->errormsg = "fetch prior and before the beggining";
stmt->errornumber = STMT_POS_BEFORE_RECORDSET;
}
- stmt->rowset_start -= stmt->options.rowset_size;
+ stmt->rowset_start -= opts->rowset_size;
}
break;
@@ -1187,7 +1213,7 @@ PGAPI_ExtendedFetch(
case SQL_FETCH_LAST:
mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
- stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - stmt->options.rowset_size);
+ stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - opts->rowset_size);
break;
case SQL_FETCH_ABSOLUTE:
@@ -1255,7 +1281,7 @@ PGAPI_ExtendedFetch(
/* If *new* rowset is prior to result_set, return no data found */
if (stmt->rowset_start < 0)
{
- if (stmt->rowset_start + stmt->options.rowset_size <= 0)
+ if (stmt->rowset_start + opts->rowset_size <= 0)
{
stmt->rowset_start = -1;
return SQL_NO_DATA_FOUND;
@@ -1271,7 +1297,7 @@ PGAPI_ExtendedFetch(
stmt->currTuple = stmt->rowset_start - 1;
/* increment the base row in the tuple cache */
- QR_set_rowset_size(res, stmt->options.rowset_size);
+ QR_set_rowset_size(res, opts->rowset_size);
/* QR_inc_base(res, stmt->last_fetch_count); */
/* Is inc_base right ? */
res->base = stmt->rowset_start;
@@ -1281,7 +1307,7 @@ PGAPI_ExtendedFetch(
mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt->currTuple);
truncated = error = FALSE;
- for (i = 0; i < stmt->options.rowset_size; i++)
+ for (i = 0; i < opts->rowset_size; i++)
{
stmt->bind_row = i; /* set the binding location */
result = SC_fetch(stmt);
@@ -1302,11 +1328,14 @@ PGAPI_ExtendedFetch(
#ifdef DRIVER_CURSOR_IMPLEMENT
else if (res->keyset)
{
- UWORD pstatus = res->keyset[stmt->currTuple].status & KEYSET_INFO_PUBLIC;
+ DWORD currp = stmt->rowset_start + i;
+ UWORD pstatus = res->keyset[currp].status & KEYSET_INFO_PUBLIC;
if (pstatus != 0)
{
rgfRowStatus[i] = pstatus;
- res->keyset[stmt->currTuple].status &= (~KEYSET_INFO_PUBLIC);
+ /* refresh the status */
+ if (SQL_ROW_DELETED != pstatus)
+ res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
}
else
rgfRowStatus[i] = SQL_ROW_SUCCESS;
@@ -1314,6 +1343,8 @@ PGAPI_ExtendedFetch(
#endif /* DRIVER_CURSOR_IMPLEMENT */
else
*(rgfRowStatus + i) = SQL_ROW_SUCCESS;
+if (rgfRowStatus[i] != SQL_ROW_SUCCESS)
+inolog("rgfRowStatus[%d]=%d\n", i, rgfRowStatus[i]);
}
}
@@ -1374,39 +1405,35 @@ PGAPI_MoreResults(
/*
* Stuff for updatable cursors.
*/
-static const char *getOidValue(const QResultClass *res, int index)
+static Int2 getNumResultCols(const QResultClass *res)
{
- return QR_get_value_backend_row(res, index, QR_NumResultCols(res) - 1);
+ Int2 res_cols = QR_NumResultCols(res);
+ return res->keyset ? res_cols - 2 : res_cols;
}
static UInt4 getOid(const QResultClass *res, int index)
{
return res->keyset[index].oid;
}
-static const char *getTidValue(const QResultClass *res, int index)
-{
- return QR_get_value_backend_row(res, index, QR_NumResultCols(res) - 2);
-}
static void getTid(const QResultClass *res, int index, UInt4 *blocknum, UInt2 *offset)
{
*blocknum = res->keyset[index].blocknum;
*offset = res->keyset[index].offset;
}
-static void KeySetSet(const QResultClass *res, int index)
+static void KeySetSet(const TupleField *tuple, int num_fields, KeySet *keyset)
{
- int num_fields = res->num_fields;
- TupleField *tuple = res->backend_tuples + num_fields * index;
- KeySet *keyset = res->keyset + index;
-
sscanf(tuple[num_fields - 2].value, "(%u,%hu)",
&keyset->blocknum, &keyset->offset);
sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid);
}
+#define LATEST_TUPLE_LOAD 1L
+#define USE_INSERTED_TID (1L << 1)
static QResultClass *
-positioned_load(StatementClass *stmt, BOOL latest, int res_cols, UInt4 oid, const char *tidval)
+positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval)
{
QResultClass *qres;
char *selstr;
+ BOOL latest = ((flag & LATEST_TUPLE_LOAD) != 0);
UInt4 len;
len = strlen(stmt->load_statement);
@@ -1419,6 +1446,12 @@ positioned_load(StatementClass *stmt, BOOL latest, int res_cols, UInt4 oid, cons
else
sprintf(selstr, "%s where ctid = '%s' and oid = %u", stmt->load_statement, tidval, oid);
}
+ else if ((flag & USE_INSERTED_TID) != 0)
+ {
+ len += 50;
+ selstr = malloc(len);
+ sprintf(selstr, "%s where ctid = currtid(0, '(,)') and oid = %u", stmt->load_statement, oid);
+ }
else
{
len += 20;
@@ -1428,23 +1461,24 @@ positioned_load(StatementClass *stmt, BOOL latest, int res_cols, UInt4 oid, cons
mylog("selstr=%s\n", selstr);
qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, CLEAR_RESULT_ON_ABORT);
-free(selstr);
+ free(selstr);
return qres;
}
RETCODE SQL_API
-SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
+SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count)
{
int i,
res_cols;
- UWORD rcnt, global_ridx, offset;
+ UWORD rcnt, offset;
UInt4 oid, blocknum;
QResultClass *res,
*qres;
+ IRDFields *irdflds = SC_get_IRD(stmt);
RETCODE ret = SQL_ERROR;
char tidval[32];
- mylog("positioned load fi=%x ti=%x\n", stmt->fi, stmt->ti);
+ mylog("positioned load fi=%x ti=%x\n", irdflds->fi, stmt->ti);
rcnt = 0;
if (count)
*count = 0;
@@ -1452,23 +1486,18 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
return SQL_ERROR;
if (!stmt->ti)
parse_statement(stmt); /* not preferable */
- if (!stmt->ti || stmt->ntab != 1)
+ if (!stmt->updatable)
{
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
return SQL_ERROR;
}
global_ridx = irow + stmt->rowset_start;
- res_cols = QR_NumResultCols(res);
if (!(oid = getOid(res, global_ridx)))
return SQL_SUCCESS_WITH_INFO;
getTid(res, global_ridx, &blocknum, &offset);
sprintf(tidval, "(%u, %u)", blocknum, offset);
- /*if (!(oidval = getOidValue(res, global_ridx)))
- return SQL_SUCCESS_WITH_INFO;
- sscanf(oidval, "%u", &oid);
- tidval = getTidValue(res, global_ridx);*/
- res_cols -= 2;
- if (qres = positioned_load(stmt, TRUE, res_cols, oid, tidval), qres)
+ res_cols = getNumResultCols(res);
+ if (qres = positioned_load(stmt, LATEST_TUPLE_LOAD, oid, tidval), qres)
{
TupleField *tupleo, *tuplen;
@@ -1476,9 +1505,18 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
tupleo = res->backend_tuples + res->num_fields * global_ridx;
if (rcnt == 1)
{
+ int effective_fields = res_cols;
+
QR_set_position(qres, 0);
tuplen = qres->tupleField;
- for (i = 0; i < res->num_fields; i++)
+ if (res->keyset)
+ {
+ if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
+ strcmp(tuplen[qres->num_fields - 2].value, tidval))
+ res->keyset[global_ridx].status |= SQL_ROW_UPDATED;
+ KeySetSet(tuplen, qres->num_fields, res->keyset + global_ridx);
+ }
+ for (i = 0; i < effective_fields; i++)
{
if (tupleo[i].value)
free(tupleo[i].value);
@@ -1487,13 +1525,6 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
tupleo[i].value = tuplen[i].value;
tuplen[i].value = NULL;
}
- if (res->keyset)
- {
- if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
- strcmp(tupleo[res->num_fields - 2].value, tidval))
- res->keyset[global_ridx].status |= SQL_ROW_UPDATED;
- KeySetSet(res, global_ridx);
- }
ret = SQL_SUCCESS;
}
else
@@ -1503,10 +1534,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
ret = SQL_SUCCESS_WITH_INFO;
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
{
- if (tupleo[res_cols + 1].value)
- free(tupleo[res_cols + 1].value);
- tupleo[res_cols + 1].value = NULL;
- tupleo[res_cols + 1].len = 0;
+ res->keyset[global_ridx].oid = 0;
res->keyset[global_ridx].status |= SQL_ROW_DELETED;
}
}
@@ -1520,24 +1548,23 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
}
RETCODE SQL_API
-SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
+SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
{
int i;
- QResultClass *res,
- *qres;
+ QResultClass *res, *qres;
RETCODE ret = SQL_ERROR;
- mylog("positioned new fi=%x ti=%x\n", stmt->fi, stmt->ti);
+ mylog("positioned new ti=%x\n", stmt->ti);
if (!(res = SC_get_Curres(stmt)))
return SQL_ERROR;
if (!stmt->ti)
parse_statement(stmt); /* not preferable */
- if (!stmt->ti || stmt->ntab != 1)
+ if (!stmt->updatable)
{
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
return SQL_ERROR;
}
- if (qres = positioned_load(stmt, TRUE, QR_NumResultCols(res) - 2, oid, tidval), qres)
+ if (qres = positioned_load(stmt, tidRef ? USE_INSERTED_TID : 0, oid, NULL), qres)
{
TupleField *tupleo, *tuplen;
int count = QR_get_num_tuples(qres);
@@ -1545,6 +1572,8 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
QR_set_position(qres, 0);
if (count == 1)
{
+ int effective_fields = res->num_fields;
+
tuplen = qres->tupleField;
if (res->fcount >= res->count_allocated)
{
@@ -1569,22 +1598,29 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
res->count_allocated = tuple_size;
}
tupleo = res->backend_tuples + res->num_fields * res->fcount;
- for (i = 0; i < res->num_fields; i++)
+ KeySetSet(tuplen, qres->num_fields, res->keyset + res->fcount);
+ for (i = 0; i < effective_fields; i++)
{
tupleo[i].len = tuplen[i].len;
tuplen[i].len = 0;
tupleo[i].value = tuplen[i].value;
tuplen[i].value = NULL;
}
- KeySetSet(res, res->fcount);
+ for (; i < res->num_fields; i++)
+ {
+ tupleo[i].len = 0;
+ tupleo[i].value = NULL;
+ }
res->fcount++;
ret = SQL_SUCCESS;
}
+ else if (0 == count)
+ ret = SQL_NO_DATA_FOUND;
else
{
stmt->errornumber = STMT_ROW_VERSION_CHANGED;
- stmt->errormsg = "the content was changed before updation";
- ret = SQL_SUCCESS_WITH_INFO;
+ stmt->errormsg = "the driver cound't identify inserted rows";
+ ret = SQL_ERROR;
}
QR_Destructor(qres);
/* stmt->currTuple = stmt->rowset_start + irow; */
@@ -1593,7 +1629,7 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
}
static RETCODE SQL_API
-irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow)
+irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow, UDWORD global_ridx)
{
if (ret != SQL_ERROR)
{
@@ -1604,18 +1640,17 @@ irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow
sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
{
if (updcnt == 1)
- SC_pos_reload(stmt, irow, (UWORD *) 0);
+ SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
else if (updcnt == 0)
{
stmt->errornumber = STMT_ROW_VERSION_CHANGED;
stmt->errormsg = "the content was changed before updation";
ret = SQL_ERROR;
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
- SC_pos_reload(stmt, irow, (UWORD *) 0);
+ SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
}
else
ret = SQL_ERROR;
- stmt->currTuple = stmt->rowset_start + irow;
}
else
ret = SQL_ERROR;
@@ -1627,62 +1662,60 @@ irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow
}
return ret;
}
-RETCODE SQL_API
+RETCODE
SC_pos_update(StatementClass *stmt,
- UWORD irow)
+ UWORD irow, UDWORD global_ridx)
{
int i,
- res_cols,
num_cols,
upd_cols;
- UWORD global_ridx;
QResultClass *res;
- BindInfoClass *bindings = stmt->bindings;
+ ARDFields *opts = SC_get_ARD(stmt);
+ IRDFields *irdflds = SC_get_IRD(stmt);
+ BindInfoClass *bindings = opts->bindings;
+ FIELD_INFO **fi = SC_get_IRD(stmt)->fi;
char updstr[4096];
RETCODE ret;
UInt4 oid, offset, blocknum;
UInt2 pgoffset;
- Int4 *used;
+ Int4 *used, bind_size = opts->bind_size;
- mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, SC_get_Curres(stmt)->base, stmt->fi, stmt->ti);
+ mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, SC_get_Curres(stmt)->base,fi, stmt->ti);
if (!(res = SC_get_Curres(stmt)))
return SQL_ERROR;
if (!stmt->ti)
parse_statement(stmt); /* not preferable */
- if (!stmt->ti || stmt->ntab != 1)
+ if (!stmt->updatable)
{
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
return SQL_ERROR;
}
- global_ridx = irow + stmt->rowset_start;
- res_cols = QR_NumResultCols(res);
- /*if (!(oidval = getOidValue(res, global_ridx)))*/
if (!(oid = getOid(res, global_ridx)))
{
stmt->errormsg = "The row is already deleted";
return SQL_ERROR;
}
- /*tidval = getTidValue(res, global_ridx);*/
getTid(res, global_ridx, &blocknum, &pgoffset);
sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name);
- num_cols = stmt->nfld;
- if (stmt->options.row_offset_ptr)
- offset = *stmt->options.row_offset_ptr;
- else
- offset = 0;
+ num_cols = irdflds->nfields;
+ offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
for (i = upd_cols = 0; i < num_cols; i++)
{
if (used = bindings[i].used, used != NULL)
{
used += (offset >> 2);
- mylog("%d used=%d\n", i, *used);
- if (*used != SQL_IGNORE)
+ if (bind_size > 0)
+ used += (bind_size * irow / 4);
+ else
+ used += irow;
+ mylog("%d used=%d,%x\n", i, *used, used);
+ if (*used != SQL_IGNORE && fi[i]->updatable)
{
if (upd_cols)
- sprintf(updstr, "%s, \"%s\" = ?", updstr, stmt->fi[i]->name);
+ sprintf(updstr, "%s, \"%s\" = ?", updstr, fi[i]->name);
else
- sprintf(updstr, "%s \"%s\" = ?", updstr, stmt->fi[i]->name);
+ sprintf(updstr, "%s \"%s\" = ?", updstr, fi[i]->name);
upd_cols++;
}
}
@@ -1695,6 +1728,7 @@ SC_pos_update(StatementClass *stmt,
int j;
int res_cols = QR_NumResultCols(res);
StatementClass *qstmt;
+ APDFields *apdopts;
/*sprintf(updstr, "%s where ctid = '%s' and oid = %s", updstr,
tidval, oidval);*/
@@ -1704,21 +1738,26 @@ SC_pos_update(StatementClass *stmt,
if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
return SQL_ERROR;
qstmt = (StatementClass *) hstmt;
- qstmt->options.param_bind_type = stmt->options.bind_size;
- qstmt->options.param_offset_ptr = stmt->options.row_offset_ptr;
+ apdopts = SC_get_APD(qstmt);
+ apdopts->param_bind_type = opts->bind_size;
+ apdopts->param_offset_ptr = opts->row_offset_ptr;
for (i = j = 0; i < num_cols; i++)
{
if (used = bindings[i].used, used != NULL)
{
used += (offset >> 2);
+ if (bind_size > 0)
+ used += (bind_size * irow / 4);
+ else
+ used += irow;
mylog("%d used=%d\n", i, *used);
- if (*used != SQL_IGNORE)
+ if (*used != SQL_IGNORE && fi[i]->updatable)
{
PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j,
SQL_PARAM_INPUT, bindings[i].returntype,
- pgtype_to_sqltype(stmt, QR_get_field_type(res, i)),
+ pgtype_to_concise_type(stmt, QR_get_field_type(res, i)),
QR_get_fieldsize(res, i),
- (SQLSMALLINT) stmt->fi[i]->precision,
+ (SQLSMALLINT) fi[i]->decimal_digits,
bindings[i].buffer,
bindings[i].buflen,
bindings[i].used);
@@ -1739,55 +1778,61 @@ SC_pos_update(StatementClass *stmt,
stmt->errormsg = "SetPos with data_at_exec not yet supported";
ret = SQL_ERROR;
}
- ret = irow_update(ret, stmt, qstmt, irow);
+ ret = irow_update(ret, stmt, qstmt, irow, global_ridx);
PGAPI_FreeStmt(hstmt, SQL_DROP);
}
else
+ {
ret = SQL_SUCCESS_WITH_INFO;
+ stmt->errormsg = "update list null";
+ }
if (SQL_SUCCESS == ret && res->keyset)
- res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | DRV_SELF_UPDATED);
+ {
+ if (CC_is_in_trans(SC_get_conn(stmt)))
+ res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATING);
+ else
+ res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED);
+ }
#if (ODBCVER >= 0x0300)
- if (stmt->options.rowStatusArray)
+ if (irdflds->rowStatusArray)
{
switch (ret)
{
case SQL_SUCCESS:
- stmt->options.rowStatusArray[irow] = SQL_ROW_UPDATED;
+ irdflds->rowStatusArray[irow] = SQL_ROW_UPDATED;
break;
default:
- stmt->options.rowStatusArray[irow] = ret;
+ irdflds->rowStatusArray[irow] = ret;
}
}
#endif /* ODBCVER */
return ret;
}
-RETCODE SQL_API
+RETCODE
SC_pos_delete(StatementClass *stmt,
- UWORD irow)
+ UWORD irow, UDWORD global_ridx)
{
- int res_cols;
- UWORD global_ridx, offset;
+ UWORD offset;
QResultClass *res, *qres;
- BindInfoClass *bindings = stmt->bindings;
+ ARDFields *opts = SC_get_ARD(stmt);
+ IRDFields *irdflds = SC_get_IRD(stmt);
+ BindInfoClass *bindings = opts->bindings;
char dltstr[4096];
RETCODE ret;
/*const char *oidval;*/
UInt4 oid, blocknum;
- mylog("POS DELETE fi=%x ti=%x\n", stmt->fi, stmt->ti);
+ mylog("POS DELETE ti=%x\n", stmt->ti);
if (!(res = SC_get_Curres(stmt)))
return SQL_ERROR;
if (!stmt->ti)
parse_statement(stmt); /* not preferable */
- if (!stmt->ti || stmt->ntab != 1)
+ if (!stmt->updatable)
{
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
return SQL_ERROR;
}
- res_cols = QR_NumResultCols(res);
- global_ridx = irow + stmt->rowset_start;
- /* if (!(oidval = getOidValue(res, global_ridx)))*/
if (!(oid = getOid(res, global_ridx)))
{
stmt->errormsg = "The row is already deleted";
@@ -1810,18 +1855,17 @@ SC_pos_delete(StatementClass *stmt,
sscanf(cmdstr, "DELETE %d", &dltcnt) == 1)
{
if (dltcnt == 1)
- SC_pos_reload(stmt, irow, (UWORD *) 0);
+ SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
else if (dltcnt == 0)
{
stmt->errornumber = STMT_ROW_VERSION_CHANGED;
stmt->errormsg = "the content was changed before deletion";
ret = SQL_ERROR;
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
- SC_pos_reload(stmt, irow, (UWORD *) 0);
+ SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
}
else
ret = SQL_ERROR;
- stmt->currTuple = stmt->rowset_start + irow;
}
else
ret = SQL_ERROR;
@@ -1836,17 +1880,22 @@ SC_pos_delete(StatementClass *stmt,
if (qres)
QR_Destructor(qres);
if (SQL_SUCCESS == ret && res->keyset)
- res->keyset[global_ridx].status |= (SQL_ROW_DELETED | DRV_SELF_DELETED);
+ {
+ if (CC_is_in_trans(SC_get_conn(stmt)))
+ res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
+ else
+ res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
+ }
#if (ODBCVER >= 0x0300)
- if (stmt->options.rowStatusArray)
+ if (irdflds->rowStatusArray)
{
switch (ret)
{
case SQL_SUCCESS:
- stmt->options.rowStatusArray[irow] = SQL_ROW_DELETED;
+ irdflds->rowStatusArray[irow] = SQL_ROW_DELETED;
break;
default:
- stmt->options.rowStatusArray[irow] = ret;
+ irdflds->rowStatusArray[irow] = ret;
}
}
#endif /* ODBCVER */
@@ -1858,24 +1907,42 @@ irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos
{
if (ret != SQL_ERROR)
{
- int addcnt;
+ int addcnt;
UInt4 oid;
- const char *cmdstr = QR_get_command(SC_get_Curres(istmt));
+ ARDFields *opts = SC_get_ARD(stmt);
+ QResultClass *ires = SC_get_Curres(istmt);
+ const char *cmdstr;
+ cmdstr = QR_get_command((ires->next ? ires->next : ires));
if (cmdstr &&
sscanf(cmdstr, "INSERT %u %d", &oid, &addcnt) == 2 &&
addcnt == 1)
{
- SC_pos_newload(stmt, oid, NULL);
- if (stmt->bookmark.buffer)
+ ConnectionClass *conn = SC_get_conn(stmt);
+ RETCODE qret;
+
+ qret = SQL_NO_DATA_FOUND;
+ if (PG_VERSION_GE(conn, 7.2))
+ {
+ qret = SC_pos_newload(stmt, oid, TRUE);
+ if (SQL_ERROR == qret)
+ return qret;
+ }
+ if (SQL_NO_DATA_FOUND == qret)
+ {
+ qret = SC_pos_newload(stmt, oid, FALSE);
+ if (SQL_ERROR == qret)
+ return qret;
+ }
+ if (opts->bookmark->buffer)
{
char buf[32];
- UInt4 offset = stmt->options.row_offset_ptr ? *stmt->options.row_offset_ptr : 0;
+ UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
sprintf(buf, "%ld", addpos + 1);
copy_and_convert_field(stmt, 0, buf,
- SQL_C_ULONG, stmt->bookmark.buffer + offset,
- 0, stmt->bookmark.used ? stmt->bookmark.used
+ SQL_C_ULONG, opts->bookmark->buffer + offset,
+ 0, opts->bookmark->used ? opts->bookmark->used
+ (offset >> 2) : NULL);
}
}
@@ -1887,7 +1954,7 @@ irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos
}
return ret;
}
-RETCODE SQL_API
+RETCODE
SC_pos_add(StatementClass *stmt,
UWORD irow)
{
@@ -1896,51 +1963,62 @@ SC_pos_add(StatementClass *stmt,
i;
HSTMT hstmt;
StatementClass *qstmt;
+ ConnectionClass *conn;
QResultClass *res;
- BindInfoClass *bindings = stmt->bindings;
+ ARDFields *opts = SC_get_ARD(stmt);
+ IRDFields *irdflds = SC_get_IRD(stmt);
+ APDFields *apdopts;
+ BindInfoClass *bindings = opts->bindings;
+ FIELD_INFO **fi = SC_get_IRD(stmt)->fi;
char addstr[4096];
RETCODE ret;
UInt4 offset;
- Int4 *used;
+ Int4 *used, bind_size = opts->bind_size;
- mylog("POS ADD fi=%x ti=%x\n", stmt->fi, stmt->ti);
+ mylog("POS ADD fi=%x ti=%x\n", fi, stmt->ti);
if (!(res = SC_get_Curres(stmt)))
return SQL_ERROR;
if (!stmt->ti)
parse_statement(stmt); /* not preferable */
- if (!stmt->ti || stmt->ntab != 1)
+ if (!stmt->updatable)
{
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
return SQL_ERROR;
}
- num_cols = stmt->nfld;
+ num_cols = irdflds->nfields;
+ conn = SC_get_conn(stmt);
sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
return SQL_ERROR;
- if (stmt->options.row_offset_ptr)
- offset = *stmt->options.row_offset_ptr;
+ if (opts->row_offset_ptr)
+ offset = *opts->row_offset_ptr;
else
offset = 0;
qstmt = (StatementClass *) hstmt;
- qstmt->options.param_bind_type = stmt->options.bind_size;
- qstmt->options.param_offset_ptr = stmt->options.row_offset_ptr;
+ apdopts = SC_get_APD(qstmt);
+ apdopts->param_bind_type = opts->bind_size;
+ apdopts->param_offset_ptr = opts->row_offset_ptr;
for (i = add_cols = 0; i < num_cols; i++)
{
if (used = bindings[i].used, used != NULL)
{
used += (offset >> 2);
+ if (bind_size > 0)
+ used += (bind_size * irow / 4);
+ else
+ used += irow;
mylog("%d used=%d\n", i, *used);
- if (*used != SQL_IGNORE)
+ if (*used != SQL_IGNORE && fi[i]->updatable)
{
if (add_cols)
- sprintf(addstr, "%s, \"%s\"", addstr, stmt->fi[i]->name);
+ sprintf(addstr, "%s, \"%s\"", addstr, fi[i]->name);
else
- sprintf(addstr, "%s\"%s\"", addstr, stmt->fi[i]->name);
+ sprintf(addstr, "%s\"%s\"", addstr, fi[i]->name);
PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++add_cols,
SQL_PARAM_INPUT, bindings[i].returntype,
- pgtype_to_sqltype(stmt, QR_get_field_type(res, i)),
+ pgtype_to_concise_type(stmt, QR_get_field_type(res, i)),
QR_get_fieldsize(res, i),
- (SQLSMALLINT) stmt->fi[i]->precision,
+ (SQLSMALLINT) fi[i]->decimal_digits,
bindings[i].buffer,
bindings[i].buflen,
bindings[i].used);
@@ -1983,20 +2061,28 @@ SC_pos_add(StatementClass *stmt,
stmt->bind_row = brow_save;
}
else
+ {
ret = SQL_SUCCESS_WITH_INFO;
+ stmt->errormsg = "insert list null";
+ }
PGAPI_FreeStmt(hstmt, SQL_DROP);
if (SQL_SUCCESS == ret && res->keyset)
- res->keyset[res->fcount - 1].status |= DRV_SELF_ADDED;
+ {
+ if (CC_is_in_trans(conn))
+ res->keyset[res->fcount - 1].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING);
+ else
+ res->keyset[res->fcount - 1].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED);
+ }
#if (ODBCVER >= 0x0300)
- if (stmt->options.rowStatusArray)
+ if (irdflds->rowStatusArray)
{
switch (ret)
{
case SQL_SUCCESS:
- stmt->options.rowStatusArray[irow] = SQL_ROW_ADDED;
+ irdflds->rowStatusArray[irow] = SQL_ROW_ADDED;
break;
default:
- stmt->options.rowStatusArray[irow] = ret;
+ irdflds->rowStatusArray[irow] = ret;
}
}
#endif /* ODBCVER */
@@ -2009,6 +2095,47 @@ SC_pos_add(StatementClass *stmt,
*/
#endif /* DRIVER_CURSOR_IMPLEMENT */
+RETCODE
+SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx)
+{
+ RETCODE ret;
+#if (ODBCVER >= 0x0300)
+ IRDFields *irdflds = SC_get_IRD(stmt);
+#endif /* ODBCVER */
+ /* save the last_fetch_count */
+ int last_fetch = stmt->last_fetch_count;
+ int bind_save = stmt->bind_row;
+
+#ifdef DRIVER_CURSOR_IMPLEMENT
+ if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
+ SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
+#endif /* DRIVER_CURSOR_IMPLEMENT */
+ stmt->bind_row = irow;
+ ret = SC_fetch(stmt);
+ /* restore the last_fetch_count */
+ stmt->last_fetch_count = last_fetch;
+ stmt->bind_row = bind_save;
+#if (ODBCVER >= 0x0300)
+ if (irdflds->rowStatusArray)
+ {
+ switch (ret)
+ {
+ case SQL_ERROR:
+ irdflds->rowStatusArray[irow] = SQL_ROW_ERROR;
+ break;
+ case SQL_SUCCESS:
+ irdflds->rowStatusArray[irow] = SQL_ROW_SUCCESS;
+ break;
+ default:
+ irdflds->rowStatusArray[irow] = ret;
+ break;
+ }
+ }
+#endif /* ODBCVER */
+
+ return SQL_SUCCESS;
+}
+
/*
* This positions the cursor within a rowset, that was positioned using SQLExtendedFetch.
* This will be useful (so far) only when using SQLGetData after SQLExtendedFetch.
@@ -2023,10 +2150,13 @@ PGAPI_SetPos(
static char *func = "PGAPI_SetPos";
RETCODE ret;
StatementClass *stmt = (StatementClass *) hstmt;
+ ConnectionClass *conn = SC_get_conn(stmt);
QResultClass *res;
- int num_cols,
- i;
- BindInfoClass *bindings = stmt->bindings;
+ int num_cols, i, start_row, end_row, processed;
+ ARDFields *opts;
+ BindInfoClass *bindings;
+ UDWORD global_ridx, fcount;
+ BOOL auto_commit_needed = FALSE;
if (!stmt)
{
@@ -2034,6 +2164,8 @@ PGAPI_SetPos(
return SQL_INVALID_HANDLE;
}
+ opts = SC_get_ARD(stmt);
+ bindings = opts->bindings;
#ifdef DRIVER_CURSOR_IMPLEMENT
mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func, fOption, irow, fLock, stmt->currTuple);
if (stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
@@ -2055,12 +2187,9 @@ PGAPI_SetPos(
SC_log_error(func, "", stmt);
return SQL_ERROR;
}
- num_cols = QR_NumResultCols(res);
if (irow == 0) /* bulk operation */
{
- int processed;
-
if (SQL_POSITION == fOption)
{
stmt->errornumber = STMT_ROW_OUT_OF_RANGE;
@@ -2068,78 +2197,86 @@ PGAPI_SetPos(
SC_log_error(func, "", stmt);
return SQL_ERROR;
}
- ret = SQL_SUCCESS;
- for (i = 0, processed = 0; i < stmt->options.rowset_size; i++)
- {
-#if (ODBCVER >= 0x0300)
- if (!stmt->options.row_operation_ptr || stmt->options.row_operation_ptr[i] == SQL_ROW_PROCEED)
- {
-#endif /* ODBCVER */
- if (ret = PGAPI_SetPos(hstmt, (UWORD) (i + 1), fOption, fLock), SQL_ERROR == ret)
- break;
- processed++;
-#if (ODBCVER >= 0x0300)
- }
-#endif /* ODBCVER */
- }
- if (processed > 0 && SQL_ERROR == ret)
- {
- processed++;
- ret = SQL_SUCCESS_WITH_INFO;
- stmt->errornumber = STMT_ERROR_IN_ROW;
- }
- if (stmt->options.rowsFetched)
- *stmt->options.rowsFetched = processed;
- return ret;
+ start_row = 0;
+ end_row = opts->rowset_size - 1;
}
-
- if (irow > stmt->last_fetch_count)
+ else
{
- stmt->errornumber = STMT_ROW_OUT_OF_RANGE;
- stmt->errormsg = "Row value out of range";
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ if (irow > stmt->last_fetch_count)
+ {
+ stmt->errornumber = STMT_ROW_OUT_OF_RANGE;
+ stmt->errormsg = "Row value out of range";
+ SC_log_error(func, "", stmt);
+ return SQL_ERROR;
+ }
+ start_row = end_row = irow - 1;
}
- irow--;
-
+ num_cols = QR_NumResultCols(res);
+ /* Reset for SQLGetData */
+ if (bindings)
+ for (i = 0; i < num_cols; i++)
+ bindings[i].data_left = -1;
+ ret = SQL_SUCCESS;
+ fcount = res->fcount;
#ifdef DRIVER_CURSOR_IMPLEMENT
switch (fOption)
{
case SQL_UPDATE:
- return SC_pos_update(stmt, irow);
case SQL_DELETE:
- return SC_pos_delete(stmt, irow);
case SQL_ADD:
- return SC_pos_add(stmt, irow);
+ if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed)
+ PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
+ break;
}
#endif /* DRIVER_CURSOR_IMPLEMENT */
- /* Reset for SQLGetData */
- for (i = 0; i < num_cols; i++)
- bindings[i].data_left = -1;
-
- if (fOption == SQL_REFRESH)
+ for (i = start_row, processed = 0; i <= end_row; i++)
{
- /* save the last_fetch_count */
- int last_fetch = stmt->last_fetch_count;
- int bind_save = stmt->bind_row;
-
+#if (ODBCVER >= 0x0300)
+ if (0 != irow || !opts->row_operation_ptr || opts->row_operation_ptr[i] == SQL_ROW_PROCEED)
+ {
+#endif /* ODBCVER */
+ global_ridx = i + stmt->rowset_start;
+ switch (fOption)
+ {
#ifdef DRIVER_CURSOR_IMPLEMENT
- if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
- SC_pos_reload(stmt, irow, (UWORD *) 0);
+ case SQL_UPDATE:
+ ret = SC_pos_update(stmt, (UWORD) i, global_ridx);
+ break;
+ case SQL_DELETE:
+ ret = SC_pos_delete(stmt, (UWORD) i, global_ridx);
+ break;
+ case SQL_ADD:
+ ret = SC_pos_add(stmt, (UWORD) i);
+ break;
#endif /* DRIVER_CURSOR_IMPLEMENT */
- stmt->currTuple = stmt->rowset_start + irow - 1;
- stmt->bind_row = irow;
- SC_fetch(stmt);
- /* restore the last_fetch_count */
- stmt->last_fetch_count = last_fetch;
- stmt->bind_row = bind_save;
+ case SQL_REFRESH:
+ ret = SC_pos_refresh(stmt, (UWORD) i, global_ridx);
+ break;
+ }
+ processed++;
+ if (SQL_ERROR == ret)
+ break;
+#if (ODBCVER >= 0x0300)
+ }
+#endif /* ODBCVER */
}
- else
- stmt->currTuple = stmt->rowset_start + irow;
- QR_set_position(res, irow);
-
- return SQL_SUCCESS;
+ if (SQL_ERROR == ret)
+ res->fcount = fcount; /* restore the count */
+ if (auto_commit_needed)
+ PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
+ if (irow > 0)
+ {
+ if (SQL_ADD != fOption) /* for SQLGetData */
+ {
+ stmt->currTuple = stmt->rowset_start + irow - 1;
+ QR_set_position(res, irow - 1);
+ }
+ }
+ else if (SC_get_IRD(stmt)->rowsFetched)
+ *SC_get_IRD(stmt)->rowsFetched = processed;
+inolog("rowset=%d processed=%d ret=%d\n", opts->rowset_size, processed, ret);
+ return ret;
}
diff --git a/src/interfaces/odbc/setup.c b/src/interfaces/odbc/setup.c
index 0175d69f32b..f243f0e2429 100644
--- a/src/interfaces/odbc/setup.c
+++ b/src/interfaces/odbc/setup.c
@@ -56,7 +56,7 @@ typedef struct tagSETUPDLG
/* Prototypes */
void INTFUNC CenterDialog(HWND hdlg);
-int CALLBACK ConfigDlgProc(HWND hdlg, WORD wMsg, WPARAM wParam, LPARAM lParam);
+int CALLBACK ConfigDlgProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
void INTFUNC ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg);
BOOL INTFUNC SetDSNAttributes(HWND hwnd, LPSETUPDLG lpsetupdlg);
@@ -211,7 +211,7 @@ CenterDialog(HWND hdlg)
*/
int CALLBACK
ConfigDlgProc(HWND hdlg,
- WORD wMsg,
+ UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
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");
diff --git a/src/interfaces/odbc/statement.h b/src/interfaces/odbc/statement.h
index 74583fbb2da..65fa088cb45 100644
--- a/src/interfaces/odbc/statement.h
+++ b/src/interfaces/odbc/statement.h
@@ -12,6 +12,7 @@
#include "psqlodbc.h"
#include "bind.h"
+#include "descriptor.h"
#ifndef FALSE
@@ -77,6 +78,7 @@ typedef enum
#define STMT_INVALID_OPTION_IDENTIFIER 28
#define STMT_RETURN_NULL_WITHOUT_INDICATOR 29
#define STMT_ERROR_IN_ROW 30
+#define STMT_INVALID_DESCRIPTOR_IDENTIFIER 31
/* statement types */
enum
@@ -115,33 +117,6 @@ enum
STMT_FETCH_EXTENDED,
};
-typedef struct
-{
- COL_INFO *col_info; /* cached SQLColumns info for this table */
- char name[MAX_TABLE_LEN + 1];
- char alias[MAX_TABLE_LEN + 1];
-} TABLE_INFO;
-
-typedef struct
-{
- TABLE_INFO *ti; /* resolve to explicit table names */
- int precision;
- int scale;
- int display_size;
- int length;
- int type;
- char nullable;
- char func;
- char expr;
- char quote;
- char dquote;
- char numeric;
- char updatable;
- char dot[MAX_TABLE_LEN + 1];
- char name[MAX_COLUMN_LEN + 1];
- char alias[MAX_COLUMN_LEN + 1];
-} FIELD_INFO;
-
/******** Statement Handle ***********/
struct StatementClass_
@@ -152,19 +127,23 @@ struct StatementClass_
QResultClass *curres; /* the current result in the chain */
HSTMT FAR *phstmt;
StatementOptions options;
+ ARDFields ardopts;
+ IRDFields irdopts;
+ APDFields apdopts;
+ IPDFields ipdopts;
STMT_Status status;
char *errormsg;
int errornumber;
/* information on bindings */
- BindInfoClass *bindings; /* array to store the binding information */
- BindInfoClass bookmark;
- int bindings_allocated;
+ /*** BindInfoClass *bindings; ***/ /* array to store the binding information */
+ /*** BindInfoClass bookmark;
+ int bindings_allocated; ***/
/* information on statement parameters */
- int parameters_allocated;
- ParameterInfoClass *parameters;
+ /*** int parameters_allocated;
+ ParameterInfoClass *parameters; ***/
Int4 currTuple; /* current absolute row number (GetData,
* SetPos, SQLFetch) */
@@ -184,8 +163,6 @@ struct StatementClass_
* statement that has been executed */
TABLE_INFO **ti;
- FIELD_INFO **fi;
- int nfld;
int ntab;
int parse_status;
@@ -219,6 +196,7 @@ struct StatementClass_
char inaccurate_result; /* Current status is PREMATURE but
* result is inaccurate */
char miscinfo;
+ char updatable;
SWORD errorpos;
SWORD error_recsize;
char *load_statement; /* to (re)load updatable individual rows */
@@ -231,6 +209,10 @@ struct StatementClass_
#define SC_get_Result(a) (a->result)
#define SC_set_Curres(a, b) (a->curres = b)
#define SC_get_Curres(a) (a->curres)
+#define SC_get_ARD(a) (&(a->ardopts))
+#define SC_get_APD(a) (&(a->apdopts))
+#define SC_get_IRD(a) (&(a->irdopts))
+#define SC_get_IPD(a) (&(a->ipdopts))
/* options for SC_free_params() */
#define STMT_FREE_PARAMS_ALL 0
@@ -262,5 +244,9 @@ RETCODE SC_fetch(StatementClass *self);
void SC_free_params(StatementClass *self, char option);
void SC_log_error(const char *func, const char *desc, const StatementClass *self);
unsigned long SC_get_bookmark(StatementClass *self);
+RETCODE SC_pos_update(StatementClass *self, UWORD irow, UDWORD index);
+RETCODE SC_pos_delete(StatementClass *self, UWORD irow, UDWORD index);
+RETCODE SC_pos_refresh(StatementClass *self, UWORD irow, UDWORD index);
+RETCODE SC_pos_add(StatementClass *self, UWORD irow);
#endif
diff --git a/src/interfaces/odbc/tuple.h b/src/interfaces/odbc/tuple.h
index 388f9fa0210..eb00cfd5094 100644
--- a/src/interfaces/odbc/tuple.h
+++ b/src/interfaces/odbc/tuple.h
@@ -38,10 +38,21 @@ struct KeySet_
UDWORD blocknum;
UDWORD oid;
};
-#define KEYSET_INFO_PUBLIC 0x0f
-#define DRV_SELF_ADDED (1L << 4)
-#define DRV_SELF_DELETED (1L << 5)
-#define DRV_SELF_UPDATED (1L << 6)
+/* Rollback(index + original TID) info */
+struct Rollback_
+{
+ UDWORD index;
+ UDWORD blocknum;
+ UWORD offset;
+};
+#define KEYSET_INFO_PUBLIC 0x07
+#define CURS_SELF_ADDING (1L << 3)
+#define CURS_SELF_DELETING (1L << 4)
+#define CURS_SELF_UPDATING (1L << 5)
+#define CURS_SELF_ADDED (1L << 6)
+#define CURS_SELF_DELETED (1L << 7)
+#define CURS_SELF_UPDATED (1L << 8)
+#define CURS_NEEDS_REREAD (1L << 9)
/* These macros are wrappers for the corresponding set_tuplefield functions
but these handle automatic NULL determination and call set_tuplefield_null()
diff --git a/src/interfaces/odbc/win32.mak b/src/interfaces/odbc/win32.mak
index 637e3763376..1614f4f2c33 100644
--- a/src/interfaces/odbc/win32.mak
+++ b/src/interfaces/odbc/win32.mak
@@ -96,9 +96,9 @@ CLEAN :
CPP=cl.exe
!IF "$(CFG)" == "MultibyteRelease"
-CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "MULTIBYTE" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "MULTIBYTE" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
!ELSE
-CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
!ENDIF
.c{$(INTDIR)}.obj::
diff --git a/src/interfaces/odbc/win32_30w.mak b/src/interfaces/odbc/win32_30w.mak
index 4455069fdad..e4dd84a66c5 100644
--- a/src/interfaces/odbc/win32_30w.mak
+++ b/src/interfaces/odbc/win32_30w.mak
@@ -1,7 +1,7 @@
#
# File: win32_30w.mak
#
-# Description: psqlodbc30 Unicode version Makefile for Win32.
+# Description: psqlodbc30w Unicode version Makefile for Win32.
#
# Configurations: Unicode30Debug, Unicode30
# Build Types: ALL, CLEAN
@@ -45,7 +45,7 @@ OUTDIR=.\Unicode30
OUTDIRBIN=.\Unicode30
INTDIR=.\Unicode30
-ALL : "$(OUTDIRBIN)\psqlodbc30.dll"
+ALL : "$(OUTDIRBIN)\psqlodbc30w.dll"
CLEAN :
@@ -82,7 +82,7 @@ CLEAN :
-@erase "$(INTDIR)\odbcapi.obj"
-@erase "$(INTDIR)\odbcapi30.obj"
-@erase "$(INTDIR)\vc60.idb"
- -@erase "$(OUTDIR)\psqlodbc30.dll"
+ -@erase "$(OUTDIR)\psqlodbc30w.dll"
-@erase "$(OUTDIR)\psqlodbc.exp"
-@erase "$(OUTDIR)\psqlodbc.lib"
@@ -131,7 +131,7 @@ BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc"
BSC32_SBRS= \
LINK32=link.exe
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"psqlodbc_api30w.def" /out:"$(OUTDIRBIN)\psqlodbc30.dll" /implib:"$(OUTDIR)\psqlodbc.lib"
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"psqlodbc_api30w.def" /out:"$(OUTDIRBIN)\psqlodbc30w.dll" /implib:"$(OUTDIR)\psqlodbc.lib"
DEF_FILE= "psqlodbc_api30w.def"
LINK32_OBJS= \
"$(INTDIR)\bind.obj" \
@@ -167,14 +167,14 @@ LINK32_OBJS= \
"$(INTDIR)\odbcapi30.obj" \
"$(INTDIR)\psqlodbc.res"
-"$(OUTDIRBIN)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+"$(OUTDIRBIN)\psqlodbc30w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "Unicode30Debug"
-ALL : "$(OUTDIR)\psqlodbc30.dll"
+ALL : "$(OUTDIR)\psqlodbc30w.dll"
CLEAN :
@@ -212,7 +212,7 @@ CLEAN :
-@erase "$(INTDIR)\odbcapi30.obj"
-@erase "$(INTDIR)\vc60.idb"
-@erase "$(INTDIR)\vc60.pdb"
- -@erase "$(OUTDIR)\psqlodbc30.dll"
+ -@erase "$(OUTDIR)\psqlodbc30w.dll"
-@erase "$(OUTDIR)\psqlodbc.exp"
-@erase "$(OUTDIR)\psqlodbc.ilk"
-@erase "$(OUTDIR)\psqlodbc.lib"
@@ -263,7 +263,7 @@ BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc"
BSC32_SBRS= \
LINK32=link.exe
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\psqlodbc.pdb" /debug /machine:I386 /def:"psqlodbc_api30w.def" /out:"$(OUTDIR)\psqlodbc30.dll" /implib:"$(OUTDIR)\psqlodbc.lib" /pdbtype:sept
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\psqlodbc.pdb" /debug /machine:I386 /def:"psqlodbc_api30w.def" /out:"$(OUTDIR)\psqlodbc30w.dll" /implib:"$(OUTDIR)\psqlodbc.lib" /pdbtype:sept
DEF_FILE= "psqlodbc_api30w.def"
LINK32_OBJS= \
"$(INTDIR)\bind.obj" \
@@ -299,7 +299,7 @@ LINK32_OBJS= \
"$(INTDIR)\odbcapi30.obj" \
"$(INTDIR)\psqlodbc.res"
-"$(OUTDIR)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+"$(OUTDIR)\psqlodbc30w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<