From 87225ca31d1212008c47f5085f5fd4d77431cb69 Mon Sep 17 00:00:00 2001
From: Byron Nikolaidis <byronn@insightdist.com>
Date: Wed, 11 Nov 1998 21:54:01 +0000
Subject: [PATCH] Update for version 06-40-0001

---
 src/interfaces/odbc/columninfo.c   |  32 +++++++--
 src/interfaces/odbc/columninfo.h   |   6 +-
 src/interfaces/odbc/connection.c   |  62 +++++++++++++----
 src/interfaces/odbc/connection.h   |  12 ++--
 src/interfaces/odbc/convert.c      |   4 +-
 src/interfaces/odbc/dlg_specific.c |  27 ++++++--
 src/interfaces/odbc/dlg_specific.h |   2 +
 src/interfaces/odbc/execute.c      |   2 +-
 src/interfaces/odbc/misc.c         |   2 +-
 src/interfaces/odbc/misc.h         |  46 ++++++-------
 src/interfaces/odbc/pgtypes.c      |   3 +
 src/interfaces/odbc/psqlodbc.h     |   8 ++-
 src/interfaces/odbc/psqlodbc.rc    | 105 ++++++++++++++---------------
 src/interfaces/odbc/qresult.c      |  10 +--
 src/interfaces/odbc/qresult.h      |   3 +-
 src/interfaces/odbc/resource.h     |   8 +--
 src/interfaces/odbc/results.c      |   2 +-
 src/interfaces/odbc/socket.h       |   7 --
 src/interfaces/odbc/statement.h    |   3 +-
 19 files changed, 211 insertions(+), 133 deletions(-)

diff --git a/src/interfaces/odbc/columninfo.c b/src/interfaces/odbc/columninfo.c
index 41e6e74635..fed86d5dcd 100644
--- a/src/interfaces/odbc/columninfo.c
+++ b/src/interfaces/odbc/columninfo.c
@@ -13,6 +13,7 @@
  */
 
 #include "columninfo.h"
+#include "connection.h"
 #include "socket.h"
 #include <stdlib.h>
 #include <malloc.h>
@@ -31,6 +32,7 @@ ColumnInfoClass *rv;
 		rv->adtid = NULL;
 		rv->adtsize = NULL;
 		rv->display_size = NULL;
+		rv->atttypmod = NULL;
 	}
 
 	return rv;
@@ -49,14 +51,19 @@ CI_Destructor(ColumnInfoClass *self)
 	If self is null, then just read, don't store.
 */
 char
-CI_read_fields(ColumnInfoClass *self, SocketClass *sock)
+CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn)
 {
 Int2 lf;
 int new_num_fields;
 Oid new_adtid;
 Int2 new_adtsize;
+Int4 new_atttypmod = -1;
 char new_field_name[MAX_MESSAGE_LEN+1];
+SocketClass *sock;
+ConnInfo *ci;
 
+	sock = CC_get_socket(conn);
+	ci = &conn->connInfo;
 
 	/* at first read in the number of fields that are in the query */
 	new_num_fields = (Int2) SOCK_get_int(sock, sizeof(Int2));
@@ -74,10 +81,23 @@ char new_field_name[MAX_MESSAGE_LEN+1];
 		new_adtid = (Oid) SOCK_get_int(sock, 4);
 		new_adtsize = (Int2) SOCK_get_int(sock, 2);
 
-		mylog("CI_read_fields: fieldname='%s', adtid=%d, adtsize=%d\n", new_field_name, new_adtid, new_adtsize);
+		/*	If 6.4 protocol, then read the atttypmod field */
+		if ( ! PROTOCOL_63(ci) && ! PROTOCOL_62(ci)) {
+
+			mylog("READING ATTTYPMOD\n");
+			new_atttypmod = (Int4) SOCK_get_int(sock, 4);
+
+			/*	Subtract the header length */
+			new_atttypmod -= 4;
+			if (new_atttypmod < 0)
+				new_atttypmod = -1;
+
+		}
+
+		mylog("CI_read_fields: fieldname='%s', adtid=%d, adtsize=%d, atttypmod=%d\n", new_field_name, new_adtid, new_adtsize, new_atttypmod);
 
 		if (self)
-			CI_set_field_info(self, lf, new_field_name, new_adtid, new_adtsize);
+			CI_set_field_info(self, lf, new_field_name, new_adtid, new_adtsize, new_atttypmod);
 	}
 
 	return (SOCK_get_errcode(sock) == 0);
@@ -101,6 +121,8 @@ int num_fields = self->num_fields;
 	free(self->adtid);
 	free(self->adtsize);
 	free(self->display_size);
+
+	free(self->atttypmod);
 }
 
 void
@@ -114,11 +136,12 @@ CI_set_num_fields(ColumnInfoClass *self, int new_num_fields)
 	self->adtid = (Oid *) malloc (sizeof(Oid) * self->num_fields);
 	self->adtsize = (Int2 *) malloc (sizeof(Int2) * self->num_fields);
 	self->display_size = (Int2 *) malloc(sizeof(Int2) * self->num_fields);
+	self->atttypmod = (Int4 *) malloc(sizeof(Int4) * self->num_fields);
 }
 
 void
 CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name, 
