]> granicus.if.org Git - postgresql/blobdiff - src/backend/catalog/heap.c
Revise collation derivation method and expression-tree representation.
[postgresql] / src / backend / catalog / heap.c
index 769b3b635755cba06db16a6ef098e5b218a2bc70..567eb7fd6ebb42acff259e71235c651f2440a3a6 100644 (file)
@@ -3,12 +3,12 @@
  * heap.c
  *       code to create and destroy POSTGRES heap relations
  *
- * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.345 2008/11/19 10:34:51 heikki Exp $
+ *       src/backend/catalog/heap.c
  *
  *
  * INTERFACE ROUTINES
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/indexing.h"
+#include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_attrdef.h"
+#include "catalog/pg_collation.h"
 #include "catalog/pg_constraint.h"
+#include "catalog/pg_foreign_table.h"
 #include "catalog/pg_inherits.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_statistic.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/var.h"
 #include "parser/parse_coerce.h"
+#include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
 #include "storage/bufmgr.h"
 #include "storage/freespace.h"
 #include "storage/smgr.h"
+#include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/inval.h"
 #include "utils/tqual.h"
 
 
+/* Potentially set by contrib/pg_upgrade_support functions */
+Oid                    binary_upgrade_next_heap_pg_class_oid = InvalidOid;
+Oid                    binary_upgrade_next_toast_pg_class_oid = InvalidOid;
+
 static void AddNewRelationTuple(Relation pg_class_desc,
                                        Relation new_rel_desc,
-                                       Oid new_rel_oid, Oid new_type_oid,
+                                       Oid new_rel_oid,
+                                       Oid new_type_oid,
+                                       Oid reloftype,
                                        Oid relowner,
                                        char relkind,
+                                       Datum relacl,
                                        Datum reloptions);
 static Oid AddNewRelationType(const char *typeName,
                                   Oid typeNamespace,
                                   Oid new_rel_oid,
                                   char new_rel_kind,
+                                  Oid ownerid,
+                                  Oid new_row_type,
                                   Oid new_array_type);
 static void RelationRemoveInheritance(Oid relid);
 static void StoreRelCheck(Relation rel, char *ccname, Node *expr,
-                                                 bool is_local, int inhcount);
+                         bool is_local, int inhcount);
 static void StoreConstraints(Relation rel, List *cooked_constraints);
 static bool MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
-                                                                               bool allow_merge, bool is_local);
+                                                       bool allow_merge, bool is_local);
 static void SetRelationNumChecks(Relation rel, int numchecks);
 static Node *cookConstraint(ParseState *pstate,
                           Node *raw_constraint,
@@ -109,6 +124,12 @@ static List *insert_ordered_unique_oid(List *list, Oid datum);
  *             Disadvantage:  special cases will be all over the place.
  */
 
+/*
+ * The initializers below do not include the attoptions or attacl fields,
+ * but that's OK - we're never going to reference anything beyond the
+ * fixed-size portion of the structure anyway.
+ */
+
 static FormData_pg_attribute a1 = {
        0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
        SelfItemPointerAttributeNumber, 0, -1, -1,
@@ -220,7 +241,9 @@ heap_create(const char *relname,
                        Oid relid,
                        TupleDesc tupDesc,
                        char relkind,
+                       char relpersistence,
                        bool shared_relation,
+                       bool mapped_relation,
                        bool allow_system_table_mods)
 {
        bool            create_storage;
@@ -249,6 +272,7 @@ heap_create(const char *relname,
        {
                case RELKIND_VIEW:
                case RELKIND_COMPOSITE_TYPE:
+               case RELKIND_FOREIGN_TABLE:
                        create_storage = false;
 
                        /*
@@ -291,7 +315,9 @@ heap_create(const char *relname,
                                                                         tupDesc,
                                                                         relid,
                                                                         reltablespace,
-                                                                        shared_relation);
+                                                                        shared_relation,
+                                                                        mapped_relation,
+                                                                        relpersistence);
 
        /*
         * Have the storage manager create the relation's disk file, if needed.
@@ -302,7 +328,7 @@ heap_create(const char *relname,
        if (create_storage)
        {
                RelationOpenSmgr(rel);
-               RelationCreateStorage(rel->rd_node, rel->rd_istemp);
+               RelationCreateStorage(rel->rd_node, relpersistence);
        }
 
        return rel;
@@ -348,7 +374,8 @@ heap_create(const char *relname,
  * --------------------------------
  */
 void
-CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind)
+CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
+                                                bool allow_system_table_mods)
 {
        int                     i;
        int                     j;
@@ -402,7 +429,9 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind)
        for (i = 0; i < natts; i++)
        {
                CheckAttributeType(NameStr(tupdesc->attrs[i]->attname),
-                                                  tupdesc->attrs[i]->atttypid);
+                                                  tupdesc->attrs[i]->atttypid,
+                                                  tupdesc->attrs[i]->attcollation,
+                                                  allow_system_table_mods);
        }
 }
 
@@ -415,7 +444,8 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind)
  * --------------------------------
  */
 void
