Header And Logo

PostgreSQL
| The world's most advanced open source database.

nodeIndexscan.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * nodeIndexscan.c
00004  *    Routines to support indexed scans of relations
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/executor/nodeIndexscan.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 /*
00016  * INTERFACE ROUTINES
00017  *      ExecIndexScan           scans a relation using an index
00018  *      IndexNext               retrieve next tuple using index
00019  *      ExecInitIndexScan       creates and initializes state info.
00020  *      ExecReScanIndexScan     rescans the indexed relation.
00021  *      ExecEndIndexScan        releases all storage.
00022  *      ExecIndexMarkPos        marks scan position.
00023  *      ExecIndexRestrPos       restores scan position.
00024  */
00025 #include "postgres.h"
00026 
00027 #include "access/nbtree.h"
00028 #include "access/relscan.h"
00029 #include "executor/execdebug.h"
00030 #include "executor/nodeIndexscan.h"
00031 #include "optimizer/clauses.h"
00032 #include "utils/array.h"
00033 #include "utils/lsyscache.h"
00034 #include "utils/memutils.h"
00035 #include "utils/rel.h"
00036 
00037 
00038 static TupleTableSlot *IndexNext(IndexScanState *node);
00039 
00040 
00041 /* ----------------------------------------------------------------
00042  *      IndexNext
00043  *
00044  *      Retrieve a tuple from the IndexScan node's currentRelation
00045  *      using the index specified in the IndexScanState information.
00046  * ----------------------------------------------------------------
00047  */
00048 static TupleTableSlot *
00049 IndexNext(IndexScanState *node)
00050 {
00051     EState     *estate;
00052     ExprContext *econtext;
00053     ScanDirection direction;
00054     IndexScanDesc scandesc;
00055     HeapTuple   tuple;
00056     TupleTableSlot *slot;
00057 
00058     /*
00059      * extract necessary information from index scan node
00060      */
00061     estate = node->ss.ps.state;
00062     direction = estate->es_direction;
00063     /* flip direction if this is an overall backward scan */
00064     if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir))
00065     {
00066         if (ScanDirectionIsForward(direction))
00067             direction = BackwardScanDirection;
00068         else if (ScanDirectionIsBackward(direction))
00069             direction = ForwardScanDirection;
00070     }
00071     scandesc = node->iss_ScanDesc;
00072     econtext = node->ss.ps.ps_ExprContext;
00073     slot = node->ss.ss_ScanTupleSlot;
00074 
00075     /*
00076      * ok, now that we have what we need, fetch the next tuple.
00077      */
00078     while ((tuple = index_getnext(scandesc, direction)) != NULL)
00079     {
00080         /*
00081          * Store the scanned tuple in the scan tuple slot of the scan state.
00082          * Note: we pass 'false' because tuples returned by amgetnext are
00083          * pointers onto disk pages and must not be pfree()'d.
00084          */
00085         ExecStoreTuple(tuple,   /* tuple to store */
00086                        slot,    /* slot to store in */
00087                        scandesc->xs_cbuf,       /* buffer containing tuple */
00088                        false);  /* don't pfree */
00089 
00090         /*
00091          * If the index was lossy, we have to recheck the index quals using
00092          * the fetched tuple.
00093          */
00094         if (scandesc->xs_recheck)
00095         {
00096             econtext->ecxt_scantuple = slot;
00097             ResetExprContext(econtext);
00098             if (!ExecQual(node->indexqualorig, econtext, false))
00099             {
00100                 /* Fails recheck, so drop it and loop back for another */
00101                 InstrCountFiltered2(node, 1);
00102                 continue;
00103             }
00104         }
00105 
00106         return slot;
00107     }
00108 
00109     /*
00110      * if we get here it means the index scan failed so we are at the end of
00111      * the scan..
00112      */
00113     return ExecClearTuple(slot);
00114 }
00115 
00116 /*
00117  * IndexRecheck -- access method routine to recheck a tuple in EvalPlanQual
00118  */
00119 static bool
00120 IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
00121 {
00122     ExprContext *econtext;
00123 
00124     /*
00125      * extract necessary information from index scan node
00126      */
00127     econtext = node->ss.ps.ps_ExprContext;
00128 
00129     /* Does the tuple meet the indexqual condition? */
00130     econtext->ecxt_scantuple = slot;
00131 
00132     ResetExprContext(econtext);
00133 
00134     return ExecQual(node->indexqualorig, econtext, false);
00135 }
00136 
00137 /* ----------------------------------------------------------------
00138  *      ExecIndexScan(node)
00139  * ----------------------------------------------------------------
00140  */
00141 TupleTableSlot *
00142 ExecIndexScan(IndexScanState *node)
00143 {
00144     /*
00145      * If we have runtime keys and they've not already been set up, do it now.
00146      */
00147     if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
00148         ExecReScan((PlanState *) node);
00149 
00150     return ExecScan(&node->ss,
00151                     (ExecScanAccessMtd) IndexNext,
00152                     (ExecScanRecheckMtd) IndexRecheck);
00153 }
00154 
00155 /* ----------------------------------------------------------------
00156  *      ExecReScanIndexScan(node)
00157  *
00158  *      Recalculates the values of any scan keys whose value depends on
00159  *      information known at runtime, then rescans the indexed relation.
00160  *
00161  *      Updating the scan key was formerly done separately in
00162  *      ExecUpdateIndexScanKeys. Integrating it into ReScan makes
00163  *      rescans of indices and relations/general streams more uniform.
00164  * ----------------------------------------------------------------
00165  */
00166 void
00167 ExecReScanIndexScan(IndexScanState *node)
00168 {
00169     /*
00170      * If we are doing runtime key calculations (ie, any of the index key
00171      * values weren't simple Consts), compute the new key values.  But first,
00172      * reset the context so we don't leak memory as each outer tuple is
00173      * scanned.  Note this assumes that we will recalculate *all* runtime keys
00174      * on each call.
00175      */
00176     if (node->iss_NumRuntimeKeys != 0)
00177     {
00178         ExprContext *econtext = node->iss_RuntimeContext;
00179 
00180         ResetExprContext(econtext);
00181         ExecIndexEvalRuntimeKeys(econtext,
00182                                  node->iss_RuntimeKeys,
00183                                  node->iss_NumRuntimeKeys);
00184     }
00185     node->iss_RuntimeKeysReady = true;
00186 
00187     /* reset index scan */
00188     index_rescan(node->iss_ScanDesc,
00189                  node->iss_ScanKeys, node->iss_NumScanKeys,
00190                  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
00191 
00192     ExecScanReScan(&node->ss);
00193 }
00194 
00195 
00196 /*
00197  * ExecIndexEvalRuntimeKeys
00198  *      Evaluate any runtime key values, and update the scankeys.
00199  */
00200 void
00201 ExecIndexEvalRuntimeKeys(ExprContext *econtext,
00202                          IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
00203 {
00204     int         j;
00205     MemoryContext oldContext;
00206 
00207     /* We want to keep the key values in per-tuple memory */
00208     oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
00209 
00210     for (j = 0; j < numRuntimeKeys; j++)
00211     {
00212         ScanKey     scan_key = runtimeKeys[j].scan_key;
00213         ExprState  *key_expr = runtimeKeys[j].key_expr;
00214         Datum       scanvalue;
00215         bool        isNull;
00216 
00217         /*
00218          * For each run-time key, extract the run-time expression and evaluate
00219          * it with respect to the current context.  We then stick the result
00220          * into the proper scan key.
00221          *
00222          * Note: the result of the eval could be a pass-by-ref value that's
00223          * stored in some outer scan's tuple, not in
00224          * econtext->ecxt_per_tuple_memory.  We assume that the outer tuple
00225          * will stay put throughout our scan.  If this is wrong, we could copy
00226          * the result into our context explicitly, but I think that's not
00227          * necessary.
00228          *
00229          * It's also entirely possible that the result of the eval is a
00230          * toasted value.  In this case we should forcibly detoast it, to
00231          * avoid repeat detoastings each time the value is examined by an
00232          * index support function.
00233          */
00234         scanvalue = ExecEvalExpr(key_expr,
00235                                  econtext,
00236                                  &isNull,
00237                                  NULL);
00238         if (isNull)
00239         {
00240             scan_key->sk_argument = scanvalue;
00241             scan_key->sk_flags |= SK_ISNULL;
00242         }
00243         else
00244         {
00245             if (runtimeKeys[j].key_toastable)
00246                 scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
00247             scan_key->sk_argument = scanvalue;
00248             scan_key->sk_flags &= ~SK_ISNULL;
00249         }
00250     }
00251 
00252     MemoryContextSwitchTo(oldContext);
00253 }
00254 
00255 /*
00256  * ExecIndexEvalArrayKeys
00257  *      Evaluate any array key values, and set up to iterate through arrays.
00258  *
00259  * Returns TRUE if there are array elements to consider; FALSE means there
00260  * is at least one null or empty array, so no match is possible.  On TRUE
00261  * result, the scankeys are initialized with the first elements of the arrays.
00262  */
00263 bool
00264 ExecIndexEvalArrayKeys(ExprContext *econtext,
00265                        IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
00266 {
00267     bool        result = true;
00268     int         j;
00269     MemoryContext oldContext;
00270 
00271     /* We want to keep the arrays in per-tuple memory */
00272     oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
00273 
00274     for (j = 0; j < numArrayKeys; j++)
00275     {
00276         ScanKey     scan_key = arrayKeys[j].scan_key;
00277         ExprState  *array_expr = arrayKeys[j].array_expr;
00278         Datum       arraydatum;
00279         bool        isNull;
00280         ArrayType  *arrayval;
00281         int16       elmlen;
00282         bool        elmbyval;
00283         char        elmalign;
00284         int         num_elems;
00285         Datum      *elem_values;
00286         bool       *elem_nulls;
00287 
00288         /*
00289          * Compute and deconstruct the array expression. (Notes in
00290          * ExecIndexEvalRuntimeKeys() apply here too.)
00291          */
00292         arraydatum = ExecEvalExpr(array_expr,
00293                                   econtext,
00294                                   &isNull,
00295                                   NULL);
00296         if (isNull)
00297         {
00298             result = false;
00299             break;              /* no point in evaluating more */
00300         }
00301         arrayval = DatumGetArrayTypeP(arraydatum);
00302         /* We could cache this data, but not clear it's worth it */
00303         get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
00304                              &elmlen, &elmbyval, &elmalign);
00305         deconstruct_array(arrayval,
00306                           ARR_ELEMTYPE(arrayval),
00307                           elmlen, elmbyval, elmalign,
00308                           &elem_values, &elem_nulls, &num_elems);
00309         if (num_elems <= 0)
00310         {
00311             result = false;
00312             break;              /* no point in evaluating more */
00313         }
00314 
00315         /*
00316          * Note: we expect the previous array data, if any, to be
00317          * automatically freed by resetting the per-tuple context; hence no
00318          * pfree's here.
00319          */
00320         arrayKeys[j].elem_values = elem_values;
00321         arrayKeys[j].elem_nulls = elem_nulls;
00322         arrayKeys[j].num_elems = num_elems;
00323         scan_key->sk_argument = elem_values[0];
00324         if (elem_nulls[0])
00325             scan_key->sk_flags |= SK_ISNULL;
00326         else
00327             scan_key->sk_flags &= ~SK_ISNULL;
00328         arrayKeys[j].next_elem = 1;
00329     }
00330 
00331     MemoryContextSwitchTo(oldContext);
00332 
00333     return result;
00334 }
00335 
00336 /*
00337  * ExecIndexAdvanceArrayKeys
00338  *      Advance to the next set of array key values, if any.
00339  *
00340  * Returns TRUE if there is another set of values to consider, FALSE if not.
00341  * On TRUE result, the scankeys are initialized with the next set of values.
00342  */
00343 bool
00344 ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
00345 {
00346     bool        found = false;
00347     int         j;
00348 
00349     /*
00350      * Note we advance the rightmost array key most quickly, since it will
00351      * correspond to the lowest-order index column among the available
00352      * qualifications.  This is hypothesized to result in better locality of
00353      * access in the index.
00354      */
00355     for (j = numArrayKeys - 1; j >= 0; j--)
00356     {
00357         ScanKey     scan_key = arrayKeys[j].scan_key;
00358         int         next_elem = arrayKeys[j].next_elem;
00359         int         num_elems = arrayKeys[j].num_elems;
00360         Datum      *elem_values = arrayKeys[j].elem_values;
00361         bool       *elem_nulls = arrayKeys[j].elem_nulls;
00362 
00363         if (next_elem >= num_elems)
00364         {
00365             next_elem = 0;
00366             found = false;      /* need to advance next array key */
00367         }
00368         else
00369             found = true;
00370         scan_key->sk_argument = elem_values[next_elem];
00371         if (elem_nulls[next_elem])
00372             scan_key->sk_flags |= SK_ISNULL;
00373         else
00374             scan_key->sk_flags &= ~SK_ISNULL;
00375         arrayKeys[j].next_elem = next_elem + 1;
00376         if (found)
00377             break;
00378     }
00379 
00380     return found;
00381 }
00382 
00383 
00384 /* ----------------------------------------------------------------
00385  *      ExecEndIndexScan
00386  * ----------------------------------------------------------------
00387  */
00388 void
00389 ExecEndIndexScan(IndexScanState *node)
00390 {
00391     Relation    indexRelationDesc;
00392     IndexScanDesc indexScanDesc;
00393     Relation    relation;
00394 
00395     /*
00396      * extract information from the node
00397      */
00398     indexRelationDesc = node->iss_RelationDesc;
00399     indexScanDesc = node->iss_ScanDesc;
00400     relation = node->ss.ss_currentRelation;
00401 
00402     /*
00403      * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
00404      */
00405 #ifdef NOT_USED
00406     ExecFreeExprContext(&node->ss.ps);
00407     if (node->iss_RuntimeContext)
00408         FreeExprContext(node->iss_RuntimeContext, true);
00409 #endif
00410 
00411     /*
00412      * clear out tuple table slots
00413      */
00414     ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
00415     ExecClearTuple(node->ss.ss_ScanTupleSlot);
00416 
00417     /*
00418      * close the index relation (no-op if we didn't open it)
00419      */
00420     if (indexScanDesc)
00421         index_endscan(indexScanDesc);
00422     if (indexRelationDesc)
00423         index_close(indexRelationDesc, NoLock);
00424 
00425     /*
00426      * close the heap relation.
00427      */
00428     ExecCloseScanRelation(relation);
00429 }
00430 
00431 /* ----------------------------------------------------------------
00432  *      ExecIndexMarkPos
00433  * ----------------------------------------------------------------
00434  */
00435 void
00436 ExecIndexMarkPos(IndexScanState *node)
00437 {
00438     index_markpos(node->iss_ScanDesc);
00439 }
00440 
00441 /* ----------------------------------------------------------------
00442  *      ExecIndexRestrPos
00443  * ----------------------------------------------------------------
00444  */
00445 void
00446 ExecIndexRestrPos(IndexScanState *node)
00447 {
00448     index_restrpos(node->iss_ScanDesc);
00449 }
00450 
00451 /* ----------------------------------------------------------------
00452  *      ExecInitIndexScan
00453  *
00454  *      Initializes the index scan's state information, creates
00455  *      scan keys, and opens the base and index relations.
00456  *
00457  *      Note: index scans have 2 sets of state information because
00458  *            we have to keep track of the base relation and the
00459  *            index relation.
00460  * ----------------------------------------------------------------
00461  */
00462 IndexScanState *
00463 ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
00464 {
00465     IndexScanState *indexstate;
00466     Relation    currentRelation;
00467     bool        relistarget;
00468 
00469     /*
00470      * create state structure
00471      */
00472     indexstate = makeNode(IndexScanState);
00473     indexstate->ss.ps.plan = (Plan *) node;
00474     indexstate->ss.ps.state = estate;
00475 
00476     /*
00477      * Miscellaneous initialization
00478      *
00479      * create expression context for node
00480      */
00481     ExecAssignExprContext(estate, &indexstate->ss.ps);
00482 
00483     indexstate->ss.ps.ps_TupFromTlist = false;
00484 
00485     /*
00486      * initialize child expressions
00487      *
00488      * Note: we don't initialize all of the indexqual expression, only the
00489      * sub-parts corresponding to runtime keys (see below).  Likewise for
00490      * indexorderby, if any.  But the indexqualorig expression is always
00491      * initialized even though it will only be used in some uncommon cases ---
00492      * would be nice to improve that.  (Problem is that any SubPlans present
00493      * in the expression must be found now...)
00494      */
00495     indexstate->ss.ps.targetlist = (List *)
00496         ExecInitExpr((Expr *) node->scan.plan.targetlist,
00497                      (PlanState *) indexstate);
00498     indexstate->ss.ps.qual = (List *)
00499         ExecInitExpr((Expr *) node->scan.plan.qual,
00500                      (PlanState *) indexstate);
00501     indexstate->indexqualorig = (List *)
00502         ExecInitExpr((Expr *) node->indexqualorig,
00503                      (PlanState *) indexstate);
00504 
00505     /*
00506      * tuple table initialization
00507      */
00508     ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
00509     ExecInitScanTupleSlot(estate, &indexstate->ss);
00510 
00511     /*
00512      * open the base relation and acquire appropriate lock on it.
00513      */
00514     currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
00515 
00516     indexstate->ss.ss_currentRelation = currentRelation;
00517     indexstate->ss.ss_currentScanDesc = NULL;   /* no heap scan here */
00518 
00519     /*
00520      * get the scan type from the relation descriptor.
00521      */
00522     ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation));
00523 
00524     /*
00525      * Initialize result tuple type and projection info.
00526      */
00527     ExecAssignResultTypeFromTL(&indexstate->ss.ps);
00528     ExecAssignScanProjectionInfo(&indexstate->ss);
00529 
00530     /*
00531      * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
00532      * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
00533      * references to nonexistent indexes.
00534      */
00535     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
00536         return indexstate;
00537 
00538     /*
00539      * Open the index relation.
00540      *
00541      * If the parent table is one of the target relations of the query, then
00542      * InitPlan already opened and write-locked the index, so we can avoid
00543      * taking another lock here.  Otherwise we need a normal reader's lock.
00544      */
00545     relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
00546     indexstate->iss_RelationDesc = index_open(node->indexid,
00547                                      relistarget ? NoLock : AccessShareLock);
00548 
00549     /*
00550      * Initialize index-specific scan state
00551      */
00552     indexstate->iss_RuntimeKeysReady = false;
00553     indexstate->iss_RuntimeKeys = NULL;
00554     indexstate->iss_NumRuntimeKeys = 0;
00555 
00556     /*
00557      * build the index scan keys from the index qualification
00558      */
00559     ExecIndexBuildScanKeys((PlanState *) indexstate,
00560                            indexstate->iss_RelationDesc,
00561                            node->indexqual,
00562                            false,
00563                            &indexstate->iss_ScanKeys,
00564                            &indexstate->iss_NumScanKeys,
00565                            &indexstate->iss_RuntimeKeys,
00566                            &indexstate->iss_NumRuntimeKeys,
00567                            NULL,    /* no ArrayKeys */
00568                            NULL);
00569 
00570     /*
00571      * any ORDER BY exprs have to be turned into scankeys in the same way
00572      */
00573     ExecIndexBuildScanKeys((PlanState *) indexstate,
00574                            indexstate->iss_RelationDesc,
00575                            node->indexorderby,
00576                            true,
00577                            &indexstate->iss_OrderByKeys,
00578                            &indexstate->iss_NumOrderByKeys,
00579                            &indexstate->iss_RuntimeKeys,
00580                            &indexstate->iss_NumRuntimeKeys,
00581                            NULL,    /* no ArrayKeys */
00582                            NULL);
00583 
00584     /*
00585      * If we have runtime keys, we need an ExprContext to evaluate them. The
00586      * node's standard context won't do because we want to reset that context
00587      * for every tuple.  So, build another context just like the other one...
00588      * -tgl 7/11/00
00589      */
00590     if (indexstate->iss_NumRuntimeKeys != 0)
00591     {
00592         ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
00593 
00594         ExecAssignExprContext(estate, &indexstate->ss.ps);
00595         indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
00596         indexstate->ss.ps.ps_ExprContext = stdecontext;
00597     }
00598     else
00599     {
00600         indexstate->iss_RuntimeContext = NULL;
00601     }
00602 
00603     /*
00604      * Initialize scan descriptor.
00605      */
00606     indexstate->iss_ScanDesc = index_beginscan(currentRelation,
00607                                                indexstate->iss_RelationDesc,
00608                                                estate->es_snapshot,
00609                                                indexstate->iss_NumScanKeys,
00610                                              indexstate->iss_NumOrderByKeys);
00611 
00612     /*
00613      * If no run-time keys to calculate, go ahead and pass the scankeys to the
00614      * index AM.
00615      */
00616     if (indexstate->iss_NumRuntimeKeys == 0)
00617         index_rescan(indexstate->iss_ScanDesc,
00618                      indexstate->iss_ScanKeys, indexstate->iss_NumScanKeys,
00619                 indexstate->iss_OrderByKeys, indexstate->iss_NumOrderByKeys);
00620 
00621     /*
00622      * all done.
00623      */
00624     return indexstate;
00625 }
00626 
00627 
00628 /*
00629  * ExecIndexBuildScanKeys
00630  *      Build the index scan keys from the index qualification expressions
00631  *
00632  * The index quals are passed to the index AM in the form of a ScanKey array.
00633  * This routine sets up the ScanKeys, fills in all constant fields of the
00634  * ScanKeys, and prepares information about the keys that have non-constant
00635  * comparison values.  We divide index qual expressions into five types:
00636  *
00637  * 1. Simple operator with constant comparison value ("indexkey op constant").
00638  * For these, we just fill in a ScanKey containing the constant value.
00639  *
00640  * 2. Simple operator with non-constant value ("indexkey op expression").
00641  * For these, we create a ScanKey with everything filled in except the
00642  * expression value, and set up an IndexRuntimeKeyInfo struct to drive
00643  * evaluation of the expression at the right times.
00644  *
00645  * 3. RowCompareExpr ("(indexkey, indexkey, ...) op (expr, expr, ...)").
00646  * For these, we create a header ScanKey plus a subsidiary ScanKey array,
00647  * as specified in access/skey.h.  The elements of the row comparison
00648  * can have either constant or non-constant comparison values.
00649  *
00650  * 4. ScalarArrayOpExpr ("indexkey op ANY (array-expression)").  If the index
00651  * has rd_am->amsearcharray, we handle these the same as simple operators,
00652  * setting the SK_SEARCHARRAY flag to tell the AM to handle them.  Otherwise,
00653  * we create a ScanKey with everything filled in except the comparison value,
00654  * and set up an IndexArrayKeyInfo struct to drive processing of the qual.
00655  * (Note that if we use an IndexArrayKeyInfo struct, the array expression is
00656  * always treated as requiring runtime evaluation, even if it's a constant.)
00657  *
00658  * 5. NullTest ("indexkey IS NULL/IS NOT NULL").  We just fill in the
00659  * ScanKey properly.
00660  *
00661  * This code is also used to prepare ORDER BY expressions for amcanorderbyop
00662  * indexes.  The behavior is exactly the same, except that we have to look up
00663  * the operator differently.  Note that only cases 1 and 2 are currently
00664  * possible for ORDER BY.
00665  *
00666  * Input params are:
00667  *
00668  * planstate: executor state node we are working for
00669  * index: the index we are building scan keys for
00670  * quals: indexquals (or indexorderbys) expressions
00671  * isorderby: true if processing ORDER BY exprs, false if processing quals
00672  * *runtimeKeys: ptr to pre-existing IndexRuntimeKeyInfos, or NULL if none
00673  * *numRuntimeKeys: number of pre-existing runtime keys
00674  *
00675  * Output params are:
00676  *
00677  * *scanKeys: receives ptr to array of ScanKeys
00678  * *numScanKeys: receives number of scankeys
00679  * *runtimeKeys: receives ptr to array of IndexRuntimeKeyInfos, or NULL if none
00680  * *numRuntimeKeys: receives number of runtime keys
00681  * *arrayKeys: receives ptr to array of IndexArrayKeyInfos, or NULL if none
00682  * *numArrayKeys: receives number of array keys
00683  *
00684  * Caller may pass NULL for arrayKeys and numArrayKeys to indicate that
00685  * IndexArrayKeyInfos are not supported.
00686  */
00687 void
00688 ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
00689                        List *quals, bool isorderby,
00690                        ScanKey *scanKeys, int *numScanKeys,
00691                        IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys,
00692                        IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
00693 {
00694     ListCell   *qual_cell;
00695     ScanKey     scan_keys;
00696     IndexRuntimeKeyInfo *runtime_keys;
00697     IndexArrayKeyInfo *array_keys;
00698     int         n_scan_keys;
00699     int         n_runtime_keys;
00700     int         max_runtime_keys;
00701     int         n_array_keys;
00702     int         j;
00703 
00704     /* Allocate array for ScanKey structs: one per qual */
00705     n_scan_keys = list_length(quals);
00706     scan_keys = (ScanKey) palloc(n_scan_keys * sizeof(ScanKeyData));
00707 
00708     /*
00709      * runtime_keys array is dynamically resized as needed.  We handle it this
00710      * way so that the same runtime keys array can be shared between
00711      * indexquals and indexorderbys, which will be processed in separate calls
00712      * of this function.  Caller must be sure to pass in NULL/0 for first
00713      * call.
00714      */
00715     runtime_keys = *runtimeKeys;
00716     n_runtime_keys = max_runtime_keys = *numRuntimeKeys;
00717 
00718     /* Allocate array_keys as large as it could possibly need to be */
00719     array_keys = (IndexArrayKeyInfo *)
00720         palloc0(n_scan_keys * sizeof(IndexArrayKeyInfo));
00721     n_array_keys = 0;
00722 
00723     /*
00724      * for each opclause in the given qual, convert the opclause into a single
00725      * scan key
00726      */
00727     j = 0;
00728     foreach(qual_cell, quals)
00729     {
00730         Expr       *clause = (Expr *) lfirst(qual_cell);
00731         ScanKey     this_scan_key = &scan_keys[j++];
00732         Oid         opno;       /* operator's OID */
00733         RegProcedure opfuncid;  /* operator proc id used in scan */
00734         Oid         opfamily;   /* opfamily of index column */
00735         int         op_strategy;    /* operator's strategy number */
00736         Oid         op_lefttype;    /* operator's declared input types */
00737         Oid         op_righttype;
00738         Expr       *leftop;     /* expr on lhs of operator */
00739         Expr       *rightop;    /* expr on rhs ... */
00740         AttrNumber  varattno;   /* att number used in scan */
00741 
00742         if (IsA(clause, OpExpr))
00743         {
00744             /* indexkey op const or indexkey op expression */
00745             int         flags = 0;
00746             Datum       scanvalue;
00747 
00748             opno = ((OpExpr *) clause)->opno;
00749             opfuncid = ((OpExpr *) clause)->opfuncid;
00750 
00751             /*
00752              * leftop should be the index key Var, possibly relabeled
00753              */
00754             leftop = (Expr *) get_leftop(clause);
00755 
00756             if (leftop && IsA(leftop, RelabelType))
00757                 leftop = ((RelabelType *) leftop)->arg;
00758 
00759             Assert(leftop != NULL);
00760 
00761             if (!(IsA(leftop, Var) &&
00762                   ((Var *) leftop)->varno == INDEX_VAR))
00763                 elog(ERROR, "indexqual doesn't have key on left side");
00764 
00765             varattno = ((Var *) leftop)->varattno;
00766             if (varattno < 1 || varattno > index->rd_index->indnatts)
00767                 elog(ERROR, "bogus index qualification");
00768 
00769             /*
00770              * We have to look up the operator's strategy number.  This
00771              * provides a cross-check that the operator does match the index.
00772              */
00773             opfamily = index->rd_opfamily[varattno - 1];
00774 
00775             get_op_opfamily_properties(opno, opfamily, isorderby,
00776                                        &op_strategy,
00777                                        &op_lefttype,
00778                                        &op_righttype);
00779 
00780             if (isorderby)
00781                 flags |= SK_ORDER_BY;
00782 
00783             /*
00784              * rightop is the constant or variable comparison value
00785              */
00786             rightop = (Expr *) get_rightop(clause);
00787 
00788             if (rightop && IsA(rightop, RelabelType))
00789                 rightop = ((RelabelType *) rightop)->arg;
00790 
00791             Assert(rightop != NULL);
00792 
00793             if (IsA(rightop, Const))
00794             {
00795                 /* OK, simple constant comparison value */
00796                 scanvalue = ((Const *) rightop)->constvalue;
00797                 if (((Const *) rightop)->constisnull)
00798                     flags |= SK_ISNULL;
00799             }
00800             else
00801             {
00802                 /* Need to treat this one as a runtime key */
00803                 if (n_runtime_keys >= max_runtime_keys)
00804                 {
00805                     if (max_runtime_keys == 0)
00806                     {
00807                         max_runtime_keys = 8;
00808                         runtime_keys = (IndexRuntimeKeyInfo *)
00809                             palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
00810                     }
00811                     else
00812                     {
00813                         max_runtime_keys *= 2;
00814                         runtime_keys = (IndexRuntimeKeyInfo *)
00815                             repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
00816                     }
00817                 }
00818                 runtime_keys[n_runtime_keys].scan_key = this_scan_key;
00819                 runtime_keys[n_runtime_keys].key_expr =
00820                     ExecInitExpr(rightop, planstate);
00821                 runtime_keys[n_runtime_keys].key_toastable =
00822                     TypeIsToastable(op_righttype);
00823                 n_runtime_keys++;
00824                 scanvalue = (Datum) 0;
00825             }
00826 
00827             /*
00828              * initialize the scan key's fields appropriately
00829              */
00830             ScanKeyEntryInitialize(this_scan_key,
00831                                    flags,
00832                                    varattno,    /* attribute number to scan */
00833                                    op_strategy, /* op's strategy */
00834                                    op_righttype,        /* strategy subtype */
00835                                    ((OpExpr *) clause)->inputcollid,    /* collation */
00836                                    opfuncid,    /* reg proc to use */
00837                                    scanvalue);  /* constant */
00838         }
00839         else if (IsA(clause, RowCompareExpr))
00840         {
00841             /* (indexkey, indexkey, ...) op (expression, expression, ...) */
00842             RowCompareExpr *rc = (RowCompareExpr *) clause;
00843             ListCell   *largs_cell = list_head(rc->largs);
00844             ListCell   *rargs_cell = list_head(rc->rargs);
00845             ListCell   *opnos_cell = list_head(rc->opnos);
00846             ListCell   *collids_cell = list_head(rc->inputcollids);
00847             ScanKey     first_sub_key;
00848             int         n_sub_key;
00849 
00850             Assert(!isorderby);
00851 
00852             first_sub_key = (ScanKey)
00853                 palloc(list_length(rc->opnos) * sizeof(ScanKeyData));
00854             n_sub_key = 0;
00855 
00856             /* Scan RowCompare columns and generate subsidiary ScanKey items */
00857             while (opnos_cell != NULL)
00858             {
00859                 ScanKey     this_sub_key = &first_sub_key[n_sub_key];
00860                 int         flags = SK_ROW_MEMBER;
00861                 Datum       scanvalue;
00862                 Oid         inputcollation;
00863 
00864                 /*
00865                  * leftop should be the index key Var, possibly relabeled
00866                  */
00867                 leftop = (Expr *) lfirst(largs_cell);
00868                 largs_cell = lnext(largs_cell);
00869 
00870                 if (leftop && IsA(leftop, RelabelType))
00871                     leftop = ((RelabelType *) leftop)->arg;
00872 
00873                 Assert(leftop != NULL);
00874 
00875                 if (!(IsA(leftop, Var) &&
00876                       ((Var *) leftop)->varno == INDEX_VAR))
00877                     elog(ERROR, "indexqual doesn't have key on left side");
00878 
00879                 varattno = ((Var *) leftop)->varattno;
00880 
00881                 /*
00882                  * We have to look up the operator's associated btree support
00883                  * function
00884                  */
00885                 opno = lfirst_oid(opnos_cell);
00886                 opnos_cell = lnext(opnos_cell);
00887 
00888                 if (index->rd_rel->relam != BTREE_AM_OID ||
00889                     varattno < 1 || varattno > index->rd_index->indnatts)
00890                     elog(ERROR, "bogus RowCompare index qualification");
00891                 opfamily = index->rd_opfamily[varattno - 1];
00892 
00893                 get_op_opfamily_properties(opno, opfamily, isorderby,
00894                                            &op_strategy,
00895                                            &op_lefttype,
00896                                            &op_righttype);
00897 
00898                 if (op_strategy != rc->rctype)
00899                     elog(ERROR, "RowCompare index qualification contains wrong operator");
00900 
00901                 opfuncid = get_opfamily_proc(opfamily,
00902                                              op_lefttype,
00903                                              op_righttype,
00904                                              BTORDER_PROC);
00905 
00906                 inputcollation = lfirst_oid(collids_cell);
00907                 collids_cell = lnext(collids_cell);
00908 
00909                 /*
00910                  * rightop is the constant or variable comparison value
00911                  */
00912                 rightop = (Expr *) lfirst(rargs_cell);
00913                 rargs_cell = lnext(rargs_cell);
00914 
00915                 if (rightop && IsA(rightop, RelabelType))
00916                     rightop = ((RelabelType *) rightop)->arg;
00917 
00918                 Assert(rightop != NULL);
00919 
00920                 if (IsA(rightop, Const))
00921                 {
00922                     /* OK, simple constant comparison value */
00923                     scanvalue = ((Const *) rightop)->constvalue;
00924                     if (((Const *) rightop)->constisnull)
00925                         flags |= SK_ISNULL;
00926                 }
00927                 else
00928                 {
00929                     /* Need to treat this one as a runtime key */
00930                     if (n_runtime_keys >= max_runtime_keys)
00931                     {
00932                         if (max_runtime_keys == 0)
00933                         {
00934                             max_runtime_keys = 8;
00935                             runtime_keys = (IndexRuntimeKeyInfo *)
00936                                 palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
00937                         }
00938                         else
00939                         {
00940                             max_runtime_keys *= 2;
00941                             runtime_keys = (IndexRuntimeKeyInfo *)
00942                                 repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
00943                         }
00944                     }
00945                     runtime_keys[n_runtime_keys].scan_key = this_sub_key;
00946                     runtime_keys[n_runtime_keys].key_expr =
00947                         ExecInitExpr(rightop, planstate);
00948                     runtime_keys[n_runtime_keys].key_toastable =
00949                         TypeIsToastable(op_righttype);
00950                     n_runtime_keys++;
00951                     scanvalue = (Datum) 0;
00952                 }
00953 
00954                 /*
00955                  * initialize the subsidiary scan key's fields appropriately
00956                  */
00957                 ScanKeyEntryInitialize(this_sub_key,
00958                                        flags,
00959                                        varattno,        /* attribute number */
00960                                        op_strategy,     /* op's strategy */
00961                                        op_righttype,    /* strategy subtype */
00962                                        inputcollation,  /* collation */
00963                                        opfuncid,        /* reg proc to use */
00964                                        scanvalue);      /* constant */
00965                 n_sub_key++;
00966             }
00967 
00968             /* Mark the last subsidiary scankey correctly */
00969             first_sub_key[n_sub_key - 1].sk_flags |= SK_ROW_END;
00970 
00971             /*
00972              * We don't use ScanKeyEntryInitialize for the header because it
00973              * isn't going to contain a valid sk_func pointer.
00974              */
00975             MemSet(this_scan_key, 0, sizeof(ScanKeyData));
00976             this_scan_key->sk_flags = SK_ROW_HEADER;
00977             this_scan_key->sk_attno = first_sub_key->sk_attno;
00978             this_scan_key->sk_strategy = rc->rctype;
00979             /* sk_subtype, sk_collation, sk_func not used in a header */
00980             this_scan_key->sk_argument = PointerGetDatum(first_sub_key);
00981         }
00982         else if (IsA(clause, ScalarArrayOpExpr))
00983         {
00984             /* indexkey op ANY (array-expression) */
00985             ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
00986             int         flags = 0;
00987             Datum       scanvalue;
00988 
00989             Assert(!isorderby);
00990 
00991             Assert(saop->useOr);
00992             opno = saop->opno;
00993             opfuncid = saop->opfuncid;
00994 
00995             /*
00996              * leftop should be the index key Var, possibly relabeled
00997              */
00998             leftop = (Expr *) linitial(saop->args);
00999 
01000             if (leftop && IsA(leftop, RelabelType))
01001                 leftop = ((RelabelType *) leftop)->arg;
01002 
01003             Assert(leftop != NULL);
01004 
01005             if (!(IsA(leftop, Var) &&
01006                   ((Var *) leftop)->varno == INDEX_VAR))
01007                 elog(ERROR, "indexqual doesn't have key on left side");
01008 
01009             varattno = ((Var *) leftop)->varattno;
01010             if (varattno < 1 || varattno > index->rd_index->indnatts)
01011                 elog(ERROR, "bogus index qualification");
01012 
01013             /*
01014              * We have to look up the operator's strategy number.  This
01015              * provides a cross-check that the operator does match the index.
01016              */
01017             opfamily = index->rd_opfamily[varattno - 1];
01018 
01019             get_op_opfamily_properties(opno, opfamily, isorderby,
01020                                        &op_strategy,
01021                                        &op_lefttype,
01022                                        &op_righttype);
01023 
01024             /*
01025              * rightop is the constant or variable array value
01026              */
01027             rightop = (Expr *) lsecond(saop->args);
01028 
01029             if (rightop && IsA(rightop, RelabelType))
01030                 rightop = ((RelabelType *) rightop)->arg;
01031 
01032             Assert(rightop != NULL);
01033 
01034             if (index->rd_am->amsearcharray)
01035             {
01036                 /* Index AM will handle this like a simple operator */
01037                 flags |= SK_SEARCHARRAY;
01038                 if (IsA(rightop, Const))
01039                 {
01040                     /* OK, simple constant comparison value */
01041                     scanvalue = ((Const *) rightop)->constvalue;
01042                     if (((Const *) rightop)->constisnull)
01043                         flags |= SK_ISNULL;
01044                 }
01045                 else
01046                 {
01047                     /* Need to treat this one as a runtime key */
01048                     if (n_runtime_keys >= max_runtime_keys)
01049                     {
01050                         if (max_runtime_keys == 0)
01051                         {
01052                             max_runtime_keys = 8;
01053                             runtime_keys = (IndexRuntimeKeyInfo *)
01054                                 palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
01055                         }
01056                         else
01057                         {
01058                             max_runtime_keys *= 2;
01059                             runtime_keys = (IndexRuntimeKeyInfo *)
01060                                 repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
01061                         }
01062                     }
01063                     runtime_keys[n_runtime_keys].scan_key = this_scan_key;
01064                     runtime_keys[n_runtime_keys].key_expr =
01065                         ExecInitExpr(rightop, planstate);
01066 
01067                     /*
01068                      * Careful here: the runtime expression is not of
01069                      * op_righttype, but rather is an array of same; so
01070                      * TypeIsToastable() isn't helpful.  However, we can
01071                      * assume that all array types are toastable.
01072                      */
01073                     runtime_keys[n_runtime_keys].key_toastable = true;
01074                     n_runtime_keys++;
01075                     scanvalue = (Datum) 0;
01076                 }
01077             }
01078             else
01079             {
01080                 /* Executor has to expand the array value */
01081                 array_keys[n_array_keys].scan_key = this_scan_key;
01082                 array_keys[n_array_keys].array_expr =
01083                     ExecInitExpr(rightop, planstate);
01084                 /* the remaining fields were zeroed by palloc0 */
01085                 n_array_keys++;
01086                 scanvalue = (Datum) 0;
01087             }
01088 
01089             /*
01090              * initialize the scan key's fields appropriately
01091              */
01092             ScanKeyEntryInitialize(this_scan_key,
01093                                    flags,
01094                                    varattno,    /* attribute number to scan */
01095                                    op_strategy, /* op's strategy */
01096                                    op_righttype,        /* strategy subtype */
01097                                    saop->inputcollid,   /* collation */
01098                                    opfuncid,    /* reg proc to use */
01099                                    scanvalue);  /* constant */
01100         }
01101         else if (IsA(clause, NullTest))
01102         {
01103             /* indexkey IS NULL or indexkey IS NOT NULL */
01104             NullTest   *ntest = (NullTest *) clause;
01105             int         flags;
01106 
01107             Assert(!isorderby);
01108 
01109             /*
01110              * argument should be the index key Var, possibly relabeled
01111              */
01112             leftop = ntest->arg;
01113 
01114             if (leftop && IsA(leftop, RelabelType))
01115                 leftop = ((RelabelType *) leftop)->arg;
01116 
01117             Assert(leftop != NULL);
01118 
01119             if (!(IsA(leftop, Var) &&
01120                   ((Var *) leftop)->varno == INDEX_VAR))
01121                 elog(ERROR, "NullTest indexqual has wrong key");
01122 
01123             varattno = ((Var *) leftop)->varattno;
01124 
01125             /*
01126              * initialize the scan key's fields appropriately
01127              */
01128             switch (ntest->nulltesttype)
01129             {
01130                 case IS_NULL:
01131                     flags = SK_ISNULL | SK_SEARCHNULL;
01132                     break;
01133                 case IS_NOT_NULL:
01134                     flags = SK_ISNULL | SK_SEARCHNOTNULL;
01135                     break;
01136                 default:
01137                     elog(ERROR, "unrecognized nulltesttype: %d",
01138                          (int) ntest->nulltesttype);
01139                     flags = 0;  /* keep compiler quiet */
01140                     break;
01141             }
01142 
01143             ScanKeyEntryInitialize(this_scan_key,
01144                                    flags,
01145                                    varattno,    /* attribute number to scan */
01146                                    InvalidStrategy,     /* no strategy */
01147                                    InvalidOid,  /* no strategy subtype */
01148                                    InvalidOid,  /* no collation */
01149                                    InvalidOid,  /* no reg proc for this */
01150                                    (Datum) 0);  /* constant */
01151         }
01152         else
01153             elog(ERROR, "unsupported indexqual type: %d",
01154                  (int) nodeTag(clause));
01155     }
01156 
01157     Assert(n_runtime_keys <= max_runtime_keys);
01158 
01159     /* Get rid of any unused arrays */
01160     if (n_array_keys == 0)
01161     {
01162         pfree(array_keys);
01163         array_keys = NULL;
01164     }
01165 
01166     /*
01167      * Return info to our caller.
01168      */
01169     *scanKeys = scan_keys;
01170     *numScanKeys = n_scan_keys;
01171     *runtimeKeys = runtime_keys;
01172     *numRuntimeKeys = n_runtime_keys;
01173     if (arrayKeys)
01174     {
01175         *arrayKeys = array_keys;
01176         *numArrayKeys = n_array_keys;
01177     }
01178     else if (n_array_keys != 0)
01179         elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
01180 }