On Thu, Jun 25, 2020 at 09:38:23AM +0200, Daniel Gustafsson wrote: > Attached is a rebased version which was updated to handle the changes for op > class parameters introduced in 911e70207703799605.
Thanks for the updated version. While re-reading the code, I got cold feet with the changes done in recordDependencyOn(). Sure, we could do as you propose, but that does not have to be part of this patch I think, aimed at switching more catalogs to use multi inserts, and it just feels a duplicate of recordMultipleDependencies(), with the same comments copied all over the place, etc. MAX_TEMPLATE_BYTES in pg_shdepend.c needs a comment to explain that this is to cap the number of slots used in copyTemplateDependencies() for pg_shdepend. Not much a fan of the changes in GenerateTypeDependencies(), particularly the use of refobjs[8], capped to the number of items from typeForm. If we add new members I think that this would break easily without us actually noticing that it broke. The use of ObjectAddressSet() is a good idea though, but it does not feel consistent if you don't the same coding rule to typbasetype, typcollation or typelem. I am also thinking to split this part of the cleanup in a first independent patch. pg_constraint.c, pg_operator.c, extension.c and pg_aggregate.c were using ObjectAddressSubSet() with subset set to 0 when registering a dependency. It is simpler to just use ObjectAddressSet(). As this updates the way dependencies are tracked and recorded, that's better if kept in the main patch. + /* TODO is nreferenced a reasonable allocation of slots? */ + slot = palloc(sizeof(TupleTableSlot *) * nreferenced); It seems to me that we could just apply the same rule as for pg_attribute and pg_shdepend, no? CatalogTupleInsertWithInfo() becomes mostly unused with this patch, its only caller being now LOs. Just noticing, I'd rather not remove it for now. The attached includes a bunch of modifications I have done while going through the patch (I indend to split and apply the changes of pg_type.c separately first, just lacked of time now to send a proper split), and there is the number of slots for pg_depend insertions that still needs to be addressed. On top of that pgindent has not been run yet. That's all I have for today, overall the patch is taking a committable shape :) -- Michael
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index a8f7e9965b..b7626a7ecf 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -178,6 +178,8 @@ extern void record_object_address_dependencies(const ObjectAddress *depender, extern void sort_object_addresses(ObjectAddresses *addrs); +extern void reset_object_addresses(ObjectAddresses *addrs); + extern void free_object_addresses(ObjectAddresses *addrs); /* in pg_depend.c */ diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index cbfdfe2abe..d31141c1a2 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -93,10 +93,11 @@ extern void heap_truncate_check_FKs(List *relations, bool tempTables); extern List *heap_truncate_find_FKs(List *relationIds); -extern void InsertPgAttributeTuple(Relation pg_attribute_rel, - Form_pg_attribute new_attribute, - Datum attoptions, - CatalogIndexState indstate); +extern void InsertPgAttributeTuples(Relation pg_attribute_rel, + TupleDesc tupdesc, + Oid new_rel_oid, + Datum *attoptions, + CatalogIndexState indstate); extern void InsertPgClassTuple(Relation pg_class_desc, Relation new_rel_desc, diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 8be303870f..a7e2a9b26b 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -19,6 +19,7 @@ #define INDEXING_H #include "access/htup.h" +#include "nodes/execnodes.h" #include "utils/relcache.h" /* @@ -36,6 +37,10 @@ extern void CatalogCloseIndexes(CatalogIndexState indstate); extern void CatalogTupleInsert(Relation heapRel, HeapTuple tup); extern void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate); +extern void CatalogTuplesMultiInsertWithInfo(Relation heapRel, + TupleTableSlot **slot, + int ntuples, + CatalogIndexState indstate); extern void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup); extern void CatalogTupleUpdateWithInfo(Relation heapRel, diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 537913d1bb..3334bef458 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -2168,10 +2168,6 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, RelationPutHeapTuple(relation, buffer, heaptup, false); - /* - * We don't use heap_multi_insert for catalog tuples yet, but - * better be prepared... - */ if (needwal && need_cids) log_heap_new_cid(relation, heaptup); } diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index b33a2f94af..edba9f1ca7 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -2698,6 +2698,22 @@ sort_object_addresses(ObjectAddresses *addrs) object_address_comparator); } +/* + * Clear an ObjectAddresses array such that it can be reused to avoid an + * allocation cycle. + */ +void +reset_object_addresses(ObjectAddresses *addrs) +{ + if (addrs->numrefs == 0) + return; + + memset(addrs->refs, 0, addrs->maxrefs * sizeof(ObjectAddress)); + if (addrs->extras) + memset(addrs->extras, 0, addrs->maxrefs * sizeof(ObjectAddressExtra)); + addrs->numrefs = 0; +} + /* * Clean up when done with an ObjectAddresses array. */ diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 3c83fe6bab..1a37bb2d0e 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -710,70 +710,115 @@ 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_ATTRINSERT_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 count = 0; + bool close_index = false; - /* This is a tad tedious, but way cleaner than what we used to do... */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); + td = RelationGetDescr(pg_attribute_rel); - 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; + nslots = Min(tupdesc->natts, + (MAX_ATTRINSERT_BYTES / sizeof(FormData_pg_attribute))); + slot = palloc(sizeof(TupleTableSlot *) * nslots); + for (int i = 0; i < nslots; i++) + slot[i] = MakeSingleTupleTableSlot(td, &TTSOpsHeapTuple); - /* 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; + while (natts < tupdesc->natts) + { + Form_pg_attribute attrs = TupleDescAttr(tupdesc, natts); - tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls); + ExecClearTuple(slot[count]); - /* 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); + if (new_rel_oid != InvalidOid) + slot[count]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_rel_oid); + else + slot[count]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(attrs->attrelid); - heap_freetuple(tup); + slot[count]->tts_values[Anum_pg_attribute_attname - 1] = NameGetDatum(&attrs->attname); + slot[count]->tts_values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(attrs->atttypid); + slot[count]->tts_values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(attrs->attstattarget); + slot[count]->tts_values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(attrs->attlen); + slot[count]->tts_values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(attrs->attnum); + slot[count]->tts_values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(attrs->attndims); + slot[count]->tts_values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1); + slot[count]->tts_values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(attrs->atttypmod); + slot[count]->tts_values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(attrs->attbyval); + slot[count]->tts_values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(attrs->attstorage); + slot[count]->tts_values[Anum_pg_attribute_attalign - 1] = CharGetDatum(attrs->attalign); + slot[count]->tts_values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(attrs->attnotnull); + slot[count]->tts_values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(attrs->atthasdef); + slot[count]->tts_values[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(attrs->atthasmissing); + slot[count]->tts_values[Anum_pg_attribute_attidentity - 1] = CharGetDatum(attrs->attidentity); + slot[count]->tts_values[Anum_pg_attribute_attgenerated - 1] = CharGetDatum(attrs->attgenerated); + slot[count]->tts_values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(attrs->attisdropped); + slot[count]->tts_values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(attrs->attislocal); + slot[count]->tts_values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(attrs->attinhcount); + slot[count]->tts_values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(attrs->attcollation); + if (attoptions && attoptions[natts] != (Datum) 0) + slot[count]->tts_values[Anum_pg_attribute_attoptions - 1] = attoptions[natts]; + else + slot[count]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true; + + /* start out with empty permissions and empty options */ + slot[count]->tts_isnull[Anum_pg_attribute_attacl - 1] = true; + slot[count]->tts_isnull[Anum_pg_attribute_attfdwoptions - 1] = true; + slot[count]->tts_isnull[Anum_pg_attribute_attmissingval - 1] = true; + + ExecStoreVirtualTuple(slot[count]); + count++; + + if (count == nslots || natts == tupdesc->natts - 1) + { + if (!indstate) + { + indstate = CatalogOpenIndexes(pg_attribute_rel); + close_index = true; + } + + CatalogTuplesMultiInsertWithInfo(pg_attribute_rel, slot, count, indstate); + count = 0; + } + + natts++; + } + + if (close_index) + CatalogCloseIndexes(indstate); + + for (int i = 0; i < Min(tupdesc->natts, nslots); i++) + ExecDropSingleTupleTableSlot(slot[i]); + pfree(slot); } /* -------------------------------- @@ -788,8 +833,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,35 +846,31 @@ AddNewAttributeTuples(Oid new_rel_oid, indstate = CatalogOpenIndexes(rel); + /* 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); + /* - * First we add the user attributes. This is also a convenient place to - * add dependencies on their datatypes and collations. + * Now add dependencies on their datatypes and collations */ - for (i = 0; i < natts; i++) + for (int 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); - /* Add dependency info */ myself.classId = RelationRelationId; myself.objectId = new_rel_oid; myself.objectSubId = i + 1; referenced.classId = TypeRelationId; - referenced.objectId = attr->atttypid; + referenced.objectId = tupdesc->attrs[i].atttypid; referenced.objectSubId = 0; 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) { referenced.classId = CollationRelationId; - referenced.objectId = attr->attcollation; + referenced.objectId = tupdesc->attrs[i].attcollation; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } @@ -844,17 +883,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); } /* @@ -3537,6 +3571,7 @@ StorePartitionKey(Relation rel, bool nulls[Natts_pg_partitioned_table]; ObjectAddress myself; ObjectAddress referenced; + ObjectAddresses *refobjs; Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); @@ -3584,27 +3619,34 @@ StorePartitionKey(Relation rel, myself.objectId = RelationGetRelid(rel); myself.objectSubId = 0; - /* Operator class and collation per key column */ + refobjs = new_object_addresses(); + + /* + * Operator class and collation per key column. Gather all the + * normal dependencies first, and record them all at once. + */ for (i = 0; i < partnatts; i++) { - referenced.classId = OperatorClassRelationId; - referenced.objectId = partopclass[i]; - referenced.objectSubId = 0; + ObjectAddress ocobj; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(ocobj, OperatorClassRelationId, partopclass[i]); + add_exact_object_address(&ocobj, refobjs); /* The default collation is pinned, so don't bother recording it */ if (OidIsValid(partcollation[i]) && partcollation[i] != DEFAULT_COLLATION_OID) { - referenced.classId = CollationRelationId; - referenced.objectId = partcollation[i]; - referenced.objectSubId = 0; + ObjectAddress collobj; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(collobj, CollationRelationId, partcollation[i]); + add_exact_object_address(&collobj, refobjs); } } + /* Store the dependencies in the catalog */ + record_object_address_dependencies(&myself, refobjs, DEPENDENCY_NORMAL); + free_object_addresses(refobjs); + /* * The partitioning columns are made internally dependent on the table, * because we cannot drop any of them without dropping the whole table. diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index cdc01c49c9..b19492b683 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -106,8 +106,7 @@ static TupleDesc ConstructTupleDescriptor(Relation heapRelation, Oid *classObjectId); static void InitializeAttributeOids(Relation indexRelation, int numatts, Oid indexoid); -static void AppendAttributeTuples(Relation indexRelation, int numatts, - Datum *attopts); +static void AppendAttributeTuples(Relation indexRelation, Datum *attopts); static void UpdateIndexRelation(Oid indexoid, Oid heapoid, Oid parentIndexId, IndexInfo *indexInfo, @@ -485,12 +484,11 @@ InitializeAttributeOids(Relation indexRelation, * ---------------------------------------------------------------- */ static void -AppendAttributeTuples(Relation indexRelation, int numatts, Datum *attopts) +AppendAttributeTuples(Relation indexRelation, Datum *attopts) { Relation pg_attribute; CatalogIndexState indstate; TupleDesc indexTupDesc; - int i; /* * open the attribute relation and its indexes @@ -504,15 +502,7 @@ AppendAttributeTuples(Relation indexRelation, int numatts, Datum *attopts) */ indexTupDesc = RelationGetDescr(indexRelation); - for (i = 0; i < numatts; i++) - { - Form_pg_attribute attr = TupleDescAttr(indexTupDesc, i); - Datum attoptions = attopts ? attopts[i] : (Datum) 0; - - Assert(attr->attnum == i + 1); - - InsertPgAttributeTuple(pg_attribute, attr, attoptions, indstate); - } + InsertPgAttributeTuples(pg_attribute, indexTupDesc, InvalidOid, attopts, indstate); CatalogCloseIndexes(indstate); @@ -979,8 +969,7 @@ index_create(Relation heapRelation, /* * append ATTRIBUTE tuples for the index */ - AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs, - indexInfo->ii_OpclassOptions); + AppendAttributeTuples(indexRelation, indexInfo->ii_OpclassOptions); /* ---------------- * update pg_index @@ -1029,11 +1018,14 @@ index_create(Relation heapRelation, { ObjectAddress myself, referenced; + ObjectAddresses *refobjs; myself.classId = RelationRelationId; myself.objectId = indexRelationId; myself.objectSubId = 0; + refobjs = new_object_addresses(); + if ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0) { char constraintType; @@ -1070,14 +1062,14 @@ index_create(Relation heapRelation, /* Create auto dependencies on simply-referenced columns */ for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) { + ObjectAddress obj; + if (indexInfo->ii_IndexAttrNumbers[i] != 0) { - referenced.classId = RelationRelationId; - referenced.objectId = heapRelationId; - referenced.objectSubId = indexInfo->ii_IndexAttrNumbers[i]; - - recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); - + ObjectAddressSubSet(obj, RelationRelationId, + heapRelationId, + indexInfo->ii_IndexAttrNumbers[i]); + add_exact_object_address(&obj, refobjs); have_simple_col = true; } } @@ -1096,6 +1088,8 @@ index_create(Relation heapRelation, recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); } + else + record_object_address_dependencies(&myself, refobjs, DEPENDENCY_AUTO); } /* @@ -1121,29 +1115,30 @@ index_create(Relation heapRelation, /* Store dependency on collations */ /* The default collation is pinned, so don't bother recording it */ + reset_object_addresses(refobjs); for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++) { + ObjectAddress obj; + if (OidIsValid(collationObjectId[i]) && collationObjectId[i] != DEFAULT_COLLATION_OID) { - referenced.classId = CollationRelationId; - referenced.objectId = collationObjectId[i]; - referenced.objectSubId = 0; - - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, CollationRelationId, collationObjectId[i]); + add_exact_object_address(&obj, refobjs); } } /* Store dependency on operator classes */ for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++) { - referenced.classId = OperatorClassRelationId; - referenced.objectId = classObjectId[i]; - referenced.objectSubId = 0; + ObjectAddress obj; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, OperatorClassRelationId, classObjectId[i]); + add_exact_object_address(&obj, refobjs); } + record_object_address_dependencies(&myself, refobjs, DEPENDENCY_NORMAL); + /* Store dependencies on anything mentioned in index expressions */ if (indexInfo->ii_Expressions) { @@ -1163,6 +1158,8 @@ index_create(Relation heapRelation, DEPENDENCY_NORMAL, DEPENDENCY_AUTO, false); } + + free_object_addresses(refobjs); } else { diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index d63fcf58cf..1eabeb52ca 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -18,6 +18,7 @@ #include "access/genam.h" #include "access/heapam.h" #include "access/htup_details.h" +#include "access/xact.h" #include "catalog/index.h" #include "catalog/indexing.h" #include "executor/executor.h" @@ -209,6 +210,41 @@ CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexInsert(indstate, tup); } +/* + * CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples + * + * Insert multiple tuples into the catalog relation at once, with an amortized + * cost of CatalogOpenIndexes. + */ +void +CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, + int ntuples, CatalogIndexState indstate) +{ + /* Nothing to do */ + if (ntuples <= 0) + return; + + heap_multi_insert(heapRel, slot, ntuples, + GetCurrentCommandId(true), 0, NULL); + + /* + * There is no equivalent to heap_multi_insert for the catalog indexes, so + * we must loop over and insert individually. + */ + for (int i = 0; i < ntuples; i++) + { + bool should_free; + HeapTuple tuple; + + tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free); + tuple->t_tableOid = slot[i]->tts_tableOid; + CatalogIndexInsert(indstate, tuple); + + if (should_free) + heap_freetuple(tuple); + } +} + /* * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple * diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 7d887ea24a..7eb262edd7 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -103,8 +103,9 @@ AggregateCreate(const char *aggName, TupleDesc tupDesc; char *detailmsg; int i; - ObjectAddress myself, - referenced; + ObjectAddress myself; + ObjectAddresses *refobjs; + ObjectAddress obj; AclResult aclresult; /* sanity checks (caller should have caught these) */ @@ -741,84 +742,70 @@ AggregateCreate(const char *aggName, * way. */ + refobjs = new_object_addresses(); + /* Depends on transition function */ - referenced.classId = ProcedureRelationId; - referenced.objectId = transfn; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, transfn); + add_exact_object_address(&obj, refobjs); /* Depends on final function, if any */ if (OidIsValid(finalfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = finalfn; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, finalfn); + add_exact_object_address(&obj, refobjs); } /* Depends on combine function, if any */ if (OidIsValid(combinefn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = combinefn; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, combinefn); + add_exact_object_address(&obj, refobjs); } /* Depends on serialization function, if any */ if (OidIsValid(serialfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = serialfn; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, serialfn); + add_exact_object_address(&obj, refobjs); } /* Depends on deserialization function, if any */ if (OidIsValid(deserialfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = deserialfn; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, deserialfn); + add_exact_object_address(&obj, refobjs); } /* Depends on forward transition function, if any */ if (OidIsValid(mtransfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = mtransfn; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, mtransfn); + add_exact_object_address(&obj, refobjs); } /* Depends on inverse transition function, if any */ if (OidIsValid(minvtransfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = minvtransfn; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, minvtransfn); + add_exact_object_address(&obj, refobjs); } /* Depends on final function, if any */ if (OidIsValid(mfinalfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = mfinalfn; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, mfinalfn); + add_exact_object_address(&obj, refobjs); } /* Depends on sort operator, if any */ if (OidIsValid(sortop)) { - referenced.classId = OperatorRelationId; - referenced.objectId = sortop; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, OperatorRelationId, sortop); + add_exact_object_address(&obj, refobjs); } + record_object_address_dependencies(&myself, refobjs, DEPENDENCY_NORMAL); + return myself; } diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index 90932be831..18cbb706b6 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -91,6 +91,8 @@ CreateConstraintEntry(const char *constraintName, NameData cname; int i; ObjectAddress conobject; + ObjectAddresses *refobjs; + ObjectAddress obj; conDesc = table_open(ConstraintRelationId, RowExclusiveLock); @@ -229,30 +231,30 @@ CreateConstraintEntry(const char *constraintName, table_close(conDesc, RowExclusiveLock); + refobjs = new_object_addresses(); + + /* + * Build all the auto dependencies to track. These are all recorded at + * once. + */ if (OidIsValid(relId)) { /* * Register auto dependency from constraint to owning relation, or to * specific column(s) if any are mentioned. */ - ObjectAddress relobject; - - relobject.classId = RelationRelationId; - relobject.objectId = relId; if (constraintNTotalKeys > 0) { for (i = 0; i < constraintNTotalKeys; i++) { - relobject.objectSubId = constraintKey[i]; - - recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO); + ObjectAddressSubSet(obj, RelationRelationId, relId, constraintKey[i]); + add_exact_object_address(&obj, refobjs); } } else { - relobject.objectSubId = 0; - - recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO); + ObjectAddressSet(obj, RelationRelationId, relId); + add_exact_object_address(&obj, refobjs); } } @@ -261,39 +263,36 @@ CreateConstraintEntry(const char *constraintName, /* * Register auto dependency from constraint to owning domain */ - ObjectAddress domobject; - - domobject.classId = TypeRelationId; - domobject.objectId = domainId; - domobject.objectSubId = 0; - - recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO); + ObjectAddressSet(obj, TypeRelationId, domainId); + add_exact_object_address(&obj, refobjs); } + record_object_address_dependencies(&conobject, refobjs, DEPENDENCY_AUTO); + + reset_object_addresses(refobjs); + + /* + * Build all the normal dependencies to track. These are all recorded + * at once. + */ if (OidIsValid(foreignRelId)) { /* * Register normal dependency from constraint to foreign relation, or * to specific column(s) if any are mentioned. */ - ObjectAddress relobject; - - relobject.classId = RelationRelationId; - relobject.objectId = foreignRelId; if (foreignNKeys > 0) { for (i = 0; i < foreignNKeys; i++) { - relobject.objectSubId = foreignKey[i]; - - recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL); + ObjectAddressSubSet(obj, RelationRelationId, foreignRelId, foreignKey[i]); + add_exact_object_address(&obj, refobjs); } } else { - relobject.objectSubId = 0; - - recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, RelationRelationId, foreignRelId); + add_exact_object_address(&obj, refobjs); } } @@ -305,13 +304,8 @@ CreateConstraintEntry(const char *constraintName, * or primary-key constraints, the dependency runs the other way, and * is not made here.) */ - ObjectAddress relobject; - - relobject.classId = RelationRelationId; - relobject.objectId = indexRelId; - relobject.objectSubId = 0; - - recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, RelationRelationId, indexRelId); + add_exact_object_address(&obj, refobjs); } if (foreignNKeys > 0) @@ -322,28 +316,29 @@ CreateConstraintEntry(const char *constraintName, * all three operators for a column are the same; otherwise they are * different. */ - ObjectAddress oprobject; - - oprobject.classId = OperatorRelationId; - oprobject.objectSubId = 0; - for (i = 0; i < foreignNKeys; i++) { - oprobject.objectId = pfEqOp[i]; - recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, OperatorRelationId, pfEqOp[i]); + add_exact_object_address(&obj, refobjs); + if (ppEqOp[i] != pfEqOp[i]) { - oprobject.objectId = ppEqOp[i]; - recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, OperatorRelationId, ppEqOp[i]); + add_exact_object_address(&obj, refobjs); } + if (ffEqOp[i] != pfEqOp[i]) { - oprobject.objectId = ffEqOp[i]; - recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, OperatorRelationId, ffEqOp[i]); + add_exact_object_address(&obj, refobjs); } } } + record_object_address_dependencies(&conobject, refobjs, DEPENDENCY_NORMAL); + + free_object_addresses(refobjs); + /* * We don't bother to register dependencies on the exclusion operators of * an exclusion constraint. We assume they are members of the opclass diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index 21cfdcace9..92effb3b86 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -59,10 +59,9 @@ recordMultipleDependencies(const ObjectAddress *depender, { Relation dependDesc; CatalogIndexState indstate; - HeapTuple tup; + TupleTableSlot **slot; + int ntuples; int i; - bool nulls[Natts_pg_depend]; - Datum values[Natts_pg_depend]; if (nreferenced <= 0) return; /* nothing to do */ @@ -79,9 +78,10 @@ recordMultipleDependencies(const ObjectAddress *depender, /* Don't open indexes unless we need to make an update */ indstate = NULL; - memset(nulls, false, sizeof(nulls)); + /* TODO is nreferenced a reasonable allocation of slots? */ + slot = palloc(sizeof(TupleTableSlot *) * nreferenced); - for (i = 0; i < nreferenced; i++, referenced++) + for (i = 0, ntuples = 0; i < nreferenced; i++, referenced++) { /* * If the referenced object is pinned by the system, there's no real @@ -90,34 +90,48 @@ recordMultipleDependencies(const ObjectAddress *depender, */ if (!isObjectPinned(referenced, dependDesc)) { + slot[ntuples] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc), + &TTSOpsHeapTuple); + ExecClearTuple(slot[ntuples]); + /* * Record the Dependency. Note we don't bother to check for * duplicate dependencies; there's no harm in them. */ - values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId); - values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId); - values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId); + slot[ntuples]->tts_values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId); + slot[ntuples]->tts_values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId); + slot[ntuples]->tts_values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId); - values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId); - values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId); - values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId); + slot[ntuples]->tts_values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior); - values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior); + slot[ntuples]->tts_values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId); + slot[ntuples]->tts_values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId); + slot[ntuples]->tts_values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId); - tup = heap_form_tuple(dependDesc->rd_att, values, nulls); + memset(slot[ntuples]->tts_isnull, false, + slot[ntuples]->tts_tupleDescriptor->natts * sizeof(bool)); + + ExecStoreVirtualTuple(slot[ntuples]); + ntuples++; /* fetch index info only when we know we need it */ if (indstate == NULL) indstate = CatalogOpenIndexes(dependDesc); - - CatalogTupleInsertWithInfo(dependDesc, tup, indstate); - - heap_freetuple(tup); } } + /* + * We will have an indstate in case we found any tuples to insert in the + * catalog, so perform a multi insert and close the index again when done. + */ if (indstate != NULL) + { + CatalogTuplesMultiInsertWithInfo(dependDesc, slot, ntuples, indstate); CatalogCloseIndexes(indstate); + } + + for (int i = 0; i < ntuples; i++) + ExecDropSingleTupleTableSlot(slot[i]); table_close(dependDesc, RowExclusiveLock); } diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index 340e284ae4..f2360488c9 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -773,13 +773,16 @@ ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate) { Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple); - ObjectAddress myself, - referenced; + ObjectAddress myself; + ObjectAddresses *refobjs; + ObjectAddress obj; myself.classId = OperatorRelationId; myself.objectId = oper->oid; myself.objectSubId = 0; + refobjs = new_object_addresses(); + /* * If we are updating the operator, delete any existing entries, except * for extension membership which should remain the same. @@ -793,37 +796,29 @@ makeOperatorDependencies(HeapTuple tuple, bool isUpdate) /* Dependency on namespace */ if (OidIsValid(oper->oprnamespace)) { - referenced.classId = NamespaceRelationId; - referenced.objectId = oper->oprnamespace; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, NamespaceRelationId, oper->oprnamespace); + add_exact_object_address(&obj, refobjs); } /* Dependency on left type */ if (OidIsValid(oper->oprleft)) { - referenced.classId = TypeRelationId; - referenced.objectId = oper->oprleft; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, TypeRelationId, oper->oprleft); + add_exact_object_address(&obj, refobjs); } /* Dependency on right type */ if (OidIsValid(oper->oprright)) { - referenced.classId = TypeRelationId; - referenced.objectId = oper->oprright; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, TypeRelationId, oper->oprright); + add_exact_object_address(&obj, refobjs); } /* Dependency on result type */ if (OidIsValid(oper->oprresult)) { - referenced.classId = TypeRelationId; - referenced.objectId = oper->oprresult; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, TypeRelationId, oper->oprresult); + add_exact_object_address(&obj, refobjs); } /* @@ -838,30 +833,27 @@ makeOperatorDependencies(HeapTuple tuple, bool isUpdate) /* Dependency on implementation function */ if (OidIsValid(oper->oprcode)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = oper->oprcode; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, oper->oprcode); + add_exact_object_address(&obj, refobjs); } /* Dependency on restriction selectivity function */ if (OidIsValid(oper->oprrest)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = oper->oprrest; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, oper->oprrest); + add_exact_object_address(&obj, refobjs); } /* Dependency on join selectivity function */ if (OidIsValid(oper->oprjoin)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = oper->oprjoin; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, oper->oprjoin); + add_exact_object_address(&obj, refobjs); } + record_object_address_dependencies(&myself, refobjs, DEPENDENCY_NORMAL); + free_object_addresses(refobjs); + /* Dependency on owner */ recordDependencyOnOwner(OperatorRelationId, oper->oid, oper->oprowner); diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 6cdda35d1c..9395085e75 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -109,8 +109,9 @@ ProcedureCreate(const char *procedureName, NameData procname; TupleDesc tupDesc; bool is_update; - ObjectAddress myself, - referenced; + ObjectAddress myself; + ObjectAddresses *refobjs; + ObjectAddress obj; char *detailmsg; int i; Oid trfid; @@ -589,48 +590,38 @@ ProcedureCreate(const char *procedureName, myself.objectId = retval; myself.objectSubId = 0; + refobjs = new_object_addresses(); + /* dependency on namespace */ - referenced.classId = NamespaceRelationId; - referenced.objectId = procNamespace; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, NamespaceRelationId, procNamespace); + add_exact_object_address(&obj, refobjs); /* dependency on implementation language */ - referenced.classId = LanguageRelationId; - referenced.objectId = languageObjectId; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, LanguageRelationId, languageObjectId); + add_exact_object_address(&obj, refobjs); /* dependency on return type */ - referenced.classId = TypeRelationId; - referenced.objectId = returnType; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, TypeRelationId, returnType); + add_exact_object_address(&obj, refobjs); /* dependency on transform used by return type, if any */ if ((trfid = get_transform_oid(returnType, languageObjectId, true))) { - referenced.classId = TransformRelationId; - referenced.objectId = trfid; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, TransformRelationId, trfid); + add_exact_object_address(&obj, refobjs); } /* dependency on parameter types */ for (i = 0; i < allParamCount; i++) { - referenced.classId = TypeRelationId; - referenced.objectId = allParams[i]; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, TypeRelationId, allParams[i]); + add_exact_object_address(&obj, refobjs); /* dependency on transform used by parameter type, if any */ if ((trfid = get_transform_oid(allParams[i], languageObjectId, true))) { - referenced.classId = TransformRelationId; - referenced.objectId = trfid; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, TransformRelationId, trfid); + add_exact_object_address(&obj, refobjs); } } @@ -642,12 +633,13 @@ ProcedureCreate(const char *procedureName, /* dependency on support function, if any */ if (OidIsValid(prosupport)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = prosupport; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, ProcedureRelationId, prosupport); + add_exact_object_address(&obj, refobjs); } + record_object_address_dependencies(&myself, refobjs, DEPENDENCY_NORMAL); + free_object_addresses(refobjs); + /* dependency on owner */ if (!is_update) recordDependencyOnOwner(ProcedureRelationId, retval, proowner); diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index f776e821b3..2092bcc74b 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -785,6 +785,13 @@ checkSharedDependencies(Oid classId, Oid objectId, return true; } + +/* + * Cap the maximum amount of bytes allocated for copyTemplateDependencies + * slots. + */ +#define MAX_TEMPLATE_BYTES 65535 + /* * copyTemplateDependencies * @@ -799,14 +806,19 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId) ScanKeyData key[1]; SysScanDesc scan; HeapTuple tup; + int slotCount; CatalogIndexState indstate; - Datum values[Natts_pg_shdepend]; - bool nulls[Natts_pg_shdepend]; - bool replace[Natts_pg_shdepend]; + TupleTableSlot **slot; + int nslots; sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); sdepDesc = RelationGetDescr(sdepRel); + nslots = MAX_TEMPLATE_BYTES / sizeof(FormData_pg_shdepend); + slot = palloc(sizeof(TupleTableSlot *) * nslots); + for (int i = 0; i < nslots; i++) + slot[i] = MakeSingleTupleTableSlot(sdepDesc, &TTSOpsHeapTuple); + indstate = CatalogOpenIndexes(sdepRel); /* Scan all entries with dbid = templateDbId */ @@ -818,14 +830,6 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId) scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true, NULL, 1, key); - /* Set up to copy the tuples except for inserting newDbId */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - memset(replace, false, sizeof(replace)); - - replace[Anum_pg_shdepend_dbid - 1] = true; - values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId); - /* * Copy the entries of the original database, changing the database Id to * that of the new database. Note that because we are not copying rows @@ -833,20 +837,45 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId) * copy the ownership dependency of the template database itself; this is * what we want. */ + slotCount = 0; while (HeapTupleIsValid(tup = systable_getnext(scan))) { - HeapTuple newtup; + Form_pg_shdepend shdep; - newtup = heap_modify_tuple(tup, sdepDesc, values, nulls, replace); - CatalogTupleInsertWithInfo(sdepRel, newtup, indstate); + ExecClearTuple(slot[slotCount]); - heap_freetuple(newtup); + shdep = (Form_pg_shdepend) GETSTRUCT(tup); + + slot[slotCount]->tts_values[Anum_pg_shdepend_dbid] = ObjectIdGetDatum(newDbId); + slot[slotCount]->tts_values[Anum_pg_shdepend_classid] = shdep->classid; + slot[slotCount]->tts_values[Anum_pg_shdepend_objid] = shdep->objid; + slot[slotCount]->tts_values[Anum_pg_shdepend_objsubid] = shdep->objsubid; + slot[slotCount]->tts_values[Anum_pg_shdepend_refclassid] = shdep->refclassid; + slot[slotCount]->tts_values[Anum_pg_shdepend_refobjid] = shdep->refobjid; + slot[slotCount]->tts_values[Anum_pg_shdepend_deptype] = shdep->deptype; + + ExecStoreVirtualTuple(slot[slotCount]); + slotCount++; + + if (slotCount == nslots) + { + CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slotCount, indstate); + slotCount = 0; + } } + /* Insert any tuples left in the buffer */ + if (slotCount > 0) + CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slotCount, indstate); + systable_endscan(scan); CatalogCloseIndexes(indstate); table_close(sdepRel, RowExclusiveLock); + + for (int i = 0; i < nslots; i++) + ExecDropSingleTupleTableSlot(slot[i]); + pfree(slot); } /* diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index cd56714968..79ffe317dd 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -579,9 +579,7 @@ GenerateTypeDependencies(HeapTuple typeTuple, deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0); } - myself.classId = TypeRelationId; - myself.objectId = typeObjectId; - myself.objectSubId = 0; + ObjectAddressSet(myself, TypeRelationId, typeObjectId); /* * Make dependencies on namespace, owner, ACL, extension. @@ -591,9 +589,8 @@ GenerateTypeDependencies(HeapTuple typeTuple, */ if (!isDependentType) { - referenced.classId = NamespaceRelationId; - referenced.objectId = typeForm->typnamespace; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, NamespaceRelationId, + typeForm->typnamespace); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); recordDependencyOnOwner(TypeRelationId, typeObjectId, @@ -608,57 +605,43 @@ GenerateTypeDependencies(HeapTuple typeTuple, /* Normal dependencies on the I/O functions */ if (OidIsValid(typeForm->typinput)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = typeForm->typinput; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typinput); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } if (OidIsValid(typeForm->typoutput)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = typeForm->typoutput; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typoutput); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } if (OidIsValid(typeForm->typreceive)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = typeForm->typreceive; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typreceive); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } if (OidIsValid(typeForm->typsend)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = typeForm->typsend; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsend); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } if (OidIsValid(typeForm->typmodin)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = typeForm->typmodin; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodin); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } if (OidIsValid(typeForm->typmodout)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = typeForm->typmodout; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodout); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } if (OidIsValid(typeForm->typanalyze)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = typeForm->typanalyze; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typanalyze); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } @@ -673,9 +656,7 @@ GenerateTypeDependencies(HeapTuple typeTuple, */ if (OidIsValid(typeForm->typrelid)) { - referenced.classId = RelationRelationId; - referenced.objectId = typeForm->typrelid; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, RelationRelationId, typeForm->typrelid); if (relationKind != RELKIND_COMPOSITE_TYPE) recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); @@ -690,9 +671,7 @@ GenerateTypeDependencies(HeapTuple typeTuple, */ if (OidIsValid(typeForm->typelem)) { - referenced.classId = TypeRelationId; - referenced.objectId = typeForm->typelem; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, TypeRelationId, typeForm->typelem); recordDependencyOn(&myself, &referenced, isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL); } @@ -700,9 +679,7 @@ GenerateTypeDependencies(HeapTuple typeTuple, /* Normal dependency from a domain to its base type. */ if (OidIsValid(typeForm->typbasetype)) { - referenced.classId = TypeRelationId; - referenced.objectId = typeForm->typbasetype; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, TypeRelationId, typeForm->typbasetype); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } @@ -711,9 +688,7 @@ GenerateTypeDependencies(HeapTuple typeTuple, if (OidIsValid(typeForm->typcollation) && typeForm->typcollation != DEFAULT_COLLATION_OID) { - referenced.classId = CollationRelationId; - referenced.objectId = typeForm->typcollation; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, CollationRelationId, typeForm->typcollation); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 472e69fdaf..d3b76adf5a 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1782,7 +1782,8 @@ InsertExtensionTuple(const char *extName, Oid extOwner, bool nulls[Natts_pg_extension]; HeapTuple tuple; ObjectAddress myself; - ObjectAddress nsp; + ObjectAddresses *refobjs; + ObjectAddress obj; ListCell *lc; /* @@ -1823,29 +1824,29 @@ InsertExtensionTuple(const char *extName, Oid extOwner, /* * Record dependencies on owner, schema, and prerequisite extensions */ + refobjs = new_object_addresses(); + recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner); myself.classId = ExtensionRelationId; myself.objectId = extensionOid; myself.objectSubId = 0; - nsp.classId = NamespaceRelationId; - nsp.objectId = schemaOid; - nsp.objectSubId = 0; - - recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL); + ObjectAddressSet(obj, NamespaceRelationId, schemaOid); + add_exact_object_address(&obj, refobjs); foreach(lc, requiredExtensions) { Oid reqext = lfirst_oid(lc); - ObjectAddress otherext; + ObjectAddress reqobj; - otherext.classId = ExtensionRelationId; - otherext.objectId = reqext; - otherext.objectSubId = 0; - - recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL); + ObjectAddressSet(reqobj, ExtensionRelationId, reqext); + add_exact_object_address(&reqobj, refobjs); } + + record_object_address_dependencies(&myself, refobjs, DEPENDENCY_NORMAL); + free_object_addresses(refobjs); + /* Post creation hook for new extension */ InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f79044f39f..e7d8c062dd 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -5975,6 +5975,8 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *childcmd; AclResult aclresult; ObjectAddress address; + TupleDesc tupdesc; + FormData_pg_attribute *aattr[] = {&attribute}; /* At top level, permission check was done in ATPrepCmd, else do it */ if (recursing) @@ -6128,11 +6130,13 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, attribute.attislocal = colDef->is_local; attribute.attinhcount = colDef->inhcount; attribute.attcollation = collOid; - /* attribute.attacl is handled by InsertPgAttributeTuple */ + /* attribute.attacl is handled by InsertPgAttributeTuples */ ReleaseSysCache(typeTuple); - InsertPgAttributeTuple(attrdesc, &attribute, (Datum) 0, NULL); + tupdesc = CreateTupleDesc(lengthof(aattr), (FormData_pg_attribute **) &aattr); + + InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL); table_close(attrdesc, RowExclusiveLock); diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index e3e6634d7e..814416d936 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -2069,11 +2069,10 @@ WHERE classid = 'pg_class'::regclass AND index concur_reindex_ind3 | column c1 of table concur_reindex_tab | a index concur_reindex_ind3 | table concur_reindex_tab | a index concur_reindex_ind4 | column c1 of table concur_reindex_tab | a - index concur_reindex_ind4 | column c1 of table concur_reindex_tab | a index concur_reindex_ind4 | column c2 of table concur_reindex_tab | a materialized view concur_reindex_matview | schema public | n table concur_reindex_tab | schema public | n -(9 rows) +(8 rows) REINDEX INDEX CONCURRENTLY concur_reindex_ind1; REINDEX TABLE CONCURRENTLY concur_reindex_tab; @@ -2097,11 +2096,10 @@ WHERE classid = 'pg_class'::regclass AND index concur_reindex_ind3 | column c1 of table concur_reindex_tab | a index concur_reindex_ind3 | table concur_reindex_tab | a index concur_reindex_ind4 | column c1 of table concur_reindex_tab | a - index concur_reindex_ind4 | column c1 of table concur_reindex_tab | a index concur_reindex_ind4 | column c2 of table concur_reindex_tab | a materialized view concur_reindex_matview | schema public | n table concur_reindex_tab | schema public | n -(9 rows) +(8 rows) -- Check that comments are preserved CREATE TABLE testcomment (i int);
signature.asc
Description: PGP signature