On Fri, Jun 26, 2020 at 02:26:50PM +0200, Daniel Gustafsson wrote: > On 26 Jun 2020, at 10:11, Michael Paquier <mich...@paquier.xyz> wrote: >> + /* 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? > > I think so, I see no reason not to.
I was actually looking a patch to potentially support REINDEX for partitioned table, and the CONCURRENTLY case may need this patch, still if a lot of dependencies are switched at once it may be a problem, so it is better to cap it. One thing though is that we may finish by allocating more slots than what's necessary if some dependencies are pinned, but using multi-inserts would be a gain anyway, and the patch does not insert in more slots than needed. > I like it, thanks for hacking on it. I will take another look at it later > today when back at my laptop. Thanks. I have been able to apply the independent part of pg_type.c as of 68de144. Attached is a rebased set, with more splitting work done after a new round of review. 0001 is more refactoring to use more ObjectAddress[Sub]Set() where we can, leading to some more cleanup: 5 files changed, 43 insertions(+), 120 deletions(-) In this round, I got confused with the way ObjectAddress items are assigned, assuming that we have to use the same dependency type for a bunch of dependencies to attach. Using add_exact_object_address() is fine for this purpose, but this also makes me wonder if we should try to think harder about this interface so as we would be able to insert a bunch of dependency tuples with multiple types of dependencies handled. So this has made me remove reset_object_addresses() from the patch series, as it was used when dependency types were mixed up. We could also discuss that separately, but that's not strongly mandatory here. There are however cases where it is straight-forward to gather and insert multiple records, like in InsertExtensionTuple() (as does already tsearchcmds.c), which is what 0002 does. An opposite example is StorePartitionKey(), where there is a mix of normal and internal dependencies, so I have removed it for now. 0003 is the main patch, where I have capped the number of slots used for pg_depend similarly what is done for pg_shdepend and pg_attribute to flush tuples in batches of 64kB. ExecDropSingleTupleTableSlot() was also called for an incorrect number of slots when it came to pg_shdepend. I was thinking if it could be possible to do more consolidation between the three places where we calculate the number of slots to use, but that would also mean to have more tuple slot dependency moving around, which is not great. Anyway, this leaves in patch 0003 only the multi-INSERT logic, without the pieces that manipulated the dependency recording and insertions (we still have three ObjectAddress[Sub]Set calls in heap.c but the same area of the code is reworked for attribute insertions). 0001 and 0002 are committable and independent pieces, while 0003 still needs more attention. One thing I also wanted to do with 0003 is measure the difference in WAL produced (say pg_shdepend when using the regression database as template) to have an idea of the gain. -- Michael
From 9552ba259e42d2d14e49aa19a86d27e1ebfd7cd3 Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@paquier.xyz> Date: Mon, 29 Jun 2020 14:52:58 +0900 Subject: [PATCH 1/3] Refactor ObjectAddress field assignments in more places This is a continuation of 68de144, with more places in the backend code that can be simplified with the macros able to assign values to the fields of ObjectAddress. Author: Daniel Gustafsson, Michael Paquier Discussion: https://postgr.es/m/20190213182737.mxn6hkdxwrzgx...@alap3.anarazel.de --- src/backend/catalog/index.c | 39 ++++++++--------------------- src/backend/catalog/pg_aggregate.c | 36 +++++++------------------- src/backend/catalog/pg_constraint.c | 28 ++++++--------------- src/backend/catalog/pg_operator.c | 28 ++++++--------------- src/backend/catalog/pg_proc.c | 32 ++++++----------------- 5 files changed, 43 insertions(+), 120 deletions(-) diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index cdc01c49c9..fc088d3f52 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -1030,9 +1030,7 @@ index_create(Relation heapRelation, ObjectAddress myself, referenced; - myself.classId = RelationRelationId; - myself.objectId = indexRelationId; - myself.objectSubId = 0; + ObjectAddressSet(myself, RelationRelationId, indexRelationId); if ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0) { @@ -1072,12 +1070,10 @@ index_create(Relation heapRelation, { if (indexInfo->ii_IndexAttrNumbers[i] != 0) { - referenced.classId = RelationRelationId; - referenced.objectId = heapRelationId; - referenced.objectSubId = indexInfo->ii_IndexAttrNumbers[i]; - + ObjectAddressSubSet(referenced, RelationRelationId, + heapRelationId, + indexInfo->ii_IndexAttrNumbers[i]); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); - have_simple_col = true; } } @@ -1090,10 +1086,8 @@ index_create(Relation heapRelation, */ if (!have_simple_col) { - referenced.classId = RelationRelationId; - referenced.objectId = heapRelationId; - referenced.objectSubId = 0; - + ObjectAddressSet(referenced, RelationRelationId, + heapRelationId); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); } } @@ -1106,16 +1100,10 @@ index_create(Relation heapRelation, */ if (OidIsValid(parentIndexRelid)) { - referenced.classId = RelationRelationId; - referenced.objectId = parentIndexRelid; - referenced.objectSubId = 0; - + ObjectAddressSet(referenced, RelationRelationId, parentIndexRelid); recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI); - referenced.classId = RelationRelationId; - referenced.objectId = heapRelationId; - referenced.objectSubId = 0; - + ObjectAddressSet(referenced, RelationRelationId, heapRelationId); recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC); } @@ -1126,10 +1114,8 @@ index_create(Relation heapRelation, if (OidIsValid(collationObjectId[i]) && collationObjectId[i] != DEFAULT_COLLATION_OID) { - referenced.classId = CollationRelationId; - referenced.objectId = collationObjectId[i]; - referenced.objectSubId = 0; - + ObjectAddressSet(referenced, CollationRelationId, + collationObjectId[i]); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } } @@ -1137,10 +1123,7 @@ index_create(Relation heapRelation, /* Store dependency on operator classes */ for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++) { - referenced.classId = OperatorClassRelationId; - referenced.objectId = classObjectId[i]; - referenced.objectSubId = 0; - + ObjectAddressSet(referenced, OperatorClassRelationId, classObjectId[i]); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 7d887ea24a..89007ad1ed 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -742,80 +742,62 @@ AggregateCreate(const char *aggName, */ /* Depends on transition function */ - referenced.classId = ProcedureRelationId; - referenced.objectId = transfn; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, transfn); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* Depends on final function, if any */ if (OidIsValid(finalfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = finalfn; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, finalfn); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Depends on combine function, if any */ if (OidIsValid(combinefn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = combinefn; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, combinefn); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Depends on serialization function, if any */ if (OidIsValid(serialfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = serialfn; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, serialfn); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Depends on deserialization function, if any */ if (OidIsValid(deserialfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = deserialfn; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, deserialfn); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Depends on forward transition function, if any */ if (OidIsValid(mtransfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = mtransfn; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, mtransfn); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Depends on inverse transition function, if any */ if (OidIsValid(minvtransfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = minvtransfn; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, minvtransfn); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Depends on final function, if any */ if (OidIsValid(mfinalfn)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = mfinalfn; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, mfinalfn); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Depends on sort operator, if any */ if (OidIsValid(sortop)) { - referenced.classId = OperatorRelationId; - referenced.objectId = sortop; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, OperatorRelationId, sortop); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index 90932be831..4f5b9e9f48 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -237,21 +237,18 @@ CreateConstraintEntry(const char *constraintName, */ ObjectAddress relobject; - relobject.classId = RelationRelationId; - relobject.objectId = relId; if (constraintNTotalKeys > 0) { for (i = 0; i < constraintNTotalKeys; i++) { - relobject.objectSubId = constraintKey[i]; - + ObjectAddressSubSet(relobject, RelationRelationId, relId, + constraintKey[i]); recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO); } } else { - relobject.objectSubId = 0; - + ObjectAddressSet(relobject, RelationRelationId, relId); recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO); } } @@ -263,10 +260,7 @@ CreateConstraintEntry(const char *constraintName, */ ObjectAddress domobject; - domobject.classId = TypeRelationId; - domobject.objectId = domainId; - domobject.objectSubId = 0; - + ObjectAddressSet(domobject, TypeRelationId, domainId); recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO); } @@ -278,21 +272,18 @@ CreateConstraintEntry(const char *constraintName, */ ObjectAddress relobject; - relobject.classId = RelationRelationId; - relobject.objectId = foreignRelId; if (foreignNKeys > 0) { for (i = 0; i < foreignNKeys; i++) { - relobject.objectSubId = foreignKey[i]; - + ObjectAddressSubSet(relobject, RelationRelationId, + foreignRelId, foreignKey[i]); recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL); } } else { - relobject.objectSubId = 0; - + ObjectAddressSet(relobject, RelationRelationId, foreignRelId); recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL); } } @@ -307,10 +298,7 @@ CreateConstraintEntry(const char *constraintName, */ ObjectAddress relobject; - relobject.classId = RelationRelationId; - relobject.objectId = indexRelId; - relobject.objectSubId = 0; - + ObjectAddressSet(relobject, RelationRelationId, indexRelId); recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL); } diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index 340e284ae4..61254c8ba2 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -793,36 +793,28 @@ makeOperatorDependencies(HeapTuple tuple, bool isUpdate) /* Dependency on namespace */ if (OidIsValid(oper->oprnamespace)) { - referenced.classId = NamespaceRelationId; - referenced.objectId = oper->oprnamespace; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, NamespaceRelationId, oper->oprnamespace); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Dependency on left type */ if (OidIsValid(oper->oprleft)) { - referenced.classId = TypeRelationId; - referenced.objectId = oper->oprleft; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, TypeRelationId, oper->oprleft); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Dependency on right type */ if (OidIsValid(oper->oprright)) { - referenced.classId = TypeRelationId; - referenced.objectId = oper->oprright; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, TypeRelationId, oper->oprright); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Dependency on result type */ if (OidIsValid(oper->oprresult)) { - referenced.classId = TypeRelationId; - referenced.objectId = oper->oprresult; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, TypeRelationId, oper->oprresult); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } @@ -838,27 +830,21 @@ makeOperatorDependencies(HeapTuple tuple, bool isUpdate) /* Dependency on implementation function */ if (OidIsValid(oper->oprcode)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = oper->oprcode; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, oper->oprcode); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Dependency on restriction selectivity function */ if (OidIsValid(oper->oprrest)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = oper->oprrest; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, oper->oprrest); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Dependency on join selectivity function */ if (OidIsValid(oper->oprjoin)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = oper->oprjoin; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, oper->oprjoin); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 6cdda35d1c..a28ab74d60 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -585,51 +585,37 @@ ProcedureCreate(const char *procedureName, if (is_update) deleteDependencyRecordsFor(ProcedureRelationId, retval, true); - myself.classId = ProcedureRelationId; - myself.objectId = retval; - myself.objectSubId = 0; + ObjectAddressSet(myself, ProcedureRelationId, retval); /* dependency on namespace */ - referenced.classId = NamespaceRelationId; - referenced.objectId = procNamespace; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, NamespaceRelationId, procNamespace); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on implementation language */ - referenced.classId = LanguageRelationId; - referenced.objectId = languageObjectId; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, LanguageRelationId, languageObjectId); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on return type */ - referenced.classId = TypeRelationId; - referenced.objectId = returnType; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, TypeRelationId, returnType); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* 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; + ObjectAddressSet(referenced, TransformRelationId, trfid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* dependency on parameter types */ for (i = 0; i < allParamCount; i++) { - referenced.classId = TypeRelationId; - referenced.objectId = allParams[i]; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, TypeRelationId, allParams[i]); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* 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; + ObjectAddressSet(referenced, TransformRelationId, trfid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } } @@ -642,9 +628,7 @@ ProcedureCreate(const char *procedureName, /* dependency on support function, if any */ if (OidIsValid(prosupport)) { - referenced.classId = ProcedureRelationId; - referenced.objectId = prosupport; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, ProcedureRelationId, prosupport); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } -- 2.27.0
From efdd3f918a015d9e7ce8aafa4a17fe98033222c5 Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@paquier.xyz> Date: Mon, 29 Jun 2020 15:25:16 +0900 Subject: [PATCH 2/3] Refactor dependency handling when creating extension Extensions mostly use the same type of dependencies when creating them, so refactor the code to register all dependencies at once, and insert them in batches. --- src/backend/commands/extension.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 472e69fdaf..5159e18cbf 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1783,6 +1783,7 @@ InsertExtensionTuple(const char *extName, Oid extOwner, HeapTuple tuple; ObjectAddress myself; ObjectAddress nsp; + ObjectAddresses *refobjs; ListCell *lc; /* @@ -1825,27 +1826,25 @@ InsertExtensionTuple(const char *extName, Oid extOwner, */ recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner); - myself.classId = ExtensionRelationId; - myself.objectId = extensionOid; - myself.objectSubId = 0; + refobjs = new_object_addresses(); - nsp.classId = NamespaceRelationId; - nsp.objectId = schemaOid; - nsp.objectSubId = 0; + ObjectAddressSet(myself, ExtensionRelationId, extensionOid); - recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL); + ObjectAddressSet(nsp, NamespaceRelationId, schemaOid); + add_exact_object_address(&nsp, refobjs); foreach(lc, requiredExtensions) { Oid reqext = lfirst_oid(lc); ObjectAddress otherext; - otherext.classId = ExtensionRelationId; - otherext.objectId = reqext; - otherext.objectSubId = 0; - - recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL); + ObjectAddressSet(otherext, ExtensionRelationId, reqext); + add_exact_object_address(&otherext, refobjs); } + + record_object_address_dependencies(&myself, refobjs, DEPENDENCY_NORMAL); + free_object_addresses(refobjs); + /* Post creation hook for new extension */ InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0); -- 2.27.0
From 804c7ce410ebb5e92a260d6c17dbaff9b3276070 Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@paquier.xyz> Date: Mon, 29 Jun 2020 15:35:47 +0900 Subject: [PATCH 3/3] Do multi-INSERTs for pg_depend, pg_shdepend and pg_attribute --- src/include/catalog/heap.h | 9 +- src/include/catalog/indexing.h | 5 + src/backend/access/heap/heapam.c | 4 - src/backend/catalog/heap.c | 203 +++++++++++++++++------------- src/backend/catalog/index.c | 19 +-- src/backend/catalog/indexing.c | 36 ++++++ src/backend/catalog/pg_depend.c | 96 ++++++++++---- src/backend/catalog/pg_shdepend.c | 60 ++++++--- src/backend/commands/tablecmds.c | 8 +- 9 files changed, 289 insertions(+), 151 deletions(-) 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/heap.c b/src/backend/catalog/heap.c index 3c83fe6bab..36e85e929f 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -710,70 +710,122 @@ CheckAttributeType(const char *attname, } /* - * InsertPgAttributeTuple - * Construct and insert a new tuple in pg_attribute. + * Cap the maximum amount of bytes allocated for InsertPgAttributeTuples() + * slots. + */ +#define MAX_PGATTRIBUTE_INSERT_BYTES 65535 + +/* + * InsertPgAttributeTuples + * Construct and insert a set of tuples in pg_attribute. * - * Caller has already opened and locked pg_attribute. new_attribute is the - * attribute to insert. attcacheoff is always initialized to -1, attacl, - * attfdwoptions and attmissingval are always initialized to NULL. + * Caller has already opened and locked pg_attribute. tupdesc contains the + * attributes to insert. attcacheoff is always initialized to -1, attacl, + * attfdwoptions and attmissingval are always initialized to NULL. attoptions + * must contain the same number of elements as tupdesc, or be NULL. * * indstate is the index state for CatalogTupleInsertWithInfo. It can be * passed as NULL, in which case we'll fetch the necessary info. (Don't do * this when inserting multiple attributes, because it's a tad more * expensive.) + * + * new_rel_oid is the relation OID assigned to the attributes inserted. + * If set to InvalidOid, the relation OID from tupdesc is used instead. */ void -InsertPgAttributeTuple(Relation pg_attribute_rel, - Form_pg_attribute new_attribute, - Datum attoptions, - CatalogIndexState indstate) +InsertPgAttributeTuples(Relation pg_attribute_rel, + TupleDesc tupdesc, + Oid new_rel_oid, + Datum *attoptions, + CatalogIndexState indstate) { - Datum values[Natts_pg_attribute]; - bool nulls[Natts_pg_attribute]; - HeapTuple tup; + TupleTableSlot **slot; + TupleDesc td; + int nslots; + int natts = 0; + int slotCount = 0; + bool close_index = false; - /* 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; + /* Initialize the number of slots to use */ + nslots = Min(tupdesc->natts, + (MAX_PGATTRIBUTE_INSERT_BYTES / sizeof(FormData_pg_attribute))); + slot = palloc(sizeof(TupleTableSlot *) * nslots); + for (int i = 0; i < nslots; i++) + slot[i] = MakeSingleTupleTableSlot(td, &TTSOpsHeapTuple); - /* 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[slotCount]); - /* 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[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_rel_oid); + else + slot[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(attrs->attrelid); - heap_freetuple(tup); + slot[slotCount]->tts_values[Anum_pg_attribute_attname - 1] = NameGetDatum(&attrs->attname); + slot[slotCount]->tts_values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(attrs->atttypid); + slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(attrs->attstattarget); + slot[slotCount]->tts_values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(attrs->attlen); + slot[slotCount]->tts_values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(attrs->attnum); + slot[slotCount]->tts_values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(attrs->attndims); + slot[slotCount]->tts_values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1); + slot[slotCount]->tts_values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(attrs->atttypmod); + slot[slotCount]->tts_values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(attrs->attbyval); + slot[slotCount]->tts_values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(attrs->attstorage); + slot[slotCount]->tts_values[Anum_pg_attribute_attalign - 1] = CharGetDatum(attrs->attalign); + slot[slotCount]->tts_values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(attrs->attnotnull); + slot[slotCount]->tts_values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(attrs->atthasdef); + slot[slotCount]->tts_values[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(attrs->atthasmissing); + slot[slotCount]->tts_values[Anum_pg_attribute_attidentity - 1] = CharGetDatum(attrs->attidentity); + slot[slotCount]->tts_values[Anum_pg_attribute_attgenerated - 1] = CharGetDatum(attrs->attgenerated); + slot[slotCount]->tts_values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(attrs->attisdropped); + slot[slotCount]->tts_values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(attrs->attislocal); + slot[slotCount]->tts_values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(attrs->attinhcount); + slot[slotCount]->tts_values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(attrs->attcollation); + if (attoptions && attoptions[natts] != (Datum) 0) + slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] = attoptions[natts]; + else + slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true; + + /* start out with empty permissions and empty options */ + slot[slotCount]->tts_isnull[Anum_pg_attribute_attacl - 1] = true; + slot[slotCount]->tts_isnull[Anum_pg_attribute_attfdwoptions - 1] = true; + slot[slotCount]->tts_isnull[Anum_pg_attribute_attmissingval - 1] = true; + + ExecStoreVirtualTuple(slot[slotCount]); + slotCount++; + + /* + * If slots are full or the end of processing has been reached, + * insert a batch of tuples. + */ + if (slotCount == nslots || natts == tupdesc->natts - 1) + { + /* fetch index info only when we know we need it */ + if (!indstate) + { + indstate = CatalogOpenIndexes(pg_attribute_rel); + close_index = true; + } + + /* insert the new tuples and update the indexes */ + CatalogTuplesMultiInsertWithInfo(pg_attribute_rel, slot, slotCount, + indstate); + slotCount = 0; + } + + natts++; + } + + if (close_index) + CatalogCloseIndexes(indstate); + for (int i = 0; i < nslots; i++) + ExecDropSingleTupleTableSlot(slot[i]); + pfree(slot); } /* -------------------------------- @@ -788,8 +840,6 @@ AddNewAttributeTuples(Oid new_rel_oid, TupleDesc tupdesc, char relkind) { - Form_pg_attribute attr; - int i; Relation rel; CatalogIndexState indstate; int natts = tupdesc->natts; @@ -803,36 +853,26 @@ AddNewAttributeTuples(Oid new_rel_oid, indstate = CatalogOpenIndexes(rel); - /* - * First we add the user attributes. This is also a convenient place to - * add dependencies on their datatypes and collations. - */ - for (i = 0; i < natts; i++) + /* set stats detail level to a sane default */ + for (int i = 0; i < natts; i++) + tupdesc->attrs[i].attstattarget = -1; + InsertPgAttributeTuples(rel, tupdesc, new_rel_oid, NULL, indstate); + + /* add dependencies on their datatypes and collations */ + for (int i = 0; i < natts; i++) { - 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.objectSubId = 0; + ObjectAddressSubSet(myself, RelationRelationId, new_rel_oid, i + 1); + ObjectAddressSet(referenced, TypeRelationId, + tupdesc->attrs[i].atttypid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* The default collation is pinned, so don't bother recording it */ - if (OidIsValid(attr->attcollation) && - attr->attcollation != DEFAULT_COLLATION_OID) + if (OidIsValid(tupdesc->attrs[i].attcollation) && + tupdesc->attrs[i].attcollation != DEFAULT_COLLATION_OID) { - referenced.classId = CollationRelationId; - referenced.objectId = attr->attcollation; - referenced.objectSubId = 0; + ObjectAddressSet(referenced, CollationRelationId, + tupdesc->attrs[i].attcollation); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } } @@ -844,17 +884,12 @@ AddNewAttributeTuples(Oid new_rel_oid, */ if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) { - for (i = 0; i < (int) lengthof(SysAtt); i++) - { - FormData_pg_attribute attStruct; + TupleDesc td; - memcpy(&attStruct, SysAtt[i], sizeof(FormData_pg_attribute)); + td = CreateTupleDesc(lengthof(SysAtt), (FormData_pg_attribute **) &SysAtt); - /* Fill in the correct relation OID in the copied tuple */ - attStruct.attrelid = new_rel_oid; - - InsertPgAttributeTuple(rel, &attStruct, (Datum) 0, indstate); - } + InsertPgAttributeTuples(rel, td, new_rel_oid, NULL, indstate); + FreeTupleDesc(td); } /* diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index fc088d3f52..255ebac15b 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 diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index d63fcf58cf..3d249b4cb5 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 given 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_depend.c b/src/backend/catalog/pg_depend.c index 21cfdcace9..1fe993d9a9 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -47,6 +47,12 @@ recordDependencyOn(const ObjectAddress *depender, recordMultipleDependencies(depender, referenced, 1, behavior); } +/* + * Cap the maximum amount of bytes allocated for recordMultipleDependencies() + * slots. + */ +#define MAX_PGDEPEND_INSERT_BYTES 65535 + /* * Record multiple dependencies (of the same kind) for a single dependent * object. This has a little less overhead than recording each separately. @@ -59,10 +65,10 @@ recordMultipleDependencies(const ObjectAddress *depender, { Relation dependDesc; CatalogIndexState indstate; - HeapTuple tup; - int i; - bool nulls[Natts_pg_depend]; - Datum values[Natts_pg_depend]; + TupleTableSlot **slot; + int nslots; + int slotCount = 0; + bool close_index = false; if (nreferenced <= 0) return; /* nothing to do */ @@ -79,46 +85,82 @@ recordMultipleDependencies(const ObjectAddress *depender, /* Don't open indexes unless we need to make an update */ indstate = NULL; - memset(nulls, false, sizeof(nulls)); + /* Initialize the number of slots to use */ + nslots = Min(nreferenced, + (MAX_PGDEPEND_INSERT_BYTES / sizeof(FormData_pg_depend))); + slot = palloc(sizeof(TupleTableSlot *) * nslots); - for (i = 0; i < nreferenced; i++, referenced++) + for (int i = 0; i < nslots; i++) + slot[i] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc), + &TTSOpsHeapTuple); + + for (int i = 0; i < nreferenced; i++, referenced++) { /* * If the referenced object is pinned by the system, there's no real * need to record dependencies on it. This saves lots of space in * pg_depend, so it's worth the time taken to check. */ - if (!isObjectPinned(referenced, dependDesc)) + if (isObjectPinned(referenced, dependDesc)) + continue; + + ExecClearTuple(slot[slotCount]); + + /* + * Record the Dependency. Note we don't bother to check for + * duplicate dependencies; there's no harm in them. + */ + slot[slotCount]->tts_values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId); + slot[slotCount]->tts_values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId); + slot[slotCount]->tts_values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId); + slot[slotCount]->tts_values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior); + slot[slotCount]->tts_values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId); + slot[slotCount]->tts_values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId); + slot[slotCount]->tts_values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId); + + memset(slot[slotCount]->tts_isnull, false, + slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool)); + + ExecStoreVirtualTuple(slot[slotCount]); + slotCount++; + + /* If slots are full, insert a batch of tuples */ + if (slotCount == nslots) { - /* - * 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); - - 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); - - values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior); - - tup = heap_form_tuple(dependDesc->rd_att, values, nulls); - /* fetch index info only when we know we need it */ if (indstate == NULL) + { indstate = CatalogOpenIndexes(dependDesc); + close_index = true; + } - CatalogTupleInsertWithInfo(dependDesc, tup, indstate); - - heap_freetuple(tup); + /* Insert the new tuples and update the indexes */ + CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slotCount, + indstate); + slotCount = 0; } } - if (indstate != NULL) + /* Insert any tuples if any left in the buffer */ + if (slotCount > 0) + { + /* Again, index information may not exist yet */ + if (indstate == NULL) + { + indstate = CatalogOpenIndexes(dependDesc); + close_index = true; + } + + CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slotCount, indstate); + } + + /* close the indexes, we are done */ + if (close_index) CatalogCloseIndexes(indstate); + for (int i = 0; i < nslots; i++) + ExecDropSingleTupleTableSlot(slot[i]); + table_close(dependDesc, RowExclusiveLock); } diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index f776e821b3..1754bbfb57 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_PGSHDEPEND_INSERT_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_PGSHDEPEND_INSERT_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,46 @@ 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 slots are full, insert a batch of tuples */ + 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/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); -- 2.27.0
signature.asc
Description: PGP signature