Changeset: 266b6c8a0632 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/266b6c8a0632
Modified Files:
        clients/odbc/driver/ODBCDbc.h
        clients/odbc/driver/SQLBrowseConnect.c
        clients/odbc/driver/SQLConnect.c
        clients/odbc/driver/SQLDriverConnect.c
        clients/odbc/driver/SQLExecute.c
        clients/odbc/driver/SQLPrepare.c
Branch: default
Log Message:

Added ODBC connection string parameter: mapToLongVarchar=<posint>
  Specifies the length of a string at which to begin mapping string values to 
an ODBC SQL_WLONGVARCHAR data type instead of the default ODBC SQL_WVARCHAR 
data type.
    0 (or unset): Maps string values in their default ODBC data types. Default 
= 0.
    > 0: Specifies the maximum number of string characters to map to default 
ODBC string data types. All strings larger than this value are mapped to 
SQL_WLONGVARCHAR.
  You can also specify this parameter only as a connection parameter.
Note: This is a used to workaround an MS SQL Server linked server limitation 
which can not deal with varchars larger than 4000.


diffs (249 lines):

diff --git a/clients/odbc/driver/ODBCDbc.h b/clients/odbc/driver/ODBCDbc.h
--- a/clients/odbc/driver/ODBCDbc.h
+++ b/clients/odbc/driver/ODBCDbc.h
@@ -59,6 +59,7 @@ typedef struct tODBCDRIVERDBC {
        bool has_comment;       /* whether the server has sys.comments */
        bool allow_hugeint;     /* whether the application deals with HUGEINT */
        bool raw_strings;       /* server uses raw strings */
+       int mapToLongVarchar;   /* when > 0 we map WVARCHAR to WLONGVARCHAR, 
default 0 */
        SQLUINTEGER sql_attr_autocommit;
        SQLUINTEGER sql_attr_metadata_id;
        SQLUINTEGER sql_attr_connection_timeout;
@@ -148,9 +149,13 @@ SQLRETURN ODBCConnectionString(SQLRETURN
                               SQLSMALLINT *StringLength2Ptr,
                               const char *dsn, const char *uid,
                               const char *pwd, const char *host,
-                              int port, const char *database);
+                              int port, const char *database,
+                              int mapToLongVarchar);
 SQLRETURN MNDBAllocStmt(ODBCDbc *dbc, SQLHANDLE *pnOutputHandle);
-SQLRETURN MNDBConnect(ODBCDbc *dbc, const SQLCHAR *szDataSource, SQLSMALLINT 
nDataSourceLength, const SQLCHAR *szUID, SQLSMALLINT nUIDLength, const SQLCHAR 
*szPWD, SQLSMALLINT nPWDLength, const char *host, int port, const char *schema);
+SQLRETURN MNDBConnect(ODBCDbc *dbc, const SQLCHAR *szDataSource, SQLSMALLINT 
nDataSourceLength,
+                       const SQLCHAR *szUID, SQLSMALLINT nUIDLength,
+                       const SQLCHAR *szPWD, SQLSMALLINT nPWDLength,
+                       const char *host, int port, const char *dbname, int 
mapToLongVarchar);
 SQLRETURN MNDBGetConnectAttr(ODBCDbc *dbc, SQLINTEGER Attribute, SQLPOINTER 
ValuePtr, SQLINTEGER BufferLength, SQLINTEGER *StringLength);
 SQLRETURN MNDBSetConnectAttr(ODBCDbc *dbc, SQLINTEGER Attribute, SQLPOINTER 
ValuePtr, SQLINTEGER StringLength);
 
