1 /* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "sql/parse_tree_partitions.h"
24
25 #include "m_ctype.h"
26 #include "my_dbug.h"
27 #include "my_sys.h"
28 #include "mysql_com.h"
29 #include "mysqld_error.h"
30 #include "sql/derror.h"
31 #include "sql/item.h"
32 #include "sql/parse_location.h"
33 #include "sql/sql_class.h"
34 #include "sql/sql_const.h"
35 #include "sql/sql_lex.h"
36 #include "sql/sql_list.h"
37 #include "sql/sql_parse.h"
38 #include "sql_string.h"
39
Partition_parse_context(THD * thd_arg,partition_info * part_info_arg,partition_element * current_partition_arg,partition_element * curr_part_elem_arg,bool is_add_or_reorganize_partition)40 Partition_parse_context::Partition_parse_context(
41 THD *thd_arg, partition_info *part_info_arg,
42 partition_element *current_partition_arg,
43 partition_element *curr_part_elem_arg, bool is_add_or_reorganize_partition)
44 : Parse_context(thd_arg, thd_arg->lex->current_select()),
45 Parser_partition_info(part_info_arg, current_partition_arg,
46 curr_part_elem_arg, nullptr, 0),
47 is_add_or_reorganize_partition(is_add_or_reorganize_partition) {}
48
contextualize(Partition_parse_context * pc)49 bool PT_subpartition::contextualize(Partition_parse_context *pc) {
50 partition_info *const part_info = pc->part_info;
51
52 if (part_info->use_default_subpartitions &&
53 part_info->partitions.elements >= 2) {
54 /*
55 create table t1 (a int)
56 partition by list (a) subpartition by hash (a)
57 (partition p0 values in (1),
58 partition p1 values in (2) subpartition sp11);
59 causes us to arrive since we are on the second
60 partition, but still use_default_subpartitions
61 is set. When we come here we're processing at least
62 the second partition (the current partition processed
63 have already been put into the partitions list.
64 */
65 error(pc, pos, ER_THD(pc->thd, ER_PARTITION_WRONG_NO_SUBPART_ERROR));
66 return true;
67 }
68
69 auto *sub_p_elem =
70 new (pc->mem_root) partition_element(pc->current_partition);
71 if (sub_p_elem == nullptr) return true;
72
73 if (check_string_char_length(to_lex_cstring(name), "", NAME_CHAR_LEN,
74 system_charset_info, true)) {
75 my_error(ER_TOO_LONG_IDENT, MYF(0), name);
76 return true;
77 }
78
79 sub_p_elem->partition_name = name;
80
81 part_info->use_default_subpartitions = false;
82 part_info->use_default_num_subpartitions = false;
83 pc->count_curr_subparts++;
84
85 Partition_parse_context subpart_pc(pc->thd, part_info, pc->current_partition,
86 sub_p_elem,
87 pc->is_add_or_reorganize_partition);
88
89 if (options != nullptr) {
90 for (auto option : *options) {
91 if (option->contextualize(&subpart_pc)) return true;
92 }
93 if (sub_p_elem->engine_type != nullptr)
94 part_info->default_engine_type = sub_p_elem->engine_type;
95 }
96 if (pc->current_partition->subpartitions.push_back(sub_p_elem)) return true;
97
98 return false;
99 }
100
contextualize(Partition_parse_context * pc)101 bool PT_part_value_item_max::contextualize(Partition_parse_context *pc) {
102 if (super::contextualize(pc)) return true;
103
104 if (pc->part_info->part_type == partition_type::LIST) {
105 error(pc, pos, ER_THD(pc->thd, ER_MAXVALUE_IN_VALUES_IN));
106 return true;
107 }
108 if (pc->add_max_value()) return true;
109
110 return false;
111 }
112
contextualize(Partition_parse_context * pc)113 bool PT_part_value_item_expr::contextualize(Partition_parse_context *pc) {
114 if (super::contextualize(pc) || expr->itemize(pc, &expr)) return true;
115
116 if (!pc->thd->lex->safe_to_cache_query) {
117 error(pc, pos, ER_THD(pc->thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
118 return true;
119 }
120 if (pc->add_column_list_value(pc->thd, expr)) return true;
121
122 return false;
123 }
124
contextualize(Partition_parse_context * pc)125 bool PT_part_value_item_list_paren::contextualize(Partition_parse_context *pc) {
126 pc->part_info->print_debug("( part_value_item_list_paren", nullptr);
127 /* Initialisation code needed for each list of value expressions */
128 if (!(pc->part_info->part_type == partition_type::LIST &&
129 pc->part_info->num_columns == 1U) &&
130 pc->init_column_part()) {
131 return true;
132 }
133
134 for (auto value : *values) {
135 if (value->contextualize(pc)) return true;
136 }
137
138 pc->part_info->print_debug(") part_value_item_list_paren", nullptr);
139 if (pc->part_info->num_columns == 0)
140 pc->part_info->num_columns = pc->curr_list_object;
141 if (pc->part_info->num_columns != pc->curr_list_object) {
142 /*
143 All value items lists must be of equal length, in some cases
144 which is covered by the above if-statement we don't know yet
145 how many columns is in the partition so the assignment above
146 ensures that we only report errors when we know we have an
147 error.
148 */
149 pc->part_info->print_debug("Kilroy I", nullptr);
150 error(pc, paren_pos, ER_THD(pc->thd, ER_PARTITION_COLUMN_LIST_ERROR));
151 return true;
152 }
153 pc->curr_list_object = 0;
154 return false;
155 }
156
contextualize(Partition_parse_context * pc)157 bool PT_part_values_in_item::contextualize(Partition_parse_context *pc) {
158 if (super::contextualize(pc) || item->contextualize(pc)) return true;
159
160 partition_info *const part_info = pc->part_info;
161 part_info->print_debug("part_values_in: part_value_item_list_paren", nullptr);
162
163 if (part_info->num_columns != 1U) {
164 if (!pc->is_add_or_reorganize_partition || part_info->num_columns == 0 ||
165 part_info->num_columns > MAX_REF_PARTS) {
166 part_info->print_debug("Kilroy III", nullptr);
167 error(pc, pos, ER_THD(pc->thd, ER_PARTITION_COLUMN_LIST_ERROR));
168 return true;
169 }
170 /*
171 Reorganize the current large array into a list of small
172 arrays with one entry in each array. This can happen
173 in the first partition of an ALTER TABLE statement where
174 we ADD or REORGANIZE partitions. Also can only happen
175 for LIST [COLUMNS] partitions.
176 */
177 if (pc->reorganize_into_single_field_col_val()) return true;
178 }
179 return false;
180 }
181
contextualize(Partition_parse_context * pc)182 bool PT_part_values_in_list::contextualize(Partition_parse_context *pc) {
183 if (super::contextualize(pc)) return true;
184
185 for (auto item : *list) {
186 if (item->contextualize(pc)) return true;
187 }
188
189 if (pc->part_info->num_columns < 2U) {
190 error(pc, pos, ER_THD(pc->thd, ER_ROW_SINGLE_PARTITION_FIELD_ERROR));
191 return true;
192 }
193 return false;
194 }
195
contextualize(Partition_parse_context * pc)196 bool PT_part_definition::contextualize(Partition_parse_context *pc) {
197 DBUG_ASSERT(pc->current_partition == nullptr &&
198 pc->curr_part_elem == nullptr);
199
200 if (super::contextualize(pc)) return true;
201
202 partition_info *const part_info = pc->part_info;
203
204 auto *const curr_part = new (pc->thd->mem_root) partition_element();
205 if (curr_part == nullptr) return true;
206
207 Partition_parse_context ppc(pc->thd, part_info, curr_part, curr_part,
208 pc->is_add_or_reorganize_partition);
209
210 if (!curr_part || part_info->partitions.push_back(curr_part)) return true;
211 curr_part->part_state = PART_NORMAL;
212 part_info->use_default_partitions = false;
213 part_info->use_default_num_partitions = false;
214
215 if (check_string_char_length(to_lex_cstring(name), "", NAME_CHAR_LEN,
216 system_charset_info, true)) {
217 my_error(ER_TOO_LONG_IDENT, MYF(0), name.str);
218 return true;
219 }
220
221 curr_part->partition_name = name.str;
222
223 switch (type) {
224 case partition_type::HASH: {
225 if (part_info->part_type == partition_type::NONE)
226 part_info->part_type = partition_type::HASH;
227 else if (part_info->part_type == partition_type::RANGE) {
228 errorf(&ppc, pos, ER_THD(pc->thd, ER_PARTITION_REQUIRES_VALUES_ERROR),
229 "RANGE", "LESS THAN");
230 return true;
231 } else if (part_info->part_type == partition_type::LIST) {
232 errorf(&ppc, pos, ER_THD(pc->thd, ER_PARTITION_REQUIRES_VALUES_ERROR),
233 "LIST", "IN");
234 return true;
235 }
236 } break;
237 case partition_type::RANGE: {
238 if (part_info->part_type == partition_type::NONE)
239 part_info->part_type = partition_type::RANGE;
240 else if (part_info->part_type != partition_type::RANGE) {
241 my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "RANGE", "LESS THAN");
242 return true;
243 }
244
245 if (opt_part_values == nullptr) // MAX_VALUE_SYM
246 {
247 if (part_info->num_columns && part_info->num_columns != 1U) {
248 part_info->print_debug("Kilroy II", nullptr);
249 error(&ppc, values_pos,
250 ER_THD(pc->thd, ER_PARTITION_COLUMN_LIST_ERROR));
251 return true;
252 } else
253 part_info->num_columns = 1U;
254 if (ppc.init_column_part() || ppc.add_max_value()) return true;
255 } else if (opt_part_values->contextualize(&ppc))
256 return true;
257 } break;
258 case partition_type::LIST: {
259 if (part_info->part_type == partition_type::NONE)
260 part_info->part_type = partition_type::LIST;
261 else if (part_info->part_type != partition_type::LIST) {
262 my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "LIST", "IN");
263 return true;
264 }
265
266 if (opt_part_values->contextualize(&ppc)) return true;
267 } break;
268 default:
269 DBUG_ASSERT(false);
270 error(&ppc, pos, ER_THD(pc->thd, ER_UNKNOWN_ERROR));
271 return true;
272 }
273
274 if (opt_part_options != nullptr) {
275 for (auto option : *opt_part_options) {
276 if (option->contextualize(&ppc)) return true;
277 }
278 if (curr_part->engine_type != nullptr)
279 part_info->default_engine_type = curr_part->engine_type;
280 }
281
282 if (opt_sub_partitions == nullptr) {
283 if (part_info->num_subparts != 0 && !part_info->use_default_subpartitions) {
284 /*
285 We come here when we have defined subpartitions on the first
286 partition but not on all the subsequent partitions.
287 */
288 error(&ppc, sub_partitions_pos,
289 ER_THD(pc->thd, ER_PARTITION_WRONG_NO_SUBPART_ERROR));
290 return true;
291 }
292 } else {
293 for (auto subpartition : *opt_sub_partitions) {
294 if (subpartition->contextualize(&ppc)) return true;
295 }
296
297 if (part_info->num_subparts != 0) {
298 if (part_info->num_subparts != ppc.count_curr_subparts) {
299 error(&ppc, sub_partitions_pos,
300 ER_THD(pc->thd, ER_PARTITION_WRONG_NO_SUBPART_ERROR));
301 return true;
302 }
303 } else if (ppc.count_curr_subparts > 0) {
304 if (part_info->partitions.elements > 1) {
305 error(&ppc, sub_partitions_pos,
306 ER_THD(pc->thd, ER_PARTITION_WRONG_NO_SUBPART_ERROR));
307 return true;
308 }
309 part_info->num_subparts = ppc.count_curr_subparts;
310 }
311 }
312 return false;
313 }
314
contextualize(Partition_parse_context * pc)315 bool PT_sub_partition_by_hash::contextualize(Partition_parse_context *pc) {
316 if (super::contextualize(pc) || hash->itemize(pc, &hash)) return true;
317
318 partition_info *const part_info = pc->part_info;
319
320 part_info->subpart_type = partition_type::HASH;
321 part_info->linear_hash_ind = is_linear;
322
323 LEX *const lex = pc->thd->lex;
324 if (!lex->safe_to_cache_query) {
325 error(pc, hash_pos, ER_THD(pc->thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
326 return true;
327 }
328 lex->safe_to_cache_query = true;
329
330 /* TODO: remove const_cast */
331 if (part_info->set_part_expr(const_cast<char *>(hash_pos.cpp.start), hash,
332 const_cast<char *>(hash_pos.cpp.end), true))
333 return true;
334
335 if (opt_num_subparts > 0) {
336 part_info->num_subparts = opt_num_subparts;
337 part_info->use_default_num_subpartitions = false;
338 }
339 return false;
340 }
341
contextualize(Partition_parse_context * pc)342 bool PT_sub_partition_by_key::contextualize(Partition_parse_context *pc) {
343 if (super::contextualize(pc)) return true;
344
345 partition_info *const part_info = pc->part_info;
346
347 part_info->subpart_type = partition_type::HASH;
348 part_info->list_of_subpart_fields = true;
349
350 part_info->linear_hash_ind = is_linear;
351 part_info->key_algorithm = key_algo;
352
353 if (field_names->elements > MAX_REF_PARTS) {
354 my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0),
355 "list of subpartition fields");
356 return true;
357 }
358 part_info->subpart_field_list = *field_names;
359
360 if (opt_num_subparts > 0) {
361 part_info->num_subparts = opt_num_subparts;
362 part_info->use_default_num_subpartitions = false;
363 }
364 return false;
365 }
366
set_part_field_list(Partition_parse_context * pc,List<char> * list)367 bool PT_part_type_def::set_part_field_list(Partition_parse_context *pc,
368 List<char> *list) {
369 if (list->elements > MAX_REF_PARTS) {
370 my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0),
371 "list of partition fields");
372 return true;
373 }
374 pc->part_info->num_columns = list->elements;
375 pc->part_info->part_field_list = *list;
376 return false;
377 }
378
itemize_part_expr(Partition_parse_context * pc,const POS & pos,Item ** item)379 bool PT_part_type_def::itemize_part_expr(Partition_parse_context *pc,
380 const POS &pos, Item **item) {
381 if ((*item)->itemize(pc, item)) return true;
382
383 if (!pc->thd->lex->safe_to_cache_query) {
384 error(pc, pos, ER_THD(pc->thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
385 return true;
386 }
387 pc->thd->lex->safe_to_cache_query = true;
388
389 if (pc->part_info->set_part_expr(const_cast<char *>(pos.cpp.start), *item,
390 const_cast<char *>(pos.cpp.end), false))
391 return true;
392
393 return false;
394 }
395
contextualize(Partition_parse_context * pc)396 bool PT_part_type_def_key::contextualize(Partition_parse_context *pc) {
397 if (super::contextualize(pc)) return true;
398
399 pc->part_info->part_type = partition_type::HASH;
400 pc->part_info->column_list = false;
401 pc->part_info->key_algorithm = key_algo;
402 pc->part_info->linear_hash_ind = is_linear;
403 pc->part_info->list_of_part_fields = true;
404
405 if (opt_columns != nullptr && set_part_field_list(pc, opt_columns))
406 return true;
407
408 return false;
409 }
410
contextualize(Partition_parse_context * pc)411 bool PT_part_type_def_hash::contextualize(Partition_parse_context *pc) {
412 if (super::contextualize(pc) || itemize_part_expr(pc, expr_pos, &expr))
413 return true;
414
415 pc->part_info->part_type = partition_type::HASH;
416 pc->part_info->column_list = false;
417 pc->part_info->linear_hash_ind = is_linear;
418 pc->part_info->num_columns = 1;
419
420 return false;
421 }
422
contextualize(Partition_parse_context * pc)423 bool PT_part_type_def_range_expr::contextualize(Partition_parse_context *pc) {
424 if (super::contextualize(pc) || itemize_part_expr(pc, expr_pos, &expr))
425 return true;
426
427 pc->part_info->part_type = partition_type::RANGE;
428 pc->part_info->column_list = false;
429 pc->part_info->num_columns = 1;
430
431 return false;
432 }
433
contextualize(Partition_parse_context * pc)434 bool PT_part_type_def_range_columns::contextualize(
435 Partition_parse_context *pc) {
436 if (super::contextualize(pc)) return true;
437
438 pc->part_info->part_type = partition_type::RANGE;
439 pc->part_info->column_list = true;
440 pc->part_info->list_of_part_fields = true;
441
442 return set_part_field_list(pc, columns);
443 }
444
contextualize(Partition_parse_context * pc)445 bool PT_part_type_def_list_expr::contextualize(Partition_parse_context *pc) {
446 if (super::contextualize(pc) || itemize_part_expr(pc, expr_pos, &expr))
447 return true;
448
449 pc->part_info->part_type = partition_type::LIST;
450 pc->part_info->column_list = false;
451 pc->part_info->num_columns = 1;
452
453 return false;
454 }
455
contextualize(Partition_parse_context * pc)456 bool PT_part_type_def_list_columns::contextualize(Partition_parse_context *pc) {
457 if (super::contextualize(pc)) return true;
458
459 pc->part_info->part_type = partition_type::LIST;
460 pc->part_info->column_list = true;
461 pc->part_info->list_of_part_fields = true;
462
463 return set_part_field_list(pc, columns);
464 }
465
contextualize(Parse_context * pc)466 bool PT_partition::contextualize(Parse_context *pc) {
467 if (super::contextualize(pc)) return true;
468
469 Partition_parse_context part_pc(pc->thd, &part_info, false);
470 if (part_type_def->contextualize(&part_pc)) return true;
471
472 if (opt_num_parts != 0) {
473 part_info.num_parts = opt_num_parts;
474 part_info.use_default_num_partitions = false;
475 }
476
477 if (opt_sub_part != nullptr && opt_sub_part->contextualize(&part_pc))
478 return true;
479
480 if (part_defs == nullptr) {
481 if (part_info.part_type == partition_type::RANGE) {
482 my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "RANGE");
483 return true;
484 } else if (part_info.part_type == partition_type::LIST) {
485 my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "LIST");
486 return true;
487 }
488 } else {
489 for (auto part_def : *part_defs) {
490 if (part_def->contextualize(&part_pc)) return true;
491 }
492 uint count_curr_parts = part_info.partitions.elements;
493
494 if (part_info.num_parts != 0) {
495 if (part_info.num_parts != count_curr_parts) {
496 error(&part_pc, part_defs_pos,
497 ER_THD(pc->thd, ER_PARTITION_WRONG_NO_PART_ERROR));
498 return true;
499 }
500 } else if (count_curr_parts > 0)
501 part_info.num_parts = count_curr_parts;
502 }
503 return false;
504 }
505