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;
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;
}
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;
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;
}
UDWORD crow,
UDWORD FAR *pirow)
{
+char *func = "SQLParamOptions";
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
return SQL_ERROR;
}
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 {
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; ibindings_allocated; i++)
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");
}
{
EnvironmentClass *env = (EnvironmentClass *)henv;
ConnectionClass *conn;
-
+char *func="SQLAllocConnect";
conn = CC_Constructor();
mylog("**** SQLAllocConnect: henv = %u, conn = %u\n", henv, 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;
}
env->errornumber = ENV_ALLOC_ERROR;
CC_Destructor(conn);
*phdbc = SQL_NULL_HDBC;
+ EN_log_error(func, "", env);
return SQL_ERROR;
}
{
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;
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;
}
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;
}
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;
}
/******* 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 */
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)
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);
}
*/
-
// 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;
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
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.
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;
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));
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;
}
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));
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));
{
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,
// 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);
}
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);
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);
}
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);
ci->fake_oid_index,
ODBC_INI);
+ SQLWritePrivateProfileString(DSN,
+ INI_ROWVERSIONING,
+ ci->row_versioning,
+ ODBC_INI);
+
SQLWritePrivateProfileString(DSN,
INI_SHOWSYSTEMTABLES,
ci->show_system_tables,
#define INI_FAKEOIDINDEX "FakeOidIndex"
#define INI_SHOWOIDCOLUMN "ShowOidColumn"
+#define INI_ROWVERSIONING "RowVersioning"
#define INI_SHOWSYSTEMTABLES "ShowSystemTables"
#define INI_LIE "Lie"
#define INI_EXTRASYSTABLEPREFIXES "ExtraSysTablePrefixes"
#define DEFAULT_FAKEOIDINDEX 0
#define DEFAULT_SHOWOIDCOLUMN 0
+#define DEFAULT_ROWVERSIONING 0
#define DEFAULT_SHOWSYSTEMTABLES 0 // dont show system tables
#define DEFAULT_LIE 0
SWORD FAR *pcbConnStrOut,
UWORD fDriverCompletion)
{
+char *func = "SQLDriverConnect";
ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci;
RETCODE dialog_result;
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);
// 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;
}
else if (retval == 0) {
// error msg filled in above
+ CC_log_error(func, "Error from CC_Connect", conn);
return SQL_ERROR;
}
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;
}
RETCODE SQL_API SQLFreeEnv(HENV henv)
{
+char *func = "SQLFreeEnv";
EnvironmentClass *env = (EnvironmentClass *) henv;
mylog("**** in SQLFreeEnv: env = %u ** \n", env);
}
mylog(" error\n");
+ EN_log_error(func, "Error freeing environment", env);
return SQL_ERROR;
}
// 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) {
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);
+}
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
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
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;
}
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;
}
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;
}
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);
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;
}
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;
}
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
*/
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);
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;
}
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;
}
HDBC hdbc,
UWORD fType)
{
+char *func = "SQLTransact";
extern ConnectionClass *conns[];
ConnectionClass *conn;
QResultClass *res;
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.
} 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;
}
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;
}
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)
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);
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
}
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);
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);
if ( ! buffer) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (3)";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
current_param->EXEC_buffer = buffer;
}
- else
+ else {
+ SC_log_error(func, "bad cbValue", stmt);
return SQL_ERROR;
+ }
}
}
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) {
// 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;
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;
// 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;
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;
/* unrecognized key */
conn->errormsg = "Unrecognized key passed to SQLGetInfo.";
conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
+ CC_log_error(func, "", conn);
return SQL_ERROR;
}
HSTMT hstmt,
SWORD fSqlType)
{
+char *func = "SQLGetTypeInfo";
StatementClass *stmt = (StatementClass *) hstmt;
TupleNode *row;
int i;
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;
}
UCHAR FAR * szTableType,
SWORD cbTableType)
{
+char *func = "SQLTables";
StatementClass *stmt = (StatementClass *) hstmt;
StatementClass *tbl_stmt;
TupleNode *row;
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;
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;
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
UCHAR FAR * szColumnName,
SWORD cbColumnName)
{
+char *func = "SQLColumns";
StatementClass *stmt = (StatementClass *) hstmt;
TupleNode *row;
HSTMT hcol_stmt;
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;
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;
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;
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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)) {
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;
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);
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;
UWORD fUnique,
UWORD fAccuracy)
{
+char *func="SQLStatistics";
StatementClass *stmt = (StatementClass *) hstmt;
char index_query[MAX_STATEMENT_LEN];
HSTMT hindx_stmt;
mylog("**** SQLStatistics(): ENTER, stmt=%u\n", stmt);
if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
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;
}
if ( ! table_name) {
stmt->errormsg = "No table name passed to SQLStatistics.";
stmt->errornumber = STMT_INTERNAL_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
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;
}
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;
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;
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;
}
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;
}
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;
}
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;
}
UCHAR FAR * szTableName,
SWORD cbTableName)
{
+char *func = "SQLPrimaryKeys";
StatementClass *stmt = (StatementClass *) hstmt;
TupleNode *row;
RETCODE result;
mylog("**** SQLPrimaryKeys(): ENTER, stmt=%u\n", stmt);
if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
stmt->manual_result = TRUE;
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;
}
UCHAR FAR * szFkTableName,
SWORD cbFkTableName)
{
+char *func = "SQLForeignKeys";
StatementClass *stmt = (StatementClass *) hstmt;
TupleNode *row;
HSTMT htbl_stmt;
memset(primaryKey, 0, sizeof(primaryKey));
if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
stmt->manual_result = TRUE;
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
UCHAR FAR * szColumnName,
SWORD cbColumnName)
{
+char *func="SQLProcedureColumns";
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
return SQL_ERROR;
}
UCHAR FAR * szProcName,
SWORD cbProcName)
{
+char *func="SQLProcedures";
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
return SQL_ERROR;
}
UCHAR FAR * szTableName,
SWORD cbTableName)
{
+char *func="SQLTablePrivileges";
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
return SQL_ERROR;
}
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:
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;
}
*/
default:
conn->errormsg = "Illegal parameter value for SQL_AUTOCOMMIT";
conn->errornumber = CONN_INVALID_ARGUMENT_NO;
+ CC_log_error(func, "", conn);
return SQL_ERROR;
}
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;
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:
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;
+ }
}
UWORD fOption,
UDWORD vParam)
{
+char *func="SQLSetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt;
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:
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;
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) {
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:
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;
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,
PG_TYPE_OID,
PG_TYPE_MONEY,
PG_TYPE_BOOL,
- PG_TYPE_DATETIME,
PG_TYPE_BYTEA,
PG_TYPE_LO,
0 };
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;
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;
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";
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;
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 */
/* 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;
}
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;
}
#define PG_TYPE_DATE 1082
#define PG_TYPE_TIME 1083
#define PG_TYPE_DATETIME 1184
+#define PG_TYPE_TIMESTAMP 1296
extern Int4 pgtypes_defined[];
/* 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"
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
//
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
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"
#define DRV_BOOLS_CHAR 1050
#define DS_SHOWSYSTEMTABLES 1051
#define DRV_EXTRASYSTABLEPREFIXES 1051
+#define DS_ROWVERSIONING 1052
// Next default values for new objects
//
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) {
}
}
+ SC_log_error(func, "Bad return value", stmt);
return SQL_ERROR;
}
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);
/* 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;
}
SWORD FAR *pibScale,
SWORD FAR *pfNullable)
{
+char *func="SQLDescribeCol";
/* gets all the information about a specific column */
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *result;
int p;
ConnInfo *ci;
- if ( ! stmt)
+ if ( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
+ }
ci = &(stmt->hdbc->connInfo);
/* 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;
}
// 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;
}
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);
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;
}
// 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;
}
SDWORD cbValueMax,
SDWORD FAR *pcbValue)
{
+char *func="SQLGetData";
QResultClass *res;
StatementClass *stmt = (StatementClass *) hstmt;
int num_cols, num_rows;
mylog("SQLGetData: enter, stmt=%u\n", stmt);
if( ! stmt) {
+ SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
res = stmt->result;
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;
}
if (icol >= num_cols) {
stmt->errormsg = "Invalid column number.";
stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
(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);
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;
}
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:
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;
}
}
RETCODE SQL_API SQLFetch(
HSTMT hstmt)
{
+char *func = "SQLFetch";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;
int retval;
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;
}
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;
}
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;
}
// 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;
}
mylog("SQLFetch: error\n");
stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Error fetching next row";
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
}
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) {
} 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;
}
UDWORD FAR *pcrow,
UWORD FAR *rgfRowStatus)
{
+char *func = "SQLExtendedFetch";
StatementClass *stmt = (StatementClass *) hstmt;
int num_tuples;
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)
break;
default:
+ SC_log_error(func, "Unsupported SQLExtendedFetch Direction", stmt);
return SQL_ERROR;
}
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.
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.
SDWORD crowKeyset,
UWORD crowRowset)
{
- return SQL_ERROR;
+char *func = "SQLSetScrollOptions";
+
+ SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
+ return SQL_ERROR;
}
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);
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;
}
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();
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;
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;
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 */
}
/* 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);
} else {
stmt->errormsg = "Invalid option passed to SQLFreeStmt.";
stmt->errornumber = STMT_OPTION_OUT_OF_RANGE_ERROR;
+ SC_log_error(func, "", stmt);
return SQL_ERROR;
}
RETCODE SC_execute(StatementClass *self)
{
+char *func="SC_execute";
ConnectionClass *conn;
QResultClass *res;
char ok, was_ok, was_nonfatal;
if ( ! res) {
self->errormsg = "Could not begin a transaction";
self->errornumber = STMT_EXEC_ERROR;
+ SC_log_error(func, "", self);
return SQL_ERROR;
}
if (!ok) {
self->errormsg = "Could not begin a transaction";
self->errornumber = STMT_EXEC_ERROR;
+ SC_log_error(func, "", self);
return SQL_ERROR;
}
else
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;
}
}
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);
}
+
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