-                                      Oid new_adtid, Int2 new_adtsize)
+                                      Oid new_adtid, Int2 new_adtsize, Int4 new_atttypmod)
 {
     
 	// check bounds
@@ -130,6 +153,7 @@ CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
 	self->name[field_num] = strdup(new_name);  
 	self->adtid[field_num] = new_adtid;
 	self->adtsize[field_num] = new_adtsize;
+	self->atttypmod[field_num] = new_atttypmod;
 
 	self->display_size[field_num] = 0;
 }
diff --git a/src/interfaces/odbc/columninfo.h b/src/interfaces/odbc/columninfo.h
index 01c654da84..3ec1cc92d5 100644
--- a/src/interfaces/odbc/columninfo.h
+++ b/src/interfaces/odbc/columninfo.h
@@ -18,6 +18,7 @@ struct ColumnInfoClass_ {
 	Oid		*adtid;				/* list of type ids */
 	Int2	*adtsize;			/* list type sizes */
 	Int2	*display_size;		/* the display size (longest row) */
+	Int4	*atttypmod;			/* the length of bpchar/varchar */
 };
 
 #define CI_get_num_fields(self)			(self->num_fields)
@@ -25,17 +26,18 @@ struct ColumnInfoClass_ {
 #define CI_get_fieldname(self, col)		(self->name[col])
 #define CI_get_fieldsize(self, col)		(self->adtsize[col])
 #define CI_get_display_size(self, col)	(self->display_size[col])
+#define CI_get_atttypmod(self, col)		(self->atttypmod[col])
 
 ColumnInfoClass *CI_Constructor(void);
 void CI_Destructor(ColumnInfoClass *self);
 void CI_free_memory(ColumnInfoClass *self);
-char CI_read_fields(ColumnInfoClass *self, SocketClass *sock);
+char CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn);
 
 /* functions for setting up the fields from within the program, */
 /* without reading from a socket */
 void CI_set_num_fields(ColumnInfoClass *self, int new_num_fields);
 void CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name, 
-                       Oid new_adtid, Int2 new_adtsize);
+                       Oid new_adtid, Int2 new_adtsize, Int4 atttypmod);
 
 
 #endif
diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c
index 3857f73d70..c07b051070 100644
--- a/src/interfaces/odbc/connection.c
+++ b/src/interfaces/odbc/connection.c
@@ -472,8 +472,9 @@ static char *func="CC_connect";
 			globals.unknown_sizes, 
 			globals.max_varchar_size, 
 			globals.max_longvarchar_size);
-		qlog("                disable_optimizer=%d, unique_index=%d, use_declarefetch=%d\n",
+		qlog("                disable_optimizer=%d, ksqo=%d, unique_index=%d, use_declarefetch=%d\n",
 			globals.disable_optimizer,
+			globals.ksqo,
 			globals.unique_index,
 			globals.use_declarefetch);
 		qlog("                text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d\n",
@@ -542,7 +543,11 @@ static char *func="CC_connect";
 			// Send length of Authentication Block
 			SOCK_put_int(sock, 4+sizeof(StartupPacket), 4); 
 
-			sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LATEST);
+			if ( PROTOCOL_63(ci))
+				sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_63);
+			else
+				sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LATEST);
+
 			strncpy(sp.database, ci->database, SM_DATABASE);
 			strncpy(sp.user, ci->username, SM_USER);
 
@@ -913,22 +918,41 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 
 				SOCK_put_string(sock, "Q ");
 				SOCK_flush_output(sock);
-				while(!clear) {
-					SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
-					mylog("send_query: read command '%s'\n", cmdbuffer);
-					clear = (cmdbuffer[0] == 'I');
-
-					if (cmdbuffer[0] == 'N')
-						qlog("NOTICE from backend during send_query: '%s'\n", &cmdbuffer[1]);
-					else if (cmdbuffer[0] == 'E')
-						qlog("ERROR from backend during send_query: '%s'\n", &cmdbuffer[1]);
-					else if (cmdbuffer[0] == 'C')
-						qlog("Command response: '%s'\n", &cmdbuffer[1]);
-				}
 
+				while( ! clear) {
+					id = SOCK_get_char(sock);
+					switch(id) {
+					case 'I':
+						(void) SOCK_get_char(sock);
+						clear = TRUE;
+						break;
+					case 'Z':
+						break;
+					case 'C':
+						SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
+						qlog("Command response: '%s'\n", cmdbuffer);
+						break;
+					case 'N':
+						SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
+						qlog("NOTICE from backend during clear: '%s'\n", cmdbuffer);
+						break;
+					case 'E':
+						SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
+						qlog("ERROR from backend during clear: '%s'\n", cmdbuffer);
+						break;
+					}
+				}
+				
 				mylog("send_query: returning res = %u\n", res);
 				return res;
 			}
+		case 'K':	/* Secret key (6.4 protocol) */
+			(void)SOCK_get_int(sock, 4); /* pid */
+			(void)SOCK_get_int(sock, 4); /* key */
+
+			break;
+		case 'Z':	/* Backend is ready for new query (6.4) */
+			break;
 		case 'N' : /* NOTICE: */
 			SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
 
@@ -1209,6 +1233,16 @@ static char *func="CC_send_settings";
 	
 	}
 
