1 /* Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 /**
24 @file ha_example.cc
25
26 @brief
27 The ha_example engine is a stubbed storage engine for example purposes only;
28 it does nothing at this point. Its purpose is to provide a source
29 code illustration of how to begin writing new storage engines; see also
30 /storage/example/ha_example.h.
31
32 @details
33 ha_example will let you create/open/delete tables, but
34 nothing further (for example, indexes are not supported nor can data
35 be stored in the table). Use this example as a template for
36 implementing the same functionality in your own storage engine. You
37 can enable the example storage engine in your build by doing the
38 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 ha_example::rnd_next
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::extra
76 ha_example::external_lock
77 ha_example::extra
78 ENUM HA_EXTRA_RESET Reset database to after open
79 @endcode
80
81 Here you see that the example storage engine has 9 rows called before
82 rnd_next signals that it has reached the end of its data. Also note that
83 the table in question was already opened; had it not been open, a call to
84 ha_example::open() would also have been necessary. Calls to
85 ha_example::extra() are hints as to what will be occurring to the request.
86
87 A Longer Example can be found called the "Skeleton Engine" which can be
88 found on TangentOrg. It has both an engine and a full build environment
89 for building a pluggable storage engine.
90
91 Happy coding!<br>
92 -Brian
93 */
94
95 #include "storage/example/ha_example.h"
96
97 #include "my_dbug.h"
98 #include "mysql/plugin.h"
99 #include "sql/sql_class.h"
100 #include "sql/sql_plugin.h"
101 #include "typelib.h"
102
103 static handler *example_create_handler(handlerton *hton, TABLE_SHARE *table,
104 bool partitioned, MEM_ROOT *mem_root);
105
106 handlerton *example_hton;
107
108 /* Interface to mysqld, to check system tables supported by SE */
109 static bool example_is_supported_system_table(const char *db,
110 const char *table_name,
111 bool is_sql_layer_system_table);
112
Example_share()113 Example_share::Example_share() { thr_lock_init(&lock); }
114
example_init_func(void * p)115 static int example_init_func(void *p) {
116 DBUG_TRACE;
117
118 example_hton = (handlerton *)p;
119 example_hton->state = SHOW_OPTION_YES;
120 example_hton->create = example_create_handler;
121 example_hton->flags = HTON_CAN_RECREATE;
122 example_hton->is_supported_system_table = example_is_supported_system_table;
123
124 return 0;
125 }
126
127 /**
128 @brief
129 Example of simple lock controls. The "share" it creates is a
130 structure we will pass to each example handler. Do you have to have
131 one of these? Well, you have pieces that are used for locking, and
132 they are needed to function.
133 */
134
get_share()135 Example_share *ha_example::get_share() {
136 Example_share *tmp_share;
137
138 DBUG_TRACE;
139
140 lock_shared_ha_data();
141 if (!(tmp_share = static_cast<Example_share *>(get_ha_share_ptr()))) {
142 tmp_share = new Example_share;
143 if (!tmp_share) goto err;
144
145 set_ha_share_ptr(static_cast<Handler_share *>(tmp_share));
146 }
147 err:
148 unlock_shared_ha_data();
149 return tmp_share;
150 }
151
example_create_handler(handlerton * hton,TABLE_SHARE * table,bool,MEM_ROOT * mem_root)152 static handler *example_create_handler(handlerton *hton, TABLE_SHARE *table,
153 bool, MEM_ROOT *mem_root) {
154 return new (mem_root) ha_example(hton, table);
155 }
156
ha_example(handlerton * hton,TABLE_SHARE * table_arg)157 ha_example::ha_example(handlerton *hton, TABLE_SHARE *table_arg)
158 : handler(hton, table_arg) {}
159
160 /*
161 List of all system tables specific to the SE.
162 Array element would look like below,
163 { "<database_name>", "<system table name>" },
164 The last element MUST be,
165 { (const char*)NULL, (const char*)NULL }
166
167 This array is optional, so every SE need not implement it.
168 */
169 static st_handler_tablename ha_example_system_tables[] = {
170 {(const char *)nullptr, (const char *)nullptr}};
171
172 /**
173 @brief Check if the given db.tablename is a system table for this SE.
174
175 @param db Database name to check.
176 @param table_name table name to check.
177 @param is_sql_layer_system_table if the supplied db.table_name is a SQL
178 layer system table.
179
180 @retval true Given db.table_name is supported system table.
181 @retval false Given db.table_name is not a supported system table.
182 */
example_is_supported_system_table(const char * db,const char * table_name,bool is_sql_layer_system_table)183 static bool example_is_supported_system_table(const char *db,
184 const char *table_name,
185 bool is_sql_layer_system_table) {
186 st_handler_tablename *systab;
187
188 // Does this SE support "ALL" SQL layer system tables ?
189 if (is_sql_layer_system_table) return false;
190
191 // Check if this is SE layer system tables
192 systab = ha_example_system_tables;
193 while (systab && systab->db) {
194 if (systab->db == db && strcmp(systab->tablename, table_name) == 0)
195 return true;
196 systab++;
197 }
198
199 return false;
200 }
201
202 /**
203 @brief
204 Used for opening tables. The name will be the name of the file.
205
206 @details
207 A table is opened when it needs to be opened; e.g. when a request comes in
208 for a SELECT on the table (tables are not open and closed for each request,
209 they are cached).
210
211 Called from handler.cc by handler::ha_open(). The server opens all tables by
212 calling ha_open() which then calls the handler specific open().
213
214 @see
215 handler::ha_open() in handler.cc
216 */
217
open(const char *,int,uint,const dd::Table *)218 int ha_example::open(const char *, int, uint, const dd::Table *) {
219 DBUG_TRACE;
220
221 if (!(share = get_share())) return 1;
222 thr_lock_data_init(&share->lock, &lock, nullptr);
223
224 return 0;
225 }
226
227 /**
228 @brief
229 Closes a table.
230
231 @details
232 Called from sql_base.cc, sql_select.cc, and table.cc. In sql_select.cc it is
233 only used to close up temporary tables or during the process where a
234 temporary table is converted over to being a myisam table.
235
236 For sql_base.cc look at close_data_tables().
237
238 @see
239 sql_base.cc, sql_select.cc and table.cc
240 */
241
close(void)242 int ha_example::close(void) {
243 DBUG_TRACE;
244 return 0;
245 }
246
247 /**
248 @brief
249 write_row() inserts a row. No extra() hint is given currently if a bulk load
250 is happening. buf() is a byte array of data. You can use the field
251 information to extract the data from the native byte array type.
252
253 @details
254 Example of this would be:
255 @code
256 for (Field **field=table->field ; *field ; field++)
257 {
258 ...
259 }
260 @endcode
261
262 See ha_tina.cc for an example of extracting all of the data as strings.
263 ha_berekly.cc has an example of how to store it intact by "packing" it
264 for ha_berkeley's own native storage type.
265
266 See the note for update_row() on auto_increments. This case also applies to
267 write_row().
268
269 Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
270 sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
271
272 @see
273 item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
274 sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc and sql_update.cc
275 */
276
write_row(uchar *)277 int ha_example::write_row(uchar *) {
278 DBUG_TRACE;
279 /*
280 Example of a successful write_row. We don't store the data
281 anywhere; they are thrown away. A real implementation will
282 probably need to do something with 'buf'. We report a success
283 here, to pretend that the insert was successful.
284 */
285 return 0;
286 }
287
288 /**
289 @brief
290 Yes, update_row() does what you expect, it updates a row. old_data will have
291 the previous row record in it, while new_data will have the newest data in it.
292 Keep in mind that the server can do updates based on ordering if an ORDER BY
293 clause was used. Consecutive ordering is not guaranteed.
294
295 @details
296 Currently new_data will not have an updated auto_increament record. You can
297 do this for example by doing:
298
299 @code
300
301 if (table->next_number_field && record == table->record[0])
302 update_auto_increment();
303
304 @endcode
305
306 Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
307
308 @see
309 sql_select.cc, sql_acl.cc, sql_update.cc and sql_insert.cc
310 */
update_row(const uchar *,uchar *)311 int ha_example::update_row(const uchar *, uchar *) {
312 DBUG_TRACE;
313 return HA_ERR_WRONG_COMMAND;
314 }
315
316 /**
317 @brief
318 This will delete a row. buf will contain a copy of the row to be deleted.
319 The server will call this right after the current row has been called (from
320 either a previous rnd_nexT() or index call).
321
322 @details
323 If you keep a pointer to the last row or can access a primary key it will
324 make doing the deletion quite a bit easier. Keep in mind that the server does
325 not guarantee consecutive deletions. ORDER BY clauses can be used.
326
327 Called in sql_acl.cc and sql_udf.cc to manage internal table
328 information. Called in sql_delete.cc, sql_insert.cc, and
329 sql_select.cc. In sql_select it is used for removing duplicates
330 while in insert it is used for REPLACE calls.
331
332 @see
333 sql_acl.cc, sql_udf.cc, sql_delete.cc, sql_insert.cc and sql_select.cc
334 */
335
delete_row(const uchar *)336 int ha_example::delete_row(const uchar *) {
337 DBUG_TRACE;
338 return HA_ERR_WRONG_COMMAND;
339 }
340
341 /**
342 @brief
343 Positions an index cursor to the index specified in the handle. Fetches the
344 row if available. If the key value is null, begin at the first key of the
345 index.
346 */
347
index_read_map(uchar *,const uchar *,key_part_map,enum ha_rkey_function)348 int ha_example::index_read_map(uchar *, const uchar *, key_part_map,
349 enum ha_rkey_function) {
350 int rc;
351 DBUG_TRACE;
352 rc = HA_ERR_WRONG_COMMAND;
353 return rc;
354 }
355
356 /**
357 @brief
358 Used to read forward through the index.
359 */
360
index_next(uchar *)361 int ha_example::index_next(uchar *) {
362 int rc;
363 DBUG_TRACE;
364 rc = HA_ERR_WRONG_COMMAND;
365 return rc;
366 }
367
368 /**
369 @brief
370 Used to read backwards through the index.
371 */
372
index_prev(uchar *)373 int ha_example::index_prev(uchar *) {
374 int rc;
375 DBUG_TRACE;
376 rc = HA_ERR_WRONG_COMMAND;
377 return rc;
378 }
379
380 /**
381 @brief
382 index_first() asks for the first key in the index.
383
384 @details
385 Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
386
387 @see
388 opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
389 */
index_first(uchar *)390 int ha_example::index_first(uchar *) {
391 int rc;
392 DBUG_TRACE;
393 rc = HA_ERR_WRONG_COMMAND;
394 return rc;
395 }
396
397 /**
398 @brief
399 index_last() asks for the last key in the index.
400
401 @details
402 Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
403
404 @see
405 opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
406 */
index_last(uchar *)407 int ha_example::index_last(uchar *) {
408 int rc;
409 DBUG_TRACE;
410 rc = HA_ERR_WRONG_COMMAND;
411 return rc;
412 }
413
414 /**
415 @brief
416 rnd_init() is called when the system wants the storage engine to do a table
417 scan. See the example in the introduction at the top of this file to see when
418 rnd_init() is called.
419
420 @details
421 Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc,
422 sql_table.cc, and sql_update.cc.
423
424 @see
425 filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and
426 sql_update.cc
427 */
rnd_init(bool)428 int ha_example::rnd_init(bool) {
429 DBUG_TRACE;
430 return 0;
431 }
432
rnd_end()433 int ha_example::rnd_end() {
434 DBUG_TRACE;
435 return 0;
436 }
437
438 /**
439 @brief
440 This is called for each row of the table scan. When you run out of records
441 you should return HA_ERR_END_OF_FILE. Fill buff up with the row information.
442 The Field structure for the table is the key to getting data into buf
443 in a manner that will allow the server to understand it.
444
445 @details
446 Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc,
447 sql_table.cc, and sql_update.cc.
448
449 @see
450 filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and
451 sql_update.cc
452 */
rnd_next(uchar *)453 int ha_example::rnd_next(uchar *) {
454 int rc;
455 DBUG_TRACE;
456 rc = HA_ERR_END_OF_FILE;
457 return rc;
458 }
459
460 /**
461 @brief
462 position() is called after each call to rnd_next() if the data needs
463 to be ordered. You can do something like the following to store
464 the position:
465 @code
466 my_store_ptr(ref, ref_length, current_position);
467 @endcode
468
469 @details
470 The server uses ref to store data. ref_length in the above case is
471 the size needed to store current_position. ref is just a byte array
472 that the server will maintain. If you are using offsets to mark rows, then
473 current_position should be the offset. If it is a primary key like in
474 BDB, then it needs to be a primary key.
475
476 Called from filesort.cc, sql_select.cc, sql_delete.cc, and sql_update.cc.
477
478 @see
479 filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc
480 */
position(const uchar *)481 void ha_example::position(const uchar *) { DBUG_TRACE; }
482
483 /**
484 @brief
485 This is like rnd_next, but you are given a position to use
486 to determine the row. The position will be of the type that you stored in
487 ref. You can use ha_get_ptr(pos,ref_length) to retrieve whatever key
488 or position you saved when position() was called.
489
490 @details
491 Called from filesort.cc, records.cc, sql_insert.cc, sql_select.cc, and
492 sql_update.cc.
493
494 @see
495 filesort.cc, records.cc, sql_insert.cc, sql_select.cc and sql_update.cc
496 */
rnd_pos(uchar *,uchar *)497 int ha_example::rnd_pos(uchar *, uchar *) {
498 int rc;
499 DBUG_TRACE;
500 rc = HA_ERR_WRONG_COMMAND;
501 return rc;
502 }
503
504 /**
505 @brief
506 ::info() is used to return information to the optimizer. See my_base.h for
507 the complete description.
508
509 @details
510 Currently this table handler doesn't implement most of the fields really
511 needed. SHOW also makes use of this data.
512
513 You will probably want to have the following in your code:
514 @code
515 if (records < 2)
516 records = 2;
517 @endcode
518 The reason is that the server will optimize for cases of only a single
519 record. If, in a table scan, you don't know the number of records, it
520 will probably be better to set records to two so you can return as many
521 records as you need. Along with records, a few more variables you may wish
522 to set are:
523 records
524 deleted
525 data_file_length
526 index_file_length
527 delete_length
528 check_time
529 Take a look at the public variables in handler.h for more information.
530
531 Called in filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc,
532 sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc,
533 sql_select.cc, sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc,
534 sql_show.cc, sql_table.cc, sql_union.cc, and sql_update.cc.
535
536 @see
537 filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc,
538 sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc,
539 sql_select.cc, sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc,
540 sql_show.cc, sql_table.cc, sql_union.cc and sql_update.cc
541 */
info(uint)542 int ha_example::info(uint) {
543 DBUG_TRACE;
544 return 0;
545 }
546
547 /**
548 @brief
549 extra() is called whenever the server wishes to send a hint to
550 the storage engine. The myisam engine implements the most hints.
551 ha_innodb.cc has the most exhaustive list of these hints.
552
553 @see
554 ha_innodb.cc
555 */
extra(enum ha_extra_function)556 int ha_example::extra(enum ha_extra_function) {
557 DBUG_TRACE;
558 return 0;
559 }
560
561 /**
562 @brief
563 Used to delete all rows in a table, including cases of truncate and cases
564 where the optimizer realizes that all rows will be removed as a result of an
565 SQL statement.
566
567 @details
568 Called from item_sum.cc by Item_func_group_concat::clear(),
569 Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
570 Called from sql_delete.cc by mysql_delete().
571 Called from sql_select.cc by JOIN::reinit().
572 Called from sql_union.cc by st_select_lex_unit::exec().
573
574 @see
575 Item_func_group_concat::clear(), Item_sum_count_distinct::clear() and
576 Item_func_group_concat::clear() in item_sum.cc;
577 mysql_delete() in sql_delete.cc;
578 JOIN::reinit() in sql_select.cc and
579 st_select_lex_unit::exec() in sql_union.cc.
580 */
delete_all_rows()581 int ha_example::delete_all_rows() {
582 DBUG_TRACE;
583 return HA_ERR_WRONG_COMMAND;
584 }
585
586 /**
587 @brief
588 This create a lock on the table. If you are implementing a storage engine
589 that can handle transacations look at ha_berkely.cc to see how you will
590 want to go about doing this. Otherwise you should consider calling flock()
591 here. Hint: Read the section "locking functions for mysql" in lock.cc to
592 understand this.
593
594 @details
595 Called from lock.cc by lock_external() and unlock_external(). Also called
596 from sql_table.cc by copy_data_between_tables().
597
598 @see
599 lock.cc by lock_external() and unlock_external() in lock.cc;
600 the section "locking functions for mysql" in lock.cc;
601 copy_data_between_tables() in sql_table.cc.
602 */
external_lock(THD *,int)603 int ha_example::external_lock(THD *, int) {
604 DBUG_TRACE;
605 return 0;
606 }
607
608 /**
609 @brief
610 The idea with handler::store_lock() is: The statement decides which locks
611 should be needed for the table. For updates/deletes/inserts we get WRITE
612 locks, for SELECT... we get read locks.
613
614 @details
615 Before adding the lock into the table lock handler (see thr_lock.c),
616 mysqld calls store lock with the requested locks. Store lock can now
617 modify a write lock to a read lock (or some other lock), ignore the
618 lock (if we don't want to use MySQL table locks at all), or add locks
619 for many tables (like we do when we are using a MERGE handler).
620
621 Berkeley DB, for example, changes all WRITE locks to TL_WRITE_ALLOW_WRITE
622 (which signals that we are doing WRITES, but are still allowing other
623 readers and writers).
624
625 When releasing locks, store_lock() is also called. In this case one
626 usually doesn't have to do anything.
627
628 In some exceptional cases MySQL may send a request for a TL_IGNORE;
629 This means that we are requesting the same lock as last time and this
630 should also be ignored. (This may happen when someone does a flush
631 table when we have opened a part of the tables, in which case mysqld
632 closes and reopens the tables and tries to get the same locks at last
633 time). In the future we will probably try to remove this.
634
635 Called from lock.cc by get_lock_data().
636
637 @note
638 In this method one should NEVER rely on table->in_use, it may, in fact,
639 refer to a different thread! (this happens if get_lock_data() is called
640 from mysql_lock_abort_for_thread() function)
641
642 @see
643 get_lock_data() in lock.cc
644 */
store_lock(THD *,THR_LOCK_DATA ** to,enum thr_lock_type lock_type)645 THR_LOCK_DATA **ha_example::store_lock(THD *, THR_LOCK_DATA **to,
646 enum thr_lock_type lock_type) {
647 if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) lock.type = lock_type;
648 *to++ = &lock;
649 return to;
650 }
651
652 /**
653 @brief
654 Used to delete a table. By the time delete_table() has been called all
655 opened references to this table will have been closed (and your globally
656 shared references released). The variable name will just be the name of
657 the table. You will need to remove any files you have created at this point.
658
659 @details
660 If you do not implement this, the default delete_table() is called from
661 handler.cc and it will delete all files with the file extensions from
662 handlerton::file_extensions.
663
664 Called from handler.cc by delete_table and ha_create_table(). Only used
665 during create if the table_flag HA_DROP_BEFORE_CREATE was specified for
666 the storage engine.
667
668 @see
669 delete_table and ha_create_table() in handler.cc
670 */
delete_table(const char *,const dd::Table *)671 int ha_example::delete_table(const char *, const dd::Table *) {
672 DBUG_TRACE;
673 /* This is not implemented but we want someone to be able that it works. */
674 return 0;
675 }
676
677 /**
678 @brief
679 Renames a table from one name to another via an alter table call.
680
681 @details
682 If you do not implement this, the default rename_table() is called from
683 handler.cc and it will delete all files with the file extensions from
684 handlerton::file_extensions.
685
686 Called from sql_table.cc by mysql_rename_table().
687
688 @see
689 mysql_rename_table() in sql_table.cc
690 */
rename_table(const char *,const char *,const dd::Table *,dd::Table *)691 int ha_example::rename_table(const char *, const char *, const dd::Table *,
692 dd::Table *) {
693 DBUG_TRACE;
694 return HA_ERR_WRONG_COMMAND;
695 }
696
697 /**
698 @brief
699 Given a starting key and an ending key, estimate the number of rows that
700 will exist between the two keys.
701
702 @details
703 end_key may be empty, in which case determine if start_key matches any rows.
704
705 Called from opt_range.cc by check_quick_keys().
706
707 @see
708 check_quick_keys() in opt_range.cc
709 */
records_in_range(uint,key_range *,key_range *)710 ha_rows ha_example::records_in_range(uint, key_range *, key_range *) {
711 DBUG_TRACE;
712 return 10; // low number to force index usage
713 }
714
715 static MYSQL_THDVAR_STR(last_create_thdvar, PLUGIN_VAR_MEMALLOC, nullptr,
716 nullptr, nullptr, nullptr);
717
718 static MYSQL_THDVAR_UINT(create_count_thdvar, 0, nullptr, nullptr, nullptr, 0,
719 0, 1000, 0);
720
721 /**
722 @brief
723 create() is called to create a database. The variable name will have the name
724 of the table.
725
726 @details
727 When create() is called you do not need to worry about
728 opening the table. Also, the .frm file will have already been
729 created so adjusting create_info is not necessary. You can overwrite
730 the .frm file at this point if you wish to change the table
731 definition, but there are no methods currently provided for doing
732 so.
733
734 Called from handle.cc by ha_create_table().
735
736 @see
737 ha_create_table() in handle.cc
738 */
739
create(const char * name,TABLE *,HA_CREATE_INFO *,dd::Table *)740 int ha_example::create(const char *name, TABLE *, HA_CREATE_INFO *,
741 dd::Table *) {
742 DBUG_TRACE;
743 /*
744 This is not implemented but we want someone to be able to see that it
745 works.
746 */
747
748 /*
749 It's just an example of THDVAR_SET() usage below.
750 */
751 THD *thd = ha_thd();
752 char *buf = (char *)my_malloc(PSI_NOT_INSTRUMENTED, SHOW_VAR_FUNC_BUFF_SIZE,
753 MYF(MY_FAE));
754 snprintf(buf, SHOW_VAR_FUNC_BUFF_SIZE, "Last creation '%s'", name);
755 THDVAR_SET(thd, last_create_thdvar, buf);
756 my_free(buf);
757
758 uint count = THDVAR(thd, create_count_thdvar) + 1;
759 THDVAR_SET(thd, create_count_thdvar, &count);
760
761 return 0;
762 }
763
764 struct st_mysql_storage_engine example_storage_engine = {
765 MYSQL_HANDLERTON_INTERFACE_VERSION};
766
767 static ulong srv_enum_var = 0;
768 static ulong srv_ulong_var = 0;
769 static double srv_double_var = 0;
770 static int srv_signed_int_var = 0;
771 static long srv_signed_long_var = 0;
772 static longlong srv_signed_longlong_var = 0;
773
774 const char *enum_var_names[] = {"e1", "e2", NullS};
775
776 TYPELIB enum_var_typelib = {array_elements(enum_var_names) - 1,
777 "enum_var_typelib", enum_var_names, nullptr};
778
779 static MYSQL_SYSVAR_ENUM(enum_var, // name
780 srv_enum_var, // varname
781 PLUGIN_VAR_RQCMDARG, // opt
782 "Sample ENUM system variable.", // comment
783 nullptr, // check
784 nullptr, // update
785 0, // def
786 &enum_var_typelib); // typelib
787
788 static MYSQL_SYSVAR_ULONG(ulong_var, srv_ulong_var, PLUGIN_VAR_RQCMDARG,
789 "0..1000", nullptr, nullptr, 8, 0, 1000, 0);
790
791 static MYSQL_SYSVAR_DOUBLE(double_var, srv_double_var, PLUGIN_VAR_RQCMDARG,
792 "0.500000..1000.500000", nullptr, nullptr, 8.5, 0.5,
793 1000.5,
794 0); // reserved always 0
795
796 static MYSQL_THDVAR_DOUBLE(double_thdvar, PLUGIN_VAR_RQCMDARG,
797 "0.500000..1000.500000", nullptr, nullptr, 8.5, 0.5,
798 1000.5, 0);
799
800 static MYSQL_SYSVAR_INT(signed_int_var, srv_signed_int_var, PLUGIN_VAR_RQCMDARG,
801 "INT_MIN..INT_MAX", nullptr, nullptr, -10, INT_MIN,
802 INT_MAX, 0);
803
804 static MYSQL_THDVAR_INT(signed_int_thdvar, PLUGIN_VAR_RQCMDARG,
805 "INT_MIN..INT_MAX", nullptr, nullptr, -10, INT_MIN,
806 INT_MAX, 0);
807
808 static MYSQL_SYSVAR_LONG(signed_long_var, srv_signed_long_var,
809 PLUGIN_VAR_RQCMDARG, "LONG_MIN..LONG_MAX", nullptr,
810 nullptr, -10, LONG_MIN, LONG_MAX, 0);
811
812 static MYSQL_THDVAR_LONG(signed_long_thdvar, PLUGIN_VAR_RQCMDARG,
813 "LONG_MIN..LONG_MAX", nullptr, nullptr, -10, LONG_MIN,
814 LONG_MAX, 0);
815
816 static MYSQL_SYSVAR_LONGLONG(signed_longlong_var, srv_signed_longlong_var,
817 PLUGIN_VAR_RQCMDARG, "LLONG_MIN..LLONG_MAX",
818 nullptr, nullptr, -10, LLONG_MIN, LLONG_MAX, 0);
819
820 static MYSQL_THDVAR_LONGLONG(signed_longlong_thdvar, PLUGIN_VAR_RQCMDARG,
821 "LLONG_MIN..LLONG_MAX", nullptr, nullptr, -10,
822 LLONG_MIN, LLONG_MAX, 0);
823
824 static SYS_VAR *example_system_variables[] = {
825 MYSQL_SYSVAR(enum_var),
826 MYSQL_SYSVAR(ulong_var),
827 MYSQL_SYSVAR(double_var),
828 MYSQL_SYSVAR(double_thdvar),
829 MYSQL_SYSVAR(last_create_thdvar),
830 MYSQL_SYSVAR(create_count_thdvar),
831 MYSQL_SYSVAR(signed_int_var),
832 MYSQL_SYSVAR(signed_int_thdvar),
833 MYSQL_SYSVAR(signed_long_var),
834 MYSQL_SYSVAR(signed_long_thdvar),
835 MYSQL_SYSVAR(signed_longlong_var),
836 MYSQL_SYSVAR(signed_longlong_thdvar),
837 nullptr};
838
839 // this is an example of SHOW_FUNC
show_func_example(MYSQL_THD,SHOW_VAR * var,char * buf)840 static int show_func_example(MYSQL_THD, SHOW_VAR *var, char *buf) {
841 var->type = SHOW_CHAR;
842 var->value = buf; // it's of SHOW_VAR_FUNC_BUFF_SIZE bytes
843 snprintf(buf, SHOW_VAR_FUNC_BUFF_SIZE,
844 "enum_var is %lu, ulong_var is %lu, "
845 "double_var is %f, signed_int_var is %d, "
846 "signed_long_var is %ld, signed_longlong_var is %lld",
847 srv_enum_var, srv_ulong_var, srv_double_var, srv_signed_int_var,
848 srv_signed_long_var, srv_signed_longlong_var);
849 return 0;
850 }
851
852 struct example_vars_t {
853 ulong var1;
854 double var2;
855 char var3[64];
856 bool var4;
857 bool var5;
858 ulong var6;
859 };
860
861 example_vars_t example_vars = {100, 20.01, "three hundred", true, false, 8250};
862
863 static SHOW_VAR show_status_example[] = {
864 {"var1", (char *)&example_vars.var1, SHOW_LONG, SHOW_SCOPE_GLOBAL},
865 {"var2", (char *)&example_vars.var2, SHOW_DOUBLE, SHOW_SCOPE_GLOBAL},
866 {nullptr, nullptr, SHOW_UNDEF,
867 SHOW_SCOPE_UNDEF} // null terminator required
868 };
869
870 static SHOW_VAR show_array_example[] = {
871 {"array", (char *)show_status_example, SHOW_ARRAY, SHOW_SCOPE_GLOBAL},
872 {"var3", (char *)&example_vars.var3, SHOW_CHAR, SHOW_SCOPE_GLOBAL},
873 {"var4", (char *)&example_vars.var4, SHOW_BOOL, SHOW_SCOPE_GLOBAL},
874 {nullptr, nullptr, SHOW_UNDEF, SHOW_SCOPE_UNDEF}};
875
876 static SHOW_VAR func_status[] = {
877 {"example_func_example", (char *)show_func_example, SHOW_FUNC,
878 SHOW_SCOPE_GLOBAL},
879 {"example_status_var5", (char *)&example_vars.var5, SHOW_BOOL,
880 SHOW_SCOPE_GLOBAL},
881 {"example_status_var6", (char *)&example_vars.var6, SHOW_LONG,
882 SHOW_SCOPE_GLOBAL},
883 {"example_status", (char *)show_array_example, SHOW_ARRAY,
884 SHOW_SCOPE_GLOBAL},
885 {nullptr, nullptr, SHOW_UNDEF, SHOW_SCOPE_UNDEF}};
886
mysql_declare_plugin(example)887 mysql_declare_plugin(example){
888 MYSQL_STORAGE_ENGINE_PLUGIN,
889 &example_storage_engine,
890 "EXAMPLE",
891 PLUGIN_AUTHOR_ORACLE,
892 "Example storage engine",
893 PLUGIN_LICENSE_GPL,
894 example_init_func, /* Plugin Init */
895 nullptr, /* Plugin check uninstall */
896 nullptr, /* Plugin Deinit */
897 0x0001 /* 0.1 */,
898 func_status, /* status variables */
899 example_system_variables, /* system variables */
900 nullptr, /* config options */
901 0, /* flags */
902 } mysql_declare_plugin_end;
903