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