From 5d08521fcd1a5e00f65f25a342b81a11ceb73a68 Mon Sep 17 00:00:00 2001
From: Hiroshi Inoue <inoue@tpf.co.jp>
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. <<odbc.diff>>
---
 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 fa56824011d..9e5223b83b3 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 fe1344df8ab..98fbca2f794 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 8251271a05c..8222d985180 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 332ccc5cbb1..2cbe6e6a87a 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 681c72759d0..bf43d6522b5 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 b0d8539eb79..54fd4e2eeae 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 1d934106d3b..503b478372a 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
-- 
GitLab