diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-12-02 20:50:48 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-12-02 20:51:37 -0500 |
commit | d583f10b7e0b9e1ed18f339f3177ed42ac2f7570 (patch) | |
tree | dab8027658ca6bf21b0199c15c5f775578d645c9 /src/backend/executor/nodeIndexscan.c | |
parent | d7e5d151daa2d5fe096953ae0b3530707b7c87f5 (diff) | |
download | postgresql-d583f10b7e0b9e1ed18f339f3177ed42ac2f7570.tar.gz postgresql-d583f10b7e0b9e1ed18f339f3177ed42ac2f7570.zip |
Create core infrastructure for KNNGIST.
This is a heavily revised version of builtin_knngist_core-0.9. The
ordering operators are no longer mixed in with actual quals, which would
have confused not only humans but significant parts of the planner.
Instead, ordering operators are carried separately throughout planning and
execution.
Since the API for ambeginscan and amrescan functions had to be changed
anyway, this commit takes the opportunity to rationalize that a bit.
RelationGetIndexScan no longer forces a premature index_rescan call;
instead, callers of index_beginscan must call index_rescan too. Aside from
making the AM-side initialization logic a bit less peculiar, this has the
advantage that we do not make a useless extra am_rescan call when there are
runtime key values. AMs formerly could not assume that the key values
passed to amrescan were actually valid; now they can.
Teodor Sigaev and Tom Lane
Diffstat (limited to 'src/backend/executor/nodeIndexscan.c')
-rw-r--r-- | src/backend/executor/nodeIndexscan.c | 160 |
1 files changed, 114 insertions, 46 deletions
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index ee5fc72c209..3aed2960d3f 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -181,7 +181,9 @@ ExecReScanIndexScan(IndexScanState *node) node->iss_RuntimeKeysReady = true; /* reset index scan */ - index_rescan(node->iss_ScanDesc, node->iss_ScanKeys); + index_rescan(node->iss_ScanDesc, + node->iss_ScanKeys, node->iss_NumScanKeys, + node->iss_OrderByKeys, node->iss_NumOrderByKeys); ExecScanReScan(&node->ss); } @@ -480,10 +482,11 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) * initialize child expressions * * Note: we don't initialize all of the indexqual expression, only the - * sub-parts corresponding to runtime keys (see below). The indexqualorig - * expression is always initialized even though it will only be used in - * some uncommon cases --- would be nice to improve that. (Problem is - * that any SubPlans present in the expression must be found now...) + * sub-parts corresponding to runtime keys (see below). Likewise for + * indexorderby, if any. But the indexqualorig expression is always + * initialized even though it will only be used in some uncommon cases --- + * would be nice to improve that. (Problem is that any SubPlans present + * in the expression must be found now...) */ indexstate->ss.ps.targetlist = (List *) ExecInitExpr((Expr *) node->scan.plan.targetlist, @@ -543,6 +546,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) * Initialize index-specific scan state */ indexstate->iss_RuntimeKeysReady = false; + indexstate->iss_RuntimeKeys = NULL; + indexstate->iss_NumRuntimeKeys = 0; /* * build the index scan keys from the index qualification @@ -551,6 +556,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) indexstate->iss_RelationDesc, node->scan.scanrelid, node->indexqual, + false, &indexstate->iss_ScanKeys, &indexstate->iss_NumScanKeys, &indexstate->iss_RuntimeKeys, @@ -559,6 +565,21 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) NULL); /* + * any ORDER BY exprs have to be turned into scankeys in the same way + */ + ExecIndexBuildScanKeys((PlanState *) indexstate, + indexstate->iss_RelationDesc, + node->scan.scanrelid, + node->indexorderby, + true, + &indexstate->iss_OrderByKeys, + &indexstate->iss_NumOrderByKeys, + &indexstate->iss_RuntimeKeys, + &indexstate->iss_NumRuntimeKeys, + NULL, /* no ArrayKeys */ + NULL); + + /* * If we have runtime keys, we need an ExprContext to evaluate them. The * node's standard context won't do because we want to reset that context * for every tuple. So, build another context just like the other one... @@ -584,7 +605,16 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) indexstate->iss_RelationDesc, estate->es_snapshot, indexstate->iss_NumScanKeys, - indexstate->iss_ScanKeys); + indexstate->iss_NumOrderByKeys); + + /* + * If no run-time keys to calculate, go ahead and pass the scankeys to + * the index AM. + */ + if (indexstate->iss_NumRuntimeKeys == 0) + index_rescan(indexstate->iss_ScanDesc, + indexstate->iss_ScanKeys, indexstate->iss_NumScanKeys, + indexstate->iss_OrderByKeys, indexstate->iss_NumOrderByKeys); /* * all done. @@ -624,12 +654,20 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) * 5. NullTest ("indexkey IS NULL/IS NOT NULL"). We just fill in the * ScanKey properly. * + * This code is also used to prepare ORDER BY expressions for amcanorderbyop + * indexes. The behavior is exactly the same, except that we have to look up + * the operator differently. Note that only cases 1 and 2 are currently + * possible for ORDER BY. + * * Input params are: * * planstate: executor state node we are working for * index: the index we are building scan keys for * scanrelid: varno of the index's relation within current query - * quals: indexquals expressions + * quals: indexquals (or indexorderbys) expressions + * isorderby: true if processing ORDER BY exprs, false if processing quals + * *runtimeKeys: ptr to pre-existing IndexRuntimeKeyInfos, or NULL if none + * *numRuntimeKeys: number of pre-existing runtime keys * * Output params are: * @@ -645,7 +683,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) */ void ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, - List *quals, ScanKey *scanKeys, int *numScanKeys, + List *quals, bool isorderby, + ScanKey *scanKeys, int *numScanKeys, IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, IndexArrayKeyInfo **arrayKeys, int *numArrayKeys) { @@ -654,43 +693,31 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, IndexRuntimeKeyInfo *runtime_keys; IndexArrayKeyInfo *array_keys; int n_scan_keys; - int extra_scan_keys; int n_runtime_keys; + int max_runtime_keys; int n_array_keys; int j; + /* Allocate array for ScanKey structs: one per qual */ + n_scan_keys = list_length(quals); + scan_keys = (ScanKey) palloc(n_scan_keys * sizeof(ScanKeyData)); + /* - * If there are any RowCompareExpr quals, we need extra ScanKey entries - * for them, and possibly extra runtime-key entries. Count up what's - * needed. (The subsidiary ScanKey arrays for the RowCompareExprs could - * be allocated as separate chunks, but we have to count anyway to make - * runtime_keys large enough, so might as well just do one palloc.) + * runtime_keys array is dynamically resized as needed. We handle it + * this way so that the same runtime keys array can be shared between + * indexquals and indexorderbys, which will be processed in separate + * calls of this function. Caller must be sure to pass in NULL/0 for + * first call. */ - n_scan_keys = list_length(quals); - extra_scan_keys = 0; - foreach(qual_cell, quals) - { - if (IsA(lfirst(qual_cell), RowCompareExpr)) - extra_scan_keys += - list_length(((RowCompareExpr *) lfirst(qual_cell))->opnos); - } - scan_keys = (ScanKey) - palloc((n_scan_keys + extra_scan_keys) * sizeof(ScanKeyData)); - /* Allocate these arrays as large as they could possibly need to be */ - runtime_keys = (IndexRuntimeKeyInfo *) - palloc((n_scan_keys + extra_scan_keys) * sizeof(IndexRuntimeKeyInfo)); + runtime_keys = *runtimeKeys; + n_runtime_keys = max_runtime_keys = *numRuntimeKeys; + + /* Allocate array_keys as large as it could possibly need to be */ array_keys = (IndexArrayKeyInfo *) palloc0(n_scan_keys * sizeof(IndexArrayKeyInfo)); - n_runtime_keys = 0; n_array_keys = 0; /* - * Below here, extra_scan_keys is index of first cell to use for next - * RowCompareExpr - */ - extra_scan_keys = n_scan_keys; - - /* * for each opclause in the given qual, convert the opclause into a single * scan key */ @@ -742,11 +769,14 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, */ opfamily = index->rd_opfamily[varattno - 1]; - get_op_opfamily_properties(opno, opfamily, + get_op_opfamily_properties(opno, opfamily, isorderby, &op_strategy, &op_lefttype, &op_righttype); + if (isorderby) + flags |= SK_ORDER_BY; + /* * rightop is the constant or variable comparison value */ @@ -767,6 +797,21 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, 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); @@ -794,12 +839,19 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, ListCell *largs_cell = list_head(rc->largs); ListCell *rargs_cell = list_head(rc->rargs); ListCell *opnos_cell = list_head(rc->opnos); - ScanKey first_sub_key = &scan_keys[extra_scan_keys]; + ScanKey first_sub_key; + int n_sub_key; + + Assert(!isorderby); + + first_sub_key = (ScanKey) + palloc(list_length(rc->opnos) * sizeof(ScanKeyData)); + n_sub_key = 0; /* Scan RowCompare columns and generate subsidiary ScanKey items */ while (opnos_cell != NULL) { - ScanKey this_sub_key = &scan_keys[extra_scan_keys]; + ScanKey this_sub_key = &first_sub_key[n_sub_key]; int flags = SK_ROW_MEMBER; Datum scanvalue; @@ -832,7 +884,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, elog(ERROR, "bogus RowCompare index qualification"); opfamily = index->rd_opfamily[varattno - 1]; - get_op_opfamily_properties(opno, opfamily, + get_op_opfamily_properties(opno, opfamily, isorderby, &op_strategy, &op_lefttype, &op_righttype); @@ -866,6 +918,21 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, 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_sub_key; runtime_keys[n_runtime_keys].key_expr = ExecInitExpr(rightop, planstate); @@ -885,11 +952,11 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, op_righttype, /* strategy subtype */ opfuncid, /* reg proc to use */ scanvalue); /* constant */ - extra_scan_keys++; + n_sub_key++; } /* Mark the last subsidiary scankey correctly */ - scan_keys[extra_scan_keys - 1].sk_flags |= SK_ROW_END; + first_sub_key[n_sub_key - 1].sk_flags |= SK_ROW_END; /* * We don't use ScanKeyEntryInitialize for the header because it @@ -907,6 +974,8 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, /* indexkey op ANY (array-expression) */ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; + Assert(!isorderby); + Assert(saop->useOr); opno = saop->opno; opfuncid = saop->opfuncid; @@ -935,7 +1004,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, */ opfamily = index->rd_opfamily[varattno - 1]; - get_op_opfamily_properties(opno, opfamily, + get_op_opfamily_properties(opno, opfamily, isorderby, &op_strategy, &op_lefttype, &op_righttype); @@ -973,6 +1042,8 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, NullTest *ntest = (NullTest *) clause; int flags; + Assert(!isorderby); + /* * argument should be the index key Var, possibly relabeled */ @@ -1020,12 +1091,9 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, (int) nodeTag(clause)); } + Assert(n_runtime_keys <= max_runtime_keys); + /* Get rid of any unused arrays */ - if (n_runtime_keys == 0) - { - pfree(runtime_keys); - runtime_keys = NULL; - } if (n_array_keys == 0) { pfree(array_keys); |