-CheckAttributeType(const char *attname, Oid atttypid)
+CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation,
+                                  bool allow_system_table_mods)
 {
        char            att_typtype = get_typtype(atttypid);
 
@@ -434,9 +464,11 @@ CheckAttributeType(const char *attname, Oid atttypid)
        {
                /*
                 * Refuse any attempt to create a pseudo-type column, except for a
-                * special hack for pg_statistic: allow ANYARRAY during initdb
+                * special hack for pg_statistic: allow ANYARRAY when modifying system
+                * catalogs (this allows creating pg_statistic and cloning it during
+                * VACUUM FULL)
                 */
-               if (atttypid != ANYARRAYOID || IsUnderPostmaster)
+               if (atttypid != ANYARRAYOID || !allow_system_table_mods)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                                         errmsg("column \"%s\" has pseudo-type %s",
@@ -463,11 +495,24 @@ CheckAttributeType(const char *attname, Oid atttypid)
 
                        if (attr->attisdropped)
                                continue;
-                       CheckAttributeType(NameStr(attr->attname), attr->atttypid);
+                       CheckAttributeType(NameStr(attr->attname), attr->atttypid, attr->attcollation,
+                                                          allow_system_table_mods);
                }
 
                relation_close(relation, AccessShareLock);
        }
+
+       /*
+        * This might not be strictly invalid per SQL standard, but it is
+        * pretty useless, and it cannot be dumped, so we must disallow
+        * it.
+        */
+       if (type_is_collatable(atttypid) && !OidIsValid(attcollation))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+                                        errmsg("no collation was derived for column \"%s\" with collatable type %s",
+                                                       attname, format_type_be(atttypid)),
+                                        errhint("Use the COLLATE clause to set the collation explicitly.")));
 }
 
 /*
@@ -475,9 +520,10 @@ CheckAttributeType(const char *attname, Oid atttypid)
  *             Construct and insert a new tuple in pg_attribute.
  *
  * Caller has already opened and locked pg_attribute.  new_attribute is the
- * attribute to insert.
+ * attribute to insert (but we ignore attacl and attoptions, which are always
+ * initialized to NULL).
  *
- * indstate is the index state for CatalogIndexInsert.  It can be passed as
+ * indstate is the index state for CatalogIndexInsert. It can be passed as
  * NULL, in which case we'll fetch the necessary info.  (Don't do this when
  * inserting multiple attributes, because it's a tad more expensive.)
  */
@@ -511,6 +557,11 @@ InsertPgAttributeTuple(Relation pg_attribute_rel,
        values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(new_attribute->attisdropped);
        values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(new_attribute->attislocal);
        values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(new_attribute->attinhcount);
+       values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(new_attribute->attcollation);
+
+       /* start out with empty permissions and empty options */
+       nulls[Anum_pg_attribute_attacl - 1] = true;
+       nulls[Anum_pg_attribute_attoptions - 1] = true;
 
        tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls);
 
@@ -524,6 +575,7 @@ InsertPgAttributeTuple(Relation pg_attribute_rel,
 
        heap_freetuple(tup);
 }
+
 /* --------------------------------
  *             AddNewAttributeTuples
  *
@@ -576,6 +628,14 @@ AddNewAttributeTuples(Oid new_rel_oid,
                referenced.objectId = attr->atttypid;
                referenced.objectSubId = 0;
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+               if (OidIsValid(attr->attcollation))
+               {
+                       referenced.classId = CollationRelationId;
+                       referenced.objectId = attr->attcollation;
+                       referenced.objectSubId = 0;
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+               }
        }
 
        /*
@@ -626,14 +686,16 @@ AddNewAttributeTuples(Oid new_rel_oid,
  * Caller has already opened and locked pg_class.
  * Tuple data is taken from new_rel_desc->rd_rel, except for the
  * variable-width fields which are not present in a cached reldesc.
- * We always initialize relacl to NULL (i.e., default permissions),
- * and reloptions is set to the passed-in text array (if any).
+ * relacl and reloptions are passed in Datum form (to avoid having
+ * to reference the data types in heap.h).     Pass (Datum) 0 to set them
+ * to NULL.
  * --------------------------------
  */
 void
 InsertPgClassTuple(Relation pg_class_desc,
                                   Relation new_rel_desc,
                                   Oid new_rel_oid,
+                                  Datum relacl,
                                   Datum reloptions)
 {
        Form_pg_class rd_rel = new_rel_desc->rd_rel;
@@ -648,6 +710,7 @@ InsertPgClassTuple(Relation pg_class_desc,
        values[Anum_pg_class_relname - 1] = NameGetDatum(&rd_rel->relname);
        values[Anum_pg_class_relnamespace - 1] = ObjectIdGetDatum(rd_rel->relnamespace);
        values[Anum_pg_class_reltype - 1] = ObjectIdGetDatum(rd_rel->reltype);
+       values[Anum_pg_class_reloftype - 1] = ObjectIdGetDatum(rd_rel->reloftype);
        values[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(rd_rel->relowner);
        values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(rd_rel->relam);
        values[Anum_pg_class_relfilenode - 1] = ObjectIdGetDatum(rd_rel->relfilenode);
@@ -658,6 +721,7 @@ InsertPgClassTuple(Relation pg_class_desc,
        values[Anum_pg_class_reltoastidxid - 1] = ObjectIdGetDatum(rd_rel->reltoastidxid);
        values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
        values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
+       values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence);
        values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind);
        values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts);
        values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks);
