Commit 9e8da0f7 authored by Tom Lane's avatar Tom Lane

Teach btree to handle ScalarArrayOpExpr quals natively.

This allows "indexedcol op ANY(ARRAY[...])" conditions to be used in plain
indexscans, and particularly in index-only scans.
parent 0898d71f
......@@ -491,6 +491,13 @@
for the first index column?</entry>
</row>
<row>
<entry><structfield>amsearcharray</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
<entry>Does the access method support <literal>ScalarArrayOpExpr</> searches?</entry>
</row>
<row>
<entry><structfield>amsearchnulls</structfield></entry>
<entry><type>bool</type></entry>
......
......@@ -276,11 +276,30 @@ btgettuple(PG_FUNCTION_ARGS)
scan->xs_recheck = false;
/*
* If we've already initialized this scan, we can just advance it in the
* appropriate direction. If we haven't done so yet, we call a routine to
* get the first item in the scan.
* If we have any array keys, initialize them during first call for a
* scan. We can't do this in btrescan because we don't know the scan
* direction at that time.
*/
if (BTScanPosIsValid(so->currPos))
if (so->numArrayKeys && !BTScanPosIsValid(so->currPos))
{
/* punt if we have any unsatisfiable array keys */
if (so->numArrayKeys < 0)
PG_RETURN_BOOL(false);
_bt_start_array_keys(scan, dir);
}
/* This loop handles advancing to the next array elements, if any */
do
{
/*
* If we've already initialized this scan, we can just advance it in
* the appropriate direction. If we haven't done so yet, we call
* _bt_first() to get the first item in the scan.
*/
if (!BTScanPosIsValid(so->currPos))
res = _bt_first(scan, dir);
else
{
/*
* Check to see if we should kill the previously-fetched tuple.
......@@ -288,12 +307,13 @@ btgettuple(PG_FUNCTION_ARGS)
if (scan->kill_prior_tuple)
{
/*
* Yes, remember it for later. (We'll deal with all such tuples
* at once right before leaving the index page.) The test for
* numKilled overrun is not just paranoia: if the caller reverses
* direction in the indexscan then the same item might get entered
* multiple times. It's not worth trying to optimize that, so we
* don't detect it, but instead just forget any excess entries.
* Yes, remember it for later. (We'll deal with all such
* tuples at once right before leaving the index page.) The
* test for numKilled overrun is not just paranoia: if the
* caller reverses direction in the indexscan then the same
* item might get entered multiple times. It's not worth
* trying to optimize that, so we don't detect it, but instead
* just forget any excess entries.
*/
if (so->killedItems == NULL)
so->killedItems = (int *)
......@@ -307,8 +327,12 @@ btgettuple(PG_FUNCTION_ARGS)
*/
res = _bt_next(scan, dir);
}
else
res = _bt_first(scan, dir);
/* If we have a tuple, return it ... */
if (res)
break;
/* ... otherwise see if we have more array keys to deal with */
} while (so->numArrayKeys && _bt_advance_array_keys(scan, dir));
PG_RETURN_BOOL(res);
}
......@@ -325,12 +349,24 @@ btgetbitmap(PG_FUNCTION_ARGS)
int64 ntids = 0;
ItemPointer heapTid;
/* Fetch the first page & tuple. */
if (!_bt_first(scan, ForwardScanDirection))
/*
* If we have any array keys, initialize them.
*/
if (so->numArrayKeys)
{
/* empty scan */
PG_RETURN_INT64(0);
/* punt if we have any unsatisfiable array keys */
if (so->numArrayKeys < 0)
PG_RETURN_INT64(ntids);
_bt_start_array_keys(scan, ForwardScanDirection);
}
/* This loop handles advancing to the next array elements, if any */
do
{
/* Fetch the first page & tuple */
if (_bt_first(scan, ForwardScanDirection))
{
/* Save tuple ID, and continue scanning */
heapTid = &scan->xs_ctup.t_self;
tbm_add_tuples(tbm, heapTid, 1, false);
......@@ -339,8 +375,8 @@ btgetbitmap(PG_FUNCTION_ARGS)
for (;;)
{
/*
* Advance to next tuple within page. This is the same as the easy
* case in _bt_next().
* Advance to next tuple within page. This is the same as the
* easy case in _bt_next().
*/
if (++so->currPos.itemIndex > so->currPos.lastItem)
{
......@@ -354,6 +390,9 @@ btgetbitmap(PG_FUNCTION_ARGS)
tbm_add_tuples(tbm, heapTid, 1, false);
ntids++;
}
}
/* Now see if we have more array keys to deal with */
} while (so->numArrayKeys && _bt_advance_array_keys(scan, ForwardScanDirection));
PG_RETURN_INT64(ntids);
}
......@@ -383,6 +422,12 @@ btbeginscan(PG_FUNCTION_ARGS)
so->keyData = (ScanKey) palloc(scan->numberOfKeys * sizeof(ScanKeyData));
else
so->keyData = NULL;
so->arrayKeyData = NULL; /* assume no array keys for now */
so->numArrayKeys = 0;
so->arrayKeys = NULL;
so->arrayContext = NULL;
so->killedItems = NULL; /* until needed */
so->numKilled = 0;
......@@ -460,6 +505,9 @@ btrescan(PG_FUNCTION_ARGS)
scan->numberOfKeys * sizeof(ScanKeyData));
so->numberOfKeys = 0; /* until _bt_preprocess_keys sets it */
/* If any keys are SK_SEARCHARRAY type, set up array-key info */
_bt_preprocess_array_keys(scan);
PG_RETURN_VOID();
}
......@@ -490,10 +538,13 @@ btendscan(PG_FUNCTION_ARGS)
so->markItemIndex = -1;
/* Release storage */
if (so->killedItems != NULL)
pfree(so->killedItems);
if (so->keyData != NULL)
pfree(so->keyData);
/* so->arrayKeyData and so->arrayKeys are in arrayContext */
if (so->arrayContext != NULL)
MemoryContextDelete(so->arrayContext);
if (so->killedItems != NULL)
pfree(so->killedItems);
if (so->currTuples != NULL)
pfree(so->currTuples);
/* so->markTuples should not be pfree'd, see btrescan */
......
This diff is collapsed.
......@@ -647,11 +647,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
* as specified in access/skey.h. The elements of the row comparison
* can have either constant or non-constant comparison values.
*
* 4. ScalarArrayOpExpr ("indexkey op ANY (array-expression)"). For these,
* 4. ScalarArrayOpExpr ("indexkey op ANY (array-expression)"). If the index
* has rd_am->amsearcharray, we handle these the same as simple operators,
* setting the SK_SEARCHARRAY flag to tell the AM to handle them. Otherwise,
* we create a ScanKey with everything filled in except the comparison value,
* and set up an IndexArrayKeyInfo struct to drive processing of the qual.
* (Note that we treat all array-expressions as requiring runtime evaluation,
* even if they happen to be constants.)
* (Note that if we use an IndexArrayKeyInfo struct, the array expression is
* always treated as requiring runtime evaluation, even if it's a constant.)
*
* 5. NullTest ("indexkey IS NULL/IS NOT NULL"). We just fill in the
* ScanKey properly.
......@@ -680,7 +682,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
* *numArrayKeys: receives number of array keys
*
* Caller may pass NULL for arrayKeys and numArrayKeys to indicate that
* ScalarArrayOpExpr quals are not supported.
* IndexArrayKeyInfos are not supported.
*/
void
ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
......@@ -981,6 +983,8 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
{
/* indexkey op ANY (array-expression) */
ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
int flags = 0;
Datum scanvalue;
Assert(!isorderby);
......@@ -1027,23 +1031,72 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
Assert(rightop != NULL);
if (index->rd_am->amsearcharray)
{
/* Index AM will handle this like a simple operator */
flags |= SK_SEARCHARRAY;
if (IsA(rightop, Const))
{
/* OK, simple constant comparison value */
scanvalue = ((Const *) rightop)->constvalue;
if (((Const *) rightop)->constisnull)
flags |= SK_ISNULL;
}
else
{
/* Need to treat this one as a runtime key */
if (n_runtime_keys >= max_runtime_keys)
{
if (max_runtime_keys == 0)
{
max_runtime_keys = 8;
runtime_keys = (IndexRuntimeKeyInfo *)
palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
}
else
{
max_runtime_keys *= 2;
runtime_keys = (IndexRuntimeKeyInfo *)
repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
}
}
runtime_keys[n_runtime_keys].scan_key = this_scan_key;
runtime_keys[n_runtime_keys].key_expr =
ExecInitExpr(rightop, planstate);
/*
* Careful here: the runtime expression is not of
* op_righttype, but rather is an array of same; so
* TypeIsToastable() isn't helpful. However, we can
* assume that all array types are toastable.
*/
runtime_keys[n_runtime_keys].key_toastable = true;
n_runtime_keys++;
scanvalue = (Datum) 0;
}
}
else
{
/* Executor has to expand the array value */
array_keys[n_array_keys].scan_key = this_scan_key;
array_keys[n_array_keys].array_expr =
ExecInitExpr(rightop, planstate);
/* the remaining fields were zeroed by palloc0 */
n_array_keys++;
scanvalue = (Datum) 0;
}
/*
* initialize the scan key's fields appropriately
*/
ScanKeyEntryInitialize(this_scan_key,
0, /* flags */
flags,
varattno, /* attribute number to scan */
op_strategy, /* op's strategy */
op_righttype, /* strategy subtype */
saop->inputcollid, /* collation */
opfuncid, /* reg proc to use */
(Datum) 0); /* constant */
scanvalue); /* constant */
}
else if (IsA(clause, NullTest))
{
......
......@@ -394,10 +394,15 @@ cost_index(IndexPath *path, PlannerInfo *root,
if (indexonly)
pages_fetched = ceil(pages_fetched * (1.0 - baserel->allvisfrac));
if (pages_fetched > 0)
{
min_IO_cost = spc_random_page_cost;
if (pages_fetched > 1)
min_IO_cost += (pages_fetched - 1) * spc_seq_page_cost;
}
else
min_IO_cost = 0;
}
/*
* Now interpolate based on estimated index order correlation to get total
......
......@@ -48,9 +48,9 @@
/* Whether to use ScalarArrayOpExpr to build index qualifications */
typedef enum
{
SAOP_FORBID, /* Do not use ScalarArrayOpExpr */
SAOP_ALLOW, /* OK to use ScalarArrayOpExpr */
SAOP_REQUIRE /* Require ScalarArrayOpExpr */
SAOP_PER_AM, /* Use ScalarArrayOpExpr if amsearcharray */
SAOP_ALLOW, /* Use ScalarArrayOpExpr for all indexes */
SAOP_REQUIRE /* Require ScalarArrayOpExpr to be used */
} SaOpControl;
/* Whether we are looking for plain indexscan, bitmap scan, or either */
......@@ -196,7 +196,7 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
*/
indexpaths = find_usable_indexes(root, rel,
rel->baserestrictinfo, NIL,
true, NULL, SAOP_FORBID, ST_ANYSCAN);
true, NULL, SAOP_PER_AM, ST_ANYSCAN);
/*
* Submit all the ones that can form plain IndexScan plans to add_path.
......@@ -233,8 +233,9 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
bitindexpaths = list_concat(bitindexpaths, indexpaths);
/*
* Likewise, generate paths using ScalarArrayOpExpr clauses; these can't
* be simple indexscans but they can be used in bitmap scans.
* Likewise, generate paths using executor-managed ScalarArrayOpExpr
* clauses; these can't be simple indexscans but they can be used in
* bitmap scans.
*/
indexpaths = find_saop_paths(root, rel,
rel->baserestrictinfo, NIL,
......@@ -337,6 +338,14 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
break;
}
/*
* If we're doing find_saop_paths(), we can skip indexes that support
* ScalarArrayOpExpr natively. We already generated all the potential
* indexpaths for them, so no need to do anything more.
*/
if (saop_control == SAOP_REQUIRE && index->amsearcharray)
continue;
/*
* Ignore partial indexes that do not match the query. If a partial
* index is marked predOK then we know it's OK; otherwise, if we are
......@@ -492,10 +501,10 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
/*
* find_saop_paths
* Find all the potential indexpaths that make use of ScalarArrayOpExpr
* clauses. The executor only supports these in bitmap scans, not
* plain indexscans, so we need to segregate them from the normal case.
* Otherwise, same API as find_usable_indexes().
* Find all the potential indexpaths that make use of executor-managed
* ScalarArrayOpExpr clauses. The executor only supports these in bitmap
* scans, not plain indexscans, so we need to segregate them from the
* normal case. Otherwise, same API as find_usable_indexes().
* Returns a list of IndexPaths.
*/
static List *
......@@ -1287,9 +1296,10 @@ group_clauses_by_indexkey(IndexOptInfo *index,
* expand_indexqual_rowcompare().
*
* It is also possible to match ScalarArrayOpExpr clauses to indexes, when
* the clause is of the form "indexkey op ANY (arrayconst)". Since the
* executor can only handle these in the context of bitmap index scans,
* our caller specifies whether to allow these or not.
* the clause is of the form "indexkey op ANY (arrayconst)". Since not
* all indexes handle these natively, and the executor implements them
* only in the context of bitmap index scans, our caller specifies whether
* to allow these or not.
*
* For boolean indexes, it is also possible to match the clause directly
* to the indexkey; or perhaps the clause is (NOT indexkey).
......@@ -1357,8 +1367,8 @@ match_clause_to_indexcol(IndexOptInfo *index,
expr_coll = ((OpExpr *) clause)->inputcollid;
plain_op = true;
}
else if (saop_control != SAOP_FORBID &&
clause && IsA(clause, ScalarArrayOpExpr))
else if (clause && IsA(clause, ScalarArrayOpExpr) &&
(index->amsearcharray || saop_control != SAOP_PER_AM))
{
ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
......@@ -2089,12 +2099,12 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
/*
* Find all the index paths that are usable for this join, except for
* stuff involving OR and ScalarArrayOpExpr clauses.
* stuff involving OR and executor-managed ScalarArrayOpExpr clauses.
*/
allindexpaths = find_usable_indexes(root, rel,
clause_list, NIL,
false, outer_rel,
SAOP_FORBID,
SAOP_PER_AM,
ST_ANYSCAN);
/*
......@@ -2123,8 +2133,9 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
outer_rel));
/*
* Likewise, generate paths using ScalarArrayOpExpr clauses; these can't
* be simple indexscans but they can be used in bitmap scans.
* Likewise, generate paths using executor-managed ScalarArrayOpExpr
* clauses; these can't be simple indexscans but they can be used in
* bitmap scans.
*/
bitindexpaths = list_concat(bitindexpaths,
find_saop_paths(root, rel,
......
......@@ -215,6 +215,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
info->amcanorderbyop = indexRelation->rd_am->amcanorderbyop;
info->amcanreturn = indexRelation->rd_am->amcanreturn;
info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
info->amsearcharray = indexRelation->rd_am->amsearcharray;
info->amsearchnulls = indexRelation->rd_am->amsearchnulls;
info->amhasgettuple = OidIsValid(indexRelation->rd_am->amgettuple);
info->amhasgetbitmap = OidIsValid(indexRelation->rd_am->amgetbitmap);
......
......@@ -6385,14 +6385,7 @@ btcostestimate(PG_FUNCTION_ARGS)
* is that multiple columns dilute the importance of the first column's
* ordering, but don't negate it entirely. Before 8.0 we divided the
* correlation by the number of columns, but that seems too strong.)
*
* We can skip all this if we found a ScalarArrayOpExpr, because then the
* call must be for a bitmap index scan, and the caller isn't going to
* care what the index correlation is.
*/
if (found_saop)
PG_RETURN_VOID();
MemSet(&vardata, 0, sizeof(vardata));
if (index->indexkeys[0] != 0)
......
......@@ -525,6 +525,15 @@ typedef BTScanPosData *BTScanPos;
#define BTScanPosIsValid(scanpos) BufferIsValid((scanpos).buf)
/* We need one of these for each equality-type SK_SEARCHARRAY scan key */
typedef struct BTArrayKeyInfo
{
int scan_key; /* index of associated key in arrayKeyData */
int cur_elem; /* index of current element in elem_values */
int num_elems; /* number of elems in current array value */
Datum *elem_values; /* array of num_elems Datums */
} BTArrayKeyInfo;
typedef struct BTScanOpaqueData
{
/* these fields are set by _bt_preprocess_keys(): */
......@@ -532,6 +541,13 @@ typedef struct BTScanOpaqueData
int numberOfKeys; /* number of preprocessed scan keys */
ScanKey keyData; /* array of preprocessed scan keys */
/* workspace for SK_SEARCHARRAY support */
ScanKey arrayKeyData; /* modified copy of scan->keyData */
int numArrayKeys; /* number of equality-type array keys (-1 if
* there are any unsatisfiable array keys) */
BTArrayKeyInfo *arrayKeys; /* info about each equality-type array key */
MemoryContext arrayContext; /* scan-lifespan context for array data */
/* info about killed items if any (killedItems is NULL if never used) */
int *killedItems; /* currPos.items indexes of killed items */
int numKilled; /* number of currently stored items */
......@@ -639,6 +655,9 @@ extern ScanKey _bt_mkscankey(Relation rel, IndexTuple itup);
extern ScanKey _bt_mkscankey_nodata(Relation rel);
extern void _bt_freeskey(ScanKey skey);
extern void _bt_freestack(BTStack stack);
extern void _bt_preprocess_array_keys(IndexScanDesc scan);
extern void _bt_start_array_keys(IndexScanDesc scan, ScanDirection dir);
extern bool _bt_advance_array_keys(IndexScanDesc scan, ScanDirection dir);
extern void _bt_preprocess_keys(IndexScanDesc scan);
extern IndexTuple _bt_checkkeys(IndexScanDesc scan,
Page page, OffsetNumber offnum,
......
......@@ -55,18 +55,27 @@ typedef uint16 StrategyNumber;
* If the operator is collation-sensitive, sk_collation must be set
* correctly as well.
*
* A ScanKey can also represent a ScalarArrayOpExpr, that is a condition
* "column op ANY(ARRAY[...])". This is signaled by the SK_SEARCHARRAY
* flag bit. The sk_argument is not a value of the operator's right-hand
* argument type, but rather an array of such values, and the per-element
* comparisons are to be ORed together.
*
* A ScanKey can also represent a condition "column IS NULL" or "column
* IS NOT NULL"; these cases are signaled by the SK_SEARCHNULL and
* SK_SEARCHNOTNULL flag bits respectively. The argument is always NULL,
* and the sk_strategy, sk_subtype, sk_collation, and sk_func fields are
* not used (unless set by the index AM). Currently, SK_SEARCHNULL and
* SK_SEARCHNOTNULL are supported only for index scans, not heap scans;
* and not all index AMs support them.
* not used (unless set by the index AM).
*
* SK_SEARCHARRAY, SK_SEARCHNULL and SK_SEARCHNOTNULL are supported only
* for index scans, not heap scans; and not all index AMs support them,
* only those that set amsearcharray or amsearchnulls respectively.
*
* A ScanKey can also represent an ordering operator invocation, that is
* an ordering requirement "ORDER BY indexedcol op constant". This looks
* the same as a comparison operator, except that the operator doesn't
* (usually) yield boolean. We mark such ScanKeys with SK_ORDER_BY.
* SK_SEARCHARRAY, SK_SEARCHNULL, SK_SEARCHNOTNULL cannot be used here.
*
* Note: in some places, ScanKeys are used as a convenient representation
* for the invocation of an access method support procedure. In this case
......@@ -114,6 +123,7 @@ typedef ScanKeyData *ScanKey;
* opclass, NOT the operator's implementation function.
* sk_strategy must be the same in all elements of the subsidiary array,
* that is, the same as in the header entry.
* SK_SEARCHARRAY, SK_SEARCHNULL, SK_SEARCHNOTNULL cannot be used here.
*/
/*
......@@ -128,10 +138,11 @@ typedef ScanKeyData *ScanKey;
#define SK_ROW_HEADER 0x0004 /* row comparison header (see above) */
#define SK_ROW_MEMBER 0x0008 /* row comparison member (see above) */
#define SK_ROW_END 0x0010 /* last row comparison member */
#define SK_SEARCHNULL 0x0020 /* scankey represents "col IS NULL" */
#define SK_SEARCHNOTNULL 0x0040 /* scankey represents "col IS NOT
#define SK_SEARCHARRAY 0x0020 /* scankey represents ScalarArrayOp */
#define SK_SEARCHNULL 0x0040 /* scankey represents "col IS NULL" */
#define SK_SEARCHNOTNULL 0x0080 /* scankey represents "col IS NOT
* NULL" */
#define SK_ORDER_BY 0x0080 /* scankey is for ORDER BY op */
#define SK_ORDER_BY 0x0100 /* scankey is for ORDER BY op */
/*
......
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201110141
#define CATALOG_VERSION_NO 201110161
#endif
......@@ -47,6 +47,7 @@ CATALOG(pg_am,2601)
bool amcanmulticol; /* does AM support multi-column indexes? */
bool amcanreturn; /* can AM return IndexTuples? */
bool amoptionalkey; /* can query omit key for the first column? */
bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */
bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */
bool amstorage; /* can storage type differ from column type? */
bool amclusterable; /* does AM support cluster command? */
......@@ -79,7 +80,7 @@ typedef FormData_pg_am *Form_pg_am;
* compiler constants for pg_am
* ----------------
*/
#define Natts_pg_am 29
#define Natts_pg_am 30
#define Anum_pg_am_amname 1
#define Anum_pg_am_amstrategies 2
#define Anum_pg_am_amsupport 3
......@@ -90,41 +91,42 @@ typedef FormData_pg_am *Form_pg_am;
#define Anum_pg_am_amcanmulticol 8
#define Anum_pg_am_amcanreturn 9
#define Anum_pg_am_amoptionalkey 10
#define Anum_pg_am_amsearchnulls 11
#define Anum_pg_am_amstorage 12
#define Anum_pg_am_amclusterable 13
#define Anum_pg_am_ampredlocks 14
#define Anum_pg_am_amkeytype 15
#define Anum_pg_am_aminsert 16
#define Anum_pg_am_ambeginscan 17
#define Anum_pg_am_amgettuple 18
#define Anum_pg_am_amgetbitmap 19
#define Anum_pg_am_amrescan 20
#define Anum_pg_am_amendscan 21
#define Anum_pg_am_ammarkpos 22
#define Anum_pg_am_amrestrpos 23
#define Anum_pg_am_ambuild 24
#define Anum_pg_am_ambuildempty 25
#define Anum_pg_am_ambulkdelete 26
#define Anum_pg_am_amvacuumcleanup 27
#define Anum_pg_am_amcostestimate 28
#define Anum_pg_am_amoptions 29
#define Anum_pg_am_amsearcharray 11
#define Anum_pg_am_amsearchnulls 12
#define Anum_pg_am_amstorage 13
#define Anum_pg_am_amclusterable 14
#define Anum_pg_am_ampredlocks 15
#define Anum_pg_am_amkeytype 16
#define Anum_pg_am_aminsert 17
#define Anum_pg_am_ambeginscan 18
#define Anum_pg_am_amgettuple 19
#define Anum_pg_am_amgetbitmap 20
#define Anum_pg_am_amrescan 21
#define Anum_pg_am_amendscan 22
#define Anum_pg_am_ammarkpos 23
#define Anum_pg_am_amrestrpos 24
#define Anum_pg_am_ambuild 25
#define Anum_pg_am_ambuildempty 26
#define Anum_pg_am_ambulkdelete 27
#define Anum_pg_am_amvacuumcleanup 28
#define Anum_pg_am_amcostestimate 29
#define Anum_pg_am_amoptions 30
/* ----------------
* initial contents of pg_am
* ----------------
*/
DATA(insert OID = 403 ( btree 5 1 t f t t t t t t f t t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbuildempty btbulkdelete btvacuumcleanup btcostestimate btoptions ));
DATA(insert OID = 403 ( btree 5 1 t f t t t t t t t f t t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbuildempty btbulkdelete btvacuumcleanup btcostestimate btoptions ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
DATA(insert OID = 405 ( hash 1 1 f f t f f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbuildempty hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
DATA(insert OID = 405 ( hash 1 1 f f t f f f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbuildempty hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
DESCR("hash index access method");
#define HASH_AM_OID 405
DATA(insert OID = 783 ( gist 0 8 f t f f t f t t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
DATA(insert OID = 783 ( gist 0 8 f t f f t f t f t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
DATA(insert OID = 2742 ( gin 0 5 f f f f t f t f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
DATA(insert OID = 2742 ( gin 0 5 f f f f t f t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
......
......@@ -490,8 +490,9 @@ typedef struct IndexOptInfo
bool unique; /* true if a unique index */
bool hypothetical; /* true if index doesn't really exist */
bool amcanorderbyop; /* does AM support order by operator result? */
bool amcanreturn; /* does AM know how to return tuples? */
bool amcanreturn; /* can AM return IndexTuples? */
bool amoptionalkey; /* can query omit key for the first column? */
bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */
bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */
bool amhasgettuple; /* does AM have amgettuple interface? */
bool amhasgetbitmap; /* does AM have amgetbitmap interface? */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment