1) Implement SQLParamOptions().
authorHiroshi Inoue <inoue@tpf.co.jp>
Fri, 8 Mar 2002 08:52:55 +0000 (08:52 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Fri, 8 Mar 2002 08:52:55 +0000 (08:52 +0000)
2) Handle Multiple results and implement SQLMoreResult().
3) Improve multibyte handling thanks to Eiji Tokuya.
4) Add new options.
   LF <-> CR/LF converion.
   TRUE is -1 (for VB).
5) Introduce unicode(UCS-2) support.
6) Reduce the length of connection strings.
7) Improve SQLError, SQLGetDiagRec(ODBC 3.0).
8) Implement SQLTablePrivileges().
9) Miscellaneous changes for ODBC 3.0 support.

43 files changed:
src/interfaces/odbc/bind.c
src/interfaces/odbc/connection.c
src/interfaces/odbc/connection.h
src/interfaces/odbc/convert.c
src/interfaces/odbc/convert.h
src/interfaces/odbc/dlg_specific.c
src/interfaces/odbc/dlg_specific.h
src/interfaces/odbc/drvconn.c
src/interfaces/odbc/environ.c
src/interfaces/odbc/environ.h
src/interfaces/odbc/execute.c
src/interfaces/odbc/info.c
src/interfaces/odbc/info30.c
src/interfaces/odbc/misc.c
src/interfaces/odbc/misc.h
src/interfaces/odbc/multibyte.c
src/interfaces/odbc/multibyte.h
src/interfaces/odbc/odbcapi.c
src/interfaces/odbc/odbcapi25w.c
src/interfaces/odbc/odbcapi30.c
src/interfaces/odbc/odbcapi30w.c
src/interfaces/odbc/odbcapiw.c
src/interfaces/odbc/options.c
src/interfaces/odbc/parse.c
src/interfaces/odbc/pgapi30.c
src/interfaces/odbc/pgapifunc.h
src/interfaces/odbc/pgtypes.c
src/interfaces/odbc/psqlodbc.h
src/interfaces/odbc/psqlodbc.rc
src/interfaces/odbc/psqlodbc_api30w.def [new file with mode: 0644]
src/interfaces/odbc/psqlodbc_apiw.def [new file with mode: 0644]
src/interfaces/odbc/qresult.c
src/interfaces/odbc/qresult.h
src/interfaces/odbc/resource.h
src/interfaces/odbc/results.c
src/interfaces/odbc/setup.c
src/interfaces/odbc/statement.c
src/interfaces/odbc/statement.h
src/interfaces/odbc/win32.mak
src/interfaces/odbc/win32_30.mak
src/interfaces/odbc/win32_30w.mak [new file with mode: 0644]
src/interfaces/odbc/win32w.mak [new file with mode: 0644]
src/interfaces/odbc/win_unicode.c

index f3fb35373578d2af34e4d6c5d43000cf56a00fd4..6ce32c7982b8848d0c783b7786383b9e95506a05 100644 (file)
@@ -7,7 +7,7 @@
  * Classes:            BindInfoClass, ParameterInfoClass
  *
  * API functions:  SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams,
- *                 SQLParamOptions(NI)
+ *                 SQLParamOptions
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *-------
@@ -331,17 +331,9 @@ PGAPI_ParamOptions(
 
    mylog("%s: entering... %d %x\n", func, crow, pirow);
 
-   if (crow == 1)              /* temporary solution and must be
-                                * rewritten later */
-   {
-       if (pirow)
-           *pirow = 1;
-       return SQL_SUCCESS;
-   }
-   stmt->errornumber = CONN_UNSUPPORTED_OPTION;
-   stmt->errormsg = "Function not implemented";
-   SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
-   return SQL_ERROR;
+   stmt->options.paramset_size = crow;
+   stmt->options.param_processed_ptr = pirow;
+   return SQL_SUCCESS;
 }
 
 
index 3d07474a560cc49243d270d74f8d2a7255aef1c0..44d7589496a478da99e2adc33eef5207437562de 100644 (file)
@@ -75,7 +75,8 @@ PGAPI_AllocConnect(
        return SQL_ERROR;
    }
 
-   *phdbc = (HDBC) conn;
+   if (phdbc)
+       *phdbc = (HDBC) conn;
 
    return SQL_SUCCESS;
 }
@@ -228,6 +229,16 @@ PGAPI_FreeConnect(
 }
 
 
+void
+CC_conninfo_init(ConnInfo *conninfo)
+{
+       memset(conninfo, 0, sizeof(ConnInfo));
+       conninfo->disallow_premature = -1;
+       conninfo->updatable_cursors = -1;
+       conninfo->lf_conversion = -1;
+       conninfo->true_is_minus1 = -1;
+       memcpy(&(conninfo->drivers), &globals, sizeof(globals));
+}
 /*
  *     IMPLEMENTATION CONNECTION CLASS
  */
@@ -249,11 +260,7 @@ CC_Constructor()
        rv->status = CONN_NOT_CONNECTED;
        rv->transact_status = CONN_IN_AUTOCOMMIT;       /* autocommit by default */
 
-       memset(&rv->connInfo, 0, sizeof(ConnInfo));
-#ifdef DRIVER_CURSOR_IMPLEMENT
-       rv->connInfo.updatable_cursors = 1;
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
-       memcpy(&(rv->connInfo.drivers), &globals, sizeof(globals));
+       CC_conninfo_init(&(rv->connInfo));
        rv->sock = SOCK_Constructor(rv);
        if (!rv->sock)
            return NULL;
@@ -280,6 +287,7 @@ CC_Constructor()
        rv->pg_version_major = 0;
        rv->pg_version_minor = 0;
        rv->ms_jet = 0;
+       rv->unicode = 0;
 #ifdef MULTIBYTE
        rv->client_encoding = NULL;
        rv->server_encoding = NULL;
@@ -338,7 +346,7 @@ CC_cursor_count(ConnectionClass *self)
    for (i = 0; i < self->num_stmts; i++)
    {
        stmt = self->stmts[i];
-       if (stmt && stmt->result && stmt->result->cursor)
+       if (stmt && SC_get_Result(stmt) && SC_get_Result(stmt)->cursor)
            count++;
    }
 
@@ -366,18 +374,18 @@ CC_begin(ConnectionClass *self)
    char    ret = TRUE;
    if (!CC_is_in_trans(self))
    {
-       QResultClass *res = CC_send_query(self, "BEGIN", NULL);
+       QResultClass *res = CC_send_query(self, "BEGIN", NULL, TRUE);
        mylog("CC_begin:  sending BEGIN!\n");
 
        if (res != NULL)
        {
-           ret = (!QR_aborted(res) && QR_command_successful(res));
+           ret = QR_command_successful(res);
            QR_Destructor(res);
            if (ret)
                CC_set_in_trans(self);
        }
        else
-           ret = FALSE;
+           return FALSE;
    }
 
    return ret;
@@ -393,7 +401,7 @@ CC_commit(ConnectionClass *self)
    char    ret = FALSE;
    if (CC_is_in_trans(self))
    {
-       QResultClass *res = CC_send_query(self, "COMMIT", NULL);
+       QResultClass *res = CC_send_query(self, "COMMIT", NULL, TRUE);
        mylog("CC_commit:  sending COMMIT!\n");
 
        CC_set_no_trans(self);
@@ -404,7 +412,7 @@ CC_commit(ConnectionClass *self)
            QR_Destructor(res);
        }
        else
-           ret = FALSE;
+           return FALSE;
    }
 
    return ret;
@@ -419,7 +427,7 @@ CC_abort(ConnectionClass *self)
 {
    if (CC_is_in_trans(self))
    {
-       QResultClass *res = CC_send_query(self, "ROLLBACK", NULL);
+       QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, TRUE);
        mylog("CC_abort:  sending ABORT!\n");
 
        CC_set_no_trans(self);
@@ -488,11 +496,7 @@ CC_cleanup(ConnectionClass *self)
 
    self->status = CONN_NOT_CONNECTED;
    self->transact_status = CONN_IN_AUTOCOMMIT;
-   memset(&self->connInfo, 0, sizeof(ConnInfo));
-#ifdef DRIVER_CURSOR_IMPLEMENT
-   self->connInfo.updatable_cursors = 1;
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
-   memcpy(&(self->connInfo.drivers), &globals, sizeof(globals));
+   CC_conninfo_init(&(self->connInfo));
 #ifdef MULTIBYTE
    if (self->client_encoding)
        free(self->client_encoding);
@@ -578,12 +582,12 @@ md5_auth_send(ConnectionClass *self, const char *salt)
    {
        free(pwd1);
        return 1;
-   }
+   } 
    if (!(pwd2 = malloc(MD5_PASSWD_LEN + 1)))
    {
        free(pwd1);
        return 1;
-   }
+   } 
    if (!EncryptMD5(pwd1 + strlen("md5"), salt, 4, pwd2))
    {
        free(pwd2);
@@ -595,7 +599,7 @@ md5_auth_send(ConnectionClass *self, const char *salt)
    SOCK_put_n_char(sock, pwd2, strlen(pwd2) + 1);
    SOCK_flush_output(sock);
    free(pwd2);
-   return 0;
+   return 0; 
 }
 
 char
@@ -608,7 +612,7 @@ CC_connect(ConnectionClass *self, char do_password)
    ConnInfo   *ci = &(self->connInfo);
    int         areq = -1;
    int         beresp;
-   char        msgbuffer[ERROR_MSG_LENGTH];
+   static char     msgbuffer[ERROR_MSG_LENGTH];
    char        salt[5];
    static char *func = "CC_connect";
 
@@ -651,15 +655,16 @@ CC_connect(ConnectionClass *self, char do_password)
            if (encoding && strcmp(encoding, "OTHER"))
                self->client_encoding = strdup(encoding);
        }
+       if (self->client_encoding)
+           self->ccsc = pg_CS_code(self->client_encoding);
        qlog("                extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n",
             ci->drivers.extra_systable_prefixes,
             ci->drivers.conn_settings,
             encoding ? encoding : "");
 #else
-       qlog("                extra_systable_prefixes='%s', conn_settings='%s', protocol='%s'\n",
+       qlog("                extra_systable_prefixes='%s', conn_settings='%s'\n",
             ci->drivers.extra_systable_prefixes,
-            ci->drivers.conn_settings,
-            ci->protocol);
+            ci->drivers.conn_settings);
 #endif
 
        if (self->status != CONN_NOT_CONNECTED)
@@ -914,7 +919,7 @@ another_version_retry:
     */
    mylog("sending an empty query...\n");
 
-   res = CC_send_query(self, " ", NULL);
+   res = CC_send_query(self, " ", NULL, TRUE);
    if (res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY)
    {
        mylog("got no result from the empty query.  (probably database does not exist)\n");
@@ -942,13 +947,55 @@ another_version_retry:
     * function instead.
     */
    CC_send_settings(self);
-   CC_lookup_lo(self);         /* a hack to get the oid of our large
-                                * object oid type */
-#ifdef MULTIBYTE\r
-   CC_lookup_characterset(self);\r
-#endif\r
-   CC_lookup_pg_version(self); /* Get PostgreSQL version for SQLGetInfo
-                                * use */
+   CC_lookup_lo(self);         /* a hack to get the oid of
+                          our large object oid type */
+   CC_lookup_pg_version(self);     /* Get PostgreSQL version for
+                          SQLGetInfo use */
+
+   /*
+    *  Multibyte handling is available ?
+    */
+#ifdef MULTIBYTE
+   if (PG_VERSION_GE(self, 7.0))
+   {
+       CC_lookup_characterset(self);
+       if (self->errornumber != 0)
+           return 0;
+#ifdef UNICODE_SUPPORT
+       if (self->unicode)
+       {
+           if (!self->client_encoding ||
+               stricmp(self->client_encoding, "UNICODE"))
+           {
+               QResultClass    *res;
+               if (PG_VERSION_LT(self, 7.1))
+               {
+                   self->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
+                   self->errormsg = "UTF-8 conversion isn't implemented before 7.1";
+                   return 0;
+               }
+               if (self->client_encoding)
+                   free(self->client_encoding);
+               self->client_encoding = NULL;
+               if (res = CC_send_query(self, "set client_encoding to 'UTF8'", NULL, TRUE), res)
+               {
+                   self->client_encoding = strdup("UNICODE");
+                   QR_Destructor(res);
+                   
+               }
+           }
+       }
+#endif /* UNICODE_SUPPORT */
+   }
+#ifdef UNICODE_SUPPORT
+   else if (self->unicode)
+   {
+       self->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
+       self->errormsg = "Unicode isn't supported before 7.0";
+       return 0;
+   }
+#endif /* UNICODE_SUPPORT */
+#endif /* MULTIBYTE */
 
    CC_clear_error(self);       /* clear any initial command errors */
    self->status = CONN_CONNECTED;
@@ -1081,11 +1128,12 @@ CC_get_error(ConnectionClass *self, int *number, char **message)
  * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
  */
 QResultClass *
-CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
+CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL clear_result_on_abort)
 {
    QResultClass *result_in = NULL,
-              *res = NULL,
-              *retres = NULL;
+              *cmdres = NULL,
+              *retres = NULL,
+              *res = NULL;
    char        swallow,
               *wq;
    int         id;
@@ -1094,9 +1142,9 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
                empty_reqs;
    BOOL        msg_truncated,
                ReadyToReturn,
-               tuples_return = FALSE,
                query_completed = FALSE,
                before_64 = PG_VERSION_LT(self, 6.4),
+               aborted = FALSE,
                used_passed_result_object = FALSE;
 
    /* ERROR_MSG_LENGTH is suffcient */
@@ -1156,6 +1204,20 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
        ;
    if (*wq == '\0')
        empty_reqs = 1;
+   cmdres = qi ? qi->result_in : NULL;
+   if (cmdres)
+       used_passed_result_object = TRUE;
+   else
+   {
+       cmdres = QR_Constructor();
+       if (!cmdres)
+       {
+           self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
+           self->errormsg = "Could not create result info in send_query.";
+           return NULL;
+       }
+   }
+   res = cmdres;
    while (!ReadyToReturn)
    {
        /* what type of message is coming now ? */
@@ -1199,12 +1261,14 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
                {
                    mylog("send_query: ok - 'C' - %s\n", cmdbuffer);
 
-                   if (res == NULL)    /* allow for "show" style info */
-                       res = QR_Constructor();
+                   if (query_completed)    /* allow for "show" style notices */
+                   {
+                       res->next = QR_Constructor();
+                       res = res->next;
+                   } 
 
                    mylog("send_query: setting cmdbuffer = '%s'\n", cmdbuffer);
 
-                   /* Only save the first command */
                    if (QR_command_successful(res))
                        QR_set_status(res, PGRES_COMMAND_OK);
                    QR_set_command(res, cmdbuffer);
@@ -1233,44 +1297,19 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
                if (empty_reqs == 0)
                {
                    ReadyToReturn = TRUE;
-                   if (res && QR_get_aborted(res))
-                       retres = res;
-                   else if (tuples_return)
-                       retres = result_in;
-                   else if (query_completed)
-                       retres = res;
+                   if (aborted || query_completed)
+                       retres = cmdres;
                    else
                        ReadyToReturn = FALSE;
                }
                break;
-           case 'N':           /* INFO, NOTICE, WARNING */
+           case 'N':           /* NOTICE: */
                msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
-               if (!res)
-                   res = QR_Constructor();
                if (QR_command_successful(res))
                    QR_set_status(res, PGRES_NONFATAL_ERROR);
                QR_set_notice(res, cmdbuffer);  /* will dup this string */
-#ifdef MULTIBYTE\r
-               if (strstr(cmdbuffer,"encoding is"))\r
-               {\r
-                   if (strstr(cmdbuffer,"Current client encoding is"))\r
-                       strcpy(PG_CCSS, cmdbuffer + 36);\r
-                   if (strstr(cmdbuffer,"Current server encoding is"))\r
-                       strcpy(PG_SCSS, cmdbuffer + 36);\r
-                   mylog("~~~ WARNING: '%s'\n", cmdbuffer);\r
-                   qlog("WARNING from backend during send_query: '%s'\n ClientEncoding = %s\n ServerEncoding = %s\n", cmdbuffer, PG_CCSS, PG_SCSS);\r
-\r
-               }\r
-               else\r
-               {\r
-\r
-                   mylog("~~~ WARNING: '%s'\n", cmdbuffer);\r
-                   qlog("WARNING from backend during send_query: '%s'\n", cmdbuffer);\r
-               }\r
-#else\r
-               mylog("~~~ WARNING: '%s'\n", cmdbuffer);\r
-               qlog("WARNING from backend during send_query: '%s'\n", cmdbuffer);\r
-#endif
+               mylog("~~~ NOTICE: '%s'\n", cmdbuffer);
+               qlog("NOTICE from backend during send_query: '%s'\n", cmdbuffer);
                while (msg_truncated)
                    msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
 
@@ -1280,15 +1319,13 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
            case 'I':           /* The server sends an empty query */
                /* There is a closing '\0' following the 'I', so we eat it */
                swallow = SOCK_get_char(sock);
-               if (!res)
-                   res = QR_Constructor();
                if ((swallow != '\0') || SOCK_get_errcode(sock) != 0)
                {
                    self->errornumber = CONNECTION_BACKEND_CRAZY;
                    self->errormsg = "Unexpected protocol character from backend (send_query - I)";
                    QR_set_status(res, PGRES_FATAL_ERROR);
                    ReadyToReturn = TRUE;
-                   retres = res;
+                   retres = cmdres;
                    break;
                }
                else
@@ -1315,8 +1352,6 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
                qlog("ERROR from backend during send_query: '%s'\n", self->errormsg);
 
                /* We should report that an error occured. Zoltan */
-               if (!res)
-                   res = QR_Constructor();
 
                if (!strncmp(self->errormsg, "FATAL", 5))
                {
@@ -1327,6 +1362,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
                    self->errornumber = CONNECTION_SERVER_REPORTED_WARNING;
                QR_set_status(res, PGRES_FATAL_ERROR);
                QR_set_aborted(res, TRUE);
+               aborted = TRUE;
                while (msg_truncated)
                    msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
 
@@ -1337,13 +1373,11 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
                SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
                break;
            case 'T':           /* Tuple results start here */
-               result_in = qi ? qi->result_in : NULL;
-
-               if (result_in == NULL)
+               if (query_completed)
                {
-                   result_in = QR_Constructor();
-                   mylog("send_query: 'T' no result_in: res = %u\n", result_in);
-                   if (!result_in)
+                   res->next = QR_Constructor();
+                   mylog("send_query: 'T' no result_in: res = %u\n", res->next);
+                   if (!res->next)
                    {
                        self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
                        self->errormsg = "Could not create result info in send_query.";
@@ -1351,55 +1385,60 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
                        retres = NULL;
                        break;
                    }
+                   res = res->next;
 
                    if (qi)
-                       QR_set_cache_size(result_in, qi->row_size);
-
-                   if (!QR_fetch_tuples(result_in, self, qi ? qi->cursor : NULL))
+                       QR_set_cache_size(res, qi->row_size);
+               }
+               if (!used_passed_result_object)
+               {
+                   if (!QR_fetch_tuples(res, self, qi ? qi->cursor : NULL))
                    {
                        self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
-                       self->errormsg = QR_get_message(result_in);
+                       self->errormsg = QR_get_message(res);
                        ReadyToReturn = TRUE;
                        retres = NULL;
                        break;
                    }
+                   query_completed = TRUE;
                }
                else
                {               /* next fetch, so reuse an existing result */
 
-                   used_passed_result_object = TRUE;
                    /*
                     * called from QR_next_tuple and must return
                     * immediately.
                     */
                    ReadyToReturn = TRUE;
-                   if (!QR_fetch_tuples(result_in, NULL, NULL))
+                   if (!QR_fetch_tuples(res, NULL, NULL))
                    {
                        self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
-                       self->errormsg = QR_get_message(result_in);
+                       self->errormsg = QR_get_message(res);
                        retres = NULL;
                        break;
                    }
-                   retres = result_in;
+                   retres = cmdres;
                }
-
-               tuples_return = TRUE;
                break;
            case 'D':           /* Copy in command began successfully */
-               if (!res)
-                   res = QR_Constructor();
-               if (QR_command_successful(res))
-                   QR_set_status(res, PGRES_COPY_IN);
+               if (query_completed)
+               {
+                   res->next = QR_Constructor();
+                   res = res->next;
+               }
+               QR_set_status(res, PGRES_COPY_IN);
                ReadyToReturn = TRUE;
-               retres = res;
+               retres = cmdres;
                break;
            case 'B':           /* Copy out command began successfully */
-               if (!res)
-                   res = QR_Constructor();
-               if (QR_command_successful(res))
-                   QR_set_status(res, PGRES_COPY_OUT);
+               if (query_completed)
+               {
+                   res->next = QR_Constructor();
+                   res = res->next;
+               }
+               QR_set_status(res, PGRES_COPY_OUT);
                ReadyToReturn = TRUE;
-               retres = res;
+               retres = cmdres;
                break;
            default:
                self->errornumber = CONNECTION_BACKEND_CRAZY;
@@ -1417,7 +1456,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
         */
        if (before_64)
        {
-           if (empty_reqs == 0 && (query_completed || tuples_return))
+           if (empty_reqs == 0 && query_completed)
                break;
        }
    }
@@ -1426,34 +1465,44 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
     * Break before being ready to return.
     */
    if (!ReadyToReturn)
-   {
-       if (res && QR_get_aborted(res))
-           retres = res;
-       else if (tuples_return)
-           retres = result_in;
-       else
-           retres = res;
-   }
+       retres = cmdres;
 
    /*
-    * set notice message to result_in.
+    * Cleanup garbage results before returning.
     */
-   if (result_in && res && retres == result_in)
-   {
-       if (QR_command_successful(result_in))
-           QR_set_status(result_in, QR_get_status(res));
-       QR_set_notice(result_in, QR_get_notice(res));
-   }
-
+   if (cmdres && retres != cmdres && !used_passed_result_object)
+       QR_Destructor(cmdres);
    /*
-    * Cleanup garbage results before returning.
+    * Cleanup the aborted result if specified
     */
-   if (res && retres != res)
-       QR_Destructor(res);
-   if (result_in && retres != result_in)
+   if (retres)
    {
-       if (!used_passed_result_object)
-           QR_Destructor(result_in);
+       if (aborted)
+       {
+           if (clear_result_on_abort)
+           {
+               if (!used_passed_result_object)
+               {
+                   QR_Destructor(retres);
+                   retres = NULL;
+               }
+           }
+           else
+           {
+               /*
+                *  discard results other than errors.
+                */
+               QResultClass    *qres;
+               for (qres = retres; qres->next; qres = retres)
+               {
+                   if (QR_get_aborted(qres))
+                       break;
+                   retres = qres->next;
+                   qres->next = NULL;
+                   QR_Destructor(qres);
+               }
+           }
+       }
    }
    return retres;
 }
@@ -1591,7 +1640,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
                SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
 
                mylog("send_function(G): 'N' - %s\n", msgbuffer);
-               qlog("WARNING from backend during send_function: '%s'\n", msgbuffer);
+               qlog("NOTICE from backend during send_function: '%s'\n", msgbuffer);
 
                continue;       /* dont return a result -- continue
                                 * reading */
@@ -1869,7 +1918,7 @@ CC_lookup_pg_version(ConnectionClass *self)
 
 
 void
-CC_log_error(char *func, char *desc, ConnectionClass *self)
+CC_log_error(const char *func, const char *desc, const ConnectionClass *self)
 {
 #ifdef PRN_NULLCHECK
 #define nullcheck(a) (a ? a : "(NULL)")
@@ -1894,7 +1943,10 @@ CC_log_error(char *func, char *desc, ConnectionClass *self)
        }
    }
    else
+{
        qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
+       mylog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
+}
 #undef PRN_NULLCHECK
 }
 
index df40f440d692ca66b83fd1ed24832963a36820cf..408d11836c5c0def54ee43ae9a26b7bc949a80db 100644 (file)
@@ -151,6 +151,8 @@ typedef struct
    char        focus_password;
    char        disallow_premature;
    char        updatable_cursors;
+   char        lf_conversion;
+   char        true_is_minus1;
    GLOBAL_VALUES drivers;      /* moved from driver's option */
 } ConnInfo;
 
@@ -271,6 +273,7 @@ struct ConnectionClass_
    char       *client_encoding;
    char       *server_encoding;
 #endif   /* MULTIBYTE */
+   int ccsc;
 };
 
 
@@ -290,6 +293,7 @@ struct ConnectionClass_
 
 /* prototypes */
 ConnectionClass *CC_Constructor(void);
+void       CC_conninfo_init(ConnInfo *conninfo);
 char       CC_Destructor(ConnectionClass *self);
 int            CC_cursor_count(ConnectionClass *self);
 char       CC_cleanup(ConnectionClass *self);
@@ -301,7 +305,7 @@ char        CC_connect(ConnectionClass *self, char do_password);
 char       CC_add_statement(ConnectionClass *self, StatementClass *stmt);
 char       CC_remove_statement(ConnectionClass *self, StatementClass *stmt);
 char       CC_get_error(ConnectionClass *self, int *number, char **message);
-QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi);
+QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL);
 void       CC_clear_error(ConnectionClass *self);
 char      *CC_create_errormsg(ConnectionClass *self);
 int            CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs);
@@ -309,7 +313,7 @@ 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);
+void       CC_log_error(const char *func, const char *desc, const ConnectionClass *self);
 int            CC_get_max_query_len(const ConnectionClass *self);
 
 #endif
index 4291e36c34ca61aabd6f86abe577ed9c0e679bef..a38ffd1de8313605238d294136112c2c5ac3cb3f 100644 (file)
@@ -335,12 +335,15 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
    int         bind_row = stmt->bind_row;
    int         bind_size = stmt->options.bind_size;
    int         result = COPY_OK;
-   BOOL        changed;
+   BOOL        changed, true_is_minus1 = FALSE;
    const char *neut_str = value;
    char        midtemp[2][32];
    int         mtemp_cnt = 0;
    static BindInfoClass sbic;
    BindInfoClass *pbic;
+#ifdef UNICODE_SUPPORT
+   BOOL    wchanged =   FALSE;
+#endif /* UNICODE_SUPPORT */
 
    if (stmt->current_col >= 0)
    {
@@ -474,15 +477,23 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                char       *s;
 
                s = midtemp[mtemp_cnt];
-               strcpy(s, (char *) value);
-               if (s[0] == 'f' || s[0] == 'F' || s[0] == 'n' || s[0] == 'N' || s[0] == '0')
-                   s[0] = '0';
-               else
-                   s[0] = '1';
-               s[1] = '\0';
+               switch (((char *)value)[0])
+               {
+                   case 'f':
+                   case 'F':
+                   case 'n':
+                   case 'N':
+                   case '0':
+                       strcpy(s, "0");
+                       break;
+                   default:
+                       if (true_is_minus1)
+                           strcpy(s, "-1");
+                       else
+                           strcpy(s, "1");
+               }
                neut_str = midtemp[mtemp_cnt];
                mtemp_cnt++;
-
            }
            break;
 
@@ -567,7 +578,11 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 
    rgbValueBindRow = (char *) rgbValue + rgbValueOffset;
 
+#ifdef UNICODE_SUPPORT
+   if (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR)
+#else
    if (fCType == SQL_C_CHAR)
+#endif /* UNICODE_SUPPORT */
    {
        /* Special character formatting as required */
 
@@ -599,7 +614,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                break;
 
            case PG_TYPE_BOOL:
-               len = 1;
+               len = strlen(neut_str);
                if (cbValueMax > len)
                {
                    strcpy(rgbValueBindRow, neut_str);
@@ -637,8 +652,18 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                    pbic = &stmt->bindings[stmt->current_col];
                if (pbic->data_left < 0)
                {
+                   BOOL lf_conv = SC_get_conn(stmt)->connInfo.lf_conversion;
+#ifdef UNICODE_SUPPORT
+                   if (fCType == SQL_C_WCHAR)
+                   {
+                       len = utf8_to_ucs2(neut_str, -1, NULL, 0);
+                       len *= 2;
+                       wchanged = changed = TRUE;
+                   }
+                   else
+#endif /* UNICODE_SUPPORT */
                    /* convert linefeeds to carriage-return/linefeed */
-                   len = convert_linefeeds(neut_str, NULL, 0, &changed);
+                   len = convert_linefeeds(neut_str, NULL, 0, lf_conv, &changed);
                    if (cbValueMax == 0)        /* just returns length
                                                 * info */
                    {
@@ -654,7 +679,14 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                            pbic->ttlbuf = realloc(pbic->ttlbuf, len + 1);
                            pbic->ttlbuflen = len + 1;
                        }
-                       convert_linefeeds(neut_str, pbic->ttlbuf, pbic->ttlbuflen, &changed);
+#ifdef UNICODE_SUPPORT
+                       if (fCType == SQL_C_WCHAR)
+                       {
+                           utf8_to_ucs2(neut_str, -1, (SQLWCHAR *) pbic->ttlbuf, len / 2);
+                       }
+                       else
+#endif /* UNICODE_SUPPORT */
+                       convert_linefeeds(neut_str, pbic->ttlbuf, pbic->ttlbuflen, lf_conv, &changed);
                        ptr = pbic->ttlbuf;
                    }
                    else
@@ -715,7 +747,25 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                mylog("    SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
                break;
        }
-
+#ifdef UNICODE_SUPPORT
+       if (SQL_C_WCHAR == fCType && ! wchanged)
+       {
+           if (cbValueMax > 2 * len)
+           {
+               char *str = strdup(rgbValueBindRow);
+               UInt4   ucount = utf8_to_ucs2(str, len, (SQLWCHAR *) rgbValueBindRow, cbValueMax / 2);
+               if (cbValueMax < 2 * (SDWORD) ucount)
+                   result = COPY_RESULT_TRUNCATED;
+               len = ucount * 2;
+               free(str); 
+           }
+           else
+           {
+               len *= 2;
+               result = COPY_RESULT_TRUNCATED;
+           }
+       }
+#endif /* UNICODE_SUPPORT */
 
    }
    else
@@ -1107,11 +1157,11 @@ do { \
  */
 #define CVT_SPECIAL_CHARS(buf, used) \
 do { \
-   int cnvlen = convert_special_chars(buf, NULL, used); \
+   int cnvlen = convert_special_chars(buf, NULL, used, lf_conv, conn->ccsc); \
    unsigned int    newlimit = npos + cnvlen; \
 \
    ENLARGE_NEWSTATEMENT(newlimit); \
-   convert_special_chars(buf, &new_statement[npos], used); \
+   convert_special_chars(buf, &new_statement[npos], used, lf_conv, conn->ccsc); \
    npos += cnvlen; \
 } while (0)
 
@@ -1181,9 +1231,9 @@ table_for_update(const char *stmt, int *endpos)
 }
 
 #ifdef MULTIBYTE
-#define        my_strchr(s1,c1) multibyte_strchr(s1,c1)
+#define        my_strchr(conn, s1,c1) pg_mbschr(conn->ccsc, s1,c1)
 #else
-#define        my_strchr(s1,c1) strchr(s1,c1)
+#define        my_strchr(conn, s1,c1) strchr(s1,c1)
 #endif
 /*
  * This function inserts parameters into an SQL statements.
@@ -1213,8 +1263,7 @@ copy_statement_with_parameters(StatementClass *stmt)
    time_t      t = time(NULL);
    struct tm  *tim;
    SDWORD      used;
-   char       *buffer,
-              *buf;
+   char       *buffer, *buf, *allocbuf;
    BOOL        in_quote = FALSE,
                in_dquote = FALSE,
                in_escape = FALSE;
@@ -1234,6 +1283,10 @@ copy_statement_with_parameters(StatementClass *stmt)
    BOOL        prev_token_end;
    UInt4   offset = stmt->options.param_offset_ptr ? *stmt->options.param_offset_ptr : 0;
    UInt4   current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
+   BOOL    lf_conv = ci->lf_conversion;
+#ifdef MULTIBYTE
+   encoded_str encstr;
+#endif   /* MULTIBYTE */
 
 #ifdef DRIVER_CURSOR_IMPLEMENT
    BOOL        search_from_pos = FALSE;
@@ -1311,14 +1364,14 @@ copy_statement_with_parameters(StatementClass *stmt)
    }
    param_number = -1;
 #ifdef MULTIBYTE
-   multibyte_init();
+   make_encoded_str(&encstr, conn, old_statement);
 #endif
 
    for (opos = 0; opos < oldstmtlen; opos++)
    {
-       oldchar = old_statement[opos];
 #ifdef MULTIBYTE
-       if (multibyte_char_check(oldchar) != 0)
+       oldchar = encoded_byte_check(&encstr, opos);
+       if (ENCODE_STATUS(encstr) != 0)
        {
            CVT_APPEND_CHAR(oldchar);
            continue;
@@ -1327,6 +1380,8 @@ copy_statement_with_parameters(StatementClass *stmt)
        /*
         * From here we are guaranteed to handle a 1-byte character.
         */
+#else
+       oldchar = old_statement[opos];
 #endif
 
        if (in_escape)          /* escape check */
@@ -1352,7 +1407,7 @@ copy_statement_with_parameters(StatementClass *stmt)
         * nor a double quote.
         */
        /* Squeeze carriage-return/linefeed pairs to linefeed only */
-       else if (oldchar == '\r' && opos + 1 < oldstmtlen &&
+       else if (lf_conv && oldchar == '\r' && opos + 1 < oldstmtlen &&
                 old_statement[opos + 1] == '\n')
            continue;
 
@@ -1390,11 +1445,12 @@ copy_statement_with_parameters(StatementClass *stmt)
                }
                opos += lit_call_len;
                CVT_APPEND_STR("SELECT ");
-               if (my_strchr(&old_statement[opos], '('))
+               if (my_strchr(conn, &old_statement[opos], '('))
                    proc_no_param = FALSE;
                continue;
            }
-           if (convert_escape(begin, stmt, &npos, &new_stsize, &end) != CONVERT_ESCAPE_OK)
+           if (convert_escape(begin, stmt, &npos, &new_stsize, &end
+) != CONVERT_ESCAPE_OK)
            {
                stmt->errormsg = "ODBC escape convert error";
                stmt->errornumber = STMT_EXEC_ERROR;
@@ -1585,7 +1641,7 @@ copy_statement_with_parameters(StatementClass *stmt)
        if (param_ctype == SQL_C_DEFAULT)
            param_ctype = sqltype_to_default_ctype(param_sqltype);
 
-       buf = NULL;
+       allocbuf = buf = NULL;
        param_string[0] = '\0';
        cbuf[0] = '\0';
 
@@ -1597,6 +1653,13 @@ copy_statement_with_parameters(StatementClass *stmt)
                buf = buffer;
                break;
 
+#ifdef UNICODE_SUPPORT
+           case SQL_C_WCHAR:
+               buf = allocbuf = ucs2_to_utf8((SQLWCHAR *) buffer, used / 2, &used);
+               used *= 2;
+               break;
+#endif /* UNICODE_SUPPORT */
+
            case SQL_C_DOUBLE:
                sprintf(param_string, "%.15g",
                        *((SDOUBLE *) buffer));
@@ -1729,6 +1792,11 @@ copy_statement_with_parameters(StatementClass *stmt)
            case SQL_CHAR:
            case SQL_VARCHAR:
            case SQL_LONGVARCHAR:
+#ifdef UNICODE_SUPPORT
+           case SQL_WCHAR:
+           case SQL_WVARCHAR:
+           case SQL_WLONGVARCHAR:
+#endif /* UNICODE_SUPPORT */
 
                CVT_APPEND_CHAR('\'');  /* Open Quote */
 
@@ -1801,7 +1869,7 @@ copy_statement_with_parameters(StatementClass *stmt)
                tmp[0] = '\'';
                /* Time zone stuff is unreliable */
                stime2timestamp(&st, tmp + 1, USE_ZONE, PG_VERSION_GE(conn, 7.2));
-               strcat(tmp, "'");
+               strcat(tmp, "'::timestamp");
 
                CVT_APPEND_STR(tmp);
 
@@ -1942,6 +2010,10 @@ copy_statement_with_parameters(StatementClass *stmt)
 
                break;
        }
+#ifdef UNICODE_SUPPORT
+       if (allocbuf)
+           free(allocbuf);
+#endif /* UNICODE_SUPPORT */
    }                           /* end, for */
 
    /* make sure new_statement is always null-terminated */
@@ -2032,7 +2104,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
    while ((*valptr != '\0') && isspace((unsigned char) *valptr))
        valptr++;
      
