Header And Logo

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

Functions

nodeIndexscan.c File Reference

#include "postgres.h"
#include "access/nbtree.h"
#include "access/relscan.h"
#include "executor/execdebug.h"
#include "executor/nodeIndexscan.h"
#include "optimizer/clauses.h"
#include "utils/array.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for nodeIndexscan.c:

Go to the source code of this file.

Functions

static TupleTableSlotIndexNext (IndexScanState *node)
static bool IndexRecheck (IndexScanState *node, TupleTableSlot *slot)
TupleTableSlotExecIndexScan (IndexScanState *node)
void ExecReScanIndexScan (IndexScanState *node)
void ExecIndexEvalRuntimeKeys (ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
bool ExecIndexEvalArrayKeys (ExprContext *econtext, IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
bool ExecIndexAdvanceArrayKeys (IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
void ExecEndIndexScan (IndexScanState *node)
void ExecIndexMarkPos (IndexScanState *node)
void ExecIndexRestrPos (IndexScanState *node)
IndexScanStateExecInitIndexScan (IndexScan *node, EState *estate, int eflags)
void ExecIndexBuildScanKeys (PlanState *planstate, Relation index, List *quals, bool isorderby, ScanKey *scanKeys, int *numScanKeys, IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)

Function Documentation

void ExecEndIndexScan ( IndexScanState node  ) 

Definition at line 389 of file nodeIndexscan.c.

References ExecClearTuple(), ExecCloseScanRelation(), ExecFreeExprContext(), FreeExprContext(), index_close(), index_endscan(), IndexScanState::iss_RelationDesc, IndexScanState::iss_RuntimeContext, IndexScanState::iss_ScanDesc, NoLock, ScanState::ps, PlanState::ps_ResultTupleSlot, IndexScanState::ss, ScanState::ss_currentRelation, and ScanState::ss_ScanTupleSlot.

Referenced by ExecEndNode().

{
    Relation    indexRelationDesc;
    IndexScanDesc indexScanDesc;
    Relation    relation;

    /*
     * extract information from the node
     */
    indexRelationDesc = node->iss_RelationDesc;
    indexScanDesc = node->iss_ScanDesc;
    relation = node->ss.ss_currentRelation;

    /*
     * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
     */
#ifdef NOT_USED
    ExecFreeExprContext(&node->ss.ps);
    if (node->iss_RuntimeContext)
        FreeExprContext(node->iss_RuntimeContext, true);
#endif

    /*
     * clear out tuple table slots
     */
    ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
    ExecClearTuple(node->ss.ss_ScanTupleSlot);

    /*
     * close the index relation (no-op if we didn't open it)
     */
    if (indexScanDesc)
        index_endscan(indexScanDesc);
    if (indexRelationDesc)
        index_close(indexRelationDesc, NoLock);

    /*
     * close the heap relation.
     */
    ExecCloseScanRelation(relation);
}

bool ExecIndexAdvanceArrayKeys ( IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

Definition at line 344 of file nodeIndexscan.c.

References IndexArrayKeyInfo::elem_nulls, IndexArrayKeyInfo::elem_values, IndexArrayKeyInfo::next_elem, IndexArrayKeyInfo::num_elems, IndexArrayKeyInfo::scan_key, ScanKeyData::sk_argument, and ScanKeyData::sk_flags.

Referenced by MultiExecBitmapIndexScan().

{
    bool        found = false;
    int         j;

    /*
     * Note we advance the rightmost array key most quickly, since it will
     * correspond to the lowest-order index column among the available
     * qualifications.  This is hypothesized to result in better locality of
     * access in the index.
     */
    for (j = numArrayKeys - 1; j >= 0; j--)
    {
        ScanKey     scan_key = arrayKeys[j].scan_key;
        int         next_elem = arrayKeys[j].next_elem;
        int         num_elems = arrayKeys[j].num_elems;
        Datum      *elem_values = arrayKeys[j].elem_values;
        bool       *elem_nulls = arrayKeys[j].elem_nulls;

        if (next_elem >= num_elems)
        {
            next_elem = 0;
            found = false;      /* need to advance next array key */
        }
        else
            found = true;
        scan_key->sk_argument = elem_values[next_elem];
        if (elem_nulls[next_elem])
            scan_key->sk_flags |= SK_ISNULL;
        else
            scan_key->sk_flags &= ~SK_ISNULL;
        arrayKeys[j].next_elem = next_elem + 1;
        if (found)
            break;
    }

    return found;
}

void ExecIndexBuildScanKeys ( PlanState planstate,
Relation  index,
List quals,
bool  isorderby,
ScanKey scanKeys,
int *  numScanKeys,
IndexRuntimeKeyInfo **  runtimeKeys,
int *  numRuntimeKeys,
IndexArrayKeyInfo **  arrayKeys,
int *  numArrayKeys 
)

Definition at line 688 of file nodeIndexscan.c.

References NullTest::arg, arg, ScalarArrayOpExpr::args, IndexArrayKeyInfo::array_expr, Assert, BTORDER_PROC, BTREE_AM_OID, elog, ERROR, ExecInitExpr(), get_leftop(), get_op_opfamily_properties(), get_opfamily_proc(), get_rightop(), INDEX_VAR, ScalarArrayOpExpr::inputcollid, RowCompareExpr::inputcollids, InvalidOid, InvalidStrategy, IS_NOT_NULL, IS_NULL, IsA, IndexRuntimeKeyInfo::key_expr, IndexRuntimeKeyInfo::key_toastable, RowCompareExpr::largs, lfirst, lfirst_oid, linitial, list_head(), list_length(), lnext, lsecond, MemSet, nodeTag, NULL, NullTest::nulltesttype, ScalarArrayOpExpr::opfuncid, ScalarArrayOpExpr::opno, RowCompareExpr::opnos, palloc(), palloc0(), pfree(), PointerGetDatum, RowCompareExpr::rargs, RowCompareExpr::rctype, RelationData::rd_am, RelationData::rd_index, RelationData::rd_opfamily, RelationData::rd_rel, repalloc(), IndexArrayKeyInfo::scan_key, IndexRuntimeKeyInfo::scan_key, ScanKeyEntryInitialize(), ScanKeyData::sk_argument, ScanKeyData::sk_attno, ScanKeyData::sk_flags, SK_ISNULL, ScanKeyData::sk_strategy, TypeIsToastable, and ScalarArrayOpExpr::useOr.

Referenced by ExecInitBitmapIndexScan(), ExecInitIndexOnlyScan(), and ExecInitIndexScan().

{
    ListCell   *qual_cell;
    ScanKey     scan_keys;
    IndexRuntimeKeyInfo *runtime_keys;
    IndexArrayKeyInfo *array_keys;
    int         n_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));

    /*
     * 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.
     */
    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_array_keys = 0;

    /*
     * for each opclause in the given qual, convert the opclause into a single
     * scan key
     */
    j = 0;
    foreach(qual_cell, quals)
    {
        Expr       *clause = (Expr *) lfirst(qual_cell);
        ScanKey     this_scan_key = &scan_keys[j++];
        Oid         opno;       /* operator's OID */
        RegProcedure opfuncid;  /* operator proc id used in scan */
        Oid         opfamily;   /* opfamily of index column */
        int         op_strategy;    /* operator's strategy number */
        Oid         op_lefttype;    /* operator's declared input types */
        Oid         op_righttype;
        Expr       *leftop;     /* expr on lhs of operator */
        Expr       *rightop;    /* expr on rhs ... */
        AttrNumber  varattno;   /* att number used in scan */

        if (IsA(clause, OpExpr))
        {
            /* indexkey op const or indexkey op expression */
            int         flags = 0;
            Datum       scanvalue;

            opno = ((OpExpr *) clause)->opno;
            opfuncid = ((OpExpr *) clause)->opfuncid;

            /*
             * leftop should be the index key Var, possibly relabeled
             */
            leftop = (Expr *) get_leftop(clause);

            if (leftop && IsA(leftop, RelabelType))
                leftop = ((RelabelType *) leftop)->arg;

            Assert(leftop != NULL);

            if (!(IsA(leftop, Var) &&
                  ((Var *) leftop)->varno == INDEX_VAR))
                elog(ERROR, "indexqual doesn't have key on left side");

            varattno = ((Var *) leftop)->varattno;
            if (varattno < 1 || varattno > index->rd_index->indnatts)
                elog(ERROR, "bogus index qualification");

            /*
             * We have to look up the operator's strategy number.  This
             * provides a cross-check that the operator does match the index.
             */
            opfamily = index->rd_opfamily[varattno - 1];

            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
             */
            rightop = (Expr *) get_rightop(clause);

            if (rightop && IsA(rightop, RelabelType))
                rightop = ((RelabelType *) rightop)->arg;

            Assert(rightop != NULL);

            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);
                runtime_keys[n_runtime_keys].key_toastable =
                    TypeIsToastable(op_righttype);
                n_runtime_keys++;
                scanvalue = (Datum) 0;
            }

            /*
             * initialize the scan key's fields appropriately
             */
            ScanKeyEntryInitialize(this_scan_key,
                                   flags,
                                   varattno,    /* attribute number to scan */
                                   op_strategy, /* op's strategy */
                                   op_righttype,        /* strategy subtype */
                                   ((OpExpr *) clause)->inputcollid,    /* collation */
                                   opfuncid,    /* reg proc to use */
                                   scanvalue);  /* constant */
        }
        else if (IsA(clause, RowCompareExpr))
        {
            /* (indexkey, indexkey, ...) op (expression, expression, ...) */
            RowCompareExpr *rc = (RowCompareExpr *) clause;
            ListCell   *largs_cell = list_head(rc->largs);
            ListCell   *rargs_cell = list_head(rc->rargs);
            ListCell   *opnos_cell = list_head(rc->opnos);
            ListCell   *collids_cell = list_head(rc->inputcollids);
            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 = &first_sub_key[n_sub_key];
                int         flags = SK_ROW_MEMBER;
                Datum       scanvalue;
                Oid         inputcollation;

                /*
                 * leftop should be the index key Var, possibly relabeled
                 */
                leftop = (Expr *) lfirst(largs_cell);
                largs_cell = lnext(largs_cell);

                if (leftop && IsA(leftop, RelabelType))
                    leftop = ((RelabelType *) leftop)->arg;

                Assert(leftop != NULL);

                if (!(IsA(leftop, Var) &&
                      ((Var *) leftop)->varno == INDEX_VAR))
                    elog(ERROR, "indexqual doesn't have key on left side");

                varattno = ((Var *) leftop)->varattno;

                /*
                 * We have to look up the operator's associated btree support
                 * function
                 */
                opno = lfirst_oid(opnos_cell);
                opnos_cell = lnext(opnos_cell);

                if (index->rd_rel->relam != BTREE_AM_OID ||
                    varattno < 1 || varattno > index->rd_index->indnatts)
                    elog(ERROR, "bogus RowCompare index qualification");
                opfamily = index->rd_opfamily[varattno - 1];

                get_op_opfamily_properties(opno, opfamily, isorderby,
                                           &op_strategy,
                                           &op_lefttype,
                                           &op_righttype);

                if (op_strategy != rc->rctype)
                    elog(ERROR, "RowCompare index qualification contains wrong operator");

                opfuncid = get_opfamily_proc(opfamily,
                                             op_lefttype,
                                             op_righttype,
                                             BTORDER_PROC);

                inputcollation = lfirst_oid(collids_cell);
                collids_cell = lnext(collids_cell);

                /*
                 * rightop is the constant or variable comparison value
                 */
                rightop = (Expr *) lfirst(rargs_cell);
                rargs_cell = lnext(rargs_cell);

                if (rightop && IsA(rightop, RelabelType))
                    rightop = ((RelabelType *) rightop)->arg;

                Assert(rightop != NULL);

                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_sub_key;
                    runtime_keys[n_runtime_keys].key_expr =
                        ExecInitExpr(rightop, planstate);
                    runtime_keys[n_runtime_keys].key_toastable =
                        TypeIsToastable(op_righttype);
                    n_runtime_keys++;
                    scanvalue = (Datum) 0;
                }

                /*
                 * initialize the subsidiary scan key's fields appropriately
                 */
                ScanKeyEntryInitialize(this_sub_key,
                                       flags,
                                       varattno,        /* attribute number */
                                       op_strategy,     /* op's strategy */
                                       op_righttype,    /* strategy subtype */
                                       inputcollation,  /* collation */
                                       opfuncid,        /* reg proc to use */
                                       scanvalue);      /* constant */
                n_sub_key++;
            }

            /* Mark the last subsidiary scankey correctly */
            first_sub_key[n_sub_key - 1].sk_flags |= SK_ROW_END;

            /*
             * We don't use ScanKeyEntryInitialize for the header because it
             * isn't going to contain a valid sk_func pointer.
             */
            MemSet(this_scan_key, 0, sizeof(ScanKeyData));
            this_scan_key->sk_flags = SK_ROW_HEADER;
            this_scan_key->sk_attno = first_sub_key->sk_attno;
            this_scan_key->sk_strategy = rc->rctype;
            /* sk_subtype, sk_collation, sk_func not used in a header */
            this_scan_key->sk_argument = PointerGetDatum(first_sub_key);
        }
        else if (IsA(clause, ScalarArrayOpExpr))
        {
            /* indexkey op ANY (array-expression) */
            ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
            int         flags = 0;
            Datum       scanvalue;

            Assert(!isorderby);

            Assert(saop->useOr);
            opno = saop->opno;
            opfuncid = saop->opfuncid;

            /*
             * leftop should be the index key Var, possibly relabeled
             */
            leftop = (Expr *) linitial(saop->args);

            if (leftop && IsA(leftop, RelabelType))
                leftop = ((RelabelType *) leftop)->arg;

            Assert(leftop != NULL);

            if (!(IsA(leftop, Var) &&
                  ((Var *) leftop)->varno == INDEX_VAR))
                elog(ERROR, "indexqual doesn't have key on left side");

            varattno = ((Var *) leftop)->varattno;
            if (varattno < 1 || varattno > index->rd_index->indnatts)
                elog(ERROR, "bogus index qualification");

            /*
             * We have to look up the operator's strategy number.  This
             * provides a cross-check that the operator does match the index.
             */
            opfamily = index->rd_opfamily[varattno - 1];

            get_op_opfamily_properties(opno, opfamily, isorderby,
                                       &op_strategy,
                                       &op_lefttype,
                                       &op_righttype);

            /*
             * rightop is the constant or variable array value
             */
            rightop = (Expr *) lsecond(saop->args);

            if (rightop && IsA(rightop, RelabelType))
                rightop = ((RelabelType *) rightop)->arg;

            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,
                                   flags,
                                   varattno,    /* attribute number to scan */
                                   op_strategy, /* op's strategy */
                                   op_righttype,        /* strategy subtype */
                                   saop->inputcollid,   /* collation */
                                   opfuncid,    /* reg proc to use */
                                   scanvalue);  /* constant */
        }
        else if (IsA(clause, NullTest))
        {
            /* indexkey IS NULL or indexkey IS NOT NULL */
            NullTest   *ntest = (NullTest *) clause;
            int         flags;

            Assert(!isorderby);

            /*
             * argument should be the index key Var, possibly relabeled
             */
            leftop = ntest->arg;

            if (leftop && IsA(leftop, RelabelType))
                leftop = ((RelabelType *) leftop)->arg;

            Assert(leftop != NULL);

            if (!(IsA(leftop, Var) &&
                  ((Var *) leftop)->varno == INDEX_VAR))
                elog(ERROR, "NullTest indexqual has wrong key");

            varattno = ((Var *) leftop)->varattno;

            /*
             * initialize the scan key's fields appropriately
             */
            switch (ntest->nulltesttype)
            {
                case IS_NULL:
                    flags = SK_ISNULL | SK_SEARCHNULL;
                    break;
                case IS_NOT_NULL:
                    flags = SK_ISNULL | SK_SEARCHNOTNULL;
                    break;
                default:
                    elog(ERROR, "unrecognized nulltesttype: %d",
                         (int) ntest->nulltesttype);
                    flags = 0;  /* keep compiler quiet */
                    break;
            }

            ScanKeyEntryInitialize(this_scan_key,
                                   flags,
                                   varattno,    /* attribute number to scan */
                                   InvalidStrategy,     /* no strategy */
                                   InvalidOid,  /* no strategy subtype */
                                   InvalidOid,  /* no collation */
                                   InvalidOid,  /* no reg proc for this */
                                   (Datum) 0);  /* constant */
        }
        else
            elog(ERROR, "unsupported indexqual type: %d",
                 (int) nodeTag(clause));
    }

    Assert(n_runtime_keys <= max_runtime_keys);

    /* Get rid of any unused arrays */
    if (n_array_keys == 0)
    {
        pfree(array_keys);
        array_keys = NULL;
    }

    /*
     * Return info to our caller.
     */
    *scanKeys = scan_keys;
    *numScanKeys = n_scan_keys;
    *runtimeKeys = runtime_keys;
    *numRuntimeKeys = n_runtime_keys;
    if (arrayKeys)
    {
        *arrayKeys = array_keys;
        *numArrayKeys = n_array_keys;
    }
    else if (n_array_keys != 0)
        elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
}

bool ExecIndexEvalArrayKeys ( ExprContext econtext,
IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

Definition at line 264 of file nodeIndexscan.c.

References ARR_ELEMTYPE, IndexArrayKeyInfo::array_expr, DatumGetArrayTypeP, deconstruct_array(), ExprContext::ecxt_per_tuple_memory, IndexArrayKeyInfo::elem_nulls, IndexArrayKeyInfo::elem_values, ExecEvalExpr, get_typlenbyvalalign(), MemoryContextSwitchTo(), IndexArrayKeyInfo::next_elem, NULL, IndexArrayKeyInfo::num_elems, IndexArrayKeyInfo::scan_key, ScanKeyData::sk_argument, and ScanKeyData::sk_flags.

Referenced by ExecReScanBitmapIndexScan().

{
    bool        result = true;
    int         j;
    MemoryContext oldContext;

    /* We want to keep the arrays in per-tuple memory */
    oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);

    for (j = 0; j < numArrayKeys; j++)
    {
        ScanKey     scan_key = arrayKeys[j].scan_key;
        ExprState  *array_expr = arrayKeys[j].array_expr;
        Datum       arraydatum;
        bool        isNull;
        ArrayType  *arrayval;
        int16       elmlen;
        bool        elmbyval;
        char        elmalign;
        int         num_elems;
        Datum      *elem_values;
        bool       *elem_nulls;

        /*
         * Compute and deconstruct the array expression. (Notes in
         * ExecIndexEvalRuntimeKeys() apply here too.)
         */
        arraydatum = ExecEvalExpr(array_expr,
                                  econtext,
                                  &isNull,
                                  NULL);
        if (isNull)
        {
            result = false;
            break;              /* no point in evaluating more */
        }
        arrayval = DatumGetArrayTypeP(arraydatum);
        /* We could cache this data, but not clear it's worth it */
        get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
                             &elmlen, &elmbyval, &elmalign);
        deconstruct_array(arrayval,
                          ARR_ELEMTYPE(arrayval),
                          elmlen, elmbyval, elmalign,
                          &elem_values, &elem_nulls, &num_elems);
        if (num_elems <= 0)
        {
            result = false;
            break;              /* no point in evaluating more */
        }

        /*
         * Note: we expect the previous array data, if any, to be
         * automatically freed by resetting the per-tuple context; hence no
         * pfree's here.
         */
        arrayKeys[j].elem_values = elem_values;
        arrayKeys[j].elem_nulls = elem_nulls;
        arrayKeys[j].num_elems = num_elems;
        scan_key->sk_argument = elem_values[0];
        if (elem_nulls[0])
            scan_key->sk_flags |= SK_ISNULL;
        else
            scan_key->sk_flags &= ~SK_ISNULL;
        arrayKeys[j].next_elem = 1;
    }

    MemoryContextSwitchTo(oldContext);

    return result;
}

void ExecIndexEvalRuntimeKeys ( ExprContext econtext,
IndexRuntimeKeyInfo runtimeKeys,
int  numRuntimeKeys 
)

Definition at line 201 of file nodeIndexscan.c.

References ExprContext::ecxt_per_tuple_memory, ExecEvalExpr, IndexRuntimeKeyInfo::key_expr, MemoryContextSwitchTo(), NULL, PG_DETOAST_DATUM, PointerGetDatum, IndexRuntimeKeyInfo::scan_key, ScanKeyData::sk_argument, and ScanKeyData::sk_flags.

Referenced by ExecReScanBitmapIndexScan(), ExecReScanIndexOnlyScan(), and ExecReScanIndexScan().

{
    int         j;
    MemoryContext oldContext;

    /* We want to keep the key values in per-tuple memory */
    oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);

    for (j = 0; j < numRuntimeKeys; j++)
    {
        ScanKey     scan_key = runtimeKeys[j].scan_key;
        ExprState  *key_expr = runtimeKeys[j].key_expr;
        Datum       scanvalue;
        bool        isNull;

        /*
         * For each run-time key, extract the run-time expression and evaluate
         * it with respect to the current context.  We then stick the result
         * into the proper scan key.
         *
         * Note: the result of the eval could be a pass-by-ref value that's
         * stored in some outer scan's tuple, not in
         * econtext->ecxt_per_tuple_memory.  We assume that the outer tuple
         * will stay put throughout our scan.  If this is wrong, we could copy
         * the result into our context explicitly, but I think that's not
         * necessary.
         *
         * It's also entirely possible that the result of the eval is a
         * toasted value.  In this case we should forcibly detoast it, to
         * avoid repeat detoastings each time the value is examined by an
         * index support function.
         */
        scanvalue = ExecEvalExpr(key_expr,
                                 econtext,
                                 &isNull,
                                 NULL);
        if (isNull)
        {
            scan_key->sk_argument = scanvalue;
            scan_key->sk_flags |= SK_ISNULL;
        }
        else
        {
            if (runtimeKeys[j].key_toastable)
                scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
            scan_key->sk_argument = scanvalue;
            scan_key->sk_flags &= ~SK_ISNULL;
        }
    }

    MemoryContextSwitchTo(oldContext);
}

void ExecIndexMarkPos ( IndexScanState node  ) 

Definition at line 436 of file nodeIndexscan.c.

References index_markpos(), and IndexScanState::iss_ScanDesc.

Referenced by ExecMarkPos().

void ExecIndexRestrPos ( IndexScanState node  ) 

Definition at line 446 of file nodeIndexscan.c.

References index_restrpos(), and IndexScanState::iss_ScanDesc.

Referenced by ExecRestrPos().

TupleTableSlot* ExecIndexScan ( IndexScanState node  ) 

Definition at line 142 of file nodeIndexscan.c.

References ExecReScan(), ExecScan(), IndexNext(), IndexRecheck(), IndexScanState::iss_NumRuntimeKeys, and IndexScanState::iss_RuntimeKeysReady.

Referenced by ExecProcNode().

{
    /*
     * If we have runtime keys and they've not already been set up, do it now.
     */
    if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
        ExecReScan((PlanState *) node);

    return ExecScan(&node->ss,
                    (ExecScanAccessMtd) IndexNext,
                    (ExecScanRecheckMtd) IndexRecheck);
}

IndexScanState* ExecInitIndexScan ( IndexScan node,
EState estate,
int  eflags 
)

Definition at line 463 of file nodeIndexscan.c.

References AccessShareLock, EState::es_snapshot, EXEC_FLAG_EXPLAIN_ONLY, ExecAssignExprContext(), ExecAssignResultTypeFromTL(), ExecAssignScanProjectionInfo(), ExecAssignScanType(), ExecIndexBuildScanKeys(), ExecInitExpr(), ExecInitResultTupleSlot(), ExecInitScanTupleSlot(), ExecOpenScanRelation(), ExecRelationIsTargetRelation(), index_beginscan(), index_open(), index_rescan(), IndexScan::indexid, IndexScan::indexorderby, IndexScan::indexqual, IndexScan::indexqualorig, IndexScanState::indexqualorig, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_RelationDesc, IndexScanState::iss_RuntimeKeys, IndexScanState::iss_RuntimeKeysReady, makeNode, NoLock, NULL, Scan::plan, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, PlanState::ps_TupFromTlist, Plan::qual, PlanState::qual, RelationGetDescr, IndexScan::scan, Scan::scanrelid, IndexScanState::ss, ScanState::ss_currentRelation, ScanState::ss_currentScanDesc, PlanState::state, Plan::targetlist, and PlanState::targetlist.

Referenced by ExecInitNode().

{
    IndexScanState *indexstate;
    Relation    currentRelation;
    bool        relistarget;

    /*
     * create state structure
     */
    indexstate = makeNode(IndexScanState);
    indexstate->ss.ps.plan = (Plan *) node;
    indexstate->ss.ps.state = estate;

    /*
     * Miscellaneous initialization
     *
     * create expression context for node
     */
    ExecAssignExprContext(estate, &indexstate->ss.ps);

    indexstate->ss.ps.ps_TupFromTlist = false;

    /*
     * initialize child expressions
     *
     * Note: we don't initialize all of the indexqual expression, only the
     * 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,
                     (PlanState *) indexstate);
    indexstate->ss.ps.qual = (List *)
        ExecInitExpr((Expr *) node->scan.plan.qual,
                     (PlanState *) indexstate);
    indexstate->indexqualorig = (List *)
        ExecInitExpr((Expr *) node->indexqualorig,
                     (PlanState *) indexstate);

    /*
     * tuple table initialization
     */
    ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
    ExecInitScanTupleSlot(estate, &indexstate->ss);

    /*
     * open the base relation and acquire appropriate lock on it.
     */
    currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);

    indexstate->ss.ss_currentRelation = currentRelation;
    indexstate->ss.ss_currentScanDesc = NULL;   /* no heap scan here */

    /*
     * get the scan type from the relation descriptor.
     */
    ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation));

    /*
     * Initialize result tuple type and projection info.
     */
    ExecAssignResultTypeFromTL(&indexstate->ss.ps);
    ExecAssignScanProjectionInfo(&indexstate->ss);

    /*
     * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
     * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
     * references to nonexistent indexes.
     */
    if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
        return indexstate;

    /*
     * Open the index relation.
     *
     * If the parent table is one of the target relations of the query, then
     * InitPlan already opened and write-locked the index, so we can avoid
     * taking another lock here.  Otherwise we need a normal reader's lock.
     */
    relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
    indexstate->iss_RelationDesc = index_open(node->indexid,
                                     relistarget ? NoLock : AccessShareLock);

    /*
     * 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
     */
    ExecIndexBuildScanKeys((PlanState *) indexstate,
                           indexstate->iss_RelationDesc,
                           node->indexqual,
                           false,
                           &indexstate->iss_ScanKeys,
                           &indexstate->iss_NumScanKeys,
                           &indexstate->iss_RuntimeKeys,
                           &indexstate->iss_NumRuntimeKeys,
                           NULL,    /* no ArrayKeys */
                           NULL);

    /*
     * any ORDER BY exprs have to be turned into scankeys in the same way
     */
    ExecIndexBuildScanKeys((PlanState *) indexstate,
                           indexstate->iss_RelationDesc,
                           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...
     * -tgl 7/11/00
     */
    if (indexstate->iss_NumRuntimeKeys != 0)
    {
        ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;

        ExecAssignExprContext(estate, &indexstate->ss.ps);
        indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
        indexstate->ss.ps.ps_ExprContext = stdecontext;
    }
    else
    {
        indexstate->iss_RuntimeContext = NULL;
    }

    /*
     * Initialize scan descriptor.
     */
    indexstate->iss_ScanDesc = index_beginscan(currentRelation,
                                               indexstate->iss_RelationDesc,
                                               estate->es_snapshot,
                                               indexstate->iss_NumScanKeys,
                                             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.
     */
    return indexstate;
}

void ExecReScanIndexScan ( IndexScanState node  ) 

Definition at line 167 of file nodeIndexscan.c.

References ExecIndexEvalRuntimeKeys(), ExecScanReScan(), index_rescan(), IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_RuntimeContext, IndexScanState::iss_RuntimeKeys, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanDesc, IndexScanState::iss_ScanKeys, ResetExprContext, and IndexScanState::ss.

Referenced by ExecReScan().

{
    /*
     * If we are doing runtime key calculations (ie, any of the index key
     * values weren't simple Consts), compute the new key values.  But first,
     * reset the context so we don't leak memory as each outer tuple is
     * scanned.  Note this assumes that we will recalculate *all* runtime keys
     * on each call.
     */
    if (node->iss_NumRuntimeKeys != 0)
    {
        ExprContext *econtext = node->iss_RuntimeContext;

        ResetExprContext(econtext);
        ExecIndexEvalRuntimeKeys(econtext,
                                 node->iss_RuntimeKeys,
                                 node->iss_NumRuntimeKeys);
    }
    node->iss_RuntimeKeysReady = true;

    /* reset index scan */
    index_rescan(node->iss_ScanDesc,
                 node->iss_ScanKeys, node->iss_NumScanKeys,
                 node->iss_OrderByKeys, node->iss_NumOrderByKeys);

    ExecScanReScan(&node->ss);
}

static TupleTableSlot * IndexNext ( IndexScanState node  )  [static]

Definition at line 49 of file nodeIndexscan.c.

References ExprContext::ecxt_scantuple, EState::es_direction, ExecClearTuple(), ExecQual(), ExecStoreTuple(), index_getnext(), IndexScanState::indexqualorig, InstrCountFiltered2, IndexScanState::iss_ScanDesc, NULL, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, ResetExprContext, ScanDirectionIsBackward, ScanDirectionIsForward, IndexScanState::ss, ScanState::ss_ScanTupleSlot, PlanState::state, IndexScanDescData::xs_cbuf, and IndexScanDescData::xs_recheck.

Referenced by ExecIndexScan().

{
    EState     *estate;
    ExprContext *econtext;
    ScanDirection direction;
    IndexScanDesc scandesc;
    HeapTuple   tuple;
    TupleTableSlot *slot;

    /*
     * extract necessary information from index scan node
     */
    estate = node->ss.ps.state;
    direction = estate->es_direction;
    /* flip direction if this is an overall backward scan */
    if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir))
    {
        if (ScanDirectionIsForward(direction))
            direction = BackwardScanDirection;
        else if (ScanDirectionIsBackward(direction))
            direction = ForwardScanDirection;
    }
    scandesc = node->iss_ScanDesc;
    econtext = node->ss.ps.ps_ExprContext;
    slot = node->ss.ss_ScanTupleSlot;

    /*
     * ok, now that we have what we need, fetch the next tuple.
     */
    while ((tuple = index_getnext(scandesc, direction)) != NULL)
    {
        /*
         * Store the scanned tuple in the scan tuple slot of the scan state.
         * Note: we pass 'false' because tuples returned by amgetnext are
         * pointers onto disk pages and must not be pfree()'d.
         */
        ExecStoreTuple(tuple,   /* tuple to store */
                       slot,    /* slot to store in */
                       scandesc->xs_cbuf,       /* buffer containing tuple */
                       false);  /* don't pfree */

        /*
         * If the index was lossy, we have to recheck the index quals using
         * the fetched tuple.
         */
        if (scandesc->xs_recheck)
        {
            econtext->ecxt_scantuple = slot;
            ResetExprContext(econtext);
            if (!ExecQual(node->indexqualorig, econtext, false))
            {
                /* Fails recheck, so drop it and loop back for another */
                InstrCountFiltered2(node, 1);
                continue;
            }
        }

        return slot;
    }

    /*
     * if we get here it means the index scan failed so we are at the end of
     * the scan..
     */
    return ExecClearTuple(slot);
}

static bool IndexRecheck ( IndexScanState node,
TupleTableSlot slot 
) [static]

Definition at line 120 of file nodeIndexscan.c.

References ExprContext::ecxt_scantuple, ExecQual(), IndexScanState::indexqualorig, ScanState::ps, PlanState::ps_ExprContext, ResetExprContext, and IndexScanState::ss.

Referenced by ExecIndexScan().

{
    ExprContext *econtext;

    /*
     * extract necessary information from index scan node
     */
    econtext = node->ss.ps.ps_ExprContext;

    /* Does the tuple meet the indexqual condition? */
    econtext->ecxt_scantuple = slot;

    ResetExprContext(econtext);

    return ExecQual(node->indexqualorig, econtext, false);
}