Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Functions

tablespace.h File Reference

#include "access/xlog.h"
#include "nodes/parsenodes.h"
Include dependency graph for tablespace.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  xl_tblspc_create_rec
struct  xl_tblspc_drop_rec
struct  TableSpaceOpts

Defines

#define XLOG_TBLSPC_CREATE   0x00
#define XLOG_TBLSPC_DROP   0x10

Typedefs

typedef struct xl_tblspc_create_rec xl_tblspc_create_rec
typedef struct xl_tblspc_drop_rec xl_tblspc_drop_rec
typedef struct TableSpaceOpts TableSpaceOpts

Functions

Oid CreateTableSpace (CreateTableSpaceStmt *stmt)
void DropTableSpace (DropTableSpaceStmt *stmt)
Oid RenameTableSpace (const char *oldname, const char *newname)
Oid AlterTableSpaceOptions (AlterTableSpaceOptionsStmt *stmt)
void TablespaceCreateDbspace (Oid spcNode, Oid dbNode, bool isRedo)
Oid GetDefaultTablespace (char relpersistence)
void PrepareTempTablespaces (void)
Oid get_tablespace_oid (const char *tablespacename, bool missing_ok)
char * get_tablespace_name (Oid spc_oid)
bool directory_is_empty (const char *path)
void tblspc_redo (XLogRecPtr lsn, XLogRecord *rptr)
void tblspc_desc (StringInfo buf, uint8 xl_info, char *rec)

Define Documentation

#define XLOG_TBLSPC_CREATE   0x00

Definition at line 21 of file tablespace.h.

Referenced by CreateTableSpace(), tblspc_desc(), and tblspc_redo().

#define XLOG_TBLSPC_DROP   0x10

Definition at line 22 of file tablespace.h.

Referenced by DropTableSpace(), tblspc_desc(), and tblspc_redo().


Typedef Documentation


Function Documentation

Oid AlterTableSpaceOptions ( AlterTableSpaceOptionsStmt stmt  ) 

Definition at line 891 of file tablespace.c.

References ACL_KIND_TABLESPACE, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_tablespace_spcname, Anum_pg_tablespace_spcoptions, BTEqualStrategyNumber, CatalogUpdateIndexes(), CStringGetDatum, ereport, errcode(), errmsg(), ERROR, ForwardScanDirection, GetUserId(), heap_beginscan(), heap_close, heap_endscan(), heap_freetuple(), heap_getattr, heap_getnext(), heap_modify_tuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, AlterTableSpaceOptionsStmt::isReset, NoLock, NULL, AlterTableSpaceOptionsStmt::options, pg_tablespace_ownercheck(), RelationGetDescr, RowExclusiveLock, ScanKeyInit(), simple_heap_update(), SnapshotNow, HeapTupleData::t_self, tablespace_reloptions(), AlterTableSpaceOptionsStmt::tablespacename, TableSpaceRelationId, and transformRelOptions().

Referenced by standard_ProcessUtility().

{
    Relation    rel;
    ScanKeyData entry[1];
    HeapScanDesc scandesc;
    HeapTuple   tup;
    Oid         tablespaceoid;
    Datum       datum;
    Datum       newOptions;
    Datum       repl_val[Natts_pg_tablespace];
    bool        isnull;
    bool        repl_null[Natts_pg_tablespace];
    bool        repl_repl[Natts_pg_tablespace];
    HeapTuple   newtuple;

    /* Search pg_tablespace */
    rel = heap_open(TableSpaceRelationId, RowExclusiveLock);

    ScanKeyInit(&entry[0],
                Anum_pg_tablespace_spcname,
                BTEqualStrategyNumber, F_NAMEEQ,
                CStringGetDatum(stmt->tablespacename));
    scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
    tup = heap_getnext(scandesc, ForwardScanDirection);
    if (!HeapTupleIsValid(tup))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("tablespace \"%s\" does not exist",
                        stmt->tablespacename)));

    tablespaceoid = HeapTupleGetOid(tup);

    /* Must be owner of the existing object */
    if (!pg_tablespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
                       stmt->tablespacename);

    /* Generate new proposed spcoptions (text array) */
    datum = heap_getattr(tup, Anum_pg_tablespace_spcoptions,
                         RelationGetDescr(rel), &isnull);
    newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
                                     stmt->options, NULL, NULL, false,
                                     stmt->isReset);
    (void) tablespace_reloptions(newOptions, true);

    /* Build new tuple. */
    memset(repl_null, false, sizeof(repl_null));
    memset(repl_repl, false, sizeof(repl_repl));
    if (newOptions != (Datum) 0)
        repl_val[Anum_pg_tablespace_spcoptions - 1] = newOptions;
    else
        repl_null[Anum_pg_tablespace_spcoptions - 1] = true;
    repl_repl[Anum_pg_tablespace_spcoptions - 1] = true;
    newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val,
                                 repl_null, repl_repl);

    /* Update system catalog. */
    simple_heap_update(rel, &newtuple->t_self, newtuple);
    CatalogUpdateIndexes(rel, newtuple);

    InvokeObjectPostAlterHook(TableSpaceRelationId, HeapTupleGetOid(tup), 0);

    heap_freetuple(newtuple);

    /* Conclude heap scan. */
    heap_endscan(scandesc);
    heap_close(rel, NoLock);

    return tablespaceoid;
}

Oid CreateTableSpace ( CreateTableSpaceStmt stmt  ) 

Definition at line 227 of file tablespace.c.

References allowSystemTableMods, Anum_pg_tablespace_spcacl, Anum_pg_tablespace_spcname, Anum_pg_tablespace_spcoptions, Anum_pg_tablespace_spcowner, XLogRecData::buffer, canonicalize_path(), CatalogUpdateIndexes(), create_tablespace_directories(), CStringGetDatum, XLogRecData::data, DirectFunctionCall1, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, ForceSyncCommit(), get_role_oid(), get_tablespace_oid(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, is_absolute_path, IsReservedName(), XLogRecData::len, CreateTableSpaceStmt::location, MAXPGPATH, MemSet, namein(), XLogRecData::next, NoLock, ObjectIdGetDatum, offsetof, OIDCHARS, OidIsValid, CreateTableSpaceStmt::owner, pfree(), pstrdup(), RelationData::rd_att, recordDependencyOnOwner(), RowExclusiveLock, simple_heap_insert(), superuser(), TABLESPACE_VERSION_DIRECTORY, CreateTableSpaceStmt::tablespacename, TableSpaceRelationId, xl_tblspc_create_rec::ts_id, values, XLOG_TBLSPC_CREATE, and XLogInsert().

Referenced by standard_ProcessUtility().

{
#ifdef HAVE_SYMLINK
    Relation    rel;
    Datum       values[Natts_pg_tablespace];
    bool        nulls[Natts_pg_tablespace];
    HeapTuple   tuple;
    Oid         tablespaceoid;
    char       *location;
    Oid         ownerId;

    /* Must be super user */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("permission denied to create tablespace \"%s\"",
                        stmt->tablespacename),
                 errhint("Must be superuser to create a tablespace.")));

    /* However, the eventual owner of the tablespace need not be */
    if (stmt->owner)
        ownerId = get_role_oid(stmt->owner, false);
    else
        ownerId = GetUserId();

    /* Unix-ify the offered path, and strip any trailing slashes */
    location = pstrdup(stmt->location);
    canonicalize_path(location);

    /* disallow quotes, else CREATE DATABASE would be at risk */
    if (strchr(location, '\''))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_NAME),
                 errmsg("tablespace location cannot contain single quotes")));

    /*
     * Allowing relative paths seems risky
     *
     * this also helps us ensure that location is not empty or whitespace
     */
    if (!is_absolute_path(location))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("tablespace location must be an absolute path")));

    /*
     * Check that location isn't too long. Remember that we're going to append
     * 'PG_XXX/<dboid>/<relid>.<nnn>'.  FYI, we never actually reference the
     * whole path, but mkdir() uses the first two parts.
     */
    if (strlen(location) + 1 + strlen(TABLESPACE_VERSION_DIRECTORY) + 1 +
        OIDCHARS + 1 + OIDCHARS + 1 + OIDCHARS > MAXPGPATH)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("tablespace location \"%s\" is too long",
                        location)));

    /*
     * Disallow creation of tablespaces named "pg_xxx"; we reserve this
     * namespace for system purposes.
     */
    if (!allowSystemTableMods && IsReservedName(stmt->tablespacename))
        ereport(ERROR,
                (errcode(ERRCODE_RESERVED_NAME),
                 errmsg("unacceptable tablespace name \"%s\"",
                        stmt->tablespacename),
        errdetail("The prefix \"pg_\" is reserved for system tablespaces.")));

    /*
     * Check that there is no other tablespace by this name.  (The unique
     * index would catch this anyway, but might as well give a friendlier
     * message.)
     */
    if (OidIsValid(get_tablespace_oid(stmt->tablespacename, true)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("tablespace \"%s\" already exists",
                        stmt->tablespacename)));

    /*
     * Insert tuple into pg_tablespace.  The purpose of doing this first is to
     * lock the proposed tablename against other would-be creators. The
     * insertion will roll back if we find problems below.
     */
    rel = heap_open(TableSpaceRelationId, RowExclusiveLock);

    MemSet(nulls, false, sizeof(nulls));

    values[Anum_pg_tablespace_spcname - 1] =
        DirectFunctionCall1(namein, CStringGetDatum(stmt->tablespacename));
    values[Anum_pg_tablespace_spcowner - 1] =
        ObjectIdGetDatum(ownerId);
    nulls[Anum_pg_tablespace_spcacl - 1] = true;
    nulls[Anum_pg_tablespace_spcoptions - 1] = true;

    tuple = heap_form_tuple(rel->rd_att, values, nulls);

    tablespaceoid = simple_heap_insert(rel, tuple);

    CatalogUpdateIndexes(rel, tuple);

    heap_freetuple(tuple);

    /* Record dependency on owner */
    recordDependencyOnOwner(TableSpaceRelationId, tablespaceoid, ownerId);

    /* Post creation hook for new tablespace */
    InvokeObjectPostCreateHook(TableSpaceRelationId, tablespaceoid, 0);

    create_tablespace_directories(location, tablespaceoid);

    /* Record the filesystem change in XLOG */
    {
        xl_tblspc_create_rec xlrec;
        XLogRecData rdata[2];

        xlrec.ts_id = tablespaceoid;
        rdata[0].data = (char *) &xlrec;
        rdata[0].len = offsetof(xl_tblspc_create_rec, ts_path);
        rdata[0].buffer = InvalidBuffer;
        rdata[0].next = &(rdata[1]);

        rdata[1].data = (char *) location;
        rdata[1].len = strlen(location) + 1;
        rdata[1].buffer = InvalidBuffer;
        rdata[1].next = NULL;

        (void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_CREATE, rdata);
    }

    /*
     * Force synchronous commit, to minimize the window between creating the
     * symlink on-disk and marking the transaction committed.  It's not great
     * that there is any window at all, but definitely we don't want to make
     * it larger than necessary.
     */
    ForceSyncCommit();

    pfree(location);

    /* We keep the lock on pg_tablespace until commit */
    heap_close(rel, NoLock);
