]> granicus.if.org Git - postgresql/commitdiff
tableam: Move heap-specific logic from needs_toast_table below tableam.
authorRobert Haas <rhaas@postgresql.org>
Tue, 21 May 2019 15:57:13 +0000 (11:57 -0400)
committerRobert Haas <rhaas@postgresql.org>
Tue, 21 May 2019 15:57:13 +0000 (11:57 -0400)
This allows table AMs to completely suppress TOAST table creation, or
to modify the conditions under which they are created.

Patch by me.  Reviewed by Andres Freund.

Discussion: http://postgr.es/m/CA+Tgmoa4O2n=yphqD2pERUnYmUO84bH1SqMsA-nSxBGsZ7gWfA@mail.gmail.com

src/backend/access/heap/heapam_handler.c
src/backend/catalog/toasting.c
src/include/access/tableam.h

index 8d8161fd9717f6c01f7f05f958d153969b9be54c..56b2abda5fb086d11ec0573d83d9319ab29d8c9c 100644 (file)
@@ -29,6 +29,7 @@
 #include "access/rewriteheap.h"
 #include "access/tableam.h"
 #include "access/tsmapi.h"
+#include "access/tuptoaster.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
 #include "catalog/index.h"
@@ -2009,6 +2010,57 @@ heapam_relation_size(Relation rel, ForkNumber forkNumber)
        return nblocks * BLCKSZ;
 }
 
+/*
+ * Check to see whether the table needs a TOAST table.  It does only if
+ * (1) there are any toastable attributes, and (2) the maximum length
+ * of a tuple could exceed TOAST_TUPLE_THRESHOLD.  (We don't want to
+ * create a toast table for something like "f1 varchar(20)".)
+ */
+static bool
+heapam_relation_needs_toast_table(Relation rel)
+{
+       int32           data_length = 0;
+       bool            maxlength_unknown = false;
+       bool            has_toastable_attrs = false;
+       TupleDesc       tupdesc = rel->rd_att;
+       int32           tuple_length;
+       int                     i;
+
+       for (i = 0; i < tupdesc->natts; i++)
+       {
+               Form_pg_attribute att = TupleDescAttr(tupdesc, i);
+
+               if (att->attisdropped)
+                       continue;
+               data_length = att_align_nominal(data_length, att->attalign);
+               if (att->attlen > 0)
+               {
+                       /* Fixed-length types are never toastable */
+                       data_length += att->attlen;
+               }
+               else
+               {
+                       int32           maxlen = type_maximum_size(att->atttypid,
+                                                                                                  att->atttypmod);
+
+                       if (maxlen < 0)
+                               maxlength_unknown = true;
+                       else
+                               data_length += maxlen;
+                       if (att->attstorage != 'p')
+                               has_toastable_attrs = true;
+               }
+       }
+       if (!has_toastable_attrs)
+               return false;                   /* nothing to toast? */
+       if (maxlength_unknown)
+               return true;                    /* any unlimited-length attrs? */
+       tuple_length = MAXALIGN(SizeofHeapTupleHeader +
+                                                       BITMAPLEN(tupdesc->natts)) +
+               MAXALIGN(data_length);
+       return (tuple_length > TOAST_TUPLE_THRESHOLD);
+}
+
 
 /* ------------------------------------------------------------------------
  * Planner related callbacks for the heap AM
@@ -2592,6 +2644,7 @@ static const TableAmRoutine heapam_methods = {
        .index_validate_scan = heapam_index_validate_scan,
 
        .relation_size = heapam_relation_size,
+       .relation_needs_toast_table = heapam_relation_needs_toast_table,
 
        .relation_estimate_size = heapam_estimate_rel_size,
 
index 2276d3c5d36ce7db059ecea85142858b4a66a3d6..cf20ddb4e928e95974b61da6b2dc5900ae9bb927 100644 (file)
@@ -15,7 +15,6 @@
 #include "postgres.h"
 
 #include "access/heapam.h"
-#include "access/tuptoaster.h"
 #include "access/xact.h"
 #include "catalog/binary_upgrade.h"
 #include "catalog/catalog.h"
@@ -386,21 +385,11 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 }
 
 /*
- * Check to see whether the table needs a TOAST table.  It does only if
- * (1) there are any toastable attributes, and (2) the maximum length
- * of a tuple could exceed TOAST_TUPLE_THRESHOLD.  (We don't want to
- * create a toast table for something like "f1 varchar(20)".)
+ * Check to see whether the table needs a TOAST table.
  */
 static bool
 needs_toast_table(Relation rel)
 {
-       int32           data_length = 0;
-       bool            maxlength_unknown = false;
-       bool            has_toastable_attrs = false;
-       TupleDesc       tupdesc;
-       int32           tuple_length;
-       int                     i;
-
        /*
         * No need to create a TOAST table for partitioned tables.
         */
@@ -423,39 +412,6 @@ needs_toast_table(Relation rel)
        if (IsCatalogRelation(rel) && !IsBootstrapProcessingMode())
                return false;
 
-       tupdesc = rel->rd_att;
-
-       for (i = 0; i < tupdesc->natts; i++)
-       {
-               Form_pg_attribute att = TupleDescAttr(tupdesc, i);
-
-               if (att->attisdropped)
-                       continue;
-               data_length = att_align_nominal(data_length, att->attalign);
-               if (att->attlen > 0)
-               {
-                       /* Fixed-length types are never toastable */
-                       data_length += att->attlen;
-               }
-               else
-               {
-                       int32           maxlen = type_maximum_size(att->atttypid,
-                                                                                                  att->atttypmod);
-
-                       if (maxlen < 0)
-                               maxlength_unknown = true;
-                       else
-                               data_length += maxlen;
-                       if (att->attstorage != 'p')
-                               has_toastable_attrs = true;
-               }
-       }
-       if (!has_toastable_attrs)
-               return false;                   /* nothing to toast? */
-       if (maxlength_unknown)
-               return true;                    /* any unlimited-length attrs? */
-       tuple_length = MAXALIGN(SizeofHeapTupleHeader +
-                                                       BITMAPLEN(tupdesc->natts)) +
-               MAXALIGN(data_length);
-       return (tuple_length > TOAST_TUPLE_THRESHOLD);
+       /* Otherwise, let the AM decide. */
+       return table_relation_needs_toast_table(rel);
 }
index 06eae2337a3bf031d185b60c32950f2ed2e16297..53b58c51da218cd98c7dea7281eb5862812ff7fb 100644 (file)
@@ -573,6 +573,16 @@ typedef struct TableAmRoutine
        uint64          (*relation_size) (Relation rel, ForkNumber forkNumber);
 
 
+       /*
+        * This callback should return true if the relation requires a TOAST table
+        * and false if it does not.  It may wish to examine the relation's
+        * tuple descriptor before making a decision, but if it uses some other
+        * method of storing large values (or if it does not support them) it can
+        * simply return false.
+        */
+       bool        (*relation_needs_toast_table) (Relation rel);
+
+
        /* ------------------------------------------------------------------------
         * Planner related functions.
         * ------------------------------------------------------------------------
@@ -1585,6 +1595,16 @@ table_relation_size(Relation rel, ForkNumber forkNumber)
        return rel->rd_tableam->relation_size(rel, forkNumber);
 }
 
+/*
+ * table_needs_toast_table - does this relation need a toast table?
+ */
+static inline bool
+table_relation_needs_toast_table(Relation rel)
+{
+       return rel->rd_tableam->relation_needs_toast_table(rel);
+}
+
+
 /* ----------------------------------------------------------------------------
  * Planner related functionality
  * ----------------------------------------------------------------------------