Re: CREATE TABLE LIKE INCLUDING INDEXES support - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: CREATE TABLE LIKE INCLUDING INDEXES support
Date
Msg-id 200704050308.l3538FF06436@momjian.us
Whole thread Raw
In response to CREATE TABLE LIKE INCLUDING INDEXES support  (Trevor Hardcastle <chizu@spicious.com>)
Responses Re: CREATE TABLE LIKE INCLUDING INDEXES support  (Gregory Stark <stark@enterprisedb.com>)
List pgsql-patches
Uh, shouldn't CREATE TABLE LIKE INCLUDING CONSTRAINTS already be including
any indexes in the parent table?

---------------------------------------------------------------------------

Trevor Hardcastle wrote:
> Greetings all,
>
> I wrote this patch about a week ago to introduce myself to coding on
> PostgreSQL. I wasn't entirely sure what the 'INCLUDING INDEXES' option
> was meant to do, so I held off submitting it until I could get around to
> asking about that and tweaking the documentation to reflect the patch.
> By useful coincidence the thread "Auto creation of Partitions" had this
> post in it, which made the intent of the option clear enough for me to
> go ahead and see what people think of this.
>
> Gregory Stark wrote:
> > "NikhilS" <nikkhils@gmail.com> writes:
> >
> >
> >> the intention is to use this information from the parent and make it a
> >> property of the child table. This will avoid the step for the user having to
> >> manually specify CREATE INDEX and the likes on all the children tables
> >> one-by-one.
> >>
> >
> > Missed the start of this thread. A while back I had intended to add WITH
> > INDEXES to CREATE TABLE LIKE. That would let you create a tale LIKE parent
> > WITH CONSTRAINTS WITH INDEXES and get pretty much a perfect table ready for
> > adding to the inheritance structure.
> >
> >
> >
> So, that's what this patch does. When a table is created with 'CREATE
> TABLE ... LIKE parent INCLUDING INDEXES'  this iterates over the parent
> table indexes looking for constraint indexes, and alters the
> CreateStmtContext to include equivalent indexes on the child table.
>
> This is probably a somewhat naive implementation, being a first attempt.
> I wasn't sure what sort of lock to place on the parent indexes or what
> tablespace the new indexes should be created in. Any help improving it
> would be appreciated.
>
> Thank you,
> -Trevor Hardcastle
>