#else                           /* !HAVE_SYMLINK */
    ereport(ERROR,
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
             errmsg("tablespaces are not supported on this platform")));
#endif   /* HAVE_SYMLINK */

    return tablespaceoid;
}

bool directory_is_empty ( const char *  path  ) 

Definition at line 792 of file tablespace.c.

References AllocateDir(), dirent::d_name, FreeDir(), NULL, and ReadDir().

Referenced by createdb(), and destroy_tablespace_directories().

{
    DIR        *dirdesc;
    struct dirent *de;

    dirdesc = AllocateDir(path);

    while ((de = ReadDir(dirdesc, path)) != NULL)
    {
        if (strcmp(de->d_name, ".") == 0 ||
            strcmp(de->d_name, "..") == 0)
            continue;
        FreeDir(dirdesc);
        return false;
    }

    FreeDir(dirdesc);
    return true;
}

void DropTableSpace ( DropTableSpaceStmt stmt  ) 

Definition at line 384 of file tablespace.c.

References ACL_KIND_TABLESPACE, aclcheck_error(), ACLCHECK_NO_PRIV, ACLCHECK_NOT_OWNER, Anum_pg_tablespace_spcname, BTEqualStrategyNumber, XLogRecData::buffer, CHECKPOINT_FORCE, CHECKPOINT_IMMEDIATE, CHECKPOINT_WAIT, CStringGetDatum, XLogRecData::data, DEFAULTTABLESPACE_OID, DeleteSharedComments(), deleteSharedDependencyRecordsFor(), DeleteSharedSecurityLabel(), destroy_tablespace_directories(), ereport, errcode(), errmsg(), ERROR, ForceSyncCommit(), ForwardScanDirection, GetUserId(), GLOBALTABLESPACE_OID, heap_beginscan(), heap_close, heap_endscan(), heap_getnext(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectDropHook, XLogRecData::len, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), DropTableSpaceStmt::missing_ok, XLogRecData::next, NoLock, NOTICE, pg_tablespace_ownercheck(), RequestCheckpoint(), RowExclusiveLock, ScanKeyInit(), simple_heap_delete(), SnapshotNow, HeapTupleData::t_self, TablespaceCreateLock, DropTableSpaceStmt::tablespacename, TableSpaceRelationId, xl_tblspc_drop_rec::ts_id, XLOG_TBLSPC_DROP, and XLogInsert().

