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
