From 6ab459b23824e7ff270be360eea0163f4dc16b3a Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 17 May 2019 16:01:47 -0400 Subject: [PATCH v1 1/4] tableam: Move heap-specific logic from needs_toast_table below tableam. This allows table AMs to completely suppress TOAST table creation, or to modify the conditions under which they are created. --- src/backend/access/heap/heapam_handler.c | 59 ++++++++++++++++++++++++ src/backend/catalog/toasting.c | 50 ++------------------ src/include/access/tableam.h | 30 ++++++++++++ 3 files changed, 92 insertions(+), 47 deletions(-) diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index 00505ec3f4..b73e9cd6f1 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -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" @@ -1975,6 +1976,62 @@ heapam_scan_get_blocks_done(HeapScanDesc hscan) } +/* ------------------------------------------------------------------------ + * TOAST related callbacks for the heap AM + * ------------------------------------------------------------------------ + */ + +/* + * 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_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 @@ -2558,6 +2615,8 @@ static const TableAmRoutine heapam_methods = { .relation_estimate_size = heapam_estimate_rel_size, + .needs_toast_table = heapam_needs_toast_table, + .scan_bitmap_next_block = heapam_scan_bitmap_next_block, .scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple, .scan_sample_next_block = heapam_scan_sample_next_block, diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 2276d3c5d3..be0a397d9d 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -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_needs_toast_table(rel); } diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index ebfa0d5185..ac0913c579 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -540,6 +540,21 @@ typedef struct TableAmRoutine struct ValidateIndexState *state); + /* ------------------------------------------------------------------------ + * TOAST support. + * ------------------------------------------------------------------------ + */ + + /* + * 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 (*needs_toast_table) (Relation rel); + + /* ------------------------------------------------------------------------ * Planner related functions. * ------------------------------------------------------------------------ @@ -1503,6 +1518,21 @@ table_index_validate_scan(Relation heap_rel, } +/* ---------------------------------------------------------------------------- + * TOAST + * ---------------------------------------------------------------------------- + */ + +/* + * table_needs_toast_table - does this relation need a toast table? + */ +static inline bool +table_needs_toast_table(Relation rel) +{ + return rel->rd_tableam->needs_toast_table(rel); +} + + /* ---------------------------------------------------------------------------- * Planner related functionality * ---------------------------------------------------------------------------- -- 2.17.2 (Apple Git-113)