@@ -667,8 +731,10 @@ InsertPgClassTuple(Relation pg_class_desc,
        values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers);
        values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
        values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
-       /* start out with empty permissions */
-       nulls[Anum_pg_class_relacl - 1] = true;
+       if (relacl != (Datum) 0)
+               values[Anum_pg_class_relacl - 1] = relacl;
+       else
+               nulls[Anum_pg_class_relacl - 1] = true;
        if (reloptions != (Datum) 0)
                values[Anum_pg_class_reloptions - 1] = reloptions;
        else
@@ -702,8 +768,10 @@ AddNewRelationTuple(Relation pg_class_desc,
                                        Relation new_rel_desc,
                                        Oid new_rel_oid,
                                        Oid new_type_oid,
+                                       Oid reloftype,
                                        Oid relowner,
                                        char relkind,
+                                       Datum relacl,
                                        Datum reloptions)
 {
        Form_pg_class new_rel_reltup;
@@ -759,12 +827,14 @@ AddNewRelationTuple(Relation pg_class_desc,
 
        new_rel_reltup->relowner = relowner;
        new_rel_reltup->reltype = new_type_oid;
+       new_rel_reltup->reloftype = reloftype;
        new_rel_reltup->relkind = relkind;
 
        new_rel_desc->rd_att->tdtypeid = new_type_oid;
 
        /* Now build and insert the tuple */
-       InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions);
+       InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
+                                          relacl, reloptions);
 }
 
 
@@ -779,17 +849,20 @@ AddNewRelationType(const char *typeName,
                                   Oid typeNamespace,
                                   Oid new_rel_oid,
                                   char new_rel_kind,
+                                  Oid ownerid,
+                                  Oid new_row_type,
                                   Oid new_array_type)
 {
        return
-               TypeCreate(InvalidOid,  /* no predetermined OID */
+               TypeCreate(new_row_type,        /* optional predetermined OID */
                                   typeName,    /* type name */
                                   typeNamespace,               /* type namespace */
                                   new_rel_oid, /* relation oid */
                                   new_rel_kind,        /* relation kind */
+                                  ownerid,             /* owner's ID */
                                   -1,                  /* internal size (varlena) */
                                   TYPTYPE_COMPOSITE,   /* type-type (composite) */
-                                  TYPCATEGORY_COMPOSITE, /* type-category (ditto) */
+                                  TYPCATEGORY_COMPOSITE,               /* type-category (ditto) */
                                   false,               /* composite types are never preferred */
                                   DEFAULT_TYPDELIM,    /* default array delimiter */
                                   F_RECORD_IN, /* input procedure */
@@ -810,13 +883,36 @@ AddNewRelationType(const char *typeName,
                                   'x',                 /* fully TOASTable */
                                   -1,                  /* typmod */
                                   0,                   /* array dimensions for typBaseType */
-                                  false);              /* Type NOT NULL */
+                                  false,               /* Type NOT NULL */
+                                  InvalidOid); /* typcollation */
 }
 
 /* --------------------------------
  *             heap_create_with_catalog
  *
  *             creates a new cataloged relation.  see comments above.
+ *
+ * Arguments:
+ *     relname: name to give to new rel
+ *     relnamespace: OID of namespace it goes in
+ *     reltablespace: OID of tablespace it goes in
+ *     relid: OID to assign to new rel, or InvalidOid to select a new OID
+ *     reltypeid: OID to assign to rel's rowtype, or InvalidOid to select one
+ *     ownerid: OID of new rel's owner
+ *     tupdesc: tuple descriptor (source of column definitions)
+ *     cooked_constraints: list of precooked check constraints and defaults
+ *     relkind: relkind for new rel
+ *     shared_relation: TRUE if it's to be a shared relation
+ *     mapped_relation: TRUE if the relation will use the relfilenode map
+ *     oidislocal: TRUE if oid column (if any) should be marked attislocal
+ *     oidinhcount: attinhcount to assign to oid column (if any)
+ *     oncommit: ON COMMIT marking (only relevant if it's a temp table)
+ *     reloptions: reloptions in Datum form, or (Datum) 0 if none
+ *     use_user_acl: TRUE if should look for user-defined default permissions;
+ *             if FALSE, relacl is always set NULL
+ *     allow_system_table_mods: TRUE to allow creation in system namespaces
+ *
+ * Returns the OID of the new relation
  * --------------------------------
  */
 Oid
@@ -824,19 +920,27 @@ heap_create_with_catalog(const char *relname,
                                                 Oid relnamespace,
                                                 Oid reltablespace,
                                                 Oid relid,
+                                                Oid reltypeid,
+                                                Oid reloftypeid,
                                                 Oid ownerid,
                                                 TupleDesc tupdesc,
                                                 List *cooked_constraints,
                                                 char relkind,
+                                                char relpersistence,
                                                 bool shared_relation,
+                                                bool mapped_relation,
                                                 bool oidislocal,
                                                 int oidinhcount,
                                                 OnCommitAction oncommit,
                                                 Datum reloptions,
-                                                bool allow_system_table_mods)
+                                                bool use_user_acl,
+                                                bool allow_system_table_mods,
+                                                bool if_not_exists)
 {
        Relation        pg_class_desc;
        Relation        new_rel_desc;
+       Acl                *relacl;
+       Oid                     existing_relid;
        Oid                     old_type_oid;
        Oid                     new_type_oid;
        Oid                     new_array_oid = InvalidOid;
@@ -848,12 +952,29 @@ heap_create_with_catalog(const char *relname,
         */
        Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode());
 
-       CheckAttributeNamesTypes(tupdesc, relkind);
+       CheckAttributeNamesTypes(tupdesc, relkind, allow_system_table_mods);
 
-       if (get_relname_relid(relname, relnamespace))
+       /*
+        * If the relation already exists, it's an error, unless the user specifies
+        * "IF NOT EXISTS".  In that case, we just print a notice and do nothing
+        * further.
+        */
+       existing_relid = get_relname_relid(relname, relnamespace);
+       if (existing_relid != InvalidOid)
+       {
+               if (if_not_exists)
+               {
+                       ereport(NOTICE,
+                                       (errcode(ERRCODE_DUPLICATE_TABLE),
+                                        errmsg("relation \"%s\" already exists, skipping",
+                                        relname)));
+                       heap_close(pg_class_desc, RowExclusiveLock);
+                       return InvalidOid;
+               }
                ereport(ERROR,
                                (errcode(ERRCODE_DUPLICATE_TABLE),
                                 errmsg("relation \"%s\" already exists", relname)));
+       }
 
        /*
         * Since we are going to create a rowtype as well, also check for
@@ -861,10 +982,9 @@ heap_create_with_catalog(const char *relname,
         * autogenerated array, we can rename it out of the way; otherwise we can
         * at least give a good error message.
         */
-       old_type_oid = GetSysCacheOid(TYPENAMENSP,
-                                                                 CStringGetDatum(relname),
-                                                                 ObjectIdGetDatum(relnamespace),
-                                                                 0, 0);
+       old_type_oid = GetSysCacheOid2(TYPENAMENSP,
+                                                                  CStringGetDatum(relname),
+                                                                  ObjectIdGetDatum(relnamespace));
        if (OidIsValid(old_type_oid))
        {
                if (!moveArrayTypeName(old_type_oid, relname, relnamespace))
@@ -877,23 +997,10 @@ heap_create_with_catalog(const char *relname,
        }
 
        /*
-        * Validate shared/non-shared tablespace (must check this before doing
-        * GetNewRelFileNode, to prevent Assert therein)
+        * Shared relations must be in pg_global (last-ditch check)
         */
-       if (shared_relation)
-       {
-               if (reltablespace != GLOBALTABLESPACE_OID)
-                       /* elog since this is not a user-facing error */
-                       elog(ERROR,
-                                "shared relations must be placed in pg_global tablespace");
-       }
-       else
-       {
-               if (reltablespace == GLOBALTABLESPACE_OID)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                        errmsg("only shared relations can be placed in pg_global tablespace")));
-       }
+       if (shared_relation && reltablespace != GLOBALTABLESPACE_OID)
+               elog(ERROR, "shared relations must be placed in pg_global tablespace");
 
        /*
         * Allocate an OID for the relation, unless we were told what to use.
@@ -902,8 +1009,54 @@ heap_create_with_catalog(const char *relname,
         * collide with either pg_class OIDs or existing physical files.
         */
        if (!OidIsValid(relid))
