aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/heap/heapam_handler.c53
-rw-r--r--src/backend/catalog/toasting.c50
-rw-r--r--src/include/access/tableam.h20
3 files changed, 76 insertions, 47 deletions
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 8d8161fd971..56b2abda5fb 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"
@@ -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,
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 2276d3c5d36..cf20ddb4e92 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_relation_needs_toast_table(rel);
}
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index 06eae2337a3..53b58c51da2 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -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
* ----------------------------------------------------------------------------