diff --git a/clients/odbc/driver/SQLBrowseConnect.c 
b/clients/odbc/driver/SQLBrowseConnect.c
--- a/clients/odbc/driver/SQLBrowseConnect.c
+++ b/clients/odbc/driver/SQLBrowseConnect.c
@@ -53,7 +53,7 @@ MNDBBrowseConnect(ODBCDbc *dbc,
 {
        char *key, *attr;
        char *dsn, *uid, *pwd, *host, *dbname;
-       int port;
+       int port, mapToLongVarchar;
        SQLSMALLINT len = 0;
        char buf[1024];
        int n;
@@ -81,6 +81,7 @@ MNDBBrowseConnect(ODBCDbc *dbc,
        host = dbc->host ? strdup(dbc->host) : NULL;
        port = dbc->port;
        dbname = dbc->dbname ? strdup(dbc->dbname) : NULL;
+       mapToLongVarchar = dbc->mapToLongVarchar;
 
        while ((n = ODBCGetKeyAttr(&InConnectionString, &StringLength1, &key, 
&attr)) > 0) {
                if (strcasecmp(key, "dsn") == 0 && dsn == NULL) {
@@ -106,6 +107,9 @@ MNDBBrowseConnect(ODBCDbc *dbc,
                        if (dbname)
                                free(dbname);
                        dbname = attr;
+               } else if (strcasecmp(key, "mapToLongVarchar") == 0 && 
mapToLongVarchar == 0) {
+                       mapToLongVarchar = atoi(attr);
+                       free(attr);
 #ifdef ODBCDEBUG
                } else if (strcasecmp(key, "logfile") == 0 &&
 #ifdef NATIVE_WIN32
@@ -218,13 +222,17 @@ MNDBBrowseConnect(ODBCDbc *dbc,
        }
 
        if (uid != NULL && pwd != NULL) {
-               rc = MNDBConnect(dbc, (SQLCHAR *) dsn, SQL_NTS, (SQLCHAR *) 
uid, SQL_NTS, (SQLCHAR *) pwd, SQL_NTS, host, port, dbname);
+               rc = MNDBConnect(dbc, (SQLCHAR *) dsn, SQL_NTS,
+                                (SQLCHAR *) uid, SQL_NTS,
+                                (SQLCHAR *) pwd, SQL_NTS,
+                                host, port, dbname,
+                                mapToLongVarchar);
                if (SQL_SUCCEEDED(rc)) {
                        rc = ODBCConnectionString(rc, dbc, OutConnectionString,
                                                  BufferLength,
                                                  StringLength2Ptr,
                                                  dsn, uid, pwd, host, port,
-                                                 dbname);
+                                                 dbname, mapToLongVarchar);
                }
        } else {
                len = (SQLSMALLINT) strconcat_len(
diff --git a/clients/odbc/driver/SQLConnect.c b/clients/odbc/driver/SQLConnect.c
--- a/clients/odbc/driver/SQLConnect.c
+++ b/clients/odbc/driver/SQLConnect.c
@@ -90,7 +90,8 @@ MNDBConnect(ODBCDbc *dbc,
            SQLSMALLINT NameLength3,
            const char *host,
            int port,
-           const char *dbname)
+           const char *dbname,
+           int mapToLongVarchar)
 {
        SQLRETURN rc = SQL_SUCCESS;
        char *dsn = NULL;
@@ -276,6 +277,7 @@ MNDBConnect(ODBCDbc *dbc,
                if (dbc->dbname != NULL)
                        free(dbc->dbname);
                dbc->dbname = (char *) dbname; /* discard const */
+               dbc->mapToLongVarchar = mapToLongVarchar;
                get_serverinfo(dbc);
                /* set timeout after we're connected */
                mapi_timeout(mid, dbc->sql_attr_connection_timeout * 1000);
@@ -306,7 +308,7 @@ SQLConnect(SQLHDBC ConnectionHandle,
                           ServerName, NameLength1,
                           UserName, NameLength2,
                           Authentication, NameLength3,
-                          NULL, 0, NULL);
+                          NULL, 0, NULL, 0);
 }
 
 SQLRETURN SQL_API
@@ -357,7 +359,7 @@ SQLConnectW(SQLHDBC ConnectionHandle,
                         ds, SQL_NTS,
                         uid, SQL_NTS,
                         pwd, SQL_NTS,
-                        NULL, 0, NULL);
+                        NULL, 0, NULL, 0);
 
       bailout:
        if (ds)
diff --git a/clients/odbc/driver/SQLDriverConnect.c 
b/clients/odbc/driver/SQLDriverConnect.c
--- a/clients/odbc/driver/SQLDriverConnect.c
+++ b/clients/odbc/driver/SQLDriverConnect.c
@@ -113,7 +113,8 @@ ODBCConnectionString(SQLRETURN rc,
                     const char *pwd,
                     const char *host,
                     int port,
-                    const char *database)
+                    const char *database,
+                    int mapToLongVarchar)
 {
        int n;
 #ifdef ODBCDEBUG
@@ -188,8 +189,19 @@ ODBCConnectionString(SQLRETURN rc,
        if (database) {
                if (BufferLength > 0) {
                        n = snprintf((char *) OutConnectionString,
-                                    BufferLength,
-                                    "DATABASE=%s;", database);
+                                    BufferLength, "DATABASE=%s;", database);
+                       if (n < 0)
+                               n = BufferLength + 1;
+                       BufferLength -= n;
+                       OutConnectionString += n;
+               } else {
+                       BufferLength = -1;
+               }
+       }
+       if (mapToLongVarchar > 0) {
+               if (BufferLength > 0) {
+                       n = snprintf((char *) OutConnectionString,
+                                    BufferLength, "mapToLongVarchar=%d;", 
mapToLongVarchar);
                        if (n < 0)
                                n = BufferLength + 1;
                        BufferLength -= n;
@@ -293,7 +305,7 @@ MNDBDriverConnect(ODBCDbc *dbc,
 {
        char *key, *attr;
        char *dsn = 0, *uid = 0, *pwd = 0, *host = 0, *database = 0;
-       int port = 0;
+       int port = 0, mapToLongVarchar = 0;
        SQLRETURN rc;
        int n;
 
@@ -343,6 +355,9 @@ MNDBDriverConnect(ODBCDbc *dbc,
                else if (strcasecmp(key, "port") == 0 && port == 0) {
                        port = atoi(attr);
                        free(attr);
+               } else if (strcasecmp(key, "mapToLongVarchar") == 0 && 
mapToLongVarchar == 0) {
+                       mapToLongVarchar = atoi(attr);
+                       free(attr);
 #ifdef ODBCDEBUG
 #ifdef NATIVE_WIN32
                } else if (strcasecmp(key, "logfile") == 0 &&
@@ -389,13 +404,15 @@ MNDBDriverConnect(ODBCDbc *dbc,
                rc = MNDBConnect(dbc, (SQLCHAR *) dsn, SQL_NTS,
                                 (SQLCHAR *) uid, SQL_NTS,
                                 (SQLCHAR *) pwd, SQL_NTS,
-                                host, port, database);
+                                host, port, database,
+                                mapToLongVarchar);
        }
 
        if (SQL_SUCCEEDED(rc)) {
                rc = ODBCConnectionString(rc, dbc, OutConnectionString,
                                          BufferLength, StringLength2Ptr,
-                                         dsn, uid, pwd, host, port, database);
+                                         dsn, uid, pwd, host, port, database,
+                                         mapToLongVarchar);
        }
 
        if (dsn)
diff --git a/clients/odbc/driver/SQLExecute.c b/clients/odbc/driver/SQLExecute.c
--- a/clients/odbc/driver/SQLExecute.c
+++ b/clients/odbc/driver/SQLExecute.c
@@ -48,7 +48,7 @@ static struct msql_types {
        {"hugeint", SQL_HUGEINT},
        /* {"inet", SQL_WCHAR}, */
        {"int", SQL_INTEGER},
-       /* {"json", SQL_WCHAR}, */
+       /* {"json", SQL_WVARCHAR}, */
        {"month_interval", SQL_INTERVAL_MONTH},
        {"oid", SQL_BIGINT},
        {"real", SQL_REAL},
@@ -60,7 +60,7 @@ static struct msql_types {
        {"timestamp", SQL_TYPE_TIMESTAMP},
        {"timestamptz", SQL_TYPE_TIMESTAMP},
        {"tinyint", SQL_TINYINT},
-       /* {"url", SQL_WCHAR}, */
+       /* {"url", SQL_WVARCHAR}, */
        {"uuid", SQL_GUID},
        {"varchar", SQL_WVARCHAR},
        {0, 0},                 /* sentinel */
@@ -388,6 +388,15 @@ ODBCInitResult(ODBCStmt *stmt)
                         * that */
                        rec->sql_desc_display_size = mapi_get_len(hdl, i);
                        rec->sql_desc_octet_length = 4 * 
rec->sql_desc_display_size;
+
+                       /* For large varchar column definitions conditionally
+                        * change type to SQL_WLONGVARCHAR when 
mapToLongVarchar is set (e.g. to 4000)
+                        * This is a workaround for MS SQL Server linked server
+                        * which can not handle large varchars (ref: 
SUPPORT-747) */
+                       if (rec->sql_desc_concise_type == SQL_WVARCHAR
+                        && stmt->Dbc->mapToLongVarchar > 0
+                        && rec->sql_desc_length > (SQLULEN) 
stmt->Dbc->mapToLongVarchar)
+                               rec->sql_desc_concise_type = SQL_WLONGVARCHAR;
                } else {
                        rec->sql_desc_length = ODBCLength(rec, SQL_DESC_LENGTH);
                        rec->sql_desc_display_size = ODBCLength(rec, 
SQL_DESC_DISPLAY_SIZE);
diff --git a/clients/odbc/driver/SQLPrepare.c b/clients/odbc/driver/SQLPrepare.c
--- a/clients/odbc/driver/SQLPrepare.c
+++ b/clients/odbc/driver/SQLPrepare.c
@@ -277,9 +277,18 @@ MNDBPrepare(ODBCStmt *stmt,
                    rec->sql_desc_concise_type == SQL_LONGVARCHAR ||
                    rec->sql_desc_concise_type == SQL_WCHAR ||
                    rec->sql_desc_concise_type == SQL_WVARCHAR ||
-                   rec->sql_desc_concise_type == SQL_WLONGVARCHAR)
+                   rec->sql_desc_concise_type == SQL_WLONGVARCHAR) {
                        rec->sql_desc_case_sensitive = SQL_TRUE;
-               else
+
+                       /* For large varchar column definitions conditionally
+                        * change type to SQL_WLONGVARCHAR when 
mapToLongVarchar is set (e.g. to 4000)
+                        * This is a workaround for MS SQL Server linked server
+                        * which can not handle large varchars (ref: 
SUPPORT-747) */
+                       if (rec->sql_desc_concise_type == SQL_WVARCHAR
+                        && stmt->Dbc->mapToLongVarchar > 0
+                        && rec->sql_desc_length > (SQLULEN) 
stmt->Dbc->mapToLongVarchar)
+                               rec->sql_desc_concise_type = SQL_WLONGVARCHAR;
+               } else
                        rec->sql_desc_case_sensitive = SQL_FALSE;
 
                rec->sql_desc_local_type_name = NULL;
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to