]> granicus.if.org Git - postgresql/blobdiff - src/backend/rewrite/rewriteManip.c
Implement SEMI and ANTI joins in the planner and executor. (Semijoins replace
[postgresql] / src / backend / rewrite / rewriteManip.c
index 9e6bc4808e73dae159b943fb00334ec63f4e1b6e..60492fe3d091fa52b349f5190a082531ec5277ea 100644 (file)
@@ -2,12 +2,12 @@
  *
  * 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.92 2005/10/15 02:49:24 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
@@ -152,6 +151,14 @@ OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
                }
                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;
@@ -169,19 +176,30 @@ OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
                        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 */
@@ -228,7 +246,11 @@ OffsetVarNodes(Node *node, int offset, int sublevels_up)
                        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);
@@ -288,6 +310,15 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
                }
                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;
@@ -307,21 +338,34 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
                        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 */
@@ -370,8 +414,10 @@ ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
                                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,
@@ -437,6 +483,13 @@ IncrementVarSublevelsUp_walker(Node *node,
                        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;
@@ -507,6 +560,15 @@ rangeTableEntry_used_walker(Node *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;
@@ -526,16 +588,11 @@ rangeTableEntry_used_walker(Node *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 */
@@ -715,11 +772,11 @@ AddQual(Query *parsetree, Node *qual)
                /*
                 * There's noplace to put the qual on a utility statement.
                 *
-                * If it's a NOTIFY, silently ignore the qual; this means that the NOTIFY
-                * will execute, whether or not there are any qualifying rows. While
-                * clearly wrong, this is much more useful than refusing to execute
-                * the rule at all, and extra NOTIFY events are harmless for typical
-                * uses of NOTIFY.
+                * If it's a NOTIFY, silently ignore the qual; this means that the
+                * NOTIFY will execute, whether or not there are any qualifying rows.
+                * While clearly wrong, this is much more useful than refusing to
+                * execute the rule at all, and extra NOTIFY events are harmless for
+                * typical uses of NOTIFY.
                 *
                 * If it isn't a NOTIFY, error out, since unconditional execution of
                 * other utility stmts is unlikely to be wanted.  (This case is not
@@ -838,7 +895,14 @@ resolve_one_var(Var *var, ResolveNew_context *context)
                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
@@ -902,8 +966,27 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
                }
                /* 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;
@@ -930,6 +1013,7 @@ ResolveNew(Node *node, int target_varno, int sublevels_up,
                   RangeTblEntry *target_rte,
                   List *targetlist, int event, int update_varno)
 {
+       Node       *result;
        ResolveNew_context context;
 
        context.target_varno = target_varno;
@@ -944,8 +1028,22 @@ ResolveNew(Node *node, int target_varno, int sublevels_up,
         * 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;
 }