@@ -710,70 +710,122 @@ CheckAttributeType(const char *attname,
710710}
711711
712712/*
713- * InsertPgAttributeTuple
714- * Construct and insert a new tuple in pg_attribute.
713+ * Cap the maximum amount of bytes allocated for InsertPgAttributeTuples()
714+ * slots.
715+ */
716+ #define MAX_PGATTRIBUTE_INSERT_BYTES 65535
717+
718+ /*
719+ * InsertPgAttributeTuples
720+ * Construct and insert a set of tuples in pg_attribute.
715721 *
716- * Caller has already opened and locked pg_attribute. new_attribute is the
717- * attribute to insert. attcacheoff is always initialized to -1, attacl,
718- * attfdwoptions and attmissingval are always initialized to NULL.
722+ * Caller has already opened and locked pg_attribute. tupdesc contains the
723+ * attributes to insert. attcacheoff is always initialized to -1, attacl,
724+ * attfdwoptions and attmissingval are always initialized to NULL. attoptions
725+ * must contain the same number of elements as tupdesc, or be NULL.
719726 *
720727 * indstate is the index state for CatalogTupleInsertWithInfo. It can be
721728 * passed as NULL, in which case we'll fetch the necessary info. (Don't do
722729 * this when inserting multiple attributes, because it's a tad more
723730 * expensive.)
731+ *
732+ * new_rel_oid is the relation OID assigned to the attributes inserted.
733+ * If set to InvalidOid, the relation OID from tupdesc is used instead.
724734 */
725735void
726- InsertPgAttributeTuple (Relation pg_attribute_rel ,
727- Form_pg_attribute new_attribute ,
728- Datum attoptions ,
729- CatalogIndexState indstate )
736+ InsertPgAttributeTuples (Relation pg_attribute_rel ,
737+ TupleDesc tupdesc ,
738+ Oid new_rel_oid ,
739+ Datum * attoptions ,
740+ CatalogIndexState indstate )
730741{
731- Datum values [Natts_pg_attribute ];
732- bool nulls [Natts_pg_attribute ];
733- HeapTuple tup ;
742+ TupleTableSlot * * slot ;
743+ TupleDesc td ;
744+ int nslots ;
745+ int natts = 0 ;
746+ int slotCount = 0 ;
747+ bool close_index = false;
748+
749+ td = RelationGetDescr (pg_attribute_rel );
750+
751+ /* Initialize the number of slots to use */
752+ nslots = Min (tupdesc -> natts ,
753+ (MAX_PGATTRIBUTE_INSERT_BYTES / sizeof (FormData_pg_attribute )));
754+ slot = palloc (sizeof (TupleTableSlot * ) * nslots );
755+ for (int i = 0 ; i < nslots ; i ++ )
756+ slot [i ] = MakeSingleTupleTableSlot (td , & TTSOpsHeapTuple );
757+
758+ while (natts < tupdesc -> natts )
759+ {
760+ Form_pg_attribute attrs = TupleDescAttr (tupdesc , natts );
734761
735- /* This is a tad tedious, but way cleaner than what we used to do... */
736- memset (values , 0 , sizeof (values ));
737- memset (nulls , false, sizeof (nulls ));
762+ ExecClearTuple (slot [slotCount ]);
738763
739- values [Anum_pg_attribute_attrelid - 1 ] = ObjectIdGetDatum (new_attribute -> attrelid );
740- values [Anum_pg_attribute_attname - 1 ] = NameGetDatum (& new_attribute -> attname );
741- values [Anum_pg_attribute_atttypid - 1 ] = ObjectIdGetDatum (new_attribute -> atttypid );
742- values [Anum_pg_attribute_attstattarget - 1 ] = Int32GetDatum (new_attribute -> attstattarget );
743- values [Anum_pg_attribute_attlen - 1 ] = Int16GetDatum (new_attribute -> attlen );
744- values [Anum_pg_attribute_attnum - 1 ] = Int16GetDatum (new_attribute -> attnum );
745- values [Anum_pg_attribute_attndims - 1 ] = Int32GetDatum (new_attribute -> attndims );
746- values [Anum_pg_attribute_attcacheoff - 1 ] = Int32GetDatum (-1 );
747- values [Anum_pg_attribute_atttypmod - 1 ] = Int32GetDatum (new_attribute -> atttypmod );
748- values [Anum_pg_attribute_attbyval - 1 ] = BoolGetDatum (new_attribute -> attbyval );
749- values [Anum_pg_attribute_attstorage - 1 ] = CharGetDatum (new_attribute -> attstorage );
750- values [Anum_pg_attribute_attalign - 1 ] = CharGetDatum (new_attribute -> attalign );
751- values [Anum_pg_attribute_attnotnull - 1 ] = BoolGetDatum (new_attribute -> attnotnull );
752- values [Anum_pg_attribute_atthasdef - 1 ] = BoolGetDatum (new_attribute -> atthasdef );
753- values [Anum_pg_attribute_atthasmissing - 1 ] = BoolGetDatum (new_attribute -> atthasmissing );
754- values [Anum_pg_attribute_attidentity - 1 ] = CharGetDatum (new_attribute -> attidentity );
755- values [Anum_pg_attribute_attgenerated - 1 ] = CharGetDatum (new_attribute -> attgenerated );
756- values [Anum_pg_attribute_attisdropped - 1 ] = BoolGetDatum (new_attribute -> attisdropped );
757- values [Anum_pg_attribute_attislocal - 1 ] = BoolGetDatum (new_attribute -> attislocal );
758- values [Anum_pg_attribute_attinhcount - 1 ] = Int32GetDatum (new_attribute -> attinhcount );
759- values [Anum_pg_attribute_attcollation - 1 ] = ObjectIdGetDatum (new_attribute -> attcollation );
760- values [Anum_pg_attribute_attoptions - 1 ] = attoptions ;
761-
762- /* start out with empty permissions and empty options */
763- nulls [Anum_pg_attribute_attacl - 1 ] = true;
764- nulls [Anum_pg_attribute_attoptions - 1 ] = attoptions == (Datum ) 0 ;
765- nulls [Anum_pg_attribute_attfdwoptions - 1 ] = true;
766- nulls [Anum_pg_attribute_attmissingval - 1 ] = true;
767-
768- tup = heap_form_tuple (RelationGetDescr (pg_attribute_rel ), values , nulls );
764+ if (new_rel_oid != InvalidOid )
765+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attrelid - 1 ] = ObjectIdGetDatum (new_rel_oid );
766+ else
767+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attrelid - 1 ] = ObjectIdGetDatum (attrs -> attrelid );
768+
769+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attname - 1 ] = NameGetDatum (& attrs -> attname );
770+ slot [slotCount ]-> tts_values [Anum_pg_attribute_atttypid - 1 ] = ObjectIdGetDatum (attrs -> atttypid );
771+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attstattarget - 1 ] = Int32GetDatum (attrs -> attstattarget );
772+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attlen - 1 ] = Int16GetDatum (attrs -> attlen );
773+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attnum - 1 ] = Int16GetDatum (attrs -> attnum );
774+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attndims - 1 ] = Int32GetDatum (attrs -> attndims );
775+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attcacheoff - 1 ] = Int32GetDatum (-1 );
776+ slot [slotCount ]-> tts_values [Anum_pg_attribute_atttypmod - 1 ] = Int32GetDatum (attrs -> atttypmod );
777+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attbyval - 1 ] = BoolGetDatum (attrs -> attbyval );
778+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attstorage - 1 ] = CharGetDatum (attrs -> attstorage );
779+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attalign - 1 ] = CharGetDatum (attrs -> attalign );
780+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attnotnull - 1 ] = BoolGetDatum (attrs -> attnotnull );
781+ slot [slotCount ]-> tts_values [Anum_pg_attribute_atthasdef - 1 ] = BoolGetDatum (attrs -> atthasdef );
782+ slot [slotCount ]-> tts_values [Anum_pg_attribute_atthasmissing - 1 ] = BoolGetDatum (attrs -> atthasmissing );
783+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attidentity - 1 ] = CharGetDatum (attrs -> attidentity );
784+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attgenerated - 1 ] = CharGetDatum (attrs -> attgenerated );
785+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attisdropped - 1 ] = BoolGetDatum (attrs -> attisdropped );
786+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attislocal - 1 ] = BoolGetDatum (attrs -> attislocal );
787+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attinhcount - 1 ] = Int32GetDatum (attrs -> attinhcount );
788+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attcollation - 1 ] = ObjectIdGetDatum (attrs -> attcollation );
789+ if (attoptions && attoptions [natts ] != (Datum ) 0 )
790+ slot [slotCount ]-> tts_values [Anum_pg_attribute_attoptions - 1 ] = attoptions [natts ];
791+ else
792+ slot [slotCount ]-> tts_isnull [Anum_pg_attribute_attoptions - 1 ] = true;
769793
770- /* finally insert the new tuple, update the indexes, and clean up */
771- if (indstate != NULL )
772- CatalogTupleInsertWithInfo (pg_attribute_rel , tup , indstate );
773- else
774- CatalogTupleInsert (pg_attribute_rel , tup );
794+ /* start out with empty permissions and empty options */
795+ slot [slotCount ]-> tts_isnull [Anum_pg_attribute_attacl - 1 ] = true;
796+ slot [slotCount ]-> tts_isnull [Anum_pg_attribute_attfdwoptions - 1 ] = true;
797+ slot [slotCount ]-> tts_isnull [Anum_pg_attribute_attmissingval - 1 ] = true;
775798
776- heap_freetuple (tup );
799+ ExecStoreVirtualTuple (slot [slotCount ]);
800+ slotCount ++ ;
801+
802+ /*
803+ * If slots are full or the end of processing has been reached, insert
804+ * a batch of tuples.
805+ */
806+ if (slotCount == nslots || natts == tupdesc -> natts - 1 )
807+ {
808+ /* fetch index info only when we know we need it */
809+ if (!indstate )
810+ {
811+ indstate = CatalogOpenIndexes (pg_attribute_rel );
812+ close_index = true;
813+ }
814+
815+ /* insert the new tuples and update the indexes */
816+ CatalogTuplesMultiInsertWithInfo (pg_attribute_rel , slot , slotCount ,
817+ indstate );
818+ slotCount = 0 ;
819+ }
820+
821+ natts ++ ;
822+ }
823+
824+ if (close_index )
825+ CatalogCloseIndexes (indstate );
826+ for (int i = 0 ; i < nslots ; i ++ )
827+ ExecDropSingleTupleTableSlot (slot [i ]);
828+ pfree (slot );
777829}
778830
779831/* --------------------------------
@@ -788,8 +840,6 @@ AddNewAttributeTuples(Oid new_rel_oid,
788840 TupleDesc tupdesc ,
789841 char relkind )
790842{
791- Form_pg_attribute attr ;
792- int i ;
793843 Relation rel ;
794844 CatalogIndexState indstate ;
795845 int natts = tupdesc -> natts ;
@@ -803,30 +853,26 @@ AddNewAttributeTuples(Oid new_rel_oid,
803853
804854 indstate = CatalogOpenIndexes (rel );
805855
806- /*
807- * First we add the user attributes. This is also a convenient place to
808- * add dependencies on their datatypes and collations.
809- */
810- for (i = 0 ; i < natts ; i ++ )
811- {
812- attr = TupleDescAttr (tupdesc , i );
813- /* Fill in the correct relation OID */
814- attr -> attrelid = new_rel_oid ;
815- /* Make sure this is OK, too */
816- attr -> attstattarget = -1 ;
817-
818- InsertPgAttributeTuple (rel , attr , (Datum ) 0 , indstate );
856+ /* set stats detail level to a sane default */
857+ for (int i = 0 ; i < natts ; i ++ )
858+ tupdesc -> attrs [i ].attstattarget = -1 ;
859+ InsertPgAttributeTuples (rel , tupdesc , new_rel_oid , NULL , indstate );
819860
861+ /* add dependencies on their datatypes and collations */
862+ for (int i = 0 ; i < natts ; i ++ )
863+ {
820864 /* Add dependency info */
821865 ObjectAddressSubSet (myself , RelationRelationId , new_rel_oid , i + 1 );
822- ObjectAddressSet (referenced , TypeRelationId , attr -> atttypid );
866+ ObjectAddressSet (referenced , TypeRelationId ,
867+ tupdesc -> attrs [i ].atttypid );
823868 recordDependencyOn (& myself , & referenced , DEPENDENCY_NORMAL );
824869
825870 /* The default collation is pinned, so don't bother recording it */
826- if (OidIsValid (attr -> attcollation ) &&
827- attr -> attcollation != DEFAULT_COLLATION_OID )
871+ if (OidIsValid (tupdesc -> attrs [ i ]. attcollation ) &&
872+ tupdesc -> attrs [ i ]. attcollation != DEFAULT_COLLATION_OID )
828873 {
829- ObjectAddressSet (referenced , CollationRelationId , attr -> attcollation );
874+ ObjectAddressSet (referenced , CollationRelationId ,
875+ tupdesc -> attrs [i ].attcollation );
830876 recordDependencyOn (& myself , & referenced , DEPENDENCY_NORMAL );
831877 }
832878 }
@@ -838,17 +884,12 @@ AddNewAttributeTuples(Oid new_rel_oid,
838884 */
839885 if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE )
840886 {
841- for (i = 0 ; i < (int ) lengthof (SysAtt ); i ++ )
842- {
843- FormData_pg_attribute attStruct ;
887+ TupleDesc td ;
844888
845- memcpy ( & attStruct , SysAtt [ i ], sizeof (FormData_pg_attribute ) );
889+ td = CreateTupleDesc ( lengthof ( SysAtt ), (FormData_pg_attribute * * ) & SysAtt );
846890
847- /* Fill in the correct relation OID in the copied tuple */
848- attStruct .attrelid = new_rel_oid ;
849-
850- InsertPgAttributeTuple (rel , & attStruct , (Datum ) 0 , indstate );
851- }
891+ InsertPgAttributeTuples (rel , td , new_rel_oid , NULL , indstate );
892+ FreeTupleDesc (td );
852893 }
853894
854895 /*
0 commit comments