Added to commit 7849ba( was a patch by Tsunakawa,Takayuki).
authorHiroshi Inoue <h-inoue@dream.email.ne.jp>
Tue, 25 Oct 2016 09:58:12 +0000 (18:58 +0900)
committerHiroshi Inoue <h-inoue@dream.email.ne.jp>
Wed, 2 Nov 2016 11:35:23 +0000 (20:35 +0900)
Now default isolation level is server's default instead of fixed SQL_TXN_READ_COMMITTED.
Also reduced the number of round trips using multiple commands.

connection.c
connection.h
info.c
options.c
pgapi30.c
statement.c

index 8505d8533772aebd71596fbc628d40d004eb1b37..b9811a227b468f47da76d2c0d74850c7e804d46c 100644 (file)
@@ -312,7 +312,7 @@ CC_initialize(ConnectionClass *rv, BOOL lockinit)
    rv->lobj_type = PG_TYPE_LO_UNDEFINED;
    if (isMsAccess())
        rv->ms_jet = 1;
-   rv->isolation = SQL_TXN_READ_COMMITTED;
+   rv->isolation = 0; // means initially unknown server's default isolation
    rv->mb_maxbyte_per_char = 1;
    rv->max_identifier_length = -1;
    rv->autocommit_public = SQL_AUTOCOMMIT_ON;
@@ -902,12 +902,17 @@ static char CC_initial_log(ConnectionClass *self, const char *func)
    return 1;
 }
 
+static int handle_show_results(const QResultClass *res);
+#define    TRANSACTION_ISOLATION "transaction_isolation"
+#define    ISOLATION_SHOW_QUERY "show " TRANSACTION_ISOLATION
+
 static int LIBPQ_connect(ConnectionClass *self);
 static char
 LIBPQ_CC_connect(ConnectionClass *self, char *salt_para)
 {
    int     ret;
    CSTR        func = "LIBPQ_CC_connect";
+   QResultClass    *res;
 
    mylog("%s: entering...\n", func);
 
@@ -916,9 +921,17 @@ LIBPQ_CC_connect(ConnectionClass *self, char *salt_para)
 
    if (ret = LIBPQ_connect(self), ret <= 0)
        return ret;
-   CC_send_settings(self, "SET DateStyle = 'ISO';SET extra_float_digits = 2");
+   res = CC_send_query(self, "SET DateStyle = 'ISO';SET extra_float_digits = 2;" ISOLATION_SHOW_QUERY, NULL, 0, NULL);
+   if (QR_command_maybe_successful(res))
+   {
+       handle_show_results(res);
+       ret = 1;
+   }
+   else
+       ret = 0;
+   QR_Destructor(res);
 
-   return 1;
+   return ret;
 }
 
 char
@@ -950,10 +963,10 @@ CC_connect(ConnectionClass *self, char *salt_para)
     */
 
    /* Global settings */
- retsend = CC_send_settings(self, GET_NAME(self->connInfo.drivers.conn_settings));
  retsend = CC_send_settings(self, GET_NAME(self->connInfo.drivers.conn_settings));
    /* Per Datasource settings */
- if (retsend)
-    retsend = CC_send_settings(self, GET_NAME(self->connInfo.conn_settings));
  if (retsend)
+       retsend = CC_send_settings(self, GET_NAME(self->connInfo.conn_settings));
 
    if (CC_get_errornumber(self) > 0)
        saverr = strdup(CC_get_errormsg(self));
@@ -981,11 +994,12 @@ CC_connect(ConnectionClass *self, char *salt_para)
    }
 #endif /* UNICODE_SUPPORT */
 
-   if (!CC_set_transact(self, self->isolation))
-   {
-       ret = 0;
-       goto cleanup;
-   }
+   if (self->server_isolation != self->isolation)
+       if (!CC_set_transact(self, self->isolation))
+       {
+           ret = 0;
+           goto cleanup;
+       }
 
    ci->updatable_cursors = DISALLOW_UPDATABLE_CURSORS;
    if (ci->allow_keyset)
@@ -1139,6 +1153,67 @@ mylog("max_identifier_length=%d\n", len);
    return len < 0 ? 0 : len;
 }
 
