static void readindextuple(readindexinfo *info, Relation irel, Relation hrel, Datum *values, bool *nulls) { BlockNumber blkno; Page page; OffsetNumber offnum; IndexTuple itup; HeapTupleData htup; Buffer hbuf; AttrNumber attno; TupleDesc tupdesc = RelationGetDescr(irel); blkno = info->blkno; page = info->page; offnum = info->offnum; itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum)); htup.t_self = itup->t_tid; values[1] = ItemPointerGetDatum(&itup->t_tid); if (hrel == NULL) values[2] = PointerGetDatum(cstring_to_text(AOTupleIdToString((AOTupleId *)&itup->t_tid))); else values[2] = PointerGetDatum(cstring_to_text("N/A")); values[3] = PointerGetDatum(istatus_text(PageGetItemId(page, offnum))); if (hrel != NULL) { if (heap_fetch(hrel, SnapshotAny, &htup, &hbuf, true, NULL)) values[4] = PointerGetDatum(hstatus_text(htup.t_data, true)); else if (htup.t_data) values[4] = PointerGetDatum(hstatus_text(htup.t_data, false)); else values[4] = PointerGetDatum(cstring_to_text("NOT_FOUND")); ReleaseBuffer(hbuf); } else values[4] = PointerGetDatum(cstring_to_text("N/A")); for (attno = 1; attno <= tupdesc->natts; attno++) { bool isnull; values[FIXED_COLUMN+attno-1] = index_getattr(itup, attno, tupdesc, &isnull); nulls[FIXED_COLUMN+attno-1] = isnull; } }
Datum dbms_alert_defered_signal(PG_FUNCTION_ARGS) { TriggerData *trigdata = (TriggerData *) fcinfo->context; TupleDesc tupdesc; HeapTuple rettuple; char *relname; text *name; text *message; int event_col; int message_col; Datum datum; bool isnull; int cycle = 0; float8 endtime; float8 timeout = 2; if (!CALLED_AS_TRIGGER(fcinfo)) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("not called by trigger manager"))); if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("not called on valid event"))); if (SPI_connect() < 0) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("SPI_connect failed"))); if (strcmp((relname = SPI_getrelname(trigdata->tg_relation)), "ora_alerts") != 0) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("not called with valid relation"))); rettuple = trigdata->tg_trigtuple; tupdesc = trigdata->tg_relation->rd_att; if (SPI_ERROR_NOATTRIBUTE == (event_col = SPI_fnumber(tupdesc, "event"))) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("attribute event not found"))); if (SPI_ERROR_NOATTRIBUTE == (message_col = SPI_fnumber(tupdesc, "message"))) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("attribute message not found"))); datum = SPI_getbinval(rettuple, tupdesc, event_col, &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("event name is NULL"), errdetail("Eventname may not be NULL."))); name = DatumGetTextP(datum); datum = SPI_getbinval(rettuple, tupdesc, message_col, &isnull); if (isnull) message = NULL; else message = DatumGetTextP(datum); WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS, false)) { ItemPointer tid; Oid argtypes[1] = {TIDOID}; char nulls[1] = {' '}; Datum values[1]; void *plan; create_message(name, message); LWLockRelease(shmem_lock); tid = &rettuple->t_data->t_ctid; if (!(plan = SPI_prepare("DELETE FROM ora_alerts WHERE ctid = $1", 1, argtypes))) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("SPI_prepare failed"))); values[0] = ItemPointerGetDatum(tid); if (SPI_OK_DELETE != SPI_execute_plan(plan, values, nulls, false, 1)) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("can't execute sql"))); SPI_finish(); return PointerGetDatum(rettuple); } WATCH_POST(timeout, endtime, cycle); LOCK_ERROR(); PG_RETURN_NULL(); }
Datum readindex(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; readindexinfo *info; Relation irel = NULL; Relation hrel = NULL; MIRROREDLOCK_BUFMGR_DECLARE; if (SRF_IS_FIRSTCALL()) { Oid irelid = PG_GETARG_OID(0); TupleDesc tupdesc; MemoryContext oldcontext; AttrNumber outattnum; TupleDesc itupdesc; int i; AttrNumber attno; irel = index_open(irelid, AccessShareLock); itupdesc = RelationGetDescr(irel); outattnum = FIXED_COLUMN + itupdesc->natts; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); tupdesc = CreateTemplateTupleDesc(outattnum, false); attno = 1; TupleDescInitEntry(tupdesc, attno++, "ictid", TIDOID, -1, 0); TupleDescInitEntry(tupdesc, attno++, "hctid", TIDOID, -1, 0); TupleDescInitEntry(tupdesc, attno++, "aotid", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, attno++, "istatus", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, attno++, "hstatus", TEXTOID, -1, 0); for (i = 0; i < itupdesc->natts; i++) { Form_pg_attribute attr = itupdesc->attrs[i]; TupleDescInitEntry(tupdesc, attno++, NameStr(attr->attname), attr->atttypid, attr->atttypmod, 0); } funcctx->tuple_desc = BlessTupleDesc(tupdesc); info = (readindexinfo *) palloc(sizeof(readindexinfo)); funcctx->user_fctx = (void *) info; info->outattnum = outattnum; info->ireloid = irelid; hrel = relation_open(irel->rd_index->indrelid, AccessShareLock); if (hrel->rd_rel != NULL && (hrel->rd_rel->relstorage == 'a' || hrel->rd_rel->relstorage == 'c')) { relation_close(hrel, AccessShareLock); hrel = NULL; info->hreloid = InvalidOid; } else info->hreloid = irel->rd_index->indrelid; info->num_pages = RelationGetNumberOfBlocks(irel); info->blkno = BTREE_METAPAGE + 1; info->page = NULL; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); info = (readindexinfo *) funcctx->user_fctx; /* * Open the relations (on first call, we did that above already). * We unfortunately have to look up the relcache entry on every call, * because if we store it in the cross-call context, we won't get a * chance to release it if the function isn't run to completion, * e.g. because of a LIMIT clause. We only lock the relation on the * first call, and keep the lock until completion, however. */ if (!irel) irel = index_open(info->ireloid, NoLock); if (!hrel && info->hreloid != InvalidOid) hrel = heap_open(info->hreloid, NoLock); while (info->blkno < info->num_pages) { Datum values[255]; bool nulls[255]; ItemPointerData itid; HeapTuple tuple; Datum result; if (info->page == NULL) { Buffer buf; /* * Make copy of the page, because we cannot hold a buffer pin * across calls (we wouldn't have a chance to release it, if the * function isn't run to completion.) */ info->page = palloc(BLCKSZ); MIRROREDLOCK_BUFMGR_LOCK; buf = ReadBuffer(irel, info->blkno); memcpy(info->page, BufferGetPage(buf), BLCKSZ); ReleaseBuffer(buf); MIRROREDLOCK_BUFMGR_UNLOCK; info->opaque = (BTPageOpaque) PageGetSpecialPointer(info->page); info->minoff = P_FIRSTDATAKEY(info->opaque); info->maxoff = PageGetMaxOffsetNumber(info->page); info->offnum = info->minoff; } if (!P_ISLEAF(info->opaque) || info->offnum > info->maxoff) { pfree(info->page); info->page = NULL; info->blkno++; continue; } MemSet(nulls, false, info->outattnum * sizeof(bool)); ItemPointerSet(&itid, info->blkno, info->offnum); values[0] = ItemPointerGetDatum(&itid); readindextuple(info, irel, hrel, values, nulls); info->offnum = OffsetNumberNext(info->offnum); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); if (hrel != NULL) heap_close(hrel, NoLock); index_close(irel, NoLock); SRF_RETURN_NEXT(funcctx, result); } if (hrel != NULL) heap_close(hrel, AccessShareLock); index_close(irel, AccessShareLock); SRF_RETURN_DONE(funcctx); }
Datum gin_leafpage_items(PG_FUNCTION_ARGS) { bytea *raw_page = PG_GETARG_BYTEA_P(0); int raw_page_size; FuncCallContext *fctx; gin_leafpage_items_state *inter_call_data; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use raw page functions")))); raw_page_size = VARSIZE(raw_page) - VARHDRSZ; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext mctx; Page page; GinPageOpaque opaq; if (raw_page_size < BLCKSZ) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input page too small (%d bytes)", raw_page_size))); page = VARDATA(raw_page); if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData))) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input page is not a valid GIN data leaf page"), errdetail("Special size %d, expected %d", (int) PageGetSpecialSize(page), (int) MAXALIGN(sizeof(GinPageOpaqueData))))); opaq = (GinPageOpaque) PageGetSpecialPointer(page); if (opaq->flags != (GIN_DATA | GIN_LEAF | GIN_COMPRESSED)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input page is not a compressed GIN data leaf page"), errdetail("Flags %04X, expected %04X", opaq->flags, (GIN_DATA | GIN_LEAF | GIN_COMPRESSED)))); fctx = SRF_FIRSTCALL_INIT(); mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); inter_call_data = palloc(sizeof(gin_leafpage_items_state)); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); inter_call_data->tupd = tupdesc; inter_call_data->seg = GinDataLeafPageGetPostingList(page); inter_call_data->lastseg = (GinPostingList *) (((char *) inter_call_data->seg) + GinDataLeafPageGetPostingListSize(page)); fctx->user_fctx = inter_call_data; MemoryContextSwitchTo(mctx); } fctx = SRF_PERCALL_SETUP(); inter_call_data = fctx->user_fctx; if (inter_call_data->seg != inter_call_data->lastseg) { GinPostingList *cur = inter_call_data->seg; HeapTuple resultTuple; Datum result; Datum values[3]; bool nulls[3]; int ndecoded, i; ItemPointer tids; Datum *tids_datum; memset(nulls, 0, sizeof(nulls)); values[0] = ItemPointerGetDatum(&cur->first); values[1] = UInt16GetDatum(cur->nbytes); /* build an array of decoded item pointers */ tids = ginPostingListDecode(cur, &ndecoded); tids_datum = (Datum *) palloc(ndecoded * sizeof(Datum)); for (i = 0; i < ndecoded; i++) tids_datum[i] = ItemPointerGetDatum(&tids[i]); values[2] = PointerGetDatum(construct_array(tids_datum, ndecoded, TIDOID, sizeof(ItemPointerData), false, 's')); pfree(tids_datum); pfree(tids); /* Build and return the result tuple. */ resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls); result = HeapTupleGetDatum(resultTuple); inter_call_data->seg = GinNextPostingListSegment(cur); SRF_RETURN_NEXT(fctx, result); } else SRF_RETURN_DONE(fctx); }
Datum readindex(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; readindexinfo *info; MIRROREDLOCK_BUFMGR_DECLARE; if (SRF_IS_FIRSTCALL()) { Oid irelid = PG_GETARG_OID(0); TupleDesc tupdesc; MemoryContext oldcontext; AttrNumber outattnum; Relation irel; TupleDesc itupdesc; int i; AttrNumber attno; irel = index_open(irelid, AccessShareLock); itupdesc = RelationGetDescr(irel); outattnum = FIXED_COLUMN + itupdesc->natts; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); tupdesc = CreateTemplateTupleDesc(outattnum, false); attno = 1; TupleDescInitEntry(tupdesc, attno++, "ictid", TIDOID, -1, 0); TupleDescInitEntry(tupdesc, attno++, "hctid", TIDOID, -1, 0); TupleDescInitEntry(tupdesc, attno++, "aotid", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, attno++, "istatus", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, attno++, "hstatus", TEXTOID, -1, 0); for (i = 0; i < itupdesc->natts; i++) { Form_pg_attribute attr = itupdesc->attrs[i]; TupleDescInitEntry(tupdesc, attno++, NameStr(attr->attname), attr->atttypid, attr->atttypmod, 0); } funcctx->tuple_desc = BlessTupleDesc(tupdesc); info = (readindexinfo *) palloc(sizeof(readindexinfo)); funcctx->user_fctx = (void *) info; info->outattnum = outattnum; info->irel = irel; info->hrel = relation_open(irel->rd_index->indrelid, AccessShareLock); if (info->hrel->rd_rel != NULL && (info->hrel->rd_rel->relstorage == 'a' || info->hrel->rd_rel->relstorage == 'c')) { relation_close(info->hrel, AccessShareLock); info->hrel = NULL; } info->num_pages = RelationGetNumberOfBlocks(irel); info->blkno = BTREE_METAPAGE + 1; info->page = NULL; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); info = (readindexinfo *) funcctx->user_fctx; while (info->blkno < info->num_pages) { Datum values[255]; bool nulls[255]; ItemPointerData itid; HeapTuple tuple; Datum result; if (info->page == NULL) { MIRROREDLOCK_BUFMGR_LOCK; info->buf = ReadBuffer(info->irel, info->blkno); info->page = BufferGetPage(info->buf); info->opaque = (BTPageOpaque) PageGetSpecialPointer(info->page); info->minoff = P_FIRSTDATAKEY(info->opaque); info->maxoff = PageGetMaxOffsetNumber(info->page); info->offnum = info->minoff; MIRROREDLOCK_BUFMGR_UNLOCK; } if (!P_ISLEAF(info->opaque) || info->offnum > info->maxoff) { ReleaseBuffer(info->buf); info->page = NULL; info->blkno++; continue; } MemSet(nulls, false, info->outattnum * sizeof(bool)); ItemPointerSet(&itid, info->blkno, info->offnum); values[0] = ItemPointerGetDatum(&itid); readindextuple(info, values, nulls); info->offnum = OffsetNumberNext(info->offnum); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } if (info->hrel != NULL) relation_close(info->hrel, AccessShareLock); index_close(info->irel, AccessShareLock); SRF_RETURN_DONE(funcctx); }
static Datum gp_aovisimap_internal(PG_FUNCTION_ARGS, Oid aoRelOid) { Datum values[3]; bool nulls[3]; HeapTuple tuple; Datum result; typedef struct Context { Relation aorel; AppendOnlyVisimapScan visiMapScan; AOTupleId aoTupleId; } Context; FuncCallContext *funcctx; Context *context; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext oldcontext; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* * switch to memory context appropriate for multiple function * calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* build tupdesc for result tuples */ tupdesc = CreateTemplateTupleDesc(3, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tid", TIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "segno", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "row_num", INT8OID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* * Collect all the locking information that we will format and send * out as a result set. */ context = (Context *) palloc0(sizeof(Context)); context->aorel = heap_open(aoRelOid, AccessShareLock); if (!(RelationIsAoRows(context->aorel) || RelationIsAoCols(context->aorel))) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Function not supported on relation"))); } AppendOnlyVisimapScan_Init(&context->visiMapScan, context->aorel->rd_appendonly->visimaprelid, context->aorel->rd_appendonly->visimapidxid, AccessShareLock, SnapshotNow); AOTupleIdInit_Init(&context->aoTupleId); funcctx->user_fctx = (void *) context; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); context = (Context *) funcctx->user_fctx; while (true) { if (!AppendOnlyVisimapScan_GetNextInvisible( &context->visiMapScan, &context->aoTupleId)) { break; } MemSet(values, 0, sizeof(values)); MemSet(nulls, false, sizeof(nulls)); values[0] = ItemPointerGetDatum((ItemPointer)&context->aoTupleId); values[1] = Int32GetDatum(AOTupleIdGet_segmentFileNum(&context->aoTupleId)); values[2] = Int64GetDatum(AOTupleIdGet_rowNum(&context->aoTupleId)); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } AppendOnlyVisimapScan_Finish(&context->visiMapScan, AccessShareLock); heap_close(context->aorel, AccessShareLock); pfree(context); funcctx->user_fctx = NULL; SRF_RETURN_DONE(funcctx); }