1/* Copyright (c) 2004, 2013, Oracle and/or its affiliates.
2 Copyright (c) 2010, 2014, SkySQL Ab.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
17/**
18 @file ha_example.cc
19
20 @brief
21 The ha_example engine is a stubbed storage engine for example purposes only;
22 it does almost nothing at this point. Its purpose is to provide a source
23 code illustration of how to begin writing new storage engines; see also
24 storage/example/ha_example.h.
25
26 Additionally, this file includes an example of a daemon plugin which does
27 nothing at all - absolutely nothing, even less than example storage engine.
28 But it shows that one dll/so can contain more than one plugin.
29
30 @details
31 ha_example will let you create/open/delete tables, but
32 nothing further (for example, indexes are not supported nor can data
33 be stored in the table). It also provides new status (example_func_example)
34 and system (example_ulong_var and example_enum_var) variables.
35
36 Use this example as a template for implementing the same functionality in
37 your own storage engine. You can enable the example storage engine in your
38 build by doing the following during your build process:<br> ./configure
39 --with-example-storage-engine
40
41 Once this is done, MySQL will let you create tables with:<br>
42 CREATE TABLE <table name> (...) ENGINE=EXAMPLE;
43
44 The example storage engine is set up to use table locks. It
45 implements an example "SHARE" that is inserted into a hash by table
46 name. You can use this to store information of state that any
47 example handler object will be able to see when it is using that
48 table.
49
50 Please read the object definition in ha_example.h before reading the rest
51 of this file.
52
53 @note
54 When you create an EXAMPLE table, the MySQL Server creates a table .frm
55 (format) file in the database directory, using the table name as the file
56 name as is customary with MySQL. No other files are created. To get an idea
57 of what occurs, here is an example select that would do a scan of an entire
58 table:
59
60 @code
61 ha_example::store_lock
62 ha_example::external_lock
63 ha_example::info
64 ha_example::rnd_init
65 ha_example::extra
66 ENUM HA_EXTRA_CACHE Cache record in HA_rrnd()
67 ha_example::rnd_next
68 ha_example::rnd_next
69 ha_example::rnd_next
70 ha_example::rnd_next
71 ha_example::rnd_next
72 ha_example::rnd_next
73 ha_example::rnd_next
74 ha_example::rnd_next
75 ha_example::rnd_next
76 ha_example::extra
77 ENUM HA_EXTRA_NO_CACHE End caching of records (def)
78 ha_example::external_lock
79 ha_example::extra
80 ENUM HA_EXTRA_RESET Reset database to after open
81 @endcode
82
83 Here you see that the example storage engine has 9 rows called before
84 rnd_next signals that it has reached the end of its data. Also note that
85 the table in question was already opened; had it not been open, a call to
86 ha_example::open() would also have been necessary. Calls to
87 ha_example::extra() are hints as to what will be occuring to the request.
88
89 A Longer Example can be found called the "Skeleton Engine" which can be
90 found on TangentOrg. It has both an engine and a full build environment
91 for building a pluggable storage engine.
92
93 Happy coding!<br>
94 -Brian
95*/
96
97#ifdef USE_PRAGMA_IMPLEMENTATION
98#pragma implementation // gcc: Class implementation
99#endif
100
101#include <my_config.h>
102#include <mysql/plugin.h>
103#include "ha_example.h"
104#include "sql_class.h"
105
106static handler *example_create_handler(handlerton *hton,
107 TABLE_SHARE *table,
108 MEM_ROOT *mem_root);
109
110handlerton *example_hton;
111
112static MYSQL_THDVAR_ULONG(varopt_default, PLUGIN_VAR_RQCMDARG,
113 "default value of the VAROPT table option", NULL, NULL, 5, 0, 100, 0);
114
115/**
116 Structure for CREATE TABLE options (table options).
117 It needs to be called ha_table_option_struct.
118
119 The option values can be specified in the CREATE TABLE at the end:
120 CREATE TABLE ( ... ) *here*
121*/
122
123struct ha_table_option_struct
124{
125 const char *strparam;
126 ulonglong ullparam;
127 uint enumparam;
128 bool boolparam;
129 ulonglong varparam;
130};
131
132
133/**
134 Structure for CREATE TABLE options (field options).
135 It needs to be called ha_field_option_struct.
136
137 The option values can be specified in the CREATE TABLE per field:
138 CREATE TABLE ( field ... *here*, ... )
139*/
140
141struct ha_field_option_struct
142{
143 const char *complex_param_to_parse_it_in_engine;
144};
145
146/*
147 no example here, but index options can be declared similarly
148 using the ha_index_option_struct structure.
149
150 Their values can be specified in the CREATE TABLE per index:
151 CREATE TABLE ( field ..., .., INDEX .... *here*, ... )
152*/
153
154ha_create_table_option example_table_option_list[]=
155{
156 /*
157 one numeric option, with the default of UINT_MAX32, valid
158 range of values 0..UINT_MAX32, and a "block size" of 10
159 (any value must be divisible by 10).
160 */
161 HA_TOPTION_NUMBER("ULL", ullparam, UINT_MAX32, 0, UINT_MAX32, 10),
162 /*
163 one option that takes an arbitrary string
164 */
165 HA_TOPTION_STRING("STR", strparam),
166 /*
167 one enum option. a valid values are strings ONE and TWO.
168 A default value is 0, that is "one".
169 */
170 HA_TOPTION_ENUM("one_or_two", enumparam, "one,two", 0),
171 /*
172 one boolean option, the valid values are YES/NO, ON/OFF, 1/0.
173 The default is 1, that is true, yes, on.
174 */
175 HA_TOPTION_BOOL("YESNO", boolparam, 1),
176 /*
177 one option defined by the system variable. The type, the range, or
178 a list of allowed values is the same as for the system variable.
179 */
180 HA_TOPTION_SYSVAR("VAROPT", varparam, varopt_default),
181
182 HA_TOPTION_END
183};
184
185ha_create_table_option example_field_option_list[]=
186{
187 /*
188 If the engine wants something more complex than a string, number, enum,
189 or boolean - for example a list - it needs to specify the option
190 as a string and parse it internally.
191 */
192 HA_FOPTION_STRING("COMPLEX", complex_param_to_parse_it_in_engine),
193 HA_FOPTION_END
194};
195
196
197/**
198 @brief
199 Function we use in the creation of our hash to get key.
200*/
201
202#ifdef HAVE_PSI_INTERFACE
203static PSI_mutex_key ex_key_mutex_Example_share_mutex;
204
205static PSI_mutex_info all_example_mutexes[]=
206{
207 { &ex_key_mutex_Example_share_mutex, "Example_share::mutex", 0}
208};
209
210static void init_example_psi_keys()
211{
212 const char* category= "example";
213 int count;
214
215 count= array_elements(all_example_mutexes);
216 mysql_mutex_register(category, all_example_mutexes, count);
217}
218#endif
219
220
221/**
222 @brief
223 If frm_error() is called then we will use this to determine
224 the file extensions that exist for the storage engine. This is also
225 used by the default rename_table and delete_table method in
226 handler.cc and by the default discover_many method.
227
228 For engines that have two file name extentions (separate meta/index file
229 and data file), the order of elements is relevant. First element of engine
230 file name extentions array should be meta/index file extention. Second
231 element - data file extention. This order is assumed by
232 prepare_for_repair() when REPAIR TABLE ... USE_FRM is issued.
233
234 @see
235 rename_table method in handler.cc and
236 delete_table method in handler.cc
237*/
238
239static const char *ha_example_exts[] = {
240 NullS
241};
242
243Example_share::Example_share()
244{
245 thr_lock_init(&lock);
246 mysql_mutex_init(ex_key_mutex_Example_share_mutex,
247 &mutex, MY_MUTEX_INIT_FAST);
248}
249
250
251static int example_init_func(void *p)
252{
253 DBUG_ENTER("example_init_func");
254
255#ifdef HAVE_PSI_INTERFACE
256 init_example_psi_keys();
257#endif
258
259 example_hton= (handlerton *)p;
260 example_hton->state= SHOW_OPTION_YES;
261 example_hton->create= example_create_handler;
262 example_hton->flags= HTON_CAN_RECREATE;
263 example_hton->table_options= example_table_option_list;
264 example_hton->field_options= example_field_option_list;
265 example_hton->tablefile_extensions= ha_example_exts;
266
267 DBUG_RETURN(0);
268}
269
270
271/**
272 @brief
273 Example of simple lock controls. The "share" it creates is a
274 structure we will pass to each example handler. Do you have to have
275 one of these? Well, you have pieces that are used for locking, and
276 they are needed to function.
277*/
278
279Example_share *ha_example::get_share()
280{
281 Example_share *tmp_share;
282
283 DBUG_ENTER("ha_example::get_share()");
284
285 lock_shared_ha_data();
286 if (!(tmp_share= static_cast<Example_share*>(get_ha_share_ptr())))
287 {
288 tmp_share= new Example_share;
289 if (!tmp_share)
290 goto err;
291
292 set_ha_share_ptr(static_cast<Handler_share*>(tmp_share));
293 }
294err:
295 unlock_shared_ha_data();
296 DBUG_RETURN(tmp_share);
297}
298
299static handler* example_create_handler(handlerton *hton,
300 TABLE_SHARE *table,
301 MEM_ROOT *mem_root)
302{
303 return new (mem_root) ha_example(hton, table);
304}
305
306ha_example::ha_example(handlerton *hton, TABLE_SHARE *table_arg)
307 :handler(hton, table_arg)
308{}
309
310
311/**
312 @brief
313 Used for opening tables. The name will be the name of the file.
314
315 @details
316 A table is opened when it needs to be opened; e.g. when a request comes in
317 for a SELECT on the table (tables are not open and closed for each request,
318 they are cached).
319
320 Called from handler.cc by handler::ha_open(). The server opens all tables by
321 calling ha_open() which then calls the handler specific open().
322
323 @see
324 handler::ha_open() in handler.cc
325*/
326
327int ha_example::open(const char *name, int mode, uint test_if_locked)
328{
329 DBUG_ENTER("ha_example::open");
330
331 if (!(share = get_share()))
332 DBUG_RETURN(1);
333 thr_lock_data_init(&share->lock,&lock,NULL);
334
335#ifndef DBUG_OFF
336 ha_table_option_struct *options= table->s->option_struct;
337
338 DBUG_ASSERT(options);
339 DBUG_PRINT("info", ("strparam: '%-.64s' ullparam: %llu enumparam: %u "\
340 "boolparam: %u",
341 (options->strparam ? options->strparam : "<NULL>"),
342 options->ullparam, options->enumparam, options->boolparam));
343#endif
344
345 DBUG_RETURN(0);
346}
347
348
349/**
350 @brief
351 Closes a table.
352
353 @details
354 Called from sql_base.cc, sql_select.cc, and table.cc. In sql_select.cc it is
355 only used to close up temporary tables or during the process where a
356 temporary table is converted over to being a myisam table.
357
358 For sql_base.cc look at close_data_tables().
359
360 @see
361 sql_base.cc, sql_select.cc and table.cc
362*/
363
364int ha_example::close(void)
365{
366 DBUG_ENTER("ha_example::close");
367 DBUG_RETURN(0);
368}
369
370
371/**
372 @brief
373 write_row() inserts a row. No extra() hint is given currently if a bulk load
374 is happening. buf() is a byte array of data. You can use the field
375 information to extract the data from the native byte array type.
376
377 @details
378 Example of this would be:
379 @code
380 for (Field **field=table->field ; *field ; field++)
381 {
382 ...
383 }
384 @endcode
385
386 See ha_tina.cc for an example of extracting all of the data as strings.
387 ha_berekly.cc has an example of how to store it intact by "packing" it
388 for ha_berkeley's own native storage type.
389
390 See the note for update_row() on auto_increments and timestamps. This
391 case also applies to write_row().
392
393 Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
394 sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
395
396 @see
397 item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
398 sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc and sql_update.cc
399*/
400
401int ha_example::write_row(uchar *buf)
402{
403 DBUG_ENTER("ha_example::write_row");
404 /*
405 Example of a successful write_row. We don't store the data
406 anywhere; they are thrown away. A real implementation will
407 probably need to do something with 'buf'. We report a success
408 here, to pretend that the insert was successful.
409 */
410 DBUG_RETURN(0);
411}
412
413
414/**
415 @brief
416 Yes, update_row() does what you expect, it updates a row. old_data will have
417 the previous row record in it, while new_data will have the newest data in it.
418 Keep in mind that the server can do updates based on ordering if an ORDER BY
419 clause was used. Consecutive ordering is not guaranteed.
420
421 @details
422 Currently new_data will not have an updated auto_increament record, or
423 and updated timestamp field. You can do these for example by doing:
424 @code
425 if (table->next_number_field && record == table->record[0])
426 update_auto_increment();
427 @endcode
428
429 Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
430
431 @see
432 sql_select.cc, sql_acl.cc, sql_update.cc and sql_insert.cc
433*/
434int ha_example::update_row(const uchar *old_data, const uchar *new_data)
435{
436
437 DBUG_ENTER("ha_example::update_row");
438 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
439}
440
441
442/**
443 @brief
444 This will delete a row. buf will contain a copy of the row to be deleted.
445 The server will call this right after the current row has been called (from
446 either a previous rnd_nexT() or index call).
447
448 @details
449 If you keep a pointer to the last row or can access a primary key it will
450 make doing the deletion quite a bit easier. Keep in mind that the server does
451 not guarantee consecutive deletions. ORDER BY clauses can be used.
452
453 Called in sql_acl.cc and sql_udf.cc to manage internal table
454 information. Called in sql_delete.cc, sql_insert.cc, and
455 sql_select.cc. In sql_select it is used for removing duplicates
456 while in insert it is used for REPLACE calls.
457
458 @see
459 sql_acl.cc, sql_udf.cc, sql_delete.cc, sql_insert.cc and sql_select.cc
460*/
461
462int ha_example::delete_row(const uchar *buf)
463{
464 DBUG_ENTER("ha_example::delete_row");
465 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
466}
467
468
469/**
470 @brief
471 Positions an index cursor to the index specified in the handle. Fetches the
472 row if available. If the key value is null, begin at the first key of the
473 index.
474*/
475
476int ha_example::index_read_map(uchar *buf, const uchar *key,
477 key_part_map keypart_map __attribute__((unused)),
478 enum ha_rkey_function find_flag
479 __attribute__((unused)))
480{
481 int rc;
482 DBUG_ENTER("ha_example::index_read");
483 rc= HA_ERR_WRONG_COMMAND;
484 DBUG_RETURN(rc);
485}
486
487
488/**
489 @brief
490 Used to read forward through the index.
491*/
492
493int ha_example::index_next(uchar *buf)
494{
495 int rc;
496 DBUG_ENTER("ha_example::index_next");
497 rc= HA_ERR_WRONG_COMMAND;
498 DBUG_RETURN(rc);
499}
500
501
502/**
503 @brief
504 Used to read backwards through the index.
505*/
506
507int ha_example::index_prev(uchar *buf)
508{
509 int rc;
510 DBUG_ENTER("ha_example::index_prev");
511 rc= HA_ERR_WRONG_COMMAND;
512 DBUG_RETURN(rc);
513}
514
515
516/**
517 @brief
518 index_first() asks for the first key in the index.
519
520 @details
521 Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
522
523 @see
524 opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
525*/
526int ha_example::index_first(uchar *buf)
527{
528 int rc;
529 DBUG_ENTER("ha_example::index_first");
530 rc= HA_ERR_WRONG_COMMAND;
531 DBUG_RETURN(rc);
532}
533
534
535/**
536 @brief
537 index_last() asks for the last key in the index.
538
539 @details
540 Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
541
542 @see
543 opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
544*/
545int ha_example::index_last(uchar *buf)
546{
547 int rc;
548 DBUG_ENTER("ha_example::index_last");
549 rc= HA_ERR_WRONG_COMMAND;
550 DBUG_RETURN(rc);
551}
552
553
554/**
555 @brief
556 rnd_init() is called when the system wants the storage engine to do a table
557 scan. See the example in the introduction at the top of this file to see when
558 rnd_init() is called.
559
560 @details
561 Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
562 and sql_update.cc.
563
564 @see
565 filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
566*/
567int ha_example::rnd_init(bool scan)
568{
569 DBUG_ENTER("ha_example::rnd_init");
570 DBUG_RETURN(0);
571}
572
573int ha_example::rnd_end()
574{
575 DBUG_ENTER("ha_example::rnd_end");
576 DBUG_RETURN(0);
577}
578
579
580/**
581 @brief
582 This is called for each row of the table scan. When you run out of records
583 you should return HA_ERR_END_OF_FILE. Fill buff up with the row information.
584 The Field structure for the table is the key to getting data into buf
585 in a manner that will allow the server to understand it.
586
587 @details
588 Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
589 and sql_update.cc.
590
591 @see
592 filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
593*/
594int ha_example::rnd_next(uchar *buf)
595{
596 int rc;
597 DBUG_ENTER("ha_example::rnd_next");
598 rc= HA_ERR_END_OF_FILE;
599 DBUG_RETURN(rc);
600}
601
602
603/**
604 @brief
605 position() is called after each call to rnd_next() if the data needs
606 to be ordered. You can do something like the following to store
607 the position:
608 @code
609 my_store_ptr(ref, ref_length, current_position);
610 @endcode
611
612 @details
613 The server uses ref to store data. ref_length in the above case is
614 the size needed to store current_position. ref is just a byte array
615 that the server will maintain. If you are using offsets to mark rows, then
616 current_position should be the offset. If it is a primary key like in
617 BDB, then it needs to be a primary key.
618
619 Called from filesort.cc, sql_select.cc, sql_delete.cc, and sql_update.cc.
620
621 @see
622 filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc
623*/
624void ha_example::position(const uchar *record)
625{
626 DBUG_ENTER("ha_example::position");
627 DBUG_VOID_RETURN;
628}
629
630
631/**
632 @brief
633 This is like rnd_next, but you are given a position to use
634 to determine the row. The position will be of the type that you stored in
635 ref. You can use ha_get_ptr(pos,ref_length) to retrieve whatever key
636 or position you saved when position() was called.
637
638 @details
639 Called from filesort.cc, records.cc, sql_insert.cc, sql_select.cc, and sql_update.cc.
640
641 @see
642 filesort.cc, records.cc, sql_insert.cc, sql_select.cc and sql_update.cc
643*/
644int ha_example::rnd_pos(uchar *buf, uchar *pos)
645{
646 int rc;
647 DBUG_ENTER("ha_example::rnd_pos");
648 rc= HA_ERR_WRONG_COMMAND;
649 DBUG_RETURN(rc);
650}
651
652
653/**
654 @brief
655 ::info() is used to return information to the optimizer. See my_base.h for
656 the complete description.
657
658 @details
659 Currently this table handler doesn't implement most of the fields really needed.
660 SHOW also makes use of this data.
661
662 You will probably want to have the following in your code:
663 @code
664 if (records < 2)
665 records = 2;
666 @endcode
667 The reason is that the server will optimize for cases of only a single
668 record. If, in a table scan, you don't know the number of records, it
669 will probably be better to set records to two so you can return as many
670 records as you need. Along with records, a few more variables you may wish
671 to set are:
672 records
673 deleted
674 data_file_length
675 index_file_length
676 delete_length
677 check_time
678 Take a look at the public variables in handler.h for more information.
679
680 Called in filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc,
681 sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc,
682 sql_select.cc, sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc,
683 sql_table.cc, sql_union.cc, and sql_update.cc.
684
685 @see
686 filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc, sql_delete.cc,
687 sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc, sql_select.cc,
688 sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_table.cc,
689 sql_union.cc and sql_update.cc
690*/
691int ha_example::info(uint flag)
692{
693 DBUG_ENTER("ha_example::info");
694 DBUG_RETURN(0);
695}
696
697
698/**
699 @brief
700 extra() is called whenever the server wishes to send a hint to
701 the storage engine. The myisam engine implements the most hints.
702 ha_innodb.cc has the most exhaustive list of these hints.
703
704 @see
705 ha_innodb.cc
706*/
707int ha_example::extra(enum ha_extra_function operation)
708{
709 DBUG_ENTER("ha_example::extra");
710 DBUG_RETURN(0);
711}
712
713
714/**
715 @brief
716 Used to delete all rows in a table, including cases of truncate and cases where
717 the optimizer realizes that all rows will be removed as a result of an SQL statement.
718
719 @details
720 Called from item_sum.cc by Item_func_group_concat::clear(),
721 Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
722 Called from sql_delete.cc by mysql_delete().
723 Called from sql_select.cc by JOIN::reinit().
724 Called from sql_union.cc by st_select_lex_unit::exec().
725
726 @see
727 Item_func_group_concat::clear(), Item_sum_count_distinct::clear() and
728 Item_func_group_concat::clear() in item_sum.cc;
729 mysql_delete() in sql_delete.cc;
730 JOIN::reinit() in sql_select.cc and
731 st_select_lex_unit::exec() in sql_union.cc.
732*/
733int ha_example::delete_all_rows()
734{
735 DBUG_ENTER("ha_example::delete_all_rows");
736 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
737}
738
739
740/**
741 @brief
742 This create a lock on the table. If you are implementing a storage engine
743 that can handle transacations look at ha_berkely.cc to see how you will
744 want to go about doing this. Otherwise you should consider calling flock()
745 here. Hint: Read the section "locking functions for mysql" in lock.cc to understand
746 this.
747
748 @details
749 Called from lock.cc by lock_external() and unlock_external(). Also called
750 from sql_table.cc by copy_data_between_tables().
751
752 @see
753 lock.cc by lock_external() and unlock_external() in lock.cc;
754 the section "locking functions for mysql" in lock.cc;
755 copy_data_between_tables() in sql_table.cc.
756*/
757int ha_example::external_lock(THD *thd, int lock_type)
758{
759 DBUG_ENTER("ha_example::external_lock");
760 DBUG_RETURN(0);
761}
762
763
764/**
765 @brief
766 The idea with handler::store_lock() is: The statement decides which locks
767 should be needed for the table. For updates/deletes/inserts we get WRITE
768 locks, for SELECT... we get read locks.
769
770 @details
771 Before adding the lock into the table lock handler (see thr_lock.c),
772 mysqld calls store lock with the requested locks. Store lock can now
773 modify a write lock to a read lock (or some other lock), ignore the
774 lock (if we don't want to use MySQL table locks at all), or add locks
775 for many tables (like we do when we are using a MERGE handler).
776
777 Berkeley DB, for example, changes all WRITE locks to TL_WRITE_ALLOW_WRITE
778 (which signals that we are doing WRITES, but are still allowing other
779 readers and writers).
780
781 When releasing locks, store_lock() is also called. In this case one
782 usually doesn't have to do anything.
783
784 In some exceptional cases MySQL may send a request for a TL_IGNORE;
785 This means that we are requesting the same lock as last time and this
786 should also be ignored. (This may happen when someone does a flush
787 table when we have opened a part of the tables, in which case mysqld
788 closes and reopens the tables and tries to get the same locks at last
789 time). In the future we will probably try to remove this.
790
791 Called from lock.cc by get_lock_data().
792
793 @note
794 In this method one should NEVER rely on table->in_use, it may, in fact,
795 refer to a different thread! (this happens if get_lock_data() is called
796 from mysql_lock_abort_for_thread() function)
797
798 @see
799 get_lock_data() in lock.cc
800*/
801THR_LOCK_DATA **ha_example::store_lock(THD *thd,
802 THR_LOCK_DATA **to,
803 enum thr_lock_type lock_type)
804{
805 if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
806 lock.type=lock_type;
807 *to++= &lock;
808 return to;
809}
810
811
812/**
813 @brief
814 Used to delete a table. By the time delete_table() has been called all
815 opened references to this table will have been closed (and your globally
816 shared references released). The variable name will just be the name of
817 the table. You will need to remove any files you have created at this point.
818
819 @details
820 If you do not implement this, the default delete_table() is called from
821 handler.cc and it will delete all files with the file extensions returned
822 by bas_ext().
823
824 Called from handler.cc by delete_table and ha_create_table(). Only used
825 during create if the table_flag HA_DROP_BEFORE_CREATE was specified for
826 the storage engine.
827
828 @see
829 delete_table and ha_create_table() in handler.cc
830*/
831int ha_example::delete_table(const char *name)
832{
833 DBUG_ENTER("ha_example::delete_table");
834 /* This is not implemented but we want someone to be able that it works. */
835 DBUG_RETURN(0);
836}
837
838
839/**
840 @brief
841 Given a starting key and an ending key, estimate the number of rows that
842 will exist between the two keys.
843
844 @details
845 end_key may be empty, in which case determine if start_key matches any rows.
846
847 Called from opt_range.cc by check_quick_keys().
848
849 @see
850 check_quick_keys() in opt_range.cc
851*/
852ha_rows ha_example::records_in_range(uint inx, key_range *min_key,
853 key_range *max_key)
854{
855 DBUG_ENTER("ha_example::records_in_range");
856 DBUG_RETURN(10); // low number to force index usage
857}
858
859
860/**
861 @brief
862 create() is called to create a database. The variable name will have the name
863 of the table.
864
865 @details
866 When create() is called you do not need to worry about
867 opening the table. Also, the .frm file will have already been
868 created so adjusting create_info is not necessary. You can overwrite
869 the .frm file at this point if you wish to change the table
870 definition, but there are no methods currently provided for doing
871 so.
872
873 Called from handle.cc by ha_create_table().
874
875 @see
876 ha_create_table() in handle.cc
877*/
878
879int ha_example::create(const char *name, TABLE *table_arg,
880 HA_CREATE_INFO *create_info)
881{
882#ifndef DBUG_OFF
883 ha_table_option_struct *options= table_arg->s->option_struct;
884 DBUG_ENTER("ha_example::create");
885 /*
886 This example shows how to support custom engine specific table and field
887 options.
888 */
889 DBUG_ASSERT(options);
890 DBUG_PRINT("info", ("strparam: '%-.64s' ullparam: %llu enumparam: %u "\
891 "boolparam: %u",
892 (options->strparam ? options->strparam : "<NULL>"),
893 options->ullparam, options->enumparam, options->boolparam));
894 for (Field **field= table_arg->s->field; *field; field++)
895 {
896 ha_field_option_struct *field_options= (*field)->option_struct;
897 DBUG_ASSERT(field_options);
898 DBUG_PRINT("info", ("field: %s complex: '%-.64s'",
899 (*field)->field_name.str,
900 (field_options->complex_param_to_parse_it_in_engine ?
901 field_options->complex_param_to_parse_it_in_engine :
902 "<NULL>")));
903 }
904#endif
905 DBUG_RETURN(0);
906}
907
908
909/**
910 check_if_supported_inplace_alter() is used to ask the engine whether
911 it can execute this ALTER TABLE statement in place or the server needs to
912 create a new table and copy th data over.
913
914 The engine may answer that the inplace alter is not supported or,
915 if supported, whether the server should protect the table from concurrent
916 accesses. Return values are
917
918 HA_ALTER_INPLACE_NOT_SUPPORTED
919 HA_ALTER_INPLACE_EXCLUSIVE_LOCK
920 HA_ALTER_INPLACE_SHARED_LOCK
921 etc
922*/
923
924enum_alter_inplace_result
925ha_example::check_if_supported_inplace_alter(TABLE* altered_table,
926 Alter_inplace_info* ha_alter_info)
927{
928 HA_CREATE_INFO *info= ha_alter_info->create_info;
929 DBUG_ENTER("ha_example::check_if_supported_inplace_alter");
930
931 if (ha_alter_info->handler_flags & ALTER_CHANGE_CREATE_OPTION)
932 {
933 /*
934 This example shows how custom engine specific table and field
935 options can be accessed from this function to be compared.
936 */
937 ha_table_option_struct *param_new= info->option_struct;
938 ha_table_option_struct *param_old= table->s->option_struct;
939
940 /*
941 check important parameters:
942 for this example engine, we'll assume that changing ullparam or
943 boolparam requires a table to be rebuilt, while changing strparam
944 or enumparam - does not.
945
946 For debugging purposes we'll announce this to the user
947 (don't do it in production!)
948
949 */
950 if (param_new->ullparam != param_old->ullparam)
951 {
952 push_warning_printf(ha_thd(), Sql_condition::WARN_LEVEL_NOTE,
953 ER_UNKNOWN_ERROR, "EXAMPLE DEBUG: ULL %llu -> %llu",
954 param_old->ullparam, param_new->ullparam);
955 DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
956 }
957
958 if (param_new->boolparam != param_old->boolparam)
959 {
960 push_warning_printf(ha_thd(), Sql_condition::WARN_LEVEL_NOTE,
961 ER_UNKNOWN_ERROR, "EXAMPLE DEBUG: YESNO %u -> %u",
962 param_old->boolparam, param_new->boolparam);
963 DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
964 }
965 }
966
967 if (ha_alter_info->handler_flags & ALTER_COLUMN_OPTION)
968 {
969 for (uint i= 0; i < table->s->fields; i++)
970 {
971 ha_field_option_struct *f_old= table->s->field[i]->option_struct;
972 ha_field_option_struct *f_new= info->fields_option_struct[i];
973 DBUG_ASSERT(f_old);
974 if (f_new)
975 {
976 push_warning_printf(ha_thd(), Sql_condition::WARN_LEVEL_NOTE,
977 ER_UNKNOWN_ERROR, "EXAMPLE DEBUG: Field %`s COMPLEX '%s' -> '%s'",
978 table->s->field[i]->field_name.str,
979 f_old->complex_param_to_parse_it_in_engine,
980 f_new->complex_param_to_parse_it_in_engine);
981 }
982 else
983 DBUG_PRINT("info", ("old field %i did not changed", i));
984 }
985 }
986
987 DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK);
988}
989
990
991struct st_mysql_storage_engine example_storage_engine=
992{ MYSQL_HANDLERTON_INTERFACE_VERSION };
993
994static ulong srv_enum_var= 0;
995static ulong srv_ulong_var= 0;
996static double srv_double_var= 0;
997
998const char *enum_var_names[]=
999{
1000 "e1", "e2", NullS
1001};
1002
1003TYPELIB enum_var_typelib=
1004{
1005 array_elements(enum_var_names) - 1, "enum_var_typelib",
1006 enum_var_names, NULL
1007};
1008
1009static MYSQL_SYSVAR_ENUM(
1010 enum_var, // name
1011 srv_enum_var, // varname
1012 PLUGIN_VAR_RQCMDARG, // opt
1013 "Sample ENUM system variable.", // comment
1014 NULL, // check
1015 NULL, // update
1016 0, // def
1017 &enum_var_typelib); // typelib
1018
1019static MYSQL_THDVAR_INT(int_var, PLUGIN_VAR_RQCMDARG, "-1..1",
1020 NULL, NULL, 0, -1, 1, 0);
1021
1022static MYSQL_SYSVAR_ULONG(
1023 ulong_var,
1024 srv_ulong_var,
1025 PLUGIN_VAR_RQCMDARG,
1026 "0..1000",
1027 NULL,
1028 NULL,
1029 8,
1030 0,
1031 1000,
1032 0);
1033
1034static MYSQL_SYSVAR_DOUBLE(
1035 double_var,
1036 srv_double_var,
1037 PLUGIN_VAR_RQCMDARG,
1038 "0.500000..1000.500000",
1039 NULL,
1040 NULL,
1041 8.5,
1042 0.5,
1043 1000.5,
1044 0); // reserved always 0
1045
1046static MYSQL_THDVAR_DOUBLE(
1047 double_thdvar,
1048 PLUGIN_VAR_RQCMDARG,
1049 "0.500000..1000.500000",
1050 NULL,
1051 NULL,
1052 8.5,
1053 0.5,
1054 1000.5,
1055 0);
1056
1057static struct st_mysql_sys_var* example_system_variables[]= {
1058 MYSQL_SYSVAR(enum_var),
1059 MYSQL_SYSVAR(ulong_var),
1060 MYSQL_SYSVAR(int_var),
1061 MYSQL_SYSVAR(double_var),
1062 MYSQL_SYSVAR(double_thdvar),
1063 MYSQL_SYSVAR(varopt_default),
1064 NULL
1065};
1066
1067// this is an example of SHOW_SIMPLE_FUNC and of my_snprintf() service
1068// If this function would return an array, one should use SHOW_FUNC
1069static int show_func_example(MYSQL_THD thd, struct st_mysql_show_var *var,
1070 char *buf)
1071{
1072 var->type= SHOW_CHAR;
1073 var->value= buf; // it's of SHOW_VAR_FUNC_BUFF_SIZE bytes
1074 my_snprintf(buf, SHOW_VAR_FUNC_BUFF_SIZE,
1075 "enum_var is %lu, ulong_var is %lu, int_var is %d, "
1076 "double_var is %f, %.6b", // %b is a MySQL extension
1077 srv_enum_var, srv_ulong_var, THDVAR(thd, int_var),
1078 srv_double_var, "really");
1079 return 0;
1080}
1081
1082static struct st_mysql_show_var func_status[]=
1083{
1084 {"func_example", (char *)show_func_example, SHOW_SIMPLE_FUNC},
1085 {0,0,SHOW_UNDEF}
1086};
1087
1088struct st_mysql_daemon unusable_example=
1089{ MYSQL_DAEMON_INTERFACE_VERSION };
1090
1091mysql_declare_plugin(example)
1092{
1093 MYSQL_STORAGE_ENGINE_PLUGIN,
1094 &example_storage_engine,
1095 "EXAMPLE",
1096 "Brian Aker, MySQL AB",
1097 "Example storage engine",
1098 PLUGIN_LICENSE_GPL,
1099 example_init_func, /* Plugin Init */
1100 NULL, /* Plugin Deinit */
1101 0x0001 /* 0.1 */,
1102 func_status, /* status variables */
1103 example_system_variables, /* system variables */
1104 NULL, /* config options */
1105 0, /* flags */
1106}
1107mysql_declare_plugin_end;
1108maria_declare_plugin(example)
1109{
1110 MYSQL_STORAGE_ENGINE_PLUGIN,
1111 &example_storage_engine,
1112 "EXAMPLE",
1113 "Brian Aker, MySQL AB",
1114 "Example storage engine",
1115 PLUGIN_LICENSE_GPL,
1116 example_init_func, /* Plugin Init */
1117 NULL, /* Plugin Deinit */
1118 0x0001, /* version number (0.1) */
1119 func_status, /* status variables */
1120 example_system_variables, /* system variables */
1121 "0.1", /* string version */
1122 MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
1123},
1124{
1125 MYSQL_DAEMON_PLUGIN,
1126 &unusable_example,
1127 "UNUSABLE",
1128 "Sergei Golubchik",
1129 "Unusable Daemon",
1130 PLUGIN_LICENSE_GPL,
1131 NULL, /* Plugin Init */
1132 NULL, /* Plugin Deinit */
1133 0x030E, /* version number (3.14) */
1134 NULL, /* status variables */
1135 NULL, /* system variables */
1136 "3.14.15.926" , /* version, as a string */
1137 MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
1138}
1139maria_declare_plugin_end;
1140