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-2008, PostgreSQL Global Development Group
36 * Portions Copyright (c) 1994, Regents of the University of California
42 *-------------------------------------------------------------------------
48 #include <sys/types.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"
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.
99 TablespaceCreateDbspace(Oid spcNode
, Oid dbNode
, bool isRedo
)
105 * The global tablespace doesn't have per-database subdirectories, so
106 * nothing to do for it.
108 if (spcNode
== GLOBALTABLESPACE_OID
)
111 Assert(OidIsValid(spcNode
));
112 Assert(OidIsValid(dbNode
));
114 dir
= GetDatabasePath(dbNode
, spcNode
);
116 if (stat(dir
, &st
) < 0)
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
130 if (stat(dir
, &st
) == 0 && S_ISDIR(st
.st_mode
))
132 /* need not do anything */
137 if (mkdir(dir
, S_IRWXU
) < 0)
141 if (errno
!= ENOENT
|| !isRedo
)
143 (errcode_for_file_access(),
144 errmsg("could not create directory \"%s\": %m",
146 /* Try to make parent directory too */
147 parentdir
= pstrdup(dir
);
148 get_parent_directory(parentdir
);
149 if (mkdir(parentdir
, S_IRWXU
) < 0)
151 (errcode_for_file_access(),
152 errmsg("could not create directory \"%s\": %m",
155 if (mkdir(dir
, S_IRWXU
) < 0)
157 (errcode_for_file_access(),
158 errmsg("could not create directory \"%s\": %m",
163 LWLockRelease(TablespaceCreateLock
);
168 (errcode_for_file_access(),
169 errmsg("could not stat directory \"%s\": %m", dir
)));
175 if (!S_ISDIR(st
.st_mode
))
177 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
178 errmsg("\"%s\" exists but is not a directory",
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
193 CreateTableSpace(CreateTableSpaceStmt
*stmt
)
197 Datum values
[Natts_pg_tablespace
];
198 char nulls
[Natts_pg_tablespace
];
205 /* Must be super user */
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 */
215 ownerId
= get_roleid_checked(stmt
->owner
);
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
, '\''))
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
))
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))
246 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
247 errmsg("tablespace location \"%s\" is too long",
251 * Disallow creation of tablespaces named "pg_xxx"; we reserve this
252 * namespace for system purposes.
254 if (!allowSystemTableMods
&& IsReservedName(stmt
->tablespacename
))
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
266 if (OidIsValid(get_tablespace_oid(stmt
->tablespacename
)))
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)
306 (errcode_for_file_access(),
307 errmsg("could not set permissions on directory \"%s\": %m",
311 * Check the target directory is empty.
313 if (!directory_is_empty(location
))
315 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
316 errmsg("directory \"%s\" is not empty",
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)
336 (errcode_for_file_access(),
337 errmsg("could not create symbolic link \"%s\": %m",
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.
370 /* We keep the lock on pg_tablespace until commit */
371 heap_close(rel
, NoLock
);
372 #else /* !HAVE_SYMLINK */
374 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
375 errmsg("tablespaces are not supported on this platform")));
376 #endif /* HAVE_SYMLINK */
382 * Be careful to check that the tablespace is empty.
385 DropTableSpace(DropTableSpaceStmt
*stmt
)
388 char *tablespacename
= stmt
->tablespacename
;
389 HeapScanDesc scandesc
;
392 ScanKeyData entry
[1];
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
)
412 (errcode(ERRCODE_UNDEFINED_OBJECT
),
413 errmsg("tablespace \"%s\" does not exist",
419 (errmsg("tablespace \"%s\" does not exist, skipping",
421 /* XXX I assume I need one or both of these next two calls */
422 heap_endscan(scandesc
);
423 heap_close(rel
, NoLock
);
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
,
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
,
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 */
483 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
484 errmsg("tablespace \"%s\" is not empty",
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.
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 */
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
539 remove_tablespace_directories(Oid tablespaceoid
, bool redo
)
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
);
578 (errcode_for_file_access(),
579 errmsg("could not open directory \"%s\": %m",
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)
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
))
605 /* Do the real deed */
606 if (rmdir(subfile
) < 0)
608 (errcode_for_file_access(),
609 errmsg("could not remove directory \"%s\": %m",
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)
628 (errcode_for_file_access(),
629 errmsg("could not remove file \"%s\": %m",
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)
645 (errcode_for_file_access(),
646 errmsg("could not remove directory \"%s\": %m",
651 if (unlink(location
) < 0)
653 (errcode_for_file_access(),
654 errmsg("could not remove symbolic link \"%s\": %m",
664 * write out the PG_VERSION file in the specified directory
667 set_short_version(const char *path
)
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
] == '.')
688 else if (short_version
[end
] < '0' || short_version
[end
] > '9')
690 /* gone past digits and dots */
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
)
703 (errcode_for_file_access(),
704 errmsg("could not write to file \"%s\": %m",
706 fprintf(version_file
, "%s\n", short_version
);
707 if (FreeFile(version_file
))
709 (errcode_for_file_access(),
710 errmsg("could not write to file \"%s\": %m",
714 pfree(short_version
);
718 * Check if a directory is empty.
720 * This probably belongs somewhere else, but not sure where...
723 directory_is_empty(const char *path
)
728 dirdesc
= AllocateDir(path
);
730 while ((de
= ReadDir(dirdesc
, path
)) != NULL
)
732 if (strcmp(de
->d_name
, ".") == 0 ||
733 strcmp(de
->d_name
, "..") == 0)
744 * Rename a tablespace
747 RenameTableSpace(const char *oldname
, const char *newname
)
750 ScanKeyData entry
[1];
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
))
767 (errcode(ERRCODE_UNDEFINED_OBJECT
),
768 errmsg("tablespace \"%s\" does not exist",
771 newtuple
= heap_copytuple(tup
);
772 newform
= (Form_pg_tablespace
) GETSTRUCT(newtuple
);
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
))
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
))
796 (errcode(ERRCODE_DUPLICATE_OBJECT
),
797 errmsg("tablespace \"%s\" already exists",
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
815 AlterTableSpaceOwner(const char *name
, Oid newOwnerId
)
818 ScanKeyData entry
[1];
819 HeapScanDesc scandesc
;
820 Form_pg_tablespace spcForm
;
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
))
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
];
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
,
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
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
),
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
),
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 */
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",
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
)
957 /* The temp-table case is handled elsewhere */
960 PrepareTempTablespaces();
961 return GetNextTempTableSpace();
964 /* Fast path for default_tablespace == "" */
965 if (default_tablespace
== NULL
|| default_tablespace
[0] == '\0')
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
)
988 * Routines for handling the GUC variable 'temp_tablespaces'.
991 /* assign_hook: validate new temp_tablespaces, do extra actions as needed */
993 assign_temp_tablespaces(const char *newval
, bool doit
, GucSource source
)
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 */
1006 list_free(namelist
);
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.
1026 tblSpcs
= (Oid
*) MemoryContextAlloc(TopTransactionContext
,
1027 list_length(namelist
) * sizeof(Oid
));
1029 foreach(l
, namelist
)
1031 char *curname
= (char *) lfirst(l
);
1033 AclResult aclresult
;
1035 /* Allow an empty string (signifying database default) */
1036 if (curname
[0] == '\0')
1038 tblSpcs
[numSpcs
++] = InvalidOid
;
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
)
1052 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1053 errmsg("tablespace \"%s\" does not exist",
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
;
1068 /* Check permissions similarly */
1069 aclresult
= pg_tablespace_aclcheck(curoid
, GetUserId(),
1071 if (aclresult
!= ACLCHECK_OK
)
1073 if (source
>= PGC_S_INTERACTIVE
)
1074 aclcheck_error(aclresult
, ACL_KIND_TABLESPACE
, curname
);
1078 tblSpcs
[numSpcs
++] = curoid
;
1081 /* If actively "doing it", give the new list to fd.c */
1083 SetTempTablespaces(tblSpcs
, numSpcs
);
1089 list_free(namelist
);
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
1102 PrepareTempTablespaces(void)
1110 /* No work if already done in current transaction */
1111 if (TempTablespacesAreSet())
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())
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);
1133 list_free(namelist
);
1137 /* Store tablespace OIDs in an array in TopTransactionContext */
1138 tblSpcs
= (Oid
*) MemoryContextAlloc(TopTransactionContext
,
1139 list_length(namelist
) * sizeof(Oid
));
1141 foreach(l
, namelist
)
1143 char *curname
= (char *) lfirst(l
);
1145 AclResult aclresult
;
1147 /* Allow an empty string (signifying database default) */
1148 if (curname
[0] == '\0')
1150 tblSpcs
[numSpcs
++] = InvalidOid
;
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 */
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
;
1172 /* Check permissions similarly */
1173 aclresult
= pg_tablespace_aclcheck(curoid
, GetUserId(),
1175 if (aclresult
!= ACLCHECK_OK
)
1178 tblSpcs
[numSpcs
++] = curoid
;
1181 SetTempTablespaces(tblSpcs
, numSpcs
);
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
)
1198 HeapScanDesc scandesc
;
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
);
1220 result
= InvalidOid
;
1222 heap_endscan(scandesc
);
1223 heap_close(rel
, AccessShareLock
);
1229 * get_tablespace_name - given a tablespace OID, look up the name
1231 * Returns a palloc'd string, or NULL if no such tablespace.
1234 get_tablespace_name(Oid spc_oid
)
1238 HeapScanDesc scandesc
;
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
));
1262 heap_endscan(scandesc
);
1263 heap_close(rel
, AccessShareLock
);
1270 * TABLESPACE resource manager's routines
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
;
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)
1289 (errcode_for_file_access(),
1290 errmsg("could not set permissions on directory \"%s\": %m",
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
)
1304 (errcode_for_file_access(),
1305 errmsg("could not create symbolic link \"%s\": %m",
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))
1317 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
1318 errmsg("tablespace %u is not empty",
1322 elog(PANIC
, "tblspc_redo: unknown op code %u", info
);
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
);
1344 appendStringInfo(buf
, "UNKNOWN");