1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-07 19:06:32 +03:00

Tid access method feature from Hiroshi Inoue, Inoue@tpf.co.jp

This commit is contained in:
Bruce Momjian
1999-11-23 20:07:06 +00:00
parent 54ffd4677a
commit 6f9ff92cc0
28 changed files with 1396 additions and 32 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -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_;
@@ -174,6 +175,29 @@ cost_index(Oid indexid,
return temp;
}
/*
* 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

View File

@@ -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;
}

View File

@@ -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))
{
/*

View File

@@ -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));

View File

@@ -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:

View File

@@ -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 $
*
*-------------------------------------------------------------------------
*/
@@ -318,6 +318,32 @@ create_index_path(Query *root,
return pathnode;
}
/*
* 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