Clean up some very old and crufty code for TID scan planning. Not much
authorTom Lane
Tue, 23 Aug 2005 20:49:47 +0000 (20:49 +0000)
committerTom Lane
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 
-
+#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));