Move the HTSU_Result enum definition into snapshot.h, to avoid including
[PostgreSQL.git] / src / backend / commands / tablespace.c
bloba89cf5cfaa492bebdc29ac4f110c0e7035839e21
1 /*-------------------------------------------------------------------------
3 * tablespace.c
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
8 * system.
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-2008, PostgreSQL Global Development Group
36 * Portions Copyright (c) 1994, Regents of the University of California
39 * IDENTIFICATION
40 * $PostgreSQL$
42 *-------------------------------------------------------------------------
44 #include "postgres.h"
46 #include <unistd.h>
47 #include <dirent.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
51 #include "access/heapam.h"
52 #include "access/xact.h"
53 #include "catalog/catalog.h"
54 #include "catalog/dependency.h"
55 #include "catalog/indexing.h"
56 #include "catalog/pg_tablespace.h"
57 #include "commands/comment.h"
58 #include "commands/tablespace.h"
59 #include "miscadmin.h"
60 #include "postmaster/bgwriter.h"
61 #include "storage/fd.h"
62 #include "utils/acl.h"
63 #include "utils/builtins.h"
64 #include "utils/fmgroids.h"
65 #include "utils/guc.h"
66 #include "utils/lsyscache.h"
67 #include "utils/memutils.h"
68 #include "utils/tqual.h"
71 /* GUC variables */
72 char *default_tablespace = NULL;
73 char *temp_tablespaces = NULL;
76 static bool remove_tablespace_directories(Oid tablespaceoid, bool redo);
77 static void set_short_version(const char *path);
81 * Each database using a table space is isolated into its own name space
82 * by a subdirectory named for the database OID. On first creation of an
83 * object in the tablespace, create the subdirectory. If the subdirectory
84 * already exists, just fall through quietly.
86 * isRedo indicates that we are creating an object during WAL replay.
87 * In this case we will cope with the possibility of the tablespace
88 * directory not being there either --- this could happen if we are
89 * replaying an operation on a table in a subsequently-dropped tablespace.
90 * We handle this by making a directory in the place where the tablespace
91 * symlink would normally be. This isn't an exact replay of course, but
92 * it's the best we can do given the available information.
94 * If tablespaces are not supported, you might think this could be a no-op,
95 * but you'd be wrong: we still need it in case we have to re-create a
96 * database subdirectory (of $PGDATA/base) during WAL replay.
98 void
99 TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo)
101 struct stat st;
102 char *dir;
105 * The global tablespace doesn't have per-database subdirectories, so
106 * nothing to do for it.
108 if (spcNode == GLOBALTABLESPACE_OID)
109 return;
111 Assert(OidIsValid(spcNode));
112 Assert(OidIsValid(dbNode));
114 dir = GetDatabasePath(dbNode, spcNode);
116 if (stat(dir, &st) < 0)
118 if (errno == ENOENT)
121 * Acquire TablespaceCreateLock to ensure that no DROP TABLESPACE
122 * or TablespaceCreateDbspace is running concurrently.
124 LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE);
127 * Recheck to see if someone created the directory while we were
128 * waiting for lock.
130 if (stat(dir, &st) == 0 && S_ISDIR(st.st_mode))
132 /* need not do anything */
134 else
136 /* OK, go for it */
137 if (mkdir(dir, S_IRWXU) < 0)
139 char *parentdir;
141 if (errno != ENOENT || !isRedo)
142 ereport(ERROR,
143 (errcode_for_file_access(),
144 errmsg("could not create directory \"%s\": %m",
145 dir)));
146 /* Try to make parent directory too */
147 parentdir = pstrdup(dir);
148 get_parent_directory(parentdir);
149 if (mkdir(parentdir, S_IRWXU) < 0)
150 ereport(ERROR,
151 (errcode_for_file_access(),
152 errmsg("could not create directory \"%s\": %m",
153 parentdir)));
154 pfree(parentdir);
155 if (mkdir(dir, S_IRWXU) < 0)
156 ereport(ERROR,
157 (errcode_for_file_access(),
158 errmsg("could not create directory \"%s\": %m",
159 dir)));
163 LWLockRelease(TablespaceCreateLock);
165 else
167 ereport(ERROR,
168 (errcode_for_file_access(),
169 errmsg("could not stat directory \"%s\": %m", dir)));
172 else
174 /* be paranoid */
175 if (!S_ISDIR(st.st_mode))
176 ereport(ERROR,
177 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
178 errmsg("\"%s\" exists but is not a directory",
179 dir)));
182 pfree(dir);
186 * Create a table space
188 * Only superusers can create a tablespace. This seems a reasonable restriction
189 * since we're determining the system layout and, anyway, we probably have
190 * root if we're doing this kind of activity
192 void
193 CreateTableSpace(CreateTableSpaceStmt *stmt)
195 #ifdef HAVE_SYMLINK
196 Relation rel;
197 Datum values[Natts_pg_tablespace];
198 char nulls[Natts_pg_tablespace];
199 HeapTuple tuple;
200 Oid tablespaceoid;
201 char *location;
202 char *linkloc;
203 Oid ownerId;
205 /* Must be super user */
206 if (!superuser())
207 ereport(ERROR,
208 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
209 errmsg("permission denied to create tablespace \"%s\"",
210 stmt->tablespacename),
211 errhint("Must be superuser to create a tablespace.")));
213 /* However, the eventual owner of the tablespace need not be */
214 if (stmt->owner)
215 ownerId = get_roleid_checked(stmt->owner);
216 else
217 ownerId = GetUserId();
219 /* Unix-ify the offered path, and strip any trailing slashes */
220 location = pstrdup(stmt->location);
221 canonicalize_path(location);
223 /* disallow quotes, else CREATE DATABASE would be at risk */
224 if (strchr(location, '\''))
225 ereport(ERROR,
226 (errcode(ERRCODE_INVALID_NAME),
227 errmsg("tablespace location cannot contain single quotes")));
230 * Allowing relative paths seems risky
232 * this also helps us ensure that location is not empty or whitespace
234 if (!is_absolute_path(location))
235 ereport(ERROR,
236 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
237 errmsg("tablespace location must be an absolute path")));
240 * Check that location isn't too long. Remember that we're going to append
241 * '/<dboid>/<relid>.<nnn>' (XXX but do we ever form the whole path
242 * explicitly? This may be overly conservative.)
244 if (strlen(location) >= (MAXPGPATH - 1 - 10 - 1 - 10 - 1 - 10))
245 ereport(ERROR,
246 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
247 errmsg("tablespace location \"%s\" is too long",
248 location)));
251 * Disallow creation of tablespaces named "pg_xxx"; we reserve this
252 * namespace for system purposes.
254 if (!allowSystemTableMods && IsReservedName(stmt->tablespacename))
255 ereport(ERROR,
256 (errcode(ERRCODE_RESERVED_NAME),
257 errmsg("unacceptable tablespace name \"%s\"",
258 stmt->tablespacename),
259 errdetail("The prefix \"pg_\" is reserved for system tablespaces.")));
262 * Check that there is no other tablespace by this name. (The unique
263 * index would catch this anyway, but might as well give a friendlier
264 * message.)
266 if (OidIsValid(get_tablespace_oid(stmt->tablespacename)))
267 ereport(ERROR,
268 (errcode(ERRCODE_DUPLICATE_OBJECT),
269 errmsg("tablespace \"%s\" already exists",
270 stmt->tablespacename)));
273 * Insert tuple into pg_tablespace. The purpose of doing this first is to
274 * lock the proposed tablename against other would-be creators. The
275 * insertion will roll back if we find problems below.
277 rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
279 MemSet(nulls, ' ', Natts_pg_tablespace);
281 values[Anum_pg_tablespace_spcname - 1] =
282 DirectFunctionCall1(namein, CStringGetDatum(stmt->tablespacename));
283 values[Anum_pg_tablespace_spcowner - 1] =
284 ObjectIdGetDatum(ownerId);
285 values[Anum_pg_tablespace_spclocation - 1] =
286 CStringGetTextDatum(location);
287 nulls[Anum_pg_tablespace_spcacl - 1] = 'n';
289 tuple = heap_formtuple(rel->rd_att, values, nulls);
291 tablespaceoid = simple_heap_insert(rel, tuple);
293 CatalogUpdateIndexes(rel, tuple);
295 heap_freetuple(tuple);
297 /* Record dependency on owner */
298 recordDependencyOnOwner(TableSpaceRelationId, tablespaceoid, ownerId);
301 * Attempt to coerce target directory to safe permissions. If this fails,
302 * it doesn't exist or has the wrong owner.
304 if (chmod(location, 0700) != 0)
305 ereport(ERROR,
306 (errcode_for_file_access(),
307 errmsg("could not set permissions on directory \"%s\": %m",
308 location)));
311 * Check the target directory is empty.
313 if (!directory_is_empty(location))
314 ereport(ERROR,
315 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
316 errmsg("directory \"%s\" is not empty",
317 location)));
320 * Create the PG_VERSION file in the target directory. This has several
321 * purposes: to make sure we can write in the directory, to prevent
322 * someone from creating another tablespace pointing at the same directory
323 * (the emptiness check above will fail), and to label tablespace
324 * directories by PG version.
326 set_short_version(location);
329 * All seems well, create the symlink
331 linkloc = (char *) palloc(10 + 10 + 1);
332 sprintf(linkloc, "pg_tblspc/%u", tablespaceoid);
334 if (symlink(location, linkloc) < 0)
335 ereport(ERROR,
336 (errcode_for_file_access(),
337 errmsg("could not create symbolic link \"%s\": %m",
338 linkloc)));
340 /* Record the filesystem change in XLOG */
342 xl_tblspc_create_rec xlrec;
343 XLogRecData rdata[2];
345 xlrec.ts_id = tablespaceoid;
346 rdata[0].data = (char *) &xlrec;
347 rdata[0].len = offsetof(xl_tblspc_create_rec, ts_path);
348 rdata[0].buffer = InvalidBuffer;
349 rdata[0].next = &(rdata[1]);
351 rdata[1].data = (char *) location;
352 rdata[1].len = strlen(location) + 1;
353 rdata[1].buffer = InvalidBuffer;
354 rdata[1].next = NULL;
356 (void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_CREATE, rdata);
360 * Force synchronous commit, to minimize the window between creating the
361 * symlink on-disk and marking the transaction committed. It's not great
362 * that there is any window at all, but definitely we don't want to make
363 * it larger than necessary.
365 ForceSyncCommit();
367 pfree(linkloc);
368 pfree(location);
370 /* We keep the lock on pg_tablespace until commit */
371 heap_close(rel, NoLock);
372 #else /* !HAVE_SYMLINK */
373 ereport(ERROR,
374 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
375 errmsg("tablespaces are not supported on this platform")));
376 #endif /* HAVE_SYMLINK */
380 * Drop a table space
382 * Be careful to check that the tablespace is empty.
384 void
385 DropTableSpace(DropTableSpaceStmt *stmt)
387 #ifdef HAVE_SYMLINK
388 char *tablespacename = stmt->tablespacename;
389 HeapScanDesc scandesc;
390 Relation rel;
391 HeapTuple tuple;
392 ScanKeyData entry[1];
393 Oid tablespaceoid;
396 * Find the target tuple
398 rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
400 ScanKeyInit(&entry[0],
401 Anum_pg_tablespace_spcname,
402 BTEqualStrategyNumber, F_NAMEEQ,
403 CStringGetDatum(tablespacename));
404 scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
405 tuple = heap_getnext(scandesc, ForwardScanDirection);
407 if (!HeapTupleIsValid(tuple))
409 if (!stmt->missing_ok)
411 ereport(ERROR,
412 (errcode(ERRCODE_UNDEFINED_OBJECT),
413 errmsg("tablespace \"%s\" does not exist",
414 tablespacename)));
416 else
418 ereport(NOTICE,
419 (errmsg("tablespace \"%s\" does not exist, skipping",
420 tablespacename)));
421 /* XXX I assume I need one or both of these next two calls */
422 heap_endscan(scandesc);
423 heap_close(rel, NoLock);
425 return;
428 tablespaceoid = HeapTupleGetOid(tuple);
430 /* Must be tablespace owner */
431 if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId()))
432 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
433 tablespacename);
435 /* Disallow drop of the standard tablespaces, even by superuser */
436 if (tablespaceoid == GLOBALTABLESPACE_OID ||
437 tablespaceoid == DEFAULTTABLESPACE_OID)
438 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE,
439 tablespacename);
442 * Remove the pg_tablespace tuple (this will roll back if we fail below)
444 simple_heap_delete(rel, &tuple->t_self);
446 heap_endscan(scandesc);
449 * Remove any comments on this tablespace.
451 DeleteSharedComments(tablespaceoid, TableSpaceRelationId);
454 * Remove dependency on owner.
456 deleteSharedDependencyRecordsFor(TableSpaceRelationId, tablespaceoid);
459 * Acquire TablespaceCreateLock to ensure that no TablespaceCreateDbspace
460 * is running concurrently.
462 LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE);
465 * Try to remove the physical infrastructure.
467 if (!remove_tablespace_directories(tablespaceoid, false))
470 * Not all files deleted? However, there can be lingering empty files
471 * in the directories, left behind by for example DROP TABLE, that
472 * have been scheduled for deletion at next checkpoint (see comments
473 * in mdunlink() for details). We could just delete them immediately,
474 * but we can't tell them apart from important data files that we
475 * mustn't delete. So instead, we force a checkpoint which will clean
476 * out any lingering files, and try again.
478 RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
479 if (!remove_tablespace_directories(tablespaceoid, false))
481 /* Still not empty, the files must be important then */
482 ereport(ERROR,
483 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
484 errmsg("tablespace \"%s\" is not empty",
485 tablespacename)));
489 /* Record the filesystem change in XLOG */
491 xl_tblspc_drop_rec xlrec;
492 XLogRecData rdata[1];
494 xlrec.ts_id = tablespaceoid;
495 rdata[0].data = (char *) &xlrec;
496 rdata[0].len = sizeof(xl_tblspc_drop_rec);
497 rdata[0].buffer = InvalidBuffer;
498 rdata[0].next = NULL;
500 (void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_DROP, rdata);
504 * Note: because we checked that the tablespace was empty, there should be
505 * no need to worry about flushing shared buffers or free space map
506 * entries for relations in the tablespace.
510 * Force synchronous commit, to minimize the window between removing the
511 * files on-disk and marking the transaction committed. It's not great
512 * that there is any window at all, but definitely we don't want to make
513 * it larger than necessary.
515 ForceSyncCommit();
518 * Allow TablespaceCreateDbspace again.
520 LWLockRelease(TablespaceCreateLock);
522 /* We keep the lock on pg_tablespace until commit */
523 heap_close(rel, NoLock);
524 #else /* !HAVE_SYMLINK */
525 ereport(ERROR,
526 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
527 errmsg("tablespaces are not supported on this platform")));
528 #endif /* HAVE_SYMLINK */
532 * remove_tablespace_directories: attempt to remove filesystem infrastructure
534 * Returns TRUE if successful, FALSE if some subdirectory is not empty
536 * redo indicates we are redoing a drop from XLOG; okay if nothing there
538 static bool
539 remove_tablespace_directories(Oid tablespaceoid, bool redo)
541 char *location;
542 DIR *dirdesc;
543 struct dirent *de;
544 char *subfile;
545 struct stat st;
547 location = (char *) palloc(10 + 10 + 1);
548 sprintf(location, "pg_tblspc/%u", tablespaceoid);
551 * Check if the tablespace still contains any files. We try to rmdir each
552 * per-database directory we find in it. rmdir failure implies there are
553 * still files in that subdirectory, so give up. (We do not have to worry
554 * about undoing any already completed rmdirs, since the next attempt to
555 * use the tablespace from that database will simply recreate the
556 * subdirectory via TablespaceCreateDbspace.)
558 * Since we hold TablespaceCreateLock, no one else should be creating any
559 * fresh subdirectories in parallel. It is possible that new files are
560 * being created within subdirectories, though, so the rmdir call could
561 * fail. Worst consequence is a less friendly error message.
563 * If redo is true then ENOENT is a likely outcome here, and we allow it
564 * to pass without comment. In normal operation we still allow it, but
565 * with a warning. This is because even though ProcessUtility disallows
566 * DROP TABLESPACE in a transaction block, it's possible that a previous
567 * DROP failed and rolled back after removing the tablespace directories
568 * and symlink. We want to allow a new DROP attempt to succeed at
569 * removing the catalog entries, so we should not give a hard error here.
571 dirdesc = AllocateDir(location);
572 if (dirdesc == NULL)
574 if (errno == ENOENT)
576 if (!redo)
577 ereport(WARNING,
578 (errcode_for_file_access(),
579 errmsg("could not open directory \"%s\": %m",
580 location)));
581 pfree(location);
582 return true;
584 /* else let ReadDir report the error */
587 while ((de = ReadDir(dirdesc, location)) != NULL)
589 /* Note we ignore PG_VERSION for the nonce */
590 if (strcmp(de->d_name, ".") == 0 ||
591 strcmp(de->d_name, "..") == 0 ||
592 strcmp(de->d_name, "PG_VERSION") == 0)
593 continue;
595 subfile = palloc(strlen(location) + 1 + strlen(de->d_name) + 1);
596 sprintf(subfile, "%s/%s", location, de->d_name);
598 /* This check is just to deliver a friendlier error message */
599 if (!directory_is_empty(subfile))
601 FreeDir(dirdesc);
602 return false;
605 /* Do the real deed */
606 if (rmdir(subfile) < 0)
607 ereport(ERROR,
608 (errcode_for_file_access(),
609 errmsg("could not remove directory \"%s\": %m",
610 subfile)));
612 pfree(subfile);
615 FreeDir(dirdesc);
618 * Okay, try to unlink PG_VERSION (we allow it to not be there, even in
619 * non-REDO case, for robustness).
621 subfile = palloc(strlen(location) + 11 + 1);
622 sprintf(subfile, "%s/PG_VERSION", location);
624 if (unlink(subfile) < 0)
626 if (errno != ENOENT)
627 ereport(ERROR,
628 (errcode_for_file_access(),
629 errmsg("could not remove file \"%s\": %m",
630 subfile)));
633 pfree(subfile);
636 * Okay, try to remove the symlink. We must however deal with the
637 * possibility that it's a directory instead of a symlink --- this could
638 * happen during WAL replay (see TablespaceCreateDbspace), and it is also
639 * the normal case on Windows.
641 if (lstat(location, &st) == 0 && S_ISDIR(st.st_mode))
643 if (rmdir(location) < 0)
644 ereport(ERROR,
645 (errcode_for_file_access(),
646 errmsg("could not remove directory \"%s\": %m",
647 location)));
649 else
651 if (unlink(location) < 0)
652 ereport(ERROR,
653 (errcode_for_file_access(),
654 errmsg("could not remove symbolic link \"%s\": %m",
655 location)));
658 pfree(location);
660 return true;
664 * write out the PG_VERSION file in the specified directory
666 static void
667 set_short_version(const char *path)
669 char *short_version;
670 bool gotdot = false;
671 int end;
672 char *fullname;
673 FILE *version_file;
675 /* Construct short version string (should match initdb.c) */
676 short_version = pstrdup(PG_VERSION);
678 for (end = 0; short_version[end] != '\0'; end++)
680 if (short_version[end] == '.')
682 Assert(end != 0);
683 if (gotdot)
684 break;
685 else
686 gotdot = true;
688 else if (short_version[end] < '0' || short_version[end] > '9')
690 /* gone past digits and dots */
691 break;
694 Assert(end > 0 && short_version[end - 1] != '.' && gotdot);
695 short_version[end] = '\0';
697 /* Now write the file */
698 fullname = palloc(strlen(path) + 11 + 1);
699 sprintf(fullname, "%s/PG_VERSION", path);
700 version_file = AllocateFile(fullname, PG_BINARY_W);
701 if (version_file == NULL)
702 ereport(ERROR,
703 (errcode_for_file_access(),
704 errmsg("could not write to file \"%s\": %m",
705 fullname)));
706 fprintf(version_file, "%s\n", short_version);
707 if (FreeFile(version_file))
708 ereport(ERROR,
709 (errcode_for_file_access(),
710 errmsg("could not write to file \"%s\": %m",
711 fullname)));
713 pfree(fullname);
714 pfree(short_version);
718 * Check if a directory is empty.
720 * This probably belongs somewhere else, but not sure where...
722 bool
723 directory_is_empty(const char *path)
725 DIR *dirdesc;
726 struct dirent *de;
728 dirdesc = AllocateDir(path);
730 while ((de = ReadDir(dirdesc, path)) != NULL)
732 if (strcmp(de->d_name, ".") == 0 ||
733 strcmp(de->d_name, "..") == 0)
734 continue;
735 FreeDir(dirdesc);
736 return false;
739 FreeDir(dirdesc);
740 return true;
744 * Rename a tablespace
746 void
747 RenameTableSpace(const char *oldname, const char *newname)
749 Relation rel;
750 ScanKeyData entry[1];
751 HeapScanDesc scan;
752 HeapTuple tup;
753 HeapTuple newtuple;
754 Form_pg_tablespace newform;
756 /* Search pg_tablespace */
757 rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
759 ScanKeyInit(&entry[0],
760 Anum_pg_tablespace_spcname,
761 BTEqualStrategyNumber, F_NAMEEQ,
762 CStringGetDatum(oldname));
763 scan = heap_beginscan(rel, SnapshotNow, 1, entry);
764 tup = heap_getnext(scan, ForwardScanDirection);
765 if (!HeapTupleIsValid(tup))
766 ereport(ERROR,
767 (errcode(ERRCODE_UNDEFINED_OBJECT),
768 errmsg("tablespace \"%s\" does not exist",
769 oldname)));
771 newtuple = heap_copytuple(tup);
772 newform = (Form_pg_tablespace) GETSTRUCT(newtuple);
774 heap_endscan(scan);
776 /* Must be owner */
777 if (!pg_tablespace_ownercheck(HeapTupleGetOid(newtuple), GetUserId()))
778 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, oldname);
780 /* Validate new name */
781 if (!allowSystemTableMods && IsReservedName(newname))
782 ereport(ERROR,
783 (errcode(ERRCODE_RESERVED_NAME),
784 errmsg("unacceptable tablespace name \"%s\"", newname),
785 errdetail("The prefix \"pg_\" is reserved for system tablespaces.")));
787 /* Make sure the new name doesn't exist */
788 ScanKeyInit(&entry[0],
789 Anum_pg_tablespace_spcname,
790 BTEqualStrategyNumber, F_NAMEEQ,
791 CStringGetDatum(newname));
792 scan = heap_beginscan(rel, SnapshotNow, 1, entry);
793 tup = heap_getnext(scan, ForwardScanDirection);
794 if (HeapTupleIsValid(tup))
795 ereport(ERROR,
796 (errcode(ERRCODE_DUPLICATE_OBJECT),
797 errmsg("tablespace \"%s\" already exists",
798 newname)));
800 heap_endscan(scan);
802 /* OK, update the entry */
803 namestrcpy(&(newform->spcname), newname);
805 simple_heap_update(rel, &newtuple->t_self, newtuple);
806 CatalogUpdateIndexes(rel, newtuple);
808 heap_close(rel, NoLock);
812 * Change tablespace owner
814 void
815 AlterTableSpaceOwner(const char *name, Oid newOwnerId)
817 Relation rel;
818 ScanKeyData entry[1];
819 HeapScanDesc scandesc;
820 Form_pg_tablespace spcForm;
821 HeapTuple tup;
823 /* Search pg_tablespace */
824 rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
826 ScanKeyInit(&entry[0],
827 Anum_pg_tablespace_spcname,
828 BTEqualStrategyNumber, F_NAMEEQ,
829 CStringGetDatum(name));
830 scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
831 tup = heap_getnext(scandesc, ForwardScanDirection);
832 if (!HeapTupleIsValid(tup))
833 ereport(ERROR,
834 (errcode(ERRCODE_UNDEFINED_OBJECT),
835 errmsg("tablespace \"%s\" does not exist", name)));
837 spcForm = (Form_pg_tablespace) GETSTRUCT(tup);
840 * If the new owner is the same as the existing owner, consider the
841 * command to have succeeded. This is for dump restoration purposes.
843 if (spcForm->spcowner != newOwnerId)
845 Datum repl_val[Natts_pg_tablespace];
846 char repl_null[Natts_pg_tablespace];
847 char repl_repl[Natts_pg_tablespace];
848 Acl *newAcl;
849 Datum aclDatum;
850 bool isNull;
851 HeapTuple newtuple;
853 /* Otherwise, must be owner of the existing object */
854 if (!pg_tablespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
855 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
856 name);
858 /* Must be able to become new owner */
859 check_is_member_of_role(GetUserId(), newOwnerId);
862 * Normally we would also check for create permissions here, but there
863 * are none for tablespaces so we follow what rename tablespace does
864 * and omit the create permissions check.
866 * NOTE: Only superusers may create tablespaces to begin with and so
867 * initially only a superuser would be able to change its ownership
868 * anyway.
871 memset(repl_null, ' ', sizeof(repl_null));
872 memset(repl_repl, ' ', sizeof(repl_repl));
874 repl_repl[Anum_pg_tablespace_spcowner - 1] = 'r';
875 repl_val[Anum_pg_tablespace_spcowner - 1] = ObjectIdGetDatum(newOwnerId);
878 * Determine the modified ACL for the new owner. This is only
879 * necessary when the ACL is non-null.
881 aclDatum = heap_getattr(tup,
882 Anum_pg_tablespace_spcacl,
883 RelationGetDescr(rel),
884 &isNull);
885 if (!isNull)
887 newAcl = aclnewowner(DatumGetAclP(aclDatum),
888 spcForm->spcowner, newOwnerId);
889 repl_repl[Anum_pg_tablespace_spcacl - 1] = 'r';
890 repl_val[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(newAcl);
893 newtuple = heap_modifytuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl);
895 simple_heap_update(rel, &newtuple->t_self, newtuple);
896 CatalogUpdateIndexes(rel, newtuple);
898 heap_freetuple(newtuple);
900 /* Update owner dependency reference */
901 changeDependencyOnOwner(TableSpaceRelationId, HeapTupleGetOid(tup),
902 newOwnerId);
905 heap_endscan(scandesc);
906 heap_close(rel, NoLock);
911 * Routines for handling the GUC variable 'default_tablespace'.
914 /* assign_hook: validate new default_tablespace, do extra actions as needed */
915 const char *
916 assign_default_tablespace(const char *newval, bool doit, GucSource source)
919 * If we aren't inside a transaction, we cannot do database access so
920 * cannot verify the name. Must accept the value on faith.
922 if (IsTransactionState())
924 if (newval[0] != '\0' &&
925 !OidIsValid(get_tablespace_oid(newval)))
927 ereport(GUC_complaint_elevel(source),
928 (errcode(ERRCODE_UNDEFINED_OBJECT),
929 errmsg("tablespace \"%s\" does not exist",
930 newval)));
931 return NULL;
935 return newval;
939 * GetDefaultTablespace -- get the OID of the current default tablespace
941 * Regular objects and temporary objects have different default tablespaces,
942 * hence the forTemp parameter must be specified.
944 * May return InvalidOid to indicate "use the database's default tablespace".
946 * Note that caller is expected to check appropriate permissions for any
947 * result other than InvalidOid.
949 * This exists to hide (and possibly optimize the use of) the
950 * default_tablespace GUC variable.
953 GetDefaultTablespace(bool forTemp)
955 Oid result;
957 /* The temp-table case is handled elsewhere */
958 if (forTemp)
960 PrepareTempTablespaces();
961 return GetNextTempTableSpace();
964 /* Fast path for default_tablespace == "" */
965 if (default_tablespace == NULL || default_tablespace[0] == '\0')
966 return InvalidOid;
969 * It is tempting to cache this lookup for more speed, but then we would
970 * fail to detect the case where the tablespace was dropped since the GUC
971 * variable was set. Note also that we don't complain if the value fails
972 * to refer to an existing tablespace; we just silently return InvalidOid,
973 * causing the new object to be created in the database's tablespace.
975 result = get_tablespace_oid(default_tablespace);
978 * Allow explicit specification of database's default tablespace in
979 * default_tablespace without triggering permissions checks.
981 if (result == MyDatabaseTableSpace)
982 result = InvalidOid;
983 return result;
988 * Routines for handling the GUC variable 'temp_tablespaces'.
991 /* assign_hook: validate new temp_tablespaces, do extra actions as needed */
992 const char *
993 assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
995 char *rawname;
996 List *namelist;
998 /* Need a modifiable copy of string */
999 rawname = pstrdup(newval);
1001 /* Parse string into list of identifiers */
1002 if (!SplitIdentifierString(rawname, ',', &namelist))
1004 /* syntax error in name list */
1005 pfree(rawname);
1006 list_free(namelist);
1007 return NULL;
1011 * If we aren't inside a transaction, we cannot do database access so
1012 * cannot verify the individual names. Must accept the list on faith.
1013 * Fortunately, there's then also no need to pass the data to fd.c.
1015 if (IsTransactionState())
1018 * If we error out below, or if we are called multiple times in one
1019 * transaction, we'll leak a bit of TopTransactionContext memory.
1020 * Doesn't seem worth worrying about.
1022 Oid *tblSpcs;
1023 int numSpcs;
1024 ListCell *l;
1026 tblSpcs = (Oid *) MemoryContextAlloc(TopTransactionContext,
1027 list_length(namelist) * sizeof(Oid));
1028 numSpcs = 0;
1029 foreach(l, namelist)
1031 char *curname = (char *) lfirst(l);
1032 Oid curoid;
1033 AclResult aclresult;
1035 /* Allow an empty string (signifying database default) */
1036 if (curname[0] == '\0')
1038 tblSpcs[numSpcs++] = InvalidOid;
1039 continue;
1042 /* Else verify that name is a valid tablespace name */
1043 curoid = get_tablespace_oid(curname);
1044 if (curoid == InvalidOid)
1047 * In an interactive SET command, we ereport for bad info.
1048 * Otherwise, silently ignore any bad list elements.
1050 if (source >= PGC_S_INTERACTIVE)
1051 ereport(ERROR,
1052 (errcode(ERRCODE_UNDEFINED_OBJECT),
1053 errmsg("tablespace \"%s\" does not exist",
1054 curname)));
1055 continue;
1059 * Allow explicit specification of database's default tablespace
1060 * in temp_tablespaces without triggering permissions checks.
1062 if (curoid == MyDatabaseTableSpace)
1064 tblSpcs[numSpcs++] = InvalidOid;
1065 continue;
1068 /* Check permissions similarly */
1069 aclresult = pg_tablespace_aclcheck(curoid, GetUserId(),
1070 ACL_CREATE);
1071 if (aclresult != ACLCHECK_OK)
1073 if (source >= PGC_S_INTERACTIVE)
1074 aclcheck_error(aclresult, ACL_KIND_TABLESPACE, curname);
1075 continue;
1078 tblSpcs[numSpcs++] = curoid;
1081 /* If actively "doing it", give the new list to fd.c */
1082 if (doit)
1083 SetTempTablespaces(tblSpcs, numSpcs);
1084 else
1085 pfree(tblSpcs);
1088 pfree(rawname);
1089 list_free(namelist);
1091 return newval;
1095 * PrepareTempTablespaces -- prepare to use temp tablespaces
1097 * If we have not already done so in the current transaction, parse the
1098 * temp_tablespaces GUC variable and tell fd.c which tablespace(s) to use
1099 * for temp files.
1101 void
1102 PrepareTempTablespaces(void)
1104 char *rawname;
1105 List *namelist;
1106 Oid *tblSpcs;
1107 int numSpcs;
1108 ListCell *l;
1110 /* No work if already done in current transaction */
1111 if (TempTablespacesAreSet())
1112 return;
1115 * Can't do catalog access unless within a transaction. This is just a
1116 * safety check in case this function is called by low-level code that
1117 * could conceivably execute outside a transaction. Note that in such a
1118 * scenario, fd.c will fall back to using the current database's default
1119 * tablespace, which should always be OK.
1121 if (!IsTransactionState())
1122 return;
1124 /* Need a modifiable copy of string */
1125 rawname = pstrdup(temp_tablespaces);
1127 /* Parse string into list of identifiers */
1128 if (!SplitIdentifierString(rawname, ',', &namelist))
1130 /* syntax error in name list */
1131 SetTempTablespaces(NULL, 0);
1132 pfree(rawname);
1133 list_free(namelist);
1134 return;
1137 /* Store tablespace OIDs in an array in TopTransactionContext */
1138 tblSpcs = (Oid *) MemoryContextAlloc(TopTransactionContext,
1139 list_length(namelist) * sizeof(Oid));
1140 numSpcs = 0;
1141 foreach(l, namelist)
1143 char *curname = (char *) lfirst(l);
1144 Oid curoid;
1145 AclResult aclresult;
1147 /* Allow an empty string (signifying database default) */
1148 if (curname[0] == '\0')
1150 tblSpcs[numSpcs++] = InvalidOid;
1151 continue;
1154 /* Else verify that name is a valid tablespace name */
1155 curoid = get_tablespace_oid(curname);
1156 if (curoid == InvalidOid)
1158 /* Silently ignore any bad list elements */
1159 continue;
1163 * Allow explicit specification of database's default tablespace in
1164 * temp_tablespaces without triggering permissions checks.
1166 if (curoid == MyDatabaseTableSpace)
1168 tblSpcs[numSpcs++] = InvalidOid;
1169 continue;
1172 /* Check permissions similarly */
1173 aclresult = pg_tablespace_aclcheck(curoid, GetUserId(),
1174 ACL_CREATE);
1175 if (aclresult != ACLCHECK_OK)
1176 continue;
1178 tblSpcs[numSpcs++] = curoid;
1181 SetTempTablespaces(tblSpcs, numSpcs);
1183 pfree(rawname);
1184 list_free(namelist);
1189 * get_tablespace_oid - given a tablespace name, look up the OID
1191 * Returns InvalidOid if tablespace name not found.
1194 get_tablespace_oid(const char *tablespacename)
1196 Oid result;
1197 Relation rel;
1198 HeapScanDesc scandesc;
1199 HeapTuple tuple;
1200 ScanKeyData entry[1];
1203 * Search pg_tablespace. We use a heapscan here even though there is an
1204 * index on name, on the theory that pg_tablespace will usually have just
1205 * a few entries and so an indexed lookup is a waste of effort.
1207 rel = heap_open(TableSpaceRelationId, AccessShareLock);
1209 ScanKeyInit(&entry[0],
1210 Anum_pg_tablespace_spcname,
1211 BTEqualStrategyNumber, F_NAMEEQ,
1212 CStringGetDatum(tablespacename));
1213 scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
1214 tuple = heap_getnext(scandesc, ForwardScanDirection);
1216 /* We assume that there can be at most one matching tuple */
1217 if (HeapTupleIsValid(tuple))
1218 result = HeapTupleGetOid(tuple);
1219 else
1220 result = InvalidOid;
1222 heap_endscan(scandesc);
1223 heap_close(rel, AccessShareLock);
1225 return result;
1229 * get_tablespace_name - given a tablespace OID, look up the name
1231 * Returns a palloc'd string, or NULL if no such tablespace.
1233 char *
1234 get_tablespace_name(Oid spc_oid)
1236 char *result;
1237 Relation rel;
1238 HeapScanDesc scandesc;
1239 HeapTuple tuple;
1240 ScanKeyData entry[1];
1243 * Search pg_tablespace. We use a heapscan here even though there is an
1244 * index on oid, on the theory that pg_tablespace will usually have just a
1245 * few entries and so an indexed lookup is a waste of effort.
1247 rel = heap_open(TableSpaceRelationId, AccessShareLock);
1249 ScanKeyInit(&entry[0],
1250 ObjectIdAttributeNumber,
1251 BTEqualStrategyNumber, F_OIDEQ,
1252 ObjectIdGetDatum(spc_oid));
1253 scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
1254 tuple = heap_getnext(scandesc, ForwardScanDirection);
1256 /* We assume that there can be at most one matching tuple */
1257 if (HeapTupleIsValid(tuple))
1258 result = pstrdup(NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname));
1259 else
1260 result = NULL;
1262 heap_endscan(scandesc);
1263 heap_close(rel, AccessShareLock);
1265 return result;
1270 * TABLESPACE resource manager's routines
1272 void
1273 tblspc_redo(XLogRecPtr lsn, XLogRecord *record)
1275 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1277 if (info == XLOG_TBLSPC_CREATE)
1279 xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) XLogRecGetData(record);
1280 char *location = xlrec->ts_path;
1281 char *linkloc;
1284 * Attempt to coerce target directory to safe permissions. If this
1285 * fails, it doesn't exist or has the wrong owner.
1287 if (chmod(location, 0700) != 0)
1288 ereport(ERROR,
1289 (errcode_for_file_access(),
1290 errmsg("could not set permissions on directory \"%s\": %m",
1291 location)));
1293 /* Create or re-create the PG_VERSION file in the target directory */
1294 set_short_version(location);
1296 /* Create the symlink if not already present */
1297 linkloc = (char *) palloc(10 + 10 + 1);
1298 sprintf(linkloc, "pg_tblspc/%u", xlrec->ts_id);
1300 if (symlink(location, linkloc) < 0)
1302 if (errno != EEXIST)
1303 ereport(ERROR,
1304 (errcode_for_file_access(),
1305 errmsg("could not create symbolic link \"%s\": %m",
1306 linkloc)));
1309 pfree(linkloc);
1311 else if (info == XLOG_TBLSPC_DROP)
1313 xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) XLogRecGetData(record);
1315 if (!remove_tablespace_directories(xlrec->ts_id, true))
1316 ereport(ERROR,
1317 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1318 errmsg("tablespace %u is not empty",
1319 xlrec->ts_id)));
1321 else
1322 elog(PANIC, "tblspc_redo: unknown op code %u", info);
1325 void
1326 tblspc_desc(StringInfo buf, uint8 xl_info, char *rec)
1328 uint8 info = xl_info & ~XLR_INFO_MASK;
1330 if (info == XLOG_TBLSPC_CREATE)
1332 xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
1334 appendStringInfo(buf, "create ts: %u \"%s\"",
1335 xlrec->ts_id, xlrec->ts_path);
1337 else if (info == XLOG_TBLSPC_DROP)
1339 xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
1341 appendStringInfo(buf, "drop ts: %u", xlrec->ts_id);
1343 else
1344 appendStringInfo(buf, "UNKNOWN");