Copy column storage parameters on CREATE TABLE LIKE/INHERITS
Here is an updated version of the "Copy storage parameters" patch.
http://archives.postgresql.org/pgsql-hackers/2008-07/msg01417.php
This patch copies only column storage parameters and does not copy
reloptions as a result of the discussion, in which reloptions should
not be copied because LIKE and INHERITS are not table definitions,
but column definitions.
Copying reloptions (or copying just table's definition) might be useful
in some cases, but it should be done by another independent patch.
Inheriting column storage parameters is useful if we duplicate an
existing table. CREATE TABLE AS is useful to avoid WALs in that time:
CREATE TABLE (LIKE target) WITH (<same as the target table>)
AS SELECT * FROM target;
However, we cannot execute ALTER COLUMN SET STORAGE after creating the
new table and before inserting, because there are no time to execute
commands between them. So we need some methods to set column storage
parameters at creating a table.
Regards,
---
ITAGAKI Takahiro
NTT Open Source Software Center
Attachments:
inherits-column-params.patchapplication/octet-stream; name=inherits-column-params.patchDownload
diff -cpr head/doc/src/sgml/ref/create_table.sgml inherits-column-params/doc/src/sgml/ref/create_table.sgml
*** head/doc/src/sgml/ref/create_table.sgml Sat May 10 08:32:04 2008
--- inherits-column-params/doc/src/sgml/ref/create_table.sgml Tue Aug 12 17:08:12 2008
*************** and <replaceable class="PARAMETER">table
*** 229,234 ****
--- 229,237 ----
will always be chosen for it.
</para>
+ <para>
+ Column storage parameters are also copied from parent tables.
+ </para>
<!--
<para>
<productname>PostgreSQL</> automatically allows the
*************** and <replaceable class="PARAMETER">table
*** 251,257 ****
<para>
The <literal>LIKE</literal> clause specifies a table from which
the new table automatically copies all column names, their data types,
! and their not-null constraints.
</para>
<para>
Unlike <literal>INHERITS</literal>, the new table and original table
--- 254,260 ----
<para>
The <literal>LIKE</literal> clause specifies a table from which
the new table automatically copies all column names, their data types,
! their not-null constraints, and their column storage parameters.
</para>
<para>
Unlike <literal>INHERITS</literal>, the new table and original table
diff -cpr head/src/backend/parser/parse_utilcmd.c inherits-column-params/src/backend/parser/parse_utilcmd.c
*** head/src/backend/parser/parse_utilcmd.c Wed Jul 16 10:30:22 2008
--- inherits-column-params/src/backend/parser/parse_utilcmd.c Tue Aug 12 17:08:12 2008
*************** static void transformFKConstraints(Parse
*** 114,119 ****
--- 114,121 ----
static void transformConstraintAttrs(List *constraintList);
static void transformColumnType(ParseState *pstate, ColumnDef *column);
static void setSchemaName(char *context_schema, char **stmt_schema_name);
+ static AlterTableStmt *appendSetStorageCmd(AlterTableStmt *stmt,
+ RangeVar *rel, Form_pg_attribute attr);
/*
*************** transformCreateStmt(CreateStmt *stmt, co
*** 138,143 ****
--- 140,146 ----
List *result;
List *save_alist;
ListCell *elements;
+ AlterTableStmt *alterstmt = NULL;
/*
* We must not scribble on the passed-in CreateStmt, so copy it. (This is
*************** transformCreateStmt(CreateStmt *stmt, co
*** 215,220 ****
--- 218,251 ----
}
}
+ /* Copy column storage parameters. */
+ foreach(elements, cxt.inhRelations)
+ {
+ RangeVar *inh = lfirst(elements);
+ Relation rel;
+ TupleDesc tupleDesc;
+ int i;
+
+ Assert(IsA(inh, RangeVar));
+ rel = heap_openrv(inh, AccessShareLock);
+ if (rel->rd_rel->relkind != RELKIND_RELATION)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("inherited relation \"%s\" is not a table",
+ inh->relname)));
+
+ /* Copy column storage parameter. */
+ tupleDesc = RelationGetDescr(rel);
+ for (i = 0; i < tupleDesc->natts; i++)
+ alterstmt = appendSetStorageCmd(alterstmt, cxt.relation,
+ tupleDesc->attrs[i]);
+
+ heap_close(rel, NoLock);
+ }
+
+ if (alterstmt)
+ cxt.alist = lappend(cxt.alist, alterstmt);
+
/*
* transformIndexConstraints wants cxt.alist to contain only index
* statements, so transfer anything we already have into save_alist.
*************** transformInhRelation(ParseState *pstate,
*** 545,550 ****
--- 576,582 ----
bool including_constraints = false;
bool including_indexes = false;
ListCell *elem;
+ AlterTableStmt *alterstmt = NULL;
relation = heap_openrv(inhRelation->relation, AccessShareLock);
*************** transformInhRelation(ParseState *pstate,
*** 663,670 ****
--- 695,708 ----
def->cooked_default = pstrdup(this_default);
}
+
+ /* Copy column storage parameter. */
+ alterstmt = appendSetStorageCmd(alterstmt, cxt->relation, attribute);
}
+ if (alterstmt)
+ cxt->alist = lappend(cxt->alist, alterstmt);
+
/*
* Copy CHECK constraints if requested, being careful to adjust attribute
* numbers
*************** setSchemaName(char *context_schema, char
*** 2105,2108 ****
--- 2143,2201 ----
errmsg("CREATE specifies a schema (%s) "
"different from the one being created (%s)",
*stmt_schema_name, context_schema)));
+ }
+
+ /*
+ * Append ALTER COLUMN SET STORAGE command to stmt if needed.
+ */
+ static AlterTableStmt *
+ appendSetStorageCmd(AlterTableStmt *stmt, RangeVar *rel, Form_pg_attribute attr)
+ {
+ char *storage;
+ AlterTableCmd *altercmd;
+
+ /* Ignore dropped columns. */
+ if (attr->attisdropped)
+ return stmt;
+
+ /* No command needed if the default storage paramater is used. */
+ if (attr->attstorage == get_typstorage(attr->atttypid))
+ return stmt;
+
+ switch (attr->attstorage)
+ {
+ case 'p':
+ storage = "plain";
+ break;
+ case 'm':
+ storage = "main";
+ break;
+ case 'x':
+ storage = "extended";
+ break;
+ case 'e':
+ storage = "external";
+ break;
+ default:
+ elog(ERROR, "unexpected storage type: %c", attr->attstorage);
+ storage = NULL;
+ break;
+ }
+
+ altercmd = makeNode(AlterTableCmd);
+ altercmd->subtype = AT_SetStorage;
+ altercmd->name = pstrdup(NameStr(attr->attname));
+ altercmd->def = (Node *) makeString(storage);
+
+ /* SET STORAGE commands are merged into one AlterTableStmt. */
+ if (stmt == NULL)
+ {
+ stmt = makeNode(AlterTableStmt);
+ stmt->relation = rel;
+ stmt->cmds = NIL;
+ stmt->relkind = OBJECT_TABLE;
+ }
+ stmt->cmds = lappend(stmt->cmds, altercmd);
+
+ return stmt;
}
diff -cpr head/src/test/regress/expected/inherit.out inherits-column-params/src/test/regress/expected/inherit.out
*** head/src/test/regress/expected/inherit.out Thu Jun 12 06:53:49 2008
--- inherits-column-params/src/test/regress/expected/inherit.out Tue Aug 12 17:08:12 2008
*************** drop table pp1 cascade;
*** 904,906 ****
--- 904,927 ----
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table cc1
drop cascades to table cc2
+ -- Test inheritance with column storage parameters
+ CREATE TABLE table_with_stg (a text) WITH (oids);
+ ALTER TABLE table_with_stg ALTER COLUMN a SET STORAGE main;
+ CREATE TABLE table_inh () INHERITS (table_with_stg);
+ \d+ table_inh
+ Table "public.table_inh"
+ Column | Type | Modifiers | Storage | Description
+ --------+------+-----------+---------+-------------
+ a | text | | main |
+ Inherits: table_with_stg
+ Has OIDs: yes
+
+ CREATE TABLE table_like (LIKE table_with_stg);
+ \d+ table_like
+ Table "public.table_like"
+ Column | Type | Modifiers | Storage | Description
+ --------+------+-----------+---------+-------------
+ a | text | | main |
+ Has OIDs: no
+
+ DROP TABLE table_with_stg, table_inh, table_like CASCADE;
diff -cpr head/src/test/regress/sql/inherit.sql inherits-column-params/src/test/regress/sql/inherit.sql
*** head/src/test/regress/sql/inherit.sql Sat May 10 08:32:05 2008
--- inherits-column-params/src/test/regress/sql/inherit.sql Tue Aug 12 17:08:12 2008
*************** create table cc2(f4 float) inherits(pp1,
*** 276,278 ****
--- 276,287 ----
alter table pp1 add column a2 int check (a2 > 0);
\d cc2
drop table pp1 cascade;
+
+ -- Test inheritance with column storage parameters
+ CREATE TABLE table_with_stg (a text) WITH (oids);
+ ALTER TABLE table_with_stg ALTER COLUMN a SET STORAGE main;
+ CREATE TABLE table_inh () INHERITS (table_with_stg);
+ \d+ table_inh
+ CREATE TABLE table_like (LIKE table_with_stg);
+ \d+ table_like
+ DROP TABLE table_with_stg, table_inh, table_like CASCADE;
Greetings,
I've reviewed the patch here:
http://archives.postgresql.org/message-id/20080812170932.8E65.52131E4D@oss.ntt.co.jp
and am happy to report that it looks to be in good order. It has
documentation and regression updates, is in context diff format,
patches against current CVS with only some minor fuzz, and appears to
work as advertised. I looked over the patch and could easily follow
what was going on, did some additional testing beyond the regression
tests, and reviewed the documentation changes.
My only comment on this patch is that the documentation updates might
include a link back to Section 53.2 for more information, and/or to
the SET STORAGE portion of the alter table/alter column command
documentation, since the only other 'storage' reference in create
table's documentation is about table storage parameters.
Thanks!
Stephen
ITAGAKI Takahiro <itagaki.takahiro@oss.ntt.co.jp> writes:
Here is an updated version of the "Copy storage parameters" patch.
http://archives.postgresql.org/pgsql-hackers/2008-07/msg01417.php
I looked this over and feel that it still needs work. The
implementation seems appropriate for columns coming from LIKE clauses,
but there are two big issues for columns coming from inheritance parent
tables:
* The patch opens and acquires lock on the parent relations far too
early. That is supposed to happen in DefineRelation, which among other
things contains the appropriate permissions check. It would be possible
to use this patch to hold AccessShareLock for a long time on tables you
have no permissions for.
* There is no consideration for merging of similarly-named columns
coming from different parent tables. The general approach taken in
DefineRelation is to throw an error if there are incompatible properties
in columns to be merged, and I think the same should happen for storage
properties. What you actually would get, here, is that some random one
of the columns would "win".
In short, I think you need two implementations, one for LIKE and one
for INHERITS, and the appropriate place to tackle the latter case is in
DefineRelation (or even more specifically, MergeAttributes).
Also I concur with Stephen Frost's suggestion to add a couple of
cross-references to the documentation patches.
regards, tom lane