]> granicus.if.org Git - postgresql/commitdiff
Clean up some very old and crufty code for TID scan planning. Not much
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Aug 2005 20:49:47 +0000 (20:49 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Aug 2005 20:49:47 +0000 (20:49 +0000)
functional difference really, but make use of stuff added to the planner
since this code was touched last.

src/backend/optimizer/path/tidpath.c

index 239e20c96358638e7ddcfdbe90644b8b2aec226b..348524372e113de46f8f33902b83526c0d9ff34f 100644 (file)
 /*-------------------------------------------------------------------------
  *
  * tidpath.c
- *       Routines to determine which tids are usable for scanning a
- *       given relation, and create TidPaths accordingly.
+ *       Routines to determine which TID conditions are usable for scanning
+ *       a given relation, and create TidPaths accordingly.
+ *
+ * What we are looking for here is WHERE conditions of the form
+ * "CTID = pseudoconstant", which can be implemented by just fetching
+ * the tuple directly via heap_fetch().  We can also handle OR conditions
+ * if each OR arm contains such a condition; in particular this allows
+ *             WHERE ctid IN (tid1, tid2, ...)
+ *
+ * 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
+ * doesn't seem to be enough use-case to justify adding a lot of code
+ * for that.
+ *
  *
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/tidpath.c,v 1.23 2005/06/05 22:32:55 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/tidpath.c,v 1.24 2005/08/23 20:49:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
-#include <math.h>
-
+#include "access/htup.h"
 #include "catalog/pg_operator.h"
+#include "catalog/pg_type.h"
 #include "optimizer/clauses.h"
-#include "optimizer/cost.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
-#include "parser/parse_coerce.h"
-#include "utils/lsyscache.h"
-
+#include "parser/parse_expr.h"
 
-static List *TidqualFromRestrictinfo(Relids relids, List *restrictinfo);
-static bool isEvaluable(int varno, Node *node);
-static Node *TidequalClause(int varno, OpExpr *node);
-static List *TidqualFromExpr(int varno, Expr *expr);
 
+static Node *IsTidEqualClause(int varno, OpExpr *node);
+static List *TidQualFromExpr(int varno, Node *expr);
+static List *TidQualFromRestrictinfo(int varno, List *restrictinfo);
 
-static bool
-isEvaluable(int varno, Node *node)
-{
-       ListCell   *l;
-       FuncExpr   *expr;
-
-       if (IsA(node, Const))
-               return true;
-       if (IsA(node, Param))
-               return true;
-       if (IsA(node, Var))
-       {
-               Var                *var = (Var *) node;
-
-               if (var->varno == varno)
-                       return false;
-               return true;
-       }
-       if (!is_funcclause(node))
-               return false;
-       expr = (FuncExpr *) node;
-       foreach(l, expr->args)
-       {
-               if (!isEvaluable(varno, lfirst(l)))
-                       return false;
-       }
-
-       return true;
-}
 
 /*
- *     The 2nd parameter should be an opclause
- *     Extract the right node if the opclause is CTID= ....
- *       or    the left  node if the opclause is ....=CTID
+ * Check to see if an opclause is of the form
+ *             CTID = pseudoconstant
+ * or
+ *             pseudoconstant = CTID
+ *
+ * If it is, return the pseudoconstant subnode; if not, return NULL.
+ *
+ * We check that the CTID Var belongs to relation "varno".  That is probably
+ * redundant considering this is only applied to restriction clauses, but
+ * let's be safe.
  */
 static Node *
-TidequalClause(int varno, OpExpr *node)
+IsTidEqualClause(int varno, OpExpr *node)
 {
-       Node       *rnode = NULL,
-                          *arg1,
+       Node       *arg1,
                           *arg2,
-                          *arg;
+                          *other;
        Var                *var;
-       Const      *aconst;
-       Param      *param;
-       FuncExpr   *expr;
 
+       /* Operator must be tideq */
        if (node->opno != TIDEqualOperator)
-               return rnode;
+               return NULL;
        if (list_length(node->args) != 2)
-               return rnode;
+               return NULL;
        arg1 = linitial(node->args);
        arg2 = lsecond(node->args);
 
-       arg = NULL;
-       if (IsA(arg1, Var))
+       /* Look for CTID as either argument */
+       other = NULL;
+       if (arg1 && IsA(arg1, Var))
        {
                var = (Var *) arg1;
-               if (var->varno == varno &&
-                       var->varattno == SelfItemPointerAttributeNumber &&
-                       var->vartype == TIDOID)
-                       arg = arg2;
-               else if (var->varnoold == varno &&
-                                var->varoattno == SelfItemPointerAttributeNumber &&
-                                var->vartype == TIDOID)
-                       arg = arg2;
+               if (var->varattno == SelfItemPointerAttributeNumber &&
+                       var->vartype == TIDOID &&
+                       var->varno == varno &&
+                       var->varlevelsup == 0)
+                       other = arg2;
        }
-       if ((!arg) && IsA(arg2, Var))
+       if (!other && arg2 && IsA(arg2, Var))
        {
                var = (Var *) arg2;
-               if (var->varno == varno &&
-                       var->varattno == SelfItemPointerAttributeNumber &&
-                       var->vartype == TIDOID)
-                       arg = arg1;
+               if (var->varattno == SelfItemPointerAttributeNumber &&
+                       var->vartype == TIDOID &&
+                       var->varno == varno &&
+                       var->varlevelsup == 0)
+                       other = arg1;
        }
-       if (!arg)
-               return rnode;
-       switch (nodeTag(arg))
-       {
-               case T_Const:
-                       aconst = (Const *) arg;
-                       if (aconst->consttype != TIDOID)
-                               return rnode;
-                       if (aconst->constbyval)
-                               return rnode;
-                       rnode = arg;
-                       break;
-               case T_Param:
-                       param = (Param *) arg;
-                       if (param->paramtype != TIDOID)
-                               return rnode;
-                       rnode = arg;
-                       break;
-               case T_Var:
-                       var = (Var *) arg;
-                       if (var->varno == varno ||
-                               var->vartype != TIDOID)
-                               return rnode;
-                       rnode = arg;
-                       break;
-               case T_FuncExpr:
-                       expr = (FuncExpr *) arg;
-                       if (expr->funcresulttype != TIDOID)
-                               return rnode;
-                       if (isEvaluable(varno, (Node *) expr))
-                               rnode = arg;
-                       break;
-               default:
-                       break;
-       }
-       return rnode;
+       if (!other)
+               return NULL;
+       if (exprType(other) != TIDOID)
+               return NULL;                    /* probably can't happen */
+
+       /* The other argument must be a pseudoconstant */
+       if (!is_pseudo_constant_clause(other))
+               return NULL;
+
+       return other;                           /* success */
 }
 
 /*
- *     Extract the list of CTID values from a specified expr node.
- *     When the expr node is an or_clause,we try to extract CTID
- *     values from all member nodes. However we would discard them
- *     all if we couldn't extract CTID values from a member node.
- *     When the expr node is an and_clause,we return the list of
- *     CTID values if we could extract the CTID values from a member
- *     node.
+ *     Extract a set of CTID conditions from the given qual expression
+ *
+ *     If the expression is an AND clause, we can use a CTID condition
+ *     from any sub-clause.  If it is an OR clause, we must be able to
+ *     extract a CTID condition from every sub-clause, or we can't use it.
+ *
+ *     In theory, in the AND case we could get CTID conditions from different
+ *     sub-clauses, in which case we could try to pick the most efficient one.
+ *     In practice, such usage seems very unlikely, so we don't bother; we
+ *     just exit as soon as we find the first candidate.
+ *
+ *     Returns a List of pseudoconstant TID expressions, or NIL if no match.
+ *     (Has to be a list for the OR case.)
  */
 static List *
-TidqualFromExpr(int varno, Expr *expr)
+TidQualFromExpr(int varno, Node *expr)
 {
        List       *rlst = NIL,
                           *frtn;
        ListCell   *l;
-       Node       *node = (Node *) expr,
-                          *rnode;
+       Node       *rnode;
 
-       if (is_opclause(node))
+       if (is_opclause(expr))
        {
-               rnode = TidequalClause(varno, (OpExpr *) expr);
+               /* base case: check for tideq opclause */
+               rnode = IsTidEqualClause(varno, (OpExpr *) expr);
                if (rnode)
-                       rlst = lcons(rnode, rlst);
+                       rlst = list_make1(rnode);
        }
-       else if (and_clause(node))
+       else if (and_clause(expr))
        {
                foreach(l, ((BoolExpr *) expr)->args)
                {
-                       node = (Node *) lfirst(l);
-                       rlst = TidqualFromExpr(varno, (Expr *) node);
+                       rlst = TidQualFromExpr(varno, (Node *) lfirst(l));
                        if (rlst)
                                break;
                }
        }
-       else if (or_clause(node))
+       else if (or_clause(expr))
        {
                foreach(l, ((BoolExpr *) expr)->args)
                {
-                       node = (Node *) lfirst(l);
-                       frtn = TidqualFromExpr(varno, (Expr *) node);
+                       frtn = TidQualFromExpr(varno, (Node *) lfirst(l));
                        if (frtn)
                                rlst = list_concat(rlst, frtn);
                        else
@@ -199,25 +160,25 @@ TidqualFromExpr(int varno, Expr *expr)
        return rlst;
 }
 
+/*
+ *     Extract a set of CTID conditions from the given restrictinfo list
+ *
+ *     This is essentially identical to the AND case of TidQualFromExpr,
+ *     except for the format of the input.
+ */
 static List *
-TidqualFromRestrictinfo(Relids relids, List *restrictinfo)
+TidQualFromRestrictinfo(int varno, List *restrictinfo)
 {
-       ListCell   *l;
        List       *rlst = NIL;
-       int                     varno;
-       Node       *node;
-       Expr       *expr;
+       ListCell   *l;
 
-       if (bms_membership(relids) != BMS_SINGLETON)
-               return NIL;
-       varno = bms_singleton_member(relids);
        foreach(l, restrictinfo)
        {
-               node = (Node *) lfirst(l);
-               if (!IsA(node, RestrictInfo))
-                       continue;
-               expr = ((RestrictInfo *) node)->clause;
-               rlst = TidqualFromExpr(varno, expr);
+               RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
+
+               if (!IsA(rinfo, RestrictInfo))
+                       continue;                       /* probably should never happen */
+               rlst = TidQualFromExpr(varno, (Node *) rinfo->clause);
                if (rlst)
                        break;
        }
@@ -226,14 +187,16 @@ TidqualFromRestrictinfo(Relids relids, List *restrictinfo)
 
 /*
  * create_tidscan_paths
- *       Creates paths corresponding to tid direct scans of the given rel.
+ *       Create paths corresponding to direct TID scans of the given rel.
+ *
  *       Candidate paths are added to the rel's pathlist (using add_path).
  */
 void
 create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel)
 {
-       List       *tideval = TidqualFromRestrictinfo(rel->relids,
-                                                                                                 rel->baserestrictinfo);
+       List       *tideval;
+
+       tideval = TidQualFromRestrictinfo(rel->relid, rel->baserestrictinfo);
 
        if (tideval)
                add_path(rel, (Path *) create_tidscan_path(root, rel, tideval));