-               relid = GetNewRelFileNode(reltablespace, shared_relation,
-                                                                 pg_class_desc);
+       {
+               /*
+                *      Use binary-upgrade override for pg_class.oid/relfilenode,
+                *      if supplied.
+                */
+               if (OidIsValid(binary_upgrade_next_heap_pg_class_oid) &&
+                       (relkind == RELKIND_RELATION || relkind == RELKIND_SEQUENCE ||
+                        relkind == RELKIND_VIEW || relkind == RELKIND_COMPOSITE_TYPE ||
+                        relkind == RELKIND_FOREIGN_TABLE))
+               {
+                       relid = binary_upgrade_next_heap_pg_class_oid;
+                       binary_upgrade_next_heap_pg_class_oid = InvalidOid;
+               }
+               else if (OidIsValid(binary_upgrade_next_toast_pg_class_oid) &&
+                                relkind == RELKIND_TOASTVALUE)
+               {
+                       relid = binary_upgrade_next_toast_pg_class_oid;
+                       binary_upgrade_next_toast_pg_class_oid = InvalidOid;
+               }
+               else
+                       relid = GetNewRelFileNode(reltablespace, pg_class_desc,
+                                                                         relpersistence);
+       }
+
+       /*
+        * Determine the relation's initial permissions.
+        */
+       if (use_user_acl)
+       {
+               switch (relkind)
+               {
+                       case RELKIND_RELATION:
+                       case RELKIND_VIEW:
+                       case RELKIND_FOREIGN_TABLE:
+                               relacl = get_user_default_acl(ACL_OBJECT_RELATION, ownerid,
+                                                                                         relnamespace);
+                               break;
+                       case RELKIND_SEQUENCE:
+                               relacl = get_user_default_acl(ACL_OBJECT_SEQUENCE, ownerid,
+                                                                                         relnamespace);
+                               break;
+                       default:
+                               relacl = NULL;
+                               break;
+               }
+       }
+       else
+               relacl = NULL;
 
        /*
         * Create the relcache entry (mostly dummy at this point) and the physical
@@ -916,7 +1069,9 @@ heap_create_with_catalog(const char *relname,
                                                           relid,
                                                           tupdesc,
                                                           relkind,
+                                                          relpersistence,
                                                           shared_relation,
+                                                          mapped_relation,
                                                           allow_system_table_mods);
 
        Assert(relid == RelationGetRelid(new_rel_desc));
@@ -925,22 +1080,20 @@ heap_create_with_catalog(const char *relname,
         * Decide whether to create an array type over the relation's rowtype. We
         * do not create any array types for system catalogs (ie, those made
         * during initdb).      We create array types for regular relations, views,
-        * and composite types ... but not, eg, for toast tables or sequences.
+        * composite types and foreign tables ... but not, eg, for toast tables or
+        * sequences.
         */
        if (IsUnderPostmaster && (relkind == RELKIND_RELATION ||
                                                          relkind == RELKIND_VIEW ||
+                                                         relkind == RELKIND_FOREIGN_TABLE ||
                                                          relkind == RELKIND_COMPOSITE_TYPE))
