Merge lp:~laurynas-biveinis/percona-server/tokudb-multiple-clust-keys into lp:percona-server/5.6

Proposed by Laurynas Biveinis
Status: Superseded
Proposed branch: lp:~laurynas-biveinis/percona-server/tokudb-multiple-clust-keys
Merge into: lp:percona-server/5.6
Diff against target: 576 lines (+313/-28)
14 files modified
include/my_base.h (+3/-1)
include/mysql_com.h (+2/-0)
mysql-test/r/tokudb_clustering_key_grammar.result (+73/-0)
mysql-test/t/tokudb_clustering_key_grammar.test (+99/-0)
sql/handler.h (+5/-0)
sql/lex.h (+1/-0)
sql/sql_class.h (+2/-1)
sql/sql_parse.cc (+12/-5)
sql/sql_show.cc (+3/-0)
sql/sql_table.cc (+17/-2)
sql/sql_yacc.yy (+56/-13)
sql/table.cc (+29/-4)
sql/unireg.cc (+9/-1)
tests/mysql_client_test.c (+2/-1)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-server/tokudb-multiple-clust-keys
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Needs Fixing
Laurynas Biveinis Pending
Review via email: mp+204305@code.launchpad.net

This proposal supersedes a proposal from 2014-01-10.

This proposal has been superseded by a proposal from 2014-02-26.

Description of the change

2nd MP:

- Extended the testcase to test CREATE CLUSTERING INDEX ON, to test
  CLUSTERING in combination with UNIQUE (and CONSTRAINT if UNIQUE),
  to test LOCK and ALGORITHM clauses for ALTER TABLE ADD INDEX, and
  to test the same clauses without CLUSTERING.
- Declare new handlerton flag HTON_SUPPORTS_CLUSTERED_KEYS.
- Assign values to enum Key::Keytype to support or'ing of enum
  constants.
- In mysql_prepare_create_table(), allow presence of and handle
  Key::CLUSTERING and Key::UNIQUE in a same key->type. Check for
  HTON_SUPPORTS_CLUSTERED_KEYS if Key::CLUSTERING found, and return
  HA_ILLEGAL_HA_CREATE_OPTION if unsupported.
- In mysql_prepare_alter_table(), handle both HA_CLUSTERING and
  HA_NOSAME if both present in the same key_info->flags.
- In parser, replace opt_unique clause with opt_unique_or_clustering
  that allows UNIQUE, CLUSTERING, and a combination of the two where
  previously only UNIQUE was allowed in key definitions and CREATE
  INDEX statement. This also fixes a bug from the previous approach
  which did not allow ALGORITHM and LOCK clauses for ALTER TABLE
  ... CLUSTERING ...

http://jenkins.percona.com/job/percona-server-5.6-param/494/

1st MP:

    Add support for CLUSTERING key type that is a clustering secondary
    key, that is, the whole of the row can be accessed through the index
    without going through the primary clustered index. This implements
    the query parser and index definition persistence bits,
    https://blueprints.launchpad.net/percona-server/+spec/multiple-clustering-keys.

    - New lexer symbol CLUSTERING, new key type in the grammar CREATE TABLE and
      ALTER TABLE ADD INDEX clauses.
    - New key type Key::Keytype::CLUSTERING, handle it in
      INFORMATION_SCHEMA.TABLES, write it out to FRM as a combination of
      spatial and fulltext key types, handle this combination on FRM
      read. This is to avoid a FRM format change.
    - New testcase tokudb_clustering_key_grammar.

http://jenkins.percona.com/job/percona-server-5.6-param/473/

To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

- s/INFORMATION_SCHEMA.TABLES/SHOW CREATE TABLE/ in the revision comment

- I don’t think we should allow creation of non-TokuDB tables with
  secondary clustering keys. Otherwise once the optimizer support is
  reviewed and merged, we will get optimizer making incorrect
  assumptions about secondary clustering keys for tables that don’t
  actually implement it. On top of that, bad and hard-to-diagnose
  things may happen on downgrade or migration to another server flavor;

- I see there’s no support for UNIQUE CLUSTERING KEYs. Let’s fix it if
  it’s an oversight, or document if it’s a known limitation?

- any specific reasons to add another reserved keyword to the parser?

review: Needs Fixing
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal

Grammar rules for CLUSTERING do not include opt_index_lock_algorithm, which suggests that

ALTER TABLE t1 ADD CLUSTERING INDEX b (b), LOCK=EXCLUSIVE, ALGORITHM=COPY;

syntax is not supported. It probably should be.

review: Needs Fixing
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal

CREATE CLUSTERING INDEX b ON t1 (b)

syntax is not tested by the testcase.

CREATE CLUSTERING INDEX b ON t1 (b) LOCK=EXCLUSIVE ALGORITHM=COPY

fails with a parse error due to that missing opt_index_lock_algorithm.

review: Needs Fixing
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal

> - s/INFORMATION_SCHEMA.TABLES/SHOW CREATE TABLE/ in the revision
> comment

Fixed.

