constraints. Christopher Kings-Lynne.
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.83 2004/07/12 01:22:53 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.84 2004/08/02 04:25:31 tgl Exp $
PostgreSQL documentation
-->
where <replaceable class="PARAMETER">column_constraint</replaceable> is:
[ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
-{ NOT NULL | NULL | UNIQUE | PRIMARY KEY |
+{ NOT NULL |
+ NULL |
+ UNIQUE [ USING INDEX TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable> ] |
+ PRIMARY KEY [ USING INDEX TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable> ] |
CHECK (<replaceable class="PARAMETER">expression</replaceable>) |
REFERENCES <replaceable class="PARAMETER">reftable</replaceable> [ ( <replaceable class="PARAMETER">refcolumn</replaceable> ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
[ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ] }
and <replaceable class="PARAMETER">table_constraint</replaceable> is:
[ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
-{ UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) |
- PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) |
+{ UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) [ USING INDEX TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable> ] |
+ PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) [ USING INDEX TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable> ] |
CHECK ( <replaceable class="PARAMETER">expression</replaceable> ) |
FOREIGN KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) REFERENCES <replaceable class="PARAMETER">reftable</replaceable> [ ( <replaceable class="PARAMETER">refcolumn</replaceable> [, ... ] ) ]
[ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ] }
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>USING INDEX TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable></literal></term>
+ <listitem>
+ <para>
+ This clause allows selection of the tablespace in which the index
+ associated with a <literal>UNIQUE</literal> or <literal>PRIMARY
+ KEY</literal> constraint will be created. If not supplied, the index
+ will be created in the same tablespace as the table.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
</refsect2>
<refsect2>
- <title>TABLESPACE</title>
+ <title>TABLESPACE and USING INDEX TABLESPACE</title>
<para>
The <productname>PostgreSQL</productname> concept of tablespaces is not
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_tablespace.sgml,v 1.2 2004/06/25 21:55:50 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_tablespace.sgml,v 1.3 2004/08/02 04:25:37 tgl Exp $
PostgreSQL documentation
-->
A user with appropriate privileges can pass
<replaceable class="parameter">tablespacename</> to <command>CREATE
DATABASE</>, <command>CREATE SCHEMA</>, <command>CREATE TABLE</>,
- <command>CREATE INDEX</> or <command>CREATE SEQUENCE</> to have the data
+ <command>CREATE INDEX</> or <command>ADD CONSTRAINT</> to have the data
files for these objects stored within the specified tablespace.
</para>
</refsect1>
<member><xref linkend="sql-createschema" endterm="sql-createschema-title"></member>
<member><xref linkend="sql-createtable" endterm="sql-createtable-title"></member>
<member><xref linkend="sql-createindex" endterm="sql-createindex-title"></member>
- <member><xref linkend="sql-createsequence" endterm="sql-createsequence-title"></member>
<member><xref linkend="sql-droptablespace" endterm="sql-droptablespace-title"></member>
<member><xref linkend="sql-altertablespace" endterm="sql-altertablespace-title"></member>
</simplelist>
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.288 2004/07/12 05:37:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.289 2004/08/02 04:26:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
COPY_NODE_FIELD(raw_expr);
COPY_STRING_FIELD(cooked_expr);
COPY_NODE_FIELD(keys);
+ COPY_STRING_FIELD(indexspace);
return newnode;
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.227 2004/07/12 05:37:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.228 2004/08/02 04:26:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
COMPARE_NODE_FIELD(raw_expr);
COMPARE_STRING_FIELD(cooked_expr);
COMPARE_NODE_FIELD(keys);
+ COMPARE_STRING_FIELD(indexspace);
return true;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.240 2004/06/18 06:13:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.241 2004/08/02 04:26:05 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
case CONSTR_PRIMARY:
appendStringInfo(str, "PRIMARY_KEY");
WRITE_NODE_FIELD(keys);
+ WRITE_STRING_FIELD(indexspace);
+ break;
+
+ case CONSTR_UNIQUE:
+ appendStringInfo(str, "UNIQUE");
+ WRITE_NODE_FIELD(keys);
+ WRITE_STRING_FIELD(indexspace);
break;
case CONSTR_CHECK:
appendStringInfo(str, "NOT_NULL");
break;
- case CONSTR_UNIQUE:
- appendStringInfo(str, "UNIQUE");
- WRITE_NODE_FIELD(keys);
- break;
-
default:
appendStringInfo(str, "<unrecognized_constraint>");
break;
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.307 2004/07/12 05:37:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.308 2004/08/02 04:26:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
index->relation = cxt->relation;
index->accessMethod = DEFAULT_INDEX_TYPE;
- index->tableSpace = NULL;
+ index->tableSpace = constraint->indexspace;
index->indexParams = NIL;
index->whereClause = NULL;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.468 2004/07/27 05:10:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.469 2004/08/02 04:26:35 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
%type <list> constraints_set_list
%type <boolean> constraints_set_mode
-%type <str> OptTableSpace OptTableSpaceOwner
+%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
/*
n->raw_expr = NULL;
n->cooked_expr = NULL;
n->keys = NULL;
+ n->indexspace = NULL;
$$ = (Node *)n;
}
| NULL_P
n->raw_expr = NULL;
n->cooked_expr = NULL;
n->keys = NULL;
+ n->indexspace = NULL;
$$ = (Node *)n;
}
- | UNIQUE
+ | UNIQUE OptConsTableSpace
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE;
n->raw_expr = NULL;
n->cooked_expr = NULL;
n->keys = NULL;
+ n->indexspace = $2;
$$ = (Node *)n;
}
- | PRIMARY KEY
+ | PRIMARY KEY OptConsTableSpace
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_PRIMARY;
n->raw_expr = NULL;
n->cooked_expr = NULL;
n->keys = NULL;
+ n->indexspace = $3;
$$ = (Node *)n;
}
| CHECK '(' a_expr ')'
n->raw_expr = $3;
n->cooked_expr = NULL;
n->keys = NULL;
+ n->indexspace = NULL;
$$ = (Node *)n;
}
| DEFAULT b_expr
}
n->cooked_expr = NULL;
n->keys = NULL;
+ n->indexspace = NULL;
$$ = (Node *)n;
}
| REFERENCES qualified_name opt_column_list key_match key_actions
n->name = NULL;
n->raw_expr = $3;
n->cooked_expr = NULL;
+ n->indexspace = NULL;
$$ = (Node *)n;
}
- | UNIQUE '(' columnList ')'
+ | UNIQUE '(' columnList ')' OptConsTableSpace
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE;
n->raw_expr = NULL;
n->cooked_expr = NULL;
n->keys = $3;
+ n->indexspace = $5;
$$ = (Node *)n;
}
- | PRIMARY KEY '(' columnList ')'
+ | PRIMARY KEY '(' columnList ')' OptConsTableSpace
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_PRIMARY;
n->raw_expr = NULL;
n->cooked_expr = NULL;
n->keys = $4;
+ n->indexspace = $6;
$$ = (Node *)n;
}
| FOREIGN KEY '(' columnList ')' REFERENCES qualified_name
| /*EMPTY*/ { $$ = NULL; }
;
+OptConsTableSpace: USING INDEX TABLESPACE name { $$ = $4; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
/*
* Note: CREATE TABLE ... AS SELECT ... is just another spelling for
* back to source text
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.175 2004/07/06 04:50:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.176 2004/08/02 04:27:15 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
int prettyFlags);
static char *pg_get_expr_worker(text *expr, Oid relid, char *relname,
int prettyFlags);
+static Oid get_constraint_index(Oid constraintRelOid, Oid constraintOid);
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
int prettyFlags);
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
{
Datum val;
bool isnull;
+ Oid indexOid;
/* Start off the constraint definition */
if (conForm->contype == CONSTRAINT_PRIMARY)
appendStringInfo(&buf, ")");
+ /* Add TABLESPACE if it's not default */
+ indexOid = get_constraint_index(RelationGetRelid(conDesc),
+ constraintId);
+ if (OidIsValid(indexOid))
+ {
+ Oid reltablespace;
+ Oid indtablespace;
+
+ reltablespace = get_rel_tablespace(conForm->conrelid);
+ indtablespace = get_rel_tablespace(indexOid);
+ if (OidIsValid(indtablespace) &&
+ indtablespace != reltablespace)
+ {
+ char *spcname = get_tablespace_name(indtablespace);
+
+ if (spcname) /* just paranoia... */
+ {
+ appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
+ quote_identifier(spcname));
+ pfree(spcname);
+ }
+ }
+ }
break;
}
case CONSTRAINT_CHECK:
PG_RETURN_NULL();
}
+/*
+ * get_constraint_index
+ * Given the OID of a unique or primary-key constraint,
+ * look up the OID of the underlying index.
+ *
+ * We make the caller pass in the OID of pg_constraint, too, simply because
+ * it's probably got it at hand already.
+ *
+ * Returns InvalidOid if index can't be found.
+ */
+static Oid
+get_constraint_index(Oid constraintRelOid, Oid constraintOid)
+{
+ Oid result = InvalidOid;
+ Relation depRel;
+ ScanKeyData key[3];
+ SysScanDesc scan;
+ HeapTuple tup;
+
+ /* Search the dependency table for the dependent index */
+ depRel = heap_openr(DependRelationName, AccessShareLock);
+
+ ScanKeyInit(&key[0],
+ Anum_pg_depend_refclassid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(constraintRelOid));
+ ScanKeyInit(&key[1],
+ Anum_pg_depend_refobjid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(constraintOid));
+ ScanKeyInit(&key[2],
+ Anum_pg_depend_refobjsubid,
+ BTEqualStrategyNumber, F_INT4EQ,
+ Int32GetDatum(0));
+
+ scan = systable_beginscan(depRel, DependReferenceIndex, true,
+ SnapshotNow, 3, key);
+
+ while (HeapTupleIsValid(tup = systable_getnext(scan)))
+ {
+ Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
+
+ /*
+ * We assume any internal dependency of a relation on the constraint
+ * must be what we are looking for.
+ */
+ if (deprec->classid == RelOid_pg_class &&
+ deprec->objsubid == 0 &&
+ deprec->deptype == DEPENDENCY_INTERNAL)
+ {
+ result = deprec->objid;
+ break;
+ }
+ }
+
+ systable_endscan(scan);
+ heap_close(depRel, AccessShareLock);
+
+ return result;
+}
+
/* ----------
* deparse_expression - General utility for deparsing expressions
* by PostgreSQL
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.380 2004/07/19 21:39:48 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.381 2004/08/02 04:28:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
i_contype,
i_conname,
i_contableoid,
- i_conoid;
+ i_conoid,
+ i_tablespace;
int ntups;
for (i = 0; i < numTables; i++)
* one internal dependency.
*/
resetPQExpBuffer(query);
- if (g_fout->remoteVersion >= 70300)
+ if (g_fout->remoteVersion >= 70500)
{
appendPQExpBuffer(query,
"SELECT t.tableoid, t.oid, "
"i.indkey, i.indisclustered, "
"c.contype, c.conname, "
"c.tableoid as contableoid, "
- "c.oid as conoid "
+ "c.oid as conoid, "
+ "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) as tablespace "
+ "FROM pg_catalog.pg_index i "
+ "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
+ "LEFT JOIN pg_catalog.pg_depend d "
+ "ON (d.classid = t.tableoid "
+ "AND d.objid = t.oid "
+ "AND d.deptype = 'i') "
+ "LEFT JOIN pg_catalog.pg_constraint c "
+ "ON (d.refclassid = c.tableoid "
+ "AND d.refobjid = c.oid) "
+ "WHERE i.indrelid = '%u'::pg_catalog.oid "
+ "ORDER BY indexname",
+ tbinfo->dobj.catId.oid);
+ }
+ else if (g_fout->remoteVersion >= 70300)
+ {
+ appendPQExpBuffer(query,
+ "SELECT t.tableoid, t.oid, "
+ "t.relname as indexname, "
+ "pg_catalog.pg_get_indexdef(i.indexrelid) as indexdef, "
+ "t.relnatts as indnkeys, "
+ "i.indkey, i.indisclustered, "
+ "c.contype, c.conname, "
+ "c.tableoid as contableoid, "
+ "c.oid as conoid, "
+ "NULL as tablespace "
"FROM pg_catalog.pg_index i "
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
"LEFT JOIN pg_catalog.pg_depend d "
"ELSE '0'::char END as contype, "
"t.relname as conname, "
"0::oid as contableoid, "
- "t.oid as conoid "
+ "t.oid as conoid, "
+ "NULL as tablespace "
"FROM pg_index i, pg_class t "
"WHERE t.oid = i.indexrelid "
"AND i.indrelid = '%u'::oid "
"ELSE '0'::char END as contype, "
"t.relname as conname, "
"0::oid as contableoid, "
- "t.oid as conoid "
+ "t.oid as conoid, "
+ "NULL as tablespace "
"FROM pg_index i, pg_class t "
"WHERE t.oid = i.indexrelid "
"AND i.indrelid = '%u'::oid "
i_conname = PQfnumber(res, "conname");
i_contableoid = PQfnumber(res, "contableoid");
i_conoid = PQfnumber(res, "conoid");
+ i_tablespace = PQfnumber(res, "tablespace");
indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo));
constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
indxinfo[j].indextable = tbinfo;
indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
+ indxinfo[j].tablespace = strdup(PQgetvalue(res, j, i_tablespace));
/*
* In pre-7.4 releases, indkeys may contain more entries than
fmtId(attname));
}
- appendPQExpBuffer(q, ");\n");
+ appendPQExpBuffer(q, ")");
+
+ /* Output tablespace clause if necessary */
+ if (strlen(indxinfo->tablespace) != 0 &&
+ strcmp(indxinfo->tablespace,
+ indxinfo->indextable->reltablespace) != 0)
+ {
+ appendPQExpBuffer(q, " USING INDEX TABLESPACE %s",
+ fmtId(indxinfo->tablespace));
+ }
+
+ appendPQExpBuffer(q, ";\n");
/* If the index is clustered, we need to record that. */
if (indxinfo->indisclustered)
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.109 2004/06/18 06:14:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.110 2004/08/02 04:28:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
DumpableObject dobj;
TableInfo *indextable; /* link to table the index is for */
char *indexdef;
+ char *tablespace; /* tablespace in which index is stored */
int indnkeys;
Oid *indkeys;
bool indisclustered;
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.263 2004/07/27 05:11:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.264 2004/08/02 04:28:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
char *cooked_expr; /* expr, as nodeToString representation */
List *keys; /* String nodes naming referenced
* column(s) */
+ char *indexspace; /* index tablespace for PKEY/UNIQUE
+ * constraints; NULL for default */
} Constraint;
/* ----------