@@ -710,70 +710,122 @@ CheckAttributeType(const char *attname,
710
710
}
711
711
712
712
/*
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.
715
721
*
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.
719
726
*
720
727
* indstate is the index state for CatalogTupleInsertWithInfo. It can be
721
728
* passed as NULL, in which case we'll fetch the necessary info. (Don't do
722
729
* this when inserting multiple attributes, because it's a tad more
723
730
* 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.
724
734
*/
725
735
void
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 )
730
741
{
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 );
734
761
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 ]);
738
763
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;
769
793
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;
775
798
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 );
777
829
}
778
830
779
831
/* --------------------------------
@@ -788,8 +840,6 @@ AddNewAttributeTuples(Oid new_rel_oid,
788
840
TupleDesc tupdesc ,
789
841
char relkind )
790
842
{
791
- Form_pg_attribute attr ;
792
- int i ;
793
843
Relation rel ;
794
844
CatalogIndexState indstate ;
795
845
int natts = tupdesc -> natts ;
@@ -803,30 +853,26 @@ AddNewAttributeTuples(Oid new_rel_oid,
803
853
804
854
indstate = CatalogOpenIndexes (rel );
805
855
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 );
819
860
861
+ /* add dependencies on their datatypes and collations */
862
+ for (int i = 0 ; i < natts ; i ++ )
863
+ {
820
864
/* Add dependency info */
821
865
ObjectAddressSubSet (myself , RelationRelationId , new_rel_oid , i + 1 );
822
- ObjectAddressSet (referenced , TypeRelationId , attr -> atttypid );
866
+ ObjectAddressSet (referenced , TypeRelationId ,
867
+ tupdesc -> attrs [i ].atttypid );
823
868
recordDependencyOn (& myself , & referenced , DEPENDENCY_NORMAL );
824
869
825
870
/* 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 )
828
873
{
829
- ObjectAddressSet (referenced , CollationRelationId , attr -> attcollation );
874
+ ObjectAddressSet (referenced , CollationRelationId ,
875
+ tupdesc -> attrs [i ].attcollation );
830
876
recordDependencyOn (& myself , & referenced , DEPENDENCY_NORMAL );
831
877
}
832
878
}
@@ -838,17 +884,12 @@ AddNewAttributeTuples(Oid new_rel_oid,
838
884
*/
839
885
if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE )
840
886
{
841
- for (i = 0 ; i < (int ) lengthof (SysAtt ); i ++ )
842
- {
843
- FormData_pg_attribute attStruct ;
887
+ TupleDesc td ;
844
888
845
- memcpy ( & attStruct , SysAtt [ i ], sizeof (FormData_pg_attribute ) );
889
+ td = CreateTupleDesc ( lengthof ( SysAtt ), (FormData_pg_attribute * * ) & SysAtt );
846
890
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 );
852
893
}
853
894
854
895
/*
0 commit comments