1 | #ifndef HA_PARTITION_INCLUDED |
2 | #define HA_PARTITION_INCLUDED |
3 | |
4 | /* |
5 | Copyright (c) 2005, 2012, Oracle and/or its affiliates. |
6 | Copyright (c) 2009, 2013, Monty Program Ab & SkySQL Ab. |
7 | |
8 | This program is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; version 2 of the License. |
11 | |
12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with this program; if not, write to the Free Software |
19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
20 | |
21 | #include "sql_partition.h" /* part_id_range, partition_element */ |
22 | #include "queues.h" /* QUEUE */ |
23 | |
24 | #define PARTITION_BYTES_IN_POS 2 |
25 | |
26 | |
27 | /** Struct used for partition_name_hash */ |
28 | typedef struct st_part_name_def |
29 | { |
30 | uchar *partition_name; |
31 | uint length; |
32 | uint32 part_id; |
33 | my_bool is_subpart; |
34 | } PART_NAME_DEF; |
35 | |
36 | /** class where to save partitions Handler_share's */ |
37 | class Parts_share_refs |
38 | { |
39 | public: |
40 | uint num_parts; /**< Size of ha_share array */ |
41 | Handler_share **ha_shares; /**< Storage for each part */ |
42 | Parts_share_refs() |
43 | { |
44 | num_parts= 0; |
45 | ha_shares= NULL; |
46 | } |
47 | ~Parts_share_refs() |
48 | { |
49 | uint i; |
50 | for (i= 0; i < num_parts; i++) |
51 | delete ha_shares[i]; |
52 | delete[] ha_shares; |
53 | } |
54 | bool init(uint arg_num_parts) |
55 | { |
56 | DBUG_ASSERT(!num_parts && !ha_shares); |
57 | num_parts= arg_num_parts; |
58 | /* Allocate an array of Handler_share pointers */ |
59 | ha_shares= new Handler_share *[num_parts]; |
60 | if (!ha_shares) |
61 | { |
62 | num_parts= 0; |
63 | return true; |
64 | } |
65 | memset(ha_shares, 0, sizeof(Handler_share*) * num_parts); |
66 | return false; |
67 | } |
68 | }; |
69 | |
70 | class ha_partition; |
71 | |
72 | /* Partition Full Text Search info */ |
73 | struct st_partition_ft_info |
74 | { |
75 | struct _ft_vft *please; |
76 | st_partition_ft_info *next; |
77 | ha_partition *file; |
78 | FT_INFO **part_ft_info; |
79 | }; |
80 | |
81 | |
82 | #ifdef HAVE_PSI_MUTEX_INTERFACE |
83 | extern PSI_mutex_key key_partition_auto_inc_mutex; |
84 | #endif |
85 | |
86 | /** |
87 | Partition specific Handler_share. |
88 | */ |
89 | class Partition_share : public Handler_share |
90 | { |
91 | public: |
92 | bool auto_inc_initialized; |
93 | mysql_mutex_t auto_inc_mutex; /**< protecting auto_inc val */ |
94 | ulonglong next_auto_inc_val; /**< first non reserved value */ |
95 | /** |
96 | Hash of partition names. Initialized in the first ha_partition::open() |
97 | for the table_share. After that it is read-only, i.e. no locking required. |
98 | */ |
99 | bool partition_name_hash_initialized; |
100 | HASH partition_name_hash; |
101 | /** Storage for each partitions Handler_share */ |
102 | Parts_share_refs partitions_share_refs; |
103 | Partition_share() |
104 | : auto_inc_initialized(false), |
105 | next_auto_inc_val(0), |
106 | partition_name_hash_initialized(false), |
107 | partition_names(NULL) |
108 | { |
109 | mysql_mutex_init(key_partition_auto_inc_mutex, |
110 | &auto_inc_mutex, |
111 | MY_MUTEX_INIT_FAST); |
112 | } |
113 | |
114 | ~Partition_share() |
115 | { |
116 | mysql_mutex_destroy(&auto_inc_mutex); |
117 | if (partition_names) |
118 | { |
119 | my_free(partition_names); |
120 | } |
121 | if (partition_name_hash_initialized) |
122 | { |
123 | my_hash_free(&partition_name_hash); |
124 | } |
125 | } |
126 | |
127 | bool init(uint num_parts); |
128 | |
129 | /** |
130 | Release reserved auto increment values not used. |
131 | @param thd Thread. |
132 | @param table_share Table Share |
133 | @param next_insert_id Next insert id (first non used auto inc value). |
134 | @param max_reserved End of reserved auto inc range. |
135 | */ |
136 | void release_auto_inc_if_possible(THD *thd, TABLE_SHARE *table_share, |
137 | const ulonglong next_insert_id, |
138 | const ulonglong max_reserved); |
139 | |
140 | /** lock mutex protecting auto increment value next_auto_inc_val. */ |
141 | inline void lock_auto_inc() |
142 | { |
143 | mysql_mutex_lock(&auto_inc_mutex); |
144 | } |
145 | /** unlock mutex protecting auto increment value next_auto_inc_val. */ |
146 | inline void unlock_auto_inc() |
147 | { |
148 | mysql_mutex_unlock(&auto_inc_mutex); |
149 | } |
150 | /** |
151 | Populate partition_name_hash with partition and subpartition names |
152 | from part_info. |
153 | @param part_info Partition info containing all partitions metadata. |
154 | |
155 | @return Operation status. |
156 | @retval false Success. |
157 | @retval true Failure. |
158 | */ |
159 | bool populate_partition_name_hash(partition_info *part_info); |
160 | /** Get partition name. |
161 | |
162 | @param part_id Partition id (for subpartitioned table only subpartition |
163 | names will be returned.) |
164 | |
165 | @return partition name or NULL if error. |
166 | */ |
167 | const char *get_partition_name(size_t part_id) const; |
168 | private: |
169 | const uchar **partition_names; |
170 | /** |
171 | Insert [sub]partition name into partition_name_hash |
172 | @param name Partition name. |
173 | @param part_id Partition id. |
174 | @param is_subpart True if subpartition else partition. |
175 | |
176 | @return Operation status. |
177 | @retval false Success. |
178 | @retval true Failure. |
179 | */ |
180 | bool insert_partition_name_in_hash(const char *name, |
181 | uint part_id, |
182 | bool is_subpart); |
183 | }; |
184 | |
185 | typedef struct st_partition_key_multi_range |
186 | { |
187 | uint id; |
188 | uchar *key[2]; |
189 | uint length[2]; |
190 | KEY_MULTI_RANGE key_multi_range; |
191 | range_id_t ptr; |
192 | st_partition_key_multi_range *next; |
193 | } PARTITION_KEY_MULTI_RANGE; |
194 | |
195 | |
196 | typedef struct st_partition_part_key_multi_range |
197 | { |
198 | PARTITION_KEY_MULTI_RANGE *partition_key_multi_range; |
199 | st_partition_part_key_multi_range *next; |
200 | } PARTITION_PART_KEY_MULTI_RANGE; |
201 | |
202 | |
203 | class ha_partition; |
204 | typedef struct st_partition_part_key_multi_range_hld |
205 | { |
206 | ha_partition *partition; |
207 | uint32 part_id; |
208 | PARTITION_PART_KEY_MULTI_RANGE *partition_part_key_multi_range; |
209 | } PARTITION_PART_KEY_MULTI_RANGE_HLD; |
210 | |
211 | |
212 | extern "C" int cmp_key_part_id(void *key_p, uchar *ref1, uchar *ref2); |
213 | extern "C" int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); |
214 | |
215 | class ha_partition :public handler |
216 | { |
217 | private: |
218 | enum partition_index_scan_type |
219 | { |
220 | partition_index_read= 0, |
221 | partition_index_first= 1, |
222 | partition_index_last= 3, |
223 | partition_index_read_last= 4, |
224 | partition_read_range = 5, |
225 | partition_no_index_scan= 6, |
226 | partition_read_multi_range = 7, |
227 | partition_ft_read= 8 |
228 | }; |
229 | /* Data for the partition handler */ |
230 | int m_mode; // Open mode |
231 | uint m_open_test_lock; // Open test_if_locked |
232 | uchar *m_file_buffer; // Content of the .par file |
233 | char *m_name_buffer_ptr; // Pointer to first partition name |
234 | MEM_ROOT m_mem_root; |
235 | plugin_ref *m_engine_array; // Array of types of the handlers |
236 | handler **m_file; // Array of references to handler inst. |
237 | uint m_file_tot_parts; // Debug |
238 | handler **m_new_file; // Array of references to new handlers |
239 | handler **m_reorged_file; // Reorganised partitions |
240 | handler **m_added_file; // Added parts kept for errors |
241 | LEX_CSTRING *m_connect_string; |
242 | partition_info *m_part_info; // local reference to partition |
243 | Field **m_part_field_array; // Part field array locally to save acc |
244 | uchar *m_ordered_rec_buffer; // Row and key buffer for ord. idx scan |
245 | st_partition_ft_info *ft_first; |
246 | st_partition_ft_info *ft_current; |
247 | /* |
248 | Current index. |
249 | When used in key_rec_cmp: If clustered pk, index compare |
250 | must compare pk if given index is same for two rows. |
251 | So normally m_curr_key_info[0]= current index and m_curr_key[1]= NULL, |
252 | and if clustered pk, [0]= current index, [1]= pk, [2]= NULL |
253 | */ |
254 | KEY *m_curr_key_info[3]; // Current index |
255 | uchar *m_rec0; // table->record[0] |
256 | const uchar *m_err_rec; // record which gave error |
257 | QUEUE m_queue; // Prio queue used by sorted read |
258 | |
259 | /* |
260 | Length of an element in m_ordered_rec_buffer. The elements are composed of |
261 | |
262 | [part_no] [table->record copy] [underlying_table_rowid] |
263 | |
264 | underlying_table_rowid is only stored when the table has no extended keys. |
265 | */ |
266 | size_t m_priority_queue_rec_len; |
267 | |
268 | /* |
269 | If true, then sorting records by key value also sorts them by their |
270 | underlying_table_rowid. |
271 | */ |
272 | bool m_using_extended_keys; |
273 | |
274 | /* |
275 | Since the partition handler is a handler on top of other handlers, it |
276 | is necessary to keep information about what the underlying handler |
277 | characteristics is. It is not possible to keep any handler instances |
278 | for this since the MySQL Server sometimes allocating the handler object |
279 | without freeing them. |
280 | */ |
281 | enum enum_handler_status |
282 | { |
283 | handler_not_initialized= 0, |
284 | handler_initialized, |
285 | handler_opened, |
286 | handler_closed |
287 | }; |
288 | enum_handler_status m_handler_status; |
289 | |
290 | uint m_reorged_parts; // Number of reorganised parts |
291 | uint m_tot_parts; // Total number of partitions; |
292 | uint m_num_locks; // For engines like ha_blackhole, which needs no locks |
293 | uint m_last_part; // Last file that we update,write,read |
294 | part_id_range m_part_spec; // Which parts to scan |
295 | uint m_scan_value; // Value passed in rnd_init |
296 | // call |
297 | uint m_ref_length; // Length of position in this |
298 | // handler object |
299 | key_range m_start_key; // index read key range |
300 | enum partition_index_scan_type m_index_scan_type;// What type of index |
301 | // scan |
302 | uint m_top_entry; // Which partition is to |
303 | // deliver next result |
304 | uint m_rec_length; // Local copy of record length |
305 | |
306 | bool m_ordered; // Ordered/Unordered index scan |
307 | bool m_pkey_is_clustered; // Is primary key clustered |
308 | bool m_create_handler; // Handler used to create table |
309 | bool m_is_sub_partitioned; // Is subpartitioned |
310 | bool m_ordered_scan_ongoing; |
311 | bool m_rnd_init_and_first; |
312 | bool m_ft_init_and_first; |
313 | |
314 | /* |
315 | If set, this object was created with ha_partition::clone and doesn't |
316 | "own" the m_part_info structure. |
317 | */ |
318 | ha_partition *m_is_clone_of; |
319 | MEM_ROOT *m_clone_mem_root; |
320 | |
321 | /* |
322 | We keep track if all underlying handlers are MyISAM since MyISAM has a |
323 | great number of extra flags not needed by other handlers. |
324 | */ |
325 | bool m_myisam; // Are all underlying handlers |
326 | // MyISAM |
327 | /* |
328 | We keep track of InnoDB handlers below since it requires proper setting |
329 | of query_id in fields at index_init and index_read calls. |
330 | */ |
331 | bool m_innodb; // Are all underlying handlers |
332 | // InnoDB |
333 | /* |
334 | When calling extra(HA_EXTRA_CACHE) we do not pass this to the underlying |
335 | handlers immediately. Instead we cache it and call the underlying |
336 | immediately before starting the scan on the partition. This is to |
337 | prevent allocating a READ CACHE for each partition in parallel when |
338 | performing a full table scan on MyISAM partitioned table. |
339 | This state is cleared by extra(HA_EXTRA_NO_CACHE). |
340 | */ |
341 | bool ; |
342 | uint ; |
343 | /* The same goes for HA_EXTRA_PREPARE_FOR_UPDATE */ |
344 | bool ; |
345 | /* Which partition has active cache */ |
346 | uint ; |
347 | |
348 | void init_handler_variables(); |
349 | /* |
350 | Variables for lock structures. |
351 | */ |
352 | THR_LOCK_DATA lock; /* MySQL lock */ |
353 | |
354 | bool auto_increment_lock; /**< lock reading/updating auto_inc */ |
355 | /** |
356 | Flag to keep the auto_increment lock through out the statement. |
357 | This to ensure it will work with statement based replication. |
358 | */ |
359 | bool auto_increment_safe_stmt_log_lock; |
360 | /** For optimizing ha_start_bulk_insert calls */ |
361 | MY_BITMAP m_bulk_insert_started; |
362 | ha_rows m_bulk_inserted_rows; |
363 | /** used for prediction of start_bulk_insert rows */ |
364 | enum_monotonicity_info m_part_func_monotonicity_info; |
365 | part_id_range m_direct_update_part_spec; |
366 | bool m_pre_calling; |
367 | bool m_pre_call_use_parallel; |
368 | /* Keep track of bulk access requests */ |
369 | bool bulk_access_executing; |
370 | |
371 | /** keep track of locked partitions */ |
372 | MY_BITMAP m_locked_partitions; |
373 | /** Stores shared auto_increment etc. */ |
374 | Partition_share *part_share; |
375 | /** Temporary storage for new partitions Handler_shares during ALTER */ |
376 | List<Parts_share_refs> m_new_partitions_share_refs; |
377 | /** Sorted array of partition ids in descending order of number of rows. */ |
378 | uint32 *m_part_ids_sorted_by_num_of_records; |
379 | /* Compare function for my_qsort2, for reversed order. */ |
380 | static int compare_number_of_records(ha_partition *me, |
381 | const uint32 *a, |
382 | const uint32 *b); |
383 | /** keep track of partitions to call ha_reset */ |
384 | MY_BITMAP m_partitions_to_reset; |
385 | /** partitions that returned HA_ERR_KEY_NOT_FOUND. */ |
386 | MY_BITMAP m_key_not_found_partitions; |
387 | bool m_key_not_found; |
388 | List<String> *m_partitions_to_open; |
389 | MY_BITMAP m_opened_partitions; |
390 | /** This is one of the m_file-s that it guaranteed to be opened. */ |
391 | /** It is set in open_read_partitions() */ |
392 | handler *m_file_sample; |
393 | public: |
394 | handler **get_child_handlers() |
395 | { |
396 | return m_file; |
397 | } |
398 | virtual part_id_range *get_part_spec() |
399 | { |
400 | return &m_part_spec; |
401 | } |
402 | virtual uint get_no_current_part_id() |
403 | { |
404 | return NO_CURRENT_PART_ID; |
405 | } |
406 | Partition_share *get_part_share() { return part_share; } |
407 | handler *clone(const char *name, MEM_ROOT *mem_root); |
408 | virtual void set_part_info(partition_info *part_info) |
409 | { |
410 | m_part_info= part_info; |
411 | m_is_sub_partitioned= part_info->is_sub_partitioned(); |
412 | } |
413 | |
414 | virtual void return_record_by_parent(); |
415 | |
416 | /* |
417 | ------------------------------------------------------------------------- |
418 | MODULE create/delete handler object |
419 | ------------------------------------------------------------------------- |
420 | Object create/delete methode. The normal called when a table object |
421 | exists. There is also a method to create the handler object with only |
422 | partition information. This is used from mysql_create_table when the |
423 | table is to be created and the engine type is deduced to be the |
424 | partition handler. |
425 | ------------------------------------------------------------------------- |
426 | */ |
427 | ha_partition(handlerton *hton, TABLE_SHARE * table); |
428 | ha_partition(handlerton *hton, partition_info * part_info); |
429 | ha_partition(handlerton *hton, TABLE_SHARE *share, |
430 | partition_info *part_info_arg, |
431 | ha_partition *clone_arg, |
432 | MEM_ROOT *clone_mem_root_arg); |
433 | ~ha_partition(); |
434 | void ha_partition_init(); |
435 | /* |
436 | A partition handler has no characteristics in itself. It only inherits |
437 | those from the underlying handlers. Here we set-up those constants to |
438 | enable later calls of the methods to retrieve constants from the under- |
439 | lying handlers. Returns false if not successful. |
440 | */ |
441 | bool initialize_partition(MEM_ROOT *mem_root); |
442 | |
443 | /* |
444 | ------------------------------------------------------------------------- |
445 | MODULE meta data changes |
446 | ------------------------------------------------------------------------- |
447 | Meta data routines to CREATE, DROP, RENAME table and often used at |
448 | ALTER TABLE (update_create_info used from ALTER TABLE and SHOW ..). |
449 | |
450 | update_table_comment is used in SHOW TABLE commands to provide a |
451 | chance for the handler to add any interesting comments to the table |
452 | comments not provided by the users comment. |
453 | |
454 | create_partitioning_metadata is called before opening a new handler object |
455 | with openfrm to call create. It is used to create any local handler |
456 | object needed in opening the object in openfrm |
457 | ------------------------------------------------------------------------- |
458 | */ |
459 | virtual int delete_table(const char *from); |
460 | virtual int rename_table(const char *from, const char *to); |
461 | virtual int create(const char *name, TABLE *form, |
462 | HA_CREATE_INFO *create_info); |
463 | virtual int create_partitioning_metadata(const char *name, |
464 | const char *old_name, int action_flag); |
465 | virtual void update_create_info(HA_CREATE_INFO *create_info); |
466 | virtual char *(const char *); |
467 | virtual int change_partitions(HA_CREATE_INFO *create_info, |
468 | const char *path, |
469 | ulonglong * const copied, |
470 | ulonglong * const deleted, |
471 | const uchar *pack_frm_data, |
472 | size_t pack_frm_len); |
473 | virtual int drop_partitions(const char *path); |
474 | virtual int rename_partitions(const char *path); |
475 | bool get_no_parts(const char *name, uint *num_parts) |
476 | { |
477 | DBUG_ENTER("ha_partition::get_no_parts" ); |
478 | *num_parts= m_tot_parts; |
479 | DBUG_RETURN(0); |
480 | } |
481 | virtual void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share); |
482 | virtual bool check_if_incompatible_data(HA_CREATE_INFO *create_info, |
483 | uint table_changes); |
484 | void update_part_create_info(HA_CREATE_INFO *create_info, uint part_id) |
485 | { |
486 | m_file[part_id]->update_create_info(create_info); |
487 | } |
488 | private: |
489 | int copy_partitions(ulonglong * const copied, ulonglong * const deleted); |
490 | void cleanup_new_partition(uint part_count); |
491 | int prepare_new_partition(TABLE *table, HA_CREATE_INFO *create_info, |
492 | handler *file, const char *part_name, |
493 | partition_element *p_elem, |
494 | uint disable_non_uniq_indexes); |
495 | /* |
496 | delete_table and rename_table uses very similar logic which |
497 | is packed into this routine. |
498 | */ |
499 | uint del_ren_table(const char *from, const char *to); |
500 | /* |
501 | One method to create the table_name.par file containing the names of the |
502 | underlying partitions, their engine and the number of partitions. |
503 | And one method to read it in. |
504 | */ |
505 | bool create_handler_file(const char *name); |
506 | bool setup_engine_array(MEM_ROOT *mem_root); |
507 | bool read_par_file(const char *name); |
508 | bool get_from_handler_file(const char *name, MEM_ROOT *mem_root, |
509 | bool is_clone); |
510 | bool new_handlers_from_part_info(MEM_ROOT *mem_root); |
511 | bool create_handlers(MEM_ROOT *mem_root); |
512 | void clear_handler_file(); |
513 | int set_up_table_before_create(TABLE *table_arg, |
514 | const char *partition_name_with_path, |
515 | HA_CREATE_INFO *info, |
516 | partition_element *p_elem); |
517 | partition_element *find_partition_element(uint part_id); |
518 | bool insert_partition_name_in_hash(const char *name, uint part_id, |
519 | bool is_subpart); |
520 | bool populate_partition_name_hash(); |
521 | Partition_share *get_share(); |
522 | bool set_ha_share_ref(Handler_share **ha_share); |
523 | void fix_data_dir(char* path); |
524 | bool init_partition_bitmaps(); |
525 | void free_partition_bitmaps(); |
526 | |
527 | public: |
528 | |
529 | /* |
530 | ------------------------------------------------------------------------- |
531 | MODULE open/close object |
532 | ------------------------------------------------------------------------- |
533 | Open and close handler object to ensure all underlying files and |
534 | objects allocated and deallocated for query handling is handled |
535 | properly. |
536 | ------------------------------------------------------------------------- |
537 | |
538 | A handler object is opened as part of its initialisation and before |
539 | being used for normal queries (not before meta-data changes always. |
540 | If the object was opened it will also be closed before being deleted. |
541 | */ |
542 | virtual int open(const char *name, int mode, uint test_if_locked); |
543 | virtual int close(void); |
544 | |
545 | /* |
546 | ------------------------------------------------------------------------- |
547 | MODULE start/end statement |
548 | ------------------------------------------------------------------------- |
549 | This module contains methods that are used to understand start/end of |
550 | statements, transaction boundaries, and aid for proper concurrency |
551 | control. |
552 | The partition handler need not implement abort and commit since this |
553 | will be handled by any underlying handlers implementing transactions. |
554 | There is only one call to each handler type involved per transaction |
555 | and these go directly to the handlers supporting transactions |
556 | ------------------------------------------------------------------------- |
557 | */ |
558 | virtual THR_LOCK_DATA **store_lock(THD * thd, THR_LOCK_DATA ** to, |
559 | enum thr_lock_type lock_type); |
560 | virtual int external_lock(THD * thd, int lock_type); |
561 | LEX_CSTRING *engine_name() { return hton_name(partition_ht()); } |
562 | /* |
563 | When table is locked a statement is started by calling start_stmt |
564 | instead of external_lock |
565 | */ |
566 | virtual int start_stmt(THD * thd, thr_lock_type lock_type); |
567 | /* |
568 | Lock count is number of locked underlying handlers (I assume) |
569 | */ |
570 | virtual uint lock_count(void) const; |
571 | /* |
572 | Call to unlock rows not to be updated in transaction |
573 | */ |
574 | virtual void unlock_row(); |
575 | /* |
576 | Check if semi consistent read |
577 | */ |
578 | virtual bool was_semi_consistent_read(); |
579 | /* |
580 | Call to hint about semi consistent read |
581 | */ |
582 | virtual void try_semi_consistent_read(bool); |
583 | |
584 | /* |
585 | NOTE: due to performance and resource issues with many partitions, |
586 | we only use the m_psi on the ha_partition handler, excluding all |
587 | partitions m_psi. |
588 | */ |
589 | #ifdef HAVE_M_PSI_PER_PARTITION |
590 | /* |
591 | Bind the table/handler thread to track table i/o. |
592 | */ |
593 | virtual void unbind_psi(); |
594 | virtual void rebind_psi(); |
595 | #endif |
596 | /* |
597 | ------------------------------------------------------------------------- |
598 | MODULE change record |
599 | ------------------------------------------------------------------------- |
600 | This part of the handler interface is used to change the records |
601 | after INSERT, DELETE, UPDATE, REPLACE method calls but also other |
602 | special meta-data operations as ALTER TABLE, LOAD DATA, TRUNCATE. |
603 | ------------------------------------------------------------------------- |
604 | |
605 | These methods are used for insert (write_row), update (update_row) |
606 | and delete (delete_row). All methods to change data always work on |
607 | one row at a time. update_row and delete_row also contains the old |
608 | row. |
609 | delete_all_rows will delete all rows in the table in one call as a |
610 | special optimisation for DELETE from table; |
611 | |
612 | Bulk inserts are supported if all underlying handlers support it. |
613 | start_bulk_insert and end_bulk_insert is called before and after a |
614 | number of calls to write_row. |
615 | */ |
616 | virtual int write_row(uchar * buf); |
617 | virtual bool start_bulk_update(); |
618 | virtual int exec_bulk_update(ha_rows *dup_key_found); |
619 | virtual int end_bulk_update(); |
620 | virtual int bulk_update_row(const uchar *old_data, const uchar *new_data, |
621 | ha_rows *dup_key_found); |
622 | virtual int update_row(const uchar * old_data, const uchar * new_data); |
623 | virtual int direct_update_rows_init(); |
624 | virtual int pre_direct_update_rows_init(); |
625 | virtual int direct_update_rows(ha_rows *update_rows); |
626 | virtual int pre_direct_update_rows(); |
627 | virtual bool start_bulk_delete(); |
628 | virtual int end_bulk_delete(); |
629 | virtual int delete_row(const uchar * buf); |
630 | virtual int direct_delete_rows_init(); |
631 | virtual int pre_direct_delete_rows_init(); |
632 | virtual int direct_delete_rows(ha_rows *delete_rows); |
633 | virtual int pre_direct_delete_rows(); |
634 | virtual int delete_all_rows(void); |
635 | virtual int truncate(); |
636 | virtual void start_bulk_insert(ha_rows rows, uint flags); |
637 | virtual int end_bulk_insert(); |
638 | private: |
639 | ha_rows guess_bulk_insert_rows(); |
640 | void start_part_bulk_insert(THD *thd, uint part_id); |
641 | long estimate_read_buffer_size(long original_size); |
642 | public: |
643 | |
644 | /* |
645 | Method for truncating a specific partition. |
646 | (i.e. ALTER TABLE t1 TRUNCATE PARTITION p). |
647 | |
648 | @remark This method is a partitioning-specific hook |
649 | and thus not a member of the general SE API. |
650 | */ |
651 | int truncate_partition(Alter_info *, bool *binlog_stmt); |
652 | |
653 | virtual bool is_fatal_error(int error, uint flags) |
654 | { |
655 | if (!handler::is_fatal_error(error, flags) || |
656 | error == HA_ERR_NO_PARTITION_FOUND || |
657 | error == HA_ERR_NOT_IN_LOCK_PARTITIONS) |
658 | return FALSE; |
659 | return TRUE; |
660 | } |
661 | |
662 | |
663 | /* |
664 | ------------------------------------------------------------------------- |
665 | MODULE full table scan |
666 | ------------------------------------------------------------------------- |
667 | This module is used for the most basic access method for any table |
668 | handler. This is to fetch all data through a full table scan. No |
669 | indexes are needed to implement this part. |
670 | It contains one method to start the scan (rnd_init) that can also be |
671 | called multiple times (typical in a nested loop join). Then proceeding |
672 | to the next record (rnd_next) and closing the scan (rnd_end). |
673 | To remember a record for later access there is a method (position) |
674 | and there is a method used to retrieve the record based on the stored |
675 | position. |
676 | The position can be a file position, a primary key, a ROWID dependent |
677 | on the handler below. |
678 | ------------------------------------------------------------------------- |
679 | */ |
680 | /* |
681 | unlike index_init(), rnd_init() can be called two times |
682 | without rnd_end() in between (it only makes sense if scan=1). |
683 | then the second call should prepare for the new table scan |
684 | (e.g if rnd_init allocates the cursor, second call should |
685 | position it to the start of the table, no need to deallocate |
686 | and allocate it again |
687 | */ |
688 | virtual int rnd_init(bool scan); |
689 | virtual int rnd_end(); |
690 | virtual int rnd_next(uchar * buf); |
691 | virtual int rnd_pos(uchar * buf, uchar * pos); |
692 | virtual int rnd_pos_by_record(uchar *record); |
693 | virtual void position(const uchar * record); |
694 | |
695 | /* |
696 | ------------------------------------------------------------------------- |
697 | MODULE index scan |
698 | ------------------------------------------------------------------------- |
699 | This part of the handler interface is used to perform access through |
700 | indexes. The interface is defined as a scan interface but the handler |
701 | can also use key lookup if the index is a unique index or a primary |
702 | key index. |
703 | Index scans are mostly useful for SELECT queries but are an important |
704 | part also of UPDATE, DELETE, REPLACE and CREATE TABLE table AS SELECT |
705 | and so forth. |
706 | Naturally an index is needed for an index scan and indexes can either |
707 | be ordered, hash based. Some ordered indexes can return data in order |
708 | but not necessarily all of them. |
709 | There are many flags that define the behavior of indexes in the |
710 | various handlers. These methods are found in the optimizer module. |
711 | ------------------------------------------------------------------------- |
712 | |
713 | index_read is called to start a scan of an index. The find_flag defines |
714 | the semantics of the scan. These flags are defined in |
715 | include/my_base.h |
716 | index_read_idx is the same but also initializes index before calling doing |
717 | the same thing as index_read. Thus it is similar to index_init followed |
718 | by index_read. This is also how we implement it. |
719 | |
720 | index_read/index_read_idx does also return the first row. Thus for |
721 | key lookups, the index_read will be the only call to the handler in |
722 | the index scan. |
723 | |
724 | index_init initializes an index before using it and index_end does |
725 | any end processing needed. |
726 | */ |
727 | virtual int index_read_map(uchar * buf, const uchar * key, |
728 | key_part_map keypart_map, |
729 | enum ha_rkey_function find_flag); |
730 | virtual int index_init(uint idx, bool sorted); |
731 | virtual int index_end(); |
732 | |
733 | /** |
734 | @breif |
735 | Positions an index cursor to the index specified in the hanlde. Fetches the |
736 | row if available. If the key value is null, begin at first key of the |
737 | index. |
738 | */ |
739 | virtual int index_read_idx_map(uchar *buf, uint index, const uchar *key, |
740 | key_part_map keypart_map, |
741 | enum ha_rkey_function find_flag); |
742 | /* |
743 | These methods are used to jump to next or previous entry in the index |
744 | scan. There are also methods to jump to first and last entry. |
745 | */ |
746 | virtual int index_next(uchar * buf); |
747 | virtual int index_prev(uchar * buf); |
748 | virtual int index_first(uchar * buf); |
749 | virtual int index_last(uchar * buf); |
750 | virtual int index_next_same(uchar * buf, const uchar * key, uint keylen); |
751 | |
752 | int index_read_last_map(uchar *buf, |
753 | const uchar *key, |
754 | key_part_map keypart_map); |
755 | |
756 | /* |
757 | read_first_row is virtual method but is only implemented by |
758 | handler.cc, no storage engine has implemented it so neither |
759 | will the partition handler. |
760 | |
761 | virtual int read_first_row(uchar *buf, uint primary_key); |
762 | */ |
763 | |
764 | |
765 | virtual int read_range_first(const key_range * start_key, |
766 | const key_range * end_key, |
767 | bool eq_range, bool sorted); |
768 | virtual int read_range_next(); |
769 | |
770 | |
771 | HANDLER_BUFFER *m_mrr_buffer; |
772 | uint *m_mrr_buffer_size; |
773 | uchar *m_mrr_full_buffer; |
774 | uint m_mrr_full_buffer_size; |
775 | uint m_mrr_new_full_buffer_size; |
776 | MY_BITMAP m_mrr_used_partitions; |
777 | uint *m_stock_range_seq; |
778 | uint m_current_range_seq; |
779 | uint m_mrr_mode; |
780 | uint m_mrr_n_ranges; |
781 | range_id_t *m_range_info; |
782 | bool m_multi_range_read_first; |
783 | uint m_mrr_range_init_flags; |
784 | uint m_mrr_range_length; |
785 | PARTITION_KEY_MULTI_RANGE *m_mrr_range_first; |
786 | PARTITION_KEY_MULTI_RANGE *m_mrr_range_current; |
787 | uint *m_part_mrr_range_length; |
788 | PARTITION_PART_KEY_MULTI_RANGE **m_part_mrr_range_first; |
789 | PARTITION_PART_KEY_MULTI_RANGE **m_part_mrr_range_current; |
790 | PARTITION_PART_KEY_MULTI_RANGE_HLD *m_partition_part_key_multi_range_hld; |
791 | range_seq_t m_seq; |
792 | RANGE_SEQ_IF *m_seq_if; |
793 | RANGE_SEQ_IF m_part_seq_if; |
794 | |
795 | virtual int multi_range_key_create_key( |
796 | RANGE_SEQ_IF *seq, |
797 | range_seq_t seq_it |
798 | ); |
799 | virtual ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, |
800 | void *seq_init_param, |
801 | uint n_ranges, uint *bufsz, |
802 | uint *mrr_mode, |
803 | Cost_estimate *cost); |
804 | virtual ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, |
805 | uint key_parts, uint *bufsz, |
806 | uint *mrr_mode, Cost_estimate *cost); |
807 | virtual int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param, |
808 | uint n_ranges, uint mrr_mode, |
809 | HANDLER_BUFFER *buf); |
810 | virtual int multi_range_read_next(range_id_t *range_info); |
811 | virtual int multi_range_read_explain_info(uint mrr_mode, char *str, |
812 | size_t size); |
813 | uint last_part() { return m_last_part; } |
814 | |
815 | private: |
816 | bool init_record_priority_queue(); |
817 | void destroy_record_priority_queue(); |
818 | int common_index_read(uchar * buf, bool have_start_key); |
819 | int common_first_last(uchar * buf); |
820 | int partition_scan_set_up(uchar * buf, bool idx_read_flag); |
821 | bool check_parallel_search(); |
822 | int handle_pre_scan(bool reverse_order, bool use_parallel); |
823 | int handle_unordered_next(uchar * buf, bool next_same); |
824 | int handle_unordered_scan_next_partition(uchar * buf); |
825 | int handle_ordered_index_scan(uchar * buf, bool reverse_order); |
826 | int handle_ordered_index_scan_key_not_found(); |
827 | int handle_ordered_next(uchar * buf, bool next_same); |
828 | int handle_ordered_prev(uchar * buf); |
829 | void return_top_record(uchar * buf); |
830 | public: |
831 | /* |
832 | ------------------------------------------------------------------------- |
833 | MODULE information calls |
834 | ------------------------------------------------------------------------- |
835 | This calls are used to inform the handler of specifics of the ongoing |
836 | scans and other actions. Most of these are used for optimisation |
837 | purposes. |
838 | ------------------------------------------------------------------------- |
839 | */ |
840 | virtual int info(uint); |
841 | void get_dynamic_partition_info(PARTITION_STATS *stat_info, |
842 | uint part_id); |
843 | void set_partitions_to_open(List<String> *partition_names); |
844 | int change_partitions_to_open(List<String> *partition_names); |
845 | int open_read_partitions(char *name_buff, size_t name_buff_size); |
846 | virtual int (enum ha_extra_function operation); |
847 | virtual int (enum ha_extra_function operation, ulong cachesize); |
848 | virtual int reset(void); |
849 | virtual uint count_query_cache_dependant_tables(uint8 *tables_type); |
850 | virtual my_bool |
851 | register_query_cache_dependant_tables(THD *thd, |
852 | Query_cache *cache, |
853 | Query_cache_block_table **block, |
854 | uint *n); |
855 | |
856 | private: |
857 | my_bool reg_query_cache_dependant_table(THD *thd, |
858 | char *engine_key, |
859 | uint engine_key_len, |
860 | char *query_key, uint query_key_len, |
861 | uint8 type, |
862 | Query_cache *cache, |
863 | Query_cache_block_table |
864 | **block_table, |
865 | handler *file, uint *n); |
866 | static const uint NO_CURRENT_PART_ID= NOT_A_PARTITION_ID; |
867 | int (enum ha_extra_function operation); |
868 | int (enum ha_extra_function operations); |
869 | void (uint partition_id); |
870 | void (uint partition_id); |
871 | void (uint cachesize); |
872 | handler *get_open_file_sample() const { return m_file_sample; } |
873 | public: |
874 | |
875 | /* |
876 | ------------------------------------------------------------------------- |
877 | MODULE optimiser support |
878 | ------------------------------------------------------------------------- |
879 | ------------------------------------------------------------------------- |
880 | */ |
881 | |
882 | /* |
883 | NOTE !!!!!! |
884 | ------------------------------------------------------------------------- |
885 | ------------------------------------------------------------------------- |
886 | One important part of the public handler interface that is not depicted in |
887 | the methods is the attribute records |
888 | |
889 | which is defined in the base class. This is looked upon directly and is |
890 | set by calling info(HA_STATUS_INFO) ? |
891 | ------------------------------------------------------------------------- |
892 | */ |
893 | |
894 | private: |
895 | /* Helper functions for optimizer hints. */ |
896 | ha_rows min_rows_for_estimate(); |
897 | uint get_biggest_used_partition(uint *part_index); |
898 | public: |
899 | |
900 | /* |
901 | keys_to_use_for_scanning can probably be implemented as the |
902 | intersection of all underlying handlers if mixed handlers are used. |
903 | This method is used to derive whether an index can be used for |
904 | index-only scanning when performing an ORDER BY query. |
905 | Only called from one place in sql_select.cc |
906 | */ |
907 | virtual const key_map *keys_to_use_for_scanning(); |
908 | |
909 | /* |
910 | Called in test_quick_select to determine if indexes should be used. |
911 | */ |
912 | virtual double scan_time(); |
913 | |
914 | /* |
915 | The next method will never be called if you do not implement indexes. |
916 | */ |
917 | virtual double read_time(uint index, uint ranges, ha_rows rows); |
918 | /* |
919 | For the given range how many records are estimated to be in this range. |
920 | Used by optimiser to calculate cost of using a particular index. |
921 | */ |
922 | virtual ha_rows records_in_range(uint inx, key_range * min_key, |
923 | key_range * max_key); |
924 | |
925 | /* |
926 | Upper bound of number records returned in scan is sum of all |
927 | underlying handlers. |
928 | */ |
929 | virtual ha_rows estimate_rows_upper_bound(); |
930 | |
931 | /* |
932 | table_cache_type is implemented by the underlying handler but all |
933 | underlying handlers must have the same implementation for it to work. |
934 | */ |
935 | virtual uint8 table_cache_type(); |
936 | virtual ha_rows records(); |
937 | |
938 | /* Calculate hash value for PARTITION BY KEY tables. */ |
939 | static uint32 calculate_key_hash_value(Field **field_array); |
940 | |
941 | /* |
942 | ------------------------------------------------------------------------- |
943 | MODULE print messages |
944 | ------------------------------------------------------------------------- |
945 | This module contains various methods that returns text messages for |
946 | table types, index type and error messages. |
947 | ------------------------------------------------------------------------- |
948 | */ |
949 | /* |
950 | The name of the index type that will be used for display |
951 | Here we must ensure that all handlers use the same index type |
952 | for each index created. |
953 | */ |
954 | virtual const char *index_type(uint inx); |
955 | |
956 | /* The name of the table type that will be used for display purposes */ |
957 | virtual const char *table_type() const; |
958 | |
959 | /* The name of the row type used for the underlying tables. */ |
960 | virtual enum row_type get_row_type() const; |
961 | |
962 | /* |
963 | Handler specific error messages |
964 | */ |
965 | virtual void print_error(int error, myf errflag); |
966 | virtual bool get_error_message(int error, String * buf); |
967 | /* |
968 | ------------------------------------------------------------------------- |
969 | MODULE handler characteristics |
970 | ------------------------------------------------------------------------- |
971 | This module contains a number of methods defining limitations and |
972 | characteristics of the handler. The partition handler will calculate |
973 | this characteristics based on underlying handler characteristics. |
974 | ------------------------------------------------------------------------- |
975 | |
976 | This is a list of flags that says what the storage engine |
977 | implements. The current table flags are documented in handler.h |
978 | The partition handler will support whatever the underlying handlers |
979 | support except when specifically mentioned below about exceptions |
980 | to this rule. |
981 | NOTE: This cannot be cached since it can depend on TRANSACTION ISOLATION |
982 | LEVEL which is dynamic, see bug#39084. |
983 | |
984 | HA_READ_RND_SAME: |
985 | Not currently used. (Means that the handler supports the rnd_same() call) |
986 | (MyISAM, HEAP) |
987 | |
988 | HA_TABLE_SCAN_ON_INDEX: |
989 | Used to avoid scanning full tables on an index. If this flag is set then |
990 | the handler always has a primary key (hidden if not defined) and this |
991 | index is used for scanning rather than a full table scan in all |
992 | situations. |
993 | (InnoDB, Federated) |
994 | |
995 | HA_REC_NOT_IN_SEQ: |
996 | This flag is set for handlers that cannot guarantee that the rows are |
997 | returned accroding to incremental positions (0, 1, 2, 3...). |
998 | This also means that rnd_next() should return HA_ERR_RECORD_DELETED |
999 | if it finds a deleted row. |
1000 | (MyISAM (not fixed length row), HEAP, InnoDB) |
1001 | |
1002 | HA_CAN_GEOMETRY: |
1003 | Can the storage engine handle spatial data. |
1004 | Used to check that no spatial attributes are declared unless |
1005 | the storage engine is capable of handling it. |
1006 | (MyISAM) |
1007 | |
1008 | HA_FAST_KEY_READ: |
1009 | Setting this flag indicates that the handler is equally fast in |
1010 | finding a row by key as by position. |
1011 | This flag is used in a very special situation in conjunction with |
1012 | filesort's. For further explanation see intro to init_read_record. |
1013 | (HEAP, InnoDB) |
1014 | |
1015 | HA_NULL_IN_KEY: |
1016 | Is NULL values allowed in indexes. |
1017 | If this is not allowed then it is not possible to use an index on a |
1018 | NULLable field. |
1019 | (HEAP, MyISAM, InnoDB) |
1020 | |
1021 | HA_DUPLICATE_POS: |
1022 | Tells that we can the position for the conflicting duplicate key |
1023 | record is stored in table->file->dupp_ref. (insert uses rnd_pos() on |
1024 | this to find the duplicated row) |
1025 | (MyISAM) |
1026 | |
1027 | HA_CAN_INDEX_BLOBS: |
1028 | Is the storage engine capable of defining an index of a prefix on |
1029 | a BLOB attribute. |
1030 | (Federated, MyISAM, InnoDB) |
1031 | |
1032 | HA_AUTO_PART_KEY: |
1033 | Auto increment fields can be part of a multi-part key. For second part |
1034 | auto-increment keys, the auto_incrementing is done in handler.cc |
1035 | (Federated, MyISAM) |
1036 | |
1037 | HA_REQUIRE_PRIMARY_KEY: |
1038 | Can't define a table without primary key (and cannot handle a table |
1039 | with hidden primary key) |
1040 | (No handler has this limitation currently) |
1041 | |
1042 | HA_STATS_RECORDS_IS_EXACT: |
1043 | Does the counter of records after the info call specify an exact |
1044 | value or not. If it does this flag is set. |
1045 | Only MyISAM and HEAP uses exact count. |
1046 | |
1047 | HA_CAN_INSERT_DELAYED: |
1048 | Can the storage engine support delayed inserts. |
1049 | To start with the partition handler will not support delayed inserts. |
1050 | Further investigation needed. |
1051 | (HEAP, MyISAM) |
1052 | |
1053 | HA_PRIMARY_KEY_IN_READ_INDEX: |
1054 | This parameter is set when the handler will also return the primary key |
1055 | when doing read-only-key on another index. |
1056 | |
1057 | HA_NOT_DELETE_WITH_CACHE: |
1058 | Seems to be an old MyISAM feature that is no longer used. No handler |
1059 | has it defined but it is checked in init_read_record. |
1060 | Further investigation needed. |
1061 | (No handler defines it) |
1062 | |
1063 | HA_NO_PREFIX_CHAR_KEYS: |
1064 | Indexes on prefixes of character fields is not allowed. |
1065 | (Federated) |
1066 | |
1067 | HA_CAN_FULLTEXT: |
1068 | Does the storage engine support fulltext indexes |
1069 | The partition handler will start by not supporting fulltext indexes. |
1070 | (MyISAM) |
1071 | |
1072 | HA_CAN_SQL_HANDLER: |
1073 | Can the HANDLER interface in the MySQL API be used towards this |
1074 | storage engine. |
1075 | (MyISAM, InnoDB) |
1076 | |
1077 | HA_NO_AUTO_INCREMENT: |
1078 | Set if the storage engine does not support auto increment fields. |
1079 | (Currently not set by any handler) |
1080 | |
1081 | HA_HAS_CHECKSUM: |
1082 | Special MyISAM feature. Has special SQL support in CREATE TABLE. |
1083 | No special handling needed by partition handler. |
1084 | (MyISAM) |
1085 | |
1086 | HA_FILE_BASED: |
1087 | Should file names always be in lower case (used by engines |
1088 | that map table names to file names. |
1089 | Since partition handler has a local file this flag is set. |
1090 | (Federated, MyISAM) |
1091 | |
1092 | HA_CAN_BIT_FIELD: |
1093 | Is the storage engine capable of handling bit fields? |
1094 | (MyISAM) |
1095 | |
1096 | HA_NEED_READ_RANGE_BUFFER: |
1097 | Is Read Multi-Range supported => need multi read range buffer |
1098 | This parameter specifies whether a buffer for read multi range |
1099 | is needed by the handler. Whether the handler supports this |
1100 | feature or not is dependent of whether the handler implements |
1101 | read_multi_range* calls or not. The only handler currently |
1102 | supporting this feature is NDB so the partition handler need |
1103 | not handle this call. There are methods in handler.cc that will |
1104 | transfer those calls into index_read and other calls in the |
1105 | index scan module. |
1106 | (No handler defines it) |
1107 | |
1108 | HA_PRIMARY_KEY_REQUIRED_FOR_POSITION: |
1109 | Does the storage engine need a PK for position? |
1110 | (InnoDB) |
1111 | |
1112 | HA_FILE_BASED is always set for partition handler since we use a |
1113 | special file for handling names of partitions, engine types. |
1114 | HA_REC_NOT_IN_SEQ is always set for partition handler since we cannot |
1115 | guarantee that the records will be returned in sequence. |
1116 | HA_DUPLICATE_POS, |
1117 | HA_CAN_INSERT_DELAYED, HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is disabled |
1118 | until further investigated. |
1119 | */ |
1120 | virtual Table_flags table_flags() const; |
1121 | |
1122 | /* |
1123 | This is a bitmap of flags that says how the storage engine |
1124 | implements indexes. The current index flags are documented in |
1125 | handler.h. If you do not implement indexes, just return zero |
1126 | here. |
1127 | |
1128 | part is the key part to check. First key part is 0 |
1129 | If all_parts it's set, MySQL want to know the flags for the combined |
1130 | index up to and including 'part'. |
1131 | |
1132 | HA_READ_NEXT: |
1133 | Does the index support read next, this is assumed in the server |
1134 | code and never checked so all indexes must support this. |
1135 | Note that the handler can be used even if it doesn't have any index. |
1136 | (HEAP, MyISAM, Federated, InnoDB) |
1137 | |
1138 | HA_READ_PREV: |
1139 | Can the index be used to scan backwards. |
1140 | (HEAP, MyISAM, InnoDB) |
1141 | |
1142 | HA_READ_ORDER: |
1143 | Can the index deliver its record in index order. Typically true for |
1144 | all ordered indexes and not true for hash indexes. |
1145 | In first step this is not true for partition handler until a merge |
1146 | sort has been implemented in partition handler. |
1147 | Used to set keymap part_of_sortkey |
1148 | This keymap is only used to find indexes usable for resolving an ORDER BY |
1149 | in the query. Thus in most cases index_read will work just fine without |
1150 | order in result production. When this flag is set it is however safe to |
1151 | order all output started by index_read since most engines do this. With |
1152 | read_multi_range calls there is a specific flag setting order or not |
1153 | order so in those cases ordering of index output can be avoided. |
1154 | (InnoDB, HEAP, MyISAM) |
1155 | |
1156 | HA_READ_RANGE: |
1157 | Specify whether index can handle ranges, typically true for all |
1158 | ordered indexes and not true for hash indexes. |
1159 | Used by optimiser to check if ranges (as key >= 5) can be optimised |
1160 | by index. |
1161 | (InnoDB, MyISAM, HEAP) |
1162 | |
1163 | HA_ONLY_WHOLE_INDEX: |
1164 | Can't use part key searches. This is typically true for hash indexes |
1165 | and typically not true for ordered indexes. |
1166 | (Federated, HEAP) |
1167 | |
1168 | HA_KEYREAD_ONLY: |
1169 | Does the storage engine support index-only scans on this index. |
1170 | Enables use of HA_EXTRA_KEYREAD and HA_EXTRA_NO_KEYREAD |
1171 | Used to set key_map keys_for_keyread and to check in optimiser for |
1172 | index-only scans. When doing a read under HA_EXTRA_KEYREAD the handler |
1173 | only have to fill in the columns the key covers. If |
1174 | HA_PRIMARY_KEY_IN_READ_INDEX is set then also the PRIMARY KEY columns |
1175 | must be updated in the row. |
1176 | (InnoDB, MyISAM) |
1177 | */ |
1178 | virtual ulong index_flags(uint inx, uint part, bool all_parts) const |
1179 | { |
1180 | /* |
1181 | The following code is not safe if you are using different |
1182 | storage engines or different index types per partition. |
1183 | */ |
1184 | return m_file[0]->index_flags(inx, part, all_parts); |
1185 | } |
1186 | |
1187 | /** |
1188 | wrapper function for handlerton alter_table_flags, since |
1189 | the ha_partition_hton cannot know all its capabilities |
1190 | */ |
1191 | virtual alter_table_operations alter_table_flags(alter_table_operations flags); |
1192 | /* |
1193 | unireg.cc will call the following to make sure that the storage engine |
1194 | can handle the data it is about to send. |
1195 | |
1196 | The maximum supported values is the minimum of all handlers in the table |
1197 | */ |
1198 | uint min_of_the_max_uint(uint (handler::*operator_func)(void) const) const; |
1199 | virtual uint max_supported_record_length() const; |
1200 | virtual uint max_supported_keys() const; |
1201 | virtual uint max_supported_key_parts() const; |
1202 | virtual uint max_supported_key_length() const; |
1203 | virtual uint max_supported_key_part_length() const; |
1204 | virtual uint min_record_length(uint options) const; |
1205 | |
1206 | /* |
1207 | Primary key is clustered can only be true if all underlying handlers have |
1208 | this feature. |
1209 | */ |
1210 | virtual bool primary_key_is_clustered() |
1211 | { return m_pkey_is_clustered; } |
1212 | |
1213 | /* |
1214 | ------------------------------------------------------------------------- |
1215 | MODULE compare records |
1216 | ------------------------------------------------------------------------- |
1217 | cmp_ref checks if two references are the same. For most handlers this is |
1218 | a simple memcmp of the reference. However some handlers use primary key |
1219 | as reference and this can be the same even if memcmp says they are |
1220 | different. This is due to character sets and end spaces and so forth. |
1221 | For the partition handler the reference is first two bytes providing the |
1222 | partition identity of the referred record and then the reference of the |
1223 | underlying handler. |
1224 | Thus cmp_ref for the partition handler always returns FALSE for records |
1225 | not in the same partition and uses cmp_ref on the underlying handler |
1226 | to check whether the rest of the reference part is also the same. |
1227 | ------------------------------------------------------------------------- |
1228 | */ |
1229 | virtual int cmp_ref(const uchar * ref1, const uchar * ref2); |
1230 | /* |
1231 | ------------------------------------------------------------------------- |
1232 | MODULE auto increment |
1233 | ------------------------------------------------------------------------- |
1234 | This module is used to handle the support of auto increments. |
1235 | |
1236 | This variable in the handler is used as part of the handler interface |
1237 | It is maintained by the parent handler object and should not be |
1238 | touched by child handler objects (see handler.cc for its use). |
1239 | |
1240 | auto_increment_column_changed |
1241 | ------------------------------------------------------------------------- |
1242 | */ |
1243 | virtual bool need_info_for_auto_inc(); |
1244 | virtual bool can_use_for_auto_inc_init(); |
1245 | virtual void get_auto_increment(ulonglong offset, ulonglong increment, |
1246 | ulonglong nb_desired_values, |
1247 | ulonglong *first_value, |
1248 | ulonglong *nb_reserved_values); |
1249 | virtual void release_auto_increment(); |
1250 | private: |
1251 | virtual int reset_auto_increment(ulonglong value); |
1252 | void update_next_auto_inc_val(); |
1253 | virtual void lock_auto_increment() |
1254 | { |
1255 | /* lock already taken */ |
1256 | if (auto_increment_safe_stmt_log_lock) |
1257 | return; |
1258 | if (table_share->tmp_table == NO_TMP_TABLE) |
1259 | { |
1260 | part_share->lock_auto_inc(); |
1261 | DBUG_ASSERT(!auto_increment_lock); |
1262 | auto_increment_lock= TRUE; |
1263 | } |
1264 | } |
1265 | virtual void unlock_auto_increment() |
1266 | { |
1267 | /* |
1268 | If auto_increment_safe_stmt_log_lock is true, we have to keep the lock. |
1269 | It will be set to false and thus unlocked at the end of the statement by |
1270 | ha_partition::release_auto_increment. |
1271 | */ |
1272 | if (auto_increment_lock && !auto_increment_safe_stmt_log_lock) |
1273 | { |
1274 | auto_increment_lock= FALSE; |
1275 | part_share->unlock_auto_inc(); |
1276 | } |
1277 | } |
1278 | virtual void set_auto_increment_if_higher(Field *field) |
1279 | { |
1280 | ulonglong nr= (((Field_num*) field)->unsigned_flag || |
1281 | field->val_int() > 0) ? field->val_int() : 0; |
1282 | lock_auto_increment(); |
1283 | DBUG_ASSERT(part_share->auto_inc_initialized || |
1284 | !can_use_for_auto_inc_init()); |
1285 | /* must check when the mutex is taken */ |
1286 | if (nr >= part_share->next_auto_inc_val) |
1287 | part_share->next_auto_inc_val= nr + 1; |
1288 | unlock_auto_increment(); |
1289 | } |
1290 | |
1291 | public: |
1292 | |
1293 | /* |
1294 | ------------------------------------------------------------------------- |
1295 | MODULE initialize handler for HANDLER call |
1296 | ------------------------------------------------------------------------- |
1297 | This method is a special InnoDB method called before a HANDLER query. |
1298 | ------------------------------------------------------------------------- |
1299 | */ |
1300 | virtual void init_table_handle_for_HANDLER(); |
1301 | |
1302 | /* |
1303 | The remainder of this file defines the handler methods not implemented |
1304 | by the partition handler |
1305 | */ |
1306 | |
1307 | /* |
1308 | ------------------------------------------------------------------------- |
1309 | MODULE foreign key support |
1310 | ------------------------------------------------------------------------- |
1311 | The following methods are used to implement foreign keys as supported by |
1312 | InnoDB. Implement this ?? |
1313 | get_foreign_key_create_info is used by SHOW CREATE TABLE to get a textual |
1314 | description of how the CREATE TABLE part to define FOREIGN KEY's is done. |
1315 | free_foreign_key_create_info is used to free the memory area that provided |
1316 | this description. |
1317 | can_switch_engines checks if it is ok to switch to a new engine based on |
1318 | the foreign key info in the table. |
1319 | ------------------------------------------------------------------------- |
1320 | |
1321 | virtual char* get_foreign_key_create_info() |
1322 | virtual void free_foreign_key_create_info(char* str) |
1323 | |
1324 | virtual int get_foreign_key_list(THD *thd, |
1325 | List<FOREIGN_KEY_INFO> *f_key_list) |
1326 | virtual uint referenced_by_foreign_key() |
1327 | */ |
1328 | virtual bool can_switch_engines(); |
1329 | /* |
1330 | ------------------------------------------------------------------------- |
1331 | MODULE fulltext index |
1332 | ------------------------------------------------------------------------- |
1333 | */ |
1334 | void ft_close_search(FT_INFO *handler); |
1335 | virtual int ft_init(); |
1336 | virtual int pre_ft_init(); |
1337 | virtual void ft_end(); |
1338 | virtual int pre_ft_end(); |
1339 | virtual FT_INFO *ft_init_ext(uint flags, uint inx, String *key); |
1340 | virtual int ft_read(uchar *buf); |
1341 | virtual int pre_ft_read(bool use_parallel); |
1342 | |
1343 | /* |
1344 | ------------------------------------------------------------------------- |
1345 | MODULE restart full table scan at position (MyISAM) |
1346 | ------------------------------------------------------------------------- |
1347 | The following method is only used by MyISAM when used as |
1348 | temporary tables in a join. |
1349 | virtual int restart_rnd_next(uchar *buf, uchar *pos); |
1350 | */ |
1351 | |
1352 | /* |
1353 | ------------------------------------------------------------------------- |
1354 | MODULE in-place ALTER TABLE |
1355 | ------------------------------------------------------------------------- |
1356 | These methods are in the handler interface. (used by innodb-plugin) |
1357 | They are used for in-place alter table: |
1358 | ------------------------------------------------------------------------- |
1359 | */ |
1360 | virtual enum_alter_inplace_result |
1361 | check_if_supported_inplace_alter(TABLE *altered_table, |
1362 | Alter_inplace_info *ha_alter_info); |
1363 | virtual bool prepare_inplace_alter_table(TABLE *altered_table, |
1364 | Alter_inplace_info *ha_alter_info); |
1365 | virtual bool inplace_alter_table(TABLE *altered_table, |
1366 | Alter_inplace_info *ha_alter_info); |
1367 | virtual bool commit_inplace_alter_table(TABLE *altered_table, |
1368 | Alter_inplace_info *ha_alter_info, |
1369 | bool commit); |
1370 | virtual void notify_table_changed(); |
1371 | |
1372 | /* |
1373 | ------------------------------------------------------------------------- |
1374 | MODULE tablespace support |
1375 | ------------------------------------------------------------------------- |
1376 | Admin of table spaces is not applicable to the partition handler (InnoDB) |
1377 | This means that the following method is not implemented: |
1378 | ------------------------------------------------------------------------- |
1379 | virtual int discard_or_import_tablespace(my_bool discard) |
1380 | */ |
1381 | |
1382 | /* |
1383 | ------------------------------------------------------------------------- |
1384 | MODULE admin MyISAM |
1385 | ------------------------------------------------------------------------- |
1386 | |
1387 | ------------------------------------------------------------------------- |
1388 | OPTIMIZE TABLE, CHECK TABLE, ANALYZE TABLE and REPAIR TABLE are |
1389 | mapped to a routine that handles looping over a given set of |
1390 | partitions and those routines send a flag indicating to execute on |
1391 | all partitions. |
1392 | ------------------------------------------------------------------------- |
1393 | */ |
1394 | virtual int optimize(THD* thd, HA_CHECK_OPT *check_opt); |
1395 | virtual int analyze(THD* thd, HA_CHECK_OPT *check_opt); |
1396 | virtual int check(THD* thd, HA_CHECK_OPT *check_opt); |
1397 | virtual int repair(THD* thd, HA_CHECK_OPT *check_opt); |
1398 | virtual bool check_and_repair(THD *thd); |
1399 | virtual bool auto_repair(int error) const; |
1400 | virtual bool is_crashed() const; |
1401 | virtual int check_for_upgrade(HA_CHECK_OPT *check_opt); |
1402 | |
1403 | /* |
1404 | ------------------------------------------------------------------------- |
1405 | MODULE condition pushdown |
1406 | ------------------------------------------------------------------------- |
1407 | */ |
1408 | virtual const COND *cond_push(const COND *cond); |
1409 | virtual void cond_pop(); |
1410 | virtual void clear_top_table_fields(); |
1411 | virtual int info_push(uint info_type, void *info); |
1412 | |
1413 | private: |
1414 | int handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, uint flags); |
1415 | int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, uint part_id, |
1416 | uint flag); |
1417 | /** |
1418 | Check if the rows are placed in the correct partition. If the given |
1419 | argument is true, then move the rows to the correct partition. |
1420 | */ |
1421 | int check_misplaced_rows(uint read_part_id, bool repair); |
1422 | void append_row_to_str(String &str); |
1423 | public: |
1424 | |
1425 | /* |
1426 | ------------------------------------------------------------------------- |
1427 | Admin commands not supported currently (almost purely MyISAM routines) |
1428 | This means that the following methods are not implemented: |
1429 | ------------------------------------------------------------------------- |
1430 | |
1431 | virtual int backup(TD* thd, HA_CHECK_OPT *check_opt); |
1432 | virtual int restore(THD* thd, HA_CHECK_OPT *check_opt); |
1433 | virtual int dump(THD* thd, int fd = -1); |
1434 | virtual int net_read_dump(NET* net); |
1435 | */ |
1436 | virtual uint checksum() const; |
1437 | /* Enabled keycache for performance reasons, WL#4571 */ |
1438 | virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt); |
1439 | virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt); |
1440 | virtual TABLE_LIST *get_next_global_for_child(); |
1441 | |
1442 | /* |
1443 | ------------------------------------------------------------------------- |
1444 | MODULE enable/disable indexes |
1445 | ------------------------------------------------------------------------- |
1446 | Enable/Disable Indexes are only supported by HEAP and MyISAM. |
1447 | ------------------------------------------------------------------------- |
1448 | */ |
1449 | virtual int disable_indexes(uint mode); |
1450 | virtual int enable_indexes(uint mode); |
1451 | virtual int indexes_are_disabled(void); |
1452 | |
1453 | /* |
1454 | ------------------------------------------------------------------------- |
1455 | MODULE append_create_info |
1456 | ------------------------------------------------------------------------- |
1457 | append_create_info is only used by MyISAM MERGE tables and the partition |
1458 | handler will not support this handler as underlying handler. |
1459 | Implement this?? |
1460 | ------------------------------------------------------------------------- |
1461 | virtual void append_create_info(String *packet) |
1462 | */ |
1463 | |
1464 | /* |
1465 | the following heavily relies on the fact that all partitions |
1466 | are in the same storage engine. |
1467 | |
1468 | When this limitation is lifted, the following hack should go away, |
1469 | and a proper interface for engines needs to be introduced: |
1470 | |
1471 | an PARTITION_SHARE structure that has a pointer to the TABLE_SHARE. |
1472 | is given to engines everywhere where TABLE_SHARE is used now |
1473 | has members like option_struct, ha_data |
1474 | perhaps TABLE needs to be split the same way too... |
1475 | |
1476 | this can also be done before partition will support a mix of engines, |
1477 | but preferably together with other incompatible API changes. |
1478 | */ |
1479 | virtual handlerton *partition_ht() const |
1480 | { |
1481 | handlerton *h= m_file[0]->ht; |
1482 | for (uint i=1; i < m_tot_parts; i++) |
1483 | DBUG_ASSERT(h == m_file[i]->ht); |
1484 | return h; |
1485 | } |
1486 | |
1487 | ha_rows part_records(void *_part_elem) |
1488 | { |
1489 | partition_element *part_elem= reinterpret_cast<partition_element *>(_part_elem); |
1490 | DBUG_ASSERT(m_part_info); |
1491 | uint32 sub_factor= m_part_info->num_subparts ? m_part_info->num_subparts : 1; |
1492 | uint32 part_id= part_elem->id * sub_factor; |
1493 | uint32 part_id_end= part_id + sub_factor; |
1494 | DBUG_ASSERT(part_id_end <= m_tot_parts); |
1495 | ha_rows part_recs= 0; |
1496 | for (; part_id < part_id_end; ++part_id) |
1497 | { |
1498 | handler *file= m_file[part_id]; |
1499 | DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), part_id)); |
1500 | file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_OPEN); |
1501 | part_recs+= file->stats.records; |
1502 | } |
1503 | return part_recs; |
1504 | } |
1505 | |
1506 | friend int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); |
1507 | friend int cmp_key_part_id(void *key_p, uchar *ref1, uchar *ref2); |
1508 | }; |
1509 | #endif /* HA_PARTITION_INCLUDED */ |
1510 | |