]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Update to v.0246
authorByron Nikolaidis <byronn@insightdist.com>
Tue, 16 Jun 1998 21:29:19 +0000 (21:29 +0000)
committerByron Nikolaidis <byronn@insightdist.com>
Tue, 16 Jun 1998 21:29:19 +0000 (21:29 +0000)
20 files changed:
src/interfaces/odbc/bind.c
src/interfaces/odbc/connection.c
src/interfaces/odbc/connection.h
src/interfaces/odbc/convert.c
src/interfaces/odbc/dlg_specific.c
src/interfaces/odbc/dlg_specific.h
src/interfaces/odbc/drvconn.c
src/interfaces/odbc/environ.c
src/interfaces/odbc/environ.h
src/interfaces/odbc/execute.c
src/interfaces/odbc/info.c
src/interfaces/odbc/options.c
src/interfaces/odbc/pgtypes.c
src/interfaces/odbc/pgtypes.h
src/interfaces/odbc/psqlodbc.h
src/interfaces/odbc/psqlodbc.rc
src/interfaces/odbc/resource.h
src/interfaces/odbc/results.c
src/interfaces/odbc/statement.c
src/interfaces/odbc/statement.h

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