@@ -37,18 +37,6 @@ typedef struct brin_column_state
3737FmgrInfo outputFn [FLEXIBLE_ARRAY_MEMBER ];
3838}brin_column_state ;
3939
40- typedef struct brin_page_state
41- {
42- BrinDesc * bdesc ;
43- Page page ;
44- OffsetNumber offset ;
45- bool unusedItem ;
46- bool done ;
47- AttrNumber attno ;
48- BrinMemTuple * dtup ;
49- brin_column_state * columns [FLEXIBLE_ARRAY_MEMBER ];
50- }brin_page_state ;
51-
5240
5341static Page verify_brin_page (bytea * raw_page ,uint16 type ,
5442const char * strtype );
@@ -119,89 +107,89 @@ verify_brin_page(bytea *raw_page, uint16 type, const char *strtype)
119107Datum
120108brin_page_items (PG_FUNCTION_ARGS )
121109{
122- brin_page_state * state ;
123- FuncCallContext * fctx ;
110+ bytea * raw_page = PG_GETARG_BYTEA_P (0 );
111+ Oid indexRelid = PG_GETARG_OID (1 );
112+ ReturnSetInfo * rsinfo = (ReturnSetInfo * )fcinfo -> resultinfo ;
113+ TupleDesc tupdesc ;
114+ MemoryContext oldcontext ;
115+ Tuplestorestate * tupstore ;
116+ Relation indexRel ;
117+ brin_column_state * * columns ;
118+ BrinDesc * bdesc ;
119+ BrinMemTuple * dtup ;
120+ Page page ;
121+ OffsetNumber offset ;
122+ AttrNumber attno ;
123+ bool unusedItem ;
124124
125125if (!superuser ())
126126ereport (ERROR ,
127127(errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
128128 (errmsg ("must be superuser to use raw page functions" ))));
129129
130- if (SRF_IS_FIRSTCALL ())
131- {
132- bytea * raw_page = PG_GETARG_BYTEA_P (0 );
133- Oid indexRelid = PG_GETARG_OID (1 );
134- Page page ;
135- TupleDesc tupdesc ;
136- MemoryContext mctx ;
137- Relation indexRel ;
138- AttrNumber attno ;
139-
140- /* minimally verify the page we got */
141- page = verify_brin_page (raw_page ,BRIN_PAGETYPE_REGULAR ,"regular" );
130+ /* check to see if caller supports us returning a tuplestore */
131+ if (rsinfo == NULL || !IsA (rsinfo ,ReturnSetInfo ))
132+ ereport (ERROR ,
133+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
134+ errmsg ("set-valued function called in context that cannot accept a set" )));
135+ if (!(rsinfo -> allowedModes & SFRM_Materialize )||
136+ rsinfo -> expectedDesc == NULL )
137+ ereport (ERROR ,
138+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
139+ errmsg ("materialize mode required, but it is not allowed in this context" )));
142140
143- /* create a function context for cross-call persistence */
144- fctx = SRF_FIRSTCALL_INIT ();
141+ /* Build a tuple descriptor for our result type */
142+ if (get_call_result_type (fcinfo ,NULL ,& tupdesc )!= TYPEFUNC_COMPOSITE )
143+ elog (ERROR ,"return type must be a row type" );
145144
146- /*switch tomemory context appropriate for multiple function calls */
147- mctx = MemoryContextSwitchTo (fctx -> multi_call_memory_ctx );
145+ /*Build tuplestore tohold the result rows */
146+ oldcontext = MemoryContextSwitchTo (rsinfo -> econtext -> ecxt_per_query_memory );
148147
149- /* Build a tuple descriptor for our result type */
150- if (get_call_result_type (fcinfo ,NULL ,& tupdesc )!= TYPEFUNC_COMPOSITE )
151- elog (ERROR ,"return type must be a row type" );
148+ tupstore = tuplestore_begin_heap (true, false,work_mem );
149+ rsinfo -> returnMode = SFRM_Materialize ;
150+ rsinfo -> setResult = tupstore ;
151+ rsinfo -> setDesc = tupdesc ;
152152
153- indexRel = index_open ( indexRelid , AccessShareLock );
153+ MemoryContextSwitchTo ( oldcontext );
154154
155- state = palloc (offsetof( brin_page_state , columns ) +
156- sizeof ( brin_column_state ) * RelationGetDescr ( indexRel ) -> natts );
155+ indexRel = index_open ( indexRelid , AccessShareLock );
156+ bdesc = brin_build_desc ( indexRel );
157157
158- state -> bdesc = brin_build_desc (indexRel );
159- state -> page = page ;
160- state -> offset = FirstOffsetNumber ;
161- state -> unusedItem = false;
162- state -> done = false;
163- state -> dtup = NULL ;
158+ /* minimally verify the page we got */
159+ page = verify_brin_page (raw_page ,BRIN_PAGETYPE_REGULAR ,"regular" );
164160
165- /*
166- * Initialize output functions for all indexed datatypes; simplifies
167- * calling them later.
168- */
169- for (attno = 1 ;attno <=state -> bdesc -> bd_tupdesc -> natts ;attno ++ )
161+ /*
162+ * Initialize output functions for all indexed datatypes; simplifies
163+ * calling them later.
164+ */
165+ columns = palloc (sizeof (brin_column_state * )* RelationGetDescr (indexRel )-> natts );
166+ for (attno = 1 ;attno <=bdesc -> bd_tupdesc -> natts ;attno ++ )
167+ {
168+ Oid output ;
169+ bool isVarlena ;
170+ BrinOpcInfo * opcinfo ;
171+ int i ;
172+ brin_column_state * column ;
173+
174+ opcinfo = bdesc -> bd_info [attno - 1 ];
175+ column = palloc (offsetof(brin_column_state ,outputFn )+
176+ sizeof (FmgrInfo )* opcinfo -> oi_nstored );
177+
178+ column -> nstored = opcinfo -> oi_nstored ;
179+ for (i = 0 ;i < opcinfo -> oi_nstored ;i ++ )
170180{
171- Oid output ;
172- bool isVarlena ;
173- BrinOpcInfo * opcinfo ;
174- int i ;
175- brin_column_state * column ;
176-
177- opcinfo = state -> bdesc -> bd_info [attno - 1 ];
178- column = palloc (offsetof(brin_column_state ,outputFn )+
179- sizeof (FmgrInfo )* opcinfo -> oi_nstored );
180-
181- column -> nstored = opcinfo -> oi_nstored ;
182- for (i = 0 ;i < opcinfo -> oi_nstored ;i ++ )
183- {
184- getTypeOutputInfo (opcinfo -> oi_typcache [i ]-> type_id ,& output ,& isVarlena );
185- fmgr_info (output ,& column -> outputFn [i ]);
186- }
187-
188- state -> columns [attno - 1 ]= column ;
181+ getTypeOutputInfo (opcinfo -> oi_typcache [i ]-> type_id ,& output ,& isVarlena );
182+ fmgr_info (output ,& column -> outputFn [i ]);
189183}
190184
191- index_close (indexRel ,AccessShareLock );
192-
193- fctx -> user_fctx = state ;
194- fctx -> tuple_desc = BlessTupleDesc (tupdesc );
195-
196- MemoryContextSwitchTo (mctx );
185+ columns [attno - 1 ]= column ;
197186}
198187
199- fctx = SRF_PERCALL_SETUP () ;
200- state = fctx -> user_fctx ;
201-
202- if (! state -> done )
188+ offset = FirstOffsetNumber ;
189+ unusedItem = false ;
190+ dtup = NULL ;
191+ for (;; )
203192{
204- HeapTuple result ;
205193Datum values [7 ];
206194bool nulls [7 ];
207195
@@ -211,39 +199,30 @@ brin_page_items(PG_FUNCTION_ARGS)
211199 * signal for obtaining and decoding the next one. If that's not the
212200 * case, we output the next attribute.
213201 */
214- if (state -> dtup == NULL )
202+ if (dtup == NULL )
215203{
216- BrinTuple * tup ;
217- MemoryContext mctx ;
218204ItemId itemId ;
219205
220- /* deformed tuple must live across calls */
221- mctx = MemoryContextSwitchTo (fctx -> multi_call_memory_ctx );
222-
223206/* verify item status: if there's no data, we can't decode */
224- itemId = PageGetItemId (state -> page ,state -> offset );
207+ itemId = PageGetItemId (page ,offset );
225208if (ItemIdIsUsed (itemId ))
226209{
227- tup = (BrinTuple * )PageGetItem (state -> page ,
228- PageGetItemId (state -> page ,
229- state -> offset ));
230- state -> dtup = brin_deform_tuple (state -> bdesc ,tup );
231- state -> attno = 1 ;
232- state -> unusedItem = false;
210+ dtup = brin_deform_tuple (bdesc ,
211+ (BrinTuple * )PageGetItem (page ,itemId ));
212+ attno = 1 ;
213+ unusedItem = false;
233214}
234215else
235- state -> unusedItem = true;
236-
237- MemoryContextSwitchTo (mctx );
216+ unusedItem = true;
238217}
239218else
240- state -> attno ++ ;
219+ attno ++ ;
241220
242221MemSet (nulls ,0 ,sizeof (nulls ));
243222
244- if (state -> unusedItem )
223+ if (unusedItem )
245224{
246- values [0 ]= UInt16GetDatum (state -> offset );
225+ values [0 ]= UInt16GetDatum (offset );
247226nulls [1 ]= true;
248227nulls [2 ]= true;
249228nulls [3 ]= true;
@@ -253,17 +232,17 @@ brin_page_items(PG_FUNCTION_ARGS)
253232}
254233else
255234{
256- int att = state -> attno - 1 ;
257-
258- values [0 ]= UInt16GetDatum (state -> offset );
259- values [1 ]= UInt32GetDatum (state -> dtup -> bt_blkno );
260- values [2 ]= UInt16GetDatum (state -> attno );
261- values [3 ]= BoolGetDatum (state -> dtup -> bt_columns [att ].bv_allnulls );
262- values [4 ]= BoolGetDatum (state -> dtup -> bt_columns [att ].bv_hasnulls );
263- values [5 ]= BoolGetDatum (state -> dtup -> bt_placeholder );
264- if (!state -> dtup -> bt_columns [att ].bv_allnulls )
235+ int att = attno - 1 ;
236+
237+ values [0 ]= UInt16GetDatum (offset );
238+ values [1 ]= UInt32GetDatum (dtup -> bt_blkno );
239+ values [2 ]= UInt16GetDatum (attno );
240+ values [3 ]= BoolGetDatum (dtup -> bt_columns [att ].bv_allnulls );
241+ values [4 ]= BoolGetDatum (dtup -> bt_columns [att ].bv_hasnulls );
242+ values [5 ]= BoolGetDatum (dtup -> bt_placeholder );
243+ if (!dtup -> bt_columns [att ].bv_allnulls )
265244{
266- BrinValues * bvalues = & state -> dtup -> bt_columns [att ];
245+ BrinValues * bvalues = & dtup -> bt_columns [att ];
267246StringInfoData s ;
268247bool first ;
269248int i ;
@@ -272,14 +251,14 @@ brin_page_items(PG_FUNCTION_ARGS)
272251appendStringInfoChar (& s ,'{' );
273252
274253first = true;
275- for (i = 0 ;i < state -> columns [att ]-> nstored ;i ++ )
254+ for (i = 0 ;i < columns [att ]-> nstored ;i ++ )
276255{
277256char * val ;
278257
279258if (!first )
280259appendStringInfoString (& s ," .. " );
281260first = false;
282- val = OutputFunctionCall (& state -> columns [att ]-> outputFn [i ],
261+ val = OutputFunctionCall (& columns [att ]-> outputFn [i ],
283262bvalues -> bv_values [i ]);
284263appendStringInfoString (& s ,val );
285264pfree (val );
@@ -295,35 +274,35 @@ brin_page_items(PG_FUNCTION_ARGS)
295274}
296275}
297276
298- result = heap_form_tuple ( fctx -> tuple_desc ,values ,nulls );
277+ tuplestore_putvalues ( tupstore , tupdesc ,values ,nulls );
299278
300279/*
301280 * If the item was unused, jump straight to the next one; otherwise,
302281 * the only cleanup needed here is to set our signal to go to the next
303282 * tuple in the following iteration, by freeing the current one.
304283 */
305- if (state -> unusedItem )
306- state -> offset = OffsetNumberNext (state -> offset );
307- else if (state -> attno >=state -> bdesc -> bd_tupdesc -> natts )
284+ if (unusedItem )
285+ offset = OffsetNumberNext (offset );
286+ else if (attno >=bdesc -> bd_tupdesc -> natts )
308287{
309- pfree (state -> dtup );
310- state -> dtup = NULL ;
311- state -> offset = OffsetNumberNext (state -> offset );
288+ pfree (dtup );
289+ dtup = NULL ;
290+ offset = OffsetNumberNext (offset );
312291}
313292
314293/*
315- * If we're beyond the end of the page, set flag to end the function
316- * in the following iteration.
294+ * If we're beyond the end of the page, we're done.
317295 */
318- if (state -> offset > PageGetMaxOffsetNumber (state -> page ))
319- state -> done = true;
320-
321- SRF_RETURN_NEXT (fctx ,HeapTupleGetDatum (result ));
296+ if (offset > PageGetMaxOffsetNumber (page ))
297+ break ;
322298}
323299
324- brin_free_desc (state -> bdesc );
300+ /* clean up and return the tuplestore */
301+ brin_free_desc (bdesc );
302+ tuplestore_donestoring (tupstore );
303+ index_close (indexRel ,AccessShareLock );
325304
326- SRF_RETURN_DONE ( fctx ) ;
305+ return ( Datum ) 0 ;
327306}
328307
329308Datum