/* * 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)".) * No need to create a TOAST table for partitioned tables. */ 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; if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) 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); }
/* * 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)".) */ bool RelationNeedsToastTable(Relation rel) { int32 data_length = 0; bool maxlength_unknown = false; bool has_toastable_attrs = false; TupleDesc tupdesc; Form_pg_attribute *att; int32 tuple_length; int i; if(RelationIsExternal(rel)) return false; tupdesc = rel->rd_att; att = tupdesc->attrs; for (i = 0; i < tupdesc->natts; i++) { if (att[i]->attisdropped) continue; data_length = att_align_nominal(data_length, att[i]->attalign); if (att[i]->attlen > 0) { /* Fixed-length types are never toastable */ data_length += att[i]->attlen; } else { int32 maxlen = type_maximum_size(att[i]->atttypid, att[i]->atttypmod); if (maxlen < 0) maxlength_unknown = true; else data_length += maxlen; if (att[i]->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(offsetof(HeapTupleHeaderData, t_bits) + BITMAPLEN(tupdesc->natts)) + MAXALIGN(data_length); return (tuple_length > TOAST_TUPLE_THRESHOLD); }
/* * get_typavgwidth * * Given a type OID and a typmod value (pass -1 if typmod is unknown), * estimate the average width of values of the type. This is used by * the planner, which doesn't require absolutely correct results; * it's OK (and expected) to guess if we don't know for sure. */ int32 get_typavgwidth(Oid typid, int32 typmod) { int typlen = get_typlen(typid); int32 maxwidth; /* * Easy if it's a fixed-width type */ if (typlen > 0) return typlen; /* * type_maximum_size knows the encoding of typmod for some datatypes; * don't duplicate that knowledge here. */ maxwidth = type_maximum_size(typid, typmod); if (maxwidth > 0) { /* * For BPCHAR, the max width is also the only width. Otherwise we * need to guess about the typical data width given the max. A sliding * scale for percentage of max width seems reasonable. */ if (typid == BPCHAROID) return maxwidth; if (maxwidth <= 32) return maxwidth; /* assume full width */ if (maxwidth < 1000) return 32 + (maxwidth - 32) / 2; /* assume 50% */ /* * Beyond 1000, assume we're looking at something like * "varchar(10000)" where the limit isn't actually reached often, and * use a fixed estimate. */ return 32 + (1000 - 32) / 2; } /* * Ooops, we have no idea ... wild guess time. */ return 32; }
/* * 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 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 (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) return false; /* * We cannot allow toasting a shared relation after initdb (because * there's no way to mark it toasted in other databases' pg_class). */ if (rel->rd_rel->relisshared && !IsBootstrapProcessingMode()) return false; /* * Ignore attempts to create toast tables on catalog tables after initdb. * Which catalogs get toast tables is explicitly chosen in * catalog/toasting.h. (We could get here via some ALTER TABLE command if * the catalog doesn't have a toast table.) */ 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); }