Referenced by standard_ProcessUtility().

{
#ifdef HAVE_SYMLINK
    char       *tablespacename = stmt->tablespacename;
    HeapScanDesc scandesc;
    Relation    rel;
    HeapTuple   tuple;
    ScanKeyData entry[1];
    Oid         tablespaceoid;

    /*
     * Find the target tuple
     */
    rel = heap_open(TableSpaceRelationId, RowExclusiveLock);

    ScanKeyInit(&entry[0],
                Anum_pg_tablespace_spcname,
                BTEqualStrategyNumber, F_NAMEEQ,
                CStringGetDatum(tablespacename));
    scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
    tuple = heap_getnext(scandesc, ForwardScanDirection);

    if (!HeapTupleIsValid(tuple))
    {
        if (!stmt->missing_ok)
        {
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                     errmsg("tablespace \"%s\" does not exist",
                            tablespacename)));
        }
        else
        {
            ereport(NOTICE,
                    (errmsg("tablespace \"%s\" does not exist, skipping",
                            tablespacename)));
            /* XXX I assume I need one or both of these next two calls */
            heap_endscan(scandesc);
            heap_close(rel, NoLock);
        }
        return;
    }

    tablespaceoid = HeapTupleGetOid(tuple);

    /* Must be tablespace owner */
    if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
                       tablespacename);

    /* Disallow drop of the standard tablespaces, even by superuser */
    if (tablespaceoid == GLOBALTABLESPACE_OID ||
        tablespaceoid == DEFAULTTABLESPACE_OID)
        aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE,
                       tablespacename);

    /* DROP hook for the tablespace being removed */
    InvokeObjectDropHook(TableSpaceRelationId, tablespaceoid, 0);

    /*
     * Remove the pg_tablespace tuple (this will roll back if we fail below)
     */
    simple_heap_delete(rel, &tuple->t_self);

    heap_endscan(scandesc);

    /*
     * Remove any comments or security labels on this tablespace.
     */
    DeleteSharedComments(tablespaceoid, TableSpaceRelationId);
    DeleteSharedSecurityLabel(tablespaceoid, TableSpaceRelationId);

    /*
     * Remove dependency on owner.
     */
    deleteSharedDependencyRecordsFor(TableSpaceRelationId, tablespaceoid, 0);

    /*
     * Acquire TablespaceCreateLock to ensure that no TablespaceCreateDbspace
     * is running concurrently.
     */
    LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE);

    /*
     * Try to remove the physical infrastructure.
     */
    if (!destroy_tablespace_directories(tablespaceoid, false))
    {
        /*
         * Not all files deleted?  However, there can be lingering empty files
         * in the directories, left behind by for example DROP TABLE, that
         * have been scheduled for deletion at next checkpoint (see comments
         * in mdunlink() for details).  We could just delete them immediately,
         * but we can't tell them apart from important data files that we
         * mustn't delete.  So instead, we force a checkpoint which will clean
         * out any lingering files, and try again.
         */
        RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
        if (!destroy_tablespace_directories(tablespaceoid, false))
        {
            /* Still not empty, the files must be important then */
            ereport(ERROR,
                    (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                     errmsg("tablespace \"%s\" is not empty",
                            tablespacename)));
        }
    }

    /* Record the filesystem change in XLOG */
    {
        xl_tblspc_drop_rec xlrec;
        XLogRecData rdata[1];

        xlrec.ts_id = tablespaceoid;
        rdata[0].data = (char *) &xlrec;
        rdata[0].len = sizeof(xl_tblspc_drop_rec);
        rdata[0].buffer = InvalidBuffer;
        rdata[0].next = NULL;

        (void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_DROP, rdata);
    }

    /*
     * Note: because we checked that the tablespace was empty, there should be
     * no need to worry about flushing shared buffers or free space map
     * entries for relations in the tablespace.
     */

    /*
     * Force synchronous commit, to minimize the window between removing the
     * files on-disk and marking the transaction committed.  It's not great
     * that there is any window at all, but definitely we don't want to make
     * it larger than necessary.
     */
    ForceSyncCommit();

    /*
     * Allow TablespaceCreateDbspace again.
     */
    LWLockRelease(TablespaceCreateLock);

    /* We keep the lock on pg_tablespace until commit */
    heap_close(rel, NoLock);
