LCOV - code coverage report
Current view: top level - src/backend/commands - tablespace.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 263 400 65.8 %
Date: 2020-06-01 08:06:25 Functions: 17 17 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * tablespace.c
       4             :  *    Commands to manipulate table spaces
       5             :  *
       6             :  * Tablespaces in PostgreSQL are designed to allow users to determine
       7             :  * where the data file(s) for a given database object reside on the file
       8             :  * system.
       9             :  *
      10             :  * A tablespace represents a directory on the file system. At tablespace
      11             :  * creation time, the directory must be empty. To simplify things and
      12             :  * remove the possibility of having file name conflicts, we isolate
      13             :  * files within a tablespace into database-specific subdirectories.
      14             :  *
      15             :  * To support file access via the information given in RelFileNode, we
      16             :  * maintain a symbolic-link map in $PGDATA/pg_tblspc. The symlinks are
      17             :  * named by tablespace OIDs and point to the actual tablespace directories.
      18             :  * There is also a per-cluster version directory in each tablespace.
      19             :  * Thus the full path to an arbitrary file is
      20             :  *          $PGDATA/pg_tblspc/spcoid/PG_MAJORVER_CATVER/dboid/relfilenode
      21             :  * e.g.
      22             :  *          $PGDATA/pg_tblspc/20981/PG_9.0_201002161/719849/83292814
      23             :  *
      24             :  * There are two tablespaces created at initdb time: pg_global (for shared
      25             :  * tables) and pg_default (for everything else).  For backwards compatibility
      26             :  * and to remain functional on platforms without symlinks, these tablespaces
      27             :  * are accessed specially: they are respectively
      28             :  *          $PGDATA/global/relfilenode
      29             :  *          $PGDATA/base/dboid/relfilenode
      30             :  *
      31             :  * To allow CREATE DATABASE to give a new database a default tablespace
      32             :  * that's different from the template database's default, we make the
      33             :  * provision that a zero in pg_class.reltablespace means the database's
      34             :  * default tablespace.  Without this, CREATE DATABASE would have to go in
      35             :  * and munge the system catalogs of the new database.
      36             :  *
      37             :  *
      38             :  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
      39             :  * Portions Copyright (c) 1994, Regents of the University of California
      40             :  *
      41             :  *
      42             :  * IDENTIFICATION
      43             :  *    src/backend/commands/tablespace.c
      44             :  *
      45             :  *-------------------------------------------------------------------------
      46             :  */
      47             : #include "postgres.h"
      48             : 
      49             : #include <unistd.h>
      50             : #include <dirent.h>
      51             : #include <sys/stat.h>
      52             : 
      53             : #include "access/heapam.h"
      54             : #include "access/htup_details.h"
      55             : #include "access/reloptions.h"
      56             : #include "access/sysattr.h"
      57             : #include "access/tableam.h"
      58             : #include "access/xact.h"
      59             : #include "access/xlog.h"
      60             : #include "access/xloginsert.h"
      61             : #include "catalog/catalog.h"
      62             : #include "catalog/dependency.h"
      63             : #include "catalog/indexing.h"
      64             : #include "catalog/namespace.h"
      65             : #include "catalog/objectaccess.h"
      66             : #include "catalog/pg_namespace.h"
      67             : #include "catalog/pg_tablespace.h"
      68             : #include "commands/comment.h"
      69             : #include "commands/seclabel.h"
      70             : #include "commands/tablecmds.h"
      71             : #include "commands/tablespace.h"
      72             : #include "common/file_perm.h"
      73             : #include "miscadmin.h"
      74             : #include "postmaster/bgwriter.h"
      75             : #include "storage/fd.h"
      76             : #include "storage/lmgr.h"
      77             : #include "storage/standby.h"
      78             : #include "utils/acl.h"
      79             : #include "utils/builtins.h"
      80             : #include "utils/fmgroids.h"
      81             : #include "utils/guc.h"
      82             : #include "utils/lsyscache.h"
      83             : #include "utils/memutils.h"
      84             : #include "utils/rel.h"
      85             : #include "utils/varlena.h"
      86             : 
      87             : /* GUC variables */
      88             : char       *default_tablespace = NULL;
      89             : char       *temp_tablespaces = NULL;
      90             : 
      91             : 
      92             : static void create_tablespace_directories(const char *location,
      93             :                                           const Oid tablespaceoid);
      94             : static bool destroy_tablespace_directories(Oid tablespaceoid, bool redo);
      95             : 
      96             : 
      97             : /*
      98             :  * Each database using a table space is isolated into its own name space
      99             :  * by a subdirectory named for the database OID.  On first creation of an
     100             :  * object in the tablespace, create the subdirectory.  If the subdirectory
     101             :  * already exists, fall through quietly.
     102             :  *
     103             :  * isRedo indicates that we are creating an object during WAL replay.
     104             :  * In this case we will cope with the possibility of the tablespace
     105             :  * directory not being there either --- this could happen if we are
     106             :  * replaying an operation on a table in a subsequently-dropped tablespace.
     107             :  * We handle this by making a directory in the place where the tablespace
     108             :  * symlink would normally be.  This isn't an exact replay of course, but
     109             :  * it's the best we can do given the available information.
     110             :  *
     111             :  * If tablespaces are not supported, we still need it in case we have to
     112             :  * re-create a database subdirectory (of $PGDATA/base) during WAL replay.
     113             :  */
     114             : void
     115      180184 : TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo)
     116             : {
     117             :     struct stat st;
     118             :     char       *dir;
     119             : 
     120             :     /*
     121             :      * The global tablespace doesn't have per-database subdirectories, so
     122             :      * nothing to do for it.
     123             :      */
     124      180184 :     if (spcNode == GLOBALTABLESPACE_OID)
     125       20704 :         return;
     126             : 
     127             :     Assert(OidIsValid(spcNode));
     128             :     Assert(OidIsValid(dbNode));
     129             : 
     130      159480 :     dir = GetDatabasePath(dbNode, spcNode);
     131             : 
     132      159480 :     if (stat(dir, &st) < 0)
     133             :     {
     134             :         /* Directory does not exist? */
     135          16 :         if (errno == ENOENT)
     136             :         {
     137             :             /*
     138             :              * Acquire TablespaceCreateLock to ensure that no DROP TABLESPACE
     139             :              * or TablespaceCreateDbspace is running concurrently.
     140             :              */
     141          16 :             LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE);
     142             : 
     143             :             /*
     144             :              * Recheck to see if someone created the directory while we were
     145             :              * waiting for lock.
     146             :              */
     147          16 :             if (stat(dir, &st) == 0 && S_ISDIR(st.st_mode))
     148             :             {
     149             :                 /* Directory was created */
     150             :             }
     151             :             else
     152             :             {
     153             :                 /* Directory creation failed? */
     154          16 :                 if (MakePGDirectory(dir) < 0)
     155             :                 {
     156             :                     char       *parentdir;
     157             : 
     158             :                     /* Failure other than not exists or not in WAL replay? */
     159           0 :                     if (errno != ENOENT || !isRedo)
     160           0 :                         ereport(ERROR,
     161             :                                 (errcode_for_file_access(),
     162             :                                  errmsg("could not create directory \"%s\": %m",
     163             :                                         dir)));
     164             : 
     165             :                     /*
     166             :                      * Parent directories are missing during WAL replay, so
     167             :                      * continue by creating simple parent directories rather
     168             :                      * than a symlink.
     169             :                      */
     170             : 
     171             :                     /* create two parents up if not exist */
     172           0 :                     parentdir = pstrdup(dir);
     173           0 :                     get_parent_directory(parentdir);
     174           0 :                     get_parent_directory(parentdir);
     175             :                     /* Can't create parent and it doesn't already exist? */
     176           0 :                     if (MakePGDirectory(parentdir) < 0 && errno != EEXIST)
     177           0 :                         ereport(ERROR,
     178             :                                 (errcode_for_file_access(),
     179             :                                  errmsg("could not create directory \"%s\": %m",
     180             :                                         parentdir)));
     181           0 :                     pfree(parentdir);
     182             : 
     183             :                     /* create one parent up if not exist */
     184           0 :                     parentdir = pstrdup(dir);
     185           0 :                     get_parent_directory(parentdir);
     186             :                     /* Can't create parent and it doesn't already exist? */
     187           0 :                     if (MakePGDirectory(parentdir) < 0 && errno != EEXIST)
     188           0 :                         ereport(ERROR,
     189             :                                 (errcode_for_file_access(),
     190             :                                  errmsg("could not create directory \"%s\": %m",
     191             :                                         parentdir)));
     192           0 :                     pfree(parentdir);
     193             : 
     194             :                     /* Create database directory */
     195           0 :                     if (MakePGDirectory(dir) < 0)
     196           0 :                         ereport(ERROR,
     197             :                                 (errcode_for_file_access(),
     198             :                                  errmsg("could not create directory \"%s\": %m",
     199             :                                         dir)));
     200             :                 }
     201             :             }
     202             : 
     203          16 :             LWLockRelease(TablespaceCreateLock);
     204             :         }
     205             :         else
     206             :         {
     207           0 :             ereport(ERROR,
     208             :                     (errcode_for_file_access(),
     209             :                      errmsg("could not stat directory \"%s\": %m", dir)));
     210             :         }
     211             :     }
     212             :     else
     213             :     {
     214             :         /* Is it not a directory? */
     215      159464 :         if (!S_ISDIR(st.st_mode))
     216           0 :             ereport(ERROR,
     217             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     218             :                      errmsg("\"%s\" exists but is not a directory",
     219             :                             dir)));
     220             :     }
     221             : 
     222      159480 :     pfree(dir);
     223             : }
     224             : 
     225             : /*
     226             :  * Create a table space
     227             :  *
     228             :  * Only superusers can create a tablespace. This seems a reasonable restriction
     229             :  * since we're determining the system layout and, anyway, we probably have
     230             :  * root if we're doing this kind of activity
     231             :  */
     232             : Oid
     233          38 : CreateTableSpace(CreateTableSpaceStmt *stmt)
     234             : {
     235             : #ifdef HAVE_SYMLINK
     236             :     Relation    rel;
     237             :     Datum       values[Natts_pg_tablespace];
     238             :     bool        nulls[Natts_pg_tablespace];
     239             :     HeapTuple   tuple;
     240             :     Oid         tablespaceoid;
     241             :     char       *location;
     242             :     Oid         ownerId;
     243             :     Datum       newOptions;
     244             : 
     245             :     /* Must be super user */
     246          38 :     if (!superuser())
     247           0 :         ereport(ERROR,
     248             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     249             :                  errmsg("permission denied to create tablespace \"%s\"",
     250             :                         stmt->tablespacename),
     251             :                  errhint("Must be superuser to create a tablespace.")));
     252             : 
     253             :     /* However, the eventual owner of the tablespace need not be */
     254          38 :     if (stmt->owner)
     255           0 :         ownerId = get_rolespec_oid(stmt->owner, false);
     256             :     else
     257          38 :         ownerId = GetUserId();
     258             : 
     259             :     /* Unix-ify the offered path, and strip any trailing slashes */
     260          38 :     location = pstrdup(stmt->location);
     261          38 :     canonicalize_path(location);
     262             : 
     263             :     /* disallow quotes, else CREATE DATABASE would be at risk */
     264          38 :     if (strchr(location, '\''))
     265           0 :         ereport(ERROR,
     266             :                 (errcode(ERRCODE_INVALID_NAME),
     267             :                  errmsg("tablespace location cannot contain single quotes")));
     268             : 
     269             :     /*
     270             :      * Allowing relative paths seems risky
     271             :      *
     272             :      * this also helps us ensure that location is not empty or whitespace
     273             :      */
     274          38 :     if (!is_absolute_path(location))
     275           0 :         ereport(ERROR,
     276             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     277             :                  errmsg("tablespace location must be an absolute path")));
     278             : 
     279             :     /*
     280             :      * Check that location isn't too long. Remember that we're going to append
     281             :      * 'PG_XXX/<dboid>/<relid>_<fork>.<nnn>'.  FYI, we never actually
     282             :      * reference the whole path here, but MakePGDirectory() uses the first two
     283             :      * parts.
     284             :      */
     285          76 :     if (strlen(location) + 1 + strlen(TABLESPACE_VERSION_DIRECTORY) + 1 +
     286          38 :         OIDCHARS + 1 + OIDCHARS + 1 + FORKNAMECHARS + 1 + OIDCHARS > MAXPGPATH)
     287           0 :         ereport(ERROR,
     288             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     289             :                  errmsg("tablespace location \"%s\" is too long",
     290             :                         location)));
     291             : 
     292             :     /* Warn if the tablespace is in the data directory. */
     293          38 :     if (path_is_prefix_of_path(DataDir, location))
     294           0 :         ereport(WARNING,
     295             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     296             :                  errmsg("tablespace location should not be inside the data directory")));
     297             : 
     298             :     /*
     299             :      * Disallow creation of tablespaces named "pg_xxx"; we reserve this
     300             :      * namespace for system purposes.
     301             :      */
     302          38 :     if (!allowSystemTableMods && IsReservedName(stmt->tablespacename))
     303           2 :         ereport(ERROR,
     304             :                 (errcode(ERRCODE_RESERVED_NAME),
     305             :                  errmsg("unacceptable tablespace name \"%s\"",
     306             :                         stmt->tablespacename),
     307             :                  errdetail("The prefix \"pg_\" is reserved for system tablespaces.")));
     308             : 
     309             :     /*
     310             :      * If built with appropriate switch, whine when regression-testing
     311             :      * conventions for tablespace names are violated.
     312             :      */
     313             : #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
     314             :     if (strncmp(stmt->tablespacename, "regress_", 8) != 0)
     315             :         elog(WARNING, "tablespaces created by regression test cases should have names starting with \"regress_\"");
     316             : #endif
     317             : 
     318             :     /*
     319             :      * Check that there is no other tablespace by this name.  (The unique
     320             :      * index would catch this anyway, but might as well give a friendlier
     321             :      * message.)
     322             :      */
     323          36 :     if (OidIsValid(get_tablespace_oid(stmt->tablespacename, true)))
     324           0 :         ereport(ERROR,
     325             :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
     326             :                  errmsg("tablespace \"%s\" already exists",
     327             :                         stmt->tablespacename)));
     328             : 
     329             :     /*
     330             :      * Insert tuple into pg_tablespace.  The purpose of doing this first is to
     331             :      * lock the proposed tablename against other would-be creators. The
     332             :      * insertion will roll back if we find problems below.
     333             :      */
     334          36 :     rel = table_open(TableSpaceRelationId, RowExclusiveLock);
     335             : 
     336          36 :     MemSet(nulls, false, sizeof(nulls));
     337             : 
     338          36 :     tablespaceoid = GetNewOidWithIndex(rel, TablespaceOidIndexId,
     339             :                                        Anum_pg_tablespace_oid);
     340          36 :     values[Anum_pg_tablespace_oid - 1] = ObjectIdGetDatum(tablespaceoid);
     341          36 :     values[Anum_pg_tablespace_spcname - 1] =
     342          36 :         DirectFunctionCall1(namein, CStringGetDatum(stmt->tablespacename));
     343          36 :     values[Anum_pg_tablespace_spcowner - 1] =
     344          36 :         ObjectIdGetDatum(ownerId);
     345          36 :     nulls[Anum_pg_tablespace_spcacl - 1] = true;
     346             : 
     347             :     /* Generate new proposed spcoptions (text array) */
     348          36 :     newOptions = transformRelOptions((Datum) 0,
     349             :                                      stmt->options,
     350             :                                      NULL, NULL, false, false);
     351          36 :     (void) tablespace_reloptions(newOptions, true);
     352          32 :     if (newOptions != (Datum) 0)
     353           4 :         values[Anum_pg_tablespace_spcoptions - 1] = newOptions;
     354             :     else
     355          28 :         nulls[Anum_pg_tablespace_spcoptions - 1] = true;
     356             : 
     357          32 :     tuple = heap_form_tuple(rel->rd_att, values, nulls);
     358             : 
     359          32 :     CatalogTupleInsert(rel, tuple);
     360             : 
     361          32 :     heap_freetuple(tuple);
     362             : 
     363             :     /* Record dependency on owner */
     364          32 :     recordDependencyOnOwner(TableSpaceRelationId, tablespaceoid, ownerId);
     365             : 
     366             :     /* Post creation hook for new tablespace */
     367          32 :     InvokeObjectPostCreateHook(TableSpaceRelationId, tablespaceoid, 0);
     368             : 
     369          32 :     create_tablespace_directories(location, tablespaceoid);
     370             : 
     371             :     /* Record the filesystem change in XLOG */
     372             :     {
     373             :         xl_tblspc_create_rec xlrec;
     374             : 
     375          26 :         xlrec.ts_id = tablespaceoid;
     376             : 
     377          26 :         XLogBeginInsert();
     378          26 :         XLogRegisterData((char *) &xlrec,
     379             :                          offsetof(xl_tblspc_create_rec, ts_path));
     380          26 :         XLogRegisterData((char *) location, strlen(location) + 1);
     381             : 
     382          26 :         (void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_CREATE);
     383             :     }
     384             : 
     385             :     /*
     386             :      * Force synchronous commit, to minimize the window between creating the
     387             :      * symlink on-disk and marking the transaction committed.  It's not great
     388             :      * that there is any window at all, but definitely we don't want to make
     389             :      * it larger than necessary.
     390             :      */
     391          26 :     ForceSyncCommit();
     392             : 
     393          26 :     pfree(location);
     394             : 
     395             :     /* We keep the lock on pg_tablespace until commit */
     396          26 :     table_close(rel, NoLock);
     397             : 
     398          26 :     return tablespaceoid;
     399             : #else                           /* !HAVE_SYMLINK */
     400             :     ereport(ERROR,
     401             :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     402             :              errmsg("tablespaces are not supported on this platform")));
     403             :     return InvalidOid;          /* keep compiler quiet */
     404             : #endif                          /* HAVE_SYMLINK */
     405             : }
     406             : 
     407             : /*
     408             :  * Drop a table space
     409             :  *
     410             :  * Be careful to check that the tablespace is empty.
     411             :  */
     412             : void
     413          20 : DropTableSpace(DropTableSpaceStmt *stmt)
     414             : {
     415             : #ifdef HAVE_SYMLINK
     416          20 :     char       *tablespacename = stmt->tablespacename;
     417             :     TableScanDesc scandesc;
     418             :     Relation    rel;
     419             :     HeapTuple   tuple;
     420             :     Form_pg_tablespace spcform;
     421             :     ScanKeyData entry[1];
     422             :     Oid         tablespaceoid;
     423             : 
     424             :     /*
     425             :      * Find the target tuple
     426             :      */
     427          20 :     rel = table_open(TableSpaceRelationId, RowExclusiveLock);
     428             : 
     429          20 :     ScanKeyInit(&entry[0],
     430             :                 Anum_pg_tablespace_spcname,
     431             :                 BTEqualStrategyNumber, F_NAMEEQ,
     432             :                 CStringGetDatum(tablespacename));
     433          20 :     scandesc = table_beginscan_catalog(rel, 1, entry);
     434          20 :     tuple = heap_getnext(scandesc, ForwardScanDirection);
     435             : 
     436          20 :     if (!HeapTupleIsValid(tuple))
     437             :     {
     438           0 :         if (!stmt->missing_ok)
     439             :         {
     440           0 :             ereport(ERROR,
     441             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     442             :                      errmsg("tablespace \"%s\" does not exist",
     443             :                             tablespacename)));
     444             :         }
     445             :         else
     446             :         {
     447           0 :             ereport(NOTICE,
     448             :                     (errmsg("tablespace \"%s\" does not exist, skipping",
     449             :                             tablespacename)));
     450             :             /* XXX I assume I need one or both of these next two calls */
     451           0 :             table_endscan(scandesc);
     452           0 :             table_close(rel, NoLock);
     453             :         }
     454           0 :         return;
     455             :     }
     456             : 
     457          20 :     spcform = (Form_pg_tablespace) GETSTRUCT(tuple);
     458          20 :     tablespaceoid = spcform->oid;
     459             : 
     460             :     /* Must be tablespace owner */
     461          20 :     if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId()))
     462           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TABLESPACE,
     463             :                        tablespacename);
     464             : 
     465             :     /* Disallow drop of the standard tablespaces, even by superuser */
     466          20 :     if (tablespaceoid == GLOBALTABLESPACE_OID ||
     467             :         tablespaceoid == DEFAULTTABLESPACE_OID)
     468           0 :         aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_TABLESPACE,
     469             :                        tablespacename);
     470             : 
     471             :     /* DROP hook for the tablespace being removed */
     472          20 :     InvokeObjectDropHook(TableSpaceRelationId, tablespaceoid, 0);
     473             : 
     474             :     /*
     475             :      * Remove the pg_tablespace tuple (this will roll back if we fail below)
     476             :      */
     477          20 :     CatalogTupleDelete(rel, &tuple->t_self);
     478             : 
     479          20 :     table_endscan(scandesc);
     480             : 
     481             :     /*
     482             :      * Remove any comments or security labels on this tablespace.
     483             :      */
     484          20 :     DeleteSharedComments(tablespaceoid, TableSpaceRelationId);
     485          20 :     DeleteSharedSecurityLabel(tablespaceoid, TableSpaceRelationId);
     486             : 
     487             :     /*
     488             :      * Remove dependency on owner.
     489             :      */
     490          20 :     deleteSharedDependencyRecordsFor(TableSpaceRelationId, tablespaceoid, 0);
     491             : 
     492             :     /*
     493             :      * Acquire TablespaceCreateLock to ensure that no TablespaceCreateDbspace
     494             :      * is running concurrently.
     495             :      */
     496          20 :     LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE);
     497             : 
     498             :     /*
     499             :      * Try to remove the physical infrastructure.
     500             :      */
     501          20 :     if (!destroy_tablespace_directories(tablespaceoid, false))
     502             :     {
     503             :         /*
     504             :          * Not all files deleted?  However, there can be lingering empty files
     505             :          * in the directories, left behind by for example DROP TABLE, that
     506             :          * have been scheduled for deletion at next checkpoint (see comments
     507             :          * in mdunlink() for details).  We could just delete them immediately,
     508             :          * but we can't tell them apart from important data files that we
     509             :          * mustn't delete.  So instead, we force a checkpoint which will clean
     510             :          * out any lingering files, and try again.
     511             :          *
     512             :          * XXX On Windows, an unlinked file persists in the directory listing
     513             :          * until no process retains an open handle for the file.  The DDL
     514             :          * commands that schedule files for unlink send invalidation messages
     515             :          * directing other PostgreSQL processes to close the files.  DROP
     516             :          * TABLESPACE should not give up on the tablespace becoming empty
     517             :          * until all relevant invalidation processing is complete.
     518             :          */
     519          12 :         RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
     520          12 :         if (!destroy_tablespace_directories(tablespaceoid, false))
     521             :         {
     522             :             /* Still not empty, the files must be important then */
     523           4 :             ereport(ERROR,
     524             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     525             :                      errmsg("tablespace \"%s\" is not empty",
     526             :                             tablespacename)));
     527             :         }
     528             :     }
     529             : 
     530             :     /* Record the filesystem change in XLOG */
     531             :     {
     532             :         xl_tblspc_drop_rec xlrec;
     533             : 
     534          16 :         xlrec.ts_id = tablespaceoid;
     535             : 
     536          16 :         XLogBeginInsert();
     537          16 :         XLogRegisterData((char *) &xlrec, sizeof(xl_tblspc_drop_rec));
     538             : 
     539          16 :         (void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_DROP);
     540             :     }
     541             : 
     542             :     /*
     543             :      * Note: because we checked that the tablespace was empty, there should be
     544             :      * no need to worry about flushing shared buffers or free space map
     545             :      * entries for relations in the tablespace.
     546             :      */
     547             : 
     548             :     /*
     549             :      * Force synchronous commit, to minimize the window between removing the
     550             :      * files on-disk and marking the transaction committed.  It's not great
     551             :      * that there is any window at all, but definitely we don't want to make
     552             :      * it larger than necessary.
     553             :      */
     554          16 :     ForceSyncCommit();
     555             : 
     556             :     /*
     557             :      * Allow TablespaceCreateDbspace again.
     558             :      */
     559          16 :     LWLockRelease(TablespaceCreateLock);
     560             : 
     561             :     /* We keep the lock on pg_tablespace until commit */
     562          16 :     table_close(rel, NoLock);
     563             : #else                           /* !HAVE_SYMLINK */
     564             :     ereport(ERROR,
     565             :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     566             :              errmsg("tablespaces are not supported on this platform")));
     567             : #endif                          /* HAVE_SYMLINK */
     568             : }
     569             : 
     570             : 
     571             : /*
     572             :  * create_tablespace_directories
     573             :  *
     574             :  *  Attempt to create filesystem infrastructure linking $PGDATA/pg_tblspc/
     575             :  *  to the specified directory
     576             :  */
     577             : static void
     578          38 : create_tablespace_directories(const char *location, const Oid tablespaceoid)
     579             : {
     580             :     char       *linkloc;
     581             :     char       *location_with_version_dir;
     582             :     struct stat st;
     583             : 
     584          38 :     linkloc = psprintf("pg_tblspc/%u", tablespaceoid);
     585          38 :     location_with_version_dir = psprintf("%s/%s", location,
     586             :                                          TABLESPACE_VERSION_DIRECTORY);
     587             : 
     588             :     /*
     589             :      * Attempt to coerce target directory to safe permissions.  If this fails,
     590             :      * it doesn't exist or has the wrong owner.
     591             :      */
     592          38 :     if (chmod(location, pg_dir_create_mode) != 0)
     593             :     {
     594           6 :         if (errno == ENOENT)
     595           6 :             ereport(ERROR,
     596             :                     (errcode(ERRCODE_UNDEFINED_FILE),
     597             :                      errmsg("directory \"%s\" does not exist", location),
     598             :                      InRecovery ? errhint("Create this directory for the tablespace before "
     599             :                                           "restarting the server.") : 0));
     600             :         else
     601           0 :             ereport(ERROR,
     602             :                     (errcode_for_file_access(),
     603             :                      errmsg("could not set permissions on directory \"%s\": %m",
     604             :                             location)));
     605             :     }
     606             : 
     607          32 :     if (InRecovery)
     608             :     {
     609             :         /*
     610             :          * Our theory for replaying a CREATE is to forcibly drop the target
     611             :          * subdirectory if present, and then recreate it. This may be more
     612             :          * work than needed, but it is simple to implement.
     613             :          */
     614           6 :         if (stat(location_with_version_dir, &st) == 0 && S_ISDIR(st.st_mode))
     615             :         {
     616           6 :             if (!rmtree(location_with_version_dir, true))
     617             :                 /* If this failed, MakePGDirectory() below is going to error. */
     618           0 :                 ereport(WARNING,
     619             :                         (errmsg("some useless files may be left behind in old database directory \"%s\"",
     620             :                                 location_with_version_dir)));
     621             :         }
     622             :     }
     623             : 
     624             :     /*
     625             :      * The creation of the version directory prevents more than one tablespace
     626             :      * in a single location.
     627             :      */
     628          32 :     if (MakePGDirectory(location_with_version_dir) < 0)
     629             :     {
     630           0 :         if (errno == EEXIST)
     631           0 :             ereport(ERROR,
     632             :                     (errcode(ERRCODE_OBJECT_IN_USE),
     633             :                      errmsg("directory \"%s\" already in use as a tablespace",
     634             :                             location_with_version_dir)));
     635             :         else
     636           0 :             ereport(ERROR,
     637             :                     (errcode_for_file_access(),
     638             :                      errmsg("could not create directory \"%s\": %m",
     639             :                             location_with_version_dir)));
     640             :     }
     641             : 
     642             :     /*
     643             :      * In recovery, remove old symlink, in case it points to the wrong place.
     644             :      */
     645          32 :     if (InRecovery)
     646           6 :         remove_tablespace_symlink(linkloc);
     647             : 
     648             :     /*
     649             :      * Create the symlink under PGDATA
     650             :      */
     651          32 :     if (symlink(location, linkloc) < 0)
     652           0 :         ereport(ERROR,
     653             :                 (errcode_for_file_access(),
     654             :                  errmsg("could not create symbolic link \"%s\": %m",
     655             :                         linkloc)));
     656             : 
     657          32 :     pfree(linkloc);
     658          32 :     pfree(location_with_version_dir);
     659          32 : }
     660             : 
     661             : 
     662             : /*
     663             :  * destroy_tablespace_directories
     664             :  *
     665             :  * Attempt to remove filesystem infrastructure for the tablespace.
     666             :  *
     667             :  * 'redo' indicates we are redoing a drop from XLOG; in that case we should
     668             :  * not throw an ERROR for problems, just LOG them.  The worst consequence of
     669             :  * not removing files here would be failure to release some disk space, which
     670             :  * does not justify throwing an error that would require manual intervention
     671             :  * to get the database running again.
     672             :  *
     673             :  * Returns true if successful, false if some subdirectory is not empty
     674             :  */
     675             : static bool
     676          32 : destroy_tablespace_directories(Oid tablespaceoid, bool redo)
     677             : {
     678             :     char       *linkloc;
     679             :     char       *linkloc_with_version_dir;
     680             :     DIR        *dirdesc;
     681             :     struct dirent *de;
     682             :     char       *subfile;
     683             :     struct stat st;
     684             : 
     685          32 :     linkloc_with_version_dir = psprintf("pg_tblspc/%u/%s", tablespaceoid,
     686             :                                         TABLESPACE_VERSION_DIRECTORY);
     687             : 
     688             :     /*
     689             :      * Check if the tablespace still contains any files.  We try to rmdir each
     690             :      * per-database directory we find in it.  rmdir failure implies there are
     691             :      * still files in that subdirectory, so give up.  (We do not have to worry
     692             :      * about undoing any already completed rmdirs, since the next attempt to
     693             :      * use the tablespace from that database will simply recreate the
     694             :      * subdirectory via TablespaceCreateDbspace.)
     695             :      *
     696             :      * Since we hold TablespaceCreateLock, no one else should be creating any
     697             :      * fresh subdirectories in parallel. It is possible that new files are
     698             :      * being created within subdirectories, though, so the rmdir call could
     699             :      * fail.  Worst consequence is a less friendly error message.
     700             :      *
     701             :      * If redo is true then ENOENT is a likely outcome here, and we allow it
     702             :      * to pass without comment.  In normal operation we still allow it, but
     703             :      * with a warning.  This is because even though ProcessUtility disallows
     704             :      * DROP TABLESPACE in a transaction block, it's possible that a previous
     705             :      * DROP failed and rolled back after removing the tablespace directories
     706             :      * and/or symlink.  We want to allow a new DROP attempt to succeed at
     707             :      * removing the catalog entries (and symlink if still present), so we
     708             :      * should not give a hard error here.
     709             :      */
     710          32 :     dirdesc = AllocateDir(linkloc_with_version_dir);
     711          32 :     if (dirdesc == NULL)
     712             :     {
     713           0 :         if (errno == ENOENT)
     714             :         {
     715           0 :             if (!redo)
     716           0 :                 ereport(WARNING,
     717             :                         (errcode_for_file_access(),
     718             :                          errmsg("could not open directory \"%s\": %m",
     719             :                                 linkloc_with_version_dir)));
     720             :             /* The symlink might still exist, so go try to remove it */
     721           0 :             goto remove_symlink;
     722             :         }
     723           0 :         else if (redo)
     724             :         {
     725             :             /* in redo, just log other types of error */
     726           0 :             ereport(LOG,
     727             :                     (errcode_for_file_access(),
     728             :                      errmsg("could not open directory \"%s\": %m",
     729             :                             linkloc_with_version_dir)));
     730           0 :             pfree(linkloc_with_version_dir);
     731           0 :             return false;
     732             :         }
     733             :         /* else let ReadDir report the error */
     734             :     }
     735             : 
     736          84 :     while ((de = ReadDir(dirdesc, linkloc_with_version_dir)) != NULL)
     737             :     {
     738          68 :         if (strcmp(de->d_name, ".") == 0 ||
     739          46 :             strcmp(de->d_name, "..") == 0)
     740          44 :             continue;
     741             : 
     742          24 :         subfile = psprintf("%s/%s", linkloc_with_version_dir, de->d_name);
     743             : 
     744             :         /* This check is just to deliver a friendlier error message */
     745          24 :         if (!redo && !directory_is_empty(subfile))
     746             :         {
     747          16 :             FreeDir(dirdesc);
     748          16 :             pfree(subfile);
     749          16 :             pfree(linkloc_with_version_dir);
     750          16 :             return false;
     751             :         }
     752             : 
     753             :         /* remove empty directory */
     754           8 :         if (rmdir(subfile) < 0)
     755           0 :             ereport(redo ? LOG : ERROR,
     756             :                     (errcode_for_file_access(),
     757             :                      errmsg("could not remove directory \"%s\": %m",
     758             :                             subfile)));
     759             : 
     760           8 :         pfree(subfile);
     761             :     }
     762             : 
     763          16 :     FreeDir(dirdesc);
     764             : 
     765             :     /* remove version directory */
     766          16 :     if (rmdir(linkloc_with_version_dir) < 0)
     767             :     {
     768           0 :         ereport(redo ? LOG : ERROR,
     769             :                 (errcode_for_file_access(),
     770             :                  errmsg("could not remove directory \"%s\": %m",
     771             :                         linkloc_with_version_dir)));
     772           0 :         pfree(linkloc_with_version_dir);
     773           0 :         return false;
     774             :     }
     775             : 
     776             :     /*
     777             :      * Try to remove the symlink.  We must however deal with the possibility
     778             :      * that it's a directory instead of a symlink --- this could happen during
     779             :      * WAL replay (see TablespaceCreateDbspace), and it is also the case on
     780             :      * Windows where junction points lstat() as directories.
     781             :      *
     782             :      * Note: in the redo case, we'll return true if this final step fails;
     783             :      * there's no point in retrying it.  Also, ENOENT should provoke no more
     784             :      * than a warning.
     785             :      */
     786          16 : remove_symlink:
     787          16 :     linkloc = pstrdup(linkloc_with_version_dir);
     788          16 :     get_parent_directory(linkloc);
     789          16 :     if (lstat(linkloc, &st) < 0)
     790             :     {
     791           0 :         int         saved_errno = errno;
     792             : 
     793           0 :         ereport(redo ? LOG : (saved_errno == ENOENT ? WARNING : ERROR),
     794             :                 (errcode_for_file_access(),
     795             :                  errmsg("could not stat file \"%s\": %m",
     796             :                         linkloc)));
     797             :     }
     798          16 :     else if (S_ISDIR(st.st_mode))
     799             :     {
     800           0 :         if (rmdir(linkloc) < 0)
     801             :         {
     802           0 :             int         saved_errno = errno;
     803             : 
     804           0 :             ereport(redo ? LOG : (saved_errno == ENOENT ? WARNING : ERROR),
     805             :                     (errcode_for_file_access(),
     806             :                      errmsg("could not remove directory \"%s\": %m",
     807             :                             linkloc)));
     808             :         }
     809             :     }
     810             : #ifdef S_ISLNK
     811          16 :     else if (S_ISLNK(st.st_mode))
     812             :     {
     813          16 :         if (unlink(linkloc) < 0)
     814             :         {
     815           0 :             int         saved_errno = errno;
     816             : 
     817           0 :             ereport(redo ? LOG : (saved_errno == ENOENT ? WARNING : ERROR),
     818             :                     (errcode_for_file_access(),
     819             :                      errmsg("could not remove symbolic link \"%s\": %m",
     820             :                             linkloc)));
     821             :         }
     822             :     }
     823             : #endif
     824             :     else
     825             :     {
     826             :         /* Refuse to remove anything that's not a directory or symlink */
     827           0 :         ereport(redo ? LOG : ERROR,
     828             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     829             :                  errmsg("\"%s\" is not a directory or symbolic link",
     830             :                         linkloc)));
     831             :     }
     832             : 
     833          16 :     pfree(linkloc_with_version_dir);
     834          16 :     pfree(linkloc);
     835             : 
     836          16 :     return true;
     837             : }
     838             : 
     839             : 
     840             : /*
     841             :  * Check if a directory is empty.
     842             :  *
     843             :  * This probably belongs somewhere else, but not sure where...
     844             :  */
     845             : bool
     846        1004 : directory_is_empty(const char *path)
     847             : {
     848             :     DIR        *dirdesc;
     849             :     struct dirent *de;
     850             : 
     851        1004 :     dirdesc = AllocateDir(path);
     852             : 
     853        1028 :     while ((de = ReadDir(dirdesc, path)) != NULL)
     854             :     {
     855        1020 :         if (strcmp(de->d_name, ".") == 0 ||
     856        1008 :             strcmp(de->d_name, "..") == 0)
     857          24 :             continue;
     858         996 :         FreeDir(dirdesc);
     859         996 :         return false;
     860             :     }
     861             : 
     862           8 :     FreeDir(dirdesc);
     863           8 :     return true;
     864             : }
     865             : 
     866             : /*
     867             :  *  remove_tablespace_symlink
     868             :  *
     869             :  * This function removes symlinks in pg_tblspc.  On Windows, junction points
     870             :  * act like directories so we must be able to apply rmdir.  This function
     871             :  * works like the symlink removal code in destroy_tablespace_directories,
     872             :  * except that failure to remove is always an ERROR.  But if the file doesn't
     873             :  * exist at all, that's OK.
     874             :  */
     875             : void
     876           6 : remove_tablespace_symlink(const char *linkloc)
     877             : {
     878             :     struct stat st;
     879             : 
     880           6 :     if (lstat(linkloc, &st) < 0)
     881             :     {
     882           0 :         if (errno == ENOENT)
     883           0 :             return;
     884           0 :         ereport(ERROR,
     885             :                 (errcode_for_file_access(),
     886             :                  errmsg("could not stat file \"%s\": %m", linkloc)));
     887             :     }
     888             : 
     889           6 :     if (S_ISDIR(st.st_mode))
     890             :     {
     891             :         /*
     892             :          * This will fail if the directory isn't empty, but not if it's a
     893             :          * junction point.
     894             :          */
     895           0 :         if (rmdir(linkloc) < 0 && errno != ENOENT)
     896           0 :             ereport(ERROR,
     897             :                     (errcode_for_file_access(),
     898             :                      errmsg("could not remove directory \"%s\": %m",
     899             :                             linkloc)));
     900             :     }
     901             : #ifdef S_ISLNK
     902           6 :     else if (S_ISLNK(st.st_mode))
     903             :     {
     904           6 :         if (unlink(linkloc) < 0 && errno != ENOENT)
     905           0 :             ereport(ERROR,
     906             :                     (errcode_for_file_access(),
     907             :                      errmsg("could not remove symbolic link \"%s\": %m",
     908             :                             linkloc)));
     909             :     }
     910             : #endif
     911             :     else
     912             :     {
     913             :         /* Refuse to remove anything that's not a directory or symlink */
     914           0 :         ereport(ERROR,
     915             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     916             :                  errmsg("\"%s\" is not a directory or symbolic link",
     917             :                         linkloc)));
     918             :     }
     919             : }
     920             : 
     921             : /*
     922             :  * Rename a tablespace
     923             :  */
     924             : ObjectAddress
     925           4 : RenameTableSpace(const char *oldname, const char *newname)
     926             : {
     927             :     Oid         tspId;
     928             :     Relation    rel;
     929             :     ScanKeyData entry[1];
     930             :     TableScanDesc scan;
     931             :     HeapTuple   tup;
     932             :     HeapTuple   newtuple;
     933             :     Form_pg_tablespace newform;
     934             :     ObjectAddress address;
     935             : 
     936             :     /* Search pg_tablespace */
     937           4 :     rel = table_open(TableSpaceRelationId, RowExclusiveLock);
     938             : 
     939           4 :     ScanKeyInit(&entry[0],
     940             :                 Anum_pg_tablespace_spcname,
     941             :                 BTEqualStrategyNumber, F_NAMEEQ,
     942             :                 CStringGetDatum(oldname));
     943           4 :     scan = table_beginscan_catalog(rel, 1, entry);
     944           4 :     tup = heap_getnext(scan, ForwardScanDirection);
     945           4 :     if (!HeapTupleIsValid(tup))
     946           0 :         ereport(ERROR,
     947             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     948             :                  errmsg("tablespace \"%s\" does not exist",
     949             :                         oldname)));
     950             : 
     951           4 :     newtuple = heap_copytuple(tup);
     952           4 :     newform = (Form_pg_tablespace) GETSTRUCT(newtuple);
     953           4 :     tspId = newform->oid;
     954             : 
     955           4 :     table_endscan(scan);
     956             : 
     957             :     /* Must be owner */
     958           4 :     if (!pg_tablespace_ownercheck(tspId, GetUserId()))
     959           0 :         aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_TABLESPACE, oldname);
     960             : 
     961             :     /* Validate new name */
     962           4 :     if (!allowSystemTableMods && IsReservedName(newname))
     963           0 :         ereport(ERROR,
     964             :                 (errcode(ERRCODE_RESERVED_NAME),
     965             :                  errmsg("unacceptable tablespace name \"%s\"", newname),
     966             :                  errdetail("The prefix \"pg_\" is reserved for system tablespaces.")));
     967             : 
     968             :     /*
     969             :      * If built with appropriate switch, whine when regression-testing
     970             :      * conventions for tablespace names are violated.
     971             :      */
     972             : #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
     973             :     if (strncmp(newname, "regress_", 8) != 0)
     974             :         elog(WARNING, "tablespaces created by regression test cases should have names starting with \"regress_\"");
     975             : #endif
     976             : 
     977             :     /* Make sure the new name doesn't exist */
     978           4 :     ScanKeyInit(&entry[0],
     979             :                 Anum_pg_tablespace_spcname,
     980             :                 BTEqualStrategyNumber, F_NAMEEQ,
     981             :                 CStringGetDatum(newname));
     982           4 :     scan = table_beginscan_catalog(rel, 1, entry);
     983           4 :     tup = heap_getnext(scan, ForwardScanDirection);
     984           4 :     if (HeapTupleIsValid(tup))
     985           0 :         ereport(ERROR,
     986             :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
     987             :                  errmsg("tablespace \"%s\" already exists",
     988             :                         newname)));
     989             : 
     990           4 :     table_endscan(scan);
     991             : 
     992             :     /* OK, update the entry */
     993           4 :     namestrcpy(&(newform->spcname), newname);
     994             : 
     995           4 :     CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
     996             : 
     997           4 :     InvokeObjectPostAlterHook(TableSpaceRelationId, tspId, 0);
     998             : 
     999           4 :     ObjectAddressSet(address, TableSpaceRelationId, tspId);
    1000             : 
    1001           4 :     table_close(rel, NoLock);
    1002             : 
    1003           4 :     return address;
    1004             : }
    1005             : 
    1006             : /*
    1007             :  * Alter table space options
    1008             :  */
    1009             : Oid
    1010          16 : AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
    1011             : {
    1012             :     Relation    rel;
    1013             :     ScanKeyData entry[1];
    1014             :     TableScanDesc scandesc;
    1015             :     HeapTuple   tup;
    1016             :     Oid         tablespaceoid;
    1017             :     Datum       datum;
    1018             :     Datum       newOptions;
    1019             :     Datum       repl_val[Natts_pg_tablespace];
    1020             :     bool        isnull;
    1021             :     bool        repl_null[Natts_pg_tablespace];
    1022             :     bool        repl_repl[Natts_pg_tablespace];
    1023             :     HeapTuple   newtuple;
    1024             : 
    1025             :     /* Search pg_tablespace */
    1026          16 :     rel = table_open(TableSpaceRelationId, RowExclusiveLock);
    1027             : 
    1028          16 :     ScanKeyInit(&entry[0],
    1029             :                 Anum_pg_tablespace_spcname,
    1030             :                 BTEqualStrategyNumber, F_NAMEEQ,
    1031          16 :                 CStringGetDatum(stmt->tablespacename));
    1032          16 :     scandesc = table_beginscan_catalog(rel, 1, entry);
    1033          16 :     tup = heap_getnext(scandesc, ForwardScanDirection);
    1034          16 :     if (!HeapTupleIsValid(tup))
    1035           0 :         ereport(ERROR,
    1036             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    1037             :                  errmsg("tablespace \"%s\" does not exist",
    1038             :                         stmt->tablespacename)));
    1039             : 
    1040          16 :     tablespaceoid = ((Form_pg_tablespace) GETSTRUCT(tup))->oid;
    1041             : 
    1042             :     /* Must be owner of the existing object */
    1043          16 :     if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId()))
    1044           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TABLESPACE,
    1045           0 :                        stmt->tablespacename);
    1046             : 
    1047             :     /* Generate new proposed spcoptions (text array) */
    1048          16 :     datum = heap_getattr(tup, Anum_pg_tablespace_spcoptions,
    1049             :                          RelationGetDescr(rel), &isnull);
    1050          16 :     newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
    1051             :                                      stmt->options, NULL, NULL, false,
    1052          16 :                                      stmt->isReset);
    1053          12 :     (void) tablespace_reloptions(newOptions, true);
    1054             : 
    1055             :     /* Build new tuple. */
    1056           8 :     memset(repl_null, false, sizeof(repl_null));
    1057           8 :     memset(repl_repl, false, sizeof(repl_repl));
    1058           8 :     if (newOptions != (Datum) 0)
    1059           8 :         repl_val[Anum_pg_tablespace_spcoptions - 1] = newOptions;
    1060             :     else
    1061           0 :         repl_null[Anum_pg_tablespace_spcoptions - 1] = true;
    1062           8 :     repl_repl[Anum_pg_tablespace_spcoptions - 1] = true;
    1063           8 :     newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val,
    1064             :                                  repl_null, repl_repl);
    1065             : 
    1066             :     /* Update system catalog. */
    1067           8 :     CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
    1068             : 
    1069           8 :     InvokeObjectPostAlterHook(TableSpaceRelationId, tablespaceoid, 0);
    1070             : 
    1071           8 :     heap_freetuple(newtuple);
    1072             : 
    1073             :     /* Conclude heap scan. */
    1074           8 :     table_endscan(scandesc);
    1075           8 :     table_close(rel, NoLock);
    1076             : 
    1077           8 :     return tablespaceoid;
    1078             : }
    1079             : 
    1080             : /*
    1081             :  * Routines for handling the GUC variable 'default_tablespace'.
    1082             :  */
    1083             : 
    1084             : /* check_hook: validate new default_tablespace */
    1085             : bool
    1086        2554 : check_default_tablespace(char **newval, void **extra, GucSource source)
    1087             : {
    1088             :     /*
    1089             :      * If we aren't inside a transaction, or connected to a database, we
    1090             :      * cannot do the catalog accesses necessary to verify the name.  Must
    1091             :      * accept the value on faith.
    1092             :      */
    1093        2554 :     if (IsTransactionState() && MyDatabaseId != InvalidOid)
    1094             :     {
    1095         402 :         if (**newval != '\0' &&
    1096          32 :             !OidIsValid(get_tablespace_oid(*newval, true)))
    1097             :         {
    1098             :             /*
    1099             :              * When source == PGC_S_TEST, don't throw a hard error for a
    1100             :              * nonexistent tablespace, only a NOTICE.  See comments in guc.h.
    1101             :              */
    1102           0 :             if (source == PGC_S_TEST)
    1103             :             {
    1104           0 :                 ereport(NOTICE,
    1105             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
    1106             :                          errmsg("tablespace \"%s\" does not exist",
    1107             :                                 *newval)));
    1108             :             }
    1109             :             else
    1110             :             {
    1111           0 :                 GUC_check_errdetail("Tablespace \"%s\" does not exist.",
    1112             :                                     *newval);
    1113           0 :                 return false;
    1114             :             }
    1115             :         }
    1116             :     }
    1117             : 
    1118        2554 :     return true;
    1119             : }
    1120             : 
    1121             : /*
    1122             :  * GetDefaultTablespace -- get the OID of the current default tablespace
    1123             :  *
    1124             :  * Temporary objects have different default tablespaces, hence the
    1125             :  * relpersistence parameter must be specified.  Also, for partitioned tables,
    1126             :  * we disallow specifying the database default, so that needs to be specified
    1127             :  * too.
    1128             :  *
    1129             :  * May return InvalidOid to indicate "use the database's default tablespace".
    1130             :  *
    1131             :  * Note that caller is expected to check appropriate permissions for any
    1132             :  * result other than InvalidOid.
    1133             :  *
    1134             :  * This exists to hide (and possibly optimize the use of) the
    1135             :  * default_tablespace GUC variable.
    1136             :  */
    1137             : Oid
    1138      121414 : GetDefaultTablespace(char relpersistence, bool partitioned)
    1139             : {
    1140             :     Oid         result;
    1141             : 
    1142             :     /* The temp-table case is handled elsewhere */
    1143      121414 :     if (relpersistence == RELPERSISTENCE_TEMP)
    1144             :     {
    1145        2224 :         PrepareTempTablespaces();
    1146        2224 :         return GetNextTempTableSpace();
    1147             :     }
    1148             : 
    1149             :     /* Fast path for default_tablespace == "" */
    1150      119190 :     if (default_tablespace == NULL || default_tablespace[0] == '\0')
    1151      119154 :         return InvalidOid;
    1152             : 
    1153             :     /*
    1154             :      * It is tempting to cache this lookup for more speed, but then we would
    1155             :      * fail to detect the case where the tablespace was dropped since the GUC
    1156             :      * variable was set.  Note also that we don't complain if the value fails
    1157             :      * to refer to an existing tablespace; we just silently return InvalidOid,
    1158             :      * causing the new object to be created in the database's tablespace.
    1159             :      */
    1160          36 :     result = get_tablespace_oid(default_tablespace, true);
    1161             : 
    1162             :     /*
    1163             :      * Allow explicit specification of database's default tablespace in
    1164             :      * default_tablespace without triggering permissions checks.  Don't allow
    1165             :      * specifying that when creating a partitioned table, however, since the
    1166             :      * result is confusing.
    1167             :      */
    1168          36 :     if (result == MyDatabaseTableSpace)
    1169             :     {
    1170           8 :         if (partitioned)
    1171           8 :             ereport(ERROR,
    1172             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1173             :                      errmsg("cannot specify default tablespace for partitioned relations")));
    1174           0 :         result = InvalidOid;
    1175             :     }
    1176          28 :     return result;
    1177             : }
    1178             : 
    1179             : 
    1180             : /*
    1181             :  * Routines for handling the GUC variable 'temp_tablespaces'.
    1182             :  */
    1183             : 
    1184             : typedef struct
    1185             : {
    1186             :     int         numSpcs;
    1187             :     Oid         tblSpcs[FLEXIBLE_ARRAY_MEMBER];
    1188             : } temp_tablespaces_extra;
    1189             : 
    1190             : /* check_hook: validate new temp_tablespaces */
    1191             : bool
    1192        2184 : check_temp_tablespaces(char **newval, void **extra, GucSource source)
    1193             : {
    1194             :     char       *rawname;
    1195             :     List       *namelist;
    1196             : 
    1197             :     /* Need a modifiable copy of string */
    1198        2184 :     rawname = pstrdup(*newval);
    1199             : 
    1200             :     /* Parse string into list of identifiers */
    1201        2184 :     if (!SplitIdentifierString(rawname, ',', &namelist))
    1202             :     {
    1203             :         /* syntax error in name list */
    1204           0 :         GUC_check_errdetail("List syntax is invalid.");
    1205           0 :         pfree(rawname);
    1206           0 :         list_free(namelist);
    1207           0 :         return false;
    1208             :     }
    1209             : 
    1210             :     /*
    1211             :      * If we aren't inside a transaction, or connected to a database, we
    1212             :      * cannot do the catalog accesses necessary to verify the name.  Must
    1213             :      * accept the value on faith. Fortunately, there's then also no need to
    1214             :      * pass the data to fd.c.
    1215             :      */
    1216        2184 :     if (IsTransactionState() && MyDatabaseId != InvalidOid)
    1217             :     {
    1218             :         temp_tablespaces_extra *myextra;
    1219             :         Oid        *tblSpcs;
    1220             :         int         numSpcs;
    1221             :         ListCell   *l;
    1222             : 
    1223             :         /* temporary workspace until we are done verifying the list */
    1224           0 :         tblSpcs = (Oid *) palloc(list_length(namelist) * sizeof(Oid));
    1225           0 :         numSpcs = 0;
    1226           0 :         foreach(l, namelist)
    1227             :         {
    1228           0 :             char       *curname = (char *) lfirst(l);
    1229             :             Oid         curoid;
    1230             :             AclResult   aclresult;
    1231             : 
    1232             :             /* Allow an empty string (signifying database default) */
    1233           0 :             if (curname[0] == '\0')
    1234             :             {
    1235           0 :                 tblSpcs[numSpcs++] = InvalidOid;
    1236           0 :                 continue;
    1237             :             }
    1238             : 
    1239             :             /*
    1240             :              * In an interactive SET command, we ereport for bad info.  When
    1241             :              * source == PGC_S_TEST, don't throw a hard error for a
    1242             :              * nonexistent tablespace, only a NOTICE.  See comments in guc.h.
    1243             :              */
    1244           0 :             curoid = get_tablespace_oid(curname, source <= PGC_S_TEST);
    1245           0 :             if (curoid == InvalidOid)
    1246             :             {
    1247           0 :                 if (source == PGC_S_TEST)
    1248           0 :                     ereport(NOTICE,
    1249             :                             (errcode(ERRCODE_UNDEFINED_OBJECT),
    1250             :                              errmsg("tablespace \"%s\" does not exist",
    1251             :                                     curname)));
    1252           0 :                 continue;
    1253             :             }
    1254             : 
    1255             :             /*
    1256             :              * Allow explicit specification of database's default tablespace
    1257             :              * in temp_tablespaces without triggering permissions checks.
    1258             :              */
    1259           0 :             if (curoid == MyDatabaseTableSpace)
    1260             :             {
    1261           0 :                 tblSpcs[numSpcs++] = InvalidOid;
    1262           0 :                 continue;
    1263             :             }
    1264             : 
    1265             :             /* Check permissions, similarly complaining only if interactive */
    1266           0 :             aclresult = pg_tablespace_aclcheck(curoid, GetUserId(),
    1267             :                                                ACL_CREATE);
    1268           0 :             if (aclresult != ACLCHECK_OK)
    1269             :             {
    1270           0 :                 if (source >= PGC_S_INTERACTIVE)
    1271           0 :                     aclcheck_error(aclresult, OBJECT_TABLESPACE, curname);
    1272           0 :                 continue;
    1273             :             }
    1274             : 
    1275           0 :             tblSpcs[numSpcs++] = curoid;
    1276             :         }
    1277             : 
    1278             :         /* Now prepare an "extra" struct for assign_temp_tablespaces */
    1279           0 :         myextra = malloc(offsetof(temp_tablespaces_extra, tblSpcs) +
    1280             :                          numSpcs * sizeof(Oid));
    1281           0 :         if (!myextra)
    1282           0 :             return false;
    1283           0 :         myextra->numSpcs = numSpcs;
    1284           0 :         memcpy(myextra->tblSpcs, tblSpcs, numSpcs * sizeof(Oid));
    1285           0 :         *extra = (void *) myextra;
    1286             : 
    1287           0 :         pfree(tblSpcs);
    1288             :     }
    1289             : 
    1290        2184 :     pfree(rawname);
    1291        2184 :     list_free(namelist);
    1292             : 
    1293        2184 :     return true;
    1294             : }
    1295             : 
    1296             : /* assign_hook: do extra actions as needed */
    1297             : void
    1298        2184 : assign_temp_tablespaces(const char *newval, void *extra)
    1299             : {
    1300        2184 :     temp_tablespaces_extra *myextra = (temp_tablespaces_extra *) extra;
    1301             : 
    1302             :     /*
    1303             :      * If check_temp_tablespaces was executed inside a transaction, then pass
    1304             :      * the list it made to fd.c.  Otherwise, clear fd.c's list; we must be
    1305             :      * still outside a transaction, or else restoring during transaction exit,
    1306             :      * and in either case we can just let the next PrepareTempTablespaces call
    1307             :      * make things sane.
    1308             :      */
    1309        2184 :     if (myextra)
    1310           0 :         SetTempTablespaces(myextra->tblSpcs, myextra->numSpcs);
    1311             :     else
    1312        2184 :         SetTempTablespaces(NULL, 0);
    1313        2184 : }
    1314             : 
    1315             : /*
    1316             :  * PrepareTempTablespaces -- prepare to use temp tablespaces
    1317             :  *
    1318             :  * If we have not already done so in the current transaction, parse the
    1319             :  * temp_tablespaces GUC variable and tell fd.c which tablespace(s) to use
    1320             :  * for temp files.
    1321             :  */
    1322             : void
    1323        5254 : PrepareTempTablespaces(void)
    1324             : {
    1325             :     char       *rawname;
    1326             :     List       *namelist;
    1327             :     Oid        *tblSpcs;
    1328             :     int         numSpcs;
    1329             :     ListCell   *l;
    1330             : 
    1331             :     /* No work if already done in current transaction */
    1332        5254 :     if (TempTablespacesAreSet())
    1333        3128 :         return;
    1334             : 
    1335             :     /*
    1336             :      * Can't do catalog access unless within a transaction.  This is just a
    1337             :      * safety check in case this function is called by low-level code that
    1338             :      * could conceivably execute outside a transaction.  Note that in such a
    1339             :      * scenario, fd.c will fall back to using the current database's default
    1340             :      * tablespace, which should always be OK.
    1341             :      */
    1342        2268 :     if (!IsTransactionState())
    1343         142 :         return;
    1344             : 
    1345             :     /* Need a modifiable copy of string */
    1346        2126 :     rawname = pstrdup(temp_tablespaces);
    1347             : 
    1348             :     /* Parse string into list of identifiers */
    1349        2126 :     if (!SplitIdentifierString(rawname, ',', &namelist))
    1350             :     {
    1351             :         /* syntax error in name list */
    1352           0 :         SetTempTablespaces(NULL, 0);
    1353           0 :         pfree(rawname);
    1354           0 :         list_free(namelist);
    1355           0 :         return;
    1356             :     }
    1357             : 
    1358             :     /* Store tablespace OIDs in an array in TopTransactionContext */
    1359        2126 :     tblSpcs = (Oid *) MemoryContextAlloc(TopTransactionContext,
    1360        2126 :                                          list_length(namelist) * sizeof(Oid));
    1361        2126 :     numSpcs = 0;
    1362        2126 :     foreach(l, namelist)
    1363             :     {
    1364           0 :         char       *curname = (char *) lfirst(l);
    1365             :         Oid         curoid;
    1366             :         AclResult   aclresult;
    1367             : 
    1368             :         /* Allow an empty string (signifying database default) */
    1369           0 :         if (curname[0] == '\0')
    1370             :         {
    1371           0 :             tblSpcs[numSpcs++] = InvalidOid;
    1372           0 :             continue;
    1373             :         }
    1374             : 
    1375             :         /* Else verify that name is a valid tablespace name */
    1376           0 :         curoid = get_tablespace_oid(curname, true);
    1377           0 :         if (curoid == InvalidOid)
    1378             :         {
    1379             :             /* Skip any bad list elements */
    1380           0 :             continue;
    1381             :         }
    1382             : 
    1383             :         /*
    1384             :          * Allow explicit specification of database's default tablespace in
    1385             :          * temp_tablespaces without triggering permissions checks.
    1386             :          */
    1387           0 :         if (curoid == MyDatabaseTableSpace)
    1388             :         {
    1389           0 :             tblSpcs[numSpcs++] = InvalidOid;
    1390           0 :             continue;
    1391             :         }
    1392             : 
    1393             :         /* Check permissions similarly */
    1394           0 :         aclresult = pg_tablespace_aclcheck(curoid, GetUserId(),
    1395             :                                            ACL_CREATE);
    1396           0 :         if (aclresult != ACLCHECK_OK)
    1397           0 :             continue;
    1398             : 
    1399           0 :         tblSpcs[numSpcs++] = curoid;
    1400             :     }
    1401             : 
    1402        2126 :     SetTempTablespaces(tblSpcs, numSpcs);
    1403             : 
    1404        2126 :     pfree(rawname);
    1405        2126 :     list_free(namelist);
    1406             : }
    1407             : 
    1408             : 
    1409             : /*
    1410             :  * get_tablespace_oid - given a tablespace name, look up the OID
    1411             :  *
    1412             :  * If missing_ok is false, throw an error if tablespace name not found.  If
    1413             :  * true, just return InvalidOid.
    1414             :  */
    1415             : Oid
    1416         406 : get_tablespace_oid(const char *tablespacename, bool missing_ok)
    1417             : {
    1418             :     Oid         result;
    1419             :     Relation    rel;
    1420             :     TableScanDesc scandesc;
    1421             :     HeapTuple   tuple;
    1422             :     ScanKeyData entry[1];
    1423             : 
    1424             :     /*
    1425             :      * Search pg_tablespace.  We use a heapscan here even though there is an
    1426             :      * index on name, on the theory that pg_tablespace will usually have just
    1427             :      * a few entries and so an indexed lookup is a waste of effort.
    1428             :      */
    1429         406 :     rel = table_open(TableSpaceRelationId, AccessShareLock);
    1430             : 
    1431         406 :     ScanKeyInit(&entry[0],
    1432             :                 Anum_pg_tablespace_spcname,
    1433             :                 BTEqualStrategyNumber, F_NAMEEQ,
    1434             :                 CStringGetDatum(tablespacename));
    1435         406 :     scandesc = table_beginscan_catalog(rel, 1, entry);
    1436         406 :     tuple = heap_getnext(scandesc, ForwardScanDirection);
    1437             : 
    1438             :     /* We assume that there can be at most one matching tuple */
    1439         406 :     if (HeapTupleIsValid(tuple))
    1440         362 :         result = ((Form_pg_tablespace) GETSTRUCT(tuple))->oid;
    1441             :     else
    1442          44 :         result = InvalidOid;
    1443             : 
    1444         406 :     table_endscan(scandesc);
    1445         406 :     table_close(rel, AccessShareLock);
    1446             : 
    1447         406 :     if (!OidIsValid(result) && !missing_ok)
    1448           8 :         ereport(ERROR,
    1449             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    1450             :                  errmsg("tablespace \"%s\" does not exist",
    1451             :                         tablespacename)));
    1452             : 
    1453         398 :     return result;
    1454             : }
    1455             : 
    1456             : /*
    1457             :  * get_tablespace_name - given a tablespace OID, look up the name
    1458             :  *
    1459             :  * Returns a palloc'd string, or NULL if no such tablespace.
    1460             :  */
    1461             : char *
    1462          64 : get_tablespace_name(Oid spc_oid)
    1463             : {
    1464             :     char       *result;
    1465             :     Relation    rel;
    1466             :     TableScanDesc scandesc;
    1467             :     HeapTuple   tuple;
    1468             :     ScanKeyData entry[1];
    1469             : 
    1470             :     /*
    1471             :      * Search pg_tablespace.  We use a heapscan here even though there is an
    1472             :      * index on oid, on the theory that pg_tablespace will usually have just a
    1473             :      * few entries and so an indexed lookup is a waste of effort.
    1474             :      */
    1475          64 :     rel = table_open(TableSpaceRelationId, AccessShareLock);
    1476             : 
    1477          64 :     ScanKeyInit(&entry[0],
    1478             :                 Anum_pg_tablespace_oid,
    1479             :                 BTEqualStrategyNumber, F_OIDEQ,
    1480             :                 ObjectIdGetDatum(spc_oid));
    1481          64 :     scandesc = table_beginscan_catalog(rel, 1, entry);
    1482          64 :     tuple = heap_getnext(scandesc, ForwardScanDirection);
    1483             : 
    1484             :     /* We assume that there can be at most one matching tuple */
    1485          64 :     if (HeapTupleIsValid(tuple))
    1486          64 :         result = pstrdup(NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname));
    1487             :     else
    1488           0 :         result = NULL;
    1489             : 
    1490          64 :     table_endscan(scandesc);
    1491          64 :     table_close(rel, AccessShareLock);
    1492             : 
    1493          64 :     return result;
    1494             : }
    1495             : 
    1496             : 
    1497             : /*
    1498             :  * TABLESPACE resource manager's routines
    1499             :  */
    1500             : void
    1501           6 : tblspc_redo(XLogReaderState *record)
    1502             : {
    1503           6 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
    1504             : 
    1505             :     /* Backup blocks are not used in tblspc records */
    1506             :     Assert(!XLogRecHasAnyBlockRefs(record));
    1507             : 
    1508           6 :     if (info == XLOG_TBLSPC_CREATE)
    1509             :     {
    1510           6 :         xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) XLogRecGetData(record);
    1511           6 :         char       *location = xlrec->ts_path;
    1512             : 
    1513           6 :         create_tablespace_directories(location, xlrec->ts_id);
    1514             :     }
    1515           0 :     else if (info == XLOG_TBLSPC_DROP)
    1516             :     {
    1517           0 :         xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) XLogRecGetData(record);
    1518             : 
    1519             :         /*
    1520             :          * If we issued a WAL record for a drop tablespace it implies that
    1521             :          * there were no files in it at all when the DROP was done. That means
    1522             :          * that no permanent objects can exist in it at this point.
    1523             :          *
    1524             :          * It is possible for standby users to be using this tablespace as a
    1525             :          * location for their temporary files, so if we fail to remove all
    1526             :          * files then do conflict processing and try again, if currently
    1527             :          * enabled.
    1528             :          *
    1529             :          * Other possible reasons for failure include bollixed file
    1530             :          * permissions on a standby server when they were okay on the primary,
    1531             :          * etc etc. There's not much we can do about that, so just remove what
    1532             :          * we can and press on.
    1533             :          */
    1534           0 :         if (!destroy_tablespace_directories(xlrec->ts_id, true))
    1535             :         {
    1536           0 :             ResolveRecoveryConflictWithTablespace(xlrec->ts_id);
    1537             : 
    1538             :             /*
    1539             :              * If we did recovery processing then hopefully the backends who
    1540             :              * wrote temp files should have cleaned up and exited by now.  So
    1541             :              * retry before complaining.  If we fail again, this is just a LOG
    1542             :              * condition, because it's not worth throwing an ERROR for (as
    1543             :              * that would crash the database and require manual intervention
    1544             :              * before we could get past this WAL record on restart).
    1545             :              */
    1546           0 :             if (!destroy_tablespace_directories(xlrec->ts_id, true))
    1547           0 :                 ereport(LOG,
    1548             :                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    1549             :                          errmsg("directories for tablespace %u could not be removed",
    1550             :                                 xlrec->ts_id),
    1551             :                          errhint("You can remove the directories manually if necessary.")));
    1552             :         }
    1553             :     }
    1554             :     else
    1555           0 :         elog(PANIC, "tblspc_redo: unknown op code %u", info);
    1556           6 : }

Generated by: LCOV version 1.13