1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-02 04:21:28 +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:
Tom Lane
2007-06-11 01:16:30 +00:00
parent 85d72f0516
commit 6808f1b1de
30 changed files with 940 additions and 127 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.85 2007/04/21 21:01:44 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.86 2007/06/11 01:16:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,6 +18,7 @@
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/plancat.h"
#include "parser/parsetree.h"
#include "utils/fmgroids.h"
@@ -712,6 +713,15 @@ clause_selectivity(PlannerInfo *root,
varRelid,
jointype);
}
else if (IsA(clause, CurrentOfExpr))
{
/* CURRENT OF selects at most one row of its table */
CurrentOfExpr *cexpr = (CurrentOfExpr *) clause;
RelOptInfo *crel = find_base_rel(root, cexpr->cvarno);
if (crel->tuples > 0)
s1 = 1.0 / crel->tuples;
}
else if (IsA(clause, RelabelType))
{
/* Not sure this case is needed, but it can't hurt */

View File

@@ -54,7 +54,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.184 2007/06/05 21:31:05 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.185 2007/06/11 01:16:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -770,6 +770,7 @@ cost_tidscan(Path *path, PlannerInfo *root,
Cost startup_cost = 0;
Cost run_cost = 0;
Cost cpu_per_tuple;
QualCost tid_qual_cost;
int ntuples;
ListCell *l;
@@ -799,12 +800,20 @@ cost_tidscan(Path *path, PlannerInfo *root,
}
}
/*
* The TID qual expressions will be computed once, any other baserestrict
* quals once per retrived tuple.
*/
cost_qual_eval(&tid_qual_cost, tidquals, root);
/* disk costs --- assume each tuple on a different page */
run_cost += random_page_cost * ntuples;
/* CPU costs */
startup_cost += baserel->baserestrictcost.startup;
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
startup_cost += baserel->baserestrictcost.startup +
tid_qual_cost.per_tuple;
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple -
tid_qual_cost.per_tuple;
run_cost += cpu_per_tuple * ntuples;
path->startup_cost = startup_cost;
@@ -1991,6 +2000,11 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
cpu_operator_cost;
}
}
else if (IsA(node, CurrentOfExpr))
{
/* This is noticeably more expensive than a typical operator */
context->total.per_tuple += 100 * cpu_operator_cost;
}
else if (IsA(node, SubLink))
{
/* This routine should not be applied to un-planned expressions */

View File

@@ -12,6 +12,12 @@
* this allows
* WHERE ctid IN (tid1, tid2, ...)
*
* We also support "WHERE CURRENT OF cursor" conditions (CurrentOfExpr),
* which amount to "CTID = run-time-determined-TID". These could in
* theory be translated to a simple comparison of CTID to the result of
* a function, but in practice it works better to keep the special node
* representation all the way through to execution.
*
* There is currently no special support for joins involving CTID; in
* particular nothing corresponding to best_inner_indexscan(). Since it's
* not very useful to store TIDs of one table in another table, there
@@ -24,7 +30,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/tidpath.c,v 1.29 2007/01/05 22:19:31 momjian Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/tidpath.c,v 1.30 2007/06/11 01:16:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -174,6 +180,12 @@ TidQualFromExpr(Node *expr, int varno)
if (IsTidEqualAnyClause((ScalarArrayOpExpr *) expr, varno))
rlst = list_make1(expr);
}
else if (expr && IsA(expr, CurrentOfExpr))
{
/* another base case: check for CURRENT OF on this rel */
if (((CurrentOfExpr *) expr)->cvarno == varno)
rlst = list_make1(expr);
}
else if (and_clause(expr))
{
foreach(l, ((BoolExpr *) expr)->args)