From e1716475e40c3305550fbf3b59ff47e551545036 Mon Sep 17 00:00:00 2001
From: Hiroshi Inoue <inoue@tpf.co.jp>
Date: Fri, 1 Mar 2002 07:18:34 +0000
Subject: [PATCH] Add files for Unicode support.

---
 src/interfaces/odbc/connection.h  |   1 +
 src/interfaces/odbc/odbcapi25w.c  |  75 ++++
 src/interfaces/odbc/odbcapi30w.c  | 122 +++++++
 src/interfaces/odbc/odbcapiw.c    | 562 ++++++++++++++++++++++++++++++
 src/interfaces/odbc/pgapi30.c     | 495 ++++++++++++++++++++++++++
 src/interfaces/odbc/win_unicode.c | 137 ++++++++
 6 files changed, 1392 insertions(+)
 create mode 100644 src/interfaces/odbc/odbcapi25w.c
 create mode 100644 src/interfaces/odbc/odbcapi30w.c
 create mode 100755 src/interfaces/odbc/odbcapiw.c
 create mode 100644 src/interfaces/odbc/pgapi30.c
 create mode 100644 src/interfaces/odbc/win_unicode.c

diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h
index 0ef91a139f0..df40f440d69 100644
--- a/src/interfaces/odbc/connection.h
+++ b/src/interfaces/odbc/connection.h
@@ -266,6 +266,7 @@ struct ConnectionClass_
 	Int2		pg_version_major;
 	Int2		pg_version_minor;
 	char		ms_jet;
+	char		unicode;
 #ifdef	MULTIBYTE
 	char	   *client_encoding;
 	char	   *server_encoding;
