@@ -54,6 +54,14 @@ PG_FUNCTION_INFO_V1(pg_relpages);
5454PG_FUNCTION_INFO_V1 (pg_relpagesbyid );
5555PG_FUNCTION_INFO_V1 (pgstatginindex );
5656
57+ PG_FUNCTION_INFO_V1 (pgstatindex_v1_5 );
58+ PG_FUNCTION_INFO_V1 (pgstatindexbyid_v1_5 );
59+ PG_FUNCTION_INFO_V1 (pg_relpages_v1_5 );
60+ PG_FUNCTION_INFO_V1 (pg_relpagesbyid_v1_5 );
61+ PG_FUNCTION_INFO_V1 (pgstatginindex_v1_5 );
62+
63+ Datum pgstatginindex_internal (Oid relid , FunctionCallInfo fcinfo );
64+
5765#define IS_INDEX (r ) ((r)->rd_rel->relkind == RELKIND_INDEX)
5866#define IS_BTREE (r ) ((r)->rd_rel->relam == BTREE_AM_OID)
5967#define IS_GIN (r ) ((r)->rd_rel->relam == GIN_AM_OID)
@@ -99,6 +107,10 @@ static Datum pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo);
99107 * pgstatindex()
100108 *
101109 * Usage: SELECT * FROM pgstatindex('t1_pkey');
110+ *
111+ * The superuser() check here must be kept as the library might be upgraded
112+ * without the extension being upgraded, meaning that in pre-1.5 installations
113+ * these functions could be called by any user.
102114 * ------------------------------------------------------
103115 */
104116Datum
@@ -119,6 +131,31 @@ pgstatindex(PG_FUNCTION_ARGS)
119131 PG_RETURN_DATUM (pgstatindex_impl (rel , fcinfo ));
120132}
121133
134+ /*
135+ * As of pgstattuple version 1.5, we no longer need to check if the user
136+ * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
137+ * Users can then grant access to it based on their policies.
138+ *
139+ * Otherwise identical to pgstatindex (above).
140+ */
141+ Datum
142+ pgstatindex_v1_5 (PG_FUNCTION_ARGS )
143+ {
144+ text * relname = PG_GETARG_TEXT_P (0 );
145+ Relation rel ;
146+ RangeVar * relrv ;
147+
148+ relrv = makeRangeVarFromNameList (textToQualifiedNameList (relname ));
149+ rel = relation_openrv (relrv , AccessShareLock );
150+
151+ PG_RETURN_DATUM (pgstatindex_impl (rel , fcinfo ));
152+ }
153+
154+ /*
155+ * The superuser() check here must be kept as the library might be upgraded
156+ * without the extension being upgraded, meaning that in pre-1.5 installations
157+ * these functions could be called by any user.
158+ */
122159Datum
123160pgstatindexbyid (PG_FUNCTION_ARGS )
124161{
@@ -135,6 +172,18 @@ pgstatindexbyid(PG_FUNCTION_ARGS)
135172 PG_RETURN_DATUM (pgstatindex_impl (rel , fcinfo ));
136173}
137174
175+ /* No need for superuser checks in v1.5, see above */
176+ Datum
177+ pgstatindexbyid_v1_5 (PG_FUNCTION_ARGS )
178+ {
179+ Oid relid = PG_GETARG_OID (0 );
180+ Relation rel ;
181+
182+ rel = relation_open (relid , AccessShareLock );
183+
184+ PG_RETURN_DATUM (pgstatindex_impl (rel , fcinfo ));
185+ }
186+
138187static Datum
139188pgstatindex_impl (Relation rel , FunctionCallInfo fcinfo )
140189{
@@ -292,6 +341,8 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
292341 *
293342 * Usage: SELECT pg_relpages('t1');
294343 * SELECT pg_relpages('t1_pkey');
344+ *
345+ * Must keep superuser() check, see above.
295346 * --------------------------------------------------------
296347 */
297348Datum
@@ -319,6 +370,28 @@ pg_relpages(PG_FUNCTION_ARGS)
319370 PG_RETURN_INT64 (relpages );
320371}
321372
373+ /* No need for superuser checks in v1.5, see above */
374+ Datum
375+ pg_relpages_v1_5 (PG_FUNCTION_ARGS )
376+ {
377+ text * relname = PG_GETARG_TEXT_P (0 );
378+ int64 relpages ;
379+ Relation rel ;
380+ RangeVar * relrv ;
381+
382+ relrv = makeRangeVarFromNameList (textToQualifiedNameList (relname ));
383+ rel = relation_openrv (relrv , AccessShareLock );
384+
385+ /* note: this will work OK on non-local temp tables */
386+
387+ relpages = RelationGetNumberOfBlocks (rel );
388+
389+ relation_close (rel , AccessShareLock );
390+
391+ PG_RETURN_INT64 (relpages );
392+ }
393+
394+ /* Must keep superuser() check, see above. */
322395Datum
323396pg_relpagesbyid (PG_FUNCTION_ARGS )
324397{
@@ -342,16 +415,58 @@ pg_relpagesbyid(PG_FUNCTION_ARGS)
342415 PG_RETURN_INT64 (relpages );
343416}
344417
418+ /* No need for superuser checks in v1.5, see above */
419+ Datum
420+ pg_relpagesbyid_v1_5 (PG_FUNCTION_ARGS )
421+ {
422+ Oid relid = PG_GETARG_OID (0 );
423+ int64 relpages ;
424+ Relation rel ;
425+
426+ rel = relation_open (relid , AccessShareLock );
427+
428+ /* note: this will work OK on non-local temp tables */
429+
430+ relpages = RelationGetNumberOfBlocks (rel );
431+
432+ relation_close (rel , AccessShareLock );
433+
434+ PG_RETURN_INT64 (relpages );
435+ }
436+
345437/* ------------------------------------------------------
346438 * pgstatginindex()
347439 *
348440 * Usage: SELECT * FROM pgstatginindex('ginindex');
441+ *
442+ * Must keep superuser() check, see above.
349443 * ------------------------------------------------------
350444 */
351445Datum
352446pgstatginindex (PG_FUNCTION_ARGS )
353447{
354448 Oid relid = PG_GETARG_OID (0 );
449+
450+ if (!superuser ())
451+ ereport (ERROR ,
452+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
453+ (errmsg ("must be superuser to use pgstattuple functions" ))));
454+
455+ PG_RETURN_DATUM (pgstatginindex_internal (relid , fcinfo ));
456+ }
457+
458+ /* No need for superuser checks in v1.5, see above */
459+ Datum
460+ pgstatginindex_v1_5 (PG_FUNCTION_ARGS )
461+ {
462+ Oid relid = PG_GETARG_OID (0 );
463+
464+ PG_RETURN_DATUM (pgstatginindex_internal (relid , fcinfo ));
465+ }
466+
467+ Datum
468+ pgstatginindex_internal (Oid relid , FunctionCallInfo fcinfo )
469+ {
355470 Relation rel ;
356471 Buffer buffer ;
357472 Page page ;
@@ -363,11 +478,6 @@ pgstatginindex(PG_FUNCTION_ARGS)
363478 bool nulls [3 ] = {false, false, false};
364479 Datum result ;
365480
366- if (!superuser ())
367- ereport (ERROR ,
368- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
369- (errmsg ("must be superuser to use pgstattuple functions" ))));
370-
371481 rel = relation_open (relid , AccessShareLock );
372482
373483 if (!IS_INDEX (rel ) || !IS_GIN (rel ))
@@ -415,5 +525,5 @@ pgstatginindex(PG_FUNCTION_ARGS)
415525 tuple = heap_form_tuple (tupleDesc , values , nulls );
416526 result = HeapTupleGetDatum (tuple );
417527
418- PG_RETURN_DATUM (result );
528+ return (result );
419529}
0 commit comments