3131#include "utils/relfilenumbermap.h"
3232#include "utils/relmapper.h"
3333#include "utils/syscache.h"
34+ #include "access/tableam.h"
3435
3536/* Divide by two and round away from zero */
3637#define half_rounded (x ) (((x) + ((x) < 0 ? -1 : 1)) / 2)
@@ -343,6 +344,61 @@ calculate_relation_size(RelFileLocator *rfn, BackendId backend, ForkNumber forkn
343344 return totalsize ;
344345}
345346
347+ /*
348+ * Try to get size using proper relation_size method in table am. Fallback to previous method
349+ * if rd_tableam->relation_size doesn't support requested counting method or otherwise refuses
350+ * to count (with negative output)
351+ */
352+ static
353+ int64 try_tableam_relation_size (Relation rel , ForkNumber forkNum , bool allforks , uint8 method )
354+ {
355+ int64 size = 0 ;
356+
357+ if (rel -> rd_rel -> relkind == RELKIND_INDEX )
358+ {
359+ /* For index check rd_tableam for parent relation */
360+ Relation tbl ;
361+
362+ tbl = relation_open (rel -> rd_index -> indrelid , AccessShareLock );
363+ if (tbl -> rd_tableam && tbl -> rd_tableam -> relation_size )
364+ {
365+ /* We call relation_size method for parent relation but provide index relation as an argument.
366+ * Method for index is always RELATION_SIZE
367+ */
368+ if (allforks )
369+ {
370+ for (ForkNumber i = 0 ; i <= MAX_FORKNUM ; i ++ )
371+ {
372+ size += tbl -> rd_tableam -> relation_size (rel , i , RELATION_SIZE );
373+ }
374+ }
375+ else
376+ size = tbl -> rd_tableam -> relation_size (rel , forkNum , RELATION_SIZE );
377+
378+ if (size >= 0 )
379+ {
380+ relation_close (tbl , AccessShareLock );
381+ return size ;
382+ }
383+ }
384+ relation_close (tbl , AccessShareLock );
385+ }
386+ else if (rel -> rd_tableam && rel -> rd_tableam -> relation_size )
387+ {
388+ if (allforks )
389+ {
390+ for (ForkNumber i = 0 ; i <= MAX_FORKNUM ; i ++ )
391+ size += rel -> rd_tableam -> relation_size (rel , i , method );
392+ }
393+ else
394+ size = rel -> rd_tableam -> relation_size (rel , forkNum , method );
395+
396+ if (size >= 0 )
397+ return size ;
398+ }
399+ return -1 ;
400+ }
401+
346402Datum
347403pg_relation_size (PG_FUNCTION_ARGS )
348404{
@@ -363,6 +419,18 @@ pg_relation_size(PG_FUNCTION_ARGS)
363419 if (rel == NULL )
364420 PG_RETURN_NULL ();
365421
422+ /*
423+ * Try to get size using proper relation_size method in table am. Fallback to previous method
424+ * if rd_tableam->relation_size doesn't support requested counting method or otherwise refuses
425+ * to count (with negative output)
426+ */
427+ size = try_tableam_relation_size (rel , forkname_to_number (text_to_cstring (forkName )), false, RELATION_SIZE );
428+ if (size >= 0 )
429+ {
430+ relation_close (rel , AccessShareLock );
431+ PG_RETURN_INT64 (size );
432+ }
433+
366434 size = calculate_relation_size (& (rel -> rd_locator ), rel -> rd_backend ,
367435 forkname_to_number (text_to_cstring (forkName )));
368436
@@ -495,6 +563,18 @@ pg_table_size(PG_FUNCTION_ARGS)
495563 if (rel == NULL )
496564 PG_RETURN_NULL ();
497565
566+ /*
567+ * Try to get size using proper relation_size method in table am. Fallback to previous method
568+ * if rd_tableam->relation_size doesn't support requested counting method or otherwise refuses
569+ * to count (with negative output)
570+ */
571+ size = try_tableam_relation_size (rel , InvalidForkNumber , true, TABLE_SIZE );
572+ if (size >= 0 )
573+ {
574+ relation_close (rel , AccessShareLock );
575+ PG_RETURN_INT64 (size );
576+ }
577+
498578 size = calculate_table_size (rel );
499579
500580 relation_close (rel , AccessShareLock );
@@ -507,13 +587,25 @@ pg_indexes_size(PG_FUNCTION_ARGS)
507587{
508588 Oid relOid = PG_GETARG_OID (0 );
509589 Relation rel ;
510- int64 size ;
590+ int64 size = 0 ;
511591
512592 rel = try_relation_open (relOid , AccessShareLock );
513593
514594 if (rel == NULL )
515595 PG_RETURN_NULL ();
516596
597+ if (rel -> rd_tableam && rel -> rd_tableam -> relation_size )
598+ {
599+ for (ForkNumber forkNum = 0 ; forkNum <= MAX_FORKNUM ; forkNum ++ )
600+ size += rel -> rd_tableam -> relation_size (rel , forkNum , INDEXES_SIZE );
601+
602+ if (size >= 0 )
603+ {
604+ relation_close (rel , AccessShareLock );
605+ PG_RETURN_INT64 (size );
606+ }
607+ }
608+
517609 size = calculate_indexes_size (rel );
518610
519611 relation_close (rel , AccessShareLock );
@@ -556,6 +648,18 @@ pg_total_relation_size(PG_FUNCTION_ARGS)
556648 if (rel == NULL )
557649 PG_RETURN_NULL ();
558650
651+ /*
652+ * Try to get size using proper relation_size method in table am. Fallback to previous method
653+ * if rd_tableam->relation_size doesn't support requested counting method or otherwise refuses
654+ * to count (with negative output)
655+ */
656+ size = try_tableam_relation_size (rel , InvalidForkNumber , true, TOTAL_SIZE );
657+ if (size >= 0 )
658+ {
659+ relation_close (rel , AccessShareLock );
660+ PG_RETURN_INT64 (size );
661+ }
662+
559663 size = calculate_total_relation_size (rel );
560664
561665 relation_close (rel , AccessShareLock );
0 commit comments