Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
0a2e5cdf
Commit
0a2e5cdf
authored
Aug 01, 1998
by
Bruce Momjian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow index use with OR clauses.
parent
0668aa88
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
287 additions
and
316 deletions
+287
-316
src/backend/executor/execQual.c
src/backend/executor/execQual.c
+1
-3
src/backend/executor/nodeIndexscan.c
src/backend/executor/nodeIndexscan.c
+118
-107
src/backend/nodes/copyfuncs.c
src/backend/nodes/copyfuncs.c
+6
-6
src/backend/nodes/equalfuncs.c
src/backend/nodes/equalfuncs.c
+17
-1
src/backend/nodes/outfuncs.c
src/backend/nodes/outfuncs.c
+3
-3
src/backend/nodes/readfuncs.c
src/backend/nodes/readfuncs.c
+4
-4
src/backend/optimizer/path/clausesel.c
src/backend/optimizer/path/clausesel.c
+3
-14
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/path/indxpath.c
+92
-127
src/backend/optimizer/path/orindxpath.c
src/backend/optimizer/path/orindxpath.c
+43
-51
No files found.
src/backend/executor/execQual.c
View file @
0a2e5cdf
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.3
3 1998/06/15 19:28:19
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.3
4 1998/08/01 22:12:02
momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -1349,8 +1349,6 @@ ExecQual(List *qual, ExprContext *econtext)
foreach
(
clause
,
qual
)
{
result
=
ExecQualClause
((
Node
*
)
lfirst
(
clause
),
econtext
);
if
(
result
==
true
)
break
;
...
...
src/backend/executor/nodeIndexscan.c
View file @
0a2e5cdf
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.
19 1998/07/27 19:37:57 vadim
Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.
20 1998/08/01 22:12:04 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -87,7 +87,6 @@ IndexNext(IndexScan *node)
IndexScanState
*
indexstate
;
ScanDirection
direction
;
Snapshot
snapshot
;
int
indexPtr
;
IndexScanDescPtr
scanDescs
;
IndexScanDesc
scandesc
;
Relation
heapRelation
;
...
...
@@ -95,7 +94,8 @@ IndexNext(IndexScan *node)
HeapTuple
tuple
;
TupleTableSlot
*
slot
;
Buffer
buffer
=
InvalidBuffer
;
int
numIndices
;
/* ----------------
* extract necessary information from index scan node
* ----------------
...
...
@@ -105,54 +105,66 @@ IndexNext(IndexScan *node)
snapshot
=
estate
->
es_snapshot
;
scanstate
=
node
->
scan
.
scanstate
;
indexstate
=
node
->
indxstate
;
indexPtr
=
indexstate
->
iss_IndexPtr
;
scanDescs
=
indexstate
->
iss_ScanDescs
;
scandesc
=
scanDescs
[
indexPtr
];
heapRelation
=
scanstate
->
css_currentRelation
;
numIndices
=
indexstate
->
iss_NumIndices
;
slot
=
scanstate
->
css_ScanTupleSlot
;
/* ----------------
* ok, now that we have what we need, fetch an index tuple.
* ----------------
*/
/* ----------------
* if scanning this index succeeded then return the
* appropriate heap tuple.. else return NULL.
* ----------------
*/
while
(
(
result
=
index_getnext
(
scandesc
,
direction
))
!=
NULL
)
while
(
indexstate
->
iss_IndexPtr
<
numIndices
)
{
tuple
=
heap_fetch
(
heapRelation
,
snapshot
,
&
result
->
heap_iptr
,
&
buffer
);
/* be tidy */
pfree
(
result
);
if
(
tuple
!=
NULL
)
{
/* ----------------
* 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 */
return
slot
;
}
else
scandesc
=
scanDescs
[
indexstate
->
iss_IndexPtr
];
while
((
result
=
index_getnext
(
scandesc
,
direction
))
!=
NULL
)
{
tuple
=
heap_fetch
(
heapRelation
,
snapshot
,
&
result
->
heap_iptr
,
&
buffer
);
/* be tidy */
pfree
(
result
);
if
(
tuple
!=
NULL
)
{
bool
prev_matches
=
false
;
int
prev_index
;
/* ----------------
* 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 */
for
(
prev_index
=
0
;
prev_index
<
indexstate
->
iss_IndexPtr
;
prev_index
++
)
{
if
(
ExecQual
(
nth
(
prev_index
,
node
->
indxqual
),
scanstate
->
cstate
.
cs_ExprContext
))
{
prev_matches
=
true
;
break
;
}
}
if
(
!
prev_matches
)
return
slot
;
else
ExecClearTuple
(
slot
);
}
if
(
BufferIsValid
(
buffer
))
ReleaseBuffer
(
buffer
);
}
if
(
indexstate
->
iss_IndexPtr
<
numIndices
)
indexstate
->
iss_IndexPtr
++
;
}
/* ----------------
* if we get here it means the index scan failed so we
* are at the end of the scan..
...
...
@@ -218,7 +230,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
int
i
;
Pointer
*
runtimeKeyInfo
;
int
indexPtr
;
int
*
numScanKeys
;
List
*
indxqual
;
List
*
qual
;
...
...
@@ -238,69 +249,62 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
numIndices
=
indexstate
->
iss_NumIndices
;
scanDescs
=
indexstate
->
iss_ScanDescs
;
scanKeys
=
indexstate
->
iss_ScanKeys
;
runtimeKeyInfo
=
(
Pointer
*
)
indexstate
->
iss_RuntimeKeyInfo
;
indxqual
=
node
->
indxqual
;
numScanKeys
=
indexstate
->
iss_NumScanKeys
;
indexstate
->
iss_IndexPtr
=
0
;
/* it's possible in subselects */
if
(
exprCtxt
==
NULL
)
exprCtxt
=
node
->
scan
.
scanstate
->
cstate
.
cs_ExprContext
;
if
(
runtimeKeyInfo
!=
NULL
)
{
/*
* get the index qualifications and recalculate the appropriate
* values
*/
indexPtr
=
indexstate
->
iss_IndexPtr
;
indxqual
=
node
->
indxqual
;
qual
=
nth
(
indexPtr
,
indxqual
);
numScanKeys
=
indexstate
->
iss_NumScanKeys
;
n_keys
=
numScanKeys
[
indexPtr
];
run_keys
=
(
int
*
)
runtimeKeyInfo
[
indexPtr
];
scan_keys
=
(
ScanKey
)
scanKeys
[
indexPtr
];
if
(
exprCtxt
!=
NULL
)
node
->
scan
.
scanstate
->
cstate
.
cs_ExprContext
->
ecxt_outertuple
=
exprCtxt
->
ecxt_outertuple
;
/* it's possible in subselects */
if
(
exprCtxt
==
NULL
)
exprCtxt
=
node
->
scan
.
scanstate
->
cstate
.
cs_ExprContext
;
for
(
j
=
0
;
j
<
n_keys
;
j
++
)
/*
* get the index qualifications and recalculate the appropriate
* values
*/
for
(
i
=
0
;
i
<
numIndices
;
i
++
)
{
if
(
runtimeKeyInfo
&&
runtimeKeyInfo
[
i
]
!=
NULL
)
{
/*
* If we have a run-time key, then extract the run-time
* expression and evaluate it with respect to the current
* outer tuple. We then stick the result into the scan key.
*/
if
(
run_keys
[
j
]
!=
NO_OP
)
qual
=
nth
(
i
,
indxqual
);
n_keys
=
numScanKeys
[
i
];
run_keys
=
(
int
*
)
runtimeKeyInfo
[
i
];
scan_keys
=
(
ScanKey
)
scanKeys
[
i
];
for
(
j
=
0
;
j
<
n_keys
;
j
++
)
{
clause
=
nth
(
j
,
qual
);
scanexpr
=
(
run_keys
[
j
]
==
RIGHT_OP
)
?
(
Node
*
)
get_rightop
(
clause
)
:
(
Node
*
)
get_leftop
(
clause
);
/*
* pass in isDone but ignore it. We don't iterate in
* quals
* If we have a run-time key, then extract the run-time
* expression and evaluate it with respect to the current
* outer tuple. We then stick the result into the scan key.
*/
scanvalue
=
(
Datum
)
ExecEvalExpr
(
scanexpr
,
exprCtxt
,
&
isNull
,
&
isDone
);
scan_keys
[
j
].
sk_argument
=
scanvalue
;
if
(
isNull
)
scan_keys
[
j
].
sk_flags
|=
SK_ISNULL
;
else
scan_keys
[
j
].
sk_flags
&=
~
SK_ISNULL
;
if
(
run_keys
[
j
]
!=
NO_OP
)
{
clause
=
nth
(
j
,
qual
);
scanexpr
=
(
run_keys
[
j
]
==
RIGHT_OP
)
?
(
Node
*
)
get_rightop
(
clause
)
:
(
Node
*
)
get_leftop
(
clause
);
/*
* pass in isDone but ignore it. We don't iterate in
* quals
*/
scanvalue
=
(
Datum
)
ExecEvalExpr
(
scanexpr
,
exprCtxt
,
&
isNull
,
&
isDone
);
scan_keys
[
j
].
sk_argument
=
scanvalue
;
if
(
isNull
)
scan_keys
[
j
].
sk_flags
|=
SK_ISNULL
;
else
scan_keys
[
j
].
sk_flags
&=
~
SK_ISNULL
;
}
}
sdesc
=
scanDescs
[
i
];
skey
=
scanKeys
[
i
];
index_rescan
(
sdesc
,
direction
,
skey
);
}
}
/*
* rescans all indices
*
* note: AMrescan assumes only one scan key. This may have to change if
* we ever decide to support multiple keys.
*/
for
(
i
=
0
;
i
<
numIndices
;
i
++
)
{
sdesc
=
scanDescs
[
i
];
skey
=
scanKeys
[
i
];
index_rescan
(
sdesc
,
direction
,
skey
);
}
/* ----------------
* perhaps return something meaningful
...
...
@@ -322,19 +326,23 @@ ExecEndIndexScan(IndexScan *node)
{
CommonScanState
*
scanstate
;
IndexScanState
*
indexstate
;
Pointer
*
runtimeKeyInfo
;
ScanKey
*
scanKeys
;
int
*
numScanKeys
;
int
numIndices
;
int
i
;
scanstate
=
node
->
scan
.
scanstate
;
indexstate
=
node
->
indxstate
;
runtimeKeyInfo
=
(
Pointer
*
)
indexstate
->
iss_RuntimeKeyInfo
;
/* ----------------
* extract information from the node
* ----------------
*/
numIndices
=
indexstate
->
iss_NumIndices
;
scanKeys
=
indexstate
->
iss_ScanKeys
;
numScanKeys
=
indexstate
->
iss_NumScanKeys
;
/* ----------------
* Free the projection info and the scan attribute info
...
...
@@ -362,7 +370,24 @@ ExecEndIndexScan(IndexScan *node)
if
(
scanKeys
[
i
]
!=
NULL
)
pfree
(
scanKeys
[
i
]);
}
pfree
(
scanKeys
);
pfree
(
numScanKeys
);
if
(
runtimeKeyInfo
)
{
for
(
i
=
0
;
i
<
numIndices
;
i
++
)
{
List
*
qual
;
int
n_keys
;
qual
=
nth
(
i
,
indxqual
);
n_keys
=
length
(
qual
);
if
(
n_keys
>
0
)
pfree
(
runtimeKeyInfo
[
i
]);
}
pfree
(
runtimeKeyInfo
);
}
/* ----------------
* clear out tuple table slots
* ----------------
...
...
@@ -430,7 +455,7 @@ ExecIndexRestrPos(IndexScan *node)
/* ----------------------------------------------------------------
* ExecInitIndexScan
*
*
* Initializes the index scan's state information, creates
* scan keys, and opens the base and index relations.
*
...
...
@@ -886,20 +911,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
if
(
have_runtime_keys
)
indexstate
->
iss_RuntimeKeyInfo
=
(
Pointer
)
runtimeKeyInfo
;
else
{
indexstate
->
iss_RuntimeKeyInfo
=
NULL
;
for
(
i
=
0
;
i
<
numIndices
;
i
++
)
{
List
*
qual
;
int
n_keys
;
qual
=
nth
(
i
,
indxqual
);
n_keys
=
length
(
qual
);
if
(
n_keys
>
0
)
pfree
(
runtimeKeyInfo
[
i
]);
}
pfree
(
runtimeKeyInfo
);
}
/* ----------------
* get the range table and direction information
...
...
@@ -991,6 +1003,5 @@ int
ExecCountSlotsIndexScan
(
IndexScan
*
node
)
{
return
ExecCountSlotsNode
(
outerPlan
((
Plan
*
)
node
))
+
ExecCountSlotsNode
(
innerPlan
((
Plan
*
)
node
))
+
INDEXSCAN_NSLOTS
;
ExecCountSlotsNode
(
innerPlan
((
Plan
*
)
node
))
+
INDEXSCAN_NSLOTS
;
}
src/backend/nodes/copyfuncs.c
View file @
0a2e5cdf
/*-------------------------------------------------------------------------
/*-------------------------------------------------------------------------
*
* copyfuncs.c--
* Copy functions for Postgres tree nodes.
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.4
4 1998/07/18 04:22:2
5 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.4
5 1998/08/01 22:12:0
5 momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -990,16 +990,16 @@ _copyArrayRef(ArrayRef *from)
*/
/* ----------------
* _copyRel
* _copyRel
OptInfo
* ----------------
*/
/*
** when you change this, also make sure to fix up xfunc_copyRel in
** when you change this, also make sure to fix up xfunc_copyRel
OptInfo
in
** planner/path/xfunc.c accordingly!!!
** -- JMH, 8/2/93
*/
static
RelOptInfo
*
_copyRel
(
RelOptInfo
*
from
)
_copyRel
OptInfo
(
RelOptInfo
*
from
)
{
RelOptInfo
*
newnode
=
makeNode
(
RelOptInfo
);
int
i
,
...
...
@@ -1735,7 +1735,7 @@ copyObject(void *from)
* RELATION NODES
*/
case
T_RelOptInfo
:
retval
=
_copyRel
(
from
);
retval
=
_copyRel
OptInfo
(
from
);
break
;
case
T_Path
:
retval
=
_copyPath
(
from
);
...
...
src/backend/nodes/equalfuncs.c
View file @
0a2e5cdf
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.1
6 1998/02/26 04:3
2:07 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.1
7 1998/08/01 22:1
2:07 momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -302,6 +302,19 @@ _equalCInfo(CInfo *a, CInfo *b)
(
b
->
indexids
)));
}
/*
* RelOptInfo is a subclass of Node.
*/
static
bool
_equalRelOptInfo
(
RelOptInfo
*
a
,
RelOptInfo
*
b
)
{
Assert
(
IsA
(
a
,
RelOptInfo
));
Assert
(
IsA
(
b
,
RelOptInfo
));
return
(
equal
((
a
->
relids
),
(
b
->
relids
)));
}
static
bool
_equalJoinMethod
(
JoinMethod
*
a
,
JoinMethod
*
b
)
{
...
...
@@ -663,6 +676,9 @@ equal(void *a, void *b)
case
T_CInfo
:
retval
=
_equalCInfo
(
a
,
b
);
break
;
case
T_RelOptInfo
:
retval
=
_equalRelOptInfo
(
a
,
b
);
break
;
case
T_JoinMethod
:
retval
=
_equalJoinMethod
(
a
,
b
);
break
;
...
...
src/backend/nodes/outfuncs.c
View file @
0a2e5cdf
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.4
1 1998/07/18 04:22:26
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.4
2 1998/08/01 22:12:08
momjian Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
...
...
@@ -990,7 +990,7 @@ _outEState(StringInfo str, EState *node)
* Stuff from relation.h
*/
static
void
_outRel
(
StringInfo
str
,
RelOptInfo
*
node
)
_outRel
OptInfo
(
StringInfo
str
,
RelOptInfo
*
node
)
{
char
buf
[
500
];
...
...
@@ -1788,7 +1788,7 @@ _outNode(StringInfo str, void *obj)
_outEState
(
str
,
obj
);
break
;
case
T_RelOptInfo
:
_outRel
(
str
,
obj
);
_outRel
OptInfo
(
str
,
obj
);
break
;
case
T_TargetEntry
:
_outTargetEntry
(
str
,
obj
);
...
...
src/backend/nodes/readfuncs.c
View file @
0a2e5cdf
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.3
3 1998/07/18 04:22:26
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.3
4 1998/08/01 22:12:09
momjian Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
...
...
@@ -1218,11 +1218,11 @@ _readEState()
*/
/* ----------------
* _readRel
* _readRel
OptInfo
* ----------------
*/
static
RelOptInfo
*
_readRel
()
_readRel
OptInfo
()
{
RelOptInfo
*
local_node
;
char
*
token
;
...
...
@@ -1991,7 +1991,7 @@ parsePlanString(void)
else
if
(
!
strncmp
(
token
,
"ESTATE"
,
length
))
return_value
=
_readEState
();
else
if
(
!
strncmp
(
token
,
"RELOPTINFO"
,
length
))
return_value
=
_readRel
();
return_value
=
_readRel
OptInfo
();
else
if
(
!
strncmp
(
token
,
"TARGETENTRY"
,
length
))
return_value
=
_readTargetEntry
();
else
if
(
!
strncmp
(
token
,
"RTE"
,
length
))
...
...
src/backend/optimizer/path/clausesel.c
View file @
0a2e5cdf
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.
9 1998/07/18 04:22:30
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.
10 1998/08/01 22:12:11
momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -159,19 +159,8 @@ set_rest_selec(Query *root, List *clauseinfo_list)
Cost
compute_clause_selec
(
Query
*
root
,
Node
*
clause
,
List
*
or_selectivities
)
{
if
(
!
is_opclause
(
clause
))
{
/*
* if it's not an operator clause, then it is a boolean clause
* -jolly
*/
/*
* Boolean variables get a selectivity of 1/2.
*/
return
(
0
.
1
);
}
if
(
is_opclause
(
clause
))
return
compute_selec
(
root
,
lcons
(
clause
,
NIL
),
or_selectivities
);
else
if
(
not_clause
(
clause
))
{
...
...
src/backend/optimizer/path/indxpath.c
View file @
0a2e5cdf
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.
19 1998/07/31 15:10:40 vadim
Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.
20 1998/08/01 22:12:12 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -21,6 +21,7 @@
#include "access/nbtree.h"
#include "catalog/catname.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "fmgr.h"
#include "nodes/makefuncs.h"
...
...
@@ -77,10 +78,7 @@ create_index_paths(Query *root, RelOptInfo *rel, RelOptInfo *index,
List
*
clausegroup_list
,
bool
join
);
static
List
*
add_index_paths
(
List
*
indexpaths
,
List
*
new_indexpaths
);
static
bool
function_index_operand
(
Expr
*
funcOpnd
,
RelOptInfo
*
rel
,
RelOptInfo
*
index
);
static
bool
SingleAttributeIndex
(
RelOptInfo
*
index
);
/* If Spyros can use a constant PRS2_BOOL_TYPEID, I can use this */
#define BOOL_TYPEID ((Oid) 16)
/*
* find-index-paths--
...
...
@@ -121,91 +119,82 @@ find_index_paths(Query *root,
List
*
joinclausegroups
=
NIL
;
List
*
joinpaths
=
NIL
;
List
*
retval
=
NIL
;
if
(
indices
==
NIL
)
return
(
NULL
);
index
=
(
RelOptInfo
*
)
lfirst
(
indices
);
retval
=
find_index_paths
(
root
,
rel
,
lnext
(
indices
),
clauseinfo_list
,
joininfo_list
);
/* If this is a partial index, return if it fails the predicate test */
if
(
index
->
indpred
!=
NIL
)
if
(
!
pred_test
(
index
->
indpred
,
clauseinfo_list
,
joininfo_list
))
return
retval
;
/*
* 1. If this index has only one key, try matching it against
* subclauses of an 'or' clause. The fields of the clauseinfo nodes
* are marked with lists of the matching indices no path are actually
* created.
*
* XXX NOTE: Currently btrees dos not support indices with > 1 key, so
* the following test will always be true for now but we have decided
* not to support index-scans on disjunction . -- lp
*/
if
(
SingleAttributeIndex
(
index
))
List
*
ilist
;
foreach
(
ilist
,
indices
)
{
index
=
(
RelOptInfo
*
)
lfirst
(
ilist
);
/* If this is a partial index, return if it fails the predicate test */
if
(
index
->
indpred
!=
NIL
)
if
(
!
pred_test
(
index
->
indpred
,
clauseinfo_list
,
joininfo_list
))
continue
;
/*
* 1. Try matching the index against subclauses of an 'or' clause.
* The fields of the clauseinfo nodes are marked with lists of the
* matching indices. No path are actually created. We currently
* only look to match the first key. We don't find multi-key index
* cases where an AND matches the first key, and the OR matches the
* second key.
*/
match_index_orclauses
(
rel
,
index
,
index
->
indexkeys
[
0
],
index
->
classlist
[
0
],
clauseinfo_list
);
}
/*
* 2. If the keys of this index match any of the available restriction
* clauses, then create pathnodes corresponding to each group of
* usable clauses.
*/
scanclausegroups
=
group_clauses_by_indexkey
(
rel
,
index
,
index
->
indexkeys
,
index
->
classlist
,
clauseinfo_list
);
scanpaths
=
NIL
;
if
(
scanclausegroups
!=
NIL
)
scanpaths
=
create_index_paths
(
root
,
rel
,
index
,
scanclausegroups
,
false
);
/*
* 3. If this index can be used with any join clause, then create
* pathnodes for each group of usable clauses. An index can be used
* with a join clause if its ordering is useful for a mergejoin, or if
* the index can possibly be used for scanning the inner relation of a
* nestloop join.
*/
joinclausegroups
=
indexable_joinclauses
(
rel
,
index
,
joininfo_list
,
clauseinfo_list
);
joinpaths
=
NIL
;
if
(
joinclausegroups
!=
NIL
)
{
List
*
new_join_paths
=
create_index_paths
(
root
,
rel
,
index
,
joinclausegroups
,
true
);
List
*
innerjoin_paths
=
index_innerjoin
(
root
,
rel
,
joinclausegroups
,
index
);
rel
->
innerjoin
=
nconc
(
rel
->
innerjoin
,
innerjoin_paths
);
joinpaths
=
new_join_paths
;
index
,
index
->
indexkeys
[
0
],
index
->
classlist
[
0
],
clauseinfo_list
);
}
/*
* 2. If the keys of this index match any of the available restriction
* clauses, then create pathnodes corresponding to each group of
* usable clauses.
*/
scanclausegroups
=
group_clauses_by_indexkey
(
rel
,
index
,
index
->
indexkeys
,
index
->
classlist
,
clauseinfo_list
);
scanpaths
=
NIL
;
if
(
scanclausegroups
!=
NIL
)
scanpaths
=
create_index_paths
(
root
,
rel
,
index
,
scanclausegroups
,
false
);
/*
* 3. If this index can be used with any join clause, then create
* pathnodes for each group of usable clauses. An index can be used
* with a join clause if its ordering is useful for a mergejoin, or if
* the index can possibly be used for scanning the inner relation of a
* nestloop join.
*/
joinclausegroups
=
indexable_joinclauses
(
rel
,
index
,
joininfo_list
,
clauseinfo_list
);
joinpaths
=
NIL
;
if
(
joinclausegroups
!=
NIL
)
{
List
*
new_join_paths
=
create_index_paths
(
root
,
rel
,
index
,
joinclausegroups
,
true
);
List
*
innerjoin_paths
=
index_innerjoin
(
root
,
rel
,
joinclausegroups
,
index
);
rel
->
innerjoin
=
nconc
(
rel
->
innerjoin
,
innerjoin_paths
);
joinpaths
=
new_join_paths
;
}
/*
* Some sanity checks to make sure that the indexpath is valid.
*/
if
(
joinpaths
!=
NULL
)
retval
=
add_index_paths
(
joinpaths
,
retval
);
if
(
scanpaths
!=
NULL
)
retval
=
add_index_paths
(
scanpaths
,
retval
);
}
/*
* Some sanity checks to make sure that the indexpath is valid.
*/
if
(
joinpaths
!=
NULL
)
retval
=
add_index_paths
(
joinpaths
,
retval
);
if
(
scanpaths
!=
NULL
)
retval
=
add_index_paths
(
scanpaths
,
retval
);
return
retval
;
}
...
...
@@ -297,7 +286,7 @@ match_index_to_operand(int indexkey,
* (1) the operator within the subclause can be used with one
* of the index's operator classes, and
* (2) there is a usable key that matches the variable within a
* s
arg
able clause.
* s
earch
able clause.
*
* 'or-clauses' are the remaining subclauses within the 'or' clause
* 'other-matching-indices' is the list of information on other indices
...
...
@@ -322,30 +311,31 @@ match_index_orclause(RelOptInfo *rel,
List
*
matched_indices
=
other_matching_indices
;
List
*
index_list
=
NIL
;
List
*
clist
;
List
*
ind
;
if
(
!
matched_indices
)
matched_indices
=
lcons
(
NIL
,
NIL
);
for
(
clist
=
or_clauses
,
ind
=
matched_indices
;
clist
;
clist
=
lnext
(
clist
),
ind
=
lnext
(
ind
))
foreach
(
clist
,
or_clauses
)
{
clause
=
lfirst
(
clist
);
if
(
is_opclause
(
clause
)
&&
op_class
(((
Oper
*
)
((
Expr
*
)
clause
)
->
oper
)
->
opno
,
xclass
,
index
->
relam
)
&&
match_index_to_operand
(
indexkey
,
((
match_index_to_operand
(
indexkey
,
(
Expr
*
)
get_leftop
((
Expr
*
)
clause
),
rel
,
index
)
&&
IsA
(
get_rightop
((
Expr
*
)
clause
),
Const
))
||
(
match_index_to_operand
(
indexkey
,
(
Expr
*
)
get_leftop
((
Expr
*
)
clause
),
rel
,
index
)
&&
IsA
(
get_rightop
((
Expr
*
)
clause
),
Const
))
IsA
(
get_rightop
((
Expr
*
)
clause
),
Const
))
))
{
matched_indices
=
lcons
(
index
,
matched_indices
);
index_list
=
lappend
(
index_list
,
matched_indices
);
}
index_list
=
lappend
(
index_list
,
matched_indices
);
/* for the first index, we are creating the indexids list */
if
(
matched_indices
)
matched_indices
=
lnext
(
matched_indices
);
}
return
(
index_list
);
...
...
@@ -1061,7 +1051,7 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
*/
test_oper
=
makeOper
(
test_op
,
/* opno */
InvalidOid
,
/* opid */
BOOL
_TYPE
ID
,
/* opresulttype */
BOOL
O
ID
,
/* opresulttype */
0
,
/* opsize */
NULL
);
/* op_fcache */
replace_opid
(
test_oper
);
...
...
@@ -1176,7 +1166,8 @@ extract_restrict_clauses(List *clausegroup)
*
*/
static
List
*
index_innerjoin
(
Query
*
root
,
RelOptInfo
*
rel
,
List
*
clausegroup_list
,
RelOptInfo
*
index
)
index_innerjoin
(
Query
*
root
,
RelOptInfo
*
rel
,
List
*
clausegroup_list
,
RelOptInfo
*
index
)
{
List
*
clausegroup
=
NIL
;
List
*
cg_list
=
NIL
;
...
...
@@ -1366,29 +1357,3 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index)
return
true
;
}
static
bool
SingleAttributeIndex
(
RelOptInfo
*
index
)
{
/*
* return false for now as I don't know if we support index scans on
* disjunction and the code doesn't work
*/
return
(
false
);
#if 0
/*
* Non-functional indices.
*/
if (index->indproc == InvalidOid)
return (index->indexkeys[0] != 0 &&
index->indexkeys[1] == 0);
/*
* We have a functional index which is a single attr index
*/
return true;
#endif
}
src/backend/optimizer/path/orindxpath.c
View file @
0a2e5cdf
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.
7 1998/07/18 04:22:3
3 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.
8 1998/08/01 22:12:1
3 momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -55,10 +55,11 @@ create_or_index_paths(Query *root,
RelOptInfo
*
rel
,
List
*
clauses
)
{
List
*
t_list
=
NIL
;
List
*
clist
;
if
(
clauses
!=
NIL
)
foreach
(
clist
,
clauses
)
{
CInfo
*
clausenode
=
(
CInfo
*
)
(
lfirst
(
cl
auses
));
CInfo
*
clausenode
=
(
CInfo
*
)
(
lfirst
(
cl
ist
));
/*
* Check to see if this clause is an 'or' clause, and, if so,
...
...
@@ -77,8 +78,11 @@ create_or_index_paths(Query *root,
index_list
=
clausenode
->
indexids
;
foreach
(
temp
,
index_list
)
{
if
(
!
temp
)
if
(
!
lfirst
(
temp
))
{
index_flag
=
false
;
break
;
}
}
if
(
index_flag
)
{
/* used to be a lisp every function */
...
...
@@ -100,8 +104,7 @@ create_or_index_paths(Query *root,
pathnode
->
path
.
pathtype
=
T_IndexScan
;
pathnode
->
path
.
parent
=
rel
;
pathnode
->
indexqual
=
lcons
(
clausenode
,
NIL
);
pathnode
->
indexqual
=
lcons
(
clausenode
,
NIL
);
pathnode
->
indexid
=
indexids
;
pathnode
->
path
.
path_cost
=
cost
;
...
...
@@ -110,9 +113,8 @@ create_or_index_paths(Query *root,
* processing -- JMH, 7/7/92
*/
pathnode
->
path
.
locclauseinfo
=
set_difference
(
clauses
,
copyObject
((
Node
*
)
rel
->
clauseinfo
));
set_difference
(
copyObject
((
Node
*
)
rel
->
clauseinfo
),
lcons
(
clausenode
,
NIL
));
#if 0 /* fix xfunc */
/* add in cost for expensive functions! -- JMH, 7/7/92 */
...
...
@@ -123,12 +125,8 @@ create_or_index_paths(Query *root,
}
#endif
clausenode
->
selectivity
=
(
Cost
)
floatVal
(
selecs
);
t_list
=
lcons
(
pathnode
,
create_or_index_paths
(
root
,
rel
,
lnext
(
clauses
)));
t_list
=
lappend
(
t_list
,
pathnode
);
}
else
t_list
=
create_or_index_paths
(
root
,
rel
,
lnext
(
clauses
));
}
}
...
...
@@ -167,32 +165,28 @@ best_or_subclause_indices(Query *root,
Cost
*
cost
,
/* return value */
List
**
selecs
)
/* return value */
{
if
(
subclauses
==
NIL
)
{
*
indexids
=
nreverse
(
examined_indexids
);
*
cost
=
subcost
;
*
selecs
=
nreverse
(
selectivities
);
}
else
List
*
slist
;
foreach
(
slist
,
subclauses
)
{
int
best_indexid
;
Cost
best_cost
;
Cost
best_selec
;
best_or_subclause_index
(
root
,
rel
,
lfirst
(
s
ubclauses
),
lfirst
(
indices
),
best_or_subclause_index
(
root
,
rel
,
lfirst
(
s
list
),
lfirst
(
indices
),
&
best_indexid
,
&
best_cost
,
&
best_selec
);
examined_indexids
=
lappendi
(
examined_indexids
,
best_indexid
);
subcost
+=
best_cost
;
selectivities
=
lappend
(
selectivities
,
makeFloat
(
best_selec
));
best_or_subclause_indices
(
root
,
rel
,
lnext
(
subclauses
),
lnext
(
indices
),
lconsi
(
best_indexid
,
examined_indexids
),
subcost
+
best_cost
,
lcons
(
makeFloat
(
best_selec
),
selectivities
),
indexids
,
cost
,
selecs
);
indices
=
lnext
(
indices
);
}
*
indexids
=
examined_indexids
;
*
cost
=
subcost
;
*
selecs
=
selectivities
;
return
;
}
...
...
@@ -219,20 +213,21 @@ best_or_subclause_index(Query *root,
Cost
*
retCost
,
/* return value */
Cost
*
retSelec
)
/* return value */
{
if
(
indices
!=
NIL
)
List
*
ilist
;
bool
first_run
=
true
;
foreach
(
ilist
,
indices
)
{
RelOptInfo
*
index
=
(
RelOptInfo
*
)
lfirst
(
ilist
);
Datum
value
;
int
flag
=
0
;
Cost
subcost
;
RelOptInfo
*
index
=
(
RelOptInfo
*
)
lfirst
(
indices
);
AttrNumber
attno
=
(
get_leftop
(
subclause
))
->
varattno
;
Oid
opno
=
((
Oper
*
)
subclause
->
oper
)
->
opno
;
bool
constant_on_right
=
non_null
((
Expr
*
)
get_rightop
(
subclause
));
float
npages
,
selec
;
int
subclause_indexid
;
Cost
subclause_cost
;
Cost
subclause_selec
;
if
(
constant_on_right
)
value
=
((
Const
*
)
get_rightop
(
subclause
))
->
constvalue
;
...
...
@@ -242,6 +237,7 @@ best_or_subclause_index(Query *root,
flag
=
(
_SELEC_IS_CONSTANT_
||
_SELEC_CONSTANT_RIGHT_
);
else
flag
=
_SELEC_CONSTANT_RIGHT_
;
index_selectivity
(
lfirsti
(
index
->
relids
),
index
->
classlist
,
lconsi
(
opno
,
NIL
),
...
...
@@ -262,26 +258,22 @@ best_or_subclause_index(Query *root,
index
->
pages
,
index
->
tuples
,
false
);
best_or_subclause_index
(
root
,
rel
,
subclause
,
lnext
(
indices
),
&
subclause_indexid
,
&
subclause_cost
,
&
subclause_selec
);
if
(
subclause_indexid
==
0
||
subcost
<
subclause_c
ost
)
if
(
first_run
||
subcost
<
*
retC
ost
)
{
*
retIndexid
=
lfirsti
(
index
->
relids
);
*
retCost
=
subcost
;
*
retSelec
=
selec
;
first_run
=
false
;
}
else
{
*
retIndexid
=
0
;
*
retCost
=
0
.
0
;
*
retSelec
=
0
.
0
;
}
}
/* we didn't get any indexes, so zero return values */
if
(
first_run
)
{
*
retIndexid
=
0
;
*
retCost
=
0
.
0
;
*
retSelec
=
0
.
0
;
}
return
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment