/* * Trivial picksplit implementaion. Function called only * if user-defined picksplit puts all keys to the one page. * That is a bug of user-defined picksplit but we'd like * to "fix" that. */ static void genericPickSplit(GISTSTATE *giststate, GistEntryVector *entryvec, GIST_SPLITVEC *v, int attno) { OffsetNumber i, maxoff; int nbytes; GistEntryVector *evec; maxoff = entryvec->n - 1; nbytes = (maxoff + 2) * sizeof(OffsetNumber); v->spl_left = (OffsetNumber *) palloc(nbytes); v->spl_right = (OffsetNumber *) palloc(nbytes); v->spl_nleft = v->spl_nright = 0; for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { if (i <= (maxoff - FirstOffsetNumber + 1) / 2) { v->spl_left[v->spl_nleft] = i; v->spl_nleft++; } else { v->spl_right[v->spl_nright] = i; v->spl_nright++; } } /* * Form unions of each page */ evec = palloc( sizeof(GISTENTRY) * entryvec->n + GEVHDRSZ ); evec->n = v->spl_nleft; memcpy(evec->vector, entryvec->vector + FirstOffsetNumber, sizeof(GISTENTRY) * evec->n); v->spl_ldatum = FunctionCall2(&giststate->unionFn[attno], PointerGetDatum(evec), PointerGetDatum(&nbytes)); evec->n = v->spl_nright; memcpy(evec->vector, entryvec->vector + FirstOffsetNumber + v->spl_nleft, sizeof(GISTENTRY) * evec->n); v->spl_rdatum = FunctionCall2(&giststate->unionFn[attno], PointerGetDatum(evec), PointerGetDatum(&nbytes)); }
/* * Inet semi join selectivity estimation for one value * * The function calculates the probability that there is at least one row * in the RHS table that satisfies the "lhs_value op column" condition. * It is used in semi join estimation to check a sample from the left hand * side table. * * The MCV and histogram from the right hand side table should be provided as * arguments with the lhs_value from the left hand side table for the join. * hist_weight is the total number of rows represented by the histogram. * For example, if the table has 1000 rows, and 10% of the rows are in the MCV * list, and another 10% are NULLs, hist_weight would be 800. * * First, the lhs_value will be matched to the most common values. If it * matches any of them, 1.0 will be returned, because then there is surely * a match. * * Otherwise, the histogram will be used to estimate the number of rows in * the second table that match the condition. If the estimate is greater * than 1.0, 1.0 will be returned, because it means there is a greater chance * that the lhs_value will match more than one row in the table. If it is * between 0.0 and 1.0, it will be returned as the probability. */ static Selectivity inet_semi_join_sel(Datum lhs_value, bool mcv_exists, Datum *mcv_values, int mcv_nvalues, bool hist_exists, Datum *hist_values, int hist_nvalues, double hist_weight, FmgrInfo *proc, int opr_codenum) { if (mcv_exists) { int i; for (i = 0; i < mcv_nvalues; i++) { if (DatumGetBool(FunctionCall2(proc, lhs_value, mcv_values[i]))) return 1.0; } } if (hist_exists && hist_weight > 0) { Selectivity hist_selec; /* Commute operator, since we're passing lhs_value on the right */ hist_selec = inet_hist_value_sel(hist_values, hist_nvalues, lhs_value, -opr_codenum); if (hist_selec > 0) return Min(1.0, hist_weight * hist_selec); } return 0.0; }
static int cmpEntries(const void *a, const void *b, void *arg) { const keyEntryData *aa = (const keyEntryData *) a; const keyEntryData *bb = (const keyEntryData *) b; cmpEntriesArg *data = (cmpEntriesArg *) arg; int res; if (aa->isnull) { if (bb->isnull) res = 0; /* NULL "=" NULL */ else res = 1; /* NULL ">" not-NULL */ } else if (bb->isnull) res = -1; /* not-NULL "<" NULL */ else res = DatumGetInt32(FunctionCall2(data->cmpDatumFunc, aa->datum, bb->datum)); /* * Detect if we have any duplicates. If there are equal keys, qsort * must compare them at some point, else it wouldn't know whether one * should go before or after the other. */ if (res == 0) data->haveDups = true; return res; }
Datum * extractEntriesS(GinState *ginstate, OffsetNumber attnum, Datum value, int32 *nentries, bool *needUnique) { Datum *entries; entries = (Datum *) DatumGetPointer(FunctionCall2( &ginstate->extractValueFn[attnum - 1], value, PointerGetDatum(nentries) )); if (entries == NULL) *nentries = 0; *needUnique = FALSE; if (*nentries > 1) { cmpEntriesData arg; arg.cmpDatumFunc = &ginstate->compareFn[attnum - 1]; arg.needUnique = needUnique; qsort_arg(entries, *nentries, sizeof(Datum), (qsort_arg_comparator) cmpEntries, (void *) &arg); } return entries; }
globle int FunctionCall( char *name, char *args, DATA_OBJECT *result) { FUNCTION_REFERENCE theReference; /*=======================================*/ /* Call the function if it can be found. */ /*=======================================*/ if (GetFunctionReference(name,&theReference)) { return(FunctionCall2(&theReference,args,result)); } /*=========================================================*/ /* Otherwise signal an error if a deffunction, defgeneric, */ /* or user defined function doesn't exist that matches */ /* the specified function name. */ /*=========================================================*/ PrintErrorID("EVALUATN",2,FALSE); PrintRouter(WERROR,"No function, generic function or deffunction of name "); PrintRouter(WERROR,name); PrintRouter(WERROR," exists for external call.\n"); return(TRUE); }
/* ---------------- * index_getbitmap - get all tuples at once from an index scan * * Adds the TIDs of all heap tuples satisfying the scan keys to a bitmap. * Since there's no interlock between the index scan and the eventual heap * access, this is only safe to use with MVCC-based snapshots: the heap * item slot could have been replaced by a newer tuple by the time we get * to it. * * Returns the number of matching tuples found. (Note: this might be only * approximate, so it should only be used for statistical purposes.) * ---------------- */ int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap) { FmgrInfo *procedure; int64 ntids; Datum d; SCAN_CHECKS; GET_SCAN_PROCEDURE(amgetbitmap); /* just make sure this is false... */ scan->kill_prior_tuple = false; /* * have the am's getbitmap proc do all the work. */ d = FunctionCall2(procedure, PointerGetDatum(scan), PointerGetDatum(bitmap)); ntids = DatumGetInt64(d); /* If int8 is pass-by-ref, must free the result to avoid memory leak */ #ifndef USE_FLOAT8_BYVAL pfree(DatumGetPointer(d)); #endif pgstat_count_index_tuples(scan->indexRelation, ntids); return ntids; }
void hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4 buflen) { int type, lenlemm; char *lemm = NULL; WParserInfo *prsobj = findprs(cfg->prs_id); LexizeData ldata; TSLexeme *norms; ParsedLex *lexs; prsobj->prs = (void *) DatumGetPointer( FunctionCall2( &(prsobj->start_info), PointerGetDatum(buf), Int32GetDatum(buflen) ) ); LexizeInit(&ldata, cfg); do { type = DatumGetInt32(FunctionCall3( &(prsobj->getlexeme_info), PointerGetDatum(prsobj->prs), PointerGetDatum(&lemm), PointerGetDatum(&lenlemm))); if (type > 0 && lenlemm >= MAXSTRLEN) { #ifdef IGNORE_LONGLEXEME ereport(NOTICE, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("A word you are indexing is too long. It will be ignored."))); continue; #else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("A word you are indexing is too long"))); #endif } LexizeAddLemm(&ldata, type, lemm, lenlemm); do { if ((norms = LexizeExec(&ldata, &lexs)) != NULL) addHLParsedLex(prs, query, lexs, norms); else addHLParsedLex(prs, query, lexs, NULL); } while (norms); } while (type > 0); FunctionCall1( &(prsobj->end_info), PointerGetDatum(prsobj->prs) ); }
/* * execTuplesMatch * Return true if two tuples match in all the indicated fields. * * This actually implements SQL's notion of "not distinct". Two nulls * match, a null and a not-null don't match. * * slot1, slot2: the tuples to compare (must have same columns!) * numCols: the number of attributes to be examined * matchColIdx: array of attribute column numbers * eqFunctions: array of fmgr lookup info for the equality functions to use * evalContext: short-term memory context for executing the functions * * NB: evalContext is reset each time! */ bool execTuplesMatch(TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, MemoryContext evalContext) { MemoryContext oldContext; bool result; int i; /* Reset and switch into the temp context. */ MemoryContextReset(evalContext); oldContext = MemoryContextSwitchTo(evalContext); /* * We cannot report a match without checking all the fields, but we can * report a non-match as soon as we find unequal fields. So, start * comparing at the last field (least significant sort key). That's the * most likely to be different if we are dealing with sorted input. */ result = true; for (i = numCols; --i >= 0;) { AttrNumber att = matchColIdx[i]; Datum attr1, attr2; bool isNull1, isNull2; attr1 = slot_getattr(slot1, att, &isNull1); attr2 = slot_getattr(slot2, att, &isNull2); if (isNull1 != isNull2) { result = false; /* one null and one not; they aren't equal */ break; } if (isNull1) continue; /* both are null, treat as equal */ /* Apply the type-specific equality function */ if (!DatumGetBool(FunctionCall2(&eqfunctions[i], attr1, attr2))) { result = false; /* they aren't equal */ break; } } MemoryContextSwitchTo(oldContext); return result; }
static int compare_indextuple(const IndexTuple itup1, const IndexTuple itup2, ScanKey entry, int keysz, TupleDesc tupdes, bool *hasnull) { int i; int32 compare; *hasnull = false; for (i = 1; i <= keysz; i++, entry++) { Datum attrDatum1, attrDatum2; bool isNull1, isNull2; attrDatum1 = index_getattr(itup1, i, tupdes, &isNull1); attrDatum2 = index_getattr(itup2, i, tupdes, &isNull2); if (isNull1) { *hasnull = true; if (isNull2) compare = 0; /* NULL "=" NULL */ else if (entry->sk_flags & SK_BT_NULLS_FIRST) compare = -1; /* NULL "<" NOT_NULL */ else compare = 1; /* NULL ">" NOT_NULL */ } else if (isNull2) { *hasnull = true; if (entry->sk_flags & SK_BT_NULLS_FIRST) compare = 1; /* NOT_NULL ">" NULL */ else compare = -1; /* NOT_NULL "<" NULL */ } else { compare = #if PG_VERSION_NUM >= 90100 DatumGetInt32(FunctionCall2Coll(&entry->sk_func, entry->sk_collation, attrDatum1, attrDatum2)); #else DatumGetInt32(FunctionCall2(&entry->sk_func, attrDatum1, attrDatum2)); #endif if (entry->sk_flags & SK_BT_DESC) compare = -compare; } if (compare != 0) return compare; } return 0; }
int compareEntries(GinState *ginstate, OffsetNumber attnum, Datum a, Datum b) { return DatumGetInt32( FunctionCall2( &ginstate->compareFn[attnum - 1], a, b ) ); }
static void prs_setup_firstcall(FuncCallContext *funcctx, Oid prsid, text *txt) { TupleDesc tupdesc; MemoryContext oldcontext; PrsStorage *st; TSParserCacheEntry *prs = lookup_ts_parser_cache(prsid); char *lex = NULL; int llen = 0, type = 0; void *prsdata; oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); st = (PrsStorage *) palloc(sizeof(PrsStorage)); st->cur = 0; st->len = 16; st->list = (LexemeEntry *) palloc(sizeof(LexemeEntry) * st->len); prsdata = (void *) DatumGetPointer(FunctionCall2(&prs->prsstart, PointerGetDatum(VARDATA(txt)), Int32GetDatum(VARSIZE(txt) - VARHDRSZ))); while ((type = DatumGetInt32(FunctionCall3(&prs->prstoken, PointerGetDatum(prsdata), PointerGetDatum(&lex), PointerGetDatum(&llen)))) != 0) { if (st->cur >= st->len) { st->len = 2 * st->len; st->list = (LexemeEntry *) repalloc(st->list, sizeof(LexemeEntry) * st->len); } st->list[st->cur].lexeme = palloc(llen + 1); memcpy(st->list[st->cur].lexeme, lex, llen); st->list[st->cur].lexeme[llen] = '\0'; st->list[st->cur].type = type; st->cur++; } FunctionCall1(&prs->prsend, PointerGetDatum(prsdata)); st->len = st->cur; st->cur = 0; funcctx->user_fctx = (void *) st; tupdesc = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tokid", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "token", TEXTOID, -1, 0); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); MemoryContextSwitchTo(oldcontext); }
void reestimateParameters(ModelInfo *modelInfo, Node *whereExpr) { //increment the commandCounter so ALL tuples (also the new INSERTED) can be accessed CommandCounterIncrement(); if(sdf==2||sdf==4){ modelInfo->disAggKeyDenominator = 0; } FunctionCall2(&(modelInfo->algInfo)->algReestimateUpdate,PointerGetDatum(modelInfo), PointerGetDatum(whereExpr)); }
static int cmpEntries(const Datum *a, const Datum *b, cmpEntriesData *arg) { int res = DatumGetInt32(FunctionCall2(arg->cmpDatumFunc, *a, *b)); if (res == 0) *(arg->needUnique) = TRUE; return res; }
/* * Checks if range overlaps with existing partitions. * Returns TRUE if overlaps and FALSE otherwise. */ Datum check_overlap(PG_FUNCTION_ARGS) { int parent_oid = DatumGetInt32(PG_GETARG_DATUM(0)); Datum p1 = PG_GETARG_DATUM(1); Oid p1_type = get_fn_expr_argtype(fcinfo->flinfo, 1); Datum p2 = PG_GETARG_DATUM(2); Oid p2_type = get_fn_expr_argtype(fcinfo->flinfo, 2); PartRelationInfo *prel; RangeRelation *rangerel; RangeEntry *ranges; FmgrInfo cmp_func_1; FmgrInfo cmp_func_2; int i; bool byVal; prel = get_pathman_relation_info(parent_oid, NULL); rangerel = get_pathman_range_relation(parent_oid, NULL); if (!prel || !rangerel || prel->parttype != PT_RANGE) PG_RETURN_NULL(); /* comparison functions */ cmp_func_1 = *get_cmp_func(p1_type, prel->atttype); cmp_func_2 = *get_cmp_func(p2_type, prel->atttype); byVal = rangerel->by_val; ranges = (RangeEntry *) dsm_array_get_pointer(&rangerel->ranges); for (i=0; i<rangerel->ranges.length; i++) { int c1 = FunctionCall2(&cmp_func_1, p1, PATHMAN_GET_DATUM(ranges[i].max, byVal)); int c2 = FunctionCall2(&cmp_func_2, p2, PATHMAN_GET_DATUM(ranges[i].min, byVal)); if (c1 < 0 && c2 > 0) PG_RETURN_BOOL(true); } PG_RETURN_BOOL(false); }
/* * processForecastModel * * gets called every time an input tuple is processed */ void processForecastModel(ModelInfo *model, Datum value) { // process value internally as double double fValue = GetDatumAsDouble(exprType((Node*) model->measure->expr), value); if((sdf==2||sdf==4)){ model->disAggKeyDenominator += fValue; } // call algorithm specific method FunctionCall2(&(model->algInfo->algProcessForecast),PointerGetDatum(model->model),Float8GetDatum(fValue)); }
static OffsetNumber choose(Relation r, Page p, IndexTuple it, RTSTATE *rtstate) { OffsetNumber maxoff; OffsetNumber i; Datum ud, id; Datum datum; float usize, dsize; OffsetNumber which; float which_grow; id = IndexTupleGetDatum(it); maxoff = PageGetMaxOffsetNumber(p); which_grow = -1.0; which = -1; for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { datum = IndexTupleGetDatum(PageGetItem(p, PageGetItemId(p, i))); FunctionCall2(&rtstate->sizeFn, datum, PointerGetDatum(&dsize)); ud = FunctionCall2(&rtstate->unionFn, datum, id); FunctionCall2(&rtstate->sizeFn, ud, PointerGetDatum(&usize)); pfree(DatumGetPointer(ud)); if (which_grow < 0 || usize - dsize < which_grow) { which = i; which_grow = usize - dsize; if (which_grow == 0) break; } } return which; }
/* * Test whether key1 matches key2. Since the equality functions may leak, * reset the temporary context at each call and do all equality calculation * in that context. */ static int build_match_key(const void *key1, const void *key2, Size keysize __attribute__((unused))) { Assert(key1); Assert(key2); BMBuildHashKey *keyData1 = (BMBuildHashKey*)key1; Datum *k1 = keyData1->attributeValueArr; bool *isNull1 = keyData1->isNullArr; BMBuildHashKey *keyData2 = (BMBuildHashKey*)key2; Datum *k2 = keyData2->attributeValueArr; bool *isNull2 = keyData2->isNullArr; int numKeys = cur_bmbuild->natts; int i; MemoryContext old; int result = 0; MemoryContextReset(cur_bmbuild->tmpcxt); old = MemoryContextSwitchTo(cur_bmbuild->tmpcxt); for(i = 0; i < numKeys; i++) { if (isNull1[i] && isNull2[i]) { /* both nulls -- treat as equal so we group them together */ } else if ( isNull1[i] || isNull2[i]) { /* one is null and one non-null -- this is inequal */ result = 1; break; } else { /* do the real comparison */ Datum attr1 = k1[i]; Datum attr2 = k2[i]; if (!DatumGetBool(FunctionCall2(&cur_bmbuild->eq_funcs[i], attr1, attr2))) { result = 1; /* they aren't equal */ break; } } } MemoryContextSwitchTo(old); return result; }
/* * Compare two keys of the same index column */ int ginCompareEntries(GinState *ginstate, OffsetNumber attnum, Datum a, GinNullCategory categorya, Datum b, GinNullCategory categoryb) { /* if not of same null category, sort by that first */ if (categorya != categoryb) return (categorya < categoryb) ? -1 : 1; /* all null items in same category are equal */ if (categorya != GIN_CAT_NORM_KEY) return 0; /* both not null, so safe to call the compareFn */ return DatumGetInt32(FunctionCall2(&ginstate->compareFn[attnum - 1], a, b)); }
/* ---------------- * index_can_return * * Does the index access method support index-only scans for the given * column? * ---------------- */ bool index_can_return(Relation indexRelation, int attno) { FmgrInfo *procedure; RELATION_CHECKS; /* amcanreturn is optional; assume FALSE if not provided by AM */ if (!RegProcedureIsValid(indexRelation->rd_am->amcanreturn)) return false; GET_REL_PROCEDURE(amcanreturn); return DatumGetBool(FunctionCall2(procedure, PointerGetDatum(indexRelation), Int32GetDatum(attno))); }
/* * Compare the tuple and slot and check if they have equal values. * * We use binary datum comparison which might return false negatives but * that's the best we can do here as there may be multiple notions of * equality for the data types and table columns don't specify which one * to use. */ static bool tuple_equals_slot(TupleDesc desc, HeapTuple tup, TupleTableSlot *slot) { Datum values[MaxTupleAttributeNumber]; bool isnull[MaxTupleAttributeNumber]; int attrnum; heap_deform_tuple(tup, desc, values, isnull); /* Check equality of the attributes. */ for (attrnum = 0; attrnum < desc->natts; attrnum++) { Form_pg_attribute att; TypeCacheEntry *typentry; /* * If one value is NULL and other is not, then they are certainly not * equal */ if (isnull[attrnum] != slot->tts_isnull[attrnum]) return false; /* * If both are NULL, they can be considered equal. */ if (isnull[attrnum]) continue; att = TupleDescAttr(desc, attrnum); typentry = lookup_type_cache(att->atttypid, TYPECACHE_EQ_OPR_FINFO); if (!OidIsValid(typentry->eq_opr_finfo.fn_oid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("could not identify an equality operator for type %s", format_type_be(att->atttypid)))); if (!DatumGetBool(FunctionCall2(&typentry->eq_opr_finfo, values[attrnum], slot->tts_values[attrnum]))) return false; } return true; }
/* ---------------- * index_vacuum_cleanup - do post-deletion cleanup of an index * * return value is an optional palloc'd struct of statistics * ---------------- */ IndexBulkDeleteResult * index_vacuum_cleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { Relation indexRelation = info->index; FmgrInfo procedure; IndexBulkDeleteResult *result; RELATION_CHECKS; GET_UNCACHED_REL_PROCEDURE(amvacuumcleanup); result = (IndexBulkDeleteResult *) DatumGetPointer(FunctionCall2(&procedure, PointerGetDatum(info), PointerGetDatum(stats))); return result; }
/* * makes union of two key */ void gistMakeUnionKey(GISTSTATE *giststate, int attno, GISTENTRY *entry1, bool isnull1, GISTENTRY *entry2, bool isnull2, Datum *dst, bool *dstisnull) { int dstsize; static char storage[2 * sizeof(GISTENTRY) + GEVHDRSZ]; GistEntryVector *evec = (GistEntryVector *) storage; evec->n = 2; if (isnull1 && isnull2) { *dstisnull = TRUE; *dst = (Datum) 0; } else { if (isnull1 == FALSE && isnull2 == FALSE) { evec->vector[0] = *entry1; evec->vector[1] = *entry2; } else if (isnull1 == FALSE) { evec->vector[0] = *entry1; evec->vector[1] = *entry1; } else { evec->vector[0] = *entry2; evec->vector[1] = *entry2; } *dstisnull = FALSE; *dst = FunctionCall2(&giststate->unionFn[attno], PointerGetDatum(evec), PointerGetDatum(&dstsize)); } }
/* * _hash_checkqual -- does the index tuple satisfy the scan conditions? */ bool _hash_checkqual(IndexScanDesc scan, IndexTuple itup) { /* * Currently, we can't check any of the scan conditions since we do not * have the original index entry value to supply to the sk_func. Always * return true; we expect that hashgettuple already set the recheck flag * to make the main indexscan code do it. */ #ifdef NOT_USED TupleDesc tupdesc = RelationGetDescr(scan->indexRelation); ScanKey key = scan->keyData; int scanKeySize = scan->numberOfKeys; while (scanKeySize > 0) { Datum datum; bool isNull; Datum test; datum = index_getattr(itup, key->sk_attno, tupdesc, &isNull); /* assume sk_func is strict */ if (isNull) return false; if (key->sk_flags & SK_ISNULL) return false; test = FunctionCall2(&key->sk_func, datum, key->sk_argument); if (!DatumGetBool(test)) return false; key++; scanKeySize--; } #endif return true; }
/* ---------------- * index_getnext_tid - get the next TID from a scan * * The result is the next TID satisfying the scan keys, * or NULL if no more matching tuples exist. * ---------------- */ ItemPointer index_getnext_tid(IndexScanDesc scan, ScanDirection direction) { FmgrInfo *procedure; bool found; SCAN_CHECKS; GET_SCAN_PROCEDURE(amgettuple); Assert(TransactionIdIsValid(RecentGlobalXmin)); /* * The AM's amgettuple proc finds the next index entry matching the scan * keys, and puts the TID into scan->xs_ctup.t_self. It should also set * scan->xs_recheck and possibly scan->xs_itup, though we pay no attention * to those fields here. */ found = DatumGetBool(FunctionCall2(procedure, PointerGetDatum(scan), Int32GetDatum(direction))); /* Reset kill flag immediately for safety */ scan->kill_prior_tuple = false; /* If we're out of index entries, we're done */ if (!found) { /* ... but first, release any held pin on a heap page */ if (BufferIsValid(scan->xs_cbuf)) { ReleaseBuffer(scan->xs_cbuf); scan->xs_cbuf = InvalidBuffer; } return NULL; } pgstat_count_index_tuples(scan->indexRelation, 1); /* Return the TID of the tuple we found. */ return &scan->xs_ctup.t_self; }
/* ---------------- * index_rescan - (re)start a scan of an index * * The caller may specify a new set of scankeys (but the number of keys * cannot change). To restart the scan without changing keys, pass NULL * for the key array. * * Note that this is also called when first starting an indexscan; * see RelationGetIndexScan. Keys *must* be passed in that case, * unless scan->numberOfKeys is zero. * ---------------- */ void index_rescan(IndexScanDesc scan, ScanKey key) { FmgrInfo *procedure; SCAN_CHECKS; GET_SCAN_PROCEDURE(amrescan); /* Release any held pin on a heap page */ if (BufferIsValid(scan->xs_cbuf)) { ReleaseBuffer(scan->xs_cbuf); scan->xs_cbuf = InvalidBuffer; } scan->kill_prior_tuple = false; /* for safety */ FunctionCall2(procedure, PointerGetDatum(scan), PointerGetDatum(key)); }
/* ---------------- * index_getbitmap - get all tuples at once from an index scan * * it invokes am's getmulti function to get a bitmap. If am is an on-disk * bitmap index access method (see bitmap.h), then a StreamBitmap is * returned; a TIDBitmap otherwise. Note that an index am's getmulti * function can assume that the bitmap that it's given as argument is of * the same type as what the function constructs itself. * ---------------- */ Node * index_getbitmap(IndexScanDesc scan, Node *bitmap) { FmgrInfo *procedure; Node *bm; SCAN_CHECKS; GET_SCAN_PROCEDURE(amgetbitmap); /* just make sure this is false... */ scan->kill_prior_tuple = false; /* * have the am's getbitmap proc do all the work. */ bm = (Node *) DatumGetPointer(FunctionCall2(procedure, PointerGetDatum(scan), PointerGetDatum(bitmap))); return bm; }
/* ---------------- * index_getnext_indexitem - get the next index tuple from a scan * * Finds the next index tuple satisfying the scan keys. Note that the * corresponding heap tuple is not accessed, and thus no time qual (snapshot) * check is done, other than the index AM's internal check for killed tuples * (which most callers of this routine will probably want to suppress by * setting scan->ignore_killed_tuples = false). * * On success (TRUE return), the found index TID is in scan->currentItemData, * and its heap TID is in scan->xs_ctup.t_self. scan->xs_cbuf is untouched. * ---------------- */ bool index_getnext_indexitem(IndexScanDesc scan, ScanDirection direction) { bool found; SCAN_CHECKS; /* just make sure this is false... */ scan->kill_prior_tuple = false; /* * have the am's gettuple proc do all the work. index_beginscan * already set up fn_getnext. */ found = DatumGetBool(FunctionCall2(&scan->fn_getnext, PointerGetDatum(scan), Int32GetDatum(direction))); return found; }
/* * Inet MCV vs MCV join selectivity estimation * * We simply add up the fractions of the populations that satisfy the clause. * The result is exact and does not need to be scaled further. */ static Selectivity inet_mcv_join_sel(Datum *mcv1_values, float4 *mcv1_numbers, int mcv1_nvalues, Datum *mcv2_values, float4 *mcv2_numbers, int mcv2_nvalues, Oid operator) { Selectivity selec = 0.0; FmgrInfo proc; int i, j; fmgr_info(get_opcode(operator), &proc); for (i = 0; i < mcv1_nvalues; i++) { for (j = 0; j < mcv2_nvalues; j++) if (DatumGetBool(FunctionCall2(&proc, mcv1_values[i], mcv2_values[j]))) selec += mcv1_numbers[i] * mcv2_numbers[j]; } return selec; }
/* * _hash_checkqual -- does the index tuple satisfy the scan conditions? */ bool _hash_checkqual(IndexScanDesc scan, IndexTuple itup) { TupleDesc tupdesc = RelationGetDescr(scan->indexRelation); ScanKey key = scan->keyData; int scanKeySize = scan->numberOfKeys; IncrIndexProcessed(); while (scanKeySize > 0) { Datum datum; bool isNull; Datum test; datum = index_getattr(itup, key->sk_attno, tupdesc, &isNull); /* assume sk_func is strict */ if (isNull) return false; if (key->sk_flags & SK_ISNULL) return false; test = FunctionCall2(&key->sk_func, datum, key->sk_argument); if (!DatumGetBool(test)) return false; key++; scanKeySize--; } return true; }
/* ---------------- * index_getnext_indexitem - get the next index tuple from a scan * * Finds the next index tuple satisfying the scan keys. Note that the * corresponding heap tuple is not accessed, and thus no time qual (snapshot) * check is done, other than the index AM's internal check for killed tuples * (which most callers of this routine will probably want to suppress by * setting scan->ignore_killed_tuples = false). * * On success (TRUE return), the heap TID of the found index entry is in * scan->xs_ctup.t_self. scan->xs_cbuf is untouched. * ---------------- */ bool index_getnext_indexitem(IndexScanDesc scan, ScanDirection direction) { FmgrInfo *procedure; bool found; SCAN_CHECKS; GET_SCAN_PROCEDURE(amgettuple); /* just make sure this is false... */ scan->kill_prior_tuple = false; /* * have the am's gettuple proc do all the work. */ found = DatumGetBool(FunctionCall2(procedure, PointerGetDatum(scan), Int32GetDatum(direction))); pgstat_count_index_tuples(scan->indexRelation, 1 /*ntids*/); return found; }