<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.116 2009/09/18 05:00:41 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.117 2009/10/12 19:49:24 adunstan Exp $
PostgreSQL documentation
-->
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable class="PARAMETER">table_name</replaceable> ( [
{ <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ DEFAULT <replaceable>default_expr</replaceable> ] [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ]
| <replaceable>table_constraint</replaceable>
- | LIKE <replaceable>parent_table</replaceable> [ { INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS | INDEXES } ] ... }
+ | LIKE <replaceable>parent_table</replaceable> [ { INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS | INDEXES | STORAGE | COMMENTS | ALL } ] ... }
[, ... ]
] )
[ INHERITS ( <replaceable>parent_table</replaceable> [, ... ] ) ]
will always be chosen for it.
</para>
+ <para>
+ Column storage parameters are also copied from parent tables.
+ </para>
+
<!--
<para>
<productname>PostgreSQL</> automatically allows the
</varlistentry>
<varlistentry>
- <term><literal>LIKE <replaceable>parent_table</replaceable> [ { INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS | INDEXES } ]</literal></term>
+ <term><literal>LIKE <replaceable>parent_table</replaceable> [ { INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS | INDEXES | STORAGE | COMMENTS | ALL } ]</literal></term>
<listitem>
<para>
The <literal>LIKE</literal> clause specifies a table from which
table, unless the <literal>INCLUDING INDEXES</literal> clause is
specified.
</para>
+ <para>
+ Storage parameters for the copied column definitions will only be copied
+ if <literal>INCLUDING STORAGE</literal> is specified. The default
+ behavior is to exclude storage parameters, resulting in the copied
+ columns in the new table having type-specific default parameters. For
+ more on storage parameters, see <xref linkend="storage-toast">.
+ </para>
+ <para>
+ Comments for the copied column, constraint, index and columns of index
+ definitions will only be copied if <literal>INCLUDING COMMENTS</literal>
+ is specified. The default behavior is to exclude comments, resulting in
+ the copied columns and constraints in the new table having no comments.
+ </para>
+ <para>
+ <literal>INCLUDING ALL</literal> is an abbreviated form of
+ <literal>INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING STORAGE INCLUDING COMMENTS</literal>.
+ </para>
<para>
Note also that unlike <literal>INHERITS</literal>, copied columns and
constraints are not merged with similarly named columns and constraints.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.128 2009/08/02 22:14:51 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.129 2009/10/12 19:49:24 adunstan Exp $
*
* NOTES
* some of the executor utility code such as "ExecTypeFromTL" should be
has_not_null |= entry->is_not_null;
desc->attrs[attnum - 1]->attislocal = entry->is_local;
desc->attrs[attnum - 1]->attinhcount = entry->inhcount;
+ if (entry->storage)
+ desc->attrs[attnum - 1]->attstorage = entry->storage;
}
if (has_not_null)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.47 2009/07/28 02:56:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.48 2009/10/12 19:49:24 adunstan Exp $
*
*-------------------------------------------------------------------------
*/
heap_close(conRel, RowExclusiveLock);
}
+
+/*
+ * GetConstraintByName
+ * Find a constraint with the specified name.
+ */
+Oid
+GetConstraintByName(Oid relid, const char *conname)
+{
+ Relation pg_constraint;
+ HeapTuple tuple;
+ SysScanDesc scan;
+ ScanKeyData skey[1];
+ Oid conOid = InvalidOid;
+
+ /*
+ * Fetch the constraint tuple from pg_constraint. There may be more than
+ * one match, because constraints are not required to have unique names;
+ * if so, error out.
+ */
+ pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_constraint_conrelid,
+ BTEqualStrategyNumber, F_OIDEQ, relid);
+
+ scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
+ SnapshotNow, 1, skey);
+
+ while (HeapTupleIsValid(tuple = systable_getnext(scan)))
+ {
+ Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
+
+ if (strcmp(NameStr(con->conname), conname) == 0)
+ {
+ if (OidIsValid(conOid))
+ {
+ char *relname = get_rel_name(relid);
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("table \"%s\" has multiple constraints named \"%s\"",
+ (relname ? relname : "(unknown)"), conname)));
+ }
+ conOid = HeapTupleGetOid(tuple);
+ }
+ }
+
+ systable_endscan(scan);
+
+ /* If no constraint exists for the relation specified, notify user */
+ if (!OidIsValid(conOid))
+ {
+ char *relname = get_rel_name(relid);
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("constraint \"%s\" for table \"%s\" does not exist",
+ conname, (relname ? relname : "(unknown)"))));
+ }
+
+ heap_close(pg_constraint, AccessShareLock);
+
+ return conOid;
+}
* Copyright (c) 1996-2009, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.107 2009/06/11 14:48:55 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.108 2009/10/12 19:49:24 adunstan Exp $
*
*-------------------------------------------------------------------------
*/
heap_close(shdescription, RowExclusiveLock);
}
+/*
+ * GetComment -- get the comment for an object, or null if not found.
+ */
+char *
+GetComment(Oid oid, Oid classoid, int32 subid)
+{
+ Relation description;
+ ScanKeyData skey[3];
+ SysScanDesc sd;
+ TupleDesc tupdesc;
+ HeapTuple tuple;
+ char *comment;
+
+ /* Use the index to search for a matching old tuple */
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_description_objoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(oid));
+ ScanKeyInit(&skey[1],
+ Anum_pg_description_classoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(classoid));
+ ScanKeyInit(&skey[2],
+ Anum_pg_description_objsubid,
+ BTEqualStrategyNumber, F_INT4EQ,
+ Int32GetDatum(subid));
+
+ description = heap_open(DescriptionRelationId, AccessShareLock);
+ tupdesc = RelationGetDescr(description);
+
+ sd = systable_beginscan(description, DescriptionObjIndexId, true,
+ SnapshotNow, 3, skey);
+
+ comment = NULL;
+ while ((tuple = systable_getnext(sd)) != NULL)
+ {
+ Datum value;
+ bool isnull;
+
+ /* Found the tuple, get description field */
+ value = heap_getattr(tuple, Anum_pg_description_description, tupdesc, &isnull);
+ if (!isnull)
+ comment = TextDatumGetCString(value);
+ break; /* Assume there can be only one match */
+ }
+
+ systable_endscan(sd);
+
+ /* Done */
+ heap_close(description, AccessShareLock);
+
+ return comment;
+}
+
/*
* CommentRelation --
*
List *relName;
char *conName;
RangeVar *rel;
- Relation pg_constraint,
- relation;
- HeapTuple tuple;
- SysScanDesc scan;
- ScanKeyData skey[1];
- Oid conOid = InvalidOid;
+ Relation relation;
+ Oid conOid;
/* Separate relname and constraint name */
nnames = list_length(qualname);
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(relation));
- /*
- * Fetch the constraint tuple from pg_constraint. There may be more than
- * one match, because constraints are not required to have unique names;
- * if so, error out.
- */
- pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
-
- ScanKeyInit(&skey[0],
- Anum_pg_constraint_conrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(RelationGetRelid(relation)));
-
- scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
- SnapshotNow, 1, skey);
-
- while (HeapTupleIsValid(tuple = systable_getnext(scan)))
- {
- Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
-
- if (strcmp(NameStr(con->conname), conName) == 0)
- {
- if (OidIsValid(conOid))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("table \"%s\" has multiple constraints named \"%s\"",
- RelationGetRelationName(relation), conName)));
- conOid = HeapTupleGetOid(tuple);
- }
- }
-
- systable_endscan(scan);
-
- /* If no constraint exists for the relation specified, notify user */
- if (!OidIsValid(conOid))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("constraint \"%s\" for table \"%s\" does not exist",
- conName, RelationGetRelationName(relation))));
+ conOid = GetConstraintByName(RelationGetRelid(relation), conName);
/* Call CreateComments() to create/drop the comments */
CreateComments(conOid, ConstraintRelationId, 0, comment);
/* Done, but hold lock on relation */
- heap_close(pg_constraint, AccessShareLock);
heap_close(relation, NoLock);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.301 2009/10/06 00:55:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.302 2009/10/12 19:49:24 adunstan Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/storage.h"
#include "catalog/toasting.h"
#include "commands/cluster.h"
+#include "commands/comment.h"
#include "commands/defrem.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h"
static void ATExecDropInherit(Relation rel, RangeVar *parent);
static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
ForkNumber forkNum, bool istemp);
+static const char * storage_name(char c);
/* ----------------------------------------------------------------
CheckTableNotInUse(rel, "TRUNCATE");
}
+
+/*----------------
+ * storage_name
+ * returns a name corresponding to a storage enum value
+ * For use in error messages
+ */
+static const char *
+storage_name(char c)
+{
+ switch (c)
+ {
+ case 'p': return "PLAIN";
+ case 'm': return "MAIN";
+ case 'x': return "EXTENDED";
+ case 'e': return "EXTERNAL";
+ default: return "???";
+ }
+}
+
/*----------
* MergeAttributes
* Returns new schema given initial schema and superclasses.
List *constraints = NIL;
int parentsWithOids = 0;
bool have_bogus_defaults = false;
+ bool have_bogus_comments = false;
int child_attno;
static Node bogus_marker = { 0 }; /* marks conflicting defaults */
errdetail("%s versus %s",
TypeNameToString(def->typeName),
format_type_be(attribute->atttypid))));
+
+ /* Copy storage parameter */
+ if (def->storage == 0)
+ def->storage = attribute->attstorage;
+ else if (def->storage != attribute->attstorage)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("inherited column \"%s\" has a storage parameter conflict",
+ attributeName),
+ errdetail("%s versus %s", storage_name(def->storage),
+ storage_name(attribute->attstorage))));
+
def->inhcount++;
/* Merge of NOT NULL constraints = OR 'em together */
def->is_not_null |= attribute->attnotnull;
def->raw_default = NULL;
def->cooked_default = NULL;
def->constraints = NIL;
+ def->storage = attribute->attstorage;
inhSchema = lappend(inhSchema, def);
newattno[parent_attno - 1] = ++child_attno;
}
errdetail("%s versus %s",
TypeNameToString(def->typeName),
TypeNameToString(newdef->typeName))));
+
+ /* Copy storage parameter */
+ if (def->storage == 0)
+ def->storage = newdef->storage;
+ else if (newdef->storage != 0 && def->storage != newdef->storage)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("column \"%s\" has a storage parameter conflict",
+ attributeName),
+ errdetail("%s versus %s", storage_name(def->storage),
+ storage_name(newdef->storage))));
+
/* Mark the column as locally defined */
def->is_local = true;
/* Merge of NOT NULL constraints = OR 'em together */
}
}
+ /* Raise an error if we found conflicting comments. */
+ if (have_bogus_comments)
+ {
+ foreach(entry, schema)
+ {
+ ColumnDef *def = lfirst(entry);
+
+ if (def->cooked_default == &bogus_marker)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
+ errmsg("column \"%s\" inherits conflicting comments", def->colname)));
+ }
+ }
+
*supOids = parentOids;
*supconstr = constraints;
*supOidCount = parentsWithOids;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.444 2009/10/12 18:10:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.445 2009/10/12 19:49:24 adunstan Exp $
*
*-------------------------------------------------------------------------
*/
InhRelation *newnode = makeNode(InhRelation);
COPY_NODE_FIELD(relation);
- COPY_NODE_FIELD(options);
+ COPY_SCALAR_FIELD(options);
return newnode;
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.366 2009/10/12 18:10:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.367 2009/10/12 19:49:24 adunstan Exp $
*
*-------------------------------------------------------------------------
*/
_equalInhRelation(InhRelation *a, InhRelation *b)
{
COMPARE_NODE_FIELD(relation);
- COMPARE_NODE_FIELD(options);
+ COMPARE_SCALAR_FIELD(options);
return true;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.682 2009/10/08 02:39:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.683 2009/10/12 19:49:24 adunstan Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
%type <keyword> col_name_keyword reserved_keyword
%type <node> TableConstraint TableLikeClause
-%type <list> TableLikeOptionList
-%type <ival> TableLikeOption
+%type <ival> TableLikeOptionList TableLikeOption
%type <list> ColQualList
%type <node> ColConstraint ColConstraintElem ConstraintAttr
%type <ival> key_actions key_delete key_match key_update key_action
CACHE CALLED CASCADE CASCADED CASE CAST CATALOG_P CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
- CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
+ CLUSTER COALESCE COLLATE COLUMN COMMENT COMMENTS COMMIT
COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS
CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB
CREATEROLE CREATEUSER CROSS CSV CURRENT_P
;
TableLikeOptionList:
- TableLikeOptionList TableLikeOption { $$ = lappend_int($1, $2); }
- | /* EMPTY */ { $$ = NIL; }
+ TableLikeOptionList INCLUDING TableLikeOption { $$ = $1 | $3; }
+ | TableLikeOptionList EXCLUDING TableLikeOption { $$ = $1 & ~$3; }
+ | /* EMPTY */ { $$ = 0; }
;
TableLikeOption:
- INCLUDING DEFAULTS { $$ = CREATE_TABLE_LIKE_INCLUDING_DEFAULTS; }
- | EXCLUDING DEFAULTS { $$ = CREATE_TABLE_LIKE_EXCLUDING_DEFAULTS; }
- | INCLUDING CONSTRAINTS { $$ = CREATE_TABLE_LIKE_INCLUDING_CONSTRAINTS; }
- | EXCLUDING CONSTRAINTS { $$ = CREATE_TABLE_LIKE_EXCLUDING_CONSTRAINTS; }
- | INCLUDING INDEXES { $$ = CREATE_TABLE_LIKE_INCLUDING_INDEXES; }
- | EXCLUDING INDEXES { $$ = CREATE_TABLE_LIKE_EXCLUDING_INDEXES; }
+ DEFAULTS { $$ = CREATE_TABLE_LIKE_DEFAULTS; }
+ | CONSTRAINTS { $$ = CREATE_TABLE_LIKE_CONSTRAINTS; }
+ | INDEXES { $$ = CREATE_TABLE_LIKE_INDEXES; }
+ | STORAGE { $$ = CREATE_TABLE_LIKE_STORAGE; }
+ | COMMENTS { $$ = CREATE_TABLE_LIKE_COMMENTS; }
+ | ALL { $$ = CREATE_TABLE_LIKE_ALL; }
;
| CLOSE
| CLUSTER
| COMMENT
+ | COMMENTS
| COMMIT
| COMMITTED
| CONCURRENTLY
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.26 2009/10/06 00:55:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.27 2009/10/12 19:49:24 adunstan Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/pg_constraint.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_type.h"
+#include "commands/comment.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
Constraint *constraint);
static void transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
InhRelation *inhrelation);
+static char *chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt);
static IndexStmt *generateClonedIndexStmt(CreateStmtContext *cxt,
Relation parent_index, AttrNumber *attmap);
static List *get_opclass(Oid opclass, Oid actual_datatype);
TupleDesc tupleDesc;
TupleConstr *constr;
AclResult aclresult;
- bool including_defaults = false;
- bool including_constraints = false;
- bool including_indexes = false;
- ListCell *elem;
+ char *comment;
relation = parserOpenTable(pstate, inhRelation->relation, AccessShareLock);
tupleDesc = RelationGetDescr(relation);
constr = tupleDesc->constr;
- foreach(elem, inhRelation->options)
- {
- int option = lfirst_int(elem);
-
- switch (option)
- {
- case CREATE_TABLE_LIKE_INCLUDING_DEFAULTS:
- including_defaults = true;
- break;
- case CREATE_TABLE_LIKE_EXCLUDING_DEFAULTS:
- including_defaults = false;
- break;
- case CREATE_TABLE_LIKE_INCLUDING_CONSTRAINTS:
- including_constraints = true;
- break;
- case CREATE_TABLE_LIKE_EXCLUDING_CONSTRAINTS:
- including_constraints = false;
- break;
- case CREATE_TABLE_LIKE_INCLUDING_INDEXES:
- including_indexes = true;
- break;
- case CREATE_TABLE_LIKE_EXCLUDING_INDEXES:
- including_indexes = false;
- break;
- default:
- elog(ERROR, "unrecognized CREATE TABLE LIKE option: %d",
- option);
- }
- }
-
/*
* Insert the copied attributes into the cxt for the new table definition.
*/
/*
* Copy default, if present and the default has been requested
*/
- if (attribute->atthasdef && including_defaults)
+ if (attribute->atthasdef &&
+ (inhRelation->options & CREATE_TABLE_LIKE_DEFAULTS))
{
Node *this_default = NULL;
AttrDefault *attrdef;
def->cooked_default = this_default;
}
+
+ /* Likewise, copy storage if requested */
+ if (inhRelation->options & CREATE_TABLE_LIKE_STORAGE)
+ def->storage = attribute->attstorage;
+
+ /* Likewise, copy comment if requested */
+ if ((inhRelation->options & CREATE_TABLE_LIKE_COMMENTS) &&
+ (comment = GetComment(attribute->attrelid, RelationRelationId,
+ attribute->attnum)) != NULL)
+ {
+ CommentStmt *stmt = makeNode(CommentStmt);
+
+ stmt->objtype = OBJECT_COLUMN;
+ stmt->objname = list_make3(makeString(cxt->relation->schemaname),
+ makeString(cxt->relation->relname),
+ makeString(def->colname));
+ stmt->objargs = NIL;
+ stmt->comment = comment;
+
+ cxt->alist = lappend(cxt->alist, stmt);
+ }
}
/*
* Copy CHECK constraints if requested, being careful to adjust attribute
* numbers
*/
- if (including_constraints && tupleDesc->constr)
+ if ((inhRelation->options & CREATE_TABLE_LIKE_CONSTRAINTS) && tupleDesc->constr)
{
AttrNumber *attmap = varattnos_map_schema(tupleDesc, cxt->columns);
int ccnum;
n->raw_expr = NULL;
n->cooked_expr = nodeToString(ccbin_node);
cxt->ckconstraints = lappend(cxt->ckconstraints, n);
+
+ /* Copy comment on constraint */
+ if ((inhRelation->options & CREATE_TABLE_LIKE_COMMENTS) &&
+ (comment = GetComment(GetConstraintByName(RelationGetRelid(
+ relation), n->conname), ConstraintRelationId, 0)) != NULL)
+ {
+ CommentStmt *stmt = makeNode(CommentStmt);
+
+ stmt->objtype = OBJECT_CONSTRAINT;
+ stmt->objname = list_make3(makeString(cxt->relation->schemaname),
+ makeString(cxt->relation->relname),
+ makeString(n->conname));
+ stmt->objargs = NIL;
+ stmt->comment = comment;
+
+ cxt->alist = lappend(cxt->alist, stmt);
+ }
}
}
/*
* Likewise, copy indexes if requested
*/
- if (including_indexes && relation->rd_rel->relhasindex)
+ if ((inhRelation->options & CREATE_TABLE_LIKE_INDEXES) &&
+ relation->rd_rel->relhasindex)
{
AttrNumber *attmap = varattnos_map_schema(tupleDesc, cxt->columns);
List *parent_indexes;
/* Build CREATE INDEX statement to recreate the parent_index */
index_stmt = generateClonedIndexStmt(cxt, parent_index, attmap);
+ /* Copy comment on index */
+ if (inhRelation->options & CREATE_TABLE_LIKE_COMMENTS)
+ {
+ CommentStmt *stmt;
+ ListCell *lc;
+ int i;
+
+ comment = GetComment(parent_index_oid, RelationRelationId, 0);
+
+ if (comment != NULL)
+ {
+ /* Assign name for index because CommentStmt requires name. */
+ if (index_stmt->idxname == NULL)
+ index_stmt->idxname = chooseIndexName(cxt->relation, index_stmt);
+
+ stmt = makeNode(CommentStmt);
+ stmt->objtype = OBJECT_INDEX;
+ stmt->objname = list_make2(makeString(cxt->relation->schemaname),
+ makeString(index_stmt->idxname));
+ stmt->objargs = NIL;
+ stmt->comment = comment;
+
+ cxt->alist = lappend(cxt->alist, stmt);
+ }
+
+ /* Copy comment on index's columns */
+ i = 0;
+ foreach(lc, index_stmt->indexParams)
+ {
+ char *attname;
+
+ i++;
+ comment = GetComment(parent_index_oid, RelationRelationId, i);
+ if (comment == NULL)
+ continue;
+
+ /* Assign name for index because CommentStmt requires name. */
+ if (index_stmt->idxname == NULL)
+ index_stmt->idxname = chooseIndexName(cxt->relation, index_stmt);
+
+ attname = ((IndexElem *) lfirst(lc))->name;
+
+ /* expression index has a dummy column name */
+ if (attname == NULL)
+ {
+ attname = palloc(NAMEDATALEN);
+ sprintf(attname, "pg_expression_%d", i);
+ }
+
+ stmt = makeNode(CommentStmt);
+ stmt->objtype = OBJECT_COLUMN;
+ stmt->objname = list_make3(
+ makeString(cxt->relation->schemaname),
+ makeString(index_stmt->idxname),
+ makeString(attname));
+ stmt->objargs = NIL;
+ stmt->comment = comment;
+
+ cxt->alist = lappend(cxt->alist, stmt);
+ }
+ }
+
/* Save it in the inh_indexes list for the time being */
cxt->inh_indexes = lappend(cxt->inh_indexes, index_stmt);
heap_close(relation, NoLock);
}
+/*
+ * chooseIndexName
+ *
+ * Set name to unnamed index. See also the same logic in DefineIndex.
+ */
+static char *
+chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt)
+{
+ Oid namespaceId;
+
+ namespaceId = RangeVarGetCreationNamespace(relation);
+ if (index_stmt->primary)
+ {
+ /* no need for column list with pkey */
+ return ChooseRelationName(relation->relname, NULL,
+ "pkey", namespaceId);
+ }
+ else
+ {
+ IndexElem *iparam = (IndexElem *) linitial(index_stmt->indexParams);
+
+ return ChooseRelationName(relation->relname, iparam->name,
+ "key", namespaceId);
+ }
+}
+
/*
* Generate an IndexStmt node using information from an already existing index
* "source_idx". Attribute numbers should be adjusted according to attmap.
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.32 2009/07/28 02:56:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.33 2009/10/12 19:49:24 adunstan Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
Oid newNspId, bool isType);
+extern Oid GetConstraintByName(Oid relid, const char *conname);
#endif /* PG_CONSTRAINT_H */
/*
- * $PostgreSQL: pgsql/src/include/commands/comment.h,v 1.24 2009/06/11 14:49:11 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/comment.h,v 1.25 2009/10/12 19:49:24 adunstan Exp $
*
*-------------------------------------------------------------------------
*
extern void CreateSharedComments(Oid oid, Oid classoid, char *comment);
+extern char *GetComment(Oid oid, Oid classoid, int32 subid);
+
#endif /* COMMENT_H */
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.406 2009/10/12 18:10:51 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.407 2009/10/12 19:49:24 adunstan Exp $
*
*-------------------------------------------------------------------------
*/
int inhcount; /* number of times column is inherited */
bool is_local; /* column has local (non-inherited) def'n */
bool is_not_null; /* NOT NULL constraint specified? */
+ char storage; /* storage parameter of column */
Node *raw_default; /* default value (untransformed parse tree) */
Node *cooked_default; /* default value (transformed expr tree) */
List *constraints; /* other constraints on column */
{
NodeTag type;
RangeVar *relation;
- List *options; /* integer List of CreateStmtLikeOption */
+ bits32 options; /* bitmap of CreateStmtLikeOption */
} InhRelation;
typedef enum CreateStmtLikeOption
{
- CREATE_TABLE_LIKE_INCLUDING_DEFAULTS,
- CREATE_TABLE_LIKE_EXCLUDING_DEFAULTS,
- CREATE_TABLE_LIKE_INCLUDING_CONSTRAINTS,
- CREATE_TABLE_LIKE_EXCLUDING_CONSTRAINTS,
- CREATE_TABLE_LIKE_INCLUDING_INDEXES,
- CREATE_TABLE_LIKE_EXCLUDING_INDEXES
+ CREATE_TABLE_LIKE_DEFAULTS = 1 << 0,
+ CREATE_TABLE_LIKE_CONSTRAINTS = 1 << 1,
+ CREATE_TABLE_LIKE_INDEXES = 1 << 2,
+ CREATE_TABLE_LIKE_STORAGE = 1 << 3,
+ CREATE_TABLE_LIKE_COMMENTS = 1 << 4,
+ CREATE_TABLE_LIKE_ALL = 0xFFFFFFFF
} CreateStmtLikeOption;
/*
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.3 2009/09/22 23:43:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.4 2009/10/12 19:49:24 adunstan Exp $
*
*-------------------------------------------------------------------------
*/
PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD)
PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD)
PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD)
+PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD)
PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD)
PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD)
PG_KEYWORD("concurrently", CONCURRENTLY, UNRESERVED_KEYWORD)
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table cc1
drop cascades to table cc2
+-- including storage and comments
+CREATE TABLE t1 (a text CHECK (length(a) > 2) PRIMARY KEY, b text);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t1_pkey" for table "t1"
+CREATE INDEX t1_b_key ON t1 (b);
+CREATE INDEX t1_fnidx ON t1 ((a || b));
+COMMENT ON COLUMN t1.a IS 'A';
+COMMENT ON COLUMN t1.b IS 'B';
+COMMENT ON CONSTRAINT t1_a_check ON t1 IS 't1_a_check';
+COMMENT ON INDEX t1_pkey IS 'index pkey';
+COMMENT ON INDEX t1_b_key IS 'index b_key';
+COMMENT ON COLUMN t1_pkey.a IS 'index column pkey.a';
+COMMENT ON COLUMN t1_fnidx.pg_expression_1 IS 'index column fnidx';
+ALTER TABLE t1 ALTER COLUMN a SET STORAGE MAIN;
+CREATE TABLE t2 (c text);
+ALTER TABLE t2 ALTER COLUMN c SET STORAGE EXTERNAL;
+COMMENT ON COLUMN t2.c IS 'C';
+CREATE TABLE t3 (a text CHECK (length(a) < 5), c text);
+ALTER TABLE t3 ALTER COLUMN c SET STORAGE EXTERNAL;
+ALTER TABLE t3 ALTER COLUMN a SET STORAGE MAIN;
+COMMENT ON COLUMN t3.a IS 'A3';
+COMMENT ON COLUMN t3.c IS 'C';
+COMMENT ON CONSTRAINT t3_a_check ON t3 IS 't3_a_check';
+CREATE TABLE t4 (a text, c text);
+ALTER TABLE t4 ALTER COLUMN c SET STORAGE EXTERNAL;
+CREATE TABLE t12_storage (LIKE t1 INCLUDING STORAGE, LIKE t2 INCLUDING STORAGE);
+\d+ t12_storage
+ Table "public.t12_storage"
+ Column | Type | Modifiers | Storage | Description
+--------+------+-----------+----------+-------------
+ a | text | not null | main |
+ b | text | | extended |
+ c | text | | external |
+Has OIDs: no
+
+CREATE TABLE t12_comments (LIKE t1 INCLUDING COMMENTS, LIKE t2 INCLUDING COMMENTS);
+\d+ t12_comments
+ Table "public.t12_comments"
+ Column | Type | Modifiers | Storage | Description
+--------+------+-----------+----------+-------------
+ a | text | not null | extended | A
+ b | text | | extended | B
+ c | text | | extended | C
+Has OIDs: no
+
+CREATE TABLE t1_inh (LIKE t1 INCLUDING CONSTRAINTS INCLUDING COMMENTS) INHERITS (t1);
+NOTICE: merging column "a" with inherited definition
+NOTICE: merging column "b" with inherited definition
+NOTICE: merging constraint "t1_a_check" with inherited definition
+\d+ t1_inh
+ Table "public.t1_inh"
+ Column | Type | Modifiers | Storage | Description
+--------+------+-----------+----------+-------------
+ a | text | not null | main | A
+ b | text | | extended | B
+Check constraints:
+ "t1_a_check" CHECK (length(a) > 2)
+Inherits: t1
+Has OIDs: no
+
+SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 't1_inh'::regclass;
+ description
+-------------
+ t1_a_check
+(1 row)
+
+CREATE TABLE t13_inh () INHERITS (t1, t3);
+NOTICE: merging multiple inherited definitions of column "a"
+\d+ t13_inh
+ Table "public.t13_inh"
+ Column | Type | Modifiers | Storage | Description
+--------+------+-----------+----------+-------------
+ a | text | not null | main |
+ b | text | | extended |
+ c | text | | external |
+Check constraints:
+ "t1_a_check" CHECK (length(a) > 2)
+ "t3_a_check" CHECK (length(a) < 5)
+Inherits: t1,
+ t3
+Has OIDs: no
+
+CREATE TABLE t13_like (LIKE t3 INCLUDING CONSTRAINTS INCLUDING COMMENTS INCLUDING STORAGE) INHERITS (t1);
+NOTICE: merging column "a" with inherited definition
+\d+ t13_like
+ Table "public.t13_like"
+ Column | Type | Modifiers | Storage | Description
+--------+------+-----------+----------+-------------
+ a | text | not null | main | A3
+ b | text | | extended |
+ c | text | | external | C
+Check constraints:
+ "t1_a_check" CHECK (length(a) > 2)
+ "t3_a_check" CHECK (length(a) < 5)
+Inherits: t1
+Has OIDs: no
+
+SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 't13_like'::regclass;
+ description
+-------------
+ t3_a_check
+(1 row)
+
+CREATE TABLE t_all (LIKE t1 INCLUDING ALL);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t_all_pkey" for table "t_all"
+\d+ t_all
+ Table "public.t_all"
+ Column | Type | Modifiers | Storage | Description
+--------+------+-----------+----------+-------------
+ a | text | not null | main | A
+ b | text | | extended | B
+Indexes:
+ "t_all_pkey" PRIMARY KEY, btree (a)
+ "t_all_b_key" btree (b)
+ "t_all_key" btree ((a || b))
+Check constraints:
+ "t1_a_check" CHECK (length(a) > 2)
+Has OIDs: no
+
+SELECT c.relname, objsubid, description FROM pg_description, pg_index i, pg_class c WHERE classoid = 'pg_class'::regclass AND objoid = i.indexrelid AND c.oid = i.indexrelid AND i.indrelid = 't_all'::regclass ORDER BY c.relname, objsubid;
+ relname | objsubid | description
+-------------+----------+---------------------
+ t_all_b_key | 0 | index b_key
+ t_all_key | 1 | index column fnidx
+ t_all_pkey | 0 | index pkey
+ t_all_pkey | 1 | index column pkey.a
+(4 rows)
+
+CREATE TABLE inh_error1 () INHERITS (t1, t4);
+NOTICE: merging multiple inherited definitions of column "a"
+ERROR: inherited column "a" has a storage parameter conflict
+DETAIL: MAIN versus EXTENDED
+CREATE TABLE inh_error2 (LIKE t4 INCLUDING STORAGE) INHERITS (t1);
+NOTICE: merging column "a" with inherited definition
+ERROR: column "a" has a storage parameter conflict
+DETAIL: MAIN versus EXTENDED
+DROP TABLE t1, t2, t3, t4, t12_storage, t12_comments, t1_inh, t13_inh, t13_like, t_all;
alter table pp1 add column a2 int check (a2 > 0);
\d cc2
drop table pp1 cascade;
+
+-- including storage and comments
+CREATE TABLE t1 (a text CHECK (length(a) > 2) PRIMARY KEY, b text);
+CREATE INDEX t1_b_key ON t1 (b);
+CREATE INDEX t1_fnidx ON t1 ((a || b));
+COMMENT ON COLUMN t1.a IS 'A';
+COMMENT ON COLUMN t1.b IS 'B';
+COMMENT ON CONSTRAINT t1_a_check ON t1 IS 't1_a_check';
+COMMENT ON INDEX t1_pkey IS 'index pkey';
+COMMENT ON INDEX t1_b_key IS 'index b_key';
+COMMENT ON COLUMN t1_pkey.a IS 'index column pkey.a';
+COMMENT ON COLUMN t1_fnidx.pg_expression_1 IS 'index column fnidx';
+ALTER TABLE t1 ALTER COLUMN a SET STORAGE MAIN;
+
+CREATE TABLE t2 (c text);
+ALTER TABLE t2 ALTER COLUMN c SET STORAGE EXTERNAL;
+COMMENT ON COLUMN t2.c IS 'C';
+
+CREATE TABLE t3 (a text CHECK (length(a) < 5), c text);
+ALTER TABLE t3 ALTER COLUMN c SET STORAGE EXTERNAL;
+ALTER TABLE t3 ALTER COLUMN a SET STORAGE MAIN;
+COMMENT ON COLUMN t3.a IS 'A3';
+COMMENT ON COLUMN t3.c IS 'C';
+COMMENT ON CONSTRAINT t3_a_check ON t3 IS 't3_a_check';
+
+CREATE TABLE t4 (a text, c text);
+ALTER TABLE t4 ALTER COLUMN c SET STORAGE EXTERNAL;
+
+CREATE TABLE t12_storage (LIKE t1 INCLUDING STORAGE, LIKE t2 INCLUDING STORAGE);
+\d+ t12_storage
+CREATE TABLE t12_comments (LIKE t1 INCLUDING COMMENTS, LIKE t2 INCLUDING COMMENTS);
+\d+ t12_comments
+CREATE TABLE t1_inh (LIKE t1 INCLUDING CONSTRAINTS INCLUDING COMMENTS) INHERITS (t1);
+\d+ t1_inh
+SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 't1_inh'::regclass;
+CREATE TABLE t13_inh () INHERITS (t1, t3);
+\d+ t13_inh
+CREATE TABLE t13_like (LIKE t3 INCLUDING CONSTRAINTS INCLUDING COMMENTS INCLUDING STORAGE) INHERITS (t1);
+\d+ t13_like
+SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 't13_like'::regclass;
+
+CREATE TABLE t_all (LIKE t1 INCLUDING ALL);
+\d+ t_all
+SELECT c.relname, objsubid, description FROM pg_description, pg_index i, pg_class c WHERE classoid = 'pg_class'::regclass AND objoid = i.indexrelid AND c.oid = i.indexrelid AND i.indrelid = 't_all'::regclass ORDER BY c.relname, objsubid;
+
+CREATE TABLE inh_error1 () INHERITS (t1, t4);
+CREATE TABLE inh_error2 (LIKE t4 INCLUDING STORAGE) INHERITS (t1);
+
+DROP TABLE t1, t2, t3, t4, t12_storage, t12_comments, t1_inh, t13_inh, t13_like, t_all;