> - I don’t think we should allow creation of non-TokuDB tables with
> secondary clustering keys. Otherwise once the optimizer support is
> reviewed and merged, we will get optimizer making incorrect
> assumptions about secondary clustering keys for tables that don’t
> actually implement it. On top of that, bad and hard-to-diagnose
> things may happen on downgrade or migration to another server
> flavor;

I agree and this was how I implemented it the first time before
Tokutek asked me to change to be treated as a hint. I didn't think of
downgrade/migration issues then or I wouldn't have changed. (I don't
see how the optimizer could make incorrect assumptions because no
other storage engine would return HA_CLUSTERING in index_flags()).

Added a handlerton flag HTON_SUPPORTS_CLUSTERED_KEYS. This is
different from e.g. HA_CAN_RTREE etc, which are handler flags, but the
property of supporting clustered keys seems to me to be global and not
of table level for a SE.

For error message I reused ER_ILLEGAL_HA_CREATE_OPTION ("Table storage
engine 'InnoDB' does not support the create option 'CLUSTERING'")

> - I see there’s no support for UNIQUE CLUSTERING KEYs. Let’s fix it if
> it’s an oversight, or document if it’s a known limitation?

An oversight on my part, not sure about Tokutek. Syntax extended as
follows. Where previously "UNIQUE" was accepted as a valid modifier,
"CLUSTERING" is accepted too, as well as "UNIQUE CLUSTERING" and
"CLUSTERING UNIQUE":
- CREATE UNIQUE INDEX;
- as a part of key definition:
  - CREATE TABLE (..., [CONSTRAINT ... ] UNIQUE KEY ...,)
  - ALTER TABLE ADD [CONSTRAINT ...] UNIQUE KEY

The way the grammar was changed, it accepts "UNIQUE UNIQUE" and
"CLUSTERING CLUSTERING" too. IMHO benign.

Also now it is possible to create such "constraints" as CONSTRAINT c1
CLUSTERING KEY, which is not really a constraint at all, but again
IMHO benign and I don't see an easy way to forbid it without blowing
up shift/reduce conflict count in the parser.

One place where the syntax was not extended was field attribute
syntax:
  - CREATE TABLE (..., b INT UNIQUE CLUSTERING KEY, ...).
It appeared to require more changes to the parser, and can be done in
a follow-up if really needed.

>
> - any specific reasons to add another reserved keyword to the
> parser?

I have reviewed the existing keywords and couldn't choose any IMHO
suitable replacement candidate. Also, I'm not sure Tokutek would
appreciate a forced mass search-replace in their testsuite that also
makes 5.5 to 5.6 upmerges less automatic.

Revision history for this message
Alexey Kopytov (akopytov) wrote :
Download full text (4.2 KiB)

>> - s/INFORMATION_SCHEMA.TABLES/SHOW CREATE TABLE/ in the revision
>> comment
>
> Fixed.
>
>> - I don’t think we should allow creation of non-TokuDB tables with
>> secondary clustering keys. Otherwise once the optimizer support is
>> reviewed and merged, we will get optimizer making incorrect
>> assumptions about secondary clustering keys for tables that don’t
>> actually implement it. On top of that, bad and hard-to-diagnose
>> things may happen on downgrade or migration to another server
>> flavor;
>
> I agree and this was how I implemented it the first time before
> Tokutek asked me to change to be treated as a hint. I didn't think of
> downgrade/migration issues then or I wouldn't have changed. (I don't
> see how the optimizer could make incorrect assumptions because no
> other storage engine would return HA_CLUSTERING in index_flags()).
>

The best way to handle this has been implemented in MariaDB via
SE-specific options in CREATE/ALTER. I doubt we should port those
extensions as a part of this work, just pointing out that the way we are
implementing it will inevitably have unwanted side effects.

Wrt optimizer changes: there’s code in the optimizer that takes flags
from key definition into account (rather than just flags returned by the
storage engine). For example, some code checks key definition flags and
assumes it to be a regular key if none if the previous checks for
specific flags return true. If you allow CLUSTERING keys for storage
engine that don’t support them, you still get the HA_CLUSTERING key set
in key definition flags.

