297 lines
6.5 KiB
C
297 lines
6.5 KiB
C
|
/*-------------------------------------------------------------------------
|
||
|
*
|
||
|
* tidpath.c
|
||
|
* Routines to determine which tids are usable for scanning a
|
||
|
* given relation, and create TidPaths accordingly.
|
||
|
*
|
||
|
* Copyright (c) 1994, Regents of the University of California
|
||
|
*
|
||
|
*
|
||
|
* IDENTIFICATION
|
||
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/tidpath.c,v 1.1 1999/11/23 20:06:55 momjian Exp $
|
||
|
*
|
||
|
*-------------------------------------------------------------------------
|
||
|
*/
|
||
|
#include <math.h>
|
||
|
|
||
|
#include "postgres.h"
|
||
|
|
||
|
#include "access/heapam.h"
|
||
|
#include "catalog/catname.h"
|
||
|
#include "catalog/pg_amop.h"
|
||
|
#include "catalog/pg_operator.h"
|
||
|
#include "executor/executor.h"
|
||
|
#include "nodes/makefuncs.h"
|
||
|
#include "nodes/nodeFuncs.h"
|
||
|
#include "optimizer/clauses.h"
|
||
|
#include "optimizer/cost.h"
|
||
|
#include "optimizer/pathnode.h"
|
||
|
#include "optimizer/paths.h"
|
||
|
#include "optimizer/plancat.h"
|
||
|
#include "optimizer/restrictinfo.h"
|
||
|
#include "parser/parse_coerce.h"
|
||
|
#include "parser/parse_expr.h"
|
||
|
#include "parser/parse_oper.h"
|
||
|
#include "parser/parsetree.h"
|
||
|
#include "utils/lsyscache.h"
|
||
|
|
||
|
static List *create_tidscan_joinpaths(RelOptInfo *);
|
||
|
static List *TidqualFromRestrictinfo(List *relids, List * restrictinfo);
|
||
|
static bool isEvaluable(int varno, Node *node);
|
||
|
static Node *TidequalClause(int varno, Expr *node);
|
||
|
static List *TidqualFromExpr(int varno, Expr *expr);
|
||
|
|
||
|
static
|
||
|
bool isEvaluable(int varno, Node *node)
|
||
|
{
|
||
|
List *lst;
|
||
|
Expr *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 = (Expr *)node;
|
||
|
foreach (lst, expr->args)
|
||
|
{
|
||
|
if (!isEvaluable(varno, lfirst(lst)))
|
||
|
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, Expr *node)
|
||
|
{
|
||
|
Node *rnode = 0, *arg1, *arg2, *arg;
|
||
|
Oper *oper;
|
||
|
Var *var;
|
||
|
Const *aconst;
|
||
|
Param *param;
|
||
|
Expr *expr;
|
||
|
|
||
|
if (!node->oper) return rnode;
|
||
|
if (!node->args) return rnode;
|
||
|
if (length(node->args) != 2) return rnode;
|
||
|
oper = (Oper *) node->oper;
|
||
|
if (oper->opno != TIDEqualOperator)
|
||
|
return rnode;
|
||
|
arg1 = lfirst(node->args);
|
||
|
arg2 = lsecond(node->args);
|
||
|
|
||
|
arg = (Node *)0;
|
||
|
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_Expr:
|
||
|
expr = (Expr *) arg;
|
||
|
if (expr->typeOid != TIDOID) return rnode;
|
||
|
if (expr->opType != FUNC_EXPR) 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, *lst, *frtn;
|
||
|
Node *node = (Node *) expr, *rnode;
|
||
|
|
||
|
if (is_opclause(node))
|
||
|
{
|
||
|
rnode = TidequalClause(varno, expr);
|
||
|
if (rnode)
|
||
|
{
|
||
|
rlst = lcons(rnode, rlst);
|
||
|
}
|
||
|
}
|
||
|
else if (and_clause(node))
|
||
|
{
|
||
|
foreach (lst, expr->args)
|
||
|
{
|
||
|
node = lfirst(lst);
|
||
|
if (!IsA(node, Expr))
|
||
|
continue;
|
||
|
rlst = TidqualFromExpr(varno, (Expr *)node);
|
||
|
if (rlst)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else if (or_clause(node))
|
||
|
{
|
||
|
foreach (lst, expr->args)
|
||
|
{
|
||
|
node = lfirst(lst);
|
||
|
if (IsA(node, Expr) &&
|
||
|
(frtn = TidqualFromExpr(varno, (Expr *)node)) )
|
||
|
{
|
||
|
rlst = nconc(rlst, frtn);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (rlst)
|
||
|
freeList(rlst);
|
||
|
rlst = NIL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return rlst;
|
||
|
}
|
||
|
|
||
|
static
|
||
|
List *TidqualFromRestrictinfo(List *relids, List * restrictinfo)
|
||
|
{
|
||
|
List *lst, *rlst = NIL;
|
||
|
int varno;
|
||
|
Node *node;
|
||
|
Expr *expr;
|
||
|
|
||
|
if (length(relids)>1) return NIL;
|
||
|
varno = (int)lfirst(relids);
|
||
|
foreach (lst, restrictinfo)
|
||
|
{
|
||
|
node = lfirst(lst);
|
||
|
if (!IsA(node, RestrictInfo)) continue;
|
||
|
expr = ((RestrictInfo *)node)->clause;
|
||
|
rlst = TidqualFromExpr(varno, expr);
|
||
|
if (rlst)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return rlst;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* create_tidscan_joinpaths
|
||
|
* Creates a path corresponding to a tid_direct scan, returning the
|
||
|
* pathnode.
|
||
|
*
|
||
|
*/
|
||
|
List *
|
||
|
create_tidscan_joinpaths(RelOptInfo *rel)
|
||
|
{
|
||
|
List *rlst = NIL, *lst;
|
||
|
TidPath *pathnode = (TidPath *)0;
|
||
|
List *restinfo, *tideval;
|
||
|
|
||
|
foreach (lst, rel->joininfo)
|
||
|
{
|
||
|
JoinInfo *joininfo = (JoinInfo *)lfirst(lst);
|
||
|
restinfo = joininfo->jinfo_restrictinfo;
|
||
|
tideval = TidqualFromRestrictinfo(rel->relids, restinfo);
|
||
|
if (tideval && length(tideval) == 1)
|
||
|
{
|
||
|
pathnode = makeNode(TidPath);
|
||
|
|
||
|
pathnode->path.pathtype = T_TidScan;
|
||
|
pathnode->path.parent = rel;
|
||
|
pathnode->path.path_cost = 0.0;
|
||
|
pathnode->path.pathkeys = NIL;
|
||
|
|
||
|
pathnode->path.path_cost = cost_tidscan(tideval);
|
||
|
pathnode->tideval = tideval;
|
||
|
/*
|
||
|
pathnode->tideval = copyObject(tideval);
|
||
|
freeList(tideval);
|
||
|
*/
|
||
|
pathnode->unjoined_relids = joininfo->unjoined_relids;
|
||
|
rlst = lappend(rlst, pathnode);
|
||
|
}
|
||
|
}
|
||
|
rel->innerjoin = nconc(rel->innerjoin, rlst);
|
||
|
return rlst;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* create_tidscan_paths
|
||
|
* Creates a path corresponding to a tid direct scan, returning the
|
||
|
* pathnode List.
|
||
|
*
|
||
|
*/
|
||
|
List *
|
||
|
create_tidscan_paths(Query *root, RelOptInfo *rel)
|
||
|
{
|
||
|
List *rlst = NIL;
|
||
|
TidPath *pathnode = (TidPath *)0;
|
||
|
List *tideval = TidqualFromRestrictinfo(rel->relids, rel->restrictinfo);
|
||
|
|
||
|
if (tideval)
|
||
|
pathnode = create_tidscan_path(rel, tideval);
|
||
|
if (pathnode)
|
||
|
rlst = lcons(pathnode, rlst);
|
||
|
create_tidscan_joinpaths(rel);
|
||
|
|
||
|
return rlst;
|
||
|
}
|