> Index: src/backend/parser/analyze.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/parser/analyze.c,v
> retrieving revision 1.361
> diff -c -r1.361 analyze.c
> *** src/backend/parser/analyze.c    20 Feb 2007 17:32:16 -0000    1.361
> --- src/backend/parser/analyze.c    7 Mar 2007 01:43:12 -0000
> ***************
> *** 14,19 ****
> --- 14,20 ----
>   #include "postgres.h"
>
>   #include "access/heapam.h"
> + #include "access/genam.h"
>   #include "catalog/heap.h"
>   #include "catalog/index.h"
>   #include "catalog/namespace.h"
> ***************
> *** 40,45 ****
> --- 41,47 ----
>   #include "utils/acl.h"
>   #include "utils/builtins.h"
>   #include "utils/lsyscache.h"
> + #include "utils/relcache.h"
>   #include "utils/syscache.h"
>
>
> ***************
> *** 1345,1355 ****
>           }
>       }
>
> -     if (including_indexes)
> -         ereport(ERROR,
> -                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
> -                  errmsg("LIKE INCLUDING INDEXES is not implemented")));
> -
>       /*
>        * Insert the copied attributes into the cxt for the new table
>        * definition.
> --- 1347,1352 ----
> ***************
> *** 1448,1453 ****
> --- 1445,1519 ----
>       }
>
>       /*
> +      * Clone constraint indexes if requested.
> +      */
> +     if (including_indexes && relation->rd_rel->relhasindex)
> +     {
> +         List       *parent_index_list = RelationGetIndexList(relation);
> +         ListCell   *parent_index_scan;
> +
> +         foreach(parent_index_scan, parent_index_list)
> +         {
> +             Oid        parent_index_oid = lfirst_oid(parent_index_scan);
> +             Relation   parent_index;
> +
> +             parent_index = index_open(parent_index_oid, AccessShareLock);
> +
> +             /*
> +              * Create new unique or primary key indexes on the child.
> +              */
> +             if (parent_index->rd_index->indisunique || parent_index->rd_index->indisprimary)
> +             {
> +                 IndexInfo  *parent_index_info;
> +                 Constraint *n = makeNode(Constraint);
> +                 AttrNumber  parent_attno;
> +
> +                 parent_index_info = BuildIndexInfo(parent_index);
> +
> +                 if (parent_index->rd_index->indisprimary)
> +                 {
> +                     n->contype = CONSTR_PRIMARY;
> +                 }
> +                 else
> +                 {
> +                     n->contype = CONSTR_UNIQUE;
> +                 }
> +                 /* Let DefineIndex name it */
> +                 n->name = NULL;
> +                 n->raw_expr = NULL;
> +                 n->cooked_expr = NULL;
> +
> +                 /*
> +                  * Search through the possible index keys, and append
> +                  * the names of simple columns to the new index key list.
> +                  */
> +                 for (parent_attno = 1; parent_attno <= parent_index->rd_att->natts;
> +                      parent_attno++)
> +                 {
> +                     Form_pg_attribute attribute = parent_index->rd_att->attrs[parent_attno - 1];
> +                     char       *attributeName = NameStr(attribute->attname);
> +
> +                     /*
> +                      * Ignore dropped columns in the parent.
> +                      */
> +                     if (!attribute->attisdropped)
> +                         n->keys = lappend(n->keys,
> +                                           makeString(attributeName));
> +                 }
> +
> +                 /* Add the new index constraint to the create context */
> +                 cxt->ixconstraints = lappend(cxt->ixconstraints, n);
> +
> +                 ereport(NOTICE,
> +                         (errmsg("Index \"%s\" cloned.",
> +                                 RelationGetRelationName(parent_index))));
> +             }
> +
> +             relation_close(parent_index, AccessShareLock);
> +         }
> +     }
> +
> +     /*
>        * Close the parent rel, but keep our AccessShareLock on it until xact
>        * commit.    That will prevent someone else from deleting or ALTERing the
>        * parent before the child is committed.
> Index: doc/src/sgml/ref/create_table.sgml
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/create_table.sgml,v
> retrieving revision 1.107
> diff -c -r1.107 create_table.sgml
> *** doc/src/sgml/ref/create_table.sgml    1 Feb 2007 00:28:18 -0000    1.107
> --- doc/src/sgml/ref/create_table.sgml    7 Mar 2007 01:43:13 -0000
> ***************
> *** 23,29 ****
>   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 class="PARAMETER">column_constraint</replaceable> [ ... ] ] 
>       | <replaceable>table_constraint</replaceable>
> !     | LIKE <replaceable>parent_table</replaceable> [ { INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS } ] ... }
>       [, ... ]
>   ] )
>   [ INHERITS ( <replaceable>parent_table</replaceable> [, ... ] ) ]
> --- 23,29 ----
>   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 class="PARAMETER">column_constraint</replaceable> [ ... ] ] 
>       | <replaceable>table_constraint</replaceable>
> !     | LIKE <replaceable>parent_table</replaceable> [ { INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS | INDEXES }
]... } 
>       [, ... ]
>   ] )
>   [ INHERITS ( <replaceable>parent_table</replaceable> [, ... ] ) ]
> ***************
> *** 237,243 ****
>      </varlistentry>
>
>      <varlistentry>
> !     <term><literal>LIKE <replaceable>parent_table</replaceable> [ { INCLUDING | EXCLUDING } { DEFAULTS |
CONSTRAINTS} ]</literal></term> 
>       <listitem>
>        <para>
>         The <literal>LIKE</literal> clause specifies a table from which
> --- 237,243 ----
>      </varlistentry>
>
>      <varlistentry>
> !     <term><literal>LIKE <replaceable>parent_table</replaceable> [ { INCLUDING | EXCLUDING | INDEXES } { DEFAULTS |
CONSTRAINTS} ]</literal></term> 
>       <listitem>
>        <para>
>         The <literal>LIKE</literal> clause specifies a table from which
> ***************
> *** 260,269 ****
>        <para>
>         Not-null constraints are always copied to the new table.
>         <literal>CHECK</literal> constraints will only be copied if
> !       <literal>INCLUDING CONSTRAINTS</literal> is specified; other types of
> !       constraints will never be copied. Also, no distinction is made between
> !       column constraints and table constraints — when constraints are
> !       requested, all check constraints are copied.
>        </para>
>        <para>
>         Note also that unlike <literal>INHERITS</literal>, copied columns and
> --- 260,271 ----
>        <para>
>         Not-null constraints are always copied to the new table.
>         <literal>CHECK</literal> constraints will only be copied if
> !       <literal>INCLUDING CONSTRAINTS</literal> is specified. UNIQUE and
> !       PRIMARY KEY constraints will only be copied if
> !       <literal>INCLUDING INDEXES</literal> is specified. Also, no
> !       distinction is made between column constraints and table constraints
> !       — when constraints are requested, all check constraints are
> !       copied.
>        </para>
>        <para>
>         Note also that unlike <literal>INHERITS</literal>, copied columns and
> Index: src/test/regress/sql/inherit.sql
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/inherit.sql,v
> retrieving revision 1.10
> diff -c -r1.10 inherit.sql
> *** src/test/regress/sql/inherit.sql    27 Jun 2006 03:43:20 -0000    1.10
> --- src/test/regress/sql/inherit.sql    7 Mar 2007 01:43:13 -0000
> ***************
> *** 155,160 ****
> --- 155,164 ----
>   INSERT INTO inhg VALUES ('x', 'foo',  'y');  /* fails due to constraint */
>   SELECT * FROM inhg; /* Two records with three columns in order x=x, xx=text, y=y */
>   DROP TABLE inhg;
> + CREATE TABLE inhg (x text, LIKE inhx INCLUDING INDEXES, y text); /* Copies indexes */
> + INSERT INTO inhg VALUES ('x', 'text', 'y'); /* Succeeds */
> + INSERT INTO inhg VALUES ('x', 'text', 'y'); /* Fails -- Unique constraints are copied */
> + DROP TABLE inhg;
>
>
>   -- Test changing the type of inherited columns
> Index: src/test/regress/expected/inherit.out
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/inherit.out,v
> retrieving revision 1.20
> diff -c -r1.20 inherit.out
> *** src/test/regress/expected/inherit.out    27 Jun 2006 03:43:20 -0000    1.20
> --- src/test/regress/expected/inherit.out    7 Mar 2007 01:43:14 -0000
> ***************
> *** 633,638 ****
> --- 633,645 ----
>   (2 rows)
>
>   DROP TABLE inhg;
> + CREATE TABLE inhg (x text, LIKE inhx INCLUDING INDEXES, y text); /* Copies indexes */
> + NOTICE:  Index "inhx_pkey" cloned.
> + NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "inhg_pkey" for table "inhg"
> + INSERT INTO inhg VALUES ('x', 'text', 'y'); /* Succeeds */
> + INSERT INTO inhg VALUES ('x', 'text', 'y'); /* Fails -- Unique constraints are copied */
> + ERROR:  duplicate key violates unique constraint "inhg_pkey"
> + DROP TABLE inhg;
>   -- Test changing the type of inherited columns
>   insert into d values('test','one','two','three');
>   alter table a alter column aa type integer using bit_length(aa);

>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: if posting/reading through Usenet, please send an appropriate
>        subscribe-nomail command to majordomo@postgresql.org so that your
>        message can get through to the mailing list cleanly

--
  Bruce Momjian  <bruce@momjian.us>          http://momjian.us
  EnterpriseDB                               http://www.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +

pgsql-patches by date:

Previous
From: Alvaro Herrera
Date:
Subject: Re: autovacuum multiworkers, patch 5
Next
From: Gregory Stark
Date:
Subject: Re: CREATE TABLE LIKE INCLUDING INDEXES support