Update to v.0246
authorByron Nikolaidis
Tue, 16 Jun 1998 21:29:19 +0000 (21:29 +0000)
committerByron Nikolaidis
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; ibindings_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