1 | #ifndef PARTITION_INFO_INCLUDED |
2 | #define PARTITION_INFO_INCLUDED |
3 | |
4 | /* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. |
5 | |
6 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
18 | |
19 | #ifdef USE_PRAGMA_INTERFACE |
20 | #pragma interface /* gcc class implementation */ |
21 | #endif |
22 | |
23 | #include "sql_class.h" |
24 | #include "partition_element.h" |
25 | #include "sql_partition.h" |
26 | |
27 | class partition_info; |
28 | struct TABLE_LIST; |
29 | /* Some function typedefs */ |
30 | typedef int (*get_part_id_func)(partition_info *part_info, uint32 *part_id, |
31 | longlong *func_value); |
32 | typedef int (*get_subpart_id_func)(partition_info *part_info, uint32 *part_id); |
33 | typedef bool (*check_constants_func)(THD *thd, partition_info *part_info); |
34 | |
35 | struct st_ddl_log_memory_entry; |
36 | |
37 | struct Vers_part_info : public Sql_alloc |
38 | { |
39 | Vers_part_info() : |
40 | limit(0), |
41 | now_part(NULL), |
42 | hist_part(NULL) |
43 | { |
44 | interval.type= INTERVAL_LAST; |
45 | } |
46 | Vers_part_info(Vers_part_info &src) : |
47 | interval(src.interval), |
48 | limit(src.limit), |
49 | now_part(NULL), |
50 | hist_part(NULL) |
51 | { |
52 | } |
53 | bool initialized() |
54 | { |
55 | if (now_part) |
56 | { |
57 | DBUG_ASSERT(now_part->id != UINT_MAX32); |
58 | DBUG_ASSERT(now_part->type() == partition_element::CURRENT); |
59 | if (hist_part) |
60 | { |
61 | DBUG_ASSERT(hist_part->id != UINT_MAX32); |
62 | DBUG_ASSERT(hist_part->type() == partition_element::HISTORY); |
63 | } |
64 | return true; |
65 | } |
66 | return false; |
67 | } |
68 | struct { |
69 | my_time_t start; |
70 | INTERVAL step; |
71 | enum interval_type type; |
72 | bool is_set() { return type < INTERVAL_LAST; } |
73 | } interval; |
74 | ulonglong limit; |
75 | partition_element *now_part; |
76 | partition_element *hist_part; |
77 | }; |
78 | |
79 | class partition_info : public Sql_alloc |
80 | { |
81 | public: |
82 | /* |
83 | * Here comes a set of definitions needed for partitioned table handlers. |
84 | */ |
85 | List<partition_element> partitions; |
86 | List<partition_element> temp_partitions; |
87 | |
88 | List<const char> part_field_list; |
89 | List<const char> subpart_field_list; |
90 | |
91 | /* |
92 | If there is no subpartitioning, use only this func to get partition ids. |
93 | If there is subpartitioning, use the this func to get partition id when |
94 | you have both partition and subpartition fields. |
95 | */ |
96 | get_part_id_func get_partition_id; |
97 | |
98 | /* Get partition id when we don't have subpartition fields */ |
99 | get_part_id_func get_part_partition_id; |
100 | |
101 | /* |
102 | Get subpartition id when we have don't have partition fields by we do |
103 | have subpartition ids. |
104 | Mikael said that for given constant tuple |
105 | {subpart_field1, ..., subpart_fieldN} the subpartition id will be the |
106 | same in all subpartitions |
107 | */ |
108 | get_subpart_id_func get_subpartition_id; |
109 | |
110 | /* |
111 | When we have various string fields we might need some preparation |
112 | before and clean-up after calling the get_part_id_func's. We need |
113 | one such method for get_part_partition_id and one for |
114 | get_subpartition_id. |
115 | */ |
116 | get_part_id_func get_part_partition_id_charset; |
117 | get_subpart_id_func get_subpartition_id_charset; |
118 | |
119 | check_constants_func check_constants; |
120 | |
121 | /* NULL-terminated array of fields used in partitioned expression */ |
122 | Field **part_field_array; |
123 | Field **subpart_field_array; |
124 | Field **part_charset_field_array; |
125 | Field **subpart_charset_field_array; |
126 | /* |
127 | Array of all fields used in partition and subpartition expression, |
128 | without duplicates, NULL-terminated. |
129 | */ |
130 | Field **full_part_field_array; |
131 | /* |
132 | Set of all fields used in partition and subpartition expression. |
133 | Required for testing of partition fields in write_set when |
134 | updating. We need to set all bits in read_set because the row may |
135 | need to be inserted in a different [sub]partition. |
136 | */ |
137 | MY_BITMAP full_part_field_set; |
138 | |
139 | /* |
140 | When we have a field that requires transformation before calling the |
141 | partition functions we must allocate field buffers for the field of |
142 | the fields in the partition function. |
143 | */ |
144 | uchar **part_field_buffers; |
145 | uchar **subpart_field_buffers; |
146 | uchar **restore_part_field_ptrs; |
147 | uchar **restore_subpart_field_ptrs; |
148 | |
149 | Item *part_expr; |
150 | Item *subpart_expr; |
151 | |
152 | Item *item_free_list; |
153 | |
154 | struct st_ddl_log_memory_entry *first_log_entry; |
155 | struct st_ddl_log_memory_entry *exec_log_entry; |
156 | struct st_ddl_log_memory_entry *frm_log_entry; |
157 | |
158 | /* |
159 | Bitmaps of partitions used by the current query. |
160 | * read_partitions - partitions to be used for reading. |
161 | * lock_partitions - partitions that must be locked (read or write). |
162 | Usually read_partitions is the same set as lock_partitions, but |
163 | in case of UPDATE the WHERE clause can limit the read_partitions set, |
164 | but not neccesarily the lock_partitions set. |
165 | Usage pattern: |
166 | * Initialized in ha_partition::open(). |
167 | * read+lock_partitions is set according to explicit PARTITION, |
168 | WL#5217, in open_and_lock_tables(). |
169 | * Bits in read_partitions can be cleared in prune_partitions() |
170 | in the optimizing step. |
171 | (WL#4443 is about allowing prune_partitions() to affect lock_partitions |
172 | and be done before locking too). |
173 | * When the partition enabled handler get an external_lock call it locks |
174 | all partitions in lock_partitions (and remembers which partitions it |
175 | locked, so that it can unlock them later). In case of LOCK TABLES it will |
176 | lock all partitions, and keep them locked while lock_partitions can |
177 | change for each statement under LOCK TABLES. |
178 | * Freed at the same time item_free_list is freed. |
179 | */ |
180 | MY_BITMAP read_partitions; |
181 | MY_BITMAP lock_partitions; |
182 | bool bitmaps_are_initialized; |
183 | |
184 | union { |
185 | longlong *range_int_array; |
186 | LIST_PART_ENTRY *list_array; |
187 | part_column_list_val *range_col_array; |
188 | part_column_list_val *list_col_array; |
189 | }; |
190 | |
191 | Vers_part_info *vers_info; |
192 | |
193 | /******************************************** |
194 | * INTERVAL ANALYSIS |
195 | ********************************************/ |
196 | /* |
197 | Partitioning interval analysis function for partitioning, or NULL if |
198 | interval analysis is not supported for this kind of partitioning. |
199 | */ |
200 | get_partitions_in_range_iter get_part_iter_for_interval; |
201 | /* |
202 | Partitioning interval analysis function for subpartitioning, or NULL if |
203 | interval analysis is not supported for this kind of partitioning. |
204 | */ |
205 | get_partitions_in_range_iter get_subpart_iter_for_interval; |
206 | |
207 | /******************************************** |
208 | * INTERVAL ANALYSIS ENDS |
209 | ********************************************/ |
210 | |
211 | longlong err_value; |
212 | char* part_info_string; |
213 | |
214 | partition_element *curr_part_elem; // part or sub part |
215 | partition_element *current_partition; // partition |
216 | part_elem_value *curr_list_val; |
217 | uint curr_list_object; |
218 | uint num_columns; |
219 | |
220 | TABLE *table; |
221 | /* |
222 | These key_map's are used for Partitioning to enable quick decisions |
223 | on whether we can derive more information about which partition to |
224 | scan just by looking at what index is used. |
225 | */ |
226 | key_map all_fields_in_PF, all_fields_in_PPF, all_fields_in_SPF; |
227 | key_map some_fields_in_PF; |
228 | |
229 | handlerton *default_engine_type; |
230 | partition_type part_type; |
231 | partition_type subpart_type; |
232 | |
233 | uint part_info_len; |
234 | |
235 | uint num_parts; |
236 | uint num_subparts; |
237 | uint count_curr_subparts; // used during parsing |
238 | |
239 | uint num_list_values; |
240 | |
241 | uint num_part_fields; |
242 | uint num_subpart_fields; |
243 | uint num_full_part_fields; |
244 | |
245 | uint has_null_part_id; |
246 | uint32 default_partition_id; |
247 | /* |
248 | This variable is used to calculate the partition id when using |
249 | LINEAR KEY/HASH. This functionality is kept in the MySQL Server |
250 | but mainly of use to handlers supporting partitioning. |
251 | */ |
252 | uint16 linear_hash_mask; |
253 | /* |
254 | PARTITION BY KEY ALGORITHM=N |
255 | Which algorithm to use for hashing the fields. |
256 | N = 1 - Use 5.1 hashing (numeric fields are hashed as binary) |
257 | N = 2 - Use 5.5 hashing (numeric fields are hashed like latin1 bytes) |
258 | */ |
259 | enum enum_key_algorithm |
260 | { |
261 | KEY_ALGORITHM_NONE= 0, |
262 | KEY_ALGORITHM_51= 1, |
263 | KEY_ALGORITHM_55= 2 |
264 | }; |
265 | enum_key_algorithm key_algorithm; |
266 | |
267 | /* Only the number of partitions defined (uses default names and options). */ |
268 | bool use_default_partitions; |
269 | bool use_default_num_partitions; |
270 | /* Only the number of subpartitions defined (uses default names etc.). */ |
271 | bool use_default_subpartitions; |
272 | bool use_default_num_subpartitions; |
273 | bool default_partitions_setup; |
274 | bool defined_max_value; |
275 | inline bool has_default_partititon() |
276 | { |
277 | return (part_type == LIST_PARTITION && defined_max_value); |
278 | } |
279 | bool list_of_part_fields; // KEY or COLUMNS PARTITIONING |
280 | bool list_of_subpart_fields; // KEY SUBPARTITIONING |
281 | bool linear_hash_ind; // LINEAR HASH/KEY |
282 | bool fixed; |
283 | bool is_auto_partitioned; |
284 | bool has_null_value; |
285 | bool column_list; // COLUMNS PARTITIONING, 5.5+ |
286 | |
287 | partition_info() |
288 | : get_partition_id(NULL), get_part_partition_id(NULL), |
289 | get_subpartition_id(NULL), |
290 | part_field_array(NULL), subpart_field_array(NULL), |
291 | part_charset_field_array(NULL), |
292 | subpart_charset_field_array(NULL), |
293 | full_part_field_array(NULL), |
294 | part_field_buffers(NULL), subpart_field_buffers(NULL), |
295 | restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL), |
296 | part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), |
297 | first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL), |
298 | bitmaps_are_initialized(FALSE), |
299 | list_array(NULL), vers_info(NULL), err_value(0), |
300 | part_info_string(NULL), |
301 | curr_part_elem(NULL), current_partition(NULL), |
302 | curr_list_object(0), num_columns(0), table(NULL), |
303 | default_engine_type(NULL), |
304 | part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION), |
305 | part_info_len(0), |
306 | num_parts(0), num_subparts(0), |
307 | count_curr_subparts(0), |
308 | num_list_values(0), num_part_fields(0), num_subpart_fields(0), |
309 | num_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0), |
310 | key_algorithm(KEY_ALGORITHM_NONE), |
311 | use_default_partitions(TRUE), use_default_num_partitions(TRUE), |
312 | use_default_subpartitions(TRUE), use_default_num_subpartitions(TRUE), |
313 | default_partitions_setup(FALSE), defined_max_value(FALSE), |
314 | list_of_part_fields(FALSE), list_of_subpart_fields(FALSE), |
315 | linear_hash_ind(FALSE), fixed(FALSE), |
316 | is_auto_partitioned(FALSE), |
317 | has_null_value(FALSE), column_list(FALSE) |
318 | { |
319 | all_fields_in_PF.clear_all(); |
320 | all_fields_in_PPF.clear_all(); |
321 | all_fields_in_SPF.clear_all(); |
322 | some_fields_in_PF.clear_all(); |
323 | partitions.empty(); |
324 | temp_partitions.empty(); |
325 | part_field_list.empty(); |
326 | subpart_field_list.empty(); |
327 | } |
328 | ~partition_info() {} |
329 | |
330 | partition_info *get_clone(THD *thd); |
331 | bool set_named_partition_bitmap(const char *part_name, size_t length); |
332 | bool set_partition_bitmaps(List<String> *partition_names); |
333 | bool set_partition_bitmaps_from_table(TABLE_LIST *table_list); |
334 | /* Answers the question if subpartitioning is used for a certain table */ |
335 | bool is_sub_partitioned() |
336 | { |
337 | return (subpart_type == NOT_A_PARTITION ? FALSE : TRUE); |
338 | } |
339 | |
340 | /* Returns the total number of partitions on the leaf level */ |
341 | uint get_tot_partitions() |
342 | { |
343 | return num_parts * (is_sub_partitioned() ? num_subparts : 1); |
344 | } |
345 | |
346 | bool set_up_defaults_for_partitioning(THD *thd, handler *file, |
347 | HA_CREATE_INFO *info, |
348 | uint start_no); |
349 | const char *find_duplicate_field(); |
350 | char *find_duplicate_name(); |
351 | bool check_engine_mix(handlerton *engine_type, bool default_engine); |
352 | bool check_partition_info(THD *thd, handlerton **eng_type, |
353 | handler *file, HA_CREATE_INFO *info, |
354 | partition_info *add_or_reorg_part= NULL); |
355 | void print_no_partition_found(TABLE *table, myf errflag); |
356 | void print_debug(const char *str, uint*); |
357 | Item* get_column_item(Item *item, Field *field); |
358 | int fix_partition_values(THD *thd, |
359 | part_elem_value *val, |
360 | partition_element *part_elem); |
361 | bool fix_column_value_functions(THD *thd, |
362 | part_elem_value *val, |
363 | uint part_id); |
364 | bool fix_parser_data(THD *thd); |
365 | int add_max_value(THD *thd); |
366 | void init_col_val(part_column_list_val *col_val, Item *item); |
367 | int reorganize_into_single_field_col_val(THD *thd); |
368 | part_column_list_val *add_column_value(THD *thd); |
369 | bool set_part_expr(THD *thd, char *start_token, Item *item_ptr, |
370 | char *end_token, bool is_subpart); |
371 | bool set_up_charset_field_preps(THD *thd); |
372 | bool check_partition_field_length(); |
373 | bool init_column_part(THD *thd); |
374 | bool add_column_list_value(THD *thd, Item *item); |
375 | partition_element *get_part_elem(const char *partition_name, char *file_name, |
376 | size_t file_name_size, uint32 *part_id); |
377 | void report_part_expr_error(bool use_subpart_expr); |
378 | bool has_same_partitioning(partition_info *new_part_info); |
379 | bool error_if_requires_values() const; |
380 | private: |
381 | bool set_up_default_partitions(THD *thd, handler *file, HA_CREATE_INFO *info, |
382 | uint start_no); |
383 | bool set_up_default_subpartitions(THD *thd, handler *file, |
384 | HA_CREATE_INFO *info); |
385 | char *create_default_partition_names(THD *thd, uint part_no, uint num_parts, |
386 | uint start_no); |
387 | char *create_default_subpartition_name(THD *thd, uint subpart_no, |
388 | const char *part_name); |
389 | // FIXME: prune_partition_bitmaps() is duplicate of set_read_partitions() |
390 | bool prune_partition_bitmaps(List<String> *partition_names); |
391 | bool add_named_partition(const char *part_name, size_t length); |
392 | public: |
393 | bool set_read_partitions(List<char> *partition_names); |
394 | bool has_unique_name(partition_element *element); |
395 | |
396 | bool vers_init_info(THD *thd); |
397 | bool vers_set_interval(Item *item, interval_type int_type, my_time_t start) |
398 | { |
399 | DBUG_ASSERT(part_type == VERSIONING_PARTITION); |
400 | vers_info->interval.type= int_type; |
401 | vers_info->interval.start= start; |
402 | return get_interval_value(item, int_type, &vers_info->interval.step) || |
403 | vers_info->interval.step.neg || vers_info->interval.step.second_part || |
404 | !(vers_info->interval.step.year || vers_info->interval.step.month || |
405 | vers_info->interval.step.day || vers_info->interval.step.hour || |
406 | vers_info->interval.step.minute || vers_info->interval.step.second); |
407 | } |
408 | bool vers_set_limit(ulonglong limit) |
409 | { |
410 | DBUG_ASSERT(part_type == VERSIONING_PARTITION); |
411 | vers_info->limit= limit; |
412 | return !limit; |
413 | } |
414 | void vers_set_hist_part(THD *thd); |
415 | bool vers_setup_expression(THD *thd, uint32 alter_add= 0); /* Stage 1. */ |
416 | partition_element *get_partition(uint part_id) |
417 | { |
418 | List_iterator<partition_element> it(partitions); |
419 | partition_element *el; |
420 | while ((el= it++)) |
421 | { |
422 | if (el->id == part_id) |
423 | return el; |
424 | } |
425 | return NULL; |
426 | } |
427 | }; |
428 | |
429 | uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); |
430 | bool check_partition_dirs(partition_info *part_info); |
431 | |
432 | /* Initialize the iterator to return a single partition with given part_id */ |
433 | |
434 | static inline void init_single_partition_iterator(uint32 part_id, |
435 | PARTITION_ITERATOR *part_iter) |
436 | { |
437 | part_iter->part_nums.start= part_iter->part_nums.cur= part_id; |
438 | part_iter->part_nums.end= part_id+1; |
439 | part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; |
440 | part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE; |
441 | part_iter->get_next= get_next_partition_id_range; |
442 | } |
443 | |
444 | /* Initialize the iterator to enumerate all partitions */ |
445 | static inline |
446 | void init_all_partitions_iterator(partition_info *part_info, |
447 | PARTITION_ITERATOR *part_iter) |
448 | { |
449 | part_iter->part_nums.start= part_iter->part_nums.cur= 0; |
450 | part_iter->part_nums.end= part_info->num_parts; |
451 | part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; |
452 | part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE; |
453 | part_iter->get_next= get_next_partition_id_range; |
454 | } |
455 | |
456 | #endif /* PARTITION_INFO_INCLUDED */ |
457 | |