mirror of
https://github.com/postgres/postgres.git
synced 2025-06-27 23:21:58 +03:00
Read-only transactions, as defined in SQL.
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/features.sgml,v 2.13 2003/01/10 11:02:41 petere Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/features.sgml,v 2.14 2003/01/10 22:03:26 petere Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<appendix id="features">
|
<appendix id="features">
|
||||||
@ -642,6 +642,12 @@ $Header: /cvsroot/pgsql/doc/src/sgml/features.sgml,v 2.13 2003/01/10 11:02:41 pe
|
|||||||
<entry>ROLLBACK statement</entry>
|
<entry>ROLLBACK statement</entry>
|
||||||
<entry></entry>
|
<entry></entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>E152</entry>
|
||||||
|
<entry>Core</entry>
|
||||||
|
<entry>Basic SET TRANSACTION statement</entry>
|
||||||
|
<entry></entry>
|
||||||
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>E152-01</entry>
|
<entry>E152-01</entry>
|
||||||
<entry>Core</entry>
|
<entry>Core</entry>
|
||||||
@ -649,6 +655,13 @@ $Header: /cvsroot/pgsql/doc/src/sgml/features.sgml,v 2.13 2003/01/10 11:02:41 pe
|
|||||||
clause</entry>
|
clause</entry>
|
||||||
<entry></entry>
|
<entry></entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>E152-02</entry>
|
||||||
|
<entry>Core</entry>
|
||||||
|
<entry>SET TRANSACTION statement: READ ONLY and READ WRITE
|
||||||
|
clauses</entry>
|
||||||
|
<entry></entry>
|
||||||
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>E161</entry>
|
<entry>E161</entry>
|
||||||
<entry>Core</entry>
|
<entry>Core</entry>
|
||||||
@ -1598,19 +1611,6 @@ $Header: /cvsroot/pgsql/doc/src/sgml/features.sgml,v 2.13 2003/01/10 11:02:41 pe
|
|||||||
<entry>WITH HOLD cursors</entry>
|
<entry>WITH HOLD cursors</entry>
|
||||||
<entry>Cursor to stay open across transactions</entry>
|
<entry>Cursor to stay open across transactions</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
|
||||||
<entry>E152</entry>
|
|
||||||
<entry>Core</entry>
|
|
||||||
<entry>Basic SET TRANSACTION statement</entry>
|
|
||||||
<entry></entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<entry>E152-02</entry>
|
|
||||||
<entry>Core</entry>
|
|
||||||
<entry>SET TRANSACTION statement: READ ONLY and READ WRITE
|
|
||||||
clauses</entry>
|
|
||||||
<entry>Syntax accepted; READ ONLY not supported</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
<row>
|
||||||
<entry>E153</entry>
|
<entry>E153</entry>
|
||||||
<entry>Core</entry>
|
<entry>Core</entry>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/set_transaction.sgml,v 1.9 2002/08/04 04:31:44 momjian Exp $ -->
|
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/set_transaction.sgml,v 1.10 2003/01/10 22:03:27 petere Exp $ -->
|
||||||
<refentry id="SQL-SET-TRANSACTION">
|
<refentry id="SQL-SET-TRANSACTION">
|
||||||
<docinfo>
|
<docinfo>
|
||||||
<date>2000-11-24</date>
|
<date>2000-11-24</date>
|
||||||
@ -16,9 +16,10 @@
|
|||||||
|
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<synopsis>
|
<synopsis>
|
||||||
SET TRANSACTION ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE }
|
SET TRANSACTION
|
||||||
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL
|
[ ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE } ] [ READ WRITE | READ ONLY ]
|
||||||
{ READ COMMITTED | SERIALIZABLE }
|
SET SESSION CHARACTERISTICS AS TRANSACTION
|
||||||
|
[ ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE } ] [ READ WRITE | READ ONLY ]
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
@ -26,17 +27,19 @@ SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL
|
|||||||
<title>Description</title>
|
<title>Description</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
This command sets the transaction isolation level. The
|
The <command>SET TRANSACTION</command> command sets the transaction
|
||||||
<command>SET TRANSACTION</command> command sets the characteristics
|
characteristics of the current SQL-transaction. It has no effect on
|
||||||
for the current SQL-transaction. It has no effect on any subsequent
|
any subsequent transactions. <command>SET SESSION
|
||||||
transactions. This command cannot be used after the first query or data-modification
|
CHARACTERISTICS</command> sets the default transaction
|
||||||
statement (<command>SELECT</command>, <command>INSERT</command>,
|
characteristics for each transaction of a session. <command>SET
|
||||||
<command>DELETE</command>, <command>UPDATE</command>,
|
TRANSACTION</command> can override it for an individual
|
||||||
<command>FETCH</command>, <command>COPY</command>) of a transaction
|
transaction.
|
||||||
has been executed. <command>SET SESSION CHARACTERISTICS</command>
|
</para>
|
||||||
sets the default transaction isolation level for each transaction
|
|
||||||
for a session. <command>SET TRANSACTION</command> can override it
|
<para>
|
||||||
for an individual transaction.
|
The available transaction characteristics are the transaction
|
||||||
|
isolation level and the transaction access mode (read/write or
|
||||||
|
read-only).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -45,7 +48,7 @@ SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL
|
|||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>READ COMMITTED</term>
|
<term><literal>READ COMMITTED<literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
A statement can only see rows committed before it began. This
|
A statement can only see rows committed before it began. This
|
||||||
@ -55,7 +58,7 @@ SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>SERIALIZABLE</term>
|
<term><literal>SERIALIZABLE</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The current transaction can only see rows committed before
|
The current transaction can only see rows committed before
|
||||||
@ -72,6 +75,28 @@ SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
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.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The transaction access mode determines whether the transaction is
|
||||||
|
read/write or read-only. Read/write is the default. When a
|
||||||
|
transaction is read-only, the following SQL commands are
|
||||||
|
disallowed: <literal>INSERT</literal>, <literal>UPDATE</literal>,
|
||||||
|
<literal>DELETE</literal>, and <literal>COPY TO</literal> if the
|
||||||
|
table they would write to is not a temporary table; all
|
||||||
|
<literal>CREATE</literal>, <literal>ALTER</literal>, and
|
||||||
|
<literal>DROP</literal> commands; <literal>COMMENT</literal>,
|
||||||
|
<literal>GRANT</literal>, <literal>REVOKE</literal>,
|
||||||
|
<literal>TRUNCATE</literal>; and <literal>EXPLAIN ANALYZE</literal>
|
||||||
|
and <literal>EXECUTE</literal> if the command they would execute is
|
||||||
|
among those listed. This is a high-level notion of read-only that
|
||||||
|
does not prevent writes to disk.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
@ -97,7 +122,7 @@ SET default_transaction_isolation = '<replaceable>value</replaceable>'
|
|||||||
<title>SQL92, SQL99</title>
|
<title>SQL92, SQL99</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<option>SERIALIZABLE</option> is the default level in
|
<option>SERIALIZABLE</option> is the default transaction isolation level in
|
||||||
<acronym>SQL</acronym>. <productname>PostgreSQL</productname> does
|
<acronym>SQL</acronym>. <productname>PostgreSQL</productname> does
|
||||||
not provide the isolation levels <option>READ UNCOMMITTED</option>
|
not provide the isolation levels <option>READ UNCOMMITTED</option>
|
||||||
and <option>REPEATABLE READ</option>. Because of multiversion
|
and <option>REPEATABLE READ</option>. Because of multiversion
|
||||||
@ -107,11 +132,10 @@ SET default_transaction_isolation = '<replaceable>value</replaceable>'
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
In <acronym>SQL</acronym> there are two other transaction
|
In <acronym>SQL</acronym> there is one other transaction
|
||||||
characteristics that can be set with these commands: whether the
|
characteristic that can be set with these commands: the size of
|
||||||
transaction is read-only and the size of the diagnostics area.
|
the diagnostics area. This concept is not supported in
|
||||||
Neither of these concepts are supported in
|
<productname>PostgreSQL</productname>.
|
||||||
<productname>PostgreSQL</productname>.
|
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/start_transaction.sgml,v 1.3 2002/08/30 22:45:25 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/start_transaction.sgml,v 1.4 2003/01/10 22:03:27 petere Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ PostgreSQL documentation
|
|||||||
|
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<synopsis>
|
<synopsis>
|
||||||
START TRANSACTION [ ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE } ]
|
START TRANSACTION [ ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE } ] [ READ WRITE | READ ONLY ]
|
||||||
</synopsis>
|
</synopsis>
|
||||||
|
|
||||||
<refsect2 id="R2-SQL-START-TRANSACTION-1">
|
<refsect2 id="R2-SQL-START-TRANSACTION-1">
|
||||||
@ -77,52 +77,23 @@ WARNING: BEGIN: already a transaction in progress
|
|||||||
<title>Description</title>
|
<title>Description</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
This command begins a new transaction. If the isolation level is
|
This command begins a new transaction. If the isolation level or
|
||||||
specified, the new transaction has that isolation level. In all other
|
read/write mode is specified, the new transaction has those
|
||||||
respects, the behavior of this command is identical to the
|
characteristics, as if <xref linkend="sql-set-transaction"
|
||||||
<xref linkend="sql-begin" endterm="sql-begin-title"> command.
|
endterm="sql-set-transaction-title"> was executed. In all other
|
||||||
|
respects, the behavior of this command is identical to the <xref
|
||||||
|
linkend="sql-begin" endterm="sql-begin-title"> command.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
<title>Notes</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The isolation level of a transaction can also be set with the <xref
|
|
||||||
linkend="sql-set-transaction" endterm="sql-set-transaction-title">
|
|
||||||
command. If no isolation level is specified, the default isolation
|
|
||||||
level is used.
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1 id="R1-SQL-START-TRANSACTION-3">
|
<refsect1 id="R1-SQL-START-TRANSACTION-3">
|
||||||
<title>Compatibility</title>
|
<title>Compatibility</title>
|
||||||
|
|
||||||
<refsect2 id="R2-SQL-START-TRANSACTION-4">
|
<para>
|
||||||
<title>SQL99</title>
|
SQL99; but see also the compatibility section of <xref
|
||||||
|
linkend="sql-set-transaction" endterm="sql-set-transaction-title">.
|
||||||
<para>
|
</para>
|
||||||
<option>SERIALIZABLE</option> is the default isolation level in
|
|
||||||
<acronym>SQL99</acronym>, but it is not the usual default in
|
|
||||||
<productname>PostgreSQL</productname>: the factory default setting
|
|
||||||
is READ COMMITTED.
|
|
||||||
<productname>PostgreSQL</productname>
|
|
||||||
does not provide the isolation levels <option>READ UNCOMMITTED</option>
|
|
||||||
and <option>REPEATABLE READ</option>. Because of lack of predicate
|
|
||||||
locking, the <option>SERIALIZABLE</option> level is
|
|
||||||
not truly serializable. See the <citetitle>User's Guide</citetitle>
|
|
||||||
for details.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
In <acronym>SQL99</acronym> this statement can specify two other
|
|
||||||
properties of the new transaction: whether the transaction is
|
|
||||||
read-only and the size of the diagnostics area. Neither of these
|
|
||||||
concepts are currently supported in
|
|
||||||
<productname>PostgreSQL</productname>.
|
|
||||||
</para>
|
|
||||||
</refsect2>
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.176 2003/01/08 00:22:26 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.177 2003/01/10 22:03:26 petere Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<appendix id="release">
|
<appendix id="release">
|
||||||
@ -36,6 +36,7 @@ System can use either hash- or sort-based strategy for grouped aggregation
|
|||||||
ON COMMIT options for temp tables
|
ON COMMIT options for temp tables
|
||||||
extra_float_digits option allows pg_dump to dump float data accurately
|
extra_float_digits option allows pg_dump to dump float data accurately
|
||||||
Long options for psql and pg_dump are now available on all platforms
|
Long options for psql and pg_dump are now available on all platforms
|
||||||
|
Read-only transactions
|
||||||
]]></literallayout>
|
]]></literallayout>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.140 2002/11/23 03:59:06 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.141 2003/01/10 22:03:27 petere Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Transaction aborts can now occur two ways:
|
* Transaction aborts can now occur two ways:
|
||||||
@ -208,6 +208,9 @@ TransactionState CurrentTransactionState = &CurrentTransactionStateData;
|
|||||||
int DefaultXactIsoLevel = XACT_READ_COMMITTED;
|
int DefaultXactIsoLevel = XACT_READ_COMMITTED;
|
||||||
int XactIsoLevel;
|
int XactIsoLevel;
|
||||||
|
|
||||||
|
bool DefaultXactReadOnly = false;
|
||||||
|
bool XactReadOnly;
|
||||||
|
|
||||||
bool autocommit = true;
|
bool autocommit = true;
|
||||||
|
|
||||||
int CommitDelay = 0; /* precommit delay in microseconds */
|
int CommitDelay = 0; /* precommit delay in microseconds */
|
||||||
@ -848,6 +851,7 @@ StartTransaction(void)
|
|||||||
|
|
||||||
FreeXactSnapshot();
|
FreeXactSnapshot();
|
||||||
XactIsoLevel = DefaultXactIsoLevel;
|
XactIsoLevel = DefaultXactIsoLevel;
|
||||||
|
XactReadOnly = DefaultXactReadOnly;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the current transaction state. If the transaction system is
|
* Check the current transaction state. If the transaction system is
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.43 2003/01/07 20:56:06 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.44 2003/01/10 22:03:27 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -278,6 +278,30 @@ RelnameGetRelid(const char *relname)
|
|||||||
return InvalidOid;
|
return InvalidOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RelidGetNamespaceId
|
||||||
|
* Given a relation OID, return the namespace OID.
|
||||||
|
*/
|
||||||
|
Oid
|
||||||
|
RelidGetNamespaceId(Oid relid)
|
||||||
|
{
|
||||||
|
HeapTuple tuple;
|
||||||
|
Form_pg_class pg_class_form;
|
||||||
|
Oid result;
|
||||||
|
|
||||||
|
tuple = SearchSysCache(RELOID,
|
||||||
|
ObjectIdGetDatum(relid),
|
||||||
|
0, 0, 0);
|
||||||
|
if (!HeapTupleIsValid(tuple))
|
||||||
|
elog(ERROR, "cache lookup failed for relation %u", relid);
|
||||||
|
pg_class_form = (Form_pg_class) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
result = pg_class_form->relnamespace;
|
||||||
|
ReleaseSysCache(tuple);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelationIsVisible
|
* RelationIsVisible
|
||||||
* Determine whether a relation (identified by OID) is visible in the
|
* Determine whether a relation (identified by OID) is visible in the
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.187 2002/12/15 16:17:38 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.188 2003/01/10 22:03:27 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -348,6 +348,10 @@ DoCopy(const CopyStmt *stmt)
|
|||||||
*/
|
*/
|
||||||
rel = heap_openrv(relation, (is_from ? RowExclusiveLock : AccessShareLock));
|
rel = heap_openrv(relation, (is_from ? RowExclusiveLock : AccessShareLock));
|
||||||
|
|
||||||
|
/* check read-only transaction */
|
||||||
|
if (XactReadOnly && !is_from && !isTempNamespace(RelationGetNamespace(rel)))
|
||||||
|
elog(ERROR, "transaction is read-only");
|
||||||
|
|
||||||
/* Check permissions. */
|
/* Check permissions. */
|
||||||
aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
|
aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
|
||||||
required_access);
|
required_access);
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.196 2003/01/08 23:32:29 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.197 2003/01/10 22:03:27 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -85,6 +85,7 @@ static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid,
|
|||||||
static TupleTableSlot *EvalPlanQualNext(EState *estate);
|
static TupleTableSlot *EvalPlanQualNext(EState *estate);
|
||||||
static void EndEvalPlanQual(EState *estate);
|
static void EndEvalPlanQual(EState *estate);
|
||||||
static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
|
static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
|
||||||
|
static void ExecCheckXactReadOnly(Query *parsetree, CmdType operation);
|
||||||
static void EvalPlanQualStart(evalPlanQual *epq, EState *estate,
|
static void EvalPlanQualStart(evalPlanQual *epq, EState *estate,
|
||||||
evalPlanQual *priorepq);
|
evalPlanQual *priorepq);
|
||||||
static void EvalPlanQualStop(evalPlanQual *epq);
|
static void EvalPlanQualStop(evalPlanQual *epq);
|
||||||
@ -201,6 +202,14 @@ ExecutorRun(QueryDesc *queryDesc,
|
|||||||
operation = queryDesc->operation;
|
operation = queryDesc->operation;
|
||||||
dest = queryDesc->dest;
|
dest = queryDesc->dest;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the transaction is read-only, we need to check if any writes
|
||||||
|
* are planned to non-temporary tables. This is done here at this
|
||||||
|
* rather late stage so that we can handle EXPLAIN vs. EXPLAIN
|
||||||
|
* ANALYZE easily.
|
||||||
|
*/
|
||||||
|
ExecCheckXactReadOnly(queryDesc->parsetree, operation);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* startup tuple receiver
|
* startup tuple receiver
|
||||||
*/
|
*/
|
||||||
@ -385,6 +394,45 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ExecCheckXactReadOnly(Query *parsetree, CmdType operation)
|
||||||
|
{
|
||||||
|
if (!XactReadOnly)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* CREATE TABLE AS or SELECT INTO */
|
||||||
|
if (operation == CMD_SELECT && parsetree->into != NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (operation == CMD_DELETE || operation == CMD_INSERT
|
||||||
|
|| operation == CMD_UPDATE)
|
||||||
|
{
|
||||||
|
List *lp;
|
||||||
|
|
||||||
|
foreach(lp, parsetree->rtable)
|
||||||
|
{
|
||||||
|
RangeTblEntry *rte = lfirst(lp);
|
||||||
|
|
||||||
|
if (rte->rtekind != RTE_RELATION)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!rte->checkForWrite)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (isTempNamespace(RelidGetNamespaceId(rte->relid)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
elog(ERROR, "transaction is read-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* InitPlan
|
* InitPlan
|
||||||
*
|
*
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.394 2003/01/10 21:08:13 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.395 2003/01/10 22:03:27 petere Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -162,7 +162,7 @@ static void doNegateFloat(Value *v);
|
|||||||
%type <defelt> createdb_opt_item copy_opt_item
|
%type <defelt> createdb_opt_item copy_opt_item
|
||||||
|
|
||||||
%type <ival> opt_lock lock_type cast_context
|
%type <ival> opt_lock lock_type cast_context
|
||||||
%type <boolean> opt_force opt_or_replace
|
%type <boolean> opt_force opt_or_replace transaction_access_mode
|
||||||
|
|
||||||
%type <list> user_list
|
%type <list> user_list
|
||||||
|
|
||||||
@ -215,7 +215,8 @@ static void doNegateFloat(Value *v);
|
|||||||
target_list update_target_list insert_column_list
|
target_list update_target_list insert_column_list
|
||||||
insert_target_list def_list opt_indirection
|
insert_target_list def_list opt_indirection
|
||||||
group_clause TriggerFuncArgs select_limit
|
group_clause TriggerFuncArgs select_limit
|
||||||
opt_select_limit opclass_item_list trans_options
|
opt_select_limit opclass_item_list transaction_mode_list
|
||||||
|
transaction_mode_list_or_empty
|
||||||
TableFuncElementList
|
TableFuncElementList
|
||||||
prep_type_clause prep_type_list
|
prep_type_clause prep_type_list
|
||||||
execute_param_clause
|
execute_param_clause
|
||||||
@ -863,18 +864,18 @@ set_rest: ColId TO var_list_or_default
|
|||||||
n->args = makeList1($3);
|
n->args = makeList1($3);
|
||||||
$$ = n;
|
$$ = n;
|
||||||
}
|
}
|
||||||
| TRANSACTION ISOLATION LEVEL iso_level opt_mode
|
| TRANSACTION transaction_mode_list
|
||||||
{
|
{
|
||||||
VariableSetStmt *n = makeNode(VariableSetStmt);
|
VariableSetStmt *n = makeNode(VariableSetStmt);
|
||||||
n->name = "TRANSACTION ISOLATION LEVEL";
|
n->name = "TRANSACTION";
|
||||||
n->args = makeList1(makeStringConst($4, NULL));
|
n->args = $2;
|
||||||
$$ = n;
|
$$ = n;
|
||||||
}
|
}
|
||||||
| SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL iso_level
|
| SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list
|
||||||
{
|
{
|
||||||
VariableSetStmt *n = makeNode(VariableSetStmt);
|
VariableSetStmt *n = makeNode(VariableSetStmt);
|
||||||
n->name = "default_transaction_isolation";
|
n->name = "SESSION CHARACTERISTICS";
|
||||||
n->args = makeList1(makeStringConst($7, NULL));
|
n->args = $5;
|
||||||
$$ = n;
|
$$ = n;
|
||||||
}
|
}
|
||||||
| NAMES opt_encoding
|
| NAMES opt_encoding
|
||||||
@ -922,16 +923,6 @@ iso_level: READ COMMITTED { $$ = "read committed"; }
|
|||||||
| SERIALIZABLE { $$ = "serializable"; }
|
| SERIALIZABLE { $$ = "serializable"; }
|
||||||
;
|
;
|
||||||
|
|
||||||
opt_mode: READ WRITE
|
|
||||||
{}
|
|
||||||
| READ ONLY
|
|
||||||
{
|
|
||||||
elog(ERROR, "SET TRANSACTION/READ ONLY not yet supported");
|
|
||||||
}
|
|
||||||
| /*EMPTY*/
|
|
||||||
{}
|
|
||||||
;
|
|
||||||
|
|
||||||
opt_boolean:
|
opt_boolean:
|
||||||
TRUE_P { $$ = "true"; }
|
TRUE_P { $$ = "true"; }
|
||||||
| FALSE_P { $$ = "false"; }
|
| FALSE_P { $$ = "false"; }
|
||||||
@ -1020,7 +1011,7 @@ VariableShowStmt:
|
|||||||
| SHOW TRANSACTION ISOLATION LEVEL
|
| SHOW TRANSACTION ISOLATION LEVEL
|
||||||
{
|
{
|
||||||
VariableShowStmt *n = makeNode(VariableShowStmt);
|
VariableShowStmt *n = makeNode(VariableShowStmt);
|
||||||
n->name = "TRANSACTION ISOLATION LEVEL";
|
n->name = "transaction_isolation";
|
||||||
$$ = (Node *) n;
|
$$ = (Node *) n;
|
||||||
}
|
}
|
||||||
| SHOW SESSION AUTHORIZATION
|
| SHOW SESSION AUTHORIZATION
|
||||||
@ -1053,7 +1044,7 @@ VariableResetStmt:
|
|||||||
| RESET TRANSACTION ISOLATION LEVEL
|
| RESET TRANSACTION ISOLATION LEVEL
|
||||||
{
|
{
|
||||||
VariableResetStmt *n = makeNode(VariableResetStmt);
|
VariableResetStmt *n = makeNode(VariableResetStmt);
|
||||||
n->name = "TRANSACTION ISOLATION LEVEL";
|
n->name = "transaction_isolation";
|
||||||
$$ = (Node *) n;
|
$$ = (Node *) n;
|
||||||
}
|
}
|
||||||
| RESET SESSION AUTHORIZATION
|
| RESET SESSION AUTHORIZATION
|
||||||
@ -3500,42 +3491,42 @@ UnlistenStmt:
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
TransactionStmt:
|
TransactionStmt:
|
||||||
ABORT_TRANS opt_trans
|
ABORT_TRANS opt_transaction
|
||||||
{
|
{
|
||||||
TransactionStmt *n = makeNode(TransactionStmt);
|
TransactionStmt *n = makeNode(TransactionStmt);
|
||||||
n->command = ROLLBACK;
|
n->command = ROLLBACK;
|
||||||
n->options = NIL;
|
n->options = NIL;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| BEGIN_TRANS opt_trans
|
| BEGIN_TRANS opt_transaction
|
||||||
{
|
{
|
||||||
TransactionStmt *n = makeNode(TransactionStmt);
|
TransactionStmt *n = makeNode(TransactionStmt);
|
||||||
n->command = BEGIN_TRANS;
|
n->command = BEGIN_TRANS;
|
||||||
n->options = NIL;
|
n->options = NIL;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| START TRANSACTION trans_options
|
| START TRANSACTION transaction_mode_list_or_empty
|
||||||
{
|
{
|
||||||
TransactionStmt *n = makeNode(TransactionStmt);
|
TransactionStmt *n = makeNode(TransactionStmt);
|
||||||
n->command = START;
|
n->command = START;
|
||||||
n->options = $3;
|
n->options = $3;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| COMMIT opt_trans
|
| COMMIT opt_transaction
|
||||||
{
|
{
|
||||||
TransactionStmt *n = makeNode(TransactionStmt);
|
TransactionStmt *n = makeNode(TransactionStmt);
|
||||||
n->command = COMMIT;
|
n->command = COMMIT;
|
||||||
n->options = NIL;
|
n->options = NIL;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| END_TRANS opt_trans
|
| END_TRANS opt_transaction
|
||||||
{
|
{
|
||||||
TransactionStmt *n = makeNode(TransactionStmt);
|
TransactionStmt *n = makeNode(TransactionStmt);
|
||||||
n->command = COMMIT;
|
n->command = COMMIT;
|
||||||
n->options = NIL;
|
n->options = NIL;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| ROLLBACK opt_trans
|
| ROLLBACK opt_transaction
|
||||||
{
|
{
|
||||||
TransactionStmt *n = makeNode(TransactionStmt);
|
TransactionStmt *n = makeNode(TransactionStmt);
|
||||||
n->command = ROLLBACK;
|
n->command = ROLLBACK;
|
||||||
@ -3544,16 +3535,46 @@ TransactionStmt:
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
trans_options: ISOLATION LEVEL iso_level
|
opt_transaction: WORK {}
|
||||||
{ $$ = makeList1(makeStringConst($3, NULL)); }
|
|
||||||
| /* EMPTY */ { $$ = NIL; }
|
|
||||||
;
|
|
||||||
|
|
||||||
opt_trans: WORK {}
|
|
||||||
| TRANSACTION {}
|
| TRANSACTION {}
|
||||||
| /*EMPTY*/ {}
|
| /*EMPTY*/ {}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
transaction_mode_list:
|
||||||
|
ISOLATION LEVEL iso_level
|
||||||
|
{ $$ = makeList1(makeDefElem("transaction_isolation",
|
||||||
|
makeStringConst($3, NULL))); }
|
||||||
|
| transaction_access_mode
|
||||||
|
{ $$ = makeList1(makeDefElem("transaction_read_only",
|
||||||
|
makeIntConst($1))); }
|
||||||
|
| ISOLATION LEVEL iso_level transaction_access_mode
|
||||||
|
{
|
||||||
|
$$ = makeList2(makeDefElem("transaction_isolation",
|
||||||
|
makeStringConst($3, NULL)),
|
||||||
|
makeDefElem("transaction_read_only",
|
||||||
|
makeIntConst($4)));
|
||||||
|
}
|
||||||
|
| transaction_access_mode ISOLATION LEVEL iso_level
|
||||||
|
{
|
||||||
|
$$ = makeList2(makeDefElem("transaction_read_only",
|
||||||
|
makeIntConst($1)),
|
||||||
|
makeDefElem("transaction_isolation",
|
||||||
|
makeStringConst($4, NULL)));
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
transaction_mode_list_or_empty:
|
||||||
|
transaction_mode_list
|
||||||
|
| /* EMPTY */
|
||||||
|
{ $$ = NIL; }
|
||||||
|
;
|
||||||
|
|
||||||
|
transaction_access_mode:
|
||||||
|
READ ONLY { $$ = TRUE; }
|
||||||
|
| READ WRITE { $$ = FALSE; }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* QUERY:
|
* QUERY:
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.188 2003/01/06 00:31:44 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.189 2003/01/10 22:03:28 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -168,6 +168,66 @@ CheckOwnership(RangeVar *rel, bool noCatalogs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_xact_readonly(Node *parsetree)
|
||||||
|
{
|
||||||
|
if (!XactReadOnly)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: Commands that need to do more complicated checking are
|
||||||
|
* handled elsewhere.
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch (nodeTag(parsetree))
|
||||||
|
{
|
||||||
|
case T_AlterDatabaseSetStmt:
|
||||||
|
case T_AlterDomainStmt:
|
||||||
|
case T_AlterGroupStmt:
|
||||||
|
case T_AlterTableStmt:
|
||||||
|
case T_RenameStmt:
|
||||||
|
case T_AlterUserStmt:
|
||||||
|
case T_AlterUserSetStmt:
|
||||||
|
case T_CommentStmt:
|
||||||
|
case T_DefineStmt:
|
||||||
|
case T_CreateCastStmt:
|
||||||
|
case T_CreateConversionStmt:
|
||||||
|
case T_CreatedbStmt:
|
||||||
|
case T_CreateDomainStmt:
|
||||||
|
case T_CreateFunctionStmt:
|
||||||
|
case T_CreateGroupStmt:
|
||||||
|
case T_IndexStmt:
|
||||||
|
case T_CreatePLangStmt:
|
||||||
|
case T_CreateOpClassStmt:
|
||||||
|
case T_RuleStmt:
|
||||||
|
case T_CreateSchemaStmt:
|
||||||
|
case T_CreateSeqStmt:
|
||||||
|
case T_CreateStmt:
|
||||||
|
case T_CreateTrigStmt:
|
||||||
|
case T_CompositeTypeStmt:
|
||||||
|
case T_CreateUserStmt:
|
||||||
|
case T_ViewStmt:
|
||||||
|
case T_RemoveAggrStmt:
|
||||||
|
case T_DropCastStmt:
|
||||||
|
case T_DropStmt:
|
||||||
|
case T_DropdbStmt:
|
||||||
|
case T_RemoveFuncStmt:
|
||||||
|
case T_DropGroupStmt:
|
||||||
|
case T_DropPLangStmt:
|
||||||
|
case T_RemoveOperStmt:
|
||||||
|
case T_RemoveOpClassStmt:
|
||||||
|
case T_DropPropertyStmt:
|
||||||
|
case T_DropUserStmt:
|
||||||
|
case T_GrantStmt:
|
||||||
|
case T_TruncateStmt:
|
||||||
|
elog(ERROR, "transaction is read-only");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/*nothing*/;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ProcessUtility
|
* ProcessUtility
|
||||||
* general utility function invoker
|
* general utility function invoker
|
||||||
@ -187,6 +247,8 @@ ProcessUtility(Node *parsetree,
|
|||||||
CommandDest dest,
|
CommandDest dest,
|
||||||
char *completionTag)
|
char *completionTag)
|
||||||
{
|
{
|
||||||
|
check_xact_readonly(parsetree);
|
||||||
|
|
||||||
if (completionTag)
|
if (completionTag)
|
||||||
completionTag[0] = '\0';
|
completionTag[0] = '\0';
|
||||||
|
|
||||||
@ -214,16 +276,21 @@ ProcessUtility(Node *parsetree,
|
|||||||
{
|
{
|
||||||
BeginTransactionBlock();
|
BeginTransactionBlock();
|
||||||
|
|
||||||
/*
|
|
||||||
* Currently, the only option that can be set
|
|
||||||
* by START TRANSACTION is the isolation
|
|
||||||
* level.
|
|
||||||
*/
|
|
||||||
if (stmt->options)
|
if (stmt->options)
|
||||||
{
|
{
|
||||||
SetPGVariable("TRANSACTION ISOLATION LEVEL",
|
List *head;
|
||||||
stmt->options,
|
|
||||||
false);
|
foreach(head, stmt->options)
|
||||||
|
{
|
||||||
|
DefElem *item = (DefElem *) lfirst(head);
|
||||||
|
|
||||||
|
if (strcmp(item->defname, "transaction_isolation")==0)
|
||||||
|
SetPGVariable("transaction_isolation",
|
||||||
|
makeList1(item->arg), false);
|
||||||
|
else if (strcmp(item->defname, "transaction_read_only")==0)
|
||||||
|
SetPGVariable("transaction_read_only",
|
||||||
|
makeList1(item->arg), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -765,7 +832,45 @@ ProcessUtility(Node *parsetree,
|
|||||||
{
|
{
|
||||||
VariableSetStmt *n = (VariableSetStmt *) parsetree;
|
VariableSetStmt *n = (VariableSetStmt *) parsetree;
|
||||||
|
|
||||||
SetPGVariable(n->name, n->args, n->is_local);
|
/*
|
||||||
|
* Special cases for special SQL syntax that
|
||||||
|
* effectively sets more than one variable per
|
||||||
|
* statement.
|
||||||
|
*/
|
||||||
|
if (strcmp(n->name, "TRANSACTION")==0)
|
||||||
|
{
|
||||||
|
List *head;
|
||||||
|
|
||||||
|
foreach(head, n->args)
|
||||||
|
{
|
||||||
|
DefElem *item = (DefElem *) lfirst(head);
|
||||||
|
|
||||||
|
if (strcmp(item->defname, "transaction_isolation")==0)
|
||||||
|
SetPGVariable("transaction_isolation",
|
||||||
|
makeList1(item->arg), n->is_local);
|
||||||
|
else if (strcmp(item->defname, "transaction_read_only")==0)
|
||||||
|
SetPGVariable("transaction_read_only",
|
||||||
|
makeList1(item->arg), n->is_local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(n->name, "SESSION CHARACTERISTICS")==0)
|
||||||
|
{
|
||||||
|
List *head;
|
||||||
|
|
||||||
|
foreach(head, n->args)
|
||||||
|
{
|
||||||
|
DefElem *item = (DefElem *) lfirst(head);
|
||||||
|
|
||||||
|
if (strcmp(item->defname, "transaction_isolation")==0)
|
||||||
|
SetPGVariable("default_transaction_isolation",
|
||||||
|
makeList1(item->arg), n->is_local);
|
||||||
|
else if (strcmp(item->defname, "transaction_read_only")==0)
|
||||||
|
SetPGVariable("default_transaction_read_only",
|
||||||
|
makeList1(item->arg), n->is_local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SetPGVariable(n->name, n->args, n->is_local);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* command, configuration file, and command line options.
|
* command, configuration file, and command line options.
|
||||||
* See src/backend/utils/misc/README for more information.
|
* See src/backend/utils/misc/README for more information.
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.109 2002/12/27 14:06:34 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.110 2003/01/10 22:03:29 petere Exp $
|
||||||
*
|
*
|
||||||
* Copyright 2000 by PostgreSQL Global Development Group
|
* Copyright 2000 by PostgreSQL Global Development Group
|
||||||
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
||||||
@ -516,6 +516,14 @@ static struct config_bool
|
|||||||
{"autocommit", PGC_USERSET}, &autocommit,
|
{"autocommit", PGC_USERSET}, &autocommit,
|
||||||
true, NULL, NULL
|
true, NULL, NULL
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
{"default_transaction_read_only", PGC_USERSET}, &DefaultXactReadOnly,
|
||||||
|
false, NULL, NULL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{"transaction_read_only", PGC_USERSET, GUC_NO_RESET_ALL}, &XactReadOnly,
|
||||||
|
false, NULL, NULL
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{NULL, 0}, NULL, false, NULL, NULL
|
{NULL, 0}, NULL, false, NULL, NULL
|
||||||
@ -841,7 +849,7 @@ static struct config_string
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{"TRANSACTION ISOLATION LEVEL", PGC_USERSET, GUC_NO_RESET_ALL},
|
{"transaction_isolation", PGC_USERSET, GUC_NO_RESET_ALL},
|
||||||
&XactIsoLevel_string,
|
&XactIsoLevel_string,
|
||||||
NULL, assign_XactIsoLevel, show_XactIsoLevel
|
NULL, assign_XactIsoLevel, show_XactIsoLevel
|
||||||
},
|
},
|
||||||
@ -1157,10 +1165,12 @@ InitializeGUCOptions(void)
|
|||||||
guc_string_workspace = NULL;
|
guc_string_workspace = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prevent any attempt to override TRANSACTION ISOLATION LEVEL from
|
* Prevent any attempt to override the transaction modes from
|
||||||
* non-interactive sources.
|
* non-interactive sources.
|
||||||
*/
|
*/
|
||||||
SetConfigOption("TRANSACTION ISOLATION LEVEL", "default",
|
SetConfigOption("transaction_isolation", "default",
|
||||||
|
PGC_POSTMASTER, PGC_S_OVERRIDE);
|
||||||
|
SetConfigOption("transaction_read_only", "no",
|
||||||
PGC_POSTMASTER, PGC_S_OVERRIDE);
|
PGC_POSTMASTER, PGC_S_OVERRIDE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2000-2002 by PostgreSQL Global Development Group
|
* Copyright 2000-2002 by PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.70 2002/12/13 05:36:24 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.71 2003/01/10 22:03:30 petere Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*----------------------------------------------------------------------
|
/*----------------------------------------------------------------------
|
||||||
@ -212,13 +212,7 @@ psql_completion(char *text, int start, int end)
|
|||||||
"CONSTRAINTS",
|
"CONSTRAINTS",
|
||||||
"NAMES",
|
"NAMES",
|
||||||
"SESSION",
|
"SESSION",
|
||||||
"TRANSACTION ISOLATION LEVEL",
|
"TRANSACTION",
|
||||||
/* these are treated in backend/commands/variable.c */
|
|
||||||
"DateStyle",
|
|
||||||
"TimeZone",
|
|
||||||
"client_encoding",
|
|
||||||
"server_encoding",
|
|
||||||
"seed",
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the rest should match USERSET entries in
|
* the rest should match USERSET entries in
|
||||||
@ -229,12 +223,14 @@ psql_completion(char *text, int start, int end)
|
|||||||
"autocommit",
|
"autocommit",
|
||||||
"checkpoint_segments",
|
"checkpoint_segments",
|
||||||
"checkpoint_timeout",
|
"checkpoint_timeout",
|
||||||
|
"client_encoding",
|
||||||
"client_min_messages",
|
"client_min_messages",
|
||||||
"commit_delay",
|
"commit_delay",
|
||||||
"commit_siblings",
|
"commit_siblings",
|
||||||
"cpu_index_tuple_cost",
|
"cpu_index_tuple_cost",
|
||||||
"cpu_operator_cost",
|
"cpu_operator_cost",
|
||||||
"cpu_tuple_cost",
|
"cpu_tuple_cost",
|
||||||
|
"DateStyle",
|
||||||
"db_user_namespace",
|
"db_user_namespace",
|
||||||
"deadlock_timeout",
|
"deadlock_timeout",
|
||||||
"debug_pretty_print",
|
"debug_pretty_print",
|
||||||
@ -269,7 +265,7 @@ psql_completion(char *text, int start, int end)
|
|||||||
"lc_messages",
|
"lc_messages",
|
||||||
"lc_monetary",
|
"lc_monetary",
|
||||||
"lc_numeric",
|
"lc_numeric",
|
||||||
"lc_timeC",
|
"lc_time",
|
||||||
"log_connections",
|
"log_connections",
|
||||||
"log_duration",
|
"log_duration",
|
||||||
"log_min_error_statement",
|
"log_min_error_statement",
|
||||||
@ -294,6 +290,8 @@ psql_completion(char *text, int start, int end)
|
|||||||
"log_planner_stats",
|
"log_planner_stats",
|
||||||
"log_source_port",
|
"log_source_port",
|
||||||
"log_statement_stats",
|
"log_statement_stats",
|
||||||
|
"seed",
|
||||||
|
"server_encoding",
|
||||||
"silent_mode",
|
"silent_mode",
|
||||||
"sort_mem",
|
"sort_mem",
|
||||||
"sql_inheritance",
|
"sql_inheritance",
|
||||||
@ -309,6 +307,7 @@ psql_completion(char *text, int start, int end)
|
|||||||
"syslog_facility",
|
"syslog_facility",
|
||||||
"syslog_ident",
|
"syslog_ident",
|
||||||
"tcpip_socket",
|
"tcpip_socket",
|
||||||
|
"TimeZone",
|
||||||
"trace_notify",
|
"trace_notify",
|
||||||
"transform_null_equals",
|
"transform_null_equals",
|
||||||
"unix_socket_directory",
|
"unix_socket_directory",
|
||||||
@ -817,10 +816,18 @@ psql_completion(char *text, int start, int end)
|
|||||||
strcasecmp(prev_wd, "RESET") == 0 ||
|
strcasecmp(prev_wd, "RESET") == 0 ||
|
||||||
strcasecmp(prev_wd, "SHOW") == 0)
|
strcasecmp(prev_wd, "SHOW") == 0)
|
||||||
COMPLETE_WITH_LIST(pgsql_variables);
|
COMPLETE_WITH_LIST(pgsql_variables);
|
||||||
/* Complete "SET TRANSACTION ISOLOLATION LEVEL" */
|
/* Complete "SET TRANSACTION" */
|
||||||
else if (strcasecmp(prev2_wd, "SET") == 0 &&
|
else if ((strcasecmp(prev2_wd, "SET") == 0 &&
|
||||||
strcasecmp(prev_wd, "TRANSACTION") == 0)
|
strcasecmp(prev_wd, "TRANSACTION") == 0) ||
|
||||||
COMPLETE_WITH_CONST("ISOLATION");
|
(strcasecmp(prev4_wd, "SESSION") == 0 &&
|
||||||
|
strcasecmp(prev3_wd, "CHARACTERISTICS") == 0 &&
|
||||||
|
strcasecmp(prev2_wd, "AS") == 0 &&
|
||||||
|
strcasecmp(prev_wd, "TRANSACTION") == 0))
|
||||||
|
{
|
||||||
|
char *my_list[] = {"ISOLATION", "READ", NULL};
|
||||||
|
|
||||||
|
COMPLETE_WITH_LIST(my_list);
|
||||||
|
}
|
||||||
else if (strcasecmp(prev3_wd, "SET") == 0 &&
|
else if (strcasecmp(prev3_wd, "SET") == 0 &&
|
||||||
strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
|
strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
|
||||||
strcasecmp(prev_wd, "ISOLATION") == 0)
|
strcasecmp(prev_wd, "ISOLATION") == 0)
|
||||||
@ -840,6 +847,15 @@ psql_completion(char *text, int start, int end)
|
|||||||
strcasecmp(prev2_wd, "LEVEL") == 0 &&
|
strcasecmp(prev2_wd, "LEVEL") == 0 &&
|
||||||
strcasecmp(prev_wd, "READ") == 0)
|
strcasecmp(prev_wd, "READ") == 0)
|
||||||
COMPLETE_WITH_CONST("COMMITTED");
|
COMPLETE_WITH_CONST("COMMITTED");
|
||||||
|
else if ((strcasecmp(prev3_wd, "SET") == 0 ||
|
||||||
|
strcasecmp(prev3_wd, "AS") == 0) &&
|
||||||
|
strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
|
||||||
|
strcasecmp(prev_wd, "READ") == 0)
|
||||||
|
{
|
||||||
|
char *my_list[] = {"ONLY", "WRITE", NULL};
|
||||||
|
|
||||||
|
COMPLETE_WITH_LIST(my_list);
|
||||||
|
}
|
||||||
/* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
|
/* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
|
||||||
else if (strcasecmp(prev3_wd, "SET") == 0 &&
|
else if (strcasecmp(prev3_wd, "SET") == 0 &&
|
||||||
strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
|
strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
|
||||||
@ -853,7 +869,7 @@ psql_completion(char *text, int start, int end)
|
|||||||
strcasecmp(prev_wd, "SESSION") == 0)
|
strcasecmp(prev_wd, "SESSION") == 0)
|
||||||
{
|
{
|
||||||
char *my_list[] = {"AUTHORIZATION",
|
char *my_list[] = {"AUTHORIZATION",
|
||||||
"CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL",
|
"CHARACTERISTICS AS TRANSACTION",
|
||||||
NULL};
|
NULL};
|
||||||
|
|
||||||
COMPLETE_WITH_LIST(my_list);
|
COMPLETE_WITH_LIST(my_list);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: xact.h,v 1.48 2002/11/18 01:17:39 tgl Exp $
|
* $Id: xact.h,v 1.49 2003/01/10 22:03:30 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
extern int DefaultXactIsoLevel;
|
extern int DefaultXactIsoLevel;
|
||||||
extern int XactIsoLevel;
|
extern int XactIsoLevel;
|
||||||
|
extern bool DefaultXactReadOnly;
|
||||||
|
extern bool XactReadOnly;
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* transaction state structure
|
* transaction state structure
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: namespace.h,v 1.24 2003/01/07 20:56:07 tgl Exp $
|
* $Id: namespace.h,v 1.25 2003/01/10 22:03:30 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -51,6 +51,7 @@ typedef struct _OpclassCandidateList
|
|||||||
extern Oid RangeVarGetRelid(const RangeVar *relation, bool failOK);
|
extern Oid RangeVarGetRelid(const RangeVar *relation, bool failOK);
|
||||||
extern Oid RangeVarGetCreationNamespace(const RangeVar *newRelation);
|
extern Oid RangeVarGetCreationNamespace(const RangeVar *newRelation);
|
||||||
extern Oid RelnameGetRelid(const char *relname);
|
extern Oid RelnameGetRelid(const char *relname);
|
||||||
|
extern Oid RelidGetNamespaceId(Oid relid);
|
||||||
extern bool RelationIsVisible(Oid relid);
|
extern bool RelationIsVisible(Oid relid);
|
||||||
|
|
||||||
extern Oid TypenameGetTypid(const char *typname);
|
extern Oid TypenameGetTypid(const char *typname);
|
||||||
|
@ -40,3 +40,31 @@ SELECT * FROM aggtest;
|
|||||||
42 | 324.78
|
42 | 324.78
|
||||||
(4 rows)
|
(4 rows)
|
||||||
|
|
||||||
|
-- Read-only tests
|
||||||
|
CREATE TABLE writetest (a int);
|
||||||
|
CREATE TEMPORARY TABLE temptest (a int);
|
||||||
|
SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY;
|
||||||
|
DROP TABLE writetest; -- fail
|
||||||
|
ERROR: transaction is read-only
|
||||||
|
INSERT INTO writetest VALUES (1); -- fail
|
||||||
|
ERROR: transaction is read-only
|
||||||
|
SELECT * FROM writetest; -- ok
|
||||||
|
a
|
||||||
|
---
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
DELETE FROM temptest; -- ok
|
||||||
|
UPDATE temptest SET a = 0 WHERE a = 1 AND writetest.a = temptest.a; -- ok
|
||||||
|
PREPARE test AS UPDATE writetest SET a = 0; -- ok
|
||||||
|
EXECUTE test; -- fail
|
||||||
|
ERROR: transaction is read-only
|
||||||
|
SELECT * FROM writetest, temptest; -- ok
|
||||||
|
a | a
|
||||||
|
---+---
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
CREATE TABLE test AS SELECT * FROM writetest; -- fail
|
||||||
|
ERROR: transaction is read-only
|
||||||
|
START TRANSACTION READ WRITE;
|
||||||
|
DROP TABLE writetest; -- ok
|
||||||
|
COMMIT;
|
||||||
|
@ -33,3 +33,24 @@ SELECT oid FROM pg_class WHERE relname = 'disappear';
|
|||||||
-- should have members again
|
-- should have members again
|
||||||
SELECT * FROM aggtest;
|
SELECT * FROM aggtest;
|
||||||
|
|
||||||
|
|
||||||
|
-- Read-only tests
|
||||||
|
|
||||||
|
CREATE TABLE writetest (a int);
|
||||||
|
CREATE TEMPORARY TABLE temptest (a int);
|
||||||
|
|
||||||
|
SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY;
|
||||||
|
|
||||||
|
DROP TABLE writetest; -- fail
|
||||||
|
INSERT INTO writetest VALUES (1); -- fail
|
||||||
|
SELECT * FROM writetest; -- ok
|
||||||
|
DELETE FROM temptest; -- ok
|
||||||
|
UPDATE temptest SET a = 0 WHERE a = 1 AND writetest.a = temptest.a; -- ok
|
||||||
|
PREPARE test AS UPDATE writetest SET a = 0; -- ok
|
||||||
|
EXECUTE test; -- fail
|
||||||
|
SELECT * FROM writetest, temptest; -- ok
|
||||||
|
CREATE TABLE test AS SELECT * FROM writetest; -- fail
|
||||||
|
|
||||||
|
START TRANSACTION READ WRITE;
|
||||||
|
DROP TABLE writetest; -- ok
|
||||||
|
COMMIT;
|
||||||
|
Reference in New Issue
Block a user