#include "postgres.h"
#include "access/relscan.h"
#include "access/transam.h"
#include "catalog/index.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "utils/snapmgr.h"
#include "utils/tqual.h"
Go to the source code of this file.
#define GET_REL_PROCEDURE | ( | pname | ) |
do { \ procedure = &indexRelation->rd_aminfo->pname; \ if (!OidIsValid(procedure->fn_oid)) \ { \ RegProcedure procOid = indexRelation->rd_am->pname; \ if (!RegProcedureIsValid(procOid)) \ elog(ERROR, "invalid %s regproc", CppAsString(pname)); \ fmgr_info_cxt(procOid, procedure, indexRelation->rd_indexcxt); \ } \ } while(0)
Definition at line 105 of file indexam.c.
Referenced by index_beginscan_internal(), index_can_return(), and index_insert().
#define GET_SCAN_PROCEDURE | ( | pname | ) |
do { \ procedure = &scan->indexRelation->rd_aminfo->pname; \ if (!OidIsValid(procedure->fn_oid)) \ { \ RegProcedure procOid = scan->indexRelation->rd_am->pname; \ if (!RegProcedureIsValid(procOid)) \ elog(ERROR, "invalid %s regproc", CppAsString(pname)); \ fmgr_info_cxt(procOid, procedure, scan->indexRelation->rd_indexcxt); \ } \ } while(0)
Definition at line 124 of file indexam.c.
Referenced by index_endscan(), index_getbitmap(), index_getnext_tid(), index_markpos(), index_rescan(), and index_restrpos().
#define GET_UNCACHED_REL_PROCEDURE | ( | pname | ) |
do { \ if (!RegProcedureIsValid(indexRelation->rd_am->pname)) \ elog(ERROR, "invalid %s regproc", CppAsString(pname)); \ fmgr_info(indexRelation->rd_am->pname, &procedure); \ } while(0)
Definition at line 117 of file indexam.c.
Referenced by index_bulk_delete(), and index_vacuum_cleanup().
#define RELATION_CHECKS |
( \ AssertMacro(RelationIsValid(indexRelation)), \ AssertMacro(PointerIsValid(indexRelation->rd_am)), \ AssertMacro(!ReindexIsProcessingIndex(RelationGetRelid(indexRelation))) \ )
#define SCAN_CHECKS |
( \ AssertMacro(IndexScanIsValid(scan)), \ AssertMacro(RelationIsValid(scan->indexRelation)), \ AssertMacro(PointerIsValid(scan->indexRelation->rd_am)) \ )
IndexScanDesc index_beginscan | ( | Relation | heapRelation, | |
Relation | indexRelation, | |||
Snapshot | snapshot, | |||
int | nkeys, | |||
int | norderbys | |||
) |
Definition at line 238 of file indexam.c.
References IndexScanDescData::heapRelation, index_beginscan_internal(), and IndexScanDescData::xs_snapshot.
Referenced by check_exclusion_constraint(), copy_heap_data(), ExecInitIndexOnlyScan(), ExecInitIndexScan(), get_actual_variable_range(), systable_beginscan(), and systable_beginscan_ordered().
{ IndexScanDesc scan; scan = index_beginscan_internal(indexRelation, nkeys, norderbys, snapshot); /* * Save additional parameters into the scandesc. Everything else was set * up by RelationGetIndexScan. */ scan->heapRelation = heapRelation; scan->xs_snapshot = snapshot; return scan; }
IndexScanDesc index_beginscan_bitmap | ( | Relation | indexRelation, | |
Snapshot | snapshot, | |||
int | nkeys | |||
) |
Definition at line 264 of file indexam.c.
References index_beginscan_internal(), and IndexScanDescData::xs_snapshot.
Referenced by ExecInitBitmapIndexScan().
{ IndexScanDesc scan; scan = index_beginscan_internal(indexRelation, nkeys, 0, snapshot); /* * Save additional parameters into the scandesc. Everything else was set * up by RelationGetIndexScan. */ scan->xs_snapshot = snapshot; return scan; }
static IndexScanDesc index_beginscan_internal | ( | Relation | indexRelation, | |
int | nkeys, | |||
int | norderbys, | |||
Snapshot | snapshot | |||
) | [static] |
Definition at line 285 of file indexam.c.
References DatumGetPointer, FunctionCall3, GET_REL_PROCEDURE, Int32GetDatum, PointerGetDatum, PredicateLockRelation(), RelationData::rd_am, and RelationIncrementReferenceCount().
Referenced by index_beginscan(), and index_beginscan_bitmap().
{ IndexScanDesc scan; FmgrInfo *procedure; RELATION_CHECKS; GET_REL_PROCEDURE(ambeginscan); if (!(indexRelation->rd_am->ampredlocks)) PredicateLockRelation(indexRelation, snapshot); /* * We hold a reference count to the relcache entry throughout the scan. */ RelationIncrementReferenceCount(indexRelation); /* * Tell the AM to open a scan. */ scan = (IndexScanDesc) DatumGetPointer(FunctionCall3(procedure, PointerGetDatum(indexRelation), Int32GetDatum(nkeys), Int32GetDatum(norderbys))); return scan; }
IndexBulkDeleteResult* index_bulk_delete | ( | IndexVacuumInfo * | info, | |
IndexBulkDeleteResult * | stats, | |||
IndexBulkDeleteCallback | callback, | |||
void * | callback_state | |||
) |
Definition at line 675 of file indexam.c.
References DatumGetPointer, FunctionCall4, GET_UNCACHED_REL_PROCEDURE, IndexVacuumInfo::index, and PointerGetDatum.
Referenced by lazy_vacuum_index(), and validate_index().
{ Relation indexRelation = info->index; FmgrInfo procedure; IndexBulkDeleteResult *result; RELATION_CHECKS; GET_UNCACHED_REL_PROCEDURE(ambulkdelete); result = (IndexBulkDeleteResult *) DatumGetPointer(FunctionCall4(&procedure, PointerGetDatum(info), PointerGetDatum(stats), PointerGetDatum((Pointer) callback), PointerGetDatum(callback_state))); return result; }
Definition at line 727 of file indexam.c.
References DatumGetBool, FunctionCall1, GET_REL_PROCEDURE, PointerGetDatum, RelationData::rd_am, and RegProcedureIsValid.
Referenced by get_relation_info().
{ 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(FunctionCall1(procedure, PointerGetDatum(indexRelation))); }
Definition at line 185 of file indexam.c.
References Assert, LockInfoData::lockRelId, MAX_LOCKMODES, NoLock, RelationData::rd_lockInfo, RelationClose(), and UnlockRelationId().
Referenced by ATExecAddIndex(), ATExecAddIndexConstraint(), build_indices(), BuildEventTriggerCache(), check_index_is_clusterable(), CheckIndexCompatible(), close_lo_relation(), copy_heap_data(), DefineIndex(), enum_endpoint(), enum_range_internal(), ExecCloseIndices(), ExecEndBitmapIndexScan(), ExecEndIndexOnlyScan(), ExecEndIndexScan(), get_actual_variable_range(), get_relation_info(), gincostestimate(), index_create(), index_drop(), InitCatCachePhase2(), lookup_ts_config_cache(), reindex_index(), RelationGetIndexAttrBitmap(), RelationTruncateIndexes(), systable_endscan(), toast_delete_datum(), toast_fetch_datum(), toast_fetch_datum_slice(), toast_save_datum(), transformTableLikeClause(), TryReuseIndex(), vac_close_indexes(), vac_open_indexes(), and validate_index().
{ LockRelId relid = relation->rd_lockInfo.lockRelId; Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES); /* The relcache does the real work... */ RelationClose(relation); if (lockmode != NoLock) UnlockRelationId(&relid, lockmode); }
void index_endscan | ( | IndexScanDesc | scan | ) |
Definition at line 363 of file indexam.c.
References BufferIsValid, FunctionCall1, GET_SCAN_PROCEDURE, IndexScanDescData::indexRelation, IndexScanEnd(), PointerGetDatum, RelationDecrementReferenceCount(), ReleaseBuffer(), and IndexScanDescData::xs_cbuf.
Referenced by check_exclusion_constraint(), copy_heap_data(), ExecEndBitmapIndexScan(), ExecEndIndexOnlyScan(), ExecEndIndexScan(), get_actual_variable_range(), systable_endscan(), and systable_endscan_ordered().
{ FmgrInfo *procedure; SCAN_CHECKS; GET_SCAN_PROCEDURE(amendscan); /* Release any held pin on a heap page */ if (BufferIsValid(scan->xs_cbuf)) { ReleaseBuffer(scan->xs_cbuf); scan->xs_cbuf = InvalidBuffer; } /* End the AM's scan */ FunctionCall1(procedure, PointerGetDatum(scan)); /* Release index refcount acquired by index_beginscan */ RelationDecrementReferenceCount(scan->indexRelation); /* Release the scan data structure itself */ IndexScanEnd(scan); }
HeapTuple index_fetch_heap | ( | IndexScanDesc | scan | ) |
Definition at line 503 of file indexam.c.
References BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, heap_hot_search_buffer(), heap_page_prune_opt(), IndexScanDescData::heapRelation, IndexScanDescData::indexRelation, IsMVCCSnapshot, ItemPointerGetBlockNumber, IndexScanDescData::kill_prior_tuple, LockBuffer(), pgstat_count_heap_fetch, RecentGlobalXmin, ReleaseAndReadBuffer(), HeapTupleData::t_self, IndexScanDescData::xactStartedInRecovery, IndexScanDescData::xs_cbuf, IndexScanDescData::xs_continue_hot, IndexScanDescData::xs_ctup, and IndexScanDescData::xs_snapshot.
Referenced by index_getnext(), and IndexOnlyNext().
{ ItemPointer tid = &scan->xs_ctup.t_self; bool all_dead = false; bool got_heap_tuple; /* We can skip the buffer-switching logic if we're in mid-HOT chain. */ if (!scan->xs_continue_hot) { /* Switch to correct buffer if we don't have it already */ Buffer prev_buf = scan->xs_cbuf; scan->xs_cbuf = ReleaseAndReadBuffer(scan->xs_cbuf, scan->heapRelation, ItemPointerGetBlockNumber(tid)); /* * Prune page, but only if we weren't already on this page */ if (prev_buf != scan->xs_cbuf) heap_page_prune_opt(scan->heapRelation, scan->xs_cbuf, RecentGlobalXmin); } /* Obtain share-lock on the buffer so we can examine visibility */ LockBuffer(scan->xs_cbuf, BUFFER_LOCK_SHARE); got_heap_tuple = heap_hot_search_buffer(tid, scan->heapRelation, scan->xs_cbuf, scan->xs_snapshot, &scan->xs_ctup, &all_dead, !scan->xs_continue_hot); LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK); if (got_heap_tuple) { /* * Only in a non-MVCC snapshot can more than one member of the HOT * chain be visible. */ scan->xs_continue_hot = !IsMVCCSnapshot(scan->xs_snapshot); pgstat_count_heap_fetch(scan->indexRelation); return &scan->xs_ctup; } /* We've reached the end of the HOT chain. */ scan->xs_continue_hot = false; /* * If we scanned a whole HOT chain and found only dead tuples, tell index * AM to kill its entry for that TID (this will take effect in the next * amgettuple call, in index_getnext_tid). We do not do this when in * recovery because it may violate MVCC to do so. See comments in * RelationGetIndexScan(). */ if (!scan->xactStartedInRecovery) scan->kill_prior_tuple = all_dead; return NULL; }
int64 index_getbitmap | ( | IndexScanDesc | scan, | |
TIDBitmap * | bitmap | |||
) |
Definition at line 634 of file indexam.c.
References DatumGetInt64, DatumGetPointer, FunctionCall2, GET_SCAN_PROCEDURE, IndexScanDescData::indexRelation, IndexScanDescData::kill_prior_tuple, pfree(), pgstat_count_index_tuples, and PointerGetDatum.
Referenced by MultiExecBitmapIndexScan().
{ 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; }
HeapTuple index_getnext | ( | IndexScanDesc | scan, | |
ScanDirection | direction | |||
) |
Definition at line 580 of file indexam.c.
References Assert, BufferGetBlockNumber(), BufferIsValid, index_fetch_heap(), index_getnext_tid(), ItemPointerGetBlockNumber, NULL, HeapTupleData::t_self, IndexScanDescData::xs_cbuf, IndexScanDescData::xs_continue_hot, and IndexScanDescData::xs_ctup.
Referenced by check_exclusion_constraint(), copy_heap_data(), get_actual_variable_range(), IndexNext(), systable_getnext(), and systable_getnext_ordered().
{ HeapTuple heapTuple; ItemPointer tid; for (;;) { if (scan->xs_continue_hot) { /* * We are resuming scan of a HOT chain after having returned an * earlier member. Must still hold pin on current heap page. */ Assert(BufferIsValid(scan->xs_cbuf)); Assert(ItemPointerGetBlockNumber(&scan->xs_ctup.t_self) == BufferGetBlockNumber(scan->xs_cbuf)); } else { /* Time to fetch the next TID from the index */ tid = index_getnext_tid(scan, direction); /* If we're out of index entries, we're done */ if (tid == NULL) break; } /* * Fetch the next (or only) visible heap tuple for this index entry. * If we don't find anything, loop around and grab the next TID from * the index. */ heapTuple = index_fetch_heap(scan); if (heapTuple != NULL) return heapTuple; } return NULL; /* failure exit */ }
ItemPointer index_getnext_tid | ( | IndexScanDesc | scan, | |
ScanDirection | direction | |||
) |
Definition at line 443 of file indexam.c.
References Assert, BufferIsValid, DatumGetBool, FunctionCall2, GET_SCAN_PROCEDURE, IndexScanDescData::indexRelation, Int32GetDatum, IndexScanDescData::kill_prior_tuple, pgstat_count_index_tuples, PointerGetDatum, RecentGlobalXmin, ReleaseBuffer(), HeapTupleData::t_self, TransactionIdIsValid, IndexScanDescData::xs_cbuf, and IndexScanDescData::xs_ctup.
Referenced by index_getnext(), and IndexOnlyNext().
{ 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; }
RegProcedure index_getprocid | ( | Relation | irel, | |
AttrNumber | attnum, | |||
uint16 | procnum | |||
) |
Definition at line 770 of file indexam.c.
References Assert, NULL, RelationData::rd_am, and RelationData::rd_support.
Referenced by _hash_metapinit(), initGinState(), and initGISTstate().
{ RegProcedure *loc; int nproc; int procindex; nproc = irel->rd_am->amsupport; Assert(procnum > 0 && procnum <= (uint16) nproc); procindex = (nproc * (attnum - 1)) + (procnum - 1); loc = irel->rd_support; Assert(loc != NULL); return loc[procindex]; }
FmgrInfo* index_getprocinfo | ( | Relation | irel, | |
AttrNumber | attnum, | |||
uint16 | procnum | |||
) |
Definition at line 804 of file indexam.c.
References Assert, elog, ERROR, fmgr_info_cxt(), FmgrInfo::fn_oid, InvalidOid, NULL, RelationData::rd_am, RelationData::rd_indexcxt, RelationData::rd_support, RelationData::rd_supportinfo, RegProcedureIsValid, and RelationGetRelationName.
Referenced by _bt_first(), _bt_mkscankey(), _bt_mkscankey_nodata(), _hash_datum2hashkey(), doPickSplit(), initGinState(), initGISTstate(), spgdoinsert(), spgGetCache(), spgLeafTest(), and spgWalk().
{ FmgrInfo *locinfo; int nproc; int procindex; nproc = irel->rd_am->amsupport; Assert(procnum > 0 && procnum <= (uint16) nproc); procindex = (nproc * (attnum - 1)) + (procnum - 1); locinfo = irel->rd_supportinfo; Assert(locinfo != NULL); locinfo += procindex; /* Initialize the lookup info if first time through */ if (locinfo->fn_oid == InvalidOid) { RegProcedure *loc = irel->rd_support; RegProcedure procId; Assert(loc != NULL); procId = loc[procindex]; /* * Complain if function was not found during IndexSupportInitialize. * This should not happen unless the system tables contain bogus * entries for the index opclass. (If an AM wants to allow a support * function to be optional, it can use index_getprocid.) */ if (!RegProcedureIsValid(procId)) elog(ERROR, "missing support function %d for attribute %d of index \"%s\"", procnum, attnum, RelationGetRelationName(irel)); fmgr_info_cxt(procId, locinfo, irel->rd_indexcxt); } return locinfo; }
bool index_insert | ( | Relation | indexRelation, | |
Datum * | values, | |||
bool * | isnull, | |||
ItemPointer | heap_t_ctid, | |||
Relation | heapRelation, | |||
IndexUniqueCheck | checkUnique | |||
) |
Definition at line 203 of file indexam.c.
References CheckForSerializableConflictIn(), DatumGetBool, FunctionCall6, GET_REL_PROCEDURE, Int32GetDatum, InvalidBuffer, NULL, PointerGetDatum, and RelationData::rd_am.
Referenced by CatalogIndexInsert(), ExecInsertIndexTuples(), toast_save_datum(), and validate_index_heapscan().
{ FmgrInfo *procedure; RELATION_CHECKS; GET_REL_PROCEDURE(aminsert); if (!(indexRelation->rd_am->ampredlocks)) CheckForSerializableConflictIn(indexRelation, (HeapTuple) NULL, InvalidBuffer); /* * have the am's insert proc do all the work. */ return DatumGetBool(FunctionCall6(procedure, PointerGetDatum(indexRelation), PointerGetDatum(values), PointerGetDatum(isnull), PointerGetDatum(heap_t_ctid), PointerGetDatum(heapRelation), Int32GetDatum((int32) checkUnique))); }
void index_markpos | ( | IndexScanDesc | scan | ) |
Definition at line 392 of file indexam.c.
References FunctionCall1, GET_SCAN_PROCEDURE, and PointerGetDatum.
Referenced by ExecIndexMarkPos(), and ExecIndexOnlyMarkPos().
{ FmgrInfo *procedure; SCAN_CHECKS; GET_SCAN_PROCEDURE(ammarkpos); FunctionCall1(procedure, PointerGetDatum(scan)); }
Definition at line 160 of file indexam.c.
References ereport, errcode(), errmsg(), ERROR, RelationData::rd_rel, relation_open(), RelationGetRelationName, and RELKIND_INDEX.
Referenced by ATExecAddIndex(), ATExecAddIndexConstraint(), build_indices(), BuildEventTriggerCache(), check_index_is_clusterable(), CheckIndexCompatible(), copy_heap_data(), DefineIndex(), enum_endpoint(), enum_range_internal(), ExecInitBitmapIndexScan(), ExecInitIndexOnlyScan(), ExecInitIndexScan(), ExecOpenIndices(), get_actual_variable_range(), get_relation_info(), gincostestimate(), index_drop(), InitCatCachePhase2(), lookup_ts_config_cache(), open_lo_relation(), reindex_index(), RelationGetIndexAttrBitmap(), RelationTruncateIndexes(), systable_beginscan(), toast_delete_datum(), toast_fetch_datum(), toast_fetch_datum_slice(), toast_save_datum(), transformIndexConstraint(), transformTableLikeClause(), TryReuseIndex(), vac_open_indexes(), and validate_index().
{ Relation r; r = relation_open(relationId, lockmode); if (r->rd_rel->relkind != RELKIND_INDEX) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not an index", RelationGetRelationName(r)))); return r; }
void index_rescan | ( | IndexScanDesc | scan, | |
ScanKey | keys, | |||
int | nkeys, | |||
ScanKey | orderbys, | |||
int | norderbys | |||
) |
Definition at line 327 of file indexam.c.
References Assert, BufferIsValid, FunctionCall5, GET_SCAN_PROCEDURE, Int32GetDatum, IndexScanDescData::kill_prior_tuple, IndexScanDescData::numberOfKeys, IndexScanDescData::numberOfOrderBys, PointerGetDatum, ReleaseBuffer(), IndexScanDescData::xs_cbuf, and IndexScanDescData::xs_continue_hot.
Referenced by check_exclusion_constraint(), copy_heap_data(), ExecInitBitmapIndexScan(), ExecInitIndexOnlyScan(), ExecInitIndexScan(), ExecReScanBitmapIndexScan(), ExecReScanIndexOnlyScan(), ExecReScanIndexScan(), get_actual_variable_range(), MultiExecBitmapIndexScan(), systable_beginscan(), and systable_beginscan_ordered().
{ FmgrInfo *procedure; SCAN_CHECKS; GET_SCAN_PROCEDURE(amrescan); Assert(nkeys == scan->numberOfKeys); Assert(norderbys == scan->numberOfOrderBys); /* Release any held pin on a heap page */ if (BufferIsValid(scan->xs_cbuf)) { ReleaseBuffer(scan->xs_cbuf); scan->xs_cbuf = InvalidBuffer; } scan->xs_continue_hot = false; scan->kill_prior_tuple = false; /* for safety */ FunctionCall5(procedure, PointerGetDatum(scan), PointerGetDatum(keys), Int32GetDatum(nkeys), PointerGetDatum(orderbys), Int32GetDatum(norderbys)); }
void index_restrpos | ( | IndexScanDesc | scan | ) |
Definition at line 419 of file indexam.c.
References Assert, FunctionCall1, GET_SCAN_PROCEDURE, IsMVCCSnapshot, IndexScanDescData::kill_prior_tuple, PointerGetDatum, IndexScanDescData::xs_continue_hot, and IndexScanDescData::xs_snapshot.
Referenced by ExecIndexOnlyRestrPos(), and ExecIndexRestrPos().
{ FmgrInfo *procedure; Assert(IsMVCCSnapshot(scan->xs_snapshot)); SCAN_CHECKS; GET_SCAN_PROCEDURE(amrestrpos); scan->xs_continue_hot = false; scan->kill_prior_tuple = false; /* for safety */ FunctionCall1(procedure, PointerGetDatum(scan)); }
IndexBulkDeleteResult* index_vacuum_cleanup | ( | IndexVacuumInfo * | info, | |
IndexBulkDeleteResult * | stats | |||
) |
Definition at line 704 of file indexam.c.
References DatumGetPointer, FunctionCall2, GET_UNCACHED_REL_PROCEDURE, IndexVacuumInfo::index, and PointerGetDatum.
Referenced by do_analyze_rel(), and lazy_cleanup_index().
{ 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; }