postgresql/src/backend/optimizer/path/tidpath.c

239 lines
5.1 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* tidpath.c
* Routines to determine which tids are usable for scanning a
* given relation, and create TidPaths accordingly.
*
2003-08-04 04:40:20 +02:00
* Portions Copyright (c) 1996-2003, 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.19 2004/05/26 04:41:22 neilc Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <math.h>
#include "catalog/pg_operator.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"
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 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
*/
static Node *
TidequalClause(int varno, OpExpr *node)
{
Node *rnode = NULL,
*arg1,
*arg2,
*arg;
Var *var;
Const *aconst;
Param *param;
FuncExpr *expr;
if (node->opno != TIDEqualOperator)
return rnode;
if (length(node->args) != 2)
return rnode;
arg1 = linitial(node->args);
arg2 = lsecond(node->args);
arg = NULL;
if (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 ((!arg) && IsA(arg2, Var))
{
var = (Var *) arg2;
if (var->varno == varno &&
var->varattno == SelfItemPointerAttributeNumber &&
var->vartype == TIDOID)
arg = 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;
}
/*
* 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.
*/
static List *
TidqualFromExpr(int varno, Expr *expr)
{
List *rlst = NIL,
*frtn;
ListCell *l;
Node *node = (Node *) expr,
*rnode;
if (is_opclause(node))
{
rnode = TidequalClause(varno, (OpExpr *) expr);
if (rnode)
rlst = lcons(rnode, rlst);
}
else if (and_clause(node))
{
foreach(l, ((BoolExpr *) expr)->args)
{
node = (Node *) lfirst(l);
rlst = TidqualFromExpr(varno, (Expr *) node);
if (rlst)
break;
}
}
else if (or_clause(node))
{
foreach(l, ((BoolExpr *) expr)->args)
{
node = (Node *) lfirst(l);
frtn = TidqualFromExpr(varno, (Expr *) node);
if (frtn)
rlst = nconc(rlst, frtn);
else
{
if (rlst)
freeList(rlst);
rlst = NIL;
break;
}
}
}
return rlst;
}
static List *
TidqualFromRestrictinfo(Relids relids, List *restrictinfo)
{
ListCell *l;
List *rlst = NIL;
int varno;
Node *node;
Expr *expr;
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);
if (rlst)
break;
}
return rlst;
}
/*
* create_tidscan_paths
* Creates paths corresponding to tid direct scans of the given rel.
* Candidate paths are added to the rel's pathlist (using add_path).
*/
void
create_tidscan_paths(Query *root, RelOptInfo *rel)
{
List *tideval = TidqualFromRestrictinfo(rel->relids,
rel->baserestrictinfo);
if (tideval)
add_path(rel, (Path *) create_tidscan_path(root, rel, tideval));
}