diff options
Diffstat (limited to 'src/backend/catalog/heap.c')
-rw-r--r-- | src/backend/catalog/heap.c | 199 |
1 files changed, 120 insertions, 79 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 3985326df62..f2ca686397e 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -710,70 +710,122 @@ CheckAttributeType(const char *attname, } /* - * InsertPgAttributeTuple - * Construct and insert a new tuple in pg_attribute. + * Cap the maximum amount of bytes allocated for InsertPgAttributeTuples() + * slots. + */ +#define MAX_PGATTRIBUTE_INSERT_BYTES 65535 + +/* + * InsertPgAttributeTuples + * Construct and insert a set of tuples in pg_attribute. * - * Caller has already opened and locked pg_attribute. new_attribute is the - * attribute to insert. attcacheoff is always initialized to -1, attacl, - * attfdwoptions and attmissingval are always initialized to NULL. + * Caller has already opened and locked pg_attribute. tupdesc contains the + * attributes to insert. attcacheoff is always initialized to -1, attacl, + * attfdwoptions and attmissingval are always initialized to NULL. attoptions + * must contain the same number of elements as tupdesc, or be NULL. * * indstate is the index state for CatalogTupleInsertWithInfo. It can be * passed as NULL, in which case we'll fetch the necessary info. (Don't do * this when inserting multiple attributes, because it's a tad more * expensive.) + * + * new_rel_oid is the relation OID assigned to the attributes inserted. + * If set to InvalidOid, the relation OID from tupdesc is used instead. */ void -InsertPgAttributeTuple(Relation pg_attribute_rel, - Form_pg_attribute new_attribute, - Datum attoptions, - CatalogIndexState indstate) +InsertPgAttributeTuples(Relation pg_attribute_rel, + TupleDesc tupdesc, + Oid new_rel_oid, + Datum *attoptions, + CatalogIndexState indstate) { - Datum values[Natts_pg_attribute]; - bool nulls[Natts_pg_attribute]; - HeapTuple tup; + TupleTableSlot **slot; + TupleDesc td; + int nslots; + int natts = 0; + int slotCount = 0; + bool close_index = false; + + td = RelationGetDescr(pg_attribute_rel); + + /* Initialize the number of slots to use */ + nslots = Min(tupdesc->natts, + (MAX_PGATTRIBUTE_INSERT_BYTES / sizeof(FormData_pg_attribute))); + slot = palloc(sizeof(TupleTableSlot *) * nslots); + for (int i = 0; i < nslots; i++) + slot[i] = MakeSingleTupleTableSlot(td, &TTSOpsHeapTuple); + + while (natts < tupdesc->natts) + { + Form_pg_attribute attrs = TupleDescAttr(tupdesc, natts); - /* This is a tad tedious, but way cleaner than what we used to do... */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); + ExecClearTuple(slot[slotCount]); - values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_attribute->attrelid); - values[Anum_pg_attribute_attname - 1] = NameGetDatum(&new_attribute->attname); - values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(new_attribute->atttypid); - values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(new_attribute->attstattarget); - values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(new_attribute->attlen); - values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(new_attribute->attnum); - values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(new_attribute->attndims); - values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1); - values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(new_attribute->atttypmod); - values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(new_attribute->attbyval); - values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(new_attribute->attstorage); - values[Anum_pg_attribute_attalign - 1] = CharGetDatum(new_attribute->attalign); - values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(new_attribute->attnotnull); - values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(new_attribute->atthasdef); - values[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(new_attribute->atthasmissing); - values[Anum_pg_attribute_attidentity - 1] = CharGetDatum(new_attribute->attidentity); - values[Anum_pg_attribute_attgenerated - 1] = CharGetDatum(new_attribute->attgenerated); - values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(new_attribute->attisdropped); - values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(new_attribute->attislocal); - values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(new_attribute->attinhcount); - values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(new_attribute->attcollation); - values[Anum_pg_attribute_attoptions - 1] = attoptions; - - /* start out with empty permissions and empty options */ - nulls[Anum_pg_attribute_attacl - 1] = true; - nulls[Anum_pg_attribute_attoptions - 1] = attoptions == (Datum) 0; - nulls[Anum_pg_attribute_attfdwoptions - 1] = true; - nulls[Anum_pg_attribute_attmissingval - 1] = true; - - tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls); + if (new_rel_oid != InvalidOid) + slot[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_rel_oid); + else + slot[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(attrs->attrelid); + + slot[slotCount]->tts_values[Anum_pg_attribute_attname - 1] = NameGetDatum(&attrs->attname); + slot[slotCount]->tts_values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(attrs->atttypid); + slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(attrs->attstattarget); + slot[slotCount]->tts_values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(attrs->attlen); + slot[slotCount]->tts_values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(attrs->attnum); + slot[slotCount]->tts_values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(attrs->attndims); + slot[slotCount]->tts_values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1); + slot[slotCount]->tts_values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(attrs->atttypmod); + slot[slotCount]->tts_values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(attrs->attbyval); + slot[slotCount]->tts_values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(attrs->attstorage); + slot[slotCount]->tts_values[Anum_pg_attribute_attalign - 1] = CharGetDatum(attrs->attalign); + slot[slotCount]->tts_values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(attrs->attnotnull); + slot[slotCount]->tts_values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(attrs->atthasdef); + slot[slotCount]->tts_values[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(attrs->atthasmissing); + slot[slotCount]->tts_values[Anum_pg_attribute_attidentity - 1] = CharGetDatum(attrs->attidentity); + slot[slotCount]->tts_values[Anum_pg_attribute_attgenerated - 1] = CharGetDatum(attrs->attgenerated); + slot[slotCount]->tts_values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(attrs->attisdropped); + slot[slotCount]->tts_values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(attrs->attislocal); + slot[slotCount]->tts_values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(attrs->attinhcount); + slot[slotCount]->tts_values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(attrs->attcollation); + if (attoptions && attoptions[natts] != (Datum) 0) + slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] = attoptions[natts]; + else + slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true; - /* finally insert the new tuple, update the indexes, and clean up */ - if (indstate != NULL) - CatalogTupleInsertWithInfo(pg_attribute_rel, tup, indstate); - else - CatalogTupleInsert(pg_attribute_rel, tup); + /* start out with empty permissions and empty options */ + slot[slotCount]->tts_isnull[Anum_pg_attribute_attacl - 1] = true; + slot[slotCount]->tts_isnull[Anum_pg_attribute_attfdwoptions - 1] = true; + slot[slotCount]->tts_isnull[Anum_pg_attribute_attmissingval - 1] = true; - heap_freetuple(tup); + ExecStoreVirtualTuple(slot[slotCount]); + slotCount++; + + /* + * If slots are full or the end of processing has been reached, insert + * a batch of tuples. + */ + if (slotCount == nslots || natts == tupdesc->natts - 1) + { + /* fetch index info only when we know we need it */ + if (!indstate) + { + indstate = CatalogOpenIndexes(pg_attribute_rel); + close_index = true; + } + + /* insert the new tuples and update the indexes */ + CatalogTuplesMultiInsertWithInfo(pg_attribute_rel, slot, slotCount, + indstate); + slotCount = 0; + } + + natts++; + } + + if (close_index) + CatalogCloseIndexes(indstate); + for (int i = 0; i < nslots; i++) + ExecDropSingleTupleTableSlot(slot[i]); + pfree(slot); } /* -------------------------------- @@ -788,8 +840,6 @@ AddNewAttributeTuples(Oid new_rel_oid, TupleDesc tupdesc, char relkind) { - Form_pg_attribute attr; - int i; Relation rel; CatalogIndexState indstate; int natts = tupdesc->natts; @@ -803,30 +853,26 @@ AddNewAttributeTuples(Oid new_rel_oid, indstate = CatalogOpenIndexes(rel); - /* - * First we add the user attributes. This is also a convenient place to - * add dependencies on their datatypes and collations. - */ - for (i = 0; i < natts; i++) - { - attr = TupleDescAttr(tupdesc, i); - /* Fill in the correct relation OID */ - attr->attrelid = new_rel_oid; - /* Make sure this is OK, too */ - attr->attstattarget = -1; - - InsertPgAttributeTuple(rel, attr, (Datum) 0, indstate); + /* set stats detail level to a sane default */ + for (int i = 0; i < natts; i++) + tupdesc->attrs[i].attstattarget = -1; + InsertPgAttributeTuples(rel, tupdesc, new_rel_oid, NULL, indstate); + /* add dependencies on their datatypes and collations */ + for (int i = 0; i < natts; i++) + { /* Add dependency info */ ObjectAddressSubSet(myself, RelationRelationId, new_rel_oid, i + 1); - ObjectAddressSet(referenced, TypeRelationId, attr->atttypid); + ObjectAddressSet(referenced, TypeRelationId, + tupdesc->attrs[i].atttypid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* The default collation is pinned, so don't bother recording it */ - if (OidIsValid(attr->attcollation) && - attr->attcollation != DEFAULT_COLLATION_OID) + if (OidIsValid(tupdesc->attrs[i].attcollation) && + tupdesc->attrs[i].attcollation != DEFAULT_COLLATION_OID) { - ObjectAddressSet(referenced, CollationRelationId, attr->attcollation); + ObjectAddressSet(referenced, CollationRelationId, + tupdesc->attrs[i].attcollation); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } } @@ -838,17 +884,12 @@ AddNewAttributeTuples(Oid new_rel_oid, */ if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) { - for (i = 0; i < (int) lengthof(SysAtt); i++) - { - FormData_pg_attribute attStruct; + TupleDesc td; - memcpy(&attStruct, SysAtt[i], sizeof(FormData_pg_attribute)); + td = CreateTupleDesc(lengthof(SysAtt), (FormData_pg_attribute **) &SysAtt); - /* Fill in the correct relation OID in the copied tuple */ - attStruct.attrelid = new_rel_oid; - - InsertPgAttributeTuple(rel, &attStruct, (Datum) 0, indstate); - } + InsertPgAttributeTuples(rel, td, new_rel_oid, NULL, indstate); + FreeTupleDesc(td); } /* |