#else                           /* !HAVE_SYMLINK */
    ereport(ERROR,
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
             errmsg("tablespaces are not supported on this platform")));
#endif   /* HAVE_SYMLINK */
}

char* get_tablespace_name ( Oid  spc_oid  ) 

Definition at line 1341 of file tablespace.c.

References AccessShareLock, BTEqualStrategyNumber, ForwardScanDirection, GETSTRUCT, heap_beginscan(), heap_close, heap_endscan(), heap_getnext(), heap_open(), HeapTupleIsValid, NameStr, ObjectIdAttributeNumber, ObjectIdGetDatum, pstrdup(), ScanKeyInit(), SnapshotNow, and TableSpaceRelationId.

Referenced by calculate_tablespace_size(), DefineIndex(), DefineRelation(), generateClonedIndexStmt(), getObjectDescription(), getObjectIdentity(), pg_get_constraintdef_worker(), pg_get_indexdef_worker(), and shdepLockAndCheckObject().

{
    char       *result;
    Relation    rel;
    HeapScanDesc scandesc;
    HeapTuple   tuple;
    ScanKeyData entry[1];

    /*
     * Search pg_tablespace.  We use a heapscan here even though there is an
     * index on oid, on the theory that pg_tablespace will usually have just a
     * few entries and so an indexed lookup is a waste of effort.
     */
    rel = heap_open(TableSpaceRelationId, AccessShareLock);

    ScanKeyInit(&entry[0],
                ObjectIdAttributeNumber,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(spc_oid));
    scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
    tuple = heap_getnext(scandesc, ForwardScanDirection);

    /* We assume that there can be at most one matching tuple */
    if (HeapTupleIsValid(tuple))
        result = pstrdup(NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname));
    else
        result = NULL;

    heap_endscan(scandesc);
    heap_close(rel, AccessShareLock);

    return result;
}

Oid get_tablespace_oid ( const char *  tablespacename,
bool  missing_ok 
)

Definition at line 1295 of file tablespace.c.

References AccessShareLock, Anum_pg_tablespace_spcname, BTEqualStrategyNumber, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, ForwardScanDirection, heap_beginscan(), heap_close, heap_endscan(), heap_getnext(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, OidIsValid, ScanKeyInit(), SnapshotNow, and TableSpaceRelationId.

Referenced by ATPrepSetTableSpace(), check_default_tablespace(), check_temp_tablespaces(), convert_tablespace_name(), createdb(), CreateTableSpace(), DefineIndex(), DefineRelation(), get_object_address_unqualified(), GetDefaultTablespace(), movedb(), objectNamesToOids(), pg_tablespace_size_name(), and PrepareTempTablespaces().

{
    Oid         result;
    Relation    rel;
    HeapScanDesc scandesc;
    HeapTuple   tuple;
    ScanKeyData entry[1];

    /*
     * Search pg_tablespace.  We use a heapscan here even though there is an
     * index on name, on the theory that pg_tablespace will usually have just
     * a few entries and so an indexed lookup is a waste of effort.
     */
    rel = heap_open(TableSpaceRelationId, AccessShareLock);

    ScanKeyInit(&entry[0],
                Anum_pg_tablespace_spcname,
                BTEqualStrategyNumber, F_NAMEEQ,
                CStringGetDatum(tablespacename));
    scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
    tuple = heap_getnext(scandesc, ForwardScanDirection);

    /* We assume that there can be at most one matching tuple */
    if (HeapTupleIsValid(tuple))
        result = HeapTupleGetOid(tuple);
    else
        result = InvalidOid;

    heap_endscan(scandesc);
    heap_close(rel, AccessShareLock);

    if (!OidIsValid(result) && !missing_ok)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("tablespace \"%s\" does not exist",
                        tablespacename)));

    return result;
}

Oid GetDefaultTablespace ( char  relpersistence  ) 

Definition at line 1021 of file tablespace.c.

References default_tablespace, get_tablespace_oid(), GetNextTempTableSpace(), MyDatabaseTableSpace, NULL, PrepareTempTablespaces(), and RELPERSISTENCE_TEMP.

Referenced by DefineIndex(), and DefineRelation().

