1 /*****************************************************************************
2 
3 Copyright (c) 2014, 2019, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8 
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation.  The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License, version 2.0, for more details.
20 
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24 
25 *****************************************************************************/
26 
27 /* The InnoDB Partition handler: the interface between MySQL and InnoDB. */
28 
29 #ifndef ha_innopart_h
30 #define ha_innopart_h
31 
32 #include "partitioning/partition_handler.h"
33 
34 /* Forward declarations */
35 class Altered_partitions;
36 class partition_info;
37 
38 /** HA_DUPLICATE_POS and HA_READ_BEFORE_WRITE_REMOVAL is not
39 set from ha_innobase, but cannot yet be supported in ha_innopart.
40 Full text and geometry is not yet supported. */
41 const handler::Table_flags	HA_INNOPART_DISABLED_TABLE_FLAGS =
42 	( HA_CAN_FULLTEXT
43 	| HA_CAN_FULLTEXT_EXT
44 	| HA_CAN_GEOMETRY
45 	| HA_DUPLICATE_POS
46 	| HA_READ_BEFORE_WRITE_REMOVAL);
47 
48 /** InnoDB partition specific Handler_share. */
49 class Ha_innopart_share : public Partition_share
50 {
51 private:
52 	/** Array of all included table definitions (one per partition). */
53 	dict_table_t**		m_table_parts;
54 
55 	/** Instead of INNOBASE_SHARE::idx_trans_tbl. Maps MySQL index number
56 	to InnoDB index per partition. */
57 	dict_index_t**		m_index_mapping;
58 
59 	/** Total number of partitions. */
60 	uint			m_tot_parts;
61 
62 	/** Number of indexes. */
63 	uint			m_index_count;
64 
65 	/** Reference count. */
66 	uint			m_ref_count;
67 
68 	/** Pointer back to owning TABLE_SHARE. */
69 	TABLE_SHARE*		m_table_share;
70 
71 public:
72 	Ha_innopart_share(
73 		TABLE_SHARE*	table_share);
74 
75 	~Ha_innopart_share();
76 
77 	/** Set innodb table for given partition.
78 	@param[in]	part_id	Partition number.
79 	@param[in]	table	Table. */
80 	inline
81 	void
set_table_part(uint part_id,dict_table_t * table)82 	set_table_part(
83 		uint		part_id,
84 		dict_table_t*	table)
85 	{
86 		ut_ad(m_table_parts != NULL);
87 		ut_ad(part_id < m_tot_parts);
88 		m_table_parts[part_id] = table;
89 	}
90 
91 	/** Return innodb table for given partition.
92 	@param[in]	part_id	Partition number.
93 	@return	InnoDB table. */
94 	inline
95 	dict_table_t*
get_table_part(uint part_id)96 	get_table_part(
97 		uint	part_id) const
98 	{
99 		ut_ad(m_table_parts != NULL);
100 		ut_ad(part_id < m_tot_parts);
101 		return(m_table_parts[part_id]);
102 	}
103 
104 	/** Return innodb index for given partition and key number.
105 	@param[in]	part_id	Partition number.
106 	@param[in]	keynr	Key number.
107 	@return	InnoDB index. */
108 	dict_index_t*
109 	get_index(
110 		uint	part_id,
111 		uint	keynr);
112 
113 	/** Get MySQL key number corresponding to InnoDB index.
114 	@param[in]	part_id	Partition number.
115 	@param[in]	index	InnoDB index.
116 	@return	MySQL key number or MAX_KEY if non-existent. */
117 	uint
118 	get_mysql_key(
119 		uint			part_id,
120 		const dict_index_t*	index);
121 
122 	/** Initialize the share with table and indexes per partition.
123 	@param[in]	part_info	Partition info (partition names to use)
124 	@param[in]	table_name	Table name (db/table_name)
125 	@return false on success else true. */
126 	bool
127 	open_table_parts(
128 		partition_info*	part_info,
129 		const char*	table_name);
130 
131 	/** Close the table partitions.
132 	If all instances are closed, also release the resources. */
133 	void
134 	close_table_parts();
135 
136 	/* Static helper functions. */
137 	/** Fold to lower case if windows or lower_case_table_names == 1.
138 	@param[in,out]	s	String to fold.*/
139 	static
140 	void
141 	partition_name_casedn_str(
142 		char*	s);
143 
144 	/** Translate and append partition name.
145 	@param[out]	to	String to write in filesystem charset
146 	@param[in]	from	Name in system charset
147 	@param[in]	sep	Separator
148 	@param[in]	len	Max length of to buffer
149 	@return	length of written string. */
150 	static
151 	size_t
152 	append_sep_and_name(
153 		char*		to,
154 		const char*	from,
155 		const char*	sep,
156 		size_t		len);
157 
158 	/** Set up the virtual column template for partition table, and points
159 	all m_table_parts[]->vc_templ to it.
160 	@param[in]      table           MySQL TABLE object
161 	@param[in]      ib_table        InnoDB dict_table_t
162 	@param[in]      table_name      Table name (db/table_name) */
163 	void
164 	set_v_templ(
165 		TABLE*		table,
166 		dict_table_t*	ib_table,
167 		const char*	name);
168 
169 private:
170 	/** Disable default constructor. */
Ha_innopart_share()171 	Ha_innopart_share() {};
172 
173 	/** Open one partition (lower lever innodb table).
174 	@param[in]	part_id	Partition to open.
175 	@param[in]	partition_name	Name of partition.
176 	@return false on success else true. */
177 	bool
178 	open_one_table_part(
179 		uint		part_id,
180 		const char*	partition_name);
181 };
182 
183 /** The class defining a partitioning aware handle to an InnoDB table.
184 Based on ha_innobase and extended with
185 - Partition_helper for re-using common partitioning functionality
186 - Partition_handler for providing partitioning specific api calls.
187 Generic partitioning functions are implemented in Partition_helper.
188 Lower level storage functions are implemented in ha_innobase.
189 Partition_handler is inherited for implementing the handler level interface
190 for partitioning specific functions, like change_partitions and
191 truncate_partition.
192 InnoDB specific functions related to partitioning is implemented here. */
193 class ha_innopart:
194 	public ha_innobase,
195 	public Partition_helper,
196 	public Partition_handler
197 {
198 public:
199 	ha_innopart(
200 		handlerton*	hton,
201 		TABLE_SHARE*	table_arg);
202 
203 	~ha_innopart();
204 
205 	/** Clone this handler, used when needing more than one cursor
206 	to the same table.
207 	@param[in]	name		Table name.
208 	@param[in]	mem_root	mem_root to allocate from.
209 	@retval	Pointer to clone or NULL if error. */
210 	handler*
211 	clone(
212 		const char*	name,
213 		MEM_ROOT*	mem_root);
214 
215 	/** Check and register a table in the query cache.
216 	Ask InnoDB if a query to a table can be cached.
217 	@param[in]	thd		User thread handle.
218 	@param[in]	table_key	Normalized path to the table.
219 	@param[in]	key_length	Lenght of table_key.
220 	@param[out]	call_back	Function pointer for checking if data
221 	has changed.
222 	@param[in,out]	engine_data	Data for call_back (not used).
223 	@return TRUE if query caching of the table is permitted. */
224 	my_bool
register_query_cache_table(THD * thd,char * table_key,size_t key_length,qc_engine_callback * call_back,ulonglong * engine_data)225 	register_query_cache_table(
226 		THD*			thd,
227 		char*			table_key,
228 		size_t			key_length,
229 		qc_engine_callback*	call_back,
230 		ulonglong*		engine_data)
231 	{
232 		/* Currently this would need to go through every
233 		[sub] partition in the table to see if any of them has changed.
234 		See row_search_check_if_query_cache_permitted().
235 		So disabled until we can avoid check all partitions. */
236 		return(FALSE);
237 	}
238 
239 	/** On-line ALTER TABLE interface @see handler0alter.cc @{ */
240 
241 	/** Check if InnoDB supports a particular alter table in-place.
242 	@param[in]	altered_table	TABLE object for new version of table.
243 	@param[in,out]	ha_alter_info	Structure describing changes to be done
244 	by ALTER TABLE and holding data used during in-place alter.
245 	@retval	HA_ALTER_INPLACE_NOT_SUPPORTED	Not supported
246 	@retval	HA_ALTER_INPLACE_NO_LOCK	Supported
247 	@retval	HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE	Supported, but
248 	requires lock during main phase and exclusive lock during prepare
249 	phase.
250 	@retval	HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE	Supported, prepare
251 	phase requires exclusive lock. */
252 	enum_alter_inplace_result
253 	check_if_supported_inplace_alter(
254 		TABLE*			altered_table,
255 		Alter_inplace_info*	ha_alter_info);
256 
257 	/** Prepare in-place ALTER for table.
258 	Allows InnoDB to update internal structures with concurrent
259 	writes blocked (provided that check_if_supported_inplace_alter()
260 	did not return HA_ALTER_INPLACE_NO_LOCK).
261 	This will be invoked before inplace_alter_table().
262 	@param[in]	altered_table	TABLE object for new version of table.
263 	@param[in,out]	ha_alter_info	Structure describing changes to be done
264 	by ALTER TABLE and holding data used during in-place alter.
265 	@retval	true	Failure.
266 	@retval	false	Success. */
267 	bool
268 	prepare_inplace_alter_table(
269 		TABLE*			altered_table,
270 		Alter_inplace_info*	ha_alter_info);
271 
272 	/** Alter the table structure in-place.
273 	Alter the table structure in-place with operations
274 	specified using HA_ALTER_FLAGS and Alter_inplace_information.
275 	The level of concurrency allowed during this operation depends
276 	on the return value from check_if_supported_inplace_alter().
277 	@param[in]	altered_table	TABLE object for new version of table.
278 	@param[in,out]	ha_alter_info	Structure describing changes to be done
279 	by ALTER TABLE and holding data used during in-place alter.
280 	@retval	true	Failure.
281 	@retval	false	Success. */
282 	bool
283 	inplace_alter_table(
284 		TABLE*			altered_table,
285 		Alter_inplace_info*	ha_alter_info);
286 
287 	/** Commit or rollback.
288 	Commit or rollback the changes made during
289 	prepare_inplace_alter_table() and inplace_alter_table() inside
290 	the storage engine. Note that the allowed level of concurrency
291 	during this operation will be the same as for
292 	inplace_alter_table() and thus might be higher than during
293 	prepare_inplace_alter_table(). (E.g concurrent writes were
294 	blocked during prepare, but might not be during commit).
295 	@param[in]	altered_table	TABLE object for new version of table.
296 	@param[in]	ha_alter_info	Structure describing changes to be done
297 	by ALTER TABLE and holding data used during in-place alter.
298 	@param[in,out]	commit		true => Commit, false => Rollback.
299 	@retval	true	Failure.
300 	@retval	false	Success. */
301 	bool
302 	commit_inplace_alter_table(
303 		TABLE*			altered_table,
304 		Alter_inplace_info*	ha_alter_info,
305 		bool			commit);
306 
307 	/** Notify the storage engine that the table structure (.frm) has
308 	been updated.
309 
310 	ha_partition allows inplace operations that also upgrades the engine
311 	if it supports partitioning natively. So if this is the case then
312 	we will remove the .par file since it is not used with ha_innopart
313 	(we use the internal data dictionary instead). */
314 	void
315 	notify_table_changed();
316 	/** @} */
317 
318 	// TODO: should we implement init_table_handle_for_HANDLER() ?
319 	// (or is sql_stat_start handled correctly anyway?)
320 	int
321 	optimize(
322 		THD*		thd,
323 		HA_CHECK_OPT*	check_opt);
324 
325 	int
326 	discard_or_import_tablespace(
327 		my_bool	discard);
328 
329 	/** Compare key and rowid.
330 	Helper function for sorting records in the priority queue.
331 	a/b points to table->record[0] rows which must have the
332 	key fields set. The bytes before a and b store the rowid.
333 	This is used for comparing/sorting rows first according to
334 	KEY and if same KEY, by rowid (ref).
335 
336 	@param[in]	key_info	Null terminated array of index
337 	information.
338 	@param[in]	a		Pointer to record+ref in first record.
339 	@param[in]	b		Pointer to record+ref in second record.
340 	@return Return value is SIGN(first_rec - second_rec)
341 	@retval	0	Keys are equal.
342 	@retval	-1	second_rec is greater than first_rec.
343 	@retval	+1	first_rec is greater than second_rec. */
344 	static
345 	int
346 	key_and_rowid_cmp(
347 		KEY**	key_info,
348 		uchar	*a,
349 		uchar	*b);
350 
351 	int
352 	extra(
353 		enum ha_extra_function	operation);
354 
355 	void
356 	print_error(
357 		int	error,
358 		myf	errflag);
359 
360 	bool
361 	is_ignorable_error(
362 		int	error);
363 
364 	int
365 	start_stmt(
366 		THD*		thd,
367 		thr_lock_type	lock_type);
368 
369 	ha_rows
370 	records_in_range(
371 		uint		inx,
372 		key_range*	min_key,
373 		key_range*	max_key);
374 
375 	ha_rows
376 	estimate_rows_upper_bound();
377 
378 	uint
379 	alter_table_flags(
380 		uint	flags);
381 
382 	void
383 	update_create_info(
384 		HA_CREATE_INFO*	create_info);
385 
386 	int
387 	create(
388 		const char*	name,
389 		TABLE*		form,
390 		HA_CREATE_INFO*	create_info);
391 
392 	int
393 	truncate();
394 
395 	int
396 	check(
397 		THD*		thd,
398 		HA_CHECK_OPT*	check_opt);
399 
400 	/** Repair table.
401 	Will only handle records in wrong partition, not repairing
402 	corrupt innodb indexes.
403 	@param[in]	thd	Thread context.
404 	@param[in]	repair_opt	Repair options.
405 	@return 0 or error code. */
406 	int
407 	repair(
408 		THD*		thd,
409 		HA_CHECK_OPT*	repair_opt);
410 
411 	bool
412 	can_switch_engines();
413 
414 	uint
415 	referenced_by_foreign_key();
416 
417 	void
418 	get_auto_increment(
419 		ulonglong	offset,
420 		ulonglong	increment,
421 		ulonglong	nb_desired_values,
422 		ulonglong*	first_value,
423 		ulonglong*	nb_reserved_values);
424 
425 
426 	/** Get partition row type
427 	@param[in] Id of partition for which row type to be retrieved
428 	@return Partition row type */
429 	enum row_type get_partition_row_type(uint part_id);
430 
431 	int
432 	cmp_ref(
433 		const uchar*	ref1,
434 		const uchar*	ref2);
435 
436 	int
read_range_first(const key_range * start_key,const key_range * end_key,bool eq_range_arg,bool sorted)437 	read_range_first(
438 		const key_range*	start_key,
439 		const key_range*	end_key,
440 		bool			eq_range_arg,
441 		bool			sorted)
442 	{
443 		return(Partition_helper::ph_read_range_first(
444 						start_key,
445 						end_key,
446 						eq_range_arg,
447 						sorted));
448 	}
449 
450 	void
position(const uchar * record)451 	position(
452 		const uchar*	record)
453 	{
454 		Partition_helper::ph_position(record);
455 	}
456 
457 	/* TODO: Implement these! */
458 	bool
check_if_incompatible_data(HA_CREATE_INFO * info,uint table_changes)459 	check_if_incompatible_data(
460 		HA_CREATE_INFO*	info,
461 		uint		table_changes)
462 	{
463 		ut_ad(0);
464 		return(COMPATIBLE_DATA_NO);
465 	}
466 
467 	int
delete_all_rows()468 	delete_all_rows()
469 	{
470 		return(handler::delete_all_rows());
471 	}
472 
473 	int
disable_indexes(uint mode)474 	disable_indexes(
475 		uint	mode)
476 	{
477 		return(HA_ERR_WRONG_COMMAND);
478 	}
479 
480 	int
enable_indexes(uint mode)481 	enable_indexes(
482 		uint	mode)
483 	{
484 		return(HA_ERR_WRONG_COMMAND);
485 	}
486 
487 	void
free_foreign_key_create_info(char * str)488 	free_foreign_key_create_info(
489 		char*	str)
490 	{
491 		ut_ad(0);
492 	}
493 
494 	int
ft_init()495 	ft_init()
496 	{
497 		ut_ad(0);
498 		return(HA_ERR_WRONG_COMMAND);
499 	}
500 
501 	FT_INFO*
ft_init_ext(uint flags,uint inx,String * key)502 	ft_init_ext(
503 		uint	flags,
504 		uint	inx,
505 		String*	key)
506 	{
507 		ut_ad(0);
508 		return(NULL);
509 	}
510 
511 	FT_INFO*
ft_init_ext_with_hints(uint inx,String * key,Ft_hints * hints)512 	ft_init_ext_with_hints(
513 		uint		inx,
514 		String*		key,
515 		Ft_hints*	hints)
516 	{
517 		ut_ad(0);
518 		return(NULL);
519 	}
520 
521 	int
ft_read(uchar * buf)522 	ft_read(
523 		uchar*	buf)
524 	{
525 		ut_ad(0);
526 		return(HA_ERR_WRONG_COMMAND);
527 	}
528 
529 	bool
get_foreign_dup_key(char * child_table_name,uint child_table_name_len,char * child_key_name,uint child_key_name_len)530 	get_foreign_dup_key(
531 		char*	child_table_name,
532 		uint	child_table_name_len,
533 		char*	child_key_name,
534 		uint	child_key_name_len)
535 	{
536 		ut_ad(0);
537 		return(false);
538 	}
539 
540 	// TODO: not yet supporting FK.
541 	char*
get_foreign_key_create_info()542 	get_foreign_key_create_info()
543 	{
544 		return(NULL);
545 	}
546 
547 	// TODO: not yet supporting FK.
548 	int
get_foreign_key_list(THD * thd,List<FOREIGN_KEY_INFO> * f_key_list)549 	get_foreign_key_list(
550 		THD*			thd,
551 		List<FOREIGN_KEY_INFO>*	f_key_list)
552 	{
553 		return(0);
554 	}
555 
556 	// TODO: not yet supporting FK.
557 	int
get_parent_foreign_key_list(THD * thd,List<FOREIGN_KEY_INFO> * f_key_list)558 	get_parent_foreign_key_list(
559 		THD*			thd,
560 		List<FOREIGN_KEY_INFO>*	f_key_list)
561 	{
562 		return(0);
563 	}
564 
565 	// TODO: not yet supporting FK.
566 	int
get_cascade_foreign_key_table_list(THD * thd,List<st_handler_tablename> * fk_table_list)567 	get_cascade_foreign_key_table_list(
568 		THD*				thd,
569 		List<st_handler_tablename>*	fk_table_list)
570 	{
571 		return(0);
572 	}
573 
574 	int
read_range_next()575 	read_range_next()
576 	{
577 		return(Partition_helper::ph_read_range_next());
578 	}
579 
580 	uint32
calculate_key_hash_value(Field ** field_array)581 	calculate_key_hash_value(
582 		Field**	field_array)
583 	{
584 		return(Partition_helper::ph_calculate_key_hash_value(field_array));
585 	}
586 
587 	Table_flags
table_flags()588 	table_flags() const
589 	{
590 		return(ha_innobase::table_flags() | HA_CAN_REPAIR);
591 	}
592 
593 	void
release_auto_increment()594 	release_auto_increment()
595 	{
596 		Partition_helper::ph_release_auto_increment();
597 	}
598 
599 	/** Implementing Partition_handler interface @see partition_handler.h
600 	@{ */
601 
602 	/** See Partition_handler. */
603 	void
get_dynamic_partition_info(ha_statistics * stat_info,ha_checksum * check_sum,uint part_id)604 	get_dynamic_partition_info(
605 		ha_statistics*	stat_info,
606 		ha_checksum*	check_sum,
607 		uint		part_id)
608 	{
609 		Partition_helper::get_dynamic_partition_info_low(
610 			stat_info,
611 			check_sum,
612 			part_id);
613 	}
614 
615 	uint
alter_flags(uint flags MY_ATTRIBUTE ((unused)))616 	alter_flags(
617 		uint	flags MY_ATTRIBUTE((unused))) const
618 	{
619 		return(HA_PARTITION_FUNCTION_SUPPORTED
620 		       | HA_FAST_CHANGE_PARTITION);
621 	}
622 
623 	Partition_handler*
get_partition_handler()624 	get_partition_handler()
625 	{
626 		return(static_cast<Partition_handler*>(this));
627 	}
628 
629 	void
set_part_info(partition_info * part_info,bool early)630 	set_part_info(
631 		partition_info*	part_info,
632 		bool		early)
633 	{
634 		Partition_helper::set_part_info_low(part_info, early);
635 	}
636 
637 	void
initialize_partitioning(partition_info * part_info,bool early)638 	initialize_partitioning(
639 		partition_info*	part_info,
640 		bool		early)
641 	{
642 		Partition_helper::set_part_info_low(part_info, early);
643 	}
644 
645 	handler*
get_handler()646 	get_handler()
647 	{
648 		return(static_cast<handler*>(this));
649 	}
650 	/** @} */
651 
652 private:
653 	/** Pointer to Ha_innopart_share on the TABLE_SHARE. */
654 	Ha_innopart_share*	m_part_share;
655 
656 	/** ins_node per partition. Synchronized with prebuilt->ins_node
657 	when changing partitions. */
658 	ins_node_t**		m_ins_node_parts;
659 
660 	/** upd_node per partition. Synchronized with prebuilt->upd_node
661 	when changing partitions. */
662 	upd_node_t**		m_upd_node_parts;
663 
664 	/** blob_heap per partition. Synchronized with prebuilt->blob_heap
665 	when changing partitions. */
666 	mem_heap_t**		m_blob_heap_parts;
667 
668 	/** trx_id from the partitions table->def_trx_id. Keep in sync
669 	with prebuilt->trx_id when changing partitions.
670 	prebuilt only reflects the current partition! */
671 	trx_id_t*		m_trx_id_parts;
672 
673 	/** row_read_type per partition. */
674 	ulint*			m_row_read_type_parts;
675 
676 	/** sql_stat_start per partition. */
677 	uchar*			m_sql_stat_start_parts;
678 
679 	/** persistent cursors per partition. */
680 	btr_pcur_t*		m_pcur_parts;
681 
682 	/** persistent cluster cursors per partition. */
683 	btr_pcur_t*		m_clust_pcur_parts;
684 
685 	/** map from part_id to offset in above two arrays. */
686 	uint16_t*		m_pcur_map;
687 
688 	/** Original m_prebuilt->pcur. */
689 	btr_pcur_t*		m_pcur;
690 
691 	/** Original m_prebuilt->clust_pcur. */
692 	btr_pcur_t*		m_clust_pcur;
693 
694 	/** New partitions during ADD/REORG/... PARTITION. */
695 	Altered_partitions*	m_new_partitions;
696 
697 	/** Clear used ins_nodes and upd_nodes. */
698 	void
699 	clear_ins_upd_nodes();
700 
701 	/** Clear the blob heaps for all partitions */
702 	void
703 	clear_blob_heaps();
704 
705 	/** Reset state of file to after 'open'. This function is called
706 	after every statement for all tables used by that statement. */
707 	int
708 	reset();
709 
710 	/** Allocate the array to hold blob heaps for all partitions */
711 	mem_heap_t**
712 	alloc_blob_heap_array();
713 
714 	/** Free the array that holds blob heaps for all partitions */
715 	void
716 	free_blob_heap_array();
717 
718 	/** Changes the active index of a handle.
719 	@param[in]	part_id	Use this partition.
720 	@param[in]	keynr	Use this index; MAX_KEY means always
721 	clustered index, even if it was internally generated by InnoDB.
722 	@return 0 or error code. */
723 	int
724 	change_active_index(
725 		uint	part_id,
726 		uint	keynr);
727 
728 	/** Move to next partition and set its index.
729 	@return	0 for success else error number. */
730 	int
731 	next_partition_index();
732 
733 	/** Internally called for initializing auto increment value.
734 	Should never be called, but defined to catch such errors.
735 	@return 0 on success else error code. */
736 	int
737 	innobase_initialize_autoinc();
738 
739 	/** Get the index for the current partition
740 	@param[in]	keynr	MySQL index number.
741 	@return InnoDB index or NULL. */
742 	dict_index_t*
743 	innobase_get_index(
744 		uint	keynr);
745 
746 	/** Get the index for a handle.
747 	Does not change active index.
748 	@param[in]	keynr	use this index; MAX_KEY means always clustered
749 	index, even if it was internally generated by InnoDB.
750 	@param[in]	part_id	From this partition.
751 	@return NULL or index instance. */
752 	dict_index_t*
753 	innopart_get_index(
754 		uint	part_id,
755 		uint	keynr);
756 
757 	/** Change active partition.
758 	Copies needed info into m_prebuilt from the partition specific memory.
759 	@param[in]	part_id	Partition to set as active. */
760 	void
761 	set_partition(
762 		uint	part_id);
763 
764 	/** Update active partition.
765 	Copies needed info from m_prebuilt into the partition specific memory.
766 	@param[in]	part_id	Partition to set as active. */
767 	void
768 	update_partition(
769 		uint	part_id);
770 
771 	/** Helpers needed by Partition_helper, @see partition_handler.h @{ */
772 
773 	/** Set the autoinc column max value.
774 	This should only be called once from ha_innobase::open().
775 	Therefore there's no need for a covering lock.
776 	@param[in]	no_lock	If locking should be skipped. Not used!
777 	@return 0 on success else error code. */
778 	int
779 	initialize_auto_increment(
780 		bool	/* no_lock */);
781 
782 	/** Save currently highest auto increment value.
783 	@param[in]	nr	Auto increment value to save. */
784 	void
785 	save_auto_increment(
786 		ulonglong	nr);
787 
788 	/** Setup the ordered record buffer and the priority queue.
789 	@param[in]	used_parts	Number of used partitions in query.
790 	@return false for success, else true. */
791 	int
792 	init_record_priority_queue_for_parts(
793 		uint	used_parts);
794 
795 	/** Destroy the ordered record buffer and the priority queue. */
796 	void
797 	destroy_record_priority_queue_for_parts();
798 
799 	/** Prepare for creating new partitions during ALTER TABLE ...
800 	PARTITION.
801 	@param[in]	num_partitions	Number of new partitions to be created.
802 	@param[in]	only_create	True if only creating the partition
803 	(no open/lock is needed).
804 	@return 0 for success else error code. */
805 	int
806 	prepare_for_new_partitions(
807 		uint	num_partitions,
808 		bool	only_create);
809 
810 	/** Create a new partition to be filled during ALTER TABLE ...
811 	PARTITION.
812 	@param[in]	table		Table to create the partition in.
813 	@param[in]	create_info	Table/partition specific create info.
814 	@param[in]	part_name	Partition name.
815 	@param[in]	new_part_id	Partition id in new table.
816 	@param[in]	part_elem	Partition element.
817 	@return 0 for success else error code. */
818 	int
819 	create_new_partition(
820 		TABLE*			table,
821 		HA_CREATE_INFO*		create_info,
822 		const char*		part_name,
823 		uint			new_part_id,
824 		partition_element*	part_elem);
825 
826 	/** Close and finalize new partitions. */
827 	void
828 	close_new_partitions();
829 
830 	/** write row to new partition.
831 	@param[in]	new_part	New partition to write to.
832 	@return 0 for success else error code. */
833 	int
834 	write_row_in_new_part(
835 		uint	new_part);
836 
837 	/** Write a row in specific partition.
838 	Stores a row in an InnoDB database, to the table specified in this
839 	handle.
840 	@param[in]	part_id	Partition to write to.
841 	@param[in]	row	A row in MySQL format.
842 	@return error code. */
843 	int
844 	write_row_in_part(
845 		uint	part_id,
846 		uchar*	row);
847 
848 	/** Update a row in partition.
849 	Updates a row given as a parameter to a new value.
850 	@param[in]	part_id	Partition to update row in.
851 	@param[in]	old_row	Old row in MySQL format.
852 	@param[in]	new_row	New row in MySQL format.
853 	@return error number or 0. */
854 	int
855 	update_row_in_part(
856 		uint		part_id,
857 		const uchar*	old_row,
858 		uchar*		new_row);
859 
860 	/** Deletes a row in partition.
861 	@param[in]	part_id	Partition to delete from.
862 	@param[in]	row	Row to delete in MySQL format.
863 	@return error number or 0. */
864 	int
865 	delete_row_in_part(
866 		uint		part_id,
867 		const uchar*	row);
868 
869 	/** Return first record in index from a partition.
870 	@param[in]	part	Partition to read from.
871 	@param[out]	record	First record in index in the partition.
872 	@return error number or 0. */
873 	int
874 	index_first_in_part(
875 		uint	part,
876 		uchar*	record);
877 
878 	/** Return last record in index from a partition.
879 	@param[in]	part	Partition to read from.
880 	@param[out]	record	Last record in index in the partition.
881 	@return error number or 0. */
882 	int
883 	index_last_in_part(
884 		uint	part,
885 		uchar*	record);
886 
887 	/** Return previous record in index from a partition.
888 	@param[in]	part	Partition to read from.
889 	@param[out]	record	Last record in index in the partition.
890 	@return error number or 0. */
891 	int
892 	index_prev_in_part(
893 		uint	part,
894 		uchar*	record);
895 
896 	/** Return next record in index from a partition.
897 	@param[in]	part	Partition to read from.
898 	@param[out]	record	Last record in index in the partition.
899 	@return error number or 0. */
900 	int
901 	index_next_in_part(
902 		uint	part,
903 		uchar*	record);
904 
905 	/** Return next same record in index from a partition.
906 	This routine is used to read the next record, but only if the key is
907 	the same as supplied in the call.
908 	@param[in]	part	Partition to read from.
909 	@param[out]	record	Last record in index in the partition.
910 	@param[in]	key	Key to match.
911 	@param[in]	length	Length of key.
912 	@return error number or 0. */
913 	int
914 	index_next_same_in_part(
915 		uint		part,
916 		uchar*		record,
917 		const uchar*	key,
918 		uint		length);
919 
920 	/** Start index scan and return first record from a partition.
921 	This routine starts an index scan using a start key. The calling
922 	function will check the end key on its own.
923 	@param[in]	part	Partition to read from.
924 	@param[out]	record	First matching record in index in the partition.
925 	@param[in]	key	Key to match.
926 	@param[in]	keypart_map	Which part of the key to use.
927 	@param[in]	find_flag	Key condition/direction to use.
928 	@return error number or 0. */
929 	int
930 	index_read_map_in_part(
931 		uint			part,
932 		uchar*			record,
933 		const uchar*		key,
934 		key_part_map		keypart_map,
935 		enum ha_rkey_function	find_flag);
936 
937 	/** Return last matching record in index from a partition.
938 	@param[in]	part	Partition to read from.
939 	@param[out]	record	Last matching record in index in the partition.
940 	@param[in]	key	Key to match.
941 	@param[in]	keypart_map	Which part of the key to use.
942 	@return error number or 0. */
943 	int
944 	index_read_last_map_in_part(
945 		uint		part,
946 		uchar*		record,
947 		const uchar*	key,
948 		key_part_map	keypart_map);
949 
950 	/** Start index scan and return first record from a partition.
951 	This routine starts an index scan using a start and end key.
952 	@param[in]	part	Partition to read from.
953 	@param[out]	record	First matching record in index in the partition.
954 	if NULL use table->record[0] as return buffer.
955 	@param[in]	start_key	Start key to match.
956 	@param[in]	end_key	End key to match.
957 	@param[in]	eq_range	Is equal range, start_key == end_key.
958 	@param[in]	sorted	Return rows in sorted order.
959 	@return error number or 0. */
960 	int
961 	read_range_first_in_part(
962 		uint			part,
963 		uchar*			record,
964 		const key_range*	start_key,
965 		const key_range*	end_key,
966 		bool			eq_range,
967 		bool			sorted);
968 
969 	/** Return next record in index range scan from a partition.
970 	@param[in]	part	Partition to read from.
971 	@param[out]	record	First matching record in index in the partition.
972 	if NULL use table->record[0] as return buffer.
973 	@return error number or 0. */
974 	int
975 	read_range_next_in_part(
976 		uint	part,
977 		uchar*	record);
978 
979 	/** Start index scan and return first record from a partition.
980 	This routine starts an index scan using a start key. The calling
981 	function will check the end key on its own.
982 	@param[in]	part	Partition to read from.
983 	@param[out]	record	First matching record in index in the partition.
984 	@param[in]	index	Index to read from.
985 	@param[in]	key	Key to match.
986 	@param[in]	keypart_map	Which part of the key to use.
987 	@param[in]	find_flag	Key condition/direction to use.
988 	@return error number or 0. */
989 	int
990 	index_read_idx_map_in_part(
991 		uint			part,
992 		uchar*			record,
993 		uint			index,
994 		const uchar*		key,
995 		key_part_map		keypart_map,
996 		enum ha_rkey_function	find_flag);
997 
998 	/** Initialize random read/scan of a specific partition.
999 	@param[in]	part_id		Partition to initialize.
1000 	@param[in]	table_scan	True for scan else random access.
1001 	@return error number or 0. */
1002 	int
1003 	rnd_init_in_part(
1004 		uint	part_id,
1005 		bool	table_scan);
1006 
1007 	/** Get next row during scan of a specific partition.
1008 	@param[in]	part_id	Partition to read from.
1009 	@param[out]	record	Next row.
1010 	@return error number or 0. */
1011 	int
1012 	rnd_next_in_part(
1013 		uint	part_id,
1014 		uchar*	record);
1015 
1016 	/** End random read/scan of a specific partition.
1017 	@param[in]	part_id		Partition to end random read/scan.
1018 	@param[in]	table_scan	True for scan else random access.
1019 	@return error number or 0. */
1020 	int
1021 	rnd_end_in_part(
1022 		uint	part_id,
1023 		bool	table_scan);
1024 
1025 	/** Get a reference to the current cursor position in the last used
1026 	partition.
1027 	@param[out]	ref	Reference (PK if exists else row_id).
1028 	@param[in]	record	Record to position. */
1029 	void
1030 	position_in_last_part(
1031 		uchar*		ref,
1032 		const uchar*	record);
1033 
1034 	/** Read row using position using given record to find.
1035 	Only useful when position is based on primary key
1036 	@param[in]	record  Current record in MySQL Row Format.
1037 	@return error number or 0. */
1038 	int
1039 	rnd_pos_by_record(
1040 		uchar*  record);
1041 
1042         /** Copy a cached MySQL record.
1043 	@param[out]	to_record	Where to copy the MySQL record.
1044 	@param[in]	from_record	Which record to copy. */
1045 	void
1046 	copy_cached_row(
1047 		uchar*		to_record,
1048 		const uchar*	from_record);
1049 	/** @} */
1050 
1051 	/* Private handler:: functions specific for native InnoDB partitioning.
1052 	@see handler.h @{ */
1053 
1054 	int
1055 	open(
1056 		const char*	name,
1057 		int		mode,
1058 		uint		test_if_locked);
1059 
1060 	int
1061 	close();
1062 
1063 	double
1064 	scan_time();
1065 
1066 	/** Was the last returned row semi consistent read.
1067 	In an UPDATE or DELETE, if the row under the cursor was locked by
1068 	another transaction, and the engine used an optimistic read of the last
1069 	committed row value under the cursor, then the engine returns 1 from
1070 	this function. MySQL must NOT try to update this optimistic value. If
1071 	the optimistic value does not match the WHERE condition, MySQL can
1072 	decide to skip over this row. This can be used to avoid unnecessary
1073 	lock waits.
1074 
1075 	If this method returns true, it will also signal the storage
1076 	engine that the next read will be a locking re-read of the row.
1077 	@see handler.h and row0mysql.h
1078 	@return	true if last read was semi consistent else false. */
1079 	bool was_semi_consistent_read();
1080 
1081 	/** Try semi consistent read.
1082 	Tell the engine whether it should avoid unnecessary lock waits.
1083 	If yes, in an UPDATE or DELETE, if the row under the cursor was locked
1084 	by another transaction, the engine may try an optimistic read of
1085 	the last committed row value under the cursor.
1086 	@see handler.h and row0mysql.h
1087 	@param[in]	yes	Should semi-consistent read be used. */
1088 	void try_semi_consistent_read(
1089 		bool	yes);
1090 
1091 	/** Removes a lock on a row.
1092 	Removes a new lock set on a row, if it was not read optimistically.
1093 	This can be called after a row has been read in the processing of
1094 	an UPDATE or a DELETE query. @see ha_innobase::unlock_row(). */
1095 	void unlock_row();
1096 
1097 	int
1098 	index_init(
1099 		uint	index,
1100 		bool	sorted);
1101 
1102 	int
1103 	index_end();
1104 
1105 	int
rnd_init(bool scan)1106 	rnd_init(
1107 		bool	scan)
1108 	{
1109 		return(Partition_helper::ph_rnd_init(scan));
1110 	}
1111 
1112 	int
rnd_end()1113 	rnd_end()
1114 	{
1115 		return(Partition_helper::ph_rnd_end());
1116 	}
1117 
1118 	int
1119 	external_lock(
1120 		THD*	thd,
1121 		int	lock_type);
1122 
1123 	THR_LOCK_DATA**
1124 	store_lock(
1125 		THD*			thd,
1126 		THR_LOCK_DATA**		to,
1127 		thr_lock_type		lock_type);
1128 
1129 	int
write_row(uchar * record)1130 	write_row(
1131 		uchar*	record)
1132 	{
1133 		return(Partition_helper::ph_write_row(record));
1134 	}
1135 
1136 	int
update_row(const uchar * old_record,uchar * new_record)1137 	update_row(
1138 		const uchar*	old_record,
1139 		uchar*		new_record)
1140 	{
1141 		return(Partition_helper::ph_update_row(old_record, new_record));
1142 	}
1143 
1144 	int
delete_row(const uchar * record)1145 	delete_row(
1146 		const uchar*	record)
1147 	{
1148 		return(Partition_helper::ph_delete_row(record));
1149 	}
1150 	/** @} */
1151 
1152 	/** Truncate partition.
1153 	Called from Partition_handler::trunctate_partition(). */
1154 	int
1155 	truncate_partition_low();
1156 
1157 	/** Change partitions according to ALTER TABLE ... PARTITION ...
1158 	Called from Partition_handler::change_partitions().
1159 	@param[in]	create_info	Table create info.
1160 	@param[in]	path		Path including db/table_name.
1161 	@param[out]	copied		Number of copied rows.
1162 	@param[out]	deleted		Number of deleted rows.
1163 	@return	0 for success or error code. */
1164 	int
change_partitions_low(HA_CREATE_INFO * create_info,const char * path,ulonglong * const copied,ulonglong * const deleted)1165 	change_partitions_low(
1166 		HA_CREATE_INFO*		create_info,
1167 		const char*		path,
1168 		ulonglong* const	copied,
1169 		ulonglong* const	deleted)
1170 	{
1171 		return(Partition_helper::change_partitions(
1172 						create_info,
1173 						path,
1174 						copied,
1175 						deleted));
1176 	}
1177 
1178 	/** Access methods to protected areas in handler to avoid adding
1179 	friend class Partition_helper in class handler.
1180 	@see partition_handler.h @{ */
1181 
1182 	THD*
get_thd()1183 	get_thd() const
1184 	{
1185 		return ha_thd();
1186 	}
1187 
1188 	TABLE*
get_table()1189 	get_table() const
1190 	{
1191 		return table;
1192 	}
1193 
1194 	bool
get_eq_range()1195 	get_eq_range() const
1196 	{
1197 		return eq_range;
1198 	}
1199 
1200 	void
set_eq_range(bool eq_range_arg)1201 	set_eq_range(bool eq_range_arg)
1202 	{
1203 		eq_range= eq_range_arg;
1204 	}
1205 
1206 	void
set_range_key_part(KEY_PART_INFO * key_part)1207 	set_range_key_part(KEY_PART_INFO *key_part)
1208 	{
1209 		range_key_part= key_part;
1210 	}
1211 	/** @} */
1212 
1213 	/** Fill in data_dir_path and tablespace name from internal data
1214 	dictionary.
1215 	@param	part_elem	Partition element to fill.
1216 	@param	ib_table	InnoDB table to copy from. */
1217 	void
1218 	update_part_elem(
1219 		partition_element*	part_elem,
1220 		dict_table_t*		ib_table);
1221 protected:
1222 	/* Protected handler:: functions specific for native InnoDB partitioning.
1223 	@see handler.h @{ */
1224 
1225 	int
rnd_next(uchar * record)1226 	rnd_next(
1227 		uchar*	record)
1228 	{
1229 		return(Partition_helper::ph_rnd_next(record));
1230 	}
1231 
1232 	int
1233 	rnd_pos(
1234 		uchar*	record,
1235 		uchar*	pos);
1236 
1237 #ifdef WL6742
1238 	/* Removing WL6742 as part of Bug 23046302 */
1239 	int
1240 	records(
1241 		ha_rows*	num_rows);
1242 #endif
1243 
1244 	int
index_next(uchar * record)1245 	index_next(
1246 		uchar*	record)
1247 	{
1248 		return(Partition_helper::ph_index_next(record));
1249 	}
1250 
1251 	int
index_next_same(uchar * record,const uchar * key,uint keylen)1252 	index_next_same(
1253 		uchar*		record,
1254 		const uchar*	key,
1255 		uint		keylen)
1256 	{
1257 		return(Partition_helper::ph_index_next_same(record, key, keylen));
1258 	}
1259 
1260 	int
index_prev(uchar * record)1261 	index_prev(
1262 		uchar*	record)
1263 	{
1264 		return(Partition_helper::ph_index_prev(record));
1265 	}
1266 
1267 	int
index_first(uchar * record)1268 	index_first(
1269 		uchar*	record)
1270 	{
1271 		return(Partition_helper::ph_index_first(record));
1272 	}
1273 
1274 	int
index_last(uchar * record)1275 	index_last(
1276 		uchar*	record)
1277 	{
1278 		return(Partition_helper::ph_index_last(record));
1279 	}
1280 
1281 	int
index_read_last_map(uchar * record,const uchar * key,key_part_map keypart_map)1282 	index_read_last_map(
1283 		uchar*		record,
1284 		const uchar*	key,
1285 		key_part_map	keypart_map)
1286 	{
1287 		return(Partition_helper::ph_index_read_last_map(
1288 						record,
1289 						key,
1290 						keypart_map));
1291 	}
1292 
1293 	int
index_read_map(uchar * buf,const uchar * key,key_part_map keypart_map,enum ha_rkey_function find_flag)1294 	index_read_map(
1295 		uchar*			buf,
1296 		const uchar*		key,
1297 		key_part_map		keypart_map,
1298 		enum ha_rkey_function	find_flag)
1299 	{
1300 		return(Partition_helper::ph_index_read_map(
1301 				buf,
1302 				key,
1303 				keypart_map,
1304 				find_flag));
1305 	}
1306 
1307 	int
index_read_idx_map(uchar * buf,uint index,const uchar * key,key_part_map keypart_map,enum ha_rkey_function find_flag)1308 	index_read_idx_map(
1309 		uchar*			buf,
1310 		uint			index,
1311 		const uchar*		key,
1312 		key_part_map		keypart_map,
1313 		enum ha_rkey_function	find_flag)
1314 	{
1315 		return(Partition_helper::ph_index_read_idx_map(
1316 				buf,
1317 				index,
1318 				key,
1319 				keypart_map,
1320 				find_flag));
1321 	}
1322 	/** @} */
1323 
1324 	/** Updates and return statistics.
1325 	Returns statistics information of the table to the MySQL interpreter,
1326 	in various fields of the handle object.
1327 	@param[in]	flag		Flags for what to update and return.
1328 	@param[in]	is_analyze	True if called from ::analyze().
1329 	@return	HA_ERR_* error code or 0. */
1330 	int
1331 	info_low(
1332 		uint	flag,
1333 		bool	is_analyze);
1334 };
1335 #endif /* ha_innopart_h */
1336