-       {
-               /* OK, so pre-assign a type OID for the array type */
-               Relation        pg_type = heap_open(TypeRelationId, AccessShareLock);
-
-               new_array_oid = GetNewOid(pg_type);
-               heap_close(pg_type, AccessShareLock);
-       }
+               new_array_oid = AssignTypeArrayOid();
 
        /*
         * Since defining a relation also defines a complex type, we add a new
-        * system type corresponding to the new relation.
+        * system type corresponding to the new relation.  The OID of the type can
+        * be preselected by the caller, but if reltypeid is InvalidOid, we'll
+        * generate a new OID for it.
         *
         * NOTE: we could get a unique-index failure here, in case someone else is
         * creating the same type name in parallel but hadn't committed yet when
@@ -950,6 +1103,8 @@ heap_create_with_catalog(const char *relname,
                                                                          relnamespace,
                                                                          relid,
                                                                          relkind,
+                                                                         ownerid,
+                                                                         reltypeid,
                                                                          new_array_oid);
 
        /*
@@ -966,9 +1121,10 @@ heap_create_with_catalog(const char *relname,
                                   relnamespace,        /* Same namespace as parent */
                                   InvalidOid,  /* Not composite, no relationOid */
                                   0,                   /* relkind, also N/A here */
+                                  ownerid,             /* owner's ID */
                                   -1,                  /* Internal size (varlena) */
                                   TYPTYPE_BASE,        /* Not composite - typelem is */
-                                  TYPCATEGORY_ARRAY, /* type-category (array) */
+                                  TYPCATEGORY_ARRAY,   /* type-category (array) */
                                   false,               /* array types are never preferred */
                                   DEFAULT_TYPDELIM,    /* default array delimiter */
                                   F_ARRAY_IN,  /* array input proc */
@@ -989,7 +1145,8 @@ heap_create_with_catalog(const char *relname,
                                   'x',                 /* fully TOASTable */
                                   -1,                  /* typmod */
                                   0,                   /* array dimensions for typBaseType */
-                                  false);              /* Type NOT NULL */
+                                  false,               /* Type NOT NULL */
+                                  InvalidOid); /* typcollation */
 
                pfree(relarrayname);
        }
@@ -1005,8 +1162,10 @@ heap_create_with_catalog(const char *relname,
                                                new_rel_desc,
                                                relid,
                                                new_type_oid,
+                                               reloftypeid,
                                                ownerid,
                                                relkind,
+                                               PointerGetDatum(relacl),
                                                reloptions);
 
        /*
@@ -1017,12 +1176,16 @@ heap_create_with_catalog(const char *relname,
 
        /*
         * Make a dependency link to force the relation to be deleted if its
-        * namespace is.  Also make a dependency link to its owner.
+        * namespace is.  Also make a dependency link to its owner, as well as
+        * dependencies for any roles mentioned in the default ACL.
         *
         * For composite types, these dependencies are tracked for the pg_type
         * entry, so we needn't record them here.  Likewise, TOAST tables don't
         * need a namespace dependency (they live in a pinned namespace) nor an
-        * owner dependency (they depend indirectly through the parent table).
+        * owner dependency (they depend indirectly through the parent table), nor
+        * should they have any ACL entries.  The same applies for extension
+        * dependencies.
+        *
         * Also, skip this in bootstrap mode, since we don't make dependencies
         * while bootstrapping.
         */
@@ -1042,8 +1205,33 @@ heap_create_with_catalog(const char *relname,
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
                recordDependencyOnOwner(RelationRelationId, relid, ownerid);
+
+               recordDependencyOnCurrentExtension(&myself);
+
+               if (reloftypeid)
+               {
+                       referenced.classId = TypeRelationId;
+                       referenced.objectId = reloftypeid;
+                       referenced.objectSubId = 0;
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+               }
+
+               if (relacl != NULL)
+               {
+                       int                     nnewmembers;
+                       Oid                *newmembers;
+
+                       nnewmembers = aclmembers(relacl, &newmembers);
+                       updateAclDependencies(RelationRelationId, relid, 0,
+                                                                 ownerid,
+                                                                 0, NULL,
+                                                                 nnewmembers, newmembers);
+               }
        }
 
