}
#endif /* UNICODE_SUPPORT */
+ if (!CC_set_transact(self, self->isolation))
+ {
+ ret = 0;
+ goto cleanup;
+ }
+
ci->updatable_cursors = DISALLOW_UPDATABLE_CURSORS;
if (ci->allow_keyset)
{
}
#endif /* _HANDLE_ENLIST_IN_DTC_ */
+
+BOOL
+CC_set_transact(ConnectionClass *self, UInt4 isolation)
+{
+ char *query;
+ QResultClass *res;
+
+ if (PG_VERSION_LT(self, 8.0) &&
+ (isolation == SQL_TXN_READ_UNCOMMITTED ||
+ isolation == SQL_TXN_REPEATABLE_READ))
+ {
+ CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "READ_UNCOMMITTED or REPEATABLE_READ is not supported by the server", __FUNCTION__);
+ return FALSE;
+ }
+
+ switch (isolation)
+ {
+ case SQL_TXN_SERIALIZABLE:
+ query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE";
+ break;
+ case SQL_TXN_REPEATABLE_READ:
+ query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ";
+ break;
+ case SQL_TXN_READ_UNCOMMITTED:
+ query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED";
+ break;
+ default:
+ query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED";
+ break;
+ }
+ 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;
+ }
+ QR_Destructor(res);
+ self->isolation_set_delay = 0;
+
+ return TRUE;
+}
+
#define CONN_INVALID_AUTHENTICATION 210
#define CONN_AUTH_TYPE_UNSUPPORTED 211
#define CONN_UNABLE_TO_LOAD_DLL 212
-
+#define CONN_ILLEGAL_TRANSACT_STATE 213
#define CONN_VALUE_OUT_OF_RANGE 214
#define CONN_OPTION_NOT_FOR_THE_DRIVER 216
* 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;
void CC_examine_global_transaction(ConnectionClass *self);
+
+BOOL CC_set_transact(ConnectionClass *self, UInt4 isolation);
+
/* CC_send_query options */
enum {
IGNORE_ABORT_ON_CONN = 1L /* not set the error result even when */
/* invalid argument value */
break;
case CONN_TRANSACT_IN_PROGRES:
- pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
-
- /*
- * when the user tries to switch commit mode in a
- * transaction
- */
- /* -> function sequence error */
+ pg_sqlstate_set(env, szSqlState, "HY011", "S1011");
break;
case CONN_NO_MEMORY_ERROR:
pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
case CONN_NOT_IMPLEMENTED_ERROR:
pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
break;
+ case CONN_ILLEGAL_TRANSACT_STATE:
+ pg_sqlstate_set(env, szSqlState, "25000", "S1010");
+ break;
case CONN_VALUE_OUT_OF_RANGE:
pg_sqlstate_set(env, szSqlState, "HY019", "22003");
break;
case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */
len = 4;
- value = SQL_TXN_READ_COMMITTED | SQL_TXN_SERIALIZABLE;
+ value = SQL_TXN_READ_UNCOMMITTED | SQL_TXN_READ_COMMITTED |
+ SQL_TXN_REPEATABLE_READ | SQL_TXN_SERIALIZABLE;
break;
case SQL_UNION: /* ODBC 2.0 */
#ifdef _HANDLE_ENLIST_IN_DTC_
if (CC_is_in_global_trans(conn))
{
- CC_set_error(conn, CONN_TRANSACT_IN_PROGRES, "Don't change AUTOCOMMIT mode in a distributed transaction", func);
+ CC_set_error(conn, CONN_ILLEGAL_TRANSACT_STATE, "Don't change AUTOCOMMIT mode in a distributed transaction", func);
return SQL_ERROR;
}
#endif /* _HANDLE_ENLIST_IN_DTC_ */
break;
case SQL_TXN_ISOLATION:
- retval = SQL_SUCCESS;
if (conn->isolation == vParam)
break;
- switch (vParam)
- {
- case SQL_TXN_SERIALIZABLE:
- break;
- case SQL_TXN_REPEATABLE_READ:
- if (PG_VERSION_LT(conn, 8.0))
- retval = SQL_ERROR;
- break;
- case SQL_TXN_READ_COMMITTED:
- break;
- case SQL_TXN_READ_UNCOMMITTED:
- if (PG_VERSION_LT(conn, 8.0))
- retval = SQL_ERROR;
- break;
- default:
- retval = SQL_ERROR;
- }
- if (SQL_ERROR == retval)
+ /*
+ * 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)
{
- CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "Illegal parameter value for SQL_TXN_ISOLATION", func);
- return SQL_ERROR;
+ conn->isolation = (UInt4) vParam;
+ conn->isolation_set_delay = 1;
+ break;
}
- else
- {
- char *query;
- QResultClass *res;
- if (CC_is_in_trans(conn))
- {
- if (CC_does_autocommit(conn) && !CC_is_in_error_trans(conn))
- CC_commit(conn);
- else
- {
- CC_set_error(conn, CONN_TRANSACT_IN_PROGRES, "Cannot switch isolation level while a transaction is in progress", func);
- return SQL_ERROR;
- }
- }
- switch (vParam)
- {
- case SQL_TXN_SERIALIZABLE:
- query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE";
- break;
- case SQL_TXN_REPEATABLE_READ:
- query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ";
- break;
- case SQL_TXN_READ_UNCOMMITTED:
- query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED";
- break;
- default:
- query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED";
- break;
- }
- res = CC_send_query(conn, query, NULL, 0, NULL);
- if (!QR_command_maybe_successful(res))
- retval = SQL_ERROR;
+ /* The ODBC spec prohibits changing the isolation level while in manual transaction. */
+ if (CC_is_in_trans(conn))
+ {
+ if (CC_does_autocommit(conn) && !CC_is_in_error_trans(conn))
+ CC_commit(conn);
else
- conn->isolation = (UInt4) vParam;
- QR_Destructor(res);
- if (SQL_ERROR == retval)
{
- CC_set_error(conn, CONN_EXEC_ERROR, "ISOLATION change request to the server error", func);
+ CC_set_error(conn, CONN_TRANSACT_IN_PROGRES, "Cannot switch isolation level while a transaction is in progress", func);
return SQL_ERROR;
}
}
+
+ if (!CC_set_transact(conn, (UInt4) vParam))
+ return SQL_ERROR;
+
+ conn->isolation = (UInt4) vParam;
break;
/* These options should be handled by driver manager */