+static SQLINTEGER
+isolation_str_to_enum(const char *str_isolation)
+{
+   SQLINTEGER  isolation = 0;
+
+   if (strnicmp(str_isolation, "seri", 4) == 0)
+       isolation = SQL_TXN_SERIALIZABLE;
+   else if (strnicmp(str_isolation, "repe", 4) == 0)
+       isolation = SQL_TXN_REPEATABLE_READ;
+   else if (strnicmp(str_isolation, "read com", 8) == 0)
+       isolation = SQL_TXN_READ_COMMITTED;
+   else if (strnicmp(str_isolation, "read unc", 8) == 0)
+       isolation = SQL_TXN_READ_UNCOMMITTED;
+
+   return isolation;
+}
+
+static int handle_show_results(const QResultClass *res)
+{
+   int         count = 0;
+   const QResultClass  *qres;
+   ConnectionClass     *conn = QR_get_conn(res);
+
+   for (qres = res; qres; qres = qres->next)
+   {
+       if (!qres->command ||
+           stricmp(qres->command, "SHOW") != 0)
+           continue;
+       if (strcmp(QR_get_fieldname(qres, 0), TRANSACTION_ISOLATION) == 0)
+       {
+           conn->server_isolation = isolation_str_to_enum(QR_get_value_backend_text(qres, 0, 0));
+           mylog("isolation %d to be %d\n", conn->server_isolation, conn->isolation);
+           if (0 == conn->isolation)
+               conn->isolation = conn->server_isolation;
+           if (0 == conn->default_isolation)
+               conn->default_isolation = conn->server_isolation;
+           count++;
+       }
+   }
+
+   return count;
+}
+/*
+ * This function may not be called as long as ISOLATION_SHOW_QUERY is
+ * issued in LIBPQ_CC_connect.
+ */
+int    CC_get_isolation(ConnectionClass *self)
+{
+   SQLINTEGER  isolation = 0;
+   QResultClass    *res;
+
+   res = CC_send_query(self, ISOLATION_SHOW_QUERY, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+   if (QR_command_maybe_successful(res))
+   {
+       handle_show_results(res);
+       isolation = self->server_isolation;
+   }
+   QR_Destructor(res);
+mylog("isolation=%d\n", isolation);
+   return isolation;
+}
 
 void
 CC_set_error(ConnectionClass *self, int number, const char *message, const char *func)
@@ -1946,6 +2021,8 @@ cleanup:
     */
    LIBPQ_update_transaction_status(self);
 
+   if (retres)
+       QR_set_conn(retres, self);
    return retres;
 }
 
