Mini update to fix SQLGetInfo to work properly (truncation, NULL)

This commit is contained in:
Byron Nikolaidis 1998-12-31 00:26:06 +00:00
parent 5df20d4449
commit bc9bab0390
6 changed files with 258 additions and 350 deletions

View File

@ -63,6 +63,7 @@ typedef enum {
#define CONN_UNABLE_TO_LOAD_DLL 212 #define CONN_UNABLE_TO_LOAD_DLL 212
#define CONN_OPTION_VALUE_CHANGED 213 #define CONN_OPTION_VALUE_CHANGED 213
#define CONN_VALUE_OUT_OF_RANGE 214
/* Conn_status defines */ /* Conn_status defines */
#define CONN_IN_AUTOCOMMIT 0x01 #define CONN_IN_AUTOCOMMIT 0x01

View File

@ -187,6 +187,9 @@ int status;
strcpy(szSqlState, "S1109"); strcpy(szSqlState, "S1109");
break; break;
case STMT_VALUE_OUT_OF_RANGE:
strcpy(szSqlState, "22003");
break;
default: default:
strcpy(szSqlState, "S1000"); strcpy(szSqlState, "S1000");
// also a general error // also a general error
@ -238,6 +241,10 @@ int status;
case CONN_OPTION_VALUE_CHANGED: case CONN_OPTION_VALUE_CHANGED:
strcpy(szSqlState, "01S02"); strcpy(szSqlState, "01S02");
break; break;
case STMT_TRUNCATED:
strcpy(szSqlState, "01004");
// data truncated
break;
case CONN_INIREAD_ERROR: case CONN_INIREAD_ERROR:
strcpy(szSqlState, "IM002"); strcpy(szSqlState, "IM002");
// data source not found // data source not found
@ -277,6 +284,12 @@ int status;
case STMT_NOT_IMPLEMENTED_ERROR: case STMT_NOT_IMPLEMENTED_ERROR:
strcpy(szSqlState, "S1C00"); strcpy(szSqlState, "S1C00");
break; break;
case CONN_VALUE_OUT_OF_RANGE:
case STMT_VALUE_OUT_OF_RANGE:
strcpy(szSqlState, "22003");
break;
default: default:
strcpy(szSqlState, "S1000"); strcpy(szSqlState, "S1000");
// general error // general error

View File

@ -69,7 +69,9 @@ RETCODE SQL_API SQLGetInfo(
static char *func = "SQLGetInfo"; static char *func = "SQLGetInfo";
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci; ConnInfo *ci;
char *p; char *p = NULL;
int len = 0, value = 0;
RETCODE result;
mylog( "%s: entering...fInfoType=%d\n", func, fInfoType); mylog( "%s: entering...fInfoType=%d\n", func, fInfoType);
@ -78,71 +80,46 @@ char *p;
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
if (NULL == (char *)rgbInfoValue) {
CC_log_error(func, "Bad rgbInfoValue", conn);
return SQL_INVALID_HANDLE;
}
ci = &conn->connInfo; ci = &conn->connInfo;
switch (fInfoType) { switch (fInfoType) {
case SQL_ACCESSIBLE_PROCEDURES: /* ODBC 1.0 */ case SQL_ACCESSIBLE_PROCEDURES: /* ODBC 1.0 */
// can the user call all functions returned by SQLProcedures? p = "N";
// I assume access permissions could prevent this in some cases(?)
// anyway, SQLProcedures doesn't exist yet.
if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break; break;
case SQL_ACCESSIBLE_TABLES: /* ODBC 1.0 */ case SQL_ACCESSIBLE_TABLES: /* ODBC 1.0 */
// is the user guaranteed "SELECT" on every table? p = "N";
if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break; break;
case SQL_ACTIVE_CONNECTIONS: /* ODBC 1.0 */ case SQL_ACTIVE_CONNECTIONS: /* ODBC 1.0 */
// how many simultaneous connections do we support? len = 2;
*((WORD *)rgbInfoValue) = MAX_CONNECTIONS; value = MAX_CONNECTIONS;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_ACTIVE_STATEMENTS: /* ODBC 1.0 */ case SQL_ACTIVE_STATEMENTS: /* ODBC 1.0 */
// no limit on the number of active statements. len = 2;
*((WORD *)rgbInfoValue) = (WORD)0; value = 0;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_ALTER_TABLE: /* ODBC 2.0 */ case SQL_ALTER_TABLE: /* ODBC 2.0 */
// what does 'alter table' support? (bitmask) len = 4;
// postgres doesn't seem to let you drop columns. value = SQL_AT_ADD_COLUMN;
*((DWORD *)rgbInfoValue) = SQL_AT_ADD_COLUMN;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_BOOKMARK_PERSISTENCE: /* ODBC 2.0 */ case SQL_BOOKMARK_PERSISTENCE: /* ODBC 2.0 */
// through what operations do bookmarks persist? (bitmask) len = 4;
// bookmarks don't exist yet, so they're not very persistent. value = 0;
*((DWORD *)rgbInfoValue) = 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_COLUMN_ALIAS: /* ODBC 2.0 */ case SQL_COLUMN_ALIAS: /* ODBC 2.0 */
// do we support column aliases? guess not. p = "N";
if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break; break;
case SQL_CONCAT_NULL_BEHAVIOR: /* ODBC 1.0 */ case SQL_CONCAT_NULL_BEHAVIOR: /* ODBC 1.0 */
// how does concatenation work with NULL columns? len = 2;
// not sure how you do concatentation, but this way seems value = SQL_CB_NON_NULL;
// more reasonable
*((WORD *)rgbInfoValue) = SQL_CB_NON_NULL;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
// which types of data-conversion do we support?
// currently we don't support any, except converting a type
// to itself.
case SQL_CONVERT_BIGINT: case SQL_CONVERT_BIGINT:
case SQL_CONVERT_BINARY: case SQL_CONVERT_BINARY:
case SQL_CONVERT_BIT: case SQL_CONVERT_BIT:
@ -162,570 +139,448 @@ char *p;
case SQL_CONVERT_TINYINT: case SQL_CONVERT_TINYINT:
case SQL_CONVERT_VARBINARY: case SQL_CONVERT_VARBINARY:
case SQL_CONVERT_VARCHAR: /* ODBC 1.0 */ case SQL_CONVERT_VARCHAR: /* ODBC 1.0 */
// only return the type we were called with (bitmask) len = 4;
*((DWORD *)rgbInfoValue) = fInfoType; value = fInfoType;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_CONVERT_FUNCTIONS: /* ODBC 1.0 */ case SQL_CONVERT_FUNCTIONS: /* ODBC 1.0 */
// which conversion functions do we support? (bitmask) len = 4;
*((DWORD *)rgbInfoValue) = 0; value = 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_CORRELATION_NAME: /* ODBC 1.0 */ case SQL_CORRELATION_NAME: /* ODBC 1.0 */
// I don't know what a correlation name is, so I guess we don't
// support them.
// *((WORD *)rgbInfoValue) = (WORD)SQL_CN_NONE;
// well, let's just say we do--otherwise Query won't work.
*((WORD *)rgbInfoValue) = (WORD)SQL_CN_ANY;
if(pcbInfoValue) { *pcbInfoValue = 2; }
/* Saying no correlation name makes Query not work right.
value = SQL_CN_NONE;
*/
len = 2;
value = SQL_CN_ANY;
break; break;
case SQL_CURSOR_COMMIT_BEHAVIOR: /* ODBC 1.0 */ case SQL_CURSOR_COMMIT_BEHAVIOR: /* ODBC 1.0 */
// postgres definitely closes cursors when a transaction ends, len = 2;
// but you shouldn't have to re-prepare a statement after value = SQL_CB_CLOSE;
// commiting a transaction (I don't think)
*((WORD *)rgbInfoValue) = (WORD)SQL_CB_CLOSE;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_CURSOR_ROLLBACK_BEHAVIOR: /* ODBC 1.0 */ case SQL_CURSOR_ROLLBACK_BEHAVIOR: /* ODBC 1.0 */
// see above len = 2;
*((WORD *)rgbInfoValue) = (WORD)SQL_CB_CLOSE; value = SQL_CB_CLOSE;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_DATA_SOURCE_NAME: /* ODBC 1.0 */ case SQL_DATA_SOURCE_NAME: /* ODBC 1.0 */
p = CC_get_DSN(conn); p = CC_get_DSN(conn);
if (pcbInfoValue) *pcbInfoValue = strlen(p);
strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
break; break;
case SQL_DATA_SOURCE_READ_ONLY: /* ODBC 1.0 */ case SQL_DATA_SOURCE_READ_ONLY: /* ODBC 1.0 */
if (pcbInfoValue) *pcbInfoValue = 1; p = CC_is_readonly(conn) ? "Y" : "N";
sprintf((char *)rgbInfoValue, "%c", CC_is_readonly(conn) ? 'Y' : 'N');
break; break;
case SQL_DATABASE_NAME: /* Support for old ODBC 1.0 Apps */ case SQL_DATABASE_NAME: /* Support for old ODBC 1.0 Apps */
// case SQL_CURRENT_QUALIFIER:
// this tag doesn't seem to be in ODBC 2.0, and it conflicts
// with a valid tag (SQL_TIMEDATE_ADD_INTERVALS).
/* Returning the database name causes problems in MS Query. /* Returning the database name causes problems in MS Query.
It generates query like: "SELECT DISTINCT a FROM byronncrap3 crap3" It generates query like: "SELECT DISTINCT a FROM byronncrap3 crap3"
p = CC_get_database(conn);
*/ */
p = ""; // CC_get_database(conn); p = "";
if (pcbInfoValue) *pcbInfoValue = strlen(p);
strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
break; break;
case SQL_DBMS_NAME: /* ODBC 1.0 */ case SQL_DBMS_NAME: /* ODBC 1.0 */
if (pcbInfoValue) *pcbInfoValue = strlen(DBMS_NAME); p = DBMS_NAME;
strncpy_null((char *)rgbInfoValue, DBMS_NAME, (size_t)cbInfoValueMax);
break; break;
case SQL_DBMS_VER: /* ODBC 1.0 */ case SQL_DBMS_VER: /* ODBC 1.0 */
if (pcbInfoValue) *pcbInfoValue = 25; p = DBMS_VERSION;
strncpy_null((char *)rgbInfoValue, DBMS_VERSION, (size_t)cbInfoValueMax);
break; break;
case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */ case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
// are dirty reads, non-repeatable reads, and phantoms possible? (bitmask) len = 4;
// by direct experimentation they are not. postgres forces value = SQL_TXN_READ_COMMITTED; //SQL_TXN_SERIALIZABLE;
// the newer transaction to wait before doing something that
// would cause one of these problems.
*((DWORD *)rgbInfoValue) = SQL_TXN_READ_COMMITTED; //SQL_TXN_SERIALIZABLE;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_DRIVER_NAME: /* ODBC 1.0 */ case SQL_DRIVER_NAME: /* ODBC 1.0 */
// this should be the actual filename of the driver
p = DRIVER_FILE_NAME; p = DRIVER_FILE_NAME;
if (pcbInfoValue) *pcbInfoValue = strlen(p);
strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
break; break;
case SQL_DRIVER_ODBC_VER: case SQL_DRIVER_ODBC_VER:
if (pcbInfoValue) *pcbInfoValue = 5; p = DRIVER_ODBC_VER;
strncpy_null((char *)rgbInfoValue, "02.00", (size_t)cbInfoValueMax);
break; break;
case SQL_DRIVER_VER: /* ODBC 1.0 */ case SQL_DRIVER_VER: /* ODBC 1.0 */
p = POSTGRESDRIVERVERSION; p = POSTGRESDRIVERVERSION;
if (pcbInfoValue) *pcbInfoValue = strlen(p);
strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
break; break;
case SQL_EXPRESSIONS_IN_ORDERBY: /* ODBC 1.0 */ case SQL_EXPRESSIONS_IN_ORDERBY: /* ODBC 1.0 */
// can you have expressions in an 'order by' clause? p = "N";
// not sure about this. say no for now.
if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break; break;
case SQL_FETCH_DIRECTION: /* ODBC 1.0 */ case SQL_FETCH_DIRECTION: /* ODBC 1.0 */
// which fetch directions are supported? (bitmask) len = 4;
*((DWORD *)rgbInfoValue) = globals.use_declarefetch ? (SQL_FD_FETCH_NEXT) : (SQL_FD_FETCH_NEXT | value = globals.use_declarefetch ? (SQL_FD_FETCH_NEXT) : (SQL_FD_FETCH_NEXT |
SQL_FD_FETCH_FIRST | SQL_FD_FETCH_FIRST |
SQL_FD_FETCH_LAST | SQL_FD_FETCH_LAST |
SQL_FD_FETCH_PRIOR | SQL_FD_FETCH_PRIOR |
SQL_FD_FETCH_ABSOLUTE | SQL_FD_FETCH_ABSOLUTE |
SQL_FD_FETCH_RELATIVE); SQL_FD_FETCH_RELATIVE);
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_FILE_USAGE: /* ODBC 2.0 */ case SQL_FILE_USAGE: /* ODBC 2.0 */
// we are a two-tier driver, not a file-based one. len = 2;
*((WORD *)rgbInfoValue) = (WORD)SQL_FILE_NOT_SUPPORTED; value = SQL_FILE_NOT_SUPPORTED;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_GETDATA_EXTENSIONS: /* ODBC 2.0 */ case SQL_GETDATA_EXTENSIONS: /* ODBC 2.0 */
// (bitmask) len = 4;
*((DWORD *)rgbInfoValue) = (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND | SQL_GD_BLOCK); value = (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND | SQL_GD_BLOCK);
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_GROUP_BY: /* ODBC 2.0 */ case SQL_GROUP_BY: /* ODBC 2.0 */
// how do the columns selected affect the columns you can group by? len = 2;
*((WORD *)rgbInfoValue) = SQL_GB_GROUP_BY_EQUALS_SELECT; value = SQL_GB_GROUP_BY_EQUALS_SELECT;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_IDENTIFIER_CASE: /* ODBC 1.0 */ case SQL_IDENTIFIER_CASE: /* ODBC 1.0 */
// are identifiers case-sensitive (yes, but only when quoted. If not quoted, they /* are identifiers case-sensitive (yes, but only when quoted. If not quoted, they
// default to lowercase) default to lowercase)
*((WORD *)rgbInfoValue) = SQL_IC_LOWER; */
if(pcbInfoValue) { *pcbInfoValue = 2; } len = 2;
value = SQL_IC_LOWER;
break; break;
case SQL_IDENTIFIER_QUOTE_CHAR: /* ODBC 1.0 */ case SQL_IDENTIFIER_QUOTE_CHAR: /* ODBC 1.0 */
// the character used to quote "identifiers" (what are they?) /* the character used to quote "identifiers" */
if (pcbInfoValue) *pcbInfoValue = 1; p = PROTOCOL_62(ci) ? " " : "\"";
strncpy_null((char *)rgbInfoValue, PROTOCOL_62(ci) ? " " : "\"", (size_t)cbInfoValueMax);
break; break;
case SQL_KEYWORDS: /* ODBC 2.0 */ case SQL_KEYWORDS: /* ODBC 2.0 */
// do this later p = "";
conn->errormsg = "SQL_KEYWORDS parameter to SQLGetInfo not implemented.";
conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
CC_log_error(func, "", conn);
return SQL_ERROR;
break; break;
case SQL_LIKE_ESCAPE_CLAUSE: /* ODBC 2.0 */ case SQL_LIKE_ESCAPE_CLAUSE: /* ODBC 2.0 */
// is there a character that escapes '%' and '_' in a LIKE clause? /* is there a character that escapes '%' and '_' in a LIKE clause?
// not as far as I can tell not as far as I can tell
if (pcbInfoValue) *pcbInfoValue = 1; */
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax); p = "N";
break; break;
case SQL_LOCK_TYPES: /* ODBC 2.0 */ case SQL_LOCK_TYPES: /* ODBC 2.0 */
// which lock types does SQLSetPos support? (bitmask) len = 4;
*((DWORD *)rgbInfoValue) = globals.lie ? (SQL_LCK_NO_CHANGE | SQL_LCK_EXCLUSIVE | SQL_LCK_UNLOCK) : SQL_LCK_NO_CHANGE; value = globals.lie ? (SQL_LCK_NO_CHANGE | SQL_LCK_EXCLUSIVE | SQL_LCK_UNLOCK) : SQL_LCK_NO_CHANGE;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_MAX_BINARY_LITERAL_LEN: /* ODBC 2.0 */ case SQL_MAX_BINARY_LITERAL_LEN: /* ODBC 2.0 */
// the maximum length of a query is 2k, so maybe we should len = 4;
// set the maximum length of all these literals to that value? value = 0;
// for now just use zero for 'unknown or no limit'
// maximum length of a binary literal
*((DWORD *)rgbInfoValue) = 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_MAX_CHAR_LITERAL_LEN: /* ODBC 2.0 */ case SQL_MAX_CHAR_LITERAL_LEN: /* ODBC 2.0 */
// maximum length of a character literal len = 4;
*((DWORD *)rgbInfoValue) = 0; value = 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_MAX_COLUMN_NAME_LEN: /* ODBC 1.0 */ case SQL_MAX_COLUMN_NAME_LEN: /* ODBC 1.0 */
// maximum length of a column name len = 2;
*((WORD *)rgbInfoValue) = MAX_COLUMN_LEN; value = MAX_COLUMN_LEN;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_MAX_COLUMNS_IN_GROUP_BY: /* ODBC 2.0 */ case SQL_MAX_COLUMNS_IN_GROUP_BY: /* ODBC 2.0 */
// maximum number of columns in a 'group by' clause len = 2;
*((WORD *)rgbInfoValue) = 0; value = 0;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_MAX_COLUMNS_IN_INDEX: /* ODBC 2.0 */ case SQL_MAX_COLUMNS_IN_INDEX: /* ODBC 2.0 */
// maximum number of columns in an index len = 2;
*((WORD *)rgbInfoValue) = 0; value = 0;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_MAX_COLUMNS_IN_ORDER_BY: /* ODBC 2.0 */ case SQL_MAX_COLUMNS_IN_ORDER_BY: /* ODBC 2.0 */
// maximum number of columns in an ORDER BY statement len = 2;
*((WORD *)rgbInfoValue) = 0; value = 0;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_MAX_COLUMNS_IN_SELECT: /* ODBC 2.0 */ case SQL_MAX_COLUMNS_IN_SELECT: /* ODBC 2.0 */
*((WORD *)rgbInfoValue) = 0; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = 0;
break; break;
case SQL_MAX_COLUMNS_IN_TABLE: /* ODBC 2.0 */ case SQL_MAX_COLUMNS_IN_TABLE: /* ODBC 2.0 */
*((WORD *)rgbInfoValue) = 0; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = 0;
break; break;
case SQL_MAX_CURSOR_NAME_LEN: /* ODBC 1.0 */ case SQL_MAX_CURSOR_NAME_LEN: /* ODBC 1.0 */
*((WORD *)rgbInfoValue) = MAX_CURSOR_LEN; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = MAX_CURSOR_LEN;
break; break;
case SQL_MAX_INDEX_SIZE: /* ODBC 2.0 */ case SQL_MAX_INDEX_SIZE: /* ODBC 2.0 */
*((DWORD *)rgbInfoValue) = 0; len = 4;
if(pcbInfoValue) { *pcbInfoValue = 4; } value = 0;
break; break;
case SQL_MAX_OWNER_NAME_LEN: /* ODBC 1.0 */ case SQL_MAX_OWNER_NAME_LEN: /* ODBC 1.0 */
// the maximum length of a table owner's name. (0 == none) len = 2;
// (maybe this should be 8) value = 0;
*((WORD *)rgbInfoValue) = (WORD)0;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_MAX_PROCEDURE_NAME_LEN: /* ODBC 1.0 */ case SQL_MAX_PROCEDURE_NAME_LEN: /* ODBC 1.0 */
*((WORD *)rgbInfoValue) = 0; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = 0;
break; break;
case SQL_MAX_QUALIFIER_NAME_LEN: /* ODBC 1.0 */ case SQL_MAX_QUALIFIER_NAME_LEN: /* ODBC 1.0 */
*((WORD *)rgbInfoValue) = 0; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = 0;
break; break;
case SQL_MAX_ROW_SIZE: /* ODBC 2.0 */ case SQL_MAX_ROW_SIZE: /* ODBC 2.0 */
// the maximum size of one row len = 4;
// here I do know a definite value value = 8192;
*((DWORD *)rgbInfoValue) = 8192;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_MAX_ROW_SIZE_INCLUDES_LONG: /* ODBC 2.0 */ case SQL_MAX_ROW_SIZE_INCLUDES_LONG: /* ODBC 2.0 */
// does the preceding value include LONGVARCHAR and LONGVARBINARY /* does the preceding value include LONGVARCHAR and LONGVARBINARY
// fields? Well, it does include longvarchar, but not longvarbinary. fields? Well, it does include longvarchar, but not longvarbinary.
if (pcbInfoValue) *pcbInfoValue = 1; */
strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax); p = "Y";
break; break;
case SQL_MAX_STATEMENT_LEN: /* ODBC 2.0 */ case SQL_MAX_STATEMENT_LEN: /* ODBC 2.0 */
// there should be a definite value here (2k?) /* maybe this should be 8192? */
*((DWORD *)rgbInfoValue) = 0; len = 4;
if(pcbInfoValue) { *pcbInfoValue = 4; } value = 0;
break; break;
case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */ case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */
*((WORD *)rgbInfoValue) = MAX_TABLE_LEN; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = MAX_TABLE_LEN;
break; break;
case SQL_MAX_TABLES_IN_SELECT: /* ODBC 2.0 */ case SQL_MAX_TABLES_IN_SELECT: /* ODBC 2.0 */
*((WORD *)rgbInfoValue) = 0; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = 0;
break; break;
case SQL_MAX_USER_NAME_LEN: case SQL_MAX_USER_NAME_LEN:
*(SWORD FAR *)rgbInfoValue = 0; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = 0;
break; break;
case SQL_MULT_RESULT_SETS: /* ODBC 1.0 */ case SQL_MULT_RESULT_SETS: /* ODBC 1.0 */
// do we support multiple result sets? Not really, but say yes anyway? /* Don't support multiple result sets but say yes anyway? */
if (pcbInfoValue) *pcbInfoValue = 1; p = "Y";
strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
break; break;
case SQL_MULTIPLE_ACTIVE_TXN: /* ODBC 1.0 */ case SQL_MULTIPLE_ACTIVE_TXN: /* ODBC 1.0 */
// do we support multiple simultaneous transactions? p = "Y";
if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
break; break;
case SQL_NEED_LONG_DATA_LEN: /* ODBC 2.0 */ case SQL_NEED_LONG_DATA_LEN: /* ODBC 2.0 */
if (pcbInfoValue) *pcbInfoValue = 1;
/* Dont need the length, SQLPutData can handle any size and multiple calls */ /* Dont need the length, SQLPutData can handle any size and multiple calls */
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax); p = "N";
break; break;
case SQL_NON_NULLABLE_COLUMNS: /* ODBC 1.0 */ case SQL_NON_NULLABLE_COLUMNS: /* ODBC 1.0 */
*((WORD *)rgbInfoValue) = (WORD)SQL_NNC_NON_NULL; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = SQL_NNC_NON_NULL;
break; break;
case SQL_NULL_COLLATION: /* ODBC 2.0 */ case SQL_NULL_COLLATION: /* ODBC 2.0 */
// where are nulls sorted? /* where are nulls sorted? */
*((WORD *)rgbInfoValue) = (WORD)SQL_NC_END; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = SQL_NC_END;
break; break;
case SQL_NUMERIC_FUNCTIONS: /* ODBC 1.0 */ case SQL_NUMERIC_FUNCTIONS: /* ODBC 1.0 */
// what numeric functions are supported? (bitmask) len = 4;
// I'm not sure if any of these are actually supported value = 0;
*((DWORD *)rgbInfoValue) = 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_ODBC_API_CONFORMANCE: /* ODBC 1.0 */ case SQL_ODBC_API_CONFORMANCE: /* ODBC 1.0 */
*((WORD *)rgbInfoValue) = SQL_OAC_LEVEL1; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = SQL_OAC_LEVEL1;
break; break;
case SQL_ODBC_SAG_CLI_CONFORMANCE: /* ODBC 1.0 */ case SQL_ODBC_SAG_CLI_CONFORMANCE: /* ODBC 1.0 */
// can't find any reference to SAG in the ODBC reference manual len = 2;
// (although it's in the index, it doesn't actually appear on value = SQL_OSCC_NOT_COMPLIANT;
// the pages referenced)
*((WORD *)rgbInfoValue) = SQL_OSCC_NOT_COMPLIANT;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_ODBC_SQL_CONFORMANCE: /* ODBC 1.0 */ case SQL_ODBC_SQL_CONFORMANCE: /* ODBC 1.0 */
*((WORD *)rgbInfoValue) = SQL_OSC_CORE; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = SQL_OSC_CORE;
break; break;
case SQL_ODBC_SQL_OPT_IEF: /* ODBC 1.0 */ case SQL_ODBC_SQL_OPT_IEF: /* ODBC 1.0 */
// do we support the "Integrity Enhancement Facility" (?) p = "N";
// (something to do with referential integrity?)
if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break; break;
case SQL_ORDER_BY_COLUMNS_IN_SELECT: /* ODBC 2.0 */ case SQL_ORDER_BY_COLUMNS_IN_SELECT: /* ODBC 2.0 */
// do the columns sorted by have to be in the list of p = "Y";
// columns selected?
if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
break; break;
case SQL_OUTER_JOINS: /* ODBC 1.0 */ case SQL_OUTER_JOINS: /* ODBC 1.0 */
// do we support outer joins? p = "N";
if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break; break;
case SQL_OWNER_TERM: /* ODBC 1.0 */ case SQL_OWNER_TERM: /* ODBC 1.0 */
// what we call an owner p = "owner";
if (pcbInfoValue) *pcbInfoValue = 5;
strncpy_null((char *)rgbInfoValue, "owner", (size_t)cbInfoValueMax);
break; break;
case SQL_OWNER_USAGE: /* ODBC 2.0 */ case SQL_OWNER_USAGE: /* ODBC 2.0 */
// in which statements can "owners be used"? (what does that mean? len = 4;
// specifying 'owner.table' instead of just 'table' or something?) value = 0;
// (bitmask)
*((DWORD *)rgbInfoValue) = 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_POS_OPERATIONS: /* ODBC 2.0 */ case SQL_POS_OPERATIONS: /* ODBC 2.0 */
// what functions does SQLSetPos support? (bitmask) len = 4;
*((DWORD *)rgbInfoValue) = globals.lie ? (SQL_POS_POSITION | SQL_POS_REFRESH | SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD) : (SQL_POS_POSITION | SQL_POS_REFRESH); value = globals.lie ? (SQL_POS_POSITION | SQL_POS_REFRESH | SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD) : (SQL_POS_POSITION | SQL_POS_REFRESH);
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */ case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */
// what 'positioned' functions are supported? (bitmask) len = 4;
*((DWORD *)rgbInfoValue) = globals.lie ? (SQL_PS_POSITIONED_DELETE | value = globals.lie ? (SQL_PS_POSITIONED_DELETE |
SQL_PS_POSITIONED_UPDATE | SQL_PS_POSITIONED_UPDATE |
SQL_PS_SELECT_FOR_UPDATE) : 0; SQL_PS_SELECT_FOR_UPDATE) : 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_PROCEDURE_TERM: /* ODBC 1.0 */ case SQL_PROCEDURE_TERM: /* ODBC 1.0 */
// what do we call a procedure? p = "procedure";
if (pcbInfoValue) *pcbInfoValue = 9;
strncpy_null((char *)rgbInfoValue, "procedure", (size_t)cbInfoValueMax);
break; break;
case SQL_PROCEDURES: /* ODBC 1.0 */ case SQL_PROCEDURES: /* ODBC 1.0 */
// do we support procedures? p = "Y";
if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
break; break;
case SQL_QUALIFIER_LOCATION: /* ODBC 2.0 */ case SQL_QUALIFIER_LOCATION: /* ODBC 2.0 */
// where does the qualifier go (before or after the table name?) len = 2;
// we don't really use qualifiers, so... value = SQL_QL_START;
*((WORD *)rgbInfoValue) = SQL_QL_START;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break; break;
case SQL_QUALIFIER_NAME_SEPARATOR: /* ODBC 1.0 */ case SQL_QUALIFIER_NAME_SEPARATOR: /* ODBC 1.0 */
// not really too sure what a qualifier is supposed to do either p = "";
// (specify the name of a database in certain cases?), so nix
// on that, too.
if (pcbInfoValue) *pcbInfoValue = 0;
strncpy_null((char *)rgbInfoValue, "", (size_t)cbInfoValueMax);
break; break;
case SQL_QUALIFIER_TERM: /* ODBC 1.0 */ case SQL_QUALIFIER_TERM: /* ODBC 1.0 */
// what we call a qualifier p = "";
if (pcbInfoValue) *pcbInfoValue = 0;
strncpy_null((char *)rgbInfoValue, "", (size_t)cbInfoValueMax);
break; break;
case SQL_QUALIFIER_USAGE: /* ODBC 2.0 */ case SQL_QUALIFIER_USAGE: /* ODBC 2.0 */
// where can qualifiers be used? (bitmask) len = 4;
// nowhere value = 0;
*((DWORD *)rgbInfoValue) = 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_QUOTED_IDENTIFIER_CASE: /* ODBC 2.0 */ case SQL_QUOTED_IDENTIFIER_CASE: /* ODBC 2.0 */
// are "quoted" identifiers case-sensitive? YES /* are "quoted" identifiers case-sensitive? YES! */
*((WORD *)rgbInfoValue) = SQL_IC_SENSITIVE; len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = SQL_IC_SENSITIVE;
break; break;
case SQL_ROW_UPDATES: /* ODBC 1.0 */ case SQL_ROW_UPDATES: /* ODBC 1.0 */
// Driver doesn't support keyset-driven or mixed cursors, so /* Driver doesn't support keyset-driven or mixed cursors, so
// not much point in saying row updates are supported not much point in saying row updates are supported
if (pcbInfoValue) *pcbInfoValue = 1; */
strncpy_null((char *)rgbInfoValue, globals.lie ? "Y" : "N", (size_t)cbInfoValueMax); p = globals.lie ? "Y" : "N";
break; break;
case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */ case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */
// what concurrency options are supported BY THE CURSOR? (bitmask) len = 4;
*((DWORD *)rgbInfoValue) = globals.lie ? (SQL_SCCO_READ_ONLY | value = globals.lie ? (SQL_SCCO_READ_ONLY |
SQL_SCCO_LOCK | SQL_SCCO_LOCK |
SQL_SCCO_OPT_ROWVER | SQL_SCCO_OPT_ROWVER |
SQL_SCCO_OPT_VALUES) : (SQL_SCCO_READ_ONLY); SQL_SCCO_OPT_VALUES) : (SQL_SCCO_READ_ONLY);
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */ case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */
// what options are supported for scrollable cursors? (bitmask) len = 4;
// for declare/fetch, only FORWARD scrolling is allowed value = globals.lie ? (SQL_SO_FORWARD_ONLY |
// otherwise, the result set is STATIC (to SQLExtendedFetch for example) SQL_SO_STATIC |
*((DWORD *)rgbInfoValue) = globals.lie ? (SQL_SO_FORWARD_ONLY | SQL_SO_KEYSET_DRIVEN |
SQL_SO_STATIC | SQL_SO_DYNAMIC |
SQL_SO_KEYSET_DRIVEN | SQL_SO_MIXED) : (globals.use_declarefetch ? SQL_SO_FORWARD_ONLY : (SQL_SO_FORWARD_ONLY | SQL_SO_STATIC));
SQL_SO_DYNAMIC |
SQL_SO_MIXED) : (globals.use_declarefetch ? SQL_SO_FORWARD_ONLY : (SQL_SO_FORWARD_ONLY | SQL_SO_STATIC));
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */ case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
// this is supposed to be the character that escapes '_' or '%' p = "";
// in LIKE clauses. as far as I can tell postgres doesn't have one
// (backslash generates an error). returning an empty string means
// no escape character is supported.
if (pcbInfoValue) *pcbInfoValue = 0;
strncpy_null((char *)rgbInfoValue, "", (size_t)cbInfoValueMax);
break; break;
case SQL_SERVER_NAME: /* ODBC 1.0 */ case SQL_SERVER_NAME: /* ODBC 1.0 */
p = CC_get_server(conn); p = CC_get_server(conn);
if (pcbInfoValue) *pcbInfoValue = strlen(p);
strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
break; break;
case SQL_SPECIAL_CHARACTERS: /* ODBC 2.0 */ case SQL_SPECIAL_CHARACTERS: /* ODBC 2.0 */
// what special characters can be used in table and column names, etc.? p = "_";
// probably more than just this...
if (pcbInfoValue) *pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "_", (size_t)cbInfoValueMax);
break; break;
case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */ case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */
// can changes made inside a cursor be detected? (or something like that) len = 4;
// (bitmask) value = globals.lie ? (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES) : 0;
// only applies to SQLSetPos, which doesn't exist yet.
*((DWORD *)rgbInfoValue) = globals.lie ? (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES) : 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_STRING_FUNCTIONS: /* ODBC 1.0 */ case SQL_STRING_FUNCTIONS: /* ODBC 1.0 */
// what string functions exist? (bitmask) len = 4;
*((DWORD *)rgbInfoValue) = (SQL_FN_STR_CONCAT | value = (SQL_FN_STR_CONCAT |
SQL_FN_STR_LCASE | SQL_FN_STR_LCASE |
SQL_FN_STR_LENGTH | SQL_FN_STR_LENGTH |
SQL_FN_STR_LOCATE | SQL_FN_STR_LOCATE |
SQL_FN_STR_LTRIM | SQL_FN_STR_LTRIM |
SQL_FN_STR_RTRIM | SQL_FN_STR_RTRIM |
SQL_FN_STR_SUBSTRING | SQL_FN_STR_SUBSTRING |
SQL_FN_STR_UCASE); SQL_FN_STR_UCASE);
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_SUBQUERIES: /* ODBC 2.0 */ case SQL_SUBQUERIES: /* ODBC 2.0 */
/* postgres 6.3 supports subqueries */ /* postgres 6.3 supports subqueries */
*((DWORD *)rgbInfoValue) = (SQL_SQ_QUANTIFIED | len = 4;
SQL_SQ_IN | value = (SQL_SQ_QUANTIFIED |
SQL_SQ_EXISTS | SQL_SQ_IN |
SQL_SQ_COMPARISON); SQL_SQ_EXISTS |
if(pcbInfoValue) { *pcbInfoValue = 4; } SQL_SQ_COMPARISON);
break; break;
case SQL_SYSTEM_FUNCTIONS: /* ODBC 1.0 */ case SQL_SYSTEM_FUNCTIONS: /* ODBC 1.0 */
// what system functions are supported? (bitmask) len = 4;
// none of these seem to be supported, either value = 0;
*((DWORD *)rgbInfoValue) = 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_TABLE_TERM: /* ODBC 1.0 */ case SQL_TABLE_TERM: /* ODBC 1.0 */
// what we call a table p = "table";
if (pcbInfoValue) *pcbInfoValue = 5;
strncpy_null((char *)rgbInfoValue, "table", (size_t)cbInfoValueMax);
break; break;
case SQL_TIMEDATE_ADD_INTERVALS: /* ODBC 2.0 */ case SQL_TIMEDATE_ADD_INTERVALS: /* ODBC 2.0 */
// what resolutions are supported by the "TIMESTAMPADD scalar len = 4;
// function" (whatever that is)? (bitmask) value = 0;
*((DWORD *)rgbInfoValue) = 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_TIMEDATE_DIFF_INTERVALS: /* ODBC 2.0 */ case SQL_TIMEDATE_DIFF_INTERVALS: /* ODBC 2.0 */
// what resolutions are supported by the "TIMESTAMPDIFF scalar len = 4;
// function" (whatever that is)? (bitmask) value = 0;
*((DWORD *)rgbInfoValue) = 0;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_TIMEDATE_FUNCTIONS: /* ODBC 1.0 */ case SQL_TIMEDATE_FUNCTIONS: /* ODBC 1.0 */
// what time and date functions are supported? (bitmask) len = 4;
*((DWORD *)rgbInfoValue) = (SQL_FN_TD_NOW); value = (SQL_FN_TD_NOW);
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_TXN_CAPABLE: /* ODBC 1.0 */ case SQL_TXN_CAPABLE: /* ODBC 1.0 */
*((WORD *)rgbInfoValue) = (WORD)SQL_TC_ALL; /* Postgres can deal with create or drop table statements in a transaction */
// Postgres can deal with create or drop table statements in a transaction len = 2;
if(pcbInfoValue) { *pcbInfoValue = 2; } value = SQL_TC_ALL;
break; break;
case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */ case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */
// what transaction isolation options are available? (bitmask) len = 4;
// only the default--serializable transactions. value = SQL_TXN_READ_COMMITTED; // SQL_TXN_SERIALIZABLE;
*((DWORD *)rgbInfoValue) = SQL_TXN_READ_COMMITTED; // SQL_TXN_SERIALIZABLE;
if(pcbInfoValue) { *pcbInfoValue = 4; }
break; break;
case SQL_UNION: /* ODBC 2.0 */ case SQL_UNION: /* ODBC 2.0 */
/* unions with all supported in postgres 6.3 */ /* unions with all supported in postgres 6.3 */
*((DWORD *)rgbInfoValue) = (SQL_U_UNION | SQL_U_UNION_ALL); len = 4;
if(pcbInfoValue) { *pcbInfoValue = 4; } value = (SQL_U_UNION | SQL_U_UNION_ALL);
break; break;
case SQL_USER_NAME: /* ODBC 1.0 */ case SQL_USER_NAME: /* ODBC 1.0 */
p = CC_get_username(conn); p = CC_get_username(conn);
if (pcbInfoValue) *pcbInfoValue = strlen(p);
strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
break; break;
default: default:
@ -736,7 +591,43 @@ char *p;
return SQL_ERROR; return SQL_ERROR;
} }
return SQL_SUCCESS; result = SQL_SUCCESS;
mylog("SQLGetInfo: p='%s', len=%d, value=%d, cbMax=%d\n", p?p:"<NULL>", len, value, cbInfoValueMax);
/* NOTE, that if rgbInfoValue is NULL, then no warnings or errors should
result and just pcbInfoValue is returned, which indicates what length
would be required if a real buffer had been passed in.
*/
if (p) { /* char/binary data */
len = strlen(p);
if (rgbInfoValue) {
strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
if (len >= cbInfoValueMax) {
result = SQL_SUCCESS_WITH_INFO;
conn->errornumber = STMT_TRUNCATED;
conn->errormsg = "The buffer was too small for the result.";
}
}
}
else { /* numeric data */
if (rgbInfoValue) {
if (len == 2 )
*((WORD *)rgbInfoValue) = (WORD) value;
else if (len == 4)
*((DWORD *)rgbInfoValue) = (DWORD) value;
}
}
if (pcbInfoValue)
*pcbInfoValue = len;
return result;
} }
// - - - - - - - - - // - - - - - - - - -

