OSDN Git Service

Refactor broken CREATE TABLE IF NOT EXISTS support.
[pg-rex/syncrep.git] / src / backend / catalog / toasting.c
index 9e2f20e..a8cf0db 100644 (file)
@@ -4,11 +4,11 @@
  *       This file contains routines to support creation of toast tables
  *
  *
- * Portions Copyright (c) 1996-2009, 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/toasting.c,v 1.18 2009/07/29 20:56:18 tgl Exp $
+ *       src/backend/catalog/toasting.c
  *
  *-------------------------------------------------------------------------
  */
 #include "utils/builtins.h"
 #include "utils/syscache.h"
 
+/* Potentially set by contrib/pg_upgrade_support functions */
+extern Oid     binary_upgrade_next_toast_pg_class_oid;
+
+Oid                    binary_upgrade_next_toast_pg_type_oid = InvalidOid;
 
 static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
-                                  Datum reloptions, bool force);
+                                  Datum reloptions);
 static bool needs_toast_table(Relation rel);
 
 
 /*
  * AlterTableCreateToastTable
  *             If the table needs a toast table, and doesn't already have one,
- *             then create a toast table for it.  (With the force option, make
- *             a toast table even if it appears unnecessary.)
- *
- * The caller can also specify the OID to be used for the toast table.
- * Usually, toastOid should be InvalidOid to allow a free OID to be assigned.
- * (This option, as well as the force option, is not used by core Postgres,
- * but is provided to support pg_migrator.)
+ *             then create a toast table for it.
  *
  * reloptions for the toast table can be passed, too.  Pass (Datum) 0
  * for default reloptions.
@@ -56,20 +54,19 @@ static bool needs_toast_table(Relation rel);
  * to end with CommandCounterIncrement if it makes any changes.
  */
 void
-AlterTableCreateToastTable(Oid relOid, Oid toastOid,
-                                                  Datum reloptions, bool force)
+AlterTableCreateToastTable(Oid relOid, Datum reloptions)
 {
        Relation        rel;
 
        /*
-        * Grab an exclusive lock on the target table, which we will NOT release
-        * until end of transaction.  (This is probably redundant in all present
-        * uses...)
+        * Grab a DDL-exclusive lock on the target table, since we'll update the
+        * pg_class tuple.  This is redundant for all present users.  Tuple toasting
+        * behaves safely in the face of a concurrent TOAST table add.
         */
-       rel = heap_open(relOid, AccessExclusiveLock);
+       rel = heap_open(relOid, ShareUpdateExclusiveLock);
 
        /* create_toast_table does all the work */
-       (void) create_toast_table(rel, toastOid, InvalidOid, reloptions, force);
+       (void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions);
 
        heap_close(rel, NoLock);
 }
@@ -95,7 +92,7 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
                                                relName)));
 
        /* create_toast_table does all the work */
-       if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0, false))
+       if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0))
                elog(ERROR, "\"%s\" does not require a toast table",
                         relName);
 
@@ -106,25 +103,27 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
 /*
  * create_toast_table --- internal workhorse
  *
- * rel is already opened and exclusive-locked
- * toastOid and toastIndexOid are normally InvalidOid, but
- * either or both can be nonzero to specify caller-assigned OIDs
+ * rel is already opened and locked
+ * toastOid and toastIndexOid are normally InvalidOid, but during
+ * bootstrap they can be nonzero to specify hand-assigned OIDs
  */
 static bool
-create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
-                                  Datum reloptions, bool force)
+create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptions)
 {
        Oid                     relOid = RelationGetRelid(rel);
        HeapTuple       reltup;
        TupleDesc       tupdesc;
        bool            shared_relation;
+       bool            mapped_relation;
+       Relation        toast_rel;
        Relation        class_rel;
        Oid                     toast_relid;
-       Oid                     toast_idxid;
+       Oid                     toast_typid = InvalidOid;
        Oid                     namespaceid;
        char            toast_relname[NAMEDATALEN];
        char            toast_idxname[NAMEDATALEN];
        IndexInfo  *indexInfo;
+       Oid                     collationObjectId[2];
        Oid                     classObjectId[2];
        int16           coloptions[2];
        ObjectAddress baseobject,
@@ -142,6 +141,9 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
                                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                 errmsg("shared tables cannot be toasted after initdb")));
 
+       /* It's mapped if and only if its parent is, too */
+       mapped_relation = RelationIsMapped(rel);
+
        /*
         * Is it already toasted?
         */
