*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.96 2000/11/12 00:36:58 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.97 2000/12/06 23:55:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "optimizer/subselect.h"
#include "optimizer/tlist.h"
#include "optimizer/var.h"
+#include "parser/analyze.h"
#include "parser/parsetree.h"
#include "parser/parse_expr.h"
#include "rewrite/rewriteManip.h"
int rtoffset;
Node *subjointree;
List *subtlist;
+ List *l;
/*
* First, recursively pull up the subquery's subqueries,
parse->havingQual =
ResolveNew(parse->havingQual,
varno, 0, subtlist, CMD_SELECT, 0);
+ /*
+ * Pull up any FOR UPDATE markers, too.
+ */
+ foreach(l, subquery->rowMarks)
+ {
+ int submark = lfirsti(l);
+
+ parse->rowMarks = lappendi(parse->rowMarks,
+ submark + rtoffset);
+ }
/*
* Miscellaneous housekeeping.
*/
parse->hasSubLinks |= subquery->hasSubLinks;
+ /* subquery won't be pulled up if it hasAggs, so no work there */
+
/*
* Return the adjusted subquery jointree to replace the
* RangeTblRef entry in my jointree.
subquery->into != NULL ||
subquery->isPortal)
elog(ERROR, "is_simple_subquery: subquery is bogus");
- /*
- * Also check for currently-unsupported features.
- */
- if (subquery->rowMarks)
- elog(ERROR, "FOR UPDATE is not supported in subselects");
/*
* Can't currently pull up a query with setops.
* Maybe after querytree redesign...
tlist = postprocess_setop_tlist(result_plan->targetlist, tlist);
+ /*
+ * Can't handle FOR UPDATE here (parser should have checked already,
+ * but let's make sure).
+ */
+ if (parse->rowMarks)
+ elog(ERROR, "SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT");
+
/*
* We set current_pathkeys NIL indicating we do not know sort
* order. This is correct when the top set operation is UNION ALL,
{
List *l;
+ /*
+ * We've got trouble if the FOR UPDATE appears inside grouping,
+ * since grouping renders a reference to individual tuple CTIDs
+ * invalid. This is also checked at parse time, but that's
+ * insufficient because of rule substitution, query pullup, etc.
+ */
+ CheckSelectForUpdate(parse);
+
+ /* Currently the executor only supports FOR UPDATE at top level */
+ if (PlannerQueryLevel > 1)
+ elog(ERROR, "SELECT FOR UPDATE is not allowed in subselects");
+
foreach(l, parse->rowMarks)
{
Index rti = lfirsti(l);
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: analyze.c,v 1.170 2000/12/05 19:57:55 tgl Exp $
+ * $Id: analyze.c,v 1.171 2000/12/06 23:55:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "mb/pg_wchar.h"
#endif
-void CheckSelectForUpdate(Query *qry); /* no points for style... */
-
static Query *transformStmt(ParseState *pstate, Node *stmt);
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.84 2000/12/05 19:15:09 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.85 2000/12/06 23:55:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/lsyscache.h"
-extern void CheckSelectForUpdate(Query *rule_action); /* in analyze.c */
-
-
static RewriteInfo *gatherRewriteMeta(Query *parsetree,
Query *rule_action,
Node *rule_qual,
ChangeVarNodes(info->rule_qual,
PRS2_OLD_VARNO + rt_length, rt_index, 0);
- /*
- * Update resultRelation too ... perhaps this should be done by
- * Offset/ChangeVarNodes?
- */
- if (sub_action->resultRelation)
- {
- int result_reln;
- int new_result_reln;
-
- result_reln = sub_action->resultRelation;
- switch (result_reln)
- {
- case PRS2_OLD_VARNO:
- new_result_reln = rt_index;
- break;
- case PRS2_NEW_VARNO:
- default:
- new_result_reln = result_reln + rt_length;
- break;
- }
- sub_action->resultRelation = new_result_reln;
- }
-
/*
* We want the main parsetree's rtable to end up as the concatenation
* of its original contents plus those of all the relevant rule
{
Index innerrti = 1;
- CheckSelectForUpdate(rule_action);
-
/*
* Remove the view from the list of rels that will actually be
* marked FOR UPDATE by the executor. It will still be access-
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.52 2000/12/05 19:15:09 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.53 2000/12/06 23:55:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* sublevels_up doesn't get incremented prematurely.
*/
if (node && IsA(node, Query))
- query_tree_walker((Query *) node, OffsetVarNodes_walker,
+ {
+ Query *qry = (Query *) node;
+ List *l;
+
+ /*
+ * If we are starting at a Query, and sublevels_up is zero, then we
+ * must also fix rangetable indexes in the Query itself --- namely
+ * resultRelation and rowMarks entries. sublevels_up cannot be zero
+ * when recursing into a subquery, so there's no need to have the
+ * same logic inside OffsetVarNodes_walker.
+ */
+ if (sublevels_up == 0)
+ {
+ if (qry->resultRelation)
+ qry->resultRelation += offset;
+ foreach(l, qry->rowMarks)
+ {
+ lfirsti(l) += offset;
+ }
+ }
+ query_tree_walker(qry, OffsetVarNodes_walker,
(void *) &context, true);
+ }
else
OffsetVarNodes_walker(node, &context);
}
* sublevels_up doesn't get incremented prematurely.
*/
if (node && IsA(node, Query))
- query_tree_walker((Query *) node, ChangeVarNodes_walker,
+ {
+ Query *qry = (Query *) node;
+ List *l;
+
+ /*
+ * If we are starting at a Query, and sublevels_up is zero, then we
+ * must also fix rangetable indexes in the Query itself --- namely
+ * resultRelation and rowMarks entries. sublevels_up cannot be zero
+ * when recursing into a subquery, so there's no need to have the
+ * same logic inside ChangeVarNodes_walker.
+ */
+ if (sublevels_up == 0)
+ {
+ if (qry->resultRelation == rt_index)
+ qry->resultRelation = new_index;
+ foreach(l, qry->rowMarks)
+ {
+ if (lfirsti(l) == rt_index)
+ lfirsti(l) = new_index;
+ }
+ }
+ query_tree_walker(qry, ChangeVarNodes_walker,
(void *) &context, true);
+ }
else
ChangeVarNodes_walker(node, &context);
}
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: analyze.h,v 1.12 2000/10/07 00:58:21 tgl Exp $
+ * $Id: analyze.h,v 1.13 2000/12/06 23:55:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern List *parse_analyze(Node *parseTree, ParseState *parentParseState);
+extern void CheckSelectForUpdate(Query *qry);
+
#endif /* ANALYZE_H */