diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2004-11-05 19:17:13 +0000 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2004-11-05 19:17:13 +0000 |
| commit | 98e8b4805324d8ba0b196b8ffaafd5ddd3051ea1 (patch) | |
| tree | 61d027f5621f3ff37a675fb2e9982e0d28a81242 /src/backend/commands | |
| parent | 0ed3c7665e2fe46efd3eef936a1265be2ec6707f (diff) | |
| download | postgresql-98e8b4805324d8ba0b196b8ffaafd5ddd3051ea1.tar.gz | |
Create 'default_tablespace' GUC variable that supplies a TABLESPACE
clause implicitly whenever one is not given explicitly. Remove concept
of a schema having an associated tablespace, and simplify the rules for
selecting a default tablespace for a table or index. It's now just
(a) explicit TABLESPACE clause; (b) default_tablespace if that's not an
empty string; (c) database's default. This will allow pg_dump to use
SET commands instead of tablespace clauses to determine object locations
(but I didn't actually make it do so). All per recent discussions.
Diffstat (limited to 'src/backend/commands')
| -rw-r--r-- | src/backend/commands/indexcmds.c | 40 | ||||
| -rw-r--r-- | src/backend/commands/schemacmds.c | 33 | ||||
| -rw-r--r-- | src/backend/commands/tablecmds.c | 69 | ||||
| -rw-r--r-- | src/backend/commands/tablespace.c | 225 |
4 files changed, 189 insertions, 178 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index bdbf8708b1..b3f80470c0 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.126 2004/09/13 20:06:29 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.127 2004/11/05 19:15:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,6 +24,7 @@ #include "catalog/namespace.h" #include "catalog/pg_opclass.h" #include "catalog/pg_proc.h" +#include "catalog/pg_tablespace.h" #include "commands/dbcommands.h" #include "commands/defrem.h" #include "commands/tablecmds.h" @@ -66,7 +67,7 @@ static bool relationHasPrimaryKey(Relation rel); * that a nonconflicting default name should be picked. * 'accessMethodName': name of the AM to use. * 'tableSpaceName': name of the tablespace to create the index in. - * NULL specifies using the same tablespace as the parent relation. + * NULL specifies using the appropriate default. * 'attributeList': a list of IndexElem specifying columns and expressions * to index on. * 'predicate': the partial-index condition, or NULL if none. @@ -157,32 +158,45 @@ DefineIndex(RangeVar *heapRelation, get_namespace_name(namespaceId)); } - /* Determine tablespace to use */ + /* + * Select tablespace to use. If not specified, use default_tablespace + * (which may in turn default to database's default). + */ if (tableSpaceName) { - AclResult aclresult; - tablespaceId = get_tablespace_oid(tableSpaceName); if (!OidIsValid(tablespaceId)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", tableSpaceName))); - /* check permissions */ + } + else + { + tablespaceId = GetDefaultTablespace(); + /* note InvalidOid is OK in this case */ + } + + /* Check permissions except when using database's default */ + if (OidIsValid(tablespaceId)) + { + AclResult aclresult; + aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_TABLESPACE, - tableSpaceName); - } - else - { - /* Use the parent rel's tablespace */ - tablespaceId = get_rel_tablespace(relationId); - /* Note there is no additional permission check in this path */ + get_tablespace_name(tablespaceId)); } /* + * Force shared indexes into the pg_global tablespace. This is a bit of + * a hack but seems simpler than marking them in the BKI commands. + */ + if (rel->rd_rel->relisshared) + tablespaceId = GLOBALTABLESPACE_OID; + + /* * Select name for index if caller didn't specify */ if (indexRelationName == NULL) diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index b4e1cd7798..fc2410bacc 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.25 2004/09/02 00:22:16 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.26 2004/11/05 19:15:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,7 +23,6 @@ #include "catalog/pg_namespace.h" #include "commands/dbcommands.h" #include "commands/schemacmds.h" -#include "commands/tablespace.h" #include "miscadmin.h" #include "parser/analyze.h" #include "tcop/utility.h" @@ -42,7 +41,6 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) const char *schemaName = stmt->schemaname; const char *authId = stmt->authid; Oid namespaceId; - Oid tablespaceId; List *parsetree_list; ListCell *parsetree_item; const char *owner_name; @@ -102,35 +100,8 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) errmsg("unacceptable schema name \"%s\"", schemaName), errdetail("The prefix \"pg_\" is reserved for system schemas."))); - /* - * Select default tablespace for schema. If not given, use zero which - * implies the database's default tablespace. - */ - if (stmt->tablespacename) - { - AclResult aclresult; - - tablespaceId = get_tablespace_oid(stmt->tablespacename); - if (!OidIsValid(tablespaceId)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("tablespace \"%s\" does not exist", - stmt->tablespacename))); - /* check permissions */ - aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), - ACL_CREATE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_TABLESPACE, - stmt->tablespacename); - } - else - { - tablespaceId = InvalidOid; - /* note there is no permission check in this path */ - } - /* Create the schema's namespace */ - namespaceId = NamespaceCreate(schemaName, owner_userid, tablespaceId); + namespaceId = NamespaceCreate(schemaName, owner_userid); /* Advance cmd counter to make the namespace visible */ CommandCounterIncrement(); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 4593327d35..e4001f0102 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.138 2004/10/30 20:52:56 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.139 2004/11/05 19:15:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -168,7 +168,6 @@ static void StoreCatalogInheritance(Oid relationId, List *supers); static int findAttrByName(const char *attributeName, List *schema); static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass); static bool needs_toast_table(Relation rel); -static void check_tablespace_exists(Oid tablespaceId, Oid namespaceId); static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids); static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, @@ -313,34 +312,34 @@ DefineRelation(CreateStmt *stmt, char relkind) } /* - * Select tablespace to use. If not specified, use containing - * schema's default tablespace (which may in turn default to - * database's default). + * Select tablespace to use. If not specified, use default_tablespace + * (which may in turn default to database's default). */ if (stmt->tablespacename) { - AclResult aclresult; - tablespaceId = get_tablespace_oid(stmt->tablespacename); if (!OidIsValid(tablespaceId)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", stmt->tablespacename))); - /* check permissions */ + } + else + { + tablespaceId = GetDefaultTablespace(); + /* note InvalidOid is OK in this case */ + } + + /* Check permissions except when using database's default */ + if (OidIsValid(tablespaceId)) + { + AclResult aclresult; + aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_TABLESPACE, - stmt->tablespacename); - } - else - { - tablespaceId = get_namespace_tablespace(namespaceId); - /* note no permission check on tablespace in this case */ - /* check to see that schema's tablespace still exists */ - if (OidIsValid(tablespaceId)) - check_tablespace_exists(tablespaceId, namespaceId); + get_tablespace_name(tablespaceId)); } /* @@ -5890,42 +5889,6 @@ needs_toast_table(Relation rel) return (tuple_length > TOAST_TUPLE_THRESHOLD); } -/* - * Verify that a schema's tablespace still exists - * - * We need this because DROP TABLESPACE cannot check whether the target - * tablespace is the default tablespace for any schemas. (It could check - * in the current database, but that doesn't seem very helpful.) Subsequent - * attempts to create tables in that tablespace will fail. This code just - * exists to ensure that we give a helpful error message. - */ -static void -check_tablespace_exists(Oid tablespaceId, Oid namespaceId) -{ - Relation pg_tablespace; - ScanKeyData entry[1]; - HeapScanDesc scan; - HeapTuple tuple; - - /* There's no syscache for pg_tablespace, so must look the hard way */ - pg_tablespace = heap_openr(TableSpaceRelationName, AccessShareLock); - ScanKeyInit(&entry[0], - ObjectIdAttributeNumber, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(tablespaceId)); - scan = heap_beginscan(pg_tablespace, SnapshotNow, 1, entry); - tuple = heap_getnext(scan, ForwardScanDirection); - if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("tablespace with OID %u does not exist", - tablespaceId), - errdetail("The default tablespace for schema \"%s\" has been dropped.", - get_namespace_name(namespaceId)))); - heap_endscan(scan); - heap_close(pg_tablespace, AccessShareLock); -} - /* * This code supports diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 55f086d660..4dd1120c9d 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -3,7 +3,6 @@ * tablespace.c * Commands to manipulate table spaces * - * * Tablespaces in PostgreSQL are designed to allow users to determine * where the data file(s) for a given database object reside on the file * system. @@ -26,18 +25,11 @@ * $PGDATA/global/relfilenode * $PGDATA/base/dboid/relfilenode * - * The implementation is designed to be backwards compatible. For this reason - * (and also as a feature unto itself) when a user creates an object without - * specifying a tablespace, we look at the object's parent and place - * the object in the parent's tablespace. The hierarchy is as follows: - * database > schema > table > index - * * To allow CREATE DATABASE to give a new database a default tablespace * that's different from the template database's default, we make the * provision that a zero in pg_class.reltablespace means the database's * default tablespace. Without this, CREATE DATABASE would have to go in - * and munge the system catalogs of the new database. This special meaning - * of zero also applies in pg_namespace.nsptablespace. + * and munge the system catalogs of the new database. * * * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group @@ -45,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.13 2004/11/05 17:11:05 petere Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.14 2004/11/05 19:15:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -69,10 +61,15 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/syscache.h" +/* GUC variable */ +char *default_tablespace = NULL; + + static bool remove_tablespace_directories(Oid tablespaceoid, bool redo); static void set_short_version(const char *path); @@ -726,77 +723,6 @@ directory_is_empty(const char *path) } /* - * get_tablespace_oid - given a tablespace name, look up the OID - * - * Returns InvalidOid if tablespace name not found. - */ -Oid -get_tablespace_oid(const char *tablespacename) -{ - Oid result; - Relation rel; - HeapScanDesc scandesc; - HeapTuple tuple; - ScanKeyData entry[1]; - - /* Search pg_tablespace */ - rel = heap_openr(TableSpaceRelationName, 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); - - if (HeapTupleIsValid(tuple)) - result = HeapTupleGetOid(tuple); - else - result = InvalidOid; - - heap_endscan(scandesc); - heap_close(rel, AccessShareLock); - - return result; -} - -/* - * get_tablespace_name - given a tablespace OID, look up the name - * - * Returns a palloc'd string, or NULL if no such tablespace. - */ -char * -get_tablespace_name(Oid spc_oid) -{ - char *result; - Relation rel; - HeapScanDesc scandesc; - HeapTuple tuple; - ScanKeyData entry[1]; - - /* Search pg_tablespace */ - rel = heap_openr(TableSpaceRelationName, 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; -} - -/* * Rename a tablespace */ void @@ -946,6 +872,143 @@ AlterTableSpaceOwner(const char *name, AclId newOwnerSysId) heap_close(rel, NoLock); } + +/* + * Routines for handling the GUC variable 'default_tablespace'. + */ + +/* assign_hook: validate new default_tablespace, do extra actions as needed */ +const char * +assign_default_tablespace(const char *newval, bool doit, GucSource source) +{ + /* + * If we aren't inside a transaction, we cannot do database access so + * cannot verify the name. Must accept the value on faith. + */ + if (IsTransactionState()) + { + if (newval[0] != '\0' && + !OidIsValid(get_tablespace_oid(newval))) + { + if (source >= PGC_S_INTERACTIVE) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace \"%s\" does not exist", + newval))); + return NULL; + } + } + + return newval; +} + +/* + * GetDefaultTablespace -- get the OID of the current default tablespace + * + * May return InvalidOid to indicate "use the database's default tablespace" + * + * This exists to hide (and possibly optimize the use of) the + * default_tablespace GUC variable. + */ +Oid +GetDefaultTablespace(void) +{ + Oid result; + + /* 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); + /* + * Allow explicit specification of database's default tablespace in + * default_tablespace without triggering permissions checks. + */ + if (result == MyDatabaseTableSpace) + result = InvalidOid; + return result; +} + + +/* + * get_tablespace_oid - given a tablespace name, look up the OID + * + * Returns InvalidOid if tablespace name not found. + */ +Oid +get_tablespace_oid(const char *tablespacename) +{ + Oid result; + Relation rel; + HeapScanDesc scandesc; + HeapTuple tuple; + ScanKeyData entry[1]; + + /* Search pg_tablespace */ + rel = heap_openr(TableSpaceRelationName, 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); + + if (HeapTupleIsValid(tuple)) + result = HeapTupleGetOid(tuple); + else + result = InvalidOid; + + heap_endscan(scandesc); + heap_close(rel, AccessShareLock); + + return result; +} + +/* + * get_tablespace_name - given a tablespace OID, look up the name + * + * Returns a palloc'd string, or NULL if no such tablespace. + */ +char * +get_tablespace_name(Oid spc_oid) +{ + char *result; + Relation rel; + HeapScanDesc scandesc; + HeapTuple tuple; + ScanKeyData entry[1]; + + /* Search pg_tablespace */ + rel = heap_openr(TableSpaceRelationName, 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; +} + + /* * TABLESPACE resource manager's routines */ |
