mirror of
https://github.com/postgres/postgres.git
synced 2025-06-26 12:21:12 +03:00
Patches for Vadim's multikey indexing...
This commit is contained in:
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/Attic/indexvalid.c,v 1.13 1997/03/12 20:56:32 scrappy Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/Attic/indexvalid.c,v 1.14 1997/03/18 18:38:19 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -48,7 +48,7 @@ index_keytest(IndexTuple tuple,
|
|||||||
|
|
||||||
while (scanKeySize > 0) {
|
while (scanKeySize > 0) {
|
||||||
datum = index_getattr(tuple,
|
datum = index_getattr(tuple,
|
||||||
1,
|
key[0].sk_attno,
|
||||||
tupdesc,
|
tupdesc,
|
||||||
&isNull);
|
&isNull);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.15 1997/02/22 10:04:14 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.16 1997/03/18 18:38:35 scrappy Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* This file contains only the public interface routines.
|
* This file contains only the public interface routines.
|
||||||
@ -423,6 +423,7 @@ btrescan(IndexScanDesc scan, bool fromEnd, ScanKey scankey)
|
|||||||
|
|
||||||
/* reset the scan key */
|
/* reset the scan key */
|
||||||
so->numberOfKeys = scan->numberOfKeys;
|
so->numberOfKeys = scan->numberOfKeys;
|
||||||
|
so->numberOfFirstKeys = 0;
|
||||||
so->qual_ok = 1; /* may be changed by _bt_orderkeys */
|
so->qual_ok = 1; /* may be changed by _bt_orderkeys */
|
||||||
if (scan->numberOfKeys > 0) {
|
if (scan->numberOfKeys > 0) {
|
||||||
memmove(scan->keyData,
|
memmove(scan->keyData,
|
||||||
@ -433,7 +434,9 @@ btrescan(IndexScanDesc scan, bool fromEnd, ScanKey scankey)
|
|||||||
so->numberOfKeys * sizeof(ScanKeyData));
|
so->numberOfKeys * sizeof(ScanKeyData));
|
||||||
/* order the keys in the qualification */
|
/* order the keys in the qualification */
|
||||||
if (so->numberOfKeys > 1)
|
if (so->numberOfKeys > 1)
|
||||||
_bt_orderkeys(scan->relation, &so->numberOfKeys, so->keyData, &so->qual_ok);
|
_bt_orderkeys(scan->relation, so);
|
||||||
|
else
|
||||||
|
so->numberOfFirstKeys = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finally, be sure that the scan exploits the tree order */
|
/* finally, be sure that the scan exploits the tree order */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.14 1997/02/18 17:13:48 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.15 1997/03/18 18:38:41 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -562,7 +562,6 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
|
|||||||
Page page;
|
Page page;
|
||||||
OffsetNumber offnum;
|
OffsetNumber offnum;
|
||||||
RetrieveIndexResult res;
|
RetrieveIndexResult res;
|
||||||
BlockNumber blkno;
|
|
||||||
ItemPointer current;
|
ItemPointer current;
|
||||||
BTItem btitem;
|
BTItem btitem;
|
||||||
IndexTuple itup;
|
IndexTuple itup;
|
||||||
@ -584,8 +583,9 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
|
|||||||
|
|
||||||
/* we still have the buffer pinned and locked */
|
/* we still have the buffer pinned and locked */
|
||||||
buf = so->btso_curbuf;
|
buf = so->btso_curbuf;
|
||||||
blkno = BufferGetBlockNumber(buf);
|
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
/* step one tuple in the appropriate direction */
|
/* step one tuple in the appropriate direction */
|
||||||
if (!_bt_step(scan, &buf, dir))
|
if (!_bt_step(scan, &buf, dir))
|
||||||
return ((RetrieveIndexResult) NULL);
|
return ((RetrieveIndexResult) NULL);
|
||||||
@ -596,19 +596,22 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
|
|||||||
btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
|
btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
|
||||||
itup = &btitem->bti_itup;
|
itup = &btitem->bti_itup;
|
||||||
|
|
||||||
if (_bt_checkqual(scan, itup)) {
|
if (_bt_checkqual(scan, itup))
|
||||||
|
{
|
||||||
res = FormRetrieveIndexResult(current, &(itup->t_tid));
|
res = FormRetrieveIndexResult(current, &(itup->t_tid));
|
||||||
|
|
||||||
/* remember which buffer we have pinned and locked */
|
/* remember which buffer we have pinned and locked */
|
||||||
so->btso_curbuf = buf;
|
so->btso_curbuf = buf;
|
||||||
} else {
|
return (res);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while ( _bt_checkforkeys (scan, itup, so->numberOfFirstKeys) );
|
||||||
|
|
||||||
ItemPointerSetInvalid(current);
|
ItemPointerSetInvalid(current);
|
||||||
so->btso_curbuf = InvalidBuffer;
|
so->btso_curbuf = InvalidBuffer;
|
||||||
_bt_relbuf(rel, buf, BT_READ);
|
_bt_relbuf(rel, buf, BT_READ);
|
||||||
res = (RetrieveIndexResult) NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (res);
|
return ((RetrieveIndexResult) NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -660,13 +663,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
|||||||
* ordered to take advantage of index ordering) to position ourselves
|
* ordered to take advantage of index ordering) to position ourselves
|
||||||
* at the right place in the scan.
|
* at the right place in the scan.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX -- The attribute number stored in the scan key is the attno
|
|
||||||
* in the heap relation. We need to transmogrify this into
|
|
||||||
* the index relation attno here. For the moment, we have
|
|
||||||
* hardwired attno == 1.
|
|
||||||
*/
|
|
||||||
proc = index_getprocid(rel, 1, BTORDER_PROC);
|
proc = index_getprocid(rel, 1, BTORDER_PROC);
|
||||||
ScanKeyEntryInitialize(&skdata, so->keyData[0].sk_flags, 1, proc,
|
ScanKeyEntryInitialize(&skdata, so->keyData[0].sk_flags, 1, proc,
|
||||||
so->keyData[0].sk_argument);
|
so->keyData[0].sk_argument);
|
||||||
@ -802,12 +798,20 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
|||||||
btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
|
btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
|
||||||
itup = &btitem->bti_itup;
|
itup = &btitem->bti_itup;
|
||||||
|
|
||||||
if (_bt_checkqual(scan, itup)) {
|
if ( _bt_checkqual(scan, itup) )
|
||||||
|
{
|
||||||
res = FormRetrieveIndexResult(current, &(itup->t_tid));
|
res = FormRetrieveIndexResult(current, &(itup->t_tid));
|
||||||
|
|
||||||
/* remember which buffer we have pinned */
|
/* remember which buffer we have pinned */
|
||||||
so->btso_curbuf = buf;
|
so->btso_curbuf = buf;
|
||||||
} else {
|
}
|
||||||
|
else if ( _bt_checkforkeys (scan, itup, so->numberOfFirstKeys) )
|
||||||
|
{
|
||||||
|
so->btso_curbuf = buf;
|
||||||
|
return (_bt_next (scan, dir));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ItemPointerSetInvalid(current);
|
ItemPointerSetInvalid(current);
|
||||||
so->btso_curbuf = InvalidBuffer;
|
so->btso_curbuf = InvalidBuffer;
|
||||||
_bt_relbuf(rel, buf, BT_READ);
|
_bt_relbuf(rel, buf, BT_READ);
|
||||||
@ -1224,7 +1228,14 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
|
|||||||
|
|
||||||
/* remember which buffer we have pinned */
|
/* remember which buffer we have pinned */
|
||||||
so->btso_curbuf = buf;
|
so->btso_curbuf = buf;
|
||||||
} else {
|
}
|
||||||
|
else if ( _bt_checkforkeys (scan, itup, so->numberOfFirstKeys) )
|
||||||
|
{
|
||||||
|
so->btso_curbuf = buf;
|
||||||
|
return (_bt_next (scan, dir));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
_bt_relbuf(rel, buf, BT_READ);
|
_bt_relbuf(rel, buf, BT_READ);
|
||||||
res = (RetrieveIndexResult) NULL;
|
res = (RetrieveIndexResult) NULL;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.7 1996/11/05 10:35:38 scrappy Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.8 1997/03/18 18:38:46 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -80,7 +80,7 @@ _bt_freestack(BTStack stack)
|
|||||||
* more than one qual clauses using this index.
|
* more than one qual clauses using this index.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
_bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key, uint16 *qual_ok)
|
_bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||||
{
|
{
|
||||||
ScanKey xform;
|
ScanKey xform;
|
||||||
ScanKeyData *cur;
|
ScanKeyData *cur;
|
||||||
@ -89,83 +89,61 @@ _bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key, uint16 *qual
|
|||||||
long test;
|
long test;
|
||||||
int i, j;
|
int i, j;
|
||||||
int init[BTMaxStrategyNumber+1];
|
int init[BTMaxStrategyNumber+1];
|
||||||
|
ScanKey key;
|
||||||
|
uint16 numberOfKeys, new_numberOfKeys = 0;
|
||||||
|
AttrNumber attno = 1;
|
||||||
|
|
||||||
/* haven't looked at any strategies yet */
|
numberOfKeys = so->numberOfKeys;
|
||||||
for (i = 0; i <= BTMaxStrategyNumber; i++)
|
key = so->keyData;
|
||||||
init[i] = 0;
|
|
||||||
|
if ( numberOfKeys <= 1 )
|
||||||
|
return;
|
||||||
|
|
||||||
/* get space for the modified array of keys */
|
/* get space for the modified array of keys */
|
||||||
nbytes = BTMaxStrategyNumber * sizeof(ScanKeyData);
|
nbytes = BTMaxStrategyNumber * sizeof(ScanKeyData);
|
||||||
xform = (ScanKey) palloc(nbytes);
|
xform = (ScanKey) palloc(nbytes);
|
||||||
|
|
||||||
|
cur = &key[0];
|
||||||
|
if ( cur->sk_attno != 1 )
|
||||||
|
elog (WARN, "_bt_orderkeys: key(s) for attribute 1 missed");
|
||||||
|
|
||||||
memset(xform, 0, nbytes);
|
memset(xform, 0, nbytes);
|
||||||
|
|
||||||
|
|
||||||
/* get the strategy map for this index/attribute pair */
|
|
||||||
/*
|
|
||||||
* XXX
|
|
||||||
* When we support multiple keys in a single index, this is what
|
|
||||||
* we'll want to do. At present, the planner is hosed, so we
|
|
||||||
* hard-wire the attribute number below. Postgres only does single-
|
|
||||||
* key indices...
|
|
||||||
* map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
|
||||||
* BTMaxStrategyNumber,
|
|
||||||
* key->data[0].attributeNumber);
|
|
||||||
*/
|
|
||||||
map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
||||||
BTMaxStrategyNumber,
|
BTMaxStrategyNumber,
|
||||||
1 /* XXX */ );
|
attno);
|
||||||
|
for (j = 0; j <= BTMaxStrategyNumber; j++)
|
||||||
|
init[j] = 0;
|
||||||
|
|
||||||
/* check each key passed in */
|
/* check each key passed in */
|
||||||
for (i = *numberOfKeys; --i >= 0; ) {
|
for (i = 0; ; )
|
||||||
|
{
|
||||||
|
if ( i < numberOfKeys )
|
||||||
cur = &key[i];
|
cur = &key[i];
|
||||||
for (j = BTMaxStrategyNumber; --j >= 0; ) {
|
if ( i == numberOfKeys || cur->sk_attno != attno )
|
||||||
if (cur->sk_procedure == map->entry[j].sk_procedure)
|
{
|
||||||
break;
|
if ( cur->sk_attno != attno + 1 && i < numberOfKeys )
|
||||||
|
{
|
||||||
|
elog (WARN, "_bt_orderkeys: key(s) for attribute %d missed", attno + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* have we seen one of these before? */
|
|
||||||
if (init[j]) {
|
|
||||||
/* yup, use the appropriate value */
|
|
||||||
test =
|
|
||||||
(long) FMGR_PTR2(cur->sk_func, cur->sk_procedure,
|
|
||||||
cur->sk_argument, xform[j].sk_argument);
|
|
||||||
if (test)
|
|
||||||
xform[j].sk_argument = cur->sk_argument;
|
|
||||||
else if ( j == (BTEqualStrategyNumber - 1) )
|
|
||||||
*qual_ok = 0; /* key == a && key == b, but a != b */
|
|
||||||
} else {
|
|
||||||
/* nope, use this value */
|
|
||||||
memmove(&xform[j], cur, sizeof(*cur));
|
|
||||||
|
|
||||||
init[j] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if = has been specified, no other key will be used */
|
|
||||||
/*
|
/*
|
||||||
* XXX
|
* If = has been specified, no other key will be used.
|
||||||
* But in case of key < 2 && key == 1 and so on
|
* In case of key < 2 && key == 1 and so on
|
||||||
* we have to set qual_ok to 0
|
* we have to set qual_ok to 0
|
||||||
*/
|
*/
|
||||||
if (init[BTEqualStrategyNumber - 1]) {
|
if (init[BTEqualStrategyNumber - 1])
|
||||||
|
{
|
||||||
ScanKeyData *eq, *chk;
|
ScanKeyData *eq, *chk;
|
||||||
|
|
||||||
eq = &xform[BTEqualStrategyNumber - 1];
|
eq = &xform[BTEqualStrategyNumber - 1];
|
||||||
|
|
||||||
for (j = BTMaxStrategyNumber; --j >= 0; )
|
for (j = BTMaxStrategyNumber; --j >= 0; )
|
||||||
{
|
{
|
||||||
if ( j == (BTEqualStrategyNumber - 1) || init[j] == 0 )
|
if ( j == (BTEqualStrategyNumber - 1) || init[j] == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
chk = &xform[j];
|
chk = &xform[j];
|
||||||
|
|
||||||
test = (long) fmgr(chk->sk_procedure, eq->sk_argument, chk->sk_argument);
|
test = (long) fmgr(chk->sk_procedure, eq->sk_argument, chk->sk_argument);
|
||||||
|
|
||||||
if (!test)
|
if (!test)
|
||||||
*qual_ok = 0;
|
so->qual_ok = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
init[BTLessStrategyNumber - 1] = 0;
|
init[BTLessStrategyNumber - 1] = 0;
|
||||||
init[BTLessEqualStrategyNumber - 1] = 0;
|
init[BTLessEqualStrategyNumber - 1] = 0;
|
||||||
init[BTGreaterEqualStrategyNumber - 1] = 0;
|
init[BTGreaterEqualStrategyNumber - 1] = 0;
|
||||||
@ -174,13 +152,12 @@ _bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key, uint16 *qual
|
|||||||
|
|
||||||
/* only one of <, <= */
|
/* only one of <, <= */
|
||||||
if (init[BTLessStrategyNumber - 1]
|
if (init[BTLessStrategyNumber - 1]
|
||||||
&& init[BTLessEqualStrategyNumber - 1]) {
|
&& init[BTLessEqualStrategyNumber - 1])
|
||||||
|
{
|
||||||
ScanKeyData *lt, *le;
|
ScanKeyData *lt, *le;
|
||||||
|
|
||||||
lt = &xform[BTLessStrategyNumber - 1];
|
lt = &xform[BTLessStrategyNumber - 1];
|
||||||
le = &xform[BTLessEqualStrategyNumber - 1];
|
le = &xform[BTLessEqualStrategyNumber - 1];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DO NOT use the cached function stuff here -- this is key
|
* DO NOT use the cached function stuff here -- this is key
|
||||||
* ordering, happens only when the user expresses a hokey
|
* ordering, happens only when the user expresses a hokey
|
||||||
@ -188,9 +165,7 @@ _bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key, uint16 *qual
|
|||||||
* transform maps are hard-coded, and can't be initialized
|
* transform maps are hard-coded, and can't be initialized
|
||||||
* in the correct way.
|
* in the correct way.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
test = (long) fmgr(le->sk_procedure, lt->sk_argument, le->sk_argument);
|
test = (long) fmgr(le->sk_procedure, lt->sk_argument, le->sk_argument);
|
||||||
|
|
||||||
if (test)
|
if (test)
|
||||||
init[BTLessEqualStrategyNumber - 1] = 0;
|
init[BTLessEqualStrategyNumber - 1] = 0;
|
||||||
else
|
else
|
||||||
@ -199,8 +174,8 @@ _bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key, uint16 *qual
|
|||||||
|
|
||||||
/* only one of >, >= */
|
/* only one of >, >= */
|
||||||
if (init[BTGreaterStrategyNumber - 1]
|
if (init[BTGreaterStrategyNumber - 1]
|
||||||
&& init[BTGreaterEqualStrategyNumber - 1]) {
|
&& init[BTGreaterEqualStrategyNumber - 1])
|
||||||
|
{
|
||||||
ScanKeyData *gt, *ge;
|
ScanKeyData *gt, *ge;
|
||||||
|
|
||||||
gt = &xform[BTGreaterStrategyNumber - 1];
|
gt = &xform[BTGreaterStrategyNumber - 1];
|
||||||
@ -208,7 +183,6 @@ _bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key, uint16 *qual
|
|||||||
|
|
||||||
/* see note above on function cache */
|
/* see note above on function cache */
|
||||||
test = (long) fmgr(ge->sk_procedure, gt->sk_argument, ge->sk_argument);
|
test = (long) fmgr(ge->sk_procedure, gt->sk_argument, ge->sk_argument);
|
||||||
|
|
||||||
if (test)
|
if (test)
|
||||||
init[BTGreaterEqualStrategyNumber - 1] = 0;
|
init[BTGreaterEqualStrategyNumber - 1] = 0;
|
||||||
else
|
else
|
||||||
@ -216,13 +190,55 @@ _bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key, uint16 *qual
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* okay, reorder and count */
|
/* okay, reorder and count */
|
||||||
j = 0;
|
for (j = BTMaxStrategyNumber; --j >= 0; )
|
||||||
|
if (init[j])
|
||||||
|
key[new_numberOfKeys++] = xform[j];
|
||||||
|
|
||||||
for (i = BTMaxStrategyNumber; --i >= 0; )
|
if ( attno == 1 )
|
||||||
if (init[i])
|
so->numberOfFirstKeys = new_numberOfKeys;
|
||||||
key[j++] = xform[i];
|
|
||||||
|
|
||||||
*numberOfKeys = j;
|
if ( i == numberOfKeys )
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* initialization for new attno */
|
||||||
|
attno = cur->sk_attno;
|
||||||
|
memset(xform, 0, nbytes);
|
||||||
|
map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
||||||
|
BTMaxStrategyNumber,
|
||||||
|
attno);
|
||||||
|
/* haven't looked at any strategies yet */
|
||||||
|
for (j = 0; j <= BTMaxStrategyNumber; j++)
|
||||||
|
init[j] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = BTMaxStrategyNumber; --j >= 0; )
|
||||||
|
{
|
||||||
|
if (cur->sk_procedure == map->entry[j].sk_procedure)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* have we seen one of these before? */
|
||||||
|
if (init[j])
|
||||||
|
{
|
||||||
|
/* yup, use the appropriate value */
|
||||||
|
test =
|
||||||
|
(long) FMGR_PTR2(cur->sk_func, cur->sk_procedure,
|
||||||
|
cur->sk_argument, xform[j].sk_argument);
|
||||||
|
if (test)
|
||||||
|
xform[j].sk_argument = cur->sk_argument;
|
||||||
|
else if ( j == (BTEqualStrategyNumber - 1) )
|
||||||
|
so->qual_ok = 0; /* key == a && key == b, but a != b */
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
/* nope, use this value */
|
||||||
|
memmove(&xform[j], cur, sizeof(*cur));
|
||||||
|
init[j] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
so->numberOfKeys = new_numberOfKeys;
|
||||||
|
|
||||||
pfree(xform);
|
pfree(xform);
|
||||||
}
|
}
|
||||||
@ -230,9 +246,25 @@ _bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key, uint16 *qual
|
|||||||
bool
|
bool
|
||||||
_bt_checkqual(IndexScanDesc scan, IndexTuple itup)
|
_bt_checkqual(IndexScanDesc scan, IndexTuple itup)
|
||||||
{
|
{
|
||||||
if (scan->numberOfKeys > 0)
|
BTScanOpaque so;
|
||||||
|
|
||||||
|
so = (BTScanOpaque) scan->opaque;
|
||||||
|
if (so->numberOfKeys > 0)
|
||||||
return (index_keytest(itup, RelationGetTupleDescriptor(scan->relation),
|
return (index_keytest(itup, RelationGetTupleDescriptor(scan->relation),
|
||||||
scan->numberOfKeys, scan->keyData));
|
so->numberOfKeys, so->keyData));
|
||||||
|
else
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
_bt_checkforkeys(IndexScanDesc scan, IndexTuple itup, Size keysz)
|
||||||
|
{
|
||||||
|
BTScanOpaque so;
|
||||||
|
|
||||||
|
so = (BTScanOpaque) scan->opaque;
|
||||||
|
if ( keysz > 0 && so->numberOfKeys >= keysz )
|
||||||
|
return (index_keytest(itup, RelationGetTupleDescriptor(scan->relation),
|
||||||
|
keysz, so->keyData));
|
||||||
else
|
else
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.6 1997/03/12 21:00:17 scrappy Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.7 1997/03/18 18:39:40 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,8 +53,9 @@ static bool match_index_to_operand(int indexkey, Expr *operand,
|
|||||||
static List *match_index_orclause(Rel *rel, Rel *index, int indexkey,
|
static List *match_index_orclause(Rel *rel, Rel *index, int indexkey,
|
||||||
int xclass, List *or_clauses, List *other_matching_indices);
|
int xclass, List *or_clauses, List *other_matching_indices);
|
||||||
static List *group_clauses_by_indexkey(Rel *rel, Rel *index,
|
static List *group_clauses_by_indexkey(Rel *rel, Rel *index,
|
||||||
int *indexkeys, Oid *classes, List *clauseinfo_list,
|
int *indexkeys, Oid *classes, List *clauseinfo_list);
|
||||||
bool join);
|
static List *group_clauses_by_ikey_for_joins(Rel *rel, Rel *index,
|
||||||
|
int *indexkeys, Oid *classes, List *join_cinfo_list, List *restr_cinfo_list);
|
||||||
static CInfo *match_clause_to_indexkey(Rel *rel, Rel *index, int indexkey,
|
static CInfo *match_clause_to_indexkey(Rel *rel, Rel *index, int indexkey,
|
||||||
int xclass, CInfo *clauseInfo, bool join);
|
int xclass, CInfo *clauseInfo, bool join);
|
||||||
static bool pred_test(List *predicate_list, List *clauseinfo_list,
|
static bool pred_test(List *predicate_list, List *clauseinfo_list,
|
||||||
@ -63,7 +64,8 @@ static bool one_pred_test(Expr *predicate, List *clauseinfo_list);
|
|||||||
static bool one_pred_clause_expr_test(Expr *predicate, Node *clause);
|
static bool one_pred_clause_expr_test(Expr *predicate, Node *clause);
|
||||||
static bool one_pred_clause_test(Expr *predicate, Node *clause);
|
static bool one_pred_clause_test(Expr *predicate, Node *clause);
|
||||||
static bool clause_pred_clause_test(Expr *predicate, Node *clause);
|
static bool clause_pred_clause_test(Expr *predicate, Node *clause);
|
||||||
static List *indexable_joinclauses(Rel *rel, Rel *index, List *joininfo_list);
|
static List *indexable_joinclauses (Rel *rel, Rel *index,
|
||||||
|
List *joininfo_list, List *clauseinfo_list);
|
||||||
static List *index_innerjoin(Query *root, Rel *rel,
|
static List *index_innerjoin(Query *root, Rel *rel,
|
||||||
List *clausegroup_list, Rel *index);
|
List *clausegroup_list, Rel *index);
|
||||||
static List *create_index_paths(Query *root, Rel *rel, Rel *index,
|
static List *create_index_paths(Query *root, Rel *rel, Rel *index,
|
||||||
@ -114,7 +116,6 @@ find_index_paths (Query *root,
|
|||||||
List *joinclausegroups = NIL;
|
List *joinclausegroups = NIL;
|
||||||
List *joinpaths = NIL;
|
List *joinpaths = NIL;
|
||||||
List *retval = NIL;
|
List *retval = NIL;
|
||||||
extern List *add_index_paths();
|
|
||||||
|
|
||||||
if(indices == NIL)
|
if(indices == NIL)
|
||||||
return(NULL);
|
return(NULL);
|
||||||
@ -160,8 +161,7 @@ find_index_paths (Query *root,
|
|||||||
index,
|
index,
|
||||||
index->indexkeys,
|
index->indexkeys,
|
||||||
index->classlist,
|
index->classlist,
|
||||||
clauseinfo_list,
|
clauseinfo_list);
|
||||||
false);
|
|
||||||
|
|
||||||
scanpaths = NIL;
|
scanpaths = NIL;
|
||||||
if (scanclausegroups != NIL)
|
if (scanclausegroups != NIL)
|
||||||
@ -178,7 +178,7 @@ find_index_paths (Query *root,
|
|||||||
* useful for a mergejoin, or if the index can possibly be
|
* useful for a mergejoin, or if the index can possibly be
|
||||||
* used for scanning the inner relation of a nestloop join.
|
* used for scanning the inner relation of a nestloop join.
|
||||||
*/
|
*/
|
||||||
joinclausegroups = indexable_joinclauses(rel,index,joininfo_list);
|
joinclausegroups = indexable_joinclauses(rel,index,joininfo_list, clauseinfo_list);
|
||||||
joinpaths = NIL;
|
joinpaths = NIL;
|
||||||
|
|
||||||
if (joinclausegroups != NIL)
|
if (joinclausegroups != NIL)
|
||||||
@ -375,10 +375,8 @@ match_index_orclause(Rel *rel,
|
|||||||
* (2) a list of join clauses between 'rel' and a fixed set of
|
* (2) a list of join clauses between 'rel' and a fixed set of
|
||||||
* relations,
|
* relations,
|
||||||
* depending on the value of 'join'.
|
* depending on the value of 'join'.
|
||||||
* 'startlist' is a list of those clause nodes that have matched the keys
|
*
|
||||||
* that have already been checked.
|
* NOTE: it works now for restriction clauses only. - vadim 03/18/97
|
||||||
* 'join' is a flag indicating that the clauses being checked are join
|
|
||||||
* clauses.
|
|
||||||
*
|
*
|
||||||
* Returns all possible groups of clauses that will match (given that
|
* Returns all possible groups of clauses that will match (given that
|
||||||
* one or more clauses can match any of the remaining keys).
|
* one or more clauses can match any of the remaining keys).
|
||||||
@ -391,48 +389,147 @@ group_clauses_by_indexkey(Rel *rel,
|
|||||||
Rel *index,
|
Rel *index,
|
||||||
int *indexkeys,
|
int *indexkeys,
|
||||||
Oid *classes,
|
Oid *classes,
|
||||||
List *clauseinfo_list,
|
List *clauseinfo_list)
|
||||||
bool join)
|
|
||||||
{
|
{
|
||||||
List *curCinfo = NIL;
|
List *curCinfo = NIL;
|
||||||
CInfo *matched_clause = (CInfo*)NULL;
|
CInfo *matched_clause = (CInfo*)NULL;
|
||||||
List *clausegroup = NIL;
|
List *clausegroup = NIL;
|
||||||
|
int curIndxKey;
|
||||||
|
Oid curClass;
|
||||||
|
|
||||||
if (clauseinfo_list == NIL)
|
if (clauseinfo_list == NIL)
|
||||||
return NIL;
|
return NIL;
|
||||||
|
|
||||||
foreach (curCinfo,clauseinfo_list) {
|
while ( !DoneMatchingIndexKeys(indexkeys, index) )
|
||||||
CInfo *temp = (CInfo*)lfirst(curCinfo);
|
{
|
||||||
int *curIndxKey = indexkeys;
|
List *tempgroup = NIL;
|
||||||
Oid *curClass = classes;
|
|
||||||
|
curIndxKey = indexkeys[0];
|
||||||
|
curClass = classes[0];
|
||||||
|
|
||||||
|
foreach (curCinfo,clauseinfo_list)
|
||||||
|
{
|
||||||
|
CInfo *temp = (CInfo*)lfirst(curCinfo);
|
||||||
|
|
||||||
do {
|
|
||||||
/*
|
|
||||||
* If we can't find any matching clauses for the first of
|
|
||||||
* the remaining keys, give up.
|
|
||||||
*/
|
|
||||||
matched_clause = match_clause_to_indexkey (rel,
|
matched_clause = match_clause_to_indexkey (rel,
|
||||||
index,
|
index,
|
||||||
curIndxKey[0],
|
curIndxKey,
|
||||||
curClass[0],
|
curClass,
|
||||||
temp,
|
temp,
|
||||||
join);
|
false);
|
||||||
if (!matched_clause)
|
if (!matched_clause)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tempgroup = lappend(tempgroup, matched_clause);
|
||||||
|
}
|
||||||
|
if ( tempgroup == NIL )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
clausegroup = lcons(matched_clause, clausegroup);
|
clausegroup = nconc (clausegroup, tempgroup);
|
||||||
curIndxKey++;
|
|
||||||
curClass++;
|
indexkeys++;
|
||||||
|
classes++;
|
||||||
|
|
||||||
} while ( !DoneMatchingIndexKeys(curIndxKey, index) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* clausegroup holds all matched clauses ordered by indexkeys */
|
||||||
|
|
||||||
if (clausegroup != NIL)
|
if (clausegroup != NIL)
|
||||||
return(lcons(clausegroup, NIL));
|
return(lcons(clausegroup, NIL));
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* group-clauses-by-ikey-for-joins--
|
||||||
|
* special edition of group-clauses-by-indexkey - will
|
||||||
|
* match join & restriction clauses. See comment in indexable_joinclauses.
|
||||||
|
* - vadim 03/18/97
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static List *
|
||||||
|
group_clauses_by_ikey_for_joins(Rel *rel,
|
||||||
|
Rel *index,
|
||||||
|
int *indexkeys,
|
||||||
|
Oid *classes,
|
||||||
|
List *join_cinfo_list,
|
||||||
|
List *restr_cinfo_list)
|
||||||
|
{
|
||||||
|
List *curCinfo = NIL;
|
||||||
|
CInfo *matched_clause = (CInfo*)NULL;
|
||||||
|
List *clausegroup = NIL;
|
||||||
|
int curIndxKey;
|
||||||
|
Oid curClass;
|
||||||
|
bool jfound = false;
|
||||||
|
|
||||||
|
if (join_cinfo_list == NIL)
|
||||||
|
return NIL;
|
||||||
|
|
||||||
|
while ( !DoneMatchingIndexKeys(indexkeys, index) )
|
||||||
|
{
|
||||||
|
List *tempgroup = NIL;
|
||||||
|
|
||||||
|
curIndxKey = indexkeys[0];
|
||||||
|
curClass = classes[0];
|
||||||
|
|
||||||
|
foreach (curCinfo,join_cinfo_list)
|
||||||
|
{
|
||||||
|
CInfo *temp = (CInfo*)lfirst(curCinfo);
|
||||||
|
|
||||||
|
matched_clause = match_clause_to_indexkey (rel,
|
||||||
|
index,
|
||||||
|
curIndxKey,
|
||||||
|
curClass,
|
||||||
|
temp,
|
||||||
|
true);
|
||||||
|
if (!matched_clause)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tempgroup = lappend(tempgroup, matched_clause);
|
||||||
|
jfound = true;
|
||||||
|
}
|
||||||
|
foreach (curCinfo,restr_cinfo_list)
|
||||||
|
{
|
||||||
|
CInfo *temp = (CInfo*)lfirst(curCinfo);
|
||||||
|
|
||||||
|
matched_clause = match_clause_to_indexkey (rel,
|
||||||
|
index,
|
||||||
|
curIndxKey,
|
||||||
|
curClass,
|
||||||
|
temp,
|
||||||
|
false);
|
||||||
|
if (!matched_clause)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tempgroup = lappend(tempgroup, matched_clause);
|
||||||
|
}
|
||||||
|
if ( tempgroup == NIL )
|
||||||
|
break;
|
||||||
|
|
||||||
|
clausegroup = nconc (clausegroup, tempgroup);
|
||||||
|
|
||||||
|
indexkeys++;
|
||||||
|
classes++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clausegroup holds all matched clauses ordered by indexkeys */
|
||||||
|
|
||||||
|
if (clausegroup != NIL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* if no one join clause was matched then there ain't clauses
|
||||||
|
* for joins at all.
|
||||||
|
*/
|
||||||
|
if ( !jfound )
|
||||||
|
{
|
||||||
|
freeList (clausegroup);
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
return(lcons(clausegroup, NIL));
|
||||||
|
}
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IndexScanableClause () MACRO
|
* IndexScanableClause () MACRO
|
||||||
*
|
*
|
||||||
@ -482,6 +579,7 @@ match_clause_to_indexkey(Rel *rel,
|
|||||||
Expr *clause = clauseInfo->clause;
|
Expr *clause = clauseInfo->clause;
|
||||||
Var *leftop, *rightop;
|
Var *leftop, *rightop;
|
||||||
Oid join_op = InvalidOid;
|
Oid join_op = InvalidOid;
|
||||||
|
Oid restrict_op = InvalidOid;
|
||||||
bool isIndexable = false;
|
bool isIndexable = false;
|
||||||
|
|
||||||
if (or_clause((Node*)clause) ||
|
if (or_clause((Node*)clause) ||
|
||||||
@ -496,8 +594,6 @@ match_clause_to_indexkey(Rel *rel,
|
|||||||
*/
|
*/
|
||||||
if (!join)
|
if (!join)
|
||||||
{
|
{
|
||||||
Oid restrict_op = InvalidOid;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for standard s-argable clause
|
* Check for standard s-argable clause
|
||||||
*/
|
*/
|
||||||
@ -542,9 +638,6 @@ match_clause_to_indexkey(Rel *rel,
|
|||||||
* In place list modification.
|
* In place list modification.
|
||||||
* (op const var/func) -> (op var/func const)
|
* (op const var/func) -> (op var/func const)
|
||||||
*/
|
*/
|
||||||
/* BUG! Old version:
|
|
||||||
CommuteClause(clause, restrict_op);
|
|
||||||
*/
|
|
||||||
CommuteClause((Node*)clause);
|
CommuteClause((Node*)clause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -556,13 +649,15 @@ match_clause_to_indexkey(Rel *rel,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (rightop
|
if (rightop
|
||||||
&& match_index_to_operand(indexkey,(Expr*)rightop,rel,index)) {
|
&& match_index_to_operand(indexkey,(Expr*)rightop,rel,index))
|
||||||
|
{
|
||||||
|
|
||||||
join_op = get_commutator(((Oper*)((Expr*)clause)->oper)->opno);
|
join_op = get_commutator(((Oper*)((Expr*)clause)->oper)->opno);
|
||||||
|
|
||||||
} else if (leftop
|
} else if (leftop
|
||||||
&& match_index_to_operand(indexkey,
|
&& match_index_to_operand(indexkey,
|
||||||
(Expr*)leftop,rel,index)) {
|
(Expr*)leftop,rel,index))
|
||||||
|
{
|
||||||
join_op = ((Oper*)((Expr*)clause)->oper)->opno;
|
join_op = ((Oper*)((Expr*)clause)->oper)->opno;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,9 +1051,14 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
|
|||||||
*
|
*
|
||||||
* Returns a list of these clause groups.
|
* Returns a list of these clause groups.
|
||||||
*
|
*
|
||||||
|
* Added: clauseinfo_list - list of restriction CInfos. It's to
|
||||||
|
* support multi-column indices in joins and for cases
|
||||||
|
* when a key is in both join & restriction clauses. - vadim 03/18/97
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
static List *
|
static List *
|
||||||
indexable_joinclauses(Rel *rel, Rel *index, List *joininfo_list)
|
indexable_joinclauses(Rel *rel, Rel *index,
|
||||||
|
List *joininfo_list, List *clauseinfo_list)
|
||||||
{
|
{
|
||||||
JInfo *joininfo = (JInfo*)NULL;
|
JInfo *joininfo = (JInfo*)NULL;
|
||||||
List *cg_list = NIL;
|
List *cg_list = NIL;
|
||||||
@ -967,13 +1067,16 @@ indexable_joinclauses(Rel *rel, Rel *index, List *joininfo_list)
|
|||||||
|
|
||||||
foreach(i,joininfo_list) {
|
foreach(i,joininfo_list) {
|
||||||
joininfo = (JInfo*)lfirst(i);
|
joininfo = (JInfo*)lfirst(i);
|
||||||
|
|
||||||
|
if ( joininfo->jinfoclauseinfo == NIL )
|
||||||
|
continue;
|
||||||
clausegroups =
|
clausegroups =
|
||||||
group_clauses_by_indexkey (rel,
|
group_clauses_by_ikey_for_joins (rel,
|
||||||
index,
|
index,
|
||||||
index->indexkeys,
|
index->indexkeys,
|
||||||
index->classlist,
|
index->classlist,
|
||||||
joininfo->jinfoclauseinfo,
|
joininfo->jinfoclauseinfo,
|
||||||
true);
|
clauseinfo_list);
|
||||||
|
|
||||||
if (clausegroups != NIL) {
|
if (clausegroups != NIL) {
|
||||||
List *clauses = lfirst(clausegroups);
|
List *clauses = lfirst(clausegroups);
|
||||||
@ -1056,6 +1159,7 @@ index_innerjoin(Query *root, Rel *rel, List *clausegroup_list, Rel *index)
|
|||||||
pathnode->path.pathtype = T_IndexScan;
|
pathnode->path.pathtype = T_IndexScan;
|
||||||
pathnode->path.parent = rel;
|
pathnode->path.parent = rel;
|
||||||
pathnode->indexid = index->relids;
|
pathnode->indexid = index->relids;
|
||||||
|
pathnode->indexkeys = index->indexkeys;
|
||||||
pathnode->indexqual = clausegroup;
|
pathnode->indexqual = clausegroup;
|
||||||
|
|
||||||
pathnode->path.joinid = ((CInfo*)lfirst(clausegroup))->cinfojoinid;
|
pathnode->path.joinid = ((CInfo*)lfirst(clausegroup))->cinfojoinid;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.8 1997/03/12 21:05:56 scrappy Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.9 1997/03/18 18:40:05 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -418,21 +418,34 @@ create_nestloop_node(JoinPath *best_path,
|
|||||||
|
|
||||||
if (IsA(inner_node,IndexScan)) {
|
if (IsA(inner_node,IndexScan)) {
|
||||||
/* An index is being used to reduce the number of tuples scanned in
|
/* An index is being used to reduce the number of tuples scanned in
|
||||||
* the inner relation.
|
* the inner relation. There will never be more than one index used
|
||||||
* There will never be more than one index used in the inner
|
* in the inner scan path, so we need only consider the first set of
|
||||||
* scan path, so we need only consider the first set of
|
|
||||||
* qualifications in indxqual.
|
* qualifications in indxqual.
|
||||||
|
*
|
||||||
|
* But there may be more than one clauses in this "first set"
|
||||||
|
* in the case of multi-column indices. - vadim 03/18/97
|
||||||
*/
|
*/
|
||||||
|
|
||||||
List *inner_indxqual = lfirst(((IndexScan*)inner_node)->indxqual);
|
List *inner_indxqual = lfirst(((IndexScan*)inner_node)->indxqual);
|
||||||
List *inner_qual = (inner_indxqual == NULL)? NULL:lfirst(inner_indxqual);
|
List *inner_qual;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
foreach (inner_qual, inner_indxqual)
|
||||||
|
{
|
||||||
|
if ( !(qual_clause_p ((Node*)inner_qual)) )
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we have in fact found a join index qualification, remove these
|
/* If we have in fact found a join index qualification, remove these
|
||||||
* index clauses from the nestloop's join clauses and reset the
|
* index clauses from the nestloop's join clauses and reset the
|
||||||
* inner(index) scan's qualification so that the var nodes refer to
|
* inner(index) scan's qualification so that the var nodes refer to
|
||||||
* the proper outer join relation attributes.
|
* the proper outer join relation attributes.
|
||||||
*/
|
*/
|
||||||
if (!(qual_clause_p((Node*)inner_qual))) {
|
if ( found )
|
||||||
|
{
|
||||||
List *new_inner_qual = NIL;
|
List *new_inner_qual = NIL;
|
||||||
|
|
||||||
clauses = set_difference(clauses,inner_indxqual);
|
clauses = set_difference(clauses,inner_indxqual);
|
||||||
@ -613,7 +626,7 @@ fix_indxqual_references(Node *clause, Path *index_path)
|
|||||||
if (lfirsti(index_path->parent->relids) == ((Var*)clause)->varno) {
|
if (lfirsti(index_path->parent->relids) == ((Var*)clause)->varno) {
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
int varatt = ((Var*)clause)->varattno;
|
int varatt = ((Var*)clause)->varattno;
|
||||||
int *indexkeys = index_path->parent->indexkeys;
|
int *indexkeys = ((IndexPath*)index_path)->indexkeys;
|
||||||
|
|
||||||
if (indexkeys) {
|
if (indexkeys) {
|
||||||
while (indexkeys[pos] != 0) {
|
while (indexkeys[pos] != 0) {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.1.1.1 1996/07/09 06:21:38 scrappy Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.2 1997/03/18 18:40:40 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -248,10 +248,11 @@ create_index_path(Query *root,
|
|||||||
|
|
||||||
pathnode->path.pathtype = T_IndexScan;
|
pathnode->path.pathtype = T_IndexScan;
|
||||||
pathnode->path.parent = rel;
|
pathnode->path.parent = rel;
|
||||||
pathnode->indexid = index->relids;
|
|
||||||
|
|
||||||
pathnode->path.p_ordering.ordtype = SORTOP_ORDER;
|
pathnode->path.p_ordering.ordtype = SORTOP_ORDER;
|
||||||
pathnode->path.p_ordering.ord.sortop = index->ordering;
|
pathnode->path.p_ordering.ord.sortop = index->ordering;
|
||||||
|
|
||||||
|
pathnode->indexid = index->relids;
|
||||||
|
pathnode->indexkeys = index->indexkeys;
|
||||||
pathnode->indexqual = NIL;
|
pathnode->indexqual = NIL;
|
||||||
|
|
||||||
/* copy clauseinfo list into path for expensive function processing
|
/* copy clauseinfo list into path for expensive function processing
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: nbtree.h,v 1.9 1997/02/22 10:08:27 vadim Exp $
|
* $Id: nbtree.h,v 1.10 1997/03/18 18:41:16 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -68,6 +68,7 @@ typedef struct BTScanOpaqueData {
|
|||||||
Buffer btso_mrkbuf;
|
Buffer btso_mrkbuf;
|
||||||
uint16 qual_ok; /* 0 for quals like key == 1 && key > 2 */
|
uint16 qual_ok; /* 0 for quals like key == 1 && key > 2 */
|
||||||
uint16 numberOfKeys; /* number of key attributes */
|
uint16 numberOfKeys; /* number of key attributes */
|
||||||
|
uint16 numberOfFirstKeys; /* number of first key attributes */
|
||||||
ScanKey keyData; /* key descriptor */
|
ScanKey keyData; /* key descriptor */
|
||||||
} BTScanOpaqueData;
|
} BTScanOpaqueData;
|
||||||
|
|
||||||
@ -270,9 +271,9 @@ extern bool _bt_invokestrat(Relation rel, AttrNumber attno,
|
|||||||
extern ScanKey _bt_mkscankey(Relation rel, IndexTuple itup);
|
extern ScanKey _bt_mkscankey(Relation rel, IndexTuple itup);
|
||||||
extern void _bt_freeskey(ScanKey skey);
|
extern void _bt_freeskey(ScanKey skey);
|
||||||
extern void _bt_freestack(BTStack stack);
|
extern void _bt_freestack(BTStack stack);
|
||||||
extern void _bt_orderkeys(Relation relation, uint16 *numberOfKeys,
|
extern void _bt_orderkeys(Relation relation, BTScanOpaque so);
|
||||||
ScanKey key, uint16 *qual_ok);
|
|
||||||
extern bool _bt_checkqual(IndexScanDesc scan, IndexTuple itup);
|
extern bool _bt_checkqual(IndexScanDesc scan, IndexTuple itup);
|
||||||
|
extern bool _bt_checkforkeys(IndexScanDesc scan, IndexTuple itup, Size keysz);
|
||||||
extern BTItem _bt_formitem(IndexTuple itup);
|
extern BTItem _bt_formitem(IndexTuple itup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: relation.h,v 1.3 1996/11/06 07:44:18 scrappy Exp $
|
* $Id: relation.h,v 1.4 1997/03/18 18:41:37 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -150,6 +150,7 @@ typedef struct IndexPath {
|
|||||||
Path path;
|
Path path;
|
||||||
List *indexid;
|
List *indexid;
|
||||||
List *indexqual;
|
List *indexqual;
|
||||||
|
int *indexkeys; /* to transform heap attnos into index ones */
|
||||||
} IndexPath;
|
} IndexPath;
|
||||||
|
|
||||||
typedef struct JoinPath {
|
typedef struct JoinPath {
|
||||||
|
Reference in New Issue
Block a user