mirror of https://github.com/postgres/postgres
Tid access method feature from Hiroshi Inoue, Inoue@tpf.co.jp
parent
54ffd4677a
commit
6f9ff92cc0
@ -0,0 +1,550 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* nodeTidscan.c |
||||
* Routines to support direct tid scans of relations |
||||
* |
||||
* Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.1 1999/11/23 20:06:51 momjian Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
/*
|
||||
* INTERFACE ROUTINES |
||||
* |
||||
* ExecTidScan scans a relation using tids |
||||
* ExecInitTidScan creates and initializes state info. |
||||
* ExecTidReScan rescans the tid relation. |
||||
* ExecEndTidScan releases all storage. |
||||
* ExecTidMarkPos marks scan position. |
||||
* ExecTidRestrPos restores scan position. |
||||
* |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "executor/executor.h" |
||||
#include "executor/execdebug.h" |
||||
#include "executor/nodeTidscan.h" |
||||
#include "optimizer/clauses.h" /* for get_op, get_leftop, get_rightop */ |
||||
#include "access/heapam.h" |
||||
#include "parser/parsetree.h" |
||||
|
||||
static int TidListCreate(List *, ExprContext *, ItemPointer *); |
||||
static TupleTableSlot *TidNext(TidScan *node); |
||||
|
||||
static int |
||||
TidListCreate(List *evalList, ExprContext *econtext, ItemPointer *tidList) |
||||
{ |
||||
List *lst; |
||||
ItemPointer itemptr; |
||||
bool isNull; |
||||
int numTids = 0; |
||||
|
||||
foreach (lst, evalList) |
||||
{ |
||||
itemptr = (ItemPointer)ExecEvalExpr(lfirst(lst), econtext, |
||||
&isNull, (bool *)0); |
||||
if (itemptr && ItemPointerIsValid(itemptr)) |
||||
{ |
||||
tidList[numTids] = itemptr; |
||||
numTids++; |
||||
} |
||||
} |
||||
return numTids; |
||||
} |
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* TidNext |
||||
* |
||||
* Retrieve a tuple from the TidScan node's currentRelation |
||||
* using the tids in the TidScanState information. |
||||
* |
||||
* ---------------------------------------------------------------- |
||||
*/ |
||||
static TupleTableSlot * |
||||
TidNext(TidScan *node) |
||||
{ |
||||
EState *estate; |
||||
CommonScanState *scanstate; |
||||
TidScanState *tidstate; |
||||
ScanDirection direction; |
||||
Snapshot snapshot; |
||||
Relation heapRelation; |
||||
HeapTuple tuple; |
||||
TupleTableSlot *slot; |
||||
Buffer buffer = InvalidBuffer; |
||||
int numTids; |
||||
|
||||
bool bBackward; |
||||
int tidNumber; |
||||
ItemPointer *tidList, itemptr; |
||||
|
||||
/* ----------------
|
||||
* extract necessary information from tid scan node |
||||
* ---------------- |
||||
*/ |
||||
estate = node->scan.plan.state; |
||||
direction = estate->es_direction; |
||||
snapshot = estate->es_snapshot; |
||||
scanstate = node->scan.scanstate; |
||||
tidstate = node->tidstate; |
||||
heapRelation = scanstate->css_currentRelation; |
||||
numTids = tidstate->tss_NumTids; |
||||
tidList = tidstate->tss_TidList; |
||||
slot = scanstate->css_ScanTupleSlot; |
||||
|
||||
/*
|
||||
* Check if we are evaluating PlanQual for tuple of this relation. |
||||
* Additional checking is not good, but no other way for now. We could |
||||
* introduce new nodes for this case and handle TidScan --> NewNode |
||||
* switching in Init/ReScan plan... |
||||
*/ |
||||
if (estate->es_evTuple != NULL && |
||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL) |
||||
{ |
||||
int iptr, numQuals; |
||||
|
||||
ExecClearTuple(slot); |
||||
if (estate->es_evTupleNull[node->scan.scanrelid - 1]) |
||||
return slot; /* return empty slot */ |
||||
|
||||
slot->val = estate->es_evTuple[node->scan.scanrelid - 1]; |
||||
slot->ttc_shouldFree = false; |
||||
/* Flag for the next call that no more tuples */ |
||||
estate->es_evTupleNull[node->scan.scanrelid - 1] = true; |
||||
return (slot); |
||||
} |
||||
|
||||
tuple = &(tidstate->tss_htup); |
||||
|
||||
/* ----------------
|
||||
* ok, now that we have what we need, fetch an tid tuple. |
||||
* if scanning this tid succeeded then return the |
||||
* appropriate heap tuple.. else return NULL. |
||||
* ---------------- |
||||
*/ |
||||
bBackward = ScanDirectionIsBackward(direction); |
||||
if (bBackward) |
||||
{ |
||||
tidNumber = numTids - tidstate->tss_TidPtr - 1; |
||||
if (tidNumber < 0) |
||||
{ |
||||
tidNumber = 0; |
||||
tidstate->tss_TidPtr = numTids - 1; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if ((tidNumber = tidstate->tss_TidPtr) < 0) |
||||
{ |
||||
tidNumber = 0; |
||||
tidstate->tss_TidPtr = 0; |
||||
} |
||||
} |
||||
while (tidNumber < numTids) |
||||
{ |
||||
bool slot_is_valid = false; |
||||
|
||||
itemptr = tidList[tidstate->tss_TidPtr]; |
||||
tuple->t_data = NULL; |
||||
if (itemptr) |
||||
{ |
||||
tuple->t_self = *(itemptr); |
||||
heap_fetch(heapRelation, snapshot, tuple, &buffer); |
||||
} |
||||
if (tuple->t_data != NULL) |
||||
{ |
||||
bool prev_matches = false; |
||||
int prev_tid; |
||||
|
||||
/* ----------------
|
||||
* store the scanned tuple in the scan tuple slot of |
||||
* the scan state. Eventually we will only do this and not |
||||
* return a tuple. Note: we pass 'false' because tuples |
||||
* returned by amgetnext are pointers onto disk pages and |
||||
* were not created with palloc() and so should not be pfree()'d. |
||||
* ---------------- |
||||
*/ |
||||
ExecStoreTuple(tuple, /* tuple to store */ |
||||
slot, /* slot to store in */ |
||||
buffer, /* buffer associated with tuple */ |
||||
false); /* don't pfree */ |
||||
|
||||
/*
|
||||
* At this point we have an extra pin on the buffer, |
||||
* because ExecStoreTuple incremented the pin count. |
||||
* Drop our local pin. |
||||
*/ |
||||
ReleaseBuffer(buffer);
|
||||
/*
|
||||
* We must check to see if the current tuple would have |
||||
* been matched by an earlier tid, so we don't double |
||||
* report it. We do this by passing the tuple through |
||||
* ExecQual and look for failure with all previous |
||||
* qualifications. |
||||
*/ |
||||
for (prev_tid = 0; prev_tid < tidstate->tss_TidPtr; |
||||
prev_tid++) |
||||
{ |
||||
if (ItemPointerEquals(tidList[prev_tid], &tuple->t_self)) |
||||
{ |
||||
prev_matches = true; |
||||
break; |
||||
} |
||||
} |
||||
if (!prev_matches) |
||||
slot_is_valid = true; |
||||
else |
||||
ExecClearTuple(slot); |
||||
} |
||||
else if (BufferIsValid(buffer)) |
||||
ReleaseBuffer(buffer); |
||||
tidNumber++; |
||||
if (bBackward) |
||||
tidstate->tss_TidPtr--; |
||||
else |
||||
tidstate->tss_TidPtr++; |
||||
if (slot_is_valid) |
||||
return slot;
|
||||
} |
||||
/* ----------------
|
||||
* if we get here it means the tid scan failed so we |
||||
* are at the end of the scan.. |
||||
* ---------------- |
||||
*/ |
||||
return ExecClearTuple(slot); |
||||
} |
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecTidScan(node) |
||||
* |
||||
* Scans the relation using tids and returns |
||||
* the next qualifying tuple in the direction specified. |
||||
* It calls ExecScan() and passes it the access methods which returns |
||||
* the next tuple using the tids. |
||||
* |
||||
* Conditions: |
||||
* -- the "cursor" maintained by the AMI is positioned at the tuple |
||||
* returned previously. |
||||
* |
||||
* Initial States: |
||||
* -- the relation indicated is opened for scanning so that the |
||||
* "cursor" is positioned before the first qualifying tuple. |
||||
* -- tidPtr points to the first tid. |
||||
* -- state variable ruleFlag = nil. |
||||
* ---------------------------------------------------------------- |
||||
*/ |
||||
TupleTableSlot * |
||||
ExecTidScan(TidScan *node) |
||||
{ |
||||
/* ----------------
|
||||
* use TidNext as access method |
||||
* ---------------- |
||||
*/ |
||||
return ExecScan(&node->scan, TidNext); |
||||
} |
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecTidReScan(node) |
||||
* ---------------------------------------------------------------- |
||||
*/ |
||||
void |
||||
ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent) |
||||
{ |
||||
EState *estate; |
||||
TidScanState *tidstate; |
||||
Plan *outerPlan; |
||||
ItemPointer *tidList; |
||||
|
||||
tidstate = node->tidstate; |
||||
estate = node->scan.plan.state; |
||||
tidstate->tss_TidPtr = -1; |
||||
tidList = tidstate->tss_TidList; |
||||
|
||||
if ((outerPlan = outerPlan((Plan *) node)) != NULL) |
||||
{ |
||||
/* we are scanning a subplan */ |
||||
outerPlan = outerPlan((Plan *) node); |
||||
ExecReScan(outerPlan, exprCtxt, parent); |
||||
} |
||||
else |
||||
/* otherwise, we are scanning a relation */ |
||||
{ |
||||
/* If this is re-scanning of PlanQual ... */ |
||||
if (estate->es_evTuple != NULL && |
||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL) |
||||
{ |
||||
estate->es_evTupleNull[node->scan.scanrelid - 1] = false; |
||||
return; |
||||
} |
||||
|
||||
/* it's possible in subselects */ |
||||
if (exprCtxt == NULL) |
||||
exprCtxt = node->scan.scanstate->cstate.cs_ExprContext; |
||||
|
||||
node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple = exprCtxt->ecxt_outertuple; |
||||
tidstate->tss_NumTids = TidListCreate(node->tideval, exprCtxt, tidList); |
||||
} |
||||
|
||||
/* ----------------
|
||||
* perhaps return something meaningful |
||||
* ---------------- |
||||
*/ |
||||
return; |
||||
} |
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecEndTidScan |
||||
* |
||||
* Releases any storage allocated through C routines. |
||||
* Returns nothing. |
||||
* ---------------------------------------------------------------- |
||||
*/ |
||||
void |
||||
ExecEndTidScan(TidScan *node) |
||||
{ |
||||
CommonScanState *scanstate; |
||||
TidScanState *tidstate; |
||||
|
||||
scanstate = node->scan.scanstate; |
||||
tidstate = node->tidstate; |
||||
if (tidstate && tidstate->tss_TidList) |
||||
pfree(tidstate->tss_TidList); |
||||
|
||||
/* ----------------
|
||||
* extract information from the node |
||||
* ---------------- |
||||
*/ |
||||
|
||||
/* ----------------
|
||||
* Free the projection info and the scan attribute info |
||||
* |
||||
* Note: we don't ExecFreeResultType(scanstate) |
||||
* because the rule manager depends on the tupType |
||||
* returned by ExecMain(). So for now, this |
||||
* is freed at end-transaction time. -cim 6/2/91 |
||||
* ---------------- |
||||
*/ |
||||
ExecFreeProjectionInfo(&scanstate->cstate); |
||||
|
||||
/* ----------------
|
||||
* close the heap and tid relations |
||||
* ---------------- |
||||
*/ |
||||
ExecCloseR((Plan *) node); |
||||
|
||||
/* ----------------
|
||||
* clear out tuple table slots |
||||
* ---------------- |
||||
*/ |
||||
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot); |
||||
ExecClearTuple(scanstate->css_ScanTupleSlot); |
||||
/* ExecClearTuple(scanstate->css_RawTupleSlot); */ |
||||
} |
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecTidMarkPos |
||||
* |
||||
* Marks scan position by marking the current tid. |
||||
* Returns nothing. |
||||
* ---------------------------------------------------------------- |
||||
*/ |
||||
void |
||||
ExecTidMarkPos(TidScan *node) |
||||
{ |
||||
TidScanState *tidstate; |
||||
|
||||
tidstate = node->tidstate; |
||||
tidstate->tss_MarkTidPtr = tidstate->tss_TidPtr; |
||||
} |
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecTidRestrPos |
||||
* |
||||
* Restores scan position by restoring the current tid. |
||||
* Returns nothing. |
||||
* |
||||
* XXX Assumes previously marked scan position belongs to current tid |
||||
* ---------------------------------------------------------------- |
||||
*/ |
||||
void |
||||
ExecTidRestrPos(TidScan *node) |
||||
{ |
||||
TidScanState *tidstate; |
||||
|
||||
tidstate = node->tidstate; |
||||
tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr; |
||||
} |
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecInitTidScan |
||||
* |
||||
* Initializes the tid scan's state information, creates |
||||
* scan keys, and opens the base and tid relations. |
||||
* |
||||
* Parameters: |
||||
* node: TidNode node produced by the planner. |
||||
* estate: the execution state initialized in InitPlan. |
||||
* ---------------------------------------------------------------- |
||||
*/ |
||||
bool |
||||
ExecInitTidScan(TidScan *node, EState *estate, Plan *parent) |
||||
{ |
||||
TidScanState *tidstate; |
||||
CommonScanState *scanstate; |
||||
ItemPointer *tidList; |
||||
int numTids; |
||||
int tidPtr; |
||||
List *rangeTable; |
||||
RangeTblEntry *rtentry; |
||||
Oid relid; |
||||
Oid reloid; |
||||
|
||||
Relation currentRelation; |
||||
int baseid; |
||||
|
||||
List *execParam = NULL; |
||||
|
||||
/* ----------------
|
||||
* assign execution state to node |
||||
* ---------------- |
||||
*/ |
||||
node->scan.plan.state = estate; |
||||
|
||||
/* --------------------------------
|
||||
* Part 1) initialize scan state |
||||
* |
||||
* create new CommonScanState for node |
||||
* -------------------------------- |
||||
*/ |
||||
scanstate = makeNode(CommonScanState); |
||||
/*
|
||||
scanstate->ss_ProcOuterFlag = false; |
||||
scanstate->ss_OldRelId = 0; |
||||
*/ |
||||
|
||||
node->scan.scanstate = scanstate; |
||||
|
||||
/* ----------------
|
||||
* assign node's base_id .. we don't use AssignNodeBaseid() because |
||||
* the increment is done later on after we assign the tid scan's |
||||
* scanstate. see below. |
||||
* ---------------- |
||||
*/ |
||||
baseid = estate->es_BaseId; |
||||
/* scanstate->csstate.cstate.bnode.base_id = baseid; */ |
||||
scanstate->cstate.cs_base_id = baseid; |
||||
|
||||
/* ----------------
|
||||
* create expression context for node |
||||
* ---------------- |
||||
*/ |
||||
ExecAssignExprContext(estate, &scanstate->cstate); |
||||
|
||||
#define TIDSCAN_NSLOTS 3 |
||||
/* ----------------
|
||||
* tuple table initialization |
||||
* ---------------- |
||||
*/ |
||||
ExecInitResultTupleSlot(estate, &scanstate->cstate); |
||||
ExecInitScanTupleSlot(estate, scanstate); |
||||
/* ExecInitRawTupleSlot(estate, scanstate); */ |
||||
|
||||
/* ----------------
|
||||
* initialize projection info. result type comes from scan desc |
||||
* below.. |
||||
* ---------------- |
||||
*/ |
||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate); |
||||
|
||||
/* --------------------------------
|
||||
* Part 2) initialize tid scan state |
||||
* |
||||
* create new TidScanState for node |
||||
* -------------------------------- |
||||
*/ |
||||
tidstate = makeNode(TidScanState); |
||||
node->tidstate = tidstate; |
||||
|
||||
/* ----------------
|
||||
* assign base id to tid scan state also |
||||
* ---------------- |
||||
*/ |
||||
tidstate->cstate.cs_base_id = baseid; |
||||
baseid++; |
||||
estate->es_BaseId = baseid; |
||||
|
||||
/* ----------------
|
||||
* get the tid node information |
||||
* ---------------- |
||||
*/ |
||||
tidList = (ItemPointer *)palloc(length(node->tideval) * sizeof(ItemPointer)); |
||||
numTids = 0; |
||||
if (!node->needRescan) |
||||
numTids = TidListCreate(node->tideval, scanstate->cstate.cs_ExprContext, tidList); |
||||
tidPtr = -1; |
||||
|
||||
CXT1_printf("ExecInitTidScan: context is %d\n", CurrentMemoryContext); |
||||
|
||||
tidstate->tss_NumTids = numTids; |
||||
tidstate->tss_TidPtr = tidPtr; |
||||
tidstate->tss_TidList = tidList; |
||||
|
||||
/* ----------------
|
||||
* get the range table and direction information |
||||
* from the execution state (these are needed to |
||||
* open the relations). |
||||
* ---------------- |
||||
*/ |
||||
rangeTable = estate->es_range_table; |
||||
|
||||
/* ----------------
|
||||
* open the base relation |
||||
* ---------------- |
||||
*/ |
||||
relid = node->scan.scanrelid; |
||||
rtentry = rt_fetch(relid, rangeTable); |
||||
reloid = rtentry->relid; |
||||
|
||||
currentRelation = heap_open(reloid, AccessShareLock); |
||||
if (currentRelation == NULL) |
||||
elog(ERROR, "ExecInitTidScan heap_open failed.");
|
||||
scanstate->css_currentRelation = currentRelation; |
||||
scanstate->css_currentScanDesc = 0; |
||||
|
||||
/* ----------------
|
||||
* get the scan type from the relation descriptor. |
||||
* ---------------- |
||||
*/ |
||||
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation)); |
||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate); |
||||
|
||||
/* ----------------
|
||||
* tid scans don't have subtrees.. |
||||
* ---------------- |
||||
*/ |
||||
/* scanstate->ss_ProcOuterFlag = false; */ |
||||
|
||||
tidstate->cstate.cs_TupFromTlist = false; |
||||
|
||||
/*
|
||||
* if there are some PARAM_EXEC in skankeys then force tid rescan on |
||||
* first scan. |
||||
*/ |
||||
((Plan *) node)->chgParam = execParam; |
||||
|
||||
/* ----------------
|
||||
* all done. |
||||
* ---------------- |
||||
*/ |
||||
return TRUE; |
||||
} |
||||
|
||||
int |
||||
ExecCountSlotsTidScan(TidScan *node) |
||||
{ |
||||
return ExecCountSlotsNode(outerPlan((Plan *) node)) + |
||||
ExecCountSlotsNode(innerPlan((Plan *) node)) + TIDSCAN_NSLOTS; |
||||
} |
||||
@ -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; |
||||
} |
||||
Loading…
Reference in new issue