mirror of
https://github.com/postgres/postgres.git
synced 2025-07-02 09:02:37 +03:00
Support UPDATE/DELETE WHERE CURRENT OF cursor_name, per SQL standard.
Along the way, allow FOR UPDATE in non-WITH-HOLD cursors; there may once have been a reason to disallow that, but it seems to work now, and it's really rather necessary if you want to select a row via a cursor and then update it in a concurrent-safe fashion. Original patch by Arul Shaji, rather heavily editorialized by Tom Lane.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.69 2007/01/05 22:19:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.70 2007/06/11 01:16:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -111,6 +111,14 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
|
||||
context->varnos = bms_add_member(context->varnos, var->varno);
|
||||
return false;
|
||||
}
|
||||
if (IsA(node, CurrentOfExpr))
|
||||
{
|
||||
CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
|
||||
|
||||
if (context->sublevels_up == 0)
|
||||
context->varnos = bms_add_member(context->varnos, cexpr->cvarno);
|
||||
return false;
|
||||
}
|
||||
if (IsA(node, Query))
|
||||
{
|
||||
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
|
||||
@ -217,6 +225,8 @@ contain_var_clause_walker(Node *node, void *context)
|
||||
return true; /* abort the tree traversal and return true */
|
||||
return false;
|
||||
}
|
||||
if (IsA(node, CurrentOfExpr))
|
||||
return true;
|
||||
return expression_tree_walker(node, contain_var_clause_walker, context);
|
||||
}
|
||||
|
||||
@ -249,6 +259,13 @@ contain_vars_of_level_walker(Node *node, int *sublevels_up)
|
||||
{
|
||||
if (((Var *) node)->varlevelsup == *sublevels_up)
|
||||
return true; /* abort tree traversal and return true */
|
||||
return false;
|
||||
}
|
||||
if (IsA(node, CurrentOfExpr))
|
||||
{
|
||||
if (*sublevels_up == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (IsA(node, Query))
|
||||
{
|
||||
@ -376,6 +393,29 @@ find_minimum_var_level_walker(Node *node,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IsA(node, CurrentOfExpr))
|
||||
{
|
||||
int varlevelsup = 0;
|
||||
|
||||
/* convert levelsup to frame of reference of original query */
|
||||
varlevelsup -= context->sublevels_up;
|
||||
/* ignore local vars of subqueries */
|
||||
if (varlevelsup >= 0)
|
||||
{
|
||||
if (context->min_varlevel < 0 ||
|
||||
context->min_varlevel > varlevelsup)
|
||||
{
|
||||
context->min_varlevel = varlevelsup;
|
||||
|
||||
/*
|
||||
* As soon as we find a local variable, we can abort the tree
|
||||
* traversal, since min_varlevel is then certainly 0.
|
||||
*/
|
||||
if (varlevelsup == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* An Aggref must be treated like a Var of its level. Normally we'd get
|
||||
|
Reference in New Issue
Block a user