-   if (end = my_strchr(valptr, '}'), NULL == end)
+   if (end = my_strchr(conn, valptr, '}'), NULL == end)
    {
        mylog("%s couldn't find the ending }\n",func);
        return CONVERT_ESCAPE_ERROR;
@@ -2226,13 +2298,16 @@ int processParameters(const ConnectionClass *conn, const char *value,
    const char  *valptr;
    char    buf[1024];
    BOOL    in_quote, in_dquote, in_escape, leadingSpace;
+#ifdef MULTIBYTE
+   encoded_str encstr;
+#endif   /* MULTIBYTE */
  
    buf[sizeof(buf)-1] = '\0';
    innerParenthesis = 0;
    in_quote = in_dquote = in_escape = leadingSpace = FALSE;
    param_count = 0;
 #ifdef MULTIBYTE
-   multibyte_init();
+   make_encoded_str(&encstr, conn, value);
 #endif /* MULTIBYTE */
    /* begin with outer '(' */
    for (stop = FALSE, valptr = value, ipos = count = 0; *valptr != '\0'; ipos++, valptr++)
@@ -2250,7 +2325,8 @@ int processParameters(const ConnectionClass *conn, const char *value,
            return CONVERT_ESCAPE_OVERFLOW;
        }
 #ifdef MULTIBYTE
-       if (multibyte_char_check(*valptr) != 0)
+       encoded_byte_check(&encstr, ipos);
+       if (ENCODE_STATUS(encstr) != 0)
        {
            result[count++] = *valptr;
            continue;
@@ -2468,7 +2544,7 @@ parse_datetime(char *buf, SIMPLE_TIME *st)
 
 /* Change linefeed to carriage-return/linefeed */
 int
-convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed)
+convert_linefeeds(const char *si, char *dst, size_t max, BOOL convlf, BOOL *changed)
 {
    size_t      i = 0,
                out = 0;
@@ -2478,7 +2554,7 @@ convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed)
    *changed = FALSE;
    for (i = 0; si[i] && out < max - 1; i++)
    {
-       if (si[i] == '\n')
+       if (convlf && si[i] == '\n')
        {
            /* Only add the carriage-return if needed */
            if (i > 0 && si[i - 1] == '\r')
@@ -2518,12 +2594,15 @@ convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed)
  * Plus, escape any special characters.
  */
 int
-convert_special_chars(const char *si, char *dst, int used)
+convert_special_chars(const char *si, char *dst, int used, BOOL convlf, int ccsc)
 {
    size_t      i = 0,
                out = 0,
                max;
    char       *p = NULL;
+#ifdef MULTIBYTE
+   encoded_str encstr;
+#endif
 
 
    if (used == SQL_NTS)
@@ -2536,13 +2615,14 @@ convert_special_chars(const char *si, char *dst, int used)
        p[0] = '\0';
    }
 #ifdef MULTIBYTE
-   multibyte_init();
+   encoded_str_constr(&encstr, ccsc, si);
 #endif
 
    for (i = 0; i < max && si[i]; i++)
    {
 #ifdef MULTIBYTE
-       if (multibyte_char_check(si[i]) != 0)
+       encoded_nextchar(&encstr);
+       if (ENCODE_STATUS(encstr) != 0)
        {
            if (p)
                p[out] = si[i];
@@ -2550,7 +2630,7 @@ convert_special_chars(const char *si, char *dst, int used)
            continue;
        }
 #endif
-       if (si[i] == '\r' && si[i + 1] == '\n')
+       if (convlf && si[i] == '\r' && si[i + 1] == '\n')
            continue;
        else if (si[i] == '\'' || si[i] == '\\')
        {
index b06f72f3541e8c514b1d84471b5609b7bd95fd14..2d5f01859f04dd87f253549a7a4f77f371d28151 100644 (file)
@@ -21,7 +21,7 @@
 /* convert_escape results */
 #define CONVERT_ESCAPE_OK                  0
 #define CONVERT_ESCAPE_OVERFLOW                    1
-#define CONVERT_ESCAPE_ERROR                   2
+#define CONVERT_ESCAPE_ERROR                   -1
 
 typedef struct
 {
@@ -43,8 +43,8 @@ int       convert_escape(const char *value, StatementClass *stmt,
            int *npos, int *stsize, const char **val_resume);
 BOOL       convert_money(const char *s, char *sout, size_t soutmax);
 char       parse_datetime(char *buf, SIMPLE_TIME *st);
-int            convert_linefeeds(const char *s, char *dst, size_t max, BOOL *changed);
-int            convert_special_chars(const char *si, char *dst, int used);
+int            convert_linefeeds(const char *s, char *dst, size_t max, BOOL convlf, BOOL *changed);
+int            convert_special_chars(const char *si, char *dst, int used, BOOL convlf,int ccsc);
 
 int            convert_pgbinary_to_char(const char *value, char *rgbValue, int cbValueMax);
 int            convert_from_pgbinary(const unsigned char *value, unsigned char *rgbValue, int cbValueMax);
index f23fb9c527f315c7f20f72def0bb641c5f92d6d9..4fbf037cec204d01bedf905d08aea74b9eff3d90 100644 (file)
@@ -123,7 +123,7 @@ driver_optionsDraw(HWND hdlg, const ConnInfo *ci, int src, BOOL enable)
    CheckDlgButton(hdlg, DRV_OPTIMIZER, comval->disable_optimizer);
    CheckDlgButton(hdlg, DRV_KSQO, comval->ksqo);
    CheckDlgButton(hdlg, DRV_UNIQUEINDEX, comval->unique_index);
-   EnableWindow(GetDlgItem(hdlg, DRV_UNIQUEINDEX), enable);
+   /* EnableWindow(GetDlgItem(hdlg, DRV_UNIQUEINDEX), enable); */
    CheckDlgButton(hdlg, DRV_READONLY, comval->onlyread);
    EnableWindow(GetDlgItem(hdlg, DRV_READONLY), enable);
    CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, comval->use_declarefetch);
@@ -332,6 +332,8 @@ ds_optionsProc(HWND hdlg,
            CheckDlgButton(hdlg, DS_ROWVERSIONING, atoi(ci->row_versioning));
            CheckDlgButton(hdlg, DS_SHOWSYSTEMTABLES, atoi(ci->show_system_tables));
            CheckDlgButton(hdlg, DS_DISALLOWPREMATURE, ci->disallow_premature);
+           CheckDlgButton(hdlg, DS_LFCONVERSION, ci->lf_conversion);
+           CheckDlgButton(hdlg, DS_TRUEISMINUS1, ci->true_is_minus1);
 
            EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), atoi(ci->show_oid_column));
 
@@ -367,6 +369,8 @@ ds_optionsProc(HWND hdlg,
 
                    sprintf(ci->row_versioning, "%d", IsDlgButtonChecked(hdlg, DS_ROWVERSIONING));
                    ci->disallow_premature = IsDlgButtonChecked(hdlg, DS_DISALLOWPREMATURE);
+                   ci->lf_conversion = IsDlgButtonChecked(hdlg, DS_LFCONVERSION);
+                   ci->true_is_minus1 = IsDlgButtonChecked(hdlg, DS_TRUEISMINUS1);
 
                    /* OID Options */
                    sprintf(ci->fake_oid_index, "%d", IsDlgButtonChecked(hdlg, DS_FAKEOIDINDEX));
@@ -525,60 +529,186 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
    hlen = strlen(connect_string);
    if (!abbrev)
        sprintf(&connect_string[hlen],
-               ";READONLY=%s;PROTOCOL=%s;FAKEOIDINDEX=%s;SHOWOIDCOLUMN=%s;ROWVERSIONING=%s;SHOWSYSTEMTABLES=%s;CONNSETTINGS=%s;FETCH=%d;SOCKET=%d;UNKNOWNSIZES=%d;MAXVARCHARSIZE=%d;MAXLONGVARCHARSIZE=%d;DEBUG=%d;COMMLOG=%d;OPTIMIZER=%d;KSQO=%d;USEDECLAREFETCH=%d;TEXTASLONGVARCHAR=%d;UNKNOWNSASLONGVARCHAR=%d;BOOLSASCHAR=%d;PARSE=%d;CANCELASFREESTMT=%d;EXTRASYSTABLEPREFIXES=%s",
+               ";%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%s;%s=%d;%s=%d;%s=%d;%s=%d",
+               INI_READONLY,
                ci->onlyread,
+               INI_PROTOCOL,
                ci->protocol,
+               INI_FAKEOIDINDEX,
                ci->fake_oid_index,
+               INI_SHOWOIDCOLUMN,
                ci->show_oid_column,
+               INI_ROWVERSIONING,
                ci->row_versioning,
+               INI_SHOWSYSTEMTABLES,
                ci->show_system_tables,
+               INI_CONNSETTINGS,
                encoded_conn_settings,
+               INI_FETCH,
                ci->drivers.fetch_max,
+               INI_SOCKET,
                ci->drivers.socket_buffersize,
+               INI_UNKNOWNSIZES,
                ci->drivers.unknown_sizes,
+               INI_MAXVARCHARSIZE,
                ci->drivers.max_varchar_size,
+               INI_MAXLONGVARCHARSIZE,
                ci->drivers.max_longvarchar_size,
+               INI_DEBUG,
                ci->drivers.debug,
+               INI_COMMLOG,
                ci->drivers.commlog,
+               INI_OPTIMIZER,
                ci->drivers.disable_optimizer,
+               INI_KSQO,
                ci->drivers.ksqo,
+               INI_USEDECLAREFETCH,
                ci->drivers.use_declarefetch,
+               INI_TEXTASLONGVARCHAR,
                ci->drivers.text_as_longvarchar,
+               INI_UNKNOWNSASLONGVARCHAR,
                ci->drivers.unknowns_as_longvarchar,
+               INI_BOOLSASCHAR,
                ci->drivers.bools_as_char,
+               INI_PARSE,
                ci->drivers.parse,
+               INI_CANCELASFREESTMT,
                ci->drivers.cancel_as_freestmt,
-               ci->drivers.extra_systable_prefixes);
+               INI_EXTRASYSTABLEPREFIXES,
+               ci->drivers.extra_systable_prefixes,
+               INI_LFCONVERSION,
+               ci->lf_conversion,
+               INI_UPDATABLECURSORS,
+               ci->updatable_cursors,
+               INI_DISALLOWPREMATURE,
+               ci->disallow_premature,
+               INI_TRUEISMINUS1,
+               ci->true_is_minus1);
    /* Abbrebiation is needed ? */
    if (abbrev || strlen(connect_string) >= len)
+   {
+       unsigned long flag = 0;
+       if (ci->disallow_premature)
+           flag |= BIT_DISALLOWPREMATURE;
+       if (ci->updatable_cursors)
+           flag |= BIT_UPDATABLECURSORS;
+       if (ci->lf_conversion)
+           flag |= BIT_LFCONVERSION;
+       if (ci->drivers.unique_index)
+           flag |= BIT_UNIQUEINDEX;
+       if (strncmp(ci->protocol, PG64, strlen(PG64)) == 0)
+           flag |= BIT_PROTOCOL_64;
+       else if (strncmp(ci->protocol, PG63, strlen(PG63)) == 0)
+           flag |= BIT_PROTOCOL_63;
+       switch (ci->drivers.unknown_sizes)
+       {
+           case UNKNOWNS_AS_DONTKNOW:
+               flag |= BIT_UNKNOWN_DONTKNOW;
+               break;
+           case UNKNOWNS_AS_MAX:
+               flag |= BIT_UNKNOWN_ASMAX;
+               break;
+       }
+       if (ci->drivers.disable_optimizer)
+           flag |= BIT_OPTIMIZER;
+       if (ci->drivers.ksqo)
+           flag |= BIT_KSQO;
+       if (ci->drivers.commlog)
+           flag |= BIT_COMMLOG;
+       if (ci->drivers.debug)
+           flag |= BIT_DEBUG;
+       if (ci->drivers.parse)
+           flag |= BIT_PARSE;
+       if (ci->drivers.cancel_as_freestmt)
+           flag |= BIT_CANCELASFREESTMT;
+       if (ci->drivers.use_declarefetch)
+           flag |= BIT_USEDECLAREFETCH;
+       if (ci->onlyread[0] == '1')
+           flag |= BIT_READONLY;
+       if (ci->drivers.text_as_longvarchar)
+           flag |= BIT_TEXTASLONGVARCHAR;
+       if (ci->drivers.unknowns_as_longvarchar)
+           flag |= BIT_UNKNOWNSASLONGVARCHAR;
+       if (ci->drivers.bools_as_char)
+           flag |= BIT_BOOLSASCHAR;
+       if (ci->row_versioning[0] == '1')
+           flag |= BIT_ROWVERSIONING;
+       if (ci->show_system_tables[0] == '1')
+           flag |= BIT_SHOWSYSTEMTABLES;
+       if (ci->show_oid_column[0] == '1')
+           flag |= BIT_SHOWOIDCOLUMN;
+       if (ci->fake_oid_index[0] == '1')
+           flag |= BIT_FAKEOIDINDEX;
+       if (ci->true_is_minus1)
+           flag |= BIT_TRUEISMINUS1;
+
        sprintf(&connect_string[hlen],
-               ";A0=%s;A1=%s;A2=%s;A3=%s;A4=%s;A5=%s;A6=%s;A7=%d;A8=%d;A9=%d;B0=%d;B1=%d;B2=%d;B3=%d;B4=%d;B5=%d;B6=%d;B7=%d;B8=%d;B9=%d;C0=%d;C1=%d;C2=%s",
-               ci->onlyread,
-               ci->protocol,
-               ci->fake_oid_index,
-               ci->show_oid_column,
-               ci->row_versioning,
-               ci->show_system_tables,
+               ";A6=%s;A7=%d;A8=%d;B0=%d;B1=%d;C2=%s;CX=%02x%x",
                encoded_conn_settings,
                ci->drivers.fetch_max,
                ci->drivers.socket_buffersize,
-               ci->drivers.unknown_sizes,
                ci->drivers.max_varchar_size,
                ci->drivers.max_longvarchar_size,
-               ci->drivers.debug,
-               ci->drivers.commlog,
-               ci->drivers.disable_optimizer,
-               ci->drivers.ksqo,
-               ci->drivers.use_declarefetch,
-               ci->drivers.text_as_longvarchar,
-               ci->drivers.unknowns_as_longvarchar,
-               ci->drivers.bools_as_char,
-               ci->drivers.parse,
-               ci->drivers.cancel_as_freestmt,
-               ci->drivers.extra_systable_prefixes);
+               ci->drivers.extra_systable_prefixes,
+               EFFECTIVE_BIT_COUNT,
+               flag);
+   }
 }
 
+static void
+unfoldCXAttribute(ConnInfo *ci, const char *value)
+{
+   int     count;
+   unsigned long   flag;
 
+   if (strlen(value) < 2)
+   {
+       count = 3;
+       sscanf(value, "%x", &flag);
+   }
+   else
+   {
+       char    cnt[8];
+       memcpy(cnt, value, 2);
+       cnt[2] = '\0';
+       sscanf(cnt, "%x", &count);
+       sscanf(value + 2, "%x", &flag);
+   }
+   ci->disallow_premature = (char)((flag & BIT_DISALLOWPREMATURE) != 0);
+   ci->updatable_cursors = (char)((flag & BIT_UPDATABLECURSORS) != 0);
+   ci->lf_conversion = (char)((flag & BIT_LFCONVERSION) != 0);
+   if (count < 4)
+       return;
+   ci->drivers.unique_index = (char)((flag & BIT_UNIQUEINDEX) != 0);
+   if ((flag & BIT_PROTOCOL_64) != 0)
+       strcpy(ci->protocol, PG64);
+   else if ((flag & BIT_PROTOCOL_63) != 0)
+       strcpy(ci->protocol, PG63);
+   else
+       strcpy(ci->protocol, PG62);
+   if ((flag & BIT_UNKNOWN_DONTKNOW) != 0)
+       ci->drivers.unknown_sizes = UNKNOWNS_AS_DONTKNOW;
+   else if ((flag & BIT_UNKNOWN_ASMAX) != 0)
+       ci->drivers.unknown_sizes = UNKNOWNS_AS_MAX;
+   else 
+       ci->drivers.unknown_sizes = UNKNOWNS_AS_LONGEST;
+   ci->drivers.disable_optimizer = (char)((flag & BIT_OPTIMIZER) != 0);
+   ci->drivers.ksqo = (char)((flag & BIT_KSQO) != 0);
+   ci->drivers.commlog = (char)((flag & BIT_COMMLOG) != 0);
+   ci->drivers.debug = (char)((flag & BIT_DEBUG) != 0);
+   ci->drivers.parse = (char)((flag & BIT_PARSE) != 0);
+   ci->drivers.cancel_as_freestmt = (char)((flag & BIT_CANCELASFREESTMT) != 0);
+   ci->drivers.use_declarefetch = (char)((flag & BIT_USEDECLAREFETCH) != 0);
+   sprintf(ci->onlyread, "%d", (char)((flag & BIT_READONLY) != 0));
+   ci->drivers.text_as_longvarchar = (char)((flag & BIT_TEXTASLONGVARCHAR) !=0);
+   ci->drivers.unknowns_as_longvarchar = (char)((flag & BIT_UNKNOWNSASLONGVARCHAR) !=0);
+   ci->drivers.bools_as_char = (char)((flag & BIT_BOOLSASCHAR) != 0);
+   sprintf(ci->row_versioning, "%d", (char)((flag & BIT_ROWVERSIONING) != 0));
+   sprintf(ci->show_system_tables, "%d", (char)((flag & BIT_SHOWSYSTEMTABLES) != 0));
+   sprintf(ci->show_oid_column, "%d", (char)((flag & BIT_SHOWOIDCOLUMN) != 0));
+   sprintf(ci->fake_oid_index, "%d", (char)((flag & BIT_FAKEOIDINDEX) != 0));
+   ci->true_is_minus1 = (char)((flag & BIT_TRUEISMINUS1) != 0);
+}
 void
 copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
 {
@@ -630,6 +760,12 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
        ci->disallow_premature = atoi(value);
    else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, "C4") == 0)
        ci->updatable_cursors = atoi(value);
+   else if (stricmp(attribute, INI_LFCONVERSION) == 0)
+       ci->lf_conversion = atoi(value);
+   else if (stricmp(attribute, INI_TRUEISMINUS1) == 0)
+       ci->true_is_minus1 = atoi(value);
+   else if (stricmp(attribute, "CX") == 0)
+       unfoldCXAttribute(ci, value);
 
    mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s',conn_settings='%s',disallow_premature=%d)\n", ci->dsn, ci->server, ci->database, ci->username, ci->password, ci->port, ci->onlyread, ci->protocol, ci->conn_settings, ci->disallow_premature);
 }
@@ -720,6 +856,15 @@ getDSNdefaults(ConnInfo *ci)
 
    if (ci->row_versioning[0] == '\0')
        sprintf(ci->row_versioning, "%d", DEFAULT_ROWVERSIONING);
+
+   if (ci->disallow_premature < 0)
+       ci->disallow_premature = DEFAULT_DISALLOWPREMATURE;
+   if (ci->updatable_cursors < 0)
+       ci->updatable_cursors = DEFAULT_UPDATABLECURSORS;
+   if (ci->lf_conversion < 0)
+       ci->lf_conversion = DEFAULT_LFCONVERSION;
+   if (ci->true_is_minus1 < 0)
+       ci->true_is_minus1 = DEFAULT_TRUEISMINUS1;
 }
 
 
@@ -797,16 +942,32 @@ getDSNinfo(ConnInfo *ci, char overwrite)
    if (ci->translation_option[0] == '\0' || overwrite)
        SQLGetPrivateProfileString(DSN, INI_TRANSLATIONOPTION, "", ci->translation_option, sizeof(ci->translation_option), ODBC_INI);
 
-   if (ci->disallow_premature == 0 || overwrite)
+   if (ci->disallow_premature < 0 || overwrite)
    {
        SQLGetPrivateProfileString(DSN, INI_DISALLOWPREMATURE, "", temp, sizeof(temp), ODBC_INI);
-       ci->disallow_premature = atoi(temp);
+       if (temp[0])
+           ci->disallow_premature = atoi(temp);
    }
 
-   if (ci->updatable_cursors == 0 || overwrite)
+   if (ci->updatable_cursors < 0 || overwrite)
    {
        SQLGetPrivateProfileString(DSN, INI_UPDATABLECURSORS, "", temp, sizeof(temp), ODBC_INI);
-       ci->updatable_cursors = atoi(temp);
+       if (temp[0])
+           ci->updatable_cursors = atoi(temp);
+   }
+
+   if (ci->lf_conversion < 0 || overwrite)
+   {
+       SQLGetPrivateProfileString(DSN, INI_LFCONVERSION, "", temp, sizeof(temp), ODBC_INI);
+       if (temp[0])
+           ci->lf_conversion = atoi(temp);
+   }
+
+   if (ci->true_is_minus1 < 0 || overwrite)
+   {
+       SQLGetPrivateProfileString(DSN, INI_TRUEISMINUS1, "", temp, sizeof(temp), ODBC_INI);
+       if (temp[0])
+           ci->true_is_minus1 = atoi(temp);
    }
 
    /* Allow override of odbcinst.ini parameters here */
@@ -927,6 +1088,16 @@ writeDSNinfo(const ConnInfo *ci)
                                 INI_UPDATABLECURSORS,
                                 temp,
                                 ODBC_INI);
+   sprintf(temp, "%d", ci->lf_conversion);
+   SQLWritePrivateProfileString(DSN,
+                                INI_LFCONVERSION,
+                                temp,
+                                ODBC_INI);
+   sprintf(temp, "%d", ci->true_is_minus1);
+   SQLWritePrivateProfileString(DSN,
+                                INI_TRUEISMINUS1,
+                                temp,
+                                ODBC_INI);
 }
 
 
index b3192123d0fe3bafe22cab8d74ffa63128b1ee79..f293079d35f20222586f580d779cdc6e2f043fec 100644 (file)
 #define INI_TRANSLATIONOPTION          "TranslationOption"
 #define INI_DISALLOWPREMATURE          "DisallowPremature"
 #define INI_UPDATABLECURSORS           "UpdatableCursors"
+#define INI_LFCONVERSION           "LFConversion"
+#define INI_TRUEISMINUS1           "TrueIsMinus1"
+/* Bit representaion for abbreviated connection strings */
+#define BIT_LFCONVERSION           (1L)
+#define BIT_UPDATABLECURSORS           (1L<<1)
+#define BIT_DISALLOWPREMATURE          (1L<<2)
+#define BIT_UNIQUEINDEX                (1L<<3)
+#define BIT_PROTOCOL_63                (1L<<4)
+#define BIT_PROTOCOL_64                (1L<<5)
+#define BIT_UNKNOWN_DONTKNOW           (1L<<6)
+#define BIT_UNKNOWN_ASMAX          (1L<<7)
+#define BIT_OPTIMIZER              (1L<<8)
+#define BIT_KSQO               (1L<<9)
+#define BIT_COMMLOG                (1L<<10)
+#define BIT_DEBUG              (1L<<11)
+#define BIT_PARSE              (1L<<12)
+#define BIT_CANCELASFREESTMT           (1L<<13)
+#define BIT_USEDECLAREFETCH            (1L<<14)
+#define BIT_READONLY               (1L<<15)
+#define BIT_TEXTASLONGVARCHAR          (1L<<16)
+#define BIT_UNKNOWNSASLONGVARCHAR      (1L<<17)
+#define BIT_BOOLSASCHAR                (1L<<18)
+#define BIT_ROWVERSIONING          (1L<<19)
+#define BIT_SHOWSYSTEMTABLES           (1L<<20)
+#define BIT_SHOWOIDCOLUMN          (1L<<21)
+#define BIT_FAKEOIDINDEX           (1L<<22)
+#define BIT_TRUEISMINUS1           (1L<<23)
+
+#define EFFECTIVE_BIT_COUNT            24
 
 
 /* Connection Defaults */
 
 #define DEFAULT_EXTRASYSTABLEPREFIXES  "dd_;"
 
+#define DEFAULT_DISALLOWPREMATURE  0
+#define DEFAULT_TRUEISMINUS1       0
+#ifdef DRIVER_CURSOR_IMPLEMENT
+#define DEFAULT_UPDATABLECURSORS   1
+#else
+#define DEFAULT_UPDATABLECURSORS   0
+#endif /* DRIVER_CURSOR_IMPLEMENT */
+#ifdef WIN32
+#define DEFAULT_LFCONVERSION       1
+#else
+#define DEFAULT_LFCONVERSION       0
+#endif /* WIN32 */
+
 /* prototypes */
 void       getCommonDefaults(const char *section, const char *filename, ConnInfo *ci);
 
index e369525ca02a530802fccf921ae8244656e95c80..e07cec3e8c19ab25decfe7234840045ba08425c0 100644 (file)
@@ -242,7 +242,7 @@ dialog:
    qlog("conn=%u, PGAPI_DriverConnect(out)='%s'\n", conn, szConnStrOut);
 
 
-   mylog("PGAPI_DRiverConnect: returning %d\n", result);
+   mylog("PGAPI_DriverConnect: returning %d\n", result);
    return result;
 }
 
@@ -351,10 +351,7 @@ dconn_get_connect_attributes(const UCHAR FAR * connect_string, ConnInfo *ci)
               *equals;
    char       *strtok_arg;
 
-   memset(ci, 0, sizeof(ConnInfo));
-#ifdef DRIVER_CURSOR_IMPLEMENT
-   ci->updatable_cursors = 1;
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
+   CC_conninfo_init(ci);
 
    our_connect_string = strdup(connect_string);
    strtok_arg = our_connect_string;
index 1113ca57ac6e18fd1efa7690954bdfedd17ec291..69718a1914974d33ac120ddcd48c905a2cb732c1 100644 (file)
@@ -78,408 +78,450 @@ PGAPI_FreeEnv(HENV henv)
 }
 
 
+#define    DRVMNGRDIV  511
 /*     Returns the next SQL error information. */
 RETCODE        SQL_API
-PGAPI_Error(
-           HENV henv,
-           HDBC hdbc,
-           HSTMT hstmt,
+PGAPI_StmtError(   HSTMT hstmt,
+           SWORD   RecNumber,
            UCHAR FAR * szSqlState,
            SDWORD FAR * pfNativeError,
            UCHAR FAR * szErrorMsg,
            SWORD cbErrorMsgMax,
-           SWORD FAR * pcbErrorMsg)
+           SWORD FAR * pcbErrorMsg,
+           UWORD flag)
 {
-   char       *msg;
-   int         status;
-   BOOL        once_again = FALSE;
-   SWORD       msglen;
+   /* CC: return an error of a hstmt  */
+   StatementClass *stmt = (StatementClass *) hstmt;
+   char        *msg;
+   int     status;
+   BOOL        once_again = FALSE,
+           partial_ok = (flag & PODBC_ALLOW_PARTIAL_EXTRACT != 0),
+           clear_str = (flag & PODBC_ERROR_CLEAR != 0);
+   SWORD       msglen, stapos, wrtlen, pcblen;
 
-   mylog("**** PGAPI_Error: henv=%u, hdbc=%u, hstmt=%u <%d>\n", henv, hdbc, hstmt, cbErrorMsgMax);
+   mylog("**** PGAPI_StmtError: hstmt=%u <%d>\n", hstmt, cbErrorMsgMax);
 
    if (cbErrorMsgMax < 0)
        return SQL_ERROR;
-   if (SQL_NULL_HSTMT != hstmt)
-   {
-       /* CC: return an error of a hstmt  */
-       StatementClass *stmt = (StatementClass *) hstmt;
 
-       if (SC_get_error(stmt, &status, &msg))
-       {
-           mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg);
-           if (NULL == msg)
-           {
-               if (NULL != szSqlState)
-                   strcpy(szSqlState, "00000");
-               if (NULL != pcbErrorMsg)
-                   *pcbErrorMsg = 0;
-               if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-                   szErrorMsg[0] = '\0';
-
-               return SQL_NO_DATA_FOUND;
-           }
-           msglen = (SWORD) strlen(msg);
-           if (NULL != pcbErrorMsg)
-           {
-               *pcbErrorMsg = msglen;
-               if (cbErrorMsgMax == 0)
-                   once_again = TRUE;
-               else if (msglen >= cbErrorMsgMax)
-               {
-                   once_again = TRUE;
-                   *pcbErrorMsg = cbErrorMsgMax - 1;
-               }
-           }
-
-           if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-               strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
-
-           if (NULL != pfNativeError)
-               *pfNativeError = status;
-
-           if (NULL != szSqlState)
-
-               switch (status)
-               {
-                       /* now determine the SQLSTATE to be returned */
-                   case STMT_ROW_VERSION_CHANGED:
-                       strcpy(szSqlState, "01001");
-                       /* data truncated */
-                       break;
-                   case STMT_TRUNCATED:
-                       strcpy(szSqlState, "01004");
-                       /* data truncated */
-                       break;
-                   case STMT_INFO_ONLY:
-                       strcpy(szSqlState, "00000");
-                       /* just information that is returned, no error */
-                       break;
-                   case STMT_BAD_ERROR:
-                       strcpy(szSqlState, "08S01");
-                       /* communication link failure */
-                       break;
-                   case STMT_CREATE_TABLE_ERROR:
-                       strcpy(szSqlState, "S0001");
-                       /* table already exists */
-                       break;
-                   case STMT_STATUS_ERROR:
-                   case STMT_SEQUENCE_ERROR:
-                       strcpy(szSqlState, "S1010");
-                       /* Function sequence error */
-                       break;
-                   case STMT_NO_MEMORY_ERROR:
-                       strcpy(szSqlState, "S1001");
-                       /* memory allocation failure */
-                       break;
-                   case STMT_COLNUM_ERROR:
-                       strcpy(szSqlState, "S1002");
-                       /* invalid column number */
-                       break;
-                   case STMT_NO_STMTSTRING:
-                       strcpy(szSqlState, "S1001");
-                       /* having no stmtstring is also a malloc problem */
-                       break;
-                   case STMT_ERROR_TAKEN_FROM_BACKEND:
-                       strcpy(szSqlState, "S1000");
-                       /* general error */
-                       break;
-                   case STMT_INTERNAL_ERROR:
-                       strcpy(szSqlState, "S1000");
-                       /* general error */
-                       break;
-                   case STMT_ROW_OUT_OF_RANGE:
-                       strcpy(szSqlState, "S1107");
-                       break;
-
-                   case STMT_OPERATION_CANCELLED:
-                       strcpy(szSqlState, "S1008");
-                       break;
-
-                   case STMT_NOT_IMPLEMENTED_ERROR:
-                       strcpy(szSqlState, "S1C00");    /* == 'driver not
-                                                        * capable' */
-                       break;
-                   case STMT_OPTION_OUT_OF_RANGE_ERROR:
-                       strcpy(szSqlState, "S1092");
-                       break;
-                   case STMT_BAD_PARAMETER_NUMBER_ERROR:
-                       strcpy(szSqlState, "S1093");
-                       break;
-                   case STMT_INVALID_COLUMN_NUMBER_ERROR:
-                       strcpy(szSqlState, "S1002");
-                       break;
-                   case STMT_RESTRICTED_DATA_TYPE_ERROR:
-                       strcpy(szSqlState, "07006");
-                       break;
-                   case STMT_INVALID_CURSOR_STATE_ERROR:
-                       strcpy(szSqlState, "24000");
-                       break;
-                   case STMT_OPTION_VALUE_CHANGED:
-                       strcpy(szSqlState, "01S02");
-                       break;
-                   case STMT_POS_BEFORE_RECORDSET:
-                       strcpy(szSqlState, "01S06");
-                       break;
-                   case STMT_INVALID_CURSOR_NAME:
-                       strcpy(szSqlState, "34000");
-                       break;
-                   case STMT_NO_CURSOR_NAME:
-                       strcpy(szSqlState, "S1015");
-                       break;
-                   case STMT_INVALID_ARGUMENT_NO:
-                       strcpy(szSqlState, "S1009");
-                       /* invalid argument value */
-                       break;
-                   case STMT_INVALID_CURSOR_POSITION:
-                       strcpy(szSqlState, "S1109");
-                       break;
-                   case STMT_RETURN_NULL_WITHOUT_INDICATOR:
-                       strcpy(szSqlState, "22002");
-                       break;
-                   case STMT_VALUE_OUT_OF_RANGE:
-                       strcpy(szSqlState, "22003");
-                       break;
-                   case STMT_OPERATION_INVALID:
-                       strcpy(szSqlState, "S1011");
-                       break;
-                   case STMT_INVALID_OPTION_IDENTIFIER:
-                       strcpy(szSqlState, "HY092");
-                       break;
-                   case STMT_EXEC_ERROR:
-                   default:
-                       strcpy(szSqlState, "S1000");
-                       /* also a general error */
-                       break;
-               }
-           mylog("       szSqlState = '%s', szError='%s'\n", szSqlState, szErrorMsg);
-       }
+   if (!SC_get_error(stmt, &status, &msg) || NULL == msg || !msg[0])
+   {
+       mylog("SC_Get_error returned nothing.\n");
+       if (NULL != szSqlState)
+           strcpy(szSqlState, "00000");
+       if (NULL != pcbErrorMsg)
+           *pcbErrorMsg = 0;
+       if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+           szErrorMsg[0] = '\0';
+
+       return SQL_NO_DATA_FOUND;
+   }
+   mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg);
+   msglen = (SWORD) strlen(msg);
+   /*
+    *  Even though an application specifies a larger error message
+    *  buffer, the driver manager changes it silently.
+    *  Therefore we divide the error message into ... 
+    */
+   if (stmt->error_recsize < 0)
+   {
+       if (cbErrorMsgMax > 0)
+           stmt->error_recsize = cbErrorMsgMax - 1; /* apply the first request */
        else
-       {
-           if (NULL != szSqlState)
-               strcpy(szSqlState, "00000");
-           if (NULL != pcbErrorMsg)
-               *pcbErrorMsg = 0;
-           if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-               szErrorMsg[0] = '\0';
+           stmt->error_recsize = DRVMNGRDIV;
+   }
+   if (RecNumber < 0)
+   {
+       if (0 == stmt->errorpos)
+           RecNumber = 1;
+       else
+           RecNumber = 2 + (stmt->errorpos - 1) / stmt->error_recsize;
+   }
+   stapos = (RecNumber - 1) * stmt->error_recsize;
+   if (stapos > msglen)
+       return SQL_NO_DATA_FOUND; 
+   pcblen = wrtlen = msglen - stapos;
+   if (pcblen > stmt->error_recsize)
+       pcblen = stmt->error_recsize;
+   if (0 == cbErrorMsgMax)
+       wrtlen = 0; 
+   else if (wrtlen >= cbErrorMsgMax)
+   {
+       if (partial_ok)
+           wrtlen = cbErrorMsgMax - 1;
+       else if (cbErrorMsgMax <= stmt->error_recsize)
+           wrtlen = 0;
+       else 
+           wrtlen = stmt->error_recsize;
+   }
+   if (wrtlen > pcblen)
+       wrtlen = pcblen;
+   if (NULL != pcbErrorMsg)
+       *pcbErrorMsg = pcblen;
 
-           mylog("       returning NO_DATA_FOUND\n");
+   if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+   {
+       memcpy(szErrorMsg, msg + stapos, wrtlen);
+       szErrorMsg[wrtlen] = '\0';
+   }
 
-           return SQL_NO_DATA_FOUND;
-       }
+   if (NULL != pfNativeError)
+       *pfNativeError = status;
+
+   if (NULL != szSqlState)
 
-       if (once_again)
+       switch (status)
        {
-           int         outlen;
-
-           stmt->errornumber = status;
-           if (cbErrorMsgMax > 0)
-               outlen = *pcbErrorMsg;
-           else
-               outlen = 0;
-           if (!stmt->errormsg_malloced || !stmt->errormsg)
-           {
-               stmt->errormsg = malloc(msglen - outlen + 1);
-               stmt->errormsg_malloced = TRUE;
-           }
-           memmove(stmt->errormsg, msg + outlen, msglen - outlen + 1);
+               /* now determine the SQLSTATE to be returned */
+           case STMT_ROW_VERSION_CHANGED:
+               strcpy(szSqlState, "01001");
+               /* data truncated */
+               break;
+           case STMT_TRUNCATED:
+               strcpy(szSqlState, "01004");
+               /* data truncated */
+               break;
+           case STMT_INFO_ONLY:
+               strcpy(szSqlState, "00000");
+               /* just information that is returned, no error */
+               break;
+           case STMT_BAD_ERROR:
+               strcpy(szSqlState, "08S01");
+               /* communication link failure */
+               break;
+           case STMT_CREATE_TABLE_ERROR:
+               strcpy(szSqlState, "S0001");
+               /* table already exists */
+               break;
+           case STMT_STATUS_ERROR:
+           case STMT_SEQUENCE_ERROR:
+               strcpy(szSqlState, "S1010");
+               /* Function sequence error */
+               break;
+           case STMT_NO_MEMORY_ERROR:
+               strcpy(szSqlState, "S1001");
+               /* memory allocation failure */
+               break;
+           case STMT_COLNUM_ERROR:
+               strcpy(szSqlState, "S1002");
+               /* invalid column number */
+               break;
+           case STMT_NO_STMTSTRING:
+               strcpy(szSqlState, "S1001");
+               /* having no stmtstring is also a malloc problem */
+               break;
+           case STMT_ERROR_TAKEN_FROM_BACKEND:
+               strcpy(szSqlState, "S1000");
+               /* general error */
+               break;
+           case STMT_INTERNAL_ERROR:
+               strcpy(szSqlState, "S1000");
+               /* general error */
+               break;
+           case STMT_ROW_OUT_OF_RANGE:
+               strcpy(szSqlState, "S1107");
+               break;
+
+           case STMT_OPERATION_CANCELLED:
+               strcpy(szSqlState, "S1008");
+               break;
+
+           case STMT_NOT_IMPLEMENTED_ERROR:
+               strcpy(szSqlState, "S1C00");    /* == 'driver not
+                                                    * capable' */
+               break;
+           case STMT_OPTION_OUT_OF_RANGE_ERROR:
+               strcpy(szSqlState, "S1092");
+               break;
+           case STMT_BAD_PARAMETER_NUMBER_ERROR:
+               strcpy(szSqlState, "S1093");
+               break;
+           case STMT_INVALID_COLUMN_NUMBER_ERROR:
+               strcpy(szSqlState, "S1002");
+               break;
+           case STMT_RESTRICTED_DATA_TYPE_ERROR:
+               strcpy(szSqlState, "07006");
+               break;
+           case STMT_INVALID_CURSOR_STATE_ERROR:
+               strcpy(szSqlState, "24000");
+               break;
+           case STMT_OPTION_VALUE_CHANGED:
+               strcpy(szSqlState, "01S02");
+               break;
+           case STMT_POS_BEFORE_RECORDSET:
+               strcpy(szSqlState, "01S06");
+               break;
+           case STMT_INVALID_CURSOR_NAME:
+               strcpy(szSqlState, "34000");
+               break;
+           case STMT_NO_CURSOR_NAME:
+               strcpy(szSqlState, "S1015");
+               break;
+           case STMT_INVALID_ARGUMENT_NO:
+               strcpy(szSqlState, "S1009");
+               /* invalid argument value */
+               break;
+           case STMT_INVALID_CURSOR_POSITION:
+               strcpy(szSqlState, "S1109");
+               break;
+           case STMT_RETURN_NULL_WITHOUT_INDICATOR:
+               strcpy(szSqlState, "22002");
+               break;
+           case STMT_VALUE_OUT_OF_RANGE:
+               strcpy(szSqlState, "22003");
+               break;
+           case STMT_OPERATION_INVALID:
+               strcpy(szSqlState, "S1011");
+               break;
+           case STMT_INVALID_OPTION_IDENTIFIER:
+               strcpy(szSqlState, "HY092");
+               break;
+           case STMT_EXEC_ERROR:
+           default:
+               strcpy(szSqlState, "S1000");
+               /* also a general error */
+               break;
        }
