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