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