summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorByron Nikolaidis1998-06-16 21:29:19 +0000
committerByron Nikolaidis1998-06-16 21:29:19 +0000
commita80771f0a728ccb5c8f75753f0adac401c33fc5e (patch)
tree0277bb9466951c80c50d455f424b6148135d4837
parentfd262dac8c7eae2672949fe4ae344e932bf73ac3 (diff)
Update to v.0246
-rw-r--r--src/interfaces/odbc/bind.c95
-rw-r--r--src/interfaces/odbc/connection.c66
-rw-r--r--src/interfaces/odbc/connection.h2
-rw-r--r--src/interfaces/odbc/convert.c479
-rw-r--r--src/interfaces/odbc/dlg_specific.c19
-rw-r--r--src/interfaces/odbc/dlg_specific.h2
-rw-r--r--src/interfaces/odbc/drvconn.c10
-rw-r--r--src/interfaces/odbc/environ.c18
-rw-r--r--src/interfaces/odbc/environ.h1
-rw-r--r--src/interfaces/odbc/execute.c74
-rw-r--r--src/interfaces/odbc/info.c204
-rw-r--r--src/interfaces/odbc/options.c46
-rw-r--r--src/interfaces/odbc/pgtypes.c22
-rw-r--r--src/interfaces/odbc/pgtypes.h1
-rw-r--r--src/interfaces/odbc/psqlodbc.h4
-rw-r--r--src/interfaces/odbc/psqlodbc.rc10
-rw-r--r--src/interfaces/odbc/resource.h1
-rw-r--r--src/interfaces/odbc/results.c92
-rw-r--r--src/interfaces/odbc/statement.c61
-rw-r--r--src/interfaces/odbc/statement.h1
20 files changed, 814 insertions, 394 deletions
diff --git a/src/interfaces/odbc/bind.c b/src/interfaces/odbc/bind.c
index 504dbc20eba..0b8fe9dbde8 100644
--- a/src/interfaces/odbc/bind.c
+++ b/src/interfaces/odbc/bind.c
@@ -37,9 +37,12 @@ RETCODE SQL_API SQLBindParameter(
SDWORD FAR *pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
+char *func="SQLBindParameter";
- if( ! stmt)
+ if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
if(stmt->parameters_allocated < ipar) {
ParameterInfoClass *old_parameters;
@@ -52,6 +55,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
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;
}
@@ -133,53 +137,51 @@ RETCODE SQL_API SQLBindCol(
SDWORD FAR *pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
-Int2 numcols;
+Int2 numcols = 0;
+char *func="SQLBindCol";
mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
if (icol < 1) {
/* currently we do not support bookmarks */
stmt->errormsg = "Bookmarks are not currently supported.";
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
- icol--; /* use zero based col numbers */
-
SC_clear_error(stmt);
- if( ! stmt->result) {
- stmt->errormsg = "Can't bind columns with a NULL query result structure.";
- stmt->errornumber = STMT_SEQUENCE_ERROR;
- return SQL_ERROR;
- }
-
if( stmt->status == STMT_EXECUTING) {
stmt->errormsg = "Can't bind columns while statement is still executing.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
- numcols = QR_NumResultCols(stmt->result);
-
- mylog("SQLBindCol: numcols = %d\n", numcols);
-
- if (icol >= numcols) {
- stmt->errornumber = STMT_COLNUM_ERROR;
- stmt->errormsg = "Column number too big";
- return SQL_ERROR;
- }
+ // allocate enough bindings if not already done
+ // Most likely, 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);
+ // check to see if the bindings were allocated
if ( ! stmt->bindings) {
- stmt->errormsg = "Bindings were not allocated properly.";
- stmt->errornumber = STMT_SEQUENCE_ERROR;
+ stmt->errormsg = "Could not allocate memory for bindings.";
+ stmt->errornumber = STMT_NO_MEMORY_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
- if ((cbValueMax == 0) || (rgbValue == NULL)) {
+ icol--; /* use zero based col numbers from here out */
+
+ if (rgbValue == NULL) {
/* we have to unbind the column */
stmt->bindings[icol].buflen = 0;
stmt->bindings[icol].buffer = NULL;
@@ -216,13 +218,17 @@ RETCODE SQL_API SQLDescribeParam(
SWORD FAR *pfNullable)
{
StatementClass *stmt = (StatementClass *) hstmt;
+char *func = "SQLDescribeParam";
- if( ! stmt)
+ if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
if( (ipar < 1) || (ipar > stmt->parameters_allocated) ) {
stmt->errormsg = "Invalid parameter number for SQLDescribeParam.";
stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -254,6 +260,9 @@ RETCODE SQL_API SQLParamOptions(
UDWORD crow,
UDWORD FAR *pirow)
{
+char *func = "SQLParamOptions";
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
return SQL_ERROR;
}
@@ -273,21 +282,26 @@ RETCODE SQL_API SQLNumParams(
StatementClass *stmt = (StatementClass *) hstmt;
char in_quote = FALSE;
unsigned int i;
+char *func = "SQLNumParams";
-
- if(!stmt)
+ if(!stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
if (pcpar)
*pcpar = 0;
- else
+ else {
+ SC_log_error(func, "pcpar was null", stmt);
return SQL_ERROR;
+ }
if(!stmt->statement) {
// no statement has been allocated
stmt->errormsg = "SQLNumParams called with no statement ready.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
} else {
@@ -341,6 +355,14 @@ mylog("in extend_bindings: stmt=%u, bindings_allocated=%d, num_columns=%d\n", st
if(stmt->bindings_allocated < num_columns) {
new_bindings = create_empty_bindings(num_columns);
+ if ( ! new_bindings) {
+ if (stmt->bindings) {
+ free(stmt->bindings);
+ stmt->bindings = NULL;
+ }
+ stmt->bindings_allocated = 0;
+ return;
+ }
if(stmt->bindings) {
for(i=0; i<stmt->bindings_allocated; i++)
@@ -349,18 +371,17 @@ mylog("in extend_bindings: stmt=%u, bindings_allocated=%d, num_columns=%d\n", st
free(stmt->bindings);
}
- stmt->bindings = new_bindings; // null indicates error
+ stmt->bindings = new_bindings;
stmt->bindings_allocated = num_columns;
- } else {
- /* if we have too many, make sure the extra ones are emptied out */
- /* so we don't accidentally try to use them for anything */
- for(i = num_columns; i < stmt->bindings_allocated; i++) {
- stmt->bindings[i].buflen = 0;
- stmt->bindings[i].buffer = NULL;
- stmt->bindings[i].used = NULL;
- }
- }
+ }
+ // There is no reason to zero out extra bindings if there are
+ // more than needed. If an app has allocated extra bindings,
+ // let it worry about it by unbinding those columns.
+
+ // SQLBindCol(1..) ... SQLBindCol(10...) # got 10 bindings
+ // SQLExecDirect(...) # returns 5 cols
+ // SQLExecDirect(...) # returns 10 cols (now OK)
mylog("exit extend_bindings\n");
}
diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c
index 95eceab0c27..69de1773502 100644
--- a/src/interfaces/odbc/connection.c
+++ b/src/interfaces/odbc/connection.c
@@ -35,7 +35,7 @@ RETCODE SQL_API SQLAllocConnect(
{
EnvironmentClass *env = (EnvironmentClass *)henv;
ConnectionClass *conn;
-
+char *func="SQLAllocConnect";
conn = CC_Constructor();
mylog("**** SQLAllocConnect: henv = %u, conn = %u\n", henv, conn);
@@ -44,6 +44,7 @@ ConnectionClass *conn;
env->errormsg = "Couldn't allocate memory for Connection object.";
env->errornumber = ENV_ALLOC_ERROR;
*phdbc = SQL_NULL_HDBC;
+ EN_log_error(func, "", env);
return SQL_ERROR;
}
@@ -52,6 +53,7 @@ ConnectionClass *conn;
env->errornumber = ENV_ALLOC_ERROR;
CC_Destructor(conn);
*phdbc = SQL_NULL_HDBC;
+ EN_log_error(func, "", env);
return SQL_ERROR;
}
@@ -74,9 +76,12 @@ RETCODE SQL_API SQLConnect(
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci;
+char *func = "SQLConnect";
- if ( ! conn)
+ if ( ! conn) {
+ CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
ci = &conn->connInfo;
@@ -96,9 +101,11 @@ ConnInfo *ci;
qlog("conn = %u, SQLConnect(DSN='%s', UID='%s', PWD='%s')\n", ci->dsn, ci->username, ci->password);
- if ( CC_connect(conn, FALSE) <= 0)
+ if ( CC_connect(conn, FALSE) <= 0) {
// Error messages are filled in
+ CC_log_error(func, "Error on CC_connect", conn);
return SQL_ERROR;
+ }
return SQL_SUCCESS;
}
@@ -123,17 +130,21 @@ RETCODE SQL_API SQLDisconnect(
HDBC hdbc)
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
+char *func = "SQLDisconnect";
mylog("**** in SQLDisconnect\n");
- if ( ! conn)
+ if ( ! conn) {
+ CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
qlog("conn=%u, SQLDisconnect\n", conn);
if (conn->status == CONN_EXECUTING) {
conn->errornumber = CONN_IN_USE;
conn->errormsg = "A transaction is currently being executed";
+ CC_log_error(func, "", conn);
return SQL_ERROR;
}
@@ -155,16 +166,20 @@ RETCODE SQL_API SQLFreeConnect(
HDBC hdbc)
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
+char *func = "SQLFreeConnect";
mylog("**** in SQLFreeConnect: hdbc=%u\n", hdbc);
- if ( ! conn)
+ if ( ! conn) {
+ CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
/* Remove the connection from the environment */
if ( ! EN_remove_connection(conn->henv, conn)) {
conn->errornumber = CONN_IN_USE;
conn->errormsg = "A transaction is currently being executed";
+ CC_log_error(func, "", conn);
return SQL_ERROR;
}
@@ -577,8 +592,9 @@ char salt[2];
/******* Send any initial settings *********/
/**********************************************/
- if ( ! CC_send_settings(self))
- return 0;
+ // The Unix iodbc errors out on this call because it allocates a statement
+ // before the connection is established. Therefore, don't check for error here.
+ CC_send_settings(self);
CC_lookup_lo(self); /* a hack to get the oid of our large object oid type */
@@ -1155,6 +1171,27 @@ RETCODE result;
result = SQLFreeStmt(hstmt, SQL_DROP);
}
+void
+CC_log_error(char *func, char *desc, ConnectionClass *self)
+{
+ if (self) {
+ qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg);
+ qlog(" ------------------------------------------------------------\n");
+ qlog(" henv=%u, conn=%u, status=%u, num_stmts=%d\n", self->henv, self, self->status, self->num_stmts);
+ qlog(" sock=%u, stmts=%u, lobj_type=%d\n", self->sock, self->stmts, self->lobj_type);
+
+ qlog(" ---------------- Socket Info -------------------------------\n");
+ if (self->sock) {
+ SocketClass *sock = self->sock;
+ qlog(" socket=%d, reverse=%d, errornumber=%d, errormsg='%s'\n", sock->socket, sock->reverse, sock->errornumber, sock->errormsg);
+ qlog(" buffer_in=%u, buffer_out=%u\n", sock->buffer_in, sock->buffer_out);
+ qlog(" buffer_filled_in=%d, buffer_filled_out=%d, buffer_read_in=%d\n", sock->buffer_filled_in, sock->buffer_filled_out, sock->buffer_read_in);
+ }
+ }
+ else
+ qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
+}
+
/*
void
CC_test(ConnectionClass *self)
@@ -1165,23 +1202,28 @@ SDWORD pcbValue;
UDWORD pcrow;
UWORD rgfRowStatus;
char buf[255];
+SDWORD buflen;
+DATE_STRUCT *ds;
result = SQLAllocStmt( self, &hstmt1);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
return;
}
- result = SQLExtendedFetch(hstmt1, SQL_FETCH_ABSOLUTE, -2, &pcrow, &rgfRowStatus);
- SQLGetData(hstmt1, 1, SQL_C_CHAR, buf, sizeof(buf), &pcbValue);
- qlog("FETCH_ABSOLUTE, -2: result=%d, Col1 = '%s'\n", result, buf);
+ result = SQLExecDirect(hstmt1, "select * from cpar", SQL_NTS);
+ qlog("exec result = %d\n", result);
+
+ result = SQLBindCol(hstmt1, 2, SQL_C_DATE, buf, 0, &buflen);
+ qlog("bind result = %d\n", result);
result = SQLFetch(hstmt1);
while (result != SQL_NO_DATA_FOUND) {
+ ds = (DATE_STRUCT *) buf;
+ qlog("fetch on stmt1: result=%d, buflen=%d: year=%d, month=%d, day=%d\n", result, buflen, ds->year, ds->month, ds->day);
+
result = SQLFetch(hstmt1);
- qlog("fetch on stmt1\n");
}
SQLFreeStmt(hstmt1, SQL_DROP);
}
*/
-
diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h
index 8ffc15b3d35..e5d380c5cf0 100644
--- a/src/interfaces/odbc/connection.h
+++ b/src/interfaces/odbc/connection.h
@@ -133,6 +133,7 @@ typedef struct {
// char unknown_sizes[SMALL_REGISTRY_LEN];
char fake_oid_index[SMALL_REGISTRY_LEN];
char show_oid_column[SMALL_REGISTRY_LEN];
+ char row_versioning[SMALL_REGISTRY_LEN];
char show_system_tables[SMALL_REGISTRY_LEN];
char focus_password;
} ConnInfo;
@@ -188,5 +189,6 @@ char *CC_create_errormsg(ConnectionClass *self);
int CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs);
char CC_send_settings(ConnectionClass *self);
void CC_lookup_lo(ConnectionClass *conn);
+void CC_log_error(char *func, char *desc, ConnectionClass *self);
#endif
diff --git a/src/interfaces/odbc/convert.c b/src/interfaces/odbc/convert.c
index 22da73e0814..a6b6bac4b20 100644
--- a/src/interfaces/odbc/convert.c
+++ b/src/interfaces/odbc/convert.c
@@ -94,289 +94,272 @@ struct tm *tim;
st.y = tim->tm_year + 1900;
mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType, value, cbValueMax);
- if(value) {
- /********************************************************************
- First convert any specific postgres types into more
- useable data.
+ if ( ! value) {
+ /* handle a null just by returning SQL_NULL_DATA in pcbValue, */
+ /* and doing nothing to the buffer. */
+ if(pcbValue) {
+ *pcbValue = SQL_NULL_DATA;
+ }
+ return COPY_OK;
+ }
+
+ /********************************************************************
+ First convert any specific postgres types into more
+ useable data.
+
+ NOTE: Conversions from PG char/varchar of a date/time/timestamp
+ value to SQL_C_DATE,SQL_C_TIME, SQL_C_TIMESTAMP not supported
+ *********************************************************************/
+ switch(field_type) {
+ /* $$$ need to add parsing for date/time/timestamp strings in PG_TYPE_CHAR,VARCHAR $$$ */
+ case PG_TYPE_DATE:
+ sscanf(value, "%4d-%2d-%2d", &st.y, &st.m, &st.d);
+ break;
+
+ case PG_TYPE_TIME:
+ sscanf(value, "%2d:%2d:%2d", &st.hh, &st.mm, &st.ss);
+ break;
+
+ case PG_TYPE_ABSTIME:
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP:
+ if (strnicmp(value, "invalid", 7) != 0) {
+ sscanf(value, "%4d-%2d-%2d %2d:%2d:%2d", &st.y, &st.m, &st.d, &st.hh, &st.mm, &st.ss);
+
+ } else { /* The timestamp is invalid so set something conspicuous, like the epoch */
+ t = 0;
+ tim = localtime(&t);
+ st.m = tim->tm_mon + 1;
+ st.d = tim->tm_mday;
+ st.y = tim->tm_year + 1900;
+ st.hh = tim->tm_hour;
+ st.mm = tim->tm_min;
+ st.ss = tim->tm_sec;
+ }
+ break;
+
+ case PG_TYPE_BOOL: { /* change T/F to 1/0 */
+ char *s = (char *) value;
+ if (s[0] == 'T' || s[0] == 't')
+ s[0] = '1';
+ else
+ s[0] = '0';
+ }
+ break;
+
+ /* This is for internal use by SQLStatistics() */
+ case PG_TYPE_INT28: {
+ // this is an array of eight integers
+ short *short_array = (short *)rgbValue;
+
+ len = 16;
+
+ sscanf(value, "%hd %hd %hd %hd %hd %hd %hd %hd",
+ &short_array[0],
+ &short_array[1],
+ &short_array[2],
+ &short_array[3],
+ &short_array[4],
+ &short_array[5],
+ &short_array[6],
+ &short_array[7]);
+
+ /* There is no corresponding fCType for this. */
+ if(pcbValue)
+ *pcbValue = len;
+
+ return COPY_OK; /* dont go any further or the data will be trashed */
+ }
+
+ /* This is a large object OID, which is used to store LONGVARBINARY objects. */
+ case PG_TYPE_LO:
+
+ return convert_lo( stmt, value, fCType, rgbValue, cbValueMax, pcbValue, multiple);
+
+ default:
+
+ if (field_type == stmt->hdbc->lobj_type) /* hack until permanent type available */
+ return convert_lo( stmt, value, fCType, rgbValue, cbValueMax, pcbValue, multiple);
+ }
+
+ /* Change default into something useable */
+ if (fCType == SQL_C_DEFAULT) {
+ fCType = pgtype_to_ctype(stmt, field_type);
+
+ mylog("copy_and_convert, SQL_C_DEFAULT: fCType = %d\n", fCType);
+ }
+
+
+ if(fCType == SQL_C_CHAR) {
- NOTE: Conversions from PG char/varchar of a date/time/timestamp
- value to SQL_C_DATE,SQL_C_TIME, SQL_C_TIMESTAMP not supported
- *********************************************************************/
+ /* Special character formatting as required */
+ /* These really should return error if cbValueMax is not big enough. */
switch(field_type) {
- /* $$$ need to add parsing for date/time/timestamp strings in PG_TYPE_CHAR,VARCHAR $$$ */
case PG_TYPE_DATE:
- sscanf(value, "%4d-%2d-%2d", &st.y, &st.m, &st.d);
+ len = 10;
+ if (cbValueMax > len)
+ sprintf((char *)rgbValue, "%.4d-%.2d-%.2d", st.y, st.m, st.d);
break;
case PG_TYPE_TIME:
- sscanf(value, "%2d:%2d:%2d", &st.hh, &st.mm, &st.ss);
+ len = 8;
+ if (cbValueMax > len)
+ sprintf((char *)rgbValue, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss);
break;
case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME:
- if (strnicmp(value, "invalid", 7) != 0) {
- sscanf(value, "%4d-%2d-%2d %2d:%2d:%2d", &st.y, &st.m, &st.d, &st.hh, &st.mm, &st.ss);
-
- } else { /* The timestamp is invalid so set something conspicuous, like the epoch */
- t = 0;
- tim = localtime(&t);
- st.m = tim->tm_mon + 1;
- st.d = tim->tm_mday;
- st.y = tim->tm_year + 1900;
- st.hh = tim->tm_hour;
- st.mm = tim->tm_min;
- st.ss = tim->tm_sec;
- }
+ case PG_TYPE_TIMESTAMP:
+ len = 19;
+ if (cbValueMax > len)
+ sprintf((char *) rgbValue, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
+ st.y, st.m, st.d, st.hh, st.mm, st.ss);
break;
- case PG_TYPE_BOOL: { /* change T/F to 1/0 */
- char *s = (char *) value;
- if (s[0] == 'T' || s[0] == 't')
- s[0] = '1';
- else
- s[0] = '0';
+ case PG_TYPE_BOOL:
+ len = 1;
+ if (cbValueMax > len) {
+ strcpy((char *) rgbValue, value);
+ mylog("PG_TYPE_BOOL: rgbValue = '%s'\n", rgbValue);
}
break;
- /* This is for internal use by SQLStatistics() */
- case PG_TYPE_INT28: {
- // this is an array of eight integers
- short *short_array = (short *)rgbValue;
+ /* Currently, data is SILENTLY TRUNCATED for BYTEA and character data
+ types if there is not enough room in cbValueMax because the driver
+ can't handle multiple calls to SQLGetData for these, yet. Most likely,
+ the buffer passed in will be big enough to handle the maximum limit of
+ postgres, anyway.
- len = 16;
+ LongVarBinary types are handled correctly above, observing truncation
+ and all that stuff since there is essentially no limit on the large
+ object used to store those.
+ */
+ case PG_TYPE_BYTEA: // convert binary data to hex strings (i.e, 255 = "FF")
+ len = convert_pgbinary_to_char(value, rgbValue, cbValueMax);
+ break;
- sscanf(value, "%hd %hd %hd %hd %hd %hd %hd %hd",
- &short_array[0],
- &short_array[1],
- &short_array[2],
- &short_array[3],
- &short_array[4],
- &short_array[5],
- &short_array[6],
- &short_array[7]);
+ default:
+ /* convert linefeeds to carriage-return/linefeed */
+ convert_linefeeds( (char *) value, rgbValue, cbValueMax);
+ len = strlen(rgbValue);
- /* There is no corresponding fCType for this. */
- if(pcbValue)
- *pcbValue = len;
+ mylog(" SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValue = '%s'\n", len, cbValueMax, rgbValue);
+ break;
+ }
- return COPY_OK; /* dont go any further or the data will be trashed */
- }
- /* This is a large object OID, which is used to store LONGVARBINARY objects. */
- case PG_TYPE_LO:
+ } else {
- return convert_lo( stmt, value, fCType, rgbValue, cbValueMax, pcbValue, multiple);
+ /* for SQL_C_CHAR, its probably ok to leave currency symbols in. But
+ to convert to numeric types, it is necessary to get rid of those.
+ */
+ if (field_type == PG_TYPE_MONEY)
+ convert_money(value);
+
+ switch(fCType) {
+ case SQL_C_DATE:
+ len = 6;
+ {
+ DATE_STRUCT *ds = (DATE_STRUCT *) rgbValue;
+ ds->year = st.y;
+ ds->month = st.m;
+ ds->day = st.d;
+ }
+ break;
- default:
+ case SQL_C_TIME:
+ len = 6;
+ {
+ TIME_STRUCT *ts = (TIME_STRUCT *) rgbValue;
+ ts->hour = st.hh;
+ ts->minute = st.mm;
+ ts->second = st.ss;
+ }
+ break;
- if (field_type == stmt->hdbc->lobj_type) /* hack until permanent type available */
- return convert_lo( stmt, value, fCType, rgbValue, cbValueMax, pcbValue, multiple);
- }
+ case SQL_C_TIMESTAMP:
+ len = 16;
+ {
+ TIMESTAMP_STRUCT *ts = (TIMESTAMP_STRUCT *) rgbValue;
+ ts->year = st.y;
+ ts->month = st.m;
+ ts->day = st.d;
+ ts->hour = st.hh;
+ ts->minute = st.mm;
+ ts->second = st.ss;
+ ts->fraction = 0;
+ }
+ break;
- /* Change default into something useable */
- if (fCType == SQL_C_DEFAULT) {
- fCType = pgtype_to_ctype(stmt, field_type);
+ case SQL_C_BIT:
+ len = 1;
+ *((UCHAR *)rgbValue) = atoi(value);
+ mylog("SQL_C_BIT: val = %d, cb = %d, rgb=%d\n", atoi(value), cbValueMax, *((UCHAR *)rgbValue));
+ break;
- mylog("copy_and_convert, SQL_C_DEFAULT: fCType = %d\n", fCType);
- }
+ case SQL_C_STINYINT:
+ case SQL_C_TINYINT:
+ len = 1;
+ *((SCHAR *) rgbValue) = atoi(value);
+ break;
+ case SQL_C_UTINYINT:
+ len = 1;
+ *((UCHAR *) rgbValue) = atoi(value);
+ break;
- if(fCType == SQL_C_CHAR) {
-
- /* Special character formatting as required */
- switch(field_type) {
- case PG_TYPE_DATE:
- len = 11;
- if (cbValueMax >= len)
- sprintf((char *)rgbValue, "%.4d-%.2d-%.2d", st.y, st.m, st.d);
- break;
-
- case PG_TYPE_TIME:
- len = 9;
- if (cbValueMax >= len)
- sprintf((char *)rgbValue, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss);
- break;
-
- case PG_TYPE_ABSTIME:
- case PG_TYPE_DATETIME:
- len = 19;
- if (cbValueMax >= len)
- sprintf((char *) rgbValue, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
- st.y, st.m, st.d, st.hh, st.mm, st.ss);
- break;
-
- case PG_TYPE_BOOL:
- len = 1;
- if (cbValueMax > len) {
- strcpy((char *) rgbValue, value);
- mylog("PG_TYPE_BOOL: rgbValue = '%s'\n", rgbValue);
- }
- break;
-
- case PG_TYPE_BYTEA: // convert binary data to hex strings (i.e, 255 = "FF")
- len = convert_pgbinary_to_char(value, rgbValue, cbValueMax);
- break;
-
- default:
- /* convert linefeeds to carriage-return/linefeed */
- convert_linefeeds( (char *) value, rgbValue, cbValueMax);
- len = strlen(rgbValue);
-
- mylog(" SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValue = '%s'\n", len, cbValueMax, rgbValue);
- break;
- }
+ case SQL_C_FLOAT:
+ len = 4;
+ *((SFLOAT *)rgbValue) = (float) atof(value);
+ break;
- } else {
+ case SQL_C_DOUBLE:
+ len = 8;
+ *((SDOUBLE *)rgbValue) = atof(value);
+ break;
- /* for SQL_C_CHAR, its probably ok to leave currency symbols in. But
- to convert to numeric types, it is necessary to get rid of those.
- */
- if (field_type == PG_TYPE_MONEY)
- convert_money(value);
-
- switch(fCType) {
- case SQL_C_DATE:
- len = 6;
- if (cbValueMax >= len) {
- DATE_STRUCT *ds = (DATE_STRUCT *) rgbValue;
- ds->year = st.y;
- ds->month = st.m;
- ds->day = st.d;
- }
- break;
-
- case SQL_C_TIME:
- len = 6;
- if (cbValueMax >= len) {
- TIME_STRUCT *ts = (TIME_STRUCT *) rgbValue;
- ts->hour = st.hh;
- ts->minute = st.mm;
- ts->second = st.ss;
- }
- break;
-
- case SQL_C_TIMESTAMP:
- len = 16;
- if (cbValueMax >= len) {
- TIMESTAMP_STRUCT *ts = (TIMESTAMP_STRUCT *) rgbValue;
- ts->year = st.y;
- ts->month = st.m;
- ts->day = st.d;
- ts->hour = st.hh;
- ts->minute = st.mm;
- ts->second = st.ss;
- ts->fraction = 0;
- }
- break;
-
- case SQL_C_BIT:
- len = 1;
- if (cbValueMax >= len || field_type == PG_TYPE_BOOL) {
- *((UCHAR *)rgbValue) = atoi(value);
- mylog("SQL_C_BIT: val = %d, cb = %d, rgb=%d\n", atoi(value), cbValueMax, *((UCHAR *)rgbValue));
- }
- break;
-
- case SQL_C_STINYINT:
- case SQL_C_TINYINT:
- len = 1;
- if (cbValueMax >= len)
- *((SCHAR *) rgbValue) = atoi(value);
- break;
-
- case SQL_C_UTINYINT:
- len = 1;
- if (cbValueMax >= len)
- *((UCHAR *) rgbValue) = atoi(value);
- break;
-
- case SQL_C_FLOAT:
- len = 4;
- if(cbValueMax >= len)
- *((SFLOAT *)rgbValue) = (float) atof(value);
- break;
-
- case SQL_C_DOUBLE:
- len = 8;
- if(cbValueMax >= len)
- *((SDOUBLE *)rgbValue) = atof(value);
- break;
-
- case SQL_C_SSHORT:
- case SQL_C_SHORT:
- len = 2;
- if(cbValueMax >= len)
- *((SWORD *)rgbValue) = atoi(value);
- break;
-
- case SQL_C_USHORT:
- len = 2;
- if(cbValueMax >= len)
- *((UWORD *)rgbValue) = atoi(value);
- break;
-
- case SQL_C_SLONG:
- case SQL_C_LONG:
- len = 4;
- if(cbValueMax >= len)
- *((SDWORD *)rgbValue) = atol(value);
- break;
-
- case SQL_C_ULONG:
- len = 4;
- if(cbValueMax >= len)
- *((UDWORD *)rgbValue) = atol(value);
- break;
-
- case SQL_C_BINARY:
-
- // truncate if necessary
- // convert octal escapes to bytes
- len = convert_from_pgbinary(value, rgbValue, cbValueMax);
- mylog("SQL_C_BINARY: len = %d\n", len);
- break;
-
- default:
- return COPY_UNSUPPORTED_TYPE;
- }
- }
- } else {
- /* handle a null just by returning SQL_NULL_DATA in pcbValue, */
- /* and doing nothing to the buffer. */
- if(pcbValue) {
- *pcbValue = SQL_NULL_DATA;
- }
- }
+ case SQL_C_SSHORT:
+ case SQL_C_SHORT:
+ len = 2;
+ *((SWORD *)rgbValue) = atoi(value);
+ break;
- // store the length of what was copied, if there's a place for it
- // unless it was a NULL (in which case it was already set above)
- if(pcbValue && value)
- *pcbValue = len;
+ case SQL_C_USHORT:
+ len = 2;
+ *((UWORD *)rgbValue) = atoi(value);
+ break;
- if(len > cbValueMax) {
- mylog("!!! COPY_RESULT_TRUNCATED !!!\n");
+ case SQL_C_SLONG:
+ case SQL_C_LONG:
+ len = 4;
+ *((SDWORD *)rgbValue) = atol(value);
+ break;
- // Don't return truncated because an application
- // (like Access) will try to call GetData again
- // to retrieve the rest of the data. Since we
- // are not currently ready for this, and the result
- // is an endless loop, we better just silently
- // truncate the data.
- // return COPY_RESULT_TRUNCATED;
+ case SQL_C_ULONG:
+ len = 4;
+ *((UDWORD *)rgbValue) = atol(value);
+ break;
- // LongVarBinary types do handle truncated multiple get calls
- // through convert_lo().
+ case SQL_C_BINARY:
- if (pcbValue)
- *pcbValue = cbValueMax -1;
+ // truncate if necessary
+ // convert octal escapes to bytes
+ len = convert_from_pgbinary(value, rgbValue, cbValueMax);
+ mylog("SQL_C_BINARY: len = %d\n", len);
+ break;
+
+ default:
+ return COPY_UNSUPPORTED_TYPE;
+ }
+ }
- return COPY_OK;
+ // store the length of what was copied, if there's a place for it
+ if(pcbValue)
+ *pcbValue = len;
- } else {
+ return COPY_OK;
- return COPY_OK;
- }
}
/* This function inserts parameters into an SQL statements.
@@ -386,6 +369,7 @@ struct tm *tim;
int
copy_statement_with_parameters(StatementClass *stmt)
{
+char *func="copy_statement_with_parameters";
unsigned int opos, npos;
char param_string[128], tmp[256], cbuf[TEXT_FIELD_SIZE+5];
int param_number;
@@ -400,8 +384,10 @@ char *buffer, *buf;
char in_quote = FALSE;
- if ( ! old_statement)
+ if ( ! old_statement) {
+ SC_log_error(func, "No statement string", stmt);
return SQL_ERROR;
+ }
memset(&st, 0, sizeof(SIMPLE_TIME));
@@ -624,6 +610,7 @@ char in_quote = FALSE;
stmt->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
new_statement[npos] = '\0'; // just in case
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
diff --git a/src/interfaces/odbc/dlg_specific.c b/src/interfaces/odbc/dlg_specific.c
index e04cc8b5696..7c8c3559eec 100644
--- a/src/interfaces/odbc/dlg_specific.c
+++ b/src/interfaces/odbc/dlg_specific.c
@@ -226,6 +226,7 @@ char buf[128];
CheckDlgButton(hdlg, DS_SHOWOIDCOLUMN, atoi(ci->show_oid_column));
CheckDlgButton(hdlg, DS_FAKEOIDINDEX, atoi(ci->fake_oid_index));
+ CheckDlgButton(hdlg, DS_ROWVERSIONING, atoi(ci->row_versioning));
CheckDlgButton(hdlg, DS_SHOWSYSTEMTABLES, atoi(ci->show_system_tables));
EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), atoi(ci->show_oid_column));
@@ -273,6 +274,8 @@ char buf[128];
sprintf(ci->show_system_tables, "%d", IsDlgButtonChecked(hdlg, DS_SHOWSYSTEMTABLES));
+ sprintf(ci->row_versioning, "%d", IsDlgButtonChecked(hdlg, DS_ROWVERSIONING));
+
/* OID Options*/
sprintf(ci->fake_oid_index, "%d", IsDlgButtonChecked(hdlg, DS_FAKEOIDINDEX));
sprintf(ci->show_oid_column, "%d", IsDlgButtonChecked(hdlg, DS_SHOWOIDCOLUMN));
@@ -297,7 +300,7 @@ makeConnectString(char *connect_string, ConnInfo *ci)
{
char got_dsn = (ci->dsn[0] != '\0');
- sprintf(connect_string, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;UID=%s;READONLY=%s;PWD=%s;PROTOCOL=%s;FAKEOIDINDEX=%s;SHOWOIDCOLUMN=%s;SHOWSYSTEMTABLES=%s;CONNSETTINGS=%s",
+ sprintf(connect_string, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;UID=%s;READONLY=%s;PWD=%s;PROTOCOL=%s;FAKEOIDINDEX=%s;SHOWOIDCOLUMN=%s;ROWVERSIONING=%s;SHOWSYSTEMTABLES=%s;CONNSETTINGS=%s",
got_dsn ? "DSN" : "DRIVER",
got_dsn ? ci->dsn : ci->driver,
ci->database,
@@ -310,6 +313,7 @@ char got_dsn = (ci->dsn[0] != '\0');
// ci->unknown_sizes, -- currently only needed in Driver options.
ci->fake_oid_index,
ci->show_oid_column,
+ ci->row_versioning,
ci->show_system_tables,
ci->conn_settings);
}
@@ -355,6 +359,9 @@ copyAttributes(ConnInfo *ci, char *attribute, char *value)
else if (stricmp(attribute, INI_FAKEOIDINDEX) == 0)
strcpy(ci->fake_oid_index, value);
+ else if (stricmp(attribute, INI_ROWVERSIONING) == 0)
+ strcpy(ci->row_versioning, value);
+
else if (stricmp(attribute, INI_SHOWSYSTEMTABLES) == 0)
strcpy(ci->show_system_tables, value);
@@ -398,6 +405,8 @@ getDSNdefaults(ConnInfo *ci)
if (ci->show_system_tables[0] == '\0')
sprintf(ci->show_system_tables, "%d", DEFAULT_SHOWSYSTEMTABLES);
+ if (ci->row_versioning[0] == '\0')
+ sprintf(ci->row_versioning, "%d", DEFAULT_ROWVERSIONING);
}
@@ -448,6 +457,9 @@ char *DSN = ci->dsn;
if ( ci->fake_oid_index[0] == '\0' || overwrite)
SQLGetPrivateProfileString(DSN, INI_FAKEOIDINDEX, "", ci->fake_oid_index, sizeof(ci->fake_oid_index), ODBC_INI);
+ if ( ci->row_versioning[0] == '\0' || overwrite)
+ SQLGetPrivateProfileString(DSN, INI_ROWVERSIONING, "", ci->row_versioning, sizeof(ci->row_versioning), ODBC_INI);
+
if ( ci->show_system_tables[0] == '\0' || overwrite)
SQLGetPrivateProfileString(DSN, INI_SHOWSYSTEMTABLES, "", ci->show_system_tables, sizeof(ci->show_system_tables), ODBC_INI);
@@ -534,6 +546,11 @@ char *DSN = ci->dsn;
ODBC_INI);
SQLWritePrivateProfileString(DSN,
+ INI_ROWVERSIONING,
+ ci->row_versioning,
+ ODBC_INI);
+
+ SQLWritePrivateProfileString(DSN,
INI_SHOWSYSTEMTABLES,
ci->show_system_tables,
ODBC_INI);
diff --git a/src/interfaces/odbc/dlg_specific.h b/src/interfaces/odbc/dlg_specific.h
index 3c4ac4a6004..d5db0fe0f80 100644
--- a/src/interfaces/odbc/dlg_specific.h
+++ b/src/interfaces/odbc/dlg_specific.h
@@ -55,6 +55,7 @@
#define INI_FAKEOIDINDEX "FakeOidIndex"
#define INI_SHOWOIDCOLUMN "ShowOidColumn"
+#define INI_ROWVERSIONING "RowVersioning"
#define INI_SHOWSYSTEMTABLES "ShowSystemTables"
#define INI_LIE "Lie"
#define INI_EXTRASYSTABLEPREFIXES "ExtraSysTablePrefixes"
@@ -74,6 +75,7 @@
#define DEFAULT_FAKEOIDINDEX 0
#define DEFAULT_SHOWOIDCOLUMN 0
+#define DEFAULT_ROWVERSIONING 0
#define DEFAULT_SHOWSYSTEMTABLES 0 // dont show system tables
#define DEFAULT_LIE 0
diff --git a/src/interfaces/odbc/drvconn.c b/src/interfaces/odbc/drvconn.c
index 89cb23b1896..f51fd9f7a4e 100644
--- a/src/interfaces/odbc/drvconn.c
+++ b/src/interfaces/odbc/drvconn.c
@@ -47,6 +47,7 @@ RETCODE SQL_API SQLDriverConnect(
SWORD FAR *pcbConnStrOut,
UWORD fDriverCompletion)
{
+char *func = "SQLDriverConnect";
ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci;
RETCODE dialog_result;
@@ -56,8 +57,10 @@ char password_required = FALSE;
mylog("**** SQLDriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, szConnStrIn);
- if ( ! conn)
+ if ( ! conn) {
+ CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
qlog("conn=%u, SQLDriverConnect( in)='%s'\n", conn, szConnStrIn);
@@ -135,8 +138,10 @@ dialog:
// do the actual connect
retval = CC_connect(conn, password_required);
if (retval < 0) { /* need a password */
- if (fDriverCompletion == SQL_DRIVER_NOPROMPT)
+ if (fDriverCompletion == SQL_DRIVER_NOPROMPT) {
+ CC_log_error(func, "Need password but Driver_NoPrompt", conn);
return SQL_ERROR; /* need a password but not allowed to prompt so error */
+ }
else {
password_required = TRUE;
goto dialog;
@@ -144,6 +149,7 @@ dialog:
}
else if (retval == 0) {
// error msg filled in above
+ CC_log_error(func, "Error from CC_Connect", conn);
return SQL_ERROR;
}
diff --git a/src/interfaces/odbc/environ.c b/src/interfaces/odbc/environ.c
index 3ca80810be0..82f73e977f9 100644
--- a/src/interfaces/odbc/environ.c
+++ b/src/interfaces/odbc/environ.c
@@ -25,11 +25,14 @@ ConnectionClass *conns[MAX_CONNECTIONS];
RETCODE SQL_API SQLAllocEnv(HENV FAR *phenv)
{
+char *func = "SQLAllocEnv";
+
mylog("**** in SQLAllocEnv ** \n");
*phenv = (HENV) EN_Constructor();
if ( ! *phenv) {
*phenv = SQL_NULL_HENV;
+ EN_log_error(func, "Error allocating environment", NULL);
return SQL_ERROR;
}
@@ -39,6 +42,7 @@ mylog("**** in SQLAllocEnv ** \n");
RETCODE SQL_API SQLFreeEnv(HENV henv)
{
+char *func = "SQLFreeEnv";
EnvironmentClass *env = (EnvironmentClass *) henv;
mylog("**** in SQLFreeEnv: env = %u ** \n", env);
@@ -49,6 +53,7 @@ mylog("**** in SQLFreeEnv: env = %u ** \n", env);
}
mylog(" error\n");
+ EN_log_error(func, "Error freeing environment", env);
return SQL_ERROR;
}
@@ -73,9 +78,6 @@ int status;
// CC: return an error of a hstmt
StatementClass *stmt = (StatementClass *) hstmt;
- if (NULL == stmt)
- return SQL_INVALID_HANDLE;
-
if (SC_get_error(stmt, &status, &msg)) {
mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg);
if (NULL == msg) {
@@ -424,3 +426,13 @@ int i;
return FALSE;
}
+
+void
+EN_log_error(char *func, char *desc, EnvironmentClass *self)
+{
+ if (self) {
+ qlog("ENVIRON ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg);
+ }
+ else
+ qlog("INVALID ENVIRON HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
+}
diff --git a/src/interfaces/odbc/environ.h b/src/interfaces/odbc/environ.h
index aa941cf0c22..33cf5e433a0 100644
--- a/src/interfaces/odbc/environ.h
+++ b/src/interfaces/odbc/environ.h
@@ -29,5 +29,6 @@ char EN_Destructor(EnvironmentClass *self);
char EN_get_error(EnvironmentClass *self, int *number, char **message);
char EN_add_connection(EnvironmentClass *self, ConnectionClass *conn);
char EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn);
+void EN_log_error(char *func, char *desc, EnvironmentClass *self);
#endif
diff --git a/src/interfaces/odbc/execute.c b/src/interfaces/odbc/execute.c
index 960f16ca914..f15b149d473 100644
--- a/src/interfaces/odbc/execute.c
+++ b/src/interfaces/odbc/execute.c
@@ -32,10 +32,13 @@ RETCODE SQL_API SQLPrepare(HSTMT hstmt,
UCHAR FAR *szSqlStr,
SDWORD cbSqlStr)
{
+char *func = "SQLPrepare";
StatementClass *self = (StatementClass *) hstmt;
- if ( ! self)
+ if ( ! self) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
/* According to the ODBC specs it is valid to call SQLPrepare mulitple times.
In that case, the bound SQL statement is replaced by the new one
@@ -66,12 +69,14 @@ StatementClass *self = (StatementClass *) hstmt;
self->errornumber = STMT_SEQUENCE_ERROR;
self->errormsg = "SQLPrepare(): The handle does not point to a statement that is ready to be executed";
+ SC_log_error(func, "", self);
return SQL_ERROR;
default:
self->errornumber = STMT_INTERNAL_ERROR;
self->errormsg = "An Internal Error has occured -- Unknown statement status.";
+ SC_log_error(func, "", self);
return SQL_ERROR;
}
@@ -82,6 +87,7 @@ StatementClass *self = (StatementClass *) hstmt;
if ( ! self->statement) {
self->errornumber = STMT_NO_MEMORY_ERROR;
self->errormsg = "No memory available to store statement";
+ SC_log_error(func, "", self);
return SQL_ERROR;
}
@@ -92,6 +98,7 @@ StatementClass *self = (StatementClass *) hstmt;
if ( CC_is_readonly(self->hdbc) && STMT_UPDATE(self)) {
self->errornumber = STMT_EXEC_ERROR;
self->errormsg = "Connection is readonly, only select statements are allowed.";
+ SC_log_error(func, "", self);
return SQL_ERROR;
}
@@ -110,9 +117,12 @@ RETCODE SQL_API SQLExecDirect(
SDWORD cbSqlStr)
{
StatementClass *stmt = (StatementClass *) hstmt;
+char *func = "SQLExecDirect";
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
if (stmt->statement)
free(stmt->statement);
@@ -123,6 +133,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
if ( ! stmt->statement) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "No memory available to store statement";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -135,6 +146,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
if ( CC_is_readonly(stmt->hdbc) && STMT_UPDATE(stmt)) {
stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Connection is readonly, only select statements are allowed.";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -147,13 +159,16 @@ StatementClass *stmt = (StatementClass *) hstmt;
RETCODE SQL_API SQLExecute(
HSTMT hstmt)
{
+char *func="SQLExecute";
StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
int i, retval;
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
/* If the statement is premature, it means we already executed
it from an SQLPrepare/SQLDescribeCol type of scenario. So
@@ -161,7 +176,12 @@ int i, retval;
*/
if ( stmt->prepare && stmt->status == STMT_PREMATURE) {
stmt->status = STMT_FINISHED;
- return stmt->errormsg == NULL ? SQL_SUCCESS : SQL_ERROR;
+ if (stmt->errormsg == NULL)
+ return SQL_SUCCESS;
+ else {
+ SC_log_error(func, "", stmt);
+ return SQL_ERROR;
+ }
}
SC_clear_error(stmt);
@@ -170,12 +190,14 @@ int i, retval;
if (conn->status == CONN_EXECUTING) {
stmt->errormsg = "Connection is already in use.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
if ( ! stmt->statement) {
stmt->errornumber = STMT_NO_STMTSTRING;
stmt->errormsg = "This handle does not have a SQL statement stored in it";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -193,6 +215,7 @@ int i, retval;
stmt->errornumber = STMT_STATUS_ERROR;
stmt->errormsg = "The handle does not point to a statement that is ready to be executed";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -240,6 +263,7 @@ RETCODE SQL_API SQLTransact(
HDBC hdbc,
UWORD fType)
{
+char *func = "SQLTransact";
extern ConnectionClass *conns[];
ConnectionClass *conn;
QResultClass *res;
@@ -248,8 +272,10 @@ int lf;
mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv);
- if (hdbc == SQL_NULL_HDBC && henv == SQL_NULL_HENV)
+ if (hdbc == SQL_NULL_HDBC && henv == SQL_NULL_HENV) {
+ CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
/* If hdbc is null and henv is valid,
it means transact all connections on that henv.
@@ -277,6 +303,7 @@ mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv);
} else {
conn->errornumber = CONN_INVALID_ARGUMENT_NO;
conn->errormsg ="SQLTransact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter";
+ CC_log_error(func, "", conn);
return SQL_ERROR;
}
@@ -288,15 +315,19 @@ mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv);
res = CC_send_query(conn, stmt_string, NULL, NULL);
CC_set_no_trans(conn);
- if ( ! res)
+ if ( ! res) {
// error msg will be in the connection
+ CC_log_error(func, "", conn);
return SQL_ERROR;
+ }
ok = QR_command_successful(res);
QR_Destructor(res);
- if (!ok)
+ if (!ok) {
+ CC_log_error(func, "", conn);
return SQL_ERROR;
+ }
}
return SQL_SUCCESS;
}
@@ -307,11 +338,14 @@ mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv);
RETCODE SQL_API SQLCancel(
HSTMT hstmt) // Statement to cancel.
{
+char *func="SQLCancel";
StatementClass *stmt = (StatementClass *) hstmt;
// Check if this can handle canceling in the middle of a SQLPutData?
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
// Not in the middle of SQLParamData/SQLPutData so cancel like a close.
if (stmt->data_at_exec < 0)
@@ -354,11 +388,14 @@ RETCODE SQL_API SQLParamData(
HSTMT hstmt,
PTR FAR *prgbValue)
{
+char *func = "SQLParamData";
StatementClass *stmt = (StatementClass *) hstmt;
int i, retval;
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
mylog("SQLParamData, enter: data_at_exec=%d, params_alloc=%d\n",
stmt->data_at_exec, stmt->parameters_allocated);
@@ -366,12 +403,14 @@ int i, retval;
if (stmt->data_at_exec < 0) {
stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "No execution-time parameters for this statement";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
if (stmt->data_at_exec > stmt->parameters_allocated) {
stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "Too many execution-time parameters were present";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -422,19 +461,23 @@ RETCODE SQL_API SQLPutData(
PTR rgbValue,
SDWORD cbValue)
{
+char *func = "SQLPutData";
StatementClass *stmt = (StatementClass *) hstmt;
int old_pos, retval;
ParameterInfoClass *current_param;
char *buffer;
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
if (stmt->current_exec_param < 0) {
stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "Previous call was not SQLPutData or SQLParamData";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -450,6 +493,7 @@ char *buffer;
if ( ! current_param->EXEC_used) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (1)";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -467,6 +511,7 @@ char *buffer;
if (current_param->lobj_oid == 0) {
stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Couldnt create large object.";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -479,6 +524,7 @@ char *buffer;
if ( stmt->lobj_fd < 0) {
stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Couldnt open large object for writing.";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -493,6 +539,7 @@ char *buffer;
if ( ! current_param->EXEC_buffer) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (2)";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
}
@@ -501,6 +548,7 @@ char *buffer;
if ( ! current_param->EXEC_buffer) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (2)";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
memcpy(current_param->EXEC_buffer, rgbValue, cbValue);
@@ -530,6 +578,7 @@ char *buffer;
if ( ! buffer) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (3)";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
strcat(buffer, rgbValue);
@@ -555,6 +604,7 @@ char *buffer;
if ( ! buffer) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (3)";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -565,8 +615,10 @@ char *buffer;
current_param->EXEC_buffer = buffer;
}
- else
+ else {
+ SC_log_error(func, "bad cbValue", stmt);
return SQL_ERROR;
+ }
}
}
diff --git a/src/interfaces/odbc/info.c b/src/interfaces/odbc/info.c
index f80f0976059..a4ce1d89c38 100644
--- a/src/interfaces/odbc/info.c
+++ b/src/interfaces/odbc/info.c
@@ -45,24 +45,19 @@ RETCODE SQL_API SQLGetInfo(
SWORD cbInfoValueMax,
SWORD FAR *pcbInfoValue)
{
+char *func = "SQLGetInfo";
ConnectionClass *conn = (ConnectionClass *) hdbc;
char *p;
- if ( ! conn)
- return SQL_INVALID_HANDLE;
-
- /* CC: Some sanity checks */
- if ((NULL == (char *)rgbInfoValue) ||
- (cbInfoValueMax == 0))
-
- /* removed: */
- /* || (NULL == pcbInfoValue) */
-
- /* pcbInfoValue is ignored for non-character output. */
- /* some programs (at least Microsoft Query) seem to just send a NULL, */
- /* so let them get away with it... */
+ if ( ! conn) {
+ CC_log_error(func, "", NULL);
+ return SQL_INVALID_HANDLE;
+ }
+ if (NULL == (char *)rgbInfoValue) {
+ CC_log_error(func, "Bad rgbInfoValue", conn);
return SQL_INVALID_HANDLE;
+ }
switch (fInfoType) {
@@ -70,13 +65,13 @@ char *p;
// can the user call all functions returned by SQLProcedures?
// I assume access permissions could prevent this in some cases(?)
// anyway, SQLProcedures doesn't exist yet.
- *pcbInfoValue = 1;
+ if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break;
case SQL_ACCESSIBLE_TABLES: /* ODBC 1.0 */
// is the user guaranteed "SELECT" on every table?
- *pcbInfoValue = 1;
+ if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break;
@@ -108,7 +103,7 @@ char *p;
case SQL_COLUMN_ALIAS: /* ODBC 2.0 */
// do we support column aliases? guess not.
- *pcbInfoValue = 1;
+ if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break;
@@ -294,6 +289,7 @@ char *p;
// do this later
conn->errormsg = "SQL_KEYWORDS parameter to SQLGetInfo not implemented.";
conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
+ CC_log_error(func, "", conn);
return SQL_ERROR;
break;
@@ -398,7 +394,7 @@ char *p;
case SQL_MAX_ROW_SIZE_INCLUDES_LONG: /* ODBC 2.0 */
// does the preceding value include LONGVARCHAR and LONGVARBINARY
// fields? Well, it does include longvarchar, but not longvarbinary.
- *pcbInfoValue = 1;
+ if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
break;
@@ -715,6 +711,7 @@ char *p;
/* unrecognized key */
conn->errormsg = "Unrecognized key passed to SQLGetInfo.";
conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
+ CC_log_error(func, "", conn);
return SQL_ERROR;
}
@@ -728,6 +725,7 @@ RETCODE SQL_API SQLGetTypeInfo(
HSTMT hstmt,
SWORD fSqlType)
{
+char *func = "SQLGetTypeInfo";
StatementClass *stmt = (StatementClass *) hstmt;
TupleNode *row;
int i;
@@ -736,12 +734,14 @@ Int4 type;
mylog("**** in SQLGetTypeInfo: fSqlType = %d\n", fSqlType);
if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
stmt->manual_result = TRUE;
stmt->result = QR_Constructor();
if( ! stmt->result) {
+ SC_log_error(func, "Error creating result.", stmt);
return SQL_ERROR;
}
@@ -976,6 +976,7 @@ RETCODE SQL_API SQLTables(
UCHAR FAR * szTableType,
SWORD cbTableType)
{
+char *func = "SQLTables";
StatementClass *stmt = (StatementClass *) hstmt;
StatementClass *tbl_stmt;
TupleNode *row;
@@ -993,8 +994,10 @@ int i;
mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
- if( ! stmt)
+ if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
stmt->manual_result = TRUE;
stmt->errormsg_created = TRUE;
@@ -1005,6 +1008,7 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Couldn't allocate statement for SQLTables result.";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
tbl_stmt = (StatementClass *) htbl_stmt;
@@ -1086,6 +1090,7 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = SC_create_errormsg(htbl_stmt);
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1095,6 +1100,7 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = tbl_stmt->errormsg;
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1104,6 +1110,7 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = tbl_stmt->errormsg;
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1112,6 +1119,7 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = tbl_stmt->errormsg;
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1120,6 +1128,7 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
if(!stmt->result) {
stmt->errormsg = "Couldn't allocate memory for SQLTables result.";
stmt->errornumber = STMT_NO_MEMORY_ERROR;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1201,6 +1210,7 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
if(result != SQL_NO_DATA_FOUND) {
stmt->errormsg = SC_create_errormsg(htbl_stmt);
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1229,6 +1239,7 @@ RETCODE SQL_API SQLColumns(
UCHAR FAR * szColumnName,
SWORD cbColumnName)
{
+char *func = "SQLColumns";
StatementClass *stmt = (StatementClass *) hstmt;
TupleNode *row;
HSTMT hcol_stmt;
@@ -1238,6 +1249,7 @@ RETCODE result;
char table_owner[MAX_INFO_STRING], table_name[MAX_INFO_STRING], field_name[MAX_INFO_STRING], field_type_name[MAX_INFO_STRING];
Int2 field_number, field_length, mod_length;
Int4 field_type;
+Int2 the_type;
char not_null[MAX_INFO_STRING];
ConnInfo *ci;
@@ -1245,8 +1257,10 @@ ConnInfo *ci;
mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
- if( ! stmt)
+ if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
stmt->manual_result = TRUE;
stmt->errormsg_created = TRUE;
@@ -1273,6 +1287,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Couldn't allocate statement for SQLColumns result.";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
col_stmt = (StatementClass *) hcol_stmt;
@@ -1282,6 +1297,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = SC_create_errormsg(hcol_stmt);
stmt->errornumber = col_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1291,6 +1307,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = col_stmt->errormsg;
stmt->errornumber = col_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1300,6 +1317,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = col_stmt->errormsg;
stmt->errornumber = col_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1309,6 +1327,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = col_stmt->errormsg;
stmt->errornumber = col_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1318,6 +1337,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = col_stmt->errormsg;
stmt->errornumber = col_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1327,6 +1347,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = col_stmt->errormsg;
stmt->errornumber = col_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1336,6 +1357,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = col_stmt->errormsg;
stmt->errornumber = col_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1345,6 +1367,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = col_stmt->errormsg;
stmt->errornumber = col_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1354,6 +1377,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = col_stmt->errormsg;
stmt->errornumber = col_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1363,6 +1387,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = col_stmt->errormsg;
stmt->errornumber = col_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1371,6 +1396,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if(!stmt->result) {
stmt->errormsg = "Couldn't allocate memory for SQLColumns result.";
stmt->errornumber = STMT_NO_MEMORY_ERROR;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1402,33 +1428,37 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
Always show OID if its a system table
*/
- if (result != SQL_ERROR && ! stmt->internal &&
- (atoi(ci->show_oid_column) || strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)) {
+ if (result != SQL_ERROR && ! stmt->internal) {
- /* For OID fields */
- row = (TupleNode *)malloc(sizeof(TupleNode) +
- (12 - 1) * sizeof(TupleField));
+ if (atoi(ci->show_oid_column) || strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0) {
- set_tuplefield_string(&row->tuple[0], "");
- // see note in SQLTables()
- // set_tuplefield_string(&row->tuple[1], table_owner);
- set_tuplefield_string(&row->tuple[1], "");
- set_tuplefield_string(&row->tuple[2], table_name);
- set_tuplefield_string(&row->tuple[3], "oid");
- set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, PG_TYPE_OID));
- set_tuplefield_string(&row->tuple[5], "OID");
+ /* For OID fields */
+ the_type = PG_TYPE_OID;
+ row = (TupleNode *)malloc(sizeof(TupleNode) +
+ (12 - 1) * sizeof(TupleField));
- set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, PG_TYPE_OID, PG_STATIC,
- PG_STATIC));
- set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, PG_TYPE_OID, PG_STATIC,
- PG_STATIC));
+ set_tuplefield_string(&row->tuple[0], "");
+ // see note in SQLTables()
+ // set_tuplefield_string(&row->tuple[1], table_owner);
+ set_tuplefield_string(&row->tuple[1], "");
+ set_tuplefield_string(&row->tuple[2], table_name);
+ set_tuplefield_string(&row->tuple[3], "oid");
+ set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, the_type));
+ set_tuplefield_string(&row->tuple[5], "OID");
- set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, PG_TYPE_OID));
- set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, PG_TYPE_OID));
- set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
- set_tuplefield_string(&row->tuple[11], "");
+ 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));
+ 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], "");
+
+ QR_add_tuple(stmt->result, row);
+ }
- QR_add_tuple(stmt->result, row);
}
while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
@@ -1484,10 +1514,36 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
if(result != SQL_NO_DATA_FOUND) {
stmt->errormsg = SC_create_errormsg(hcol_stmt);
stmt->errornumber = col_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(hcol_stmt, SQL_DROP);
return SQL_ERROR;
}
+ // Put the row version column at the end so it might not be
+ // mistaken for a key field.
+ if ( ! stmt->internal && atoi(ci->row_versioning)) {
+ /* For Row Versioning fields */
+ the_type = PG_TYPE_INT4;
+
+ row = (TupleNode *)malloc(sizeof(TupleNode) +
+ (12 - 1) * sizeof(TupleField));
+
+ set_tuplefield_string(&row->tuple[0], "");
+ set_tuplefield_string(&row->tuple[1], "");
+ set_tuplefield_string(&row->tuple[2], table_name);
+ set_tuplefield_string(&row->tuple[3], "xmin");
+ set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, the_type));
+ 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));
+ 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], "");
+
+ QR_add_tuple(stmt->result, row);
+ }
+
// also, things need to think that this statement is finished so
// the results can be retrieved.
stmt->status = STMT_FINISHED;
@@ -1513,14 +1569,20 @@ RETCODE SQL_API SQLSpecialColumns(
UWORD fScope,
UWORD fNullable)
{
+char *func = "SQLSpecialColumns";
TupleNode *row;
StatementClass *stmt = (StatementClass *) hstmt;
+ConnInfo *ci;
+
mylog("**** SQLSpecialColumns(): ENTER, stmt=%u\n", stmt);
if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
+ ci = &stmt->hdbc->connInfo;
+
stmt->manual_result = TRUE;
stmt->result = QR_Constructor();
extend_bindings(stmt, 8);
@@ -1551,11 +1613,24 @@ mylog("**** SQLSpecialColumns(): ENTER, stmt=%u\n", stmt);
QR_add_tuple(stmt->result, row);
} else if(fColType == SQL_ROWVER) {
- /* can columns automatically update? */
- /* for now assume no. */
- /* return an empty result. */
- }
+ Int2 the_type = PG_TYPE_INT4;
+
+ if (atoi(ci->row_versioning)) {
+ row = (TupleNode *)malloc(sizeof(TupleNode) + (8 - 1) * sizeof(TupleField));
+
+ 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_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));
+ set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
+
+ QR_add_tuple(stmt->result, row);
+ }
+ }
stmt->status = STMT_FINISHED;
stmt->currTuple = -1;
stmt->current_col = -1;
@@ -1575,6 +1650,7 @@ RETCODE SQL_API SQLStatistics(
UWORD fUnique,
UWORD fAccuracy)
{
+char *func="SQLStatistics";
StatementClass *stmt = (StatementClass *) hstmt;
char index_query[MAX_STATEMENT_LEN];
HSTMT hindx_stmt;
@@ -1599,6 +1675,7 @@ char buf[256];
mylog("**** SQLStatistics(): ENTER, stmt=%u\n", stmt);
if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
@@ -1611,6 +1688,7 @@ mylog("**** SQLStatistics(): ENTER, stmt=%u\n", stmt);
if(!stmt->result) {
stmt->errormsg = "Couldn't allocate memory for SQLStatistics result.";
stmt->errornumber = STMT_NO_MEMORY_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -1641,6 +1719,7 @@ mylog("**** SQLStatistics(): ENTER, stmt=%u\n", stmt);
if ( ! table_name) {
stmt->errormsg = "No table name passed to SQLStatistics.";
stmt->errornumber = STMT_INTERNAL_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -1887,8 +1966,10 @@ SEEYA:
mylog("SQLStatistics(): EXIT, %s, stmt=%u\n", error ? "error" : "success", stmt);
- if (error)
+ if (error) {
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
+ }
else
return SQL_SUCCESS;
}
@@ -1904,13 +1985,17 @@ RETCODE SQL_API SQLColumnPrivileges(
UCHAR FAR * szColumnName,
SWORD cbColumnName)
{
+char *func="SQLColumnPrivileges";
/* Neither Access or Borland care about this. */
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
return SQL_ERROR;
}
RETCODE
getPrimaryKeyString(StatementClass *stmt, char *szTableName, SWORD cbTableName, char *svKey, int *nKey)
{
+char *func = "getPrimaryKeyString";
HSTMT htbl_stmt;
StatementClass *tbl_stmt;
RETCODE result;
@@ -1930,6 +2015,7 @@ int nk = 0;
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Couldn't allocate statement for Primary Key result.";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
tbl_stmt = (StatementClass *) htbl_stmt;
@@ -1940,6 +2026,7 @@ int nk = 0;
stmt->errormsg = "No Table specified to getPrimaryKeyString.";
stmt->errornumber = STMT_INTERNAL_ERROR;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1950,6 +2037,7 @@ int nk = 0;
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = SC_create_errormsg(htbl_stmt);
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1959,6 +2047,7 @@ int nk = 0;
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = tbl_stmt->errormsg;
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -1977,6 +2066,7 @@ int nk = 0;
if(result != SQL_NO_DATA_FOUND) {
stmt->errormsg = SC_create_errormsg(htbl_stmt);
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -2034,6 +2124,7 @@ RETCODE SQL_API SQLPrimaryKeys(
UCHAR FAR * szTableName,
SWORD cbTableName)
{
+char *func = "SQLPrimaryKeys";
StatementClass *stmt = (StatementClass *) hstmt;
TupleNode *row;
RETCODE result;
@@ -2043,6 +2134,7 @@ int seq = 1, nkeys = 0;
mylog("**** SQLPrimaryKeys(): ENTER, stmt=%u\n", stmt);
if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
stmt->manual_result = TRUE;
@@ -2068,6 +2160,7 @@ mylog("**** SQLPrimaryKeys(): ENTER, stmt=%u\n", stmt);
if(!stmt->result) {
stmt->errormsg = "Couldn't allocate memory for SQLPrimaryKeys result.";
stmt->errornumber = STMT_NO_MEMORY_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -2137,6 +2230,7 @@ RETCODE SQL_API SQLForeignKeys(
UCHAR FAR * szFkTableName,
SWORD cbFkTableName)
{
+char *func = "SQLForeignKeys";
StatementClass *stmt = (StatementClass *) hstmt;
TupleNode *row;
HSTMT htbl_stmt;
@@ -2156,6 +2250,7 @@ mylog("**** SQLForeignKeys(): ENTER, stmt=%u\n", stmt);
memset(primaryKey, 0, sizeof(primaryKey));
if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
stmt->manual_result = TRUE;
@@ -2165,6 +2260,7 @@ mylog("**** SQLForeignKeys(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Couldn't allocate statement for SQLForeignKeys result.";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -2224,6 +2320,7 @@ mylog("**** SQLForeignKeys(): ENTER, stmt=%u\n", stmt);
else {
stmt->errormsg = "No tables specified to SQLForeignKeys.";
stmt->errornumber = STMT_INTERNAL_ERROR;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -2232,6 +2329,7 @@ mylog("**** SQLForeignKeys(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = SC_create_errormsg(htbl_stmt);
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -2241,6 +2339,7 @@ mylog("**** SQLForeignKeys(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = tbl_stmt->errormsg;
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -2249,6 +2348,7 @@ mylog("**** SQLForeignKeys(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = tbl_stmt->errormsg;
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -2258,6 +2358,7 @@ mylog("**** SQLForeignKeys(): ENTER, stmt=%u\n", stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errormsg = tbl_stmt->errormsg;
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -2266,6 +2367,7 @@ mylog("**** SQLForeignKeys(): ENTER, stmt=%u\n", stmt);
if(!stmt->result) {
stmt->errormsg = "Couldn't allocate memory for SQLForeignKeys result.";
stmt->errornumber = STMT_NO_MEMORY_ERROR;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -2356,6 +2458,7 @@ mylog("**** SQLForeignKeys(): ENTER, stmt=%u\n", stmt);
if(result != SQL_NO_DATA_FOUND) {
stmt->errormsg = SC_create_errormsg(htbl_stmt);
stmt->errornumber = tbl_stmt->errornumber;
+ SC_log_error(func, "", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
@@ -2387,6 +2490,9 @@ RETCODE SQL_API SQLProcedureColumns(
UCHAR FAR * szColumnName,
SWORD cbColumnName)
{
+char *func="SQLProcedureColumns";
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
return SQL_ERROR;
}
@@ -2399,6 +2505,9 @@ RETCODE SQL_API SQLProcedures(
UCHAR FAR * szProcName,
SWORD cbProcName)
{
+char *func="SQLProcedures";
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
return SQL_ERROR;
}
@@ -2411,5 +2520,8 @@ RETCODE SQL_API SQLTablePrivileges(
UCHAR FAR * szTableName,
SWORD cbTableName)
{
+char *func="SQLTablePrivileges";
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
return SQL_ERROR;
}
diff --git a/src/interfaces/odbc/options.c b/src/interfaces/odbc/options.c
index ff9c53200c0..810ac849540 100644
--- a/src/interfaces/odbc/options.c
+++ b/src/interfaces/odbc/options.c
@@ -31,10 +31,14 @@ RETCODE SQL_API SQLSetConnectOption(
UWORD fOption,
UDWORD vParam)
{
+char *func="SQLSetConnectOption";
ConnectionClass *conn = (ConnectionClass *) hdbc;
- if ( ! conn)
+ if ( ! conn) {
+ CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
+
switch (fOption) {
case SQL_AUTOCOMMIT:
@@ -46,6 +50,7 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
if (CC_is_in_trans(conn)) {
conn->errormsg = "Cannot switch commit mode while a transaction is in progres";
conn->errornumber = CONN_TRANSACT_IN_PROGRES;
+ CC_log_error(func, "", conn);
return SQL_ERROR;
}
*/
@@ -64,6 +69,7 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
default:
conn->errormsg = "Illegal parameter value for SQL_AUTOCOMMIT";
conn->errornumber = CONN_INVALID_ARGUMENT_NO;
+ CC_log_error(func, "", conn);
return SQL_ERROR;
}
@@ -76,9 +82,14 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
break;
default:
+ {
+ char option[32];
conn->errormsg = "This option is currently unsupported by the driver";
conn->errornumber = CONN_UNSUPPORTED_OPTION;
+ sprintf(option, "fOption=%d", fOption);
+ CC_log_error(func, option, conn);
return SQL_ERROR;
+ }
}
return SQL_SUCCESS;
@@ -92,10 +103,13 @@ RETCODE SQL_API SQLGetConnectOption(
UWORD fOption,
PTR pvParam)
{
+char *func="SQLGetConnectOption";
ConnectionClass *conn = (ConnectionClass *) hdbc;
- if (! conn)
+ if (! conn) {
+ CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
switch (fOption) {
case SQL_AUTOCOMMIT:
@@ -111,10 +125,15 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
break;
default:
+ {
+ char option[32];
conn->errormsg = "This option is currently unsupported by the driver";
conn->errornumber = CONN_UNSUPPORTED_OPTION;
+ sprintf(option, "fOption=%d", fOption);
+ CC_log_error(func, option, conn);
return SQL_ERROR;
break;
+ }
}
@@ -128,6 +147,7 @@ RETCODE SQL_API SQLSetStmtOption(
UWORD fOption,
UDWORD vParam)
{
+char *func="SQLSetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt;
char changed = FALSE;
@@ -135,8 +155,10 @@ char changed = FALSE;
// all the time, but it tries to set a huge value for SQL_MAX_LENGTH
// and expects the driver to reduce it to the real value
- if( ! stmt)
+ if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
switch(fOption) {
case SQL_QUERY_TIMEOUT:
@@ -170,6 +192,7 @@ char changed = FALSE;
else {
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Driver does not support keyset size option";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
break;
@@ -214,12 +237,18 @@ char changed = FALSE;
case SQL_SIMULATE_CURSOR:
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Simulated positioned update/delete not supported. Use the cursor library.";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
default:
+ {
+ char option[32];
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Driver does not support this statement option";
+ sprintf(option, "fOption=%d", fOption);
+ SC_log_error(func, option, stmt);
return SQL_ERROR;
+ }
}
if (changed) {
@@ -239,14 +268,17 @@ RETCODE SQL_API SQLGetStmtOption(
UWORD fOption,
PTR pvParam)
{
+char *func="SQLGetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt;
// thought we could fake Access out by just returning SQL_SUCCESS
// all the time, but it tries to set a huge value for SQL_MAX_LENGTH
// and expects the driver to reduce it to the real value
- if( ! stmt)
+ if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
switch(fOption) {
case SQL_QUERY_TIMEOUT:
@@ -289,12 +321,18 @@ StatementClass *stmt = (StatementClass *) hstmt;
case SQL_SIMULATE_CURSOR:
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Simulated positioned update/delete not supported. Use the cursor library.";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
default:
+ {
+ char option[32];
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Driver does not support this statement option";
+ sprintf(option, "fOption=%d", fOption);
+ SC_log_error(func, option, stmt);
return SQL_ERROR;
+ }
}
return SQL_SUCCESS;
diff --git a/src/interfaces/odbc/pgtypes.c b/src/interfaces/odbc/pgtypes.c
index 20d9b42adc2..b52ef601e9b 100644
--- a/src/interfaces/odbc/pgtypes.c
+++ b/src/interfaces/odbc/pgtypes.c
@@ -46,7 +46,9 @@ Int4 pgtypes_defined[] = {
PG_TYPE_BPCHAR,
PG_TYPE_DATE,
PG_TYPE_TIME,
+ PG_TYPE_DATETIME,
PG_TYPE_ABSTIME, /* a timestamp, sort of */
+ PG_TYPE_TIMESTAMP,
PG_TYPE_TEXT,
PG_TYPE_INT2,
PG_TYPE_INT4,
@@ -55,7 +57,6 @@ Int4 pgtypes_defined[] = {
PG_TYPE_OID,
PG_TYPE_MONEY,
PG_TYPE_BOOL,
- PG_TYPE_DATETIME,
PG_TYPE_BYTEA,
PG_TYPE_LO,
0 };
@@ -97,7 +98,8 @@ Int2 pgtype_to_sqltype(StatementClass *stmt, Int4 type)
case PG_TYPE_DATE: return SQL_DATE;
case PG_TYPE_TIME: return SQL_TIME;
case PG_TYPE_ABSTIME:
- case PG_TYPE_DATETIME: return SQL_TIMESTAMP;
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP: return SQL_TIMESTAMP;
case PG_TYPE_MONEY: return SQL_FLOAT;
case PG_TYPE_BOOL: return globals.bools_as_char ? SQL_CHAR : SQL_BIT;
@@ -124,7 +126,8 @@ Int2 pgtype_to_ctype(StatementClass *stmt, Int4 type)
case PG_TYPE_DATE: return SQL_C_DATE;
case PG_TYPE_TIME: return SQL_C_TIME;
case PG_TYPE_ABSTIME:
- case PG_TYPE_DATETIME: return SQL_C_TIMESTAMP;
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP: return SQL_C_TIMESTAMP;
case PG_TYPE_MONEY: return SQL_C_FLOAT;
case PG_TYPE_BOOL: return globals.bools_as_char ? SQL_C_CHAR : SQL_C_BIT;
@@ -161,6 +164,7 @@ char *pgtype_to_name(StatementClass *stmt, Int4 type)
case PG_TYPE_TIME: return "time";
case PG_TYPE_ABSTIME: return "abstime";
case PG_TYPE_DATETIME: return "datetime";
+ case PG_TYPE_TIMESTAMP: return "timestamp";
case PG_TYPE_MONEY: return "money";
case PG_TYPE_BOOL: return "bool";
case PG_TYPE_BYTEA: return "bytea";
@@ -269,7 +273,8 @@ Int4 pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unkno
case PG_TYPE_TIME: return 8;
case PG_TYPE_ABSTIME:
- case PG_TYPE_DATETIME: return 19;
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP: return 19;
case PG_TYPE_BOOL: return 1;
@@ -327,7 +332,8 @@ Int4 pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_
case PG_TYPE_TIME: return 6;
case PG_TYPE_ABSTIME:
- case PG_TYPE_DATETIME: return 16;
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP: return 16;
/* Character types use the default precision */
@@ -350,7 +356,8 @@ Int2 pgtype_scale(StatementClass *stmt, Int4 type)
/* Number of digits to the right of the decimal point in "yyyy-mm=dd hh:mm:ss[.f...]" */
case PG_TYPE_ABSTIME:
- case PG_TYPE_DATETIME: return 0;
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP: return 0;
default: return -1;
}
@@ -391,7 +398,8 @@ Int2 pgtype_auto_increment(StatementClass *stmt, Int4 type)
case PG_TYPE_DATE:
case PG_TYPE_TIME:
case PG_TYPE_ABSTIME:
- case PG_TYPE_DATETIME: return FALSE;
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP: return FALSE;
default: return -1;
}
diff --git a/src/interfaces/odbc/pgtypes.h b/src/interfaces/odbc/pgtypes.h
index dd7d94370a3..e83ec040abd 100644
--- a/src/interfaces/odbc/pgtypes.h
+++ b/src/interfaces/odbc/pgtypes.h
@@ -58,6 +58,7 @@
#define PG_TYPE_DATE 1082
#define PG_TYPE_TIME 1083
#define PG_TYPE_DATETIME 1184
+#define PG_TYPE_TIMESTAMP 1296
extern Int4 pgtypes_defined[];
diff --git a/src/interfaces/odbc/psqlodbc.h b/src/interfaces/odbc/psqlodbc.h
index 07b7ec7b454..b11f92844a7 100644
--- a/src/interfaces/odbc/psqlodbc.h
+++ b/src/interfaces/odbc/psqlodbc.h
@@ -50,8 +50,8 @@ typedef UInt4 Oid;
/* Driver stuff */
#define DRIVERNAME "PostgreSQL ODBC"
#define DBMS_NAME "PostgreSQL"
-#define DBMS_VERSION "06.30.0244 PostgreSQL 6.3"
-#define POSTGRESDRIVERVERSION "06.30.0244"
+#define DBMS_VERSION "06.30.0246 PostgreSQL 6.3"
+#define POSTGRESDRIVERVERSION "06.30.0246"
#define DRIVER_FILE_NAME "PSQLODBC.DLL"
diff --git a/src/interfaces/odbc/psqlodbc.rc b/src/interfaces/odbc/psqlodbc.rc
index 6b251ded002..a4235e4780a 100644
--- a/src/interfaces/odbc/psqlodbc.rc
+++ b/src/interfaces/odbc/psqlodbc.rc
@@ -137,6 +137,8 @@ BEGIN
WS_TABSTOP,130,10,60,14
CONTROL "Show System &Tables",DS_SHOWSYSTEMTABLES,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,25,30,85,10
+ CONTROL "Row &Versioning",DS_ROWVERSIONING,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,130,30,85,10
GROUPBOX "OID Options",IDC_STATIC,15,50,180,25
CONTROL "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX |
WS_GROUP | WS_TABSTOP,25,60,59,10
@@ -198,8 +200,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 6,30,2,44
- PRODUCTVERSION 6,30,2,44
+ FILEVERSION 6,30,2,46
+ PRODUCTVERSION 6,30,2,46
FILEFLAGSMASK 0x3L
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -217,12 +219,12 @@ BEGIN
VALUE "Comments", "PostgreSQL ODBC driver for Windows 95\0"
VALUE "CompanyName", "Insight Distribution Systems\0"
VALUE "FileDescription", "PostgreSQL Driver\0"
- VALUE "FileVersion", " 6.30.0244\0"
+ VALUE "FileVersion", " 6.30.0246\0"
VALUE "InternalName", "psqlodbc\0"
VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft� is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
VALUE "OriginalFilename", "psqlodbc.dll\0"
VALUE "ProductName", "Microsoft Open Database Connectivity\0"
- VALUE "ProductVersion", " 6.30.0244\0"
+ VALUE "ProductVersion", " 6.30.0246\0"
END
END
BLOCK "VarFileInfo"
diff --git a/src/interfaces/odbc/resource.h b/src/interfaces/odbc/resource.h
index 51fa7078f17..5373df98dcb 100644
--- a/src/interfaces/odbc/resource.h
+++ b/src/interfaces/odbc/resource.h
@@ -45,6 +45,7 @@
#define DRV_BOOLS_CHAR 1050
#define DS_SHOWSYSTEMTABLES 1051
#define DRV_EXTRASYSTABLEPREFIXES 1051
+#define DS_ROWVERSIONING 1052
// Next default values for new objects
//
diff --git a/src/interfaces/odbc/results.c b/src/interfaces/odbc/results.c
index c06dc69170a..867d906f37f 100644
--- a/src/interfaces/odbc/results.c
+++ b/src/interfaces/odbc/results.c
@@ -36,12 +36,15 @@ RETCODE SQL_API SQLRowCount(
HSTMT hstmt,
SDWORD FAR *pcrow)
{
+char *func="SQLRowCount";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;
char *msg, *ptr;
- if ( ! stmt)
- return SQL_ERROR;
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
+ return SQL_INVALID_HANDLE;
+ }
if(stmt->statement_type == STMT_TYPE_SELECT) {
if (stmt->status == STMT_FINISHED) {
@@ -74,6 +77,7 @@ char *msg, *ptr;
}
}
+ SC_log_error(func, "Bad return value", stmt);
return SQL_ERROR;
}
@@ -86,11 +90,14 @@ RETCODE SQL_API SQLNumResultCols(
HSTMT hstmt,
SWORD FAR *pccol)
{
+char *func="SQLNumResultCols";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *result;
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
SC_clear_error(stmt);
@@ -109,6 +116,7 @@ QResultClass *result;
/* no query has been executed on this statement */
stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "No query has been executed with that handle";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -133,6 +141,7 @@ RETCODE SQL_API SQLDescribeCol(
SWORD FAR *pibScale,
SWORD FAR *pfNullable)
{
+char *func="SQLDescribeCol";
/* gets all the information about a specific column */
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *result;
@@ -141,8 +150,10 @@ Int4 fieldtype;
int p;
ConnInfo *ci;
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
ci = &(stmt->hdbc->connInfo);
@@ -162,6 +173,7 @@ ConnInfo *ci;
/* no query has been executed on this statement */
stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "No query has been assigned to this statement.";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -169,6 +181,7 @@ ConnInfo *ci;
// we do not support bookmarks
stmt->errormsg = "Bookmarks are not currently supported.";
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -255,14 +268,17 @@ RETCODE SQL_API SQLColAttributes(
SWORD FAR *pcbDesc,
SDWORD FAR *pfDesc)
{
+char *func = "SQLColAttributes";
StatementClass *stmt = (StatementClass *) hstmt;
char *value;
Int4 field_type;
ConnInfo *ci;
int unknown_sizes;
- if( ! stmt)
+ if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
ci = &(stmt->hdbc->connInfo);
@@ -277,6 +293,7 @@ int unknown_sizes;
if ( (NULL == stmt->result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)) ) {
stmt->errormsg = "Can't get column attributes: no result found.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -284,6 +301,7 @@ int unknown_sizes;
// we do not support bookmarks
stmt->errormsg = "Bookmarks are not currently supported.";
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -436,6 +454,7 @@ RETCODE SQL_API SQLGetData(
SDWORD cbValueMax,
SDWORD FAR *pcbValue)
{
+char *func="SQLGetData";
QResultClass *res;
StatementClass *stmt = (StatementClass *) hstmt;
int num_cols, num_rows;
@@ -448,6 +467,7 @@ char multiple;
mylog("SQLGetData: enter, stmt=%u\n", stmt);
if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
res = stmt->result;
@@ -455,18 +475,21 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
if (STMT_EXECUTING == stmt->status) {
stmt->errormsg = "Can't get data while statement is still executing.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
- return 0;
+ SC_log_error(func, "", stmt);
+ return SQL_ERROR;
}
if (stmt->status != STMT_FINISHED) {
stmt->errornumber = STMT_STATUS_ERROR;
stmt->errormsg = "GetData can only be called after the successful execution on a SQL statement";
- return 0;
+ SC_log_error(func, "", stmt);
+ return SQL_ERROR;
}
if (icol == 0) {
stmt->errormsg = "Bookmarks are not currently supported.";
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -478,6 +501,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
if (icol >= num_cols) {
stmt->errormsg = "Invalid column number.";
stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -488,6 +512,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
(stmt->currTuple >= num_rows)) {
stmt->errormsg = "Not positioned on a valid row for GetData.";
stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
mylog(" num_rows = %d\n", num_rows);
@@ -503,6 +528,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
if (stmt->currTuple == -1 || ! res || QR_end_tuples(res)) {
stmt->errormsg = "Not positioned on a valid row for GetData.";
stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -531,11 +557,13 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
case COPY_UNSUPPORTED_TYPE:
stmt->errormsg = "Received an unsupported type from Postgres.";
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
case COPY_UNSUPPORTED_CONVERSION:
stmt->errormsg = "Couldn't handle the necessary data type conversion.";
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
case COPY_RESULT_TRUNCATED:
@@ -544,14 +572,17 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
return SQL_SUCCESS_WITH_INFO;
case COPY_GENERAL_ERROR: /* error msg already filled in */
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
case COPY_NO_DATA_FOUND:
+ SC_log_error(func, "no data found", stmt);
return SQL_NO_DATA_FOUND;
default:
stmt->errormsg = "Unrecognized return value from copy_and_convert_field.";
stmt->errornumber = STMT_INTERNAL_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
}
@@ -562,6 +593,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
RETCODE SQL_API SQLFetch(
HSTMT hstmt)
{
+char *func = "SQLFetch";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;
int retval;
@@ -571,14 +603,17 @@ char *value;
ColumnInfoClass *ci;
// TupleField *tupleField;
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
SC_clear_error(stmt);
if ( ! (res = stmt->result)) {
stmt->errormsg = "Null statement result in SQLFetch.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -587,6 +622,7 @@ ColumnInfoClass *ci;
if (stmt->status == STMT_EXECUTING) {
stmt->errormsg = "Can't fetch while statement is still executing.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -594,6 +630,7 @@ ColumnInfoClass *ci;
if (stmt->status != STMT_FINISHED) {
stmt->errornumber = STMT_STATUS_ERROR;
stmt->errormsg = "Fetch can only be called after the successful execution on a SQL statement";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -602,6 +639,7 @@ ColumnInfoClass *ci;
// function even if SQL_ExecDirect has reported an Error
stmt->errormsg = "Bindings were not allocated properly.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -638,6 +676,7 @@ ColumnInfoClass *ci;
mylog("SQLFetch: error\n");
stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Error fetching next row";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
}
@@ -675,11 +714,13 @@ ColumnInfoClass *ci;
if(retval == COPY_UNSUPPORTED_TYPE) {
stmt->errormsg = "Received an unsupported type from Postgres.";
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
} else if(retval == COPY_UNSUPPORTED_CONVERSION) {
stmt->errormsg = "Couldn't handle the necessary data type conversion.";
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
} else if(retval == COPY_RESULT_TRUNCATED) {
@@ -692,6 +733,7 @@ ColumnInfoClass *ci;
} else if(retval != COPY_OK) {
stmt->errormsg = "Unrecognized return value from copy_and_convert_field.";
stmt->errornumber = STMT_INTERNAL_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -710,6 +752,7 @@ RETCODE SQL_API SQLExtendedFetch(
UDWORD FAR *pcrow,
UWORD FAR *rgfRowStatus)
{
+char *func = "SQLExtendedFetch";
StatementClass *stmt = (StatementClass *) hstmt;
int num_tuples;
RETCODE result;
@@ -717,11 +760,15 @@ RETCODE result;
mylog("SQLExtendedFetch: stmt=%u\n", stmt);
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
- if ( globals.use_declarefetch)
+ if ( globals.use_declarefetch) {
+ SC_log_error(func, "SQLExtendedFetch with UseDeclareFetch not yet supported", stmt);
return SQL_ERROR;
+ }
/* Initialize to no rows fetched */
if (rgfRowStatus)
@@ -776,6 +823,7 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
break;
default:
+ SC_log_error(func, "Unsupported SQLExtendedFetch Direction", stmt);
return SQL_ERROR;
}
@@ -803,7 +851,7 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
RETCODE SQL_API SQLMoreResults(
HSTMT hstmt)
{
- return SQL_NO_DATA_FOUND;
+ return SQL_NO_DATA_FOUND;
}
// This positions the cursor within a block of data.
@@ -814,7 +862,10 @@ RETCODE SQL_API SQLSetPos(
UWORD fOption,
UWORD fLock)
{
- return SQL_ERROR;
+char *func = "SQLSetPos";
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
+ return SQL_ERROR;
}
// Sets options that control the behavior of cursors.
@@ -825,7 +876,10 @@ RETCODE SQL_API SQLSetScrollOptions(
SDWORD crowKeyset,
UWORD crowRowset)
{
- return SQL_ERROR;
+char *func = "SQLSetScrollOptions";
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
+ return SQL_ERROR;
}
@@ -836,20 +890,24 @@ RETCODE SQL_API SQLSetCursorName(
UCHAR FAR *szCursor,
SWORD cbCursor)
{
+char *func="SQLSetCursorName";
StatementClass *stmt = (StatementClass *) hstmt;
int len;
mylog("SQLSetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d\n",
hstmt, szCursor, cbCursor);
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
len = (cbCursor == SQL_NTS) ? strlen(szCursor) : cbCursor;
mylog("cursor len = %d\n", len);
if (len <= 0 || len > sizeof(stmt->cursor_name) - 1) {
stmt->errornumber = STMT_INVALID_CURSOR_NAME;
stmt->errormsg = "Invalid Cursor Name";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
strncpy_null(stmt->cursor_name, szCursor, cbCursor);
@@ -864,18 +922,22 @@ RETCODE SQL_API SQLGetCursorName(
SWORD cbCursorMax,
SWORD FAR *pcbCursor)
{
+char *func="SQLGetCursorName";
StatementClass *stmt = (StatementClass *) hstmt;
mylog("SQLGetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d, pcbCursor=%u\n",
hstmt, szCursor, cbCursorMax, pcbCursor);
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
if ( stmt->cursor_name[0] == '\0') {
stmt->errornumber = STMT_NO_CURSOR_NAME;
stmt->errormsg = "No Cursor name available";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
diff --git a/src/interfaces/odbc/statement.c b/src/interfaces/odbc/statement.c
index bbf1d978185..0bbc3f68c79 100644
--- a/src/interfaces/odbc/statement.c
+++ b/src/interfaces/odbc/statement.c
@@ -46,11 +46,14 @@ static struct {
RETCODE SQL_API SQLAllocStmt(HDBC hdbc,
HSTMT FAR *phstmt)
{
+char *func="SQLAllocStmt";
ConnectionClass *conn = (ConnectionClass *) hdbc;
StatementClass *stmt;
- if( ! conn)
+ if( ! conn) {
+ CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
stmt = SC_Constructor();
@@ -60,12 +63,14 @@ StatementClass *stmt;
conn->errornumber = CONN_STMT_ALLOC_ERROR;
conn->errormsg = "No more memory to allocate a further SQL-statement";
*phstmt = SQL_NULL_HSTMT;
+ CC_log_error(func, "", conn);
return SQL_ERROR;
}
if ( ! CC_add_statement(conn, stmt)) {
conn->errormsg = "Maximum number of connections exceeded.";
conn->errornumber = CONN_STMT_ALLOC_ERROR;
+ CC_log_error(func, "", conn);
SC_Destructor(stmt);
*phstmt = SQL_NULL_HSTMT;
return SQL_ERROR;
@@ -80,12 +85,15 @@ StatementClass *stmt;
RETCODE SQL_API SQLFreeStmt(HSTMT hstmt,
UWORD fOption)
{
+char *func="SQLFreeStmt";
StatementClass *stmt = (StatementClass *) hstmt;
mylog("**** enter SQLFreeStmt: hstmt=%u, fOption=%d\n", hstmt, fOption);
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
if (fOption == SQL_DROP) {
ConnectionClass *conn = stmt->hdbc;
@@ -95,6 +103,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
if ( ! CC_remove_statement(conn, stmt)) {
stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "Statement is currently executing a transaction.";
+ SC_log_error(func, "", stmt);
return SQL_ERROR; /* stmt may be executing a transaction */
}
@@ -116,9 +125,11 @@ StatementClass *stmt = (StatementClass *) hstmt;
/* this should discard all the results, but leave the statement */
/* itself in place (it can be executed again) */
- if (!SC_recycle_statement(stmt))
+ if (!SC_recycle_statement(stmt)) {
// errormsg passed in above
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
+ }
} else if(fOption == SQL_RESET_PARAMS) {
SC_free_params(stmt, STMT_FREE_PARAMS_ALL);
@@ -126,6 +137,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
} else {
stmt->errormsg = "Invalid option passed to SQLFreeStmt.";
stmt->errornumber = STMT_OPTION_OUT_OF_RANGE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
@@ -447,6 +459,7 @@ char rv;
RETCODE SC_execute(StatementClass *self)
{
+char *func="SC_execute";
ConnectionClass *conn;
QResultClass *res;
char ok, was_ok, was_nonfatal;
@@ -466,6 +479,7 @@ Int2 oldstatus, numcols;
if ( ! res) {
self->errormsg = "Could not begin a transaction";
self->errornumber = STMT_EXEC_ERROR;
+ SC_log_error(func, "", self);
return SQL_ERROR;
}
@@ -478,6 +492,7 @@ Int2 oldstatus, numcols;
if (!ok) {
self->errormsg = "Could not begin a transaction";
self->errornumber = STMT_EXEC_ERROR;
+ SC_log_error(func, "", self);
return SQL_ERROR;
}
else
@@ -554,6 +569,7 @@ Int2 oldstatus, numcols;
if (self->bindings == NULL) {
self->errornumber = STMT_NO_MEMORY_ERROR;
self->errormsg = "Could not get enough free memory to store the binding information";
+ SC_log_error(func, "", self);
return SQL_ERROR;
}
}
@@ -582,6 +598,43 @@ Int2 oldstatus, numcols;
else if (self->errornumber == STMT_INFO_ONLY)
return SQL_SUCCESS_WITH_INFO;
- else
+ else {
+ SC_log_error(func, "", self);
return SQL_ERROR;
+ }
+}
+
+void
+SC_log_error(char *func, char *desc, StatementClass *self)
+{
+ if (self) {
+ qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg);
+ qlog(" ------------------------------------------------------------\n");
+ qlog(" hdbc=%u, stmt=%u, result=%u\n", self->hdbc, self, self->result);
+ 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(" statement_type=%d, statement='%s'\n", self->statement_type, self->statement);
+ qlog(" stmt_with_params='%s'\n", 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->maxRows, self->rowset_size, self->keyset_size, self->cursor_type, self->scroll_concurrency);
+ qlog(" cursor_name='%s'\n", self->cursor_name);
+
+ qlog(" ----------------QResult Info -------------------------------\n");
+
+ if (self->result) {
+ QResultClass *res = self->result;
+ qlog(" fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn);
+ qlog(" fetch_count=%d, fcount=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->fcount, res->num_fields, res->cursor);
+ qlog(" message='%s', command='%s', notice='%s'\n", res->message, res->command, res->notice);
+ qlog(" status=%d, inTuples=%d\n", res->status, res->inTuples);
+ }
+
+ // Log the connection error if there is one
+ CC_log_error(func, desc, self->hdbc);
+ }
+ else
+ qlog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
}
+
diff --git a/src/interfaces/odbc/statement.h b/src/interfaces/odbc/statement.h
index 53ad3894c96..6582dfda473 100644
--- a/src/interfaces/odbc/statement.h
+++ b/src/interfaces/odbc/statement.h
@@ -132,5 +132,6 @@ char SC_get_error(StatementClass *self, int *number, char **message);
char *SC_create_errormsg(StatementClass *self);
RETCODE SC_execute(StatementClass *stmt);
void SC_free_params(StatementClass *self, char option);
+void SC_log_error(char *func, char *desc, StatementClass *self);
#endif