Commit a80771f0 authored by Byron Nikolaidis's avatar Byron Nikolaidis

Update to v.0246

parent fd262dac
...@@ -37,9 +37,12 @@ RETCODE SQL_API SQLBindParameter( ...@@ -37,9 +37,12 @@ RETCODE SQL_API SQLBindParameter(
SDWORD FAR *pcbValue) SDWORD FAR *pcbValue)
{ {
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
char *func="SQLBindParameter";
if( ! stmt) if( ! stmt) {
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
if(stmt->parameters_allocated < ipar) { if(stmt->parameters_allocated < ipar) {
ParameterInfoClass *old_parameters; ParameterInfoClass *old_parameters;
...@@ -52,6 +55,7 @@ StatementClass *stmt = (StatementClass *) hstmt; ...@@ -52,6 +55,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
if ( ! stmt->parameters) { if ( ! stmt->parameters) {
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Could not allocate memory for statement parameters"; stmt->errormsg = "Could not allocate memory for statement parameters";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -133,53 +137,51 @@ RETCODE SQL_API SQLBindCol( ...@@ -133,53 +137,51 @@ RETCODE SQL_API SQLBindCol(
SDWORD FAR *pcbValue) SDWORD FAR *pcbValue)
{ {
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
Int2 numcols; Int2 numcols = 0;
char *func="SQLBindCol";
mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol); mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
if ( ! stmt) if ( ! stmt) {
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
if (icol < 1) { if (icol < 1) {
/* currently we do not support bookmarks */ /* currently we do not support bookmarks */
stmt->errormsg = "Bookmarks are not currently supported."; stmt->errormsg = "Bookmarks are not currently supported.";
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
icol--; /* use zero based col numbers */
SC_clear_error(stmt); 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) { if( stmt->status == STMT_EXECUTING) {
stmt->errormsg = "Can't bind columns while statement is still executing."; stmt->errormsg = "Can't bind columns while statement is still executing.";
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
numcols = QR_NumResultCols(stmt->result); // allocate enough bindings if not already done
// Most likely, execution of a statement would have setup the
mylog("SQLBindCol: numcols = %d\n", numcols); // necessary bindings. But some apps call BindCol before any
// statement is executed.
if (icol >= numcols) { if ( icol > stmt->bindings_allocated)
stmt->errornumber = STMT_COLNUM_ERROR; extend_bindings(stmt, icol);
stmt->errormsg = "Column number too big";
return SQL_ERROR;
}
// check to see if the bindings were allocated
if ( ! stmt->bindings) { if ( ! stmt->bindings) {
stmt->errormsg = "Bindings were not allocated properly."; stmt->errormsg = "Could not allocate memory for bindings.";
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
SC_log_error(func, "", stmt);
return SQL_ERROR; 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 */ /* we have to unbind the column */
stmt->bindings[icol].buflen = 0; stmt->bindings[icol].buflen = 0;
stmt->bindings[icol].buffer = NULL; stmt->bindings[icol].buffer = NULL;
...@@ -216,13 +218,17 @@ RETCODE SQL_API SQLDescribeParam( ...@@ -216,13 +218,17 @@ RETCODE SQL_API SQLDescribeParam(
SWORD FAR *pfNullable) SWORD FAR *pfNullable)
{ {
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
char *func = "SQLDescribeParam";
if( ! stmt) if( ! stmt) {
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
if( (ipar < 1) || (ipar > stmt->parameters_allocated) ) { if( (ipar < 1) || (ipar > stmt->parameters_allocated) ) {
stmt->errormsg = "Invalid parameter number for SQLDescribeParam."; stmt->errormsg = "Invalid parameter number for SQLDescribeParam.";
stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR; stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR;
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -254,6 +260,9 @@ RETCODE SQL_API SQLParamOptions( ...@@ -254,6 +260,9 @@ RETCODE SQL_API SQLParamOptions(
UDWORD crow, UDWORD crow,
UDWORD FAR *pirow) UDWORD FAR *pirow)
{ {
char *func = "SQLParamOptions";
SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -273,21 +282,26 @@ RETCODE SQL_API SQLNumParams( ...@@ -273,21 +282,26 @@ RETCODE SQL_API SQLNumParams(
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
char in_quote = FALSE; char in_quote = FALSE;
unsigned int i; unsigned int i;
char *func = "SQLNumParams";
if(!stmt) {
if(!stmt) SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
if (pcpar) if (pcpar)
*pcpar = 0; *pcpar = 0;
else else {
SC_log_error(func, "pcpar was null", stmt);
return SQL_ERROR; return SQL_ERROR;
}
if(!stmt->statement) { if(!stmt->statement) {
// no statement has been allocated // no statement has been allocated
stmt->errormsg = "SQLNumParams called with no statement ready."; stmt->errormsg = "SQLNumParams called with no statement ready.";
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} else { } else {
...@@ -341,6 +355,14 @@ mylog("in extend_bindings: stmt=%u, bindings_allocated=%d, num_columns=%d\n", st ...@@ -341,6 +355,14 @@ mylog("in extend_bindings: stmt=%u, bindings_allocated=%d, num_columns=%d\n", st
if(stmt->bindings_allocated < num_columns) { if(stmt->bindings_allocated < num_columns) {
new_bindings = create_empty_bindings(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) { if(stmt->bindings) {
for(i=0; i<stmt->bindings_allocated; i++) 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 ...@@ -349,18 +371,17 @@ mylog("in extend_bindings: stmt=%u, bindings_allocated=%d, num_columns=%d\n", st
free(stmt->bindings); free(stmt->bindings);
} }
stmt->bindings = new_bindings; // null indicates error stmt->bindings = new_bindings;
stmt->bindings_allocated = num_columns; 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"); mylog("exit extend_bindings\n");
} }
...@@ -35,7 +35,7 @@ RETCODE SQL_API SQLAllocConnect( ...@@ -35,7 +35,7 @@ RETCODE SQL_API SQLAllocConnect(
{ {
EnvironmentClass *env = (EnvironmentClass *)henv; EnvironmentClass *env = (EnvironmentClass *)henv;
ConnectionClass *conn; ConnectionClass *conn;
char *func="SQLAllocConnect";
conn = CC_Constructor(); conn = CC_Constructor();
mylog("**** SQLAllocConnect: henv = %u, conn = %u\n", henv, conn); mylog("**** SQLAllocConnect: henv = %u, conn = %u\n", henv, conn);
...@@ -44,6 +44,7 @@ ConnectionClass *conn; ...@@ -44,6 +44,7 @@ ConnectionClass *conn;
env->errormsg = "Couldn't allocate memory for Connection object."; env->errormsg = "Couldn't allocate memory for Connection object.";
env->errornumber = ENV_ALLOC_ERROR; env->errornumber = ENV_ALLOC_ERROR;
*phdbc = SQL_NULL_HDBC; *phdbc = SQL_NULL_HDBC;
EN_log_error(func, "", env);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -52,6 +53,7 @@ ConnectionClass *conn; ...@@ -52,6 +53,7 @@ ConnectionClass *conn;
env->errornumber = ENV_ALLOC_ERROR; env->errornumber = ENV_ALLOC_ERROR;
CC_Destructor(conn); CC_Destructor(conn);
*phdbc = SQL_NULL_HDBC; *phdbc = SQL_NULL_HDBC;
EN_log_error(func, "", env);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -74,9 +76,12 @@ RETCODE SQL_API SQLConnect( ...@@ -74,9 +76,12 @@ RETCODE SQL_API SQLConnect(
{ {
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci; ConnInfo *ci;
char *func = "SQLConnect";
if ( ! conn) if ( ! conn) {
CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
ci = &conn->connInfo; ci = &conn->connInfo;
...@@ -96,9 +101,11 @@ ConnInfo *ci; ...@@ -96,9 +101,11 @@ ConnInfo *ci;
qlog("conn = %u, SQLConnect(DSN='%s', UID='%s', PWD='%s')\n", ci->dsn, ci->username, ci->password); 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 // Error messages are filled in
CC_log_error(func, "Error on CC_connect", conn);
return SQL_ERROR; return SQL_ERROR;
}
return SQL_SUCCESS; return SQL_SUCCESS;
} }
...@@ -123,17 +130,21 @@ RETCODE SQL_API SQLDisconnect( ...@@ -123,17 +130,21 @@ RETCODE SQL_API SQLDisconnect(
HDBC hdbc) HDBC hdbc)
{ {
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
char *func = "SQLDisconnect";
mylog("**** in SQLDisconnect\n"); mylog("**** in SQLDisconnect\n");
if ( ! conn) if ( ! conn) {
CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
qlog("conn=%u, SQLDisconnect\n", conn); qlog("conn=%u, SQLDisconnect\n", conn);
if (conn->status == CONN_EXECUTING) { if (conn->status == CONN_EXECUTING) {
conn->errornumber = CONN_IN_USE; conn->errornumber = CONN_IN_USE;
conn->errormsg = "A transaction is currently being executed"; conn->errormsg = "A transaction is currently being executed";
CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -155,16 +166,20 @@ RETCODE SQL_API SQLFreeConnect( ...@@ -155,16 +166,20 @@ RETCODE SQL_API SQLFreeConnect(
HDBC hdbc) HDBC hdbc)
{ {
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
char *func = "SQLFreeConnect";
mylog("**** in SQLFreeConnect: hdbc=%u\n", hdbc); mylog("**** in SQLFreeConnect: hdbc=%u\n", hdbc);
if ( ! conn) if ( ! conn) {
CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
/* Remove the connection from the environment */ /* Remove the connection from the environment */
if ( ! EN_remove_connection(conn->henv, conn)) { if ( ! EN_remove_connection(conn->henv, conn)) {
conn->errornumber = CONN_IN_USE; conn->errornumber = CONN_IN_USE;
conn->errormsg = "A transaction is currently being executed"; conn->errormsg = "A transaction is currently being executed";
CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -577,8 +592,9 @@ char salt[2]; ...@@ -577,8 +592,9 @@ char salt[2];
/******* Send any initial settings *********/ /******* Send any initial settings *********/
/**********************************************/ /**********************************************/
if ( ! CC_send_settings(self)) // The Unix iodbc errors out on this call because it allocates a statement
return 0; // 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 */ CC_lookup_lo(self); /* a hack to get the oid of our large object oid type */
...@@ -1155,6 +1171,27 @@ RETCODE result; ...@@ -1155,6 +1171,27 @@ RETCODE result;
result = SQLFreeStmt(hstmt, SQL_DROP); 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 void
CC_test(ConnectionClass *self) CC_test(ConnectionClass *self)
...@@ -1165,23 +1202,28 @@ SDWORD pcbValue; ...@@ -1165,23 +1202,28 @@ SDWORD pcbValue;
UDWORD pcrow; UDWORD pcrow;
UWORD rgfRowStatus; UWORD rgfRowStatus;
char buf[255]; char buf[255];
SDWORD buflen;
DATE_STRUCT *ds;
result = SQLAllocStmt( self, &hstmt1); result = SQLAllocStmt( self, &hstmt1);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
return; return;
} }
result = SQLExtendedFetch(hstmt1, SQL_FETCH_ABSOLUTE, -2, &pcrow, &rgfRowStatus); result = SQLExecDirect(hstmt1, "select * from cpar", SQL_NTS);
SQLGetData(hstmt1, 1, SQL_C_CHAR, buf, sizeof(buf), &pcbValue); qlog("exec result = %d\n", result);
qlog("FETCH_ABSOLUTE, -2: result=%d, Col1 = '%s'\n", result, buf);
result = SQLBindCol(hstmt1, 2, SQL_C_DATE, buf, 0, &buflen);
qlog("bind result = %d\n", result);
result = SQLFetch(hstmt1); result = SQLFetch(hstmt1);
while (result != SQL_NO_DATA_FOUND) { 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); result = SQLFetch(hstmt1);
qlog("fetch on stmt1\n");
} }
SQLFreeStmt(hstmt1, SQL_DROP); SQLFreeStmt(hstmt1, SQL_DROP);
} }
*/ */
...@@ -133,6 +133,7 @@ typedef struct { ...@@ -133,6 +133,7 @@ typedef struct {
// char unknown_sizes[SMALL_REGISTRY_LEN]; // char unknown_sizes[SMALL_REGISTRY_LEN];
char fake_oid_index[SMALL_REGISTRY_LEN]; char fake_oid_index[SMALL_REGISTRY_LEN];
char show_oid_column[SMALL_REGISTRY_LEN]; char show_oid_column[SMALL_REGISTRY_LEN];
char row_versioning[SMALL_REGISTRY_LEN];
char show_system_tables[SMALL_REGISTRY_LEN]; char show_system_tables[SMALL_REGISTRY_LEN];
char focus_password; char focus_password;
} ConnInfo; } ConnInfo;
...@@ -188,5 +189,6 @@ char *CC_create_errormsg(ConnectionClass *self); ...@@ -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); 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); char CC_send_settings(ConnectionClass *self);
void CC_lookup_lo(ConnectionClass *conn); void CC_lookup_lo(ConnectionClass *conn);
void CC_log_error(char *func, char *desc, ConnectionClass *self);
#endif #endif
...@@ -94,7 +94,15 @@ struct tm *tim; ...@@ -94,7 +94,15 @@ struct tm *tim;
st.y = tim->tm_year + 1900; 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); mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType, value, cbValueMax);
if(value) {
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 First convert any specific postgres types into more
...@@ -115,6 +123,7 @@ struct tm *tim; ...@@ -115,6 +123,7 @@ struct tm *tim;
case PG_TYPE_ABSTIME: case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME: case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP:
if (strnicmp(value, "invalid", 7) != 0) { 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); sscanf(value, "%4d-%2d-%2d %2d:%2d:%2d", &st.y, &st.m, &st.d, &st.hh, &st.mm, &st.ss);
...@@ -185,23 +194,25 @@ struct tm *tim; ...@@ -185,23 +194,25 @@ struct tm *tim;
if(fCType == SQL_C_CHAR) { if(fCType == SQL_C_CHAR) {
/* Special character formatting as required */ /* Special character formatting as required */
/* These really should return error if cbValueMax is not big enough. */
switch(field_type) { switch(field_type) {
case PG_TYPE_DATE: case PG_TYPE_DATE:
len = 11; len = 10;
if (cbValueMax >= len) if (cbValueMax > len)
sprintf((char *)rgbValue, "%.4d-%.2d-%.2d", st.y, st.m, st.d); sprintf((char *)rgbValue, "%.4d-%.2d-%.2d", st.y, st.m, st.d);
break; break;
case PG_TYPE_TIME: case PG_TYPE_TIME:
len = 9; len = 8;
if (cbValueMax >= len) if (cbValueMax > len)
sprintf((char *)rgbValue, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss); sprintf((char *)rgbValue, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss);
break; break;
case PG_TYPE_ABSTIME: case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME: case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP:
len = 19; len = 19;
if (cbValueMax >= len) if (cbValueMax > len)
sprintf((char *) rgbValue, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", sprintf((char *) rgbValue, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
st.y, st.m, st.d, st.hh, st.mm, st.ss); st.y, st.m, st.d, st.hh, st.mm, st.ss);
break; break;
...@@ -214,6 +225,16 @@ struct tm *tim; ...@@ -214,6 +225,16 @@ struct tm *tim;
} }
break; break;
/* 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.
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") case PG_TYPE_BYTEA: // convert binary data to hex strings (i.e, 255 = "FF")
len = convert_pgbinary_to_char(value, rgbValue, cbValueMax); len = convert_pgbinary_to_char(value, rgbValue, cbValueMax);
break; break;
...@@ -227,6 +248,7 @@ struct tm *tim; ...@@ -227,6 +248,7 @@ struct tm *tim;
break; break;
} }
} else { } else {
/* for SQL_C_CHAR, its probably ok to leave currency symbols in. But /* for SQL_C_CHAR, its probably ok to leave currency symbols in. But
...@@ -238,7 +260,7 @@ struct tm *tim; ...@@ -238,7 +260,7 @@ struct tm *tim;
switch(fCType) { switch(fCType) {
case SQL_C_DATE: case SQL_C_DATE:
len = 6; len = 6;
if (cbValueMax >= len) { {
DATE_STRUCT *ds = (DATE_STRUCT *) rgbValue; DATE_STRUCT *ds = (DATE_STRUCT *) rgbValue;
ds->year = st.y; ds->year = st.y;
ds->month = st.m; ds->month = st.m;
...@@ -248,7 +270,7 @@ struct tm *tim; ...@@ -248,7 +270,7 @@ struct tm *tim;
case SQL_C_TIME: case SQL_C_TIME:
len = 6; len = 6;
if (cbValueMax >= len) { {
TIME_STRUCT *ts = (TIME_STRUCT *) rgbValue; TIME_STRUCT *ts = (TIME_STRUCT *) rgbValue;
ts->hour = st.hh; ts->hour = st.hh;
ts->minute = st.mm; ts->minute = st.mm;
...@@ -258,7 +280,7 @@ struct tm *tim; ...@@ -258,7 +280,7 @@ struct tm *tim;
case SQL_C_TIMESTAMP: case SQL_C_TIMESTAMP:
len = 16; len = 16;
if (cbValueMax >= len) { {
TIMESTAMP_STRUCT *ts = (TIMESTAMP_STRUCT *) rgbValue; TIMESTAMP_STRUCT *ts = (TIMESTAMP_STRUCT *) rgbValue;
ts->year = st.y; ts->year = st.y;
ts->month = st.m; ts->month = st.m;
...@@ -272,60 +294,50 @@ struct tm *tim; ...@@ -272,60 +294,50 @@ struct tm *tim;
case SQL_C_BIT: case SQL_C_BIT:
len = 1; len = 1;
if (cbValueMax >= len || field_type == PG_TYPE_BOOL) {
*((UCHAR *)rgbValue) = atoi(value); *((UCHAR *)rgbValue) = atoi(value);
mylog("SQL_C_BIT: val = %d, cb = %d, rgb=%d\n", atoi(value), cbValueMax, *((UCHAR *)rgbValue)); mylog("SQL_C_BIT: val = %d, cb = %d, rgb=%d\n", atoi(value), cbValueMax, *((UCHAR *)rgbValue));
}
break; break;
case SQL_C_STINYINT: case SQL_C_STINYINT:
case SQL_C_TINYINT: case SQL_C_TINYINT:
len = 1; len = 1;
if (cbValueMax >= len)
*((SCHAR *) rgbValue) = atoi(value); *((SCHAR *) rgbValue) = atoi(value);
break; break;
case SQL_C_UTINYINT: case SQL_C_UTINYINT:
len = 1; len = 1;
if (cbValueMax >= len)
*((UCHAR *) rgbValue) = atoi(value); *((UCHAR *) rgbValue) = atoi(value);
break; break;
case SQL_C_FLOAT: case SQL_C_FLOAT:
len = 4; len = 4;
if(cbValueMax >= len)
*((SFLOAT *)rgbValue) = (float) atof(value); *((SFLOAT *)rgbValue) = (float) atof(value);
break; break;
case SQL_C_DOUBLE: case SQL_C_DOUBLE:
len = 8; len = 8;
if(cbValueMax >= len)
*((SDOUBLE *)rgbValue) = atof(value); *((SDOUBLE *)rgbValue) = atof(value);
break; break;
case SQL_C_SSHORT: case SQL_C_SSHORT:
case SQL_C_SHORT: case SQL_C_SHORT:
len = 2; len = 2;
if(cbValueMax >= len)
*((SWORD *)rgbValue) = atoi(value); *((SWORD *)rgbValue) = atoi(value);
break; break;
case SQL_C_USHORT: case SQL_C_USHORT:
len = 2; len = 2;
if(cbValueMax >= len)
*((UWORD *)rgbValue) = atoi(value); *((UWORD *)rgbValue) = atoi(value);
break; break;
case SQL_C_SLONG: case SQL_C_SLONG:
case SQL_C_LONG: case SQL_C_LONG:
len = 4; len = 4;
if(cbValueMax >= len)
*((SDWORD *)rgbValue) = atol(value); *((SDWORD *)rgbValue) = atol(value);
break; break;
case SQL_C_ULONG: case SQL_C_ULONG:
len = 4; len = 4;
if(cbValueMax >= len)
*((UDWORD *)rgbValue) = atol(value); *((UDWORD *)rgbValue) = atol(value);
break; break;
...@@ -341,42 +353,13 @@ struct tm *tim; ...@@ -341,42 +353,13 @@ struct tm *tim;
return COPY_UNSUPPORTED_TYPE; 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;
}
}
// store the length of what was copied, if there's a place for it // 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)
if(pcbValue && value)
*pcbValue = len; *pcbValue = len;
if(len > cbValueMax) {
mylog("!!! COPY_RESULT_TRUNCATED !!!\n");
// 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;
// LongVarBinary types do handle truncated multiple get calls
// through convert_lo().
if (pcbValue)
*pcbValue = cbValueMax -1;
return COPY_OK; return COPY_OK;
} else {
return COPY_OK;
}
} }
/* This function inserts parameters into an SQL statements. /* This function inserts parameters into an SQL statements.
...@@ -386,6 +369,7 @@ struct tm *tim; ...@@ -386,6 +369,7 @@ struct tm *tim;
int int
copy_statement_with_parameters(StatementClass *stmt) copy_statement_with_parameters(StatementClass *stmt)
{ {
char *func="copy_statement_with_parameters";
unsigned int opos, npos; unsigned int opos, npos;
char param_string[128], tmp[256], cbuf[TEXT_FIELD_SIZE+5]; char param_string[128], tmp[256], cbuf[TEXT_FIELD_SIZE+5];
int param_number; int param_number;
...@@ -400,8 +384,10 @@ char *buffer, *buf; ...@@ -400,8 +384,10 @@ char *buffer, *buf;
char in_quote = FALSE; char in_quote = FALSE;
if ( ! old_statement) if ( ! old_statement) {
SC_log_error(func, "No statement string", stmt);
return SQL_ERROR; return SQL_ERROR;
}
memset(&st, 0, sizeof(SIMPLE_TIME)); memset(&st, 0, sizeof(SIMPLE_TIME));
...@@ -624,6 +610,7 @@ char in_quote = FALSE; ...@@ -624,6 +610,7 @@ char in_quote = FALSE;
stmt->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters"; stmt->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
new_statement[npos] = '\0'; // just in case new_statement[npos] = '\0'; // just in case
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
......
...@@ -226,6 +226,7 @@ char buf[128]; ...@@ -226,6 +226,7 @@ char buf[128];
CheckDlgButton(hdlg, DS_SHOWOIDCOLUMN, atoi(ci->show_oid_column)); CheckDlgButton(hdlg, DS_SHOWOIDCOLUMN, atoi(ci->show_oid_column));
CheckDlgButton(hdlg, DS_FAKEOIDINDEX, atoi(ci->fake_oid_index)); 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)); CheckDlgButton(hdlg, DS_SHOWSYSTEMTABLES, atoi(ci->show_system_tables));
EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), atoi(ci->show_oid_column)); EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), atoi(ci->show_oid_column));
...@@ -273,6 +274,8 @@ char buf[128]; ...@@ -273,6 +274,8 @@ char buf[128];
sprintf(ci->show_system_tables, "%d", IsDlgButtonChecked(hdlg, DS_SHOWSYSTEMTABLES)); sprintf(ci->show_system_tables, "%d", IsDlgButtonChecked(hdlg, DS_SHOWSYSTEMTABLES));
sprintf(ci->row_versioning, "%d", IsDlgButtonChecked(hdlg, DS_ROWVERSIONING));
/* OID Options*/ /* OID Options*/
sprintf(ci->fake_oid_index, "%d", IsDlgButtonChecked(hdlg, DS_FAKEOIDINDEX)); sprintf(ci->fake_oid_index, "%d", IsDlgButtonChecked(hdlg, DS_FAKEOIDINDEX));
sprintf(ci->show_oid_column, "%d", IsDlgButtonChecked(hdlg, DS_SHOWOIDCOLUMN)); sprintf(ci->show_oid_column, "%d", IsDlgButtonChecked(hdlg, DS_SHOWOIDCOLUMN));
...@@ -297,7 +300,7 @@ makeConnectString(char *connect_string, ConnInfo *ci) ...@@ -297,7 +300,7 @@ makeConnectString(char *connect_string, ConnInfo *ci)
{ {
char got_dsn = (ci->dsn[0] != '\0'); 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 ? "DSN" : "DRIVER",
got_dsn ? ci->dsn : ci->driver, got_dsn ? ci->dsn : ci->driver,
ci->database, ci->database,
...@@ -310,6 +313,7 @@ char got_dsn = (ci->dsn[0] != '\0'); ...@@ -310,6 +313,7 @@ char got_dsn = (ci->dsn[0] != '\0');
// ci->unknown_sizes, -- currently only needed in Driver options. // ci->unknown_sizes, -- currently only needed in Driver options.
ci->fake_oid_index, ci->fake_oid_index,
ci->show_oid_column, ci->show_oid_column,
ci->row_versioning,
ci->show_system_tables, ci->show_system_tables,
ci->conn_settings); ci->conn_settings);
} }
...@@ -355,6 +359,9 @@ copyAttributes(ConnInfo *ci, char *attribute, char *value) ...@@ -355,6 +359,9 @@ copyAttributes(ConnInfo *ci, char *attribute, char *value)
else if (stricmp(attribute, INI_FAKEOIDINDEX) == 0) else if (stricmp(attribute, INI_FAKEOIDINDEX) == 0)
strcpy(ci->fake_oid_index, value); 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) else if (stricmp(attribute, INI_SHOWSYSTEMTABLES) == 0)
strcpy(ci->show_system_tables, value); strcpy(ci->show_system_tables, value);
...@@ -398,6 +405,8 @@ getDSNdefaults(ConnInfo *ci) ...@@ -398,6 +405,8 @@ getDSNdefaults(ConnInfo *ci)
if (ci->show_system_tables[0] == '\0') if (ci->show_system_tables[0] == '\0')
sprintf(ci->show_system_tables, "%d", DEFAULT_SHOWSYSTEMTABLES); 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; ...@@ -448,6 +457,9 @@ char *DSN = ci->dsn;
if ( ci->fake_oid_index[0] == '\0' || overwrite) if ( ci->fake_oid_index[0] == '\0' || overwrite)
SQLGetPrivateProfileString(DSN, INI_FAKEOIDINDEX, "", ci->fake_oid_index, sizeof(ci->fake_oid_index), ODBC_INI); 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) if ( ci->show_system_tables[0] == '\0' || overwrite)
SQLGetPrivateProfileString(DSN, INI_SHOWSYSTEMTABLES, "", ci->show_system_tables, sizeof(ci->show_system_tables), ODBC_INI); SQLGetPrivateProfileString(DSN, INI_SHOWSYSTEMTABLES, "", ci->show_system_tables, sizeof(ci->show_system_tables), ODBC_INI);
...@@ -533,6 +545,11 @@ char *DSN = ci->dsn; ...@@ -533,6 +545,11 @@ char *DSN = ci->dsn;
ci->fake_oid_index, ci->fake_oid_index,
ODBC_INI); ODBC_INI);
SQLWritePrivateProfileString(DSN,
INI_ROWVERSIONING,
ci->row_versioning,
ODBC_INI);
SQLWritePrivateProfileString(DSN, SQLWritePrivateProfileString(DSN,
INI_SHOWSYSTEMTABLES, INI_SHOWSYSTEMTABLES,
ci->show_system_tables, ci->show_system_tables,
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#define INI_FAKEOIDINDEX "FakeOidIndex" #define INI_FAKEOIDINDEX "FakeOidIndex"
#define INI_SHOWOIDCOLUMN "ShowOidColumn" #define INI_SHOWOIDCOLUMN "ShowOidColumn"
#define INI_ROWVERSIONING "RowVersioning"
#define INI_SHOWSYSTEMTABLES "ShowSystemTables" #define INI_SHOWSYSTEMTABLES "ShowSystemTables"
#define INI_LIE "Lie" #define INI_LIE "Lie"
#define INI_EXTRASYSTABLEPREFIXES "ExtraSysTablePrefixes" #define INI_EXTRASYSTABLEPREFIXES "ExtraSysTablePrefixes"
...@@ -74,6 +75,7 @@ ...@@ -74,6 +75,7 @@
#define DEFAULT_FAKEOIDINDEX 0 #define DEFAULT_FAKEOIDINDEX 0
#define DEFAULT_SHOWOIDCOLUMN 0 #define DEFAULT_SHOWOIDCOLUMN 0
#define DEFAULT_ROWVERSIONING 0
#define DEFAULT_SHOWSYSTEMTABLES 0 // dont show system tables #define DEFAULT_SHOWSYSTEMTABLES 0 // dont show system tables
#define DEFAULT_LIE 0 #define DEFAULT_LIE 0
......
...@@ -47,6 +47,7 @@ RETCODE SQL_API SQLDriverConnect( ...@@ -47,6 +47,7 @@ RETCODE SQL_API SQLDriverConnect(
SWORD FAR *pcbConnStrOut, SWORD FAR *pcbConnStrOut,
UWORD fDriverCompletion) UWORD fDriverCompletion)
{ {
char *func = "SQLDriverConnect";
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci; ConnInfo *ci;
RETCODE dialog_result; RETCODE dialog_result;
...@@ -56,8 +57,10 @@ char password_required = FALSE; ...@@ -56,8 +57,10 @@ char password_required = FALSE;
mylog("**** SQLDriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, szConnStrIn); mylog("**** SQLDriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, szConnStrIn);
if ( ! conn) if ( ! conn) {
CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
qlog("conn=%u, SQLDriverConnect( in)='%s'\n", conn, szConnStrIn); qlog("conn=%u, SQLDriverConnect( in)='%s'\n", conn, szConnStrIn);
...@@ -135,8 +138,10 @@ dialog: ...@@ -135,8 +138,10 @@ dialog:
// do the actual connect // do the actual connect
retval = CC_connect(conn, password_required); retval = CC_connect(conn, password_required);
if (retval < 0) { /* need a password */ 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 */ return SQL_ERROR; /* need a password but not allowed to prompt so error */
}
else { else {
password_required = TRUE; password_required = TRUE;
goto dialog; goto dialog;
...@@ -144,6 +149,7 @@ dialog: ...@@ -144,6 +149,7 @@ dialog:
} }
else if (retval == 0) { else if (retval == 0) {
// error msg filled in above // error msg filled in above
CC_log_error(func, "Error from CC_Connect", conn);
return SQL_ERROR; return SQL_ERROR;
} }
......
...@@ -25,11 +25,14 @@ ConnectionClass *conns[MAX_CONNECTIONS]; ...@@ -25,11 +25,14 @@ ConnectionClass *conns[MAX_CONNECTIONS];
RETCODE SQL_API SQLAllocEnv(HENV FAR *phenv) RETCODE SQL_API SQLAllocEnv(HENV FAR *phenv)
{ {
char *func = "SQLAllocEnv";
mylog("**** in SQLAllocEnv ** \n"); mylog("**** in SQLAllocEnv ** \n");
*phenv = (HENV) EN_Constructor(); *phenv = (HENV) EN_Constructor();
if ( ! *phenv) { if ( ! *phenv) {
*phenv = SQL_NULL_HENV; *phenv = SQL_NULL_HENV;
EN_log_error(func, "Error allocating environment", NULL);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -39,6 +42,7 @@ mylog("**** in SQLAllocEnv ** \n"); ...@@ -39,6 +42,7 @@ mylog("**** in SQLAllocEnv ** \n");
RETCODE SQL_API SQLFreeEnv(HENV henv) RETCODE SQL_API SQLFreeEnv(HENV henv)
{ {
char *func = "SQLFreeEnv";
EnvironmentClass *env = (EnvironmentClass *) henv; EnvironmentClass *env = (EnvironmentClass *) henv;
mylog("**** in SQLFreeEnv: env = %u ** \n", env); mylog("**** in SQLFreeEnv: env = %u ** \n", env);
...@@ -49,6 +53,7 @@ mylog("**** in SQLFreeEnv: env = %u ** \n", env); ...@@ -49,6 +53,7 @@ mylog("**** in SQLFreeEnv: env = %u ** \n", env);
} }
mylog(" error\n"); mylog(" error\n");
EN_log_error(func, "Error freeing environment", env);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -73,9 +78,6 @@ int status; ...@@ -73,9 +78,6 @@ int status;
// CC: return an error of a hstmt // CC: return an error of a hstmt
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
if (NULL == stmt)
return SQL_INVALID_HANDLE;
if (SC_get_error(stmt, &status, &msg)) { if (SC_get_error(stmt, &status, &msg)) {
mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg); mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg);
if (NULL == msg) { if (NULL == msg) {
...@@ -424,3 +426,13 @@ int i; ...@@ -424,3 +426,13 @@ int i;
return FALSE; 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);
}
...@@ -29,5 +29,6 @@ char EN_Destructor(EnvironmentClass *self); ...@@ -29,5 +29,6 @@ char EN_Destructor(EnvironmentClass *self);
char EN_get_error(EnvironmentClass *self, int *number, char **message); char EN_get_error(EnvironmentClass *self, int *number, char **message);
char EN_add_connection(EnvironmentClass *self, ConnectionClass *conn); char EN_add_connection(EnvironmentClass *self, ConnectionClass *conn);
char EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn); char EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn);
void EN_log_error(char *func, char *desc, EnvironmentClass *self);
#endif #endif
...@@ -32,10 +32,13 @@ RETCODE SQL_API SQLPrepare(HSTMT hstmt, ...@@ -32,10 +32,13 @@ RETCODE SQL_API SQLPrepare(HSTMT hstmt,
UCHAR FAR *szSqlStr, UCHAR FAR *szSqlStr,
SDWORD cbSqlStr) SDWORD cbSqlStr)
{ {
char *func = "SQLPrepare";
StatementClass *self = (StatementClass *) hstmt; StatementClass *self = (StatementClass *) hstmt;
if ( ! self) if ( ! self) {
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
/* According to the ODBC specs it is valid to call SQLPrepare mulitple times. /* 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 In that case, the bound SQL statement is replaced by the new one
...@@ -66,12 +69,14 @@ StatementClass *self = (StatementClass *) hstmt; ...@@ -66,12 +69,14 @@ StatementClass *self = (StatementClass *) hstmt;
self->errornumber = STMT_SEQUENCE_ERROR; self->errornumber = STMT_SEQUENCE_ERROR;
self->errormsg = "SQLPrepare(): The handle does not point to a statement that is ready to be executed"; 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; return SQL_ERROR;
default: default:
self->errornumber = STMT_INTERNAL_ERROR; self->errornumber = STMT_INTERNAL_ERROR;
self->errormsg = "An Internal Error has occured -- Unknown statement status."; self->errormsg = "An Internal Error has occured -- Unknown statement status.";
SC_log_error(func, "", self);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -82,6 +87,7 @@ StatementClass *self = (StatementClass *) hstmt; ...@@ -82,6 +87,7 @@ StatementClass *self = (StatementClass *) hstmt;
if ( ! self->statement) { if ( ! self->statement) {
self->errornumber = STMT_NO_MEMORY_ERROR; self->errornumber = STMT_NO_MEMORY_ERROR;
self->errormsg = "No memory available to store statement"; self->errormsg = "No memory available to store statement";
SC_log_error(func, "", self);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -92,6 +98,7 @@ StatementClass *self = (StatementClass *) hstmt; ...@@ -92,6 +98,7 @@ StatementClass *self = (StatementClass *) hstmt;
if ( CC_is_readonly(self->hdbc) && STMT_UPDATE(self)) { if ( CC_is_readonly(self->hdbc) && STMT_UPDATE(self)) {
self->errornumber = STMT_EXEC_ERROR; self->errornumber = STMT_EXEC_ERROR;
self->errormsg = "Connection is readonly, only select statements are allowed."; self->errormsg = "Connection is readonly, only select statements are allowed.";
SC_log_error(func, "", self);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -110,9 +117,12 @@ RETCODE SQL_API SQLExecDirect( ...@@ -110,9 +117,12 @@ RETCODE SQL_API SQLExecDirect(
SDWORD cbSqlStr) SDWORD cbSqlStr)
{ {
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
char *func = "SQLExecDirect";
if ( ! stmt) if ( ! stmt) {
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
if (stmt->statement) if (stmt->statement)
free(stmt->statement); free(stmt->statement);
...@@ -123,6 +133,7 @@ StatementClass *stmt = (StatementClass *) hstmt; ...@@ -123,6 +133,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
if ( ! stmt->statement) { if ( ! stmt->statement) {
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "No memory available to store statement"; stmt->errormsg = "No memory available to store statement";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -135,6 +146,7 @@ StatementClass *stmt = (StatementClass *) hstmt; ...@@ -135,6 +146,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
if ( CC_is_readonly(stmt->hdbc) && STMT_UPDATE(stmt)) { if ( CC_is_readonly(stmt->hdbc) && STMT_UPDATE(stmt)) {
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Connection is readonly, only select statements are allowed."; stmt->errormsg = "Connection is readonly, only select statements are allowed.";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -147,13 +159,16 @@ StatementClass *stmt = (StatementClass *) hstmt; ...@@ -147,13 +159,16 @@ StatementClass *stmt = (StatementClass *) hstmt;
RETCODE SQL_API SQLExecute( RETCODE SQL_API SQLExecute(
HSTMT hstmt) HSTMT hstmt)
{ {
char *func="SQLExecute";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn; ConnectionClass *conn;
int i, retval; int i, retval;
if ( ! stmt) if ( ! stmt) {
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
/* If the statement is premature, it means we already executed /* If the statement is premature, it means we already executed
it from an SQLPrepare/SQLDescribeCol type of scenario. So it from an SQLPrepare/SQLDescribeCol type of scenario. So
...@@ -161,7 +176,12 @@ int i, retval; ...@@ -161,7 +176,12 @@ int i, retval;
*/ */
if ( stmt->prepare && stmt->status == STMT_PREMATURE) { if ( stmt->prepare && stmt->status == STMT_PREMATURE) {
stmt->status = STMT_FINISHED; 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); SC_clear_error(stmt);
...@@ -170,12 +190,14 @@ int i, retval; ...@@ -170,12 +190,14 @@ int i, retval;
if (conn->status == CONN_EXECUTING) { if (conn->status == CONN_EXECUTING) {
stmt->errormsg = "Connection is already in use."; stmt->errormsg = "Connection is already in use.";
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
if ( ! stmt->statement) { if ( ! stmt->statement) {
stmt->errornumber = STMT_NO_STMTSTRING; stmt->errornumber = STMT_NO_STMTSTRING;
stmt->errormsg = "This handle does not have a SQL statement stored in it"; stmt->errormsg = "This handle does not have a SQL statement stored in it";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -193,6 +215,7 @@ int i, retval; ...@@ -193,6 +215,7 @@ int i, retval;
stmt->errornumber = STMT_STATUS_ERROR; stmt->errornumber = STMT_STATUS_ERROR;
stmt->errormsg = "The handle does not point to a statement that is ready to be executed"; stmt->errormsg = "The handle does not point to a statement that is ready to be executed";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -240,6 +263,7 @@ RETCODE SQL_API SQLTransact( ...@@ -240,6 +263,7 @@ RETCODE SQL_API SQLTransact(
HDBC hdbc, HDBC hdbc,
UWORD fType) UWORD fType)
{ {
char *func = "SQLTransact";
extern ConnectionClass *conns[]; extern ConnectionClass *conns[];
ConnectionClass *conn; ConnectionClass *conn;
QResultClass *res; QResultClass *res;
...@@ -248,8 +272,10 @@ int lf; ...@@ -248,8 +272,10 @@ int lf;
mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv); 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; return SQL_INVALID_HANDLE;
}
/* If hdbc is null and henv is valid, /* If hdbc is null and henv is valid,
it means transact all connections on that henv. it means transact all connections on that henv.
...@@ -277,6 +303,7 @@ mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv); ...@@ -277,6 +303,7 @@ mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv);
} else { } else {
conn->errornumber = CONN_INVALID_ARGUMENT_NO; conn->errornumber = CONN_INVALID_ARGUMENT_NO;
conn->errormsg ="SQLTransact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter"; conn->errormsg ="SQLTransact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter";
CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -288,16 +315,20 @@ mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv); ...@@ -288,16 +315,20 @@ mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv);
res = CC_send_query(conn, stmt_string, NULL, NULL); res = CC_send_query(conn, stmt_string, NULL, NULL);
CC_set_no_trans(conn); CC_set_no_trans(conn);
if ( ! res) if ( ! res) {
// error msg will be in the connection // error msg will be in the connection
CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
}
ok = QR_command_successful(res); ok = QR_command_successful(res);
QR_Destructor(res); QR_Destructor(res);
if (!ok) if (!ok) {
CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
} }
}
return SQL_SUCCESS; return SQL_SUCCESS;
} }
...@@ -307,11 +338,14 @@ mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv); ...@@ -307,11 +338,14 @@ mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv);
RETCODE SQL_API SQLCancel( RETCODE SQL_API SQLCancel(
HSTMT hstmt) // Statement to cancel. HSTMT hstmt) // Statement to cancel.
{ {
char *func="SQLCancel";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
// Check if this can handle canceling in the middle of a SQLPutData? // 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; return SQL_INVALID_HANDLE;
}
// Not in the middle of SQLParamData/SQLPutData so cancel like a close. // Not in the middle of SQLParamData/SQLPutData so cancel like a close.
if (stmt->data_at_exec < 0) if (stmt->data_at_exec < 0)
...@@ -354,11 +388,14 @@ RETCODE SQL_API SQLParamData( ...@@ -354,11 +388,14 @@ RETCODE SQL_API SQLParamData(
HSTMT hstmt, HSTMT hstmt,
PTR FAR *prgbValue) PTR FAR *prgbValue)
{ {
char *func = "SQLParamData";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
int i, retval; int i, retval;
if ( ! stmt) if ( ! stmt) {
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
mylog("SQLParamData, enter: data_at_exec=%d, params_alloc=%d\n", mylog("SQLParamData, enter: data_at_exec=%d, params_alloc=%d\n",
stmt->data_at_exec, stmt->parameters_allocated); stmt->data_at_exec, stmt->parameters_allocated);
...@@ -366,12 +403,14 @@ int i, retval; ...@@ -366,12 +403,14 @@ int i, retval;
if (stmt->data_at_exec < 0) { if (stmt->data_at_exec < 0) {
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "No execution-time parameters for this statement"; stmt->errormsg = "No execution-time parameters for this statement";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
if (stmt->data_at_exec > stmt->parameters_allocated) { if (stmt->data_at_exec > stmt->parameters_allocated) {
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "Too many execution-time parameters were present"; stmt->errormsg = "Too many execution-time parameters were present";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -422,19 +461,23 @@ RETCODE SQL_API SQLPutData( ...@@ -422,19 +461,23 @@ RETCODE SQL_API SQLPutData(
PTR rgbValue, PTR rgbValue,
SDWORD cbValue) SDWORD cbValue)
{ {
char *func = "SQLPutData";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
int old_pos, retval; int old_pos, retval;
ParameterInfoClass *current_param; ParameterInfoClass *current_param;
char *buffer; char *buffer;
if ( ! stmt) if ( ! stmt) {
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
if (stmt->current_exec_param < 0) { if (stmt->current_exec_param < 0) {
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "Previous call was not SQLPutData or SQLParamData"; stmt->errormsg = "Previous call was not SQLPutData or SQLParamData";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -450,6 +493,7 @@ char *buffer; ...@@ -450,6 +493,7 @@ char *buffer;
if ( ! current_param->EXEC_used) { if ( ! current_param->EXEC_used) {
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (1)"; stmt->errormsg = "Out of memory in SQLPutData (1)";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -467,6 +511,7 @@ char *buffer; ...@@ -467,6 +511,7 @@ char *buffer;
if (current_param->lobj_oid == 0) { if (current_param->lobj_oid == 0) {
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Couldnt create large object."; stmt->errormsg = "Couldnt create large object.";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -479,6 +524,7 @@ char *buffer; ...@@ -479,6 +524,7 @@ char *buffer;
if ( stmt->lobj_fd < 0) { if ( stmt->lobj_fd < 0) {
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Couldnt open large object for writing."; stmt->errormsg = "Couldnt open large object for writing.";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -493,6 +539,7 @@ char *buffer; ...@@ -493,6 +539,7 @@ char *buffer;
if ( ! current_param->EXEC_buffer) { if ( ! current_param->EXEC_buffer) {
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (2)"; stmt->errormsg = "Out of memory in SQLPutData (2)";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
} }
...@@ -501,6 +548,7 @@ char *buffer; ...@@ -501,6 +548,7 @@ char *buffer;
if ( ! current_param->EXEC_buffer) { if ( ! current_param->EXEC_buffer) {
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (2)"; stmt->errormsg = "Out of memory in SQLPutData (2)";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
memcpy(current_param->EXEC_buffer, rgbValue, cbValue); memcpy(current_param->EXEC_buffer, rgbValue, cbValue);
...@@ -530,6 +578,7 @@ char *buffer; ...@@ -530,6 +578,7 @@ char *buffer;
if ( ! buffer) { if ( ! buffer) {
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (3)"; stmt->errormsg = "Out of memory in SQLPutData (3)";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
strcat(buffer, rgbValue); strcat(buffer, rgbValue);
...@@ -555,6 +604,7 @@ char *buffer; ...@@ -555,6 +604,7 @@ char *buffer;
if ( ! buffer) { if ( ! buffer) {
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (3)"; stmt->errormsg = "Out of memory in SQLPutData (3)";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -565,8 +615,10 @@ char *buffer; ...@@ -565,8 +615,10 @@ char *buffer;
current_param->EXEC_buffer = buffer; current_param->EXEC_buffer = buffer;
} }
else else {
SC_log_error(func, "bad cbValue", stmt);
return SQL_ERROR; return SQL_ERROR;
}
} }
} }
......
This diff is collapsed.
...@@ -31,10 +31,14 @@ RETCODE SQL_API SQLSetConnectOption( ...@@ -31,10 +31,14 @@ RETCODE SQL_API SQLSetConnectOption(
UWORD fOption, UWORD fOption,
UDWORD vParam) UDWORD vParam)
{ {
char *func="SQLSetConnectOption";
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
if ( ! conn) if ( ! conn) {
CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
switch (fOption) { switch (fOption) {
case SQL_AUTOCOMMIT: case SQL_AUTOCOMMIT:
...@@ -46,6 +50,7 @@ ConnectionClass *conn = (ConnectionClass *) hdbc; ...@@ -46,6 +50,7 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
if (CC_is_in_trans(conn)) { if (CC_is_in_trans(conn)) {
conn->errormsg = "Cannot switch commit mode while a transaction is in progres"; conn->errormsg = "Cannot switch commit mode while a transaction is in progres";
conn->errornumber = CONN_TRANSACT_IN_PROGRES; conn->errornumber = CONN_TRANSACT_IN_PROGRES;
CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
} }
*/ */
...@@ -64,6 +69,7 @@ ConnectionClass *conn = (ConnectionClass *) hdbc; ...@@ -64,6 +69,7 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
default: default:
conn->errormsg = "Illegal parameter value for SQL_AUTOCOMMIT"; conn->errormsg = "Illegal parameter value for SQL_AUTOCOMMIT";
conn->errornumber = CONN_INVALID_ARGUMENT_NO; conn->errornumber = CONN_INVALID_ARGUMENT_NO;
CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -76,9 +82,14 @@ ConnectionClass *conn = (ConnectionClass *) hdbc; ...@@ -76,9 +82,14 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
break; break;
default: default:
{
char option[32];
conn->errormsg = "This option is currently unsupported by the driver"; conn->errormsg = "This option is currently unsupported by the driver";
conn->errornumber = CONN_UNSUPPORTED_OPTION; conn->errornumber = CONN_UNSUPPORTED_OPTION;
sprintf(option, "fOption=%d", fOption);
CC_log_error(func, option, conn);
return SQL_ERROR; return SQL_ERROR;
}
} }
return SQL_SUCCESS; return SQL_SUCCESS;
...@@ -92,10 +103,13 @@ RETCODE SQL_API SQLGetConnectOption( ...@@ -92,10 +103,13 @@ RETCODE SQL_API SQLGetConnectOption(
UWORD fOption, UWORD fOption,
PTR pvParam) PTR pvParam)
{ {
char *func="SQLGetConnectOption";
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
if (! conn) if (! conn) {
CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
switch (fOption) { switch (fOption) {
case SQL_AUTOCOMMIT: case SQL_AUTOCOMMIT:
...@@ -111,10 +125,15 @@ ConnectionClass *conn = (ConnectionClass *) hdbc; ...@@ -111,10 +125,15 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
break; break;
default: default:
{
char option[32];
conn->errormsg = "This option is currently unsupported by the driver"; conn->errormsg = "This option is currently unsupported by the driver";
conn->errornumber = CONN_UNSUPPORTED_OPTION; conn->errornumber = CONN_UNSUPPORTED_OPTION;
sprintf(option, "fOption=%d", fOption);
CC_log_error(func, option, conn);
return SQL_ERROR; return SQL_ERROR;
break; break;
}
} }
...@@ -128,6 +147,7 @@ RETCODE SQL_API SQLSetStmtOption( ...@@ -128,6 +147,7 @@ RETCODE SQL_API SQLSetStmtOption(
UWORD fOption, UWORD fOption,
UDWORD vParam) UDWORD vParam)
{ {
char *func="SQLSetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
char changed = FALSE; char changed = FALSE;
...@@ -135,8 +155,10 @@ 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 // 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 // and expects the driver to reduce it to the real value
if( ! stmt) if( ! stmt) {
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
switch(fOption) { switch(fOption) {
case SQL_QUERY_TIMEOUT: case SQL_QUERY_TIMEOUT:
...@@ -170,6 +192,7 @@ char changed = FALSE; ...@@ -170,6 +192,7 @@ char changed = FALSE;
else { else {
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Driver does not support keyset size option"; stmt->errormsg = "Driver does not support keyset size option";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
break; break;
...@@ -214,13 +237,19 @@ char changed = FALSE; ...@@ -214,13 +237,19 @@ char changed = FALSE;
case SQL_SIMULATE_CURSOR: case SQL_SIMULATE_CURSOR:
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Simulated positioned update/delete not supported. Use the cursor library."; stmt->errormsg = "Simulated positioned update/delete not supported. Use the cursor library.";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
default: default:
{
char option[32];
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Driver does not support this statement option"; 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_ERROR;
} }
}
if (changed) { if (changed) {
stmt->errormsg = "Requested value changed."; stmt->errormsg = "Requested value changed.";
...@@ -239,14 +268,17 @@ RETCODE SQL_API SQLGetStmtOption( ...@@ -239,14 +268,17 @@ RETCODE SQL_API SQLGetStmtOption(
UWORD fOption, UWORD fOption,
PTR pvParam) PTR pvParam)
{ {
char *func="SQLGetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
// thought we could fake Access out by just returning SQL_SUCCESS // 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 // 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 // and expects the driver to reduce it to the real value
if( ! stmt) if( ! stmt) {
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
switch(fOption) { switch(fOption) {
case SQL_QUERY_TIMEOUT: case SQL_QUERY_TIMEOUT:
...@@ -289,13 +321,19 @@ StatementClass *stmt = (StatementClass *) hstmt; ...@@ -289,13 +321,19 @@ StatementClass *stmt = (StatementClass *) hstmt;
case SQL_SIMULATE_CURSOR: case SQL_SIMULATE_CURSOR:
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Simulated positioned update/delete not supported. Use the cursor library."; stmt->errormsg = "Simulated positioned update/delete not supported. Use the cursor library.";
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
default: default:
{
char option[32];
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Driver does not support this statement option"; 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_ERROR;
} }
}
return SQL_SUCCESS; return SQL_SUCCESS;
} }
......
...@@ -46,7 +46,9 @@ Int4 pgtypes_defined[] = { ...@@ -46,7 +46,9 @@ Int4 pgtypes_defined[] = {
PG_TYPE_BPCHAR, PG_TYPE_BPCHAR,
PG_TYPE_DATE, PG_TYPE_DATE,
PG_TYPE_TIME, PG_TYPE_TIME,
PG_TYPE_DATETIME,
PG_TYPE_ABSTIME, /* a timestamp, sort of */ PG_TYPE_ABSTIME, /* a timestamp, sort of */
PG_TYPE_TIMESTAMP,
PG_TYPE_TEXT, PG_TYPE_TEXT,
PG_TYPE_INT2, PG_TYPE_INT2,
PG_TYPE_INT4, PG_TYPE_INT4,
...@@ -55,7 +57,6 @@ Int4 pgtypes_defined[] = { ...@@ -55,7 +57,6 @@ Int4 pgtypes_defined[] = {
PG_TYPE_OID, PG_TYPE_OID,
PG_TYPE_MONEY, PG_TYPE_MONEY,
PG_TYPE_BOOL, PG_TYPE_BOOL,
PG_TYPE_DATETIME,
PG_TYPE_BYTEA, PG_TYPE_BYTEA,
PG_TYPE_LO, PG_TYPE_LO,
0 }; 0 };
...@@ -97,7 +98,8 @@ Int2 pgtype_to_sqltype(StatementClass *stmt, Int4 type) ...@@ -97,7 +98,8 @@ Int2 pgtype_to_sqltype(StatementClass *stmt, Int4 type)
case PG_TYPE_DATE: return SQL_DATE; case PG_TYPE_DATE: return SQL_DATE;
case PG_TYPE_TIME: return SQL_TIME; case PG_TYPE_TIME: return SQL_TIME;
case PG_TYPE_ABSTIME: 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_MONEY: return SQL_FLOAT;
case PG_TYPE_BOOL: return globals.bools_as_char ? SQL_CHAR : SQL_BIT; 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) ...@@ -124,7 +126,8 @@ Int2 pgtype_to_ctype(StatementClass *stmt, Int4 type)
case PG_TYPE_DATE: return SQL_C_DATE; case PG_TYPE_DATE: return SQL_C_DATE;
case PG_TYPE_TIME: return SQL_C_TIME; case PG_TYPE_TIME: return SQL_C_TIME;
case PG_TYPE_ABSTIME: 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_MONEY: return SQL_C_FLOAT;
case PG_TYPE_BOOL: return globals.bools_as_char ? SQL_C_CHAR : SQL_C_BIT; 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) ...@@ -161,6 +164,7 @@ char *pgtype_to_name(StatementClass *stmt, Int4 type)
case PG_TYPE_TIME: return "time"; case PG_TYPE_TIME: return "time";
case PG_TYPE_ABSTIME: return "abstime"; case PG_TYPE_ABSTIME: return "abstime";
case PG_TYPE_DATETIME: return "datetime"; case PG_TYPE_DATETIME: return "datetime";
case PG_TYPE_TIMESTAMP: return "timestamp";
case PG_TYPE_MONEY: return "money"; case PG_TYPE_MONEY: return "money";
case PG_TYPE_BOOL: return "bool"; case PG_TYPE_BOOL: return "bool";
case PG_TYPE_BYTEA: return "bytea"; case PG_TYPE_BYTEA: return "bytea";
...@@ -269,7 +273,8 @@ Int4 pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unkno ...@@ -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_TIME: return 8;
case PG_TYPE_ABSTIME: 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_BOOL: return 1;
...@@ -327,7 +332,8 @@ Int4 pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_ ...@@ -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_TIME: return 6;
case PG_TYPE_ABSTIME: 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 */ /* Character types use the default precision */
...@@ -350,7 +356,8 @@ Int2 pgtype_scale(StatementClass *stmt, Int4 type) ...@@ -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...]" */ /* 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_ABSTIME:
case PG_TYPE_DATETIME: return 0; case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP: return 0;
default: return -1; default: return -1;
} }
...@@ -391,7 +398,8 @@ Int2 pgtype_auto_increment(StatementClass *stmt, Int4 type) ...@@ -391,7 +398,8 @@ Int2 pgtype_auto_increment(StatementClass *stmt, Int4 type)
case PG_TYPE_DATE: case PG_TYPE_DATE:
case PG_TYPE_TIME: case PG_TYPE_TIME:
case PG_TYPE_ABSTIME: case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME: return FALSE; case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP: return FALSE;
default: return -1; default: return -1;
} }
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#define PG_TYPE_DATE 1082 #define PG_TYPE_DATE 1082
#define PG_TYPE_TIME 1083 #define PG_TYPE_TIME 1083
#define PG_TYPE_DATETIME 1184 #define PG_TYPE_DATETIME 1184
#define PG_TYPE_TIMESTAMP 1296
extern Int4 pgtypes_defined[]; extern Int4 pgtypes_defined[];
......
...@@ -50,8 +50,8 @@ typedef UInt4 Oid; ...@@ -50,8 +50,8 @@ typedef UInt4 Oid;
/* Driver stuff */ /* Driver stuff */
#define DRIVERNAME "PostgreSQL ODBC" #define DRIVERNAME "PostgreSQL ODBC"
#define DBMS_NAME "PostgreSQL" #define DBMS_NAME "PostgreSQL"
#define DBMS_VERSION "06.30.0244 PostgreSQL 6.3" #define DBMS_VERSION "06.30.0246 PostgreSQL 6.3"
#define POSTGRESDRIVERVERSION "06.30.0244" #define POSTGRESDRIVERVERSION "06.30.0246"
#define DRIVER_FILE_NAME "PSQLODBC.DLL" #define DRIVER_FILE_NAME "PSQLODBC.DLL"
......
...@@ -137,6 +137,8 @@ BEGIN ...@@ -137,6 +137,8 @@ BEGIN
WS_TABSTOP,130,10,60,14 WS_TABSTOP,130,10,60,14
CONTROL "Show System &Tables",DS_SHOWSYSTEMTABLES,"Button", CONTROL "Show System &Tables",DS_SHOWSYSTEMTABLES,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,25,30,85,10 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 GROUPBOX "OID Options",IDC_STATIC,15,50,180,25
CONTROL "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX | CONTROL "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX |
WS_GROUP | WS_TABSTOP,25,60,59,10 WS_GROUP | WS_TABSTOP,25,60,59,10
...@@ -198,8 +200,8 @@ END ...@@ -198,8 +200,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 6,30,2,44 FILEVERSION 6,30,2,46
PRODUCTVERSION 6,30,2,44 PRODUCTVERSION 6,30,2,46
FILEFLAGSMASK 0x3L FILEFLAGSMASK 0x3L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
...@@ -217,12 +219,12 @@ BEGIN ...@@ -217,12 +219,12 @@ BEGIN
VALUE "Comments", "PostgreSQL ODBC driver for Windows 95\0" VALUE "Comments", "PostgreSQL ODBC driver for Windows 95\0"
VALUE "CompanyName", "Insight Distribution Systems\0" VALUE "CompanyName", "Insight Distribution Systems\0"
VALUE "FileDescription", "PostgreSQL Driver\0" VALUE "FileDescription", "PostgreSQL Driver\0"
VALUE "FileVersion", " 6.30.0244\0" VALUE "FileVersion", " 6.30.0246\0"
VALUE "InternalName", "psqlodbc\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 "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 "OriginalFilename", "psqlodbc.dll\0"
VALUE "ProductName", "Microsoft Open Database Connectivity\0" VALUE "ProductName", "Microsoft Open Database Connectivity\0"
VALUE "ProductVersion", " 6.30.0244\0" VALUE "ProductVersion", " 6.30.0246\0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#define DRV_BOOLS_CHAR 1050 #define DRV_BOOLS_CHAR 1050
#define DS_SHOWSYSTEMTABLES 1051 #define DS_SHOWSYSTEMTABLES 1051
#define DRV_EXTRASYSTABLEPREFIXES 1051 #define DRV_EXTRASYSTABLEPREFIXES 1051
#define DS_ROWVERSIONING 1052
// Next default values for new objects // Next default values for new objects
// //
......
This diff is collapsed.
...@@ -46,11 +46,14 @@ static struct { ...@@ -46,11 +46,14 @@ static struct {
RETCODE SQL_API SQLAllocStmt(HDBC hdbc, RETCODE SQL_API SQLAllocStmt(HDBC hdbc,
HSTMT FAR *phstmt) HSTMT FAR *phstmt)
{ {
char *func="SQLAllocStmt";
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
StatementClass *stmt; StatementClass *stmt;
if( ! conn) if( ! conn) {
CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
stmt = SC_Constructor(); stmt = SC_Constructor();
...@@ -60,12 +63,14 @@ StatementClass *stmt; ...@@ -60,12 +63,14 @@ StatementClass *stmt;
conn->errornumber = CONN_STMT_ALLOC_ERROR; conn->errornumber = CONN_STMT_ALLOC_ERROR;
conn->errormsg = "No more memory to allocate a further SQL-statement"; conn->errormsg = "No more memory to allocate a further SQL-statement";
*phstmt = SQL_NULL_HSTMT; *phstmt = SQL_NULL_HSTMT;
CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
} }
if ( ! CC_add_statement(conn, stmt)) { if ( ! CC_add_statement(conn, stmt)) {
conn->errormsg = "Maximum number of connections exceeded."; conn->errormsg = "Maximum number of connections exceeded.";
conn->errornumber = CONN_STMT_ALLOC_ERROR; conn->errornumber = CONN_STMT_ALLOC_ERROR;
CC_log_error(func, "", conn);
SC_Destructor(stmt); SC_Destructor(stmt);
*phstmt = SQL_NULL_HSTMT; *phstmt = SQL_NULL_HSTMT;
return SQL_ERROR; return SQL_ERROR;
...@@ -80,12 +85,15 @@ StatementClass *stmt; ...@@ -80,12 +85,15 @@ StatementClass *stmt;
RETCODE SQL_API SQLFreeStmt(HSTMT hstmt, RETCODE SQL_API SQLFreeStmt(HSTMT hstmt,
UWORD fOption) UWORD fOption)
{ {
char *func="SQLFreeStmt";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
mylog("**** enter SQLFreeStmt: hstmt=%u, fOption=%d\n", hstmt, fOption); mylog("**** enter SQLFreeStmt: hstmt=%u, fOption=%d\n", hstmt, fOption);
if ( ! stmt) if ( ! stmt) {
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
}
if (fOption == SQL_DROP) { if (fOption == SQL_DROP) {
ConnectionClass *conn = stmt->hdbc; ConnectionClass *conn = stmt->hdbc;
...@@ -95,6 +103,7 @@ StatementClass *stmt = (StatementClass *) hstmt; ...@@ -95,6 +103,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
if ( ! CC_remove_statement(conn, stmt)) { if ( ! CC_remove_statement(conn, stmt)) {
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "Statement is currently executing a transaction."; stmt->errormsg = "Statement is currently executing a transaction.";
SC_log_error(func, "", stmt);
return SQL_ERROR; /* stmt may be executing a transaction */ return SQL_ERROR; /* stmt may be executing a transaction */
} }
...@@ -116,9 +125,11 @@ StatementClass *stmt = (StatementClass *) hstmt; ...@@ -116,9 +125,11 @@ StatementClass *stmt = (StatementClass *) hstmt;
/* this should discard all the results, but leave the statement */ /* this should discard all the results, but leave the statement */
/* itself in place (it can be executed again) */ /* itself in place (it can be executed again) */
if (!SC_recycle_statement(stmt)) if (!SC_recycle_statement(stmt)) {
// errormsg passed in above // errormsg passed in above
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
}
} else if(fOption == SQL_RESET_PARAMS) { } else if(fOption == SQL_RESET_PARAMS) {
SC_free_params(stmt, STMT_FREE_PARAMS_ALL); SC_free_params(stmt, STMT_FREE_PARAMS_ALL);
...@@ -126,6 +137,7 @@ StatementClass *stmt = (StatementClass *) hstmt; ...@@ -126,6 +137,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
} else { } else {
stmt->errormsg = "Invalid option passed to SQLFreeStmt."; stmt->errormsg = "Invalid option passed to SQLFreeStmt.";
stmt->errornumber = STMT_OPTION_OUT_OF_RANGE_ERROR; stmt->errornumber = STMT_OPTION_OUT_OF_RANGE_ERROR;
SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -447,6 +459,7 @@ char rv; ...@@ -447,6 +459,7 @@ char rv;
RETCODE SC_execute(StatementClass *self) RETCODE SC_execute(StatementClass *self)
{ {
char *func="SC_execute";
ConnectionClass *conn; ConnectionClass *conn;
QResultClass *res; QResultClass *res;
char ok, was_ok, was_nonfatal; char ok, was_ok, was_nonfatal;
...@@ -466,6 +479,7 @@ Int2 oldstatus, numcols; ...@@ -466,6 +479,7 @@ Int2 oldstatus, numcols;
if ( ! res) { if ( ! res) {
self->errormsg = "Could not begin a transaction"; self->errormsg = "Could not begin a transaction";
self->errornumber = STMT_EXEC_ERROR; self->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", self);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -478,6 +492,7 @@ Int2 oldstatus, numcols; ...@@ -478,6 +492,7 @@ Int2 oldstatus, numcols;
if (!ok) { if (!ok) {
self->errormsg = "Could not begin a transaction"; self->errormsg = "Could not begin a transaction";
self->errornumber = STMT_EXEC_ERROR; self->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", self);
return SQL_ERROR; return SQL_ERROR;
} }
else else
...@@ -554,6 +569,7 @@ Int2 oldstatus, numcols; ...@@ -554,6 +569,7 @@ Int2 oldstatus, numcols;
if (self->bindings == NULL) { if (self->bindings == NULL) {
self->errornumber = STMT_NO_MEMORY_ERROR; self->errornumber = STMT_NO_MEMORY_ERROR;
self->errormsg = "Could not get enough free memory to store the binding information"; self->errormsg = "Could not get enough free memory to store the binding information";
SC_log_error(func, "", self);
return SQL_ERROR; return SQL_ERROR;
} }
} }
...@@ -582,6 +598,43 @@ Int2 oldstatus, numcols; ...@@ -582,6 +598,43 @@ Int2 oldstatus, numcols;
else if (self->errornumber == STMT_INFO_ONLY) else if (self->errornumber == STMT_INFO_ONLY)
return SQL_SUCCESS_WITH_INFO; return SQL_SUCCESS_WITH_INFO;
else else {
SC_log_error(func, "", self);
return SQL_ERROR; 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);
} }
...@@ -132,5 +132,6 @@ char SC_get_error(StatementClass *self, int *number, char **message); ...@@ -132,5 +132,6 @@ char SC_get_error(StatementClass *self, int *number, char **message);
char *SC_create_errormsg(StatementClass *self); char *SC_create_errormsg(StatementClass *self);
RETCODE SC_execute(StatementClass *stmt); RETCODE SC_execute(StatementClass *stmt);
void SC_free_params(StatementClass *self, char option); void SC_free_params(StatementClass *self, char option);
void SC_log_error(char *func, char *desc, StatementClass *self);
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment