diff options
Diffstat (limited to 'contrib/pgrowlocks/pgrowlocks.c')
-rw-r--r-- | contrib/pgrowlocks/pgrowlocks.c | 124 |
1 files changed, 53 insertions, 71 deletions
diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c index e20e7f83de3..1a71b390143 100644 --- a/contrib/pgrowlocks/pgrowlocks.c +++ b/contrib/pgrowlocks/pgrowlocks.c @@ -50,13 +50,6 @@ PG_FUNCTION_INFO_V1(pgrowlocks); #define NCHARS 32 -typedef struct -{ - Relation rel; - HeapScanDesc scan; - int ncolumns; -} MyData; - #define Atnum_tid 0 #define Atnum_xmax 1 #define Atnum_ismulti 2 @@ -67,59 +60,62 @@ typedef struct Datum pgrowlocks(PG_FUNCTION_ARGS) { - FuncCallContext *funcctx; - HeapScanDesc scan; - 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; + HeapScanDesc scan; + HeapTuple tuple; + MemoryContext oldcontext; + AclResult aclresult; + char **values; - 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_P(0); - relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); - rel = heap_openrv(relrv, AccessShareLock); - - /* check permissions: must have SELECT on table */ - aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), - ACL_SELECT); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_CLASS, - RelationGetRelationName(rel)); - - scan = heap_beginscan(rel, GetActiveSnapshot(), 0, NULL); - mydata = palloc(sizeof(*mydata)); - mydata->rel = rel; - mydata->scan = scan; - mydata->ncolumns = tupdesc->natts; - funcctx->user_fctx = mydata; - - MemoryContextSwitchTo(oldcontext); - } + /* 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"); - funcctx = SRF_PERCALL_SETUP(); - attinmeta = funcctx->attinmeta; - mydata = (MyData *) funcctx->user_fctx; - scan = mydata->scan; + 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 = heap_openrv(relrv, AccessShareLock); + + /* check permissions: must have SELECT on table */ + aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), + ACL_SELECT); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_CLASS, + RelationGetRelationName(rel)); + + /* Scan the relation */ + scan = heap_beginscan(rel, GetActiveSnapshot(), 0, NULL); + + attinmeta = TupleDescGetAttInMetadata(tupdesc); + + values = (char **) palloc(tupdesc->natts * sizeof(char *)); - /* scan the relation */ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { HTSU_Result htsu; @@ -140,10 +136,6 @@ pgrowlocks(PG_FUNCTION_ARGS) */ if (htsu == HeapTupleBeingUpdated) { - char **values; - - values = (char **) palloc(mydata->ncolumns * sizeof(char *)); - values[Atnum_tid] = (char *) DirectFunctionCall1(tidout, PointerGetDatum(&tuple->t_self)); @@ -268,16 +260,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 { @@ -286,7 +269,6 @@ pgrowlocks(PG_FUNCTION_ARGS) } heap_endscan(scan); - heap_close(mydata->rel, AccessShareLock); - - SRF_RETURN_DONE(funcctx); + heap_close(rel, AccessShareLock); + return (Datum) 0; } |