mirror of
https://github.com/postgres/postgres.git
synced 2025-11-25 12:03:53 +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:
@@ -20,7 +20,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.363 2007/04/27 22:05:48 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.364 2007/06/11 01:16:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -3178,12 +3178,12 @@ transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt)
|
||||
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
|
||||
errmsg("DECLARE CURSOR cannot specify INTO")));
|
||||
|
||||
/* Implementation restriction (might go away someday) */
|
||||
if (result->rowMarks != NIL)
|
||||
/* FOR UPDATE and WITH HOLD are not compatible */
|
||||
if (result->rowMarks != NIL && (stmt->options & CURSOR_OPT_HOLD))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("DECLARE CURSOR ... FOR UPDATE/SHARE is not supported"),
|
||||
errdetail("Cursors must be READ ONLY.")));
|
||||
errmsg("DECLARE CURSOR WITH HOLD ... FOR UPDATE/SHARE is not supported"),
|
||||
errdetail("Holdable cursors must be READ ONLY.")));
|
||||
|
||||
/* We won't need the raw querytree any more */
|
||||
stmt->query = NULL;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.591 2007/04/27 22:05:48 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.592 2007/06/11 01:16:25 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -296,7 +296,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
|
||||
%type <node> TableElement ConstraintElem TableFuncElement
|
||||
%type <node> columnDef
|
||||
%type <defelt> def_elem old_aggr_elem
|
||||
%type <node> def_arg columnElem where_clause
|
||||
%type <node> def_arg columnElem where_clause where_or_current_clause
|
||||
a_expr b_expr c_expr func_expr AexprConst indirection_el
|
||||
columnref in_expr having_clause func_table array_expr
|
||||
%type <list> row type_list array_expr_list
|
||||
@@ -377,8 +377,8 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
|
||||
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
|
||||
COMMITTED CONCURRENTLY CONNECTION CONSTRAINT CONSTRAINTS
|
||||
CONTENT_P CONVERSION_P CONVERT COPY COST CREATE CREATEDB
|
||||
CREATEROLE CREATEUSER CROSS CSV CURRENT_DATE CURRENT_ROLE CURRENT_TIME
|
||||
CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
|
||||
CREATEROLE CREATEUSER CROSS CSV CURRENT_P CURRENT_DATE CURRENT_ROLE
|
||||
CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
|
||||
|
||||
DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
|
||||
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS
|
||||
@@ -5715,7 +5715,7 @@ returning_clause:
|
||||
*****************************************************************************/
|
||||
|
||||
DeleteStmt: DELETE_P FROM relation_expr_opt_alias
|
||||
using_clause where_clause returning_clause
|
||||
using_clause where_or_current_clause returning_clause
|
||||
{
|
||||
DeleteStmt *n = makeNode(DeleteStmt);
|
||||
n->relation = $3;
|
||||
@@ -5771,7 +5771,7 @@ opt_nowait: NOWAIT { $$ = TRUE; }
|
||||
UpdateStmt: UPDATE relation_expr_opt_alias
|
||||
SET set_clause_list
|
||||
from_clause
|
||||
where_clause
|
||||
where_or_current_clause
|
||||
returning_clause
|
||||
{
|
||||
UpdateStmt *n = makeNode(UpdateStmt);
|
||||
@@ -6562,6 +6562,18 @@ where_clause:
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
/* variant for UPDATE and DELETE */
|
||||
where_or_current_clause:
|
||||
WHERE a_expr { $$ = $2; }
|
||||
| WHERE CURRENT_P OF name
|
||||
{
|
||||
CurrentOfExpr *n = makeNode(CurrentOfExpr);
|
||||
n->cursor_name = $4;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
|
||||
TableFuncElementList:
|
||||
TableFuncElement
|
||||
@@ -8818,6 +8830,7 @@ unreserved_keyword:
|
||||
| CREATEROLE
|
||||
| CREATEUSER
|
||||
| CSV
|
||||
| CURRENT_P
|
||||
| CURSOR
|
||||
| CYCLE
|
||||
| DATABASE
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.187 2007/04/26 16:13:12 neilc Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.188 2007/06/11 01:16:25 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -101,6 +101,7 @@ static const ScanKeyword ScanKeywords[] = {
|
||||
{"createuser", CREATEUSER},
|
||||
{"cross", CROSS},
|
||||
{"csv", CSV},
|
||||
{"current", CURRENT_P},
|
||||
{"current_date", CURRENT_DATE},
|
||||
{"current_role", CURRENT_ROLE},
|
||||
{"current_time", CURRENT_TIME},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.218 2007/06/05 21:31:05 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.219 2007/06/11 01:16:25 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -243,6 +243,21 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
result = transformBooleanTest(pstate, (BooleanTest *) expr);
|
||||
break;
|
||||
|
||||
case T_CurrentOfExpr:
|
||||
{
|
||||
CurrentOfExpr *c = (CurrentOfExpr *) expr;
|
||||
int sublevels_up;
|
||||
|
||||
/* CURRENT OF can only appear at top level of UPDATE/DELETE */
|
||||
Assert(pstate->p_target_rangetblentry != NULL);
|
||||
c->cvarno = RTERangeTablePosn(pstate,
|
||||
pstate->p_target_rangetblentry,
|
||||
&sublevels_up);
|
||||
Assert(sublevels_up == 0);
|
||||
result = expr;
|
||||
break;
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* Quietly accept node types that may be presented when we are
|
||||
* called on an already-transformed tree.
|
||||
@@ -1863,6 +1878,9 @@ exprType(Node *expr)
|
||||
case T_SetToDefault:
|
||||
type = ((SetToDefault *) expr)->typeId;
|
||||
break;
|
||||
case T_CurrentOfExpr:
|
||||
type = BOOLOID;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
|
||||
type = InvalidOid; /* keep compiler quiet */
|
||||
|
||||
Reference in New Issue
Block a user