From 5d08521fcd1a5e00f65f25a342b81a11ceb73a68 Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Tue, 6 Feb 2001 02:21:12 +0000 Subject: [PATCH] Improved version handling introduced by Dave Page. The driver version is 07.01.0002 now. 1) initialized pg_version by DSN's protocol info so that we could always use pg_version info once a connection is established (pg_version() didn't exist before 6.4). PROTOCOL_XX() macros are removed(except from connection.[ch]). 2) provided a few macros to encapsulate connection's version info and replaced existent comparison stuff by those macros. 3) change SQLTables() so that 7.1 servers could show views. In addtion, the following patch from Dave Page is applied. This patch fixes a bug in SQLGetInfo for SQL_DBMS_VER which corrupted the driver version string. The driver version number has also been incremented to 07.01.0002. Regards, Dave. <> --- src/interfaces/odbc/columninfo.c | 2 +- src/interfaces/odbc/connection.c | 37 ++++++++++++++++++++-- src/interfaces/odbc/connection.h | 38 ++++++++++++++++++++++ src/interfaces/odbc/drvconn.c | 2 ++ src/interfaces/odbc/info.c | 54 +++++++++++++++++++++----------- src/interfaces/odbc/psqlodbc.h | 4 +-- src/interfaces/odbc/psqlodbc.rc | 8 ++--- 7 files changed, 117 insertions(+), 28 deletions(-) diff --git a/src/interfaces/odbc/columninfo.c b/src/interfaces/odbc/columninfo.c index fa56824011..9e5223b83b 100644 --- a/src/interfaces/odbc/columninfo.c +++ b/src/interfaces/odbc/columninfo.c @@ -81,7 +81,7 @@ ConnInfo *ci; new_adtsize = (Int2) SOCK_get_int(sock, 2); /* If 6.4 protocol, then read the atttypmod field */ - if ( ! PROTOCOL_63(ci) && ! PROTOCOL_62(ci)) { + if (PG_VERSION_GE(conn, 6.4)) { mylog("READING ATTTYPMOD\n"); new_atttypmod = (Int4) SOCK_get_int(sock, 4); diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c index fe1344df8a..98fbca2f79 100644 --- a/src/interfaces/odbc/connection.c +++ b/src/interfaces/odbc/connection.c @@ -98,6 +98,8 @@ static char *func = "SQLConnect"; /* get the values for the DSN from the registry */ getDSNinfo(ci, CONN_OVERWRITE); + /* initialize pg_version from connInfo.protocol */ + CC_initialize_pg_version(conn); /* override values from DSN info with UID and authStr(pwd) This only occurs if the values are actually there. @@ -253,6 +255,10 @@ ConnectionClass *rv; rv->translation_handle = NULL; rv->DataSourceToDriver = NULL; rv->DriverToDataSource = NULL; + memset(rv->pg_version, 0, sizeof(rv->pg_version)); + rv->pg_version_number = .0; + rv->pg_version_major = 0; + rv->pg_version_minor = 0; /* Initialize statement options to defaults */ @@ -1365,6 +1371,28 @@ static char *func = "CC_lookup_lo"; result = SQLFreeStmt(hstmt, SQL_DROP); } +/* This function initializes the version of PostgreSQL from + connInfo.protocol that we're connected to. + h-inoue 01-2-2001 +*/ +void +CC_initialize_pg_version(ConnectionClass *self) +{ + strcpy(self->pg_version, self->connInfo.protocol); + if (PROTOCOL_62(&self->connInfo)) { + self->pg_version_number = (float) 6.2; + self->pg_version_major = 6; + self->pg_version_minor = 2; + } else if (PROTOCOL_63(&self->connInfo)) { + self->pg_version_number = (float) 6.3; + self->pg_version_major = 6; + self->pg_version_minor = 3; + } else { + self->pg_version_number = (float) 6.4; + self->pg_version_major = 6; + self->pg_version_minor = 4; + } +} /* This function gets the version of PostgreSQL that we're connected to. This is used to return the correct info in SQLGetInfo DJP - 25-1-2001 @@ -1376,6 +1404,7 @@ HSTMT hstmt; StatementClass *stmt; RETCODE result; char *szVersion = "0.0"; +int major, minor; static char *func = "CC_lookup_pg_version"; mylog( "%s: entering...\n", func); @@ -1389,6 +1418,7 @@ static char *func = "CC_lookup_pg_version"; } stmt = (StatementClass *) hstmt; + /* get the server's version if possible */ result = SQLExecDirect(hstmt, "select version()", SQL_NTS); if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SQLFreeStmt(hstmt, SQL_DROP); @@ -1407,10 +1437,13 @@ static char *func = "CC_lookup_pg_version"; return; } - /* There's proably a nicer way of doing this... */ /* Extract the Major and Minor numbers from the string. */ /* This assumes the string starts 'Postgresql X.X' */ - sprintf(szVersion, "%c.%c", self->pg_version[11], self->pg_version[13]); + if (sscanf(self->pg_version, "%*s %d.%d", &major, &minor) >= 2) { + sprintf(szVersion, "%d.%d", major, minor); + self->pg_version_major = major; + self->pg_version_minor = minor; + } self->pg_version_number = (float) atof(szVersion); mylog("Got the PostgreSQL version string: '%s'\n", self->pg_version); diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h index 8251271a05..8222d98518 100644 --- a/src/interfaces/odbc/connection.h +++ b/src/interfaces/odbc/connection.h @@ -163,6 +163,41 @@ typedef struct { /* Macro to determine is the connection using 6.3 protocol? */ #define PROTOCOL_63(conninfo_) (strncmp((conninfo_)->protocol, PG63, strlen(PG63)) == 0) +/* + * Macros to compare the server's version with a specified version + * 1st parameter: pointer to a ConnectionClass object + * 2nd parameter: major version number + * 3rd parameter: minor version number + */ +#define SERVER_VERSION_GT(conn, major, minor) \ + ((conn)->pg_version_major > major || \ + ((conn)->pg_version_major == major && (conn)->pg_version_minor > minor)) +#define SERVER_VERSION_GE(conn, major, minor) \ + ((conn)->pg_version_major > major || \ + ((conn)->pg_version_major == major && (conn)->pg_version_minor >= minor)) +#define SERVER_VERSION_EQ(conn, major, minor) \ + ((conn)->pg_version_major == major && (conn)->pg_version_minor == minor) +#define SERVER_VERSION_LE(conn, major, minor) (! SERVER_VERSION_GT(conn, major, minor)) +#define SERVER_VERSION_LT(conn, major, minor) (! SERVER_VERSION_GE(conn, major, minor)) +/*#if ! defined(HAVE_CONFIG_H) || defined(HAVE_STRINGIZE)*/ +#define STRING_AFTER_DOT(string) (strchr(#string, '.') + 1) +/*#else +#define STRING_AFTER_DOT(str) (strchr("str", '.') + 1) +#endif*/ +/* + * Simplified macros to compare the server's version with a + * specified version + * Note: Never pass a variable as the second parameter. + * It must be a decimal constant of the form %d.%d . + */ +#define PG_VERSION_GT(conn, ver) \ + (SERVER_VERSION_GT(conn, (int) ver, atoi(STRING_AFTER_DOT(ver)))) +#define PG_VERSION_GE(conn, ver) \ + (SERVER_VERSION_GE(conn, (int) ver, atoi(STRING_AFTER_DOT(ver)))) +#define PG_VERSION_EQ(conn, ver) \ + (SERVER_VERSION_EQ(conn, (int) ver, atoi(STRING_AFTER_DOT(ver)))) +#define PG_VERSION_LE(conn, ver) (! PG_VERSION_GT(conn, ver)) +#define PG_VERSION_LT(conn, ver) (! PG_VERSION_GE(conn, ver)) /* This is used to store cached table information in the connection */ struct col_info { @@ -223,6 +258,8 @@ struct ConnectionClass_ { char errormsg_created; /* has an informative error msg been created? */ char pg_version[MAX_INFO_STRING]; /* Version of PostgreSQL we're connected to - DJP 25-1-2001 */ float pg_version_number; + Int2 pg_version_major; + Int2 pg_version_minor; }; @@ -258,6 +295,7 @@ int CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *act char CC_send_settings(ConnectionClass *self); void CC_lookup_lo(ConnectionClass *conn); void CC_lookup_pg_version(ConnectionClass *conn); +void CC_initialize_pg_version(ConnectionClass *conn); void CC_log_error(char *func, char *desc, ConnectionClass *self); diff --git a/src/interfaces/odbc/drvconn.c b/src/interfaces/odbc/drvconn.c index 332ccc5cbb..2cbe6e6a87 100644 --- a/src/interfaces/odbc/drvconn.c +++ b/src/interfaces/odbc/drvconn.c @@ -113,6 +113,8 @@ int len = 0; /* Fill in any default parameters if they are not there. */ getDSNdefaults(ci); + /* initialize pg_version */ + CC_initialize_pg_version(conn); #ifdef WIN32 dialog: diff --git a/src/interfaces/odbc/info.c b/src/interfaces/odbc/info.c index 681c72759d..bf43d6522b 100644 --- a/src/interfaces/odbc/info.c +++ b/src/interfaces/odbc/info.c @@ -69,7 +69,7 @@ RETCODE SQL_API SQLGetInfo( static char *func = "SQLGetInfo"; ConnectionClass *conn = (ConnectionClass *) hdbc; ConnInfo *ci; -char *p = NULL; +char *p = NULL, tmp[MAX_INFO_STRING]; int len = 0, value = 0; RETCODE result; @@ -193,9 +193,8 @@ RETCODE result; case SQL_DBMS_VER: /* ODBC 1.0 */ /* The ODBC spec wants ##.##.#### ...whatever... so prepend the driver */ /* version number to the dbms version string */ - p = POSTGRESDRIVERVERSION; - strcat(p, " "); - strcat(p, conn->pg_version); + sprintf(tmp, "%s %s", POSTGRESDRIVERVERSION, conn->pg_version); + p = tmp; break; case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */ @@ -255,7 +254,7 @@ RETCODE result; case SQL_IDENTIFIER_QUOTE_CHAR: /* ODBC 1.0 */ /* the character used to quote "identifiers" */ - p = PROTOCOL_62(ci) ? " " : "\""; + p = PG_VERSION_LE(conn, 6.2) ? " " : "\""; break; case SQL_KEYWORDS: /* ODBC 2.0 */ @@ -341,7 +340,7 @@ RETCODE result; case SQL_MAX_ROW_SIZE: /* ODBC 2.0 */ len = 4; - if (conn->pg_version_number >= (float) 7.1) { /* Large Rowa in 7.1+ */ + if (PG_VERSION_GE(conn, 7.1)) { /* Large Rowa in 7.1+ */ value = MAX_ROW_SIZE; } else { /* Without the Toaster we're limited to the blocksize */ value = BLCKSZ; @@ -358,11 +357,13 @@ RETCODE result; case SQL_MAX_STATEMENT_LEN: /* ODBC 2.0 */ /* maybe this should be 0? */ len = 4; - if (conn->pg_version_number >= (float) 7.0) { /* Long Queries in 7.0+ */ + if (PG_VERSION_GE(conn, 7.0)) { /* Long Queries in 7.0+ */ value = MAX_STATEMENT_LEN; - } else { /* Prior to 7.0 we used 2*BLCKSZ */ + } else if (PG_VERSION_GE(conn, 6.5)) /* Prior to 7.0 we used 2*BLCKSZ */ value = (2*BLCKSZ); - } + else /* Prior to 6.5 we used BLCKSZ */ + value = BLCKSZ; + break; case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */ @@ -431,7 +432,7 @@ RETCODE result; case SQL_OJ_CAPABILITIES: /* ODBC 2.01 */ len = 4; - if (conn->pg_version_number >= (float) 7.1) { /* OJs in 7.1+ */ + if (PG_VERSION_GE(conn, 7.1)) { /* OJs in 7.1+ */ value = (SQL_OJ_LEFT | SQL_OJ_RIGHT | SQL_OJ_FULL | @@ -445,11 +446,11 @@ RETCODE result; break; case SQL_ORDER_BY_COLUMNS_IN_SELECT: /* ODBC 2.0 */ - p = (PROTOCOL_62(ci) || PROTOCOL_63(ci)) ? "Y" : "N"; + p = (PG_VERSION_LE(conn, 6.3)) ? "Y" : "N"; break; case SQL_OUTER_JOINS: /* ODBC 1.0 */ - if (conn->pg_version_number >= (float) 7.1) { /* OJs in 7.1+ */ + if (PG_VERSION_GE(conn, 7.1)) { /* OJs in 7.1+ */ p = "Y"; } else { /* OJs not in <7.1 */ p = "N"; @@ -937,7 +938,8 @@ HSTMT htbl_stmt; RETCODE result; char *tableType; char tables_query[STD_STATEMENT_LEN]; -char table_name[MAX_INFO_STRING], table_owner[MAX_INFO_STRING], relhasrules[MAX_INFO_STRING]; +char table_name[MAX_INFO_STRING], table_owner[MAX_INFO_STRING], relkind_or_hasrules[MAX_INFO_STRING]; +ConnectionClass *conn; ConnInfo *ci; char *prefix[32], prefixes[MEDIUM_REGISTRY_LEN]; char *table_type[32], table_types[MAX_INFO_STRING]; @@ -955,6 +957,7 @@ mylog("%s: entering...stmt=%u\n", func, stmt); stmt->manual_result = TRUE; stmt->errormsg_created = TRUE; + conn = (ConnectionClass *) (stmt->hdbc); ci = &stmt->hdbc->connInfo; result = SQLAllocStmt( stmt->hdbc, &htbl_stmt); @@ -970,8 +973,14 @@ mylog("%s: entering...stmt=%u\n", func, stmt); /* Create the query to find out the tables */ /* ********************************************************************** */ - strcpy(tables_query, "select relname, usename, relhasrules from pg_class, pg_user"); - strcat(tables_query, " where relkind = 'r'"); + if (PG_VERSION_GE(conn, 7.1)) { /* view is represented by its relkind since 7.1 */ + strcpy(tables_query, "select relname, usename, relkind from pg_class, pg_user"); + strcat(tables_query, " where relkind in ('r', 'v')"); + } + else { + strcpy(tables_query, "select relname, usename, relhasrules from pg_class, pg_user"); + strcat(tables_query, " where relkind = 'r'"); + } my_strcat(tables_query, " and usename like '%.*s'", szTableOwner, cbTableOwner); my_strcat(tables_query, " and relname like '%.*s'", szTableName, cbTableName); @@ -1039,6 +1048,9 @@ mylog("%s: entering...stmt=%u\n", func, stmt); /* match users */ + if (PG_VERSION_LT(conn, 7.1)) /* filter out large objects in older versions */ + strcat(tables_query, " and relname !~ '^xinv[0-9]+'"); + strcat(tables_query, " and usesysid = relowner"); strcat(tables_query, " order by relname"); @@ -1073,7 +1085,7 @@ mylog("%s: entering...stmt=%u\n", func, stmt); return SQL_ERROR; } result = SQLBindCol(htbl_stmt, 3, SQL_C_CHAR, - relhasrules, MAX_INFO_STRING, NULL); + relkind_or_hasrules, MAX_INFO_STRING, NULL); if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { stmt->errormsg = tbl_stmt->errormsg; stmt->errornumber = tbl_stmt->errornumber; @@ -1131,7 +1143,10 @@ mylog("%s: entering...stmt=%u\n", func, stmt); } /* Determine if the table name is a view */ - view = (relhasrules[0] == '1'); + if (PG_VERSION_GE(conn, 7.1)) /* view is represented by its relkind since 7.1 */ + view = (relkind_or_hasrules[0] == 'v'); + else + view = (relkind_or_hasrules[0] == '1'); /* It must be a regular table */ regular_table = ( ! systable && ! view); @@ -1214,6 +1229,7 @@ Int4 field_type, the_type, field_length, mod_length, precision; char useStaticPrecision; char not_null[MAX_INFO_STRING], relhasrules[MAX_INFO_STRING]; ConnInfo *ci; +ConnectionClass *conn; mylog("%s: entering...stmt=%u\n", func, stmt); @@ -1226,6 +1242,7 @@ ConnInfo *ci; stmt->manual_result = TRUE; stmt->errormsg_created = TRUE; + conn = (ConnectionClass *) (stmt->hdbc); ci = &stmt->hdbc->connInfo; /* ********************************************************************** */ @@ -1236,7 +1253,7 @@ ConnInfo *ci; " from pg_user u, pg_class c, pg_attribute a, pg_type t" " where u.usesysid = c.relowner" " and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)", - PROTOCOL_62(ci) ? "a.attlen" : "a.atttypmod"); + PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod"); my_strcat(columns_query, " and c.relname like '%.*s'", szTableName, cbTableName); my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner); @@ -2315,7 +2332,6 @@ Int2 result_cols; 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; } diff --git a/src/interfaces/odbc/psqlodbc.h b/src/interfaces/odbc/psqlodbc.h index b0d8539eb7..54fd4e2eea 100644 --- a/src/interfaces/odbc/psqlodbc.h +++ b/src/interfaces/odbc/psqlodbc.h @@ -6,7 +6,7 @@ * * Comments: See "notice.txt" for copyright and license information. * - * $Id: psqlodbc.h,v 1.29 2001/01/26 22:41:59 momjian Exp $ + * $Id: psqlodbc.h,v 1.30 2001/02/06 02:21:12 inoue Exp $ */ #ifndef __PSQLODBC_H__ @@ -41,7 +41,7 @@ typedef UInt4 Oid; #define DRIVERNAME "PostgreSQL ODBC" #define DBMS_NAME "PostgreSQL" -#define POSTGRESDRIVERVERSION "07.01.0001" +#define POSTGRESDRIVERVERSION "07.01.0002" #ifdef WIN32 #define DRIVER_FILE_NAME "PSQLODBC.DLL" diff --git a/src/interfaces/odbc/psqlodbc.rc b/src/interfaces/odbc/psqlodbc.rc index 1d934106d3..503b478372 100644 --- a/src/interfaces/odbc/psqlodbc.rc +++ b/src/interfaces/odbc/psqlodbc.rc @@ -204,8 +204,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 7,1,0,1 - PRODUCTVERSION 7,1,0,1 + FILEVERSION 7,1,0,2 + PRODUCTVERSION 7,1,0,2 FILEFLAGSMASK 0x3L #ifdef _DEBUG FILEFLAGS 0x1L @@ -223,14 +223,14 @@ BEGIN VALUE "Comments", "PostgreSQL ODBC driver\0" VALUE "CompanyName", "Insight Distribution Systems\0" VALUE "FileDescription", "PostgreSQL Driver\0" - VALUE "FileVersion", " 07.01.0001\0" + VALUE "FileVersion", " 07.01.0002\0" VALUE "InternalName", "psqlodbc\0" VALUE "LegalCopyright", "\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 "PrivateBuild", "\0" VALUE "ProductName", "Microsoft Open Database Connectivity\0" - VALUE "ProductVersion", " 07.01.0001\0" + VALUE "ProductVersion", " 07.01.0002\0" VALUE "SpecialBuild", "\0" END END -- 2.40.0