{
    Oid         result;

    /* The temp-table case is handled elsewhere */
    if (relpersistence == RELPERSISTENCE_TEMP)
    {
        PrepareTempTablespaces();
        return GetNextTempTableSpace();
    }

    /* Fast path for default_tablespace == "" */
    if (default_tablespace == NULL || default_tablespace[0] == '\0')
        return InvalidOid;

    /*
     * It is tempting to cache this lookup for more speed, but then we would
     * fail to detect the case where the tablespace was dropped since the GUC
     * variable was set.  Note also that we don't complain if the value fails
     * to refer to an existing tablespace; we just silently return InvalidOid,
     * causing the new object to be created in the database's tablespace.
     */
    result = get_tablespace_oid(default_tablespace, true);

    /*
     * Allow explicit specification of database's default tablespace in
     * default_tablespace without triggering permissions checks.
     */
    if (result == MyDatabaseTableSpace)
        result = InvalidOid;
    return result;
}

void PrepareTempTablespaces ( void   ) 

Definition at line 1202 of file tablespace.c.

References ACL_CREATE, ACLCHECK_OK, get_tablespace_oid(), GetUserId(), InvalidOid, IsTransactionState(), lfirst, list_free(), list_length(), MemoryContextAlloc(), MyDatabaseTableSpace, NULL, pfree(), pg_tablespace_aclcheck(), pstrdup(), SetTempTablespaces(), SplitIdentifierString(), temp_tablespaces, TempTablespacesAreSet(), and TopTransactionContext.

Referenced by ExecHashIncreaseNumBatches(), ExecHashTableCreate(), GetDefaultTablespace(), inittapes(), and tuplestore_puttuple_common().

{
    char       *rawname;
    List       *namelist;
    Oid        *tblSpcs;
    int         numSpcs;
    ListCell   *l;

    /* No work if already done in current transaction */
    if (TempTablespacesAreSet())
        return;

    /*
     * Can't do catalog access unless within a transaction.  This is just a
     * safety check in case this function is called by low-level code that
     * could conceivably execute outside a transaction.  Note that in such a
     * scenario, fd.c will fall back to using the current database's default
     * tablespace, which should always be OK.
     */
    if (!IsTransactionState())
        return;

    /* Need a modifiable copy of string */
    rawname = pstrdup(temp_tablespaces);

    /* Parse string into list of identifiers */
    if (!SplitIdentifierString(rawname, ',', &namelist))
    {
        /* syntax error in name list */
        SetTempTablespaces(NULL, 0);
        pfree(rawname);
        list_free(namelist);
        return;
    }

    /* Store tablespace OIDs in an array in TopTransactionContext */
    tblSpcs = (Oid *) MemoryContextAlloc(TopTransactionContext,
                                         list_length(namelist) * sizeof(Oid));
    numSpcs = 0;
    foreach(l, namelist)
    {
        char       *curname = (char *) lfirst(l);
        Oid         curoid;
        AclResult   aclresult;

        /* Allow an empty string (signifying database default) */
        if (curname[0] == '\0')
        {
            tblSpcs[numSpcs++] = InvalidOid;
            continue;
        }

        /* Else verify that name is a valid tablespace name */
        curoid = get_tablespace_oid(curname, true);
        if (curoid == InvalidOid)
        {
            /* Skip any bad list elements */
            continue;
        }

        /*
         * Allow explicit specification of database's default tablespace in
         * temp_tablespaces without triggering permissions checks.
         */
        if (curoid == MyDatabaseTableSpace)
        {
            tblSpcs[numSpcs++] = InvalidOid;
            continue;
        }

        /* Check permissions similarly */
        aclresult = pg_tablespace_aclcheck(curoid, GetUserId(),
                                           ACL_CREATE);
        if (aclresult != ACLCHECK_OK)
            continue;

        tblSpcs[numSpcs++] = curoid;
    }

    SetTempTablespaces(tblSpcs, numSpcs);

    pfree(rawname);
    list_free(namelist);
}

Oid RenameTableSpace ( const char *  oldname,
const char *  newname 
)

Definition at line 817 of file tablespace.c.