> Added a handlerton flag HTON_SUPPORTS_CLUSTERED_KEYS. This is
> different from e.g. HA_CAN_RTREE etc, which are handler flags, but the
> property of supporting clustered keys seems to me to be global and not
> of table level for a SE.
>
> For error message I reused ER_ILLEGAL_HA_CREATE_OPTION ("Table storage
> engine 'InnoDB' does not support the create option 'CLUSTERING'")
>

That looks good in general. Please also add code that enforces this
restriction to open_binary_frm(). I.e. it should fail with an error if a
non-InnoDB table happens to contain both HA_SPATIAL and HA_FULLTEXT
flags for an index.

>> - I see there’s no support for UNIQUE CLUSTERING KEYs. Let’s fix it if
>> it’s an oversight, or document if it’s a known limitation?
>
> An oversight on my part, not sure about Tokutek. Syntax extended as

Are you going to report it to Tokutek?

> follows. Where previously "UNIQUE" was accepted as a valid modifier,
> "CLUSTERING" is accepted too, as well as "UNIQUE CLUSTERING" and
> "CLUSTERING UNIQUE":
> - CREATE UNIQUE INDEX;
> - as a part of key definition:
> - CREATE TABLE (..., [CONSTRAINT ... ] UNIQUE KEY ...,)
> - ALTER TABLE ADD [CONSTRAINT ...] UNIQUE KEY
>
> The way the grammar was changed, it accepts "UNIQUE UNIQUE" and
> "CLUSTERING CLUSTERING" too. IMHO benign.
>

Hm, doesn’t look that benign to me. UNIQUE UNIQUE is invalid SQL which a
user may want to be aware of. It would be aware before the change. It
will not be aware after the change.

> Also now it is possible to create such "constraints" as CONSTRAINT c1
> CLUSTERING KEY, which is not really a constraint at a...

Read more...

review: Needs Fixing

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/my_base.h'
2--- include/my_base.h 2013-12-05 17:23:10 +0000
3+++ include/my_base.h 2014-02-26 15:07:38 +0000
4@@ -258,11 +258,13 @@
5 #define HA_SPATIAL 1024 /* For spatial search */
6 #define HA_NULL_ARE_EQUAL 2048 /* NULL in key are cmp as equal */
7 #define HA_GENERATED_KEY 8192 /* Automaticly generated key */
8+#define HA_CLUSTERING (1<<31) /* TokuDB CLUSTERING key */
9
10 /* The combination of the above can be used for key type comparison. */
11 #define HA_KEYFLAG_MASK (HA_NOSAME | HA_PACK_KEY | HA_AUTO_KEY | \
12 HA_BINARY_PACK_KEY | HA_FULLTEXT | HA_UNIQUE_CHECK | \
13- HA_SPATIAL | HA_NULL_ARE_EQUAL | HA_GENERATED_KEY)
14+ HA_SPATIAL | HA_NULL_ARE_EQUAL | HA_GENERATED_KEY | \
15+ HA_CLUSTERING)
16
17 /*
18 Key contains partial segments.
19
20=== modified file 'include/mysql_com.h'
21--- include/mysql_com.h 2013-08-14 03:57:21 +0000
22+++ include/mysql_com.h 2014-02-26 15:07:38 +0000
23@@ -126,6 +126,8 @@
24 #define FIELD_FLAGS_COLUMN_FORMAT 24 /* Field column format, bit 24-25 */
25 #define FIELD_FLAGS_COLUMN_FORMAT_MASK (3 << FIELD_FLAGS_COLUMN_FORMAT)
26 #define FIELD_IS_DROPPED (1<< 26) /* Intern: Field is being dropped */
27+#define CLUSTERING_FLAG (1 << 27) /* Field has a secondary clustering
28+ key */
29
30 #define REFRESH_GRANT 1 /* Refresh grant tables */
31 #define REFRESH_LOG 2 /* Start on new log file */
32
33=== added file 'mysql-test/r/tokudb_clustering_key_grammar.result'
34--- mysql-test/r/tokudb_clustering_key_grammar.result 1970-01-01 00:00:00 +0000
35+++ mysql-test/r/tokudb_clustering_key_grammar.result 2014-02-26 15:07:38 +0000
36@@ -0,0 +1,73 @@
37+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CLUSTERING KEY b (b)) ENGINE=InnoDB;
38+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
39+CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
40+ALTER TABLE t1 ADD CLUSTERING INDEX b (b);
41+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
42+CREATE CLUSTERING INDEX b ON t1 (b) LOCK=EXCLUSIVE ALGORITHM=COPY;
43+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
44+ALTER TABLE t1 ADD CLUSTERING INDEX b (b), LOCK=EXCLUSIVE, ALGORITHM=COPY;
45+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
46+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, UNIQUE CLUSTERING KEY b (b)) ENGINE=InnoDB;
47+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
48+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, UNIQUE UNIQUE KEY b (b)) ENGINE=InnoDB;
49+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNIQUE KEY b (b)) ENGINE=InnoDB' at line 1
50+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CLUSTERING CLUSTERING KEY b (b)) ENGINE=InnoDB;
51+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CLUSTERING KEY b (b)) ENGINE=InnoDB' at line 1
52+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CLUSTERING UNIQUE KEY b (b)) ENGINE=InnoDB;
53+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
54+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CONSTRAINT c1 UNIQUE CLUSTERING KEY b (b)) ENGINE=InnoDB;
55+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
56+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CONSTRAINT c1 CLUSTERING UNIQUE KEY b (b)) ENGINE=InnoDB;
57+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
58+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CONSTRAINT c1 UNIQUE UNIQUE KEY b (b)) ENGINE=InnoDB;
59+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNIQUE KEY b (b)) ENGINE=InnoDB' at line 1
60+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CONSTRAINT c1 CLUSTERING KEY b (b)) ENGINE=InnoDB;
61+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') ENGINE=InnoDB' at line 1
62+ALTER TABLE t1 ADD UNIQUE CLUSTERING INDEX b (b);
63+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
64+ALTER TABLE t1 ADD CLUSTERING UNIQUE INDEX b (b);
65+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
66+ALTER TABLE t1 ADD UNIQUE UNIQUE INDEX b (b);
67+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNIQUE INDEX b (b)' at line 1
68+ALTER TABLE t1 ADD CLUSTERING CLUSTERING INDEX b (b);
69+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CLUSTERING INDEX b (b)' at line 1
70+ALTER TABLE t1 ADD CONSTRAINT c1 UNIQUE CLUSTERING INDEX b (b);
71+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
72+ALTER TABLE t1 ADD CONSTRAINT c1 CLUSTERING UNIQUE INDEX b (b);
73+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
74+ALTER TABLE t1 ADD CONSTRAINT c1 UNIQUE UNIQUE INDEX b (b);
75+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNIQUE INDEX b (b)' at line 1
76+ALTER TABLE t1 ADD CONSTRAINT c1 CLUSTERING INDEX b (b);
77+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
78+DROP TABLE t1;
79+CREATE TABLE t1 (a INT CLUSTERING) ENGINE=InnoDB;
80+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
81+CREATE TABLE t1 (a INT CLUSTERING KEY) ENGINE=InnoDB;
82+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
83+CREATE TABLE t1 (a INT CLUSTERING UNIQUE) ENGINE=InnoDB;
84+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
85+CREATE TABLE t1 (a INT CLUSTERING UNIQUE KEY) ENGINE=InnoDB;
86+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
87+CREATE TABLE t1 (a INT UNIQUE CLUSTERING) ENGINE=InnoDB;
88+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
89+CREATE TABLE t1 (a INT UNIQUE CLUSTERING KEY) ENGINE=InnoDB;
90+ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'CLUSTERING'
91+CREATE TABLE CLUSTERING(a INT) ENGINE=InnoDB;
92+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CLUSTERING(a INT) ENGINE=InnoDB' at line 1
93+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c INT, d INT, e INT, f INT, g INT, UNIQUE KEY b (b)) ENGINE=InnoDB;
94+ALTER TABLE t1 ADD UNIQUE INDEX c (c), LOCK=EXCLUSIVE, ALGORITHM=COPY;
95+ALTER TABLE t1 ADD CONSTRAINT c1 UNIQUE INDEX g (g);
96+ALTER TABLE t1 ADD INDEX d (d);
97+CREATE INDEX e ON t1 (e) LOCK=EXCLUSIVE ALGORITHM=COPY;
98+CREATE UNIQUE INDEX f ON t1 (f);
99+DROP TABLE t1;
100+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, KEY b (b)) ENGINE=InnoDB;
101+DROP TABLE t1;
102+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, UNIQUE b (b)) ENGINE=InnoDB;
103+DROP TABLE t1;
104+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CONSTRAINT c1 UNIQUE b (b)) ENGINE=InnoDB;
105+DROP TABLE t1;
106+CREATE TABLE t1 (a INT UNIQUE) ENGINE=InnoDB;
107+DROP TABLE t1;
108+CREATE TABLE t1 (a INT UNIQUE KEY) ENGINE=InnoDB;
109+DROP TABLE t1;
110
111=== added file 'mysql-test/t/tokudb_clustering_key_grammar.test'
112--- mysql-test/t/tokudb_clustering_key_grammar.test 1970-01-01 00:00:00 +0000
113+++ mysql-test/t/tokudb_clustering_key_grammar.test 2014-02-26 15:07:38 +0000
114@@ -0,0 +1,99 @@
115+#
116+# Test that TokuDB CLUSTERING key grammar addition syntax is understood (does not fail with
117+# ER_PARSE_ERROR), but that non-supporting storage engines reject it by returning
118+# ER_ILLEGAL_HA_CREATE_OPTION.
119+#
120+--source include/have_innodb.inc
121+
122+--error ER_ILLEGAL_HA_CREATE_OPTION
123+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CLUSTERING KEY b (b)) ENGINE=InnoDB;
124+
125+CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
126+
127+--error ER_ILLEGAL_HA_CREATE_OPTION
128+ALTER TABLE t1 ADD CLUSTERING INDEX b (b);
129+
130+--error ER_ILLEGAL_HA_CREATE_OPTION
131+CREATE CLUSTERING INDEX b ON t1 (b) LOCK=EXCLUSIVE ALGORITHM=COPY;
132+
133+--error ER_ILLEGAL_HA_CREATE_OPTION
134+ALTER TABLE t1 ADD CLUSTERING INDEX b (b), LOCK=EXCLUSIVE, ALGORITHM=COPY;
135+
136+# CLUSTERING can be combined with UNIQUE, but neither of them can be combined with itself.
137+# CLUSTERING cannot be the sole key type for a CONSTRAINT.
138+
139+--error ER_ILLEGAL_HA_CREATE_OPTION
140+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, UNIQUE CLUSTERING KEY b (b)) ENGINE=InnoDB;
141+--error ER_PARSE_ERROR
142+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, UNIQUE UNIQUE KEY b (b)) ENGINE=InnoDB;
143+--error ER_PARSE_ERROR
144+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CLUSTERING CLUSTERING KEY b (b)) ENGINE=InnoDB;
145+--error ER_ILLEGAL_HA_CREATE_OPTION
146+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CLUSTERING UNIQUE KEY b (b)) ENGINE=InnoDB;
147+--error ER_ILLEGAL_HA_CREATE_OPTION
148+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CONSTRAINT c1 UNIQUE CLUSTERING KEY b (b)) ENGINE=InnoDB;
149+--error ER_ILLEGAL_HA_CREATE_OPTION
150+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CONSTRAINT c1 CLUSTERING UNIQUE KEY b (b)) ENGINE=InnoDB;
151+--error ER_PARSE_ERROR
152+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CONSTRAINT c1 UNIQUE UNIQUE KEY b (b)) ENGINE=InnoDB;
153+--error ER_PARSE_ERROR
154+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CONSTRAINT c1 CLUSTERING KEY b (b)) ENGINE=InnoDB;
155+--error ER_ILLEGAL_HA_CREATE_OPTION
156+ALTER TABLE t1 ADD UNIQUE CLUSTERING INDEX b (b);
157+--error ER_ILLEGAL_HA_CREATE_OPTION
158+ALTER TABLE t1 ADD CLUSTERING UNIQUE INDEX b (b);
159+--error ER_PARSE_ERROR
160+ALTER TABLE t1 ADD UNIQUE UNIQUE INDEX b (b);
161+--error ER_PARSE_ERROR
162+ALTER TABLE t1 ADD CLUSTERING CLUSTERING INDEX b (b);
163+--error ER_ILLEGAL_HA_CREATE_OPTION
164+ALTER TABLE t1 ADD CONSTRAINT c1 UNIQUE CLUSTERING INDEX b (b);
165+--error ER_ILLEGAL_HA_CREATE_OPTION
166+ALTER TABLE t1 ADD CONSTRAINT c1 CLUSTERING UNIQUE INDEX b (b);
167+--error ER_PARSE_ERROR
168+ALTER TABLE t1 ADD CONSTRAINT c1 UNIQUE UNIQUE INDEX b (b);
169+--error ER_PARSE_ERROR
170+ALTER TABLE t1 ADD CONSTRAINT c1 CLUSTERING INDEX b (b);
171+
172+DROP TABLE t1;
173+
174+# Test CLUSTERING as a field attribute, alone and in combination with UNIQUE
175+
176+--error ER_ILLEGAL_HA_CREATE_OPTION
177+CREATE TABLE t1 (a INT CLUSTERING) ENGINE=InnoDB;
178+--error ER_ILLEGAL_HA_CREATE_OPTION
179+CREATE TABLE t1 (a INT CLUSTERING KEY) ENGINE=InnoDB;
180+--error ER_ILLEGAL_HA_CREATE_OPTION
181+CREATE TABLE t1 (a INT CLUSTERING UNIQUE) ENGINE=InnoDB;
182+--error ER_ILLEGAL_HA_CREATE_OPTION
183+CREATE TABLE t1 (a INT CLUSTERING UNIQUE KEY) ENGINE=InnoDB;
184+--error ER_ILLEGAL_HA_CREATE_OPTION
185+CREATE TABLE t1 (a INT UNIQUE CLUSTERING) ENGINE=InnoDB;
186+--error ER_ILLEGAL_HA_CREATE_OPTION
187+CREATE TABLE t1 (a INT UNIQUE CLUSTERING KEY) ENGINE=InnoDB;
188+
189+# CLUSTERING is not allowed as an identifier due to causing extra shift/reduce parser conflicts
190+--error ER_PARSE_ERROR
191+CREATE TABLE CLUSTERING(a INT) ENGINE=InnoDB;
192+
193+
194+# Check that the grammar changes have not broken related CLUSTERING-less clauses
195+
196+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c INT, d INT, e INT, f INT, g INT, UNIQUE KEY b (b)) ENGINE=InnoDB;
197+ALTER TABLE t1 ADD UNIQUE INDEX c (c), LOCK=EXCLUSIVE, ALGORITHM=COPY;
198+ALTER TABLE t1 ADD CONSTRAINT c1 UNIQUE INDEX g (g);
199+ALTER TABLE t1 ADD INDEX d (d);
200+CREATE INDEX e ON t1 (e) LOCK=EXCLUSIVE ALGORITHM=COPY;
201+CREATE UNIQUE INDEX f ON t1 (f);
202+DROP TABLE t1;
203+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, KEY b (b)) ENGINE=InnoDB;
204+DROP TABLE t1;
205+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, UNIQUE b (b)) ENGINE=InnoDB;
206+DROP TABLE t1;
207+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, CONSTRAINT c1 UNIQUE b (b)) ENGINE=InnoDB;
208+DROP TABLE t1;
209+
210+CREATE TABLE t1 (a INT UNIQUE) ENGINE=InnoDB;
211+DROP TABLE t1;
212+CREATE TABLE t1 (a INT UNIQUE KEY) ENGINE=InnoDB;
213+DROP TABLE t1;
214
215=== modified file 'sql/handler.h'
216--- sql/handler.h 2014-02-25 07:30:22 +0000
217+++ sql/handler.h 2014-02-26 15:07:38 +0000
218@@ -1024,6 +1024,11 @@
219 */
220 #define HTON_SUPPORTS_ONLINE_BACKUPS (1 << 11)
221
222+/**
223+ Engine supports secondary clustered keys.
224+*/
225+#define HTON_SUPPORTS_CLUSTERED_KEYS (1 << 12)
226+
227 enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
228 ISO_REPEATABLE_READ, ISO_SERIALIZABLE};
229
230
231=== modified file 'sql/lex.h'
232--- sql/lex.h 2013-12-16 12:54:12 +0000
233+++ sql/lex.h 2014-02-26 15:07:38 +0000
234@@ -115,6 +115,7 @@
235 { "CLIENT", SYM(CLIENT_SYM)},
236 { "CLIENT_STATISTICS", SYM(CLIENT_STATS_SYM)},
237 { "CLOSE", SYM(CLOSE_SYM)},
238+ { "CLUSTERING", SYM(CLUSTERING_SYM)},
239 { "COALESCE", SYM(COALESCE)},
240 { "CODE", SYM(CODE_SYM)},
241 { "COLLATE", SYM(COLLATE_SYM)},
242
243=== modified file 'sql/sql_class.h'
244--- sql/sql_class.h 2014-02-25 07:30:22 +0000
245+++ sql/sql_class.h 2014-02-26 15:07:38 +0000
246@@ -294,7 +294,8 @@
247
248 class Key :public Sql_alloc {
249 public:
250- enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL, FOREIGN_KEY};
251+ enum Keytype { PRIMARY= 0, UNIQUE= 1, MULTIPLE= 2, FULLTEXT= 4, SPATIAL= 8,
252+ FOREIGN_KEY= 16, CLUSTERING= 32 };
253 enum Keytype type;
254 KEY_CREATE_INFO key_create_info;
255 List<Key_part_spec> columns;
256
257=== modified file 'sql/sql_parse.cc'
258--- sql/sql_parse.cc 2014-02-25 07:30:22 +0000
259+++ sql/sql_parse.cc 2014-02-26 15:07:38 +0000
260@@ -6920,13 +6920,20 @@
261 lex->alter_info.key_list.push_back(key);
262 lex->col_list.empty();
263 }
264- if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
265+ if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG | CLUSTERING_FLAG))
266 {
267- Key *key;
268+ Key::Keytype keytype= (enum Key::Keytype)0;
269+ if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
270+ keytype= Key::UNIQUE;
271+ if (type_modifier & CLUSTERING_FLAG)
272+ keytype= (enum Key::Keytype)(keytype | Key::CLUSTERING);
273+ /* The keytype must be set up by the above or we will end up attempting
274+ to create a PRIMARY (== 0) key */
275+ DBUG_ASSERT(keytype != 0);
276+
277 lex->col_list.push_back(new Key_part_spec(*field_name, 0));
278- key= new Key(Key::UNIQUE, null_lex_str,
279- &default_key_create_info, 0,
280- lex->col_list);
281+ Key *key= new Key(keytype, null_lex_str, &default_key_create_info, 0,
282+ lex->col_list);
283 lex->alter_info.key_list.push_back(key);
284 lex->col_list.empty();
285 }
286
287=== modified file 'sql/sql_show.cc'
288--- sql/sql_show.cc 2013-12-16 12:54:12 +0000
289+++ sql/sql_show.cc 2014-02-26 15:07:38 +0000
290@@ -1525,6 +1525,8 @@
291 packet->append(STRING_WITH_LEN("FULLTEXT KEY "));
292 else if (key_info->flags & HA_SPATIAL)
293 packet->append(STRING_WITH_LEN("SPATIAL KEY "));
294+ else if (key_info->flags & HA_CLUSTERING)
295+ packet->append(STRING_WITH_LEN("CLUSTERING KEY "));
296 else
297 packet->append(STRING_WITH_LEN("KEY "));
298
299@@ -5227,6 +5229,7 @@
300 store_column_type(table, field, cs, IS_COLUMNS_DATA_TYPE);
301 pos=(uchar*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
302 (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
303+ (field->flags & CLUSTERING_FLAG) ? "CLU" :
304 (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
305 table->field[IS_COLUMNS_COLUMN_KEY]->store((const char*) pos,
306 strlen((const char*) pos), cs);
307
308=== modified file 'sql/sql_table.cc'
309--- sql/sql_table.cc 2013-12-16 08:45:31 +0000
310+++ sql/sql_table.cc 2014-02-26 15:07:38 +0000
311@@ -3757,7 +3757,7 @@
312 break;
313 }
314
315- switch (key->type) {
316+ switch ((unsigned)key->type) {
317 case Key::MULTIPLE:
318 key_info->flags= 0;
319 break;
320@@ -3780,6 +3780,19 @@
321 case Key::FOREIGN_KEY:
322 key_number--; // Skip this key
323 continue;
324+ case Key::CLUSTERING | Key::UNIQUE:
325+ key_info->flags= HA_NOSAME;
326+ /* fall through */
327+ case Key::CLUSTERING:
328+ if (unlikely(!ha_check_storage_engine_flag(
329+ file->ht, HTON_SUPPORTS_CLUSTERED_KEYS)))
330+ {
331+ my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
332+ ha_resolve_storage_engine_name(file->ht), "CLUSTERING");
333+ DBUG_RETURN(TRUE);
334+ }
335+ key_info->flags|= HA_CLUSTERING;
336+ break;
337 default:
338 key_info->flags = HA_NOSAME;
339 break;
340@@ -7118,7 +7131,9 @@
341 key_type= Key::FULLTEXT;
342 else
343 key_type= Key::MULTIPLE;
344-
345+ if (key_info->flags & HA_CLUSTERING)
346+ key_type= (enum Key::Keytype)(key_type | Key::CLUSTERING);
347+
348 if (index_column_dropped)
349 {
350 /*
351
352=== modified file 'sql/sql_yacc.yy'
353--- sql/sql_yacc.yy 2014-02-25 07:30:22 +0000
354+++ sql/sql_yacc.yy 2014-02-26 15:07:38 +0000
355@@ -1,5 +1,5 @@
356-/*
357- Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
358+/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights
359+ reserved.
360
361 This program is free software; you can redistribute it and/or modify
362 it under the terms of the GNU General Public License as published by
363@@ -1029,7 +1029,7 @@
364 Currently there are 161 shift/reduce conflicts.
365 We should not introduce new conflicts any more.
366 */
367-%expect 162
368+%expect 164
369
370 /*
371 Comments for TOKENS.
372@@ -1114,6 +1114,7 @@
373 %token CLIENT_SYM
374 %token CLIENT_STATS_SYM
375 %token CLOSE_SYM /* SQL-2003-R */
376+%token CLUSTERING_SYM
377 %token COALESCE /* SQL-2003-N */
378 %token CODE_SYM
379 %token COLLATE_SYM /* SQL-2003-R */
380@@ -1794,7 +1795,8 @@
381 option_type opt_var_type opt_var_ident_type
382
383 %type <key_type>
384- normal_key_type opt_unique constraint_key_type fulltext spatial
385+ normal_key_type opt_unique_combo_clustering constraint_key_type
386+ fulltext spatial unique_opt_clustering unique_combo_clustering unique clustering
387
388 %type <key_alg>
389 btree_or_rtree
390@@ -2445,7 +2447,7 @@
391 }
392 create_table_set_open_action_and_adjust_tables(lex);
393 }
394- | CREATE opt_unique INDEX_SYM ident key_alg ON table_ident
395+ | CREATE opt_unique_combo_clustering INDEX_SYM ident key_alg ON table_ident
396 {
397 if (add_create_index_prepare(Lex, $7))
398 MYSQL_YYABORT;
399@@ -6348,6 +6350,12 @@
400 | opt_constraint constraint_key_type opt_ident key_alg
401 '(' key_list ')' normal_key_options
402 {
403+ if (($1.length != 0) && ((enum Key::Keytype)$2 == Key::CLUSTERING))
404+ {
405+ /* Forbid "CONSTRAINT c CLUSTERING" */
406+ my_parse_error(ER(ER_SYNTAX_ERROR));
407+ MYSQL_YYABORT;
408+ }
409 if (add_create_index (Lex, $2, $3.str ? $3 : $1))
410 MYSQL_YYABORT;
411 }
412@@ -6747,16 +6755,22 @@
413 lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG;
414 lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX;
415 }
416- | UNIQUE_SYM
417+ | unique_combo_clustering
418 {
419 LEX *lex=Lex;
420- lex->type|= UNIQUE_FLAG;
421+ if ($1 & Key::UNIQUE)
422+ lex->type|= UNIQUE_FLAG;
423+ if ($1 & Key::CLUSTERING)
424+ lex->type|= CLUSTERING_FLAG;
425 lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX;
426 }
427- | UNIQUE_SYM KEY_SYM
428+ | unique_combo_clustering KEY_SYM
429 {
430 LEX *lex=Lex;
431- lex->type|= UNIQUE_KEY_FLAG;
432+ if ($1 & Key::UNIQUE)
433+ lex->type|= UNIQUE_KEY_FLAG;
434+ if ($1 & Key::CLUSTERING)
435+ lex->type|= CLUSTERING_FLAG;
436 lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX;
437 }
438 | COMMENT_SYM TEXT_STRING_sys { Lex->comment= $2; }
439@@ -7139,7 +7153,8 @@
440
441 constraint_key_type:
442 PRIMARY_SYM KEY_SYM { $$= Key::PRIMARY; }
443- | UNIQUE_SYM opt_key_or_index { $$= Key::UNIQUE; }
444+ | unique_combo_clustering opt_key_or_index { $$= $1; }
445+
446 ;
447
448 key_or_index:
449@@ -7158,9 +7173,37 @@
450 | INDEXES {}
451 ;
452
453-opt_unique:
454- /* empty */ { $$= Key::MULTIPLE; }
455- | UNIQUE_SYM { $$= Key::UNIQUE; }
456+opt_unique_combo_clustering:
457+ /* empty */ { $$= Key::MULTIPLE; }
458+ | unique_combo_clustering
459+ ;
460+
461+unique_combo_clustering:
462+ clustering { $$= $1; }
463+ | unique_opt_clustering { $$= $1; }
464+ ;
465+
466+unique_opt_clustering:
467+ unique
468+ {
469+ $$= $1;
470+ }
471+ | unique clustering
472+ {
473+ $$= (enum Key::Keytype)($1 | $2);
474+ }
475+ | clustering unique
476+ {
477+ $$= (enum Key::Keytype)($1 | $2);
478+ }
479+ ;
480+
481+unique:
482+ UNIQUE_SYM { $$= Key::UNIQUE; }
483+ ;
484+
485+clustering:
486+ CLUSTERING_SYM { $$= Key::CLUSTERING; }
487 ;
488
489 fulltext:
490
491=== modified file 'sql/table.cc'
492--- sql/table.cc 2013-12-05 17:23:10 +0000
493+++ sql/table.cc 2014-02-26 15:07:38 +0000
494@@ -854,11 +854,24 @@
495 KEY_PART_INFO *key_part= &keyinfo->key_part[key_part_n];
496 Field *field= key_part->field;
497
498- /* Flag field as unique if it is the only keypart in a unique index */
499+ /* Flag field as unique and/or clustering if it is the only keypart in a
500+ unique/clustering index */
501 if (key_part_n == 0 && key_n != primary_key_n)
502- field->flags |= (((keyinfo->flags & HA_NOSAME) &&
503- (keyinfo->user_defined_key_parts == 1)) ?
504- UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG);
505+ {
506+ if (((keyinfo->flags & HA_NOSAME) &&
507+ (keyinfo->user_defined_key_parts == 1)))
508+ field->flags|= UNIQUE_KEY_FLAG;
509+
510+ if (((keyinfo->flags & HA_CLUSTERING) &&
511+ (keyinfo->user_defined_key_parts == 1)))
512+ field->flags|= CLUSTERING_FLAG;
513+
514+ if (!(field->flags & (UNIQUE_KEY_FLAG | CLUSTERING_FLAG)))
515+ {
516+ field->flags|= MULTIPLE_KEY_FLAG;
517+ }
518+ }
519+
520 if (key_part_n == 0)
521 field->key_start.set_bit(key_n);
522 if (field->key_length() == key_part->length &&
523@@ -1133,6 +1146,18 @@
524 if (new_frm_ver >= 3)
525 {
526 keyinfo->flags= (uint) uint2korr(strpos) ^ HA_NOSAME;
527+ /* Replace HA_FULLTEXT & HA_SPATIAL with HA_CLUSTERING. This way we
528+ support TokuDB clustering key definitions without changing the FRM
529+ format. */
530+ if (keyinfo->flags & HA_SPATIAL && keyinfo->flags & HA_FULLTEXT)
531+ {
532+ if (!ha_check_storage_engine_flag(share->db_type(),
533+ HTON_SUPPORTS_CLUSTERED_KEYS))
534+ goto err;
535+ keyinfo->flags|= HA_CLUSTERING;
536+ keyinfo->flags&= ~HA_SPATIAL;
537+ keyinfo->flags&= ~HA_FULLTEXT;
538+ }
539 keyinfo->key_length= (uint) uint2korr(strpos+2);
540 keyinfo->user_defined_key_parts= (uint) strpos[4];
541 keyinfo->algorithm= (enum ha_key_alg) strpos[5];
542
543=== modified file 'sql/unireg.cc'
544--- sql/unireg.cc 2013-12-05 17:23:10 +0000
545+++ sql/unireg.cc 2014-02-26 15:07:38 +0000
546@@ -628,7 +628,15 @@
547 key_parts=0;
548 for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
549 {
550- int2store(pos, (key->flags ^ HA_NOSAME));
551+ /* Replace HA_CLUSTERING with HA_SPATIAL | HA_FULLTEXT to allow storing
552+ TokuDB keys without changing the FRM format. */
553+ uint16 key_flags= (uint16)key->flags;
554+ if (key->flags & HA_CLUSTERING)
555+ {
556+ key_flags|= HA_SPATIAL;
557+ key_flags|= HA_FULLTEXT;
558+ }
559+ int2store(pos, (key_flags ^ HA_NOSAME));
560 int2store(pos+2,key->key_length);
561 pos[4]= (uchar) key->user_defined_key_parts;
562 pos[5]= (uchar) key->algorithm;
563
564=== modified file 'tests/mysql_client_test.c'
565--- tests/mysql_client_test.c 2013-08-14 03:57:21 +0000
566+++ tests/mysql_client_test.c 2014-02-26 15:07:38 +0000
567@@ -4676,7 +4676,8 @@
568 fprintf(stdout, "\n MULTIPLE_KEY_FLAG");
569 if (field->flags & AUTO_INCREMENT_FLAG)
570 fprintf(stdout, "\n AUTO_INCREMENT_FLAG");
571-
572+ if (field->flags & CLUSTERING_FLAG)
573+ fprintf(stdout, "\n CLUSTERING_FLAG");
574 }
575 }
576 mysql_free_result(result);

Subscribers

People subscribed via source and target branches