LCOV - differential code coverage report
Current view: top level - src/backend/commands - tablespace.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 74.8 % 409 306 2 14 63 24 21 203 10 72 58 209 11
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 17 17 15 2 13 3
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a