diff -r -c postgresql-8.0.0rc2.orig/doc/src/sgml/ref/select.sgml
postgresql-8.0.0rc2/doc/src/sgml/ref/select.sgml
*** postgresql-8.0.0rc2.orig/doc/src/sgml/ref/select.sgml Sat Nov 27
22:27:07 2004
--- postgresql-8.0.0rc2/doc/src/sgml/ref/select.sgml Mon Dec 27 10:57:05 2004
***************
*** 30,36 ****
[ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC | USING
<replaceable class="parameter">operator</replaceable> ] [, ...] ]
[ LIMIT { <replaceable class="parameter">count</replaceable> | ALL } ]
[ OFFSET <replaceable class="parameter">start</replaceable> ]
! [ FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable>
[, ...] ] ]
where <replaceable class="parameter">from_item</replaceable> can be one of:
--- 30,36 ----
[ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC | USING
<replaceable class="parameter">operator</replaceable> ] [, ...] ]
[ LIMIT { <replaceable class="parameter">count</replaceable> | ALL } ]
[ OFFSET <replaceable class="parameter">start</replaceable> ]
! [ FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable>
[, ...] ] [NOWAIT] ]
where <replaceable class="parameter">from_item</replaceable> can be one of:
***************
*** 772,778 ****
<para>
The <literal>FOR UPDATE</literal> clause has this form:
<synopsis>
! FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [,
...] ]
</synopsis>
</para>
--- 772,778 ----
<para>
The <literal>FOR UPDATE</literal> clause has this form:
<synopsis>
! FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [,
...] ] [NOWAIT]
</synopsis>
</para>
***************
*** 789,796 ****
has already locked a selected row or rows, <command>SELECT FOR
UPDATE</command> will wait for the other transaction to complete,
and will then lock and return the updated row (or no row, if the
! row was deleted). For further discussion see <xref
! linkend="mvcc">.
</para>
<para>
--- 789,802 ----
has already locked a selected row or rows, <command>SELECT FOR
UPDATE</command> will wait for the other transaction to complete,
and will then lock and return the updated row (or no row, if the
! row was deleted). If the current transaction is not supposed to
! wait on other transactions to commit the NOWAIT option can be
! used. If <command>SELECT FOR UPDATE NOWAIT</command> finds out
! that somebody else is holding a lock an error will be thrown.
! This will only happen in case of row level locks - if somebody
! holds a table lock <command>SELECT FOR UPDATE NOWAIT</command>
! will still wait for concurrent transactions. For further
! discussion see <xref linkend="mvcc">.
</para>
<para>
diff -r -c postgresql-8.0.0rc2.orig/doc/src/sgml/sql.sgml
postgresql-8.0.0rc2/doc/src/sgml/sql.sgml
*** postgresql-8.0.0rc2.orig/doc/src/sgml/sql.sgml Mon Nov 15 07:32:14 2004
--- postgresql-8.0.0rc2/doc/src/sgml/sql.sgml Mon Dec 27 10:57:05 2004
***************
*** 866,872 ****
[ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING
<replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
[ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
[ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
! [ FOR UPDATE [ OF <replaceable class="PARAMETER">class_name</replaceable>
[, ...] ] ]
</synopsis>
</para>
--- 866,872 ----
[ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING
<replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
[ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
[ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
! [ FOR UPDATE [ OF <replaceable class="PARAMETER">class_name</replaceable>
[, ...] ] [NOWAIT] ]
</synopsis>
</para>
diff -r -c postgresql-8.0.0rc2.orig/src/backend/access/heap/heapam.c postgresql-8.0.0rc2/src/backend/access/heap/heapam.c
*** postgresql-8.0.0rc2.orig/src/backend/access/heap/heapam.c Sun Nov 14
03:04:12 2004
--- postgresql-8.0.0rc2/src/backend/access/heap/heapam.c Mon Dec 27
10:56:52 2004
***************
*** 16,21 ****
--- 16,22 ----
* relation_openrv - open any relation specified by a RangeVar
* relation_openr - open a system relation by name
* relation_close - close any relation
+ * conditional_relation_open - open with option not to wait
* heap_open - open a heap relation by relation OID
* heap_openrv - open a heap relation specified by a
RangeVar
* heap_openr - open a system heap relation by name
***************
*** 1828,1834 ****
*/
int
heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer,
! CommandId cid)
{
TransactionId xid = GetCurrentTransactionId();
ItemPointer tid = &(tuple->t_self);
--- 1829,1835 ----
*/
int
heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer,
! CommandId cid, bool nowait)
{
TransactionId xid = GetCurrentTransactionId();
ItemPointer tid = &(tuple->t_self);
***************
*** 1858,1866 ****
{
TransactionId xwait = HeapTupleHeaderGetXmax(tuple->t_data);
- /* sleep until concurrent transaction ends */
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
! XactLockTableWait(xwait);
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
if (!TransactionIdDidCommit(xwait))
--- 1859,1881 ----
{
TransactionId xwait = HeapTupleHeaderGetXmax(tuple->t_data);
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
!
! if (nowait)
! {
! /* rather error than sleep until concurrent transaction ends */
! if (!ConditionalXactLockTableWait(xwait))
! {
! ReleaseBuffer(*buffer);
! ereport(ERROR,
!
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! errmsg("data in table \"%s\" was modify by concurrent trasaction.",
! RelationGetRelationName(relation))));
! }
! }
! else
! /* sleep until concurrent transaction ends */
! XactLockTableWait(xwait);
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
if (!TransactionIdDidCommit(xwait))
diff -r -c postgresql-8.0.0rc2.orig/src/backend/commands/trigger.c
postgresql-8.0.0rc2/src/backend/commands/trigger.c
*** postgresql-8.0.0rc2.orig/src/backend/commands/trigger.c Tue Dec 7
00:57:17 2004
--- postgresql-8.0.0rc2/src/backend/commands/trigger.c Mon Dec 27 10:56:52 2004
***************
*** 1574,1580 ****
*newSlot = NULL;
tuple.t_self = *tid;
ltrmark:;
! test = heap_mark4update(relation, &tuple, &buffer, cid);
switch (test)
{
case HeapTupleSelfUpdated:
--- 1574,1580 ----
*newSlot = NULL;
tuple.t_self = *tid;
ltrmark:;
! test = heap_mark4update(relation, &tuple, &buffer, cid,
estate->es_nowait);
switch (test)
{
case HeapTupleSelfUpdated:
diff -r -c postgresql-8.0.0rc2.orig/src/backend/executor/execMain.c
postgresql-8.0.0rc2/src/backend/executor/execMain.c
*** postgresql-8.0.0rc2.orig/src/backend/executor/execMain.c Thu Oct 7
20:38:49 2004
--- postgresql-8.0.0rc2/src/backend/executor/execMain.c Mon Dec 27 10:56:52 2004
***************
*** 558,563 ****
--- 558,564 ----
/*
* Have to lock relations selected for update
*/
+ estate->es_nowait = parseTree->nowait;
estate->es_rowMark = NIL;
if (parseTree->rowMarks != NIL)
{
***************
*** 1133,1139 ****
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
test = heap_mark4update(erm->relation,
&tuple, &buffer,
!
estate->es_snapshot->curcid);
ReleaseBuffer(buffer);
switch (test)
{
--- 1134,1140 ----
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
test = heap_mark4update(erm->relation,
&tuple, &buffer,
!
estate->es_snapshot->curcid, estate->es_nowait);
ReleaseBuffer(buffer);
switch (test)
{
***************
*** 2082,2087 ****
--- 2083,2089 ----
epqstate->es_instrument = estate->es_instrument;
epqstate->es_select_into = estate->es_select_into;
epqstate->es_into_oids = estate->es_into_oids;
+ epqstate->es_nowait = estate->es_nowait;
epqstate->es_topPlan = estate->es_topPlan;
/*
diff -r -c postgresql-8.0.0rc2.orig/src/backend/executor/execUtils.c
postgresql-8.0.0rc2/src/backend/executor/execUtils.c
*** postgresql-8.0.0rc2.orig/src/backend/executor/execUtils.c Fri Oct 1
01:21:23 2004
--- postgresql-8.0.0rc2/src/backend/executor/execUtils.c Mon Dec 27
10:56:52 2004
***************
*** 203,209 ****
estate->es_instrument = false;
estate->es_select_into = false;
estate->es_into_oids = false;
!
estate->es_exprcontexts = NIL;
estate->es_per_tuple_exprcontext = NULL;
--- 203,210 ----
estate->es_instrument = false;
estate->es_select_into = false;
estate->es_into_oids = false;
! estate->es_nowait = false;
!
estate->es_exprcontexts = NIL;
estate->es_per_tuple_exprcontext = NULL;
diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/copyfuncs.c
postgresql-8.0.0rc2/src/backend/nodes/copyfuncs.c
*** postgresql-8.0.0rc2.orig/src/backend/nodes/copyfuncs.c Sun Dec 12
00:26:33 2004
--- postgresql-8.0.0rc2/src/backend/nodes/copyfuncs.c Mon Dec 27 10:56:52 2004
***************
*** 1426,1431 ****
--- 1426,1442 ----
return newnode;
}
+ static ForUpdate *
+ _copyForUpdate(ForUpdate *from)
+ {
+ ForUpdate *newnode = makeNode(ForUpdate);
+
+ COPY_NODE_FIELD(update_list);
+ COPY_SCALAR_FIELD(nowait);
+
+ return newnode;
+ }
+
static RangeSubselect *
_copyRangeSubselect(RangeSubselect *from)
{
***************
*** 1537,1542 ****
--- 1548,1554 ----
COPY_NODE_FIELD(groupClause);
COPY_NODE_FIELD(havingQual);
COPY_NODE_FIELD(distinctClause);
+ COPY_SCALAR_FIELD(nowait);
COPY_NODE_FIELD(sortClause);
COPY_NODE_FIELD(limitOffset);
COPY_NODE_FIELD(limitCount);
***************
*** 1611,1617 ****
COPY_NODE_FIELD(sortClause);
COPY_NODE_FIELD(limitOffset);
COPY_NODE_FIELD(limitCount);
! COPY_NODE_FIELD(forUpdate);
COPY_SCALAR_FIELD(op);
COPY_SCALAR_FIELD(all);
COPY_NODE_FIELD(larg);
--- 1623,1629 ----
COPY_NODE_FIELD(sortClause);
COPY_NODE_FIELD(limitOffset);
COPY_NODE_FIELD(limitCount);
! COPY_NODE_FIELD(forupdateClause);
COPY_SCALAR_FIELD(op);
COPY_SCALAR_FIELD(all);
COPY_NODE_FIELD(larg);
***************
*** 3065,3070 ****
--- 3077,3085 ----
case T_SortBy:
retval = _copySortBy(from);
break;
+ case T_ForUpdate:
+ retval = _copyForUpdate(from);
+ break;
case T_RangeSubselect:
retval = _copyRangeSubselect(from);
break;
diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/equalfuncs.c
postgresql-8.0.0rc2/src/backend/nodes/equalfuncs.c
*** postgresql-8.0.0rc2.orig/src/backend/nodes/equalfuncs.c Sun Dec 12
00:26:33 2004
--- postgresql-8.0.0rc2/src/backend/nodes/equalfuncs.c Mon Dec 27 10:56:52 2004
***************
*** 656,661 ****
--- 656,662 ----
COMPARE_NODE_FIELD(groupClause);
COMPARE_NODE_FIELD(havingQual);
COMPARE_NODE_FIELD(distinctClause);
+ COMPARE_SCALAR_FIELD(nowait);
COMPARE_NODE_FIELD(sortClause);
COMPARE_NODE_FIELD(limitOffset);
COMPARE_NODE_FIELD(limitCount);
***************
*** 719,725 ****
COMPARE_NODE_FIELD(sortClause);
COMPARE_NODE_FIELD(limitOffset);
COMPARE_NODE_FIELD(limitCount);
! COMPARE_NODE_FIELD(forUpdate);
COMPARE_SCALAR_FIELD(op);
COMPARE_SCALAR_FIELD(all);
COMPARE_NODE_FIELD(larg);
--- 720,726 ----
COMPARE_NODE_FIELD(sortClause);
COMPARE_NODE_FIELD(limitOffset);
COMPARE_NODE_FIELD(limitCount);
! COMPARE_NODE_FIELD(forupdateClause);
COMPARE_SCALAR_FIELD(op);
COMPARE_SCALAR_FIELD(all);
COMPARE_NODE_FIELD(larg);
***************
*** 1577,1582 ****
--- 1578,1592 ----
}
static bool
+ _equalForUpdate(ForUpdate *a, ForUpdate *b)
+ {
+ COMPARE_SCALAR_FIELD(nowait);
+ COMPARE_NODE_FIELD(update_list);
+
+ return true;
+ }
+
+ static bool
_equalRangeSubselect(RangeSubselect *a, RangeSubselect *b)
{
COMPARE_NODE_FIELD(subquery);
***************
*** 2202,2207 ****
--- 2212,2220 ----
case T_SortBy:
retval = _equalSortBy(a, b);
break;
+ case T_ForUpdate:
+ retval = _equalForUpdate(a, b);
+ break;
case T_RangeSubselect:
retval = _equalRangeSubselect(a, b);
break;
diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/outfuncs.c
postgresql-8.0.0rc2/src/backend/nodes/outfuncs.c
*** postgresql-8.0.0rc2.orig/src/backend/nodes/outfuncs.c Sun Dec 12
00:26:33 2004
--- postgresql-8.0.0rc2/src/backend/nodes/outfuncs.c Mon Dec 27 10:56:52 2004
***************
*** 1202,1208 ****
WRITE_NODE_FIELD(sortClause);
WRITE_NODE_FIELD(limitOffset);
WRITE_NODE_FIELD(limitCount);
! WRITE_NODE_FIELD(forUpdate);
WRITE_ENUM_FIELD(op, SetOperation);
WRITE_BOOL_FIELD(all);
WRITE_NODE_FIELD(larg);
--- 1202,1208 ----
WRITE_NODE_FIELD(sortClause);
WRITE_NODE_FIELD(limitOffset);
WRITE_NODE_FIELD(limitCount);
! WRITE_NODE_FIELD(forupdateClause);
WRITE_ENUM_FIELD(op, SetOperation);
WRITE_BOOL_FIELD(all);
WRITE_NODE_FIELD(larg);
***************
*** 1323,1328 ****
--- 1323,1329 ----
WRITE_NODE_FIELD(groupClause);
WRITE_NODE_FIELD(havingQual);
WRITE_NODE_FIELD(distinctClause);
+ WRITE_BOOL_FIELD(nowait);
WRITE_NODE_FIELD(sortClause);
WRITE_NODE_FIELD(limitOffset);
WRITE_NODE_FIELD(limitCount);
diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/readfuncs.c
postgresql-8.0.0rc2/src/backend/nodes/readfuncs.c
*** postgresql-8.0.0rc2.orig/src/backend/nodes/readfuncs.c Sun Dec 12
00:26:34 2004
--- postgresql-8.0.0rc2/src/backend/nodes/readfuncs.c Mon Dec 27 10:56:52 2004
***************
*** 149,154 ****
--- 149,155 ----
READ_NODE_FIELD(groupClause);
READ_NODE_FIELD(havingQual);
READ_NODE_FIELD(distinctClause);
+ READ_BOOL_FIELD(nowait);
READ_NODE_FIELD(sortClause);
READ_NODE_FIELD(limitOffset);
READ_NODE_FIELD(limitCount);
diff -r -c postgresql-8.0.0rc2.orig/src/backend/parser/analyze.c
postgresql-8.0.0rc2/src/backend/parser/analyze.c
*** postgresql-8.0.0rc2.orig/src/backend/parser/analyze.c Wed Nov 17
00:34:26 2004
--- postgresql-8.0.0rc2/src/backend/parser/analyze.c Mon Dec 27 10:56:52 2004
***************
*** 135,141 ****
bool isAddConstraint);
static void applyColumnNames(List *dst, List *src);
static List *getSetColTypes(ParseState *pstate, Node *node);
! static void transformForUpdate(Query *qry, List *forUpdate);
static void transformConstraintAttrs(List *constraintList);
static void transformColumnType(ParseState *pstate, ColumnDef *column);
static void release_pstate_resources(ParseState *pstate);
--- 135,141 ----
bool isAddConstraint);
static void applyColumnNames(List *dst, List *src);
static List *getSetColTypes(ParseState *pstate, Node *node);
! static void transformForUpdate(Query *qry, Node *forupdateClause);
static void transformConstraintAttrs(List *constraintList);
static void transformColumnType(ParseState *pstate, ColumnDef *column);
static void release_pstate_resources(ParseState *pstate);
***************
*** 1804,1810 ****
qry->commandType = CMD_SELECT;
/* make FOR UPDATE clause available to addRangeTableEntry */
! pstate->p_forUpdate = stmt->forUpdate;
/* process the FROM clause */
transformFromClause(pstate, stmt->fromClause);
--- 1804,1810 ----
qry->commandType = CMD_SELECT;
/* make FOR UPDATE clause available to addRangeTableEntry */
! pstate->p_forUpdate = stmt->forupdateClause ? ((ForUpdate
*)stmt->forupdateClause)->update_list : NIL;
/* process the FROM clause */
transformFromClause(pstate, stmt->fromClause);
***************
*** 1864,1871 ****
if (pstate->p_hasAggs || qry->groupClause)
parseCheckAggregates(pstate, qry);
! if (stmt->forUpdate != NIL)
! transformForUpdate(qry, stmt->forUpdate);
return qry;
}
--- 1864,1871 ----
if (pstate->p_hasAggs || qry->groupClause)
parseCheckAggregates(pstate, qry);
! if (stmt->forupdateClause)
! transformForUpdate(qry, stmt->forupdateClause);
return qry;
}
***************
*** 1893,1899 ****
List *sortClause;
Node *limitOffset;
Node *limitCount;
! List *forUpdate;
Node *node;
ListCell *left_tlist,
*dtlist;
--- 1893,1899 ----
List *sortClause;
Node *limitOffset;
Node *limitCount;
! Node *forUpdate;
Node *node;
ListCell *left_tlist,
*dtlist;
***************
*** 1931,1942 ****
sortClause = stmt->sortClause;
limitOffset = stmt->limitOffset;
limitCount = stmt->limitCount;
! forUpdate = stmt->forUpdate;
stmt->sortClause = NIL;
stmt->limitOffset = NULL;
stmt->limitCount = NULL;
! stmt->forUpdate = NIL;
/* We don't support forUpdate with set ops at the moment. */
if (forUpdate)
--- 1931,1942 ----
sortClause = stmt->sortClause;
limitOffset = stmt->limitOffset;
limitCount = stmt->limitCount;
! forUpdate = stmt->forupdateClause;
stmt->sortClause = NIL;
stmt->limitOffset = NULL;
stmt->limitCount = NULL;
! stmt->forupdateClause = NULL;
/* We don't support forUpdate with set ops at the moment. */
if (forUpdate)
***************
*** 2080,2086 ****
if (pstate->p_hasAggs || qry->groupClause)
parseCheckAggregates(pstate, qry);
! if (forUpdate != NIL)
transformForUpdate(qry, forUpdate);
return qry;
--- 2080,2086 ----
if (pstate->p_hasAggs || qry->groupClause)
parseCheckAggregates(pstate, qry);
! if (forUpdate)
transformForUpdate(qry, forUpdate);
return qry;
***************
*** 2105,2111 ****
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("INTO is only allowed on first SELECT of
UNION/INTERSECT/EXCEPT")));
/* We don't support forUpdate with set ops at the moment. */
! if (stmt->forUpdate)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("SELECT FOR UPDATE is not allowed with
UNION/INTERSECT/EXCEPT")));
--- 2105,2111 ----
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("INTO is only allowed on first SELECT of
UNION/INTERSECT/EXCEPT")));
/* We don't support forUpdate with set ops at the moment. */
! if (stmt->forupdateClause)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("SELECT FOR UPDATE is not allowed with
UNION/INTERSECT/EXCEPT")));
***************
*** 2125,2131 ****
{
Assert(stmt->larg != NULL && stmt->rarg != NULL);
if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
! stmt->forUpdate)
isLeaf = true;
else
isLeaf = false;
--- 2125,2131 ----
{
Assert(stmt->larg != NULL && stmt->rarg != NULL);
if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
! stmt->forupdateClause)
isLeaf = true;
else
isLeaf = false;
***************
*** 2737,2752 ****
* in rewriteHandler.c.
*/
static void
! transformForUpdate(Query *qry, List *forUpdate)
{
List *rowMarks = qry->rowMarks;
ListCell *l;
ListCell *rt;
! Index i;
CheckSelectForUpdate(qry);
! if (linitial(forUpdate) == NULL)
{
/* all regular tables used in query */
i = 0;
--- 2737,2761 ----
* in rewriteHandler.c.
*/
static void
! transformForUpdate(Query *qry, Node *forupdateClause)
{
List *rowMarks = qry->rowMarks;
ListCell *l;
ListCell *rt;
! Index i;
! ForUpdate *fu = (ForUpdate *) forupdateClause;
! ForUpdate empty;
! List *update_list;
CheckSelectForUpdate(qry);
! update_list = fu->update_list;
! qry->nowait = fu->nowait;
!
! memset(&empty, 0, sizeof(ForUpdate));
! empty.nowait = FALSE;
!
! if (linitial(update_list) == NULL)
{
/* all regular tables used in query */
i = 0;
***************
*** 2768,2774 ****
* FOR UPDATE of subquery is propagated
to subquery's
* rels
*/
! transformForUpdate(rte->subquery,
list_make1(NULL));
break;
default:
/* ignore JOIN, SPECIAL, FUNCTION RTEs
*/
--- 2777,2785 ----
* FOR UPDATE of subquery is propagated
to subquery's
* rels
*/
! empty.update_list = list_make1(NULL);
! transformForUpdate(rte->subquery, (Node *)
&empty);
! empty.update_list = NIL;
break;
default:
/* ignore JOIN, SPECIAL, FUNCTION RTEs
*/
***************
*** 2779,2785 ****
else
{
/* just the named tables */
! foreach(l, forUpdate)
{
char *relname = strVal(lfirst(l));
--- 2790,2796 ----
else
{
/* just the named tables */
! foreach(l, update_list)
{
char *relname = strVal(lfirst(l));
***************
*** 2804,2810 ****
* FOR UPDATE of
subquery is propagated to
* subquery's rels
*/
!
transformForUpdate(rte->subquery, list_make1(NULL));
break;
case RTE_JOIN:
ereport(ERROR,
--- 2815,2823 ----
* FOR UPDATE of
subquery is propagated to
* subquery's rels
*/
! empty.update_list =
list_make1(NULL);
!
transformForUpdate(rte->subquery, (Node *) &empty);
! empty.update_list =
NULL;
break;
case RTE_JOIN:
ereport(ERROR,
diff -r -c postgresql-8.0.0rc2.orig/src/backend/parser/gram.y
postgresql-8.0.0rc2/src/backend/parser/gram.y
*** postgresql-8.0.0rc2.orig/src/backend/parser/gram.y Mon Nov 8 05:02:20 2004
--- postgresql-8.0.0rc2/src/backend/parser/gram.y Mon Dec 27 10:56:52 2004
***************
*** 87,93 ****
static List *extractArgTypes(List *parameters);
static SelectStmt *findLeftmostSelect(SelectStmt *node);
static void insertSelectOptions(SelectStmt *stmt,
! List
*sortClause, List *forUpdate,
Node
*limitOffset, Node *limitCount);
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
static Node *doNegate(Node *n);
--- 87,93 ----
static List *extractArgTypes(List *parameters);
static SelectStmt *findLeftmostSelect(SelectStmt *node);
static void insertSelectOptions(SelectStmt *stmt,
! List
*sortClause, Node *forUpdate,
Node
*limitOffset, Node *limitCount);
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
static Node *doNegate(Node *n);
***************
*** 239,245 ****
%type <oncommit> OnCommitOption
%type <withoids> OptWithOids WithOidsAs
! %type <list> for_update_clause opt_for_update_clause update_list
%type <boolean> opt_all
%type <node> join_outer join_qual
--- 239,247 ----
%type <oncommit> OnCommitOption
%type <withoids> OptWithOids WithOidsAs
! %type <node> for_update_clause opt_for_update_clause
! %type <list> update_list
!
%type <boolean> opt_all
%type <node> join_outer join_qual
***************
*** 4801,4807 ****
simple_select
{ $$ = $1; }
| select_clause sort_clause
{
! insertSelectOptions((SelectStmt *) $1,
$2, NIL,
NULL, NULL);
$$ = $1;
}
--- 4803,4809 ----
simple_select
{ $$ = $1; }
| select_clause sort_clause
{
! insertSelectOptions((SelectStmt *) $1,
$2, NULL,
NULL, NULL);
$$ = $1;
}
***************
*** 4862,4867 ****
--- 4864,4870 ----
n->whereClause = $6;
n->groupClause = $7;
n->havingClause = $8;
+ n->forupdateClause = NULL;
$$ = (Node *)n;
}
| select_clause UNION opt_all select_clause
***************
*** 5053,5060 ****
;
for_update_clause:
! FOR UPDATE update_list
{ $$ = $3; }
! | FOR READ ONLY
{ $$ = NULL; }
;
opt_for_update_clause:
--- 5056,5069 ----
;
for_update_clause:
! FOR UPDATE update_list opt_nowait
! {
! ForUpdate *n = makeNode(ForUpdate);
! n->update_list = $3;
! n->nowait = $4;
! $$ = (Node *) n;
! }
! | FOR READ ONLY
{ $$ = NULL; }
;
opt_for_update_clause:
***************
*** 8284,8290 ****
*/
static void
insertSelectOptions(SelectStmt *stmt,
! List *sortClause, List *forUpdate,
Node *limitOffset, Node *limitCount)
{
/*
--- 8293,8299 ----
*/
static void
insertSelectOptions(SelectStmt *stmt,
! List *sortClause, Node *forUpdate,
Node *limitOffset, Node *limitCount)
{
/*
***************
*** 8301,8311 ****
}
if (forUpdate)
{
! if (stmt->forUpdate)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple FOR UPDATE clauses not
allowed")));
! stmt->forUpdate = forUpdate;
}
if (limitOffset)
{
--- 8310,8320 ----
}
if (forUpdate)
{
! if (stmt->forupdateClause)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple FOR UPDATE clauses not
allowed")));
! stmt->forupdateClause = forUpdate;
}
if (limitOffset)
{
diff -r -c postgresql-8.0.0rc2.orig/src/backend/parser/parse_type.c
postgresql-8.0.0rc2/src/backend/parser/parse_type.c
*** postgresql-8.0.0rc2.orig/src/backend/parser/parse_type.c Wed Dec 15
21:15:17 2004
--- postgresql-8.0.0rc2/src/backend/parser/parse_type.c Mon Dec 27 10:56:52 2004
***************
*** 432,438 ****
stmt->sortClause != NIL ||
stmt->limitOffset != NULL ||
stmt->limitCount != NULL ||
! stmt->forUpdate != NIL ||
stmt->op != SETOP_NONE)
goto fail;
if (list_length(stmt->targetList) != 1)
--- 432,438 ----
stmt->sortClause != NIL ||
stmt->limitOffset != NULL ||
stmt->limitCount != NULL ||
! stmt->forupdateClause != NULL ||
stmt->op != SETOP_NONE)
goto fail;
if (list_length(stmt->targetList) != 1)
diff -r -c postgresql-8.0.0rc2.orig/src/backend/storage/lmgr/lmgr.c
postgresql-8.0.0rc2/src/backend/storage/lmgr/lmgr.c
*** postgresql-8.0.0rc2.orig/src/backend/storage/lmgr/lmgr.c Thu Sep 16
18:58:33 2004
--- postgresql-8.0.0rc2/src/backend/storage/lmgr/lmgr.c Mon Dec 27 10:56:52 2004
***************
*** 393,395 ****
--- 393,435 ----
if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
TransactionIdAbort(xid);
}
+
+ /*
+ * As above, but only lock if we can get the lock without blocking.
+ * Returns TRUE if the lock was acquired.
+ */
+ bool
+ ConditionalXactLockTableWait(TransactionId xid)
+ {
+ LOCKTAG tag;
+ TransactionId myxid = GetTopTransactionId();
+
+ for (;;)
+ {
+ Assert(TransactionIdIsValid(xid));
+ Assert(!TransactionIdEquals(xid, myxid));
+
+ MemSet(&tag, 0, sizeof(tag));
+ tag.relId = XactLockTableId;
+ tag.dbId = InvalidOid;
+ tag.objId.xid = xid;
+
+ if (!LockAcquire(LockTableId, &tag, myxid, ShareLock, true))
+ return FALSE;
+ LockRelease(LockTableId, &tag, myxid, ShareLock);
+
+ if (!TransactionIdIsInProgress(xid))
+ break;
+ xid = SubTransGetParent(xid);
+ }
+
+ /*
+ * Transaction was committed/aborted/crashed - we have to update
+ * pg_clog if transaction is still marked as running.
+ */
+ if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
+ TransactionIdAbort(xid);
+
+ return TRUE;
+ }
+
diff -r -c postgresql-8.0.0rc2.orig/src/bin/psql/sql_help.h postgresql-8.0.0rc2/src/bin/psql/sql_help.h
*** postgresql-8.0.0rc2.orig/src/bin/psql/sql_help.h Tue Dec 21 05:22:44 2004
--- postgresql-8.0.0rc2/src/bin/psql/sql_help.h Mon Dec 27 10:57:05 2004
***************
*** 383,393 ****
{ "SELECT",
N_("retrieve rows from a table or view"),
! N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n * |
expression [ AS output_name ] [, ...]\n [ FROM from_item [, ...] ]\n [ WHERE
condition ]\n [ GROUP BY expression [, ...] ]\n [ HAVING condition [, ...] ]\n [
{ UNION | INTERSECT | EXCEPT } [ ALL ] select ]\n [ ORDER BY expression [ ASC | DESC |
USING operator ] [, ...] ]\n [ LIMIT { count | ALL } ]\n [ OFFSET start ]\n [
FOR UPDATE [ OF table_name [, ...] ] ]\n\nwhere from_item can be one of:\n\n [ ONLY ]
table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]\n ( select ) [ AS ]
alias [ ( column_alias [, ...] ) ]\n function_name ( [ argument [, ...] ] ) [ AS ]
alias [ ( column_alias [, ...] | column_definition [, ...] ) ]\n function_name ( [
argument [, ...] ] ) AS ( column_definition [, ...] )\n from_item [ NATURAL ]
join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]") },
{ "SELECT INTO",
N_("define a new table from the results of a query"),
! N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n * |
expression [ AS output_name ] [, ...]\n INTO [ TEMPORARY | TEMP ] [ TABLE ]
new_table\n [ FROM from_item [, ...] ]\n [ WHERE condition ]\n [ GROUP BY
expression [, ...] ]\n [ HAVING condition [, ...] ]\n [ { UNION | INTERSECT |
EXCEPT } [ ALL ] select ]\n [ ORDER BY expression [ ASC | DESC | USING operator ] [,
...] ]\n [ LIMIT { count | ALL } ]\n [ OFFSET start ]\n [ FOR UPDATE [ OF
tablename [, ...] ] ]") },
{ "SET",
N_("change a run-time parameter"),
--- 383,393 ----
{ "SELECT",
N_("retrieve rows from a table or view"),
! N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n * |
expression [ AS output_name ] [, ...]\n [ FROM from_item [, ...] ]\n [ WHERE
condition ]\n [ GROUP BY expression [, ...] ]\n [ HAVING condition [, ...] ]\n [
{ UNION | INTERSECT | EXCEPT } [ ALL ] select ]\n [ ORDER BY expression [ ASC | DESC |
USING operator ] [, ...] ]\n [ LIMIT { count | ALL } ]\n [ OFFSET start ]\n [
FOR UPDATE [ OF table_name [, ...] ] [NOWAIT] ]\n\nwhere from_item can be one of:\n\n
[ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]\n ( select ) [
AS ] alias [ ( column_alias [, ...] ) ]\n function_name ( [ argument [, ...] ] ) [ AS
] alias [ ( column_alias [, ...] | column_definition [, ...] ) ]\n function_name ( [
argument [, ...] ] ) AS ( column_definition [, ...] )\n from_item [ NATURAL ]
join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]") },
{ "SELECT INTO",
N_("define a new table from the results of a query"),
! N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n * |
expression [ AS output_name ] [, ...]\n INTO [ TEMPORARY | TEMP ] [ TABLE ]
new_table\n [ FROM from_item [, ...] ]\n [ WHERE condition ]\n [ GROUP BY
expression [, ...] ]\n [ HAVING condition [, ...] ]\n [ { UNION | INTERSECT |
EXCEPT } [ ALL ] select ]\n [ ORDER BY expression [ ASC | DESC | USING operator ] [,
...] ]\n [ LIMIT { count | ALL } ]\n [ OFFSET start ]\n [ FOR UPDATE [ OF
tablename [, ...] ] [NOWAIT] ]") },
{ "SET",
N_("change a run-time parameter"),
diff -r -c postgresql-8.0.0rc2.orig/src/include/access/heapam.h
postgresql-8.0.0rc2/src/include/access/heapam.h
*** postgresql-8.0.0rc2.orig/src/include/access/heapam.h Sun Aug 29
07:06:55 2004
--- postgresql-8.0.0rc2/src/include/access/heapam.h Mon Dec 27 10:57:05 2004
***************
*** 164,170 ****
extern int heap_update(Relation relation, ItemPointer otid, HeapTuple tup,
ItemPointer ctid, CommandId cid, Snapshot crosscheck, bool
wait);
extern int heap_mark4update(Relation relation, HeapTuple tup,
! Buffer *userbuf, CommandId cid);
extern Oid simple_heap_insert(Relation relation, HeapTuple tup);
extern void simple_heap_delete(Relation relation, ItemPointer tid);
--- 164,170 ----
extern int heap_update(Relation relation, ItemPointer otid, HeapTuple tup,
ItemPointer ctid, CommandId cid, Snapshot crosscheck, bool
wait);
extern int heap_mark4update(Relation relation, HeapTuple tup,
! Buffer *userbuf, CommandId cid, bool nowait);
extern Oid simple_heap_insert(Relation relation, HeapTuple tup);
extern void simple_heap_delete(Relation relation, ItemPointer tid);
diff -r -c postgresql-8.0.0rc2.orig/src/include/nodes/execnodes.h
postgresql-8.0.0rc2/src/include/nodes/execnodes.h
*** postgresql-8.0.0rc2.orig/src/include/nodes/execnodes.h Sun Dec 12
00:26:49 2004
--- postgresql-8.0.0rc2/src/include/nodes/execnodes.h Mon Dec 27 10:56:52 2004
***************
*** 308,313 ****
--- 308,314 ----
bool es_instrument; /* true requests runtime
instrumentation */
bool es_select_into; /* true if doing SELECT INTO */
bool es_into_oids; /* true to generate OIDs in SELECT INTO
*/
+ bool es_nowait; /* SELECT FOR UPDATE NOWAIT */
List *es_exprcontexts; /* List of ExprContexts within EState */
diff -r -c postgresql-8.0.0rc2.orig/src/include/nodes/nodes.h postgresql-8.0.0rc2/src/include/nodes/nodes.h
*** postgresql-8.0.0rc2.orig/src/include/nodes/nodes.h Sun Dec 12 00:26:49 2004
--- postgresql-8.0.0rc2/src/include/nodes/nodes.h Mon Dec 27 10:56:52 2004
***************
*** 302,307 ****
--- 302,308 ----
T_CompositeTypeStmt,
T_InhRelation,
T_FunctionParameter,
+ T_ForUpdate,
/*
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
diff -r -c postgresql-8.0.0rc2.orig/src/include/nodes/parsenodes.h
postgresql-8.0.0rc2/src/include/nodes/parsenodes.h
*** postgresql-8.0.0rc2.orig/src/include/nodes/parsenodes.h Fri Nov 5
20:16:38 2004
--- postgresql-8.0.0rc2/src/include/nodes/parsenodes.h Mon Dec 27 10:56:52 2004
***************
*** 103,108 ****
--- 103,110 ----
List *sortClause; /* a list of SortClause's */
+ bool nowait; /* are we in NOWAIT mode? */
+
Node *limitOffset; /* # of result tuples to skip */
Node *limitCount; /* # of result tuples to return */
***************
*** 422,427 ****
--- 424,439 ----
Node *arg; /* a (Value *) or a (TypeName
*) */
} DefElem;
+ /*
+ * ForUpdate -
+ * used in raw parsetrees output only
+ */
+ typedef struct ForUpdate
+ {
+ NodeTag type;
+ List *update_list; /* list of tables */
+ bool nowait; /* NOWAIT option */
+ } ForUpdate;
/****************************************************************************
* Nodes for a Query tree
***************
*** 686,692 ****
List *sortClause; /* sort clause (a list of SortBy's) */
Node *limitOffset; /* # of result tuples to skip */
Node *limitCount; /* # of result tuples to return */
! List *forUpdate; /* FOR UPDATE clause */
/*
* These fields are used only in upper-level SelectStmts.
--- 698,704 ----
List *sortClause; /* sort clause (a list of SortBy's) */
Node *limitOffset; /* # of result tuples to skip */
Node *limitCount; /* # of result tuples to return */
! Node *forupdateClause; /* FOR UPDATE clause (ForUpdate node) */
/*
* These fields are used only in upper-level SelectStmts.
diff -r -c postgresql-8.0.0rc2.orig/src/include/storage/lmgr.h
postgresql-8.0.0rc2/src/include/storage/lmgr.h
*** postgresql-8.0.0rc2.orig/src/include/storage/lmgr.h Thu Sep 16 18:58:42 2004
--- postgresql-8.0.0rc2/src/include/storage/lmgr.h Mon Dec 27 10:56:52 2004
***************
*** 60,64 ****
--- 60,65 ----
extern void XactLockTableInsert(TransactionId xid);
extern void XactLockTableDelete(TransactionId xid);
extern void XactLockTableWait(TransactionId xid);
+ extern bool ConditionalXactLockTableWait(TransactionId xid);
#endif /* LMGR_H */