Ensure CREATE TABLE (LIKE INCLUDING ALL) honors distribution strategy
authorPavan Deolasee <[email protected]>
Wed, 10 Oct 2018 10:51:40 +0000 (16:21 +0530)
committerPavan Deolasee <[email protected]>
Wed, 10 Oct 2018 10:58:21 +0000 (16:28 +0530)
We introduce two INCLUDING/EXCLUDING options to copy the distribution strategy
and the target nodes. It's quite unlikely that someone would create a LIKE
table but won't want to copy the distribution information, but it gives user
flexibility to do that. Since we did not want to add more keywords, we simply
used DISTRIBUTE and NODE, though DISTRIBUTION and NODES may have been better
names.

doc/src/sgml/ref/create_table.sgml
src/backend/parser/gram.y
src/backend/parser/parse_utilcmd.c
src/include/nodes/parsenodes.h
src/test/regress/expected/create_table_like.out
src/test/regress/sql/create_table_like.sql

index 846e4b36a6ac162e4bc697e266a786398c30954e..952ddeab10872b6c481cd87bcfd152b370efc728 100755 (executable)
@@ -556,6 +556,14 @@ FROM ( { <replaceable class="PARAMETER">numeric_literal</replaceable> | <replace
       Extended statistics are copied to the new table if
       <literal>INCLUDING STATISTICS</literal> is specified.
      </para>
+     <para>
+      Distribution strategy is copied to the new table if
+      <literal>INCLUDING DISTRIBUTE</literal> is specified.
+     </para>
+     <para>
+      Distribution nodes are copied to the new table if
+      <literal>INCLUDING NODE</literal> is specified.
+     </para>
      <para>
       Indexes, <literal>PRIMARY KEY</>, <literal>UNIQUE</>,
       and <literal>EXCLUDE</> constraints on the original table will be
@@ -581,7 +589,7 @@ FROM ( { <replaceable class="PARAMETER">numeric_literal</replaceable> | <replace
      </para>
      <para>
       <literal>INCLUDING ALL</literal> is an abbreviated form of
-      <literal>INCLUDING COMMENTS INCLUDING CONSTRAINTS INCLUDING DEFAULTS INCLUDING IDENTITY INCLUDING INDEXES INCLUDING STATISTICS INCLUDING STORAGE</literal>.
+      <literal>INCLUDING COMMENTS INCLUDING CONSTRAINTS INCLUDING DEFAULTS INCLUDING IDENTITY INCLUDING INDEXES INCLUDING STATISTICS INCLUDING STORAGE INCLUDING DISTRIBUTE INCLUDING NODE</literal>.
      </para>
      <para>
       Note that unlike <literal>INHERITS</literal>, columns and
index 68e0a265d77f286b218fb92c7bdabec77f792054..eb29f888fd340805111174711bf7e2a719d5f33a 100644 (file)
@@ -3637,6 +3637,8 @@ TableLikeOption:
                                | INDEXES                       { $$ = CREATE_TABLE_LIKE_INDEXES; }
                                | STATISTICS            { $$ = CREATE_TABLE_LIKE_STATISTICS; }
                                | STORAGE                       { $$ = CREATE_TABLE_LIKE_STORAGE; }
+                               | DISTRIBUTE            { $$ = CREATE_TABLE_LIKE_DISTRIBUTE; }
+                               | NODE                          { $$ = CREATE_TABLE_LIKE_NODE; }
                                | ALL                           { $$ = CREATE_TABLE_LIKE_ALL; }
                ;
 
index 44ab471c6220a40ad7ebb85a04bf762b808da11e..a5c64d0c8ed702f55675b08f771335d407a7fc6a 100644 (file)
@@ -116,11 +116,15 @@ typedef struct
        List       *alist;                      /* "after list" of things to do after creating
                                                                 * the table */
        IndexStmt  *pkey;                       /* PRIMARY KEY index, if any */
+
 #ifdef PGXC
        FallbackSrc fallback_source;
        List       *fallback_dist_cols;
-       DistributeBy    *distributeby;          /* original distribute by column of CREATE TABLE */
-       PGXCSubCluster  *subcluster;            /* original subcluster option of CREATE TABLE */
+
+       /* original or derived distribute by column of CREATE TABLE */
+       DistributeBy    *distributeby;
+       /* original or derived subcluster option of CREATE TABLE */
+       PGXCSubCluster  *subcluster;
 #endif
        bool            ispartitioned;  /* true if table is partitioned */
        PartitionBoundSpec *partbound;  /* transformed FOR VALUES */
@@ -473,6 +477,11 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
        stmt->tableElts = cxt.columns;
        stmt->constraints = cxt.ckconstraints;
 
+       if (stmt->distributeby == NULL)
+               stmt->distributeby = cxt.distributeby;
+       if (stmt->subcluster == NULL)
+               stmt->subcluster = cxt.subcluster;
+
        result = lappend(cxt.blist, stmt);
        result = list_concat(result, cxt.alist);
        result = list_concat(result, save_alist);
@@ -1111,6 +1120,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
        AclResult       aclresult;
        char       *comment;
        ParseCallbackState pcbstate;
+       RelationLocInfo *rel_loc_info;
 
        setup_parser_errposition_callback(&pcbstate, cxt->pstate,
                                                                          table_like_clause->relation->location);
@@ -1174,6 +1184,40 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
                                                   RelationGetRelationName(relation));
        }
 
+       rel_loc_info = RelationGetLocInfo(relation);
+
+       if ((table_like_clause->options & CREATE_TABLE_LIKE_DISTRIBUTE) &&
+               (cxt->distributeby == NULL) &&
+               (rel_loc_info != NULL))
+       {
+               cxt->distributeby = makeNode(DistributeBy);
+               switch (rel_loc_info->locatorType)
+               {
+                       case LOCATOR_TYPE_HASH:
+                               cxt->distributeby->disttype = DISTTYPE_HASH;
+                               cxt->distributeby->colname = pstrdup(rel_loc_info->partAttrName);
+                               break;
+                       case LOCATOR_TYPE_MODULO:
+                               cxt->distributeby->disttype = DISTTYPE_MODULO;
+                               cxt->distributeby->colname = pstrdup(rel_loc_info->partAttrName);
+                               break;
+                       case LOCATOR_TYPE_RROBIN:
+                               cxt->distributeby->disttype = DISTTYPE_ROUNDROBIN;
+                               break;
+                       case LOCATOR_TYPE_REPLICATED:
+                               cxt->distributeby->disttype = DISTTYPE_REPLICATION;
+                               break;
+               }
+       }
+
+       if ((table_like_clause->options & CREATE_TABLE_LIKE_NODE) &&
+               (cxt->subcluster == NULL) &&
+               (rel_loc_info != NULL))
+       {
+               if (rel_loc_info->rl_nodeList)
+                       cxt->subcluster = makeSubCluster(rel_loc_info->rl_nodeList);
+       }
+
        tupleDesc = RelationGetDescr(relation);
        constr = tupleDesc->constr;
 
index b47e0b626171e2d3a2a066625c3d2232873a474c..9baa210971209ab4038cdd4a34d77a9210651633 100644 (file)
@@ -681,6 +681,8 @@ typedef enum TableLikeOption
        CREATE_TABLE_LIKE_STORAGE = 1 << 4,
        CREATE_TABLE_LIKE_COMMENTS = 1 << 5,
        CREATE_TABLE_LIKE_STATISTICS = 1 << 6,
+       CREATE_TABLE_LIKE_DISTRIBUTE = 1 << 7,
+       CREATE_TABLE_LIKE_NODE = 1 << 8,
        CREATE_TABLE_LIKE_ALL = PG_INT32_MAX
 } TableLikeOption;
 
index 555e8daaddf76343641df01837aeca6a0f5e7cd5..ca25edb7f56c8bc288bc930ee42596ff38f3bbd9 100644 (file)
@@ -336,3 +336,70 @@ SELECT oid FROM like_test5;
 
 DROP TABLE has_oid, no_oid, like_test, like_test2, like_test3,
   like_test4, like_test5;
+-- xl tests
+CREATE TABLE like_test6 (a INT, b INT, c TEXT) DISTRIBUTE BY HASH(b);
+CREATE TABLE like_test7 (LIKE like_test6 INCLUDING ALL);
+\d+ like_test7
+                                 Table "public.like_test7"
+ Column |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a      | integer |           |          |         | plain    |              | 
+ b      | integer |           |          |         | plain    |              | 
+ c      | text    |           |          |         | extended |              | 
+Distribute By: HASH(b)
+Location Nodes: ALL DATANODES
+
+DROP TABLE like_test7;
+CREATE TABLE like_test7 (LIKE like_test6 INCLUDING DISTRIBUTE);
+\d+ like_test7
+                                 Table "public.like_test7"
+ Column |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a      | integer |           |          |         | plain    |              | 
+ b      | integer |           |          |         | plain    |              | 
+ c      | text    |           |          |         | extended |              | 
+Distribute By: HASH(b)
+Location Nodes: ALL DATANODES
+
+DROP TABLE like_test7;
+-- explicit distribution clause overwrites like clause
+CREATE TABLE like_test7 (LIKE like_test6 INCLUDING DISTRIBUTE) DISTRIBUTE BY REPLICATION;
+\d+ like_test7
+                                 Table "public.like_test7"
+ Column |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a      | integer |           |          |         | plain    |              | 
+ b      | integer |           |          |         | plain    |              | 
+ c      | text    |           |          |         | extended |              | 
+Distribute By: REPLICATION
+Location Nodes: ALL DATANODES
+
+DROP TABLE like_test7;
+DROP TABLE like_test6;
+CREATE TABLE like_test6 (a INT, b INT, c TEXT) DISTRIBUTE BY HASH(b) TO NODE (datanode_1);
+CREATE TABLE like_test7 (LIKE like_test6 INCLUDING DISTRIBUTE INCLUDING NODE);
+\d+ like_test7
+                                 Table "public.like_test7"
+ Column |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a      | integer |           |          |         | plain    |              | 
+ b      | integer |           |          |         | plain    |              | 
+ c      | text    |           |          |         | extended |              | 
+Distribute By: HASH(b)
+Location Nodes: datanode_1
+
+DROP TABLE like_test7;
+-- check if excluding works ok
+CREATE TABLE like_test7 (LIKE like_test6 INCLUDING DISTRIBUTE EXCLUDING NODE);
+\d+ like_test7
+                                 Table "public.like_test7"
+ Column |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a      | integer |           |          |         | plain    |              | 
+ b      | integer |           |          |         | plain    |              | 
+ c      | text    |           |          |         | extended |              | 
+Distribute By: HASH(b)
+Location Nodes: ALL DATANODES
+
+DROP TABLE like_test7;
+DROP TABLE like_test6;
index a8a3e80873517931120206589acd27391ff06094..98699798e515f5647c2fa6b3e78ed223e19887fa 100644 (file)
@@ -152,3 +152,26 @@ CREATE TABLE like_test5 (z INTEGER, LIKE no_oid) WITH OIDS;
 SELECT oid FROM like_test5;
 DROP TABLE has_oid, no_oid, like_test, like_test2, like_test3,
   like_test4, like_test5;
+
+-- xl tests
+CREATE TABLE like_test6 (a INT, b INT, c TEXT) DISTRIBUTE BY HASH(b);
+CREATE TABLE like_test7 (LIKE like_test6 INCLUDING ALL);
+\d+ like_test7
+DROP TABLE like_test7;
+CREATE TABLE like_test7 (LIKE like_test6 INCLUDING DISTRIBUTE);
+\d+ like_test7
+DROP TABLE like_test7;
+-- explicit distribution clause overwrites like clause
+CREATE TABLE like_test7 (LIKE like_test6 INCLUDING DISTRIBUTE) DISTRIBUTE BY REPLICATION;
+\d+ like_test7
+DROP TABLE like_test7;
+DROP TABLE like_test6;
+CREATE TABLE like_test6 (a INT, b INT, c TEXT) DISTRIBUTE BY HASH(b) TO NODE (datanode_1);
+CREATE TABLE like_test7 (LIKE like_test6 INCLUDING DISTRIBUTE INCLUDING NODE);
+\d+ like_test7
+DROP TABLE like_test7;
+-- check if excluding works ok
+CREATE TABLE like_test7 (LIKE like_test6 INCLUDING DISTRIBUTE EXCLUDING NODE);
+\d+ like_test7
+DROP TABLE like_test7;
+DROP TABLE like_test6;