+	/*	KSQO */
+	if (globals.ksqo) {
+		result = SQLExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS);
+		if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+			status = FALSE;
+
+		mylog("%s: result %d, status %d from set ksqo\n", func, result, status);
+	
+	}
+
 	/*	Global settings */
 	if (globals.conn_settings[0] != '\0') {
 		cs = strdup(globals.conn_settings);
diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h
index 895e4ce826..3340e15cbe 100644
--- a/src/interfaces/odbc/connection.h
+++ b/src/interfaces/odbc/connection.h
@@ -14,6 +14,8 @@
 #include "config.h"
 #endif
 
+#include "psqlodbc.h"
+
 #ifndef WIN32
 #include "iodbc.h"
 #include "isql.h"
@@ -24,7 +26,6 @@
 #include <sqlext.h>
 #endif
 
-#include "psqlodbc.h"
 
 typedef enum {
     CONN_NOT_CONNECTED,      /* Connection has not been established */
@@ -100,10 +101,11 @@ typedef enum {
 typedef unsigned int ProtocolVersion;
 
 #define PG_PROTOCOL(major, minor)	(((major) << 16) | (minor))
-#define PG_PROTOCOL_LATEST		PG_PROTOCOL(1, 0)
-#define PG_PROTOCOL_EARLIEST	PG_PROTOCOL(0, 0)
+#define PG_PROTOCOL_LATEST		PG_PROTOCOL(2, 0)
+#define PG_PROTOCOL_63			PG_PROTOCOL(1, 0)
+#define PG_PROTOCOL_62			PG_PROTOCOL(0, 0)
 
-/*	This startup packet is to support latest Postgres protocol (6.3) */
+/*	This startup packet is to support latest Postgres protocol (6.4, 6.3) */
 typedef struct _StartupPacket
 {
 	ProtocolVersion	protoVersion;
@@ -154,6 +156,8 @@ typedef struct {
 /*	Macro to determine is the connection using 6.2 protocol? */
 #define PROTOCOL_62(conninfo_)		(strncmp((conninfo_)->protocol, PG62, strlen(PG62)) == 0)
 
+/*	Macro to determine is the connection using 6.3 protocol? */
+#define PROTOCOL_63(conninfo_)		(strncmp((conninfo_)->protocol, PG63, strlen(PG63)) == 0)
 
 
 /*	This is used to store cached table information in the connection */
diff --git a/src/interfaces/odbc/convert.c b/src/interfaces/odbc/convert.c
index 1389c7ca3a..a5b3cbfd3f 100644
--- a/src/interfaces/odbc/convert.c
+++ b/src/interfaces/odbc/convert.c
@@ -24,6 +24,8 @@
 #include <string.h>
 #include <ctype.h>
 
+#include "psqlodbc.h"
+
 #ifndef WIN32
 #include "iodbc.h"
 #include "isql.h"
@@ -120,7 +122,7 @@ struct tm *tim;
 	st.d = tim->tm_mday;
 	st.y = tim->tm_year + 1900;
 
-	mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType, (value==NULL)?"<NULL>":value, cbValueMax);
+	mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType, value, cbValueMax);
 
 	if ( ! value) {
         /* handle a null just by returning SQL_NULL_DATA in pcbValue, */
diff --git a/src/interfaces/odbc/dlg_specific.c b/src/interfaces/odbc/dlg_specific.c
index 82e7e5a2b8..371b2d7ad8 100644
--- a/src/interfaces/odbc/dlg_specific.c
+++ b/src/interfaces/odbc/dlg_specific.c
@@ -87,6 +87,7 @@ int CALLBACK driver_optionsProc(HWND   hdlg,
 
 		CheckDlgButton(hdlg, DRV_COMMLOG, globals.commlog);
 		CheckDlgButton(hdlg, DRV_OPTIMIZER, globals.disable_optimizer);
+		CheckDlgButton(hdlg, DRV_KSQO, globals.ksqo);
 		CheckDlgButton(hdlg, DRV_UNIQUEINDEX, globals.unique_index);
 		CheckDlgButton(hdlg, DRV_READONLY, globals.readonly);
 		CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, globals.use_declarefetch);
@@ -128,6 +129,7 @@ int CALLBACK driver_optionsProc(HWND   hdlg,
 
 			globals.commlog = IsDlgButtonChecked(hdlg, DRV_COMMLOG);
 			globals.disable_optimizer = IsDlgButtonChecked(hdlg, DRV_OPTIMIZER);
+			globals.ksqo = IsDlgButtonChecked(hdlg, DRV_KSQO);
 			globals.unique_index = IsDlgButtonChecked(hdlg, DRV_UNIQUEINDEX);
 			globals.readonly = IsDlgButtonChecked(hdlg, DRV_READONLY);
 			globals.use_declarefetch = IsDlgButtonChecked(hdlg, DRV_USEDECLAREFETCH);
@@ -168,6 +170,7 @@ int CALLBACK driver_optionsProc(HWND   hdlg,
 		case IDDEFAULTS:
 			CheckDlgButton(hdlg, DRV_COMMLOG, DEFAULT_COMMLOG);
 			CheckDlgButton(hdlg, DRV_OPTIMIZER, DEFAULT_OPTIMIZER);
+			CheckDlgButton(hdlg, DRV_KSQO, DEFAULT_KSQO);
 			CheckDlgButton(hdlg, DRV_UNIQUEINDEX, DEFAULT_UNIQUEINDEX);
 			CheckDlgButton(hdlg, DRV_READONLY, DEFAULT_READONLY);
 			CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, DEFAULT_USEDECLAREFETCH);
@@ -238,8 +241,11 @@ char buf[128];
 		/*	Protocol */
 		if (strncmp(ci->protocol, PG62, strlen(PG62)) == 0)
 			CheckDlgButton(hdlg, DS_PG62, 1);
-		else
-			CheckDlgButton(hdlg, DS_PG62, 0);
+		else if (strncmp(ci->protocol, PG63, strlen(PG63)) == 0)
+			CheckDlgButton(hdlg, DS_PG63, 1);
+		else 
+			CheckDlgButton(hdlg, DS_PG64, 1);
+
 
 
 		CheckDlgButton(hdlg, DS_SHOWOIDCOLUMN, atoi(ci->show_oid_column));
@@ -273,11 +279,11 @@ char buf[128];
 			/*	Protocol */
 			if ( IsDlgButtonChecked(hdlg, DS_PG62))
 				strcpy(ci->protocol, PG62);
-			else 
+			else if ( IsDlgButtonChecked(hdlg, DS_PG63))
+				strcpy(ci->protocol, PG63);
+			else
 				ci->protocol[0] = '\0';
 
-
-
 			sprintf(ci->show_system_tables, "%d", IsDlgButtonChecked(hdlg, DS_SHOWSYSTEMTABLES));
 
 			sprintf(ci->row_versioning, "%d", IsDlgButtonChecked(hdlg, DS_ROWVERSIONING));
@@ -634,6 +640,13 @@ char temp[256];
 	else if ( ! override)
 		globals.disable_optimizer = DEFAULT_OPTIMIZER;
 
+	//	KSQO is stored in the driver section only
+	SQLGetPrivateProfileString(section, INI_KSQO, "", 
+				temp, sizeof(temp), filename);
+	if ( temp[0] ) 
+		globals.ksqo = atoi(temp);
+	else if ( ! override)
+		globals.ksqo = DEFAULT_KSQO;
 
 	//	Recognize Unique Index is stored in the driver section only
 	SQLGetPrivateProfileString(section, INI_UNIQUEINDEX, "", 
@@ -769,6 +782,10 @@ char tmp[128];
 	SQLWritePrivateProfileString(DBMS_NAME,
 		INI_OPTIMIZER, tmp, ODBCINST_INI);
 
+	sprintf(tmp, "%d", globals.ksqo);
+	SQLWritePrivateProfileString(DBMS_NAME,
+		INI_KSQO, tmp, ODBCINST_INI);
+
 	sprintf(tmp, "%d", globals.unique_index);
 	SQLWritePrivateProfileString(DBMS_NAME,
 		INI_UNIQUEINDEX, tmp, ODBCINST_INI);
diff --git a/src/interfaces/odbc/dlg_specific.h b/src/interfaces/odbc/dlg_specific.h
index b4e5ef05f1..829c9aeab7 100644
--- a/src/interfaces/odbc/dlg_specific.h
+++ b/src/interfaces/odbc/dlg_specific.h
@@ -59,6 +59,7 @@
 #define INI_COMMLOG       "CommLog"			/* Communication to backend logging */
 #define INI_PROTOCOL      "Protocol"		/* What protocol (6.2) */
 #define INI_OPTIMIZER     "Optimizer"		/* Use backend genetic optimizer */
+#define INI_KSQO          "Ksqo"            /* Keyset query optimization */
 #define INI_CONNSETTINGS  "ConnSettings"	/* Anything to send to backend on successful connection */
 #define INI_UNIQUEINDEX   "UniqueIndex"		/* Recognize unique indexes */
 #define INI_UNKNOWNSIZES  "UnknownSizes"	/* How to handle unknown result set sizes */
@@ -93,6 +94,7 @@
 #define DEFAULT_UNKNOWNSASLONGVARCHAR	0
 #define DEFAULT_BOOLSASCHAR				1
 #define DEFAULT_OPTIMIZER				1		// disable
+#define DEFAULT_KSQO					1		// on
 #define DEFAULT_UNIQUEINDEX				0		// dont recognize
 #define DEFAULT_COMMLOG					0		// dont log
 #define DEFAULT_DEBUG					0
diff --git a/src/interfaces/odbc/execute.c b/src/interfaces/odbc/execute.c
index 1baaaffc71..d87859c9fc 100644
--- a/src/interfaces/odbc/execute.c
+++ b/src/interfaces/odbc/execute.c
@@ -129,7 +129,7 @@ RETCODE SQL_API SQLExecDirect(
         SDWORD    cbSqlStr)
 {
 StatementClass *stmt = (StatementClass *) hstmt;
-RETCODE SQL_API result;
+RETCODE result;
 static char *func = "SQLExecDirect";
 
 	mylog( "%s: entering...\n", func);
diff --git a/src/interfaces/odbc/misc.c b/src/interfaces/odbc/misc.c
index 94a116299b..7e1501842c 100644
--- a/src/interfaces/odbc/misc.c
+++ b/src/interfaces/odbc/misc.c
@@ -44,7 +44,7 @@ generate_filename(char* dirname,char* prefix,char* filename)
 		return;
 
 	strcpy(filename,dirname);
-	strcat(filename,DIRSEPARATOR);
+	strcat(filename,DIRSEPERATOR);
 	if(prefix != 0)
 		strcat(filename,prefix);
 #ifndef WIN32
diff --git a/src/interfaces/odbc/misc.h b/src/interfaces/odbc/misc.h
index 10cb5114d1..194a08161c 100644
--- a/src/interfaces/odbc/misc.h
+++ b/src/interfaces/odbc/misc.h
@@ -26,7 +26,7 @@
 	portion of the registry.  You may have to manually add this key.
 	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).
@@ -39,41 +39,33 @@
 
 
 #ifdef MY_LOG
-  #define MYLOGFILE	"mylog_"
-  #ifndef WIN32
-    #define MYLOGDIR	"/tmp"
-  #else
-    #define MYLOGDIR	"c:"
-  #endif
-  void mylog();	/* prototype */
+#define MYLOGFILE	"mylog_"
+#ifndef WIN32
+#define MYLOGDIR	"/tmp"
+#else
+#define MYLOGDIR	"c:"
+#endif
+void mylog();	/* prototype */
 #else
-  #ifndef WIN32
-    #define mylog(args...)	/* GNU convention for variable arguments */
-  #else
-    #define mylog    // mylog
-  #endif
+#define mylog    // mylog
 #endif
 
 #ifdef Q_LOG
-  #define QLOGFILE	"psqlodbc_"
-  #ifndef WIN32
-    #define QLOGDIR		"/tmp"
-  #else
-    #define QLOGDIR		"c:"
-  #endif
-  void qlog();	/* prototype */
+#define QLOGFILE	"psqlodbc_"
+#ifndef WIN32
+#define QLOGDIR		"/tmp"
+#else
+#define QLOGDIR		"c:"
+#endif
+void qlog();	/* prototype */
 #else
-  #ifndef WIN32
-    #define qlog(args...)	/* GNU convention for variable arguments */
-  #else
-    #define qlog    // qlog
-  #endif
+#define qlog    // qlog
 #endif
 
 #ifndef WIN32
-#define DIRSEPARATOR	"/"
+#define DIRSEPERATOR	"/"
 #else
-#define DIRSEPARATOR	"\\"
+#define DIRSEPERATOR	"\\"
 #endif
 
 void remove_newlines(char *string);
diff --git a/src/interfaces/odbc/pgtypes.c b/src/interfaces/odbc/pgtypes.c
index 24ef584374..cdd9fc2654 100644
--- a/src/interfaces/odbc/pgtypes.c
+++ b/src/interfaces/odbc/pgtypes.c
@@ -242,6 +242,9 @@ mylog("getCharPrecision: type=%d, col=%d, unknown = %d\n", type,col,handle_unkno
 	}
 
 	/*	Size is unknown -- handle according to parameter */
+	if (QR_get_atttypmod(result, col) > -1)
+		return QR_get_atttypmod(result, col);
+
 	if (type == PG_TYPE_BPCHAR || handle_unknown_size_as == UNKNOWNS_AS_LONGEST) {
 		p = QR_get_display_size(result, col);
 		mylog("getCharPrecision: LONGEST: p = %d\n", p);
diff --git a/src/interfaces/odbc/psqlodbc.h b/src/interfaces/odbc/psqlodbc.h
index 05b3ee3018..d00c67dd82 100644
--- a/src/interfaces/odbc/psqlodbc.h
+++ b/src/interfaces/odbc/psqlodbc.h
@@ -33,6 +33,7 @@ typedef double SDOUBLE;
 
 typedef UInt4 Oid;
 
+# define ODBCVER   0x0200
 
 /* Limits */
 #define MAX_MESSAGE_LEN				8192
@@ -69,8 +70,8 @@ typedef UInt4 Oid;
 /* Driver stuff */
 #define DRIVERNAME             "PostgreSQL ODBC"
 #define DBMS_NAME              "PostgreSQL"
-#define DBMS_VERSION           "06.30.0250 PostgreSQL 6.3"
-#define POSTGRESDRIVERVERSION  "06.30.0250"
+#define DBMS_VERSION           "06.40.0001 PostgreSQL 6.4"
+#define POSTGRESDRIVERVERSION  "06.40.0001"
 
 #ifdef WIN32
 #define DRIVER_FILE_NAME		"PSQLODBC.DLL"
@@ -79,7 +80,7 @@ typedef UInt4 Oid;
 #endif
 
 #define PG62	"6.2"		/* "Protocol" key setting to force Postgres 6.2 */
-
+#define PG63	"6.3"		/* "Protocol" key setting to force postgres 6.3 */
 
 typedef struct ConnectionClass_ ConnectionClass;
 typedef struct StatementClass_ StatementClass;
@@ -106,6 +107,7 @@ typedef struct GlobalValues_
 	char				debug;
 	char				commlog;
 	char				disable_optimizer;
+	char				ksqo;
 	char				unique_index;
 	char				readonly;
 	char				use_declarefetch;
diff --git a/src/interfaces/odbc/psqlodbc.rc b/src/interfaces/odbc/psqlodbc.rc
index 3e6cafded4..779e82fea6 100644
--- a/src/interfaces/odbc/psqlodbc.rc
+++ b/src/interfaces/odbc/psqlodbc.rc
@@ -88,78 +88,77 @@ CAPTION "Advanced Options (Driver)"
 FONT 8, "MS Sans Serif"
 BEGIN
     CONTROL         "Disable Genetic &Optimizer",DRV_OPTIMIZER,"Button",
-                    BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,10,97,10
+                    BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,5,97,10
     CONTROL         "Comm&Log (C:\\psqlodbc.log)",DRV_COMMLOG,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,140,10,113,10
-    CONTROL         "Recognize Unique &Indexes",DRV_UNIQUEINDEX,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,15,25,101,10
+                    BS_AUTOCHECKBOX | WS_TABSTOP,140,5,113,10
+    CONTROL         "&KSQO (Keyset Query Optimization)",DRV_KSQO,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,15,20,124,10
     CONTROL         "&ReadOnly (Default)",DRV_READONLY,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,140,25,80,10
-    CONTROL         "&Use Declare/Fetch",DRV_USEDECLAREFETCH,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,15,40,80,10
+                    BS_AUTOCHECKBOX | WS_TABSTOP,140,20,80,10
+    CONTROL         "Recognize Unique &Indexes",DRV_UNIQUEINDEX,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,15,35,101,10
     CONTROL         "P&arse Statements",DRV_PARSE,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,140,40,80,10
-    GROUPBOX        "Unknown Sizes",IDC_STATIC,10,55,175,25
+                    WS_TABSTOP,140,35,80,10
+    CONTROL         "&Use Declare/Fetch",DRV_USEDECLAREFETCH,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,15,50,80,10
+    GROUPBOX        "Unknown Sizes",IDC_STATIC,10,65,175,25
     CONTROL         "Maximum",DRV_UNKNOWN_MAX,"Button",BS_AUTORADIOBUTTON | 
-                    WS_GROUP | WS_TABSTOP,15,65,45,10
+                    WS_GROUP | WS_TABSTOP,15,76,45,10
     CONTROL         "Don't Know",DRV_UNKNOWN_DONTKNOW,"Button",
-                    BS_AUTORADIOBUTTON | WS_TABSTOP,70,65,53,10
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,70,76,53,10
     CONTROL         "Longest",DRV_UNKNOWN_LONGEST,"Button",
-                    BS_AUTORADIOBUTTON | WS_TABSTOP,130,65,50,10
-    GROUPBOX        "Data Type Options",IDC_STATIC,10,85,270,25
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,130,76,50,10
+    GROUPBOX        "Data Type Options",IDC_STATIC,10,95,270,25
     CONTROL         "Text as LongVarChar",DRV_TEXT_LONGVARCHAR,"Button",
-                    BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,95,80,10
+                    BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,105,80,10
     CONTROL         "Unknowns as LongVarChar",DRV_UNKNOWNS_LONGVARCHAR,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,95,100,10
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,105,100,10
     CONTROL         "Bools as Char",DRV_BOOLS_CHAR,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,215,95,60,10
-    LTEXT           "&Cache Size:",IDC_STATIC,10,120,40,10
-    EDITTEXT        DRV_CACHE_SIZE,50,120,35,12,ES_AUTOHSCROLL
-    LTEXT           "Max &Varchar:",IDC_STATIC,90,120,45,10
-    EDITTEXT        DRV_VARCHAR_SIZE,135,120,35,12,ES_AUTOHSCROLL
-    LTEXT           "Max Lon&gVarChar:",IDC_STATIC,180,120,60,10
-    EDITTEXT        DRV_LONGVARCHAR_SIZE,240,120,35,12,ES_AUTOHSCROLL
-    LTEXT           "SysTable &Prefixes:",IDC_STATIC,15,135,35,20
-    EDITTEXT        DRV_EXTRASYSTABLEPREFIXES,50,140,75,12,ES_AUTOHSCROLL
-    RTEXT           "Connect &Settings:",IDC_STATIC,10,165,35,25
-    EDITTEXT        DRV_CONNSETTINGS,50,160,225,35,ES_MULTILINE | 
+                    WS_TABSTOP,215,105,60,10
+    LTEXT           "&Cache Size:",IDC_STATIC,10,130,40,10
+    EDITTEXT        DRV_CACHE_SIZE,50,130,35,12,ES_AUTOHSCROLL
+    LTEXT           "Max &Varchar:",IDC_STATIC,90,130,45,10
+    EDITTEXT        DRV_VARCHAR_SIZE,135,130,35,12,ES_AUTOHSCROLL
+    LTEXT           "Max Lon&gVarChar:",IDC_STATIC,180,130,60,10
+    EDITTEXT        DRV_LONGVARCHAR_SIZE,240,130,35,12,ES_AUTOHSCROLL
+    LTEXT           "SysTable &Prefixes:",IDC_STATIC,15,145,35,20
+    EDITTEXT        DRV_EXTRASYSTABLEPREFIXES,50,151,75,12,ES_AUTOHSCROLL
+    RTEXT           "Connect &Settings:",IDC_STATIC,10,170,35,20
+    EDITTEXT        DRV_CONNSETTINGS,50,170,225,25,ES_MULTILINE | 
                     ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
     DEFPUSHBUTTON   "OK",IDOK,45,205,50,14,WS_GROUP
     PUSHBUTTON      "Cancel",IDCANCEL,115,205,50,14
     PUSHBUTTON      "Defaults",IDDEFAULTS,185,205,50,15
 END
 
-DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 267, 170
+DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 267, 161
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Advanced Options (DataSource)"
 FONT 8, "MS Sans Serif"
 BEGIN
     CONTROL         "&ReadOnly",DS_READONLY,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,25,10,45,15
-    CONTROL         "&6.2 Protocol",DS_PG62,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,130,10,60,14
-    CONTROL         "Show System &Tables",DS_SHOWSYSTEMTABLES,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,25,30,85,10
+                    WS_GROUP | WS_TABSTOP,25,10,53,10
     CONTROL         "Row &Versioning",DS_ROWVERSIONING,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,130,30,85,10
-    GROUPBOX        "OID Options",IDC_STATIC,15,50,180,25
+                    BS_AUTOCHECKBOX | WS_TABSTOP,130,10,85,10
+    CONTROL         "Show System &Tables",DS_SHOWSYSTEMTABLES,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,25,25,85,10
+    GROUPBOX        "Protocol",IDC_STATIC,15,40,180,25
+    CONTROL         "6.4",DS_PG64,"Button",BS_AUTORADIOBUTTON | WS_GROUP,25,
+                    50,26,10
+    CONTROL         "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+                    75,50,26,10
+    CONTROL         "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+                    130,50,26,10
+    GROUPBOX        "OID Options",IDC_STATIC,15,70,180,25
     CONTROL         "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,25,60,59,10
+                    WS_GROUP | WS_TABSTOP,25,81,59,10
     CONTROL         "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,115,60,51,10
-    RTEXT           "Connect &Settings:",IDC_STATIC,10,90,35,25
-    EDITTEXT        DS_CONNSETTINGS,50,85,200,35,ES_MULTILINE | 
+                    WS_GROUP | WS_TABSTOP,115,81,51,10
+    RTEXT           "Connect &Settings:",IDC_STATIC,10,105,35,25
+    EDITTEXT        DS_CONNSETTINGS,50,105,200,20,ES_MULTILINE | 
                     ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
-    DEFPUSHBUTTON   "OK",IDOK,65,130,50,14,WS_GROUP
-    PUSHBUTTON      "Cancel",IDCANCEL,140,130,50,14
-    GROUPBOX        "Unknown Sizes",IDC_STATIC,10,145,175,25,NOT WS_VISIBLE
-    CONTROL         "Maximum",DS_UNKNOWN_MAX,"Button",BS_AUTORADIOBUTTON | 
-                    NOT WS_VISIBLE | WS_GROUP | WS_TABSTOP,15,155,45,10
-    CONTROL         "Don't Know",DS_UNKNOWN_DONTKNOW,"Button",
-                    BS_AUTORADIOBUTTON | NOT WS_VISIBLE | WS_TABSTOP,70,155,
-                    53,10
-    CONTROL         "Longest",DS_UNKNOWN_LONGEST,"Button",BS_AUTORADIOBUTTON | 
-                    NOT WS_VISIBLE | WS_TABSTOP,130,155,50,10
+    DEFPUSHBUTTON   "OK",IDOK,71,135,50,14,WS_GROUP
+    PUSHBUTTON      "Cancel",IDCANCEL,146,135,50,14
 END
 
 
@@ -190,7 +189,7 @@ BEGIN
         RIGHTMARGIN, 260
         VERTGUIDE, 55
         TOPMARGIN, 7
-        BOTTOMMARGIN, 163
+        BOTTOMMARGIN, 154
     END
 END
 #endif    // APSTUDIO_INVOKED
@@ -203,8 +202,8 @@ END
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 6,30,2,50
- PRODUCTVERSION 6,30,2,50
+ FILEVERSION 6,40,0,1
+ PRODUCTVERSION 6,40,0,1
  FILEFLAGSMASK 0x3L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -222,12 +221,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.0250\0"
+            VALUE "FileVersion", " 6.40.0001\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.0250\0"
+            VALUE "ProductVersion", " 6.40.0001\0"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/src/interfaces/odbc/qresult.c b/src/interfaces/odbc/qresult.c
index cae730d8ae..d5ee8407c8 100644
--- a/src/interfaces/odbc/qresult.c
+++ b/src/interfaces/odbc/qresult.c
@@ -186,8 +186,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
 	if (conn != NULL) {
 		self->conn = conn;
 
-		mylog("QR_fetch_tuples: cursor = '%s', self->cursor=%u\n", 
-		(cursor==NULL)?"":cursor, self->cursor);
+		mylog("QR_fetch_tuples: cursor = '%s', self->cursor=%u\n", cursor, self->cursor);
 
 		if (self->cursor)
 			free(self->cursor);
@@ -203,7 +202,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
 
 		//	Read the field attributes.
 		//	$$$$ Should do some error control HERE! $$$$
-		if ( CI_read_fields(self->fields, CC_get_socket(self->conn))) {
+		if ( CI_read_fields(self->fields, self->conn)) {
 			self->status = PGRES_FIELDS_OK;
 			self->num_fields = CI_get_num_fields(self->fields);
 		}
@@ -236,7 +235,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
 		//	Always have to read the field attributes.
 		//	But we dont have to reallocate memory for them!
 
-		if ( ! CI_read_fields(NULL, CC_get_socket(self->conn))) {
+		if ( ! CI_read_fields(NULL, self->conn)) {
 			self->status = PGRES_BAD_RESPONSE;
 			QR_set_message(self, "Error reading field information");
 			return FALSE;
@@ -369,6 +368,7 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 	for ( ; ;) {
 
 		id = SOCK_get_char(sock);
+
 		switch (id) {
 		case 'T': /* Tuples within tuples cannot be handled */
 			self->status = PGRES_BAD_RESPONSE;
@@ -441,6 +441,8 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 			continue;
 
 		default: /* this should only happen if the backend dumped core */
+			mylog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id);
+			qlog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id);
 			QR_set_message(self, "Unexpected result from backend. It probably crashed");
 			self->status = PGRES_FATAL_ERROR;
 			CC_set_no_trans(self->conn);
diff --git a/src/interfaces/odbc/qresult.h b/src/interfaces/odbc/qresult.h
index f05830d6d4..7cc2303173 100644
--- a/src/interfaces/odbc/qresult.h
+++ b/src/interfaces/odbc/qresult.h
@@ -72,12 +72,13 @@ struct QResultClass_ {
 #define QR_get_fieldname(self, fieldno_)	(CI_get_fieldname(self->fields, fieldno_))
 #define QR_get_fieldsize(self, fieldno_)	(CI_get_fieldsize(self->fields, fieldno_))    
 #define QR_get_display_size(self, fieldno_)	(CI_get_display_size(self->fields, fieldno_))    
+#define QR_get_atttypmod(self, fieldno_)	(CI_get_atttypmod(self->fields, fieldno_))    
 #define QR_get_field_type(self, fieldno_)   (CI_get_oid(self->fields, fieldno_))
 
 /*	These functions are used only for manual result sets */
 #define QR_get_num_tuples(self)				(self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->fcount)
 #define QR_add_tuple(self, new_tuple)		(TL_add_tuple(self->manual_tuples, new_tuple))
-#define QR_set_field_info(self, field_num, name, adtid, adtsize)  (CI_set_field_info(self->fields, field_num, name, adtid, adtsize))
+#define QR_set_field_info(self, field_num, name, adtid, adtsize)  (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1))
 
 /* status macros */
 #define QR_command_successful(self)		( !(self->status == PGRES_BAD_RESPONSE || self->status == PGRES_NONFATAL_ERROR || self->status == PGRES_FATAL_ERROR))
diff --git a/src/interfaces/odbc/resource.h b/src/interfaces/odbc/resource.h
index c69953fe8d..16db18bbd2 100644
--- a/src/interfaces/odbc/resource.h
+++ b/src/interfaces/odbc/resource.h
@@ -24,8 +24,6 @@
 #define DRV_OPTIMIZER                   1019
 #define DS_CONNSETTINGS                 1020
 #define IDC_DRIVER                      1021
-#define DS_UNKNOWN_MAX                  1023
-#define DS_UNKNOWN_DONTKNOW             1024
 #define DRV_CONNSETTINGS                1031
 #define DRV_UNIQUEINDEX                 1032
 #define DRV_UNKNOWN_MAX                 1035
@@ -34,7 +32,6 @@
 #define IDC_DESCTEXT                    1039
 #define DRV_MSG_LABEL                   1040
 #define DRV_UNKNOWN_LONGEST             1041
-#define DS_UNKNOWN_LONGEST              1042
 #define DRV_TEXT_LONGVARCHAR            1043
 #define DRV_UNKNOWNS_LONGVARCHAR        1044
 #define DRV_CACHE_SIZE                  1045
@@ -48,6 +45,9 @@
 #define DS_ROWVERSIONING                1052
 #define DRV_PARSE                       1052
 #define IDC_OPTIONS                     1054
+#define DRV_KSQO                        1055
+#define DS_PG64                         1057
+#define DS_PG63                         1058
 
 // Next default values for new objects
 // 
@@ -55,7 +55,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        104
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1055
+#define _APS_NEXT_CONTROL_VALUE         1060
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
diff --git a/src/interfaces/odbc/results.c b/src/interfaces/odbc/results.c
index 6bac9d0ede..5d9dfc30fb 100644
--- a/src/interfaces/odbc/results.c
+++ b/src/interfaces/odbc/results.c
@@ -855,7 +855,7 @@ mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
 				value = QR_get_value_backend_row(res, stmt->currTuple, lf);
 			}
 
-			mylog("value = '%s'\n", (value==NULL)?"<NULL>":value);
+			mylog("value = '%s'\n", value);
 
 			retval = copy_and_convert_field_bindinfo(stmt, type, value, lf);
 
diff --git a/src/interfaces/odbc/socket.h b/src/interfaces/odbc/socket.h
index 50418f9942..d57d012a48 100644
--- a/src/interfaces/odbc/socket.h
+++ b/src/interfaces/odbc/socket.h
@@ -23,13 +23,6 @@
 #include <arpa/inet.h>
 #define closesocket(xxx) close(xxx)
 #define SOCKETFD int
-#ifndef       INADDR_NONE
-#ifndef _IN_ADDR_T
-#define _IN_ADDR_T
-typedef unsigned int    in_addr_t;
-#endif
-#define INADDR_NONE ((in_addr_t)-1)
-#endif
 #else
 #include <winsock.h>
 #define SOCKETFD SOCKET
diff --git a/src/interfaces/odbc/statement.h b/src/interfaces/odbc/statement.h
index 52b64278c1..e9661ad83a 100644
--- a/src/interfaces/odbc/statement.h
+++ b/src/interfaces/odbc/statement.h
@@ -14,6 +14,8 @@
 #include "config.h"
 #endif
 
+#include "psqlodbc.h"
+
 #ifndef WIN32
 #include "iodbc.h"
 #include "isql.h"
@@ -22,7 +24,6 @@
 #include <sql.h>
 #endif
 
-#include "psqlodbc.h"
 
 #ifndef FALSE
 #define FALSE	(BOOL)0
-- 
2.50.1