+       /* Post creation hook for new relation */
+       InvokeObjectAccessHook(OAT_POST_CREATE, RelationRelationId, relid, 0);
+
        /*
         * Store any supplied constraints and defaults.
         *
@@ -1059,6 +1247,25 @@ heap_create_with_catalog(const char *relname,
        if (oncommit != ONCOMMIT_NOOP)
                register_on_commit_action(relid, oncommit);
 
+       /*
+        * If this is an unlogged relation, it needs an init fork so that it
+        * can be correctly reinitialized on restart.  Since we're going to
+        * do an immediate sync, we ony need to xlog this if archiving or
+        * streaming is enabled.  And the immediate sync is required, because
+        * otherwise there's no guarantee that this will hit the disk before
+        * the next checkpoint moves the redo pointer.
+        */
+       if (relpersistence == RELPERSISTENCE_UNLOGGED)
+       {
+               Assert(relkind == RELKIND_RELATION || relkind == RELKIND_TOASTVALUE);
+
+               smgrcreate(new_rel_desc->rd_smgr, INIT_FORKNUM, false);
+               if (XLogIsNeeded())
+                       log_smgrcreate(&new_rel_desc->rd_smgr->smgr_rnode.node,
+                                                  INIT_FORKNUM);
+               smgrimmedsync(new_rel_desc->rd_smgr, INIT_FORKNUM);
+       }
+
        /*
         * ok, the relation has been cataloged, so close our relations and return
         * the OID of the newly created relation.
@@ -1121,9 +1328,7 @@ DeleteRelationTuple(Oid relid)
        /* Grab an appropriate lock on the pg_class relation */
        pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);
 
-       tup = SearchSysCache(RELOID,
-                                                ObjectIdGetDatum(relid),
-                                                0, 0, 0);
+       tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
        if (!HeapTupleIsValid(tup))
                elog(ERROR, "cache lookup failed for relation %u", relid);
 
@@ -1200,10 +1405,9 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
 
        attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
 
-       tuple = SearchSysCacheCopy(ATTNUM,
-                                                          ObjectIdGetDatum(relid),
-                                                          Int16GetDatum(attnum),
-                                                          0, 0);
+       tuple = SearchSysCacheCopy2(ATTNUM,
+                                                               ObjectIdGetDatum(relid),
+                                                               Int16GetDatum(attnum));
        if (!HeapTupleIsValid(tuple))           /* shouldn't happen */
                elog(ERROR, "cache lookup failed for attribute %d of relation %u",
                         attnum, relid);
@@ -1368,10 +1572,9 @@ RemoveAttrDefaultById(Oid attrdefId)
        /* Fix the pg_attribute row */
        attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
 
-       tuple = SearchSysCacheCopy(ATTNUM,
-                                                          ObjectIdGetDatum(myrelid),
-                                                          Int16GetDatum(myattnum),
-                                                          0, 0);
+       tuple = SearchSysCacheCopy2(ATTNUM,
+                                                               ObjectIdGetDatum(myrelid),
+                                                               Int16GetDatum(myattnum));
        if (!HeapTupleIsValid(tuple))           /* shouldn't happen */
                elog(ERROR, "cache lookup failed for attribute %d of relation %u",
                         myattnum, myrelid);
@@ -1412,11 +1615,39 @@ heap_drop_with_catalog(Oid relid)
         */
        rel = relation_open(relid, AccessExclusiveLock);
 
+       /*
+        * There can no longer be anyone *else* touching the relation, but we
+        * might still have open queries or cursors, or pending trigger events,
+        * in our own session.
+        */
+       CheckTableNotInUse(rel, "DROP TABLE");
+
+       /*
+        * Delete pg_foreign_table tuple first.
+        */
+       if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+       {
+               Relation    rel;
+               HeapTuple   tuple;
+
+               rel = heap_open(ForeignTableRelationId, RowExclusiveLock);
+
+               tuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(relid));
+               if (!HeapTupleIsValid(tuple))
+                       elog(ERROR, "cache lookup failed for foreign table %u", relid);
+
+               simple_heap_delete(rel, &tuple->t_self);
+
+               ReleaseSysCache(tuple);
+               heap_close(rel, RowExclusiveLock);
+       }
+
        /*
         * Schedule unlinking of the relation's physical files at commit.
         */
        if (rel->rd_rel->relkind != RELKIND_VIEW &&
-               rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
+               rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
+               rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
        {
                RelationDropStorage(rel);
        }
@@ -1529,10 +1760,9 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr)
         * exists.
         */
        attrrel = heap_open(AttributeRelationId, RowExclusiveLock);
-       atttup = SearchSysCacheCopy(ATTNUM,
-                                                               ObjectIdGetDatum(RelationGetRelid(rel)),
-                                                               Int16GetDatum(attnum),
-                                                               0, 0);
+       atttup = SearchSysCacheCopy2(ATTNUM,
+                                                                ObjectIdGetDatum(RelationGetRelid(rel)),
+                                                                Int16GetDatum(attnum));
        if (!HeapTupleIsValid(atttup))
                elog(ERROR, "cache lookup failed for attribute %d of relation %u",
                         attnum, RelationGetRelid(rel));
@@ -1599,7 +1829,7 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr,
         * in check constraints; it would fail to examine the contents of
         * subselects.
         */
-       varList = pull_var_clause(expr, false);
+       varList = pull_var_clause(expr, PVC_REJECT_PLACEHOLDERS);
        keycount = list_length(varList);
 
        if (keycount > 0)
