aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/path/Makefile5
-rw-r--r--src/backend/optimizer/path/allpaths.c9
-rw-r--r--src/backend/optimizer/path/costsize.c26
-rw-r--r--src/backend/optimizer/path/tidpath.c296
-rw-r--r--src/backend/optimizer/plan/createplan.c75
-rw-r--r--src/backend/optimizer/plan/setrefs.c5
-rw-r--r--src/backend/optimizer/plan/subselect.c7
-rw-r--r--src/backend/optimizer/util/pathnode.c28
8 files changed, 442 insertions, 9 deletions
diff --git a/src/backend/optimizer/path/Makefile b/src/backend/optimizer/path/Makefile
index cdc401b8310..5e903ce666d 100644
--- a/src/backend/optimizer/path/Makefile
+++ b/src/backend/optimizer/path/Makefile
@@ -4,7 +4,7 @@
# Makefile for optimizer/path
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/src/backend/optimizer/path/Makefile,v 1.9 1999/08/16 02:17:50 tgl Exp $
+# $Header: /cvsroot/pgsql/src/backend/optimizer/path/Makefile,v 1.10 1999/11/23 20:06:54 momjian Exp $
#
#-------------------------------------------------------------------------
@@ -14,7 +14,8 @@ include ../../../Makefile.global
CFLAGS += -I../..
OBJS = allpaths.o clausesel.o costsize.o indxpath.o \
- joinpath.o joinrels.o orindxpath.o pathkeys.o prune.o
+ joinpath.o joinrels.o orindxpath.o pathkeys.o prune.o \
+ tidpath.o
all: SUBSYS.o
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 23c759bd6e6..3cc8466f77b 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.53 1999/08/16 02:17:50 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.54 1999/11/23 20:06:54 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -108,9 +108,14 @@ set_base_rel_pathlist(Query *root, List *rels)
List *sequential_scan_list;
List *rel_index_scan_list;
List *or_index_scan_list;
+ List *tidscan_pathlist;
sequential_scan_list = lcons(create_seqscan_path(rel), NIL);
-
+ /* Tid Scan Pathlist add */
+ tidscan_pathlist = create_tidscan_paths(root, rel);
+ if (tidscan_pathlist)
+ sequential_scan_list = nconc(sequential_scan_list,
+ tidscan_pathlist);
rel_index_scan_list = create_index_paths(root,
rel,
indices,
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index fcf462b83eb..99ee42cf8c7 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -18,7 +18,7 @@
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.45 1999/08/22 20:14:41 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.46 1999/11/23 20:06:54 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -59,6 +59,7 @@ bool _enable_sort_ = true;
bool _enable_nestloop_ = true;
bool _enable_mergejoin_ = true;
bool _enable_hashjoin_ = true;
+bool _enable_tidscan_ = true;
Cost _cpu_page_weight_ = _CPU_PAGE_WEIGHT_;
Cost _cpu_index_page_weight_ = _CPU_INDEX_PAGE_WEIGHT_;
@@ -175,6 +176,29 @@ cost_index(Oid indexid,
}
/*
+ * cost_tidscan
+ * Determines and returns the cost of scanning a relation using tid-s.
+ *
+ * disk = number of tids
+ * cpu = *CPU-PAGE-WEIGHT* * number_of_tids
+ *
+ * Returns a flonum.
+ *
+ */
+Cost
+cost_tidscan(List *tideval)
+{
+ Cost temp = 0;
+
+ if (!_enable_tidscan_)
+ temp += _disable_cost_;
+
+ temp += (1.0 + _cpu_page_weight_) * length(tideval);
+
+ return temp;
+}
+
+/*
* cost_sort
* Determines and returns the cost of sorting a relation by considering
* the cost of doing an external sort: XXX this is probably too low
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;
+}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index b9742d6fef5..6fda28aa747 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.76 1999/08/22 23:56:44 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.77 1999/11/23 20:06:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -37,6 +37,8 @@ static SeqScan *create_seqscan_node(Path *best_path, List *tlist,
List *scan_clauses);
static IndexScan *create_indexscan_node(IndexPath *best_path, List *tlist,
List *scan_clauses);
+static TidScan *create_tidscan_node(TidPath *best_path, List *tlist,
+ List *scan_clauses);
static NestLoop *create_nestloop_node(NestPath *best_path, List *tlist,
List *clauses, Plan *outer_node, List *outer_tlist,
Plan *inner_node, List *inner_tlist);
@@ -53,6 +55,8 @@ static Node *fix_indxqual_operand(Node *node, IndexPath *index_path,
Form_pg_index index);
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
List *indxid, List *indxqual, List *indxqualorig);
+static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
+ List *tideval);
static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
Plan *righttree);
static HashJoin *make_hashjoin(List *tlist, List *qpqual,
@@ -101,6 +105,7 @@ create_plan(Path *best_path)
{
case T_IndexScan:
case T_SeqScan:
+ case T_TidScan:
plan_node = (Plan *) create_scan_node(best_path, tlist);
break;
case T_HashJoin:
@@ -168,6 +173,12 @@ create_scan_node(Path *best_path, List *tlist)
scan_clauses);
break;
+ case T_TidScan:
+ node = (Scan *) create_tidscan_node((TidPath *) best_path,
+ tlist,
+ scan_clauses);
+ break;
+
default:
elog(ERROR, "create_scan_node: unknown node type",
best_path->pathtype);
@@ -399,6 +410,62 @@ create_indexscan_node(IndexPath *best_path,
return scan_node;
}
+static TidScan *
+make_tidscan(List *qptlist,
+ List *qpqual,
+ Index scanrelid,
+ List *tideval)
+{
+ TidScan *node = makeNode(TidScan);
+ Plan *plan = &node->scan.plan;
+
+ plan->cost = 0;
+ plan->plan_size = 0;
+ plan->plan_width = 0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = qptlist;
+ plan->qual = qpqual;
+ plan->lefttree = NULL;
+ plan->righttree = NULL;
+ node->scan.scanrelid = scanrelid;
+ node->tideval = copyObject(tideval);
+ node->needRescan = false;
+ node->scan.scanstate = (CommonScanState *) NULL;
+
+ return node;
+}
+
+/*
+ * create_tidscan_node
+ * Returns a tidscan node for the base relation scanned by 'best_path'
+ * with restriction clauses 'scan_clauses' and targetlist 'tlist'.
+ */
+static TidScan *
+create_tidscan_node(TidPath *best_path, List *tlist, List *scan_clauses)
+{
+ TidScan *scan_node = (TidScan *) NULL;
+ Index scan_relid = -1;
+ List *temp;
+
+ temp = best_path->path.parent->relids;
+ if (temp == NULL)
+ elog(ERROR, "scanrelid is empty");
+ else if (length(temp) != 1)
+ return scan_node;
+ else
+ scan_relid = (Index) lfirsti(temp);
+ scan_node = make_tidscan(tlist,
+ scan_clauses,
+ scan_relid,
+ best_path->tideval);
+
+ if (best_path->unjoined_relids)
+ scan_node->needRescan = true;
+ scan_node->scan.plan.cost = best_path->path.path_cost;
+
+ return scan_node;
+}
+
/*****************************************************************************
*
* JOIN METHODS
@@ -487,6 +554,12 @@ create_nestloop_node(NestPath *best_path,
innerrel);
}
}
+ else if (IsA(inner_node, TidScan))
+ {
+ List *inner_tideval = ((TidScan *) inner_node)->tideval;
+ TidScan *innerscan = (TidScan *) inner_node;
+ ((TidScan *) inner_node)->tideval = join_references(inner_tideval, outer_tlist, inner_tlist, innerscan->scan.scanrelid);
+ }
else if (IsA_Join(inner_node))
{
/*
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 051c2ea3e3d..ec8c67b7a7a 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.58 1999/10/30 23:07:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.59 1999/11/23 20:06:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -125,6 +125,9 @@ set_plan_references(Plan *plan)
set_plan_references((Plan *) lfirst(pl));
}
break;
+ case T_TidScan:
+ /* nothing special */
+ break;
default:
elog(ERROR, "set_plan_references: unknown plan type %d",
nodeTag(plan));
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 5290c96d5db..d04839afc29 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -6,7 +6,7 @@
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.25 1999/11/15 02:00:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.26 1999/11/23 20:06:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -534,6 +534,11 @@ SS_finalize_plan(Plan *plan)
&results);
break;
+ case T_TidScan:
+ finalize_primnode((Node *) ((TidScan *) plan)->tideval,
+ &results);
+ break;
+
case T_Agg:
case T_SeqScan:
case T_NestLoop:
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index f3b99f88929..0f9bf1b8bbb 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.54 1999/08/16 02:17:58 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.55 1999/11/23 20:07:00 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -319,6 +319,32 @@ create_index_path(Query *root,
}
/*
+ * create_tidscan_path
+ * Creates a path corresponding to a tid_direct scan, returning the
+ * pathnode.
+ *
+ */
+TidPath *
+create_tidscan_path(RelOptInfo *rel, List *tideval)
+{
+ TidPath *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);
+ /* divide selectivity for each clause to get an equal selectivity
+ * as IndexScan does OK ?
+ */
+ pathnode->tideval = copyObject(tideval);
+ pathnode->unjoined_relids = NIL;
+
+ return pathnode;
+}
+
+/*
* create_nestloop_path
* Creates a pathnode corresponding to a nestloop join between two
* relations.