@@ -3029,6 +3106,7 @@ CC_set_transact(ConnectionClass *self, UInt4 isolation)
 {
    char *query;
    QResultClass *res;
+   BOOL    bShow = FALSE;
 
    if (PG_VERSION_LT(self, 8.0) &&
        (isolation == SQL_TXN_READ_UNCOMMITTED ||
@@ -3053,15 +3131,22 @@ CC_set_transact(ConnectionClass *self, UInt4 isolation)
            query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED";
            break;
    }
-   res = CC_send_query(self, query, NULL, 0, NULL);
+   if (self->default_isolation == 0)
+       bShow = TRUE;
+   if (bShow)
+       res = CC_send_query_append(self, ISOLATION_SHOW_QUERY, NULL, 0, NULL, query);
+   else
+       res = CC_send_query(self, query, NULL, 0, NULL);
    if (!QR_command_maybe_successful(res))
    {
        CC_set_error(self, CONN_EXEC_ERROR, "ISOLATION change request to the server error", __FUNCTION__);
        QR_Destructor(res);
        return FALSE;
    }
+   if (bShow)
+       handle_show_results(res);
    QR_Destructor(res);
-   self->isolation_set_delay = 0;
+   self->server_isolation = isolation;
 
    return TRUE;
 }
index 1dcc396b4f30104b0aafd2431667b4cb65a6e606..2d2c8519b7e8b65ee337138b35fc6c05fefee170 100644 (file)
@@ -86,6 +86,9 @@ enum
 #define CONN_IN_MANUAL_TRANSACTION (1L<<2)
 #define CONN_IN_ERROR_BEFORE_IDLE  (1L<<3)
 
+/* not connected yet || already disconnected */
+#define    CC_not_connected(x) (CONN_DOWN == (x)->status || CONN_NOT_CONNECTED == (x)->status)
+
 /* AutoCommit functions */
 #define CC_is_in_autocommit(x)     (x->transact_status & CONN_IN_AUTOCOMMIT)
 #define CC_does_autocommit(x) (CONN_IN_AUTOCOMMIT == ((x)->transact_status & (CONN_IN_AUTOCOMMIT | CONN_IN_MANUAL_TRANSACTION)))
@@ -316,18 +319,19 @@ struct ConnectionClass_
    char        *server_encoding;
    Int2        ccsc;
    Int2        mb_maxbyte_per_char;
-   UInt4       isolation;
+   UInt4       isolation;      /* isolation level initially unknown */
+   SQLUINTEGER server_isolation;   /* isolation at server initially unknown */
    char        *current_schema;
    char        current_schema_valid;   /* is current_schema valid? TRUE when
                                         * current_schema == NULL means it's
                                         * really NULL, while FALSE means it's
                                         * unknown */
-   char        isolation_set_delay;
    StatementClass *unnamed_prepared_stmt;
    Int2        max_identifier_length;
    Int2        num_discardp;
    char        **discardp;
    int     num_descs;
+   SQLINTEGER  default_isolation;  /* server's default isolation initially unkown */
    DescriptorClass **descs;
    pgNAME      schemaIns;
    pgNAME      tableIns;
diff --git a/info.c b/info.c
index b5436454aec708f3d1c80d0e79ad5caafa6dfca9..6de9e04368ef93adc343bbcca4ed76471925a391 100644 (file)
--- a/info.c
+++ b/info.c
@@ -239,7 +239,9 @@ mylog("CONVERT_FUNCTIONS=" FORMAT_ULEN "\n", value);
 
        case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
            len = 4;
-           value = SQL_TXN_READ_COMMITTED;
+           if (0 == conn->default_isolation)
+               conn->isolation = CC_get_isolation(conn);
+           value = conn->default_isolation;
            break;
 
        case SQL_DRIVER_NAME:   /* ODBC 1.0 */
index 9812ed475f59f97906f4a92a4fd7d5d0c2a265f9..fa4244df57743cbbbed5ac194958c5421a094e9f 100644 (file)
--- a/options.c
+++ b/options.c
@@ -399,10 +399,9 @@ PGAPI_SetConnectOption(HDBC hdbc,
             * If the connection is not established, just record the setting to
             * reflect it upon connection.
             */
-           if (conn->status == CONN_NOT_CONNECTED || conn->status == CONN_DOWN)
+           if (CC_not_connected(conn))
            {
                conn->isolation = (UInt4) vParam;
-               conn->isolation_set_delay = 1;
                break;
            }
 
@@ -531,6 +530,12 @@ PGAPI_GetConnectOption(HDBC hdbc,
            break;
 
        case SQL_TXN_ISOLATION:
+           if (conn->isolation == 0)
+           {
+               if (CC_not_connected(conn))
+                   return SQL_NO_DATA;
+               conn->isolation = CC_get_isolation(conn);
+           }
            *((SQLUINTEGER *) pvParam) = conn->isolation;
            break;
 
@@ -540,7 +545,7 @@ PGAPI_GetConnectOption(HDBC hdbc,
        case 1209:
 #endif /* SQL_ATTR_CONNECTION_DEAD */
            mylog("CONNECTION_DEAD status=%d", conn->status);
-           *((SQLUINTEGER *) pvParam) = (conn->status == CONN_NOT_CONNECTED || conn->status == CONN_DOWN);
+           *((SQLUINTEGER *) pvParam) = CC_not_connected(conn);
            mylog(" val=%d\n", *((SQLUINTEGER *) pvParam));
                         break;
 
index 18808020f0f4059750029e02d12a30deb13e906b..f321be61ba54389d3fabcc27a129342d2e470b00 100644 (file)
--- a/pgapi30.c
+++ b/pgapi30.c
@@ -411,7 +411,7 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
            *((SQLINTEGER *) Value) = SQL_FALSE;
            break;
        case SQL_ATTR_CONNECTION_DEAD:
-           *((SQLUINTEGER *) Value) = (conn->status == CONN_NOT_CONNECTED || conn->status == CONN_DOWN);
+           *((SQLUINTEGER *) Value) = CC_not_connected(conn);
            break;
        case SQL_ATTR_CONNECTION_TIMEOUT:
            *((SQLUINTEGER *) Value) = 0;
index a8b17b19560b2d56c4c99e0f47e1763164cb426f..661963f80434c6f14b174301a69bdb488c30690f 100644 (file)
@@ -2952,7 +2952,7 @@ SC_set_errorinfo(StatementClass *self, QResultClass *res)
 {
    ConnectionClass *conn = SC_get_conn(self);
 
-   if (conn->status == CONN_NOT_CONNECTED || conn->status == CONN_DOWN)
+   if (CC_not_connected(conn))
    {
        SC_set_error_if_not_set(self, STMT_COMMUNICATION_ERROR, "The connection has been lost", __FUNCTION__);
        return;