-       else if (stmt->errormsg_malloced)
+   mylog("      szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg);
+   if (clear_str)
+   {
+       stmt->errorpos = stapos + wrtlen;
+       if (stmt->errorpos >= msglen)
            SC_clear_error(stmt);
-       if (cbErrorMsgMax == 0)
-           return SQL_SUCCESS_WITH_INFO;
-       else
-           return SQL_SUCCESS;
    }
-   else if (SQL_NULL_HDBC != hdbc)
-   {
-       ConnectionClass *conn = (ConnectionClass *) hdbc;
-
-       mylog("calling CC_get_error\n");
-       if (CC_get_error(conn, &status, &msg))
-       {
-           mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg);
-           if (NULL == msg)
-           {
-               if (NULL != szSqlState)
-                   strcpy(szSqlState, "00000");
-               if (NULL != pcbErrorMsg)
-                   *pcbErrorMsg = 0;
-               if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-                   szErrorMsg[0] = '\0';
-
-               return SQL_NO_DATA_FOUND;
-           }
-
-           msglen = strlen(msg);
-           if (NULL != pcbErrorMsg)
-           {
-               *pcbErrorMsg = msglen;
-               if (cbErrorMsgMax == 0)
-                   once_again = TRUE;
-               else if (msglen >= cbErrorMsgMax)
-                   *pcbErrorMsg = cbErrorMsgMax - 1;
-           }
-           if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-               strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
-           if (NULL != pfNativeError)
-               *pfNativeError = status;
-
-           if (NULL != szSqlState)
-               switch (status)
-               {
-                   case STMT_OPTION_VALUE_CHANGED:
-                   case CONN_OPTION_VALUE_CHANGED:
-                       strcpy(szSqlState, "01S02");
-                       break;
-                   case STMT_TRUNCATED:
-                   case CONN_TRUNCATED:
-                       strcpy(szSqlState, "01004");
-                       /* data truncated */
-                       break;
-                   case CONN_INIREAD_ERROR:
-                       strcpy(szSqlState, "IM002");
-                       /* data source not found */
-                       break;
-                   case CONN_OPENDB_ERROR:
-                       strcpy(szSqlState, "08001");
-                       /* unable to connect to data source */
-                       break;
-                   case CONN_INVALID_AUTHENTICATION:
-                   case CONN_AUTH_TYPE_UNSUPPORTED:
-                       strcpy(szSqlState, "28000");
-                       break;
-                   case CONN_STMT_ALLOC_ERROR:
-                       strcpy(szSqlState, "S1001");
-                       /* memory allocation failure */
-                       break;
-                   case CONN_IN_USE:
-                       strcpy(szSqlState, "S1000");
-                       /* general error */
-                       break;
-                   case CONN_UNSUPPORTED_OPTION:
-                       strcpy(szSqlState, "IM001");
-                       /* driver does not support this function */
-                   case CONN_INVALID_ARGUMENT_NO:
-                       strcpy(szSqlState, "S1009");
-                       /* invalid argument value */
-                       break;
-                   case CONN_TRANSACT_IN_PROGRES:
-                       strcpy(szSqlState, "S1010");
-
-                       /*
-                        * when the user tries to switch commit mode in a
-                        * transaction
-                        */
-                       /* -> function sequence error */
-                       break;
-                   case CONN_NO_MEMORY_ERROR:
-                       strcpy(szSqlState, "S1001");
-                       break;
-                   case CONN_NOT_IMPLEMENTED_ERROR:
-                   case STMT_NOT_IMPLEMENTED_ERROR:
-                       strcpy(szSqlState, "S1C00");
-                       break;
-                   case STMT_RETURN_NULL_WITHOUT_INDICATOR:
-                       strcpy(szSqlState, "22002");
-                       break;
-                   case CONN_VALUE_OUT_OF_RANGE:
-                   case STMT_VALUE_OUT_OF_RANGE:
-                       strcpy(szSqlState, "22003");
-                       break;
-                   default:
-                       strcpy(szSqlState, "S1000");
-                       /* general error */
-                       break;
-               }
-       }
-       else
-       {
-           mylog("CC_Get_error returned nothing.\n");
-           if (NULL != szSqlState)
-               strcpy(szSqlState, "00000");
-           if (NULL != pcbErrorMsg)
-               *pcbErrorMsg = 0;
-           if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-               szErrorMsg[0] = '\0';
+   if (wrtlen == 0)
+       return SQL_SUCCESS_WITH_INFO;
+   else
+       return SQL_SUCCESS;
+}
 
-           return SQL_NO_DATA_FOUND;
-       }
+RETCODE        SQL_API
+PGAPI_ConnectError(    HDBC hdbc,
+           SWORD   RecNumber,
+           UCHAR FAR * szSqlState,
+           SDWORD FAR * pfNativeError,
+           UCHAR FAR * szErrorMsg,
+           SWORD cbErrorMsgMax,
+           SWORD FAR * pcbErrorMsg,
+           UWORD flag)
+{
+   ConnectionClass *conn = (ConnectionClass *) hdbc;
+   char        *msg;
+   int     status;
+   BOOL    once_again = FALSE;
+   SWORD       msglen;
 
-       if (once_again)
-       {
-           conn->errornumber = status;
-           return SQL_SUCCESS_WITH_INFO;
-       }
-       else
-           return SQL_SUCCESS;
+   if (RecNumber != 1)
+       return SQL_NO_DATA_FOUND;
+   if (cbErrorMsgMax < 0)
+       return SQL_ERROR;
+   if (!CC_get_error(conn, &status, &msg) || NULL == msg)
+   {
+       mylog("CC_Get_error returned nothing.\n");
+       if (NULL != szSqlState)
+           strcpy(szSqlState, "00000");
+       if (NULL != pcbErrorMsg)
+           *pcbErrorMsg = 0;
+       if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+           szErrorMsg[0] = '\0';
+
+       return SQL_NO_DATA_FOUND;
    }
-   else if (SQL_NULL_HENV != henv)
+   mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg);
+
+   msglen = strlen(msg);
+   if (NULL != pcbErrorMsg)
    {
-       EnvironmentClass *env = (EnvironmentClass *) henv;
+       *pcbErrorMsg = msglen;
+       if (cbErrorMsgMax == 0)
+           once_again = TRUE;
+       else if (msglen >= cbErrorMsgMax)
+           *pcbErrorMsg = cbErrorMsgMax - 1;
+   }
+   if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+       strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
+   if (NULL != pfNativeError)
+       *pfNativeError = status;
 
-       if (EN_get_error(env, &status, &msg))
-       {
-           mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
-           if (NULL == msg)
-           {
-               if (NULL != szSqlState)
-                   strcpy(szSqlState, "00000");
-               if (NULL != pcbErrorMsg)
-                   *pcbErrorMsg = 0;
-               if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-                   szErrorMsg[0] = '\0';
-
-               return SQL_NO_DATA_FOUND;
-           }
-
-           if (NULL != pcbErrorMsg)
-               *pcbErrorMsg = (SWORD) strlen(msg);
-           if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-               strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
-           if (NULL != pfNativeError)
-               *pfNativeError = status;
-
-           if (szSqlState)
-           {
-               switch (status)
-               {
-                   case ENV_ALLOC_ERROR:
-                       /* memory allocation failure */
-                       strcpy(szSqlState, "S1001");
-                       break;
-                   default:
-                       strcpy(szSqlState, "S1000");
-                       /* general error */
-                       break;
-               }
-           }
-       }
-       else
+   if (NULL != szSqlState)
+       switch (status)
        {
-           if (NULL != szSqlState)
-               strcpy(szSqlState, "00000");
-           if (NULL != pcbErrorMsg)
-               *pcbErrorMsg = 0;
-           if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-               szErrorMsg[0] = '\0';
-
-           return SQL_NO_DATA_FOUND;
+           case STMT_OPTION_VALUE_CHANGED:
+           case CONN_OPTION_VALUE_CHANGED:
+               strcpy(szSqlState, "01S02");
+               break;
+           case STMT_TRUNCATED:
+           case CONN_TRUNCATED:
+               strcpy(szSqlState, "01004");
+               /* data truncated */
+               break;
+           case CONN_INIREAD_ERROR:
+               strcpy(szSqlState, "IM002");
+               /* data source not found */
+               break;
+           case CONN_OPENDB_ERROR:
+               strcpy(szSqlState, "08001");
+               /* unable to connect to data source */
+               break;
+           case CONN_INVALID_AUTHENTICATION:
+           case CONN_AUTH_TYPE_UNSUPPORTED:
+               strcpy(szSqlState, "28000");
+               break;
+           case CONN_STMT_ALLOC_ERROR:
+               strcpy(szSqlState, "S1001");
+               /* memory allocation failure */
+               break;
+           case CONN_IN_USE:
+               strcpy(szSqlState, "S1000");
+               /* general error */
+               break;
+           case CONN_UNSUPPORTED_OPTION:
+               strcpy(szSqlState, "IM001");
+               /* driver does not support this function */
+           case CONN_INVALID_ARGUMENT_NO:
+               strcpy(szSqlState, "S1009");
+               /* invalid argument value */
+               break;
+           case CONN_TRANSACT_IN_PROGRES:
+               strcpy(szSqlState, "S1010");
+
+               /*
+                * when the user tries to switch commit mode in a
+                * transaction
+                */
+               /* -> function sequence error */
+               break;
+           case CONN_NO_MEMORY_ERROR:
+               strcpy(szSqlState, "S1001");
+               break;
+           case CONN_NOT_IMPLEMENTED_ERROR:
+           case STMT_NOT_IMPLEMENTED_ERROR:
+               strcpy(szSqlState, "S1C00");
+               break;
+           case STMT_RETURN_NULL_WITHOUT_INDICATOR:
+               strcpy(szSqlState, "22002");
+               break;
+           case CONN_VALUE_OUT_OF_RANGE:
+           case STMT_VALUE_OUT_OF_RANGE:
+               strcpy(szSqlState, "22003");
+               break;
+           default:
+               strcpy(szSqlState, "S1000");
+               /* general error */
+               break;
        }
 
+   if (once_again)
+   {
+       conn->errornumber = status;
+       return SQL_SUCCESS_WITH_INFO;
+   }
+   else
        return SQL_SUCCESS;
+}
+
+RETCODE        SQL_API
+PGAPI_EnvError(        HENV henv,
+           SWORD   RecNumber,
+           UCHAR FAR * szSqlState,
+           SDWORD FAR * pfNativeError,
+           UCHAR FAR * szErrorMsg,
+           SWORD cbErrorMsgMax,
+           SWORD FAR * pcbErrorMsg,
+           UWORD flag)
+{
+   EnvironmentClass *env = (EnvironmentClass *) henv;
+   char        *msg;
+   int     status;
+
+   if (RecNumber != 1)
+       return SQL_NO_DATA_FOUND;
+   if (cbErrorMsgMax < 0)
+       return SQL_ERROR;
+   if (!EN_get_error(env, &status, &msg) || NULL == msg)
+   {
+           mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
+       
+       if (NULL != szSqlState)
+           strcpy(szSqlState, "00000");
+       if (NULL != pcbErrorMsg)
+           *pcbErrorMsg = 0;
+       if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+           szErrorMsg[0] = '\0';
+
+       return SQL_NO_DATA_FOUND;
    }
+   mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
 
-   if (NULL != szSqlState)
-       strcpy(szSqlState, "00000");
    if (NULL != pcbErrorMsg)
-       *pcbErrorMsg = 0;
+       *pcbErrorMsg = (SWORD) strlen(msg);
    if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-       szErrorMsg[0] = '\0';
+       strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
+   if (NULL != pfNativeError)
+       *pfNativeError = status;
 
-   return SQL_NO_DATA_FOUND;
+   if (szSqlState)
+   {
+       switch (status)
+       {
+           case ENV_ALLOC_ERROR:
+               /* memory allocation failure */
+               strcpy(szSqlState, "S1001");
+               break;
+           default:
+               strcpy(szSqlState, "S1000");
+               /* general error */
+               break;
+       }
+   }
+
+   return SQL_SUCCESS;
 }
 
 
