~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/backend/commands/tablespace.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

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