@@ -151,11 +153,12 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
        /*
         * Check to see whether the table actually needs a TOAST table.
         *
-        * Caller can optionally override this check.  (Note: at present no
-        * callers in core Postgres do so, but this option is needed by
-        * pg_migrator.)
+        * If an update-in-place toast relfilenode is specified, force toast file
+        * creation even if it seems not to need one.
         */
-       if (!force && !needs_toast_table(rel))
+       if (!needs_toast_table(rel) &&
+               (!IsBinaryUpgrade ||
+                !OidIsValid(binary_upgrade_next_toast_pg_class_oid)))
                return false;
 
        /*
@@ -194,29 +197,45 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
         * Toast tables for regular relations go in pg_toast; those for temp
         * relations go into the per-backend temp-toast-table namespace.
         */
-       if (rel->rd_islocaltemp)
+       if (RelationUsesTempNamespace(rel))
                namespaceid = GetTempToastNamespace();
        else
                namespaceid = PG_TOAST_NAMESPACE;
 
+       /* Use binary-upgrade override for pg_type.oid, if supplied. */
+       if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_toast_pg_type_oid))
+       {
+               toast_typid = binary_upgrade_next_toast_pg_type_oid;
+               binary_upgrade_next_toast_pg_type_oid = InvalidOid;
+       }
+
        toast_relid = heap_create_with_catalog(toast_relname,
                                                                                   namespaceid,
                                                                                   rel->rd_rel->reltablespace,
                                                                                   toastOid,
+                                                                                  toast_typid,
+                                                                                  InvalidOid,
                                                                                   rel->rd_rel->relowner,
                                                                                   tupdesc,
                                                                                   NIL,
                                                                                   RELKIND_TOASTVALUE,
+                                                                                  rel->rd_rel->relpersistence,
                                                                                   shared_relation,
+                                                                                  mapped_relation,
                                                                                   true,
                                                                                   0,
                                                                                   ONCOMMIT_NOOP,
                                                                                   reloptions,
+                                                                                  false,
                                                                                   true);
+       Assert(toast_relid != InvalidOid);
 
-       /* make the toast relation visible, else index creation will fail */
+       /* make the toast relation visible, else heap_open will fail */
        CommandCounterIncrement();
 
+       /* ShareLock is not really needed here, but take it anyway */
+       toast_rel = heap_open(toast_relid, ShareLock);
+
        /*
         * Create unique index on chunk_id, chunk_seq.
         *
@@ -237,33 +256,40 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
        indexInfo->ii_ExpressionsState = NIL;
        indexInfo->ii_Predicate = NIL;
        indexInfo->ii_PredicateState = NIL;
+       indexInfo->ii_ExclusionOps = NULL;
+       indexInfo->ii_ExclusionProcs = NULL;
+       indexInfo->ii_ExclusionStrats = NULL;
        indexInfo->ii_Unique = true;
        indexInfo->ii_ReadyForInserts = true;
        indexInfo->ii_Concurrent = false;
        indexInfo->ii_BrokenHotChain = false;
 
+       collationObjectId[0] = InvalidOid;
+       collationObjectId[1] = InvalidOid;
+
        classObjectId[0] = OID_BTREE_OPS_OID;
        classObjectId[1] = INT4_BTREE_OPS_OID;
 
        coloptions[0] = 0;
        coloptions[1] = 0;
 
-       toast_idxid = index_create(toast_relid, toast_idxname, toastIndexOid,
+       index_create(toast_rel, toast_idxname, toastIndexOid,
                                                           indexInfo,
+                                                          list_make2("chunk_id", "chunk_seq"),
                                                           BTREE_AM_OID,
                                                           rel->rd_rel->reltablespace,
-                                                          classObjectId, coloptions, (Datum) 0,
+                                        collationObjectId, classObjectId, coloptions, (Datum) 0,
                                                           true, false, false, false,
                                                           true, false, false);
 
+       heap_close(toast_rel, NoLock);
+
        /*
         * Store the toast table's OID in the parent relation's pg_class row
         */
        class_rel = heap_open(RelationRelationId, RowExclusiveLock);
 
-       reltup = SearchSysCacheCopy(RELOID,
-                                                               ObjectIdGetDatum(relOid),
-                                                               0, 0, 0);
+       reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
        if (!HeapTupleIsValid(reltup))
                elog(ERROR, "cache lookup failed for relation %u", relOid);