1 /*-------------------------------------------------------------------------
4 * Commands to manipulate table spaces
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
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.
15 * To support file access via the information given in RelFileNode, we
16 * maintain a symbolic-link map in $PGDATA/pg_tblspc. The symlinks are
17 * named by tablespace OIDs and point to the actual tablespace directories.
18 * Thus the full path to an arbitrary file is
19 * $PGDATA/pg_tblspc/spcoid/dboid/relfilenode
21 * There are two tablespaces created at initdb time: pg_global (for shared
22 * tables) and pg_default (for everything else). For backwards compatibility
23 * and to remain functional on platforms without symlinks, these tablespaces
24 * are accessed specially: they are respectively
25 * $PGDATA/global/relfilenode
26 * $PGDATA/base/dboid/relfilenode
28 * To allow CREATE DATABASE to give a new database a default tablespace
29 * that's different from the template database's default, we make the
30 * provision that a zero in pg_class.reltablespace means the database's
31 * default tablespace. Without this, CREATE DATABASE would have to go in
32 * and munge the system catalogs of the new database.
35 * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
36 * Portions Copyright (c) 1994, Regents of the University of California
40 * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.69 2010/01/07 04:05:39 momjian Exp $
42 *-------------------------------------------------------------------------
48 #include <sys/types.h>
51 #include "access/heapam.h"
52 #include "access/reloptions.h"
53 #include "access/sysattr.h"
54 #include "access/transam.h"
55 #include "access/xact.h"
56 #include "catalog/catalog.h"
57 #include "catalog/dependency.h"
58 #include "catalog/indexing.h"
59 #include "catalog/pg_tablespace.h"
60 #include "commands/comment.h"
61 #include "commands/defrem.h"
62 #include "commands/tablespace.h"
63 #include "miscadmin.h"
64 #include "postmaster/bgwriter.h"
65 #include "storage/fd.h"
66 #include "storage/procarray.h"
67 #include "storage/standby.h"
68 #include "utils/acl.h"
69 #include "utils/builtins.h"
70 #include "utils/fmgroids.h"
71 #include "utils/guc.h"
72 #include "utils/lsyscache.h"
73 #include "utils/memutils.h"
74 #include "utils/rel.h"
75 #include "utils/syscache.h"
76 #include "utils/tqual.h"
80 char *default_tablespace = NULL;
81 char *temp_tablespaces = NULL;
84 static bool remove_tablespace_directories(Oid tablespaceoid, bool redo);
85 static void write_version_file(const char *path);
89 * Each database using a table space is isolated into its own name space
90 * by a subdirectory named for the database OID. On first creation of an
91 * object in the tablespace, create the subdirectory. If the subdirectory
92 * already exists, fall through quietly.
94 * isRedo indicates that we are creating an object during WAL replay.
95 * In this case we will cope with the possibility of the tablespace
96 * directory not being there either --- this could happen if we are
97 * replaying an operation on a table in a subsequently-dropped tablespace.
98 * We handle this by making a directory in the place where the tablespace
99 * symlink would normally be. This isn't an exact replay of course, but
100 * it's the best we can do given the available information.
102 * If tablespaces are not supported, you might think this could be a no-op,
103 * but you'd be wrong: we still need it in case we have to re-create a
104 * database subdirectory (of $PGDATA/base) during WAL replay.
107 TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo)
113 * The global tablespace doesn't have per-database subdirectories, so
114 * nothing to do for it.
116 if (spcNode == GLOBALTABLESPACE_OID)
119 Assert(OidIsValid(spcNode));
120 Assert(OidIsValid(dbNode));
122 dir = GetDatabasePath(dbNode, spcNode);
124 if (stat(dir, &st) < 0)
129 * Acquire TablespaceCreateLock to ensure that no DROP TABLESPACE
130 * or TablespaceCreateDbspace is running concurrently.
132 LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE);
135 * Recheck to see if someone created the directory while we were
138 if (stat(dir, &st) == 0 && S_ISDIR(st.st_mode))
140 /* Directory was created. */
144 /* Directory creation failed? */
145 if (mkdir(dir, S_IRWXU) < 0)
149 /* Failure other than not exists? */
150 if (errno != ENOENT || !isRedo)
152 (errcode_for_file_access(),
153 errmsg("could not create directory \"%s\": %m",
155 /* Parent directory must be missing */
156 parentdir = pstrdup(dir);
157 get_parent_directory(parentdir);
158 /* Can't create parent either? */
159 if (mkdir(parentdir, S_IRWXU) < 0)
161 (errcode_for_file_access(),
162 errmsg("could not create directory \"%s\": %m",
165 /* Create database directory */
166 if (mkdir(dir, S_IRWXU) < 0)
168 (errcode_for_file_access(),
169 errmsg("could not create directory \"%s\": %m",
174 LWLockRelease(TablespaceCreateLock);
179 (errcode_for_file_access(),
180 errmsg("could not stat directory \"%s\": %m", dir)));
185 /* Is it not a directory? */
186 if (!S_ISDIR(st.st_mode))
188 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
189 errmsg("\"%s\" exists but is not a directory",
197 * Create a table space
199 * Only superusers can create a tablespace. This seems a reasonable restriction
200 * since we're determining the system layout and, anyway, we probably have
201 * root if we're doing this kind of activity
204 CreateTableSpace(CreateTableSpaceStmt *stmt)
208 Datum values[Natts_pg_tablespace];
209 bool nulls[Natts_pg_tablespace];
216 /* Must be super user */
219 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
220 errmsg("permission denied to create tablespace \"%s\"",
221 stmt->tablespacename),
222 errhint("Must be superuser to create a tablespace.")));
224 /* However, the eventual owner of the tablespace need not be */
226 ownerId = get_roleid_checked(stmt->owner);
228 ownerId = GetUserId();
230 /* Unix-ify the offered path, and strip any trailing slashes */
231 location = pstrdup(stmt->location);
232 canonicalize_path(location);
234 /* disallow quotes, else CREATE DATABASE would be at risk */
235 if (strchr(location, '\''))
237 (errcode(ERRCODE_INVALID_NAME),
238 errmsg("tablespace location cannot contain single quotes")));
241 * Allowing relative paths seems risky
243 * this also helps us ensure that location is not empty or whitespace
245 if (!is_absolute_path(location))
247 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
248 errmsg("tablespace location must be an absolute path")));
251 * Check that location isn't too long. Remember that we're going to append
252 * '/<dboid>/<relid>.<nnn>' (XXX but do we ever form the whole path
253 * explicitly? This may be overly conservative.)
255 if (strlen(location) >= (MAXPGPATH - 1 - OIDCHARS - 1 - OIDCHARS - 1 - OIDCHARS))
257 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
258 errmsg("tablespace location \"%s\" is too long",
262 * Disallow creation of tablespaces named "pg_xxx"; we reserve this
263 * namespace for system purposes.
265 if (!allowSystemTableMods && IsReservedName(stmt->tablespacename))
267 (errcode(ERRCODE_RESERVED_NAME),
268 errmsg("unacceptable tablespace name \"%s\"",
269 stmt->tablespacename),
270 errdetail("The prefix \"pg_\" is reserved for system tablespaces.")));
273 * Check that there is no other tablespace by this name. (The unique
274 * index would catch this anyway, but might as well give a friendlier
277 if (OidIsValid(get_tablespace_oid(stmt->tablespacename)))
279 (errcode(ERRCODE_DUPLICATE_OBJECT),
280 errmsg("tablespace \"%s\" already exists",
281 stmt->tablespacename)));
284 * Insert tuple into pg_tablespace. The purpose of doing this first is to
285 * lock the proposed tablename against other would-be creators. The
286 * insertion will roll back if we find problems below.
288 rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
290 MemSet(nulls, false, sizeof(nulls));
292 values[Anum_pg_tablespace_spcname - 1] =
293 DirectFunctionCall1(namein, CStringGetDatum(stmt->tablespacename));
294 values[Anum_pg_tablespace_spcowner - 1] =
295 ObjectIdGetDatum(ownerId);
296 values[Anum_pg_tablespace_spclocation - 1] =
297 CStringGetTextDatum(location);
298 nulls[Anum_pg_tablespace_spcacl - 1] = true;
299 nulls[Anum_pg_tablespace_spcoptions - 1] = true;
301 tuple = heap_form_tuple(rel->rd_att, values, nulls);
303 tablespaceoid = simple_heap_insert(rel, tuple);
305 CatalogUpdateIndexes(rel, tuple);
307 heap_freetuple(tuple);
309 /* Record dependency on owner */
310 recordDependencyOnOwner(TableSpaceRelationId, tablespaceoid, ownerId);
313 * Attempt to coerce target directory to safe permissions. If this fails,
314 * it doesn't exist or has the wrong owner.
316 if (chmod(location, 0700) != 0)
318 (errcode_for_file_access(),
319 errmsg("could not set permissions on directory \"%s\": %m",
323 * Check the target directory is empty.
325 if (!directory_is_empty(location))
327 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
328 errmsg("directory \"%s\" is not empty",
332 * Create the PG_VERSION file in the target directory. This has several
333 * purposes: to make sure we can write in the directory, to prevent
334 * someone from creating another tablespace pointing at the same directory
335 * (the emptiness check above will fail), and to label tablespace
336 * directories by PG version.
338 write_version_file(location);
341 * All seems well, create the symlink
343 linkloc = (char *) palloc(OIDCHARS + OIDCHARS + 1);
344 sprintf(linkloc, "pg_tblspc/%u", tablespaceoid);
346 if (symlink(location, linkloc) < 0)
348 (errcode_for_file_access(),
349 errmsg("could not create symbolic link \"%s\": %m",
352 /* Record the filesystem change in XLOG */
354 xl_tblspc_create_rec xlrec;
355 XLogRecData rdata[2];
357 xlrec.ts_id = tablespaceoid;
358 rdata[0].data = (char *) &xlrec;
359 rdata[0].len = offsetof(xl_tblspc_create_rec, ts_path);
360 rdata[0].buffer = InvalidBuffer;
361 rdata[0].next = &(rdata[1]);
363 rdata[1].data = (char *) location;
364 rdata[1].len = strlen(location) + 1;
365 rdata[1].buffer = InvalidBuffer;
366 rdata[1].next = NULL;
368 (void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_CREATE, rdata);
372 * Force synchronous commit, to minimize the window between creating the
373 * symlink on-disk and marking the transaction committed. It's not great
374 * that there is any window at all, but definitely we don't want to make
375 * it larger than necessary.
382 /* We keep the lock on pg_tablespace until commit */
383 heap_close(rel, NoLock);
384 #else /* !HAVE_SYMLINK */
386 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
387 errmsg("tablespaces are not supported on this platform")));
388 #endif /* HAVE_SYMLINK */
394 * Be careful to check that the tablespace is empty.
397 DropTableSpace(DropTableSpaceStmt *stmt)
400 char *tablespacename = stmt->tablespacename;
401 HeapScanDesc scandesc;
404 ScanKeyData entry[1];
408 * Find the target tuple
410 rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
412 ScanKeyInit(&entry[0],
413 Anum_pg_tablespace_spcname,
414 BTEqualStrategyNumber, F_NAMEEQ,
415 CStringGetDatum(tablespacename));
416 scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
417 tuple = heap_getnext(scandesc, ForwardScanDirection);
419 if (!HeapTupleIsValid(tuple))
421 if (!stmt->missing_ok)
424 (errcode(ERRCODE_UNDEFINED_OBJECT),
425 errmsg("tablespace \"%s\" does not exist",
431 (errmsg("tablespace \"%s\" does not exist, skipping",
433 /* XXX I assume I need one or both of these next two calls */
434 heap_endscan(scandesc);
435 heap_close(rel, NoLock);
440 tablespaceoid = HeapTupleGetOid(tuple);
442 /* Must be tablespace owner */
443 if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId()))
444 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
447 /* Disallow drop of the standard tablespaces, even by superuser */
448 if (tablespaceoid == GLOBALTABLESPACE_OID ||
449 tablespaceoid == DEFAULTTABLESPACE_OID)
450 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE,
454 * Remove the pg_tablespace tuple (this will roll back if we fail below)
456 simple_heap_delete(rel, &tuple->t_self);
458 heap_endscan(scandesc);
461 * Remove any comments on this tablespace.
463 DeleteSharedComments(tablespaceoid, TableSpaceRelationId);
466 * Remove dependency on owner.
468 deleteSharedDependencyRecordsFor(TableSpaceRelationId, tablespaceoid, 0);
471 * Acquire TablespaceCreateLock to ensure that no TablespaceCreateDbspace
472 * is running concurrently.
474 LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE);
477 * Try to remove the physical infrastructure.
479 if (!remove_tablespace_directories(tablespaceoid, false))
482 * Not all files deleted? However, there can be lingering empty files
483 * in the directories, left behind by for example DROP TABLE, that
484 * have been scheduled for deletion at next checkpoint (see comments
485 * in mdunlink() for details). We could just delete them immediately,
486 * but we can't tell them apart from important data files that we
487 * mustn't delete. So instead, we force a checkpoint which will clean
488 * out any lingering files, and try again.
490 RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
491 if (!remove_tablespace_directories(tablespaceoid, false))
493 /* Still not empty, the files must be important then */
495 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
496 errmsg("tablespace \"%s\" is not empty",
501 /* Record the filesystem change in XLOG */
503 xl_tblspc_drop_rec xlrec;
504 XLogRecData rdata[1];
506 xlrec.ts_id = tablespaceoid;
507 rdata[0].data = (char *) &xlrec;
508 rdata[0].len = sizeof(xl_tblspc_drop_rec);
509 rdata[0].buffer = InvalidBuffer;
510 rdata[0].next = NULL;
512 (void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_DROP, rdata);
516 * Note: because we checked that the tablespace was empty, there should be
517 * no need to worry about flushing shared buffers or free space map
518 * entries for relations in the tablespace.
522 * Force synchronous commit, to minimize the window between removing the
523 * files on-disk and marking the transaction committed. It's not great
524 * that there is any window at all, but definitely we don't want to make
525 * it larger than necessary.
530 * Allow TablespaceCreateDbspace again.
532 LWLockRelease(TablespaceCreateLock);
534 /* We keep the lock on pg_tablespace until commit */
535 heap_close(rel, NoLock);
536 #else /* !HAVE_SYMLINK */
538 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
539 errmsg("tablespaces are not supported on this platform")));
540 #endif /* HAVE_SYMLINK */
544 * remove_tablespace_directories: attempt to remove filesystem infrastructure
546 * Returns TRUE if successful, FALSE if some subdirectory is not empty
548 * redo indicates we are redoing a drop from XLOG; okay if nothing there
551 remove_tablespace_directories(Oid tablespaceoid, bool redo)
559 location = (char *) palloc(OIDCHARS + OIDCHARS + 1);
560 sprintf(location, "pg_tblspc/%u", tablespaceoid);
563 * Check if the tablespace still contains any files. We try to rmdir each
564 * per-database directory we find in it. rmdir failure implies there are
565 * still files in that subdirectory, so give up. (We do not have to worry
566 * about undoing any already completed rmdirs, since the next attempt to
567 * use the tablespace from that database will simply recreate the
568 * subdirectory via TablespaceCreateDbspace.)
570 * Since we hold TablespaceCreateLock, no one else should be creating any
571 * fresh subdirectories in parallel. It is possible that new files are
572 * being created within subdirectories, though, so the rmdir call could
573 * fail. Worst consequence is a less friendly error message.
575 * If redo is true then ENOENT is a likely outcome here, and we allow it
576 * to pass without comment. In normal operation we still allow it, but
577 * with a warning. This is because even though ProcessUtility disallows
578 * DROP TABLESPACE in a transaction block, it's possible that a previous
579 * DROP failed and rolled back after removing the tablespace directories
580 * and symlink. We want to allow a new DROP attempt to succeed at
581 * removing the catalog entries, so we should not give a hard error here.
583 dirdesc = AllocateDir(location);
590 (errcode_for_file_access(),
591 errmsg("could not open directory \"%s\": %m",
596 /* else let ReadDir report the error */
599 while ((de = ReadDir(dirdesc, location)) != NULL)
601 /* Note we ignore PG_VERSION for the nonce */
602 if (strcmp(de->d_name, ".") == 0 ||
603 strcmp(de->d_name, "..") == 0 ||
604 strcmp(de->d_name, "PG_VERSION") == 0)
607 subfile = palloc(strlen(location) + 1 + strlen(de->d_name) + 1);
608 sprintf(subfile, "%s/%s", location, de->d_name);
610 /* This check is just to deliver a friendlier error message */
611 if (!directory_is_empty(subfile))
617 /* Do the real deed */
618 if (rmdir(subfile) < 0)
620 (errcode_for_file_access(),
621 errmsg("could not remove directory \"%s\": %m",
630 * Okay, try to unlink PG_VERSION (we allow it to not be there, even in
631 * non-REDO case, for robustness).
633 subfile = palloc(strlen(location) + 11 + 1);
634 sprintf(subfile, "%s/PG_VERSION", location);
636 if (unlink(subfile) < 0)
640 (errcode_for_file_access(),
641 errmsg("could not remove file \"%s\": %m",
648 * Okay, try to remove the symlink. We must however deal with the
649 * possibility that it's a directory instead of a symlink --- this could
650 * happen during WAL replay (see TablespaceCreateDbspace), and it is also
651 * the normal case on Windows.
653 if (lstat(location, &st) == 0 && S_ISDIR(st.st_mode))
655 if (rmdir(location) < 0)
657 (errcode_for_file_access(),
658 errmsg("could not remove directory \"%s\": %m",
663 if (unlink(location) < 0)
665 (errcode_for_file_access(),
666 errmsg("could not remove symbolic link \"%s\": %m",
676 * write out the PG_VERSION file in the specified directory
679 write_version_file(const char *path)
684 /* Now write the file */
685 fullname = palloc(strlen(path) + 11 + 1);
686 sprintf(fullname, "%s/PG_VERSION", path);
688 if ((version_file = AllocateFile(fullname, PG_BINARY_W)) == NULL)
690 (errcode_for_file_access(),
691 errmsg("could not write to file \"%s\": %m",
693 fprintf(version_file, "%s\n", PG_MAJORVERSION);
694 if (FreeFile(version_file))
696 (errcode_for_file_access(),
697 errmsg("could not write to file \"%s\": %m",
704 * Check if a directory is empty.
706 * This probably belongs somewhere else, but not sure where...
709 directory_is_empty(const char *path)
714 dirdesc = AllocateDir(path);
716 while ((de = ReadDir(dirdesc, path)) != NULL)
718 if (strcmp(de->d_name, ".") == 0 ||
719 strcmp(de->d_name, "..") == 0)
730 * Rename a tablespace
733 RenameTableSpace(const char *oldname, const char *newname)
736 ScanKeyData entry[1];
740 Form_pg_tablespace newform;
742 /* Search pg_tablespace */
743 rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
745 ScanKeyInit(&entry[0],
746 Anum_pg_tablespace_spcname,
747 BTEqualStrategyNumber, F_NAMEEQ,
748 CStringGetDatum(oldname));
749 scan = heap_beginscan(rel, SnapshotNow, 1, entry);
750 tup = heap_getnext(scan, ForwardScanDirection);
751 if (!HeapTupleIsValid(tup))
753 (errcode(ERRCODE_UNDEFINED_OBJECT),
754 errmsg("tablespace \"%s\" does not exist",
757 newtuple = heap_copytuple(tup);
758 newform = (Form_pg_tablespace) GETSTRUCT(newtuple);
763 if (!pg_tablespace_ownercheck(HeapTupleGetOid(newtuple), GetUserId()))
764 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, oldname);
766 /* Validate new name */
767 if (!allowSystemTableMods && IsReservedName(newname))
769 (errcode(ERRCODE_RESERVED_NAME),
770 errmsg("unacceptable tablespace name \"%s\"", newname),
771 errdetail("The prefix \"pg_\" is reserved for system tablespaces.")));
773 /* Make sure the new name doesn't exist */
774 ScanKeyInit(&entry[0],
775 Anum_pg_tablespace_spcname,
776 BTEqualStrategyNumber, F_NAMEEQ,
777 CStringGetDatum(newname));
778 scan = heap_beginscan(rel, SnapshotNow, 1, entry);
779 tup = heap_getnext(scan, ForwardScanDirection);
780 if (HeapTupleIsValid(tup))
782 (errcode(ERRCODE_DUPLICATE_OBJECT),
783 errmsg("tablespace \"%s\" already exists",
788 /* OK, update the entry */
789 namestrcpy(&(newform->spcname), newname);
791 simple_heap_update(rel, &newtuple->t_self, newtuple);
792 CatalogUpdateIndexes(rel, newtuple);
794 heap_close(rel, NoLock);
798 * Change tablespace owner
801 AlterTableSpaceOwner(const char *name, Oid newOwnerId)
804 ScanKeyData entry[1];
805 HeapScanDesc scandesc;
806 Form_pg_tablespace spcForm;
809 /* Search pg_tablespace */
810 rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
812 ScanKeyInit(&entry[0],
813 Anum_pg_tablespace_spcname,
814 BTEqualStrategyNumber, F_NAMEEQ,
815 CStringGetDatum(name));
816 scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
817 tup = heap_getnext(scandesc, ForwardScanDirection);
818 if (!HeapTupleIsValid(tup))
820 (errcode(ERRCODE_UNDEFINED_OBJECT),
821 errmsg("tablespace \"%s\" does not exist", name)));
823 spcForm = (Form_pg_tablespace) GETSTRUCT(tup);
826 * If the new owner is the same as the existing owner, consider the
827 * command to have succeeded. This is for dump restoration purposes.
829 if (spcForm->spcowner != newOwnerId)
831 Datum repl_val[Natts_pg_tablespace];
832 bool repl_null[Natts_pg_tablespace];
833 bool repl_repl[Natts_pg_tablespace];
839 /* Otherwise, must be owner of the existing object */
840 if (!pg_tablespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
841 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
844 /* Must be able to become new owner */
845 check_is_member_of_role(GetUserId(), newOwnerId);
848 * Normally we would also check for create permissions here, but there
849 * are none for tablespaces so we follow what rename tablespace does
850 * and omit the create permissions check.
852 * NOTE: Only superusers may create tablespaces to begin with and so
853 * initially only a superuser would be able to change its ownership
857 memset(repl_null, false, sizeof(repl_null));
858 memset(repl_repl, false, sizeof(repl_repl));
860 repl_repl[Anum_pg_tablespace_spcowner - 1] = true;
861 repl_val[Anum_pg_tablespace_spcowner - 1] = ObjectIdGetDatum(newOwnerId);
864 * Determine the modified ACL for the new owner. This is only
865 * necessary when the ACL is non-null.
867 aclDatum = heap_getattr(tup,
868 Anum_pg_tablespace_spcacl,
869 RelationGetDescr(rel),
873 newAcl = aclnewowner(DatumGetAclP(aclDatum),
874 spcForm->spcowner, newOwnerId);
875 repl_repl[Anum_pg_tablespace_spcacl - 1] = true;
876 repl_val[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(newAcl);
879 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl);
881 simple_heap_update(rel, &newtuple->t_self, newtuple);
882 CatalogUpdateIndexes(rel, newtuple);
884 heap_freetuple(newtuple);
886 /* Update owner dependency reference */
887 changeDependencyOnOwner(TableSpaceRelationId, HeapTupleGetOid(tup),
891 heap_endscan(scandesc);
892 heap_close(rel, NoLock);
897 * Alter table space options
900 AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
903 ScanKeyData entry[1];
904 HeapScanDesc scandesc;
908 Datum repl_val[Natts_pg_tablespace];
910 bool repl_null[Natts_pg_tablespace];
911 bool repl_repl[Natts_pg_tablespace];
914 /* Search pg_tablespace */
915 rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
917 ScanKeyInit(&entry[0],
918 Anum_pg_tablespace_spcname,
919 BTEqualStrategyNumber, F_NAMEEQ,
920 CStringGetDatum(stmt->tablespacename));
921 scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
922 tup = heap_getnext(scandesc, ForwardScanDirection);
923 if (!HeapTupleIsValid(tup))
925 (errcode(ERRCODE_UNDEFINED_OBJECT),
926 errmsg("tablespace \"%s\" does not exist",
927 stmt->tablespacename)));
929 /* Must be owner of the existing object */
930 if (!pg_tablespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
931 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
932 stmt->tablespacename);
934 /* Generate new proposed spcoptions (text array) */
935 datum = heap_getattr(tup, Anum_pg_tablespace_spcoptions,
936 RelationGetDescr(rel), &isnull);
937 newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
938 stmt->options, NULL, NULL, false,
940 (void) tablespace_reloptions(newOptions, true);
942 /* Build new tuple. */
943 memset(repl_null, false, sizeof(repl_null));
944 memset(repl_repl, false, sizeof(repl_repl));
945 if (newOptions != (Datum) 0)
946 repl_val[Anum_pg_tablespace_spcoptions - 1] = newOptions;
948 repl_null[Anum_pg_tablespace_spcoptions - 1] = true;
949 repl_repl[Anum_pg_tablespace_spcoptions - 1] = true;
950 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val,
951 repl_null, repl_repl);
953 /* Update system catalog. */
954 simple_heap_update(rel, &newtuple->t_self, newtuple);
955 CatalogUpdateIndexes(rel, newtuple);
956 heap_freetuple(newtuple);
958 /* Conclude heap scan. */
959 heap_endscan(scandesc);
960 heap_close(rel, NoLock);
964 * Routines for handling the GUC variable 'default_tablespace'.
967 /* assign_hook: validate new default_tablespace, do extra actions as needed */
969 assign_default_tablespace(const char *newval, bool doit, GucSource source)
972 * If we aren't inside a transaction, we cannot do database access so
973 * cannot verify the name. Must accept the value on faith.
975 if (IsTransactionState())
977 if (newval[0] != '\0' &&
978 !OidIsValid(get_tablespace_oid(newval)))
980 ereport(GUC_complaint_elevel(source),
981 (errcode(ERRCODE_UNDEFINED_OBJECT),
982 errmsg("tablespace \"%s\" does not exist",
992 * GetDefaultTablespace -- get the OID of the current default tablespace
994 * Regular objects and temporary objects have different default tablespaces,
995 * hence the forTemp parameter must be specified.
997 * May return InvalidOid to indicate "use the database's default tablespace".
999 * Note that caller is expected to check appropriate permissions for any
1000 * result other than InvalidOid.
1002 * This exists to hide (and possibly optimize the use of) the
1003 * default_tablespace GUC variable.
1006 GetDefaultTablespace(bool forTemp)
1010 /* The temp-table case is handled elsewhere */
1013 PrepareTempTablespaces();
1014 return GetNextTempTableSpace();
1017 /* Fast path for default_tablespace == "" */
1018 if (default_tablespace == NULL || default_tablespace[0] == '\0')
1022 * It is tempting to cache this lookup for more speed, but then we would
1023 * fail to detect the case where the tablespace was dropped since the GUC
1024 * variable was set. Note also that we don't complain if the value fails
1025 * to refer to an existing tablespace; we just silently return InvalidOid,
1026 * causing the new object to be created in the database's tablespace.
1028 result = get_tablespace_oid(default_tablespace);
1031 * Allow explicit specification of database's default tablespace in
1032 * default_tablespace without triggering permissions checks.
1034 if (result == MyDatabaseTableSpace)
1035 result = InvalidOid;
1041 * Routines for handling the GUC variable 'temp_tablespaces'.
1044 /* assign_hook: validate new temp_tablespaces, do extra actions as needed */
1046 assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
1051 /* Need a modifiable copy of string */
1052 rawname = pstrdup(newval);
1054 /* Parse string into list of identifiers */
1055 if (!SplitIdentifierString(rawname, ',', &namelist))
1057 /* syntax error in name list */
1059 list_free(namelist);
1064 * If we aren't inside a transaction, we cannot do database access so
1065 * cannot verify the individual names. Must accept the list on faith.
1066 * Fortunately, there's then also no need to pass the data to fd.c.
1068 if (IsTransactionState())
1071 * If we error out below, or if we are called multiple times in one
1072 * transaction, we'll leak a bit of TopTransactionContext memory.
1073 * Doesn't seem worth worrying about.
1079 tblSpcs = (Oid *) MemoryContextAlloc(TopTransactionContext,
1080 list_length(namelist) * sizeof(Oid));
1082 foreach(l, namelist)
1084 char *curname = (char *) lfirst(l);
1086 AclResult aclresult;
1088 /* Allow an empty string (signifying database default) */
1089 if (curname[0] == '\0')
1091 tblSpcs[numSpcs++] = InvalidOid;
1095 /* Else verify that name is a valid tablespace name */
1096 curoid = get_tablespace_oid(curname);
1097 if (curoid == InvalidOid)
1100 * In an interactive SET command, we ereport for bad info.
1101 * Otherwise, silently ignore any bad list elements.
1103 if (source >= PGC_S_INTERACTIVE)
1105 (errcode(ERRCODE_UNDEFINED_OBJECT),
1106 errmsg("tablespace \"%s\" does not exist",
1112 * Allow explicit specification of database's default tablespace
1113 * in temp_tablespaces without triggering permissions checks.
1115 if (curoid == MyDatabaseTableSpace)
1117 tblSpcs[numSpcs++] = InvalidOid;
1121 /* Check permissions similarly */
1122 aclresult = pg_tablespace_aclcheck(curoid, GetUserId(),
1124 if (aclresult != ACLCHECK_OK)
1126 if (source >= PGC_S_INTERACTIVE)
1127 aclcheck_error(aclresult, ACL_KIND_TABLESPACE, curname);
1131 tblSpcs[numSpcs++] = curoid;
1134 /* If actively "doing it", give the new list to fd.c */
1136 SetTempTablespaces(tblSpcs, numSpcs);
1142 list_free(namelist);
1148 * PrepareTempTablespaces -- prepare to use temp tablespaces
1150 * If we have not already done so in the current transaction, parse the
1151 * temp_tablespaces GUC variable and tell fd.c which tablespace(s) to use
1155 PrepareTempTablespaces(void)
1163 /* No work if already done in current transaction */
1164 if (TempTablespacesAreSet())
1168 * Can't do catalog access unless within a transaction. This is just a
1169 * safety check in case this function is called by low-level code that
1170 * could conceivably execute outside a transaction. Note that in such a
1171 * scenario, fd.c will fall back to using the current database's default
1172 * tablespace, which should always be OK.
1174 if (!IsTransactionState())
1177 /* Need a modifiable copy of string */
1178 rawname = pstrdup(temp_tablespaces);
1180 /* Parse string into list of identifiers */
1181 if (!SplitIdentifierString(rawname, ',', &namelist))
1183 /* syntax error in name list */
1184 SetTempTablespaces(NULL, 0);
1186 list_free(namelist);
1190 /* Store tablespace OIDs in an array in TopTransactionContext */
1191 tblSpcs = (Oid *) MemoryContextAlloc(TopTransactionContext,
1192 list_length(namelist) * sizeof(Oid));
1194 foreach(l, namelist)
1196 char *curname = (char *) lfirst(l);
1198 AclResult aclresult;
1200 /* Allow an empty string (signifying database default) */
1201 if (curname[0] == '\0')
1203 tblSpcs[numSpcs++] = InvalidOid;
1207 /* Else verify that name is a valid tablespace name */
1208 curoid = get_tablespace_oid(curname);
1209 if (curoid == InvalidOid)
1211 /* Silently ignore any bad list elements */
1216 * Allow explicit specification of database's default tablespace in
1217 * temp_tablespaces without triggering permissions checks.
1219 if (curoid == MyDatabaseTableSpace)
1221 tblSpcs[numSpcs++] = InvalidOid;
1225 /* Check permissions similarly */
1226 aclresult = pg_tablespace_aclcheck(curoid, GetUserId(),
1228 if (aclresult != ACLCHECK_OK)
1231 tblSpcs[numSpcs++] = curoid;
1234 SetTempTablespaces(tblSpcs, numSpcs);
1237 list_free(namelist);
1242 * get_tablespace_oid - given a tablespace name, look up the OID
1244 * Returns InvalidOid if tablespace name not found.
1247 get_tablespace_oid(const char *tablespacename)
1251 HeapScanDesc scandesc;
1253 ScanKeyData entry[1];
1256 * Search pg_tablespace. We use a heapscan here even though there is an
1257 * index on name, on the theory that pg_tablespace will usually have just
1258 * a few entries and so an indexed lookup is a waste of effort.
1260 rel = heap_open(TableSpaceRelationId, AccessShareLock);
1262 ScanKeyInit(&entry[0],
1263 Anum_pg_tablespace_spcname,
1264 BTEqualStrategyNumber, F_NAMEEQ,
1265 CStringGetDatum(tablespacename));
1266 scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
1267 tuple = heap_getnext(scandesc, ForwardScanDirection);
1269 /* We assume that there can be at most one matching tuple */
1270 if (HeapTupleIsValid(tuple))
1271 result = HeapTupleGetOid(tuple);
1273 result = InvalidOid;
1275 heap_endscan(scandesc);
1276 heap_close(rel, AccessShareLock);
1282 * get_tablespace_name - given a tablespace OID, look up the name
1284 * Returns a palloc'd string, or NULL if no such tablespace.
1287 get_tablespace_name(Oid spc_oid)
1291 HeapScanDesc scandesc;
1293 ScanKeyData entry[1];
1296 * Search pg_tablespace. We use a heapscan here even though there is an
1297 * index on oid, on the theory that pg_tablespace will usually have just a
1298 * few entries and so an indexed lookup is a waste of effort.
1300 rel = heap_open(TableSpaceRelationId, AccessShareLock);
1302 ScanKeyInit(&entry[0],
1303 ObjectIdAttributeNumber,
1304 BTEqualStrategyNumber, F_OIDEQ,
1305 ObjectIdGetDatum(spc_oid));
1306 scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
1307 tuple = heap_getnext(scandesc, ForwardScanDirection);
1309 /* We assume that there can be at most one matching tuple */
1310 if (HeapTupleIsValid(tuple))
1311 result = pstrdup(NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname));
1315 heap_endscan(scandesc);
1316 heap_close(rel, AccessShareLock);
1323 * TABLESPACE resource manager's routines
1326 tblspc_redo(XLogRecPtr lsn, XLogRecord *record)
1328 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1330 /* Backup blocks are not used in tblspc records */
1331 Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
1333 if (info == XLOG_TBLSPC_CREATE)
1335 xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) XLogRecGetData(record);
1336 char *location = xlrec->ts_path;
1340 * Attempt to coerce target directory to safe permissions. If this
1341 * fails, it doesn't exist or has the wrong owner.
1343 if (chmod(location, 0700) != 0)
1345 (errcode_for_file_access(),
1346 errmsg("could not set permissions on directory \"%s\": %m",
1349 /* Create or re-create the PG_VERSION file in the target directory */
1350 write_version_file(location);
1352 /* Create the symlink if not already present */
1353 linkloc = (char *) palloc(OIDCHARS + OIDCHARS + 1);
1354 sprintf(linkloc, "pg_tblspc/%u", xlrec->ts_id);
1356 if (symlink(location, linkloc) < 0)
1358 if (errno != EEXIST)
1360 (errcode_for_file_access(),
1361 errmsg("could not create symbolic link \"%s\": %m",
1367 else if (info == XLOG_TBLSPC_DROP)
1369 xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) XLogRecGetData(record);
1372 * If we issued a WAL record for a drop tablespace it is
1373 * because there were no files in it at all. That means that
1374 * no permanent objects can exist in it at this point.
1376 * It is possible for standby users to be using this tablespace
1377 * as a location for their temporary files, so if we fail to
1378 * remove all files then do conflict processing and try again,
1379 * if currently enabled.
1381 if (!remove_tablespace_directories(xlrec->ts_id, true))
1383 VirtualTransactionId *temp_file_users;
1386 * Standby users may be currently using this tablespace for
1387 * for their temporary files. We only care about current
1388 * users because temp_tablespace parameter will just ignore
1389 * tablespaces that no longer exist.
1391 * Ask everybody to cancel their queries immediately so
1392 * we can ensure no temp files remain and we can remove the
1393 * tablespace. Nuke the entire site from orbit, it's the only
1396 * XXX: We could work out the pids of active backends
1397 * using this tablespace by examining the temp filenames in the
1398 * directory. We would then convert the pids into VirtualXIDs
1399 * before attempting to cancel them.
1401 * We don't wait for commit because drop tablespace is
1402 * non-transactional.
1404 temp_file_users = GetConflictingVirtualXIDs(InvalidTransactionId,
1407 ResolveRecoveryConflictWithVirtualXIDs(temp_file_users,
1409 CONFLICT_MODE_ERROR);
1412 * If we did recovery processing then hopefully the
1413 * backends who wrote temp files should have cleaned up and
1414 * exited by now. So lets recheck before we throw an error.
1415 * If !process_conflicts then this will just fail again.
1417 if (!remove_tablespace_directories(xlrec->ts_id, true))
1419 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1420 errmsg("tablespace %u is not empty",
1425 elog(PANIC, "tblspc_redo: unknown op code %u", info);
1429 tblspc_desc(StringInfo buf, uint8 xl_info, char *rec)
1431 uint8 info = xl_info & ~XLR_INFO_MASK;
1433 if (info == XLOG_TBLSPC_CREATE)
1435 xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
1437 appendStringInfo(buf, "create ts: %u \"%s\"",
1438 xlrec->ts_id, xlrec->ts_path);
1440 else if (info == XLOG_TBLSPC_DROP)
1442 xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
1444 appendStringInfo(buf, "drop ts: %u", xlrec->ts_id);
1447 appendStringInfo(buf, "UNKNOWN");