+/*     Returns the next SQL error information. */
+RETCODE        SQL_API
+PGAPI_Error(
+           HENV henv,
+           HDBC hdbc,
+           HSTMT hstmt,
+           UCHAR FAR * szSqlState,
+           SDWORD FAR * pfNativeError,
+           UCHAR FAR * szErrorMsg,
+           SWORD cbErrorMsgMax,
+           SWORD FAR * pcbErrorMsg)
+{
+   RETCODE ret;
+   UWORD   flag = PODBC_ALLOW_PARTIAL_EXTRACT | PODBC_ERROR_CLEAR;
+
+   mylog("**** PGAPI_Error: henv=%u, hdbc=%u hstmt=%d\n", henv, hdbc, hstmt);
+
+   if (cbErrorMsgMax < 0)
+       return SQL_ERROR;
+   if (SQL_NULL_HSTMT != hstmt)
+       ret = PGAPI_StmtError(hstmt, -1, szSqlState, pfNativeError,
+            szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
+   else if (SQL_NULL_HDBC != hdbc)
+       ret = PGAPI_ConnectError(hdbc, -1, szSqlState, pfNativeError,
+            szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
+   else if (SQL_NULL_HENV != hdbc)
+       ret = PGAPI_EnvError(henv, -1, szSqlState, pfNativeError,
+            szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
+   else
+   {
+       if (NULL != szSqlState)
+           strcpy(szSqlState, "00000");
+       if (NULL != pcbErrorMsg)
+           *pcbErrorMsg = 0;
+       if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+           szErrorMsg[0] = '\0';
+
+       ret = SQL_NO_DATA_FOUND;
+   }
+   mylog("**** PGAPI_Error exit code=%d\n", ret);
+   return ret;
+}
+
 /*
  * EnvironmentClass implementation
  */
@@ -493,6 +535,7 @@ EN_Constructor(void)
    {
        rv->errormsg = 0;
        rv->errornumber = 0;
+       rv->flag = 0;
    }
 
    return rv;
index 7b463b3e744e093804077c400062d2ed2e61e4c3..24b456d489915d9f479bb3f902d8f3bdf9d8bb61 100644 (file)
@@ -17,7 +17,8 @@
 struct EnvironmentClass_
 {
    char       *errormsg;
-   int         errornumber;
+   int     errornumber;
+   Int4    flag;
 };
 
 /* Environment prototypes */
@@ -28,4 +29,10 @@ char     EN_add_connection(EnvironmentClass *self, ConnectionClass *conn);
 char       EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn);
 void       EN_log_error(char *func, char *desc, EnvironmentClass *self);
 
+#define    EN_OV_ODBC2 1L
+#define    EN_is_odbc2(env) ((env->flag & EN_OV_ODBC2) != 0)
+#define    EN_is_odbc3(env) ((env->flag & EN_OV_ODBC2) == 0)
+#define EN_set_odbc2(env) (env->flag |= EN_OV_ODBC2)
+#define EN_set_odbc3(env) (env->flag &= EN_OV_ODBC2)
+
 #endif
index 4c6608923a47805db15c0e80f5b452601bda8fbf..ae095e9691e2698cf7051537ad80fa4eb0d80def 100644 (file)
@@ -267,6 +267,7 @@ PGAPI_Execute(
    if (stmt->status == STMT_FINISHED)
    {
        mylog("%s: recycling statement (should have been done by app)...\n", func);
+/******** Is this really NEEDED ? ******/
        SC_recycle_statement(stmt);
    }
 
@@ -291,6 +292,7 @@ PGAPI_Execute(
    {
        if (stmt->options.param_processed_ptr)
            *stmt->options.param_processed_ptr = 0;
+       SC_recycle_statement(stmt);
    }
 
 next_param_row:
@@ -434,26 +436,24 @@ next_param_row:
        }
        /* we are now in a transaction */
        CC_set_in_trans(conn);
-       stmt->result = res = CC_send_query(conn, stmt->stmt_with_params, NULL);
-       if (!res || QR_aborted(res))
+       res = CC_send_query(conn, stmt->stmt_with_params, NULL, TRUE);
+       if (!res)
        {
            CC_abort(conn);
            stmt->errornumber = STMT_EXEC_ERROR;
            stmt->errormsg = "Handle prepare error";
            return SQL_ERROR;
        }
-       else
+       SC_set_Result(stmt, res);
+       if (CC_is_in_autocommit(conn))
        {
-           if (CC_is_in_autocommit(conn))
-           {
-               if (issued_begin)
-                   CC_commit(conn);
-               else if (!in_trans && begin_included)
-                   CC_set_no_trans(conn);
-           }
-           stmt->status = STMT_FINISHED;
-           return SQL_SUCCESS;
+           if (issued_begin)
+               CC_commit(conn);
+           else if (!in_trans && begin_included)
+               CC_set_no_trans(conn);
        }
+       stmt->status = STMT_FINISHED;
+       return SQL_SUCCESS;
    }
    else
        return SQL_SUCCESS;
@@ -518,7 +518,7 @@ PGAPI_Transact(
    {
        mylog("PGAPI_Transact: sending on conn %d '%s'\n", conn, stmt_string);
 
-       res = CC_send_query(conn, stmt_string, NULL);
+       res = CC_send_query(conn, stmt_string, NULL, TRUE);
        CC_set_no_trans(conn);
 
        if (!res)
@@ -721,7 +721,7 @@ PGAPI_ParamData(
        /* commit transaction if needed */
        if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(stmt->hdbc))
        {
-           if (!CC_commit(stmt->hdbc))
+           if (CC_commit(stmt->hdbc))
            {
                stmt->errormsg = "Could not commit (in-line) a transaction";
                stmt->errornumber = STMT_EXEC_ERROR;
@@ -902,6 +902,14 @@ PGAPI_PutData(
        }
        else
        {
+           Int2        ctype = current_param->CType;
+           if (ctype == SQL_C_DEFAULT)
+               ctype = sqltype_to_default_ctype(current_param->SQLType);
+
+#ifdef UNICODE_SUPPORT
+           if (SQL_NTS == cbValue && SQL_C_WCHAR == ctype)
+               cbValue = 2 * ucs2strlen((SQLWCHAR *) rgbValue);
+#endif /* UNICODE_SUPPORT */
            /* for handling fields */
            if (cbValue == SQL_NTS)
            {
@@ -916,11 +924,11 @@ PGAPI_PutData(
            }
            else
            {
-               Int2        ctype = current_param->CType;
-
-               if (ctype == SQL_C_DEFAULT)
-                   ctype = sqltype_to_default_ctype(current_param->SQLType);
+#ifdef UNICODE_SUPPORT
+               if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY || ctype == SQL_C_WCHAR)
+#else
                if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY)
+#endif /* UNICODE_SUPPORT */
                {
                    current_param->EXEC_buffer = malloc(cbValue + 1);
                    if (!current_param->EXEC_buffer)
@@ -965,31 +973,31 @@ PGAPI_PutData(
        }
        else
        {
-           buffer = current_param->EXEC_buffer;
+           Int2    ctype = current_param->CType;
 
-           if (cbValue == SQL_NTS)
+           if (ctype == SQL_C_DEFAULT)
+               ctype = sqltype_to_default_ctype(current_param->SQLType);
+           buffer = current_param->EXEC_buffer;
+           if (old_pos = *current_param->EXEC_used, SQL_NTS == old_pos)
            {
-               buffer = realloc(buffer, strlen(buffer) + strlen(rgbValue) + 1);
-               if (!buffer)
-               {
-                   stmt->errornumber = STMT_NO_MEMORY_ERROR;
-                   stmt->errormsg = "Out of memory in PGAPI_PutData (3)";
-                   SC_log_error(func, "", stmt);
-                   return SQL_ERROR;
-               }
-               strcat(buffer, rgbValue);
-
-               mylog("       cbValue = SQL_NTS: strlen(buffer) = %d\n", strlen(buffer));
-
-               *current_param->EXEC_used = cbValue;
-
-               /* reassign buffer incase realloc moved it */
-               current_param->EXEC_buffer = buffer;
+#ifdef UNICODE_SUPPORT
+               if (SQL_C_WCHAR == ctype)
+                   old_pos = 2 * ucs2strlen((SQLWCHAR *) buffer);
+               else
+#endif /* UNICODE_SUPPORT */
+               old_pos = strlen(buffer);
            }
-           else if (cbValue > 0)
+           if (SQL_NTS == cbValue)
+           {
+#ifdef UNICODE_SUPPORT
+               if (SQL_C_WCHAR == ctype)
+                   cbValue = 2 * ucs2strlen((SQLWCHAR *) rgbValue);
+               else
+#endif /* UNICODE_SUPPORT */
+               cbValue = strlen(rgbValue);
+           }
+           if (cbValue > 0)
            {
-               old_pos = *current_param->EXEC_used;
-
                *current_param->EXEC_used += cbValue;
 
                mylog("        cbValue = %d, old_pos = %d, *used = %d\n", cbValue, old_pos, *current_param->EXEC_used);
index d4fda3670b66cda52e67764a07135bff9283c019..fc5dcef34152a309d7b1eaddb45953c3fb3df315 100644 (file)
@@ -10,7 +10,7 @@
  *                 SQLTables, SQLColumns, SQLStatistics, SQLSpecialColumns,
  *                 SQLPrimaryKeys, SQLForeignKeys,
  *                 SQLProcedureColumns(NI), SQLProcedures,
- *                 SQLTablePrivileges(NI), SQLColumnPrivileges(NI)
+ *                 SQLTablePrivileges, SQLColumnPrivileges(NI)
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *--------
@@ -231,13 +231,14 @@ PGAPI_GetInfo(
 
        case SQL_FETCH_DIRECTION:       /* ODBC 1.0 */
            len = 4;
-           value = ci->drivers.use_declarefetch ? (SQL_FD_FETCH_NEXT) : (SQL_FD_FETCH_NEXT |
-                                                    SQL_FD_FETCH_FIRST |
-                                                     SQL_FD_FETCH_LAST |
-                                                    SQL_FD_FETCH_PRIOR |
-                                                 SQL_FD_FETCH_ABSOLUTE |
-                                                 SQL_FD_FETCH_RELATIVE |
-                                                 SQL_FD_FETCH_BOOKMARK);
+           value = ci->drivers.use_declarefetch ? (SQL_FD_FETCH_NEXT) :
+            (SQL_FD_FETCH_NEXT | 
+            SQL_FD_FETCH_FIRST |
+            SQL_FD_FETCH_LAST |
+            SQL_FD_FETCH_PRIOR |
+            SQL_FD_FETCH_ABSOLUTE |
+            SQL_FD_FETCH_RELATIVE |
+            SQL_FD_FETCH_BOOKMARK);
            break;
 
        case SQL_FILE_USAGE:    /* ODBC 2.0 */
@@ -665,7 +666,6 @@ PGAPI_GetInfo(
            /* unrecognized key */
            conn->errormsg = "Unrecognized key passed to PGAPI_GetInfo.";
            conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
-           CC_log_error(func, "", conn);
            return SQL_ERROR;
    }
 
@@ -685,12 +685,20 @@ PGAPI_GetInfo(
 
        if (rgbInfoValue)
        {
+#ifdef UNICODE_SUPPORT
+           if (conn->unicode)
+           {
+               len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / 2);
+               len *= 2;
+           }
+           else
+#endif /* UNICODE_SUPPORT */
            strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
 
            if (len >= cbInfoValueMax)
            {
                result = SQL_SUCCESS_WITH_INFO;
-               conn->errornumber = STMT_TRUNCATED;
+               conn->errornumber = CONN_TRUNCATED;
                conn->errormsg = "The buffer was too small for tthe InfoValue.";
            }
        }
@@ -721,6 +729,7 @@ PGAPI_GetTypeInfo(
 {
    static char *func = "PGAPI_GetTypeInfo";
    StatementClass *stmt = (StatementClass *) hstmt;
+   QResultClass    *res;
    TupleNode  *row;
    int         i;
 
@@ -737,31 +746,31 @@ PGAPI_GetTypeInfo(
    }
 
    stmt->manual_result = TRUE;
-   stmt->result = QR_Constructor();
-   if (!stmt->result)
+   if (res = QR_Constructor(), !res)
    {
        SC_log_error(func, "Error creating result.", stmt);
        return SQL_ERROR;
    }
+   SC_set_Result(stmt, res);
 
    extend_bindings(stmt, 15);
 
-   QR_set_num_fields(stmt->result, 15);
-   QR_set_field_info(stmt->result, 0, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 2, "PRECISION", PG_TYPE_INT4, 4);
-   QR_set_field_info(stmt->result, 3, "LITERAL_PREFIX", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 4, "LITERAL_SUFFIX", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 5, "CREATE_PARAMS", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 6, "NULLABLE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 10, "MONEY", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 12, "LOCAL_TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
+   QR_set_num_fields(res, 15);
+   QR_set_field_info(res, 0, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 2, "PRECISION", PG_TYPE_INT4, 4);
+   QR_set_field_info(res, 3, "LITERAL_PREFIX", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 4, "LITERAL_SUFFIX", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 5, "CREATE_PARAMS", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 6, "NULLABLE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 10, "MONEY", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
 
    for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
    {
@@ -795,7 +804,7 @@ PGAPI_GetTypeInfo(
            set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, pgType, PG_STATIC));
            set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, pgType, PG_STATIC));
 
-           QR_add_tuple(stmt->result, row);
+           QR_add_tuple(res, row);
        }
    }
 
@@ -898,7 +907,7 @@ PGAPI_GetFunctions(
            pfExists[SQL_API_SQLMORERESULTS] = TRUE;
            pfExists[SQL_API_SQLNATIVESQL] = TRUE;
            pfExists[SQL_API_SQLNUMPARAMS] = TRUE;
-           pfExists[SQL_API_SQLPARAMOPTIONS] = FALSE;
+           pfExists[SQL_API_SQLPARAMOPTIONS] = TRUE;
            pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE;
            pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
            if (PG_VERSION_LT(conn, 6.5))
@@ -907,7 +916,7 @@ PGAPI_GetFunctions(
                pfExists[SQL_API_SQLPROCEDURES] = TRUE;
            pfExists[SQL_API_SQLSETPOS] = TRUE;
            pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE;       /* odbc 1.0 */
-           pfExists[SQL_API_SQLTABLEPRIVILEGES] = FALSE;
+           pfExists[SQL_API_SQLTABLEPRIVILEGES] = TRUE;
        }
    }
    else
@@ -1070,7 +1079,7 @@ PGAPI_GetFunctions(
                    *pfExists = TRUE;
                    break;
                case SQL_API_SQLPARAMOPTIONS:
-                   *pfExists = FALSE;
+                   *pfExists = TRUE;
                    break;
                case SQL_API_SQLPRIMARYKEYS:
                    *pfExists = TRUE;
@@ -1091,7 +1100,7 @@ PGAPI_GetFunctions(
                    *pfExists = TRUE;
                    break;      /* odbc 1.0 */
                case SQL_API_SQLTABLEPRIVILEGES:
-                   *pfExists = FALSE;
+                   *pfExists = TRUE;
                    break;
            }
        }
@@ -1115,6 +1124,7 @@ PGAPI_Tables(
    static char *func = "PGAPI_Tables";
    StatementClass *stmt = (StatementClass *) hstmt;
    StatementClass *tbl_stmt;
+   QResultClass    *res;
    TupleNode  *row;
    HSTMT       htbl_stmt;
    RETCODE     result;
@@ -1291,8 +1301,7 @@ PGAPI_Tables(
        return SQL_ERROR;
    }
 
-   stmt->result = QR_Constructor();
-   if (!stmt->result)
+   if (res = QR_Constructor(), !res)
    {
        stmt->errormsg = "Couldn't allocate memory for PGAPI_Tables result.";
        stmt->errornumber = STMT_NO_MEMORY_ERROR;
@@ -1300,6 +1309,7 @@ PGAPI_Tables(
        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
        return SQL_ERROR;
    }
+   SC_set_Result(stmt, res);
 
    /* the binding structure for a statement is not set up until */
 
@@ -1310,12 +1320,12 @@ PGAPI_Tables(
    extend_bindings(stmt, 5);
 
    /* set the field names */
-   QR_set_num_fields(stmt->result, 5);
-   QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 3, "TABLE_TYPE", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 4, "REMARKS", PG_TYPE_TEXT, 254);
+   QR_set_num_fields(res, 5);
+   QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 3, "TABLE_TYPE", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 4, "REMARKS", PG_TYPE_TEXT, 254);
 
    /* add the tuples */
    result = PGAPI_Fetch(htbl_stmt);
@@ -1372,6 +1382,7 @@ PGAPI_Tables(
            row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField));
 
            /*set_tuplefield_string(&row->tuple[0], "");*/
+           /*set_tuplefield_string(&row->tuple[0], "cat0");*/
            set_tuplefield_null(&row->tuple[0]);
 
            /*
@@ -1389,9 +1400,10 @@ PGAPI_Tables(
            set_tuplefield_null(&row->tuple[1]);
            set_tuplefield_string(&row->tuple[2], table_name);
            set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
-           set_tuplefield_string(&row->tuple[4], "");
+           /*set_tuplefield_string(&row->tuple[4], "");*/
+           set_tuplefield_string(&row->tuple[4], "TABLE");
 
-           QR_add_tuple(stmt->result, row);
+           QR_add_tuple(res, row);
        }
        result = PGAPI_Fetch(htbl_stmt);
    }
@@ -1425,11 +1437,14 @@ PGAPI_Tables(
  * PostgreSQL needs 2 '\\' to escape '_' and '%'. 
  */
 static int
-reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len)
+reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len, int ccsc)
 {
    int i, outlen;
    const char *in;
    BOOL    escape_in = FALSE;
+#ifdef MULTIBYTE
+   encoded_str encstr;
+#endif
 
    if (srclen == SQL_NULL_DATA)
    {
@@ -1441,12 +1456,13 @@ reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len)
    if (srclen <= 0)
        return STRCPY_FAIL;
 #ifdef MULTIBYTE
-   multibyte_init();
+   encoded_str_constr(&encstr, ccsc, src);
 #endif
    for (i = 0, in = src, outlen = 0; i < srclen && outlen < dst_len; i++, in++)
    {
 #ifdef MULTIBYTE
-                if (multibyte_char_check(*in) != 0)
+                encoded_nextchar(&encstr);
+                if (ENCODE_STATUS(encstr) != 0)
                 {
                         dest[outlen++] = *in;
                         continue;
@@ -1496,6 +1512,7 @@ PGAPI_Columns(
 {
    static char *func = "PGAPI_Columns";
    StatementClass *stmt = (StatementClass *) hstmt;
+   QResultClass    *res;
    TupleNode  *row;
    HSTMT       hcol_stmt;
    StatementClass *col_stmt;
@@ -1505,7 +1522,7 @@ PGAPI_Columns(
                table_name[MAX_INFO_STRING],
                field_name[MAX_INFO_STRING],
                field_type_name[MAX_INFO_STRING];
-   Int2        field_number,
+   Int2        field_number, sqltype,
                result_cols,
                scale;
    Int4        field_type,
@@ -1556,7 +1573,7 @@ PGAPI_Columns(
        char    esc_table_name[MAX_TABLE_LEN * 2];
        int escTbnamelen;
 
-       escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name));
+       escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
        my_strcat(columns_query, " and c.relname like '%.*s'", esc_table_name, escTbnamelen);
        my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
        my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName);
@@ -1701,8 +1718,7 @@ PGAPI_Columns(
        return SQL_ERROR;
    }
 
-   stmt->result = QR_Constructor();
-   if (!stmt->result)
+   if (res = QR_Constructor(), !res)
    {
        stmt->errormsg = "Couldn't allocate memory for PGAPI_Columns result.";
        stmt->errornumber = STMT_NO_MEMORY_ERROR;
@@ -1710,6 +1726,7 @@ PGAPI_Columns(
        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
        return SQL_ERROR;
    }
+   SC_set_Result(stmt, res);
 
    /* the binding structure for a statement is not set up until */
 
@@ -1721,23 +1738,32 @@ PGAPI_Columns(
    extend_bindings(stmt, result_cols);
 
    /* set the field names */
-   QR_set_num_fields(stmt->result, result_cols);
-   QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 6, "PRECISION", PG_TYPE_INT4, 4);
-   QR_set_field_info(stmt->result, 7, "LENGTH", PG_TYPE_INT4, 4);
-   QR_set_field_info(stmt->result, 8, "SCALE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 9, "RADIX", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 10, "NULLABLE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 11, "REMARKS", PG_TYPE_TEXT, 254);
+   QR_set_num_fields(res, result_cols);
+   QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 6, "PRECISION", PG_TYPE_INT4, 4);
+   QR_set_field_info(res, 7, "LENGTH", PG_TYPE_INT4, 4);
+   QR_set_field_info(res, 8, "SCALE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 9, "RADIX", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 10, "NULLABLE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 11, "REMARKS", PG_TYPE_TEXT, 254);
 
    /* User defined fields */
-   QR_set_field_info(stmt->result, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
-   QR_set_field_info(stmt->result, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
+#if (ODBCVER >= 0x0300)
+   QR_set_field_info(res, 12, "COLUMN_DEF", PG_TYPE_INT4, 254);
+   QR_set_field_info(res, 13, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 14, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 15, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
+   QR_set_field_info(res, 16, "ORDINAL_POSITION", PG_TYPE_INT4, 4);
+   QR_set_field_info(res, 17, "IS_NULLABLE", PG_TYPE_TEXT, 254);
+#else
+   QR_set_field_info(res, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
+   QR_set_field_info(res, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
+#endif /* ODBCVER */
 
    result = PGAPI_Fetch(hcol_stmt);
 
@@ -1764,7 +1790,8 @@ PGAPI_Columns(
            set_tuplefield_string(&row->tuple[1], "");
            set_tuplefield_string(&row->tuple[2], table_name);
            set_tuplefield_string(&row->tuple[3], "oid");
-           set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, the_type));
+           sqltype = pgtype_to_sqltype(stmt, the_type);
+           set_tuplefield_int2(&row->tuple[4], sqltype);
            set_tuplefield_string(&row->tuple[5], "OID");
 
            set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
@@ -1775,10 +1802,14 @@ PGAPI_Columns(
            set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
            set_tuplefield_string(&row->tuple[11], "");
 
+#if (ODBCVER >= 0x0300)
+           set_tuplefield_int2(&row->tuple[13], sqltype);
+#else
            set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
            set_tuplefield_int4(&row->tuple[13], the_type);
+#endif /* ODBCVER */
 
-           QR_add_tuple(stmt->result, row);
+           QR_add_tuple(res, row);
        }
    }
 
@@ -1794,7 +1825,8 @@ PGAPI_Columns(
        set_tuplefield_string(&row->tuple[1], "");
        set_tuplefield_string(&row->tuple[2], table_name);
        set_tuplefield_string(&row->tuple[3], field_name);
-       set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, field_type));
+       sqltype = pgtype_to_sqltype(stmt, field_type);
+       set_tuplefield_int2(&row->tuple[4], sqltype);
        set_tuplefield_string(&row->tuple[5], field_type_name);
 
 
@@ -1812,7 +1844,7 @@ PGAPI_Columns(
         *----------
         */
        qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,sqltype=%d,name='%s'\n",
-            table_name, field_name, field_type, pgtype_to_sqltype(stmt,field_type), field_type_name);
+            table_name, field_name, field_type, pgtype_to_sqltype, field_type_name);
 
        useStaticPrecision = TRUE;
 
@@ -1869,9 +1901,31 @@ PGAPI_Columns(
        set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, field_type));
        set_tuplefield_int2(&row->tuple[10], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type)));
        set_tuplefield_string(&row->tuple[11], "");
+#if (ODBCVER >= 0x0300)
+       switch (sqltype)
+       {
+           case SQL_TYPE_DATE:
+               set_tuplefield_int2(&row->tuple[13], SQL_DATETIME);
+               set_tuplefield_int2(&row->tuple[14], SQL_CODE_DATE);
+               break;
+           case SQL_TYPE_TIME:
+               set_tuplefield_int2(&row->tuple[13], SQL_DATETIME);
+               set_tuplefield_int2(&row->tuple[14], SQL_CODE_TIME);
+               break;
+           case SQL_TYPE_TIMESTAMP:
+               set_tuplefield_int2(&row->tuple[13], SQL_DATETIME);
+               set_tuplefield_int2(&row->tuple[14], SQL_CODE_TIMESTAMP);
+               break;
+           default:
+               set_tuplefield_int2(&row->tuple[13], sqltype);
+               break;
+       }
+       set_tuplefield_int4(&row->tuple[16], field_number);
+#else
        set_tuplefield_int4(&row->tuple[13], field_type);
+#endif /* ODBCVER */
 
-       QR_add_tuple(stmt->result, row);
+       QR_add_tuple(res, row);
 
 
        result = PGAPI_Fetch(hcol_stmt);
@@ -1913,7 +1967,7 @@ PGAPI_Columns(
        set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
        set_tuplefield_int4(&row->tuple[13], the_type);
 
-       QR_add_tuple(stmt->result, row);
+       QR_add_tuple(res, row);
    }
 
    /*
@@ -1949,6 +2003,7 @@ PGAPI_SpecialColumns(
    static char *func = "PGAPI_SpecialColumns";
    TupleNode  *row;
    StatementClass *stmt = (StatementClass *) hstmt;
+   QResultClass    *res;
    ConnInfo   *ci;
    HSTMT       hcol_stmt;
    StatementClass *col_stmt;
@@ -2017,18 +2072,19 @@ PGAPI_SpecialColumns(
    result = PGAPI_Fetch(hcol_stmt);
    PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
-   stmt->result = QR_Constructor();
+   res = QR_Constructor();
+   SC_set_Result(stmt, res);
    extend_bindings(stmt, 8);
 
-   QR_set_num_fields(stmt->result, 8);
-   QR_set_field_info(stmt->result, 0, "SCOPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 1, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 3, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 4, "PRECISION", PG_TYPE_INT4, 4);
-   QR_set_field_info(stmt->result, 5, "LENGTH", PG_TYPE_INT4, 4);
-   QR_set_field_info(stmt->result, 6, "SCALE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
+   QR_set_num_fields(res, 8);
+   QR_set_field_info(res, 0, "SCOPE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 1, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 3, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 4, "PRECISION", PG_TYPE_INT4, 4);
+   QR_set_field_info(res, 5, "LENGTH", PG_TYPE_INT4, 4);
+   QR_set_field_info(res, 6, "SCALE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
 
    if (relhasrules[0] != '1')
    {
@@ -2046,7 +2102,7 @@ PGAPI_SpecialColumns(
            set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, PG_TYPE_OID, PG_STATIC));
            set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
 
-           QR_add_tuple(stmt->result, row);
+           QR_add_tuple(res, row);
 
        }
        else if (fColType == SQL_ROWVER)
@@ -2066,7 +2122,7 @@ PGAPI_SpecialColumns(
                set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, the_type, PG_STATIC));
                set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
 
-               QR_add_tuple(stmt->result, row);
+               QR_add_tuple(res, row);
            }
        }
    }
@@ -2095,6 +2151,7 @@ PGAPI_Statistics(
 {
    static char *func = "PGAPI_Statistics";
    StatementClass *stmt = (StatementClass *) hstmt;
+   QResultClass    *res;
    char        index_query[INFO_INQUIRY_LEN];
    HSTMT       hindx_stmt;
    RETCODE     result;
@@ -2133,14 +2190,14 @@ PGAPI_Statistics(
 
    ci = &(SC_get_conn(stmt)->connInfo);
 
-   stmt->result = QR_Constructor();
-   if (!stmt->result)
+   if (res = QR_Constructor(), !res)
    {
        stmt->errormsg = "Couldn't allocate memory for PGAPI_Statistics result.";
        stmt->errornumber = STMT_NO_MEMORY_ERROR;
        SC_log_error(func, "", stmt);
        return SQL_ERROR;
    }
+   SC_set_Result(stmt, res);
 
    /* the binding structure for a statement is not set up until */
 
@@ -2151,20 +2208,20 @@ PGAPI_Statistics(
    extend_bindings(stmt, 13);
 
    /* set the field names */
-   QR_set_num_fields(stmt->result, 13);
-   QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 3, "NON_UNIQUE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 4, "INDEX_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 5, "INDEX_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 6, "TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 8, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 9, "COLLATION", PG_TYPE_CHAR, 1);
-   QR_set_field_info(stmt->result, 10, "CARDINALITY", PG_TYPE_INT4, 4);
-   QR_set_field_info(stmt->result, 11, "PAGES", PG_TYPE_INT4, 4);
-   QR_set_field_info(stmt->result, 12, "FILTER_CONDITION", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_num_fields(res, 13);
+   QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 3, "NON_UNIQUE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 4, "INDEX_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 5, "INDEX_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 6, "TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 8, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 9, "COLLATION", PG_TYPE_CHAR, 1);
+   QR_set_field_info(res, 10, "CARDINALITY", PG_TYPE_INT4, 4);
+   QR_set_field_info(res, 11, "PAGES", PG_TYPE_INT4, 4);
+   QR_set_field_info(res, 12, "FILTER_CONDITION", PG_TYPE_TEXT, MAX_INFO_STRING);
 
    /*
     * only use the table name... the owner should be redundant, and we
@@ -2395,7 +2452,7 @@ PGAPI_Statistics(
        set_tuplefield_null(&row->tuple[11]);
        set_tuplefield_null(&row->tuple[12]);
 
-       QR_add_tuple(stmt->result, row);
+       QR_add_tuple(res, row);
    }
 
    result = PGAPI_Fetch(hindx_stmt);
@@ -2457,7 +2514,7 @@ PGAPI_Statistics(
                set_tuplefield_null(&row->tuple[11]);
                set_tuplefield_null(&row->tuple[12]);
 
-               QR_add_tuple(stmt->result, row);
+               QR_add_tuple(res, row);
                i++;
            }
        }
@@ -2520,12 +2577,15 @@ PGAPI_ColumnPrivileges(
                       SWORD cbColumnName)
 {
    static char *func = "PGAPI_ColumnPrivileges";
+   StatementClass  *stmt = (StatementClass *) hstmt;
 
    mylog("%s: entering...\n", func);
 
    /* Neither Access or Borland care about this. */
 
-   SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
+   stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
+   stmt->errormsg = "not implemented";
+   SC_log_error(func, "Function not implemented", stmt);
    return SQL_ERROR;
 }
 
@@ -2547,6 +2607,7 @@ PGAPI_PrimaryKeys(
 {
    static char *func = "PGAPI_PrimaryKeys";
    StatementClass *stmt = (StatementClass *) hstmt;
+   QResultClass    *res;
    ConnectionClass *conn;
    TupleNode  *row;
    RETCODE     result;
@@ -2572,14 +2633,14 @@ PGAPI_PrimaryKeys(
    stmt->manual_result = TRUE;
    stmt->errormsg_created = TRUE;
 
-   stmt->result = QR_Constructor();
-   if (!stmt->result)
+   if (res = QR_Constructor(), !res)
    {
        stmt->errormsg = "Couldn't allocate memory for PGAPI_PrimaryKeys result.";
        stmt->errornumber = STMT_NO_MEMORY_ERROR;
        SC_log_error(func, "", stmt);
        return SQL_ERROR;
    }
+   SC_set_Result(stmt, res);
 
    /* the binding structure for a statement is not set up until */
 
@@ -2591,13 +2652,13 @@ PGAPI_PrimaryKeys(
    extend_bindings(stmt, result_cols);
 
    /* set the field names */
-   QR_set_num_fields(stmt->result, result_cols);
-   QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 4, "KEY_SEQ", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 5, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_num_fields(res, result_cols);
+   QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 4, "KEY_SEQ", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 5, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
 
 
    result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt);
@@ -2709,7 +2770,7 @@ PGAPI_PrimaryKeys(
        set_tuplefield_int2(&row->tuple[4], (Int2) (++seq));
        set_tuplefield_null(&row->tuple[5]);
 
-       QR_add_tuple(stmt->result, row);
+       QR_add_tuple(res, row);
 
        mylog(">> primaryKeys: pktab = '%s', attname = '%s', seq = %d\n", pktab, attname, seq);
 
@@ -2775,7 +2836,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
        return ret;
    if (!conn->server_encoding)
    {
-       if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL), res)
+       if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, TRUE), res)
        {
            if (QR_get_num_tuples(res) > 0)
                conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
@@ -2785,25 +2846,16 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
    if (!conn->server_encoding)
        return ret;
    sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
-   if (res = CC_send_query(conn, query, NULL), res)
-   {
-       bError = QR_get_aborted(res);
-       QR_Destructor(res);
-   }
-   else
-       bError = TRUE;
+   bError = (CC_send_query(conn, query, NULL, TRUE) == NULL);
    if (!bError && continueExec)
    {
        sprintf(query, "select OID from pg_class where relname = '%s'", serverTableName);
-       if (res = CC_send_query(conn, query, NULL), res)
+       if (res = CC_send_query(conn, query, NULL, TRUE), res)
        {
            if (QR_get_num_tuples(res) > 0)
                strcpy(saveoid, QR_get_value_backend_row(res, 0, 0));
            else
-           {
                continueExec = FALSE;
-               bError = QR_get_aborted(res);
-           }
            QR_Destructor(res);
        }
        else
@@ -2817,17 +2869,11 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
    }
    /* restore the client encoding */
    sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
-   if (res = CC_send_query(conn, query, NULL), res)
-   {
-       bError = QR_get_aborted(res);
-       QR_Destructor(res);
-   }
-   else
-       bError = TRUE;
+   bError = (CC_send_query(conn, query, NULL, TRUE) == NULL);
    if (bError || !continueExec)
        return ret;
    sprintf(query, "select relname from pg_class where OID = %s", saveoid);
-   if (res = CC_send_query(conn, query, NULL), res)
+   if (res = CC_send_query(conn, query, NULL, TRUE), res)
    {
        if (QR_get_num_tuples(res) > 0)
        {
@@ -2854,7 +2900,7 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
        return ret;
    if (!conn->server_encoding)
    {
-       if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL), res)
+       if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, TRUE), res)
        {
            if (QR_get_num_tuples(res) > 0)
                conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
@@ -2864,19 +2910,13 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
    if (!conn->server_encoding)
        return ret;
    sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
-   if (res = CC_send_query(conn, query, NULL), res)
-   {
-       bError = QR_get_aborted(res);
-       QR_Destructor(res);
-   }
-   else
-       bError = TRUE;
+   bError = (CC_send_query(conn, query, NULL, TRUE) == NULL);
    if (!bError && continueExec)
    {
        sprintf(query, "select attrelid, attnum from pg_class, pg_attribute "
                "where relname = '%s' and attrelid = pg_class.oid "
                "and attname = '%s'", serverTableName, serverColumnName);
-       if (res = CC_send_query(conn, query, NULL), res)
+       if (res = CC_send_query(conn, query, NULL, TRUE), res)
        {
            if (QR_get_num_tuples(res) > 0)
            {
@@ -2884,10 +2924,7 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
                strcpy(saveattnum, QR_get_value_backend_row(res, 0, 1));
            }
            else
-           {
                continueExec = FALSE;
-               bError = QR_get_aborted(res);
-           }
            QR_Destructor(res);
        }
        else
@@ -2901,17 +2938,11 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
    }
    /* restore the cleint encoding */
    sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
-   if (res = CC_send_query(conn, query, NULL), res)
-   {
-       bError = QR_get_aborted(res);
-       QR_Destructor(res);
-   }
-   else
-       bError = TRUE;
+   bError = (CC_send_query(conn, query, NULL, TRUE) == NULL);
    if (bError || !continueExec)
        return ret;
    sprintf(query, "select attname from pg_attribute where attrelid = %s and attnum = %s", saveattrelid, saveattnum);
-   if (res = CC_send_query(conn, query, NULL), res)
+   if (res = CC_send_query(conn, query, NULL, TRUE), res)
    {
        if (QR_get_num_tuples(res) > 0)
        {
@@ -2942,6 +2973,7 @@ PGAPI_ForeignKeys(
 {
    static char *func = "PGAPI_ForeignKeys";
    StatementClass *stmt = (StatementClass *) hstmt;
+   QResultClass    *res;
    TupleNode  *row;
    HSTMT       htbl_stmt,
                hpkey_stmt;
@@ -2997,14 +3029,14 @@ PGAPI_ForeignKeys(
    stmt->manual_result = TRUE;
    stmt->errormsg_created = TRUE;
 
-   stmt->result = QR_Constructor();
-   if (!stmt->result)
+   if (res = QR_Constructor(), !res)
    {
        stmt->errormsg = "Couldn't allocate memory for PGAPI_ForeignKeys result.";
        stmt->errornumber = STMT_NO_MEMORY_ERROR;
        SC_log_error(func, "", stmt);
        return SQL_ERROR;
    }
+   SC_set_Result(stmt, res);
 
    /* the binding structure for a statement is not set up until */
 
@@ -3016,23 +3048,23 @@ PGAPI_ForeignKeys(
    extend_bindings(stmt, result_cols);
 
    /* set the field names */
-   QR_set_num_fields(stmt->result, result_cols);
-   QR_set_field_info(stmt->result, 0, "PKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 1, "PKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 2, "PKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 3, "PKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 4, "FKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 5, "FKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 6, "FKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 7, "FKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 8, "KEY_SEQ", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 9, "UPDATE_RULE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 10, "DELETE_RULE", PG_TYPE_INT2, 2);
-   QR_set_field_info(stmt->result, 11, "FK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 12, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 13, "TRIGGER_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_num_fields(res, result_cols);
+   QR_set_field_info(res, 0, "PKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 1, "PKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 2, "PKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 3, "PKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 4, "FKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 5, "FKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 6, "FKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 7, "FKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 8, "KEY_SEQ", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 9, "UPDATE_RULE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 10, "DELETE_RULE", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 11, "FK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 12, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 13, "TRIGGER_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
 #if (ODBCVER >= 0x0300)
-   QR_set_field_info(stmt->result, 14, "DEFERRABILITY", PG_TYPE_INT2, 2);
+   QR_set_field_info(res, 14, "DEFERRABILITY", PG_TYPE_INT2, 2);
 #endif   /* ODBCVER >= 0x0300 */
 
    /*
@@ -3369,7 +3401,7 @@ PGAPI_ForeignKeys(
                set_tuplefield_int2(&row->tuple[14], defer_type);
 #endif   /* ODBCVER >= 0x0300 */
 
-               QR_add_tuple(stmt->result, row);
+               QR_add_tuple(res, row);
 #ifdef MULTIBYTE
                if (fkey_alloced)
                    free(fkey_text);
@@ -3623,7 +3655,7 @@ PGAPI_ForeignKeys(
                set_tuplefield_int2(&row->tuple[14], defer_type);
 #endif   /* ODBCVER >= 0x0300 */
 
-               QR_add_tuple(stmt->result, row);
+               QR_add_tuple(res, row);
 #ifdef MULTIBYTE
                if (pkey_alloced)
                    free(pkey_text);
@@ -3687,10 +3719,13 @@ PGAPI_ProcedureColumns(
                       SWORD cbColumnName)
 {
    static char *func = "PGAPI_ProcedureColumns";
+   StatementClass  *stmt = (StatementClass *) hstmt;
 
    mylog("%s: entering...\n", func);
 
-   SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
+   stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
+   stmt->errormsg = "not implemented";
+   SC_log_error(func, "Function not implemented", stmt);
    return SQL_ERROR;
 }
 
@@ -3717,7 +3752,7 @@ PGAPI_Procedures(
    {
        stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
        stmt->errormsg = "Version is too old";
-       SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
+       SC_log_error(func, "Function not implemented", stmt);
        return SQL_ERROR;
    }
    if (!SC_recycle_statement(stmt))
@@ -3733,16 +3768,13 @@ PGAPI_Procedures(
           " case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc");
    my_strcat(proc_query, " where proname like '%.*s'", szProcName, cbProcName);
 
-   res = CC_send_query(conn, proc_query, NULL);
-   if (!res || QR_aborted(res))
+   if (res = CC_send_query(conn, proc_query, NULL, TRUE), !res)
    {
-       if (res)
-           QR_Destructor(res);
        stmt->errornumber = STMT_EXEC_ERROR;
        stmt->errormsg = "PGAPI_Procedures query error";
        return SQL_ERROR;
    }
-   stmt->result = res;
+   SC_set_Result(stmt, res);
 
    /*
     * also, things need to think that this statement is finished so the
@@ -3759,6 +3791,52 @@ PGAPI_Procedures(
 }
 
 
+#define    ACLMAX  8
+#define ALL_PRIVILIGES "arwdRxt"
+static int
+usracl_auth(char *usracl, const char *auth)
+{
+   int i, j, addcnt = 0;
+
+   for (i = 0; auth[i]; i++)
+   {
+       for (j = 0; j < ACLMAX; j++)
+       {
+           if (usracl[j] == auth[i])
+               break;
+           else if (!usracl[j])
+           {
+               usracl[j]= auth[i];
+               addcnt++;
+               break;
+           }
+       }
+   }
+   return addcnt;
+} 
+static void
+useracl_upd(char (*useracl)[ACLMAX], QResultClass *allures, const char *user, const char *auth)
+{
+   int usercount = QR_get_num_tuples(allures), i, addcnt = 0;
+
+mylog("user=%s auth=%s\n", user, auth);
+   if (user[0])
+       for (i = 0; i < usercount; i++)
+       {
+           if (strcmp(QR_get_value_backend_row(allures, i, 0), user) == 0)
+           {
+               addcnt += usracl_auth(useracl[i], auth);
+               break;
+           }
+       }
+   else
+       for (i = 0; i < usercount; i++)
+       {
+           addcnt += usracl_auth(useracl[i], auth);
+       }
+   mylog("addcnt=%d\n", addcnt);
+}
+
 RETCODE        SQL_API
 PGAPI_TablePrivileges(
                      HSTMT hstmt,
@@ -3767,13 +3845,24 @@ PGAPI_TablePrivileges(
                      UCHAR FAR * szTableOwner,
                      SWORD cbTableOwner,
                      UCHAR FAR * szTableName,
-                     SWORD cbTableName)
+                     SWORD cbTableName,
+                     UWORD flag)
 {
    StatementClass *stmt = (StatementClass *) hstmt;
    static char *func = "PGAPI_TablePrivileges";
+   ConnectionClass *conn = SC_get_conn(stmt);
    Int2        result_cols;
+   char        proc_query[INFO_INQUIRY_LEN];
+   QResultClass    *res, *allures = NULL;
+   TupleNode   *row;
+   int     tablecount, usercount, i, j, k;
+   BOOL        grpauth, sys, su;
+   char        (*useracl)[ACLMAX], *acl, *user, *delim, *auth;
+   char        *reln, *owner, *priv;
 
    mylog("%s: entering...\n", func);
+   if (!SC_recycle_statement(stmt))
+       return SQL_ERROR;
 
    /*
     * a statement is actually executed, so we'll have to do this
@@ -3784,16 +3873,187 @@ PGAPI_TablePrivileges(
 
    /* set the field names */
    stmt->manual_result = TRUE;
-   stmt->result = QR_Constructor();
-   QR_set_num_fields(stmt->result, result_cols);
-   QR_set_field_info(stmt->result, 0, "TABLE_CAT", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 1, "TABLE_SCHEM", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 3, "GRANTOR", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 4, "GRANTEE", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 5, "PRIVILEGE", PG_TYPE_TEXT, MAX_INFO_STRING);
-   QR_set_field_info(stmt->result, 6, "IS_GRANTABLE", PG_TYPE_TEXT, MAX_INFO_STRING);
-
-   SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
-   return SQL_ERROR;
+   res = QR_Constructor();
+   SC_set_Result(stmt, res);
+   QR_set_num_fields(res, result_cols);
+   QR_set_field_info(res, 0, "TABLE_CAT", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 1, "TABLE_SCHEM", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 3, "GRANTOR", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 4, "GRANTEE", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 5, "PRIVILEGE", PG_TYPE_TEXT, MAX_INFO_STRING);
+   QR_set_field_info(res, 6, "IS_GRANTABLE", PG_TYPE_TEXT, MAX_INFO_STRING);
+
+   /*
+    * also, things need to think that this statement is finished so the
+    * results can be retrieved.
+    */
+   stmt->status = STMT_FINISHED;
+   /* set up the current tuple pointer for SQLFetch */
+   stmt->currTuple = -1;
+   stmt->rowset_start = -1;
+   stmt->current_col = -1;
+   strncpy_null(proc_query, "select relname, usename, relacl from pg_class , pg_user where", sizeof(proc_query)); 
+   if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) 
+       my_strcat(proc_query, " relname = '%.*s' and", szTableName, cbTableName);
+   else
+   {
+       char    esc_table_name[MAX_TABLE_LEN * 2];
+       int escTbnamelen;
+
+       escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
+       my_strcat(proc_query, " relname like '%.*s' and", esc_table_name, escTbnamelen);
+   }
+   strcat(proc_query, " pg_user.usesysid = relowner"); 
+   if (res = CC_send_query(conn, proc_query, NULL, TRUE), !res)
+   {
+       stmt->errornumber = STMT_EXEC_ERROR;
+       stmt->errormsg = "PGAPI_TablePrivileges query error";
+       return SQL_ERROR;
+   }
+   strncpy_null(proc_query, "select usename, usesysid, usesuper from pg_user", sizeof(proc_query));
+   tablecount = QR_get_num_tuples(res);
+   if (allures = CC_send_query(conn, proc_query, NULL, TRUE), !allures)
+   {
+       QR_Destructor(res);
+       stmt->errornumber = STMT_EXEC_ERROR;
+       stmt->errormsg = "PGAPI_TablePrivileges query error";
+       return SQL_ERROR;
+   }
+   usercount = QR_get_num_tuples(allures);
+   useracl = (char (*)[ACLMAX]) malloc(usercount * sizeof(char [ACLMAX]));
+   for (i = 0; i < tablecount; i++)
+   { 
+       memset(useracl, 0, usercount * sizeof(char[ACLMAX]));
+       acl = (char *) QR_get_value_backend_row(res, i, 2);
+       if (acl && acl[0] == '{')
+           user = acl + 1;
+       else
+           user = NULL;
+       for (; user && *user;)
+       {
+           grpauth = FALSE;
+           if (user[0] == '"' && strncmp(user + 1, "group ", 6) == 0)
+           {
+               user += 7;
+               grpauth = TRUE;
+           }
+           if (delim = strchr(user, '='), !delim)
+               break;
+           *delim = '\0';
+           auth = delim + 1;
+           if (grpauth)
+           {
+               if (delim = strchr(auth, '"'), delim)
+               {
+                   *delim = '\0';
+                   delim++;
+               }
+           }
+           else if (delim = strchr(auth, ','), delim)
+               *delim = '\0';
+           else if (delim = strchr(auth, '}'), delim)
+               *delim = '\0';
+           if (grpauth) /* handle group privilege */
+           {
+               QResultClass    *gres;
+               int     i;
+               char    *grolist, *uid, *delm;
+
+               snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user);
+               if (gres = CC_send_query(conn, proc_query, NULL, TRUE))
+               {
+                   grolist = QR_get_value_backend_row(gres, 0, 0);
+                   if (grolist && grolist[0] == '{')
+                   {
+                       for (uid = grolist + 1; *uid;)
+                       {
+                           if (delm = strchr(uid, ','), delm)
+                               *delm = '\0';
+                           else if (delm = strchr(uid, '}'), delm)
+                               *delm = '\0';
+mylog("guid=%s\n", uid);
+                           for (i = 0; i < usercount; i++)
+                           {
+                               if (strcmp(QR_get_value_backend_row(allures, i, 1), uid) == 0)
+                                   useracl_upd(useracl, allures, QR_get_value_backend_row(allures, i, 0), auth);
+                           }
+                           uid = delm + 1;
+                       }
+                   }
+                   QR_Destructor(gres);
+               }
+           }
+           else
+               useracl_upd(useracl, allures, user, auth);
+           if (!delim)
+               break;
+           user = delim + 1;
+       }
+       reln = QR_get_value_backend_row(res, i, 0);
+       owner = QR_get_value_backend_row(res, i, 1);
+       /* The owner has all privileges */
+       useracl_upd(useracl, allures, owner, ALL_PRIVILIGES);
+       for (j = 0; j < usercount; j++)
+       {
+           user = QR_get_value_backend_row(allures, j, 0);
+           su = (strcmp(QR_get_value_backend_row(allures, j, 2), "t") == 0);
+           sys = (strcmp(user, owner) == 0);
+           /* Super user has all privileges */
+           if (su)
+               useracl_upd(useracl, allures, user, ALL_PRIVILIGES);
+           for (k = 0; k < ACLMAX; k++)
+           {
+               if (!useracl[j][k])
+                   break;
+               switch (useracl[j][k])
+               {
+                   case 'R': /* rule */
+                   case 't': /* trigger */
+                       continue;
+               }
+               row = (TupleNode *) malloc(sizeof(TupleNode) + (7 - 1) *sizeof(TupleField));
+               set_tuplefield_string(&row->tuple[0], "");
+               set_tuplefield_string(&row->tuple[1], "");
+               set_tuplefield_string(&row->tuple[2], reln);
+               if (su || sys)
+                   set_tuplefield_string(&row->tuple[3], "_SYSTEM");
+               else
+                   set_tuplefield_string(&row->tuple[3], owner);
+               mylog("user=%s\n", user);
+               set_tuplefield_string(&row->tuple[4], user);
+               switch (useracl[j][k])
+               {
+                   case 'a':
+                       priv = "INSERT";
+                       break;
+                   case 'r':
+                       priv = "SELECT";
+                       break;
+                   case 'w':
+                       priv = "UPDATE";
+                       break;
+                   case 'd':
+                       priv = "DELETE";
+                       break;
+                   case 'x':
+                       priv = "REFERENCES";
+                       break;
+                   default:
+                       priv = "";
+               }
+               set_tuplefield_string(&row->tuple[5], priv);
+               /* The owner and the super user are grantable */
+               if (sys || su)
+                   set_tuplefield_string(&row->tuple[6], "YES");
+               else
+                   set_tuplefield_string(&row->tuple[6], "NO");
+               QR_add_tuple(SC_get_Result(stmt), row);
+           }
+       }
+   }
+   free(useracl);
+   QR_Destructor(res);
+   QR_Destructor(allures); 
+   return SQL_SUCCESS;
 }
index 8aa2bfdf10b2fe7df753b4818405af732bab2512..b606f0dc62253bc160e0a1d122a781a488a9f287 100644 (file)
@@ -19,6 +19,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
 {
    static char *func = "PGAPI_GetInfo30";
    ConnectionClass *conn = (ConnectionClass *) hdbc;
+   ConnInfo    *ci = &(conn->connInfo);
    char       *p = NULL;
    int         len = 0,
                value = 0;
@@ -50,35 +51,60 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
                | SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
                | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
                | SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
-               | SQL_CA1_POS_REFRESH
-               /* | SQL_CA1_BULK_ADD
+               | SQL_CA1_POS_REFRESH;
+           if (ci->drivers.lie)
+               value |=
+               ( SQL_CA1_BULK_ADD
                | SQL_CA1_BULK_UPDATE_BY_BOOKMARK
                | SQL_CA1_BULK_DELETE_BY_BOOKMARK
-               | SQL_CA1_BULK_FETCH_BY_BOOKMARK */
-               ;
+               | SQL_CA1_BULK_FETCH_BY_BOOKMARK
+
+               | SQL_CA1_LOCK_EXCLUSIVE
+               | SQL_CA1_LOCK_UNLOCK
+               | SQL_CA1_POSITIONED_UPDATE
+               | SQL_CA1_POSITIONED_DELETE
+               | SQL_CA1_SELECT_FOR_UPDATE
+               );
            break;
        case SQL_KEYSET_CURSOR_ATTRIBUTES2:
            len = 4;
-           value = SQL_CA2_OPT_ROWVER_CONCURRENCY |
-               SQL_CA2_SENSITIVITY_ADDITIONS |
-               SQL_CA2_SENSITIVITY_DELETIONS |
-               SQL_CA2_SENSITIVITY_UPDATES;
+           value = SQL_CA2_OPT_ROWVER_CONCURRENCY
+               | SQL_CA2_SENSITIVITY_ADDITIONS
+               | SQL_CA2_SENSITIVITY_DELETIONS
+               | SQL_CA2_SENSITIVITY_UPDATES;
+           if (ci->drivers.lie)
+               value |=
+               ( SQL_CA2_READ_ONLY_CONCURRENCY
+               | SQL_CA2_LOCK_CONCURRENCY
+               | SQL_CA2_OPT_VALUES_CONCURRENCY
+               | SQL_CA2_MAX_ROWS_SELECT
+               | SQL_CA2_MAX_ROWS_INSERT
+               | SQL_CA2_MAX_ROWS_DELETE
+               | SQL_CA2_MAX_ROWS_UPDATE
+               | SQL_CA2_MAX_ROWS_CATALOG
+               | SQL_CA2_MAX_ROWS_AFFECTS_ALL
+               | SQL_CA2_CRC_EXACT
+               | SQL_CA2_CRC_APPROXIMATE
+               | SQL_CA2_SIMULATE_NON_UNIQUE
+               | SQL_CA2_SIMULATE_TRY_UNIQUE
+               | SQL_CA2_SIMULATE_UNIQUE
+               );
            break;
 
        case SQL_STATIC_CURSOR_ATTRIBUTES1:
            len = 4;
-           value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
-               SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK |
-               SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION |
-               SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE |
-               SQL_CA1_POS_REFRESH;
+           value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE
+               | SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
+               | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
+               | SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
+               SQL_CA1_POS_REFRESH;
            break;
        case SQL_STATIC_CURSOR_ATTRIBUTES2:
            len = 4;
-           value = SQL_CA2_OPT_ROWVER_CONCURRENCY |
-               SQL_CA2_SENSITIVITY_ADDITIONS |
-               SQL_CA2_SENSITIVITY_DELETIONS |
-               SQL_CA2_SENSITIVITY_UPDATES;
+           value = SQL_CA2_OPT_ROWVER_CONCURRENCY
+               | SQL_CA2_SENSITIVITY_ADDITIONS
+               | SQL_CA2_SENSITIVITY_DELETIONS
+               SQL_CA2_SENSITIVITY_UPDATES;
            break;
 
        case SQL_ODBC_INTERFACE_CONFORMANCE:
@@ -103,11 +129,11 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
            break;
        case SQL_BATCH_ROW_COUNT:
            len = 4;
-           value = SQL_BRC_ROLLED_UP | SQL_BRC_EXPLICIT;
+           value = SQL_BRC_EXPLICIT;
            break;
        case SQL_BATCH_SUPPORT:
            len = 4;
-           value = SQL_BS_ROW_COUNT_EXPLICIT;
+           value = SQL_BS_SELECT_EXPLICIT | SQL_BS_ROW_COUNT_EXPLICIT;
            break;
        case SQL_CATALOG_NAME:
            len = 0;
@@ -194,7 +220,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
            len = 4;
            value = SQL_DT_DROP_TABLE;
            if (PG_VERSION_GT(conn, 7.2)) /* hopefully */
-               value |= SQL_DT_RESTRICT | SQL_DT_CASCADE;
+               value |= (SQL_DT_RESTRICT | SQL_DT_CASCADE);
            break;
        case SQL_DROP_TRANSLATION:
            len = 4;
@@ -204,7 +230,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
            len = 4;
            value = SQL_DV_DROP_VIEW;
            if (PG_VERSION_GT(conn, 7.2)) /* hopefully */
-               value |= SQL_DV_RESTRICT | SQL_DV_CASCADE;
+               value |= (SQL_DV_RESTRICT | SQL_DV_CASCADE);
            break;
        case SQL_INDEX_KEYWORDS:
            len = 4;
@@ -227,11 +253,11 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
            break;
        case SQL_PARAM_ARRAY_ROW_COUNTS:
            len = 4;
-           value = SQL_PARC_NO_BATCH;
+           value = SQL_PARC_BATCH;
            break;
        case SQL_PARAM_ARRAY_SELECTS:
            len = 4;
-           value = SQL_PAS_NO_SELECT;
+           value = SQL_PAS_BATCH;
            break;
        case SQL_SQL_CONFORMANCE:
            len = 4;
@@ -316,6 +342,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
            return SQL_ERROR;
    }
    result = SQL_SUCCESS;
+   mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
    if (p)
    {
        /* char/binary data */
@@ -323,6 +350,14 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
 
        if (rgbInfoValue)
        {
+#ifdef UNICODE_SUPPORT
+           if (conn->unicode)
+           {
+               len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / 2);
+               len *= 2;
+           }
+           else
+#endif /* UNICODE_SUPPORT */
            strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
 
            if (len >= cbInfoValueMax)
index dc505115fe39ac0802cdc24059598953c47d9e65..443d1f47b3cfda0cdb64cba4699a5239c82210a8 100644 (file)
@@ -15,7 +15,6 @@
 #include "psqlodbc.h"
 
 #include <stdio.h>
-#include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
 
index 5cedd4c147e8daeb5172b8548a4b0a059c4de95d..b658ed7c91e06d6cc7e5a7756e7b16593ff9febb 100644 (file)
@@ -38,6 +38,7 @@
 #define MYLOGDIR           "c:"
 #endif
 extern void mylog(char *fmt,...);
+#define    inolog  mylog   /* for really temporary debug */
 
 #else
 #ifndef WIN32
index 464bf244326a52b8403f2c17d2ce99113b31faf5..06e24d0871634db274d70befd001b82addd0570e 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 
-int PG_CCST;               /* Client Charcter Status */
-
-int PG_SCSC;               /* Server Charcter Set (code) */
-int PG_CCSC;               /* Client Charcter Set (code) */
-unsigned char *PG_SCSS;    /* Server Charcter Set (string) */
-unsigned char *PG_CCSS;    /* Client Charcter Set (string) */
-
 pg_CS CS_Table[] =
 {
    { "SQL_ASCII",  SQL_ASCII },
@@ -78,19 +71,29 @@ pg_ismb(int characterset_code)
 int
 pg_CS_code(const unsigned char *characterset_string)
 {
-   int i = 0, c;
+   int i = 0, c = -1;
+   unsigned len = 0;
    for(i = 0; CS_Table[i].code != OTHER; i++)
    {
        if (strstr(characterset_string,CS_Table[i].name))
-           c = CS_Table[i].code;
+       {
+                   if(strlen(CS_Table[i].name) >= len)
+                        {
+                           len = strlen(CS_Table[i].name);
+                           c = CS_Table[i].code;
+                        }
+
+       }
    }
+   if (c < 0)
+       c = i;
    return (c);
 }
 
 unsigned char *
-pg_CS_name(const int characterset_code)
+pg_CS_name(int characterset_code)
 {
-   int i = 0;
+   int i;
    for (i = 0; CS_Table[i].code != OTHER; i++)
    {
        if (CS_Table[i].code == characterset_code)
@@ -242,7 +245,7 @@ pg_CS_stat(int stat,unsigned int character,int characterset_code)
 
 
 unsigned char *
-pg_mbschr(const unsigned char *string, unsigned int character)
+pg_mbschr(int csc, const unsigned char *string, unsigned int character)
 {
    int         mb_st = 0;
    unsigned char *s;
@@ -250,7 +253,7 @@ pg_mbschr(const unsigned char *string, unsigned int character)
 
    for(;;) 
    {
-       mb_st = pg_CS_stat(mb_st, (unsigned char) *s,PG_CCSC);
+       mb_st = pg_CS_stat(mb_st, (unsigned char) *s, csc);
        if (mb_st == 0 && (*s == character || *s == 0))
            break;
        else
@@ -260,13 +263,13 @@ pg_mbschr(const unsigned char *string, unsigned int character)
 }
 
 int
-pg_mbslen(const unsigned char *string)
+pg_mbslen(int csc, const unsigned char *string)
 {
    unsigned char *s;
    int len, cs_stat;
    for (len = 0, cs_stat = 0, s = (unsigned char *) string; *s != 0; s++)
    {
-       cs_stat = pg_CS_stat(cs_stat,(unsigned int) *s, PG_CCSC);
+       cs_stat = pg_CS_stat(cs_stat,(unsigned int) *s, csc);
        if (cs_stat < 2)
            len++;
    }
@@ -274,12 +277,12 @@ pg_mbslen(const unsigned char *string)
 }
 
 unsigned char *
-pg_mbsinc(const unsigned char *current )
+pg_mbsinc(int csc, const unsigned char *current )
 {
    int mb_stat = 0;
    if (*current != 0)
    {
-       mb_stat = (int) pg_CS_stat(mb_stat, *current, PG_CCSC);
+       mb_stat = (int) pg_CS_stat(mb_stat, *current, csc);
        if (mb_stat == 0)
            mb_stat = 1;
        return ((unsigned char *) current + mb_stat);
@@ -288,43 +291,100 @@ pg_mbsinc(const unsigned char *current )
        return NULL;
 }
 
-void
-CC_lookup_characterset(ConnectionClass *self)
+static char *
+CC_lookup_cs_new(ConnectionClass *self)
 {
+   char        *encstr = NULL;
+   QResultClass    *res;
+
+   res = CC_send_query(self, "select pg_client_encoding()", NULL, TRUE);
+   if (res)
+   {
+       char    *enc = QR_get_value_backend_row(res, 0, 0);
+
+       if (enc)
+           encstr = strdup(enc);
+       QR_Destructor(res);
+   }
+   return encstr;
+}
+static char *
+CC_lookup_cs_old(ConnectionClass *self)
+{
+   char        *encstr = NULL;
    HSTMT       hstmt;
-   StatementClass *stmt;
    RETCODE     result;
-   static char *func = "CC_lookup_characterset";
-
-   mylog("%s: entering...\n", func);
-   PG_SCSS = malloc(MAX_CHARACTERSET_NAME);
-   PG_CCSS = malloc(MAX_CHARACTERSET_NAME);
 
    result = PGAPI_AllocStmt(self, &hstmt);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-       return;
-   stmt = (StatementClass *) hstmt;
+       return encstr;
 
    result = PGAPI_ExecDirect(hstmt, "Show Client_Encoding", SQL_NTS);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+   if (result == SQL_SUCCESS_WITH_INFO)
    {
-       PGAPI_FreeStmt(hstmt, SQL_DROP);
-       return;
+       char sqlState[8], errormsg[128], enc[32];
+
+       if (PGAPI_Error(NULL, NULL, hstmt, sqlState, NULL, errormsg,
+           sizeof(errormsg), NULL) == SQL_SUCCESS &&
+           sscanf(errormsg, "%*s %*s %*s %*s %*s %s", enc) > 0)
+           encstr = strdup(enc);
    }
-   result = PGAPI_AllocStmt(self, &hstmt);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-       return;
-   stmt = (StatementClass *) hstmt;
+   PGAPI_FreeStmt(hstmt, SQL_DROP);
+   return encstr;
+}
 
-   result = PGAPI_ExecDirect(hstmt, "Show Server_Encoding", SQL_NTS);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+void
+CC_lookup_characterset(ConnectionClass *self)
+{
+   char        *encstr;
+   static char *func = "CC_lookup_characterset";
+
+   mylog("%s: entering...\n", func);
+   if (PG_VERSION_LT(self, 7.2))
+       encstr = CC_lookup_cs_old(self);
+   else
+       encstr = CC_lookup_cs_new(self);
+   if (self->client_encoding)
+       free(self->client_encoding);
+   if (encstr)
+   {
+       self->client_encoding = encstr;
+       self->ccsc = pg_CS_code(encstr);
+       qlog("    [ Client encoding = '%s' (code = %d) ]\n", self->client_encoding, self->ccsc);
+       if (stricmp(pg_CS_name(self->ccsc), encstr))
+       {
+           qlog(" Client encoding = '%s' and %s\n", self->client_encoding, pg_CS_name(self->ccsc));
+           self->errornumber = CONN_VALUE_OUT_OF_RANGE;  
+           self->errormsg = "client encoding mismatch"; 
+       }
+   }
+   else
    {
-       PGAPI_FreeStmt(hstmt, SQL_DROP);
-       return;
+       self->ccsc = SQL_ASCII;
+       self->client_encoding = NULL;
    }
+}
 
-   strcpy(PG_SCSS , pg_CS_name(PG_SCSC = pg_CS_code(PG_SCSS)));
-   strcpy(PG_CCSS , pg_CS_name(PG_CCSC = pg_CS_code(PG_CCSS)));
+void encoded_str_constr(encoded_str *encstr, int ccsc, const char *str)
+{
+   encstr->ccsc = ccsc;
+   encstr->encstr = str;
+   encstr->pos = -1;
+   encstr->ccst = 0;
+}
+int encoded_nextchar(encoded_str *encstr)
+{
+   int chr;
+
+   chr = encstr->encstr[++encstr->pos]; 
+   encstr->ccst = pg_CS_stat(encstr->ccst, (unsigned int) chr, encstr->ccsc);
+   return chr; 
+}
+int encoded_byte_check(encoded_str *encstr, int abspos)
+{
+   int chr;
 
-   qlog("    [ Server encoding = '%s' (code = %d), Client encoding = '%s' (code = %d) ]\n", PG_SCSS, PG_SCSC, PG_CCSS, PG_CCSC);
+   chr = encstr->encstr[encstr->pos = abspos]; 
+   encstr->ccst = pg_CS_stat(encstr->ccst, (unsigned int) chr, encstr->ccsc);
+   return chr; 
 }
index b6d487b634d2da953f02b457be3634eeea21b179..47a57b0ade63f0a20f08fb6316db58e255cc751b 100644 (file)
@@ -4,13 +4,14 @@
  *
  */
 #include "psqlodbc.h"
+#include "qresult.h"
 
 /* PostgreSQL client encoding */
 #define SQL_ASCII          0   /* SQL/ASCII */
 #define EUC_JP             1   /* EUC for Japanese */
 #define EUC_CN             2   /* EUC for Chinese */
 #define EUC_KR             3   /* EUC for Korean */
-#define EUC_TW             4   /* EUC for Taiwan */\r
+#define EUC_TW             4   /* EUC for Taiwan */
 #define JOHAB              5
 #define UTF8               6   /* Unicode UTF-8 */
 #define MULE_INTERNAL      7   /* Mule internal code */
 #define LATIN6             13  /* ISO-8859 Latin 6 */
 #define LATIN7             14  /* ISO-8859 Latin 7 */
 #define LATIN8             15  /* ISO-8859 Latin 8 */
-#define LATIN9             16  /* ISO-8859 Latin 9 */\r
-#define LATIN10                17  /* ISO-8859 Latin 10 */\r
-#define WIN1256                18  /* Arabic Windows */\r
-#define TCVN               19  /* Vietnamese Windows */\r
-#define WIN874             20  /* Thai Windows */\r
-#define KOI8R              21  /* KOI8-R/U */\r
+#define LATIN9             16  /* ISO-8859 Latin 9 */
+#define LATIN10                17  /* ISO-8859 Latin 10 */
+#define WIN1256                18  /* Arabic Windows */
+#define TCVN               19  /* Vietnamese Windows */
+#define WIN874             20  /* Thai Windows */
+#define KOI8R              21  /* KOI8-R/U */
 #define WIN1251                22  /* windows-1251 */
 #define ALT                    23  /* Alternativny Variant (MS-DOS CP866) */
-#define ISO_8859_5         24  /* ISO-8859-5 */\r
-#define ISO_8859_6         25  /* ISO-8859-6 */\r
-#define ISO_8859_7         26  /* ISO-8859-7 */\r
-#define ISO_8859_8         27  /* ISO-8859-8 */\r
-\r
+#define ISO_8859_5         24  /* ISO-8859-5 */
+#define ISO_8859_6         25  /* ISO-8859-6 */
+#define ISO_8859_7         26  /* ISO-8859-7 */
+#define ISO_8859_8         27  /* ISO-8859-8 */
+
 #define SJIS               28  /* Shift JIS */
-#define BIG5               29  /* Big5 */\r
-#define GBK                    30  /* GBK */\r
-#define UHC                    31  /* UHC */\r
-#define WIN1250                32  /* windows-1250 */\r
-#define OTHER              -1\r
-\r
-#define MAX_CHARACTERSET_NAME  24\r
-#define MAX_CHARACTER_LEN  6\r
+#define BIG5               29  /* Big5 */
+#define GBK                    30  /* GBK */
+#define UHC                    31  /* UHC */
+#define WIN1250                32  /* windows-1250 */
+#define OTHER              -1
+
+#define MAX_CHARACTERSET_NAME  24
+#define MAX_CHARACTER_LEN  6
 
-/* OLD Type */\r
+/* OLD Type */
 // extern int  multibyte_client_encoding;  /* Multibyte client encoding. */
 // extern int  multibyte_status;   /* Multibyte charcter status. */
 //
 // void        multibyte_init(void);
 // unsigned char *check_client_encoding(unsigned char *sql_string);
 // int         multibyte_char_check(unsigned char s);
-// unsigned char *multibyte_strchr(const unsigned char *string, unsigned int c);\r
-\r
-/* New Type */\r
-\r
-extern int PG_CCST;                /* Client Character StaTus */\r
-\r
-extern int PG_SCSC;                /* Server Character Set (Code) */\r
-extern int PG_CCSC;                /* Client Character Set (Code) */\r
-extern unsigned char *PG_SCSS; /* Server Character Set (String) */\r
-extern unsigned char *PG_CCSS; /* Client Character Set (String) */\r
-\r
-extern void CC_lookup_characterset(ConnectionClass *self);\r
-\r
-extern int pg_CS_stat(int stat,unsigned int charcter,int characterset_code);\r
-extern int pg_CS_code(const unsigned char *stat_string);\r
-extern unsigned char *pg_CS_name(const int code);\r
-\r
-typedef struct pg_CS\r
-{\r
-   unsigned char *name;\r
-   int code;\r
-}pg_CS;\r
-extern pg_CS CS_Table[];\r
-\r
-extern int pg_mbslen(const unsigned char *string);\r
-extern unsigned char *pg_mbschr(const unsigned char *string, unsigned int character);\r
-extern unsigned char *pg_mbsinc( const unsigned char *current );\r
-\r
-/* Old Type Compatible */\r
-#define multibyte_init() (PG_CCST = 0)\r
-#define multibyte_char_check(X) pg_CS_stat(PG_CCST, (unsigned int) X, PG_CCSC)\r
-#define multibyte_strchr(X,Y) pg_mbschr(X,Y)\r
-#define check_client_encoding(X) pg_CS_name(PG_CCSC = pg_CS_code(X))\r
+// unsigned char *multibyte_strchr(const unsigned char *string, unsigned int c);
+
+/* New Type */
+
+extern void CC_lookup_characterset(ConnectionClass *self);
+
+extern int pg_CS_stat(int stat,unsigned int charcter,int characterset_code);
+extern int pg_CS_code(const unsigned char *stat_string);
+extern unsigned char *pg_CS_name(int code);
+
+typedef struct pg_CS
+{
+   unsigned char *name;
+   int code;
+}pg_CS;
+extern int pg_mbslen(int ccsc, const unsigned char *string);
+extern unsigned char *pg_mbschr(int ccsc, const unsigned char *string, unsigned int character);
+extern unsigned char *pg_mbsinc(int ccsc, const unsigned char *current );
+
+/* Old Type Compatible */
+typedef struct
+{
+   int ccsc;
+   const char *encstr;
+   int pos;
+   int ccst;
+} encoded_str;
+#define ENCODE_STATUS(enc) ((enc).ccst)
+
+void encoded_str_constr(encoded_str *encstr, int ccsc, const char *str);
+#define make_encoded_str(encstr, conn, str) encoded_str_constr(encstr, conn->ccsc, str)
+extern int encoded_nextchar(encoded_str *encstr);
+extern int encoded_byte_check(encoded_str *encstr, int abspos);
+#define check_client_encoding(X) pg_CS_name(pg_CS_code(X))
index 0527b21c38b3e34fa2a2219a017d523ccfda01a9..cbb31dad0a729895794320ef1fbe93df451b1c1a 100644 (file)
@@ -174,7 +174,8 @@ SQLError(HENV EnvironmentHandle,
 {
    mylog("[SQLError]");
    return PGAPI_Error(EnvironmentHandle, ConnectionHandle, StatementHandle,
-          Sqlstate, NativeError, MessageText, BufferLength, TextLength);
+          Sqlstate, NativeError, MessageText, BufferLength,
+       TextLength);
 }
 
 RETCODE        SQL_API
@@ -281,23 +282,31 @@ SQLGetInfo(HDBC ConnectionHandle,
           SQLUSMALLINT InfoType, PTR InfoValue,
           SQLSMALLINT BufferLength, SQLSMALLINT *StringLength)
 {
-#if (ODBCVER >= 0x0300)
    RETCODE     ret;
+   ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
 
+   CC_clear_error(conn);
+#if (ODBCVER >= 0x0300)
    mylog("[SQLGetInfo(30)]");
    if ((ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
                             BufferLength, StringLength)) == SQL_ERROR)
    {
        if (((ConnectionClass *) ConnectionHandle)->driver_version >= 0x0300)
-           return PGAPI_GetInfo30(ConnectionHandle, InfoType, InfoValue,
+       {
+           CC_clear_error(conn);
+           ret = PGAPI_GetInfo30(ConnectionHandle, InfoType, InfoValue,
                                   BufferLength, StringLength);
+       }
    }
-   return ret;
+   if (SQL_ERROR == ret)
+       CC_log_error("SQLGetInfo30", "", conn);
 #else
    mylog("[SQLGetInfo]");
-   return PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
-                        BufferLength, StringLength);
+   if (ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
+           BufferLength, StringLength), SQL_ERROR == ret)
+       CC_log_error("PGAPI_GetInfo", "", conn);
 #endif
+   return ret;
 }
 
 RETCODE        SQL_API
@@ -638,7 +647,7 @@ SQLTablePrivileges(
 {
    mylog("[SQLTablePrivileges]");
    return PGAPI_TablePrivileges(hstmt, szCatalogName, cbCatalogName,
-                  szSchemaName, cbSchemaName, szTableName, cbTableName);
+                  szSchemaName, cbSchemaName, szTableName, cbTableName, 0);
 }
 
 RETCODE        SQL_API
index 0bebf5d128c5e0b05ef5ad63c13369e7945500a0..47015a23220cf7275ae927829e7bd4f325bed996 100644 (file)
@@ -25,22 +25,27 @@ RETCODE  SQL_API SQLErrorW(HENV EnvironmentHandle,
            SQLSMALLINT *TextLength)
 {
    RETCODE ret;
-   SWORD   tlen;
+   SWORD   tlen, buflen;
    char    *qst = NULL, *mtxt = NULL;
 
    mylog("[SQLErrorW]");
    if (Sqlstate)
        qst = malloc(8);
-   if (MessageText)
-       mtxt = malloc(BufferLength);    
+   buflen = 0;
+   if (MessageText && BufferLength > 0)
+   {
+       buflen = BufferLength * 3 + 1;
+       mtxt = malloc(buflen);
+   }
    ret = PGAPI_Error(EnvironmentHandle, ConnectionHandle, StatementHandle,
-               qst, NativeError, mtxt, BufferLength, &tlen);
+               qst, NativeError, mtxt, buflen, &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);
+   if (mtxt)
+       free(mtxt);
    return ret;
 }
 
@@ -56,6 +61,7 @@ RETCODE  SQL_API SQLSetConnectOptionW(HDBC ConnectionHandle,
            SQLUSMALLINT Option, SQLUINTEGER Value)
 {
    mylog("[SQLSetConnectionOptionW]");
+if (!ConnectionHandle) return SQL_ERROR;
    ((ConnectionClass *) ConnectionHandle)->unicode = 1;
    return PGAPI_SetConnectOption(ConnectionHandle, Option, Value);
 }
index 2c5e73bf359e5d5845845e430487e2f9cd8424da..6d4ad1f287714ebd7a3728be469ae3203dfd93eb 100644 (file)
@@ -144,9 +144,7 @@ SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle,
        default:
            break;
    }
-   return SQL_ERROR;           /* SQLSTATE HY092 ("Invalid
-                                * attribute/option identifier") */
-
+   return SQL_ERROR;
 }
 
 /* SQLExtendedFetch -> SQLFetchScroll */
@@ -246,39 +244,9 @@ SQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
              SQLINTEGER *NativeError, SQLCHAR *MessageText,
              SQLSMALLINT BufferLength, SQLSMALLINT *TextLength)
 {
-   RETCODE     ret;
-
    mylog("[[SQLGetDiagRec]]\n");
-   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 = SQLGetDiagRec(HandleType, Handle, RecNumber, Sqlstate,
-                           NativeError, MessageText, BufferLength,
-                           TextLength);
-       free(MessageText);
-   }
-   return ret;
+   return PGAPI_GetDiagRec(HandleType, Handle, RecNumber, Sqlstate,
+           NativeError, MessageText, BufferLength, TextLength);
 }
 
 /* new function */
@@ -299,7 +267,7 @@ SQLGetEnvAttr(HENV EnvironmentHandle,
            *((unsigned int *) Value) = SQL_CP_RELAXED_MATCH;
            break;
        case SQL_ATTR_ODBC_VERSION:
-           *((unsigned int *) Value) = SQL_OV_ODBC3;
+           *((unsigned int *) Value) = EN_is_odbc2(env) ? SQL_OV_ODBC2 : SQL_OV_ODBC3;
            break;
        case SQL_ATTR_OUTPUT_NTS:
            *((unsigned int *) Value) = SQL_TRUE;
@@ -456,6 +424,7 @@ ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
 {
    RETCODE     ret = SQL_SUCCESS;
+   PTR     tptr;
    switch (FieldIdentifier)
    {
        case SQL_DESC_ARRAY_SIZE:
@@ -470,8 +439,34 @@ ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        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;
 }
@@ -495,6 +490,26 @@ APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        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; 
    }
@@ -549,6 +564,8 @@ SQLSetDescField(SQLHDESC DescriptorHandle,
    HSTMT       hstmt;
    SQLUINTEGER descType;
    StatementClass *stmt;
+   static const char *func = "SQLSetDescField";
+
    mylog("[[SQLSetDescField]] h=%u rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value);
    hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType);
    mylog("stmt=%x type=%d\n", hstmt, descType);
@@ -569,8 +586,10 @@ SQLSetDescField(SQLHDESC DescriptorHandle,
            break;
        default:ret = SQL_ERROR;
            stmt->errornumber = STMT_INTERNAL_ERROR; 
-           mylog("Error not implemented\n");
+           stmt->errormsg = "Error not implemented";
    }
+   if (ret == SQL_ERROR)
+       SC_log_error(func, "", stmt);
    return ret;
 }
 
@@ -583,6 +602,8 @@ SQLSetDescRec(SQLHDESC DescriptorHandle,
              PTR Data, SQLINTEGER *StringLength,
              SQLINTEGER *Indicator)
 {
+   const char *func = "SQLSetDescField";
+
    mylog("[[SQLSetDescRec]]\n");
    mylog("Error not implemented\n");
    return SQL_ERROR;
@@ -608,7 +629,10 @@ SQLSetEnvAttr(HENV EnvironmentHandle,
            return SQL_SUCCESS;
        case SQL_ATTR_ODBC_VERSION:
            if ((SQLUINTEGER) Value == SQL_OV_ODBC2)
-               return SQL_SUCCESS;
+               EN_set_odbc2(env);
+           else
+               EN_set_odbc3(env);
+           return SQL_SUCCESS;
            break;
        case SQL_ATTR_OUTPUT_NTS:
            if ((SQLUINTEGER) Value == SQL_TRUE)
@@ -652,44 +676,46 @@ SQLSetStmtAttr(HSTMT StatementHandle,
             * case SQL_ATTR_PREDICATE_PTR: case
             * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
             */
-       case SQL_ATTR_PARAM_OPERATION_PTR:      /* 19 */
-       case SQL_ATTR_PARAM_STATUS_PTR:         /* 20 */
-       case SQL_ATTR_ROW_OPERATION_PTR:        /* 24 */
            stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
            stmt->errormsg = "Unsupported statement option (Set)";
            SC_log_error(func, "", stmt);
            return SQL_ERROR;
 
-       case SQL_ATTR_PARAM_BIND_OFFSET_PTR:    /* 17 */
-           stmt->options.param_offset_ptr = (SQLUINTEGER *) Value;
-           break;
-       case SQL_ATTR_ROW_BIND_OFFSET_PTR:      /* 23 */
-           stmt->options.row_offset_ptr = (SQLUINTEGER *) Value;
-           break;
-
        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);
@@ -704,7 +730,7 @@ SQLSetStmtAttr(HSTMT StatementHandle,
 RETCODE        SQL_API
 PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
 {
-   ConnectionClass *conn = (ConnectionClass *) hdbc;
+   ConnectionClass *conn = (ConnectionClass *) hdbc;
    ConnInfo    *ci = &(conn->connInfo);
 
    if (fFunction != SQL_API_ODBC3_ALL_FUNCTIONS)
@@ -755,17 +781,14 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
    SQL_FUNC_ESET(pfExists, SQL_API_SQLPARAMDATA);      /* 48 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLPUTDATA);        /* 49 */
 
-   /*
-    * SQL_FUNC_ESET(pfExists, SQL_API_SQLSETCONNECTIONOPTION); 50
-    * deprecated
-    */
+   /* SQL_FUNC_ESET(pfExists, SQL_API_SQLSETCONNECTIONOPTION); 50 deprecated */
    /* SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSTMTOPTION); 51 deprecated */
-   SQL_FUNC_ESET(pfExists, SQL_API_SQLSPECIALCOLUMNS); /* 52 */
+   SQL_FUNC_ESET(pfExists, SQL_API_SQLSPECIALCOLUMNS); /* 52 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSTATISTICS);     /* 53 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLES); /* 54 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLBROWSECONNECT);  /* 55 */
    if (ci->drivers.lie)
-       SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); /* 56 not implmented yet */
+       SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); /* 56 not implemented yet */ 
    SQL_FUNC_ESET(pfExists, SQL_API_SQLDATASOURCES);    /* 57 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBEPARAM);  /* 58 */
    /* SQL_FUNC_ESET(pfExists, SQL_API_SQLEXTENDEDFETCH); 59 deprecated */
@@ -781,12 +804,11 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
    /* SQL_FUNC_ESET(pfExists, SQL_API_SQLPARAMOPTIONS); 64 deprecated */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLPRIMARYKEYS);    /* 65 */
    if (ci->drivers.lie)
-       SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURECOLUMNS); /* 66 not implmented yet */
+       SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURECOLUMNS); /* 66 not implemeted yet */ 
    SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURES);     /* 67 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSETPOS);     /* 68 */
-   SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSCROLLOPTIONS);       /* 69 deprecated */
-   if (ci->drivers.lie)
-       SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLEPRIVILEGES); /* 70 not implemented yet */
+   /* SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSCROLLOPTIONS); 69 deprecated */
+   SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLEPRIVILEGES);        /* 70 */
    /* SQL_FUNC_ESET(pfExists, SQL_API_SQLDRIVERS); */  /* 71 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLBINDPARAMETER);  /* 72 */
 
@@ -801,7 +823,7 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
    if (ci->drivers.lie)
    {
        SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCFIELD); /* 1008 not implemented yet */
-       SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCREC); /* 1009 not implemented yet */
+       SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCREC); /* 1009 not implemented yet */
        SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGFIELD); /* 1010 not implemented yet */
    }
    SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGREC);     /* 1011 */
@@ -810,7 +832,9 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSETCONNECTATTR); /* 1016 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSETDESCFIELD);   /* 1017 */
    if (ci->drivers.lie)
-       SQL_FUNC_ESET(pfExists, SQL_API_SQLSETDESCREC); /* 1018 not implemented yet */
+   {
+       SQL_FUNC_ESET(pfExists, SQL_API_SQLSETDESCREC); /* 1018 not implemented yet */
+   }
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSETENVATTR);     /* 1019 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSTMTATTR);    /* 1020 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLFETCHSCROLL);    /* 1021 */
index d2a2005c1b9f47cad12d8bb6d65850f4fdbb2dc5..35237202faa7cbf47ef2113b913f3e111541e7f5 100644 (file)
@@ -85,22 +85,37 @@ RETCODE SQL_API SQLGetDiagRecW(SWORD fHandleType,
        SQLSMALLINT *pcbErrorMsg)
 {
    RETCODE ret;
-        SWORD   tlen;
-        char    *qst = NULL, *mtxt = NULL;
+        SWORD   buflen, tlen;
+        char    *qstr = 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);
+                qstr = malloc(8);
+   buflen = 0;
+        if (szErrorMsg && cbErrorMsgMax > 0)
+   {
+       buflen = cbErrorMsgMax;
+                mtxt = malloc(buflen);
+   }
+        ret = PGAPI_GetDiagRec(fHandleType, handle, iRecord, qstr,
+                pfNativeError, mtxt, buflen, &tlen);
+   if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
+   {
+           if (qstr)
+                   utf8_to_ucs2(qstr, strlen(qstr), szSqlState, 6);
+       if (mtxt && tlen <= cbErrorMsgMax)
+       {
+               tlen = utf8_to_ucs2(mtxt, tlen, szErrorMsg, cbErrorMsgMax);
+           if (tlen >= cbErrorMsgMax)
+               ret = SQL_SUCCESS_WITH_INFO;
+       }
+       if (pcbErrorMsg)
+               *pcbErrorMsg = tlen;
+   }
+        if (qstr);
+           free(qstr);
+   if (mtxt)
+           free(mtxt);
         return ret;
 }
 
index 637f69f9699c2277cebf7b19c3d969fb5c84986d..ac1e3f28f4e9e8099d4bbdcb724488b1d6f888a6 100755 (executable)
@@ -13,7 +13,7 @@
            SQLPrepareW, SQLPrimaryKeysW, SQLProcedureColumnsW,
            SQLProceduresW, SQLSetCursorNameW,
            SQLSpecialColumnsW, SQLStatisticsW, SQLTablesW,
-           SQLTablePrivilegesW
+           SQLTablePrivilegesW, SQLGetTypeInfoW
  *-------
  */
 
@@ -102,7 +102,11 @@ RETCODE SQL_API SQLDriverConnectW(HDBC hdbc,
    ret = PGAPI_DriverConnect(hdbc, hwnd, szIn, (SWORD) inlen,
        szOut, cbConnStrOutMax, &olen, fDriverCompletion);
    if (ret != SQL_ERROR)
-       *pcbConnStrOut = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
+   {
+       UInt4 outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
+       if (pcbConnStrOut)
+           *pcbConnStrOut = outlen;
+   }
    free(szOut);
    if (szIn);
        free(szIn);
@@ -129,7 +133,11 @@ RETCODE SQL_API SQLBrowseConnectW(
    ret = PGAPI_BrowseConnect(hdbc, szIn, (SWORD) inlen,
        szOut, cbConnStrOutMax, &olen);
    if (ret != SQL_ERROR)
-       *pcbConnStrOut = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
+   {
+       UInt4   outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
+       if (pcbConnStrOut)
+           *pcbConnStrOut = outlen;
+   }
    free(szOut);
    if (szIn);
        free(szIn);
@@ -158,15 +166,28 @@ RETCODE  SQL_API SQLDescribeColW(HSTMT StatementHandle,
            SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable)
 {
    RETCODE ret;
-   SWORD   nmlen;
+   SWORD   buflen, nmlen;
    char    *clName;
 
    mylog("[SQLDescribeColW]");
-   clName = malloc(BufferLength);
+   buflen = BufferLength * 3 + 1;
+   clName = malloc(buflen);
    ret = PGAPI_DescribeCol(StatementHandle, ColumnNumber,
-       clName, BufferLength, &nmlen,
-               DataType, ColumnSize, DecimalDigits, Nullable);
-   *NameLength = utf8_to_ucs2(clName, nmlen, ColumnName, BufferLength);
+       clName, buflen, &nmlen, DataType, ColumnSize,
+       DecimalDigits, Nullable);
+   if (ret == SQL_SUCCESS)
+   {
+       UInt4   nmcount = utf8_to_ucs2(clName, nmlen, ColumnName, BufferLength);
+       if (nmcount > (UInt4) BufferLength)
+       {
+           StatementClass  *stmt = (StatementClass *) StatementHandle;
+           ret = SQL_SUCCESS_WITH_INFO;
+           stmt->errornumber = STMT_TRUNCATED;
+           stmt->errormsg = "Column name too large";
+       }
+       if (NameLength)
+           *NameLength = nmcount;
+   }
    free(clName); 
    return ret;
 }
@@ -192,13 +213,25 @@ RETCODE  SQL_API SQLGetCursorNameW(HSTMT StatementHandle,
 {
    RETCODE ret;
    char    *crName;
-   SWORD   clen;
+   SWORD   clen, buflen;
 
    mylog("[SQLGetCursorNameW]");
-   crName = malloc(BufferLength);
-   ret = PGAPI_GetCursorName(StatementHandle, crName, BufferLength,
-               &clen);
-   *NameLength = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength);
+   buflen = BufferLength * 3 + 1;
+   crName = malloc(buflen);
+   ret = PGAPI_GetCursorName(StatementHandle, crName, buflen, &clen);
+   if (ret == SQL_SUCCESS) 
+   {
+       UInt4   nmcount = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength);
+       if (nmcount > (UInt4) BufferLength)
+       {
+           StatementClass *stmt = (StatementClass *) StatementHandle;
+           ret = SQL_SUCCESS_WITH_INFO;
+           stmt->errornumber = STMT_TRUNCATED;
+           stmt->errormsg = "Cursor name too large";
+       }
+       if (NameLength)
+           *NameLength = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength);
+   }
    free(crName);
    return ret;
 }
@@ -207,23 +240,33 @@ RETCODE  SQL_API SQLGetInfoW(HDBC ConnectionHandle,
            SQLUSMALLINT InfoType, PTR InfoValue,
            SQLSMALLINT BufferLength, SQLSMALLINT *StringLength)
 {
+   ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
    RETCODE ret;
-   ((ConnectionClass *) ConnectionHandle)->unicode = 1;
+
+   conn->unicode = 1;
+   CC_clear_error(conn);
 #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,
+       if (conn->driver_version >= 0x0300)
+       {
+           CC_clear_error(conn);
+           ret = PGAPI_GetInfo30(ConnectionHandle, InfoType, InfoValue,
                        BufferLength, StringLength);
+       }
    }
-   return ret;
+   if (SQL_ERROR == ret)
+       CC_log_error("SQLGetInfoW(30)", "", conn);
 #else
    mylog("[SQLGetInfoW]");
-   return PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
+   ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
                BufferLength, StringLength);
+   if (SQL_ERROR == ret)
+       CC_log_error("SQLGetInfoW", "", conn);
 #endif
+   return ret;
 }
 
 RETCODE  SQL_API SQLPrepareW(HSTMT StatementHandle,
@@ -428,17 +471,31 @@ RETCODE SQL_API SQLNativeSqlW(
    RETCODE     ret;
    char        *szIn, *szOut;
    UInt4       slen;
-   SQLINTEGER  olen;
+   SQLINTEGER  buflen, olen;
 
    mylog("[SQLNativeSqlW]");
    ((ConnectionClass *) hdbc)->unicode = 1;
    szIn = ucs2_to_utf8(szSqlStrIn, cbSqlStrIn, &slen);
-   szOut = malloc(cbSqlStrMax);
+   buflen = 3 * cbSqlStrMax + 1;
+   szOut = malloc(buflen);
    ret = PGAPI_NativeSql(hdbc, szIn, (SQLINTEGER) slen,
-       szOut, cbSqlStrMax, &olen);
+       szOut, buflen, &olen);
    if (szIn);
        free(szIn);
-   *pcbSqlStr = utf8_to_ucs2(szOut, olen, szSqlStr, cbSqlStrMax);
+   if (ret == SQL_SUCCESS)
+   {
+       UInt4   szcount = utf8_to_ucs2(szOut, olen, szSqlStr, cbSqlStrMax);
+       if (szcount > (UInt4) cbSqlStrMax)
+       {
+           ConnectionClass *conn = (ConnectionClass *) hdbc;
+
+           ret = SQL_SUCCESS_WITH_INFO;
+           conn->errornumber = CONN_TRUNCATED;
+           conn->errormsg = "Sql string too large";
+       }
+       if (pcbSqlStr)
+           *pcbSqlStr = szcount;
+   }
    free(szOut);
    return ret;
 }
@@ -560,3 +617,10 @@ RETCODE SQL_API SQLTablePrivilegesW(
        free(tbName);
    return ret;
 }
+
+RETCODE SQL_API    SQLGetTypeInfoW(
+       SQLHSTMT    StatementHandle,
+       SQLSMALLINT DataType)
+{
+   return PGAPI_GetTypeInfo(StatementHandle, DataType);
+}
index 80ec7dac68ecd9b1715f319cb8f84b7d5821db63..d58f84916fc0b8086675882415be48b62a45bde5 100644 (file)
@@ -342,12 +342,13 @@ PGAPI_SetConnectOption(
            break;
 
        case SQL_AUTOCOMMIT:
-           if (vParam == SQL_AUTOCOMMIT_ON && CC_is_in_autocommit(conn))
+           if (vParam == SQL_AUTOCOMMIT_ON && CC_is_in_trans(conn))
                break;
-           else if (vParam == SQL_AUTOCOMMIT_OFF && !CC_is_in_autocommit(conn))
+           else if (vParam == SQL_AUTOCOMMIT_OFF && !CC_is_in_trans(conn))
                break;
            if (CC_is_in_trans(conn))
                CC_commit(conn);
+
            mylog("PGAPI_SetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam);
 
            switch (vParam)
@@ -401,8 +402,21 @@ PGAPI_SetConnectOption(
                sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
                if (fOption == 30002 && vParam)
                {
-                   if (strcmp((char *) vParam, "Microsoft Jet") == 0)
+                   int cmp;
+#ifdef UNICODE_SUPPORT
+                   char *asPara;
+                   if (conn->unicode)
+                   {
+                       asPara = ucs2_to_utf8((SQLWCHAR *) vParam, -1, NULL);
+                       cmp = strcmp(asPara, "Microsoft Jet");
+                       free(asPara);
+                   }
+                   else
+#endif /* UNICODE_SUPPORT */
+                   cmp = strncmp((char *) vParam, "Microsoft Jet", 13);
+                   if (0 == cmp)
                    {
+                       mylog("Microsoft Jet !!!!\n");
                        conn->errornumber = 0;
                        conn->ms_jet = 1;
                        return SQL_SUCCESS;
@@ -456,7 +470,7 @@ PGAPI_GetConnectOption(
 
        case SQL_CURRENT_QUALIFIER:     /* don't use qualifiers */
            if (pvParam)
-               strcpy(pvParam, "");
+               ((char *) pvParam)[0] = ((char *) pvParam)[1] = '\0';
 
            break;
 
@@ -557,7 +571,7 @@ PGAPI_GetStmtOption(
        case SQL_GET_BOOKMARK:
        case SQL_ROW_NUMBER:
 
-           res = stmt->result;
+           res = SC_get_Curres(stmt);
 
            if (stmt->manual_result || !ci->drivers.use_declarefetch)
            {
index 525fb736fdf611677ee7814dfdfaa5944345abfa..55bb08bd93b44ccb661265f590f2375cdb591d84 100644 (file)
 #define TAB_INCR   8
 #define COL_INCR   16
 
+#ifdef MULTIBYTE
+char      *getNextToken(int ccsc, char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
+#else
 char      *getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
+#endif /* MULTIBYTE */
 void       getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
 char       searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
 
 
 char *
-getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
+getNextToken(
+#ifdef MULTIBYTE
+   int ccsc, /* client encoding */
+#endif /* MULTIBYTE */
+   char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
 {
    int         i = 0;
    int         out = 0;
    char        qc,
                in_escape = FALSE;
+#ifdef MULTIBYTE
+   encoded_str encstr;
+#endif
 
    if (smax <= 1)
        return NULL;
@@ -80,17 +91,22 @@ getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dqu
    if (numeric)
        *numeric = FALSE;
 
+#ifdef MULTIBYTE
+   encoded_str_constr(&encstr, ccsc, &s[i]);
+#endif
    /* get the next token */
-   while (!isspace((unsigned char) s[i]) && s[i] != ',' &&
-          s[i] != '\0' && out != smax)
+   while (s[i] != '\0' && out < smax)
    {
 #ifdef MULTIBYTE
-       if (multibyte_char_check(s[i]) != 0)
+       encoded_nextchar(&encstr);
+       if (ENCODE_STATUS(encstr) != 0)
        {
            token[out++] = s[i++];
            continue;
        }
 #endif
+       if (isspace((unsigned char) s[i]) || s[i] == ',')
+           break;
        /* Handle quoted stuff */
        if (out == 0 && (s[i] == '\"' || s[i] == '\''))
        {
@@ -110,7 +126,8 @@ getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dqu
            while (s[i] != '\0' && out != smax)
            {
 #ifdef MULTIBYTE
-               if (multibyte_char_check(s[i]) != 0)
+               encoded_nextchar(&encstr);
+               if (ENCODE_STATUS(encstr) != 0)
                {
                    token[out++] = s[i++];
                    continue;
@@ -197,22 +214,22 @@ getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dqu
 
 
 #if 0
-QR_set_num_fields(stmt->result, 14);
-QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(stmt->result, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
-QR_set_field_info(stmt->result, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(stmt->result, 6, "PRECISION", PG_TYPE_INT4, 4);
-QR_set_field_info(stmt->result, 7, "LENGTH", PG_TYPE_INT4, 4);
-QR_set_field_info(stmt->result, 8, "SCALE", PG_TYPE_INT2, 2);
-QR_set_field_info(stmt->result, 9, "RADIX", PG_TYPE_INT2, 2);
-QR_set_field_info(stmt->result, 10, "NULLABLE", PG_TYPE_INT2, 2);
-QR_set_field_info(stmt->result, 11, "REMARKS", PG_TYPE_TEXT, 254);
+QR_set_num_fields(SC_get_Curres(stmt), 14);
+QR_set_field_info(SC_get_Curres(stmt), 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
+QR_set_field_info(SC_get_Curres(stmt), 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
+QR_set_field_info(SC_get_Curres(stmt), 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+QR_set_field_info(SC_get_Curres(stmt), 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+QR_set_field_info(SC_get_Curres(stmt), 4, "DATA_TYPE", PG_TYPE_INT2, 2);
+QR_set_field_info(SC_get_Curres(stmt), 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
+QR_set_field_info(SC_get_Curres(stmt), 6, "PRECISION", PG_TYPE_INT4, 4);
+QR_set_field_info(SC_get_Curres(stmt), 7, "LENGTH", PG_TYPE_INT4, 4);
+QR_set_field_info(SC_get_Curres(stmt), 8, "SCALE", PG_TYPE_INT2, 2);
+QR_set_field_info(SC_get_Curres(stmt), 9, "RADIX", PG_TYPE_INT2, 2);
+QR_set_field_info(SC_get_Curres(stmt), 10, "NULLABLE", PG_TYPE_INT2, 2);
+QR_set_field_info(SC_get_Curres(stmt), 11, "REMARKS", PG_TYPE_TEXT, 254);
 /* User defined fields */
-QR_set_field_info(stmt->result, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
-QR_set_field_info(stmt->result, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
+QR_set_field_info(SC_get_Curres(stmt), 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
+QR_set_field_info(SC_get_Curres(stmt), 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
 #endif
 
 void
@@ -312,9 +329,10 @@ parse_statement(StatementClass *stmt)
    stmt->ntab = 0;
 
 #ifdef MULTIBYTE
-   multibyte_init();
-#endif
+   while (pptr = ptr, (ptr = getNextToken(conn->ccsc, pptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL)
+#else
    while (pptr = ptr, (ptr = getNextToken(pptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL)
+#endif
    {
        unquoted = !(quote || dquote);
 
@@ -607,12 +625,17 @@ parse_statement(StatementClass *stmt)
                if (!dquote)
                {
                    char       *ptr;
+#ifdef MULTIBYTE
+                   encoded_str encstr;
+                   make_encoded_str(&encstr, conn, ti[stmt->ntab]->name);
+#endif   /* MULTIBYTE */
 
                    /* lower case table name */
                    for (ptr = ti[stmt->ntab]->name; *ptr; ptr++)
                    {
 #ifdef MULTIBYTE
-                       if ((unsigned char) *ptr >= 0x80)
+                       encoded_nextchar(&encstr);
+                       if (ENCODE_STATUS(encstr) != 0)
                            ptr++;
                        else
 #endif   /* MULTIBYTE */
@@ -773,13 +796,13 @@ parse_statement(StatementClass *stmt)
                 * structure
                 */
                strcpy(conn->col_info[conn->ntables]->name, ti[i]->name);
-               conn->col_info[conn->ntables]->result = col_stmt->result;
+               conn->col_info[conn->ntables]->result = SC_get_Curres(col_stmt);
 
                /*
                 * The connection will now free the result structures, so
                 * make sure that the statement doesn't free it
                 */
-               col_stmt->result = NULL;
+               SC_set_Result(col_stmt, NULL);
 
                conn->ntables++;
 
index 9ee8c58983b775e62c4a48d0c65f756c1ec7a0bd..6e4c575e31ed6ac7d32a6da08b0df53a75aa3509 100644 (file)
@@ -36,37 +36,92 @@ PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
    RETCODE     ret;
    static const char *func = "PGAPI_GetDiagRec";
 
-   mylog("%s entering ", func);
+   mylog("%s entering rec=%d", func, RecNumber);
    switch (HandleType)
    {
        case SQL_HANDLE_ENV:
-           ret = PGAPI_Error(Handle, NULL, NULL, Sqlstate, NativeError,
-                             MessageText, BufferLength, TextLength);
+           ret = PGAPI_EnvError(Handle, RecNumber, Sqlstate,
+                   NativeError, MessageText,
+                   BufferLength, TextLength, 0);
            break;
        case SQL_HANDLE_DBC:
-           ret = PGAPI_Error(NULL, Handle, NULL, Sqlstate, NativeError,
-                             MessageText, BufferLength, TextLength);
+           ret = PGAPI_ConnectError(Handle, RecNumber, Sqlstate,
+                   NativeError, MessageText, BufferLength,
+                   TextLength, 0);
            break;
        case SQL_HANDLE_STMT:
-           ret = PGAPI_Error(NULL, NULL, Handle, Sqlstate, NativeError,
-                             MessageText, BufferLength, TextLength);
+           ret = PGAPI_StmtError(Handle, RecNumber, Sqlstate,
+                   NativeError, MessageText, BufferLength,
+                   TextLength, 0);
            break;
        default:
            ret = SQL_ERROR;
    }
-   if (ret == SQL_SUCCESS_WITH_INFO &&
-       BufferLength == 0 &&
-       *TextLength)
-   {
-       SQLSMALLINT BufferLength = *TextLength + 4;
-       SQLCHAR    *MessageText = malloc(BufferLength);
+   mylog("%s exiting %d\n", func, ret);
+   return ret;
+}
+
+RETCODE        SQL_API
+PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
+       SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier,
+       PTR DiagInfoPtr, SQLSMALLINT BufferLength,
+       SQLSMALLINT *StringLengthPtr)
+{
+   RETCODE     ret = SQL_SUCCESS;
+   static const char *func = "PGAPI_GetDiagField";
 
-       ret = PGAPI_GetDiagRec(HandleType, Handle, RecNumber, Sqlstate,
-                           NativeError, MessageText, BufferLength,
-                           TextLength);
-       free(MessageText);
+   mylog("%s entering rec=%d", func, RecNumber);
+   switch (HandleType)
+   {
+       case SQL_HANDLE_ENV:
+           switch (DiagIdentifier)
+           {
+               case SQL_DIAG_CLASS_ORIGIN:
+               case SQL_DIAG_SUBCLASS_ORIGIN:
+               case SQL_DIAG_CONNECTION_NAME:
+               case SQL_DIAG_MESSAGE_TEXT:
+               case SQL_DIAG_NATIVE:
+               case SQL_DIAG_NUMBER:
+               case SQL_DIAG_RETURNCODE:
+               case SQL_DIAG_SERVER_NAME:
+               case SQL_DIAG_SQLSTATE:
+                   break;
+           }
+           break;
+       case SQL_HANDLE_DBC:
+           switch (DiagIdentifier)
+           {
+               case SQL_DIAG_CLASS_ORIGIN:
+               case SQL_DIAG_SUBCLASS_ORIGIN:
+               case SQL_DIAG_CONNECTION_NAME:
+               case SQL_DIAG_MESSAGE_TEXT:
+               case SQL_DIAG_NATIVE:
+               case SQL_DIAG_NUMBER:
+               case SQL_DIAG_RETURNCODE:
+               case SQL_DIAG_SERVER_NAME:
+               case SQL_DIAG_SQLSTATE:
+                   break;
+           }
+           break;
+       case SQL_HANDLE_STMT:
+           switch (DiagIdentifier)
+           {
+               case SQL_DIAG_CLASS_ORIGIN:
+               case SQL_DIAG_SUBCLASS_ORIGIN:
+               case SQL_DIAG_CONNECTION_NAME:
+               case SQL_DIAG_MESSAGE_TEXT:
+               case SQL_DIAG_NATIVE:
+               case SQL_DIAG_NUMBER:
+               case SQL_DIAG_RETURNCODE:
+               case SQL_DIAG_SERVER_NAME:
+               case SQL_DIAG_SQLSTATE:
+                   break;
+           }
+           break;
+       default:
+           ret = SQL_ERROR;
    }
-mylog("%s exiting\n", func);
+   mylog("%s exiting %d\n", func, ret);
    return ret;
 }
 
@@ -87,7 +142,7 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
        case SQL_ATTR_CONNECTION_TIMEOUT:
        case SQL_ATTR_METADATA_ID:
            conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
-           conn->errormsg = "Unsupported connection option (Set)";
+           conn->errormsg = "Unsupported connect attribute (Get)";
            return SQL_ERROR;
    }
    return PGAPI_GetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
@@ -373,7 +428,7 @@ PGAPI_SetConnectAttr(HDBC ConnectionHandle,
        case SQL_ATTR_CONNECTION_TIMEOUT:
        case SQL_ATTR_METADATA_ID:
            conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
-           conn->errormsg = "Unsupported connection option (Set)";
+           conn->errormsg = "Unsupported connect attribute (Set)";
            return SQL_ERROR;
    }
    return PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
index 3117a6dc379a69e4ecbf3d03b05f20d6fd73994f..f7a72a28e4339ee1948cefc8f89a2c51c9791c4f 100644 (file)
@@ -11,6 +11,8 @@
 #include <string.h>
 
 #define    PODBC_NOT_SEARCH_PATTERN    1L
+#define    PODBC_ALLOW_PARTIAL_EXTRACT 1L
+#define    PODBC_ERROR_CLEAR       (1L << 1)
 
 RETCODE SQL_API PGAPI_AllocConnect(HENV EnvironmentHandle,
                   HDBC FAR * ConnectionHandle);
@@ -56,6 +58,20 @@ RETCODE SQL_API PGAPI_Error(HENV EnvironmentHandle,
            SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
            SQLCHAR *MessageText, SQLSMALLINT BufferLength,
            SQLSMALLINT *TextLength);
+/* Helper functions for Error handling */
+RETCODE SQL_API PGAPI_EnvError(HENV EnvironmentHandle, SWORD RecNumber,
+           SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+           SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+           SQLSMALLINT *TextLength, UWORD flag);
+RETCODE SQL_API PGAPI_ConnectError(HDBC ConnectionHandle, SWORD RecNumber,
+           SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+           SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+           SQLSMALLINT *TextLength, UWORD flag);
+RETCODE SQL_API PGAPI_StmtError(HSTMT StatementHandle, SWORD RecNumber,
+           SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+           SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+           SQLSMALLINT *TextLength, UWORD flag);
+
 RETCODE SQL_API PGAPI_ExecDirect(HSTMT StatementHandle,
                 SQLCHAR *StatementText, SQLINTEGER TextLength);
 RETCODE SQL_API PGAPI_Execute(HSTMT StatementHandle);
@@ -225,7 +241,8 @@ RETCODE SQL_API PGAPI_TablePrivileges(
                      SQLCHAR *szSchemaName,
                      SQLSMALLINT cbSchemaName,
                      SQLCHAR *szTableName,
-                     SQLSMALLINT cbTableName);
+                     SQLSMALLINT cbTableName,
+                     UWORD flag);
 RETCODE SQL_API PGAPI_BindParameter(
                    HSTMT hstmt,
                    SQLUSMALLINT ipar,
@@ -243,4 +260,25 @@ RETCODE SQL_API PGAPI_SetScrollOptions(
                       SDWORD crowKeyset,
                       UWORD crowRowset);
 
+#if (ODBCVER >= 0x0300)
+RETCODE SQL_API PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
+       SQLSMALLINT RecNumber, SQLCHAR *Sqlstate,
+       SQLINTEGER *NativeError, SQLCHAR *MessageText,
+       SQLSMALLINT BufferLength, SQLSMALLINT *TextLength);
+RETCODE SQL_API PGAPI_GetConnectAttr(HDBC ConnectionHandle,
+           SQLINTEGER Attribute, PTR Value,
+           SQLINTEGER BufferLength, SQLINTEGER *StringLength);
+RETCODE SQL_API PGAPI_GetStmtAttr(HSTMT StatementHandle,
+       SQLINTEGER Attribute, PTR Value,
+       SQLINTEGER BufferLength, SQLINTEGER *StringLength);
+RETCODE SQL_API PGAPI_SetConnectAttr(HDBC ConnectionHandle,
+           SQLINTEGER Attribute, PTR Value,
+           SQLINTEGER StringLength);
+RETCODE SQL_API PGAPI_SetStmtAttr(HSTMT StatementHandle,
+       SQLINTEGER Attribute, PTR Value,
+       SQLINTEGER StringLength);
+RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle,
+           SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
+           PTR Value, SQLINTEGER BufferLength);
+#endif /* ODBCVER */
 #endif   /* define_PG_API_FUNC_H__ */
index be822a2eb4da18b1103b91930c510ebc5f8893ee..8cade89b73f9f87d55d51a8a98f0bbbe37e16f76 100644 (file)
@@ -21,6 +21,7 @@
 #include "dlg_specific.h"
 #include "statement.h"
 #include "connection.h"
+#include "environ.h"
 #include "qresult.h"
 
 
@@ -90,15 +91,26 @@ Int2        sqlTypes[] = {
    SQL_TINYINT,
    SQL_VARBINARY,
    SQL_VARCHAR,
+#ifdef UNICODE_SUPPORT
+   SQL_WCHAR,
+   SQL_WVARCHAR,
+   SQL_WLONGVARCHAR,
+#endif /* UNICODE_SUPPORT */
    0
 };
 
+#if (ODBCVER >= 0x0300) && defined(OBDCINT64)
+#define    ALLOWED_C_BIGINT    SQL_C_SBIGINT
+#else
+#define    ALLOWED_C_BIGINT    SQL_C_CHAR
+#endif
 
 Int4
 sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
 {
    Int4        pgType;
-   ConnInfo   *ci = &(SC_get_conn(stmt)->connInfo);
+   ConnectionClass *conn = SC_get_conn(stmt);
+   ConnInfo    *ci = &(conn->connInfo);
 
    switch (fSqlType)
    {
@@ -110,11 +122,20 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
            pgType = PG_TYPE_BPCHAR;
            break;
 
+#ifdef UNICODE_SUPPORT
+       case SQL_WCHAR:
+           pgType = PG_TYPE_BPCHAR;
+           break;
+#endif /* UNICODE_SUPPORT */
+
        case SQL_BIT:
            pgType = ci->drivers.bools_as_char ? PG_TYPE_CHAR : PG_TYPE_BOOL;
            break;
 
        case SQL_DATE:
+#if (ODBCVER >= 0x0300)
+       case SQL_TYPE_DATE:
+#endif /* ODBCVER */
            pgType = PG_TYPE_DATE;
            break;
 
@@ -144,6 +165,12 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
            pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
            break;
 
+#ifdef UNICODE_SUPPORT
+       case SQL_WLONGVARCHAR:
+           pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
+           break;
+#endif /* UNICODE_SUPPORT */
+
        case SQL_REAL:
            pgType = PG_TYPE_FLOAT4;
            break;
@@ -154,10 +181,16 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
            break;
 
        case SQL_TIME:
+#if (ODBCVER >= 0x0300)
+       case SQL_TYPE_TIME:
+#endif /* ODBCVER */
            pgType = PG_TYPE_TIME;
            break;
 
        case SQL_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
+       case SQL_TYPE_TIMESTAMP:
+#endif /* ODBCVER */
            pgType = PG_TYPE_DATETIME;
            break;
 
@@ -169,6 +202,12 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
            pgType = PG_TYPE_VARCHAR;
            break;
 
+#if    UNICODE_SUPPORT
+       case SQL_WVARCHAR:
+           pgType = PG_TYPE_VARCHAR;
+           break;
+#endif /* UNICODE_SUPPORT */
+
        default:
            pgType = 0;         /* ??? */
            break;
@@ -193,7 +232,9 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
 Int2
 pgtype_to_sqltype(StatementClass *stmt, Int4 type)
 {
-   ConnInfo   *ci = &(SC_get_conn(stmt)->connInfo);
+   ConnectionClass *conn = SC_get_conn(stmt);
+   ConnInfo    *ci = &(conn->connInfo);
+   EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
 
    switch (type)
    {
@@ -204,6 +245,19 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
        case PG_TYPE_NAME:
            return SQL_CHAR;
 
+#ifdef UNICODE_SUPPORT
+       case PG_TYPE_BPCHAR:
+           return conn->unicode ? SQL_WCHAR : SQL_CHAR;
+
+       case PG_TYPE_VARCHAR:
+           return conn->unicode ? SQL_WVARCHAR : SQL_VARCHAR;
+
+       case PG_TYPE_TEXT:
+           return ci->drivers.text_as_longvarchar ? 
+               (conn->unicode ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR) :
+               (conn->unicode ? SQL_WVARCHAR : SQL_VARCHAR);
+
+#else
        case PG_TYPE_BPCHAR:
            return SQL_CHAR;
 
@@ -212,6 +266,7 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
 
        case PG_TYPE_TEXT:
            return ci->drivers.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
+#endif /* UNICODE_SUPPORT */
 
        case PG_TYPE_BYTEA:
            return SQL_VARBINARY;
@@ -229,10 +284,10 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
            /* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */
        case PG_TYPE_INT8:
 #if (ODBCVER >= 0x0300)
-           return SQL_BIGINT;
-#else
-           return SQL_CHAR;
+           if (!conn->ms_jet)
+               return SQL_BIGINT;
 #endif /* ODBCVER */
+           return SQL_CHAR;
 
        case PG_TYPE_NUMERIC:
            return SQL_NUMERIC;
@@ -242,12 +297,24 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
        case PG_TYPE_FLOAT8:
            return SQL_FLOAT;
        case PG_TYPE_DATE:
+#if (ODBCVER >= 0x0300)
+           if (EN_is_odbc3(env))
+               return SQL_TYPE_DATE;
+#endif /* ODBCVER */
            return SQL_DATE;
        case PG_TYPE_TIME:
+#if (ODBCVER >= 0x0300)
+           if (EN_is_odbc3(env))
+               return SQL_TYPE_TIME;
+#endif /* ODBCVER */
            return SQL_TIME;
        case PG_TYPE_ABSTIME:
        case PG_TYPE_DATETIME:
        case PG_TYPE_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
+           if (EN_is_odbc3(env))
+               return SQL_TYPE_TIMESTAMP;
+#endif /* ODBCVER */
            return SQL_TIMESTAMP;
        case PG_TYPE_MONEY:
            return SQL_FLOAT;
@@ -273,16 +340,18 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
 Int2
 pgtype_to_ctype(StatementClass *stmt, Int4 type)
 {
-   ConnInfo   *ci = &(SC_get_conn(stmt)->connInfo);
+   ConnectionClass *conn = SC_get_conn(stmt);
+   ConnInfo    *ci = &(conn->connInfo);
+   EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
 
    switch (type)
    {
        case PG_TYPE_INT8:
 #if (ODBCVER >= 0x0300)
-           return SQL_C_SBIGINT;
-#else
+           if (!conn->ms_jet)
+               return ALLOWED_C_BIGINT;
+#endif /* ODBCVER */
            return SQL_C_CHAR;
-#endif
        case PG_TYPE_NUMERIC:
            return SQL_C_CHAR;
        case PG_TYPE_INT2:
@@ -297,24 +366,24 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
            return SQL_C_DOUBLE;
        case PG_TYPE_DATE:
 #if (ODBCVER >= 0x0300)
-           return SQL_C_TYPE_DATE;
-#else
-           return SQL_C_DATE;
+           if (EN_is_odbc3(env))
+               return SQL_C_TYPE_DATE;
 #endif /* ODBCVER */
+           return SQL_C_DATE;
        case PG_TYPE_TIME:
 #if (ODBCVER >= 0x0300)
-           return SQL_C_TYPE_TIME;
-#else
-           return SQL_C_TIME;
+           if (EN_is_odbc3(env))
+               return SQL_C_TYPE_TIME;
 #endif /* ODBCVER */
+           return SQL_C_TIME;
        case PG_TYPE_ABSTIME:
        case PG_TYPE_DATETIME:
        case PG_TYPE_TIMESTAMP:
 #if (ODBCVER >= 0x0300)
-           return SQL_C_TYPE_TIMESTAMP;
-#else
-           return SQL_C_TIMESTAMP;
+           if (EN_is_odbc3(env))
+               return SQL_C_TYPE_TIMESTAMP;
 #endif /* ODBCVER */
+           return SQL_C_TIMESTAMP;
        case PG_TYPE_MONEY:
            return SQL_C_FLOAT;
        case PG_TYPE_BOOL:
@@ -324,6 +393,12 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
            return SQL_C_BINARY;
        case PG_TYPE_LO:
            return SQL_C_BINARY;
+#ifdef UNICODE_SUPPORT
+       case PG_TYPE_BPCHAR:
+       case PG_TYPE_VARCHAR:
+       case PG_TYPE_TEXT:
+           return conn->unicode ? SQL_C_WCHAR : SQL_C_CHAR;
+#endif /* UNICODE_SUPPORT */
 
        default:
            /* hack until permanent type is available */
@@ -416,7 +491,7 @@ getNumericScale(StatementClass *stmt, Int4 type, int col)
    if (col < 0)
        return PG_NUMERIC_MAX_SCALE;
 
-   result = SC_get_Result(stmt);
+   result = SC_get_Curres(stmt);
 
    /*
     * Manual Result Sets -- use assigned column width (i.e., from
@@ -457,7 +532,7 @@ getNumericPrecision(StatementClass *stmt, Int4 type, int col)
    if (col < 0)
        return PG_NUMERIC_MAX_PRECISION;
 
-   result = SC_get_Result(stmt);
+   result = SC_get_Curres(stmt);
 
    /*
     * Manual Result Sets -- use assigned column width (i.e., from
@@ -520,10 +595,6 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
            break;
    }
 
-   /*
-    * Static Precision (i.e., the Maximum Precision of the datatype) This
-    * has nothing to do with a result set.
-    */
    if (maxsize == TEXT_FIELD_SIZE + 1) /* magic length for testing */
    {
        if (PG_VERSION_GE(SC_get_conn(stmt), 7.1))
@@ -531,10 +602,14 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
        else
            maxsize = TEXT_FIELD_SIZE;
    }
+   /*
+    * Static Precision (i.e., the Maximum Precision of the datatype) This
+    * has nothing to do with a result set.
+    */
    if (col < 0)
        return maxsize;
 
-   result = SC_get_Result(stmt);
+   result = SC_get_Curres(stmt);
 
    /*
     * Manual Result Sets -- use assigned column width (i.e., from
@@ -553,16 +628,20 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
    if (QR_get_atttypmod(result, col) > -1)
        return QR_get_atttypmod(result, col);
 
+   /* The type is really unknown */
    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);
+       if (p >= 0)
+           return p;
    }
 
-   if (p < 0 && handle_unknown_size_as == UNKNOWNS_AS_MAX)
+   if (handle_unknown_size_as == UNKNOWNS_AS_MAX)
        return maxsize;
-   else
-       return p;
+   else /* handle_unknown_size_as == DONT_KNOW */
+       return -1;
+   
 }
 
 static Int2
@@ -580,7 +659,7 @@ getTimestampScale(StatementClass *stmt, Int4 type, int col)
    if (PG_VERSION_LT(conn, 7.2))
        return 0;
 
-   result = SC_get_Result(stmt);
+   result = SC_get_Curres(stmt);
 
    /*
     * Manual Result Sets -- use assigned column width (i.e., from
@@ -615,10 +694,7 @@ getTimestampPrecision(StatementClass *stmt, Int4 type, int col)
            fixed = 8;
            break;
        case PG_TYPE_TIME_WITH_TMZONE:
-           if (USE_ZONE)
-               fixed = 11;
-           else
-               fixed = 8;
+           fixed = 11;
            break;
        case PG_TYPE_TIMESTAMP_NO_TMZONE:
            fixed = 19;
@@ -692,7 +768,10 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
            return getTimestampPrecision(stmt, type, col);
 
        case PG_TYPE_BOOL:
-           return 1;
+       {
+           BOOL    true_is_minus1 = FALSE;
+           return true_is_minus1 ? 2 : 1;
+       }
 
        case PG_TYPE_LO:
            return SQL_NO_TOTAL;
@@ -756,6 +835,8 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown
 Int4
 pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
 {
+   ConnectionClass *conn = SC_get_conn(stmt);
+
    switch (type)
    {
        case PG_TYPE_INT2:
@@ -791,15 +872,27 @@ pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_
            /* Character types (and NUMERIC) use the default precision */
        case PG_TYPE_VARCHAR:
        case PG_TYPE_BPCHAR:
+           {
+           int coef = 1;
+           Int4    prec = pgtype_precision(stmt, type, col, handle_unknown_size_as), maxvarc;
+           if (conn->unicode)
+               return (prec + 1) * 2;
 #ifdef MULTIBYTE
            /* after 7.2 */
-           if (PG_VERSION_GE(SC_get_conn(stmt), 7.2))
-               return 3 * pgtype_precision(stmt, type, col, handle_unknown_size_as);
+           if (PG_VERSION_GE(conn, 7.2))
+               coef = 3;
            else
-#else
-           /* CR -> CR/LF */
-           return 2 * pgtype_precision(stmt, type, col, handle_unknown_size_as);
 #endif   /* MULTIBYTE */
+           if ((conn->connInfo).lf_conversion)
+               /* CR -> CR/LF */
+               coef = 2;
+           if (coef == 1)
+               return prec + 1;
+           maxvarc = conn->connInfo.drivers.max_varchar_size;
+           if (prec <= maxvarc && prec * coef > maxvarc)
+               return maxvarc;
+           return coef * prec;
+           }
        default:
            return pgtype_precision(stmt, type, col, handle_unknown_size_as);
    }
@@ -885,8 +978,8 @@ pgtype_auto_increment(StatementClass *stmt, Int4 type)
        case PG_TYPE_NUMERIC:
 
        case PG_TYPE_DATE:
-       case PG_TYPE_TIME:
        case PG_TYPE_TIME_WITH_TMZONE:
+       case PG_TYPE_TIME:
        case PG_TYPE_ABSTIME:
        case PG_TYPE_DATETIME:
        case PG_TYPE_TIMESTAMP:
@@ -1058,9 +1151,16 @@ sqltype_to_default_ctype(Int2 sqltype)
 #else
            return SQL_C_CHAR;
        case SQL_BIGINT:
-           return SQL_C_SBIGINT;
+           return ALLOWED_C_BIGINT;
 #endif
 
+#ifdef UNICODE_SUPPORT
+       case SQL_WCHAR:
+       case SQL_WVARCHAR:
+       case SQL_WLONGVARCHAR:
+           return SQL_C_WCHAR;
+#endif /* UNICODE_SUPPORT */
+
        case SQL_BIT:
            return SQL_C_BIT;
 
@@ -1086,24 +1186,23 @@ sqltype_to_default_ctype(Int2 sqltype)
            return SQL_C_BINARY;
 
        case SQL_DATE:
-#if (ODBCVER >= 0x0300)
-           return SQL_C_TYPE_DATE;
-#else
            return SQL_C_DATE;
-#endif /* ODBCVER */
 
        case SQL_TIME:
-#if (ODBCVER >= 0x0300)
-           return SQL_C_TYPE_TIME;
-#else
            return SQL_C_TIME;
-#endif /* ODBCVER */
 
        case SQL_TIMESTAMP:
+           return SQL_C_TIMESTAMP;
+
 #if (ODBCVER >= 0x0300)
+       case SQL_TYPE_DATE:
+           return SQL_C_TYPE_DATE;
+
+       case SQL_TYPE_TIME:
+           return SQL_C_TYPE_TIME;
+
+       case SQL_TYPE_TIMESTAMP:
            return SQL_C_TYPE_TIMESTAMP;
-#else
-           return SQL_C_TIMESTAMP;
 #endif /* ODBCVER */
 
        default:
@@ -1167,6 +1266,7 @@ ctype_length(Int2 ctype)
 
        case SQL_C_BINARY:
        case SQL_C_CHAR:
+       case SQL_C_WCHAR:
            return 0;
 
        default:                /* should never happen */
index fc246b8b77ebf4f14f1ac8e92385c29f0513e9ca..534678e2802e28060924a5e1e084a6074f9e6256 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.57 2002/02/18 03:16:11 inoue Exp $
+ * $Id: psqlodbc.h,v 1.58 2002/03/08 08:52:53 inoue Exp $
  *
  */
 
@@ -87,7 +87,7 @@ typedef UInt4 Oid;
 #define DBMS_NAME                  "PostgreSQL"
 #endif   /* ODBCVER */
 
-#define POSTGRESDRIVERVERSION      "07.01.0010"
+#define POSTGRESDRIVERVERSION      "07.01.0011"
 
 #ifdef WIN32
 #if (ODBCVER >= 0x0300)
@@ -254,6 +254,11 @@ void       logs_on_off(int cnopen, int, int);
 
 #include "misc.h"
 
+#ifdef UNICODE_SUPPORT
+UInt4  ucs2strlen(const SQLWCHAR *ucs2str);
+char   *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen);
+UInt4  utf8_to_ucs2(const char * utf8str, Int4 ilen, SQLWCHAR *ucs2str, UInt4 buflen);
+#endif /* UNICODE_SUPPORT */
 #ifdef _MEMORY_DEBUG_
 void      *debug_alloc(size_t);
 void      *debug_realloc(void *, size_t);
index 5b7b53583ebd17aee3fbaeefdc79b851005cbe01..698bd6c74feaf5e3002c0bbf8afa1b14d83dc153 100644 (file)
@@ -138,7 +138,7 @@ BEGIN
                     BS_NOTIFY | WS_TABSTOP,247,205,40,10
 END
 
-DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 267, 161
+DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 267, 176
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Advanced Options (DataSource)"
 FONT 10, "Terminal"
@@ -151,23 +151,27 @@ BEGIN
                     BS_AUTOCHECKBOX | WS_TABSTOP,45,28,88,10
     CONTROL         "Disallow &Premature",DS_DISALLOWPREMATURE,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,149,28,86,10
-    GROUPBOX        "Protocol",IDC_STATIC,43,44,180,25
+    CONTROL         "LF <-> CR/LF convert",DS_LFCONVERSION,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,45,43,92,10
+    CONTROL         "True is -1",DS_TRUEISMINUS1,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,149,43,86,10
+    GROUPBOX        "Protocol",IDC_STATIC,43,59,180,25
     CONTROL         "7.X,6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | 
-                    WS_GROUP,53,54,47,10
+                    WS_GROUP,53,69,47,10
     CONTROL         "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
-                    131,54,26,10
+                    131,69,26,10
     CONTROL         "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
-                    187,54,26,10
-    GROUPBOX        "OID Options",IDC_STATIC,43,74,180,25
+                    187,69,26,10
+    GROUPBOX        "OID Options",IDC_STATIC,43,89,180,25
     CONTROL         "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,53,85,59,10
+                    WS_GROUP | WS_TABSTOP,53,100,59,10
     CONTROL         "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,161,85,55,10
-    LTEXT           "Connect &Settings:",IDC_STATIC,10,105,35,25
-    EDITTEXT        DS_CONNSETTINGS,50,105,200,20,ES_MULTILINE | 
+                    WS_GROUP | WS_TABSTOP,161,100,55,10
+    LTEXT           "Connect &Settings:",IDC_STATIC,10,120,35,25
+    EDITTEXT        DS_CONNSETTINGS,50,120,200,20,ES_MULTILINE | 
                     ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
-    DEFPUSHBUTTON   "OK",IDOK,71,135,50,14,WS_GROUP
-    PUSHBUTTON      "Cancel",IDCANCEL,146,135,50,14
+    DEFPUSHBUTTON   "OK",IDOK,71,150,50,14,WS_GROUP
+    PUSHBUTTON      "Cancel",IDCANCEL,146,150,50,14
 END
 #else
 DLG_CONFIG DIALOG DISCARDABLE  65, 43, 292, 116
@@ -255,7 +259,7 @@ BEGIN
                     BS_NOTIFY | WS_TABSTOP,233,224,40,10
 END
 
-DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 267, 161
+DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 267, 176
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Advanced Options (DataSource)"
 FONT 8, "MS Sans Serif"
@@ -268,23 +272,27 @@ BEGIN
                     BS_AUTOCHECKBOX | WS_TABSTOP,25,25,85,10
     CONTROL         "Disallow &Premature",DS_DISALLOWPREMATURE,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,130,25,85,10
-    GROUPBOX        "Protocol",IDC_STATIC,15,40,180,25
+    CONTROL         "LF <-> CR/LF convert",DS_LFCONVERSION,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,45,40,92,10
+    CONTROL         "True is -1",DS_TRUEISMINUS1,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,149,40,86,10
+    GROUPBOX        "Protocol",IDC_STATIC,15,55,180,25
     CONTROL         "7.X,6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | WS_GROUP,25,
-                    50,35,10
+                    65,35,10
     CONTROL         "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
-                    75,50,26,10
+                    75,65,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
+                    130,65,26,10
+    GROUPBOX        "OID Options",IDC_STATIC,15,86,180,25
     CONTROL         "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,25,81,59,10
+                    WS_GROUP | WS_TABSTOP,25,96,59,10
     CONTROL         "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX | 
-                    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 | 
+                    WS_GROUP | WS_TABSTOP,115,96,51,10
+    RTEXT           "Connect &Settings:",IDC_STATIC,10,120,35,25
+    EDITTEXT        DS_CONNSETTINGS,50,120,200,20,ES_MULTILINE | 
                     ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
-    DEFPUSHBUTTON   "OK",IDOK,71,135,50,14,WS_GROUP
-    PUSHBUTTON      "Cancel",IDCANCEL,146,135,50,14
+    DEFPUSHBUTTON   "OK",IDOK,71,150,50,14,WS_GROUP
+    PUSHBUTTON      "Cancel",IDCANCEL,146,150,50,14
 END
 #endif
 
@@ -354,8 +362,8 @@ END
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 7,1,0,10
- PRODUCTVERSION 7,1,0,10
+ FILEVERSION 7,1,0,11
+ PRODUCTVERSION 7,1,0,11
  FILEFLAGSMASK 0x3L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -377,14 +385,14 @@ BEGIN
             VALUE "CompanyName", "Insight Distribution Systems\0"
 #endif
             VALUE "FileDescription", "PostgreSQL Driver\0"
-            VALUE "FileVersion", " 07.01.0010\0"
+            VALUE "FileVersion", " 07.01.0011\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.0010\0"
+            VALUE "ProductVersion", " 07.01.0011\0"
             VALUE "SpecialBuild", "\0"
         END
     END
diff --git a/src/interfaces/odbc/psqlodbc_api30w.def b/src/interfaces/odbc/psqlodbc_api30w.def
new file mode 100644 (file)
index 0000000..71ea830
--- /dev/null
@@ -0,0 +1,106 @@
+LIBRARY psqlodbc30
+EXPORTS
+SQLAllocConnect @1
+SQLAllocEnv @2
+SQLAllocStmt @3
+SQLBindCol @4
+SQLCancel @5
+SQLColAttributes @6
+SQLConnect @7
+SQLDescribeCol @8
+SQLDisconnect @9
+SQLError @10
+SQLExecDirect @11
+SQLExecute @12
+SQLFetch @13
+SQLFreeConnect @14
+SQLFreeEnv @15
+SQLFreeStmt @16
+SQLGetCursorName @17
+SQLNumResultCols @18
+SQLPrepare @19
+SQLRowCount @20
+SQLSetCursorName @21
+SQLTransact @23
+SQLColumns @40
+SQLDriverConnect @41
+SQLGetData @43
+SQLGetFunctions @44
+SQLGetInfo @45
+SQLGetStmtOption @46
+SQLGetTypeInfo @47
+SQLParamData @48
+SQLPutData @49
+SQLSpecialColumns @52
+SQLStatistics @53
+SQLTables @54
+SQLBrowseConnect @55
+SQLColumnPrivileges @56
+SQLDescribeParam @58
+SQLExtendedFetch @59
+SQLForeignKeys @60
+SQLMoreResults @61
+SQLNativeSql @62
+SQLNumParams @63
+SQLParamOptions @64
+SQLPrimaryKeys @65
+SQLProcedureColumns @66
+SQLProcedures @67
+SQLSetPos @68
+SQLSetScrollOptions @69
+SQLTablePrivileges @70
+SQLBindParameter @72
+
+SQLAllocHandle @80
+SQLBindParam @81
+SQLCloseCursor @82
+SQLColAttribute @83
+SQLCopyDesc @84
+SQLEndTran @85
+SQLFetchScroll @86
+SQLFreeHandle @87
+SQLGetDescField @88
+SQLGetDescRec @89
+SQLGetDiagField @90
+SQLGetDiagRec @91
+SQLGetEnvAttr @92
+SQLGetConnectAttr @93
+SQLGetStmtAttr @94
+SQLSetConnectAttr @95
+SQLSetDescField @96
+SQLSetDescRec @97
+SQLSetEnvAttr @98
+SQLSetStmtAttr @99
+
+SQLDummyOrdinal @199
+dconn_FDriverConnectProc @200
+DllMain @201
+ConfigDSN @202
+
+SQLColAttributeW   @101
+SQLColumnPrivilegesW   @102
+SQLColumnsW        @103
+SQLConnectW        @104
+SQLDescribeColW        @106
+SQLExecDirectW     @107
+SQLForeignKeysW        @108
+SQLGetConnectAttrW @109
+SQLGetCursorNameW  @110
+SQLGetInfoW        @111
+SQLNativeSqlW      @112
+SQLPrepareW        @113
+SQLPrimaryKeysW        @114
+SQLProcedureColumnsW   @115
+SQLProceduresW     @116
+SQLSetConnectAttrW @117
+SQLSetCursorNameW  @118
+SQLSpecialColumnsW @119
+SQLStatisticsW     @120
+SQLTablesW     @121
+SQLTablePrivilegesW    @122
+SQLDriverConnectW  @123
+SQLGetDiagRecW     @124
+SQLGetStmtAttrW        @125
+SQLSetStmtAttrW        @126
+SQLSetDescFieldW   @127
+SQLGetTypeInfoW        @128
diff --git a/src/interfaces/odbc/psqlodbc_apiw.def b/src/interfaces/odbc/psqlodbc_apiw.def
new file mode 100644 (file)
index 0000000..c719a20
--- /dev/null
@@ -0,0 +1,84 @@
+LIBRARY psqlodbc
+EXPORTS
+SQLAllocConnect @1
+SQLAllocEnv @2
+SQLAllocStmt @3
+SQLBindCol @4
+SQLCancel @5
+SQLColAttributes @6
+SQLConnect @7
+SQLDescribeCol @8
+SQLDisconnect @9
+SQLError @10
+SQLExecDirect @11
+SQLExecute @12
+SQLFetch @13
+SQLFreeConnect @14
+SQLFreeEnv @15
+SQLFreeStmt @16
+SQLGetCursorName @17
+SQLNumResultCols @18
+SQLPrepare @19
+SQLRowCount @20
+SQLSetCursorName @21
+SQLTransact @23
+SQLColumns @40
+SQLDriverConnect @41
+SQLGetConnectOption @42
+SQLGetData @43
+SQLGetFunctions @44
+SQLGetInfo @45
+SQLGetStmtOption @46
+SQLGetTypeInfo @47
+SQLParamData @48
+SQLPutData @49
+SQLSetConnectOption @50
+SQLSetStmtOption @51
+SQLSpecialColumns @52
+SQLStatistics @53
+SQLTables @54
+SQLBrowseConnect @55
+SQLColumnPrivileges @56
+SQLDescribeParam @58
+SQLExtendedFetch @59
+SQLForeignKeys @60
+SQLMoreResults @61
+SQLNativeSql @62
+SQLNumParams @63
+SQLParamOptions @64
+SQLPrimaryKeys @65
+SQLProcedureColumns @66
+SQLProcedures @67
+SQLSetPos @68
+SQLSetScrollOptions @69
+SQLTablePrivileges @70
+SQLBindParameter @72
+
+SQLColAttributesW  @101
+SQLColumnPrivilegesW   @102
+SQLColumnsW        @103
+SQLConnectW        @104
+SQLDescribeColW        @106
+SQLExecDirectW     @107
+SQLForeignKeysW        @108
+SQLGetConnectOptionW   @109
+SQLGetCursorNameW  @110
+SQLGetInfoW        @111
+SQLNativeSqlW      @112
+SQLPrepareW        @113
+SQLPrimaryKeysW        @114
+SQLProcedureColumnsW   @115
+SQLProceduresW     @116
+SQLSetConnectOptionW   @117
+SQLSetCursorNameW  @118
+SQLSpecialColumnsW @119
+SQLStatisticsW     @120
+SQLTablesW     @121
+SQLTablePrivilegesW    @122
+SQLDriverConnectW  @123
+SQLErrorW      @124
+SQLGetTypeInfoW        @128
+
+dconn_FDriverConnectProc @200
+DllMain @201
+ConfigDSN @202
index 2cbe64f0b4c4af4b8f7528ad205f54397392dee1..2e462bf5d5bec69e27529fbf32ab10a9605f57ed 100644 (file)
@@ -108,6 +108,7 @@ QR_Constructor()
        rv->command = NULL;
        rv->notice = NULL;
        rv->conn = NULL;
+       rv->next = NULL;
        rv->inTuples = FALSE;
        rv->fcount = 0;
        rv->fetch_count = 0;
@@ -160,6 +161,9 @@ QR_Destructor(QResultClass *self)
    /* Free notice info (this is from strdup()) */
    if (self->notice)
        free(self->notice);
+   /* Destruct the result object in the chain */
+   if (self->next)
+       QR_Destructor(self->next);
 
    free(self);
 
@@ -247,6 +251,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
 
        if (self->cursor)
            free(self->cursor);
+       self->cursor = NULL;
 
        if (fetch_cursor)
        {
@@ -342,7 +347,7 @@ QR_close(QResultClass *self)
        sprintf(buf, "close %s", self->cursor);
        mylog("QResult: closing cursor: '%s'\n", buf);
 
-       res = CC_send_query(self->conn, buf, NULL);
+       res = CC_send_query(self->conn, buf, NULL, TRUE);
 
        self->inTuples = FALSE;
        self->currTuple = -1;
@@ -487,13 +492,11 @@ QR_next_tuple(QResultClass *self)
            qi.row_size = self->cache_size;
            qi.result_in = self;
            qi.cursor = NULL;
-           res = CC_send_query(self->conn, fetch, &qi);
-           if (res == NULL || QR_get_aborted(res))
+           res = CC_send_query(self->conn, fetch, &qi, TRUE);
+           if (res == NULL)
            {
                self->status = PGRES_FATAL_ERROR;
                QR_set_message(self, "Error fetching next group.");
-               if (res)
-                   QR_Destructor(res);
                return FALSE;
            }
            self->inTuples = TRUE;
@@ -689,7 +692,7 @@ QR_read_tuple(QResultClass *self, char binary)
             */
 
            flds = self->fields;
-           if (flds->display_size[field_lf] < len)
+           if (flds && flds->display_size && flds->display_size[field_lf] < len)
                flds->display_size[field_lf] = len;
        }
 
index 251bc449c126f0d09e84295b8372937bad4b3287..b304fd5d351d718925c646927b3db8464d118a39 100644 (file)
@@ -45,6 +45,7 @@ struct QResultClass_
    TupleListClass *manual_tuples;      /* manual result tuple list */
    ConnectionClass *conn;      /* the connection this result is using
                                 * (backend) */
+   QResultClass    *next;      /* the following result class */
 
    /* Stuff for declare/fetch tuples */
    int         count_allocated;    /* m(re)alloced count */
index b8bbd4fcfc1fa599bdfef45a22cae5cf6f1723b7..4cd1639887ba2229f6657d038a65df0e50585b48 100644 (file)
@@ -52,6 +52,8 @@
 #define DRV_OR_DSN                     1059\r
 #define DRV_DEBUG          1060\r
 #define DS_DISALLOWPREMATURE       1061\r
+#define DS_LFCONVERSION            1062\r
+#define DS_TRUEISMINUS1            1063\r
 \r
 /* Next default values for new objects\r */
 /*\r */
index 4d221cacc63a253dc9989427792c4423b7db7081..e43c0e3db45df71f06d6c9ca89f458d7894821a1 100644 (file)
@@ -8,7 +8,7 @@
  *
  * API functions:  SQLRowCount, SQLNumResultCols, SQLDescribeCol,
  *                 SQLColAttributes, SQLGetData, SQLFetch, SQLExtendedFetch,
- *                 SQLMoreResults(NI), SQLSetPos, SQLSetScrollOptions(NI),
+ *                 SQLMoreResults, SQLSetPos, SQLSetScrollOptions(NI),
  *                 SQLSetCursorName, SQLGetCursorName
  *
  * Comments:       See "notice.txt" for copyright and license information.
@@ -45,6 +45,7 @@ PGAPI_RowCount(
               *ptr;
    ConnInfo   *ci;
 
+   mylog("%s: entering...\n", func);
    if (!stmt)
    {
        SC_log_error(func, "", NULL);
@@ -62,7 +63,7 @@ PGAPI_RowCount(
    {
        if (stmt->status == STMT_FINISHED)
        {
-           res = SC_get_Result(stmt);
+           res = SC_get_Curres(stmt);
 
            if (res && pcrow)
            {
@@ -73,7 +74,7 @@ PGAPI_RowCount(
    }
    else
    {
-       res = SC_get_Result(stmt);
+       res = SC_get_Curres(stmt);
        if (res && pcrow)
        {
            msg = QR_get_command(res);
@@ -115,6 +116,7 @@ PGAPI_NumResultCols(
    char        parse_ok;
    ConnInfo   *ci;
 
+   mylog("%s: entering...\n", func);
    if (!stmt)
    {
        SC_log_error(func, "", NULL);
@@ -144,7 +146,7 @@ PGAPI_NumResultCols(
    if (!parse_ok)
    {
        SC_pre_execute(stmt);
-       result = SC_get_Result(stmt);
+       result = SC_get_Curres(stmt);
 
        mylog("PGAPI_NumResultCols: result = %u, status = %d, numcols = %d\n", result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1);
        if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
@@ -210,6 +212,25 @@ PGAPI_DescribeCol(
 
    SC_clear_error(stmt);
 
+#if (ODBCVER >= 0x0300)
+   if (0 == icol) /* bookmark column */
+   {
+       SQLSMALLINT fType = SQL_INTEGER;
+       if (szColName && cbColNameMax > 0)
+           *szColName = '\0';
+       if (pcbColName)
+           *pcbColName = 0;
+       if (pfSqlType)
+           *pfSqlType = fType;
+       if (pcbColDef)
+           *pcbColDef = 10;
+       if (pibScale)
+           *pibScale = 0;
+       if (pfNullable)
+           *pfNullable = SQL_NO_NULLS;
+       return SQL_SUCCESS;
+   }
+#endif /* ODBCVER */
    /*
     * Dont check for bookmark column. This is the responsibility of the
     * driver manager.
@@ -262,7 +283,7 @@ PGAPI_DescribeCol(
    {
        SC_pre_execute(stmt);
 
-       res = SC_get_Result(stmt);
+       res = SC_get_Curres(stmt);
 
        mylog("**** PGAPI_DescribeCol: res = %u, stmt->status = %d, !finished=%d, !premature=%d\n", res, stmt->status, stmt->status != STMT_FINISHED, stmt->status != STMT_PREMATURE);
        if ((NULL == res) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
@@ -305,7 +326,7 @@ PGAPI_DescribeCol(
    if (pcbColName)
        *pcbColName = len;
 
-   if (szColName)
+   if (szColName && cbColNameMax > 0)
    {
        strncpy_null(szColName, col_name, cbColNameMax);
 
@@ -379,17 +400,19 @@ PGAPI_ColAttributes(
 {
    static char *func = "PGAPI_ColAttributes";
    StatementClass *stmt = (StatementClass *) hstmt;
-   Int4        field_type = 0;
-   ConnInfo   *ci;
+   Int4        col_idx, field_type = 0;
+   ConnectionClass *conn;
+   ConnInfo    *ci;
    int         unknown_sizes;
    int         cols = 0;
    char        parse_ok;
    RETCODE     result;
-   char       *p = NULL;
+   const char   *p = NULL;
    int         len = 0,
                value = 0;
+   const   FIELD_INFO  *fi = NULL;
 
-   mylog("%s: entering...\n", func);
+   mylog("%s: entering..col=%d %d.\n", func, icol, fDescType);
 
    if (!stmt)
    {
@@ -397,7 +420,8 @@ PGAPI_ColAttributes(
        return SQL_INVALID_HANDLE;
    }
 
-   ci = &(SC_get_conn(stmt)->connInfo);
+   conn = SC_get_conn(stmt);
+   ci = &(conn->connInfo);
 
    /*
     * Dont check for bookmark column.  This is the responsibility of the
@@ -405,7 +429,24 @@ PGAPI_ColAttributes(
     * is ignored anyway, so it may be 0.
     */
 
-   icol--;
+#if (ODBCVER >= 0x0300)
+   if (0 == icol) /* bookmark column */
+   {
+       switch (fDescType)
+       {
+           case SQL_DESC_OCTET_LENGTH:
+               if (pfDesc)
+                   *pfDesc = 4;
+               break;
+           case SQL_DESC_TYPE:
+               if (pfDesc)
+                   *pfDesc = SQL_INTEGER;
+               break;
+       }
+       return SQL_SUCCESS;
+   }
+#endif /* ODBCVER */
+   col_idx = icol - 1;
 
    /* atoi(ci->unknown_sizes); */
    unknown_sizes = ci->drivers.unknown_sizes;
@@ -437,28 +478,30 @@ PGAPI_ColAttributes(
            return SQL_SUCCESS;
        }
 
-       if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[icol])
+       if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[col_idx])
        {
-           if (icol >= cols)
+           if (col_idx >= cols)
            {
                stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
                stmt->errormsg = "Invalid column number in ColAttributes.";
                SC_log_error(func, "", stmt);
                return SQL_ERROR;
            }
-           field_type = stmt->fi[icol]->type;
+           field_type = stmt->fi[col_idx]->type;
            if (field_type > 0)
                parse_ok = TRUE;
        }
    }
 
-   if (!parse_ok)
+   if (parse_ok)
+       fi = stmt->fi[col_idx];
+   else
    {
        SC_pre_execute(stmt);
 
-       mylog("**** PGAPI_ColAtt: result = %u, status = %d, numcols = %d\n", stmt->result, stmt->status, stmt->result != NULL ? QR_NumResultCols(stmt->result) : -1);
+       mylog("**** PGAPI_ColAtt: result = %u, status = %d, numcols = %d\n", SC_get_Curres(stmt), stmt->status, SC_get_Curres(stmt) != NULL ? QR_NumResultCols(SC_get_Curres(stmt)) : -1);
 
-       if ((NULL == stmt->result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
+       if ((NULL == SC_get_Curres(stmt)) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
        {
            stmt->errormsg = "Can't get column attributes: no result found.";
            stmt->errornumber = STMT_SEQUENCE_ERROR;
@@ -466,13 +509,17 @@ PGAPI_ColAttributes(
            return SQL_ERROR;
        }
 
-       cols = QR_NumResultCols(stmt->result);
+       cols = QR_NumResultCols(SC_get_Curres(stmt));
 
        /*
         * Column Count is a special case.  The Column number is ignored
         * in this case.
         */
+#if (ODBCVER >= 0x0300)
+       if (fDescType == SQL_DESC_COUNT)
+#else
        if (fDescType == SQL_COLUMN_COUNT)
+#endif /* ODBCVER */
        {
            if (pfDesc)
                *pfDesc = cols;
@@ -480,7 +527,7 @@ PGAPI_ColAttributes(
            return SQL_SUCCESS;
        }
 
-       if (icol >= cols)
+       if (col_idx >= cols)
        {
            stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
            stmt->errormsg = "Invalid column number in ColAttributes.";
@@ -488,21 +535,21 @@ PGAPI_ColAttributes(
            return SQL_ERROR;
        }
 
-       field_type = QR_get_field_type(stmt->result, icol);
+       field_type = QR_get_field_type(SC_get_Curres(stmt), col_idx);
    }
 
-   mylog("colAttr: col %d field_type = %d\n", icol, field_type);
+   mylog("colAttr: col %d field_type = %d\n", col_idx, field_type);
 
    switch (fDescType)
    {
-       case SQL_COLUMN_AUTO_INCREMENT:
+       case SQL_COLUMN_AUTO_INCREMENT: /* == SQL_DESC_AUTO_UNIQUE_VALUE */
            value = pgtype_auto_increment(stmt, field_type);
            if (value == -1)    /* non-numeric becomes FALSE (ODBC Doc) */
                value = FALSE;
 
            break;
 
-       case SQL_COLUMN_CASE_SENSITIVE:
+       case SQL_COLUMN_CASE_SENSITIVE: /* == SQL_DESC_CASE_SENSITIVE */
            value = pgtype_case_sensitive(stmt, field_type);
            break;
 
@@ -511,17 +558,17 @@ PGAPI_ColAttributes(
             *
             * case SQL_COLUMN_COUNT:
             */
-       case SQL_COLUMN_DISPLAY_SIZE:
-           value = (parse_ok) ? stmt->fi[icol]->display_size : pgtype_display_size(stmt, field_type, icol, unknown_sizes);
+       case SQL_COLUMN_DISPLAY_SIZE: /* == SQL_DESC_DISPLAY_SIZE */
+           value = fi ? fi->display_size : pgtype_display_size(stmt, field_type, col_idx, unknown_sizes);
 
-           mylog("PGAPI_ColAttributes: col %d, display_size= %d\n", icol, value);
+           mylog("PGAPI_ColAttributes: col %d, display_size= %d\n", col_idx, value);
 
            break;
 
-       case SQL_COLUMN_LABEL:
-           if (parse_ok && stmt->fi[icol]->alias[0] != '\0')
+       case SQL_COLUMN_LABEL: /* == SQL_DESC_LABEL */
+           if (fi && fi->alias[0] != '\0')
            {
-               p = stmt->fi[icol]->alias;
+               p = fi->alias;
 
                mylog("PGAPI_ColAttr: COLUMN_LABEL = '%s'\n", p);
                break;
@@ -529,70 +576,78 @@ PGAPI_ColAttributes(
            }
            /* otherwise same as column name -- FALL THROUGH!!! */
 
+#if (ODBCVER >= 0x0300)
+       case SQL_DESC_NAME:
+#else
        case SQL_COLUMN_NAME:
-           p = (parse_ok) ? stmt->fi[icol]->name : QR_get_fieldname(stmt->result, icol);
+#endif /* ODBCVER */
+           p = fi ? (fi->alias[0] ? fi->alias : fi->name) : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
 
            mylog("PGAPI_ColAttr: COLUMN_NAME = '%s'\n", p);
            break;
 
        case SQL_COLUMN_LENGTH:
-           value = (parse_ok) ? stmt->fi[icol]->length : pgtype_length(stmt, field_type, icol, unknown_sizes);
+           value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes);
 
-           mylog("PGAPI_ColAttributes: col %d, length = %d\n", icol, value);
+           mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
            break;
 
-       case SQL_COLUMN_MONEY:
+       case SQL_COLUMN_MONEY: /* == SQL_DESC_FIXED_PREC_SCALE */
            value = pgtype_money(stmt, field_type);
            break;
 
+#if (ODBCVER >= 0x0300)
+       case SQL_DESC_NULLABLE:
+#else
        case SQL_COLUMN_NULLABLE:
-           value = (parse_ok) ? stmt->fi[icol]->nullable : pgtype_nullable(stmt, field_type);
+#endif /* ODBCVER */
+           value = fi ? fi->nullable : pgtype_nullable(stmt, field_type);
            break;
 
-       case SQL_COLUMN_OWNER_NAME:
+       case SQL_COLUMN_OWNER_NAME: /* == SQL_DESC_SCHEMA_NAME */
            p = "";
            break;
 
        case SQL_COLUMN_PRECISION:
-           value = (parse_ok) ? stmt->fi[icol]->precision : pgtype_precision(stmt, field_type, icol, unknown_sizes);
+           value = fi ? fi->precision : pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
 
-           mylog("PGAPI_ColAttributes: col %d, precision = %d\n", icol, value);
+           mylog("PGAPI_ColAttributes: col %d, precision = %d\n", col_idx, value);
            break;
 
-       case SQL_COLUMN_QUALIFIER_NAME:
+       case SQL_COLUMN_QUALIFIER_NAME: /* == SQL_DESC_CATALOG_NAME */
            p = "";
            break;
 
        case SQL_COLUMN_SCALE:
-           value = pgtype_scale(stmt, field_type, icol);
+           value = pgtype_scale(stmt, field_type, col_idx);
            break;
 
-       case SQL_COLUMN_SEARCHABLE:
+       case SQL_COLUMN_SEARCHABLE: /* SQL_DESC_SEARCHABLE */
            value = pgtype_searchable(stmt, field_type);
            break;
 
-       case SQL_COLUMN_TABLE_NAME:
-           p = (parse_ok && stmt->fi[icol]->ti) ? stmt->fi[icol]->ti->name : "";
+       case SQL_COLUMN_TABLE_NAME: /* == SQL_DESC_TABLE_NAME */
+           p = fi && (fi->ti) ? fi->ti->name : "";
 
            mylog("PGAPI_ColAttr: TABLE_NAME = '%s'\n", p);
            break;
 
-       case SQL_COLUMN_TYPE:
+       case SQL_COLUMN_TYPE: /* == SQL_DESC_CONCISE_TYPE */
            value = pgtype_to_sqltype(stmt, field_type);
            break;
 
-       case SQL_COLUMN_TYPE_NAME:
+       case SQL_COLUMN_TYPE_NAME: /* == SQL_DESC_TYPE_NAME */
            p = pgtype_to_name(stmt, field_type);
            break;
 
-       case SQL_COLUMN_UNSIGNED:
+       case SQL_COLUMN_UNSIGNED: /* == SQL_DESC_UNSINGED */
            value = pgtype_unsigned(stmt, field_type);
            if (value == -1)    /* non-numeric becomes TRUE (ODBC Doc) */
                value = TRUE;
 
            break;
 
-       case SQL_COLUMN_UPDATABLE:
+       case SQL_COLUMN_UPDATABLE: /* == SQL_DESC_UPDATABLE */
 
            /*
             * Neither Access or Borland care about this.
@@ -604,6 +659,60 @@ PGAPI_ColAttributes(
 
            mylog("PGAPI_ColAttr: UPDATEABLE = %d\n", value);
            break;
+#if (ODBCVER >= 0x0300)
+       case SQL_DESC_BASE_COLUMN_NAME:
+
+           p = fi ? fi->name : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
+
+           mylog("PGAPI_ColAttr: BASE_COLUMN_NAME = '%s'\n", p);
+           break;
+       case SQL_DESC_BASE_TABLE_NAME: /* the same as TABLE_NAME ok ? */
+           p = fi && (fi->ti) ? fi->ti->name : "";
+
+           mylog("PGAPI_ColAttr: BASE_TABLE_NAME = '%s'\n", p);
+           break;
+       case SQL_DESC_LENGTH: /* different from SQL_COLUMN_LENGTH */
+           value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes);
+
+           mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
+           break;
+       case SQL_DESC_OCTET_LENGTH:
+           value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes);
+
+           mylog("PGAPI_ColAttributes: col %d, octet_length = %d\n", col_idx, value);
+           break;
+       case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */
+           value = fi ? fi->precision : pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
+
+           mylog("PGAPI_ColAttributes: col %d, desc_precision = %d\n", col_idx, value);
+           break;
+       case SQL_DESC_SCALE: /* different from SQL_COLUMN_SCALE */
+           value = pgtype_scale(stmt, field_type, col_idx);
+           break;
+       case SQL_DESC_LOCAL_TYPE_NAME:
+           p = pgtype_to_name(stmt, field_type);
+           break;
+       case SQL_DESC_TYPE:
+           value = pgtype_to_sqltype(stmt, field_type);
+           switch (value)
+           {
+               case SQL_TYPE_DATE:
+               case SQL_TYPE_TIME:
+               case SQL_TYPE_TIMESTAMP:
+                   value = SQL_DATETIME;
+                   break;
+           }
+           break;
+       case SQL_DESC_LITERAL_PREFIX:
+       case SQL_DESC_LITERAL_SUFFIX:
+       case SQL_DESC_NUM_PREC_RADIX:
+       case SQL_DESC_UNNAMED:
+#endif /* ODBCVER */
+       default:
+           stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
+           stmt->errormsg = "ColAttribute for this type not implemented yet";
+           SC_log_error(func, "", stmt);
+           return SQL_ERROR;
    }
 
    result = SQL_SUCCESS;
@@ -614,6 +723,14 @@ PGAPI_ColAttributes(
 
        if (rgbDesc)
        {
+#ifdef UNICODE_SUPPORT
+           if (conn->unicode)
+           {
+               len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbDesc, cbDescMax / 2);
+               len *= 2;
+           }
+           else
+#endif /* UNICODE_SUPPORT */
            strncpy_null((char *) rgbDesc, p, (size_t) cbDescMax);
 
            if (len >= cbDescMax)
@@ -667,7 +784,7 @@ PGAPI_GetData(
        return SQL_INVALID_HANDLE;
    }
    ci = &(SC_get_conn(stmt)->connInfo);
-   res = stmt->result;
+   res = SC_get_Curres(stmt);
 
    if (STMT_EXECUTING == stmt->status)
    {
@@ -834,7 +951,7 @@ PGAPI_Fetch(
    StatementClass *stmt = (StatementClass *) hstmt;
    QResultClass *res;
 
-   mylog("PGAPI_Fetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
+   mylog("PGAPI_Fetch: stmt = %u, stmt->result= %u\n", stmt, SC_get_Curres(stmt));
 
    if (!stmt)
    {
@@ -844,7 +961,7 @@ PGAPI_Fetch(
 
    SC_clear_error(stmt);
 
-   if (!(res = stmt->result))
+   if (!(res = SC_get_Curres(stmt)))
    {
        stmt->errormsg = "Null statement result in PGAPI_Fetch.";
        stmt->errornumber = STMT_SEQUENCE_ERROR;
@@ -935,7 +1052,7 @@ PGAPI_ExtendedFetch(
 
    SC_clear_error(stmt);
 
-   if (!(res = stmt->result))
+   if (!(res = SC_get_Curres(stmt)))
    {
        stmt->errormsg = "Null statement result in PGAPI_ExtendedFetch.";
        stmt->errornumber = STMT_SEQUENCE_ERROR;
@@ -1214,6 +1331,15 @@ RETCODE      SQL_API
 PGAPI_MoreResults(
                  HSTMT hstmt)
 {
+   const char *func = "PGAPI_MoreResults";
+   StatementClass  *stmt = (StatementClass *) hstmt;
+   QResultClass    *res;
+
+   mylog("%s: entering...\n", func);
+   if (stmt && (res = SC_get_Curres(stmt)))
+       SC_get_Curres(stmt) = res->next;
+   if (SC_get_Curres(stmt))
+       return SQL_SUCCESS; 
    return SQL_NO_DATA_FOUND;
 }
 
@@ -1243,12 +1369,7 @@ positioned_load(StatementClass *stmt, BOOL latest, int res_cols, UInt4 oid, cons
    }
    sprintf(selstr, "%s oid = %u", selstr, oid),
        mylog("selstr=%s\n", selstr);
-   qres = CC_send_query(SC_get_conn(stmt), selstr, NULL);
-   if (qres && QR_aborted(qres))
-   {
-       QR_Destructor(qres);
-       qres = (QResultClass *) 0;
-   }
+   qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, TRUE);
    return qres;
 }
 
@@ -1270,7 +1391,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
    rcnt = 0;
    if (count)
        *count = 0;
-   if (!(res = stmt->result))
+   if (!(res = SC_get_Curres(stmt)))
        return SQL_ERROR;
    if (!stmt->ti)
        parse_statement(stmt);  /* not preferable */
@@ -1339,7 +1460,7 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
    RETCODE     ret = SQL_ERROR;
 
    mylog("positioned new fi=%x ti=%x\n", stmt->fi, stmt->ti);
-   if (!(res = stmt->result))
+   if (!(res = SC_get_Curres(stmt)))
        return SQL_ERROR;
    if (!stmt->ti)
        parse_statement(stmt);  /* not preferable */
@@ -1401,6 +1522,41 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
    return ret;
 }
 
+static RETCODE SQL_API
+irow_update(RETCODE ret, StatementClass *stmt, UWORD irow)
+{
+   if (ret != SQL_ERROR)
+   {
+       int         updcnt;
+       const char *cmdstr = QR_get_command(SC_get_Curres(stmt));
+
+       if (cmdstr &&
+           sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
+       {
+           if (updcnt == 1)
+               SC_pos_reload(stmt, irow, (UWORD *) 0);
+           else if (updcnt == 0)
+           {
+               stmt->errornumber = STMT_ROW_VERSION_CHANGED;
+               stmt->errormsg = "the content was changed before updation";
+               ret = SQL_ERROR;
+               if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
+                   SC_pos_reload(stmt, irow, (UWORD *) 0);
+           }
+           else
+               ret = SQL_ERROR;
+           stmt->currTuple = stmt->rowset_start + irow;
+       }
+       else
+           ret = SQL_ERROR;
+       if (ret == SQL_ERROR && stmt->errornumber == 0)
+       {
+           stmt->errornumber = STMT_ERROR_TAKEN_FROM_BACKEND;
+           stmt->errormsg = "SetPos update return error";
+       }
+   }
+   return ret;
+}
 RETCODE        SQL_API
 SC_pos_update(StatementClass *stmt,
              UWORD irow)
@@ -1419,8 +1575,8 @@ SC_pos_update(StatementClass *stmt,
    UInt4   offset;
    Int4    *used;
 
-   mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, stmt->result->base, stmt->fi, stmt->ti);
-   if (!(res = stmt->result))
+   mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, SC_get_Curres(stmt)->base, stmt->fi, stmt->ti);
+   if (!(res = SC_get_Curres(stmt)))
        return SQL_ERROR;
    if (!stmt->ti)
        parse_statement(stmt);  /* not preferable */
@@ -1510,40 +1666,12 @@ SC_pos_update(StatementClass *stmt,
            stmt->errormsg = "SetPos with data_at_exec not yet supported";
            ret = SQL_ERROR;
        }
-       if (ret != SQL_ERROR)
-       {
-           int         updcnt;
-           const char *cmdstr = QR_get_command(qstmt->result);
-
-           if (cmdstr &&
-               sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
-           {
-               if (updcnt == 1)
-                   SC_pos_reload(stmt, irow, (UWORD *) 0);
-               else if (updcnt == 0)
-               {
-                   stmt->errornumber = STMT_ROW_VERSION_CHANGED;
-                   stmt->errormsg = "the content was changed before updation";
-                   ret = SQL_ERROR;
-                   if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
-                       SC_pos_reload(stmt, irow, (UWORD *) 0);
-               }
-               else
-                   ret = SQL_ERROR;
-               stmt->currTuple = stmt->rowset_start + irow;
-           }
-           else
-               ret = SQL_ERROR;
-           if (ret == SQL_ERROR && stmt->errornumber == 0)
-           {
-               stmt->errornumber = STMT_ERROR_TAKEN_FROM_BACKEND;
-               stmt->errormsg = "SetPos update return error";
-           }
-       }
+       ret = irow_update(ret, qstmt, irow);
        PGAPI_FreeStmt(hstmt, SQL_DROP);
    }
    else
        ret = SQL_SUCCESS_WITH_INFO;
+#if (ODBCVER >= 0x0300)
    if (stmt->options.rowStatusArray)
    {
        switch (ret)
@@ -1556,6 +1684,7 @@ SC_pos_update(StatementClass *stmt,
                break;
        }
    }
+#endif /* ODBCVER */
 
    return ret;
 }
@@ -1573,7 +1702,7 @@ SC_pos_delete(StatementClass *stmt,
    char       *oidval;
 
    mylog("POS DELETE fi=%x ti=%x\n", stmt->fi, stmt->ti);
-   if (!(res = stmt->result))
+   if (!(res = SC_get_Curres(stmt)))
        return SQL_ERROR;
    if (!stmt->ti)
        parse_statement(stmt);  /* not preferable */
@@ -1591,11 +1720,11 @@ SC_pos_delete(StatementClass *stmt,
    }
    sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s",
            stmt->ti[0]->name,
-      QR_get_value_backend_row(stmt->result, global_ridx, res_cols - 2),
+      QR_get_value_backend_row(SC_get_Curres(stmt), global_ridx, res_cols - 2),
            oidval);
 
    mylog("dltstr=%s\n", dltstr);
-   qres = CC_send_query(SC_get_conn(stmt), dltstr, NULL);
+   qres = CC_send_query(SC_get_conn(stmt), dltstr, NULL, TRUE);
    if (qres && QR_command_successful(qres))
    {
        int         dltcnt;
@@ -1630,6 +1759,7 @@ SC_pos_delete(StatementClass *stmt,
    }
    if (qres)
        QR_Destructor(qres);
+#if (ODBCVER >= 0x0300)
    if (stmt->options.rowStatusArray)
    {
        switch (ret)
@@ -1642,6 +1772,40 @@ SC_pos_delete(StatementClass *stmt,
                break;
        }
    }
+#endif /* ODBCVER */
+   return ret;
+}
+
+static RETCODE SQL_API
+irow_insert(RETCODE ret, StatementClass *stmt, int addpos)
+{
+   if (ret != SQL_ERROR)
+   {
+       int         addcnt;
+       UInt4       oid;
+       const char *cmdstr = QR_get_command(SC_get_Curres(stmt));
+
+       if (cmdstr &&
+           sscanf(cmdstr, "INSERT %u %d", &oid, &addcnt) == 2 &&
+           addcnt == 1)
+       {
+           SC_pos_newload(stmt, oid, NULL);
+           if (stmt->bookmark.buffer)
+           {
+               char        buf[32];
+
+               sprintf(buf, "%ld", addpos);
+               copy_and_convert_field(stmt, 0, buf,
+                SQL_C_ULONG, stmt->bookmark.buffer,
+                0, stmt->bookmark.used);
+           }
+       }
+       else
+       {
+           stmt->errornumber = STMT_ERROR_TAKEN_FROM_BACKEND;
+           stmt->errormsg = "SetPos insert return error";
+       }
+   }
    return ret;
 }
 RETCODE        SQL_API
@@ -1661,7 +1825,7 @@ SC_pos_add(StatementClass *stmt,
    Int4        *used;
 
    mylog("POS ADD fi=%x ti=%x\n", stmt->fi, stmt->ti);
-   if (!(res = stmt->result))
+   if (!(res = SC_get_Curres(stmt)))
        return SQL_ERROR;
    if (!stmt->ti)
        parse_statement(stmt);  /* not preferable */
@@ -1721,50 +1885,24 @@ SC_pos_add(StatementClass *stmt,
        mylog("addstr=%s\n", addstr);
        qstmt->exec_start_row = qstmt->exec_end_row = irow; 
        ret = PGAPI_ExecDirect(hstmt, addstr, strlen(addstr));
-       if (ret == SQL_NEED_DATA)       /* must be fixed */
-       {
-           stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-           stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
-           stmt->errormsg = "SetPos with data_at_exec not yet supported";
-           ret = SQL_ERROR;
-       }
        if (ret == SQL_ERROR)
        {
            stmt->errornumber = qstmt->errornumber;
            stmt->errormsg = qstmt->errormsg;
        }
-       else
+       else if (ret == SQL_NEED_DATA)      /* must be fixed */
        {
-           int         addcnt;
-           UInt4       oid;
-           const char *cmdstr = QR_get_command(qstmt->result);
-
-           if (cmdstr &&
-               sscanf(cmdstr, "INSERT %u %d", &oid, &addcnt) == 2 &&
-               addcnt == 1)
-           {
-               SC_pos_newload(stmt, oid, NULL);
-               if (stmt->bookmark.buffer)
-               {
-                   char        buf[32];
-
-                   sprintf(buf, "%ld", res->fcount);
-                   copy_and_convert_field(stmt, 0, buf,
-                                     SQL_C_ULONG, stmt->bookmark.buffer,
-                                          0, stmt->bookmark.used);
-               }
-           }
-           else
-           {
-               stmt->errornumber = STMT_ERROR_TAKEN_FROM_BACKEND;
-               stmt->errormsg = "SetPos insert return error";
-               ret = SQL_ERROR;
-           }
+           stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
+           stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
+           stmt->errormsg = "SetPos with data_at_exec not yet supported";
+           ret = SQL_ERROR;
        }
+       ret = irow_insert(ret, qstmt, res->fcount);
    }
    else
        ret = SQL_SUCCESS_WITH_INFO;
    PGAPI_FreeStmt(hstmt, SQL_DROP);
+#if (ODBCVER >= 0x0300)
    if (stmt->options.rowStatusArray)
    {
        switch (ret)
@@ -1777,6 +1915,8 @@ SC_pos_add(StatementClass *stmt,
                break;
        }
    }
+#endif /* ODBCVER */
+
    return ret;
 }
 
@@ -1823,7 +1963,7 @@ PGAPI_SetPos(
        return SQL_ERROR;
    }
 
-   if (!(res = stmt->result))
+   if (!(res = SC_get_Curres(stmt)))
    {
        stmt->errormsg = "Null statement result in PGAPI_SetPos.";
        stmt->errornumber = STMT_SEQUENCE_ERROR;
index 6bcc01bd89219eb06663ee63bff2b89786ee3fbb..0175d69f32bbedabe16dc408459b4ca64f17a724 100644 (file)
@@ -90,7 +90,6 @@ ConfigDSN(HWND hwnd,
    if (!hglbAttr)
        return FALSE;
    lpsetupdlg = (LPSETUPDLG) GlobalLock(hglbAttr);
-
    /* Parse attribute string */
    if (lpszAttributes)
        ParseAttributes(lpszAttributes, lpsetupdlg);
@@ -339,7 +338,7 @@ ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
    int         cbKey;
    char        value[MAXPGPATH];
 
-   memset(&lpsetupdlg->ci, 0, sizeof(ConnInfo));
+   CC_conninfo_init(&(lpsetupdlg->ci));
 
    for (lpsz = lpszAttributes; *lpsz; lpsz++)
    {
index 2b2e5f0634e1cc1a8cb931caaa33462e8504f820..513c916019a51bb95cdf2bd3a5d17e788fa9bb6e 100644 (file)
@@ -159,10 +159,10 @@ PGAPI_FreeStmt(HSTMT hstmt,
            }
 
            /* Free any cursors and discard any result info */
-           if (stmt->result)
+           if (SC_get_Result(stmt))
            {
-               QR_Destructor(stmt->result);
-               stmt->result = NULL;
+               QR_Destructor(SC_get_Result(stmt));
+               SC_set_Result(stmt,  NULL);
            }
        }
 
@@ -230,6 +230,7 @@ SC_Constructor(void)
        rv->hdbc = NULL;        /* no connection associated yet */
        rv->phstmt = NULL;
        rv->result = NULL;
+       rv->curres = NULL;
        rv->manual_result = FALSE;
        rv->prepare = FALSE;
        rv->status = STMT_ALLOCATED;
@@ -238,7 +239,6 @@ SC_Constructor(void)
        rv->errormsg = NULL;
        rv->errornumber = 0;
        rv->errormsg_created = FALSE;
-       rv->errormsg_malloced = FALSE;
 
        rv->statement = NULL;
        rv->stmt_with_params = NULL;
@@ -292,7 +292,9 @@ SC_Constructor(void)
 char
 SC_Destructor(StatementClass *self)
 {
-   mylog("SC_Destructor: self=%u, self->result=%u, self->hdbc=%u\n", self, self->result, self->hdbc);
+   QResultClass    *res = SC_get_Result(self);
+
+   mylog("SC_Destructor: self=%u, self->result=%u, self->hdbc=%u\n", self, res, self->hdbc);
    SC_clear_error(self);
    if (STMT_EXECUTING == self->status)
    {
@@ -301,12 +303,12 @@ SC_Destructor(StatementClass *self)
        return FALSE;
    }
 
-   if (self->result)
+   if (res)
    {
        if (!self->hdbc)
-           self->result->conn = NULL;  /* prevent any dbase activity */
+           res->conn = NULL;   /* prevent any dbase activity */
 
-       QR_Destructor(self->result);
+       QR_Destructor(res);
    }
 
    if (self->statement)
@@ -442,6 +444,7 @@ char
 SC_recycle_statement(StatementClass *self)
 {
    ConnectionClass *conn;
+   QResultClass    *res;
 
    mylog("recycle statement: self= %u\n", self);
 
@@ -514,10 +517,10 @@ SC_recycle_statement(StatementClass *self)
    self->parse_status = STMT_PARSE_NONE;
 
    /* Free any cursors */
-   if (self->result)
+   if (res = SC_get_Result(self), res)
    {
-       QR_Destructor(self->result);
-       self->result = NULL;
+       QR_Destructor(res);
+       SC_set_Result(self, NULL);
    }
    self->inaccurate_result = FALSE;
 
@@ -533,12 +536,9 @@ SC_recycle_statement(StatementClass *self)
    self->bind_row = 0;
    self->last_fetch_count = 0;
 
-   if (self->errormsg_malloced && self->errormsg)
-       free(self->errormsg);
    self->errormsg = NULL;
    self->errornumber = 0;
    self->errormsg_created = FALSE;
-   self->errormsg_malloced = FALSE;
 
    self->lobj_fd = -1;
 
@@ -583,8 +583,8 @@ SC_pre_execute(StatementClass *self)
        }
        if (!SC_is_pre_executable(self))
        {
-           self->result = QR_Constructor();
-           QR_set_status(self->result, PGRES_TUPLES_OK);
+           SC_set_Result(self, QR_Constructor());
+           QR_set_status(SC_get_Result(self), PGRES_TUPLES_OK);
            self->inaccurate_result = TRUE;
            self->status = STMT_PREMATURE;
        }
@@ -617,12 +617,11 @@ SC_unbind_cols(StatementClass *self)
 void
 SC_clear_error(StatementClass *self)
 {
-   if (self->errormsg_malloced && self->errormsg)
-       free(self->errormsg);
    self->errornumber = 0;
    self->errormsg = NULL;
    self->errormsg_created = FALSE;
-   self->errormsg_malloced = FALSE;
+   self->errorpos = 0;
+   self->error_recsize = -1;
 }
 
 
@@ -633,7 +632,7 @@ SC_clear_error(StatementClass *self)
 char *
 SC_create_errormsg(StatementClass *self)
 {
-   QResultClass *res = self->result;
+   QResultClass *res = SC_get_Curres(self);
    ConnectionClass *conn = self->hdbc;
    int         pos;
    static char msg[4096];
@@ -642,10 +641,21 @@ SC_create_errormsg(StatementClass *self)
 
    if (res && res->message)
        strcpy(msg, res->message);
-
    else if (self->errormsg)
        strcpy(msg, self->errormsg);
 
+   if (!msg[0] && res && QR_get_notice(res))
+   {
+       char *notice = QR_get_notice(res);
+       int len = strlen(notice);
+       if (len < sizeof(msg))
+       {
+           memcpy(msg, notice, len);
+           msg[len] = '\0';
+       }
+       else
+           return notice;
+   }
    if (conn)
    {
        SocketClass *sock = conn->sock;
@@ -653,7 +663,7 @@ SC_create_errormsg(StatementClass *self)
        if (conn->errormsg && conn->errormsg[0] != '\0')
        {
            pos = strlen(msg);
-           sprintf(&msg[pos], ";\n%s", conn->errormsg);
+           /*sprintf(&msg[pos], ";\n%s", conn->errormsg);*/
        }
 
        if (sock && sock->errormsg && sock->errormsg[0] != '\0')
@@ -662,9 +672,6 @@ SC_create_errormsg(StatementClass *self)
            sprintf(&msg[pos], ";\n%s", sock->errormsg);
        }
    }
-   if (!msg[0] && res && QR_get_notice(res))
-       return QR_get_notice(res);
-
    return msg;
 }
 
@@ -679,18 +686,17 @@ SC_get_error(StatementClass *self, int *number, char **message)
    {
        self->errormsg = SC_create_errormsg(self);
        self->errormsg_created = TRUE;
+       self->errorpos = 0;
+       self->error_recsize = -1;
    }
 
    if (self->errornumber)
    {
        *number = self->errornumber;
        *message = self->errormsg;
-       if (!self->errormsg_malloced)
-           self->errormsg = NULL;
    }
 
    rv = (self->errornumber != 0);
-   self->errornumber = 0;
 
    return rv;
 }
@@ -712,7 +718,7 @@ RETCODE
 SC_fetch(StatementClass *self)
 {
    static char *func = "SC_fetch";
-   QResultClass *res = self->result;
+   QResultClass *res = SC_get_Curres(self);
    int         retval,
                result;
 
@@ -901,6 +907,7 @@ SC_execute(StatementClass *self)
    static char *func = "SC_execute";
    ConnectionClass *conn;
    char        was_ok, was_nonfatal;
+   QResultClass    *res = NULL;
    Int2        oldstatus,
                numcols;
    QueryInfo   qi;
@@ -952,12 +959,12 @@ SC_execute(StatementClass *self)
        mylog("       Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name);
 
        /* send the declare/select */
-       self->result = CC_send_query(conn, self->stmt_with_params, NULL);
+       res = CC_send_query(conn, self->stmt_with_params, NULL, TRUE);
 
-       if (SC_is_fetchcursor(self) && self->result != NULL &&
-           QR_command_successful(self->result))
+       if (SC_is_fetchcursor(self) && res != NULL &&
+           QR_command_successful(res))
        {
-           QR_Destructor(self->result);
+           QR_Destructor(res);
 
            /*
             * That worked, so now send the fetch to start getting data
@@ -976,7 +983,7 @@ SC_execute(StatementClass *self)
             */
            sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name);
 
-           self->result = CC_send_query(conn, fetch, &qi);
+           res = CC_send_query(conn, fetch, &qi, FALSE);
        }
        mylog("     done sending the query:\n");
    }
@@ -984,7 +991,7 @@ SC_execute(StatementClass *self)
    {
        /* not a SELECT statement so don't use a cursor */
        mylog("      it's NOT a select statement: stmt=%u\n", self);
-       self->result = CC_send_query(conn, self->stmt_with_params, NULL);
+       res = CC_send_query(conn, self->stmt_with_params, NULL, FALSE);
 
        /*
         * We shouldn't send COMMIT. Postgres backend does the autocommit
@@ -1003,10 +1010,10 @@ SC_execute(StatementClass *self)
    self->status = STMT_FINISHED;
 
    /* Check the status of the result */
-   if (self->result)
+   if (res)
    {
-       was_ok = QR_command_successful(self->result);
-       was_nonfatal = QR_command_nonfatal(self->result);
+       was_ok = QR_command_successful(res);
+       was_nonfatal = QR_command_nonfatal(res);
 
        if (was_ok)
            self->errornumber = STMT_OK;
@@ -1018,24 +1025,30 @@ SC_execute(StatementClass *self)
        self->current_col = -1;
        self->rowset_start = -1;
 
-       /* see if the query did return any result columns */
-       numcols = QR_NumResultCols(self->result);
-
-       /* now allocate the array to hold the binding info */
-       if (numcols > 0)
+       /* issue "ABORT" when query aborted */
+       if (QR_get_aborted(res))
        {
-           extend_bindings(self, numcols);
-           if (self->bindings == NULL)
+           if (!self->internal)
+               CC_abort(conn);
+       }
+       else
+       {
+           /* see if the query did return any result columns */
+           numcols = QR_NumResultCols(res);
+           /* now allocate the array to hold the binding info */
+           if (numcols > 0)
            {
-               self->errornumber = STMT_NO_MEMORY_ERROR;
-               self->errormsg = "Could not get enough free memory to store the binding information";
-               SC_log_error(func, "", self);
-               return SQL_ERROR;
+               extend_bindings(self, numcols);
+               if (self->bindings == NULL)
+               {
+                   QR_Destructor(res);
+                   self->errornumber = STMT_NO_MEMORY_ERROR;
+                   self->errormsg = "Could not get enough free memory to store the binding information";
+                   SC_log_error(func, "", self);
+                   return SQL_ERROR;
+               }
            }
        }
-       /* issue "ABORT" when query aborted */
-       if (QR_get_aborted(self->result) && !self->internal)
-           CC_abort(conn);
    }
    else
    {
@@ -1061,6 +1074,15 @@ SC_execute(StatementClass *self)
        if (!self->internal)
            CC_abort(conn);
    }
+   if (!SC_get_Result(self))
+       SC_set_Result(self, res);
+   else
+   {
+       QResultClass    *last;
+       for (last = SC_get_Result(self); last->next; last = last->next)
+           ;
+       last->next = res;
+   }
 
    if (self->statement_type == STMT_TYPE_PROCCALL &&
        (self->errornumber == STMT_OK ||
@@ -1095,7 +1117,8 @@ SC_execute(StatementClass *self)
        return SQL_SUCCESS_WITH_INFO;
    else
    {
-       self->errormsg = "Error while executing the query";
+       if (!self->errormsg || !self->errormsg[0])
+           self->errormsg = "Error while executing the query";
        SC_log_error(func, "", self);
        return SQL_ERROR;
    }
@@ -1103,17 +1126,19 @@ SC_execute(StatementClass *self)
 
 
 void
-SC_log_error(char *func, char *desc, StatementClass *self)
+SC_log_error(const char *func, const char *desc, const StatementClass *self)
 {
 #ifdef PRN_NULLCHECK
 #define nullcheck(a) (a ? a : "(NULL)")
 #endif
    if (self)
    {
+       QResultClass *res = SC_get_Result(self);
+
        qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
        mylog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
        qlog("                 ------------------------------------------------------------\n");
-       qlog("                 hdbc=%u, stmt=%u, result=%u\n", self->hdbc, self, self->result);
+       qlog("                 hdbc=%u, stmt=%u, result=%u\n", self->hdbc, self, res);
        qlog("                 manual_result=%d, prepare=%d, internal=%d\n", self->manual_result, self->prepare, self->internal);
        qlog("                 bindings=%u, bindings_allocated=%d\n", self->bindings, self->bindings_allocated);
        qlog("                 parameters=%u, parameters_allocated=%d\n", self->parameters, self->parameters_allocated);
@@ -1126,10 +1151,8 @@ SC_log_error(char *func, char *desc, StatementClass *self)
 
        qlog("                 ----------------QResult Info -------------------------------\n");
 
-       if (self->result)
+       if (res)
        {
-           QResultClass *res = self->result;
-
            qlog("                 fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn);
            qlog("                 fetch_count=%d, fcount=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->fcount, res->num_fields, nullcheck(res->cursor));
            qlog("                 message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
@@ -1140,6 +1163,9 @@ SC_log_error(char *func, char *desc, StatementClass *self)
        CC_log_error(func, desc, self->hdbc);
    }
    else
+   {
        qlog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
+       mylog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
+   }
 #undef PRN_NULLCHECK
 }
index 534c8db4d8aa4982fa023ae97f342257024e5347..cf104aa7d1314b1b88dde1058a4cf86bc218a569 100644 (file)
@@ -103,7 +103,7 @@ enum
    STMT_PARSE_NONE = 0,
    STMT_PARSE_COMPLETE,
    STMT_PARSE_INCOMPLETE,
-   STMT_PARSE_FATAL
+   STMT_PARSE_FATAL,
 };
 
 /* Result style */
@@ -111,7 +111,7 @@ enum
 {
    STMT_FETCH_NONE = 0,
    STMT_FETCH_NORMAL,
-   STMT_FETCH_EXTENDED
+   STMT_FETCH_EXTENDED,
 };
 
 typedef struct
@@ -147,6 +147,7 @@ struct StatementClass_
    ConnectionClass *hdbc;      /* pointer to ConnectionClass this
                                 * statement belongs to */
    QResultClass *result;       /* result of the current statement */
+   QResultClass *curres;       /* the current result in the chain */
    HSTMT FAR  *phstmt;
    StatementOptions options;
 
@@ -215,14 +216,15 @@ struct StatementClass_
    char        pre_executing;  /* This statement is prematurely executing */
    char        inaccurate_result;      /* Current status is PREMATURE but
                                         * result is inaccurate */
-   char        errormsg_malloced;      /* Current error message is
-                                        * malloed (not in a static
-                                        * variable) ? */
    char        miscinfo;
+   SWORD       errorpos;
+   SWORD       error_recsize;
 };
 
 #define SC_get_conn(a)   (a->hdbc)
-#define SC_get_Result(a)  (a->result);
+#define SC_set_Result(a, b)  (a->result = a->curres = b)
+#define SC_get_Result(a)  (a->result)
+#define SC_get_Curres(a)  (a->curres)
 
 /* options for SC_free_params() */
 #define STMT_FREE_PARAMS_ALL               0
@@ -252,7 +254,7 @@ char       *SC_create_errormsg(StatementClass *self);
 RETCODE        SC_execute(StatementClass *self);
 RETCODE        SC_fetch(StatementClass *self);
 void       SC_free_params(StatementClass *self, char option);
-void       SC_log_error(char *func, char *desc, StatementClass *self);
+void       SC_log_error(const char *func, const char *desc, const StatementClass *self);
 unsigned long SC_get_bookmark(StatementClass *self);
 
 #endif
index 1d92eec1bb421ba51b5203a61a7e04ba35b29483..637e37633760099ad0175dcea2ee6b7a7a903085 100644 (file)
@@ -31,7 +31,7 @@ CFG=Release
 !MESSAGE "Release" (Win32 Release DLL)
 !MESSAGE "Debug" (Win32 Debug DLL)
 !MESSAGE "MultibyteRelease" (Win32 Release DLL with Multibyte support)
-!MESSAGE "MultibyteDebug" (Win32 Release DLL with Multibyte support)
+!MESSAGE "MultibyteDebug" (Win32 Debug DLL with Multibyte support)
 !MESSAGE 
 !ERROR An invalid configuration was specified.
 !ENDIF 
@@ -46,13 +46,15 @@ NULL=nul
 
 !IF "$(CFG)" == "MultibyteRelease"
 OUTDIR=.\MultibyteRelease
+OUTDIRBIN=.\MultibyteRelease
 INTDIR=.\MultibyteRelease
 !ELSE
 OUTDIR=.\Release
+OUTDIRBIN=.\Release
 INTDIR=.\Release
 !ENDIF
 
-ALL : "$(OUTDIR)\psqlodbc.dll"
+ALL : "$(OUTDIRBIN)\psqlodbc.dll"
 
 
 CLEAN :
@@ -64,7 +66,6 @@ CLEAN :
    -@erase "$(INTDIR)\drvconn.obj"
    -@erase "$(INTDIR)\environ.obj"
    -@erase "$(INTDIR)\execute.obj"
-   -@erase "$(INTDIR)\gpps.obj"
    -@erase "$(INTDIR)\info.obj"
    -@erase "$(INTDIR)\lobj.obj"
    -@erase "$(INTDIR)\win_md5.obj"
@@ -139,7 +140,7 @@ BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc"
 BSC32_SBRS= \
    
 LINK32=link.exe
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"psqlodbc_win32.def" /out:"$(OUTDIR)\psqlodbc.dll" /implib:"$(OUTDIR)\psqlodbc.lib" 
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"psqlodbc_win32.def" /out:"$(OUTDIRBIN)\psqlodbc.dll" /implib:"$(OUTDIR)\psqlodbc.lib" 
 DEF_FILE= "psqlodbc_win32.def"
 LINK32_OBJS= \
    "$(INTDIR)\bind.obj" \
@@ -150,7 +151,6 @@ LINK32_OBJS= \
    "$(INTDIR)\drvconn.obj" \
    "$(INTDIR)\environ.obj" \
    "$(INTDIR)\execute.obj" \
-   "$(INTDIR)\gpps.obj" \
    "$(INTDIR)\info.obj" \
    "$(INTDIR)\lobj.obj" \
    "$(INTDIR)\win_md5.obj" \
@@ -172,7 +172,7 @@ LINK32_OBJS= \
    "$(INTDIR)\odbcapi.obj" \
    "$(INTDIR)\psqlodbc.res"
 
-"$(OUTDIR)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+"$(OUTDIRBIN)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
     $(LINK32) @<<
   $(LINK32_FLAGS) $(LINK32_OBJS)
 <<
@@ -199,7 +199,6 @@ CLEAN :
    -@erase "$(INTDIR)\drvconn.obj"
    -@erase "$(INTDIR)\environ.obj"
    -@erase "$(INTDIR)\execute.obj"
-   -@erase "$(INTDIR)\gpps.obj"
    -@erase "$(INTDIR)\info.obj"
    -@erase "$(INTDIR)\lobj.obj"
    -@erase "$(INTDIR)\win_md5.obj"
@@ -288,7 +287,6 @@ LINK32_OBJS= \
    "$(INTDIR)\drvconn.obj" \
    "$(INTDIR)\environ.obj" \
    "$(INTDIR)\execute.obj" \
-   "$(INTDIR)\gpps.obj" \
    "$(INTDIR)\info.obj" \
    "$(INTDIR)\lobj.obj" \
    "$(INTDIR)\win_md5.obj"
@@ -367,12 +365,6 @@ SOURCE=execute.c
    $(CPP) $(CPP_PROJ) $(SOURCE)
 
 
-SOURCE=gpps.c
-
-"$(INTDIR)\gpps.obj" : $(SOURCE) "$(INTDIR)"
-   $(CPP) $(CPP_PROJ) $(SOURCE)
-
-
 SOURCE=info.c
 
 "$(INTDIR)\info.obj" : $(SOURCE) "$(INTDIR)"
index 021b22c3bd1968bd6d657953358a12e02cda7969..355d5a3a1abbb4176c8ef37d5ec3e6e5f44138b4 100755 (executable)
@@ -88,6 +88,7 @@ CLEAN :
    -@erase "$(INTDIR)\tuplelist.obj"
    -@erase "$(INTDIR)\odbcapi.obj"
    -@erase "$(INTDIR)\odbcapi30.obj"
+   -@erase "$(INTDIR)\pgapi30.obj"
    -@erase "$(INTDIR)\vc60.idb"
    -@erase "$(OUTDIR)\psqlodbc30.dll"
    -@erase "$(OUTDIR)\psqlodbc.exp"
@@ -174,6 +175,7 @@ LINK32_OBJS= \
    "$(INTDIR)\tuplelist.obj" \
    "$(INTDIR)\odbcapi.obj" \
    "$(INTDIR)\odbcapi30.obj" \
+   "$(INTDIR)\pgapi30.obj" \
    "$(INTDIR)\psqlodbc.res"
 
 "$(OUTDIRBIN)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@@ -225,6 +227,7 @@ CLEAN :
    -@erase "$(INTDIR)\tuplelist.obj"
    -@erase "$(INTDIR)\odbcapi.obj"
    -@erase "$(INTDIR)\odbcapi30.obj"
+   -@erase "$(INTDIR)\pgapi30.obj"
    -@erase "$(INTDIR)\vc60.idb"
    -@erase "$(INTDIR)\vc60.pdb"
    -@erase "$(OUTDIR)\psqlodbc30.dll"
@@ -314,6 +317,7 @@ LINK32_OBJS= \
    "$(INTDIR)\tuplelist.obj" \
    "$(INTDIR)\odbcapi.obj" \
    "$(INTDIR)\odbcapi30.obj" \
+   "$(INTDIR)\pgapi30.obj" \
    "$(INTDIR)\psqlodbc.res"
 
 "$(OUTDIR)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@@ -513,7 +517,10 @@ SOURCE=odbcapi30.c
 "$(INTDIR)\odbcapi30.obj" : $(SOURCE) "$(INTDIR)"
    $(CPP) $(CPP_PROJ) $(SOURCE)
 
+SOURCE=pgcapi30.c
 
+"$(INTDIR)\pgcapi30.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
 
 
 !ENDIF 
diff --git a/src/interfaces/odbc/win32_30w.mak b/src/interfaces/odbc/win32_30w.mak
new file mode 100644 (file)
index 0000000..4455069
--- /dev/null
@@ -0,0 +1,508 @@
+#
+# File:            win32_30w.mak
+#
+# Description:     psqlodbc30 Unicode version Makefile for Win32.
+#
+# Configurations:  Unicode30Debug, Unicode30
+# Build Types:     ALL, CLEAN
+# Usage:       NMAKE /f win32_30.mak CFG=[Unicode30 | Unicode30Debug] [ALL | CLEAN]
+#
+# Comments:        Created by Dave Page, 2001-02-12
+#
+
+!MESSAGE Building the PostgreSQL Unicode 3.0 Driver for Win32...
+!MESSAGE
+!IF "$(CFG)" == ""
+CFG=Unicode30
+!MESSAGE No configuration specified. Defaulting to Unicode30.
+!MESSAGE
+!ENDIF 
+
+!IF "$(CFG)" != "Unicode30" && "$(CFG)" != "Unicode30Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f win32_30.mak CFG=[Unicode30 | Unicode30Debug] [ALL | CLEAN]
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "Unicode30" (Win32 Release DLL)
+!MESSAGE "Unicode30Debug" (Win32 Debug DLL)
+!MESSAGE 
+!ERROR An invalid configuration was specified.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+!IF  "$(CFG)" == "Unicode30"
+
+OUTDIR=.\Unicode30
+OUTDIRBIN=.\Unicode30
+INTDIR=.\Unicode30
+
+ALL : "$(OUTDIRBIN)\psqlodbc30.dll"
+
+
+CLEAN :
+   -@erase "$(INTDIR)\bind.obj"
+   -@erase "$(INTDIR)\columninfo.obj"
+   -@erase "$(INTDIR)\connection.obj"
+   -@erase "$(INTDIR)\convert.obj"
+   -@erase "$(INTDIR)\dlg_specific.obj"
+   -@erase "$(INTDIR)\drvconn.obj"
+   -@erase "$(INTDIR)\environ.obj"
+   -@erase "$(INTDIR)\execute.obj"
+   -@erase "$(INTDIR)\info.obj"
+   -@erase "$(INTDIR)\info30.obj"
+   -@erase "$(INTDIR)\lobj.obj"
+   -@erase "$(INTDIR)\win_md5.obj"
+   -@erase "$(INTDIR)\misc.obj"
+   -@erase "$(INTDIR)\pgapi30.obj"
+   -@erase "$(INTDIR)\multibyte.obj"
+   -@erase "$(INTDIR)\odbcapiw.obj"
+   -@erase "$(INTDIR)\odbcapi30w.obj"
+   -@erase "$(INTDIR)\win_unicode.obj"
+   -@erase "$(INTDIR)\options.obj"
+   -@erase "$(INTDIR)\parse.obj"
+   -@erase "$(INTDIR)\pgtypes.obj"
+   -@erase "$(INTDIR)\psqlodbc.obj"
+   -@erase "$(INTDIR)\psqlodbc.res"
+   -@erase "$(INTDIR)\qresult.obj"
+   -@erase "$(INTDIR)\results.obj"
+   -@erase "$(INTDIR)\setup.obj"
+   -@erase "$(INTDIR)\socket.obj"
+   -@erase "$(INTDIR)\statement.obj"
+   -@erase "$(INTDIR)\tuple.obj"
+   -@erase "$(INTDIR)\tuplelist.obj"
+   -@erase "$(INTDIR)\odbcapi.obj"
+   -@erase "$(INTDIR)\odbcapi30.obj"
+   -@erase "$(INTDIR)\vc60.idb"
+   -@erase "$(OUTDIR)\psqlodbc30.dll"
+   -@erase "$(OUTDIR)\psqlodbc.exp"
+   -@erase "$(OUTDIR)\psqlodbc.lib"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0300" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG" 
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc" 
+BSC32_SBRS= \
+   
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"psqlodbc_api30w.def" /out:"$(OUTDIRBIN)\psqlodbc30.dll" /implib:"$(OUTDIR)\psqlodbc.lib" 
+DEF_FILE= "psqlodbc_api30w.def"
+LINK32_OBJS= \
+   "$(INTDIR)\bind.obj" \
+   "$(INTDIR)\columninfo.obj" \
+   "$(INTDIR)\connection.obj" \
+   "$(INTDIR)\convert.obj" \
+   "$(INTDIR)\dlg_specific.obj" \
+   "$(INTDIR)\drvconn.obj" \
+   "$(INTDIR)\environ.obj" \
+   "$(INTDIR)\execute.obj" \
+   "$(INTDIR)\info.obj" \
+   "$(INTDIR)\info30.obj" \
+   "$(INTDIR)\lobj.obj" \
+   "$(INTDIR)\win_md5.obj" \
+   "$(INTDIR)\misc.obj" \
+   "$(INTDIR)\pgapi30.obj" \
+   "$(INTDIR)\multibyte.obj" \
+   "$(INTDIR)\odbcapiw.obj" \
+   "$(INTDIR)\odbcapi30w.obj" \
+   "$(INTDIR)\win_unicode.obj" \
+   "$(INTDIR)\options.obj" \
+   "$(INTDIR)\parse.obj" \
+   "$(INTDIR)\pgtypes.obj" \
+   "$(INTDIR)\psqlodbc.obj" \
+   "$(INTDIR)\qresult.obj" \
+   "$(INTDIR)\results.obj" \
+   "$(INTDIR)\setup.obj" \
+   "$(INTDIR)\socket.obj" \
+   "$(INTDIR)\statement.obj" \
+   "$(INTDIR)\tuple.obj" \
+   "$(INTDIR)\tuplelist.obj" \
+   "$(INTDIR)\odbcapi.obj" \
+   "$(INTDIR)\odbcapi30.obj" \
+   "$(INTDIR)\psqlodbc.res"
+
+"$(OUTDIRBIN)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "Unicode30Debug"
+
+ALL : "$(OUTDIR)\psqlodbc30.dll"
+
+
+CLEAN :
+   -@erase "$(INTDIR)\bind.obj"
+   -@erase "$(INTDIR)\columninfo.obj"
+   -@erase "$(INTDIR)\connection.obj"
+   -@erase "$(INTDIR)\convert.obj"
+   -@erase "$(INTDIR)\dlg_specific.obj"
+   -@erase "$(INTDIR)\drvconn.obj"
+   -@erase "$(INTDIR)\environ.obj"
+   -@erase "$(INTDIR)\execute.obj"
+   -@erase "$(INTDIR)\info.obj"
+   -@erase "$(INTDIR)\info30.obj"
+   -@erase "$(INTDIR)\lobj.obj"
+   -@erase "$(INTDIR)\win_md5.obj"
+   -@erase "$(INTDIR)\misc.obj"
+   -@erase "$(INTDIR)\pgapi30.obj"
+   -@erase "$(INTDIR)\multibyte.obj"
+   -@erase "$(INTDIR)\odbcapiw.obj"
+   -@erase "$(INTDIR)\odbcapi30w.obj"
+   -@erase "$(INTDIR)\win_unicode.obj"
+   -@erase "$(INTDIR)\options.obj"
+   -@erase "$(INTDIR)\parse.obj"
+   -@erase "$(INTDIR)\pgtypes.obj"
+   -@erase "$(INTDIR)\psqlodbc.obj"
+   -@erase "$(INTDIR)\psqlodbc.res"
+   -@erase "$(INTDIR)\qresult.obj"
+   -@erase "$(INTDIR)\results.obj"
+   -@erase "$(INTDIR)\setup.obj"
+   -@erase "$(INTDIR)\socket.obj"
+   -@erase "$(INTDIR)\statement.obj"
+   -@erase "$(INTDIR)\tuple.obj"
+   -@erase "$(INTDIR)\tuplelist.obj"
+   -@erase "$(INTDIR)\odbcapi.obj"
+   -@erase "$(INTDIR)\odbcapi30.obj"
+   -@erase "$(INTDIR)\vc60.idb"
+   -@erase "$(INTDIR)\vc60.pdb"
+   -@erase "$(OUTDIR)\psqlodbc30.dll"
+   -@erase "$(OUTDIR)\psqlodbc.exp"
+   -@erase "$(OUTDIR)\psqlodbc.ilk"
+   -@erase "$(OUTDIR)\psqlodbc.lib"
+   -@erase "$(OUTDIR)\psqlodbc.pdb"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0300" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG" 
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc" 
+BSC32_SBRS= \
+   
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\psqlodbc.pdb" /debug /machine:I386 /def:"psqlodbc_api30w.def" /out:"$(OUTDIR)\psqlodbc30.dll" /implib:"$(OUTDIR)\psqlodbc.lib" /pdbtype:sept 
+DEF_FILE= "psqlodbc_api30w.def"
+LINK32_OBJS= \
+   "$(INTDIR)\bind.obj" \
+   "$(INTDIR)\columninfo.obj" \
+   "$(INTDIR)\connection.obj" \
+   "$(INTDIR)\convert.obj" \
+   "$(INTDIR)\dlg_specific.obj" \
+   "$(INTDIR)\drvconn.obj" \
+   "$(INTDIR)\environ.obj" \
+   "$(INTDIR)\execute.obj" \
+   "$(INTDIR)\info.obj" \
+   "$(INTDIR)\info30.obj" \
+   "$(INTDIR)\lobj.obj" \
+   "$(INTDIR)\win_md5.obj"
+   "$(INTDIR)\misc.obj" \
+   "$(INTDIR)\pgapi30.obj" \
+   "$(INTDIR)\multibyte.obj" \
+   "$(INTDIR)\odbcapiw.obj" \
+   "$(INTDIR)\odbcapi30w.obj" \
+   "$(INTDIR)\win_unicode.obj" \
+   "$(INTDIR)\options.obj" \
+   "$(INTDIR)\parse.obj" \
+   "$(INTDIR)\pgtypes.obj" \
+   "$(INTDIR)\psqlodbc.obj" \
+   "$(INTDIR)\qresult.obj" \
+   "$(INTDIR)\results.obj" \
+   "$(INTDIR)\setup.obj" \
+   "$(INTDIR)\socket.obj" \
+   "$(INTDIR)\statement.obj" \
+   "$(INTDIR)\tuple.obj" \
+   "$(INTDIR)\tuplelist.obj" \
+   "$(INTDIR)\odbcapi.obj" \
+   "$(INTDIR)\odbcapi30.obj" \
+   "$(INTDIR)\psqlodbc.res"
+
+"$(OUTDIR)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF 
+
+!IF "$(CFG)" == "Unicode30" || "$(CFG)" == "Unicode30Debug"
+
+SOURCE=bind.c
+
+"$(INTDIR)\bind.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=columninfo.c
+
+"$(INTDIR)\columninfo.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=connection.c
+
+"$(INTDIR)\connection.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=convert.c
+
+"$(INTDIR)\convert.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=dlg_specific.c
+
+"$(INTDIR)\dlg_specific.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=drvconn.c
+
+"$(INTDIR)\drvconn.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=environ.c
+
+"$(INTDIR)\environ.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=execute.c
+
+"$(INTDIR)\execute.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=info.c
+
+"$(INTDIR)\info.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=info30.c
+
+"$(INTDIR)\info30.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=lobj.c
+
+"$(INTDIR)\lobj.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=misc.c
+
+"$(INTDIR)\misc.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=multibyte.c
+
+"$(INTDIR)\multibyte.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=odbcapiw.c
+
+"$(INTDIR)\odbcapiw.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=pgapi30.c
+
+"$(INTDIR)\pgapi30.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=odbcapi30w.c
+
+"$(INTDIR)\odbcapi30w.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=win_unicode.c
+
+"$(INTDIR)\win_unicode.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=options.c
+
+"$(INTDIR)\options.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=parse.c
+
+"$(INTDIR)\parse.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=pgtypes.c
+
+"$(INTDIR)\pgtypes.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=psqlodbc.c
+
+"$(INTDIR)\psqlodbc.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=psqlodbc.rc
+
+!IF "$(CFG)" == "Unicode30"
+"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)"
+   $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG" /d "MULTIBYTE" $(SOURCE)
+!ENDIF
+
+!IF "$(CFG)" == "Unicode30Debug"
+"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)"
+   $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG" $(SOURCE)
+!ENDIF
+
+
+SOURCE=qresult.c
+
+"$(INTDIR)\qresult.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=results.c
+
+"$(INTDIR)\results.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=setup.c
+
+"$(INTDIR)\setup.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=socket.c
+
+"$(INTDIR)\socket.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=statement.c
+
+"$(INTDIR)\statement.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=tuple.c
+
+"$(INTDIR)\tuple.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=tuplelist.c
+
+"$(INTDIR)\tuplelist.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=win_md5.c
+
+"$(INTDIR)\win_md5.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=odbcapi.c
+
+"$(INTDIR)\odbcapi.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=odbcapi30.c
+
+"$(INTDIR)\odbcapi30.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+
+
+!ENDIF 
diff --git a/src/interfaces/odbc/win32w.mak b/src/interfaces/odbc/win32w.mak
new file mode 100644 (file)
index 0000000..24a57a1
--- /dev/null
@@ -0,0 +1,478 @@
+#
+# File:            win32w.mak
+#
+# Description:     psqlodbc Unicode version Makefile for Win32.
+#
+# Configurations:  UnicodeDebug, Unicode
+# Build Types:     ALL, CLEAN
+# Usage:       NMAKE /f win32w.mak CFG=[Unicode | UnicodeDebug] [ALL | CLEAN]
+#
+# Comments:        Created by Dave Page, 2001-02-12
+#
+
+!MESSAGE Building the PostgreSQL Unicode Driver for Win32...
+!MESSAGE
+!IF "$(CFG)" == ""
+CFG=Unicode
+!MESSAGE No configuration specified. Defaulting to Unicode.
+!MESSAGE
+!ENDIF 
+
+!IF "$(CFG)" != "Unicode" && "$(CFG)" != "UnicodeDebug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f win32w.mak CFG=[Unicode | UnicodeDebug] [ALL | CLEAN]
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "Unicode" (Win32 Release DLL)
+!MESSAGE "UnicodeDebug" (Win32 Debug DLL)
+!MESSAGE 
+!ERROR An invalid configuration was specified.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+!IF  "$(CFG)" == "Unicode"
+
+OUTDIR=.\Unicode
+OUTDIRBIN=.\Unicode
+INTDIR=.\Unicode
+
+ALL : "$(OUTDIRBIN)\psqlodbc.dll"
+
+
+CLEAN :
+   -@erase "$(INTDIR)\bind.obj"
+   -@erase "$(INTDIR)\columninfo.obj"
+   -@erase "$(INTDIR)\connection.obj"
+   -@erase "$(INTDIR)\convert.obj"
+   -@erase "$(INTDIR)\dlg_specific.obj"
+   -@erase "$(INTDIR)\drvconn.obj"
+   -@erase "$(INTDIR)\environ.obj"
+   -@erase "$(INTDIR)\execute.obj"
+   -@erase "$(INTDIR)\info.obj"
+   -@erase "$(INTDIR)\lobj.obj"
+   -@erase "$(INTDIR)\win_md5.obj"
+   -@erase "$(INTDIR)\misc.obj"
+   -@erase "$(INTDIR)\multibyte.obj"
+   -@erase "$(INTDIR)\odbcapiw.obj"
+   -@erase "$(INTDIR)\odbcapi25w.obj"
+   -@erase "$(INTDIR)\win_unicode.obj"
+   -@erase "$(INTDIR)\options.obj"
+   -@erase "$(INTDIR)\parse.obj"
+   -@erase "$(INTDIR)\pgtypes.obj"
+   -@erase "$(INTDIR)\psqlodbc.obj"
+   -@erase "$(INTDIR)\psqlodbc.res"
+   -@erase "$(INTDIR)\qresult.obj"
+   -@erase "$(INTDIR)\results.obj"
+   -@erase "$(INTDIR)\setup.obj"
+   -@erase "$(INTDIR)\socket.obj"
+   -@erase "$(INTDIR)\statement.obj"
+   -@erase "$(INTDIR)\tuple.obj"
+   -@erase "$(INTDIR)\tuplelist.obj"
+   -@erase "$(INTDIR)\odbcapi.obj"
+   -@erase "$(INTDIR)\vc60.idb"
+   -@erase "$(OUTDIR)\psqlodbc.dll"
+   -@erase "$(OUTDIR)\psqlodbc.exp"
+   -@erase "$(OUTDIR)\psqlodbc.lib"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0250" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG" 
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc" 
+BSC32_SBRS= \
+   
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"psqlodbc_apiw.def" /out:"$(OUTDIRBIN)\psqlodbc.dll" /implib:"$(OUTDIR)\psqlodbc.lib" 
+DEF_FILE= "psqlodbc_apiw.def"
+LINK32_OBJS= \
+   "$(INTDIR)\bind.obj" \
+   "$(INTDIR)\columninfo.obj" \
+   "$(INTDIR)\connection.obj" \
+   "$(INTDIR)\convert.obj" \
+   "$(INTDIR)\dlg_specific.obj" \
+   "$(INTDIR)\drvconn.obj" \
+   "$(INTDIR)\environ.obj" \
+   "$(INTDIR)\execute.obj" \
+   "$(INTDIR)\info.obj" \
+   "$(INTDIR)\lobj.obj" \
+   "$(INTDIR)\win_md5.obj" \
+   "$(INTDIR)\misc.obj" \
+   "$(INTDIR)\multibyte.obj" \
+   "$(INTDIR)\odbcapiw.obj" \
+   "$(INTDIR)\odbcapi25w.obj" \
+   "$(INTDIR)\win_unicode.obj" \
+   "$(INTDIR)\options.obj" \
+   "$(INTDIR)\parse.obj" \
+   "$(INTDIR)\pgtypes.obj" \
+   "$(INTDIR)\psqlodbc.obj" \
+   "$(INTDIR)\qresult.obj" \
+   "$(INTDIR)\results.obj" \
+   "$(INTDIR)\setup.obj" \
+   "$(INTDIR)\socket.obj" \
+   "$(INTDIR)\statement.obj" \
+   "$(INTDIR)\tuple.obj" \
+   "$(INTDIR)\tuplelist.obj" \
+   "$(INTDIR)\odbcapi.obj" \
+   "$(INTDIR)\psqlodbc.res"
+
+"$(OUTDIRBIN)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "UnicodeDebug"
+
+ALL : "$(OUTDIR)\psqlodbc.dll"
+
+
+CLEAN :
+   -@erase "$(INTDIR)\bind.obj"
+   -@erase "$(INTDIR)\columninfo.obj"
+   -@erase "$(INTDIR)\connection.obj"
+   -@erase "$(INTDIR)\convert.obj"
+   -@erase "$(INTDIR)\dlg_specific.obj"
+   -@erase "$(INTDIR)\drvconn.obj"
+   -@erase "$(INTDIR)\environ.obj"
+   -@erase "$(INTDIR)\execute.obj"
+   -@erase "$(INTDIR)\info.obj"
+   -@erase "$(INTDIR)\lobj.obj"
+   -@erase "$(INTDIR)\win_md5.obj"
+   -@erase "$(INTDIR)\misc.obj"
+   -@erase "$(INTDIR)\multibyte.obj"
+   -@erase "$(INTDIR)\odbcapiw.obj"
+   -@erase "$(INTDIR)\odbcapi25w.obj"
+   -@erase "$(INTDIR)\win_unicode.obj"
+   -@erase "$(INTDIR)\options.obj"
+   -@erase "$(INTDIR)\parse.obj"
+   -@erase "$(INTDIR)\pgtypes.obj"
+   -@erase "$(INTDIR)\psqlodbc.obj"
+   -@erase "$(INTDIR)\psqlodbc.res"
+   -@erase "$(INTDIR)\qresult.obj"
+   -@erase "$(INTDIR)\results.obj"
+   -@erase "$(INTDIR)\setup.obj"
+   -@erase "$(INTDIR)\socket.obj"
+   -@erase "$(INTDIR)\statement.obj"
+   -@erase "$(INTDIR)\tuple.obj"
+   -@erase "$(INTDIR)\tuplelist.obj"
+   -@erase "$(INTDIR)\odbcapi.obj"
+   -@erase "$(INTDIR)\vc60.idb"
+   -@erase "$(INTDIR)\vc60.pdb"
+   -@erase "$(OUTDIR)\psqlodbc.dll"
+   -@erase "$(OUTDIR)\psqlodbc.exp"
+   -@erase "$(OUTDIR)\psqlodbc.ilk"
+   -@erase "$(OUTDIR)\psqlodbc.lib"
+   -@erase "$(OUTDIR)\psqlodbc.pdb"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0250" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG" 
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc" 
+BSC32_SBRS= \
+   
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\psqlodbc.pdb" /debug /machine:I386 /def:"psqlodbc_apiw.def" /out:"$(OUTDIR)\psqlodbc.dll" /implib:"$(OUTDIR)\psqlodbc.lib" /pdbtype:sept 
+DEF_FILE= "psqlodbc_apiw.def"
+LINK32_OBJS= \
+   "$(INTDIR)\bind.obj" \
+   "$(INTDIR)\columninfo.obj" \
+   "$(INTDIR)\connection.obj" \
+   "$(INTDIR)\convert.obj" \
+   "$(INTDIR)\dlg_specific.obj" \
+   "$(INTDIR)\drvconn.obj" \
+   "$(INTDIR)\environ.obj" \
+   "$(INTDIR)\execute.obj" \
+   "$(INTDIR)\info.obj" \
+   "$(INTDIR)\lobj.obj" \
+   "$(INTDIR)\win_md5.obj"
+   "$(INTDIR)\misc.obj" \
+   "$(INTDIR)\multibyte.obj" \
+   "$(INTDIR)\odbcapiw.obj" \
+   "$(INTDIR)\odbcapi25w.obj" \
+   "$(INTDIR)\win_unicode.obj" \
+   "$(INTDIR)\options.obj" \
+   "$(INTDIR)\parse.obj" \
+   "$(INTDIR)\pgtypes.obj" \
+   "$(INTDIR)\psqlodbc.obj" \
+   "$(INTDIR)\qresult.obj" \
+   "$(INTDIR)\results.obj" \
+   "$(INTDIR)\setup.obj" \
+   "$(INTDIR)\socket.obj" \
+   "$(INTDIR)\statement.obj" \
+   "$(INTDIR)\tuple.obj" \
+   "$(INTDIR)\tuplelist.obj" \
+   "$(INTDIR)\odbcapi.obj" \
+   "$(INTDIR)\psqlodbc.res"
+
+"$(OUTDIR)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF 
+
+!IF "$(CFG)" == "Unicode" || "$(CFG)" == "UnicodeDebug"
+
+SOURCE=bind.c
+
+"$(INTDIR)\bind.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=columninfo.c
+
+"$(INTDIR)\columninfo.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=connection.c
+
+"$(INTDIR)\connection.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=convert.c
+
+"$(INTDIR)\convert.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=dlg_specific.c
+
+"$(INTDIR)\dlg_specific.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=drvconn.c
+
+"$(INTDIR)\drvconn.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=environ.c
+
+"$(INTDIR)\environ.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=execute.c
+
+"$(INTDIR)\execute.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=info.c
+
+"$(INTDIR)\info.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=lobj.c
+
+"$(INTDIR)\lobj.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=misc.c
+
+"$(INTDIR)\misc.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=multibyte.c
+
+"$(INTDIR)\multibyte.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=odbcapiw.c
+
+"$(INTDIR)\odbcapiw.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=odbcapi25w.c
+
+"$(INTDIR)\odbcapi25w.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=win_unicode.c
+
+"$(INTDIR)\win_unicode.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=options.c
+
+"$(INTDIR)\options.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=parse.c
+
+"$(INTDIR)\parse.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=pgtypes.c
+
+"$(INTDIR)\pgtypes.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=psqlodbc.c
+
+"$(INTDIR)\psqlodbc.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=psqlodbc.rc
+
+!IF "$(CFG)" == "Unicode"
+"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)"
+   $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG" /d "MULTIBYTE" $(SOURCE)
+!ENDIF
+
+!IF "$(CFG)" == "UnicodeDebug"
+"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)"
+   $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG" $(SOURCE)
+!ENDIF
+
+
+SOURCE=qresult.c
+
+"$(INTDIR)\qresult.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=results.c
+
+"$(INTDIR)\results.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=setup.c
+
+"$(INTDIR)\setup.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=socket.c
+
+"$(INTDIR)\socket.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=statement.c
+
+"$(INTDIR)\statement.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=tuple.c
+
+"$(INTDIR)\tuple.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=tuplelist.c
+
+"$(INTDIR)\tuplelist.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=win_md5.c
+
+"$(INTDIR)\win_md5.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=odbcapi.c
+
+"$(INTDIR)\odbcapi.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+
+!ENDIF 
index 11a8e396a59d9a7b63557fb0ac4596980693b778..3dfc9ff43d4e5ad2fcd79b54ab9713cebf217663 100644 (file)
 #define    byte3_mask2 0x0fc0
 #define    byte3_mask3 0x003f
 
+UInt4  ucs2strlen(const SQLWCHAR *ucs2str)
+{
+   UInt4   len;
+   for (len = 0; ucs2str[len]; len++)
+       ;
+   return len;
+}
 char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen)
 {
    char *  utf8str;
@@ -28,24 +35,21 @@ char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen)
    if (!ucs2str)
        return NULL;
    if (ilen < 0)
-   {
-       for (ilen = 0; ucs2str[ilen]; ilen++)
-           ;
-   }
+       ilen = ucs2strlen(ucs2str);
 /*mylog(" newlen=%d", ilen);*/
    utf8str = (char *) malloc(ilen * 3 + 1);
    if (utf8str)
    {
        int i, len = 0;
-       Int2        byte2code;
-       Int4        byte4code;
-
+       UInt2   byte2code;
+       Int4    byte4code;
        const SQLWCHAR  *wstr;
+
        for (i = 0, wstr = ucs2str; i < ilen; i++, wstr++)
        {
            if (!*wstr)
                break;
-           else if (iswascii(*wstr))
+           else if (0 == (*wstr & 0xff80))
                utf8str[len++] = (char) *wstr;
            else if ((*wstr & byte3check) == 0)
            {
@@ -66,7 +70,8 @@ char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen)
            }
        } 
        utf8str[len] = '\0';
-       *olen = len;
+       if (olen)
+           *olen = len;
    }
 /*mylog(" olen=%d %s\n", *olen, utf8str ? utf8str : "");*/
    return utf8str;
@@ -109,7 +114,7 @@ UInt4   utf8_to_ucs2(const char *utf8str, Int4 ilen, SQLWCHAR *ucs2str, UInt4 bufc
            {
                wcode = ((((UInt4) *str) & byte3_m1) << 12) |
                    ((((UInt4) str[1]) & byte3_m2) << 6) |
-                   ((UInt4) str[2]) & byte3_m3;
+                   (((UInt4) str[2]) & byte3_m3);
                ucs2str[ocount] = (SQLWCHAR) wcode;
            }
            ocount++;
@@ -121,7 +126,7 @@ UInt4   utf8_to_ucs2(const char *utf8str, Int4 ilen, SQLWCHAR *ucs2str, UInt4 bufc
            if (ocount < bufcount)
            {
                wcode = ((((UInt4) *str) & byte2_m1) << 6) |
-                   ((UInt4) str[1]) & byte2_m2;
+                   (((UInt4) str[1]) & byte2_m2);
                ucs2str[ocount] = (SQLWCHAR) wcode;
            }
            ocount++;