Commit e331404d authored by Tom Lane's avatar Tom Lane

Clean up some very old and crufty code for TID scan planning. Not much

functional difference really, but make use of stuff added to the planner
since this code was touched last.
parent a970a8cb
/*-------------------------------------------------------------------------
*
* 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));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment