@@ -52,13 +52,6 @@ PG_FUNCTION_INFO_V1(pgrowlocks);
52
52
53
53
#define NCHARS 32
54
54
55
- typedef struct
56
- {
57
- Relation rel ;
58
- HeapScanDesc scan ;
59
- int ncolumns ;
60
- } MyData ;
61
-
62
55
#define Atnum_tid 0
63
56
#define Atnum_xmax 1
64
57
#define Atnum_ismulti 2
@@ -69,77 +62,80 @@ typedef struct
69
62
Datum
70
63
pgrowlocks (PG_FUNCTION_ARGS )
71
64
{
72
- FuncCallContext * funcctx ;
73
- HeapScanDesc scan ;
74
- HeapTuple tuple ;
65
+ text * relname = PG_GETARG_TEXT_PP ( 0 ) ;
66
+ ReturnSetInfo * rsinfo = ( ReturnSetInfo * ) fcinfo -> resultinfo ;
67
+ bool randomAccess ;
75
68
TupleDesc tupdesc ;
69
+ Tuplestorestate * tupstore ;
76
70
AttInMetadata * attinmeta ;
77
- Datum result ;
78
- MyData * mydata ;
79
71
Relation rel ;
72
+ RangeVar * relrv ;
73
+ HeapScanDesc scan ;
74
+ HeapTuple tuple ;
75
+ MemoryContext oldcontext ;
76
+ AclResult aclresult ;
77
+ char * * values ;
78
+
79
+ /* check to see if caller supports us returning a tuplestore */
80
+ if (rsinfo == NULL || !IsA (rsinfo , ReturnSetInfo ))
81
+ ereport (ERROR ,
82
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
83
+ errmsg ("set-valued function called in context that cannot accept a set" )));
84
+ if (!(rsinfo -> allowedModes & SFRM_Materialize ))
85
+ ereport (ERROR ,
86
+ (errcode (ERRCODE_SYNTAX_ERROR ),
87
+ errmsg ("materialize mode required, but it is not allowed in this context" )));
88
+
89
+ /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
90
+ oldcontext = MemoryContextSwitchTo (rsinfo -> econtext -> ecxt_per_query_memory );
91
+
92
+ if (get_call_result_type (fcinfo , NULL , & tupdesc ) != TYPEFUNC_COMPOSITE )
93
+ elog (ERROR , "return type must be a row type" );
94
+
95
+ randomAccess = (rsinfo -> allowedModes & SFRM_Materialize_Random ) != 0 ;
96
+ tupstore = tuplestore_begin_heap (randomAccess , false, work_mem );
97
+ rsinfo -> returnMode = SFRM_Materialize ;
98
+ rsinfo -> setResult = tupstore ;
99
+ rsinfo -> setDesc = tupdesc ;
100
+
101
+ MemoryContextSwitchTo (oldcontext );
102
+
103
+ /* Access the table */
104
+ relrv = makeRangeVarFromNameList (textToQualifiedNameList (relname ));
105
+ rel = relation_openrv (relrv , AccessShareLock );
106
+
107
+ if (rel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE )
108
+ ereport (ERROR ,
109
+ (errcode (ERRCODE_WRONG_OBJECT_TYPE ),
110
+ errmsg ("\"%s\" is a partitioned table" ,
111
+ RelationGetRelationName (rel )),
112
+ errdetail ("Partitioned tables do not contain rows." )));
113
+ else if (rel -> rd_rel -> relkind != RELKIND_RELATION )
114
+ ereport (ERROR ,
115
+ (errcode (ERRCODE_WRONG_OBJECT_TYPE ),
116
+ errmsg ("\"%s\" is not a table" ,
117
+ RelationGetRelationName (rel ))));
118
+
119
+ /*
120
+ * check permissions: must have SELECT on table or be in
121
+ * pg_stat_scan_tables
122
+ */
123
+ aclresult = pg_class_aclcheck (RelationGetRelid (rel ), GetUserId (),
124
+ ACL_SELECT );
125
+ if (aclresult != ACLCHECK_OK )
126
+ aclresult = is_member_of_role (GetUserId (), DEFAULT_ROLE_STAT_SCAN_TABLES ) ? ACLCHECK_OK : ACLCHECK_NO_PRIV ;
127
+
128
+ if (aclresult != ACLCHECK_OK )
129
+ aclcheck_error (aclresult , ACL_KIND_CLASS ,
130
+ RelationGetRelationName (rel ));
131
+
132
+ /* Scan the relation */
133
+ scan = heap_beginscan (rel , GetActiveSnapshot (), 0 , NULL );
134
+
135
+ attinmeta = TupleDescGetAttInMetadata (tupdesc );
136
+
137
+ values = (char * * ) palloc (tupdesc -> natts * sizeof (char * ));
80
138
81
- if (SRF_IS_FIRSTCALL ())
82
- {
83
- text * relname ;
84
- RangeVar * relrv ;
85
- MemoryContext oldcontext ;
86
- AclResult aclresult ;
87
-
88
- funcctx = SRF_FIRSTCALL_INIT ();
89
- oldcontext = MemoryContextSwitchTo (funcctx -> multi_call_memory_ctx );
90
-
91
- /* Build a tuple descriptor for our result type */
92
- if (get_call_result_type (fcinfo , NULL , & tupdesc ) != TYPEFUNC_COMPOSITE )
93
- elog (ERROR , "return type must be a row type" );
94
-
95
- attinmeta = TupleDescGetAttInMetadata (tupdesc );
96
- funcctx -> attinmeta = attinmeta ;
97
-
98
- relname = PG_GETARG_TEXT_PP (0 );
99
- relrv = makeRangeVarFromNameList (textToQualifiedNameList (relname ));
100
- rel = relation_openrv (relrv , AccessShareLock );
101
-
102
- if (rel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE )
103
- ereport (ERROR ,
104
- (errcode (ERRCODE_WRONG_OBJECT_TYPE ),
105
- errmsg ("\"%s\" is a partitioned table" ,
106
- RelationGetRelationName (rel )),
107
- errdetail ("Partitioned tables do not contain rows." )));
108
- else if (rel -> rd_rel -> relkind != RELKIND_RELATION )
109
- ereport (ERROR ,
110
- (errcode (ERRCODE_WRONG_OBJECT_TYPE ),
111
- errmsg ("\"%s\" is not a table" ,
112
- RelationGetRelationName (rel ))));
113
-
114
- /*
115
- * check permissions: must have SELECT on table or be in
116
- * pg_stat_scan_tables
117
- */
118
- aclresult = pg_class_aclcheck (RelationGetRelid (rel ), GetUserId (),
119
- ACL_SELECT );
120
- if (aclresult != ACLCHECK_OK )
121
- aclresult = is_member_of_role (GetUserId (), DEFAULT_ROLE_STAT_SCAN_TABLES ) ? ACLCHECK_OK : ACLCHECK_NO_PRIV ;
122
-
123
- if (aclresult != ACLCHECK_OK )
124
- aclcheck_error (aclresult , ACL_KIND_CLASS ,
125
- RelationGetRelationName (rel ));
126
-
127
- scan = heap_beginscan (rel , GetActiveSnapshot (), 0 , NULL );
128
- mydata = palloc (sizeof (* mydata ));
129
- mydata -> rel = rel ;
130
- mydata -> scan = scan ;
131
- mydata -> ncolumns = tupdesc -> natts ;
132
- funcctx -> user_fctx = mydata ;
133
-
134
- MemoryContextSwitchTo (oldcontext );
135
- }
136
-
137
- funcctx = SRF_PERCALL_SETUP ();
138
- attinmeta = funcctx -> attinmeta ;
139
- mydata = (MyData * ) funcctx -> user_fctx ;
140
- scan = mydata -> scan ;
141
-
142
- /* scan the relation */
143
139
while ((tuple = heap_getnext (scan , ForwardScanDirection )) != NULL )
144
140
{
145
141
HTSU_Result htsu ;
@@ -160,10 +156,6 @@ pgrowlocks(PG_FUNCTION_ARGS)
160
156
*/
161
157
if (htsu == HeapTupleBeingUpdated )
162
158
{
163
- char * * values ;
164
-
165
- values = (char * * ) palloc (mydata -> ncolumns * sizeof (char * ));
166
-
167
159
values [Atnum_tid ] = (char * ) DirectFunctionCall1 (tidout ,
168
160
PointerGetDatum (& tuple -> t_self ));
169
161
@@ -288,16 +280,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
288
280
289
281
/* build a tuple */
290
282
tuple = BuildTupleFromCStrings (attinmeta , values );
291
-
292
- /* make the tuple into a datum */
293
- result = HeapTupleGetDatum (tuple );
294
-
295
- /*
296
- * no need to pfree what we allocated; it's on a short-lived
297
- * memory context anyway
298
- */
299
-
300
- SRF_RETURN_NEXT (funcctx , result );
283
+ tuplestore_puttuple (tupstore , tuple );
301
284
}
302
285
else
303
286
{
@@ -306,7 +289,6 @@ pgrowlocks(PG_FUNCTION_ARGS)
306
289
}
307
290
308
291
heap_endscan (scan );
309
- heap_close (mydata -> rel , AccessShareLock );
310
-
311
- SRF_RETURN_DONE (funcctx );
292
+ heap_close (rel , AccessShareLock );
293
+ return (Datum ) 0 ;
312
294
}
0 commit comments