References ACL_KIND_TABLESPACE, aclcheck_error(), ACLCHECK_NO_PRIV, allowSystemTableMods, Anum_pg_tablespace_spcname, BTEqualStrategyNumber, CatalogUpdateIndexes(), CStringGetDatum, ereport, errcode(), errdetail(), errmsg(), ERROR, ForwardScanDirection, GETSTRUCT, GetUserId(), heap_beginscan(), heap_close, heap_copytuple(), heap_endscan(), heap_getnext(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, IsReservedName(), namestrcpy(), NoLock, pg_tablespace_ownercheck(), RowExclusiveLock, ScanKeyInit(), simple_heap_update(), SnapshotNow, HeapTupleData::t_self, and TableSpaceRelationId.

Referenced by ExecRenameStmt().

{
    Oid         tspId;
    Relation    rel;
    ScanKeyData entry[1];
    HeapScanDesc scan;
    HeapTuple   tup;
    HeapTuple   newtuple;
    Form_pg_tablespace newform;

    /* Search pg_tablespace */
    rel = heap_open(TableSpaceRelationId, RowExclusiveLock);

    ScanKeyInit(&entry[0],
                Anum_pg_tablespace_spcname,
                BTEqualStrategyNumber, F_NAMEEQ,
                CStringGetDatum(oldname));
    scan = heap_beginscan(rel, SnapshotNow, 1, entry);
    tup = heap_getnext(scan, ForwardScanDirection);
    if (!HeapTupleIsValid(tup))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("tablespace \"%s\" does not exist",
                        oldname)));

    tspId = HeapTupleGetOid(tup);
    newtuple = heap_copytuple(tup);
    newform = (Form_pg_tablespace) GETSTRUCT(newtuple);

    heap_endscan(scan);

    /* Must be owner */
    if (!pg_tablespace_ownercheck(HeapTupleGetOid(newtuple), GetUserId()))
        aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, oldname);

    /* Validate new name */
    if (!allowSystemTableMods && IsReservedName(newname))
        ereport(ERROR,
                (errcode(ERRCODE_RESERVED_NAME),
                 errmsg("unacceptable tablespace name \"%s\"", newname),
        errdetail("The prefix \"pg_\" is reserved for system tablespaces.")));

    /* Make sure the new name doesn't exist */
    ScanKeyInit(&entry[0],
                Anum_pg_tablespace_spcname,
                BTEqualStrategyNumber, F_NAMEEQ,
                CStringGetDatum(newname));
    scan = heap_beginscan(rel, SnapshotNow, 1, entry);
    tup = heap_getnext(scan, ForwardScanDirection);
    if (HeapTupleIsValid(tup))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("tablespace \"%s\" already exists",
                        newname)));

    heap_endscan(scan);

    /* OK, update the entry */
    namestrcpy(&(newform->spcname), newname);

    simple_heap_update(rel, &newtuple->t_self, newtuple);
    CatalogUpdateIndexes(rel, newtuple);

    InvokeObjectPostAlterHook(TableSpaceRelationId, tspId, 0);

    heap_close(rel, NoLock);

    return tspId;
}

void TablespaceCreateDbspace ( Oid  spcNode,
Oid  dbNode,
bool  isRedo 
)

Definition at line 109 of file tablespace.c.

References Assert, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, get_parent_directory(), GetDatabasePath(), GLOBALTABLESPACE_OID, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), mkdir, OidIsValid, pfree(), pstrdup(), and TablespaceCreateLock.

Referenced by smgrcreate().

{
    struct stat st;
    char       *dir;

    /*
     * The global tablespace doesn't have per-database subdirectories, so
     * nothing to do for it.
     */
    if (spcNode == GLOBALTABLESPACE_OID)
        return;

    Assert(OidIsValid(spcNode));
    Assert(OidIsValid(dbNode));

    dir = GetDatabasePath(dbNode, spcNode);

    if (stat(dir, &st) < 0)
    {
        /* Directory does not exist? */
        if (errno == ENOENT)
        {
            /*
             * Acquire TablespaceCreateLock to ensure that no DROP TABLESPACE
             * or TablespaceCreateDbspace is running concurrently.
             */
            LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE);

            /*
             * Recheck to see if someone created the directory while we were
             * waiting for lock.
             */
            if (stat(dir, &st) == 0 && S_ISDIR(st.st_mode))
            {
                /* Directory was created */
            }
            else
            {
                /* Directory creation failed? */
                if (mkdir(dir, S_IRWXU) < 0)
                {
                    char       *parentdir;

                    /* Failure other than not exists or not in WAL replay? */
                    if (errno != ENOENT || !isRedo)
                        ereport(ERROR,
                                (errcode_for_file_access(),
                              errmsg("could not create directory \"%s\": %m",
                                     dir)));

                    /*
                     * Parent directories are missing during WAL replay, so
                     * continue by creating simple parent directories rather
                     * than a symlink.
                     */

                    /* create two parents up if not exist */
                    parentdir = pstrdup(dir);
                    get_parent_directory(parentdir);
                    get_parent_directory(parentdir);
                    /* Can't create parent and it doesn't already exist? */
                    if (mkdir(parentdir, S_IRWXU) < 0 && errno != EEXIST)
                        ereport(ERROR,
                                (errcode_for_file_access(),
                              errmsg("could not create directory \"%s\": %m",
                                     parentdir)));
                    pfree(parentdir);

                    /* create one parent up if not exist */
                    parentdir = pstrdup(dir);
                    get_parent_directory(parentdir);
                    /* Can't create parent and it doesn't already exist? */
                    if (mkdir(parentdir, S_IRWXU) < 0 && errno != EEXIST)
                        ereport(ERROR,
                                (errcode_for_file_access(),
                              errmsg("could not create directory \"%s\": %m",
                                     parentdir)));
                    pfree(parentdir);

                    /* Create database directory */
                    if (mkdir(dir, S_IRWXU) < 0)
                        ereport(ERROR,
                                (errcode_for_file_access(),
                              errmsg("could not create directory \"%s\": %m",
                                     dir)));
                }
            }

            LWLockRelease(TablespaceCreateLock);
        }
        else
        {
            ereport(ERROR,
                    (errcode_for_file_access(),
                     errmsg("could not stat directory \"%s\": %m", dir)));
        }
    }
    else
    {
        /* Is it not a directory? */
        if (!S_ISDIR(st.st_mode))
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("\"%s\" exists but is not a directory",
                            dir)));
    }

    pfree(dir);
}

