mirror of
https://github.com/postgres/postgres.git
synced 2025-04-27 22:56:53 +03:00
Improve the representation of FOR UPDATE/FOR SHARE so that we can
support both FOR UPDATE and FOR SHARE in one command, as well as both NOWAIT and normal WAIT behavior. The more general code is actually simpler and cleaner.
This commit is contained in:
parent
931bfc9664
commit
986085a7f0
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.90 2005/11/01 21:09:51 tgl Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.91 2006/04/30 18:30:38 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="parameter">expression</replac
|
|||||||
[ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC | USING <replaceable class="parameter">operator</replaceable> ] [, ...] ]
|
[ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC | USING <replaceable class="parameter">operator</replaceable> ] [, ...] ]
|
||||||
[ LIMIT { <replaceable class="parameter">count</replaceable> | ALL } ]
|
[ LIMIT { <replaceable class="parameter">count</replaceable> | ALL } ]
|
||||||
[ OFFSET <replaceable class="parameter">start</replaceable> ]
|
[ OFFSET <replaceable class="parameter">start</replaceable> ]
|
||||||
[ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] ]
|
[ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] [...] ]
|
||||||
|
|
||||||
where <replaceable class="parameter">from_item</replaceable> can be one of:
|
where <replaceable class="parameter">from_item</replaceable> can be one of:
|
||||||
|
|
||||||
@ -142,8 +142,8 @@ where <replaceable class="parameter">from_item</replaceable> can be one of:
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
If the <literal>FOR UPDATE</literal> or <literal>FOR SHARE</literal>
|
If <literal>FOR UPDATE</literal> or <literal>FOR SHARE</literal>
|
||||||
clause is specified, the
|
is specified, the
|
||||||
<command>SELECT</command> statement locks the selected rows
|
<command>SELECT</command> statement locks the selected rows
|
||||||
against concurrent updates. (See <xref linkend="sql-for-update-share"
|
against concurrent updates. (See <xref linkend="sql-for-update-share"
|
||||||
endterm="sql-for-update-share-title"> below.)
|
endterm="sql-for-update-share-title"> below.)
|
||||||
@ -852,19 +852,27 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
|
|||||||
from performing <command>SELECT FOR SHARE</command>.
|
from performing <command>SELECT FOR SHARE</command>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
It is currently not allowed for a single <command>SELECT</command>
|
|
||||||
statement to include both <literal>FOR UPDATE</literal> and
|
|
||||||
<literal>FOR SHARE</literal>, nor can different parts of the statement use
|
|
||||||
both <literal>NOWAIT</> and normal waiting mode.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If specific tables are named in <literal>FOR UPDATE</literal>
|
If specific tables are named in <literal>FOR UPDATE</literal>
|
||||||
or <literal>FOR SHARE</literal>,
|
or <literal>FOR SHARE</literal>,
|
||||||
then only rows coming from those tables are locked; any other
|
then only rows coming from those tables are locked; any other
|
||||||
tables used in the <command>SELECT</command> are simply read as
|
tables used in the <command>SELECT</command> are simply read as
|
||||||
usual.
|
usual. A <literal>FOR UPDATE</literal> or <literal>FOR SHARE</literal>
|
||||||
|
clause without a table list affects all tables used in the command.
|
||||||
|
If <literal>FOR UPDATE</literal> or <literal>FOR SHARE</literal> is
|
||||||
|
applied to a view or sub-query, it affects all tables used in
|
||||||
|
the view or sub-query.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Multiple <literal>FOR UPDATE</literal> and <literal>FOR SHARE</literal>
|
||||||
|
clauses can be written if it is necessary to specify different locking
|
||||||
|
behavior for different tables. If the same table is mentioned (or
|
||||||
|
implicitly affected) by both <literal>FOR UPDATE</literal> and
|
||||||
|
<literal>FOR SHARE</literal> clauses, then it is processed as
|
||||||
|
<literal>FOR UPDATE</literal>. Similarly, a table is processed
|
||||||
|
as <literal>NOWAIT</> if that is specified in any of the clauses
|
||||||
|
affecting it.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/select_into.sgml,v 1.36 2005/08/01 20:31:04 tgl Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/select_into.sgml,v 1.37 2006/04/30 18:30:38 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replac
|
|||||||
[ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
|
[ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
|
||||||
[ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
|
[ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
|
||||||
[ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
|
[ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
|
||||||
[ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] ]
|
[ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] [...] ]
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/sql.sgml,v 1.39 2006/03/10 19:10:49 momjian Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/sql.sgml,v 1.40 2006/04/30 18:30:38 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="sql-intro">
|
<chapter id="sql-intro">
|
||||||
<title>SQL</title>
|
<title>SQL</title>
|
||||||
@ -863,7 +863,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replac
|
|||||||
[ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
|
[ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
|
||||||
[ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
|
[ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
|
||||||
[ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
|
[ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
|
||||||
[ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] ]
|
[ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] [...] ]
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.269 2006/03/05 15:58:25 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.270 2006/04/30 18:30:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -452,6 +452,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
|||||||
Relation intoRelationDesc;
|
Relation intoRelationDesc;
|
||||||
bool do_select_into;
|
bool do_select_into;
|
||||||
TupleDesc tupType;
|
TupleDesc tupType;
|
||||||
|
ListCell *l;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do permissions checks. It's sufficient to examine the query's top
|
* Do permissions checks. It's sufficient to examine the query's top
|
||||||
@ -486,7 +487,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
|||||||
* parseTree->resultRelations identifies them all
|
* parseTree->resultRelations identifies them all
|
||||||
*/
|
*/
|
||||||
ResultRelInfo *resultRelInfo;
|
ResultRelInfo *resultRelInfo;
|
||||||
ListCell *l;
|
|
||||||
|
|
||||||
numResultRelations = list_length(resultRelations);
|
numResultRelations = list_length(resultRelations);
|
||||||
resultRelInfos = (ResultRelInfo *)
|
resultRelInfos = (ResultRelInfo *)
|
||||||
@ -549,27 +549,22 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
|||||||
* Have to lock relations selected FOR UPDATE/FOR SHARE
|
* Have to lock relations selected FOR UPDATE/FOR SHARE
|
||||||
*/
|
*/
|
||||||
estate->es_rowMarks = NIL;
|
estate->es_rowMarks = NIL;
|
||||||
estate->es_forUpdate = parseTree->forUpdate;
|
|
||||||
estate->es_rowNoWait = parseTree->rowNoWait;
|
|
||||||
if (parseTree->rowMarks != NIL)
|
|
||||||
{
|
|
||||||
ListCell *l;
|
|
||||||
|
|
||||||
foreach(l, parseTree->rowMarks)
|
foreach(l, parseTree->rowMarks)
|
||||||
{
|
{
|
||||||
Index rti = lfirst_int(l);
|
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
|
||||||
Oid relid = getrelid(rti, rangeTable);
|
Oid relid = getrelid(rc->rti, rangeTable);
|
||||||
Relation relation;
|
Relation relation;
|
||||||
ExecRowMark *erm;
|
ExecRowMark *erm;
|
||||||
|
|
||||||
relation = heap_open(relid, RowShareLock);
|
relation = heap_open(relid, RowShareLock);
|
||||||
erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
|
erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
|
||||||
erm->relation = relation;
|
erm->relation = relation;
|
||||||
erm->rti = rti;
|
erm->rti = rc->rti;
|
||||||
snprintf(erm->resname, sizeof(erm->resname), "ctid%u", rti);
|
erm->forUpdate = rc->forUpdate;
|
||||||
|
erm->noWait = rc->noWait;
|
||||||
|
snprintf(erm->resname, sizeof(erm->resname), "ctid%u", rc->rti);
|
||||||
estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
|
estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize the executor "tuple" table. We need slots for all the plan
|
* initialize the executor "tuple" table. We need slots for all the plan
|
||||||
@ -1222,7 +1217,7 @@ lnext: ;
|
|||||||
|
|
||||||
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
|
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
|
||||||
|
|
||||||
if (estate->es_forUpdate)
|
if (erm->forUpdate)
|
||||||
lockmode = LockTupleExclusive;
|
lockmode = LockTupleExclusive;
|
||||||
else
|
else
|
||||||
lockmode = LockTupleShared;
|
lockmode = LockTupleShared;
|
||||||
@ -1230,7 +1225,7 @@ lnext: ;
|
|||||||
test = heap_lock_tuple(erm->relation, &tuple, &buffer,
|
test = heap_lock_tuple(erm->relation, &tuple, &buffer,
|
||||||
&update_ctid, &update_xmax,
|
&update_ctid, &update_xmax,
|
||||||
estate->es_snapshot->curcid,
|
estate->es_snapshot->curcid,
|
||||||
lockmode, estate->es_rowNoWait);
|
lockmode, erm->noWait);
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
switch (test)
|
switch (test)
|
||||||
{
|
{
|
||||||
@ -2258,8 +2253,6 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
|
|||||||
epqstate->es_param_exec_vals = (ParamExecData *)
|
epqstate->es_param_exec_vals = (ParamExecData *)
|
||||||
palloc0(estate->es_topPlan->nParamExec * sizeof(ParamExecData));
|
palloc0(estate->es_topPlan->nParamExec * sizeof(ParamExecData));
|
||||||
epqstate->es_rowMarks = estate->es_rowMarks;
|
epqstate->es_rowMarks = estate->es_rowMarks;
|
||||||
epqstate->es_forUpdate = estate->es_forUpdate;
|
|
||||||
epqstate->es_rowNoWait = estate->es_rowNoWait;
|
|
||||||
epqstate->es_instrument = estate->es_instrument;
|
epqstate->es_instrument = estate->es_instrument;
|
||||||
epqstate->es_select_into = estate->es_select_into;
|
epqstate->es_select_into = estate->es_select_into;
|
||||||
epqstate->es_into_oids = estate->es_into_oids;
|
epqstate->es_into_oids = estate->es_into_oids;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.133 2006/03/05 15:58:26 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.134 2006/04/30 18:30:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -204,8 +204,6 @@ CreateExecutorState(void)
|
|||||||
estate->es_processed = 0;
|
estate->es_processed = 0;
|
||||||
estate->es_lastoid = InvalidOid;
|
estate->es_lastoid = InvalidOid;
|
||||||
estate->es_rowMarks = NIL;
|
estate->es_rowMarks = NIL;
|
||||||
estate->es_forUpdate = false;
|
|
||||||
estate->es_rowNoWait = false;
|
|
||||||
|
|
||||||
estate->es_instrument = false;
|
estate->es_instrument = false;
|
||||||
estate->es_select_into = false;
|
estate->es_select_into = false;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.334 2006/04/22 01:25:58 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.335 2006/04/30 18:30:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1409,6 +1409,18 @@ _copyGroupClause(GroupClause *from)
|
|||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static RowMarkClause *
|
||||||
|
_copyRowMarkClause(RowMarkClause *from)
|
||||||
|
{
|
||||||
|
RowMarkClause *newnode = makeNode(RowMarkClause);
|
||||||
|
|
||||||
|
COPY_SCALAR_FIELD(rti);
|
||||||
|
COPY_SCALAR_FIELD(forUpdate);
|
||||||
|
COPY_SCALAR_FIELD(noWait);
|
||||||
|
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
static A_Expr *
|
static A_Expr *
|
||||||
_copyAExpr(A_Expr *from)
|
_copyAExpr(A_Expr *from)
|
||||||
{
|
{
|
||||||
@ -1650,7 +1662,7 @@ _copyLockingClause(LockingClause *from)
|
|||||||
|
|
||||||
COPY_NODE_FIELD(lockedRels);
|
COPY_NODE_FIELD(lockedRels);
|
||||||
COPY_SCALAR_FIELD(forUpdate);
|
COPY_SCALAR_FIELD(forUpdate);
|
||||||
COPY_SCALAR_FIELD(nowait);
|
COPY_SCALAR_FIELD(noWait);
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
@ -1673,9 +1685,6 @@ _copyQuery(Query *from)
|
|||||||
COPY_SCALAR_FIELD(hasSubLinks);
|
COPY_SCALAR_FIELD(hasSubLinks);
|
||||||
COPY_NODE_FIELD(rtable);
|
COPY_NODE_FIELD(rtable);
|
||||||
COPY_NODE_FIELD(jointree);
|
COPY_NODE_FIELD(jointree);
|
||||||
COPY_NODE_FIELD(rowMarks);
|
|
||||||
COPY_SCALAR_FIELD(forUpdate);
|
|
||||||
COPY_SCALAR_FIELD(rowNoWait);
|
|
||||||
COPY_NODE_FIELD(targetList);
|
COPY_NODE_FIELD(targetList);
|
||||||
COPY_NODE_FIELD(groupClause);
|
COPY_NODE_FIELD(groupClause);
|
||||||
COPY_NODE_FIELD(havingQual);
|
COPY_NODE_FIELD(havingQual);
|
||||||
@ -1683,6 +1692,7 @@ _copyQuery(Query *from)
|
|||||||
COPY_NODE_FIELD(sortClause);
|
COPY_NODE_FIELD(sortClause);
|
||||||
COPY_NODE_FIELD(limitOffset);
|
COPY_NODE_FIELD(limitOffset);
|
||||||
COPY_NODE_FIELD(limitCount);
|
COPY_NODE_FIELD(limitCount);
|
||||||
|
COPY_NODE_FIELD(rowMarks);
|
||||||
COPY_NODE_FIELD(setOperations);
|
COPY_NODE_FIELD(setOperations);
|
||||||
COPY_NODE_FIELD(resultRelations);
|
COPY_NODE_FIELD(resultRelations);
|
||||||
|
|
||||||
@ -3284,6 +3294,9 @@ copyObject(void *from)
|
|||||||
case T_GroupClause:
|
case T_GroupClause:
|
||||||
retval = _copyGroupClause(from);
|
retval = _copyGroupClause(from);
|
||||||
break;
|
break;
|
||||||
|
case T_RowMarkClause:
|
||||||
|
retval = _copyRowMarkClause(from);
|
||||||
|
break;
|
||||||
case T_FkConstraint:
|
case T_FkConstraint:
|
||||||
retval = _copyFkConstraint(from);
|
retval = _copyFkConstraint(from);
|
||||||
break;
|
break;
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.270 2006/04/22 01:25:59 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.271 2006/04/30 18:30:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -665,9 +665,6 @@ _equalQuery(Query *a, Query *b)
|
|||||||
COMPARE_SCALAR_FIELD(hasSubLinks);
|
COMPARE_SCALAR_FIELD(hasSubLinks);
|
||||||
COMPARE_NODE_FIELD(rtable);
|
COMPARE_NODE_FIELD(rtable);
|
||||||
COMPARE_NODE_FIELD(jointree);
|
COMPARE_NODE_FIELD(jointree);
|
||||||
COMPARE_NODE_FIELD(rowMarks);
|
|
||||||
COMPARE_SCALAR_FIELD(forUpdate);
|
|
||||||
COMPARE_SCALAR_FIELD(rowNoWait);
|
|
||||||
COMPARE_NODE_FIELD(targetList);
|
COMPARE_NODE_FIELD(targetList);
|
||||||
COMPARE_NODE_FIELD(groupClause);
|
COMPARE_NODE_FIELD(groupClause);
|
||||||
COMPARE_NODE_FIELD(havingQual);
|
COMPARE_NODE_FIELD(havingQual);
|
||||||
@ -675,6 +672,7 @@ _equalQuery(Query *a, Query *b)
|
|||||||
COMPARE_NODE_FIELD(sortClause);
|
COMPARE_NODE_FIELD(sortClause);
|
||||||
COMPARE_NODE_FIELD(limitOffset);
|
COMPARE_NODE_FIELD(limitOffset);
|
||||||
COMPARE_NODE_FIELD(limitCount);
|
COMPARE_NODE_FIELD(limitCount);
|
||||||
|
COMPARE_NODE_FIELD(rowMarks);
|
||||||
COMPARE_NODE_FIELD(setOperations);
|
COMPARE_NODE_FIELD(setOperations);
|
||||||
COMPARE_NODE_FIELD(resultRelations);
|
COMPARE_NODE_FIELD(resultRelations);
|
||||||
|
|
||||||
@ -1688,7 +1686,7 @@ _equalLockingClause(LockingClause *a, LockingClause *b)
|
|||||||
{
|
{
|
||||||
COMPARE_NODE_FIELD(lockedRels);
|
COMPARE_NODE_FIELD(lockedRels);
|
||||||
COMPARE_SCALAR_FIELD(forUpdate);
|
COMPARE_SCALAR_FIELD(forUpdate);
|
||||||
COMPARE_SCALAR_FIELD(nowait);
|
COMPARE_SCALAR_FIELD(noWait);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1723,6 +1721,16 @@ _equalSortClause(SortClause *a, SortClause *b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_equalRowMarkClause(RowMarkClause *a, RowMarkClause *b)
|
||||||
|
{
|
||||||
|
COMPARE_SCALAR_FIELD(rti);
|
||||||
|
COMPARE_SCALAR_FIELD(forUpdate);
|
||||||
|
COMPARE_SCALAR_FIELD(noWait);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
_equalFkConstraint(FkConstraint *a, FkConstraint *b)
|
_equalFkConstraint(FkConstraint *a, FkConstraint *b)
|
||||||
{
|
{
|
||||||
@ -2297,6 +2305,9 @@ equal(void *a, void *b)
|
|||||||
/* GroupClause is equivalent to SortClause */
|
/* GroupClause is equivalent to SortClause */
|
||||||
retval = _equalSortClause(a, b);
|
retval = _equalSortClause(a, b);
|
||||||
break;
|
break;
|
||||||
|
case T_RowMarkClause:
|
||||||
|
retval = _equalRowMarkClause(a, b);
|
||||||
|
break;
|
||||||
case T_FkConstraint:
|
case T_FkConstraint:
|
||||||
retval = _equalFkConstraint(a, b);
|
retval = _equalFkConstraint(a, b);
|
||||||
break;
|
break;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.273 2006/04/22 01:25:59 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.274 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Every node type that can appear in stored rules' parsetrees *must*
|
* Every node type that can appear in stored rules' parsetrees *must*
|
||||||
@ -1418,7 +1418,7 @@ _outLockingClause(StringInfo str, LockingClause *node)
|
|||||||
|
|
||||||
WRITE_NODE_FIELD(lockedRels);
|
WRITE_NODE_FIELD(lockedRels);
|
||||||
WRITE_BOOL_FIELD(forUpdate);
|
WRITE_BOOL_FIELD(forUpdate);
|
||||||
WRITE_BOOL_FIELD(nowait);
|
WRITE_BOOL_FIELD(noWait);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1514,9 +1514,6 @@ _outQuery(StringInfo str, Query *node)
|
|||||||
WRITE_BOOL_FIELD(hasSubLinks);
|
WRITE_BOOL_FIELD(hasSubLinks);
|
||||||
WRITE_NODE_FIELD(rtable);
|
WRITE_NODE_FIELD(rtable);
|
||||||
WRITE_NODE_FIELD(jointree);
|
WRITE_NODE_FIELD(jointree);
|
||||||
WRITE_NODE_FIELD(rowMarks);
|
|
||||||
WRITE_BOOL_FIELD(forUpdate);
|
|
||||||
WRITE_BOOL_FIELD(rowNoWait);
|
|
||||||
WRITE_NODE_FIELD(targetList);
|
WRITE_NODE_FIELD(targetList);
|
||||||
WRITE_NODE_FIELD(groupClause);
|
WRITE_NODE_FIELD(groupClause);
|
||||||
WRITE_NODE_FIELD(havingQual);
|
WRITE_NODE_FIELD(havingQual);
|
||||||
@ -1524,6 +1521,7 @@ _outQuery(StringInfo str, Query *node)
|
|||||||
WRITE_NODE_FIELD(sortClause);
|
WRITE_NODE_FIELD(sortClause);
|
||||||
WRITE_NODE_FIELD(limitOffset);
|
WRITE_NODE_FIELD(limitOffset);
|
||||||
WRITE_NODE_FIELD(limitCount);
|
WRITE_NODE_FIELD(limitCount);
|
||||||
|
WRITE_NODE_FIELD(rowMarks);
|
||||||
WRITE_NODE_FIELD(setOperations);
|
WRITE_NODE_FIELD(setOperations);
|
||||||
WRITE_NODE_FIELD(resultRelations);
|
WRITE_NODE_FIELD(resultRelations);
|
||||||
}
|
}
|
||||||
@ -1546,6 +1544,16 @@ _outGroupClause(StringInfo str, GroupClause *node)
|
|||||||
WRITE_OID_FIELD(sortop);
|
WRITE_OID_FIELD(sortop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_outRowMarkClause(StringInfo str, RowMarkClause *node)
|
||||||
|
{
|
||||||
|
WRITE_NODE_TYPE("ROWMARKCLAUSE");
|
||||||
|
|
||||||
|
WRITE_UINT_FIELD(rti);
|
||||||
|
WRITE_BOOL_FIELD(forUpdate);
|
||||||
|
WRITE_BOOL_FIELD(noWait);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_outSetOperationStmt(StringInfo str, SetOperationStmt *node)
|
_outSetOperationStmt(StringInfo str, SetOperationStmt *node)
|
||||||
{
|
{
|
||||||
@ -2113,6 +2121,9 @@ _outNode(StringInfo str, void *obj)
|
|||||||
case T_GroupClause:
|
case T_GroupClause:
|
||||||
_outGroupClause(str, obj);
|
_outGroupClause(str, obj);
|
||||||
break;
|
break;
|
||||||
|
case T_RowMarkClause:
|
||||||
|
_outRowMarkClause(str, obj);
|
||||||
|
break;
|
||||||
case T_SetOperationStmt:
|
case T_SetOperationStmt:
|
||||||
_outSetOperationStmt(str, obj);
|
_outSetOperationStmt(str, obj);
|
||||||
break;
|
break;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.188 2006/04/22 01:25:59 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.189 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Path and Plan nodes do not have any readfuncs support, because we
|
* Path and Plan nodes do not have any readfuncs support, because we
|
||||||
@ -147,9 +147,6 @@ _readQuery(void)
|
|||||||
READ_BOOL_FIELD(hasSubLinks);
|
READ_BOOL_FIELD(hasSubLinks);
|
||||||
READ_NODE_FIELD(rtable);
|
READ_NODE_FIELD(rtable);
|
||||||
READ_NODE_FIELD(jointree);
|
READ_NODE_FIELD(jointree);
|
||||||
READ_NODE_FIELD(rowMarks);
|
|
||||||
READ_BOOL_FIELD(forUpdate);
|
|
||||||
READ_BOOL_FIELD(rowNoWait);
|
|
||||||
READ_NODE_FIELD(targetList);
|
READ_NODE_FIELD(targetList);
|
||||||
READ_NODE_FIELD(groupClause);
|
READ_NODE_FIELD(groupClause);
|
||||||
READ_NODE_FIELD(havingQual);
|
READ_NODE_FIELD(havingQual);
|
||||||
@ -157,6 +154,7 @@ _readQuery(void)
|
|||||||
READ_NODE_FIELD(sortClause);
|
READ_NODE_FIELD(sortClause);
|
||||||
READ_NODE_FIELD(limitOffset);
|
READ_NODE_FIELD(limitOffset);
|
||||||
READ_NODE_FIELD(limitCount);
|
READ_NODE_FIELD(limitCount);
|
||||||
|
READ_NODE_FIELD(rowMarks);
|
||||||
READ_NODE_FIELD(setOperations);
|
READ_NODE_FIELD(setOperations);
|
||||||
READ_NODE_FIELD(resultRelations);
|
READ_NODE_FIELD(resultRelations);
|
||||||
|
|
||||||
@ -219,6 +217,21 @@ _readGroupClause(void)
|
|||||||
READ_DONE();
|
READ_DONE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _readRowMarkClause
|
||||||
|
*/
|
||||||
|
static RowMarkClause *
|
||||||
|
_readRowMarkClause(void)
|
||||||
|
{
|
||||||
|
READ_LOCALS(RowMarkClause);
|
||||||
|
|
||||||
|
READ_UINT_FIELD(rti);
|
||||||
|
READ_BOOL_FIELD(forUpdate);
|
||||||
|
READ_BOOL_FIELD(noWait);
|
||||||
|
|
||||||
|
READ_DONE();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _readSetOperationStmt
|
* _readSetOperationStmt
|
||||||
*/
|
*/
|
||||||
@ -934,6 +947,8 @@ parseNodeString(void)
|
|||||||
return_value = _readSortClause();
|
return_value = _readSortClause();
|
||||||
else if (MATCH("GROUPCLAUSE", 11))
|
else if (MATCH("GROUPCLAUSE", 11))
|
||||||
return_value = _readGroupClause();
|
return_value = _readGroupClause();
|
||||||
|
else if (MATCH("ROWMARKCLAUSE", 13))
|
||||||
|
return_value = _readRowMarkClause();
|
||||||
else if (MATCH("SETOPERATIONSTMT", 16))
|
else if (MATCH("SETOPERATIONSTMT", 16))
|
||||||
return_value = _readSetOperationStmt();
|
return_value = _readSetOperationStmt();
|
||||||
else if (MATCH("ALIAS", 5))
|
else if (MATCH("ALIAS", 5))
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.144 2006/03/05 15:58:28 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.145 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -268,7 +268,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
|||||||
* currently supposes that every rowMark relation is involved in every
|
* currently supposes that every rowMark relation is involved in every
|
||||||
* row returned by the query.)
|
* row returned by the query.)
|
||||||
*/
|
*/
|
||||||
if (list_member_int(root->parse->rowMarks, parentRTindex))
|
if (get_rowmark(root->parse, parentRTindex))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("SELECT FOR UPDATE/SHARE is not supported for inheritance queries")));
|
errmsg("SELECT FOR UPDATE/SHARE is not supported for inheritance queries")));
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.209 2006/04/25 16:54:09 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.210 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -843,7 +843,7 @@ create_indexscan_plan(PlannerInfo *root,
|
|||||||
if (best_path->indexinfo->indpred)
|
if (best_path->indexinfo->indpred)
|
||||||
{
|
{
|
||||||
if (baserelid != root->parse->resultRelation &&
|
if (baserelid != root->parse->resultRelation &&
|
||||||
!list_member_int(root->parse->rowMarks, baserelid))
|
get_rowmark(root->parse, baserelid) == NULL)
|
||||||
if (predicate_implied_by(clausel,
|
if (predicate_implied_by(clausel,
|
||||||
best_path->indexinfo->indpred))
|
best_path->indexinfo->indpred))
|
||||||
continue;
|
continue;
|
||||||
@ -962,7 +962,7 @@ create_bitmap_scan_plan(PlannerInfo *root,
|
|||||||
if (ipath->indexinfo->indpred)
|
if (ipath->indexinfo->indpred)
|
||||||
{
|
{
|
||||||
if (baserelid != root->parse->resultRelation &&
|
if (baserelid != root->parse->resultRelation &&
|
||||||
!list_member_int(root->parse->rowMarks, baserelid))
|
get_rowmark(root->parse, baserelid) == NULL)
|
||||||
if (predicate_implied_by(clausel,
|
if (predicate_implied_by(clausel,
|
||||||
ipath->indexinfo->indpred))
|
ipath->indexinfo->indpred))
|
||||||
continue;
|
continue;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.37 2006/03/07 01:00:15 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.38 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -409,29 +409,9 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Pull up any FOR UPDATE/SHARE markers, too. (OffsetVarNodes
|
* Pull up any FOR UPDATE/SHARE markers, too. (OffsetVarNodes
|
||||||
* already adjusted the marker values, so just list_concat the
|
* already adjusted the marker rtindexes, so just concat the lists.)
|
||||||
* list.)
|
|
||||||
*
|
|
||||||
* Executor can't handle multiple FOR UPDATE/SHARE/NOWAIT flags,
|
|
||||||
* so complain if they are valid but different
|
|
||||||
*/
|
*/
|
||||||
if (parse->rowMarks && subquery->rowMarks)
|
|
||||||
{
|
|
||||||
if (parse->forUpdate != subquery->forUpdate)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));
|
|
||||||
if (parse->rowNoWait != subquery->rowNoWait)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("cannot use both wait and NOWAIT in one query")));
|
|
||||||
}
|
|
||||||
parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks);
|
parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks);
|
||||||
if (subquery->rowMarks)
|
|
||||||
{
|
|
||||||
parse->forUpdate = subquery->forUpdate;
|
|
||||||
parse->rowNoWait = subquery->rowNoWait;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We also have to fix the relid sets of any parent InClauseInfo
|
* We also have to fix the relid sets of any parent InClauseInfo
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.81 2006/04/05 22:11:55 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.82 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -116,7 +116,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
|
|||||||
* invalid. This is also checked at parse time, but that's
|
* invalid. This is also checked at parse time, but that's
|
||||||
* insufficient because of rule substitution, query pullup, etc.
|
* insufficient because of rule substitution, query pullup, etc.
|
||||||
*/
|
*/
|
||||||
CheckSelectLocking(parse, parse->forUpdate);
|
CheckSelectLocking(parse);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Currently the executor only supports FOR UPDATE/SHARE at top level
|
* Currently the executor only supports FOR UPDATE/SHARE at top level
|
||||||
@ -128,19 +128,19 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
|
|||||||
|
|
||||||
foreach(l, parse->rowMarks)
|
foreach(l, parse->rowMarks)
|
||||||
{
|
{
|
||||||
Index rti = lfirst_int(l);
|
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
|
||||||
Var *var;
|
Var *var;
|
||||||
char *resname;
|
char *resname;
|
||||||
TargetEntry *tle;
|
TargetEntry *tle;
|
||||||
|
|
||||||
var = makeVar(rti,
|
var = makeVar(rc->rti,
|
||||||
SelfItemPointerAttributeNumber,
|
SelfItemPointerAttributeNumber,
|
||||||
TIDOID,
|
TIDOID,
|
||||||
-1,
|
-1,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
resname = (char *) palloc(32);
|
resname = (char *) palloc(32);
|
||||||
snprintf(resname, 32, "ctid%u", rti);
|
snprintf(resname, 32, "ctid%u", rc->rti);
|
||||||
|
|
||||||
tle = makeTargetEntry((Expr *) var,
|
tle = makeTargetEntry((Expr *) var,
|
||||||
list_length(tlist) + 1,
|
list_length(tlist) + 1,
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.131 2006/03/05 15:58:31 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.132 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -816,7 +816,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
|
|||||||
*/
|
*/
|
||||||
if (rti == parse->resultRelation)
|
if (rti == parse->resultRelation)
|
||||||
lockmode = RowExclusiveLock;
|
lockmode = RowExclusiveLock;
|
||||||
else if (list_member_int(parse->rowMarks, rti))
|
else if (get_rowmark(parse, rti))
|
||||||
lockmode = RowShareLock;
|
lockmode = RowShareLock;
|
||||||
else
|
else
|
||||||
lockmode = AccessShareLock;
|
lockmode = AccessShareLock;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.333 2006/04/22 01:25:59 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.334 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1805,6 +1805,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
{
|
{
|
||||||
Query *qry = makeNode(Query);
|
Query *qry = makeNode(Query);
|
||||||
Node *qual;
|
Node *qual;
|
||||||
|
ListCell *l;
|
||||||
|
|
||||||
qry->commandType = CMD_SELECT;
|
qry->commandType = CMD_SELECT;
|
||||||
|
|
||||||
@ -1870,8 +1871,10 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
|
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
|
||||||
parseCheckAggregates(pstate, qry);
|
parseCheckAggregates(pstate, qry);
|
||||||
|
|
||||||
if (stmt->lockingClause)
|
foreach(l, stmt->lockingClause)
|
||||||
transformLockingClause(qry, stmt->lockingClause);
|
{
|
||||||
|
transformLockingClause(qry, (LockingClause *) lfirst(l));
|
||||||
|
}
|
||||||
|
|
||||||
return qry;
|
return qry;
|
||||||
}
|
}
|
||||||
@ -1899,10 +1902,11 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
List *sortClause;
|
List *sortClause;
|
||||||
Node *limitOffset;
|
Node *limitOffset;
|
||||||
Node *limitCount;
|
Node *limitCount;
|
||||||
LockingClause *lockingClause;
|
List *lockingClause;
|
||||||
Node *node;
|
Node *node;
|
||||||
ListCell *left_tlist,
|
ListCell *left_tlist,
|
||||||
*dtlist;
|
*dtlist,
|
||||||
|
*l;
|
||||||
List *targetvars,
|
List *targetvars,
|
||||||
*targetnames,
|
*targetnames,
|
||||||
*sv_relnamespace,
|
*sv_relnamespace,
|
||||||
@ -1942,7 +1946,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
stmt->sortClause = NIL;
|
stmt->sortClause = NIL;
|
||||||
stmt->limitOffset = NULL;
|
stmt->limitOffset = NULL;
|
||||||
stmt->limitCount = NULL;
|
stmt->limitCount = NULL;
|
||||||
stmt->lockingClause = NULL;
|
stmt->lockingClause = NIL;
|
||||||
|
|
||||||
/* We don't support FOR UPDATE/SHARE with set ops at the moment. */
|
/* We don't support FOR UPDATE/SHARE with set ops at the moment. */
|
||||||
if (lockingClause)
|
if (lockingClause)
|
||||||
@ -2084,8 +2088,10 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
|
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
|
||||||
parseCheckAggregates(pstate, qry);
|
parseCheckAggregates(pstate, qry);
|
||||||
|
|
||||||
if (lockingClause)
|
foreach(l, lockingClause)
|
||||||
transformLockingClause(qry, lockingClause);
|
{
|
||||||
|
transformLockingClause(qry, (LockingClause *) lfirst(l));
|
||||||
|
}
|
||||||
|
|
||||||
return qry;
|
return qry;
|
||||||
}
|
}
|
||||||
@ -2743,44 +2749,34 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
|
|||||||
|
|
||||||
/* exported so planner can check again after rewriting, query pullup, etc */
|
/* exported so planner can check again after rewriting, query pullup, etc */
|
||||||
void
|
void
|
||||||
CheckSelectLocking(Query *qry, bool forUpdate)
|
CheckSelectLocking(Query *qry)
|
||||||
{
|
{
|
||||||
const char *operation;
|
|
||||||
|
|
||||||
if (forUpdate)
|
|
||||||
operation = "SELECT FOR UPDATE";
|
|
||||||
else
|
|
||||||
operation = "SELECT FOR SHARE";
|
|
||||||
|
|
||||||
if (qry->setOperations)
|
if (qry->setOperations)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
/* translator: %s is a SQL command, like SELECT FOR UPDATE */
|
errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));
|
||||||
errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT", operation)));
|
|
||||||
if (qry->distinctClause != NIL)
|
if (qry->distinctClause != NIL)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
/* translator: %s is a SQL command, like SELECT FOR UPDATE */
|
errmsg("SELECT FOR UPDATE/SHARE is not allowed with DISTINCT clause")));
|
||||||
errmsg("%s is not allowed with DISTINCT clause", operation)));
|
|
||||||
if (qry->groupClause != NIL)
|
if (qry->groupClause != NIL)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
/* translator: %s is a SQL command, like SELECT FOR UPDATE */
|
errmsg("SELECT FOR UPDATE/SHARE is not allowed with GROUP BY clause")));
|
||||||
errmsg("%s is not allowed with GROUP BY clause", operation)));
|
|
||||||
if (qry->havingQual != NULL)
|
if (qry->havingQual != NULL)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
/* translator: %s is a SQL command, like SELECT FOR UPDATE */
|
errmsg("SELECT FOR UPDATE/SHARE is not allowed with HAVING clause")));
|
||||||
errmsg("%s is not allowed with HAVING clause", operation)));
|
|
||||||
if (qry->hasAggs)
|
if (qry->hasAggs)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
/* translator: %s is a SQL command, like SELECT FOR UPDATE */
|
errmsg("SELECT FOR UPDATE/SHARE is not allowed with aggregate functions")));
|
||||||
errmsg("%s is not allowed with aggregate functions", operation)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert FOR UPDATE/SHARE name list into rowMarks list of integer relids
|
* Transform a FOR UPDATE/SHARE clause
|
||||||
|
*
|
||||||
|
* This basically involves replacing names by integer relids.
|
||||||
*
|
*
|
||||||
* NB: if you need to change this, see also markQueryForLocking()
|
* NB: if you need to change this, see also markQueryForLocking()
|
||||||
* in rewriteHandler.c.
|
* in rewriteHandler.c.
|
||||||
@ -2789,35 +2785,18 @@ static void
|
|||||||
transformLockingClause(Query *qry, LockingClause *lc)
|
transformLockingClause(Query *qry, LockingClause *lc)
|
||||||
{
|
{
|
||||||
List *lockedRels = lc->lockedRels;
|
List *lockedRels = lc->lockedRels;
|
||||||
List *rowMarks;
|
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
ListCell *rt;
|
ListCell *rt;
|
||||||
Index i;
|
Index i;
|
||||||
LockingClause *allrels;
|
LockingClause *allrels;
|
||||||
|
|
||||||
if (qry->rowMarks)
|
CheckSelectLocking(qry);
|
||||||
{
|
|
||||||
if (lc->forUpdate != qry->forUpdate)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));
|
|
||||||
if (lc->nowait != qry->rowNoWait)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("cannot use both wait and NOWAIT in one query")));
|
|
||||||
}
|
|
||||||
qry->forUpdate = lc->forUpdate;
|
|
||||||
qry->rowNoWait = lc->nowait;
|
|
||||||
|
|
||||||
CheckSelectLocking(qry, lc->forUpdate);
|
|
||||||
|
|
||||||
/* make a clause we can pass down to subqueries to select all rels */
|
/* make a clause we can pass down to subqueries to select all rels */
|
||||||
allrels = makeNode(LockingClause);
|
allrels = makeNode(LockingClause);
|
||||||
allrels->lockedRels = NIL; /* indicates all rels */
|
allrels->lockedRels = NIL; /* indicates all rels */
|
||||||
allrels->forUpdate = lc->forUpdate;
|
allrels->forUpdate = lc->forUpdate;
|
||||||
allrels->nowait = lc->nowait;
|
allrels->noWait = lc->noWait;
|
||||||
|
|
||||||
rowMarks = qry->rowMarks;
|
|
||||||
|
|
||||||
if (lockedRels == NIL)
|
if (lockedRels == NIL)
|
||||||
{
|
{
|
||||||
@ -2831,8 +2810,7 @@ transformLockingClause(Query *qry, LockingClause *lc)
|
|||||||
switch (rte->rtekind)
|
switch (rte->rtekind)
|
||||||
{
|
{
|
||||||
case RTE_RELATION:
|
case RTE_RELATION:
|
||||||
/* use list_append_unique to avoid duplicates */
|
applyLockingClause(qry, i, lc->forUpdate, lc->noWait);
|
||||||
rowMarks = list_append_unique_int(rowMarks, i);
|
|
||||||
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
|
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
|
||||||
break;
|
break;
|
||||||
case RTE_SUBQUERY:
|
case RTE_SUBQUERY:
|
||||||
@ -2867,8 +2845,8 @@ transformLockingClause(Query *qry, LockingClause *lc)
|
|||||||
switch (rte->rtekind)
|
switch (rte->rtekind)
|
||||||
{
|
{
|
||||||
case RTE_RELATION:
|
case RTE_RELATION:
|
||||||
/* use list_append_unique to avoid duplicates */
|
applyLockingClause(qry, i,
|
||||||
rowMarks = list_append_unique_int(rowMarks, i);
|
lc->forUpdate, lc->noWait);
|
||||||
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
|
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
|
||||||
break;
|
break;
|
||||||
case RTE_SUBQUERY:
|
case RTE_SUBQUERY:
|
||||||
@ -2909,8 +2887,41 @@ transformLockingClause(Query *qry, LockingClause *lc)
|
|||||||
relname)));
|
relname)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qry->rowMarks = rowMarks;
|
/*
|
||||||
|
* Record locking info for a single rangetable item
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
applyLockingClause(Query *qry, Index rtindex, bool forUpdate, bool noWait)
|
||||||
|
{
|
||||||
|
RowMarkClause *rc;
|
||||||
|
|
||||||
|
/* Check for pre-existing entry for same rtindex */
|
||||||
|
if ((rc = get_rowmark(qry, rtindex)) != NULL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the same RTE is specified both FOR UPDATE and FOR SHARE,
|
||||||
|
* treat it as FOR UPDATE. (Reasonable, since you can't take
|
||||||
|
* both a shared and exclusive lock at the same time; it'll
|
||||||
|
* end up being exclusive anyway.)
|
||||||
|
*
|
||||||
|
* We also consider that NOWAIT wins if it's specified both ways.
|
||||||
|
* This is a bit more debatable but raising an error doesn't
|
||||||
|
* seem helpful. (Consider for instance SELECT FOR UPDATE NOWAIT
|
||||||
|
* from a view that internally contains a plain FOR UPDATE spec.)
|
||||||
|
*/
|
||||||
|
rc->forUpdate |= forUpdate;
|
||||||
|
rc->noWait |= noWait;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make a new RowMarkClause */
|
||||||
|
rc = makeNode(RowMarkClause);
|
||||||
|
rc->rti = rtindex;
|
||||||
|
rc->forUpdate = forUpdate;
|
||||||
|
rc->noWait = noWait;
|
||||||
|
qry->rowMarks = lappend(qry->rowMarks, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.543 2006/04/27 00:33:45 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.544 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -96,7 +96,7 @@ static List *check_func_name(List *names);
|
|||||||
static List *extractArgTypes(List *parameters);
|
static List *extractArgTypes(List *parameters);
|
||||||
static SelectStmt *findLeftmostSelect(SelectStmt *node);
|
static SelectStmt *findLeftmostSelect(SelectStmt *node);
|
||||||
static void insertSelectOptions(SelectStmt *stmt,
|
static void insertSelectOptions(SelectStmt *stmt,
|
||||||
List *sortClause, Node *lockingClause,
|
List *sortClause, List *lockingClause,
|
||||||
Node *limitOffset, Node *limitCount);
|
Node *limitOffset, Node *limitCount);
|
||||||
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
|
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
|
||||||
static Node *doNegate(Node *n, int location);
|
static Node *doNegate(Node *n, int location);
|
||||||
@ -253,7 +253,8 @@ static void doNegateFloat(Value *v);
|
|||||||
%type <oncommit> OnCommitOption
|
%type <oncommit> OnCommitOption
|
||||||
%type <withoids> OptWithOids
|
%type <withoids> OptWithOids
|
||||||
|
|
||||||
%type <node> for_locking_clause opt_for_locking_clause
|
%type <node> for_locking_item
|
||||||
|
%type <list> for_locking_clause opt_for_locking_clause for_locking_items
|
||||||
%type <list> locked_rels_list
|
%type <list> locked_rels_list
|
||||||
%type <boolean> opt_all
|
%type <boolean> opt_all
|
||||||
|
|
||||||
@ -5400,7 +5401,7 @@ select_no_parens:
|
|||||||
simple_select { $$ = $1; }
|
simple_select { $$ = $1; }
|
||||||
| select_clause sort_clause
|
| select_clause sort_clause
|
||||||
{
|
{
|
||||||
insertSelectOptions((SelectStmt *) $1, $2, NULL,
|
insertSelectOptions((SelectStmt *) $1, $2, NIL,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
@ -5644,12 +5645,27 @@ having_clause:
|
|||||||
;
|
;
|
||||||
|
|
||||||
for_locking_clause:
|
for_locking_clause:
|
||||||
|
for_locking_items { $$ = $1; }
|
||||||
|
| FOR READ ONLY { $$ = NIL; }
|
||||||
|
;
|
||||||
|
|
||||||
|
opt_for_locking_clause:
|
||||||
|
for_locking_clause { $$ = $1; }
|
||||||
|
| /* EMPTY */ { $$ = NIL; }
|
||||||
|
;
|
||||||
|
|
||||||
|
for_locking_items:
|
||||||
|
for_locking_item { $$ = list_make1($1); }
|
||||||
|
| for_locking_items for_locking_item { $$ = lappend($1, $2); }
|
||||||
|
;
|
||||||
|
|
||||||
|
for_locking_item:
|
||||||
FOR UPDATE locked_rels_list opt_nowait
|
FOR UPDATE locked_rels_list opt_nowait
|
||||||
{
|
{
|
||||||
LockingClause *n = makeNode(LockingClause);
|
LockingClause *n = makeNode(LockingClause);
|
||||||
n->lockedRels = $3;
|
n->lockedRels = $3;
|
||||||
n->forUpdate = TRUE;
|
n->forUpdate = TRUE;
|
||||||
n->nowait = $4;
|
n->noWait = $4;
|
||||||
$$ = (Node *) n;
|
$$ = (Node *) n;
|
||||||
}
|
}
|
||||||
| FOR SHARE locked_rels_list opt_nowait
|
| FOR SHARE locked_rels_list opt_nowait
|
||||||
@ -5657,15 +5673,9 @@ for_locking_clause:
|
|||||||
LockingClause *n = makeNode(LockingClause);
|
LockingClause *n = makeNode(LockingClause);
|
||||||
n->lockedRels = $3;
|
n->lockedRels = $3;
|
||||||
n->forUpdate = FALSE;
|
n->forUpdate = FALSE;
|
||||||
n->nowait = $4;
|
n->noWait = $4;
|
||||||
$$ = (Node *) n;
|
$$ = (Node *) n;
|
||||||
}
|
}
|
||||||
| FOR READ ONLY { $$ = NULL; }
|
|
||||||
;
|
|
||||||
|
|
||||||
opt_for_locking_clause:
|
|
||||||
for_locking_clause { $$ = $1; }
|
|
||||||
| /* EMPTY */ { $$ = NULL; }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
locked_rels_list:
|
locked_rels_list:
|
||||||
@ -8976,7 +8986,7 @@ findLeftmostSelect(SelectStmt *node)
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
insertSelectOptions(SelectStmt *stmt,
|
insertSelectOptions(SelectStmt *stmt,
|
||||||
List *sortClause, Node *lockingClause,
|
List *sortClause, List *lockingClause,
|
||||||
Node *limitOffset, Node *limitCount)
|
Node *limitOffset, Node *limitCount)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -8991,14 +9001,8 @@ insertSelectOptions(SelectStmt *stmt,
|
|||||||
errmsg("multiple ORDER BY clauses not allowed")));
|
errmsg("multiple ORDER BY clauses not allowed")));
|
||||||
stmt->sortClause = sortClause;
|
stmt->sortClause = sortClause;
|
||||||
}
|
}
|
||||||
if (lockingClause)
|
/* We can handle multiple locking clauses, though */
|
||||||
{
|
stmt->lockingClause = list_concat(stmt->lockingClause, lockingClause);
|
||||||
if (stmt->lockingClause)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
||||||
errmsg("multiple FOR UPDATE/FOR SHARE clauses not allowed")));
|
|
||||||
stmt->lockingClause = (LockingClause *) lockingClause;
|
|
||||||
}
|
|
||||||
if (limitOffset)
|
if (limitOffset)
|
||||||
{
|
{
|
||||||
if (stmt->limitOffset)
|
if (stmt->limitOffset)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.122 2006/03/23 00:19:30 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.123 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1001,6 +1001,8 @@ addRangeTableEntryForJoin(ParseState *pstate,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Has the specified refname been selected FOR UPDATE/FOR SHARE?
|
* Has the specified refname been selected FOR UPDATE/FOR SHARE?
|
||||||
|
*
|
||||||
|
* Note: we pay no attention to whether it's FOR UPDATE vs FOR SHARE.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
isLockedRel(ParseState *pstate, char *refname)
|
isLockedRel(ParseState *pstate, char *refname)
|
||||||
@ -1008,9 +1010,13 @@ isLockedRel(ParseState *pstate, char *refname)
|
|||||||
/* Outer loop to check parent query levels as well as this one */
|
/* Outer loop to check parent query levels as well as this one */
|
||||||
while (pstate != NULL)
|
while (pstate != NULL)
|
||||||
{
|
{
|
||||||
if (pstate->p_locking_clause)
|
ListCell *l;
|
||||||
|
|
||||||
|
foreach(l, pstate->p_locking_clause)
|
||||||
{
|
{
|
||||||
if (pstate->p_locking_clause->lockedRels == NIL)
|
LockingClause *lc = (LockingClause *) lfirst(l);
|
||||||
|
|
||||||
|
if (lc->lockedRels == NIL)
|
||||||
{
|
{
|
||||||
/* all tables used in query */
|
/* all tables used in query */
|
||||||
return true;
|
return true;
|
||||||
@ -1018,11 +1024,11 @@ isLockedRel(ParseState *pstate, char *refname)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* just the named tables */
|
/* just the named tables */
|
||||||
ListCell *l;
|
ListCell *l2;
|
||||||
|
|
||||||
foreach(l, pstate->p_locking_clause->lockedRels)
|
foreach(l2, lc->lockedRels)
|
||||||
{
|
{
|
||||||
char *rname = strVal(lfirst(l));
|
char *rname = strVal(lfirst(l2));
|
||||||
|
|
||||||
if (strcmp(refname, rname) == 0)
|
if (strcmp(refname, rname) == 0)
|
||||||
return true;
|
return true;
|
||||||
@ -1702,6 +1708,26 @@ get_tle_by_resno(List *tlist, AttrNumber resno)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a Query and rangetable index, return relation's RowMarkClause if any
|
||||||
|
*
|
||||||
|
* Returns NULL if relation is not selected FOR UPDATE/SHARE
|
||||||
|
*/
|
||||||
|
RowMarkClause *
|
||||||
|
get_rowmark(Query *qry, Index rtindex)
|
||||||
|
{
|
||||||
|
ListCell *l;
|
||||||
|
|
||||||
|
foreach(l, qry->rowMarks)
|
||||||
|
{
|
||||||
|
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
|
||||||
|
|
||||||
|
if (rc->rti == rtindex)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* given relation and att name, return attnum of variable
|
* given relation and att name, return attnum of variable
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.80 2006/04/04 19:35:35 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.81 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -432,7 +432,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
|
|||||||
stmt->sortClause != NIL ||
|
stmt->sortClause != NIL ||
|
||||||
stmt->limitOffset != NULL ||
|
stmt->limitOffset != NULL ||
|
||||||
stmt->limitCount != NULL ||
|
stmt->limitCount != NULL ||
|
||||||
stmt->lockingClause != NULL ||
|
stmt->lockingClause != NIL ||
|
||||||
stmt->op != SETOP_NONE)
|
stmt->op != SETOP_NONE)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (list_length(stmt->targetList) != 1)
|
if (list_length(stmt->targetList) != 1)
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.162 2006/04/05 22:11:55 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.163 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -130,7 +130,7 @@ AcquireRewriteLocks(Query *parsetree)
|
|||||||
*/
|
*/
|
||||||
if (rt_index == parsetree->resultRelation)
|
if (rt_index == parsetree->resultRelation)
|
||||||
lockmode = RowExclusiveLock;
|
lockmode = RowExclusiveLock;
|
||||||
else if (list_member_int(parsetree->rowMarks, rt_index))
|
else if (get_rowmark(parsetree, rt_index))
|
||||||
lockmode = RowShareLock;
|
lockmode = RowShareLock;
|
||||||
else
|
else
|
||||||
lockmode = AccessShareLock;
|
lockmode = AccessShareLock;
|
||||||
@ -907,6 +907,7 @@ ApplyRetrieveRule(Query *parsetree,
|
|||||||
Query *rule_action;
|
Query *rule_action;
|
||||||
RangeTblEntry *rte,
|
RangeTblEntry *rte,
|
||||||
*subrte;
|
*subrte;
|
||||||
|
RowMarkClause *rc;
|
||||||
|
|
||||||
if (list_length(rule->actions) != 1)
|
if (list_length(rule->actions) != 1)
|
||||||
elog(ERROR, "expected just one rule action");
|
elog(ERROR, "expected just one rule action");
|
||||||
@ -954,20 +955,20 @@ ApplyRetrieveRule(Query *parsetree,
|
|||||||
/*
|
/*
|
||||||
* FOR UPDATE/SHARE of view?
|
* FOR UPDATE/SHARE of view?
|
||||||
*/
|
*/
|
||||||
if (list_member_int(parsetree->rowMarks, rt_index))
|
if ((rc = get_rowmark(parsetree, rt_index)) != NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Remove the view from the list of rels that will actually be marked
|
* Remove the view from the list of rels that will actually be marked
|
||||||
* FOR UPDATE/SHARE by the executor. It will still be access- checked
|
* FOR UPDATE/SHARE by the executor. It will still be access-checked
|
||||||
* for write access, though.
|
* for write access, though.
|
||||||
*/
|
*/
|
||||||
parsetree->rowMarks = list_delete_int(parsetree->rowMarks, rt_index);
|
parsetree->rowMarks = list_delete_ptr(parsetree->rowMarks, rc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up the view's referenced tables as if FOR UPDATE/SHARE.
|
* Set up the view's referenced tables as if FOR UPDATE/SHARE.
|
||||||
*/
|
*/
|
||||||
markQueryForLocking(rule_action, parsetree->forUpdate,
|
markQueryForLocking(rule_action, rc->forUpdate,
|
||||||
parsetree->rowNoWait, true);
|
rc->noWait, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsetree;
|
return parsetree;
|
||||||
@ -987,20 +988,6 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
|
|||||||
Index rti = 0;
|
Index rti = 0;
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
if (qry->rowMarks)
|
|
||||||
{
|
|
||||||
if (forUpdate != qry->forUpdate)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));
|
|
||||||
if (noWait != qry->rowNoWait)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("cannot use both wait and NOWAIT in one query")));
|
|
||||||
}
|
|
||||||
qry->forUpdate = forUpdate;
|
|
||||||
qry->rowNoWait = noWait;
|
|
||||||
|
|
||||||
foreach(l, qry->rtable)
|
foreach(l, qry->rtable)
|
||||||
{
|
{
|
||||||
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
||||||
@ -1014,7 +1001,7 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
|
|||||||
|
|
||||||
if (rte->rtekind == RTE_RELATION)
|
if (rte->rtekind == RTE_RELATION)
|
||||||
{
|
{
|
||||||
qry->rowMarks = list_append_unique_int(qry->rowMarks, rti);
|
applyLockingClause(qry, rti, forUpdate, noWait);
|
||||||
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
|
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
|
||||||
}
|
}
|
||||||
else if (rte->rtekind == RTE_SUBQUERY)
|
else if (rte->rtekind == RTE_SUBQUERY)
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.98 2006/04/05 22:11:55 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.99 2006/04/30 18:30:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -240,7 +240,11 @@ OffsetVarNodes(Node *node, int offset, int sublevels_up)
|
|||||||
if (qry->resultRelation)
|
if (qry->resultRelation)
|
||||||
qry->resultRelation += offset;
|
qry->resultRelation += offset;
|
||||||
foreach(l, qry->rowMarks)
|
foreach(l, qry->rowMarks)
|
||||||
lfirst_int(l) += offset;
|
{
|
||||||
|
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
|
||||||
|
|
||||||
|
rc->rti += offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
query_tree_walker(qry, OffsetVarNodes_walker,
|
query_tree_walker(qry, OffsetVarNodes_walker,
|
||||||
(void *) &context, 0);
|
(void *) &context, 0);
|
||||||
@ -395,8 +399,10 @@ ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
|
|||||||
qry->resultRelation = new_index;
|
qry->resultRelation = new_index;
|
||||||
foreach(l, qry->rowMarks)
|
foreach(l, qry->rowMarks)
|
||||||
{
|
{
|
||||||
if (lfirst_int(l) == rt_index)
|
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
|
||||||
lfirst_int(l) = new_index;
|
|
||||||
|
if (rc->rti == rt_index)
|
||||||
|
rc->rti = new_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
query_tree_walker(qry, ChangeVarNodes_walker,
|
query_tree_walker(qry, ChangeVarNodes_walker,
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.256 2006/04/15 17:45:41 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.257 2006/04/30 18:30:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1796,7 +1796,7 @@ CreateQueryTag(Query *parsetree)
|
|||||||
tag = "SELECT INTO";
|
tag = "SELECT INTO";
|
||||||
else if (parsetree->rowMarks != NIL)
|
else if (parsetree->rowMarks != NIL)
|
||||||
{
|
{
|
||||||
if (parsetree->forUpdate)
|
if (((RowMarkClause *) linitial(parsetree->rowMarks))->forUpdate)
|
||||||
tag = "SELECT FOR UPDATE";
|
tag = "SELECT FOR UPDATE";
|
||||||
else
|
else
|
||||||
tag = "SELECT FOR SHARE";
|
tag = "SELECT FOR SHARE";
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* ruleutils.c - Functions to convert stored expressions/querytrees
|
* ruleutils.c - Functions to convert stored expressions/querytrees
|
||||||
* back to source text
|
* back to source text
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.220 2006/04/22 01:26:00 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.221 2006/04/30 18:30:40 tgl Exp $
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
@ -1858,27 +1858,21 @@ get_select_query_def(Query *query, deparse_context *context,
|
|||||||
get_rule_expr(query->limitCount, context, false);
|
get_rule_expr(query->limitCount, context, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the FOR UPDATE/SHARE clause if present */
|
/* Add FOR UPDATE/SHARE clauses if present */
|
||||||
if (query->rowMarks != NIL)
|
|
||||||
{
|
|
||||||
if (query->forUpdate)
|
|
||||||
appendContextKeyword(context, " FOR UPDATE OF ",
|
|
||||||
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
|
|
||||||
else
|
|
||||||
appendContextKeyword(context, " FOR SHARE OF ",
|
|
||||||
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
|
|
||||||
sep = "";
|
|
||||||
foreach(l, query->rowMarks)
|
foreach(l, query->rowMarks)
|
||||||
{
|
{
|
||||||
int rtindex = lfirst_int(l);
|
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
|
||||||
RangeTblEntry *rte = rt_fetch(rtindex, query->rtable);
|
RangeTblEntry *rte = rt_fetch(rc->rti, query->rtable);
|
||||||
|
|
||||||
appendStringInfo(buf, "%s%s",
|
if (rc->forUpdate)
|
||||||
sep,
|
appendContextKeyword(context, " FOR UPDATE",
|
||||||
|
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
|
||||||
|
else
|
||||||
|
appendContextKeyword(context, " FOR SHARE",
|
||||||
|
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
|
||||||
|
appendStringInfo(buf, " OF %s",
|
||||||
quote_identifier(rte->eref->aliasname));
|
quote_identifier(rte->eref->aliasname));
|
||||||
sep = ", ";
|
if (rc->noWait)
|
||||||
}
|
|
||||||
if (query->rowNoWait)
|
|
||||||
appendStringInfo(buf, " NOWAIT");
|
appendStringInfo(buf, " NOWAIT");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.327 2006/04/30 02:09:07 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.328 2006/04/30 18:30:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200604291
|
#define CATALOG_VERSION_NO 200604301
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.149 2006/03/05 15:58:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.150 2006/04/30 18:30:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -321,8 +321,6 @@ typedef struct EState
|
|||||||
uint32 es_processed; /* # of tuples processed */
|
uint32 es_processed; /* # of tuples processed */
|
||||||
Oid es_lastoid; /* last oid processed (by INSERT) */
|
Oid es_lastoid; /* last oid processed (by INSERT) */
|
||||||
List *es_rowMarks; /* not good place, but there is no other */
|
List *es_rowMarks; /* not good place, but there is no other */
|
||||||
bool es_forUpdate; /* true = FOR UPDATE, false = FOR SHARE */
|
|
||||||
bool es_rowNoWait; /* FOR UPDATE/SHARE NOWAIT option */
|
|
||||||
|
|
||||||
bool es_instrument; /* true requests runtime instrumentation */
|
bool es_instrument; /* true requests runtime instrumentation */
|
||||||
bool es_select_into; /* true if doing SELECT INTO */
|
bool es_select_into; /* true if doing SELECT INTO */
|
||||||
@ -351,6 +349,8 @@ typedef struct ExecRowMark
|
|||||||
{
|
{
|
||||||
Relation relation; /* opened and RowShareLock'd relation */
|
Relation relation; /* opened and RowShareLock'd relation */
|
||||||
Index rti; /* its range table index */
|
Index rti; /* its range table index */
|
||||||
|
bool forUpdate; /* true = FOR UPDATE, false = FOR SHARE */
|
||||||
|
bool noWait; /* NOWAIT option */
|
||||||
char resname[32]; /* name for its ctid junk attribute */
|
char resname[32]; /* name for its ctid junk attribute */
|
||||||
} ExecRowMark;
|
} ExecRowMark;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.185 2006/04/15 17:45:41 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.186 2006/04/30 18:30:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -320,6 +320,7 @@ typedef enum NodeTag
|
|||||||
T_InhRelation,
|
T_InhRelation,
|
||||||
T_FunctionParameter,
|
T_FunctionParameter,
|
||||||
T_LockingClause,
|
T_LockingClause,
|
||||||
|
T_RowMarkClause,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TAGS FOR RANDOM OTHER STUFF
|
* TAGS FOR RANDOM OTHER STUFF
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.309 2006/04/30 02:09:07 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.310 2006/04/30 18:30:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -57,7 +57,7 @@ typedef uint32 AclMode; /* a bitmask of privilege bits */
|
|||||||
#define ACL_USAGE (1<<8) /* for languages and namespaces */
|
#define ACL_USAGE (1<<8) /* for languages and namespaces */
|
||||||
#define ACL_CREATE (1<<9) /* for namespaces and databases */
|
#define ACL_CREATE (1<<9) /* for namespaces and databases */
|
||||||
#define ACL_CREATE_TEMP (1<<10) /* for databases */
|
#define ACL_CREATE_TEMP (1<<10) /* for databases */
|
||||||
#define ACL_CONNECT (1<<11) /* for database connection privilege */
|
#define ACL_CONNECT (1<<11) /* for databases */
|
||||||
#define N_ACL_RIGHTS 12 /* 1 plus the last 1<<x */
|
#define N_ACL_RIGHTS 12 /* 1 plus the last 1<<x */
|
||||||
#define ACL_NO_RIGHTS 0
|
#define ACL_NO_RIGHTS 0
|
||||||
/* Currently, SELECT ... FOR UPDATE/FOR SHARE requires UPDATE privileges */
|
/* Currently, SELECT ... FOR UPDATE/FOR SHARE requires UPDATE privileges */
|
||||||
@ -102,13 +102,6 @@ typedef struct Query
|
|||||||
List *rtable; /* list of range table entries */
|
List *rtable; /* list of range table entries */
|
||||||
FromExpr *jointree; /* table join tree (FROM and WHERE clauses) */
|
FromExpr *jointree; /* table join tree (FROM and WHERE clauses) */
|
||||||
|
|
||||||
List *rowMarks; /* integer list of RT indexes of relations
|
|
||||||
* that are selected FOR UPDATE/SHARE */
|
|
||||||
|
|
||||||
bool forUpdate; /* true if rowMarks are FOR UPDATE, false if
|
|
||||||
* they are FOR SHARE */
|
|
||||||
bool rowNoWait; /* FOR UPDATE/SHARE NOWAIT option */
|
|
||||||
|
|
||||||
List *targetList; /* target list (of TargetEntry) */
|
List *targetList; /* target list (of TargetEntry) */
|
||||||
|
|
||||||
List *groupClause; /* a list of GroupClause's */
|
List *groupClause; /* a list of GroupClause's */
|
||||||
@ -122,6 +115,8 @@ typedef struct Query
|
|||||||
Node *limitOffset; /* # of result tuples to skip */
|
Node *limitOffset; /* # of result tuples to skip */
|
||||||
Node *limitCount; /* # of result tuples to return */
|
Node *limitCount; /* # of result tuples to return */
|
||||||
|
|
||||||
|
List *rowMarks; /* a list of RowMarkClause's */
|
||||||
|
|
||||||
Node *setOperations; /* set-operation tree if this is top level of
|
Node *setOperations; /* set-operation tree if this is top level of
|
||||||
* a UNION/INTERSECT/EXCEPT query */
|
* a UNION/INTERSECT/EXCEPT query */
|
||||||
|
|
||||||
@ -448,7 +443,7 @@ typedef struct LockingClause
|
|||||||
NodeTag type;
|
NodeTag type;
|
||||||
List *lockedRels; /* FOR UPDATE or FOR SHARE relations */
|
List *lockedRels; /* FOR UPDATE or FOR SHARE relations */
|
||||||
bool forUpdate; /* true = FOR UPDATE, false = FOR SHARE */
|
bool forUpdate; /* true = FOR UPDATE, false = FOR SHARE */
|
||||||
bool nowait; /* NOWAIT option */
|
bool noWait; /* NOWAIT option */
|
||||||
} LockingClause;
|
} LockingClause;
|
||||||
|
|
||||||
|
|
||||||
@ -615,6 +610,19 @@ typedef struct SortClause
|
|||||||
*/
|
*/
|
||||||
typedef SortClause GroupClause;
|
typedef SortClause GroupClause;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RowMarkClause -
|
||||||
|
* representation of FOR UPDATE/SHARE clauses
|
||||||
|
*
|
||||||
|
* We create a separate RowMarkClause node for each target relation
|
||||||
|
*/
|
||||||
|
typedef struct RowMarkClause
|
||||||
|
{
|
||||||
|
NodeTag type;
|
||||||
|
Index rti; /* range table index of target relation */
|
||||||
|
bool forUpdate; /* true = FOR UPDATE, false = FOR SHARE */
|
||||||
|
bool noWait; /* NOWAIT option */
|
||||||
|
} RowMarkClause;
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Optimizable Statements
|
* Optimizable Statements
|
||||||
@ -724,7 +732,7 @@ typedef struct SelectStmt
|
|||||||
List *sortClause; /* sort clause (a list of SortBy's) */
|
List *sortClause; /* sort clause (a list of SortBy's) */
|
||||||
Node *limitOffset; /* # of result tuples to skip */
|
Node *limitOffset; /* # of result tuples to skip */
|
||||||
Node *limitCount; /* # of result tuples to return */
|
Node *limitCount; /* # of result tuples to return */
|
||||||
LockingClause *lockingClause; /* FOR UPDATE/FOR SHARE */
|
List *lockingClause; /* FOR UPDATE (list of LockingClause's) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These fields are used only in upper-level SelectStmts.
|
* These fields are used only in upper-level SelectStmts.
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.32 2006/03/14 22:48:22 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.33 2006/04/30 18:30:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -22,6 +22,8 @@ extern List *parse_analyze_varparams(Node *parseTree, const char *sourceText,
|
|||||||
Oid **paramTypes, int *numParams);
|
Oid **paramTypes, int *numParams);
|
||||||
extern List *parse_sub_analyze(Node *parseTree, ParseState *parentParseState);
|
extern List *parse_sub_analyze(Node *parseTree, ParseState *parentParseState);
|
||||||
extern List *analyzeCreateSchemaStmt(CreateSchemaStmt *stmt);
|
extern List *analyzeCreateSchemaStmt(CreateSchemaStmt *stmt);
|
||||||
extern void CheckSelectLocking(Query *qry, bool forUpdate);
|
extern void CheckSelectLocking(Query *qry);
|
||||||
|
extern void applyLockingClause(Query *qry, Index rtindex,
|
||||||
|
bool forUpdate, bool noWait);
|
||||||
|
|
||||||
#endif /* ANALYZE_H */
|
#endif /* ANALYZE_H */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.48 2006/03/14 22:48:22 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.49 2006/04/30 18:30:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -71,7 +71,7 @@ typedef struct ParseState
|
|||||||
Oid *p_paramtypes; /* OIDs of types for $n parameter symbols */
|
Oid *p_paramtypes; /* OIDs of types for $n parameter symbols */
|
||||||
int p_numparams; /* allocated size of p_paramtypes[] */
|
int p_numparams; /* allocated size of p_paramtypes[] */
|
||||||
int p_next_resno; /* next targetlist resno to assign */
|
int p_next_resno; /* next targetlist resno to assign */
|
||||||
LockingClause *p_locking_clause; /* FOR UPDATE/FOR SHARE info */
|
List *p_locking_clause; /* raw FOR UPDATE/FOR SHARE info */
|
||||||
Node *p_value_substitute; /* what to replace VALUE with, if any */
|
Node *p_value_substitute; /* what to replace VALUE with, if any */
|
||||||
bool p_variableparams;
|
bool p_variableparams;
|
||||||
bool p_hasAggs;
|
bool p_hasAggs;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/parser/parsetree.h,v 1.32 2006/03/05 15:58:58 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/parser/parsetree.h,v 1.33 2006/04/30 18:30:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -70,4 +70,11 @@ extern bool get_rte_attribute_is_dropped(RangeTblEntry *rte,
|
|||||||
|
|
||||||
extern TargetEntry *get_tle_by_resno(List *tlist, AttrNumber resno);
|
extern TargetEntry *get_tle_by_resno(List *tlist, AttrNumber resno);
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* FOR UPDATE/SHARE info
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern RowMarkClause *get_rowmark(Query *qry, Index rtindex);
|
||||||
|
|
||||||
#endif /* PARSETREE_H */
|
#endif /* PARSETREE_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user