@@ -1632,10 +1862,12 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr,
                                                  CONSTRAINT_CHECK,             /* Constraint Type */
                                                  false,        /* Is Deferrable */
                                                  false,        /* Is Deferred */
+                                                 true,         /* Is Validated */
                                                  RelationGetRelid(rel),                /* relation */
                                                  attNos,               /* attrs in the constraint */
                                                  keycount,             /* # attrs in the constraint */
                                                  InvalidOid,   /* not a domain constraint */
+                                                 InvalidOid,   /* no associated index */
                                                  InvalidOid,   /* Foreign key fields */
                                                  NULL,
                                                  NULL,
@@ -1645,12 +1877,12 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr,
                                                  ' ',
                                                  ' ',
                                                  ' ',
-                                                 InvalidOid,   /* no associated index */
-                                                 expr, /* Tree form check constraint */
-                                                 ccbin,        /* Binary form check constraint */
-                                                 ccsrc,        /* Source form check constraint */
-                                                 is_local,     /* conislocal */
-                                                 inhcount); /* coninhcount */
+                                                 NULL, /* not an exclusion constraint */
+                                                 expr, /* Tree form of check constraint */
+                                                 ccbin,        /* Binary form of check constraint */
+                                                 ccsrc,        /* Source form of check constraint */
+                                                 is_local,             /* conislocal */
+                                                 inhcount);    /* coninhcount */
 
        pfree(ccbin);
        pfree(ccsrc);
@@ -1847,11 +2079,11 @@ AddRelationNewConstraints(Relation rel,
                /*
                 * Check name uniqueness, or generate a name if none was given.
                 */
-               if (cdef->name != NULL)
+               if (cdef->conname != NULL)
                {
                        ListCell   *cell2;
 
-                       ccname = cdef->name;
+                       ccname = cdef->conname;
                        /* Check against other new constraints */
                        /* Needed because we don't do CommandCounterIncrement in loop */
                        foreach(cell2, checknames)
@@ -1867,10 +2099,10 @@ AddRelationNewConstraints(Relation rel,
                        checknames = lappend(checknames, ccname);
 
                        /*
-                        * Check against pre-existing constraints.  If we are allowed
-                        * to merge with an existing constraint, there's no more to
-                        * do here.  (We omit the duplicate constraint from the result,
-                        * which is what ATAddCheckConstraint wants.)
+                        * Check against pre-existing constraints.      If we are allowed to
+                        * merge with an existing constraint, there's no more to do here.
+                        * (We omit the duplicate constraint from the result, which is
+                        * what ATAddCheckConstraint wants.)
                         */
                        if (MergeWithExistingConstraint(rel, ccname, expr,
                                                                                        allow_merge, is_local))
@@ -1893,7 +2125,7 @@ AddRelationNewConstraints(Relation rel,
                        List       *vars;
                        char       *colname;
 
-                       vars = pull_var_clause(expr, false);
+                       vars = pull_var_clause(expr, PVC_REJECT_PLACEHOLDERS);
 
                        /* eliminate duplicates */
                        vars = list_union(NIL, vars);
@@ -1988,8 +2220,8 @@ MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
                        /* Found it.  Conflicts if not identical check constraint */
                        if (con->contype == CONSTRAINT_CHECK)
                        {
-                               Datum   val;
-                               bool    isnull;
+                               Datum           val;
+                               bool            isnull;
 
                                val = fastgetattr(tup,
                                                                  Anum_pg_constraint_conbin,
@@ -2007,8 +2239,8 @@ MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
                                           ccname, RelationGetRelationName(rel))));
                        /* OK to update the tuple */
                        ereport(NOTICE,
-                                       (errmsg("merging constraint \"%s\" with inherited definition",
-                                                       ccname)));
+                          (errmsg("merging constraint \"%s\" with inherited definition",
+                                          ccname)));
                        tup = heap_copytuple(tup);
                        con = (Form_pg_constraint) GETSTRUCT(tup);
                        if (is_local)
@@ -2045,9 +2277,8 @@ SetRelationNumChecks(Relation rel, int numchecks)
        Form_pg_class relStruct;
 
        relrel = heap_open(RelationRelationId, RowExclusiveLock);
-       reltup = SearchSysCacheCopy(RELOID,
-                                                               ObjectIdGetDatum(RelationGetRelid(rel)),
-                                                               0, 0, 0);
+       reltup = SearchSysCacheCopy1(RELOID,
+                                                                ObjectIdGetDatum(RelationGetRelid(rel)));
        if (!HeapTupleIsValid(reltup))
                elog(ERROR, "cache lookup failed for relation %u",
                         RelationGetRelid(rel));
@@ -2127,6 +2358,10 @@ cookDefault(ParseState *pstate,
                ereport(ERROR,
                                (errcode(ERRCODE_GROUPING_ERROR),
                         errmsg("cannot use aggregate function in default expression")));
+       if (pstate->p_hasWindowFuncs)
+               ereport(ERROR,
+                               (errcode(ERRCODE_WINDOWING_ERROR),
+                                errmsg("cannot use window function in default expression")));
 
        /*
         * Coerce the expression to the correct type and typmod, if given. This
@@ -2153,6 +2388,11 @@ cookDefault(ParseState *pstate,
                           errhint("You will need to rewrite or cast the expression.")));
        }
 
+       /*
+        * Finally, take care of collations in the finished expression.
+        */
+       assign_expr_collations(pstate, expr);
+
        return expr;
 }
 
@@ -2180,14 +2420,19 @@ cookConstraint(ParseState *pstate,
         */
        expr = coerce_to_boolean(pstate, expr, "CHECK");
 
+       /*
+        * Take care of collations.
+        */
+       assign_expr_collations(pstate, expr);
+
        /*
         * Make sure no outside relations are referred to.
         */
        if (list_length(pstate->p_rtable) != 1)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-                                errmsg("only table \"%s\" can be referenced in check constraint",
-                                               relname)));
+                       errmsg("only table \"%s\" can be referenced in check constraint",
+                                  relname)));
 
        /*
         * No subplans or aggregates, either...
@@ -2199,7 +2444,11 @@ cookConstraint(ParseState *pstate,
        if (pstate->p_hasAggs)
                ereport(ERROR,
                                (errcode(ERRCODE_GROUPING_ERROR),
-                                errmsg("cannot use aggregate function in check constraint")));
+                          errmsg("cannot use aggregate function in check constraint")));
+       if (pstate->p_hasWindowFuncs)
+               ereport(ERROR,
+                               (errcode(ERRCODE_WINDOWING_ERROR),
+                                errmsg("cannot use window function in check constraint")));
 
        return expr;
 }
@@ -2208,7 +2457,7 @@ cookConstraint(ParseState *pstate,
 /*
  * RemoveStatistics --- remove entries in pg_statistic for a rel or column
  *
- * If attnum is zero, remove all entries for rel; else remove only the one
+ * If attnum is zero, remove all entries for rel; else remove only the one(s)
  * for that column.
  */
 void