void tblspc_desc ( StringInfo  buf,
uint8  xl_info,
char *  rec 
)

Definition at line 21 of file tblspcdesc.c.

References appendStringInfo(), xl_tblspc_drop_rec::ts_id, xl_tblspc_create_rec::ts_id, xl_tblspc_create_rec::ts_path, XLOG_TBLSPC_CREATE, and XLOG_TBLSPC_DROP.

{
    uint8       info = xl_info & ~XLR_INFO_MASK;

    if (info == XLOG_TBLSPC_CREATE)
    {
        xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;

        appendStringInfo(buf, "create tablespace: %u \"%s\"",
                         xlrec->ts_id, xlrec->ts_path);
    }
    else if (info == XLOG_TBLSPC_DROP)
    {
        xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;

        appendStringInfo(buf, "drop tablespace: %u", xlrec->ts_id);
    }
    else
        appendStringInfo(buf, "UNKNOWN");
}

void tblspc_redo ( XLogRecPtr  lsn,
XLogRecord rptr 
)

Definition at line 1380 of file tablespace.c.

References Assert, create_tablespace_directories(), destroy_tablespace_directories(), elog, ereport, errcode(), errhint(), errmsg(), LOG, PANIC, ResolveRecoveryConflictWithTablespace(), xl_tblspc_drop_rec::ts_id, xl_tblspc_create_rec::ts_id, xl_tblspc_create_rec::ts_path, XLogRecord::xl_info, XLOG_TBLSPC_CREATE, XLOG_TBLSPC_DROP, XLogRecGetData, and XLR_BKP_BLOCK_MASK.

{
    uint8       info = record->xl_info & ~XLR_INFO_MASK;

    /* Backup blocks are not used in tblspc records */
    Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));

    if (info == XLOG_TBLSPC_CREATE)
    {
        xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) XLogRecGetData(record);
        char       *location = xlrec->ts_path;

        create_tablespace_directories(location, xlrec->ts_id);
    }
    else if (info == XLOG_TBLSPC_DROP)
    {
        xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) XLogRecGetData(record);

        /*
         * If we issued a WAL record for a drop tablespace it implies that
         * there were no files in it at all when the DROP was done. That means
         * that no permanent objects can exist in it at this point.
         *
         * It is possible for standby users to be using this tablespace as a
         * location for their temporary files, so if we fail to remove all
         * files then do conflict processing and try again, if currently
         * enabled.
         *
         * Other possible reasons for failure include bollixed file
         * permissions on a standby server when they were okay on the primary,
         * etc etc. There's not much we can do about that, so just remove what
         * we can and press on.
         */
        if (!destroy_tablespace_directories(xlrec->ts_id, true))
        {
            ResolveRecoveryConflictWithTablespace(xlrec->ts_id);

            /*
             * If we did recovery processing then hopefully the backends who
             * wrote temp files should have cleaned up and exited by now.  So
             * retry before complaining.  If we fail again, this is just a LOG
             * condition, because it's not worth throwing an ERROR for (as
             * that would crash the database and require manual intervention
             * before we could get past this WAL record on restart).
             */
            if (!destroy_tablespace_directories(xlrec->ts_id, true))
                ereport(LOG,
                        (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("directories for tablespace %u could not be removed",
                        xlrec->ts_id),
                         errhint("You can remove the directories manually if necessary.")));
        }
    }
    else
        elog(PANIC, "tblspc_redo: unknown op code %u", info);
}