View File

@ -26,7 +26,7 @@
portion of the registry. You may have to manually add this key. portion of the registry. You may have to manually add this key.
This logfile is intended for development use, not for an end user! This logfile is intended for development use, not for an end user!
*/ */
#define MY_LOG // #define MY_LOG
/* Uncomment Q_LOG to compile in the qlog() statements (Communications log, i.e. CommLog). /* Uncomment Q_LOG to compile in the qlog() statements (Communications log, i.e. CommLog).

View File

@ -33,7 +33,20 @@ typedef double SDOUBLE;
typedef UInt4 Oid; typedef UInt4 Oid;
# define ODBCVER 0x0200 /* Driver stuff */
#define ODBCVER 0x0200
#define DRIVER_ODBC_VER "02.00"
#define DRIVERNAME "PostgreSQL ODBC"
#define DBMS_NAME "PostgreSQL"
#define DBMS_VERSION "06.40.0002 PostgreSQL 6.4"
#define POSTGRESDRIVERVERSION "06.40.0002"
#ifdef WIN32
#define DRIVER_FILE_NAME "PSQLODBC.DLL"
#else
#define DRIVER_FILE_NAME "libpsqlodbc.so"
#endif
/* Limits */ /* Limits */
#define MAX_MESSAGE_LEN 8192 #define MAX_MESSAGE_LEN 8192
@ -67,17 +80,6 @@ typedef UInt4 Oid;
#define MAX_KEYLEN 512 // max key of the form "date+outlet+invoice" #define MAX_KEYLEN 512 // max key of the form "date+outlet+invoice"
#define MAX_STATEMENT_LEN MAX_MESSAGE_LEN #define MAX_STATEMENT_LEN MAX_MESSAGE_LEN
/* Driver stuff */
#define DRIVERNAME "PostgreSQL ODBC"
#define DBMS_NAME "PostgreSQL"
#define DBMS_VERSION "06.40.0002 PostgreSQL 6.4"
#define POSTGRESDRIVERVERSION "06.40.0002"
#ifdef WIN32
#define DRIVER_FILE_NAME "PSQLODBC.DLL"
#else
#define DRIVER_FILE_NAME "libpsqlodbc.so"
#endif
#define PG62 "6.2" /* "Protocol" key setting to force Postgres 6.2 */ #define PG62 "6.2" /* "Protocol" key setting to force Postgres 6.2 */
#define PG63 "6.3" /* "Protocol" key setting to force postgres 6.3 */ #define PG63 "6.3" /* "Protocol" key setting to force postgres 6.3 */

View File

@ -70,6 +70,7 @@ typedef enum {
#define STMT_ROW_OUT_OF_RANGE 21 #define STMT_ROW_OUT_OF_RANGE 21
#define STMT_OPERATION_CANCELLED 22 #define STMT_OPERATION_CANCELLED 22
#define STMT_INVALID_CURSOR_POSITION 23 #define STMT_INVALID_CURSOR_POSITION 23
#define STMT_VALUE_OUT_OF_RANGE 24
/* statement types */ /* statement types */
enum { enum {