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

Generated by: LCOV version 1.11