@@ -2238,9 +2487,10 @@ RemoveStatistics(Oid relid, AttrNumber attnum)
                nkeys = 2;
        }
 
-       scan = systable_beginscan(pgstatistic, StatisticRelidAttnumIndexId, true,
+       scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
                                                          SnapshotNow, nkeys, key);
 
+       /* we must loop even when attnum != 0, in case of inherited stats */
        while (HeapTupleIsValid(tuple = systable_getnext(scan)))
                simple_heap_delete(pgstatistic, &tuple->t_self);
 
@@ -2276,9 +2526,7 @@ RelationTruncateIndexes(Relation heapRelation)
                indexInfo = BuildIndexInfo(currentIndex);
 
                /*
-                * Now truncate the actual file (and discard buffers). The indexam
-                * is responsible for truncating the FSM in index_build(), if
-                * applicable.
+                * Now truncate the actual file (and discard buffers).
                 */
                RelationTruncate(currentIndex, 0);
 
@@ -2311,18 +2559,9 @@ heap_truncate(List *relids)
        {
                Oid                     rid = lfirst_oid(cell);
                Relation        rel;
-               Oid                     toastrelid;
 
                rel = heap_open(rid, AccessExclusiveLock);
                relations = lappend(relations, rel);
-
-               /* If there is a toast table, add it to the list too */
-               toastrelid = rel->rd_rel->reltoastrelid;
-               if (OidIsValid(toastrelid))
-               {
-                       rel = heap_open(toastrelid, AccessExclusiveLock);
-                       relations = lappend(relations, rel);
-               }
        }
 
        /* Don't allow truncate on tables that are referenced by foreign keys */
@@ -2333,19 +2572,47 @@ heap_truncate(List *relids)
        {
                Relation        rel = lfirst(cell);
 
-               /* Truncate the FSM and actual file (and discard buffers) */
-               RelationTruncate(rel, 0);
+               /* Truncate the relation */
+               heap_truncate_one_rel(rel);
 
-               /* If this relation has indexes, truncate the indexes too */
-               RelationTruncateIndexes(rel);
-
-               /*
-                * Close the relation, but keep exclusive lock on it until commit.
-                */
+               /* Close the relation, but keep exclusive lock on it until commit */
                heap_close(rel, NoLock);
        }
 }
 
+/*
+ *      heap_truncate_one_rel
+ *
+ *      This routine deletes all data within the specified relation.
+ *
+ * This is not transaction-safe, because the truncation is done immediately
+ * and cannot be rolled back later.  Caller is responsible for having
+ * checked permissions etc, and must have obtained AccessExclusiveLock.
+ */
+void
+heap_truncate_one_rel(Relation rel)
+{
+       Oid                     toastrelid;
+
+       /* Truncate the actual file (and discard buffers) */
+       RelationTruncate(rel, 0);
+
+       /* If the relation has indexes, truncate the indexes too */
+       RelationTruncateIndexes(rel);
+
+       /* If there is a toast table, truncate that too */
+       toastrelid = rel->rd_rel->reltoastrelid;
+       if (OidIsValid(toastrelid))
+       {
+               Relation        toastrel = heap_open(toastrelid, AccessExclusiveLock);
+
+               RelationTruncate(toastrel, 0);
+               RelationTruncateIndexes(toastrel);
+               /* keep the lock... */
+               heap_close(toastrel, NoLock);
+       }
+}
+
 /*
  * heap_truncate_check_FKs
  *             Check for foreign keys referencing a list of relations that