aboutsummaryrefslogtreecommitdiff
path: root/contrib/pgrowlocks/pgrowlocks.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pgrowlocks/pgrowlocks.c')
-rw-r--r--contrib/pgrowlocks/pgrowlocks.c173
1 files changed, 77 insertions, 96 deletions
diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c
index a2c44a916cf..714398831bc 100644
--- a/contrib/pgrowlocks/pgrowlocks.c
+++ b/contrib/pgrowlocks/pgrowlocks.c
@@ -54,13 +54,6 @@ PG_FUNCTION_INFO_V1(pgrowlocks);
#define NCHARS 32
-typedef struct
-{
- Relation rel;
- TableScanDesc scan;
- int ncolumns;
-} MyData;
-
#define Atnum_tid 0
#define Atnum_xmax 1
#define Atnum_ismulti 2
@@ -71,84 +64,86 @@ typedef struct
Datum
pgrowlocks(PG_FUNCTION_ARGS)
{
- FuncCallContext *funcctx;
- TableScanDesc scan;
- HeapScanDesc hscan;
- HeapTuple tuple;
+ text *relname = PG_GETARG_TEXT_PP(0);
+ ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ bool randomAccess;
TupleDesc tupdesc;
+ Tuplestorestate *tupstore;
AttInMetadata *attinmeta;
- Datum result;
- MyData *mydata;
Relation rel;
+ RangeVar *relrv;
+ TableScanDesc scan;
+ HeapScanDesc hscan;
+ HeapTuple tuple;
+ MemoryContext oldcontext;
+ AclResult aclresult;
+ char **values;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("materialize mode required, but it is not allowed in this context")));
+
+ /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
+ oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
+
+ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+ elog(ERROR, "return type must be a row type");
+
+ randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
+ tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ MemoryContextSwitchTo(oldcontext);
+
+ /* Access the table */
+ relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
+ rel = relation_openrv(relrv, AccessShareLock);
+
+ if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
+ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("only heap AM is supported")));
+
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is a partitioned table",
+ RelationGetRelationName(rel)),
+ errdetail("Partitioned tables do not contain rows.")));
+ else if (rel->rd_rel->relkind != RELKIND_RELATION)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a table",
+ RelationGetRelationName(rel))));
+
+ /*
+ * check permissions: must have SELECT on table or be in
+ * pg_stat_scan_tables
+ */
+ aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
+ ACL_SELECT);
+ if (aclresult != ACLCHECK_OK)
+ aclresult = is_member_of_role(GetUserId(), DEFAULT_ROLE_STAT_SCAN_TABLES) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
+
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
+ RelationGetRelationName(rel));
+
+ /* Scan the relation */
+ scan = table_beginscan(rel, GetActiveSnapshot(), 0, NULL);
+ hscan = (HeapScanDesc) scan;
- if (SRF_IS_FIRSTCALL())
- {
- text *relname;
- RangeVar *relrv;
- MemoryContext oldcontext;
- AclResult aclresult;
-
- funcctx = SRF_FIRSTCALL_INIT();
- oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
- /* 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");
-
- attinmeta = TupleDescGetAttInMetadata(tupdesc);
- funcctx->attinmeta = attinmeta;
-
- relname = PG_GETARG_TEXT_PP(0);
- relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
- rel = relation_openrv(relrv, AccessShareLock);
-
- if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
- ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("only heap AM is supported")));
-
- if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is a partitioned table",
- RelationGetRelationName(rel)),
- errdetail("Partitioned tables do not contain rows.")));
- else if (rel->rd_rel->relkind != RELKIND_RELATION)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table",
- RelationGetRelationName(rel))));
-
- /*
- * check permissions: must have SELECT on table or be in
- * pg_stat_scan_tables
- */
- aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
- ACL_SELECT);
- if (aclresult != ACLCHECK_OK)
- aclresult = is_member_of_role(GetUserId(), DEFAULT_ROLE_STAT_SCAN_TABLES) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
-
- if (aclresult != ACLCHECK_OK)
- aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
- RelationGetRelationName(rel));
-
- scan = table_beginscan(rel, GetActiveSnapshot(), 0, NULL);
- hscan = (HeapScanDesc) scan;
- mydata = palloc(sizeof(*mydata));
- mydata->rel = rel;
- mydata->scan = scan;
- mydata->ncolumns = tupdesc->natts;
- funcctx->user_fctx = mydata;
-
- MemoryContextSwitchTo(oldcontext);
- }
+ attinmeta = TupleDescGetAttInMetadata(tupdesc);
- funcctx = SRF_PERCALL_SETUP();
- attinmeta = funcctx->attinmeta;
- mydata = (MyData *) funcctx->user_fctx;
- scan = mydata->scan;
- hscan = (HeapScanDesc) scan;
+ values = (char **) palloc(tupdesc->natts * sizeof(char *));
- /* scan the relation */
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
TM_Result htsu;
@@ -169,10 +164,6 @@ pgrowlocks(PG_FUNCTION_ARGS)
*/
if (htsu == TM_BeingModified)
{
- char **values;
-
- values = (char **) palloc(mydata->ncolumns * sizeof(char *));
-
values[Atnum_tid] = (char *) DirectFunctionCall1(tidout,
PointerGetDatum(&tuple->t_self));
@@ -297,16 +288,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
/* build a tuple */
tuple = BuildTupleFromCStrings(attinmeta, values);
-
- /* make the tuple into a datum */
- result = HeapTupleGetDatum(tuple);
-
- /*
- * no need to pfree what we allocated; it's on a short-lived
- * memory context anyway
- */
-
- SRF_RETURN_NEXT(funcctx, result);
+ tuplestore_puttuple(tupstore, tuple);
}
else
{
@@ -315,7 +297,6 @@ pgrowlocks(PG_FUNCTION_ARGS)
}
table_endscan(scan);
- table_close(mydata->rel, AccessShareLock);
-
- SRF_RETURN_DONE(funcctx);
+ table_close(rel, AccessShareLock);
+ return (Datum) 0;
}