diff options
Diffstat (limited to 'src/backend/optimizer/path/tidpath.c')
-rw-r--r-- | src/backend/optimizer/path/tidpath.c | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c new file mode 100644 index 00000000000..9e618f7a872 --- /dev/null +++ b/src/backend/optimizer/path/tidpath.c @@ -0,0 +1,296 @@ +/*------------------------------------------------------------------------- + * + * 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; +} |