summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut2003-11-06 22:08:15 +0000
committerPeter Eisentraut2003-11-06 22:08:15 +0000
commit5eae9ddbbd881f08111dd25de03eb1c3adbfdea6 (patch)
tree0d3fe13cf3bc9cc80c52dd541cc34c1ec4383d08
parent24443bf2aa4d1af7e22f4e156e76ad2a86d9e2f9 (diff)
Implement isolation levels read uncommitted and repeatable read as acting
like the next higher one.
-rw-r--r--doc/src/sgml/mvcc.sgml21
-rw-r--r--doc/src/sgml/ref/set_transaction.sgml27
-rw-r--r--doc/src/sgml/ref/start_transaction.sgml4
-rw-r--r--doc/src/sgml/runtime.sgml10
-rw-r--r--src/backend/catalog/sql_features.txt6
-rw-r--r--src/backend/commands/trigger.c2
-rw-r--r--src/backend/commands/variable.c27
-rw-r--r--src/backend/executor/execMain.c6
-rw-r--r--src/backend/parser/gram.y12
-rw-r--r--src/backend/parser/keywords.c2
-rw-r--r--src/backend/utils/adt/ri_triggers.c2
-rw-r--r--src/backend/utils/misc/guc.c12
-rw-r--r--src/backend/utils/time/tqual.c2
-rw-r--r--src/bin/psql/tab-complete.c54
-rw-r--r--src/include/access/xact.h10
15 files changed, 142 insertions, 55 deletions
diff --git a/doc/src/sgml/mvcc.sgml b/doc/src/sgml/mvcc.sgml
index 77dace35fc..48ad556ef4 100644
--- a/doc/src/sgml/mvcc.sgml
+++ b/doc/src/sgml/mvcc.sgml
@@ -206,8 +206,25 @@ $Header$
</table>
<para>
- <productname>PostgreSQL</productname>
- offers the Read Committed and Serializable isolation levels.
+ In <productname>PostgreSQL</productname>, you can use all four
+ possible transaction isolation levels. Internally, there are only
+ two distinct isolation levels, which correspond to the levels Read
+ Committed and Serializable. When you select the level Read
+ Uncommitted you really get Read Committed, and when you select
+ Repeatable Read you really get Serializable, so the actual
+ isolation level may be stricter than what you select. This is
+ permitted by the SQL standard: the four isolation levels only
+ define which phenomena must not happen, they do not define which
+ phenomena must happen. The reason that PostgreSQL only provides
+ two isolation levels is that this is the only sensible way to map
+ the isolation levels to the multiversion concurrency control
+ architecture. The behavior of the available isolation levels is
+ detailed in the following subsections.
+ </para>
+
+ <para>
+ To set the transaction isolation level of a transaction, use the
+ command <xref linkend="sql-set-transaction">.
</para>
<sect2 id="xact-read-committed">
diff --git a/doc/src/sgml/ref/set_transaction.sgml b/doc/src/sgml/ref/set_transaction.sgml
index d50abf3ab2..dc282914c9 100644
--- a/doc/src/sgml/ref/set_transaction.sgml
+++ b/doc/src/sgml/ref/set_transaction.sgml
@@ -17,9 +17,12 @@
<refsynopsisdiv>
<synopsis>
SET TRANSACTION
- [ ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE } ] [ READ WRITE | READ ONLY ]
+ [ ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE } ]
+ [ READ WRITE | READ ONLY ]
+
SET SESSION CHARACTERISTICS AS TRANSACTION
- [ ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE } ] [ READ WRITE | READ ONLY ]
+ [ ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE } ]
+ [ READ WRITE | READ ONLY ]
</synopsis>
</refsynopsisdiv>
@@ -76,8 +79,11 @@ SET SESSION CHARACTERISTICS AS TRANSACTION
</varlistentry>
</variablelist>
- The transaction isolation level cannot be set after the first query
- or data-modification statement (<command>SELECT</command>,
+ The level <literal>READ UNCOMMITTED</literal> is mapped to
+ <literal>READ COMMITTED</literal>, the level <literal>REPEATABLE
+ READ</literal> is mapped to <literal>SERIALIZABLE</literal>, The
+ transaction isolation level cannot be set after the first query or
+ data-modification statement (<command>SELECT</command>,
<command>INSERT</command>, <command>DELETE</command>,
<command>UPDATE</command>, <command>FETCH</command>,
<command>COPY</command>) of a transaction has been executed. See
@@ -122,13 +128,12 @@ SET default_transaction_isolation = '<replaceable>value</replaceable>'
<para>
Both commands are defined in the <acronym>SQL</acronym> standard.
<literal>SERIALIZABLE</literal> is the default transaction
- isolation level in the standard; in <productname>PostgreSQL</productname> the default is
- ordinarily <literal>READ COMMITTED</literal>, but you can change it as
- described above. <productname>PostgreSQL</productname> does not
- provide the isolation levels <literal>READ UNCOMMITTED</literal>
- and <literal>REPEATABLE READ</literal>. Because of multiversion
- concurrency control, the <literal>SERIALIZABLE</literal> level is
- not truly serializable. See <xref linkend="mvcc"> for details.
+ isolation level in the standard; in
+ <productname>PostgreSQL</productname> the default is ordinarily
+ <literal>READ COMMITTED</literal>, but you can change it as
+ described above. Because of multiversion concurrency control, the
+ <literal>SERIALIZABLE</literal> level is not truly
+ serializable. See <xref linkend="mvcc"> for details.
</para>
<para>
diff --git a/doc/src/sgml/ref/start_transaction.sgml b/doc/src/sgml/ref/start_transaction.sgml
index 0b2860af88..cace8ff4f8 100644
--- a/doc/src/sgml/ref/start_transaction.sgml
+++ b/doc/src/sgml/ref/start_transaction.sgml
@@ -20,7 +20,9 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-START TRANSACTION [ ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE } ] [ READ WRITE | READ ONLY ]
+START TRANSACTION
+ [ ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE } ]
+ [ READ WRITE | READ ONLY ]
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 8f8b67b399..c745aaee63 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -2043,10 +2043,12 @@ SET ENABLE_SEQSCAN TO OFF;
<term><varname>default_transaction_isolation</varname> (<type>string</type>)</term>
<listitem>
<para>
- Each SQL transaction has an isolation level, which can be either
- <quote>read committed</quote> or <quote>serializable</quote>.
- This parameter controls the default isolation level of each new
- transaction. The default is <quote>read committed</quote>.
+ Each SQL transaction has an isolation level, which can be
+ either <quote>read uncommitted</quote>, <quote>read
+ committed</quote>, <quote>repeatable read</quote>, or
+ <quote>serializable</quote>. This parameter controls the
+ default isolation level of each new transaction. The default
+ is <quote>read committed</quote>.
</para>
<para>
diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt
index 4cd309dd65..667bb93ba8 100644
--- a/src/backend/catalog/sql_features.txt
+++ b/src/backend/catalog/sql_features.txt
@@ -156,10 +156,10 @@ F051 Basic date and time 07 LOCALTIME YES
F051 Basic date and time 08 LOCALTIMESTAMP YES
F052 Intervals and datetime arithmetic YES
F081 UNION and EXCEPT in views YES
-F111 Isolation levels other than SERIALIZABLE NO
-F111 Isolation levels other than SERIALIZABLE 01 READ UNCOMMITTED isolation level NO
+F111 Isolation levels other than SERIALIZABLE YES
+F111 Isolation levels other than SERIALIZABLE 01 READ UNCOMMITTED isolation level YES behaves like READ COMMITTED
F111 Isolation levels other than SERIALIZABLE 02 READ COMMITTED isolation level YES
-F111 Isolation levels other than SERIALIZABLE 03 REPEATABLE READ isolation level NO
+F111 Isolation levels other than SERIALIZABLE 03 REPEATABLE READ isolation level YES behaves like SERIALIZABLE
F121 Basic diagnostics management NO
F121 Basic diagnostics management 01 GET DIAGNOSTICS statement NO
F121 Basic diagnostics management 02 SET TRANSACTION statement: DIAGNOSTICS SIZE clause NO
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 81e83e98d4..8e830e88ed 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -1576,7 +1576,7 @@ ltrmark:;
case HeapTupleUpdated:
ReleaseBuffer(buffer);
- if (XactIsoLevel == XACT_SERIALIZABLE)
+ if (IsXactIsoLevelSerializable)
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 7b04226017..1f16ae962e 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -640,11 +640,21 @@ assign_XactIsoLevel(const char *value, bool doit, bool interactive)
if (doit)
XactIsoLevel = XACT_SERIALIZABLE;
}
+ else if (strcmp(value, "repeatable read") == 0)
+ {
+ if (doit)
+ XactIsoLevel = XACT_REPEATABLE_READ;
+ }
else if (strcmp(value, "read committed") == 0)
{
if (doit)
XactIsoLevel = XACT_READ_COMMITTED;
}
+ else if (strcmp(value, "read uncommitted") == 0)
+ {
+ if (doit)
+ XactIsoLevel = XACT_READ_UNCOMMITTED;
+ }
else if (strcmp(value, "default") == 0)
{
if (doit)
@@ -659,10 +669,19 @@ assign_XactIsoLevel(const char *value, bool doit, bool interactive)
const char *
show_XactIsoLevel(void)
{
- if (XactIsoLevel == XACT_SERIALIZABLE)
- return "serializable";
- else
- return "read committed";
+ switch (XactIsoLevel)
+ {
+ case XACT_READ_UNCOMMITTED:
+ return "read uncommitted";
+ case XACT_READ_COMMITTED:
+ return "read committed";
+ case XACT_REPEATABLE_READ:
+ return "repeatable read";
+ case XACT_SERIALIZABLE:
+ return "serializable";
+ default:
+ return "bogus";
+ }
}
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index d0662ea137..655c53394d 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1139,7 +1139,7 @@ lnext: ;
break;
case HeapTupleUpdated:
- if (XactIsoLevel == XACT_SERIALIZABLE)
+ if (IsXactIsoLevelSerializable)
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));
@@ -1440,7 +1440,7 @@ ldelete:;
break;
case HeapTupleUpdated:
- if (XactIsoLevel == XACT_SERIALIZABLE)
+ if (IsXactIsoLevelSerializable)
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));
@@ -1576,7 +1576,7 @@ lreplace:;
break;
case HeapTupleUpdated:
- if (XactIsoLevel == XACT_SERIALIZABLE)
+ if (IsXactIsoLevelSerializable)
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 3576d90285..bd3cf589ff 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -342,7 +342,7 @@ static void doNegateFloat(Value *v);
DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS
- DESC DISTINCT DO DOMAIN_P DOUBLE_P DROP
+ DESC DISTINCT DO DOMAIN_P DOUBLE_P DROP
EACH ELSE ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
@@ -380,7 +380,7 @@ static void doNegateFloat(Value *v);
PRECISION PRESERVE PREPARE PRIMARY
PRIOR PRIVILEGES PROCEDURAL PROCEDURE
- READ REAL RECHECK REFERENCES REINDEX RELATIVE_P RENAME REPLACE
+ READ REAL RECHECK REFERENCES REINDEX RELATIVE_P RENAME REPEATABLE REPLACE
RESET RESTART RESTRICT RETURNS REVOKE RIGHT ROLLBACK ROW ROWS
RULE
@@ -393,7 +393,7 @@ static void doNegateFloat(Value *v);
TO TOAST TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
TRUNCATE TRUSTED TYPE_P
- UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
+ UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
UPDATE USAGE USER USING
VACUUM VALID VALIDATOR VALUES VARCHAR VARYING
@@ -922,7 +922,9 @@ var_value: opt_boolean
{ $$ = makeAConst($1); }
;
-iso_level: READ COMMITTED { $$ = "read committed"; }
+iso_level: READ UNCOMMITTED { $$ = "read uncommitted"; }
+ | READ COMMITTED { $$ = "read committed"; }
+ | REPEATABLE READ { $$ = "repeatable read"; }
| SERIALIZABLE { $$ = "serializable"; }
;
@@ -7407,6 +7409,7 @@ unreserved_keyword:
| REINDEX
| RELATIVE_P
| RENAME
+ | REPEATABLE
| REPLACE
| RESET
| RESTART
@@ -7445,6 +7448,7 @@ unreserved_keyword:
| TRUNCATE
| TRUSTED
| TYPE_P
+ | UNCOMMITTED
| UNENCRYPTED
| UNKNOWN
| UNLISTEN
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index 6067787ff7..679bd45dee 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -251,6 +251,7 @@ static const ScanKeyword ScanKeywords[] = {
{"reindex", REINDEX},
{"relative", RELATIVE_P},
{"rename", RENAME},
+ {"repeatable", REPEATABLE},
{"replace", REPLACE},
{"reset", RESET},
{"restart", RESTART},
@@ -307,6 +308,7 @@ static const ScanKeyword ScanKeywords[] = {
{"truncate", TRUNCATE},
{"trusted", TRUSTED},
{"type", TYPE_P},
+ {"uncommitted", UNCOMMITTED},
{"unencrypted", UNENCRYPTED},
{"union", UNION},
{"unique", UNIQUE},
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 8c83427a49..6ef89e40e7 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -3073,7 +3073,7 @@ ri_PerformCheck(RI_QueryKey *qkey, void *qplan,
* rows under current snapshot that wouldn't be visible per the
* transaction snapshot).
*/
- if (XactIsoLevel == XACT_SERIALIZABLE)
+ if (IsXactIsoLevelSerializable)
{
useCurrentSnapshot = detectNewRows;
}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index d635c8faec..c225fc4e41 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1346,7 +1346,7 @@ static struct config_string ConfigureNamesString[] =
{"default_transaction_isolation", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the transaction isolation level of each new transaction."),
gettext_noop("Each SQL transaction has an isolation level, which "
- "can be either \"read committed\" or \"serializable\".")
+ "can be either \"read uncommitted\", \"read committed\", \"repeatable read\", or \"serializable\".")
},
&default_iso_level_string,
"read committed", assign_defaultxactisolevel, NULL
@@ -4238,11 +4238,21 @@ assign_defaultxactisolevel(const char *newval, bool doit, bool interactive)
if (doit)
DefaultXactIsoLevel = XACT_SERIALIZABLE;
}
+ else if (strcasecmp(newval, "repeatable read") == 0)
+ {
+ if (doit)
+ DefaultXactIsoLevel = XACT_REPEATABLE_READ;
+ }
else if (strcasecmp(newval, "read committed") == 0)
{
if (doit)
DefaultXactIsoLevel = XACT_READ_COMMITTED;
}
+ else if (strcasecmp(newval, "read uncommitted") == 0)
+ {
+ if (doit)
+ DefaultXactIsoLevel = XACT_READ_UNCOMMITTED;
+ }
else
return NULL;
return newval;
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index d37c829f63..6b5618c2e1 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -984,7 +984,7 @@ SetQuerySnapshot(void)
return;
}
- if (XactIsoLevel == XACT_SERIALIZABLE)
+ if (IsXactIsoLevelSerializable)
QuerySnapshot = SerializableSnapshot;
else
QuerySnapshot = GetSnapshotData(&QuerySnapshotData, false);
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 697e269aad..2f3978f6af 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -466,7 +466,7 @@ psql_completion(char *text, int start, int end)
"ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT",
"COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE", "DROP", "EXECUTE",
"EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY",
- "PREPARE", "REINDEX", "RESET", "REVOKE", "ROLLBACK", "SELECT", "SET", "SHOW",
+ "PREPARE", "REINDEX", "RESET", "REVOKE", "ROLLBACK", "SELECT", "SET", "SHOW", "START",
"TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL
};
@@ -1101,30 +1101,36 @@ psql_completion(char *text, int start, int end)
strcasecmp(prev_wd, "SHOW") == 0)
COMPLETE_WITH_LIST(pgsql_variables);
/* Complete "SET TRANSACTION" */
- else if ((strcasecmp(prev2_wd, "SET") == 0 &&
- strcasecmp(prev_wd, "TRANSACTION") == 0) ||
- (strcasecmp(prev4_wd, "SESSION") == 0 &&
- strcasecmp(prev3_wd, "CHARACTERISTICS") == 0 &&
- strcasecmp(prev2_wd, "AS") == 0 &&
- strcasecmp(prev_wd, "TRANSACTION") == 0))
+ else if ((strcasecmp(prev2_wd, "SET") == 0
+ && strcasecmp(prev_wd, "TRANSACTION") == 0)
+ || (strcasecmp(prev2_wd, "START") == 0
+ && strcasecmp(prev_wd, "TRANSACTION") == 0)
+ || (strcasecmp(prev4_wd, "SESSION") == 0
+ && strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
+ && strcasecmp(prev2_wd, "AS") == 0
+ && strcasecmp(prev_wd, "TRANSACTION") == 0))
{
static const char * const my_list[] =
{"ISOLATION", "READ", NULL};
COMPLETE_WITH_LIST(my_list);
}
- else if (strcasecmp(prev3_wd, "SET") == 0 &&
- strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
- strcasecmp(prev_wd, "ISOLATION") == 0)
+ else if ((strcasecmp(prev3_wd, "SET") == 0
+ || strcasecmp(prev3_wd, "START") == 0
+ || (strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
+ && strcasecmp(prev3_wd, "AS") == 0))
+ && strcasecmp(prev2_wd, "TRANSACTION") == 0
+ && strcasecmp(prev_wd, "ISOLATION") == 0)
COMPLETE_WITH_CONST("LEVEL");
- else if ((strcasecmp(prev4_wd, "SET") == 0 ||
- strcasecmp(prev4_wd, "AS") == 0) &&
- strcasecmp(prev3_wd, "TRANSACTION") == 0 &&
- strcasecmp(prev2_wd, "ISOLATION") == 0 &&
- strcasecmp(prev_wd, "LEVEL") == 0)
+ else if ((strcasecmp(prev4_wd, "SET") == 0
+ || strcasecmp(prev4_wd, "START") == 0
+ || strcasecmp(prev4_wd, "AS") == 0)
+ && strcasecmp(prev3_wd, "TRANSACTION") == 0
+ && strcasecmp(prev2_wd, "ISOLATION") == 0
+ && strcasecmp(prev_wd, "LEVEL") == 0)
{
static const char * const my_list[] =
- {"READ", "SERIALIZABLE", NULL};
+ {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
COMPLETE_WITH_LIST(my_list);
}
@@ -1132,7 +1138,17 @@ psql_completion(char *text, int start, int end)
strcasecmp(prev3_wd, "ISOLATION") == 0 &&
strcasecmp(prev2_wd, "LEVEL") == 0 &&
strcasecmp(prev_wd, "READ") == 0)
- COMPLETE_WITH_CONST("COMMITTED");
+ {
+ static const char * const my_list[] =
+ {"UNCOMMITTED", "COMMITTED", NULL};
+
+ COMPLETE_WITH_LIST(my_list);
+ }
+ else if (strcasecmp(prev4_wd, "TRANSACTION") == 0 &&
+ strcasecmp(prev3_wd, "ISOLATION") == 0 &&
+ strcasecmp(prev2_wd, "LEVEL") == 0 &&
+ strcasecmp(prev_wd, "REPEATABLE") == 0)
+ COMPLETE_WITH_CONST("READ");
else if ((strcasecmp(prev3_wd, "SET") == 0 ||
strcasecmp(prev3_wd, "AS") == 0) &&
strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
@@ -1200,6 +1216,10 @@ psql_completion(char *text, int start, int end)
}
}
+/* START TRANSACTION */
+ else if (strcasecmp(prev_wd, "START") == 0)
+ COMPLETE_WITH_CONST("TRANSACTION");
+
/* TRUNCATE */
else if (strcasecmp(prev_wd, "TRUNCATE") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 8af6663e77..a07ab10408 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -22,14 +22,20 @@
/*
* Xact isolation levels
*/
-#define XACT_DIRTY_READ 0 /* not implemented */
+#define XACT_READ_UNCOMMITTED 0
#define XACT_READ_COMMITTED 1
-#define XACT_REPEATABLE_READ 2 /* not implemented */
+#define XACT_REPEATABLE_READ 2
#define XACT_SERIALIZABLE 3
extern int DefaultXactIsoLevel;
extern int XactIsoLevel;
+/*
+ * We only implement two distinct levels, so this is a convenience to
+ * check which level we're really using internally.
+ */
+#define IsXactIsoLevelSerializable ((XactIsoLevel == XACT_REPEATABLE_READ || XactIsoLevel == XACT_SERIALIZABLE))
+
/* Xact read-only state */
extern bool DefaultXactReadOnly;
extern bool XactReadOnly;