aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2010-01-05 21:54:00 +0000
committerRobert Haas <rhaas@postgresql.org>2010-01-05 21:54:00 +0000
commitd86d51a95810caebcea587498068ff32fe28293e (patch)
tree031fb02a2ef325762250b163acd215cd7c31c2bb /src
parent72559b49c051ff7dc860068c96324ddf07d7955d (diff)
downloadpostgresql-d86d51a95810caebcea587498068ff32fe28293e.tar.gz
postgresql-d86d51a95810caebcea587498068ff32fe28293e.zip
Support ALTER TABLESPACE name SET/RESET ( tablespace_options ).
This patch only supports seq_page_cost and random_page_cost as parameters, but it provides the infrastructure to scalably support many more. In particular, we may want to add support for effective_io_concurrency, but I'm leaving that as future work for now. Thanks to Tom Lane for design help and Alvaro Herrera for the review.
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/common/reloptions.c50
-rw-r--r--src/backend/catalog/aclchk.c61
-rw-r--r--src/backend/commands/tablespace.c73
-rw-r--r--src/backend/nodes/copyfuncs.c17
-rw-r--r--src/backend/nodes/equalfuncs.c16
-rw-r--r--src/backend/nodes/outfuncs.c3
-rw-r--r--src/backend/optimizer/path/costsize.c63
-rw-r--r--src/backend/optimizer/util/plancat.c5
-rw-r--r--src/backend/parser/gram.y20
-rw-r--r--src/backend/tcop/utility.c15
-rw-r--r--src/backend/utils/adt/selfuncs.c26
-rw-r--r--src/backend/utils/cache/Makefile4
-rw-r--r--src/backend/utils/cache/spccache.c183
-rw-r--r--src/backend/utils/cache/syscache.c15
-rw-r--r--src/bin/pg_dump/pg_dumpall.c22
-rw-r--r--src/include/access/reloptions.h9
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/catalog/pg_tablespace.h10
-rw-r--r--src/include/commands/tablespace.h8
-rw-r--r--src/include/nodes/nodes.h3
-rw-r--r--src/include/nodes/parsenodes.h10
-rw-r--r--src/include/nodes/relation.h4
-rw-r--r--src/include/utils/spccache.h19
-rw-r--r--src/include/utils/syscache.h3
-rw-r--r--src/test/regress/input/tablespace.source6
-rw-r--r--src/test/regress/output/tablespace.source7
26 files changed, 557 insertions, 99 deletions
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 2e3fa5bcae5..28eacb4e478 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.30 2010/01/02 16:57:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.31 2010/01/05 21:53:58 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,6 +21,7 @@
#include "access/reloptions.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
+#include "commands/tablespace.h"
#include "nodes/makefuncs.h"
#include "utils/array.h"
#include "utils/builtins.h"
@@ -179,6 +180,22 @@ static relopt_real realRelOpts[] =
},
-1, 0.0, 100.0
},
+ {
+ {
+ "seq_page_cost",
+ "Sets the planner's estimate of the cost of a sequentially fetched disk page.",
+ RELOPT_KIND_TABLESPACE
+ },
+ -1, 0.0, DBL_MAX
+ },
+ {
+ {
+ "random_page_cost",
+ "Sets the planner's estimate of the cost of a nonsequentially fetched disk page.",
+ RELOPT_KIND_TABLESPACE
+ },
+ -1, 0.0, DBL_MAX
+ },
/* list terminator */
{{NULL}}
};
@@ -1168,3 +1185,34 @@ index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
return DatumGetByteaP(result);
}
+
+/*
+ * Option parser for tablespace reloptions
+ */
+bytea *
+tablespace_reloptions(Datum reloptions, bool validate)
+{
+ relopt_value *options;
+ TableSpaceOpts *tsopts;
+ int numoptions;
+ static const relopt_parse_elt tab[] = {
+ {"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)},
+ {"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)}
+ };
+
+ options = parseRelOptions(reloptions, validate, RELOPT_KIND_TABLESPACE,
+ &numoptions);
+
+ /* if none set, we're done */
+ if (numoptions == 0)
+ return NULL;
+
+ tsopts = allocateReloptStruct(sizeof(TableSpaceOpts), options, numoptions);
+
+ fillRelOptions((void *) tsopts, sizeof(TableSpaceOpts), options, numoptions,
+ validate, tab, lengthof(tab));
+
+ pfree(options);
+
+ return (bytea *) tsopts;
+}
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index d98ebdda4f8..6c16fd6a6e2 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.159 2010/01/02 16:57:36 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.160 2010/01/05 21:53:58 rhaas Exp $
*
* NOTES
* See acl.h.
@@ -2783,18 +2783,11 @@ ExecGrant_Tablespace(InternalGrant *istmt)
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
- ScanKeyData entry[1];
- SysScanDesc scan;
HeapTuple tuple;
- /* There's no syscache for pg_tablespace, so must look the hard way */
- ScanKeyInit(&entry[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(tblId));
- scan = systable_beginscan(relation, TablespaceOidIndexId, true,
- SnapshotNow, 1, entry);
- tuple = systable_getnext(scan);
+ /* Search syscache for pg_tablespace */
+ tuple = SearchSysCache(TABLESPACEOID, ObjectIdGetDatum(tblId),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for tablespace %u", tblId);
@@ -2865,8 +2858,7 @@ ExecGrant_Tablespace(InternalGrant *istmt)
noldmembers, oldmembers,
nnewmembers, newmembers);
- systable_endscan(scan);
-
+ ReleaseSysCache(tuple);
pfree(new_acl);
/* prevent error when processing duplicate objects */
@@ -3696,9 +3688,6 @@ pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
AclMode mask, AclMaskHow how)
{
AclMode result;
- Relation pg_tablespace;
- ScanKeyData entry[1];
- SysScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
@@ -3711,17 +3700,9 @@ pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
/*
* Get the tablespace's ACL from pg_tablespace
- *
- * There's no syscache for pg_tablespace, so must look the hard way
*/
- pg_tablespace = heap_open(TableSpaceRelationId, AccessShareLock);
- ScanKeyInit(&entry[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(spc_oid));
- scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
- SnapshotNow, 1, entry);
- tuple = systable_getnext(scan);
+ tuple = SearchSysCache(TABLESPACEOID, ObjectIdGetDatum(spc_oid),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -3729,8 +3710,9 @@ pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
- aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
- RelationGetDescr(pg_tablespace), &isNull);
+ aclDatum = SysCacheGetAttr(TABLESPACEOID, tuple,
+ Anum_pg_tablespace_spcacl,
+ &isNull);
if (isNull)
{
@@ -3750,8 +3732,7 @@ pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
- systable_endscan(scan);
- heap_close(pg_tablespace, AccessShareLock);
+ ReleaseSysCache(tuple);
return result;
}
@@ -4338,9 +4319,6 @@ pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
bool
pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
{
- Relation pg_tablespace;
- ScanKeyData entry[1];
- SysScanDesc scan;
HeapTuple spctuple;
Oid spcowner;
@@ -4348,17 +4326,9 @@ pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
if (superuser_arg(roleid))
return true;
- /* There's no syscache for pg_tablespace, so must look the hard way */
- pg_tablespace = heap_open(TableSpaceRelationId, AccessShareLock);
- ScanKeyInit(&entry[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(spc_oid));
- scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
- SnapshotNow, 1, entry);
-
- spctuple = systable_getnext(scan);
-
+ /* Search syscache for pg_tablespace */
+ spctuple = SearchSysCache(TABLESPACEOID, ObjectIdGetDatum(spc_oid),
+ 0, 0, 0);
if (!HeapTupleIsValid(spctuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -4366,8 +4336,7 @@ pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
- systable_endscan(scan);
- heap_close(pg_tablespace, AccessShareLock);
+ ReleaseSysCache(spctuple);
return has_privs_of_role(roleid, spcowner);
}
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 927711eed27..0da15569f36 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.65 2010/01/02 16:57:37 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.66 2010/01/05 21:53:58 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -49,6 +49,7 @@
#include <sys/stat.h>
#include "access/heapam.h"
+#include "access/reloptions.h"
#include "access/sysattr.h"
#include "access/transam.h"
#include "access/xact.h"
@@ -57,6 +58,7 @@
#include "catalog/indexing.h"
#include "catalog/pg_tablespace.h"
#include "commands/comment.h"
+#include "commands/defrem.h"
#include "commands/tablespace.h"
#include "miscadmin.h"
#include "postmaster/bgwriter.h"
@@ -70,6 +72,7 @@
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
+#include "utils/syscache.h"
#include "utils/tqual.h"
@@ -290,6 +293,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
values[Anum_pg_tablespace_spclocation - 1] =
CStringGetTextDatum(location);
nulls[Anum_pg_tablespace_spcacl - 1] = true;
+ nulls[Anum_pg_tablespace_spcoptions - 1] = true;
tuple = heap_form_tuple(rel->rd_att, values, nulls);
@@ -913,6 +917,73 @@ AlterTableSpaceOwner(const char *name, Oid newOwnerId)
/*
+ * Alter table space options
+ */
+void
+AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
+{
+ Relation rel;
+ ScanKeyData entry[1];
+ HeapScanDesc scandesc;
+ HeapTuple tup;
+ 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)));
+
+ /* 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);
+ heap_freetuple(newtuple);
+
+ /* Conclude heap scan. */
+ heap_endscan(scandesc);
+ heap_close(rel, NoLock);
+}
+
+/*
* Routines for handling the GUC variable 'default_tablespace'.
*/
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 7cbbb1f913d..8d1f1641d7c 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.458 2010/01/02 16:57:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.459 2010/01/05 21:53:58 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3064,6 +3064,18 @@ _copyDropTableSpaceStmt(DropTableSpaceStmt *from)
return newnode;
}
+static AlterTableSpaceOptionsStmt *
+_copyAlterTableSpaceOptionsStmt(AlterTableSpaceOptionsStmt *from)
+{
+ AlterTableSpaceOptionsStmt *newnode = makeNode(AlterTableSpaceOptionsStmt);
+
+ COPY_STRING_FIELD(tablespacename);
+ COPY_NODE_FIELD(options);
+ COPY_SCALAR_FIELD(isReset);
+
+ return newnode;
+}
+
static CreateFdwStmt *
_copyCreateFdwStmt(CreateFdwStmt *from)
{
@@ -4028,6 +4040,9 @@ copyObject(void *from)
case T_DropTableSpaceStmt:
retval = _copyDropTableSpaceStmt(from);
break;
+ case T_AlterTableSpaceOptionsStmt:
+ retval = _copyAlterTableSpaceOptionsStmt(from);
+ break;
case T_CreateFdwStmt:
retval = _copyCreateFdwStmt(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 20abee3898d..24e53773077 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.379 2010/01/02 16:57:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.380 2010/01/05 21:53:58 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1569,6 +1569,17 @@ _equalDropTableSpaceStmt(DropTableSpaceStmt *a, DropTableSpaceStmt *b)
}
static bool
+_equalAlterTableSpaceOptionsStmt(AlterTableSpaceOptionsStmt *a,
+ AlterTableSpaceOptionsStmt *b)
+{
+ COMPARE_STRING_FIELD(tablespacename);
+ COMPARE_NODE_FIELD(options);
+ COMPARE_SCALAR_FIELD(isReset);
+
+ return true;
+}
+
+static bool
_equalCreateFdwStmt(CreateFdwStmt *a, CreateFdwStmt *b)
{
COMPARE_STRING_FIELD(fdwname);
@@ -2720,6 +2731,9 @@ equal(void *a, void *b)
case T_DropTableSpaceStmt:
retval = _equalDropTableSpaceStmt(a, b);
break;
+ case T_AlterTableSpaceOptionsStmt:
+ retval = _equalAlterTableSpaceOptionsStmt(a, b);
+ break;
case T_CreateFdwStmt:
retval = _equalCreateFdwStmt(a, b);
break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 0342e66b515..5bd092eae25 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.379 2010/01/02 16:57:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.380 2010/01/05 21:53:58 rhaas Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1590,6 +1590,7 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node)
WRITE_NODE_FIELD(cheapest_total_path);
WRITE_NODE_FIELD(cheapest_unique_path);
WRITE_UINT_FIELD(relid);
+ WRITE_UINT_FIELD(reltablespace);
WRITE_ENUM_FIELD(rtekind, RTEKind);
WRITE_INT_FIELD(min_attr);
WRITE_INT_FIELD(max_attr);
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index bc028ee1473..f92c944925f 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -27,6 +27,11 @@
* detail. Note that all of these parameters are user-settable, in case
* the default values are drastically off for a particular platform.
*
+ * seq_page_cost and random_page_cost can also be overridden for an individual
+ * tablespace, in case some data is on a fast disk and other data is on a slow
+ * disk. Per-tablespace overrides never apply to temporary work files such as
+ * an external sort or a materialize node that overflows work_mem.
+ *
* We compute two separate costs for each path:
* total_cost: total estimated cost to fetch all tuples
* startup_cost: cost that is expended before first tuple is fetched
@@ -54,7 +59,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.213 2010/01/02 16:57:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.214 2010/01/05 21:53:58 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -76,6 +81,7 @@
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
#include "utils/selfuncs.h"
+#include "utils/spccache.h"
#include "utils/tuplesort.h"
@@ -164,6 +170,7 @@ void
cost_seqscan(Path *path, PlannerInfo *root,
RelOptInfo *baserel)
{
+ double spc_seq_page_cost;
Cost startup_cost = 0;
Cost run_cost = 0;
Cost cpu_per_tuple;
@@ -175,10 +182,15 @@ cost_seqscan(Path *path, PlannerInfo *root,
if (!enable_seqscan)
startup_cost += disable_cost;
+ /* fetch estimated page cost for tablespace containing table */
+ get_tablespace_page_costs(baserel->reltablespace,
+ NULL,
+ &spc_seq_page_cost);
+
/*
* disk costs
*/
- run_cost += seq_page_cost * baserel->pages;
+ run_cost += spc_seq_page_cost * baserel->pages;
/* CPU costs */
startup_cost += baserel->baserestrictcost.startup;
@@ -226,6 +238,8 @@ cost_index(IndexPath *path, PlannerInfo *root,
Selectivity indexSelectivity;
double indexCorrelation,
csquared;
+ double spc_seq_page_cost,
+ spc_random_page_cost;
Cost min_IO_cost,
max_IO_cost;
Cost cpu_per_tuple;
@@ -272,13 +286,18 @@ cost_index(IndexPath *path, PlannerInfo *root,
/* estimate number of main-table tuples fetched */
tuples_fetched = clamp_row_est(indexSelectivity * baserel->tuples);
+ /* fetch estimated page costs for tablespace containing table */
+ get_tablespace_page_costs(baserel->reltablespace,
+ &spc_random_page_cost,
+ &spc_seq_page_cost);
+
/*----------
* Estimate number of main-table pages fetched, and compute I/O cost.
*
* When the index ordering is uncorrelated with the table ordering,
* we use an approximation proposed by Mackert and Lohman (see
* index_pages_fetched() for details) to compute the number of pages
- * fetched, and then charge random_page_cost per page fetched.
+ * fetched, and then charge spc_random_page_cost per page fetched.
*
* When the index ordering is exactly correlated with the table ordering
* (just after a CLUSTER, for example), the number of pages fetched should
@@ -286,7 +305,7 @@ cost_index(IndexPath *path, PlannerInfo *root,
* will be sequential fetches, not the random fetches that occur in the
* uncorrelated case. So if the number of pages is more than 1, we
* ought to charge
- * random_page_cost + (pages_fetched - 1) * seq_page_cost
+ * spc_random_page_cost + (pages_fetched - 1) * spc_seq_page_cost
* For partially-correlated indexes, we ought to charge somewhere between
* these two estimates. We currently interpolate linearly between the
* estimates based on the correlation squared (XXX is that appropriate?).
@@ -309,7 +328,7 @@ cost_index(IndexPath *path, PlannerInfo *root,
(double) index->pages,
root);
- max_IO_cost = (pages_fetched * random_page_cost) / num_scans;
+ max_IO_cost = (pages_fetched * spc_random_page_cost) / num_scans;
/*
* In the perfectly correlated case, the number of pages touched by
@@ -328,7 +347,7 @@ cost_index(IndexPath *path, PlannerInfo *root,
(double) index->pages,
root);
- min_IO_cost = (pages_fetched * random_page_cost) / num_scans;
+ min_IO_cost = (pages_fetched * spc_random_page_cost) / num_scans;
}
else
{
@@ -342,13 +361,13 @@ cost_index(IndexPath *path, PlannerInfo *root,
root);
/* max_IO_cost is for the perfectly uncorrelated case (csquared=0) */
- max_IO_cost = pages_fetched * random_page_cost;
+ max_IO_cost = pages_fetched * spc_random_page_cost;
/* min_IO_cost is for the perfectly correlated case (csquared=1) */
pages_fetched = ceil(indexSelectivity * (double) baserel->pages);
- min_IO_cost = random_page_cost;
+ min_IO_cost = spc_random_page_cost;
if (pages_fetched > 1)
- min_IO_cost += (pages_fetched - 1) * seq_page_cost;
+ min_IO_cost += (pages_fetched - 1) * spc_seq_page_cost;
}
/*
@@ -553,6 +572,8 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
Cost cost_per_page;
double tuples_fetched;
double pages_fetched;
+ double spc_seq_page_cost,
+ spc_random_page_cost;
double T;
/* Should only be applied to base relations */
@@ -571,6 +592,11 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
startup_cost += indexTotalCost;
+ /* Fetch estimated page costs for tablespace containing table. */
+ get_tablespace_page_costs(baserel->reltablespace,
+ &spc_random_page_cost,
+ &spc_seq_page_cost);
+
/*
* Estimate number of main-table pages fetched.
*/
@@ -609,17 +635,18 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
pages_fetched = ceil(pages_fetched);
/*
- * For small numbers of pages we should charge random_page_cost apiece,
+ * For small numbers of pages we should charge spc_random_page_cost apiece,
* while if nearly all the table's pages are being read, it's more
- * appropriate to charge seq_page_cost apiece. The effect is nonlinear,
+ * appropriate to charge spc_seq_page_cost apiece. The effect is nonlinear,
* too. For lack of a better idea, interpolate like this to determine the
* cost per page.
*/
if (pages_fetched >= 2.0)
- cost_per_page = random_page_cost -
- (random_page_cost - seq_page_cost) * sqrt(pages_fetched / T);
+ cost_per_page = spc_random_page_cost -
+ (spc_random_page_cost - spc_seq_page_cost)
+ * sqrt(pages_fetched / T);
else
- cost_per_page = random_page_cost;
+ cost_per_page = spc_random_page_cost;
run_cost += pages_fetched * cost_per_page;
@@ -783,6 +810,7 @@ cost_tidscan(Path *path, PlannerInfo *root,
QualCost tid_qual_cost;
int ntuples;
ListCell *l;
+ double spc_random_page_cost;
/* Should only be applied to base relations */
Assert(baserel->relid > 0);
@@ -835,8 +863,13 @@ cost_tidscan(Path *path, PlannerInfo *root,
*/
cost_qual_eval(&tid_qual_cost, tidquals, root);
+ /* fetch estimated page cost for tablespace containing table */
+ get_tablespace_page_costs(baserel->reltablespace,
+ &spc_random_page_cost,
+ NULL);
+
/* disk costs --- assume each tuple on a different page */
- run_cost += random_page_cost * ntuples;
+ run_cost += spc_random_page_cost * ntuples;
/* CPU costs */
startup_cost += baserel->baserestrictcost.startup +
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 16831811072..fdce5bb5a3f 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.161 2010/01/02 16:57:48 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.162 2010/01/05 21:53:58 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -91,6 +91,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
rel->min_attr = FirstLowInvalidHeapAttributeNumber + 1;
rel->max_attr = RelationGetNumberOfAttributes(relation);
+ rel->reltablespace = RelationGetForm(relation)->reltablespace;
Assert(rel->max_attr >= rel->min_attr);
rel->attr_needed = (Relids *)
@@ -183,6 +184,8 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
info = makeNode(IndexOptInfo);
info->indexoid = index->indexrelid;
+ info->reltablespace =
+ RelationGetForm(indexRelation)->reltablespace;
info->rel = rel;
info->ncolumns = ncolumns = index->indnatts;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index ed906c1fedc..2ea08893f3b 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.701 2010/01/02 16:57:48 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.702 2010/01/05 21:53:58 rhaas Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -5687,6 +5687,24 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
n->newname = $6;
$$ = (Node *)n;
}
+ | ALTER TABLESPACE name SET reloptions
+ {
+ AlterTableSpaceOptionsStmt *n =
+ makeNode(AlterTableSpaceOptionsStmt);
+ n->tablespacename = $3;
+ n->options = $5;
+ n->isReset = FALSE;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLESPACE name RESET reloptions
+ {
+ AlterTableSpaceOptionsStmt *n =
+ makeNode(AlterTableSpaceOptionsStmt);
+ n->tablespacename = $3;
+ n->options = $5;
+ n->isReset = TRUE;
+ $$ = (Node *)n;
+ }
| ALTER TEXT_P SEARCH PARSER any_name RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 3bdc6e7819c..3da89ba08a7 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.326 2010/01/02 16:57:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.327 2010/01/05 21:53:58 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -218,6 +218,7 @@ check_xact_readonly(Node *parsetree)
case T_CreateUserMappingStmt:
case T_AlterUserMappingStmt:
case T_DropUserMappingStmt:
+ case T_AlterTableSpaceOptionsStmt:
ereport(ERROR,
(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
errmsg("transaction is read-only")));
@@ -528,6 +529,10 @@ standard_ProcessUtility(Node *parsetree,
DropTableSpace((DropTableSpaceStmt *) parsetree);
break;
+ case T_AlterTableSpaceOptionsStmt:
+ AlterTableSpaceOptions((AlterTableSpaceOptionsStmt *) parsetree);
+ break;
+
case T_CreateFdwStmt:
CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
break;
@@ -1456,6 +1461,10 @@ CreateCommandTag(Node *parsetree)
tag = "DROP TABLESPACE";
break;
+ case T_AlterTableSpaceOptionsStmt:
+ tag = "ALTER TABLESPACE";
+ break;
+
case T_CreateFdwStmt:
tag = "CREATE FOREIGN DATA WRAPPER";
break;
@@ -2238,6 +2247,10 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL;
break;
+ case T_AlterTableSpaceOptionsStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_CreateFdwStmt:
case T_AlterFdwStmt:
case T_DropFdwStmt:
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 2506eaaf82d..4bd302eab51 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.267 2010/01/04 02:44:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.268 2010/01/05 21:53:59 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -119,6 +119,7 @@
#include "utils/nabstime.h"
#include "utils/pg_locale.h"
#include "utils/selfuncs.h"
+#include "utils/spccache.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
@@ -5648,6 +5649,7 @@ genericcostestimate(PlannerInfo *root,
QualCost index_qual_cost;
double qual_op_cost;
double qual_arg_cost;
+ double spc_random_page_cost;
List *selectivityQuals;
ListCell *l;
@@ -5756,6 +5758,11 @@ genericcostestimate(PlannerInfo *root,
else
numIndexPages = 1.0;
+ /* fetch estimated page cost for schema containing index */
+ get_tablespace_page_costs(index->reltablespace,
+ &spc_random_page_cost,
+ NULL);
+
/*
* Now compute the disk access costs.
*
@@ -5802,15 +5809,16 @@ genericcostestimate(PlannerInfo *root,
* share for each outer scan. (Don't pro-rate for ScalarArrayOpExpr,
* since that's internal to the indexscan.)
*/
- *indexTotalCost = (pages_fetched * random_page_cost) / num_outer_scans;
+ *indexTotalCost = (pages_fetched * spc_random_page_cost)
+ / num_outer_scans;
}
else
{
/*
- * For a single index scan, we just charge random_page_cost per page
- * touched.
+ * For a single index scan, we just charge spc_random_page_cost per
+ * page touched.
*/
- *indexTotalCost = numIndexPages * random_page_cost;
+ *indexTotalCost = numIndexPages * spc_random_page_cost;
}
/*
@@ -5825,11 +5833,11 @@ genericcostestimate(PlannerInfo *root,
*
* We can deal with this by adding a very small "fudge factor" that
* depends on the index size. The fudge factor used here is one
- * random_page_cost per 100000 index pages, which should be small enough
- * to not alter index-vs-seqscan decisions, but will prevent indexes of
- * different sizes from looking exactly equally attractive.
+ * spc_random_page_cost per 100000 index pages, which should be small
+ * enough to not alter index-vs-seqscan decisions, but will prevent
+ * indexes of different sizes from looking exactly equally attractive.
*/
- *indexTotalCost += index->pages * random_page_cost / 100000.0;
+ *indexTotalCost += index->pages * spc_random_page_cost / 100000.0;
/*
* CPU cost: any complex expressions in the indexquals will need to be
diff --git a/src/backend/utils/cache/Makefile b/src/backend/utils/cache/Makefile
index 1766c0315f8..1a3d2cc482e 100644
--- a/src/backend/utils/cache/Makefile
+++ b/src/backend/utils/cache/Makefile
@@ -4,7 +4,7 @@
# Makefile for utils/cache
#
# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/utils/cache/Makefile,v 1.23 2008/02/19 10:30:08 petere Exp $
+# $PostgreSQL: pgsql/src/backend/utils/cache/Makefile,v 1.24 2010/01/05 21:53:59 rhaas Exp $
#
#-------------------------------------------------------------------------
@@ -13,6 +13,6 @@ top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = catcache.o inval.o plancache.o relcache.o \
- syscache.o lsyscache.o typcache.o ts_cache.o
+ spccache.o syscache.o lsyscache.o typcache.o ts_cache.o
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/utils/cache/spccache.c b/src/backend/utils/cache/spccache.c
new file mode 100644
index 00000000000..00629c09f06
--- /dev/null
+++ b/src/backend/utils/cache/spccache.c
@@ -0,0 +1,183 @@
+/*-------------------------------------------------------------------------
+ *
+ * spccache.c
+ * Tablespace cache management.
+ *
+ * We cache the parsed version of spcoptions for each tablespace to avoid
+ * needing to reparse on every lookup. Right now, there doesn't appear to
+ * be a measurable performance gain from doing this, but that might change
+ * in the future as we add more options.
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/utils/cache/spccache.c,v 1.1 2010/01/05 21:53:59 rhaas Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+#include "access/reloptions.h"
+#include "catalog/pg_tablespace.h"
+#include "commands/tablespace.h"
+#include "miscadmin.h"
+#include "optimizer/cost.h"
+#include "utils/catcache.h"
+#include "utils/hsearch.h"
+#include "utils/inval.h"
+#include "utils/spccache.h"
+#include "utils/syscache.h"
+
+static HTAB *TableSpaceCacheHash = NULL;
+
+typedef struct {
+ Oid oid;
+ TableSpaceOpts *opts;
+} TableSpace;
+
+/*
+ * InvalidateTableSpaceCacheCallback
+ * Flush all cache entries when pg_tablespace is updated.
+ *
+ * When pg_tablespace is updated, we must flush the cache entry at least
+ * for that tablespace. Currently, we just flush them all. This is quick
+ * and easy and doesn't cost much, since there shouldn't be terribly many
+ * tablespaces, nor do we expect them to be frequently modified.
+ */
+static void
+InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
+{
+ HASH_SEQ_STATUS status;
+ TableSpace *spc;
+
+ hash_seq_init(&status, TableSpaceCacheHash);
+ while ((spc = (TableSpace *) hash_seq_search(&status)) != NULL)
+ {
+ if (hash_search(TableSpaceCacheHash, (void *) &spc->oid, HASH_REMOVE,
+ NULL) == NULL)
+ elog(ERROR, "hash table corrupted");
+ if (spc->opts)
+ pfree(spc->opts);
+ }
+}
+
+/*
+ * InitializeTableSpaceCache
+ * Initiate the tablespace cache.
+ */
+static void
+InitializeTableSpaceCache(void)
+{
+ HASHCTL ctl;
+
+ /* Initialize the hash table. */
+ MemSet(&ctl, 0, sizeof(ctl));
+ ctl.keysize = sizeof(Oid);
+ ctl.entrysize = sizeof(TableSpace);
+ ctl.hash = tag_hash;
+ TableSpaceCacheHash =
+ hash_create("TableSpace cache", 16, &ctl,
+ HASH_ELEM | HASH_FUNCTION);
+
+ /* Make sure we've initialized CacheMemoryContext. */
+ if (!CacheMemoryContext)
+ CreateCacheMemoryContext();
+
+ /* Watch for invalidation events. */
+ CacheRegisterSyscacheCallback(TABLESPACEOID,
+ InvalidateTableSpaceCacheCallback,
+ (Datum) 0);
+}
+
+/*
+ * get_tablespace
+ * Fetch TableSpace structure for a specified table OID.
+ *
+ * Pointers returned by this function should not be stored, since a cache
+ * flush will invalidate them.
+ */
+static TableSpace *
+get_tablespace(Oid spcid)
+{
+ HeapTuple tp;
+ TableSpace *spc;
+ bool found;
+
+ /*
+ * Since spcid is always from a pg_class tuple, InvalidOid implies the
+ * default.
+ */
+ if (spcid == InvalidOid)
+ spcid = MyDatabaseTableSpace;
+
+ /* Find existing cache entry, or create a new one. */
+ if (!TableSpaceCacheHash)
+ InitializeTableSpaceCache();
+ spc = (TableSpace *) hash_search(TableSpaceCacheHash, (void *) &spcid,
+ HASH_ENTER, &found);
+ if (found)
+ return spc;
+
+ /*
+ * Not found in TableSpace cache. Check catcache. If we don't find a
+ * valid HeapTuple, it must mean someone has managed to request tablespace
+ * details for a non-existent tablespace. We'll just treat that case as if
+ * no options were specified.
+ */
+ tp = SearchSysCache(TABLESPACEOID, ObjectIdGetDatum(spcid), 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ spc->opts = NULL;
+ else
+ {
+ Datum datum;
+ bool isNull;
+ MemoryContext octx;
+
+ datum = SysCacheGetAttr(TABLESPACEOID,
+ tp,
+ Anum_pg_tablespace_spcoptions,
+ &isNull);
+ if (isNull)
+ spc->opts = NULL;
+ else
+ {
+ octx = MemoryContextSwitchTo(CacheMemoryContext);
+ spc->opts = (TableSpaceOpts *) tablespace_reloptions(datum, false);
+ MemoryContextSwitchTo(octx);
+ }
+ ReleaseSysCache(tp);
+ }
+
+ /* Update new TableSpace cache entry with results of option parsing. */
+ return spc;
+}
+
+/*
+ * get_tablespace_page_costs
+ * Return random and sequential page costs for a given tablespace.
+ */
+void
+get_tablespace_page_costs(Oid spcid, double *spc_random_page_cost,
+ double *spc_seq_page_cost)
+{
+ TableSpace *spc = get_tablespace(spcid);
+
+ Assert(spc != NULL);
+
+ if (spc_random_page_cost)
+ {
+ if (!spc->opts || spc->opts->random_page_cost < 0)
+ *spc_random_page_cost = random_page_cost;
+ else
+ *spc_random_page_cost = spc->opts->random_page_cost;
+ }
+
+ if (spc_seq_page_cost)
+ {
+ if (!spc->opts || spc->opts->seq_page_cost < 0)
+ *spc_seq_page_cost = seq_page_cost;
+ else
+ *spc_seq_page_cost = spc->opts->seq_page_cost;
+ }
+}
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index bd747abc80c..f35712732b2 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.123 2010/01/02 16:57:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.124 2010/01/05 21:53:59 rhaas Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
@@ -43,6 +43,7 @@
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_statistic.h"
+#include "catalog/pg_tablespace.h"
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_config_map.h"
#include "catalog/pg_ts_dict.h"
@@ -609,6 +610,18 @@ static const struct cachedesc cacheinfo[] = {
},
1024
},
+ {TableSpaceRelationId, /* TABLESPACEOID */
+ TablespaceOidIndexId,
+ 0,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0,
+ },
+ 16
+ },
{TSConfigMapRelationId, /* TSCONFIGMAP */
TSConfigMapIndexId,
0,
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 8ddc0384789..f46a29586cb 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.129 2010/01/02 16:57:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.130 2010/01/05 21:53:59 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -956,19 +956,28 @@ dumpTablespaces(PGconn *conn)
* Get all tablespaces except built-in ones (which we assume are named
* pg_xxx)
*/
- if (server_version >= 80200)
+ if (server_version >= 80500)
res = executeQuery(conn, "SELECT spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
"spclocation, spcacl, "
+ "array_to_string(spcoptions, ', '),"
"pg_catalog.shobj_description(oid, 'pg_tablespace') "
"FROM pg_catalog.pg_tablespace "
"WHERE spcname !~ '^pg_' "
"ORDER BY 1");
+ else if (server_version >= 80200)
+ res = executeQuery(conn, "SELECT spcname, "
+ "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
+ "spclocation, spcacl, null, "
+ "pg_catalog.shobj_description(oid, 'pg_tablespace'), "
+ "FROM pg_catalog.pg_tablespace "
+ "WHERE spcname !~ '^pg_' "
+ "ORDER BY 1");
else
res = executeQuery(conn, "SELECT spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
"spclocation, spcacl, "
- "null "
+ "null, null "
"FROM pg_catalog.pg_tablespace "
"WHERE spcname !~ '^pg_' "
"ORDER BY 1");
@@ -983,7 +992,8 @@ dumpTablespaces(PGconn *conn)
char *spcowner = PQgetvalue(res, i, 1);
char *spclocation = PQgetvalue(res, i, 2);
char *spcacl = PQgetvalue(res, i, 3);
- char *spccomment = PQgetvalue(res, i, 4);
+ char *spcoptions = PQgetvalue(res, i, 4);
+ char *spccomment = PQgetvalue(res, i, 5);
char *fspcname;
/* needed for buildACLCommands() */
@@ -996,6 +1006,10 @@ dumpTablespaces(PGconn *conn)
appendStringLiteralConn(buf, spclocation, conn);
appendPQExpBuffer(buf, ";\n");
+ if (spcoptions && spcoptions[0] != '\0')
+ appendPQExpBuffer(buf, "ALTER TABLESPACE %s SET (%s);\n",
+ fspcname, spcoptions);
+
if (!skip_acls &&
!buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, spcowner,
"", server_version, buf))
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index a845c1d83cf..f7f5587f7c1 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -1,7 +1,8 @@
/*-------------------------------------------------------------------------
*
* reloptions.h
- * Core support for relation options (pg_class.reloptions)
+ * Core support for relation and tablespace options (pg_class.reloptions
+ * and pg_tablespace.spcoptions)
*
* Note: the functions dealing with text-array reloptions values declare
* them as Datum, not ArrayType *, to avoid needing to include array.h
@@ -11,7 +12,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.17 2010/01/02 16:58:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.18 2010/01/05 21:53:59 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -39,8 +40,9 @@ typedef enum relopt_kind
RELOPT_KIND_HASH = (1 << 3),
RELOPT_KIND_GIN = (1 << 4),
RELOPT_KIND_GIST = (1 << 5),
+ RELOPT_KIND_TABLESPACE = (1 << 6),
/* if you add a new kind, make sure you update "last_default" too */
- RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_GIST,
+ RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_TABLESPACE,
/* some compilers treat enums as signed ints, so we can't use 1 << 31 */
RELOPT_KIND_MAX = (1 << 30)
} relopt_kind;
@@ -264,5 +266,6 @@ extern bytea *default_reloptions(Datum reloptions, bool validate,
extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
extern bytea *index_reloptions(RegProcedure amoptions, Datum reloptions,
bool validate);
+extern bytea *tablespace_reloptions(Datum reloptions, bool validate);
#endif /* RELOPTIONS_H */
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 49bb9198183..6e7a8c33fc4 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.566 2010/01/04 12:50:49 heikki Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.567 2010/01/05 21:53:59 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201001041
+#define CATALOG_VERSION_NO 201001051
#endif
diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h
index 1d15cdfa789..1c189f56510 100644
--- a/src/include/catalog/pg_tablespace.h
+++ b/src/include/catalog/pg_tablespace.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_tablespace.h,v 1.14 2010/01/05 01:06:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_tablespace.h,v 1.15 2010/01/05 21:53:59 rhaas Exp $
*
* NOTES
* the genbki.pl script reads this file and generates .bki
@@ -34,6 +34,7 @@ CATALOG(pg_tablespace,1213) BKI_SHARED_RELATION
Oid spcowner; /* owner of tablespace */
text spclocation; /* physical location (VAR LENGTH) */
aclitem spcacl[1]; /* access permissions (VAR LENGTH) */
+ text spcoptions[1]; /* per-tablespace options */
} FormData_pg_tablespace;
/* ----------------
@@ -48,14 +49,15 @@ typedef FormData_pg_tablespace *Form_pg_tablespace;
* ----------------
*/
-#define Natts_pg_tablespace 4
+#define Natts_pg_tablespace 5
#define Anum_pg_tablespace_spcname 1
#define Anum_pg_tablespace_spcowner 2
#define Anum_pg_tablespace_spclocation 3
#define Anum_pg_tablespace_spcacl 4
+#define Anum_pg_tablespace_spcoptions 5
-DATA(insert OID = 1663 ( pg_default PGUID "" _null_ ));
-DATA(insert OID = 1664 ( pg_global PGUID "" _null_ ));
+DATA(insert OID = 1663 ( pg_default PGUID "" _null_ _null_ ));
+DATA(insert OID = 1664 ( pg_global PGUID "" _null_ _null_ ));
#define DEFAULTTABLESPACE_OID 1663
#define GLOBALTABLESPACE_OID 1664
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index 332bf46f0ae..9330a1f81fe 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.21 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.22 2010/01/05 21:53:59 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,11 +32,17 @@ typedef struct xl_tblspc_drop_rec
Oid ts_id;
} xl_tblspc_drop_rec;
+typedef struct TableSpaceOpts
+{
+ float8 random_page_cost;
+ float8 seq_page_cost;
+} TableSpaceOpts;
extern void CreateTableSpace(CreateTableSpaceStmt *stmt);
extern void DropTableSpace(DropTableSpaceStmt *stmt);
extern void RenameTableSpace(const char *oldname, const char *newname);
extern void AlterTableSpaceOwner(const char *name, Oid newOwnerId);
+extern void AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt);
extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index a84de410963..e1da4954390 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.232 2010/01/02 16:58:04 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.233 2010/01/05 21:53:59 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -346,6 +346,7 @@ typedef enum NodeTag
T_CreateUserMappingStmt,
T_AlterUserMappingStmt,
T_DropUserMappingStmt,
+ T_AlterTableSpaceOptionsStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index d94c6f99086..18673ec30d8 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.421 2010/01/02 16:58:04 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.422 2010/01/05 21:53:59 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1477,6 +1477,14 @@ typedef struct DropTableSpaceStmt
bool missing_ok; /* skip error if missing? */
} DropTableSpaceStmt;
+typedef struct AlterTableSpaceOptionsStmt
+{
+ NodeTag type;
+ char *tablespacename;
+ List *options;
+ bool isReset;
+} AlterTableSpaceOptionsStmt;
+
/* ----------------------
* Create/Drop FOREIGN DATA WRAPPER Statements
* ----------------------
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index df8f4afc8d4..fd93dfcce34 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.182 2010/01/02 16:58:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.183 2010/01/05 21:54:00 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -371,6 +371,7 @@ typedef struct RelOptInfo
/* information about a base rel (not set for join rels!) */
Index relid;
+ Oid reltablespace; /* containing tablespace */
RTEKind rtekind; /* RELATION, SUBQUERY, or FUNCTION */
AttrNumber min_attr; /* smallest attrno of rel (often <0) */
AttrNumber max_attr; /* largest attrno of rel */
@@ -435,6 +436,7 @@ typedef struct IndexOptInfo
NodeTag type;
Oid indexoid; /* OID of the index relation */
+ Oid reltablespace; /* tablespace of index (not table) */
RelOptInfo *rel; /* back-link to index's table */
/* statistics from pg_class */
diff --git a/src/include/utils/spccache.h b/src/include/utils/spccache.h
new file mode 100644
index 00000000000..73b9f7370d9
--- /dev/null
+++ b/src/include/utils/spccache.h
@@ -0,0 +1,19 @@
+/*-------------------------------------------------------------------------
+ *
+ * spccache.h
+ * Tablespace cache.
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/utils/spccache.h,v 1.1 2010/01/05 21:54:00 rhaas Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SPCCACHE_H
+#define SPCCACHE_H
+
+void get_tablespace_page_costs(Oid spcid, float8 *spc_random_page_cost,
+ float8 *spc_seq_page_cost);
+
+#endif /* SPCCACHE_H */
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index 6b12c84da2e..8cdd7e79ee1 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.77 2010/01/02 16:58:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.78 2010/01/05 21:54:00 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -71,6 +71,7 @@ enum SysCacheIdentifier
RELOID,
RULERELNAME,
STATRELATTINH,
+ TABLESPACEOID,
TSCONFIGMAP,
TSCONFIGNAMENSP,
TSCONFIGOID,
diff --git a/src/test/regress/input/tablespace.source b/src/test/regress/input/tablespace.source
index df5479d5893..dba96f4547f 100644
--- a/src/test/regress/input/tablespace.source
+++ b/src/test/regress/input/tablespace.source
@@ -1,6 +1,12 @@
-- create a tablespace we can use
CREATE TABLESPACE testspace LOCATION '@testtablespace@';
+-- try setting and resetting some properties for the new tablespace
+ALTER TABLESPACE testspace SET (random_page_cost = 1.0);
+ALTER TABLESPACE testspace SET (some_nonexistent_parameter = true); -- fail
+ALTER TABLESPACE testspace RESET (random_page_cost = 2.0); -- fail
+ALTER TABLESPACE testspace RESET (random_page_cost, seq_page_cost); -- ok
+
-- create a schema we can use
CREATE SCHEMA testschema;
diff --git a/src/test/regress/output/tablespace.source b/src/test/regress/output/tablespace.source
index e57ad2b2174..79b12a86986 100644
--- a/src/test/regress/output/tablespace.source
+++ b/src/test/regress/output/tablespace.source
@@ -1,5 +1,12 @@
-- create a tablespace we can use
CREATE TABLESPACE testspace LOCATION '@testtablespace@';
+-- try setting and resetting some properties for the new tablespace
+ALTER TABLESPACE testspace SET (random_page_cost = 1.0);
+ALTER TABLESPACE testspace SET (some_nonexistent_parameter = true); -- fail
+ERROR: unrecognized parameter "some_nonexistent_parameter"
+ALTER TABLESPACE testspace RESET (random_page_cost = 2.0); -- fail
+ERROR: RESET must not include values for parameters
+ALTER TABLESPACE testspace RESET (random_page_cost, seq_page_cost); -- ok
-- create a schema we can use
CREATE SCHEMA testschema;
-- try a table