diff --git a/src/interfaces/odbc/odbcapi25w.c b/src/interfaces/odbc/odbcapi25w.c
new file mode 100644
index 00000000000..0bebf5d128c
--- /dev/null
+++ b/src/interfaces/odbc/odbcapi25w.c
@@ -0,0 +1,75 @@
+/*-------
+ * Module:			odbcapi25w.c
+ *
+ * Description:		This module contains UNICODE routines
+ *
+ * Classes:			n/a
+ *
+ * API functions:	SQLColAttributesW, SQLErrorW, SQLGetConnectOptionW,
+			SQLSetConnectOptionW
+ *-------
+ */
+
+#include "psqlodbc.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "pgapifunc.h"
+#include "connection.h"
+#include "statement.h"
+
+RETCODE  SQL_API SQLErrorW(HENV EnvironmentHandle,
+           HDBC ConnectionHandle, HSTMT StatementHandle,
+           SQLWCHAR *Sqlstate, SQLINTEGER *NativeError,
+           SQLWCHAR *MessageText, SQLSMALLINT BufferLength,
+           SQLSMALLINT *TextLength)
+{
+	RETCODE	ret;
+	SWORD	tlen;
+	char	*qst = NULL, *mtxt = NULL;
+
+	mylog("[SQLErrorW]");
+	if (Sqlstate)
+		qst = malloc(8);
+	if (MessageText)
+		mtxt = malloc(BufferLength);	
+	ret = PGAPI_Error(EnvironmentHandle, ConnectionHandle, StatementHandle,
+           	qst, NativeError, mtxt, BufferLength, &tlen);
+	if (qst)
+		utf8_to_ucs2(qst, strlen(qst), Sqlstate, 5);
+	if (TextLength)
+		*TextLength = utf8_to_ucs2(mtxt, tlen, MessageText, BufferLength);
+	free(qst);
+	free(mtxt);
+	return ret;
+}
+
+RETCODE  SQL_API SQLGetConnectOptionW(HDBC ConnectionHandle,
+           SQLUSMALLINT Option, PTR Value)
+{
+	mylog("[SQLGetConnectOptionW]");
+	((ConnectionClass *) ConnectionHandle)->unicode = 1;
+	return PGAPI_GetConnectOption(ConnectionHandle, Option, Value);
+} 
+
+RETCODE  SQL_API SQLSetConnectOptionW(HDBC ConnectionHandle,
+           SQLUSMALLINT Option, SQLUINTEGER Value)
+{
+	mylog("[SQLSetConnectionOptionW]");
+	((ConnectionClass *) ConnectionHandle)->unicode = 1;
+	return PGAPI_SetConnectOption(ConnectionHandle, Option, Value);
+}
+
+RETCODE SQL_API SQLColAttributesW(
+    HSTMT           hstmt,
+    SQLUSMALLINT       icol,
+    SQLUSMALLINT       fDescType,
+    PTR         rgbDesc,
+    SQLSMALLINT        cbDescMax,
+    SQLSMALLINT 	  *pcbDesc,
+    SQLINTEGER 		  *pfDesc)
+{
+	mylog("[SQLColAttributesW]");
+	return PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
+		cbDescMax, pcbDesc, pfDesc);
+}
diff --git a/src/interfaces/odbc/odbcapi30w.c b/src/interfaces/odbc/odbcapi30w.c
new file mode 100644
index 00000000000..d2a2005c1b9
--- /dev/null
+++ b/src/interfaces/odbc/odbcapi30w.c
@@ -0,0 +1,122 @@
+/*-------
+ * Module:			odbcapi30w.c
+ *
+ * Description:		This module contains UNICODE routines
+ *
+ * Classes:			n/a
+ *
+ * API functions:	SQLColAttributeW, SQLGetStmtW, SQLSetStmtW,
+ 			SQLSetConnectAttrW, SQLGetConnectAttrW,
+			SQLGetDescFieldW, SQLGetDescRecW, SQLGetDiagFieldW,
+			SQLGetDiagRecW,
+ *-------
+ */
+
+#include "psqlodbc.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "pgapifunc.h"
+#include "connection.h"
+#include "statement.h"
+
+
+RETCODE	SQL_API	SQLGetStmtAttrW(SQLHSTMT hstmt,
+		SQLINTEGER	fAttribute,
+		PTR		rgbValue,
+		SQLINTEGER	cbValueMax,
+		SQLINTEGER	*pcbValue)
+{
+	RETCODE	ret;
+
+	mylog("[SQLGetStmtAttrW]");
+	ret = PGAPI_GetStmtAttr(hstmt, fAttribute, rgbValue,
+		cbValueMax, pcbValue);
+	return ret;
+}
+
+RETCODE SQL_API	SQLSetStmtAttrW(SQLHSTMT hstmt,
+		SQLINTEGER	fAttribute,
+		PTR		rgbValue,
+		SQLINTEGER	cbValueMax)
+{
+	RETCODE	ret;
+
+	mylog("[SQLSetStmtAttrW]");
+	ret = PGAPI_SetStmtAttr(hstmt, fAttribute, rgbValue,
+		cbValueMax);
+	return ret;
+}
+
+RETCODE SQL_API	SQLGetConnectAttrW(HDBC hdbc,
+		SQLINTEGER	fAttribute,
+		PTR		rgbValue,
+		SQLINTEGER	cbValueMax,
+		SQLINTEGER	*pcbValue)
+{
+	RETCODE	ret;
+
+	mylog("[SQLGetConnectAttrW]");
+	ret = PGAPI_GetConnectAttr(hdbc, fAttribute, rgbValue,
+		cbValueMax, pcbValue);
+	return ret;
+}
+
+RETCODE SQL_API	SQLSetConnectAttrW(HDBC hdbc,
+		SQLINTEGER	fAttribute,
+		PTR		rgbValue,
+		SQLINTEGER	cbValue)
+{
+	RETCODE	ret;
+
+	mylog("[SQLSetConnectAttrW]");
+	ret = PGAPI_SetConnectAttr(hdbc, fAttribute, rgbValue,
+		cbValue);
+	return ret;
+}
+
+RETCODE SQL_API	SQLGetDiagRecW(SWORD fHandleType,
+		SQLHANDLE	handle,
+		SQLSMALLINT	iRecord,
+		SQLWCHAR	*szSqlState,
+		SQLINTEGER	*pfNativeError,
+		SQLWCHAR	*szErrorMsg,
+		SQLSMALLINT	cbErrorMsgMax,
+		SQLSMALLINT	*pcbErrorMsg)
+{
+	RETCODE	ret;
+        SWORD   tlen;
+        char    *qst = NULL, *mtxt = NULL;
+
+	mylog("[SQLGetDiagRecW]");
+        if (szSqlState)
+                qst = malloc(8);
+        if (szErrorMsg)
+                mtxt = malloc(cbErrorMsgMax);
+        ret = PGAPI_GetDiagRec(fHandleType, handle, iRecord, qst,
+                pfNativeError, mtxt, cbErrorMsgMax, &tlen);
+        if (qst)
+                utf8_to_ucs2(qst, strlen(qst), szSqlState, 5);
+	if (pcbErrorMsg)
+        	*pcbErrorMsg = utf8_to_ucs2(mtxt, tlen, szErrorMsg, cbErrorMsgMax);
+        free(qst);
+        free(mtxt);
+        return ret;
+}
+
+RETCODE SQL_API SQLColAttributeW(
+    HSTMT           hstmt,
+    SQLUSMALLINT       icol,
+    SQLUSMALLINT       fDescType,
+    PTR			rgbDesc,
+    SQLSMALLINT        cbDescMax,
+    SQLSMALLINT 	  *pcbDesc,
+    SQLINTEGER 		  *pfDesc)
+{
+	RETCODE	ret;
+
+	mylog("[SQLColAttributeW]");
+	ret = PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
+		cbDescMax, pcbDesc, pfDesc);
+	return ret;
+}
diff --git a/src/interfaces/odbc/odbcapiw.c b/src/interfaces/odbc/odbcapiw.c
new file mode 100755
index 00000000000..637f69f9699
--- /dev/null
+++ b/src/interfaces/odbc/odbcapiw.c
@@ -0,0 +1,562 @@
+/*-------
+ * Module:			odbcapiw.c
+ *
+ * Description:		This module contains UNICODE routines
+ *
+ * Classes:			n/a
+ *
+ * API functions:	SQLColumnPrivilegesW, SQLColumnsW,
+ 			SQLConnectW, SQLDataSourcesW, SQLDescribeColW,
+			SQLDriverConnectW, SQLExecDirectW,
+			SQLForeignKeysW,
+			SQLGetCursorNameW, SQLGetInfoW, SQLNativeSqlW,
+			SQLPrepareW, SQLPrimaryKeysW, SQLProcedureColumnsW,
+			SQLProceduresW, SQLSetCursorNameW,
+			SQLSpecialColumnsW, SQLStatisticsW, SQLTablesW,
+			SQLTablePrivilegesW
+ *-------
+ */
+
+#include "psqlodbc.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "pgapifunc.h"
+#include "connection.h"
+#include "statement.h"
+
+RETCODE  SQL_API SQLColumnsW(HSTMT StatementHandle,
+           SQLWCHAR *CatalogName, SQLSMALLINT NameLength1,
+           SQLWCHAR *SchemaName, SQLSMALLINT NameLength2,
+           SQLWCHAR *TableName, SQLSMALLINT NameLength3,
+           SQLWCHAR *ColumnName, SQLSMALLINT NameLength4)
+{
+	RETCODE	ret;
+	char	*ctName, *scName, *tbName, *clName;
+	UInt4	nmlen1, nmlen2, nmlen3, nmlen4;
+
+	mylog("[SQLColumnsW]");
+	ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1);
+	scName = ucs2_to_utf8(SchemaName, NameLength2, &nmlen2);
+	tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3);
+	clName = ucs2_to_utf8(ColumnName, NameLength4, &nmlen4);
+	ret = PGAPI_Columns(StatementHandle, ctName, (SWORD) nmlen1,
+           	scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
+           	clName, (SWORD) nmlen4, 0);
+	if (ctName)
+		free(ctName);
+	if (scName);
+		free(scName);
+	if (tbName)
+		free(tbName);
+	if (clName);
+		free(clName);
+	return ret;
+}
+
+
+RETCODE  SQL_API SQLConnectW(HDBC ConnectionHandle,
+           SQLWCHAR *ServerName, SQLSMALLINT NameLength1,
+           SQLWCHAR *UserName, SQLSMALLINT NameLength2,
+           SQLWCHAR *Authentication, SQLSMALLINT NameLength3)
+{
+	char	*svName, *usName, *auth;
+	UInt4	nmlen1, nmlen2, nmlen3;
+	RETCODE	ret;
+	
+	mylog("[SQLConnectW]");
+	((ConnectionClass *) ConnectionHandle)->unicode = 1;
+	svName = ucs2_to_utf8(ServerName, NameLength1, &nmlen1);
+	usName = ucs2_to_utf8(UserName, NameLength2, &nmlen2);
+	auth = ucs2_to_utf8(Authentication, NameLength3, &nmlen3);
+	ret = PGAPI_Connect(ConnectionHandle, svName, (SWORD) nmlen1,
+           	usName, (SWORD) nmlen2, auth, (SWORD) nmlen3);
+	if (svName);
+		free(svName);
+	if (usName);
+		free(usName);
+	if (auth);
+		free(auth);
+	return ret;
+}
+
+RETCODE SQL_API SQLDriverConnectW(HDBC hdbc,
+                                 HWND hwnd,
+                                 SQLWCHAR *szConnStrIn,
+                                 SWORD cbConnStrIn,
+                                 SQLWCHAR *szConnStrOut,
+                                 SWORD cbConnStrOutMax,
+                                 SWORD FAR *pcbConnStrOut,
+                                 UWORD fDriverCompletion)
+{
+	char	*szIn, *szOut;
+	UInt4	inlen, obuflen;
+	SWORD	olen;
+	RETCODE	ret;
+
+	mylog("[SQLDriverConnectW]");
+	((ConnectionClass *) hdbc)->unicode = 1;
+	szIn = ucs2_to_utf8(szConnStrIn, cbConnStrIn, &inlen);
+	obuflen = cbConnStrOutMax + 1;
+	szOut = malloc(obuflen);
+	ret = PGAPI_DriverConnect(hdbc, hwnd, szIn, (SWORD) inlen,
+		szOut, cbConnStrOutMax, &olen, fDriverCompletion);
+	if (ret != SQL_ERROR)
+		*pcbConnStrOut = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
+	free(szOut);
+	if (szIn);
+		free(szIn);
+	return ret;
+}
+RETCODE SQL_API SQLBrowseConnectW(
+    HDBC            hdbc,
+    SQLWCHAR 		  *szConnStrIn,
+    SQLSMALLINT        cbConnStrIn,
+    SQLWCHAR 		  *szConnStrOut,
+    SQLSMALLINT        cbConnStrOutMax,
+    SQLSMALLINT       *pcbConnStrOut)
+{
+	char	*szIn, *szOut;
+	UInt4	inlen, obuflen;
+	SWORD	olen;
+	RETCODE	ret;
+
+	mylog("[SQLBrowseConnectW]");
+	((ConnectionClass *) hdbc)->unicode = 1;
+	szIn = ucs2_to_utf8(szConnStrIn, cbConnStrIn, &inlen);
+	obuflen = cbConnStrOutMax + 1;
+	szOut = malloc(obuflen);
+	ret = PGAPI_BrowseConnect(hdbc, szIn, (SWORD) inlen,
+		szOut, cbConnStrOutMax, &olen);
+	if (ret != SQL_ERROR)
+		*pcbConnStrOut = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
+	free(szOut);
+	if (szIn);
+		free(szIn);
+	return ret;
+}
+
+RETCODE  SQL_API SQLDataSourcesW(HENV EnvironmentHandle,
+           SQLUSMALLINT Direction, SQLWCHAR *ServerName,
+           SQLSMALLINT BufferLength1, SQLSMALLINT *NameLength1,
+           SQLWCHAR *Description, SQLSMALLINT BufferLength2,
+           SQLSMALLINT *NameLength2)
+{
+	mylog("[SQLDataSourcesW]");
+	/*
+	return PGAPI_DataSources(EnvironmentHandle, Direction, ServerName,
+		 BufferLength1, NameLength1, Description, BufferLength2,
+           	NameLength2);
+	*/
+	return SQL_ERROR;
+}
+
+RETCODE  SQL_API SQLDescribeColW(HSTMT StatementHandle,
+           SQLUSMALLINT ColumnNumber, SQLWCHAR *ColumnName,
+           SQLSMALLINT BufferLength, SQLSMALLINT *NameLength,
+           SQLSMALLINT *DataType, SQLUINTEGER *ColumnSize,
+           SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable)
+{
+	RETCODE	ret;
+	SWORD	nmlen;
+	char	*clName;
+
+	mylog("[SQLDescribeColW]");
+	clName = malloc(BufferLength);
+	ret = PGAPI_DescribeCol(StatementHandle, ColumnNumber,
+		clName, BufferLength, &nmlen,
+           	DataType, ColumnSize, DecimalDigits, Nullable);
+	*NameLength = utf8_to_ucs2(clName, nmlen, ColumnName, BufferLength);
+	free(clName); 
+	return ret;
+}
+
+RETCODE  SQL_API SQLExecDirectW(HSTMT StatementHandle,
+           SQLWCHAR *StatementText, SQLINTEGER TextLength)
+{
+	RETCODE	ret;
+	char	*stxt;
+	UInt4	slen;
+
+	mylog("[SQLExecDirectW]");
+	stxt = ucs2_to_utf8(StatementText, TextLength, &slen);
+	ret = PGAPI_ExecDirect(StatementHandle, stxt, slen);
+	if (stxt);
+		free(stxt);
+	return ret;
+}
+
+RETCODE  SQL_API SQLGetCursorNameW(HSTMT StatementHandle,
+           SQLWCHAR *CursorName, SQLSMALLINT BufferLength,
+           SQLSMALLINT *NameLength)
+{
+	RETCODE	ret;
+	char	*crName;
+	SWORD	clen;
+
+	mylog("[SQLGetCursorNameW]");
+	crName = malloc(BufferLength);
+	ret = PGAPI_GetCursorName(StatementHandle, crName, BufferLength,
+           	&clen);
+	*NameLength = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength);
+	free(crName);
+	return ret;
+}
+
+RETCODE  SQL_API SQLGetInfoW(HDBC ConnectionHandle,
+           SQLUSMALLINT InfoType, PTR InfoValue,
+           SQLSMALLINT BufferLength, SQLSMALLINT *StringLength)
+{
+	RETCODE	ret;
+	((ConnectionClass *) ConnectionHandle)->unicode = 1;
+#if (ODBCVER >= 0x0300)
+	mylog("[SQLGetInfoW(30)]");
+	if ((ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
+           	BufferLength, StringLength)) == SQL_ERROR)
+	{
+		if (((ConnectionClass *) ConnectionHandle)->driver_version >= 0x0300)
+			return PGAPI_GetInfo30(ConnectionHandle, InfoType, InfoValue,
+           			BufferLength, StringLength);
+	}
+	return ret;
+#else
+	mylog("[SQLGetInfoW]");
+	return PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
+           	BufferLength, StringLength);
+#endif
+}
+
+RETCODE  SQL_API SQLPrepareW(HSTMT StatementHandle,
+           SQLWCHAR *StatementText, SQLINTEGER TextLength)
+{
+	RETCODE	ret;
+	char	*stxt;
+	UInt4	slen;
+
+	mylog("[SQLPrepareW]");
+	stxt = ucs2_to_utf8(StatementText, TextLength, &slen);
+	ret = PGAPI_Prepare(StatementHandle, stxt, slen);
+	if (stxt);
+		free(stxt);
+	return ret;
+}
+
+RETCODE  SQL_API SQLSetCursorNameW(HSTMT StatementHandle,
+           SQLWCHAR *CursorName, SQLSMALLINT NameLength)
+{
+	RETCODE	ret;
+	char	*crName;
+	UInt4	nlen;
+
+	mylog("[SQLSetCursorNameW]");
+	crName = ucs2_to_utf8(CursorName, NameLength, &nlen);
+	ret = PGAPI_SetCursorName(StatementHandle, crName, (SWORD) nlen);
+	if (crName);
+		free(crName);
+	return ret;
+}
+
+RETCODE  SQL_API SQLSpecialColumnsW(HSTMT StatementHandle,
+           SQLUSMALLINT IdentifierType, SQLWCHAR *CatalogName,
+           SQLSMALLINT NameLength1, SQLWCHAR *SchemaName,
+           SQLSMALLINT NameLength2, SQLWCHAR *TableName,
+           SQLSMALLINT NameLength3, SQLUSMALLINT Scope,
+           SQLUSMALLINT Nullable)
+{
+	RETCODE	ret;
+	char	*ctName, *scName, *tbName;
+	UInt4	nmlen1, nmlen2, nmlen3;
+	
+	mylog("[SQLSpecialColumnsW]");
+	ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1);
+	scName = ucs2_to_utf8(SchemaName, NameLength2, &nmlen2);
+	tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3);
+	ret = PGAPI_SpecialColumns(StatementHandle, IdentifierType, ctName,
+           (SWORD) nmlen1, scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
+		Scope, Nullable);
+	if (ctName);
+		free(ctName);
+	if (scName);
+		free(scName);
+	if (tbName);
+		free(tbName);
+	return ret;
+}
+
+RETCODE  SQL_API SQLStatisticsW(HSTMT StatementHandle,
+           SQLWCHAR *CatalogName, SQLSMALLINT NameLength1,
+           SQLWCHAR *SchemaName, SQLSMALLINT NameLength2,
+           SQLWCHAR *TableName, SQLSMALLINT NameLength3,
+           SQLUSMALLINT Unique, SQLUSMALLINT Reserved)
+{
+	RETCODE	ret;
+	char	*ctName, *scName, *tbName;
+	UInt4	nmlen1, nmlen2, nmlen3;
+
+	mylog("[SQLStatisticsW]");
+	ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1);
+	scName = ucs2_to_utf8(SchemaName, NameLength2, &nmlen2);
+	tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3);
+	return PGAPI_Statistics(StatementHandle, ctName, (SWORD) nmlen1,
+           scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3, Unique,
+		Reserved);
+	if (ctName);
+		free(ctName);
+	if (scName);
+		free(scName);
+	if (tbName);
+		free(tbName);
+	return ret;
+}
+
+RETCODE  SQL_API SQLTablesW(HSTMT StatementHandle,
+           SQLWCHAR *CatalogName, SQLSMALLINT NameLength1,
+           SQLWCHAR *SchemaName, SQLSMALLINT NameLength2,
+           SQLWCHAR *TableName, SQLSMALLINT NameLength3,
+           SQLWCHAR *TableType, SQLSMALLINT NameLength4)
+{
+	RETCODE	ret;
+	char	*ctName, *scName, *tbName, *tbType;
+	UInt4	nmlen1, nmlen2, nmlen3, nmlen4;
+
+	mylog("[SQLTablesW]");
+	ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1);
+	scName = ucs2_to_utf8(SchemaName, NameLength2, &nmlen2);
+	tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3);
+	tbType = ucs2_to_utf8(TableType, NameLength4, &nmlen4);
+	return PGAPI_Tables(StatementHandle, ctName, (SWORD) nmlen1,
+           scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
+           tbType, (SWORD) nmlen4);
+	if (ctName);
+		free(ctName);
+	if (scName);
+		free(scName);
+	if (tbName);
+		free(tbName);
+	if (tbType);
+		free(tbType);
+	return ret;
+}
+
+RETCODE SQL_API SQLColumnPrivilegesW(
+    HSTMT           hstmt,
+    SQLWCHAR 		  *szCatalogName,
+    SQLSMALLINT        cbCatalogName,
+    SQLWCHAR 		  *szSchemaName,
+    SQLSMALLINT        cbSchemaName,
+    SQLWCHAR 		  *szTableName,
+    SQLSMALLINT        cbTableName,
+    SQLWCHAR 		  *szColumnName,
+    SQLSMALLINT        cbColumnName)
+{
+	RETCODE	ret;
+	char	*ctName, *scName, *tbName, *clName;
+	UInt4	nmlen1, nmlen2, nmlen3, nmlen4;
+
+	mylog("[SQLColumnPrivilegesW]");
+	ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1);
+	scName = ucs2_to_utf8(szSchemaName, cbSchemaName, &nmlen2);
+	tbName = ucs2_to_utf8(szTableName, cbTableName, &nmlen3);
+	clName = ucs2_to_utf8(szColumnName, cbColumnName, &nmlen4);
+	ret = PGAPI_ColumnPrivileges(hstmt, ctName, (SWORD) nmlen1,
+		scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
+		clName, (SWORD) nmlen4);
+	if (ctName);
+		free(ctName);
+	if (scName);
+		free(scName);
+	if (tbName);
+		free(tbName);
+	if (clName);
+		free(clName);
+	return ret;
+}
+
+RETCODE SQL_API SQLForeignKeysW(
+    HSTMT           hstmt,
+    SQLWCHAR 		  *szPkCatalogName,
+    SQLSMALLINT        cbPkCatalogName,
+    SQLWCHAR 		  *szPkSchemaName,
+    SQLSMALLINT        cbPkSchemaName,
+    SQLWCHAR 		  *szPkTableName,
+    SQLSMALLINT        cbPkTableName,
+    SQLWCHAR 		  *szFkCatalogName,
+    SQLSMALLINT        cbFkCatalogName,
+    SQLWCHAR 		  *szFkSchemaName,
+    SQLSMALLINT        cbFkSchemaName,
+    SQLWCHAR 		  *szFkTableName,
+    SQLSMALLINT        cbFkTableName)
+{
+	RETCODE	ret;
+	char	*ctName, *scName, *tbName, *fkctName, *fkscName, *fktbName;
+	UInt4	nmlen1, nmlen2, nmlen3, nmlen4, nmlen5, nmlen6;
+
+	mylog("[SQLForeignKeysW]");
+	ctName = ucs2_to_utf8(szPkCatalogName, cbPkCatalogName, &nmlen1);
+	scName = ucs2_to_utf8(szPkSchemaName, cbPkSchemaName, &nmlen2);
+	tbName = ucs2_to_utf8(szPkTableName, cbPkTableName, &nmlen3);
+	fkctName = ucs2_to_utf8(szFkCatalogName, cbFkCatalogName, &nmlen4);
+	fkscName = ucs2_to_utf8(szFkSchemaName, cbFkSchemaName, &nmlen5);
+	fktbName = ucs2_to_utf8(szFkTableName, cbFkTableName, &nmlen6);
+	ret = PGAPI_ForeignKeys(hstmt, ctName, (SWORD) nmlen1,
+		scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
+		fkctName, (SWORD) nmlen4, fkscName, (SWORD) nmlen5,
+		fktbName, (SWORD) nmlen6);
+	if (ctName);
+		free(ctName);
+	if (scName);
+		free(scName);
+	if (tbName);
+		free(tbName);
+	if (fkctName);
+		free(fkctName);
+	if (fkscName);
+		free(fkscName);
+	if (fktbName);
+		free(fktbName);
+	return ret;
+}
+
+RETCODE SQL_API SQLNativeSqlW(
+    HDBC            hdbc,
+    SQLWCHAR 		  *szSqlStrIn,
+    SQLINTEGER         cbSqlStrIn,
+    SQLWCHAR 		  *szSqlStr,
+    SQLINTEGER         cbSqlStrMax,
+    SQLINTEGER 		  *pcbSqlStr)
+{
+	RETCODE		ret;
+	char		*szIn, *szOut;
+	UInt4		slen;
+	SQLINTEGER	olen;
+
+	mylog("[SQLNativeSqlW]");
+	((ConnectionClass *) hdbc)->unicode = 1;
+	szIn = ucs2_to_utf8(szSqlStrIn, cbSqlStrIn, &slen);
+	szOut = malloc(cbSqlStrMax);
+	ret = PGAPI_NativeSql(hdbc, szIn, (SQLINTEGER) slen,
+		szOut, cbSqlStrMax, &olen);
+	if (szIn);
+		free(szIn);
+	*pcbSqlStr = utf8_to_ucs2(szOut, olen, szSqlStr, cbSqlStrMax);
+	free(szOut);
+	return ret;
+}
+
+RETCODE SQL_API SQLPrimaryKeysW(
+    HSTMT           hstmt,
+    SQLWCHAR 		  *szCatalogName,
+    SQLSMALLINT        cbCatalogName,
+    SQLWCHAR 		  *szSchemaName,
+    SQLSMALLINT        cbSchemaName,
+    SQLWCHAR 		  *szTableName,
+    SQLSMALLINT        cbTableName)
+{
+	RETCODE	ret;
+	char	*ctName, *scName, *tbName;
+	UInt4	nmlen1, nmlen2, nmlen3;
+
+	mylog("[SQLPrimaryKeysW]");
+	ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1);
+	scName = ucs2_to_utf8(szSchemaName, cbSchemaName, &nmlen2);
+	tbName = ucs2_to_utf8(szTableName, cbTableName, &nmlen3);
+	return PGAPI_PrimaryKeys(hstmt, ctName, (SWORD) nmlen1,
+		scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3);
+	if (ctName);
+		free(ctName);
+	if (scName);
+		free(scName);
+	if (tbName);
+		free(tbName);
+	return ret;
+}
+
+RETCODE SQL_API SQLProcedureColumnsW(
+    HSTMT           hstmt,
+    SQLWCHAR 		  *szCatalogName,
+    SQLSMALLINT        cbCatalogName,
+    SQLWCHAR 		  *szSchemaName,
+    SQLSMALLINT        cbSchemaName,
+    SQLWCHAR 		  *szProcName,
+    SQLSMALLINT        cbProcName,
+    SQLWCHAR 		  *szColumnName,
+    SQLSMALLINT        cbColumnName)
+{
+	RETCODE	ret;
+	char	*ctName, *scName, *prName, *clName;
+	UInt4	nmlen1, nmlen2, nmlen3, nmlen4;
+
+	mylog("[SQLProcedureColumnsW]");
+	ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1);
+	scName = ucs2_to_utf8(szSchemaName, cbSchemaName, &nmlen2);
+	prName = ucs2_to_utf8(szProcName, cbProcName, &nmlen3);
+	clName = ucs2_to_utf8(szColumnName, cbColumnName, &nmlen4);
+	ret = PGAPI_ProcedureColumns(hstmt, ctName, (SWORD) nmlen1,
+		scName, (SWORD) nmlen2, prName, (SWORD) nmlen3,
+		clName, (SWORD) nmlen4);
+	if (ctName);
+		free(ctName);
+	if (scName);
+		free(scName);
+	if (prName);
+		free(prName);
+	if (clName);
+		free(clName);
+	return ret;
+}
+
+RETCODE SQL_API SQLProceduresW(
+    HSTMT           hstmt,
+    SQLWCHAR 		  *szCatalogName,
+    SQLSMALLINT        cbCatalogName,
+    SQLWCHAR 		  *szSchemaName,
+    SQLSMALLINT        cbSchemaName,
+    SQLWCHAR 		  *szProcName,
+    SQLSMALLINT        cbProcName)
+{
+	RETCODE	ret;
+	char	*ctName, *scName, *prName;
+	UInt4	nmlen1, nmlen2, nmlen3;
+
+	mylog("[SQLProceduresW]");
+	ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1);
+	scName = ucs2_to_utf8(szSchemaName, cbSchemaName, &nmlen2);
+	prName = ucs2_to_utf8(szProcName, cbProcName, &nmlen3);
+	ret = PGAPI_Procedures(hstmt, ctName, (SWORD) nmlen1,
+		scName, (SWORD) nmlen2, prName, (SWORD) nmlen3);
+	if (ctName);
+		free(ctName);
+	if (scName);
+		free(scName);
+	if (prName);
+		free(prName);
+	return ret;
+}
+
+RETCODE SQL_API SQLTablePrivilegesW(
+    HSTMT           hstmt,
+    SQLWCHAR 		  *szCatalogName,
+    SQLSMALLINT        cbCatalogName,
+    SQLWCHAR 		  *szSchemaName,
+    SQLSMALLINT        cbSchemaName,
+    SQLWCHAR 		  *szTableName,
+    SQLSMALLINT        cbTableName)
+{
+	RETCODE	ret;
+	char	*ctName, *scName, *tbName;
+	UInt4	nmlen1, nmlen2, nmlen3;
+
+	mylog("[SQLTablePrivilegesW]");
+	ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1);
+	scName = ucs2_to_utf8(szSchemaName, cbSchemaName, &nmlen2);
+	tbName = ucs2_to_utf8(szTableName, cbTableName, &nmlen3);
+	ret = PGAPI_TablePrivileges(hstmt, ctName, (SWORD) nmlen1,
+		scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3, 0);
+	if (ctName);
+		free(ctName);
+	if (scName);
+		free(scName);
+	if (tbName);
+		free(tbName);
+	return ret;
+}
diff --git a/src/interfaces/odbc/pgapi30.c b/src/interfaces/odbc/pgapi30.c
new file mode 100644
index 00000000000..9ee8c58983b
--- /dev/null
+++ b/src/interfaces/odbc/pgapi30.c
@@ -0,0 +1,495 @@
+/*-------
+ * Module:			pgapi30.c
+ *
+ * Description:		This module contains routines related to ODBC 3.0
+ *			most of their implementations are temporary
+ *			and must be rewritten properly.
+ *			2001/07/23	inoue
+ *
+ * Classes:			n/a
+ *
+ * API functions:	PGAPI_ColAttribute, PGAPI_GetDiagRec,
+			PGAPI_GetConnectAttr, PGAPI_GetStmtAttr,
+			PGAPI_SetConnectAttr, PGAPI_SetStmtAttr
+ *-------
+ */
+
+#ifndef ODBCVER
+#define ODBCVER 0x0300
+#endif
+#include "psqlodbc.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "environ.h"
+#include "connection.h"
+#include "statement.h"
+#include "pgapifunc.h"
+
+/*	SQLError -> SQLDiagRec */
+RETCODE		SQL_API
+PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
+		SQLSMALLINT RecNumber, SQLCHAR *Sqlstate,
+		SQLINTEGER *NativeError, SQLCHAR *MessageText,
+		SQLSMALLINT BufferLength, SQLSMALLINT *TextLength)
+{
+	RETCODE		ret;
+	static const char *func = "PGAPI_GetDiagRec";
+
+	mylog("%s entering ", func);
+	switch (HandleType)
+	{
+		case SQL_HANDLE_ENV:
+			ret = PGAPI_Error(Handle, NULL, NULL, Sqlstate, NativeError,
+							  MessageText, BufferLength, TextLength);
+			break;
+		case SQL_HANDLE_DBC:
+			ret = PGAPI_Error(NULL, Handle, NULL, Sqlstate, NativeError,
+							  MessageText, BufferLength, TextLength);
+			break;
+		case SQL_HANDLE_STMT:
+			ret = PGAPI_Error(NULL, NULL, Handle, Sqlstate, NativeError,
+							  MessageText, BufferLength, TextLength);
+			break;
+		default:
+			ret = SQL_ERROR;
+	}
+	if (ret == SQL_SUCCESS_WITH_INFO &&
+		BufferLength == 0 &&
+		*TextLength)
+	{
+		SQLSMALLINT BufferLength = *TextLength + 4;
+		SQLCHAR    *MessageText = malloc(BufferLength);
+
+		ret = PGAPI_GetDiagRec(HandleType, Handle, RecNumber, Sqlstate,
+							NativeError, MessageText, BufferLength,
+							TextLength);
+		free(MessageText);
+	}
+mylog("%s exiting\n", func);
+	return ret;
+}
+
+/*	SQLGetConnectOption -> SQLGetconnectAttr */
+RETCODE		SQL_API
+PGAPI_GetConnectAttr(HDBC ConnectionHandle,
+			SQLINTEGER Attribute, PTR Value,
+			SQLINTEGER BufferLength, SQLINTEGER *StringLength)
+{
+	ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+
+	mylog("PGAPI_GetConnectAttr %d\n", Attribute);
+	switch (Attribute)
+	{
+		case SQL_ATTR_ASYNC_ENABLE:
+		case SQL_ATTR_AUTO_IPD:
+		case SQL_ATTR_CONNECTION_DEAD:
+		case SQL_ATTR_CONNECTION_TIMEOUT:
+		case SQL_ATTR_METADATA_ID:
+			conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
+			conn->errormsg = "Unsupported connection option (Set)";
+			return SQL_ERROR;
+	}
+	return PGAPI_GetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
+}
+
+static HSTMT
+descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType) 
+{
+	switch (descType)
+	{
+		case SQL_ATTR_APP_ROW_DESC:		/* 10010 */
+			return StatementHandle;	/* this is bogus */
+		case SQL_ATTR_APP_PARAM_DESC:	/* 10011 */
+			return (HSTMT) ((SQLUINTEGER) StatementHandle + 1) ; /* this is bogus */
+		case SQL_ATTR_IMP_ROW_DESC:		/* 10012 */
+			return (HSTMT) ((SQLUINTEGER) StatementHandle + 2); /* this is bogus */
+		case SQL_ATTR_IMP_PARAM_DESC:	/* 10013 */
+			return (HSTMT) ((SQLUINTEGER) StatementHandle + 3); /* this is bogus */
+	}
+	return (HSTMT) 0;
+}
+static HSTMT
+statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType) 
+{
+	SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4;
+	switch (res)
+	{
+		case 0: *descType = SQL_ATTR_APP_ROW_DESC; /* 10010 */
+			break;
+		case 1: *descType = SQL_ATTR_APP_PARAM_DESC; /* 10011 */
+			break;
+		case 2: *descType = SQL_ATTR_IMP_ROW_DESC; /* 10012 */
+			break;
+		case 3: *descType = SQL_ATTR_IMP_PARAM_DESC; /* 10013 */
+			break;
+	}
+	return (HSTMT) ((SQLUINTEGER) DescHandle - res);
+}
+
+static RETCODE SQL_API
+ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+		SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
+{
+	RETCODE		ret = SQL_SUCCESS;
+	PTR		tptr;
+	switch (FieldIdentifier)
+	{
+		case SQL_DESC_ARRAY_SIZE:
+			stmt->options.rowset_size = (SQLUINTEGER) Value;
+			break; 
+		case SQL_DESC_ARRAY_STATUS_PTR:
+			stmt->options.row_operation_ptr = Value;
+			break;
+		case SQL_DESC_BIND_OFFSET_PTR:
+			stmt->options.row_offset_ptr = Value;
+			break;
+		case SQL_DESC_BIND_TYPE:
+			stmt->options.bind_size = (SQLUINTEGER) Value;
+			break;
+
+		case SQL_DESC_DATA_PTR:
+			if (!RecNumber)
+				stmt->bookmark.buffer = Value;
+			else
+				stmt->bindings[RecNumber - 1].buffer = Value;
+			break;
+		case SQL_DESC_INDICATOR_PTR:
+			if (!RecNumber)
+				tptr = stmt->bookmark.used;
+			else
+				tptr = stmt->bindings[RecNumber - 1].used;
+			if (Value != tptr)
+			{
+				ret = SQL_ERROR;
+				stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+				stmt->errormsg = "INDICATOR != OCTET_LENGTH_PTR"; 
+			}
+			break;
+		case SQL_DESC_OCTET_LENGTH_PTR:
+			if (!RecNumber)
+				stmt->bookmark.used = Value;
+			else
+				stmt->bindings[RecNumber - 1].used = Value;
+			break;
+		default:ret = SQL_ERROR;
+			stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+			stmt->errormsg = "not implemedted yet"; 
+	}
+	return ret;
+}
+
+static RETCODE SQL_API
+APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+		SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
+{
+	RETCODE		ret = SQL_SUCCESS;
+	switch (FieldIdentifier)
+	{
+		case SQL_DESC_ARRAY_SIZE:
+			stmt->options.paramset_size = (SQLUINTEGER) Value;
+			break; 
+		case SQL_DESC_ARRAY_STATUS_PTR:
+			stmt->options.param_operation_ptr = Value;
+			break;
+		case SQL_DESC_BIND_OFFSET_PTR:
+			stmt->options.param_offset_ptr = Value;
+			break;
+		case SQL_DESC_BIND_TYPE:
+			stmt->options.param_bind_type = (SQLUINTEGER) Value;
+			break;
+
+		case SQL_DESC_DATA_PTR:
+			if (stmt->parameters_allocated < RecNumber)
+				PGAPI_BindParameter(stmt, RecNumber, 0, 0, 0, 0, 0, 0, 0, 0);
+			stmt->parameters[RecNumber - 1].buffer = Value;
+			break;
+		case SQL_DESC_INDICATOR_PTR:
+			if (stmt->parameters_allocated < RecNumber ||
+			    Value != stmt->parameters[RecNumber - 1].used)
+			{
+				ret = SQL_ERROR;
+				stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+				stmt->errormsg = "INDICATOR != OCTET_LENGTH_PTR"; 
+			}
+			break;
+		case SQL_DESC_OCTET_LENGTH_PTR:
+			if (stmt->parameters_allocated < RecNumber)
+				PGAPI_BindParameter(stmt, RecNumber, 0, 0, 0, 0, 0, 0, 0, 0);
+			stmt->parameters[RecNumber - 1].used = Value;
+			break;
+		default:ret = SQL_ERROR;
+			stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+	}
+	return ret;
+}
+
+static RETCODE SQL_API
+IRDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+		SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
+{
+	RETCODE		ret = SQL_SUCCESS;
+	switch (FieldIdentifier)
+	{
+		case SQL_DESC_ARRAY_STATUS_PTR:
+			stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
+			break;
+		case SQL_DESC_ROWS_PROCESSED_PTR:
+			stmt->options.rowsFetched = (SQLUINTEGER *) Value;
+			break;
+		default:ret = SQL_ERROR;
+			stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+	}
+	return ret;
+}
+
+static RETCODE SQL_API
+IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+		SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
+{
+	RETCODE		ret = SQL_SUCCESS;
+	switch (FieldIdentifier)
+	{
+		case SQL_DESC_ARRAY_STATUS_PTR:
+			stmt->options.param_status_ptr = (SQLUSMALLINT *) Value;
+			break;
+		case SQL_DESC_ROWS_PROCESSED_PTR:
+			stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
+			break;
+		default:ret = SQL_ERROR;
+			stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+	}
+	return ret;
+}
+
+/*	SQLGetStmtOption -> SQLGetStmtAttr */
+RETCODE		SQL_API
+PGAPI_GetStmtAttr(HSTMT StatementHandle,
+		SQLINTEGER Attribute, PTR Value,
+		SQLINTEGER BufferLength, SQLINTEGER *StringLength)
+{
+	static char *func = "PGAPI_GetStmtAttr";
+	StatementClass *stmt = (StatementClass *) StatementHandle;
+	RETCODE		ret = SQL_SUCCESS;
+	int			len = 0;
+
+	mylog("%s Handle=%u %d\n", func, StatementHandle, Attribute);
+	switch (Attribute)
+	{
+		case SQL_ATTR_FETCH_BOOKMARK_PTR:		/* 16 */
+			Value = stmt->options.bookmark_ptr;
+			len = 4;
+			break;
+		case SQL_ATTR_PARAM_BIND_OFFSET_PTR:	/* 17 */
+			Value = stmt->options.param_offset_ptr;
+			len = 4;
+			break;
+		case SQL_ATTR_PARAM_BIND_TYPE:	/* 18 */
+			*((SQLUINTEGER *) Value) = stmt->options.param_bind_type;
+			len = 4;
+			break;
+		case SQL_ATTR_PARAM_OPERATION_PTR:		/* 19 */
+			Value = stmt->options.param_operation_ptr;
+			len = 4;
+			break;
+		case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
+			Value = stmt->options.param_status_ptr;
+			len = 4;
+			break;
+		case SQL_ATTR_PARAMS_PROCESSED_PTR:		/* 21 */
+			Value = stmt->options.param_processed_ptr;
+			len = 4;
+			break;
+		case SQL_ATTR_PARAMSET_SIZE:	/* 22 */
+			*((SQLUINTEGER *) Value) = stmt->options.paramset_size;
+			len = 4;
+			break;
+		case SQL_ATTR_ROW_BIND_OFFSET_PTR:		/* 23 */
+			Value = stmt->options.row_offset_ptr;
+			len = 4;
+			break;
+		case SQL_ATTR_ROW_OPERATION_PTR:		/* 24 */
+			Value = stmt->options.row_operation_ptr;
+			len = 4;
+			break;
+		case SQL_ATTR_ROW_STATUS_PTR:	/* 25 */
+			Value = stmt->options.rowStatusArray;
+			len = 4;
+			break;
+		case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
+			Value = stmt->options.rowsFetched;
+			len = 4;
+			break;
+		case SQL_ATTR_ROW_ARRAY_SIZE:	/* 27 */
+			*((SQLUINTEGER *) Value) = stmt->options.rowset_size;
+			len = 4;
+			break;
+		case SQL_ATTR_APP_ROW_DESC:		/* 10010 */
+		case SQL_ATTR_APP_PARAM_DESC:	/* 10011 */
+		case SQL_ATTR_IMP_ROW_DESC:		/* 10012 */
+		case SQL_ATTR_IMP_PARAM_DESC:	/* 10013 */
+			len = 4;
+			*((HSTMT *) Value) = descHandleFromStatementHandle(StatementHandle, Attribute); 
+			break;
+		case SQL_ATTR_AUTO_IPD:	/* 10001 */
+			/* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
+
+		case SQL_ATTR_CURSOR_SCROLLABLE:		/* -1 */
+		case SQL_ATTR_CURSOR_SENSITIVITY:		/* -2 */
+		case SQL_ATTR_ENABLE_AUTO_IPD:	/* 15 */
+		case SQL_ATTR_METADATA_ID:		/* 10014 */
+
+			/*
+			 * case SQL_ATTR_PREDICATE_PTR: case
+			 * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
+			 */
+			stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
+			stmt->errormsg = "Unsupported statement option (Get)";
+			SC_log_error(func, "", stmt);
+			return SQL_ERROR;
+		default:
+			len = 4;
+			ret = PGAPI_GetStmtOption(StatementHandle, (UWORD) Attribute, Value);
+	}
+	if (ret == SQL_SUCCESS && StringLength)
+		*StringLength = len;
+	return ret;
+}
+
+/*	SQLSetConnectOption -> SQLSetConnectAttr */
+RETCODE		SQL_API
+PGAPI_SetConnectAttr(HDBC ConnectionHandle,
+			SQLINTEGER Attribute, PTR Value,
+			SQLINTEGER StringLength)
+{
+	ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+
+	mylog("PGAPI_SetConnectAttr %d\n", Attribute);
+	switch (Attribute)
+	{
+		case SQL_ATTR_ASYNC_ENABLE:
+		case SQL_ATTR_AUTO_IPD:
+		case SQL_ATTR_CONNECTION_DEAD:
+		case SQL_ATTR_CONNECTION_TIMEOUT:
+		case SQL_ATTR_METADATA_ID:
+			conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
+			conn->errormsg = "Unsupported connection option (Set)";
+			return SQL_ERROR;
+	}
+	return PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
+}
+
+/*	new function */
+RETCODE		SQL_API
+PGAPI_SetDescField(SQLHDESC DescriptorHandle,
+			SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
+			PTR Value, SQLINTEGER BufferLength)
+{
+	RETCODE		ret = SQL_SUCCESS;
+	HSTMT		hstmt;
+	SQLUINTEGER	descType;
+	StatementClass *stmt;
+	static const char *func = "PGAPI_SetDescField";
+
+	mylog("%s h=%u rec=%d field=%d val=%x\n", func, DescriptorHandle, RecNumber, FieldIdentifier, Value);
+	hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType);
+	mylog("stmt=%x type=%d\n", hstmt, descType);
+	stmt = (StatementClass *) hstmt;
+	switch (descType)
+	{
+		case SQL_ATTR_APP_ROW_DESC:
+			ret = ARDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+			break;
+		case SQL_ATTR_APP_PARAM_DESC:
+			ret = APDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+			break;
+		case SQL_ATTR_IMP_ROW_DESC:
+			ret = IRDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+			break;
+		case SQL_ATTR_IMP_PARAM_DESC:
+			ret = IPDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+			break;
+		default:ret = SQL_ERROR;
+			stmt->errornumber = STMT_INTERNAL_ERROR; 
+			stmt->errormsg = "Error not implemented";
+	}
+	if (ret == SQL_ERROR)
+		SC_log_error(func, "", stmt);
+	return ret;
+}
+
+/*	SQLSet(Param/Scroll/Stmt)Option -> SQLSetStmtAttr */
+RETCODE		SQL_API
+PGAPI_SetStmtAttr(HSTMT StatementHandle,
+		SQLINTEGER Attribute, PTR Value,
+		SQLINTEGER StringLength)
+{
+	static char *func = "PGAPI_SetStmtAttr";
+	StatementClass *stmt = (StatementClass *) StatementHandle;
+
+	mylog("%s Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
+	switch (Attribute)
+	{
+		case SQL_ATTR_CURSOR_SCROLLABLE:		/* -1 */
+		case SQL_ATTR_CURSOR_SENSITIVITY:		/* -2 */
+
+		case SQL_ATTR_ENABLE_AUTO_IPD:	/* 15 */
+
+		case SQL_ATTR_APP_ROW_DESC:		/* 10010 */
+		case SQL_ATTR_APP_PARAM_DESC:	/* 10011 */
+		case SQL_ATTR_AUTO_IPD:	/* 10001 */
+		/* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
+		case SQL_ATTR_IMP_ROW_DESC:	/* 10012 (read-only) */
+		case SQL_ATTR_IMP_PARAM_DESC:	/* 10013 (read-only) */
+		case SQL_ATTR_METADATA_ID:		/* 10014 */
+
+			/*
+			 * case SQL_ATTR_PREDICATE_PTR: case
+			 * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
+			 */
+			stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
+			stmt->errormsg = "Unsupported statement option (Set)";
+			SC_log_error(func, "", stmt);
+			return SQL_ERROR;
+
+		case SQL_ATTR_FETCH_BOOKMARK_PTR:		/* 16 */
+			stmt->options.bookmark_ptr = Value;
+			break;
+		case SQL_ATTR_PARAM_BIND_OFFSET_PTR:	/* 17 */
+			stmt->options.param_offset_ptr = (SQLUINTEGER *) Value;
+			break;
+		case SQL_ATTR_PARAM_BIND_TYPE:	/* 18 */
+			stmt->options.param_bind_type = (SQLUINTEGER) Value;
+			break;
+		case SQL_ATTR_PARAM_OPERATION_PTR:		/* 19 */
+			stmt->options.param_operation_ptr = Value;
+			break;
+		case SQL_ATTR_PARAM_STATUS_PTR:			/* 20 */
+			stmt->options.param_status_ptr = (SQLUSMALLINT *) Value;
+			break;
+		case SQL_ATTR_PARAMS_PROCESSED_PTR:		/* 21 */
+			stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
+			break;
+		case SQL_ATTR_PARAMSET_SIZE:	/* 22 */
+			stmt->options.paramset_size = (SQLUINTEGER) Value;
+			break;
+		case SQL_ATTR_ROW_BIND_OFFSET_PTR:		/* 23 */
+			stmt->options.row_offset_ptr = (SQLUINTEGER *) Value;
+			break;
+		case SQL_ATTR_ROW_OPERATION_PTR:		/* 24 */
+			stmt->options.row_operation_ptr = Value;
+			break;
+		case SQL_ATTR_ROW_STATUS_PTR:	/* 25 */
+			stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
+			break;
+		case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
+			stmt->options.rowsFetched = (SQLUINTEGER *) Value;
+			break;
+		case SQL_ATTR_ROW_ARRAY_SIZE:	/* 27 */
+			stmt->options.rowset_size = (SQLUINTEGER) Value;
+			break;
+		default:
+			return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) Value);
+	}
+	return SQL_SUCCESS;
+}
diff --git a/src/interfaces/odbc/win_unicode.c b/src/interfaces/odbc/win_unicode.c
new file mode 100644
index 00000000000..11a8e396a59
--- /dev/null
+++ b/src/interfaces/odbc/win_unicode.c
@@ -0,0 +1,137 @@
+/*-------
+ * Module:			win_unicode.c
+ *
+ * Description:		This module contains utf8 <-> ucs2 conversion routines
+ *					under WIndows
+ *
+ *-------
+ */
+
+#include "psqlodbc.h"
+#include <stdio.h>
+#include <string.h>
+
+#define	byte3check	0xf800
+#define	byte2_base	0x80c0
+#define	byte2_mask1	0x07c0
+#define	byte2_mask2	0x003f
+#define	byte3_base	0x8080e0
+#define	byte3_mask1	0xf000
+#define	byte3_mask2	0x0fc0
+#define	byte3_mask3	0x003f
+
+char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen)
+{
+	char *	utf8str;
+/*mylog("ucs2_to_utf8 %x ilen=%d ", ucs2str, ilen);*/
+
+	if (!ucs2str)
+		return NULL;
+	if (ilen < 0)
+	{
+		for (ilen = 0; ucs2str[ilen]; ilen++)
+			;
+	}
+/*mylog(" newlen=%d", ilen);*/
+	utf8str = (char *) malloc(ilen * 3 + 1);
+	if (utf8str)
+	{
+		int	i, len = 0;
+		Int2		byte2code;
+		Int4		byte4code;
+
+		const SQLWCHAR	*wstr;
+		for (i = 0, wstr = ucs2str; i < ilen; i++, wstr++)
+		{
+			if (!*wstr)
+				break;
+			else if (iswascii(*wstr))
+				utf8str[len++] = (char) *wstr;
+			else if ((*wstr & byte3check) == 0)
+			{
+				byte2code = byte2_base |
+					    ((byte2_mask1 & *wstr) >> 6) |
+					    ((byte2_mask2 & *wstr) << 8);
+				memcpy(utf8str + len, (char *) &byte2code, sizeof(byte2code));
+				len += 2; 
+			}
+			else
+			{
+				byte4code = byte3_base |
+					    ((byte3_mask1 & *wstr) >> 12) | 
+					    ((byte3_mask2 & *wstr) << 2) | 
+					    ((byte3_mask3 & *wstr) << 16);
+				memcpy(utf8str + len, (char *) &byte4code, 3);
+				len += 3;
+			}
+		} 
+		utf8str[len] = '\0';
+		*olen = len;
+	}
+/*mylog(" olen=%d %s\n", *olen, utf8str ? utf8str : "");*/
+	return utf8str;
+}
+
+#define	byte3_m1	0x0f
+#define	byte3_m2	0x3f
+#define	byte3_m3	0x3f
+#define	byte2_m1	0x1f
+#define	byte2_m2	0x3f
+UInt4	utf8_to_ucs2(const char *utf8str, Int4 ilen, SQLWCHAR *ucs2str, UInt4 bufcount)
+{
+	int	i;
+	UInt4	ocount, wcode;
+	const unsigned char *str;
+
+/*mylog("utf8_to_ucs2 ilen=%d bufcount=%d", ilen, bufcount);*/
+	if (!utf8str || !ilen)
+		return 0;
+/*mylog(" string=%s\n", utf8str);*/
+	if (!bufcount)
+		ucs2str = NULL;
+	else if (!ucs2str)
+		bufcount = 0;
+	if (ilen < 0)
+		ilen = strlen(utf8str);
+	for (i = 0, ocount = 0, str = utf8str; i < ilen;)
+	{
+		if (iswascii(*str))
+		{
+			if (ocount < bufcount)
+				ucs2str[ocount] = *str;
+			ocount++;
+			i++;
+			str++;
+		}
+		else if (0xe0 == (*str & 0xe0)) /* 3 byte code */
+		{
+			if (ocount < bufcount)
+			{
+				wcode = ((((UInt4) *str) & byte3_m1) << 12) |
+					((((UInt4) str[1]) & byte3_m2) << 6) |
+				 	((UInt4) str[2]) & byte3_m3;
+				ucs2str[ocount] = (SQLWCHAR) wcode;
+			}
+			ocount++;
+			i += 3;
+			str += 3;
+		}
+		else
+		{
+			if (ocount < bufcount)
+			{
+				wcode = ((((UInt4) *str) & byte2_m1) << 6) |
+				 	((UInt4) str[1]) & byte2_m2;
+				ucs2str[ocount] = (SQLWCHAR) wcode;
+			}
+			ocount++;
+			i += 2;
+			str += 2;
+		}
+	}
+	if (ocount && ocount < bufcount && ucs2str)
+		ucs2str[ocount] = 0;
+/*mylog(" ocount=%d\n", ocount);*/
+	return ocount;
+}
+
-- 
GitLab