*
* rewriteManip.c
*
- * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.93 2005/11/22 18:17:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.108 2008/08/14 18:47:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
-#include "optimizer/tlist.h"
-#include "parser/parsetree.h"
+#include "parser/parse_coerce.h"
#include "parser/parse_relation.h"
+#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
-#include "utils/lsyscache.h"
typedef struct
}
return false;
}
+ if (IsA(node, CurrentOfExpr))
+ {
+ CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
+
+ if (context->sublevels_up == 0)
+ cexpr->cvarno += context->offset;
+ return false;
+ }
if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) node;
j->rtindex += context->offset;
/* fall through to examine children */
}
- if (IsA(node, InClauseInfo))
+ if (IsA(node, FlattenedSubLink))
{
- InClauseInfo *ininfo = (InClauseInfo *) node;
+ FlattenedSubLink *fslink = (FlattenedSubLink *) node;
if (context->sublevels_up == 0)
{
- ininfo->lefthand = offset_relid_set(ininfo->lefthand,
+ fslink->lefthand = offset_relid_set(fslink->lefthand,
context->offset);
- ininfo->righthand = offset_relid_set(ininfo->righthand,
+ fslink->righthand = offset_relid_set(fslink->righthand,
context->offset);
}
/* fall through to examine children */
}
+ if (IsA(node, AppendRelInfo))
+ {
+ AppendRelInfo *appinfo = (AppendRelInfo *) node;
+
+ if (context->sublevels_up == 0)
+ {
+ appinfo->parent_relid += context->offset;
+ appinfo->child_relid += context->offset;
+ }
+ /* fall through to examine children */
+ }
if (IsA(node, Query))
{
/* Recurse into subselects */
if (qry->resultRelation)
qry->resultRelation += offset;
foreach(l, qry->rowMarks)
- lfirst_int(l) += offset;
+ {
+ RowMarkClause *rc = (RowMarkClause *) lfirst(l);
+
+ rc->rti += offset;
+ }
}
query_tree_walker(qry, OffsetVarNodes_walker,
(void *) &context, 0);
}
return false;
}
+ if (IsA(node, CurrentOfExpr))
+ {
+ CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
+
+ if (context->sublevels_up == 0 &&
+ cexpr->cvarno == context->rt_index)
+ cexpr->cvarno = context->new_index;
+ return false;
+ }
if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) node;
j->rtindex = context->new_index;
/* fall through to examine children */
}
- if (IsA(node, InClauseInfo))
+ if (IsA(node, FlattenedSubLink))
{
- InClauseInfo *ininfo = (InClauseInfo *) node;
+ FlattenedSubLink *fslink = (FlattenedSubLink *) node;
if (context->sublevels_up == 0)
{
- ininfo->lefthand = adjust_relid_set(ininfo->lefthand,
+ fslink->lefthand = adjust_relid_set(fslink->lefthand,
context->rt_index,
context->new_index);
- ininfo->righthand = adjust_relid_set(ininfo->righthand,
+ fslink->righthand = adjust_relid_set(fslink->righthand,
context->rt_index,
context->new_index);
}
/* fall through to examine children */
}
+ if (IsA(node, AppendRelInfo))
+ {
+ AppendRelInfo *appinfo = (AppendRelInfo *) node;
+
+ if (context->sublevels_up == 0)
+ {
+ if (appinfo->parent_relid == context->rt_index)
+ appinfo->parent_relid = context->new_index;
+ if (appinfo->child_relid == context->rt_index)
+ appinfo->child_relid = context->new_index;
+ }
+ /* fall through to examine children */
+ }
if (IsA(node, Query))
{
/* Recurse into subselects */
qry->resultRelation = new_index;
foreach(l, qry->rowMarks)
{
- if (lfirst_int(l) == rt_index)
- lfirst_int(l) = new_index;
+ RowMarkClause *rc = (RowMarkClause *) lfirst(l);
+
+ if (rc->rti == rt_index)
+ rc->rti = new_index;
}
}
query_tree_walker(qry, ChangeVarNodes_walker,
var->varlevelsup += context->delta_sublevels_up;
return false; /* done here */
}
+ if (IsA(node, CurrentOfExpr))
+ {
+ /* this should not happen */
+ if (context->min_sublevels_up == 0)
+ elog(ERROR, "cannot push down CurrentOfExpr");
+ return false;
+ }
if (IsA(node, Aggref))
{
Aggref *agg = (Aggref *) node;
return true;
return false;
}
+ if (IsA(node, CurrentOfExpr))
+ {
+ CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
+
+ if (context->sublevels_up == 0 &&
+ cexpr->cvarno == context->rt_index)
+ return true;
+ return false;
+ }
if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) node;
return true;
/* fall through to examine children */
}
- if (IsA(node, InClauseInfo))
- {
- InClauseInfo *ininfo = (InClauseInfo *) node;
+ /* Shouldn't need to handle planner auxiliary nodes here */
+ Assert(!IsA(node, FlattenedSubLink));
+ Assert(!IsA(node, SpecialJoinInfo));
+ Assert(!IsA(node, AppendRelInfo));
- if (context->sublevels_up == 0 &&
- (bms_is_member(context->rt_index, ininfo->lefthand) ||
- bms_is_member(context->rt_index, ininfo->righthand)))
- return true;
- /* fall through to examine children */
- }
if (IsA(node, Query))
{
/* Recurse into subselects */
else
{
/* Otherwise replace unmatched var with a null */
- return (Node *) makeNullConst(var->vartype);
+ /* need coerce_to_domain in case of NOT NULL domain constraint */
+ return coerce_to_domain((Node *) makeNullConst(var->vartype,
+ var->vartypmod),
+ InvalidOid, -1,
+ var->vartype,
+ COERCE_IMPLICIT_CAST,
+ false,
+ false);
}
}
else
}
/* otherwise fall through to copy the var normally */
}
+ else if (IsA(node, CurrentOfExpr))
+ {
+ CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
+ int this_varno = (int) cexpr->cvarno;
- if (IsA(node, Query))
+ if (this_varno == context->target_varno &&
+ context->sublevels_up == 0)
+ {
+ /*
+ * We get here if a WHERE CURRENT OF expression turns out to apply
+ * to a view. Someday we might be able to translate the
+ * expression to apply to an underlying table of the view, but
+ * right now it's not implemented.
+ */
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("WHERE CURRENT OF on a view is not implemented")));
+ }
+ /* otherwise fall through to copy the expr normally */
+ }
+ else if (IsA(node, Query))
{
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
Query *newnode;
RangeTblEntry *target_rte,
List *targetlist, int event, int update_varno)
{
+ Node *result;
ResolveNew_context context;
context.target_varno = target_varno;
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
- return query_or_expression_tree_mutator(node,
- ResolveNew_mutator,
- (void *) &context,
- 0);
+ result = query_or_expression_tree_mutator(node,
+ ResolveNew_mutator,
+ (void *) &context,
+ 0);
+
+ if (context.inserted_sublink)
+ {
+ if (IsA(result, Query))
+ ((Query *) result)->hasSubLinks = true;
+
+ /*
+ * Note: if we're called on a non-Query node then it's the caller's
+ * responsibility to update hasSubLinks in the ancestor Query. This is
+ * pretty fragile and perhaps should be rethought ...
+ */
+ }
+
+ return result;
}