diff options
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 290 |
1 files changed, 5 insertions, 285 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index a33f721b1bd..53382ff3d47 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.196 2006/07/14 14:52:18 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.197 2006/07/31 01:16:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,7 +17,6 @@ #include "access/genam.h" #include "access/heapam.h" #include "access/reloptions.h" -#include "access/tuptoaster.h" #include "access/xact.h" #include "catalog/catalog.h" #include "catalog/dependency.h" @@ -29,9 +28,9 @@ #include "catalog/pg_depend.h" #include "catalog/pg_inherits.h" #include "catalog/pg_namespace.h" -#include "catalog/pg_opclass.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" +#include "catalog/toasting.h" #include "commands/cluster.h" #include "commands/defrem.h" #include "commands/tablecmds.h" @@ -170,7 +169,6 @@ static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, int16 seqNumber, Relation catalogRelation); static int findAttrByName(const char *attributeName, List *schema); static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass); -static bool needs_toast_table(Relation rel); static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid); static void AlterSeqNamespaces(Relation classRel, Relation rel, @@ -2073,12 +2071,6 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd); pass = AT_PASS_ALTER_TYPE; break; - case AT_ToastTable: /* CREATE TOAST TABLE */ - ATSimplePermissions(rel, false); - /* This command never recurses */ - /* No command-specific prep needed */ - pass = AT_PASS_MISC; - break; case AT_ChangeOwner: /* ALTER OWNER */ /* This command never recurses */ /* No command-specific prep needed */ @@ -2196,8 +2188,8 @@ ATRewriteCatalogs(List **wqueue) } /* - * Do an implicit CREATE TOAST TABLE if we executed any subcommands that - * might have added a column or changed column storage. + * Check to see if a toast table must be added, if we executed any + * subcommands that might have added a column or changed column storage. */ foreach(ltab, *wqueue) { @@ -2207,7 +2199,7 @@ ATRewriteCatalogs(List **wqueue) (tab->subcmds[AT_PASS_ADD_COL] || tab->subcmds[AT_PASS_ALTER_TYPE] || tab->subcmds[AT_PASS_COL_ATTRS])) - AlterTableCreateToastTable(tab->relid, true); + AlterTableCreateToastTable(tab->relid); } } @@ -2261,9 +2253,6 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd) case AT_AlterColumnType: /* ALTER COLUMN TYPE */ ATExecAlterColumnType(tab, rel, cmd->name, (TypeName *) cmd->def); break; - case AT_ToastTable: /* CREATE TOAST TABLE */ - AlterTableCreateToastTable(RelationGetRelid(rel), false); - break; case AT_ChangeOwner: /* ALTER OWNER */ ATExecChangeOwner(RelationGetRelid(rel), get_roleid_checked(cmd->name), @@ -6542,275 +6531,6 @@ ATExecDropInherits(Relation rel, RangeVar *parent) /* - * ALTER TABLE CREATE TOAST TABLE - * - * Note: this is also invoked from outside this module; in such cases we - * expect the caller to have verified that the relation is a table and we - * have all the right permissions. Callers expect this function - * to end with CommandCounterIncrement if it makes any changes. - */ -void -AlterTableCreateToastTable(Oid relOid, bool silent) -{ - Relation rel; - HeapTuple reltup; - TupleDesc tupdesc; - bool shared_relation; - Relation class_rel; - Oid toast_relid; - Oid toast_idxid; - char toast_relname[NAMEDATALEN]; - char toast_idxname[NAMEDATALEN]; - IndexInfo *indexInfo; - Oid classObjectId[2]; - ObjectAddress baseobject, - toastobject; - - /* - * Grab an exclusive lock on the target table, which we will NOT release - * until end of transaction. (This is probably redundant in all present - * uses...) - */ - rel = heap_open(relOid, AccessExclusiveLock); - - /* - * Toast table is shared if and only if its parent is. - * - * We cannot allow toasting a shared relation after initdb (because - * there's no way to mark it toasted in other databases' pg_class). - * Unfortunately we can't distinguish initdb from a manually started - * standalone backend (toasting happens after the bootstrap phase, so - * checking IsBootstrapProcessingMode() won't work). However, we can at - * least prevent this mistake under normal multi-user operation. - */ - shared_relation = rel->rd_rel->relisshared; - if (shared_relation && IsUnderPostmaster) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("shared tables cannot be toasted after initdb"))); - - /* - * Is it already toasted? - */ - if (rel->rd_rel->reltoastrelid != InvalidOid) - { - if (silent) - { - heap_close(rel, NoLock); - return; - } - - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("table \"%s\" already has a TOAST table", - RelationGetRelationName(rel)))); - } - - /* - * Check to see whether the table actually needs a TOAST table. - */ - if (!needs_toast_table(rel)) - { - if (silent) - { - heap_close(rel, NoLock); - return; - } - - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("table \"%s\" does not need a TOAST table", - RelationGetRelationName(rel)))); - } - - /* - * Create the toast table and its index - */ - snprintf(toast_relname, sizeof(toast_relname), - "pg_toast_%u", relOid); - snprintf(toast_idxname, sizeof(toast_idxname), - "pg_toast_%u_index", relOid); - - /* this is pretty painful... need a tuple descriptor */ - tupdesc = CreateTemplateTupleDesc(3, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, - "chunk_id", - OIDOID, - -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, - "chunk_seq", - INT4OID, - -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, - "chunk_data", - BYTEAOID, - -1, 0); - - /* - * Ensure that the toast table doesn't itself get toasted, or we'll be - * toast :-(. This is essential for chunk_data because type bytea is - * toastable; hit the other two just to be sure. - */ - tupdesc->attrs[0]->attstorage = 'p'; - tupdesc->attrs[1]->attstorage = 'p'; - tupdesc->attrs[2]->attstorage = 'p'; - - /* - * Note: the toast relation is placed in the regular pg_toast namespace - * even if its master relation is a temp table. There cannot be any - * naming collision, and the toast rel will be destroyed when its master - * is, so there's no need to handle the toast rel as temp. - * - * XXX would it make sense to apply the master's reloptions to the toast - * table? - */ - toast_relid = heap_create_with_catalog(toast_relname, - PG_TOAST_NAMESPACE, - rel->rd_rel->reltablespace, - InvalidOid, - rel->rd_rel->relowner, - tupdesc, - RELKIND_TOASTVALUE, - shared_relation, - true, - 0, - ONCOMMIT_NOOP, - (Datum) 0, - true); - - /* make the toast relation visible, else index creation will fail */ - CommandCounterIncrement(); - - /* - * Create unique index on chunk_id, chunk_seq. - * - * NOTE: the normal TOAST access routines could actually function with a - * single-column index on chunk_id only. However, the slice access - * routines use both columns for faster access to an individual chunk. In - * addition, we want it to be unique as a check against the possibility of - * duplicate TOAST chunk OIDs. The index might also be a little more - * efficient this way, since btree isn't all that happy with large numbers - * of equal keys. - */ - - indexInfo = makeNode(IndexInfo); - indexInfo->ii_NumIndexAttrs = 2; - indexInfo->ii_KeyAttrNumbers[0] = 1; - indexInfo->ii_KeyAttrNumbers[1] = 2; - indexInfo->ii_Expressions = NIL; - indexInfo->ii_ExpressionsState = NIL; - indexInfo->ii_Predicate = NIL; - indexInfo->ii_PredicateState = NIL; - indexInfo->ii_Unique = true; - - classObjectId[0] = OID_BTREE_OPS_OID; - classObjectId[1] = INT4_BTREE_OPS_OID; - - toast_idxid = index_create(toast_relid, toast_idxname, InvalidOid, - indexInfo, - BTREE_AM_OID, - rel->rd_rel->reltablespace, - classObjectId, (Datum) 0, - true, true, false, true, false); - - /* - * Store the toast table's OID in the parent relation's pg_class row - */ - class_rel = heap_open(RelationRelationId, RowExclusiveLock); - - reltup = SearchSysCacheCopy(RELOID, - ObjectIdGetDatum(relOid), - 0, 0, 0); - if (!HeapTupleIsValid(reltup)) - elog(ERROR, "cache lookup failed for relation %u", relOid); - - ((Form_pg_class) GETSTRUCT(reltup))->reltoastrelid = toast_relid; - - simple_heap_update(class_rel, &reltup->t_self, reltup); - - /* Keep catalog indexes current */ - CatalogUpdateIndexes(class_rel, reltup); - - heap_freetuple(reltup); - - heap_close(class_rel, RowExclusiveLock); - - /* - * Register dependency from the toast table to the master, so that the - * toast table will be deleted if the master is. - */ - baseobject.classId = RelationRelationId; - baseobject.objectId = relOid; - baseobject.objectSubId = 0; - toastobject.classId = RelationRelationId; - toastobject.objectId = toast_relid; - toastobject.objectSubId = 0; - - recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL); - - /* - * Clean up and make changes visible - */ - heap_close(rel, NoLock); - - CommandCounterIncrement(); -} - -/* - * 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; - Form_pg_attribute *att; - int32 tuple_length; - int i; - - tupdesc = rel->rd_att; - att = tupdesc->attrs; - - for (i = 0; i < tupdesc->natts; i++) - { - if (att[i]->attisdropped) - continue; - data_length = att_align(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); -} - - -/* * Execute ALTER TABLE SET SCHEMA * * Note: caller must have checked ownership of the relation already |