LCOV - code coverage report
Current view: top level - src/backend/catalog - heap.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 917 954 96.1 %
Date: 2019-06-19 14:06:47 Functions: 40 41 97.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * heap.c
       4             :  *    code to create and destroy POSTGRES heap relations
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/catalog/heap.c
      12             :  *
      13             :  *
      14             :  * INTERFACE ROUTINES
      15             :  *      heap_create()           - Create an uncataloged heap relation
      16             :  *      heap_create_with_catalog() - Create a cataloged relation
      17             :  *      heap_drop_with_catalog() - Removes named relation from catalogs
      18             :  *
      19             :  * NOTES
      20             :  *    this code taken from access/heap/create.c, which contains
      21             :  *    the old heap_create_with_catalog, amcreate, and amdestroy.
      22             :  *    those routines will soon call these routines using the function
      23             :  *    manager,
      24             :  *    just like the poorly named "NewXXX" routines do.  The
      25             :  *    "New" routines are all going to die soon, once and for all!
      26             :  *      -cim 1/13/91
      27             :  *
      28             :  *-------------------------------------------------------------------------
      29             :  */
      30             : #include "postgres.h"
      31             : 
      32             : #include "access/genam.h"
      33             : #include "access/htup_details.h"
      34             : #include "access/multixact.h"
      35             : #include "access/relation.h"
      36             : #include "access/sysattr.h"
      37             : #include "access/table.h"
      38             : #include "access/tableam.h"
      39             : #include "access/transam.h"
      40             : #include "access/xact.h"
      41             : #include "access/xlog.h"
      42             : #include "catalog/binary_upgrade.h"
      43             : #include "catalog/catalog.h"
      44             : #include "catalog/dependency.h"
      45             : #include "catalog/heap.h"
      46             : #include "catalog/index.h"
      47             : #include "catalog/objectaccess.h"
      48             : #include "catalog/partition.h"
      49             : #include "catalog/pg_am.h"
      50             : #include "catalog/pg_attrdef.h"
      51             : #include "catalog/pg_collation.h"
      52             : #include "catalog/pg_constraint.h"
      53             : #include "catalog/pg_foreign_table.h"
      54             : #include "catalog/pg_inherits.h"
      55             : #include "catalog/pg_namespace.h"
      56             : #include "catalog/pg_opclass.h"
      57             : #include "catalog/pg_partitioned_table.h"
      58             : #include "catalog/pg_statistic.h"
      59             : #include "catalog/pg_subscription_rel.h"
      60             : #include "catalog/pg_tablespace.h"
      61             : #include "catalog/pg_type.h"
      62             : #include "catalog/storage.h"
      63             : #include "catalog/storage_xlog.h"
      64             : #include "commands/tablecmds.h"
      65             : #include "commands/typecmds.h"
      66             : #include "executor/executor.h"
      67             : #include "miscadmin.h"
      68             : #include "nodes/nodeFuncs.h"
      69             : #include "optimizer/optimizer.h"
      70             : #include "parser/parse_coerce.h"
      71             : #include "parser/parse_collate.h"
      72             : #include "parser/parse_expr.h"
      73             : #include "parser/parse_relation.h"
      74             : #include "parser/parsetree.h"
      75             : #include "partitioning/partdesc.h"
      76             : #include "storage/lmgr.h"
      77             : #include "storage/predicate.h"
      78             : #include "storage/smgr.h"
      79             : #include "utils/acl.h"
      80             : #include "utils/builtins.h"
      81             : #include "utils/datum.h"
      82             : #include "utils/fmgroids.h"
      83             : #include "utils/inval.h"
      84             : #include "utils/lsyscache.h"
      85             : #include "utils/partcache.h"
      86             : #include "utils/rel.h"
      87             : #include "utils/ruleutils.h"
      88             : #include "utils/snapmgr.h"
      89             : #include "utils/syscache.h"
      90             : 
      91             : 
      92             : /* Potentially set by pg_upgrade_support functions */
      93             : Oid         binary_upgrade_next_heap_pg_class_oid = InvalidOid;
      94             : Oid         binary_upgrade_next_toast_pg_class_oid = InvalidOid;
      95             : 
      96             : static void AddNewRelationTuple(Relation pg_class_desc,
      97             :                                 Relation new_rel_desc,
      98             :                                 Oid new_rel_oid,
      99             :                                 Oid new_type_oid,
     100             :                                 Oid reloftype,
     101             :                                 Oid relowner,
     102             :                                 char relkind,
     103             :                                 TransactionId relfrozenxid,
     104             :                                 TransactionId relminmxid,
     105             :                                 Datum relacl,
     106             :                                 Datum reloptions);
     107             : static ObjectAddress AddNewRelationType(const char *typeName,
     108             :                                         Oid typeNamespace,
     109             :                                         Oid new_rel_oid,
     110             :                                         char new_rel_kind,
     111             :                                         Oid ownerid,
     112             :                                         Oid new_row_type,
     113             :                                         Oid new_array_type);
     114             : static void RelationRemoveInheritance(Oid relid);
     115             : static Oid  StoreRelCheck(Relation rel, const char *ccname, Node *expr,
     116             :                           bool is_validated, bool is_local, int inhcount,
     117             :                           bool is_no_inherit, bool is_internal);
     118             : static void StoreConstraints(Relation rel, List *cooked_constraints,
     119             :                              bool is_internal);
     120             : static bool MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr,
     121             :                                         bool allow_merge, bool is_local,
     122             :                                         bool is_initially_valid,
     123             :                                         bool is_no_inherit);
     124             : static void SetRelationNumChecks(Relation rel, int numchecks);
     125             : static Node *cookConstraint(ParseState *pstate,
     126             :                             Node *raw_constraint,
     127             :                             char *relname);
     128             : static List *insert_ordered_unique_oid(List *list, Oid datum);
     129             : 
     130             : 
     131             : /* ----------------------------------------------------------------
     132             :  *              XXX UGLY HARD CODED BADNESS FOLLOWS XXX
     133             :  *
     134             :  *      these should all be moved to someplace in the lib/catalog
     135             :  *      module, if not obliterated first.
     136             :  * ----------------------------------------------------------------
     137             :  */
     138             : 
     139             : 
     140             : /*
     141             :  * Note:
     142             :  *      Should the system special case these attributes in the future?
     143             :  *      Advantage:  consume much less space in the ATTRIBUTE relation.
     144             :  *      Disadvantage:  special cases will be all over the place.
     145             :  */
     146             : 
     147             : /*
     148             :  * The initializers below do not include trailing variable length fields,
     149             :  * but that's OK - we're never going to reference anything beyond the
     150             :  * fixed-size portion of the structure anyway.
     151             :  */
     152             : 
     153             : static const FormData_pg_attribute a1 = {
     154             :     .attname = {"ctid"},
     155             :     .atttypid = TIDOID,
     156             :     .attlen = sizeof(ItemPointerData),
     157             :     .attnum = SelfItemPointerAttributeNumber,
     158             :     .attcacheoff = -1,
     159             :     .atttypmod = -1,
     160             :     .attbyval = false,
     161             :     .attstorage = 'p',
     162             :     .attalign = 's',
     163             :     .attnotnull = true,
     164             :     .attislocal = true,
     165             : };
     166             : 
     167             : static const FormData_pg_attribute a2 = {
     168             :     .attname = {"xmin"},
     169             :     .atttypid = XIDOID,
     170             :     .attlen = sizeof(TransactionId),
     171             :     .attnum = MinTransactionIdAttributeNumber,
     172             :     .attcacheoff = -1,
     173             :     .atttypmod = -1,
     174             :     .attbyval = true,
     175             :     .attstorage = 'p',
     176             :     .attalign = 'i',
     177             :     .attnotnull = true,
     178             :     .attislocal = true,
     179             : };
     180             : 
     181             : static const FormData_pg_attribute a3 = {
     182             :     .attname = {"cmin"},
     183             :     .atttypid = CIDOID,
     184             :     .attlen = sizeof(CommandId),
     185             :     .attnum = MinCommandIdAttributeNumber,
     186             :     .attcacheoff = -1,
     187             :     .atttypmod = -1,
     188             :     .attbyval = true,
     189             :     .attstorage = 'p',
     190             :     .attalign = 'i',
     191             :     .attnotnull = true,
     192             :     .attislocal = true,
     193             : };
     194             : 
     195             : static const FormData_pg_attribute a4 = {
     196             :     .attname = {"xmax"},
     197             :     .atttypid = XIDOID,
     198             :     .attlen = sizeof(TransactionId),
     199             :     .attnum = MaxTransactionIdAttributeNumber,
     200             :     .attcacheoff = -1,
     201             :     .atttypmod = -1,
     202             :     .attbyval = true,
     203             :     .attstorage = 'p',
     204             :     .attalign = 'i',
     205             :     .attnotnull = true,
     206             :     .attislocal = true,
     207             : };
     208             : 
     209             : static const FormData_pg_attribute a5 = {
     210             :     .attname = {"cmax"},
     211             :     .atttypid = CIDOID,
     212             :     .attlen = sizeof(CommandId),
     213             :     .attnum = MaxCommandIdAttributeNumber,
     214             :     .attcacheoff = -1,
     215             :     .atttypmod = -1,
     216             :     .attbyval = true,
     217             :     .attstorage = 'p',
     218             :     .attalign = 'i',
     219             :     .attnotnull = true,
     220             :     .attislocal = true,
     221             : };
     222             : 
     223             : /*
     224             :  * We decided to call this attribute "tableoid" rather than say
     225             :  * "classoid" on the basis that in the future there may be more than one
     226             :  * table of a particular class/type. In any case table is still the word
     227             :  * used in SQL.
     228             :  */
     229             : static const FormData_pg_attribute a6 = {
     230             :     .attname = {"tableoid"},
     231             :     .atttypid = OIDOID,
     232             :     .attlen = sizeof(Oid),
     233             :     .attnum = TableOidAttributeNumber,
     234             :     .attcacheoff = -1,
     235             :     .atttypmod = -1,
     236             :     .attbyval = true,
     237             :     .attstorage = 'p',
     238             :     .attalign = 'i',
     239             :     .attnotnull = true,
     240             :     .attislocal = true,
     241             : };
     242             : 
     243             : static const FormData_pg_attribute *SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6};
     244             : 
     245             : /*
     246             :  * This function returns a Form_pg_attribute pointer for a system attribute.
     247             :  * Note that we elog if the presented attno is invalid, which would only
     248             :  * happen if there's a problem upstream.
     249             :  */
     250             : const FormData_pg_attribute *
     251           0 : SystemAttributeDefinition(AttrNumber attno)
     252             : {
     253           0 :     if (attno >= 0 || attno < -(int) lengthof(SysAtt))
     254           0 :         elog(ERROR, "invalid system attribute number %d", attno);
     255           0 :     return SysAtt[-attno - 1];
     256             : }
     257             : 
     258             : /*
     259             :  * If the given name is a system attribute name, return a Form_pg_attribute
     260             :  * pointer for a prototype definition.  If not, return NULL.
     261             :  */
     262             : const FormData_pg_attribute *
     263      360254 : SystemAttributeByName(const char *attname)
     264             : {
     265             :     int         j;
     266             : 
     267     2457706 :     for (j = 0; j < (int) lengthof(SysAtt); j++)
     268             :     {
     269     2133958 :         const FormData_pg_attribute *att = SysAtt[j];
     270             : 
     271     2133958 :         if (strcmp(NameStr(att->attname), attname) == 0)
     272       36506 :             return att;
     273             :     }
     274             : 
     275      323748 :     return NULL;
     276             : }
     277             : 
     278             : 
     279             : /* ----------------------------------------------------------------
     280             :  *              XXX END OF UGLY HARD CODED BADNESS XXX
     281             :  * ---------------------------------------------------------------- */
     282             : 
     283             : 
     284             : /* ----------------------------------------------------------------
     285             :  *      heap_create     - Create an uncataloged heap relation
     286             :  *
     287             :  *      Note API change: the caller must now always provide the OID
     288             :  *      to use for the relation.  The relfilenode may (and, normally,
     289             :  *      should) be left unspecified.
     290             :  *
     291             :  *      rel->rd_rel is initialized by RelationBuildLocalRelation,
     292             :  *      and is mostly zeroes at return.
     293             :  * ----------------------------------------------------------------
     294             :  */
     295             : Relation
     296      170618 : heap_create(const char *relname,
     297             :             Oid relnamespace,
     298             :             Oid reltablespace,
     299             :             Oid relid,
     300             :             Oid relfilenode,
     301             :             Oid accessmtd,
     302             :             TupleDesc tupDesc,
     303             :             char relkind,
     304             :             char relpersistence,
     305             :             bool shared_relation,
     306             :             bool mapped_relation,
     307             :             bool allow_system_table_mods,
     308             :             TransactionId *relfrozenxid,
     309             :             MultiXactId *relminmxid)
     310             : {
     311             :     bool        create_storage;
     312             :     Relation    rel;
     313             : 
     314             :     /* The caller must have provided an OID for the relation. */
     315             :     Assert(OidIsValid(relid));
     316             : 
     317             :     /*
     318             :      * Don't allow creating relations in pg_catalog directly, even though it
     319             :      * is allowed to move user defined relations there. Semantics with search
     320             :      * paths including pg_catalog are too confusing for now.
     321             :      *
     322             :      * But allow creating indexes on relations in pg_catalog even if
     323             :      * allow_system_table_mods = off, upper layers already guarantee it's on a
     324             :      * user defined relation, not a system one.
     325             :      */
     326      237394 :     if (!allow_system_table_mods &&
     327      170762 :         ((IsCatalogNamespace(relnamespace) && relkind != RELKIND_INDEX) ||
     328       66776 :          IsToastNamespace(relnamespace)) &&
     329           4 :         IsNormalProcessingMode())
     330           4 :         ereport(ERROR,
     331             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     332             :                  errmsg("permission denied to create \"%s.%s\"",
     333             :                         get_namespace_name(relnamespace), relname),
     334             :                  errdetail("System catalog modifications are currently disallowed.")));
     335             : 
     336      170614 :     *relfrozenxid = InvalidTransactionId;
     337      170614 :     *relminmxid = InvalidMultiXactId;
     338             : 
     339             :     /* Handle reltablespace for specific relkinds. */
     340      170614 :     switch (relkind)
     341             :     {
     342             :         case RELKIND_VIEW:
     343             :         case RELKIND_COMPOSITE_TYPE:
     344             :         case RELKIND_FOREIGN_TABLE:
     345             : 
     346             :             /*
     347             :              * Force reltablespace to zero if the relation has no physical
     348             :              * storage.  This is mainly just for cleanliness' sake.
     349             :              *
     350             :              * Partitioned tables and indexes don't have physical storage
     351             :              * either, but we want to keep their tablespace settings so that
     352             :              * their children can inherit it.
     353             :              */
     354       41414 :             reltablespace = InvalidOid;
     355       41414 :             break;
     356             : 
     357             :         case RELKIND_SEQUENCE:
     358             : 
     359             :             /*
     360             :              * Force reltablespace to zero for sequences, since we don't
     361             :              * support moving them around into different tablespaces.
     362             :              */
     363         894 :             reltablespace = InvalidOid;
     364         894 :             break;
     365             :         default:
     366      128306 :             break;
     367             :     }
     368             : 
     369             :     /*
     370             :      * Decide whether to create storage. If caller passed a valid relfilenode,
     371             :      * storage is already created, so don't do it here.  Also don't create it
     372             :      * for relkinds without physical storage.
     373             :      */
     374      170614 :     if (!RELKIND_HAS_STORAGE(relkind) || OidIsValid(relfilenode))
     375       44200 :         create_storage = false;
     376             :     else
     377             :     {
     378      126414 :         create_storage = true;
     379      126414 :         relfilenode = relid;
     380             :     }
     381             : 
     382             :     /*
     383             :      * Never allow a pg_class entry to explicitly specify the database's
     384             :      * default tablespace in reltablespace; force it to zero instead. This
     385             :      * ensures that if the database is cloned with a different default
     386             :      * tablespace, the pg_class entry will still match where CREATE DATABASE
     387             :      * will put the physically copied relation.
     388             :      *
     389             :      * Yes, this is a bit of a hack.
     390             :      */
     391      170614 :     if (reltablespace == MyDatabaseTableSpace)
     392          18 :         reltablespace = InvalidOid;
     393             : 
     394             :     /*
     395             :      * build the relcache entry.
     396             :      */
     397      170614 :     rel = RelationBuildLocalRelation(relname,
     398             :                                      relnamespace,
     399             :                                      tupDesc,
     400             :                                      relid,
     401             :                                      accessmtd,
     402             :                                      relfilenode,
     403             :                                      reltablespace,
     404             :                                      shared_relation,
     405             :                                      mapped_relation,
     406             :                                      relpersistence,
     407             :                                      relkind);
     408             : 
     409             :     /*
     410             :      * Have the storage manager create the relation's disk file, if needed.
     411             :      *
     412             :      * For relations the callback creates both the main and the init fork, for
     413             :      * indexes only the main fork is created. The other forks will be created
     414             :      * on demand.
     415             :      */
     416      170614 :     if (create_storage)
     417             :     {
     418      126414 :         RelationOpenSmgr(rel);
     419             : 
     420      126414 :         switch (rel->rd_rel->relkind)
     421             :         {
     422             :             case RELKIND_VIEW:
     423             :             case RELKIND_COMPOSITE_TYPE:
     424             :             case RELKIND_FOREIGN_TABLE:
     425             :             case RELKIND_PARTITIONED_TABLE:
     426             :             case RELKIND_PARTITIONED_INDEX:
     427             :                 Assert(false);
     428           0 :                 break;
     429             : 
     430             :             case RELKIND_INDEX:
     431             :             case RELKIND_SEQUENCE:
     432       66076 :                 RelationCreateStorage(rel->rd_node, relpersistence);
     433       66076 :                 break;
     434             : 
     435             :             case RELKIND_RELATION:
     436             :             case RELKIND_TOASTVALUE:
     437             :             case RELKIND_MATVIEW:
     438       60338 :                 table_relation_set_new_filenode(rel, &rel->rd_node,
     439             :                                                 relpersistence,
     440             :                                                 relfrozenxid, relminmxid);
     441       60338 :                 break;
     442             :         }
     443             :     }
     444             : 
     445      170614 :     return rel;
     446             : }
     447             : 
     448             : /* ----------------------------------------------------------------
     449             :  *      heap_create_with_catalog        - Create a cataloged relation
     450             :  *
     451             :  *      this is done in multiple steps:
     452             :  *
     453             :  *      1) CheckAttributeNamesTypes() is used to make certain the tuple
     454             :  *         descriptor contains a valid set of attribute names and types
     455             :  *
     456             :  *      2) pg_class is opened and get_relname_relid()
     457             :  *         performs a scan to ensure that no relation with the
     458             :  *         same name already exists.
     459             :  *
     460             :  *      3) heap_create() is called to create the new relation on disk.
     461             :  *
     462             :  *      4) TypeCreate() is called to define a new type corresponding
     463             :  *         to the new relation.
     464             :  *
     465             :  *      5) AddNewRelationTuple() is called to register the
     466             :  *         relation in pg_class.
     467             :  *
     468             :  *      6) AddNewAttributeTuples() is called to register the
     469             :  *         new relation's schema in pg_attribute.
     470             :  *
     471             :  *      7) StoreConstraints is called ()        - vadim 08/22/97
     472             :  *
     473             :  *      8) the relations are closed and the new relation's oid
     474             :  *         is returned.
     475             :  *
     476             :  * ----------------------------------------------------------------
     477             :  */
     478             : 
     479             : /* --------------------------------
     480             :  *      CheckAttributeNamesTypes
     481             :  *
     482             :  *      this is used to make certain the tuple descriptor contains a
     483             :  *      valid set of attribute names and datatypes.  a problem simply
     484             :  *      generates ereport(ERROR) which aborts the current transaction.
     485             :  *
     486             :  *      relkind is the relkind of the relation to be created.
     487             :  *      flags controls which datatypes are allowed, cf CheckAttributeType.
     488             :  * --------------------------------
     489             :  */
     490             : void
     491      104002 : CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
     492             :                          int flags)
     493             : {
     494             :     int         i;
     495             :     int         j;
     496      104002 :     int         natts = tupdesc->natts;
     497             : 
     498             :     /* Sanity check on column count */
     499      104002 :     if (natts < 0 || natts > MaxHeapAttributeNumber)
     500           0 :         ereport(ERROR,
     501             :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
     502             :                  errmsg("tables can have at most %d columns",
     503             :                         MaxHeapAttributeNumber)));
     504             : 
     505             :     /*
     506             :      * first check for collision with system attribute names
     507             :      *
     508             :      * Skip this for a view or type relation, since those don't have system
     509             :      * attributes.
     510             :      */
     511      104002 :     if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
     512             :     {
     513      331882 :         for (i = 0; i < natts; i++)
     514             :         {
     515      269560 :             Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
     516             : 
     517      269560 :             if (SystemAttributeByName(NameStr(attr->attname)) != NULL)
     518           0 :                 ereport(ERROR,
     519             :                         (errcode(ERRCODE_DUPLICATE_COLUMN),
     520             :                          errmsg("column name \"%s\" conflicts with a system column name",
     521             :                                 NameStr(attr->attname))));
     522             :         }
     523             :     }
     524             : 
     525             :     /*
     526             :      * next check for repeated attribute names
     527             :      */
     528      667426 :     for (i = 1; i < natts; i++)
     529             :     {
     530     8634426 :         for (j = 0; j < i; j++)
     531             :         {
     532     8071002 :             if (strcmp(NameStr(TupleDescAttr(tupdesc, j)->attname),
     533     8071002 :                        NameStr(TupleDescAttr(tupdesc, i)->attname)) == 0)
     534           0 :                 ereport(ERROR,
     535             :                         (errcode(ERRCODE_DUPLICATE_COLUMN),
     536             :                          errmsg("column name \"%s\" specified more than once",
     537             :                                 NameStr(TupleDescAttr(tupdesc, j)->attname))));
     538             :         }
     539             :     }
     540             : 
     541             :     /*
     542             :      * next check the attribute types
     543             :      */
     544      771198 :     for (i = 0; i < natts; i++)
     545             :     {
     546      667204 :         CheckAttributeType(NameStr(TupleDescAttr(tupdesc, i)->attname),
     547             :                            TupleDescAttr(tupdesc, i)->atttypid,
     548             :                            TupleDescAttr(tupdesc, i)->attcollation,
     549             :                            NIL, /* assume we're creating a new rowtype */
     550             :                            flags);
     551             :     }
     552      103994 : }
     553             : 
     554             : /* --------------------------------
     555             :  *      CheckAttributeType
     556             :  *
     557             :  *      Verify that the proposed datatype of an attribute is legal.
     558             :  *      This is needed mainly because there are types (and pseudo-types)
     559             :  *      in the catalogs that we do not support as elements of real tuples.
     560             :  *      We also check some other properties required of a table column.
     561             :  *
     562             :  * If the attribute is being proposed for addition to an existing table or
     563             :  * composite type, pass a one-element list of the rowtype OID as
     564             :  * containing_rowtypes.  When checking a to-be-created rowtype, it's
     565             :  * sufficient to pass NIL, because there could not be any recursive reference
     566             :  * to a not-yet-existing rowtype.
     567             :  *
     568             :  * flags is a bitmask controlling which datatypes we allow.  For the most
     569             :  * part, pseudo-types are disallowed as attribute types, but there are some
     570             :  * exceptions: ANYARRAYOID, RECORDOID, and RECORDARRAYOID can be allowed
     571             :  * in some cases.  (This works because values of those type classes are
     572             :  * self-identifying to some extent.  However, RECORDOID and RECORDARRAYOID
     573             :  * are reliably identifiable only within a session, since the identity info
     574             :  * may use a typmod that is only locally assigned.  The caller is expected
     575             :  * to know whether these cases are safe.)
     576             :  * --------------------------------
     577             :  */
     578             : void
     579      905112 : CheckAttributeType(const char *attname,
     580             :                    Oid atttypid, Oid attcollation,
     581             :                    List *containing_rowtypes,
     582             :                    int flags)
     583             : {
     584      905112 :     char        att_typtype = get_typtype(atttypid);
     585             :     Oid         att_typelem;
     586             : 
     587      905112 :     if (att_typtype == TYPTYPE_PSEUDO)
     588             :     {
     589             :         /*
     590             :          * We disallow pseudo-type columns, with the exception of ANYARRAY,
     591             :          * RECORD, and RECORD[] when the caller says that those are OK.
     592             :          *
     593             :          * We don't need to worry about recursive containment for RECORD and
     594             :          * RECORD[] because (a) no named composite type should be allowed to
     595             :          * contain those, and (b) two "anonymous" record types couldn't be
     596             :          * considered to be the same type, so infinite recursion isn't
     597             :          * possible.
     598             :          */
     599        2588 :         if (!((atttypid == ANYARRAYOID && (flags & CHKATYPE_ANYARRAY)) ||
     600           8 :               (atttypid == RECORDOID && (flags & CHKATYPE_ANYRECORD)) ||
     601           4 :               (atttypid == RECORDARRAYOID && (flags & CHKATYPE_ANYRECORD))))
     602           8 :             ereport(ERROR,
     603             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     604             :                      errmsg("column \"%s\" has pseudo-type %s",
     605             :                             attname, format_type_be(atttypid))));
     606             :     }
     607      902536 :     else if (att_typtype == TYPTYPE_DOMAIN)
     608             :     {
     609             :         /*
     610             :          * If it's a domain, recurse to check its base type.
     611             :          */
     612      212176 :         CheckAttributeType(attname, getBaseType(atttypid), attcollation,
     613             :                            containing_rowtypes,
     614             :                            flags);
     615             :     }
     616      690360 :     else if (att_typtype == TYPTYPE_COMPOSITE)
     617             :     {
     618             :         /*
     619             :          * For a composite type, recurse into its attributes.
     620             :          */
     621             :         Relation    relation;
     622             :         TupleDesc   tupdesc;
     623             :         int         i;
     624             : 
     625             :         /*
     626             :          * Check for self-containment.  Eventually we might be able to allow
     627             :          * this (just return without complaint, if so) but it's not clear how
     628             :          * many other places would require anti-recursion defenses before it
     629             :          * would be safe to allow tables to contain their own rowtype.
     630             :          */
     631         352 :         if (list_member_oid(containing_rowtypes, atttypid))
     632          20 :             ereport(ERROR,
     633             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     634             :                      errmsg("composite type %s cannot be made a member of itself",
     635             :                             format_type_be(atttypid))));
     636             : 
     637         332 :         containing_rowtypes = lcons_oid(atttypid, containing_rowtypes);
     638             : 
     639         332 :         relation = relation_open(get_typ_typrelid(atttypid), AccessShareLock);
     640             : 
     641         332 :         tupdesc = RelationGetDescr(relation);
     642             : 
     643        1082 :         for (i = 0; i < tupdesc->natts; i++)
     644             :         {
     645         758 :             Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
     646             : 
     647         758 :             if (attr->attisdropped)
     648           2 :                 continue;
     649         756 :             CheckAttributeType(NameStr(attr->attname),
     650             :                                attr->atttypid, attr->attcollation,
     651             :                                containing_rowtypes,
     652             :                                flags);
     653             :         }
     654             : 
     655         324 :         relation_close(relation, AccessShareLock);
     656             : 
     657         324 :         containing_rowtypes = list_delete_first(containing_rowtypes);
     658             :     }
     659      690008 :     else if (OidIsValid((att_typelem = get_element_type(atttypid))))
     660             :     {
     661             :         /*
     662             :          * Must recurse into array types, too, in case they are composite.
     663             :          */
     664       22694 :         CheckAttributeType(attname, att_typelem, attcollation,
     665             :                            containing_rowtypes,
     666             :                            flags);
     667             :     }
     668             : 
     669             :     /*
     670             :      * This might not be strictly invalid per SQL standard, but it is pretty
     671             :      * useless, and it cannot be dumped, so we must disallow it.
     672             :      */
     673      905064 :     if (!OidIsValid(attcollation) && type_is_collatable(atttypid))
     674           0 :         ereport(ERROR,
     675             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     676             :                  errmsg("no collation was derived for column \"%s\" with collatable type %s",
     677             :                         attname, format_type_be(atttypid)),
     678             :                  errhint("Use the COLLATE clause to set the collation explicitly.")));
     679      905064 : }
     680             : 
     681             : /*
     682             :  * InsertPgAttributeTuple
     683             :  *      Construct and insert a new tuple in pg_attribute.
     684             :  *
     685             :  * Caller has already opened and locked pg_attribute.  new_attribute is the
     686             :  * attribute to insert.  attcacheoff is always initialized to -1, attacl and
     687             :  * attoptions are always initialized to NULL.
     688             :  *
     689             :  * indstate is the index state for CatalogTupleInsertWithInfo.  It can be
     690             :  * passed as NULL, in which case we'll fetch the necessary info.  (Don't do
     691             :  * this when inserting multiple attributes, because it's a tad more
     692             :  * expensive.)
     693             :  */
     694             : void
     695     1153562 : InsertPgAttributeTuple(Relation pg_attribute_rel,
     696             :                        Form_pg_attribute new_attribute,
     697             :                        CatalogIndexState indstate)
     698             : {
     699             :     Datum       values[Natts_pg_attribute];
     700             :     bool        nulls[Natts_pg_attribute];
     701             :     HeapTuple   tup;
     702             : 
     703             :     /* This is a tad tedious, but way cleaner than what we used to do... */
     704     1153562 :     memset(values, 0, sizeof(values));
     705     1153562 :     memset(nulls, false, sizeof(nulls));
     706             : 
     707     1153562 :     values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_attribute->attrelid);
     708     1153562 :     values[Anum_pg_attribute_attname - 1] = NameGetDatum(&new_attribute->attname);
     709     1153562 :     values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(new_attribute->atttypid);
     710     1153562 :     values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(new_attribute->attstattarget);
     711     1153562 :     values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(new_attribute->attlen);
     712     1153562 :     values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(new_attribute->attnum);
     713     1153562 :     values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(new_attribute->attndims);
     714     1153562 :     values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
     715     1153562 :     values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(new_attribute->atttypmod);
     716     1153562 :     values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(new_attribute->attbyval);
     717     1153562 :     values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(new_attribute->attstorage);
     718     1153562 :     values[Anum_pg_attribute_attalign - 1] = CharGetDatum(new_attribute->attalign);
     719     1153562 :     values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(new_attribute->attnotnull);
     720     1153562 :     values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(new_attribute->atthasdef);
     721     1153562 :     values[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(new_attribute->atthasmissing);
     722     1153562 :     values[Anum_pg_attribute_attidentity - 1] = CharGetDatum(new_attribute->attidentity);
     723     1153562 :     values[Anum_pg_attribute_attgenerated - 1] = CharGetDatum(new_attribute->attgenerated);
     724     1153562 :     values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(new_attribute->attisdropped);
     725     1153562 :     values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(new_attribute->attislocal);
     726     1153562 :     values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(new_attribute->attinhcount);
     727     1153562 :     values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(new_attribute->attcollation);
     728             : 
     729             :     /* start out with empty permissions and empty options */
     730     1153562 :     nulls[Anum_pg_attribute_attacl - 1] = true;
     731     1153562 :     nulls[Anum_pg_attribute_attoptions - 1] = true;
     732     1153562 :     nulls[Anum_pg_attribute_attfdwoptions - 1] = true;
     733     1153562 :     nulls[Anum_pg_attribute_attmissingval - 1] = true;
     734             : 
     735     1153562 :     tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls);
     736             : 
     737             :     /* finally insert the new tuple, update the indexes, and clean up */
     738     1153562 :     if (indstate != NULL)
     739     1152200 :         CatalogTupleInsertWithInfo(pg_attribute_rel, tup, indstate);
     740             :     else
     741        1362 :         CatalogTupleInsert(pg_attribute_rel, tup);
     742             : 
     743     1153562 :     heap_freetuple(tup);
     744     1153562 : }
     745             : 
     746             : /* --------------------------------
     747             :  *      AddNewAttributeTuples
     748             :  *
     749             :  *      this registers the new relation's schema by adding
     750             :  *      tuples to pg_attribute.
     751             :  * --------------------------------
     752             :  */
     753             : static void
     754      103482 : AddNewAttributeTuples(Oid new_rel_oid,
     755             :                       TupleDesc tupdesc,
     756             :                       char relkind)
     757             : {
     758             :     Form_pg_attribute attr;
     759             :     int         i;
     760             :     Relation    rel;
     761             :     CatalogIndexState indstate;
     762      103482 :     int         natts = tupdesc->natts;
     763             :     ObjectAddress myself,
     764             :                 referenced;
     765             : 
     766             :     /*
     767             :      * open pg_attribute and its indexes.
     768             :      */
     769      103482 :     rel = table_open(AttributeRelationId, RowExclusiveLock);
     770             : 
     771      103482 :     indstate = CatalogOpenIndexes(rel);
     772             : 
     773             :     /*
     774             :      * First we add the user attributes.  This is also a convenient place to
     775             :      * add dependencies on their datatypes and collations.
     776             :      */
     777      769310 :     for (i = 0; i < natts; i++)
     778             :     {
     779      665828 :         attr = TupleDescAttr(tupdesc, i);
     780             :         /* Fill in the correct relation OID */
     781      665828 :         attr->attrelid = new_rel_oid;
     782             :         /* Make sure this is OK, too */
     783      665828 :         attr->attstattarget = -1;
     784             : 
     785      665828 :         InsertPgAttributeTuple(rel, attr, indstate);
     786             : 
     787             :         /* Add dependency info */
     788      665828 :         myself.classId = RelationRelationId;
     789      665828 :         myself.objectId = new_rel_oid;
     790      665828 :         myself.objectSubId = i + 1;
     791      665828 :         referenced.classId = TypeRelationId;
     792      665828 :         referenced.objectId = attr->atttypid;
     793      665828 :         referenced.objectSubId = 0;
     794      665828 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     795             : 
     796             :         /* The default collation is pinned, so don't bother recording it */
     797      955764 :         if (OidIsValid(attr->attcollation) &&
     798      289936 :             attr->attcollation != DEFAULT_COLLATION_OID)
     799             :         {
     800      253460 :             referenced.classId = CollationRelationId;
     801      253460 :             referenced.objectId = attr->attcollation;
     802      253460 :             referenced.objectSubId = 0;
     803      253460 :             recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     804             :         }
     805             :     }
     806             : 
     807             :     /*
     808             :      * Next we add the system attributes.  Skip OID if rel has no OIDs. Skip
     809             :      * all for a view or type relation.  We don't bother with making datatype
     810             :      * dependencies here, since presumably all these types are pinned.
     811             :      */
     812      103482 :     if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
     813             :     {
     814      436100 :         for (i = 0; i < (int) lengthof(SysAtt); i++)
     815             :         {
     816             :             FormData_pg_attribute attStruct;
     817             : 
     818      373800 :             memcpy(&attStruct, SysAtt[i], sizeof(FormData_pg_attribute));
     819             : 
     820             :             /* Fill in the correct relation OID in the copied tuple */
     821      373800 :             attStruct.attrelid = new_rel_oid;
     822             : 
     823      373800 :             InsertPgAttributeTuple(rel, &attStruct, indstate);
     824             :         }
     825             :     }
     826             : 
     827             :     /*
     828             :      * clean up
     829             :      */
     830      103482 :     CatalogCloseIndexes(indstate);
     831             : 
     832      103482 :     table_close(rel, RowExclusiveLock);
     833      103482 : }
     834             : 
     835             : /* --------------------------------
     836             :  *      InsertPgClassTuple
     837             :  *
     838             :  *      Construct and insert a new tuple in pg_class.
     839             :  *
     840             :  * Caller has already opened and locked pg_class.
     841             :  * Tuple data is taken from new_rel_desc->rd_rel, except for the
     842             :  * variable-width fields which are not present in a cached reldesc.
     843             :  * relacl and reloptions are passed in Datum form (to avoid having
     844             :  * to reference the data types in heap.h).  Pass (Datum) 0 to set them
     845             :  * to NULL.
     846             :  * --------------------------------
     847             :  */
     848             : void
     849      169342 : InsertPgClassTuple(Relation pg_class_desc,
     850             :                    Relation new_rel_desc,
     851             :                    Oid new_rel_oid,
     852             :                    Datum relacl,
     853             :                    Datum reloptions)
     854             : {
     855      169342 :     Form_pg_class rd_rel = new_rel_desc->rd_rel;
     856             :     Datum       values[Natts_pg_class];
     857             :     bool        nulls[Natts_pg_class];
     858             :     HeapTuple   tup;
     859             : 
     860             :     /* This is a tad tedious, but way cleaner than what we used to do... */
     861      169342 :     memset(values, 0, sizeof(values));
     862      169342 :     memset(nulls, false, sizeof(nulls));
     863             : 
     864      169342 :     values[Anum_pg_class_oid - 1] = ObjectIdGetDatum(new_rel_oid);
     865      169342 :     values[Anum_pg_class_relname - 1] = NameGetDatum(&rd_rel->relname);
     866      169342 :     values[Anum_pg_class_relnamespace - 1] = ObjectIdGetDatum(rd_rel->relnamespace);
     867      169342 :     values[Anum_pg_class_reltype - 1] = ObjectIdGetDatum(rd_rel->reltype);
     868      169342 :     values[Anum_pg_class_reloftype - 1] = ObjectIdGetDatum(rd_rel->reloftype);
     869      169342 :     values[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(rd_rel->relowner);
     870      169342 :     values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(rd_rel->relam);
     871      169342 :     values[Anum_pg_class_relfilenode - 1] = ObjectIdGetDatum(rd_rel->relfilenode);
     872      169342 :     values[Anum_pg_class_reltablespace - 1] = ObjectIdGetDatum(rd_rel->reltablespace);
     873      169342 :     values[Anum_pg_class_relpages - 1] = Int32GetDatum(rd_rel->relpages);
     874      169342 :     values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples);
     875      169342 :     values[Anum_pg_class_relallvisible - 1] = Int32GetDatum(rd_rel->relallvisible);
     876      169342 :     values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid);
     877      169342 :     values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
     878      169342 :     values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
     879      169342 :     values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence);
     880      169342 :     values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind);
     881      169342 :     values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts);
     882      169342 :     values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks);
     883      169342 :     values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules);
     884      169342 :     values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers);
     885      169342 :     values[Anum_pg_class_relrowsecurity - 1] = BoolGetDatum(rd_rel->relrowsecurity);
     886      169342 :     values[Anum_pg_class_relforcerowsecurity - 1] = BoolGetDatum(rd_rel->relforcerowsecurity);
     887      169342 :     values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
     888      169342 :     values[Anum_pg_class_relispopulated - 1] = BoolGetDatum(rd_rel->relispopulated);
     889      169342 :     values[Anum_pg_class_relreplident - 1] = CharGetDatum(rd_rel->relreplident);
     890      169342 :     values[Anum_pg_class_relispartition - 1] = BoolGetDatum(rd_rel->relispartition);
     891      169342 :     values[Anum_pg_class_relrewrite - 1] = ObjectIdGetDatum(rd_rel->relrewrite);
     892      169342 :     values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
     893      169342 :     values[Anum_pg_class_relminmxid - 1] = MultiXactIdGetDatum(rd_rel->relminmxid);
     894      169342 :     if (relacl != (Datum) 0)
     895          52 :         values[Anum_pg_class_relacl - 1] = relacl;
     896             :     else
     897      169290 :         nulls[Anum_pg_class_relacl - 1] = true;
     898      169342 :     if (reloptions != (Datum) 0)
     899        1058 :         values[Anum_pg_class_reloptions - 1] = reloptions;
     900             :     else
     901      168284 :         nulls[Anum_pg_class_reloptions - 1] = true;
     902             : 
     903             :     /* relpartbound is set by updating this tuple, if necessary */
     904      169342 :     nulls[Anum_pg_class_relpartbound - 1] = true;
     905             : 
     906      169342 :     tup = heap_form_tuple(RelationGetDescr(pg_class_desc), values, nulls);
     907             : 
     908             :     /* finally insert the new tuple, update the indexes, and clean up */
     909      169342 :     CatalogTupleInsert(pg_class_desc, tup);
     910             : 
     911      169342 :     heap_freetuple(tup);
     912      169342 : }
     913             : 
     914             : /* --------------------------------
     915             :  *      AddNewRelationTuple
     916             :  *
     917             :  *      this registers the new relation in the catalogs by
     918             :  *      adding a tuple to pg_class.
     919             :  * --------------------------------
     920             :  */
     921             : static void
     922      103482 : AddNewRelationTuple(Relation pg_class_desc,
     923             :                     Relation new_rel_desc,
     924             :                     Oid new_rel_oid,
     925             :                     Oid new_type_oid,
     926             :                     Oid reloftype,
     927             :                     Oid relowner,
     928             :                     char relkind,
     929             :                     TransactionId relfrozenxid,
     930             :                     TransactionId relminmxid,
     931             :                     Datum relacl,
     932             :                     Datum reloptions)
     933             : {
     934             :     Form_pg_class new_rel_reltup;
     935             : 
     936             :     /*
     937             :      * first we update some of the information in our uncataloged relation's
     938             :      * relation descriptor.
     939             :      */
     940      103482 :     new_rel_reltup = new_rel_desc->rd_rel;
     941             : 
     942      103482 :     switch (relkind)
     943             :     {
     944             :         case RELKIND_RELATION:
     945             :         case RELKIND_MATVIEW:
     946             :         case RELKIND_INDEX:
     947             :         case RELKIND_TOASTVALUE:
     948             :             /* The relation is real, but as yet empty */
     949       59066 :             new_rel_reltup->relpages = 0;
     950       59066 :             new_rel_reltup->reltuples = 0;
     951       59066 :             new_rel_reltup->relallvisible = 0;
     952       59066 :             break;
     953             :         case RELKIND_SEQUENCE:
     954             :             /* Sequences always have a known size */
     955         894 :             new_rel_reltup->relpages = 1;
     956         894 :             new_rel_reltup->reltuples = 1;
     957         894 :             new_rel_reltup->relallvisible = 0;
     958         894 :             break;
     959             :         default:
     960             :             /* Views, etc, have no disk storage */
     961       43522 :             new_rel_reltup->relpages = 0;
     962       43522 :             new_rel_reltup->reltuples = 0;
     963       43522 :             new_rel_reltup->relallvisible = 0;
     964       43522 :             break;
     965             :     }
     966             : 
     967      103482 :     new_rel_reltup->relfrozenxid = relfrozenxid;
     968      103482 :     new_rel_reltup->relminmxid = relminmxid;
     969      103482 :     new_rel_reltup->relowner = relowner;
     970      103482 :     new_rel_reltup->reltype = new_type_oid;
     971      103482 :     new_rel_reltup->reloftype = reloftype;
     972             : 
     973             :     /* relispartition is always set by updating this tuple later */
     974      103482 :     new_rel_reltup->relispartition = false;
     975             : 
     976      103482 :     new_rel_desc->rd_att->tdtypeid = new_type_oid;
     977             : 
     978             :     /* Now build and insert the tuple */
     979      103482 :     InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
     980             :                        relacl, reloptions);
     981      103482 : }
     982             : 
     983             : 
     984             : /* --------------------------------
     985             :  *      AddNewRelationType -
     986             :  *
     987             :  *      define a composite type corresponding to the new relation
     988             :  * --------------------------------
     989             :  */
     990             : static ObjectAddress
     991      103482 : AddNewRelationType(const char *typeName,
     992             :                    Oid typeNamespace,
     993             :                    Oid new_rel_oid,
     994             :                    char new_rel_kind,
     995             :                    Oid ownerid,
     996             :                    Oid new_row_type,
     997             :                    Oid new_array_type)
     998             : {
     999             :     return
    1000      103482 :         TypeCreate(new_row_type,    /* optional predetermined OID */
    1001             :                    typeName,    /* type name */
    1002             :                    typeNamespace,   /* type namespace */
    1003             :                    new_rel_oid, /* relation oid */
    1004             :                    new_rel_kind,    /* relation kind */
    1005             :                    ownerid,     /* owner's ID */
    1006             :                    -1,          /* internal size (varlena) */
    1007             :                    TYPTYPE_COMPOSITE,   /* type-type (composite) */
    1008             :                    TYPCATEGORY_COMPOSITE,   /* type-category (ditto) */
    1009             :                    false,       /* composite types are never preferred */
    1010             :                    DEFAULT_TYPDELIM,    /* default array delimiter */
    1011             :                    F_RECORD_IN, /* input procedure */
    1012             :                    F_RECORD_OUT,    /* output procedure */
    1013             :                    F_RECORD_RECV,   /* receive procedure */
    1014             :                    F_RECORD_SEND,   /* send procedure */
    1015             :                    InvalidOid,  /* typmodin procedure - none */
    1016             :                    InvalidOid,  /* typmodout procedure - none */
    1017             :                    InvalidOid,  /* analyze procedure - default */
    1018             :                    InvalidOid,  /* array element type - irrelevant */
    1019             :                    false,       /* this is not an array type */
    1020             :                    new_array_type,  /* array type if any */
    1021             :                    InvalidOid,  /* domain base type - irrelevant */
    1022             :                    NULL,        /* default value - none */
    1023             :                    NULL,        /* default binary representation */
    1024             :                    false,       /* passed by reference */
    1025             :                    'd',         /* alignment - must be the largest! */
    1026             :                    'x',         /* fully TOASTable */
    1027             :                    -1,          /* typmod */
    1028             :                    0,           /* array dimensions for typBaseType */
    1029             :                    false,       /* Type NOT NULL */
    1030             :                    InvalidOid); /* rowtypes never have a collation */
    1031             : }
    1032             : 
    1033             : /* --------------------------------
    1034             :  *      heap_create_with_catalog
    1035             :  *
    1036             :  *      creates a new cataloged relation.  see comments above.
    1037             :  *
    1038             :  * Arguments:
    1039             :  *  relname: name to give to new rel
    1040             :  *  relnamespace: OID of namespace it goes in
    1041             :  *  reltablespace: OID of tablespace it goes in
    1042             :  *  relid: OID to assign to new rel, or InvalidOid to select a new OID
    1043             :  *  reltypeid: OID to assign to rel's rowtype, or InvalidOid to select one
    1044             :  *  reloftypeid: if a typed table, OID of underlying type; else InvalidOid
    1045             :  *  ownerid: OID of new rel's owner
    1046             :  *  tupdesc: tuple descriptor (source of column definitions)
    1047             :  *  cooked_constraints: list of precooked check constraints and defaults
    1048             :  *  relkind: relkind for new rel
    1049             :  *  relpersistence: rel's persistence status (permanent, temp, or unlogged)
    1050             :  *  shared_relation: true if it's to be a shared relation
    1051             :  *  mapped_relation: true if the relation will use the relfilenode map
    1052             :  *  oncommit: ON COMMIT marking (only relevant if it's a temp table)
    1053             :  *  reloptions: reloptions in Datum form, or (Datum) 0 if none
    1054             :  *  use_user_acl: true if should look for user-defined default permissions;
    1055             :  *      if false, relacl is always set NULL
    1056             :  *  allow_system_table_mods: true to allow creation in system namespaces
    1057             :  *  is_internal: is this a system-generated catalog?
    1058             :  *
    1059             :  * Output parameters:
    1060             :  *  typaddress: if not null, gets the object address of the new pg_type entry
    1061             :  *
    1062             :  * Returns the OID of the new relation
    1063             :  * --------------------------------
    1064             :  */
    1065             : Oid
    1066      103508 : heap_create_with_catalog(const char *relname,
    1067             :                          Oid relnamespace,
    1068             :                          Oid reltablespace,
    1069             :                          Oid relid,
    1070             :                          Oid reltypeid,
    1071             :                          Oid reloftypeid,
    1072             :                          Oid ownerid,
    1073             :                          Oid accessmtd,
    1074             :                          TupleDesc tupdesc,
    1075             :                          List *cooked_constraints,
    1076             :                          char relkind,
    1077             :                          char relpersistence,
    1078             :                          bool shared_relation,
    1079             :                          bool mapped_relation,
    1080             :                          OnCommitAction oncommit,
    1081             :                          Datum reloptions,
    1082             :                          bool use_user_acl,
    1083             :                          bool allow_system_table_mods,
    1084             :                          bool is_internal,
    1085             :                          Oid relrewrite,
    1086             :                          ObjectAddress *typaddress)
    1087             : {
    1088             :     Relation    pg_class_desc;
    1089             :     Relation    new_rel_desc;
    1090             :     Acl        *relacl;
    1091             :     Oid         existing_relid;
    1092             :     Oid         old_type_oid;
    1093             :     Oid         new_type_oid;
    1094             :     ObjectAddress new_type_addr;
    1095      103508 :     Oid         new_array_oid = InvalidOid;
    1096             :     TransactionId relfrozenxid;
    1097             :     MultiXactId relminmxid;
    1098             : 
    1099      103508 :     pg_class_desc = table_open(RelationRelationId, RowExclusiveLock);
    1100             : 
    1101             :     /*
    1102             :      * sanity checks
    1103             :      */
    1104             :     Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode());
    1105             : 
    1106             :     /*
    1107             :      * Validate proposed tupdesc for the desired relkind.  If
    1108             :      * allow_system_table_mods is on, allow ANYARRAY to be used; this is a
    1109             :      * hack to allow creating pg_statistic and cloning it during VACUUM FULL.
    1110             :      */
    1111      103508 :     CheckAttributeNamesTypes(tupdesc, relkind,
    1112             :                              allow_system_table_mods ? CHKATYPE_ANYARRAY : 0);
    1113             : 
    1114             :     /*
    1115             :      * This would fail later on anyway, if the relation already exists.  But
    1116             :      * by catching it here we can emit a nicer error message.
    1117             :      */
    1118      103500 :     existing_relid = get_relname_relid(relname, relnamespace);
    1119      103500 :     if (existing_relid != InvalidOid)
    1120          14 :         ereport(ERROR,
    1121             :                 (errcode(ERRCODE_DUPLICATE_TABLE),
    1122             :                  errmsg("relation \"%s\" already exists", relname)));
    1123             : 
    1124             :     /*
    1125             :      * Since we are going to create a rowtype as well, also check for
    1126             :      * collision with an existing type name.  If there is one and it's an
    1127             :      * autogenerated array, we can rename it out of the way; otherwise we can
    1128             :      * at least give a good error message.
    1129             :      */
    1130      103486 :     old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
    1131             :                                    CStringGetDatum(relname),
    1132             :                                    ObjectIdGetDatum(relnamespace));
    1133      103486 :     if (OidIsValid(old_type_oid))
    1134             :     {
    1135           2 :         if (!moveArrayTypeName(old_type_oid, relname, relnamespace))
    1136           0 :             ereport(ERROR,
    1137             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    1138             :                      errmsg("type \"%s\" already exists", relname),
    1139             :                      errhint("A relation has an associated type of the same name, "
    1140             :                              "so you must use a name that doesn't conflict "
    1141             :                              "with any existing type.")));
    1142             :     }
    1143             : 
    1144             :     /*
    1145             :      * Shared relations must be in pg_global (last-ditch check)
    1146             :      */
    1147      103486 :     if (shared_relation && reltablespace != GLOBALTABLESPACE_OID)
    1148           0 :         elog(ERROR, "shared relations must be placed in pg_global tablespace");
    1149             : 
    1150             :     /*
    1151             :      * Allocate an OID for the relation, unless we were told what to use.
    1152             :      *
    1153             :      * The OID will be the relfilenode as well, so make sure it doesn't
    1154             :      * collide with either pg_class OIDs or existing physical files.
    1155             :      */
    1156      103486 :     if (!OidIsValid(relid))
    1157             :     {
    1158             :         /* Use binary-upgrade override for pg_class.oid/relfilenode? */
    1159       73594 :         if (IsBinaryUpgrade &&
    1160         746 :             (relkind == RELKIND_RELATION || relkind == RELKIND_SEQUENCE ||
    1161         588 :              relkind == RELKIND_VIEW || relkind == RELKIND_MATVIEW ||
    1162         542 :              relkind == RELKIND_COMPOSITE_TYPE || relkind == RELKIND_FOREIGN_TABLE ||
    1163             :              relkind == RELKIND_PARTITIONED_TABLE))
    1164             :         {
    1165        1238 :             if (!OidIsValid(binary_upgrade_next_heap_pg_class_oid))
    1166           0 :                 ereport(ERROR,
    1167             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1168             :                          errmsg("pg_class heap OID value not set when in binary upgrade mode")));
    1169             : 
    1170        1238 :             relid = binary_upgrade_next_heap_pg_class_oid;
    1171        1238 :             binary_upgrade_next_heap_pg_class_oid = InvalidOid;
    1172             :         }
    1173             :         /* There might be no TOAST table, so we have to test for it. */
    1174       72774 :         else if (IsBinaryUpgrade &&
    1175         836 :                  OidIsValid(binary_upgrade_next_toast_pg_class_oid) &&
    1176             :                  relkind == RELKIND_TOASTVALUE)
    1177             :         {
    1178         418 :             relid = binary_upgrade_next_toast_pg_class_oid;
    1179         418 :             binary_upgrade_next_toast_pg_class_oid = InvalidOid;
    1180             :         }
    1181             :         else
    1182       71938 :             relid = GetNewRelFileNode(reltablespace, pg_class_desc,
    1183             :                                       relpersistence);
    1184             :     }
    1185             : 
    1186             :     /*
    1187             :      * Determine the relation's initial permissions.
    1188             :      */
    1189      103486 :     if (use_user_acl)
    1190             :     {
    1191       63662 :         switch (relkind)
    1192             :         {
    1193             :             case RELKIND_RELATION:
    1194             :             case RELKIND_VIEW:
    1195             :             case RELKIND_MATVIEW:
    1196             :             case RELKIND_FOREIGN_TABLE:
    1197             :             case RELKIND_PARTITIONED_TABLE:
    1198       62362 :                 relacl = get_user_default_acl(OBJECT_TABLE, ownerid,
    1199             :                                               relnamespace);
    1200       62362 :                 break;
    1201             :             case RELKIND_SEQUENCE:
    1202         894 :                 relacl = get_user_default_acl(OBJECT_SEQUENCE, ownerid,
    1203             :                                               relnamespace);
    1204         894 :                 break;
    1205             :             default:
    1206         406 :                 relacl = NULL;
    1207         406 :                 break;
    1208             :         }
    1209             :     }
    1210             :     else
    1211       39824 :         relacl = NULL;
    1212             : 
    1213             :     /*
    1214             :      * Create the relcache entry (mostly dummy at this point) and the physical
    1215             :      * disk file.  (If we fail further down, it's the smgr's responsibility to
    1216             :      * remove the disk file again.)
    1217             :      */
    1218      103486 :     new_rel_desc = heap_create(relname,
    1219             :                                relnamespace,
    1220             :                                reltablespace,
    1221             :                                relid,
    1222             :                                InvalidOid,
    1223             :                                accessmtd,
    1224             :                                tupdesc,
    1225             :                                relkind,
    1226             :                                relpersistence,
    1227             :                                shared_relation,
    1228             :                                mapped_relation,
    1229             :                                allow_system_table_mods,
    1230             :                                &relfrozenxid,
    1231             :                                &relminmxid);
    1232             : 
    1233             :     Assert(relid == RelationGetRelid(new_rel_desc));
    1234             : 
    1235      103482 :     new_rel_desc->rd_rel->relrewrite = relrewrite;
    1236             : 
    1237             :     /*
    1238             :      * Decide whether to create an array type over the relation's rowtype. We
    1239             :      * do not create any array types for system catalogs (ie, those made
    1240             :      * during initdb). We do not create them where the use of a relation as
    1241             :      * such is an implementation detail: toast tables, sequences and indexes.
    1242             :      */
    1243      103482 :     if (IsUnderPostmaster && (relkind == RELKIND_RELATION ||
    1244       10142 :                               relkind == RELKIND_VIEW ||
    1245        9974 :                               relkind == RELKIND_MATVIEW ||
    1246        9742 :                               relkind == RELKIND_FOREIGN_TABLE ||
    1247        9336 :                               relkind == RELKIND_COMPOSITE_TYPE ||
    1248             :                               relkind == RELKIND_PARTITIONED_TABLE))
    1249       21206 :         new_array_oid = AssignTypeArrayOid();
    1250             : 
    1251             :     /*
    1252             :      * Since defining a relation also defines a complex type, we add a new
    1253             :      * system type corresponding to the new relation.  The OID of the type can
    1254             :      * be preselected by the caller, but if reltypeid is InvalidOid, we'll
    1255             :      * generate a new OID for it.
    1256             :      *
    1257             :      * NOTE: we could get a unique-index failure here, in case someone else is
    1258             :      * creating the same type name in parallel but hadn't committed yet when
    1259             :      * we checked for a duplicate name above.
    1260             :      */
    1261      103482 :     new_type_addr = AddNewRelationType(relname,
    1262             :                                        relnamespace,
    1263             :                                        relid,
    1264             :                                        relkind,
    1265             :                                        ownerid,
    1266             :                                        reltypeid,
    1267             :                                        new_array_oid);
    1268      103482 :     new_type_oid = new_type_addr.objectId;
    1269      103482 :     if (typaddress)
    1270         406 :         *typaddress = new_type_addr;
    1271             : 
    1272             :     /*
    1273             :      * Now make the array type if wanted.
    1274             :      */
    1275      103482 :     if (OidIsValid(new_array_oid))
    1276             :     {
    1277             :         char       *relarrayname;
    1278             : 
    1279       21206 :         relarrayname = makeArrayTypeName(relname, relnamespace);
    1280             : 
    1281       21206 :         TypeCreate(new_array_oid,   /* force the type's OID to this */
    1282             :                    relarrayname,    /* Array type name */
    1283             :                    relnamespace,    /* Same namespace as parent */
    1284             :                    InvalidOid,  /* Not composite, no relationOid */
    1285             :                    0,           /* relkind, also N/A here */
    1286             :                    ownerid,     /* owner's ID */
    1287             :                    -1,          /* Internal size (varlena) */
    1288             :                    TYPTYPE_BASE,    /* Not composite - typelem is */
    1289             :                    TYPCATEGORY_ARRAY,   /* type-category (array) */
    1290             :                    false,       /* array types are never preferred */
    1291             :                    DEFAULT_TYPDELIM,    /* default array delimiter */
    1292             :                    F_ARRAY_IN,  /* array input proc */
    1293             :                    F_ARRAY_OUT, /* array output proc */
    1294             :                    F_ARRAY_RECV,    /* array recv (bin) proc */
    1295             :                    F_ARRAY_SEND,    /* array send (bin) proc */
    1296             :                    InvalidOid,  /* typmodin procedure - none */
    1297             :                    InvalidOid,  /* typmodout procedure - none */
    1298             :                    F_ARRAY_TYPANALYZE,  /* array analyze procedure */
    1299             :                    new_type_oid,    /* array element type - the rowtype */
    1300             :                    true,        /* yes, this is an array type */
    1301             :                    InvalidOid,  /* this has no array type */
    1302             :                    InvalidOid,  /* domain base type - irrelevant */
    1303             :                    NULL,        /* default value - none */
    1304             :                    NULL,        /* default binary representation */
    1305             :                    false,       /* passed by reference */
    1306             :                    'd',         /* alignment - must be the largest! */
    1307             :                    'x',         /* fully TOASTable */
    1308             :                    -1,          /* typmod */
    1309             :                    0,           /* array dimensions for typBaseType */
    1310             :                    false,       /* Type NOT NULL */
    1311             :                    InvalidOid); /* rowtypes never have a collation */
    1312             : 
    1313       21206 :         pfree(relarrayname);
    1314             :     }
    1315             : 
    1316             :     /*
    1317             :      * now create an entry in pg_class for the relation.
    1318             :      *
    1319             :      * NOTE: we could get a unique-index failure here, in case someone else is
    1320             :      * creating the same relation name in parallel but hadn't committed yet
    1321             :      * when we checked for a duplicate name above.
    1322             :      */
    1323      103482 :     AddNewRelationTuple(pg_class_desc,
    1324             :                         new_rel_desc,
    1325             :                         relid,
    1326             :                         new_type_oid,
    1327             :                         reloftypeid,
    1328             :                         ownerid,
    1329             :                         relkind,
    1330             :                         relfrozenxid,
    1331             :                         relminmxid,
    1332             :                         PointerGetDatum(relacl),
    1333             :                         reloptions);
    1334             : 
    1335             :     /*
    1336             :      * now add tuples to pg_attribute for the attributes in our new relation.
    1337             :      */
    1338      103482 :     AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind);
    1339             : 
    1340             :     /*
    1341             :      * Make a dependency link to force the relation to be deleted if its
    1342             :      * namespace is.  Also make a dependency link to its owner, as well as
    1343             :      * dependencies for any roles mentioned in the default ACL.
    1344             :      *
    1345             :      * For composite types, these dependencies are tracked for the pg_type
    1346             :      * entry, so we needn't record them here.  Likewise, TOAST tables don't
    1347             :      * need a namespace dependency (they live in a pinned namespace) nor an
    1348             :      * owner dependency (they depend indirectly through the parent table), nor
    1349             :      * should they have any ACL entries.  The same applies for extension
    1350             :      * dependencies.
    1351             :      *
    1352             :      * Also, skip this in bootstrap mode, since we don't make dependencies
    1353             :      * while bootstrapping.
    1354             :      */
    1355      103482 :     if (relkind != RELKIND_COMPOSITE_TYPE &&
    1356       82750 :         relkind != RELKIND_TOASTVALUE &&
    1357       82750 :         !IsBootstrapProcessingMode())
    1358             :     {
    1359             :         ObjectAddress myself,
    1360             :                     referenced;
    1361             : 
    1362       63988 :         myself.classId = RelationRelationId;
    1363       63988 :         myself.objectId = relid;
    1364       63988 :         myself.objectSubId = 0;
    1365             : 
    1366       63988 :         referenced.classId = NamespaceRelationId;
    1367       63988 :         referenced.objectId = relnamespace;
    1368       63988 :         referenced.objectSubId = 0;
    1369       63988 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    1370             : 
    1371       63988 :         recordDependencyOnOwner(RelationRelationId, relid, ownerid);
    1372             : 
    1373       63988 :         recordDependencyOnNewAcl(RelationRelationId, relid, 0, ownerid, relacl);
    1374             : 
    1375       63988 :         recordDependencyOnCurrentExtension(&myself, false);
    1376             : 
    1377       63988 :         if (reloftypeid)
    1378             :         {
    1379          46 :             referenced.classId = TypeRelationId;
    1380          46 :             referenced.objectId = reloftypeid;
    1381          46 :             referenced.objectSubId = 0;
    1382          46 :             recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    1383             :         }
    1384             : 
    1385             :         /*
    1386             :          * Make a dependency link to force the relation to be deleted if its
    1387             :          * access method is. Do this only for relation and materialized views.
    1388             :          *
    1389             :          * No need to add an explicit dependency for the toast table, as the
    1390             :          * main table depends on it.
    1391             :          */
    1392       63988 :         if (relkind == RELKIND_RELATION ||
    1393             :             relkind == RELKIND_MATVIEW)
    1394             :         {
    1395       19978 :             referenced.classId = AccessMethodRelationId;
    1396       19978 :             referenced.objectId = accessmtd;
    1397       19978 :             referenced.objectSubId = 0;
    1398       19978 :             recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    1399             :         }
    1400             :     }
    1401             : 
    1402             :     /* Post creation hook for new relation */
    1403      103482 :     InvokeObjectPostCreateHookArg(RelationRelationId, relid, 0, is_internal);
    1404             : 
    1405             :     /*
    1406             :      * Store any supplied constraints and defaults.
    1407             :      *
    1408             :      * NB: this may do a CommandCounterIncrement and rebuild the relcache
    1409             :      * entry, so the relation must be valid and self-consistent at this point.
    1410             :      * In particular, there are not yet constraints and defaults anywhere.
    1411             :      */
    1412      103482 :     StoreConstraints(new_rel_desc, cooked_constraints, is_internal);
    1413             : 
    1414             :     /*
    1415             :      * If there's a special on-commit action, remember it
    1416             :      */
    1417      103482 :     if (oncommit != ONCOMMIT_NOOP)
    1418          84 :         register_on_commit_action(relid, oncommit);
    1419             : 
    1420             :     /*
    1421             :      * ok, the relation has been cataloged, so close our relations and return
    1422             :      * the OID of the newly created relation.
    1423             :      */
    1424      103482 :     table_close(new_rel_desc, NoLock);  /* do not unlock till end of xact */
    1425      103482 :     table_close(pg_class_desc, RowExclusiveLock);
    1426             : 
    1427      103482 :     return relid;
    1428             : }
    1429             : 
    1430             : /*
    1431             :  *      RelationRemoveInheritance
    1432             :  *
    1433             :  * Formerly, this routine checked for child relations and aborted the
    1434             :  * deletion if any were found.  Now we rely on the dependency mechanism
    1435             :  * to check for or delete child relations.  By the time we get here,
    1436             :  * there are no children and we need only remove any pg_inherits rows
    1437             :  * linking this relation to its parent(s).
    1438             :  */
    1439             : static void
    1440       22252 : RelationRemoveInheritance(Oid relid)
    1441             : {
    1442             :     Relation    catalogRelation;
    1443             :     SysScanDesc scan;
    1444             :     ScanKeyData key;
    1445             :     HeapTuple   tuple;
    1446             : 
    1447       22252 :     catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
    1448             : 
    1449       22252 :     ScanKeyInit(&key,
    1450             :                 Anum_pg_inherits_inhrelid,
    1451             :                 BTEqualStrategyNumber, F_OIDEQ,
    1452             :                 ObjectIdGetDatum(relid));
    1453             : 
    1454       22252 :     scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
    1455             :                               NULL, 1, &key);
    1456             : 
    1457       48248 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
    1458        3744 :         CatalogTupleDelete(catalogRelation, &tuple->t_self);
    1459             : 
    1460       22252 :     systable_endscan(scan);
    1461       22252 :     table_close(catalogRelation, RowExclusiveLock);
    1462       22252 : }
    1463             : 
    1464             : /*
    1465             :  *      DeleteRelationTuple
    1466             :  *
    1467             :  * Remove pg_class row for the given relid.
    1468             :  *
    1469             :  * Note: this is shared by relation deletion and index deletion.  It's
    1470             :  * not intended for use anyplace else.
    1471             :  */
    1472             : void
    1473       34018 : DeleteRelationTuple(Oid relid)
    1474             : {
    1475             :     Relation    pg_class_desc;
    1476             :     HeapTuple   tup;
    1477             : 
    1478             :     /* Grab an appropriate lock on the pg_class relation */
    1479       34018 :     pg_class_desc = table_open(RelationRelationId, RowExclusiveLock);
    1480             : 
    1481       34018 :     tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    1482       34018 :     if (!HeapTupleIsValid(tup))
    1483           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
    1484             : 
    1485             :     /* delete the relation tuple from pg_class, and finish up */
    1486       34018 :     CatalogTupleDelete(pg_class_desc, &tup->t_self);
    1487             : 
    1488       34018 :     ReleaseSysCache(tup);
    1489             : 
    1490       34018 :     table_close(pg_class_desc, RowExclusiveLock);
    1491       34018 : }
    1492             : 
    1493             : /*
    1494             :  *      DeleteAttributeTuples
    1495             :  *
    1496             :  * Remove pg_attribute rows for the given relid.
    1497             :  *
    1498             :  * Note: this is shared by relation deletion and index deletion.  It's
    1499             :  * not intended for use anyplace else.
    1500             :  */
    1501             : void
    1502       34018 : DeleteAttributeTuples(Oid relid)
    1503             : {
    1504             :     Relation    attrel;
    1505             :     SysScanDesc scan;
    1506             :     ScanKeyData key[1];
    1507             :     HeapTuple   atttup;
    1508             : 
    1509             :     /* Grab an appropriate lock on the pg_attribute relation */
    1510       34018 :     attrel = table_open(AttributeRelationId, RowExclusiveLock);
    1511             : 
    1512             :     /* Use the index to scan only attributes of the target relation */
    1513       34018 :     ScanKeyInit(&key[0],
    1514             :                 Anum_pg_attribute_attrelid,
    1515             :                 BTEqualStrategyNumber, F_OIDEQ,
    1516             :                 ObjectIdGetDatum(relid));
    1517             : 
    1518       34018 :     scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
    1519             :                               NULL, 1, key);
    1520             : 
    1521             :     /* Delete all the matching tuples */
    1522      266622 :     while ((atttup = systable_getnext(scan)) != NULL)
    1523      198586 :         CatalogTupleDelete(attrel, &atttup->t_self);
    1524             : 
    1525             :     /* Clean up after the scan */
    1526       34018 :     systable_endscan(scan);
    1527       34018 :     table_close(attrel, RowExclusiveLock);
    1528       34018 : }
    1529             : 
    1530             : /*
    1531             :  *      DeleteSystemAttributeTuples
    1532             :  *
    1533             :  * Remove pg_attribute rows for system columns of the given relid.
    1534             :  *
    1535             :  * Note: this is only used when converting a table to a view.  Views don't
    1536             :  * have system columns, so we should remove them from pg_attribute.
    1537             :  */
    1538             : void
    1539          10 : DeleteSystemAttributeTuples(Oid relid)
    1540             : {
    1541             :     Relation    attrel;
    1542             :     SysScanDesc scan;
    1543             :     ScanKeyData key[2];
    1544             :     HeapTuple   atttup;
    1545             : 
    1546             :     /* Grab an appropriate lock on the pg_attribute relation */
    1547          10 :     attrel = table_open(AttributeRelationId, RowExclusiveLock);
    1548             : 
    1549             :     /* Use the index to scan only system attributes of the target relation */
    1550          10 :     ScanKeyInit(&key[0],
    1551             :                 Anum_pg_attribute_attrelid,
    1552             :                 BTEqualStrategyNumber, F_OIDEQ,
    1553             :                 ObjectIdGetDatum(relid));
    1554          10 :     ScanKeyInit(&key[1],
    1555             :                 Anum_pg_attribute_attnum,
    1556             :                 BTLessEqualStrategyNumber, F_INT2LE,
    1557             :                 Int16GetDatum(0));
    1558             : 
    1559          10 :     scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
    1560             :                               NULL, 2, key);
    1561             : 
    1562             :     /* Delete all the matching tuples */
    1563          80 :     while ((atttup = systable_getnext(scan)) != NULL)
    1564          60 :         CatalogTupleDelete(attrel, &atttup->t_self);
    1565             : 
    1566             :     /* Clean up after the scan */
    1567          10 :     systable_endscan(scan);
    1568          10 :     table_close(attrel, RowExclusiveLock);
    1569          10 : }
    1570             : 
    1571             : /*
    1572             :  *      RemoveAttributeById
    1573             :  *
    1574             :  * This is the guts of ALTER TABLE DROP COLUMN: actually mark the attribute
    1575             :  * deleted in pg_attribute.  We also remove pg_statistic entries for it.
    1576             :  * (Everything else needed, such as getting rid of any pg_attrdef entry,
    1577             :  * is handled by dependency.c.)
    1578             :  */
    1579             : void
    1580        1230 : RemoveAttributeById(Oid relid, AttrNumber attnum)
    1581             : {
    1582             :     Relation    rel;
    1583             :     Relation    attr_rel;
    1584             :     HeapTuple   tuple;
    1585             :     Form_pg_attribute attStruct;
    1586             :     char        newattname[NAMEDATALEN];
    1587             : 
    1588             :     /*
    1589             :      * Grab an exclusive lock on the target table, which we will NOT release
    1590             :      * until end of transaction.  (In the simple case where we are directly
    1591             :      * dropping this column, AlterTableDropColumn already did this ... but
    1592             :      * when cascading from a drop of some other object, we may not have any
    1593             :      * lock.)
    1594             :      */
    1595        1230 :     rel = relation_open(relid, AccessExclusiveLock);
    1596             : 
    1597        1230 :     attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
    1598             : 
    1599        1230 :     tuple = SearchSysCacheCopy2(ATTNUM,
    1600             :                                 ObjectIdGetDatum(relid),
    1601             :                                 Int16GetDatum(attnum));
    1602        1230 :     if (!HeapTupleIsValid(tuple))   /* shouldn't happen */
    1603           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1604             :              attnum, relid);
    1605        1230 :     attStruct = (Form_pg_attribute) GETSTRUCT(tuple);
    1606             : 
    1607        1230 :     if (attnum < 0)
    1608             :     {
    1609             :         /* System attribute (probably OID) ... just delete the row */
    1610             : 
    1611           0 :         CatalogTupleDelete(attr_rel, &tuple->t_self);
    1612             :     }
    1613             :     else
    1614             :     {
    1615             :         /* Dropping user attributes is lots harder */
    1616             : 
    1617             :         /* Mark the attribute as dropped */
    1618        1230 :         attStruct->attisdropped = true;
    1619             : 
    1620             :         /*
    1621             :          * Set the type OID to invalid.  A dropped attribute's type link
    1622             :          * cannot be relied on (once the attribute is dropped, the type might
    1623             :          * be too). Fortunately we do not need the type row --- the only
    1624             :          * really essential information is the type's typlen and typalign,
    1625             :          * which are preserved in the attribute's attlen and attalign.  We set
    1626             :          * atttypid to zero here as a means of catching code that incorrectly
    1627             :          * expects it to be valid.
    1628             :          */
    1629        1230 :         attStruct->atttypid = InvalidOid;
    1630             : 
    1631             :         /* Remove any NOT NULL constraint the column may have */
    1632        1230 :         attStruct->attnotnull = false;
    1633             : 
    1634             :         /* We don't want to keep stats for it anymore */
    1635        1230 :         attStruct->attstattarget = 0;
    1636             : 
    1637             :         /* Unset this so no one tries to look up the generation expression */
    1638        1230 :         attStruct->attgenerated = '\0';
    1639             : 
    1640             :         /*
    1641             :          * Change the column name to something that isn't likely to conflict
    1642             :          */
    1643        1230 :         snprintf(newattname, sizeof(newattname),
    1644             :                  "........pg.dropped.%d........", attnum);
    1645        1230 :         namestrcpy(&(attStruct->attname), newattname);
    1646             : 
    1647             :         /* clear the missing value if any */
    1648        1230 :         if (attStruct->atthasmissing)
    1649             :         {
    1650             :             Datum       valuesAtt[Natts_pg_attribute];
    1651             :             bool        nullsAtt[Natts_pg_attribute];
    1652             :             bool        replacesAtt[Natts_pg_attribute];
    1653             : 
    1654             :             /* update the tuple - set atthasmissing and attmissingval */
    1655           8 :             MemSet(valuesAtt, 0, sizeof(valuesAtt));
    1656           8 :             MemSet(nullsAtt, false, sizeof(nullsAtt));
    1657           8 :             MemSet(replacesAtt, false, sizeof(replacesAtt));
    1658             : 
    1659           8 :             valuesAtt[Anum_pg_attribute_atthasmissing - 1] =
    1660             :                 BoolGetDatum(false);
    1661           8 :             replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
    1662           8 :             valuesAtt[Anum_pg_attribute_attmissingval - 1] = (Datum) 0;
    1663           8 :             nullsAtt[Anum_pg_attribute_attmissingval - 1] = true;
    1664           8 :             replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
    1665             : 
    1666           8 :             tuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel),
    1667             :                                       valuesAtt, nullsAtt, replacesAtt);
    1668             :         }
    1669             : 
    1670        1230 :         CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
    1671             :     }
    1672             : 
    1673             :     /*
    1674             :      * Because updating the pg_attribute row will trigger a relcache flush for
    1675             :      * the target relation, we need not do anything else to notify other
    1676             :      * backends of the change.
    1677             :      */
    1678             : 
    1679        1230 :     table_close(attr_rel, RowExclusiveLock);
    1680             : 
    1681        1230 :     if (attnum > 0)
    1682        1230 :         RemoveStatistics(relid, attnum);
    1683             : 
    1684        1230 :     relation_close(rel, NoLock);
    1685        1230 : }
    1686             : 
    1687             : /*
    1688             :  *      RemoveAttrDefault
    1689             :  *
    1690             :  * If the specified relation/attribute has a default, remove it.
    1691             :  * (If no default, raise error if complain is true, else return quietly.)
    1692             :  */
    1693             : void
    1694         334 : RemoveAttrDefault(Oid relid, AttrNumber attnum,
    1695             :                   DropBehavior behavior, bool complain, bool internal)
    1696             : {
    1697             :     Relation    attrdef_rel;
    1698             :     ScanKeyData scankeys[2];
    1699             :     SysScanDesc scan;
    1700             :     HeapTuple   tuple;
    1701         334 :     bool        found = false;
    1702             : 
    1703         334 :     attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
    1704             : 
    1705         334 :     ScanKeyInit(&scankeys[0],
    1706             :                 Anum_pg_attrdef_adrelid,
    1707             :                 BTEqualStrategyNumber, F_OIDEQ,
    1708             :                 ObjectIdGetDatum(relid));
    1709         334 :     ScanKeyInit(&scankeys[1],
    1710             :                 Anum_pg_attrdef_adnum,
    1711             :                 BTEqualStrategyNumber, F_INT2EQ,
    1712             :                 Int16GetDatum(attnum));
    1713             : 
    1714         334 :     scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
    1715             :                               NULL, 2, scankeys);
    1716             : 
    1717             :     /* There should be at most one matching tuple, but we loop anyway */
    1718         896 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
    1719             :     {
    1720             :         ObjectAddress object;
    1721         228 :         Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple);
    1722             : 
    1723         228 :         object.classId = AttrDefaultRelationId;
    1724         228 :         object.objectId = attrtuple->oid;
    1725         228 :         object.objectSubId = 0;
    1726             : 
    1727         228 :         performDeletion(&object, behavior,
    1728             :                         internal ? PERFORM_DELETION_INTERNAL : 0);
    1729             : 
    1730         228 :         found = true;
    1731             :     }
    1732             : 
    1733         334 :     systable_endscan(scan);
    1734         334 :     table_close(attrdef_rel, RowExclusiveLock);
    1735             : 
    1736         334 :     if (complain && !found)
    1737           0 :         elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
    1738             :              relid, attnum);
    1739         334 : }
    1740             : 
    1741             : /*
    1742             :  *      RemoveAttrDefaultById
    1743             :  *
    1744             :  * Remove a pg_attrdef entry specified by OID.  This is the guts of
    1745             :  * attribute-default removal.  Note it should be called via performDeletion,
    1746             :  * not directly.
    1747             :  */
    1748             : void
    1749        1294 : RemoveAttrDefaultById(Oid attrdefId)
    1750             : {
    1751             :     Relation    attrdef_rel;
    1752             :     Relation    attr_rel;
    1753             :     Relation    myrel;
    1754             :     ScanKeyData scankeys[1];
    1755             :     SysScanDesc scan;
    1756             :     HeapTuple   tuple;
    1757             :     Oid         myrelid;
    1758             :     AttrNumber  myattnum;
    1759             : 
    1760             :     /* Grab an appropriate lock on the pg_attrdef relation */
    1761        1294 :     attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
    1762             : 
    1763             :     /* Find the pg_attrdef tuple */
    1764        1294 :     ScanKeyInit(&scankeys[0],
    1765             :                 Anum_pg_attrdef_oid,
    1766             :                 BTEqualStrategyNumber, F_OIDEQ,
    1767             :                 ObjectIdGetDatum(attrdefId));
    1768             : 
    1769        1294 :     scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
    1770             :                               NULL, 1, scankeys);
    1771             : 
    1772        1294 :     tuple = systable_getnext(scan);
    1773        1294 :     if (!HeapTupleIsValid(tuple))
    1774           0 :         elog(ERROR, "could not find tuple for attrdef %u", attrdefId);
    1775             : 
    1776        1294 :     myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
    1777        1294 :     myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
    1778             : 
    1779             :     /* Get an exclusive lock on the relation owning the attribute */
    1780        1294 :     myrel = relation_open(myrelid, AccessExclusiveLock);
    1781             : 
    1782             :     /* Now we can delete the pg_attrdef row */
    1783        1294 :     CatalogTupleDelete(attrdef_rel, &tuple->t_self);
    1784             : 
    1785        1294 :     systable_endscan(scan);
    1786        1294 :     table_close(attrdef_rel, RowExclusiveLock);
    1787             : 
    1788             :     /* Fix the pg_attribute row */
    1789        1294 :     attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
    1790             : 
    1791        1294 :     tuple = SearchSysCacheCopy2(ATTNUM,
    1792             :                                 ObjectIdGetDatum(myrelid),
    1793             :                                 Int16GetDatum(myattnum));
    1794        1294 :     if (!HeapTupleIsValid(tuple))   /* shouldn't happen */
    1795           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1796             :              myattnum, myrelid);
    1797             : 
    1798        1294 :     ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;
    1799             : 
    1800        1294 :     CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
    1801             : 
    1802             :     /*
    1803             :      * Our update of the pg_attribute row will force a relcache rebuild, so
    1804             :      * there's nothing else to do here.
    1805             :      */
    1806        1294 :     table_close(attr_rel, RowExclusiveLock);
    1807             : 
    1808             :     /* Keep lock on attribute's rel until end of xact */
    1809        1294 :     relation_close(myrel, NoLock);
    1810        1294 : }
    1811             : 
    1812             : /*
    1813             :  * heap_drop_with_catalog   - removes specified relation from catalogs
    1814             :  *
    1815             :  * Note that this routine is not responsible for dropping objects that are
    1816             :  * linked to the pg_class entry via dependencies (for example, indexes and
    1817             :  * constraints).  Those are deleted by the dependency-tracing logic in
    1818             :  * dependency.c before control gets here.  In general, therefore, this routine
    1819             :  * should never be called directly; go through performDeletion() instead.
    1820             :  */
    1821             : void
    1822       22252 : heap_drop_with_catalog(Oid relid)
    1823             : {
    1824             :     Relation    rel;
    1825             :     HeapTuple   tuple;
    1826       22252 :     Oid         parentOid = InvalidOid,
    1827       22252 :                 defaultPartOid = InvalidOid;
    1828             : 
    1829             :     /*
    1830             :      * To drop a partition safely, we must grab exclusive lock on its parent,
    1831             :      * because another backend might be about to execute a query on the parent
    1832             :      * table.  If it relies on previously cached partition descriptor, then it
    1833             :      * could attempt to access the just-dropped relation as its partition. We
    1834             :      * must therefore take a table lock strong enough to prevent all queries
    1835             :      * on the table from proceeding until we commit and send out a
    1836             :      * shared-cache-inval notice that will make them update their partition
    1837             :      * descriptors.
    1838             :      */
    1839       22252 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    1840       22252 :     if (!HeapTupleIsValid(tuple))
    1841           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
    1842       22252 :     if (((Form_pg_class) GETSTRUCT(tuple))->relispartition)
    1843             :     {
    1844        2958 :         parentOid = get_partition_parent(relid);
    1845        2958 :         LockRelationOid(parentOid, AccessExclusiveLock);
    1846             : 
    1847             :         /*
    1848             :          * If this is not the default partition, dropping it will change the
    1849             :          * default partition's partition constraint, so we must lock it.
    1850             :          */
    1851        2958 :         defaultPartOid = get_default_partition_oid(parentOid);
    1852        2958 :         if (OidIsValid(defaultPartOid) && relid != defaultPartOid)
    1853         200 :             LockRelationOid(defaultPartOid, AccessExclusiveLock);
    1854             :     }
    1855             : 
    1856       22252 :     ReleaseSysCache(tuple);
    1857             : 
    1858             :     /*
    1859             :      * Open and lock the relation.
    1860             :      */
    1861       22252 :     rel = relation_open(relid, AccessExclusiveLock);
    1862             : 
    1863             :     /*
    1864             :      * There can no longer be anyone *else* touching the relation, but we
    1865             :      * might still have open queries or cursors, or pending trigger events, in
    1866             :      * our own session.
    1867             :      */
    1868       22252 :     CheckTableNotInUse(rel, "DROP TABLE");
    1869             : 
    1870             :     /*
    1871             :      * This effectively deletes all rows in the table, and may be done in a
    1872             :      * serializable transaction.  In that case we must record a rw-conflict in
    1873             :      * to this transaction from each transaction holding a predicate lock on
    1874             :      * the table.
    1875             :      */
    1876       22252 :     CheckTableForSerializableConflictIn(rel);
    1877             : 
    1878             :     /*
    1879             :      * Delete pg_foreign_table tuple first.
    1880             :      */
    1881       22252 :     if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
    1882             :     {
    1883             :         Relation    rel;
    1884             :         HeapTuple   tuple;
    1885             : 
    1886          92 :         rel = table_open(ForeignTableRelationId, RowExclusiveLock);
    1887             : 
    1888          92 :         tuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(relid));
    1889          92 :         if (!HeapTupleIsValid(tuple))
    1890           0 :             elog(ERROR, "cache lookup failed for foreign table %u", relid);
    1891             : 
    1892          92 :         CatalogTupleDelete(rel, &tuple->t_self);
    1893             : 
    1894          92 :         ReleaseSysCache(tuple);
    1895          92 :         table_close(rel, RowExclusiveLock);
    1896             :     }
    1897             : 
    1898             :     /*
    1899             :      * If a partitioned table, delete the pg_partitioned_table tuple.
    1900             :      */
    1901       22252 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    1902        1606 :         RemovePartitionKeyByRelId(relid);
    1903             : 
    1904             :     /*
    1905             :      * If the relation being dropped is the default partition itself,
    1906             :      * invalidate its entry in pg_partitioned_table.
    1907             :      */
    1908       22252 :     if (relid == defaultPartOid)
    1909         160 :         update_default_partition_oid(parentOid, InvalidOid);
    1910             : 
    1911             :     /*
    1912             :      * Schedule unlinking of the relation's physical files at commit.
    1913             :      */
    1914       43436 :     if (rel->rd_rel->relkind != RELKIND_VIEW &&
    1915       42160 :         rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
    1916       41860 :         rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
    1917       20884 :         rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
    1918             :     {
    1919       19278 :         RelationDropStorage(rel);
    1920             :     }
    1921             : 
    1922             :     /*
    1923             :      * Close relcache entry, but *keep* AccessExclusiveLock on the relation
    1924             :      * until transaction commit.  This ensures no one else will try to do
    1925             :      * something with the doomed relation.
    1926             :      */
    1927       22252 :     relation_close(rel, NoLock);
    1928             : 
    1929             :     /*
    1930             :      * Remove any associated relation synchronization states.
    1931             :      */
    1932       22252 :     RemoveSubscriptionRel(InvalidOid, relid);
    1933             : 
    1934             :     /*
    1935             :      * Forget any ON COMMIT action for the rel
    1936             :      */
    1937       22252 :     remove_on_commit_action(relid);
    1938             : 
    1939             :     /*
    1940             :      * Flush the relation from the relcache.  We want to do this before
    1941             :      * starting to remove catalog entries, just to be certain that no relcache
    1942             :      * entry rebuild will happen partway through.  (That should not really
    1943             :      * matter, since we don't do CommandCounterIncrement here, but let's be
    1944             :      * safe.)
    1945             :      */
    1946       22252 :     RelationForgetRelation(relid);
    1947             : 
    1948             :     /*
    1949             :      * remove inheritance information
    1950             :      */
    1951       22252 :     RelationRemoveInheritance(relid);
    1952             : 
    1953             :     /*
    1954             :      * delete statistics
    1955             :      */
    1956       22252 :     RemoveStatistics(relid, 0);
    1957             : 
    1958             :     /*
    1959             :      * delete attribute tuples
    1960             :      */
    1961       22252 :     DeleteAttributeTuples(relid);
    1962             : 
    1963             :     /*
    1964             :      * delete relation tuple
    1965             :      */
    1966       22252 :     DeleteRelationTuple(relid);
    1967             : 
    1968       22252 :     if (OidIsValid(parentOid))
    1969             :     {
    1970             :         /*
    1971             :          * If this is not the default partition, the partition constraint of
    1972             :          * the default partition has changed to include the portion of the key
    1973             :          * space previously covered by the dropped partition.
    1974             :          */
    1975        2958 :         if (OidIsValid(defaultPartOid) && relid != defaultPartOid)
    1976         200 :             CacheInvalidateRelcacheByRelid(defaultPartOid);
    1977             : 
    1978             :         /*
    1979             :          * Invalidate the parent's relcache so that the partition is no longer
    1980             :          * included in its partition descriptor.
    1981             :          */
    1982        2958 :         CacheInvalidateRelcacheByRelid(parentOid);
    1983             :         /* keep the lock */
    1984             :     }
    1985       22252 : }
    1986             : 
    1987             : 
    1988             : /*
    1989             :  * RelationClearMissing
    1990             :  *
    1991             :  * Set atthasmissing and attmissingval to false/null for all attributes
    1992             :  * where they are currently set. This can be safely and usefully done if
    1993             :  * the table is rewritten (e.g. by VACUUM FULL or CLUSTER) where we know there
    1994             :  * are no rows left with less than a full complement of attributes.
    1995             :  *
    1996             :  * The caller must have an AccessExclusive lock on the relation.
    1997             :  */
    1998             : void
    1999         850 : RelationClearMissing(Relation rel)
    2000             : {
    2001             :     Relation    attr_rel;
    2002         850 :     Oid         relid = RelationGetRelid(rel);
    2003         850 :     int         natts = RelationGetNumberOfAttributes(rel);
    2004             :     int         attnum;
    2005             :     Datum       repl_val[Natts_pg_attribute];
    2006             :     bool        repl_null[Natts_pg_attribute];
    2007             :     bool        repl_repl[Natts_pg_attribute];
    2008             :     Form_pg_attribute attrtuple;
    2009             :     HeapTuple   tuple,
    2010             :                 newtuple;
    2011             : 
    2012         850 :     memset(repl_val, 0, sizeof(repl_val));
    2013         850 :     memset(repl_null, false, sizeof(repl_null));
    2014         850 :     memset(repl_repl, false, sizeof(repl_repl));
    2015             : 
    2016         850 :     repl_val[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(false);
    2017         850 :     repl_null[Anum_pg_attribute_attmissingval - 1] = true;
    2018             : 
    2019         850 :     repl_repl[Anum_pg_attribute_atthasmissing - 1] = true;
    2020         850 :     repl_repl[Anum_pg_attribute_attmissingval - 1] = true;
    2021             : 
    2022             : 
    2023             :     /* Get a lock on pg_attribute */
    2024         850 :     attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
    2025             : 
    2026             :     /* process each non-system attribute, including any dropped columns */
    2027        3314 :     for (attnum = 1; attnum <= natts; attnum++)
    2028             :     {
    2029        2464 :         tuple = SearchSysCache2(ATTNUM,
    2030             :                                 ObjectIdGetDatum(relid),
    2031             :                                 Int16GetDatum(attnum));
    2032        2464 :         if (!HeapTupleIsValid(tuple))   /* shouldn't happen */
    2033           0 :             elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    2034             :                  attnum, relid);
    2035             : 
    2036        2464 :         attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
    2037             : 
    2038             :         /* ignore any where atthasmissing is not true */
    2039        2464 :         if (attrtuple->atthasmissing)
    2040             :         {
    2041          40 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel),
    2042             :                                          repl_val, repl_null, repl_repl);
    2043             : 
    2044          40 :             CatalogTupleUpdate(attr_rel, &newtuple->t_self, newtuple);
    2045             : 
    2046          40 :             heap_freetuple(newtuple);
    2047             :         }
    2048             : 
    2049        2464 :         ReleaseSysCache(tuple);
    2050             :     }
    2051             : 
    2052             :     /*
    2053             :      * Our update of the pg_attribute rows will force a relcache rebuild, so
    2054             :      * there's nothing else to do here.
    2055             :      */
    2056         850 :     table_close(attr_rel, RowExclusiveLock);
    2057         850 : }
    2058             : 
    2059             : /*
    2060             :  * SetAttrMissing
    2061             :  *
    2062             :  * Set the missing value of a single attribute. This should only be used by
    2063             :  * binary upgrade. Takes an AccessExclusive lock on the relation owning the
    2064             :  * attribute.
    2065             :  */
    2066             : void
    2067           4 : SetAttrMissing(Oid relid, char *attname, char *value)
    2068             : {
    2069             :     Datum       valuesAtt[Natts_pg_attribute];
    2070             :     bool        nullsAtt[Natts_pg_attribute];
    2071             :     bool        replacesAtt[Natts_pg_attribute];
    2072             :     Datum       missingval;
    2073             :     Form_pg_attribute attStruct;
    2074             :     Relation    attrrel,
    2075             :                 tablerel;
    2076             :     HeapTuple   atttup,
    2077             :                 newtup;
    2078             : 
    2079             :     /* lock the table the attribute belongs to */
    2080           4 :     tablerel = table_open(relid, AccessExclusiveLock);
    2081             : 
    2082             :     /* Lock the attribute row and get the data */
    2083           4 :     attrrel = table_open(AttributeRelationId, RowExclusiveLock);
    2084           4 :     atttup = SearchSysCacheAttName(relid, attname);
    2085           4 :     if (!HeapTupleIsValid(atttup))
    2086           0 :         elog(ERROR, "cache lookup failed for attribute %s of relation %u",
    2087             :              attname, relid);
    2088           4 :     attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
    2089             : 
    2090             :     /* get an array value from the value string */
    2091           4 :     missingval = OidFunctionCall3(F_ARRAY_IN,
    2092             :                                   CStringGetDatum(value),
    2093             :                                   ObjectIdGetDatum(attStruct->atttypid),
    2094             :                                   Int32GetDatum(attStruct->atttypmod));
    2095             : 
    2096             :     /* update the tuple - set atthasmissing and attmissingval */
    2097           4 :     MemSet(valuesAtt, 0, sizeof(valuesAtt));
    2098           4 :     MemSet(nullsAtt, false, sizeof(nullsAtt));
    2099           4 :     MemSet(replacesAtt, false, sizeof(replacesAtt));
    2100             : 
    2101           4 :     valuesAtt[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(true);
    2102           4 :     replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
    2103           4 :     valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
    2104           4 :     replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
    2105             : 
    2106           4 :     newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
    2107             :                                valuesAtt, nullsAtt, replacesAtt);
    2108           4 :     CatalogTupleUpdate(attrrel, &newtup->t_self, newtup);
    2109             : 
    2110             :     /* clean up */
    2111           4 :     ReleaseSysCache(atttup);
    2112           4 :     table_close(attrrel, RowExclusiveLock);
    2113           4 :     table_close(tablerel, AccessExclusiveLock);
    2114           4 : }
    2115             : 
    2116             : /*
    2117             :  * Store a default expression for column attnum of relation rel.
    2118             :  *
    2119             :  * Returns the OID of the new pg_attrdef tuple.
    2120             :  *
    2121             :  * add_column_mode must be true if we are storing the default for a new
    2122             :  * attribute, and false if it's for an already existing attribute. The reason
    2123             :  * for this is that the missing value must never be updated after it is set,
    2124             :  * which can only be when a column is added to the table. Otherwise we would
    2125             :  * in effect be changing existing tuples.
    2126             :  */
    2127             : Oid
    2128        1760 : StoreAttrDefault(Relation rel, AttrNumber attnum,
    2129             :                  Node *expr, bool is_internal, bool add_column_mode)
    2130             : {
    2131             :     char       *adbin;
    2132             :     Relation    adrel;
    2133             :     HeapTuple   tuple;
    2134             :     Datum       values[4];
    2135             :     static bool nulls[4] = {false, false, false, false};
    2136             :     Relation    attrrel;
    2137             :     HeapTuple   atttup;
    2138             :     Form_pg_attribute attStruct;
    2139             :     char        attgenerated;
    2140             :     Oid         attrdefOid;
    2141             :     ObjectAddress colobject,
    2142             :                 defobject;
    2143             : 
    2144        1760 :     adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);
    2145             : 
    2146             :     /*
    2147             :      * Flatten expression to string form for storage.
    2148             :      */
    2149        1760 :     adbin = nodeToString(expr);
    2150             : 
    2151             :     /*
    2152             :      * Make the pg_attrdef entry.
    2153             :      */
    2154        1760 :     attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId,
    2155             :                                     Anum_pg_attrdef_oid);
    2156        1760 :     values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid);
    2157        1760 :     values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
    2158        1760 :     values[Anum_pg_attrdef_adnum - 1] = attnum;
    2159        1760 :     values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin);
    2160             : 
    2161        1760 :     tuple = heap_form_tuple(adrel->rd_att, values, nulls);
    2162        1760 :     CatalogTupleInsert(adrel, tuple);
    2163             : 
    2164        1760 :     defobject.classId = AttrDefaultRelationId;
    2165        1760 :     defobject.objectId = attrdefOid;
    2166        1760 :     defobject.objectSubId = 0;
    2167             : 
    2168        1760 :     table_close(adrel, RowExclusiveLock);
    2169             : 
    2170             :     /* now can free some of the stuff allocated above */
    2171        1760 :     pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
    2172        1760 :     heap_freetuple(tuple);
    2173        1760 :     pfree(adbin);
    2174             : 
    2175             :     /*
    2176             :      * Update the pg_attribute entry for the column to show that a default
    2177             :      * exists.
    2178             :      */
    2179        1760 :     attrrel = table_open(AttributeRelationId, RowExclusiveLock);
    2180        1760 :     atttup = SearchSysCacheCopy2(ATTNUM,
    2181             :                                  ObjectIdGetDatum(RelationGetRelid(rel)),
    2182             :                                  Int16GetDatum(attnum));
    2183        1760 :     if (!HeapTupleIsValid(atttup))
    2184           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    2185             :              attnum, RelationGetRelid(rel));
    2186        1760 :     attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
    2187        1760 :     attgenerated = attStruct->attgenerated;
    2188        1760 :     if (!attStruct->atthasdef)
    2189             :     {
    2190             :         Form_pg_attribute defAttStruct;
    2191             : 
    2192             :         ExprState  *exprState;
    2193        1760 :         Expr       *expr2 = (Expr *) expr;
    2194        1760 :         EState     *estate = NULL;
    2195             :         ExprContext *econtext;
    2196             :         Datum       valuesAtt[Natts_pg_attribute];
    2197             :         bool        nullsAtt[Natts_pg_attribute];
    2198             :         bool        replacesAtt[Natts_pg_attribute];
    2199        1760 :         Datum       missingval = (Datum) 0;
    2200        1760 :         bool        missingIsNull = true;
    2201             : 
    2202        1760 :         MemSet(valuesAtt, 0, sizeof(valuesAtt));
    2203        1760 :         MemSet(nullsAtt, false, sizeof(nullsAtt));
    2204        1760 :         MemSet(replacesAtt, false, sizeof(replacesAtt));
    2205        1760 :         valuesAtt[Anum_pg_attribute_atthasdef - 1] = true;
    2206        1760 :         replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
    2207             : 
    2208        1760 :         if (add_column_mode && !attgenerated)
    2209             :         {
    2210         278 :             expr2 = expression_planner(expr2);
    2211         278 :             estate = CreateExecutorState();
    2212         278 :             exprState = ExecPrepareExpr(expr2, estate);
    2213         278 :             econtext = GetPerTupleExprContext(estate);
    2214             : 
    2215         278 :             missingval = ExecEvalExpr(exprState, econtext,
    2216             :                                       &missingIsNull);
    2217             : 
    2218         278 :             FreeExecutorState(estate);
    2219             : 
    2220         278 :             defAttStruct = TupleDescAttr(rel->rd_att, attnum - 1);
    2221             : 
    2222         278 :             if (missingIsNull)
    2223             :             {
    2224             :                 /* if the default evaluates to NULL, just store a NULL array */
    2225           0 :                 missingval = (Datum) 0;
    2226             :             }
    2227             :             else
    2228             :             {
    2229             :                 /* otherwise make a one-element array of the value */
    2230         278 :                 missingval = PointerGetDatum(
    2231             :                                              construct_array(&missingval,
    2232             :                                                              1,
    2233             :                                                              defAttStruct->atttypid,
    2234             :                                                              defAttStruct->attlen,
    2235             :                                                              defAttStruct->attbyval,
    2236             :                                                              defAttStruct->attalign));
    2237             :             }
    2238             : 
    2239         278 :             valuesAtt[Anum_pg_attribute_atthasmissing - 1] = !missingIsNull;
    2240         278 :             replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
    2241         278 :             valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
    2242         278 :             replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
    2243         278 :             nullsAtt[Anum_pg_attribute_attmissingval - 1] = missingIsNull;
    2244             :         }
    2245        1760 :         atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
    2246             :                                    valuesAtt, nullsAtt, replacesAtt);
    2247             : 
    2248        1760 :         CatalogTupleUpdate(attrrel, &atttup->t_self, atttup);
    2249             : 
    2250        1760 :         if (!missingIsNull)
    2251         278 :             pfree(DatumGetPointer(missingval));
    2252             : 
    2253             :     }
    2254        1760 :     table_close(attrrel, RowExclusiveLock);
    2255        1760 :     heap_freetuple(atttup);
    2256             : 
    2257             :     /*
    2258             :      * Make a dependency so that the pg_attrdef entry goes away if the column
    2259             :      * (or whole table) is deleted.
    2260             :      */
    2261        1760 :     colobject.classId = RelationRelationId;
    2262        1760 :     colobject.objectId = RelationGetRelid(rel);
    2263        1760 :     colobject.objectSubId = attnum;
    2264             : 
    2265        1760 :     recordDependencyOn(&defobject, &colobject, DEPENDENCY_AUTO);
    2266             : 
    2267             :     /*
    2268             :      * Record dependencies on objects used in the expression, too.
    2269             :      */
    2270        1760 :     if (attgenerated)
    2271             :     {
    2272             :         /*
    2273             :          * Generated column: Dropping anything that the generation expression
    2274             :          * refers to automatically drops the generated column.
    2275             :          */
    2276         212 :         recordDependencyOnSingleRelExpr(&colobject, expr, RelationGetRelid(rel),
    2277             :                                         DEPENDENCY_AUTO,
    2278             :                                         DEPENDENCY_AUTO, false);
    2279             :     }
    2280             :     else
    2281             :     {
    2282             :         /*
    2283             :          * Normal default: Dropping anything that the default refers to
    2284             :          * requires CASCADE and drops the default only.
    2285             :          */
    2286        1548 :         recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel),
    2287             :                                         DEPENDENCY_NORMAL,
    2288             :                                         DEPENDENCY_NORMAL, false);
    2289             :     }
    2290             : 
    2291             :     /*
    2292             :      * Post creation hook for attribute defaults.
    2293             :      *
    2294             :      * XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a
    2295             :      * couple of deletion/creation of the attribute's default entry, so the
    2296             :      * callee should check existence of an older version of this entry if it
    2297             :      * needs to distinguish.
    2298             :      */
    2299        1760 :     InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
    2300             :                                   RelationGetRelid(rel), attnum, is_internal);
    2301             : 
    2302        1760 :     return attrdefOid;
    2303             : }
    2304             : 
    2305             : /*
    2306             :  * Store a check-constraint expression for the given relation.
    2307             :  *
    2308             :  * Caller is responsible for updating the count of constraints
    2309             :  * in the pg_class entry for the relation.
    2310             :  *
    2311             :  * The OID of the new constraint is returned.
    2312             :  */
    2313             : static Oid
    2314        1080 : StoreRelCheck(Relation rel, const char *ccname, Node *expr,
    2315             :               bool is_validated, bool is_local, int inhcount,
    2316             :               bool is_no_inherit, bool is_internal)
    2317             : {
    2318             :     char       *ccbin;
    2319             :     List       *varList;
    2320             :     int         keycount;
    2321             :     int16      *attNos;
    2322             :     Oid         constrOid;
    2323             : 
    2324             :     /*
    2325             :      * Flatten expression to string form for storage.
    2326             :      */
    2327        1080 :     ccbin = nodeToString(expr);
    2328             : 
    2329             :     /*
    2330             :      * Find columns of rel that are used in expr
    2331             :      *
    2332             :      * NB: pull_var_clause is okay here only because we don't allow subselects
    2333             :      * in check constraints; it would fail to examine the contents of
    2334             :      * subselects.
    2335             :      */
    2336        1080 :     varList = pull_var_clause(expr, 0);
    2337        1080 :     keycount = list_length(varList);
    2338             : 
    2339        1080 :     if (keycount > 0)
    2340             :     {
    2341             :         ListCell   *vl;
    2342        1074 :         int         i = 0;
    2343             : 
    2344        1074 :         attNos = (int16 *) palloc(keycount * sizeof(int16));
    2345        2394 :         foreach(vl, varList)
    2346             :         {
    2347        1320 :             Var        *var = (Var *) lfirst(vl);
    2348             :             int         j;
    2349             : 
    2350        1440 :             for (j = 0; j < i; j++)
    2351         256 :                 if (attNos[j] == var->varattno)
    2352         136 :                     break;
    2353        1320 :             if (j == i)
    2354        1184 :                 attNos[i++] = var->varattno;
    2355             :         }
    2356        1074 :         keycount = i;
    2357             :     }
    2358             :     else
    2359           6 :         attNos = NULL;
    2360             : 
    2361             :     /*
    2362             :      * Partitioned tables do not contain any rows themselves, so a NO INHERIT
    2363             :      * constraint makes no sense.
    2364             :      */
    2365        1140 :     if (is_no_inherit &&
    2366          60 :         rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    2367          12 :         ereport(ERROR,
    2368             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    2369             :                  errmsg("cannot add NO INHERIT constraint to partitioned table \"%s\"",
    2370             :                         RelationGetRelationName(rel))));
    2371             : 
    2372             :     /*
    2373             :      * Create the Check Constraint
    2374             :      */
    2375        1068 :     constrOid =
    2376        2136 :         CreateConstraintEntry(ccname,   /* Constraint Name */
    2377        1068 :                               RelationGetNamespace(rel),    /* namespace */
    2378             :                               CONSTRAINT_CHECK, /* Constraint Type */
    2379             :                               false,    /* Is Deferrable */
    2380             :                               false,    /* Is Deferred */
    2381             :                               is_validated,
    2382             :                               InvalidOid,   /* no parent constraint */
    2383             :                               RelationGetRelid(rel),    /* relation */
    2384             :                               attNos,   /* attrs in the constraint */
    2385             :                               keycount, /* # key attrs in the constraint */
    2386             :                               keycount, /* # total attrs in the constraint */
    2387             :                               InvalidOid,   /* not a domain constraint */
    2388             :                               InvalidOid,   /* no associated index */
    2389             :                               InvalidOid,   /* Foreign key fields */
    2390             :                               NULL,
    2391             :                               NULL,
    2392             :                               NULL,
    2393             :                               NULL,
    2394             :                               0,
    2395             :                               ' ',
    2396             :                               ' ',
    2397             :                               ' ',
    2398             :                               NULL, /* not an exclusion constraint */
    2399             :                               expr, /* Tree form of check constraint */
    2400             :                               ccbin,    /* Binary form of check constraint */
    2401             :                               is_local, /* conislocal */
    2402             :                               inhcount, /* coninhcount */
    2403             :                               is_no_inherit,    /* connoinherit */
    2404             :                               is_internal); /* internally constructed? */
    2405             : 
    2406        1068 :     pfree(ccbin);
    2407             : 
    2408        1068 :     return constrOid;
    2409             : }
    2410             : 
    2411             : /*
    2412             :  * Store defaults and constraints (passed as a list of CookedConstraint).
    2413             :  *
    2414             :  * Each CookedConstraint struct is modified to store the new catalog tuple OID.
    2415             :  *
    2416             :  * NOTE: only pre-cooked expressions will be passed this way, which is to
    2417             :  * say expressions inherited from an existing relation.  Newly parsed
    2418             :  * expressions can be added later, by direct calls to StoreAttrDefault
    2419             :  * and StoreRelCheck (see AddRelationNewConstraints()).
    2420             :  */
    2421             : static void
    2422      103482 : StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal)
    2423             : {
    2424      103482 :     int         numchecks = 0;
    2425             :     ListCell   *lc;
    2426             : 
    2427      103482 :     if (cooked_constraints == NIL)
    2428      103284 :         return;                 /* nothing to do */
    2429             : 
    2430             :     /*
    2431             :      * Deparsing of constraint expressions will fail unless the just-created
    2432             :      * pg_attribute tuples for this relation are made visible.  So, bump the
    2433             :      * command counter.  CAUTION: this will cause a relcache entry rebuild.
    2434             :      */
    2435         198 :     CommandCounterIncrement();
    2436             : 
    2437         442 :     foreach(lc, cooked_constraints)
    2438             :     {
    2439         244 :         CookedConstraint *con = (CookedConstraint *) lfirst(lc);
    2440             : 
    2441         244 :         switch (con->contype)
    2442             :         {
    2443             :             case CONSTR_DEFAULT:
    2444         148 :                 con->conoid = StoreAttrDefault(rel, con->attnum, con->expr,
    2445             :                                                is_internal, false);
    2446         148 :                 break;
    2447             :             case CONSTR_CHECK:
    2448          96 :                 con->conoid =
    2449         384 :                     StoreRelCheck(rel, con->name, con->expr,
    2450         288 :                                   !con->skip_validation, con->is_local,
    2451          96 :                                   con->inhcount, con->is_no_inherit,
    2452          96 :                                   is_internal);
    2453          96 :                 numchecks++;
    2454          96 :                 break;
    2455             :             default:
    2456           0 :                 elog(ERROR, "unrecognized constraint type: %d",
    2457             :                      (int) con->contype);
    2458             :         }
    2459             :     }
    2460             : 
    2461         198 :     if (numchecks > 0)
    2462          84 :         SetRelationNumChecks(rel, numchecks);
    2463             : }
    2464             : 
    2465             : /*
    2466             :  * AddRelationNewConstraints
    2467             :  *
    2468             :  * Add new column default expressions and/or constraint check expressions
    2469             :  * to an existing relation.  This is defined to do both for efficiency in
    2470             :  * DefineRelation, but of course you can do just one or the other by passing
    2471             :  * empty lists.
    2472             :  *
    2473             :  * rel: relation to be modified
    2474             :  * newColDefaults: list of RawColumnDefault structures
    2475             :  * newConstraints: list of Constraint nodes
    2476             :  * allow_merge: true if check constraints may be merged with existing ones
    2477             :  * is_local: true if definition is local, false if it's inherited
    2478             :  * is_internal: true if result of some internal process, not a user request
    2479             :  *
    2480             :  * All entries in newColDefaults will be processed.  Entries in newConstraints
    2481             :  * will be processed only if they are CONSTR_CHECK type.
    2482             :  *
    2483             :  * Returns a list of CookedConstraint nodes that shows the cooked form of
    2484             :  * the default and constraint expressions added to the relation.
    2485             :  *
    2486             :  * NB: caller should have opened rel with AccessExclusiveLock, and should
    2487             :  * hold that lock till end of transaction.  Also, we assume the caller has
    2488             :  * done a CommandCounterIncrement if necessary to make the relation's catalog
    2489             :  * tuples visible.
    2490             :  */
    2491             : List *
    2492        2568 : AddRelationNewConstraints(Relation rel,
    2493             :                           List *newColDefaults,
    2494             :                           List *newConstraints,
    2495             :                           bool allow_merge,
    2496             :                           bool is_local,
    2497             :                           bool is_internal,
    2498             :                           const char *queryString)
    2499             : {
    2500        2568 :     List       *cookedConstraints = NIL;
    2501             :     TupleDesc   tupleDesc;
    2502             :     TupleConstr *oldconstr;
    2503             :     int         numoldchecks;
    2504             :     ParseState *pstate;
    2505             :     RangeTblEntry *rte;
    2506             :     int         numchecks;
    2507             :     List       *checknames;
    2508             :     ListCell   *cell;
    2509             :     Node       *expr;
    2510             :     CookedConstraint *cooked;
    2511             : 
    2512             :     /*
    2513             :      * Get info about existing constraints.
    2514             :      */
    2515        2568 :     tupleDesc = RelationGetDescr(rel);
    2516        2568 :     oldconstr = tupleDesc->constr;
    2517        2568 :     if (oldconstr)
    2518        1830 :         numoldchecks = oldconstr->num_check;
    2519             :     else
    2520         738 :         numoldchecks = 0;
    2521             : 
    2522             :     /*
    2523             :      * Create a dummy ParseState and insert the target relation as its sole
    2524             :      * rangetable entry.  We need a ParseState for transformExpr.
    2525             :      */
    2526        2568 :     pstate = make_parsestate(NULL);
    2527        2568 :     pstate->p_sourcetext = queryString;
    2528        2568 :     rte = addRangeTableEntryForRelation(pstate,
    2529             :                                         rel,
    2530             :                                         AccessShareLock,
    2531             :                                         NULL,
    2532             :                                         false,
    2533             :                                         true);
    2534        2568 :     addRTEtoQuery(pstate, rte, true, true, true);
    2535             : 
    2536             :     /*
    2537             :      * Process column default expressions.
    2538             :      */
    2539        4270 :     foreach(cell, newColDefaults)
    2540             :     {
    2541        1778 :         RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell);
    2542        1778 :         Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1);
    2543             :         Oid         defOid;
    2544             : 
    2545        3556 :         expr = cookDefault(pstate, colDef->raw_default,
    2546             :                            atp->atttypid, atp->atttypmod,
    2547        1778 :                            NameStr(atp->attname),
    2548        1778 :                            atp->attgenerated);
    2549             : 
    2550             :         /*
    2551             :          * If the expression is just a NULL constant, we do not bother to make
    2552             :          * an explicit pg_attrdef entry, since the default behavior is
    2553             :          * equivalent.  This applies to column defaults, but not for
    2554             :          * generation expressions.
    2555             :          *
    2556             :          * Note a nonobvious property of this test: if the column is of a
    2557             :          * domain type, what we'll get is not a bare null Const but a
    2558             :          * CoerceToDomain expr, so we will not discard the default.  This is
    2559             :          * critical because the column default needs to be retained to
    2560             :          * override any default that the domain might have.
    2561             :          */
    2562        3404 :         if (expr == NULL ||
    2563        3212 :             (!colDef->generated &&
    2564        2244 :              IsA(expr, Const) &&
    2565         734 :              castNode(Const, expr)->constisnull))
    2566         110 :             continue;
    2567             : 
    2568             :         /* If the DEFAULT is volatile we cannot use a missing value */
    2569        1592 :         if (colDef->missingMode && contain_volatile_functions((Node *) expr))
    2570          20 :             colDef->missingMode = false;
    2571             : 
    2572        1592 :         defOid = StoreAttrDefault(rel, colDef->attnum, expr, is_internal,
    2573        1592 :                                   colDef->missingMode);
    2574             : 
    2575        1592 :         cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
    2576        1592 :         cooked->contype = CONSTR_DEFAULT;
    2577        1592 :         cooked->conoid = defOid;
    2578        1592 :         cooked->name = NULL;
    2579        1592 :         cooked->attnum = colDef->attnum;
    2580        1592 :         cooked->expr = expr;
    2581        1592 :         cooked->skip_validation = false;
    2582        1592 :         cooked->is_local = is_local;
    2583        1592 :         cooked->inhcount = is_local ? 0 : 1;
    2584        1592 :         cooked->is_no_inherit = false;
    2585        1592 :         cookedConstraints = lappend(cookedConstraints, cooked);
    2586             :     }
    2587             : 
    2588             :     /*
    2589             :      * Process constraint expressions.
    2590             :      */
    2591        2492 :     numchecks = numoldchecks;
    2592        2492 :     checknames = NIL;
    2593        3514 :     foreach(cell, newConstraints)
    2594             :     {
    2595        1070 :         Constraint *cdef = (Constraint *) lfirst(cell);
    2596             :         char       *ccname;
    2597             :         Oid         constrOid;
    2598             : 
    2599        1070 :         if (cdef->contype != CONSTR_CHECK)
    2600           0 :             continue;
    2601             : 
    2602        1070 :         if (cdef->raw_expr != NULL)
    2603             :         {
    2604             :             Assert(cdef->cooked_expr == NULL);
    2605             : 
    2606             :             /*
    2607             :              * Transform raw parsetree to executable expression, and verify
    2608             :              * it's valid as a CHECK constraint.
    2609             :              */
    2610        1030 :             expr = cookConstraint(pstate, cdef->raw_expr,
    2611        1030 :                                   RelationGetRelationName(rel));
    2612             :         }
    2613             :         else
    2614             :         {
    2615             :             Assert(cdef->cooked_expr != NULL);
    2616             : 
    2617             :             /*
    2618             :              * Here, we assume the parser will only pass us valid CHECK
    2619             :              * expressions, so we do no particular checking.
    2620             :              */
    2621          40 :             expr = stringToNode(cdef->cooked_expr);
    2622             :         }
    2623             : 
    2624             :         /*
    2625             :          * Check name uniqueness, or generate a name if none was given.
    2626             :          */
    2627        1050 :         if (cdef->conname != NULL)
    2628             :         {
    2629             :             ListCell   *cell2;
    2630             : 
    2631         790 :             ccname = cdef->conname;
    2632             :             /* Check against other new constraints */
    2633             :             /* Needed because we don't do CommandCounterIncrement in loop */
    2634         820 :             foreach(cell2, checknames)
    2635             :             {
    2636          30 :                 if (strcmp((char *) lfirst(cell2), ccname) == 0)
    2637           0 :                     ereport(ERROR,
    2638             :                             (errcode(ERRCODE_DUPLICATE_OBJECT),
    2639             :                              errmsg("check constraint \"%s\" already exists",
    2640             :                                     ccname)));
    2641             :             }
    2642             : 
    2643             :             /* save name for future checks */
    2644         790 :             checknames = lappend(checknames, ccname);
    2645             : 
    2646             :             /*
    2647             :              * Check against pre-existing constraints.  If we are allowed to
    2648             :              * merge with an existing constraint, there's no more to do here.
    2649             :              * (We omit the duplicate constraint from the result, which is
    2650             :              * what ATAddCheckConstraint wants.)
    2651             :              */
    2652        1580 :             if (MergeWithExistingConstraint(rel, ccname, expr,
    2653             :                                             allow_merge, is_local,
    2654         790 :                                             cdef->initially_valid,
    2655         790 :                                             cdef->is_no_inherit))
    2656          50 :                 continue;
    2657             :         }
    2658             :         else
    2659             :         {
    2660             :             /*
    2661             :              * When generating a name, we want to create "tab_col_check" for a
    2662             :              * column constraint and "tab_check" for a table constraint.  We
    2663             :              * no longer have any info about the syntactic positioning of the
    2664             :              * constraint phrase, so we approximate this by seeing whether the
    2665             :              * expression references more than one column.  (If the user
    2666             :              * played by the rules, the result is the same...)
    2667             :              *
    2668             :              * Note: pull_var_clause() doesn't descend into sublinks, but we
    2669             :              * eliminated those above; and anyway this only needs to be an
    2670             :              * approximate answer.
    2671             :              */
    2672             :             List       *vars;
    2673             :             char       *colname;
    2674             : 
    2675         260 :             vars = pull_var_clause(expr, 0);
    2676             : 
    2677             :             /* eliminate duplicates */
    2678         260 :             vars = list_union(NIL, vars);
    2679             : 
    2680         260 :             if (list_length(vars) == 1)
    2681         232 :                 colname = get_attname(RelationGetRelid(rel),
    2682         232 :                                       ((Var *) linitial(vars))->varattno,
    2683             :                                       true);
    2684             :             else
    2685          28 :                 colname = NULL;
    2686             : 
    2687         260 :             ccname = ChooseConstraintName(RelationGetRelationName(rel),
    2688             :                                           colname,
    2689             :                                           "check",
    2690         260 :                                           RelationGetNamespace(rel),
    2691             :                                           checknames);
    2692             : 
    2693             :             /* save name for future checks */
    2694         260 :             checknames = lappend(checknames, ccname);
    2695             :         }
    2696             : 
    2697             :         /*
    2698             :          * OK, store it.
    2699             :          */
    2700         984 :         constrOid =
    2701        1968 :             StoreRelCheck(rel, ccname, expr, cdef->initially_valid, is_local,
    2702         984 :                           is_local ? 0 : 1, cdef->is_no_inherit, is_internal);
    2703             : 
    2704         972 :         numchecks++;
    2705             : 
    2706         972 :         cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
    2707         972 :         cooked->contype = CONSTR_CHECK;
    2708         972 :         cooked->conoid = constrOid;
    2709         972 :         cooked->name = ccname;
    2710         972 :         cooked->attnum = 0;
    2711         972 :         cooked->expr = expr;
    2712         972 :         cooked->skip_validation = cdef->skip_validation;
    2713         972 :         cooked->is_local = is_local;
    2714         972 :         cooked->inhcount = is_local ? 0 : 1;
    2715         972 :         cooked->is_no_inherit = cdef->is_no_inherit;
    2716         972 :         cookedConstraints = lappend(cookedConstraints, cooked);
    2717             :     }
    2718             : 
    2719             :     /*
    2720             :      * Update the count of constraints in the relation's pg_class tuple. We do
    2721             :      * this even if there was no change, in order to ensure that an SI update
    2722             :      * message is sent out for the pg_class tuple, which will force other
    2723             :      * backends to rebuild their relcache entries for the rel. (This is
    2724             :      * critical if we added defaults but not constraints.)
    2725             :      */
    2726        2444 :     SetRelationNumChecks(rel, numchecks);
    2727             : 
    2728        2444 :     return cookedConstraints;
    2729             : }
    2730             : 
    2731             : /*
    2732             :  * Check for a pre-existing check constraint that conflicts with a proposed
    2733             :  * new one, and either adjust its conislocal/coninhcount settings or throw
    2734             :  * error as needed.
    2735             :  *
    2736             :  * Returns true if merged (constraint is a duplicate), or false if it's
    2737             :  * got a so-far-unique name, or throws error if conflict.
    2738             :  *
    2739             :  * XXX See MergeConstraintsIntoExisting too if you change this code.
    2740             :  */
    2741             : static bool
    2742         790 : MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr,
    2743             :                             bool allow_merge, bool is_local,
    2744             :                             bool is_initially_valid,
    2745             :                             bool is_no_inherit)
    2746             : {
    2747             :     bool        found;
    2748             :     Relation    conDesc;
    2749             :     SysScanDesc conscan;
    2750             :     ScanKeyData skey[3];
    2751             :     HeapTuple   tup;
    2752             : 
    2753             :     /* Search for a pg_constraint entry with same name and relation */
    2754         790 :     conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
    2755             : 
    2756         790 :     found = false;
    2757             : 
    2758         790 :     ScanKeyInit(&skey[0],
    2759             :                 Anum_pg_constraint_conrelid,
    2760             :                 BTEqualStrategyNumber, F_OIDEQ,
    2761         790 :                 ObjectIdGetDatum(RelationGetRelid(rel)));
    2762         790 :     ScanKeyInit(&skey[1],
    2763             :                 Anum_pg_constraint_contypid,
    2764             :                 BTEqualStrategyNumber, F_OIDEQ,
    2765             :                 ObjectIdGetDatum(InvalidOid));
    2766         790 :     ScanKeyInit(&skey[2],
    2767             :                 Anum_pg_constraint_conname,
    2768             :                 BTEqualStrategyNumber, F_NAMEEQ,
    2769             :                 CStringGetDatum(ccname));
    2770             : 
    2771         790 :     conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId, true,
    2772             :                                  NULL, 3, skey);
    2773             : 
    2774             :     /* There can be at most one matching row */
    2775         790 :     if (HeapTupleIsValid(tup = systable_getnext(conscan)))
    2776             :     {
    2777          66 :         Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
    2778             : 
    2779             :         /* Found it.  Conflicts if not identical check constraint */
    2780          66 :         if (con->contype == CONSTRAINT_CHECK)
    2781             :         {
    2782             :             Datum       val;
    2783             :             bool        isnull;
    2784             : 
    2785          62 :             val = fastgetattr(tup,
    2786             :                               Anum_pg_constraint_conbin,
    2787             :                               conDesc->rd_att, &isnull);
    2788          62 :             if (isnull)
    2789           0 :                 elog(ERROR, "null conbin for rel %s",
    2790             :                      RelationGetRelationName(rel));
    2791          62 :             if (equal(expr, stringToNode(TextDatumGetCString(val))))
    2792          58 :                 found = true;
    2793             :         }
    2794             : 
    2795             :         /*
    2796             :          * If the existing constraint is purely inherited (no local
    2797             :          * definition) then interpret addition of a local constraint as a
    2798             :          * legal merge.  This allows ALTER ADD CONSTRAINT on parent and child
    2799             :          * tables to be given in either order with same end state.  However if
    2800             :          * the relation is a partition, all inherited constraints are always
    2801             :          * non-local, including those that were merged.
    2802             :          */
    2803          66 :         if (is_local && !con->conislocal && !rel->rd_rel->relispartition)
    2804          24 :             allow_merge = true;
    2805             : 
    2806          66 :         if (!found || !allow_merge)
    2807           8 :             ereport(ERROR,
    2808             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    2809             :                      errmsg("constraint \"%s\" for relation \"%s\" already exists",
    2810             :                             ccname, RelationGetRelationName(rel))));
    2811             : 
    2812             :         /* If the child constraint is "no inherit" then cannot merge */
    2813          58 :         if (con->connoinherit)
    2814           0 :             ereport(ERROR,
    2815             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2816             :                      errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
    2817             :                             ccname, RelationGetRelationName(rel))));
    2818             : 
    2819             :         /*
    2820             :          * Must not change an existing inherited constraint to "no inherit"
    2821             :          * status.  That's because inherited constraints should be able to
    2822             :          * propagate to lower-level children.
    2823             :          */
    2824          58 :         if (con->coninhcount > 0 && is_no_inherit)
    2825           4 :             ereport(ERROR,
    2826             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2827             :                      errmsg("constraint \"%s\" conflicts with inherited constraint on relation \"%s\"",
    2828             :                             ccname, RelationGetRelationName(rel))));
    2829             : 
    2830             :         /*
    2831             :          * If the child constraint is "not valid" then cannot merge with a
    2832             :          * valid parent constraint.
    2833             :          */
    2834          54 :         if (is_initially_valid && !con->convalidated)
    2835           4 :             ereport(ERROR,
    2836             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2837             :                      errmsg("constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\"",
    2838             :                             ccname, RelationGetRelationName(rel))));
    2839             : 
    2840             :         /* OK to update the tuple */
    2841          50 :         ereport(NOTICE,
    2842             :                 (errmsg("merging constraint \"%s\" with inherited definition",
    2843             :                         ccname)));
    2844             : 
    2845          50 :         tup = heap_copytuple(tup);
    2846          50 :         con = (Form_pg_constraint) GETSTRUCT(tup);
    2847             : 
    2848             :         /*
    2849             :          * In case of partitions, an inherited constraint must be inherited
    2850             :          * only once since it cannot have multiple parents and it is never
    2851             :          * considered local.
    2852             :          */
    2853          50 :         if (rel->rd_rel->relispartition)
    2854             :         {
    2855           8 :             con->coninhcount = 1;
    2856           8 :             con->conislocal = false;
    2857             :         }
    2858             :         else
    2859             :         {
    2860          42 :             if (is_local)
    2861          20 :                 con->conislocal = true;
    2862             :             else
    2863          22 :                 con->coninhcount++;
    2864             :         }
    2865             : 
    2866          50 :         if (is_no_inherit)
    2867             :         {
    2868             :             Assert(is_local);
    2869           0 :             con->connoinherit = true;
    2870             :         }
    2871             : 
    2872          50 :         CatalogTupleUpdate(conDesc, &tup->t_self, tup);
    2873             :     }
    2874             : 
    2875         774 :     systable_endscan(conscan);
    2876         774 :     table_close(conDesc, RowExclusiveLock);
    2877             : 
    2878         774 :     return found;
    2879             : }
    2880             : 
    2881             : /*
    2882             :  * Update the count of constraints in the relation's pg_class tuple.
    2883             :  *
    2884             :  * Caller had better hold exclusive lock on the relation.
    2885             :  *
    2886             :  * An important side effect is that a SI update message will be sent out for
    2887             :  * the pg_class tuple, which will force other backends to rebuild their
    2888             :  * relcache entries for the rel.  Also, this backend will rebuild its
    2889             :  * own relcache entry at the next CommandCounterIncrement.
    2890             :  */
    2891             : static void
    2892        2528 : SetRelationNumChecks(Relation rel, int numchecks)
    2893             : {
    2894             :     Relation    relrel;
    2895             :     HeapTuple   reltup;
    2896             :     Form_pg_class relStruct;
    2897             : 
    2898        2528 :     relrel = table_open(RelationRelationId, RowExclusiveLock);
    2899        2528 :     reltup = SearchSysCacheCopy1(RELOID,
    2900             :                                  ObjectIdGetDatum(RelationGetRelid(rel)));
    2901        2528 :     if (!HeapTupleIsValid(reltup))
    2902           0 :         elog(ERROR, "cache lookup failed for relation %u",
    2903             :              RelationGetRelid(rel));
    2904        2528 :     relStruct = (Form_pg_class) GETSTRUCT(reltup);
    2905             : 
    2906        2528 :     if (relStruct->relchecks != numchecks)
    2907             :     {
    2908        1010 :         relStruct->relchecks = numchecks;
    2909             : 
    2910        1010 :         CatalogTupleUpdate(relrel, &reltup->t_self, reltup);
    2911             :     }
    2912             :     else
    2913             :     {
    2914             :         /* Skip the disk update, but force relcache inval anyway */
    2915        1518 :         CacheInvalidateRelcache(rel);
    2916             :     }
    2917             : 
    2918        2528 :     heap_freetuple(reltup);
    2919        2528 :     table_close(relrel, RowExclusiveLock);
    2920        2528 : }
    2921             : 
    2922             : /*
    2923             :  * Check for references to generated columns
    2924             :  */
    2925             : static bool
    2926         610 : check_nested_generated_walker(Node *node, void *context)
    2927             : {
    2928         610 :     ParseState *pstate = context;
    2929             : 
    2930         610 :     if (node == NULL)
    2931           0 :         return false;
    2932         610 :     else if (IsA(node, Var))
    2933             :     {
    2934         200 :         Var        *var = (Var *) node;
    2935             :         Oid         relid;
    2936             :         AttrNumber  attnum;
    2937             : 
    2938         200 :         relid = rt_fetch(var->varno, pstate->p_rtable)->relid;
    2939         200 :         attnum = var->varattno;
    2940             : 
    2941         200 :         if (OidIsValid(relid) && AttributeNumberIsValid(attnum) && get_attgenerated(relid, attnum))
    2942          12 :             ereport(ERROR,
    2943             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    2944             :                      errmsg("cannot use generated column \"%s\" in column generation expression",
    2945             :                             get_attname(relid, attnum, false)),
    2946             :                      errdetail("A generated column cannot reference another generated column."),
    2947             :                      parser_errposition(pstate, var->location)));
    2948             : 
    2949         188 :         return false;
    2950             :     }
    2951             :     else
    2952         410 :         return expression_tree_walker(node, check_nested_generated_walker,
    2953             :                                       (void *) context);
    2954             : }
    2955             : 
    2956             : static void
    2957         208 : check_nested_generated(ParseState *pstate, Node *node)
    2958             : {
    2959         208 :     check_nested_generated_walker(node, pstate);
    2960         196 : }
    2961             : 
    2962             : /*
    2963             :  * Take a raw default and convert it to a cooked format ready for
    2964             :  * storage.
    2965             :  *
    2966             :  * Parse state should be set up to recognize any vars that might appear
    2967             :  * in the expression.  (Even though we plan to reject vars, it's more
    2968             :  * user-friendly to give the correct error message than "unknown var".)
    2969             :  *
    2970             :  * If atttypid is not InvalidOid, coerce the expression to the specified
    2971             :  * type (and typmod atttypmod).   attname is only needed in this case:
    2972             :  * it is used in the error message, if any.
    2973             :  */
    2974             : Node *
    2975        2130 : cookDefault(ParseState *pstate,
    2976             :             Node *raw_default,
    2977             :             Oid atttypid,
    2978             :             int32 atttypmod,
    2979             :             const char *attname,
    2980             :             char attgenerated)
    2981             : {
    2982             :     Node       *expr;
    2983             : 
    2984             :     Assert(raw_default != NULL);
    2985             : 
    2986             :     /*
    2987             :      * Transform raw parsetree to executable expression.
    2988             :      */
    2989        2130 :     expr = transformExpr(pstate, raw_default, attgenerated ? EXPR_KIND_GENERATED_COLUMN : EXPR_KIND_COLUMN_DEFAULT);
    2990             : 
    2991        2074 :     if (attgenerated)
    2992             :     {
    2993         208 :         check_nested_generated(pstate, expr);
    2994             : 
    2995         196 :         if (contain_mutable_functions(expr))
    2996           4 :             ereport(ERROR,
    2997             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2998             :                      errmsg("generation expression is not immutable")));
    2999             :     }
    3000             :     else
    3001             :     {
    3002             :         /*
    3003             :          * For a default expression, transformExpr() should have rejected
    3004             :          * column references.
    3005             :          */
    3006             :         Assert(!contain_var_clause(expr));
    3007             :     }
    3008             : 
    3009             :     /*
    3010             :      * Coerce the expression to the correct type and typmod, if given. This
    3011             :      * should match the parser's processing of non-defaulted expressions ---
    3012             :      * see transformAssignedExpr().
    3013             :      */
    3014        2058 :     if (OidIsValid(atttypid))
    3015             :     {
    3016        2058 :         Oid         type_id = exprType(expr);
    3017             : 
    3018        2058 :         expr = coerce_to_target_type(pstate, expr, type_id,
    3019             :                                      atttypid, atttypmod,
    3020             :                                      COERCION_ASSIGNMENT,
    3021             :                                      COERCE_IMPLICIT_CAST,
    3022             :                                      -1);
    3023        2054 :         if (expr == NULL)
    3024           0 :             ereport(ERROR,
    3025             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3026             :                      errmsg("column \"%s\" is of type %s"
    3027             :                             " but default expression is of type %s",
    3028             :                             attname,
    3029             :                             format_type_be(atttypid),
    3030             :                             format_type_be(type_id)),
    3031             :                      errhint("You will need to rewrite or cast the expression.")));
    3032             :     }
    3033             : 
    3034             :     /*
    3035             :      * Finally, take care of collations in the finished expression.
    3036             :      */
    3037        2054 :     assign_expr_collations(pstate, expr);
    3038             : 
    3039        2054 :     return expr;
    3040             : }
    3041             : 
    3042             : /*
    3043             :  * Take a raw CHECK constraint expression and convert it to a cooked format
    3044             :  * ready for storage.
    3045             :  *
    3046             :  * Parse state must be set up to recognize any vars that might appear
    3047             :  * in the expression.
    3048             :  */
    3049             : static Node *
    3050        1030 : cookConstraint(ParseState *pstate,
    3051             :                Node *raw_constraint,
    3052             :                char *relname)
    3053             : {
    3054             :     Node       *expr;
    3055             : 
    3056             :     /*
    3057             :      * Transform raw parsetree to executable expression.
    3058             :      */
    3059        1030 :     expr = transformExpr(pstate, raw_constraint, EXPR_KIND_CHECK_CONSTRAINT);
    3060             : 
    3061             :     /*
    3062             :      * Make sure it yields a boolean result.
    3063             :      */
    3064        1010 :     expr = coerce_to_boolean(pstate, expr, "CHECK");
    3065             : 
    3066             :     /*
    3067             :      * Take care of collations.
    3068             :      */
    3069        1010 :     assign_expr_collations(pstate, expr);
    3070             : 
    3071             :     /*
    3072             :      * Make sure no outside relations are referred to (this is probably dead
    3073             :      * code now that add_missing_from is history).
    3074             :      */
    3075        1010 :     if (list_length(pstate->p_rtable) != 1)
    3076           0 :         ereport(ERROR,
    3077             :                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
    3078             :                  errmsg("only table \"%s\" can be referenced in check constraint",
    3079             :                         relname)));
    3080             : 
    3081        1010 :     return expr;
    3082             : }
    3083             : 
    3084             : 
    3085             : /*
    3086             :  * RemoveStatistics --- remove entries in pg_statistic for a rel or column
    3087             :  *
    3088             :  * If attnum is zero, remove all entries for rel; else remove only the one(s)
    3089             :  * for that column.
    3090             :  */
    3091             : void
    3092       24214 : RemoveStatistics(Oid relid, AttrNumber attnum)
    3093             : {
    3094             :     Relation    pgstatistic;
    3095             :     SysScanDesc scan;
    3096             :     ScanKeyData key[2];
    3097             :     int         nkeys;
    3098             :     HeapTuple   tuple;
    3099             : 
    3100       24214 :     pgstatistic = table_open(StatisticRelationId, RowExclusiveLock);
    3101             : 
    3102       24214 :     ScanKeyInit(&key[0],
    3103             :                 Anum_pg_statistic_starelid,
    3104             :                 BTEqualStrategyNumber, F_OIDEQ,
    3105             :                 ObjectIdGetDatum(relid));
    3106             : 
    3107       24214 :     if (attnum == 0)
    3108       22500 :         nkeys = 1;
    3109             :     else
    3110             :     {
    3111        1714 :         ScanKeyInit(&key[1],
    3112             :                     Anum_pg_statistic_staattnum,
    3113             :                     BTEqualStrategyNumber, F_INT2EQ,
    3114             :                     Int16GetDatum(attnum));
    3115        1714 :         nkeys = 2;
    3116             :     }
    3117             : 
    3118       24214 :     scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
    3119             :                               NULL, nkeys, key);
    3120             : 
    3121             :     /* we must loop even when attnum != 0, in case of inherited stats */
    3122       48926 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
    3123         498 :         CatalogTupleDelete(pgstatistic, &tuple->t_self);
    3124             : 
    3125       24214 :     systable_endscan(scan);
    3126             : 
    3127       24214 :     table_close(pgstatistic, RowExclusiveLock);
    3128       24214 : }
    3129             : 
    3130             : 
    3131             : /*
    3132             :  * RelationTruncateIndexes - truncate all indexes associated
    3133             :  * with the heap relation to zero tuples.
    3134             :  *
    3135             :  * The routine will truncate and then reconstruct the indexes on
    3136             :  * the specified relation.  Caller must hold exclusive lock on rel.
    3137             :  */
    3138             : static void
    3139         284 : RelationTruncateIndexes(Relation heapRelation)
    3140             : {
    3141             :     ListCell   *indlist;
    3142             : 
    3143             :     /* Ask the relcache to produce a list of the indexes of the rel */
    3144         312 :     foreach(indlist, RelationGetIndexList(heapRelation))
    3145             :     {
    3146          28 :         Oid         indexId = lfirst_oid(indlist);
    3147             :         Relation    currentIndex;
    3148             :         IndexInfo  *indexInfo;
    3149             : 
    3150             :         /* Open the index relation; use exclusive lock, just to be sure */
    3151          28 :         currentIndex = index_open(indexId, AccessExclusiveLock);
    3152             : 
    3153             :         /* Fetch info needed for index_build */
    3154          28 :         indexInfo = BuildIndexInfo(currentIndex);
    3155             : 
    3156             :         /*
    3157             :          * Now truncate the actual file (and discard buffers).
    3158             :          */
    3159          28 :         RelationTruncate(currentIndex, 0);
    3160             : 
    3161             :         /* Initialize the index and rebuild */
    3162             :         /* Note: we do not need to re-establish pkey setting */
    3163          28 :         index_build(heapRelation, currentIndex, indexInfo, true, false);
    3164             : 
    3165             :         /* We're done with this index */
    3166          28 :         index_close(currentIndex, NoLock);
    3167             :     }
    3168         284 : }
    3169             : 
    3170             : /*
    3171             :  *   heap_truncate
    3172             :  *
    3173             :  *   This routine deletes all data within all the specified relations.
    3174             :  *
    3175             :  * This is not transaction-safe!  There is another, transaction-safe
    3176             :  * implementation in commands/tablecmds.c.  We now use this only for
    3177             :  * ON COMMIT truncation of temporary tables, where it doesn't matter.
    3178             :  */
    3179             : void
    3180         160 : heap_truncate(List *relids)
    3181             : {
    3182         160 :     List       *relations = NIL;
    3183             :     ListCell   *cell;
    3184             : 
    3185             :     /* Open relations for processing, and grab exclusive access on each */
    3186         364 :     foreach(cell, relids)
    3187             :     {
    3188         204 :         Oid         rid = lfirst_oid(cell);
    3189             :         Relation    rel;
    3190             : 
    3191         204 :         rel = table_open(rid, AccessExclusiveLock);
    3192         204 :         relations = lappend(relations, rel);
    3193             :     }
    3194             : 
    3195             :     /* Don't allow truncate on tables that are referenced by foreign keys */
    3196         160 :     heap_truncate_check_FKs(relations, true);
    3197             : 
    3198             :     /* OK to do it */
    3199         352 :     foreach(cell, relations)
    3200             :     {
    3201         196 :         Relation    rel = lfirst(cell);
    3202             : 
    3203             :         /* Truncate the relation */
    3204         196 :         heap_truncate_one_rel(rel);
    3205             : 
    3206             :         /* Close the relation, but keep exclusive lock on it until commit */
    3207         196 :         table_close(rel, NoLock);
    3208             :     }
    3209         156 : }
    3210             : 
    3211             : /*
    3212             :  *   heap_truncate_one_rel
    3213             :  *
    3214             :  *   This routine deletes all data within the specified relation.
    3215             :  *
    3216             :  * This is not transaction-safe, because the truncation is done immediately
    3217             :  * and cannot be rolled back later.  Caller is responsible for having
    3218             :  * checked permissions etc, and must have obtained AccessExclusiveLock.
    3219             :  */
    3220             : void
    3221         276 : heap_truncate_one_rel(Relation rel)
    3222             : {
    3223             :     Oid         toastrelid;
    3224             : 
    3225             :     /*
    3226             :      * Truncate the relation.  Partitioned tables have no storage, so there is
    3227             :      * nothing to do for them here.
    3228             :      */
    3229         276 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    3230          16 :         return;
    3231             : 
    3232             :     /* Truncate the underlying relation */
    3233         260 :     table_relation_nontransactional_truncate(rel);
    3234             : 
    3235             :     /* If the relation has indexes, truncate the indexes too */
    3236         260 :     RelationTruncateIndexes(rel);
    3237             : 
    3238             :     /* If there is a toast table, truncate that too */
    3239         260 :     toastrelid = rel->rd_rel->reltoastrelid;
    3240         260 :     if (OidIsValid(toastrelid))
    3241             :     {
    3242          24 :         Relation    toastrel = table_open(toastrelid, AccessExclusiveLock);
    3243             : 
    3244          24 :         table_relation_nontransactional_truncate(toastrel);
    3245          24 :         RelationTruncateIndexes(toastrel);
    3246             :         /* keep the lock... */
    3247          24 :         table_close(toastrel, NoLock);
    3248             :     }
    3249             : }
    3250             : 
    3251             : /*
    3252             :  * heap_truncate_check_FKs
    3253             :  *      Check for foreign keys referencing a list of relations that
    3254             :  *      are to be truncated, and raise error if there are any
    3255             :  *
    3256             :  * We disallow such FKs (except self-referential ones) since the whole point
    3257             :  * of TRUNCATE is to not scan the individual rows to be thrown away.
    3258             :  *
    3259             :  * This is split out so it can be shared by both implementations of truncate.
    3260             :  * Caller should already hold a suitable lock on the relations.
    3261             :  *
    3262             :  * tempTables is only used to select an appropriate error message.
    3263             :  */
    3264             : void
    3265         856 : heap_truncate_check_FKs(List *relations, bool tempTables)
    3266             : {
    3267         856 :     List       *oids = NIL;
    3268             :     List       *dependents;
    3269             :     ListCell   *cell;
    3270             : 
    3271             :     /*
    3272             :      * Build a list of OIDs of the interesting relations.
    3273             :      *
    3274             :      * If a relation has no triggers, then it can neither have FKs nor be
    3275             :      * referenced by a FK from another table, so we can ignore it.  For
    3276             :      * partitioned tables, FKs have no triggers, so we must include them
    3277             :      * anyway.
    3278             :      */
    3279        2902 :     foreach(cell, relations)
    3280             :     {
    3281        2046 :         Relation    rel = lfirst(cell);
    3282             : 
    3283        3510 :         if (rel->rd_rel->relhastriggers ||
    3284        1464 :             rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    3285         926 :             oids = lappend_oid(oids, RelationGetRelid(rel));
    3286             :     }
    3287             : 
    3288             :     /*
    3289             :      * Fast path: if no relation has triggers, none has FKs either.
    3290             :      */
    3291         856 :     if (oids == NIL)
    3292         474 :         return;
    3293             : 
    3294             :     /*
    3295             :      * Otherwise, must scan pg_constraint.  We make one pass with all the
    3296             :      * relations considered; if this finds nothing, then all is well.
    3297             :      */
    3298         382 :     dependents = heap_truncate_find_FKs(oids);
    3299         382 :     if (dependents == NIL)
    3300         330 :         return;
    3301             : 
    3302             :     /*
    3303             :      * Otherwise we repeat the scan once per relation to identify a particular
    3304             :      * pair of relations to complain about.  This is pretty slow, but
    3305             :      * performance shouldn't matter much in a failure path.  The reason for
    3306             :      * doing things this way is to ensure that the message produced is not
    3307             :      * dependent on chance row locations within pg_constraint.
    3308             :      */
    3309          68 :     foreach(cell, oids)
    3310             :     {
    3311          68 :         Oid         relid = lfirst_oid(cell);
    3312             :         ListCell   *cell2;
    3313             : 
    3314          68 :         dependents = heap_truncate_find_FKs(list_make1_oid(relid));
    3315             : 
    3316         108 :         foreach(cell2, dependents)
    3317             :         {
    3318          92 :             Oid         relid2 = lfirst_oid(cell2);
    3319             : 
    3320          92 :             if (!list_member_oid(oids, relid2))
    3321             :             {
    3322          52 :                 char       *relname = get_rel_name(relid);
    3323          52 :                 char       *relname2 = get_rel_name(relid2);
    3324             : 
    3325          52 :                 if (tempTables)
    3326           4 :                     ereport(ERROR,
    3327             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3328             :                              errmsg("unsupported ON COMMIT and foreign key combination"),
    3329             :                              errdetail("Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting.",
    3330             :                                        relname2, relname)));
    3331             :                 else
    3332          48 :                     ereport(ERROR,
    3333             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3334             :                              errmsg("cannot truncate a table referenced in a foreign key constraint"),
    3335             :                              errdetail("Table \"%s\" references \"%s\".",
    3336             :                                        relname2, relname),
    3337             :                              errhint("Truncate table \"%s\" at the same time, "
    3338             :                                      "or use TRUNCATE ... CASCADE.",
    3339             :                                      relname2)));
    3340             :             }
    3341             :         }
    3342             :     }
    3343             : }
    3344             : 
    3345             : /*
    3346             :  * heap_truncate_find_FKs
    3347             :  *      Find relations having foreign keys referencing any of the given rels
    3348             :  *
    3349             :  * Input and result are both lists of relation OIDs.  The result contains
    3350             :  * no duplicates, does *not* include any rels that were already in the input
    3351             :  * list, and is sorted in OID order.  (The last property is enforced mainly
    3352             :  * to guarantee consistent behavior in the regression tests; we don't want
    3353             :  * behavior to change depending on chance locations of rows in pg_constraint.)
    3354             :  *
    3355             :  * Note: caller should already have appropriate lock on all rels mentioned
    3356             :  * in relationIds.  Since adding or dropping an FK requires exclusive lock
    3357             :  * on both rels, this ensures that the answer will be stable.
    3358             :  */
    3359             : List *
    3360         480 : heap_truncate_find_FKs(List *relationIds)
    3361             : {
    3362         480 :     List       *result = NIL;
    3363             :     Relation    fkeyRel;
    3364             :     SysScanDesc fkeyScan;
    3365             :     HeapTuple   tuple;
    3366             : 
    3367             :     /*
    3368             :      * Must scan pg_constraint.  Right now, it is a seqscan because there is
    3369             :      * no available index on confrelid.
    3370             :      */
    3371         480 :     fkeyRel = table_open(ConstraintRelationId, AccessShareLock);
    3372             : 
    3373         480 :     fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false,
    3374             :                                   NULL, 0, NULL);
    3375             : 
    3376       51482 :     while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))
    3377             :     {
    3378       50522 :         Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
    3379             : 
    3380             :         /* Not a foreign key */
    3381       50522 :         if (con->contype != CONSTRAINT_FOREIGN)
    3382       32524 :             continue;
    3383             : 
    3384             :         /* Not referencing one of our list of tables */
    3385       17998 :         if (!list_member_oid(relationIds, con->confrelid))
    3386       17510 :             continue;
    3387             : 
    3388             :         /* Add referencer unless already in input or result list */
    3389         488 :         if (!list_member_oid(relationIds, con->conrelid))
    3390         296 :             result = insert_ordered_unique_oid(result, con->conrelid);
    3391             :     }
    3392             : 
    3393         480 :     systable_endscan(fkeyScan);
    3394         480 :     table_close(fkeyRel, AccessShareLock);
    3395             : 
    3396         480 :     return result;
    3397             : }
    3398             : 
    3399             : /*
    3400             :  * insert_ordered_unique_oid
    3401             :  *      Insert a new Oid into a sorted list of Oids, preserving ordering,
    3402             :  *      and eliminating duplicates
    3403             :  *
    3404             :  * Building the ordered list this way is O(N^2), but with a pretty small
    3405             :  * constant, so for the number of entries we expect it will probably be
    3406             :  * faster than trying to apply qsort().  It seems unlikely someone would be
    3407             :  * trying to truncate a table with thousands of dependent tables ...
    3408             :  */
    3409             : static List *
    3410         296 : insert_ordered_unique_oid(List *list, Oid datum)
    3411             : {
    3412             :     ListCell   *prev;
    3413             : 
    3414             :     /* Does the datum belong at the front? */
    3415         296 :     if (list == NIL || datum < linitial_oid(list))
    3416         152 :         return lcons_oid(datum, list);
    3417             :     /* Does it match the first entry? */
    3418         144 :     if (datum == linitial_oid(list))
    3419           0 :         return list;            /* duplicate, so don't insert */
    3420             :     /* No, so find the entry it belongs after */
    3421         144 :     prev = list_head(list);
    3422             :     for (;;)
    3423          80 :     {
    3424         224 :         ListCell   *curr = lnext(prev);
    3425             : 
    3426         224 :         if (curr == NULL || datum < lfirst_oid(curr))
    3427             :             break;              /* it belongs after 'prev', before 'curr' */
    3428             : 
    3429          88 :         if (datum == lfirst_oid(curr))
    3430           8 :             return list;        /* duplicate, so don't insert */
    3431             : 
    3432          80 :         prev = curr;
    3433             :     }
    3434             :     /* Insert datum into list after 'prev' */
    3435         136 :     lappend_cell_oid(list, prev, datum);
    3436         136 :     return list;
    3437             : }
    3438             : 
    3439             : /*
    3440             :  * StorePartitionKey
    3441             :  *      Store information about the partition key rel into the catalog
    3442             :  */
    3443             : void
    3444        2032 : StorePartitionKey(Relation rel,
    3445             :                   char strategy,
    3446             :                   int16 partnatts,
    3447             :                   AttrNumber *partattrs,
    3448             :                   List *partexprs,
    3449             :                   Oid *partopclass,
    3450             :                   Oid *partcollation)
    3451             : {
    3452             :     int         i;
    3453             :     int2vector *partattrs_vec;
    3454             :     oidvector  *partopclass_vec;
    3455             :     oidvector  *partcollation_vec;
    3456             :     Datum       partexprDatum;
    3457             :     Relation    pg_partitioned_table;
    3458             :     HeapTuple   tuple;
    3459             :     Datum       values[Natts_pg_partitioned_table];
    3460             :     bool        nulls[Natts_pg_partitioned_table];
    3461             :     ObjectAddress myself;
    3462             :     ObjectAddress referenced;
    3463             : 
    3464             :     Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
    3465             : 
    3466             :     /* Copy the partition attribute numbers, opclass OIDs into arrays */
    3467        2032 :     partattrs_vec = buildint2vector(partattrs, partnatts);
    3468        2032 :     partopclass_vec = buildoidvector(partopclass, partnatts);
    3469        2032 :     partcollation_vec = buildoidvector(partcollation, partnatts);
    3470             : 
    3471             :     /* Convert the expressions (if any) to a text datum */
    3472        2032 :     if (partexprs)
    3473             :     {
    3474             :         char       *exprString;
    3475             : 
    3476         124 :         exprString = nodeToString(partexprs);
    3477         124 :         partexprDatum = CStringGetTextDatum(exprString);
    3478         124 :         pfree(exprString);
    3479             :     }
    3480             :     else
    3481        1908 :         partexprDatum = (Datum) 0;
    3482             : 
    3483        2032 :     pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock);
    3484             : 
    3485        2032 :     MemSet(nulls, false, sizeof(nulls));
    3486             : 
    3487             :     /* Only this can ever be NULL */
    3488        2032 :     if (!partexprDatum)
    3489        1908 :         nulls[Anum_pg_partitioned_table_partexprs - 1] = true;
    3490             : 
    3491        2032 :     values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
    3492        2032 :     values[Anum_pg_partitioned_table_partstrat - 1] = CharGetDatum(strategy);
    3493        2032 :     values[Anum_pg_partitioned_table_partnatts - 1] = Int16GetDatum(partnatts);
    3494        2032 :     values[Anum_pg_partitioned_table_partdefid - 1] = ObjectIdGetDatum(InvalidOid);
    3495        2032 :     values[Anum_pg_partitioned_table_partattrs - 1] = PointerGetDatum(partattrs_vec);
    3496        2032 :     values[Anum_pg_partitioned_table_partclass - 1] = PointerGetDatum(partopclass_vec);
    3497        2032 :     values[Anum_pg_partitioned_table_partcollation - 1] = PointerGetDatum(partcollation_vec);
    3498        2032 :     values[Anum_pg_partitioned_table_partexprs - 1] = partexprDatum;
    3499             : 
    3500        2032 :     tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls);
    3501             : 
    3502        2032 :     CatalogTupleInsert(pg_partitioned_table, tuple);
    3503        2032 :     table_close(pg_partitioned_table, RowExclusiveLock);
    3504             : 
    3505             :     /* Mark this relation as dependent on a few things as follows */
    3506        2032 :     myself.classId = RelationRelationId;
    3507        2032 :     myself.objectId = RelationGetRelid(rel);
    3508        2032 :     myself.objectSubId = 0;
    3509             : 
    3510             :     /* Operator class and collation per key column */
    3511        4270 :     for (i = 0; i < partnatts; i++)
    3512             :     {
    3513        2238 :         referenced.classId = OperatorClassRelationId;
    3514        2238 :         referenced.objectId = partopclass[i];
    3515        2238 :         referenced.objectSubId = 0;
    3516             : 
    3517        2238 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    3518             : 
    3519             :         /* The default collation is pinned, so don't bother recording it */
    3520        2516 :         if (OidIsValid(partcollation[i]) &&
    3521         278 :             partcollation[i] != DEFAULT_COLLATION_OID)
    3522             :         {
    3523          24 :             referenced.classId = CollationRelationId;
    3524          24 :             referenced.objectId = partcollation[i];
    3525          24 :             referenced.objectSubId = 0;
    3526             : 
    3527          24 :             recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    3528             :         }
    3529             :     }
    3530             : 
    3531             :     /*
    3532             :      * Anything mentioned in the expressions.  We must ignore the column
    3533             :      * references, which will depend on the table itself; there is no separate
    3534             :      * partition key object.
    3535             :      */
    3536        2032 :     if (partexprs)
    3537         124 :         recordDependencyOnSingleRelExpr(&myself,
    3538             :                                         (Node *) partexprs,
    3539             :                                         RelationGetRelid(rel),
    3540             :                                         DEPENDENCY_NORMAL,
    3541             :                                         DEPENDENCY_AUTO, true);
    3542             : 
    3543             :     /*
    3544             :      * We must invalidate the relcache so that the next
    3545             :      * CommandCounterIncrement() will cause the same to be rebuilt using the
    3546             :      * information in just created catalog entry.
    3547             :      */
    3548        2032 :     CacheInvalidateRelcache(rel);
    3549        2032 : }
    3550             : 
    3551             : /*
    3552             :  *  RemovePartitionKeyByRelId
    3553             :  *      Remove pg_partitioned_table entry for a relation
    3554             :  */
    3555             : void
    3556        1606 : RemovePartitionKeyByRelId(Oid relid)
    3557             : {
    3558             :     Relation    rel;
    3559             :     HeapTuple   tuple;
    3560             : 
    3561        1606 :     rel = table_open(PartitionedRelationId, RowExclusiveLock);
    3562             : 
    3563        1606 :     tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
    3564        1606 :     if (!HeapTupleIsValid(tuple))
    3565           0 :         elog(ERROR, "cache lookup failed for partition key of relation %u",
    3566             :              relid);
    3567             : 
    3568        1606 :     CatalogTupleDelete(rel, &tuple->t_self);
    3569             : 
    3570        1606 :     ReleaseSysCache(tuple);
    3571        1606 :     table_close(rel, RowExclusiveLock);
    3572        1606 : }
    3573             : 
    3574             : /*
    3575             :  * StorePartitionBound
    3576             :  *      Update pg_class tuple of rel to store the partition bound and set
    3577             :  *      relispartition to true
    3578             :  *
    3579             :  * If this is the default partition, also update the default partition OID in
    3580             :  * pg_partitioned_table.
    3581             :  *
    3582             :  * Also, invalidate the parent's relcache, so that the next rebuild will load
    3583             :  * the new partition's info into its partition descriptor.  If there is a
    3584             :  * default partition, we must invalidate its relcache entry as well.
    3585             :  */
    3586             : void
    3587        4146 : StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
    3588             : {
    3589             :     Relation    classRel;
    3590             :     HeapTuple   tuple,
    3591             :                 newtuple;
    3592             :     Datum       new_val[Natts_pg_class];
    3593             :     bool        new_null[Natts_pg_class],
    3594             :                 new_repl[Natts_pg_class];
    3595             :     Oid         defaultPartOid;
    3596             : 
    3597             :     /* Update pg_class tuple */
    3598        4146 :     classRel = table_open(RelationRelationId, RowExclusiveLock);
    3599        4146 :     tuple = SearchSysCacheCopy1(RELOID,
    3600             :                                 ObjectIdGetDatum(RelationGetRelid(rel)));
    3601        4146 :     if (!HeapTupleIsValid(tuple))
    3602           0 :         elog(ERROR, "cache lookup failed for relation %u",
    3603             :              RelationGetRelid(rel));
    3604             : 
    3605             : #ifdef USE_ASSERT_CHECKING
    3606             :     {
    3607             :         Form_pg_class classForm;
    3608             :         bool        isnull;
    3609             : 
    3610             :         classForm = (Form_pg_class) GETSTRUCT(tuple);
    3611             :         Assert(!classForm->relispartition);
    3612             :         (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound,
    3613             :                                &isnull);
    3614             :         Assert(isnull);
    3615             :     }
    3616             : #endif
    3617             : 
    3618             :     /* Fill in relpartbound value */
    3619        4146 :     memset(new_val, 0, sizeof(new_val));
    3620        4146 :     memset(new_null, false, sizeof(new_null));
    3621        4146 :     memset(new_repl, false, sizeof(new_repl));
    3622        4146 :     new_val[Anum_pg_class_relpartbound - 1] = CStringGetTextDatum(nodeToString(bound));
    3623        4146 :     new_null[Anum_pg_class_relpartbound - 1] = false;
    3624        4146 :     new_repl[Anum_pg_class_relpartbound - 1] = true;
    3625        4146 :     newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
    3626             :                                  new_val, new_null, new_repl);
    3627             :     /* Also set the flag */
    3628        4146 :     ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true;
    3629        4146 :     CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
    3630        4146 :     heap_freetuple(newtuple);
    3631        4146 :     table_close(classRel, RowExclusiveLock);
    3632             : 
    3633             :     /*
    3634             :      * If we're storing bounds for the default partition, update
    3635             :      * pg_partitioned_table too.
    3636             :      */
    3637        4146 :     if (bound->is_default)
    3638         222 :         update_default_partition_oid(RelationGetRelid(parent),
    3639             :                                      RelationGetRelid(rel));
    3640             : 
    3641             :     /* Make these updates visible */
    3642        4146 :     CommandCounterIncrement();
    3643             : 
    3644             :     /*
    3645             :      * The partition constraint for the default partition depends on the
    3646             :      * partition bounds of every other partition, so we must invalidate the
    3647             :      * relcache entry for that partition every time a partition is added or
    3648             :      * removed.
    3649             :      */
    3650        4146 :     defaultPartOid = get_default_oid_from_partdesc(RelationGetPartitionDesc(parent));
    3651        4146 :     if (OidIsValid(defaultPartOid))
    3652         314 :         CacheInvalidateRelcacheByRelid(defaultPartOid);
    3653             : 
    3654        4146 :     CacheInvalidateRelcache(parent);
    3655        4146 : }

Generated by: LCOV version 1.13