#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"
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
.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,
#include "postgres.h"
#include "access/heapam.h"
-#include "access/tuptoaster.h"
#include "access/xact.h"
#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
}
/*
- * 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.
*/
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);
}
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.
* ------------------------------------------------------------------------
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
* ----------------------------------------------------------------------------