1 /* Copyright (c) 2004, 2016, 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 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 #include "sql_priv.h"
98 #include "sql_class.h" // MYSQL_HANDLERTON_INTERFACE_VERSION
99 #include "ha_example.h"
100 #include "probes_mysql.h"
101 #include "sql_plugin.h"
102
103 static handler *example_create_handler(handlerton *hton,
104 TABLE_SHARE *table,
105 MEM_ROOT *mem_root);
106
107 handlerton *example_hton;
108
109 /* Interface to mysqld, to check system tables supported by SE */
110 static const char* example_system_database();
111 static bool example_is_supported_system_table(const char *db,
112 const char *table_name,
113 bool is_sql_layer_system_table);
114 #ifdef HAVE_PSI_INTERFACE
115 static PSI_mutex_key ex_key_mutex_Example_share_mutex;
116
117 static PSI_mutex_info all_example_mutexes[]=
118 {
119 { &ex_key_mutex_Example_share_mutex, "Example_share::mutex", 0}
120 };
121
init_example_psi_keys()122 static void init_example_psi_keys()
123 {
124 const char* category= "example";
125 int count;
126
127 count= array_elements(all_example_mutexes);
128 mysql_mutex_register(category, all_example_mutexes, count);
129 }
130 #endif
131
Example_share()132 Example_share::Example_share()
133 {
134 thr_lock_init(&lock);
135 mysql_mutex_init(ex_key_mutex_Example_share_mutex,
136 &mutex, MY_MUTEX_INIT_FAST);
137 }
138
139
example_init_func(void * p)140 static int example_init_func(void *p)
141 {
142 DBUG_ENTER("example_init_func");
143
144 #ifdef HAVE_PSI_INTERFACE
145 init_example_psi_keys();
146 #endif
147
148 example_hton= (handlerton *)p;
149 example_hton->state= SHOW_OPTION_YES;
150 example_hton->create= example_create_handler;
151 example_hton->flags= HTON_CAN_RECREATE;
152 example_hton->system_database= example_system_database;
153 example_hton->is_supported_system_table= example_is_supported_system_table;
154
155 DBUG_RETURN(0);
156 }
157
158
159 /**
160 @brief
161 Example of simple lock controls. The "share" it creates is a
162 structure we will pass to each example handler. Do you have to have
163 one of these? Well, you have pieces that are used for locking, and
164 they are needed to function.
165 */
166
get_share()167 Example_share *ha_example::get_share()
168 {
169 Example_share *tmp_share;
170
171 DBUG_ENTER("ha_example::get_share()");
172
173 lock_shared_ha_data();
174 if (!(tmp_share= static_cast<Example_share*>(get_ha_share_ptr())))
175 {
176 tmp_share= new Example_share;
177 if (!tmp_share)
178 goto err;
179
180 set_ha_share_ptr(static_cast<Handler_share*>(tmp_share));
181 }
182 err:
183 unlock_shared_ha_data();
184 DBUG_RETURN(tmp_share);
185 }
186
187
example_create_handler(handlerton * hton,TABLE_SHARE * table,MEM_ROOT * mem_root)188 static handler* example_create_handler(handlerton *hton,
189 TABLE_SHARE *table,
190 MEM_ROOT *mem_root)
191 {
192 return new (mem_root) ha_example(hton, table);
193 }
194
ha_example(handlerton * hton,TABLE_SHARE * table_arg)195 ha_example::ha_example(handlerton *hton, TABLE_SHARE *table_arg)
196 :handler(hton, table_arg)
197 {}
198
199
200 /**
201 @brief
202 If frm_error() is called then we will use this to determine
203 the file extensions that exist for the storage engine. This is also
204 used by the default rename_table and delete_table method in
205 handler.cc.
206
207 For engines that have two file name extentions (separate meta/index file
208 and data file), the order of elements is relevant. First element of engine
209 file name extentions array should be meta/index file extention. Second
210 element - data file extention. This order is assumed by
211 prepare_for_repair() when REPAIR TABLE ... USE_FRM is issued.
212
213 @see
214 rename_table method in handler.cc and
215 delete_table method in handler.cc
216 */
217
218 static const char *ha_example_exts[] = {
219 NullS
220 };
221
bas_ext() const222 const char **ha_example::bas_ext() const
223 {
224 return ha_example_exts;
225 }
226
227 /*
228 Following handler function provides access to
229 system database specific to SE. This interface
230 is optional, so every SE need not implement it.
231 */
232 const char* ha_example_system_database= NULL;
example_system_database()233 const char* example_system_database()
234 {
235 return ha_example_system_database;
236 }
237
238 /*
239 List of all system tables specific to the SE.
240 Array element would look like below,
241 { "<database_name>", "<system table name>" },
242 The last element MUST be,
243 { (const char*)NULL, (const char*)NULL }
244
245 This array is optional, so every SE need not implement it.
246 */
247 static st_system_tablename ha_example_system_tables[]= {
248 {(const char*)NULL, (const char*)NULL}
249 };
250
251 /**
252 @brief Check if the given db.tablename is a system table for this SE.
253
254 @param db Database name to check.
255 @param table_name table name to check.
256 @param is_sql_layer_system_table if the supplied db.table_name is a SQL
257 layer system table.
258
259 @return
260 @retval TRUE Given db.table_name is supported system table.
261 @retval FALSE Given db.table_name is not a supported system table.
262 */
example_is_supported_system_table(const char * db,const char * table_name,bool is_sql_layer_system_table)263 static bool example_is_supported_system_table(const char *db,
264 const char *table_name,
265 bool is_sql_layer_system_table)
266 {
267 st_system_tablename *systab;
268
269 // Does this SE support "ALL" SQL layer system tables ?
270 if (is_sql_layer_system_table)
271 return false;
272
273 // Check if this is SE layer system tables
274 systab= ha_example_system_tables;
275 while (systab && systab->db)
276 {
277 if (systab->db == db &&
278 strcmp(systab->tablename, table_name) == 0)
279 return true;
280 systab++;
281 }
282
283 return false;
284 }
285
286
287 /**
288 @brief
289 Used for opening tables. The name will be the name of the file.
290
291 @details
292 A table is opened when it needs to be opened; e.g. when a request comes in
293 for a SELECT on the table (tables are not open and closed for each request,
294 they are cached).
295
296 Called from handler.cc by handler::ha_open(). The server opens all tables by
297 calling ha_open() which then calls the handler specific open().
298
299 @see
300 handler::ha_open() in handler.cc
301 */
302
open(const char * name,int mode,uint test_if_locked)303 int ha_example::open(const char *name, int mode, uint test_if_locked)
304 {
305 DBUG_ENTER("ha_example::open");
306
307 if (!(share = get_share()))
308 DBUG_RETURN(1);
309 thr_lock_data_init(&share->lock,&lock,NULL);
310
311 DBUG_RETURN(0);
312 }
313
314
315 /**
316 @brief
317 Closes a table.
318
319 @details
320 Called from sql_base.cc, sql_select.cc, and table.cc. In sql_select.cc it is
321 only used to close up temporary tables or during the process where a
322 temporary table is converted over to being a myisam table.
323
324 For sql_base.cc look at close_data_tables().
325
326 @see
327 sql_base.cc, sql_select.cc and table.cc
328 */
329
close(void)330 int ha_example::close(void)
331 {
332 DBUG_ENTER("ha_example::close");
333 DBUG_RETURN(0);
334 }
335
336
337 /**
338 @brief
339 write_row() inserts a row. No extra() hint is given currently if a bulk load
340 is happening. buf() is a byte array of data. You can use the field
341 information to extract the data from the native byte array type.
342
343 @details
344 Example of this would be:
345 @code
346 for (Field **field=table->field ; *field ; field++)
347 {
348 ...
349 }
350 @endcode
351
352 See ha_tina.cc for an example of extracting all of the data as strings.
353 ha_berekly.cc has an example of how to store it intact by "packing" it
354 for ha_berkeley's own native storage type.
355
356 See the note for update_row() on auto_increments. This case also applies to
357 write_row().
358
359 Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
360 sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
361
362 @see
363 item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
364 sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc and sql_update.cc
365 */
366
write_row(uchar * buf)367 int ha_example::write_row(uchar *buf)
368 {
369 DBUG_ENTER("ha_example::write_row");
370 /*
371 Example of a successful write_row. We don't store the data
372 anywhere; they are thrown away. A real implementation will
373 probably need to do something with 'buf'. We report a success
374 here, to pretend that the insert was successful.
375 */
376 DBUG_RETURN(0);
377 }
378
379
380 /**
381 @brief
382 Yes, update_row() does what you expect, it updates a row. old_data will have
383 the previous row record in it, while new_data will have the newest data in it.
384 Keep in mind that the server can do updates based on ordering if an ORDER BY
385 clause was used. Consecutive ordering is not guaranteed.
386
387 @details
388 Currently new_data will not have an updated auto_increament record. You can
389 do this for example by doing:
390
391 @code
392
393 if (table->next_number_field && record == table->record[0])
394 update_auto_increment();
395
396 @endcode
397
398 Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
399
400 @see
401 sql_select.cc, sql_acl.cc, sql_update.cc and sql_insert.cc
402 */
update_row(const uchar * old_data,uchar * new_data)403 int ha_example::update_row(const uchar *old_data, uchar *new_data)
404 {
405
406 DBUG_ENTER("ha_example::update_row");
407 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
408 }
409
410
411 /**
412 @brief
413 This will delete a row. buf will contain a copy of the row to be deleted.
414 The server will call this right after the current row has been called (from
415 either a previous rnd_nexT() or index call).
416
417 @details
418 If you keep a pointer to the last row or can access a primary key it will
419 make doing the deletion quite a bit easier. Keep in mind that the server does
420 not guarantee consecutive deletions. ORDER BY clauses can be used.
421
422 Called in sql_acl.cc and sql_udf.cc to manage internal table
423 information. Called in sql_delete.cc, sql_insert.cc, and
424 sql_select.cc. In sql_select it is used for removing duplicates
425 while in insert it is used for REPLACE calls.
426
427 @see
428 sql_acl.cc, sql_udf.cc, sql_delete.cc, sql_insert.cc and sql_select.cc
429 */
430
delete_row(const uchar * buf)431 int ha_example::delete_row(const uchar *buf)
432 {
433 DBUG_ENTER("ha_example::delete_row");
434 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
435 }
436
437
438 /**
439 @brief
440 Positions an index cursor to the index specified in the handle. Fetches the
441 row if available. If the key value is null, begin at the first key of the
442 index.
443 */
444
index_read_map(uchar * buf,const uchar * key,key_part_map keypart_map MY_ATTRIBUTE ((unused)),enum ha_rkey_function find_flag MY_ATTRIBUTE ((unused)))445 int ha_example::index_read_map(uchar *buf, const uchar *key,
446 key_part_map keypart_map MY_ATTRIBUTE((unused)),
447 enum ha_rkey_function find_flag
448 MY_ATTRIBUTE((unused)))
449 {
450 int rc;
451 DBUG_ENTER("ha_example::index_read");
452 MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
453 rc= HA_ERR_WRONG_COMMAND;
454 MYSQL_INDEX_READ_ROW_DONE(rc);
455 DBUG_RETURN(rc);
456 }
457
458
459 /**
460 @brief
461 Used to read forward through the index.
462 */
463
index_next(uchar * buf)464 int ha_example::index_next(uchar *buf)
465 {
466 int rc;
467 DBUG_ENTER("ha_example::index_next");
468 MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
469 rc= HA_ERR_WRONG_COMMAND;
470 MYSQL_INDEX_READ_ROW_DONE(rc);
471 DBUG_RETURN(rc);
472 }
473
474
475 /**
476 @brief
477 Used to read backwards through the index.
478 */
479
index_prev(uchar * buf)480 int ha_example::index_prev(uchar *buf)
481 {
482 int rc;
483 DBUG_ENTER("ha_example::index_prev");
484 MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
485 rc= HA_ERR_WRONG_COMMAND;
486 MYSQL_INDEX_READ_ROW_DONE(rc);
487 DBUG_RETURN(rc);
488 }
489
490
491 /**
492 @brief
493 index_first() asks for the first key in the index.
494
495 @details
496 Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
497
498 @see
499 opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
500 */
index_first(uchar * buf)501 int ha_example::index_first(uchar *buf)
502 {
503 int rc;
504 DBUG_ENTER("ha_example::index_first");
505 MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
506 rc= HA_ERR_WRONG_COMMAND;
507 MYSQL_INDEX_READ_ROW_DONE(rc);
508 DBUG_RETURN(rc);
509 }
510
511
512 /**
513 @brief
514 index_last() asks for the last key in the index.
515
516 @details
517 Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
518
519 @see
520 opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
521 */
index_last(uchar * buf)522 int ha_example::index_last(uchar *buf)
523 {
524 int rc;
525 DBUG_ENTER("ha_example::index_last");
526 MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
527 rc= HA_ERR_WRONG_COMMAND;
528 MYSQL_INDEX_READ_ROW_DONE(rc);
529 DBUG_RETURN(rc);
530 }
531
532
533 /**
534 @brief
535 rnd_init() is called when the system wants the storage engine to do a table
536 scan. See the example in the introduction at the top of this file to see when
537 rnd_init() is called.
538
539 @details
540 Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
541 and sql_update.cc.
542
543 @see
544 filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
545 */
rnd_init(bool scan)546 int ha_example::rnd_init(bool scan)
547 {
548 DBUG_ENTER("ha_example::rnd_init");
549 DBUG_RETURN(0);
550 }
551
rnd_end()552 int ha_example::rnd_end()
553 {
554 DBUG_ENTER("ha_example::rnd_end");
555 DBUG_RETURN(0);
556 }
557
558
559 /**
560 @brief
561 This is called for each row of the table scan. When you run out of records
562 you should return HA_ERR_END_OF_FILE. Fill buff up with the row information.
563 The Field structure for the table is the key to getting data into buf
564 in a manner that will allow the server to understand it.
565
566 @details
567 Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
568 and sql_update.cc.
569
570 @see
571 filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
572 */
rnd_next(uchar * buf)573 int ha_example::rnd_next(uchar *buf)
574 {
575 int rc;
576 DBUG_ENTER("ha_example::rnd_next");
577 MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str,
578 TRUE);
579 rc= HA_ERR_END_OF_FILE;
580 MYSQL_READ_ROW_DONE(rc);
581 DBUG_RETURN(rc);
582 }
583
584
585 /**
586 @brief
587 position() is called after each call to rnd_next() if the data needs
588 to be ordered. You can do something like the following to store
589 the position:
590 @code
591 my_store_ptr(ref, ref_length, current_position);
592 @endcode
593
594 @details
595 The server uses ref to store data. ref_length in the above case is
596 the size needed to store current_position. ref is just a byte array
597 that the server will maintain. If you are using offsets to mark rows, then
598 current_position should be the offset. If it is a primary key like in
599 BDB, then it needs to be a primary key.
600
601 Called from filesort.cc, sql_select.cc, sql_delete.cc, and sql_update.cc.
602
603 @see
604 filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc
605 */
position(const uchar * record)606 void ha_example::position(const uchar *record)
607 {
608 DBUG_ENTER("ha_example::position");
609 DBUG_VOID_RETURN;
610 }
611
612
613 /**
614 @brief
615 This is like rnd_next, but you are given a position to use
616 to determine the row. The position will be of the type that you stored in
617 ref. You can use ha_get_ptr(pos,ref_length) to retrieve whatever key
618 or position you saved when position() was called.
619
620 @details
621 Called from filesort.cc, records.cc, sql_insert.cc, sql_select.cc, and sql_update.cc.
622
623 @see
624 filesort.cc, records.cc, sql_insert.cc, sql_select.cc and sql_update.cc
625 */
rnd_pos(uchar * buf,uchar * pos)626 int ha_example::rnd_pos(uchar *buf, uchar *pos)
627 {
628 int rc;
629 DBUG_ENTER("ha_example::rnd_pos");
630 MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str,
631 TRUE);
632 rc= HA_ERR_WRONG_COMMAND;
633 MYSQL_READ_ROW_DONE(rc);
634 DBUG_RETURN(rc);
635 }
636
637
638 /**
639 @brief
640 ::info() is used to return information to the optimizer. See my_base.h for
641 the complete description.
642
643 @details
644 Currently this table handler doesn't implement most of the fields really needed.
645 SHOW also makes use of this data.
646
647 You will probably want to have the following in your code:
648 @code
649 if (records < 2)
650 records = 2;
651 @endcode
652 The reason is that the server will optimize for cases of only a single
653 record. If, in a table scan, you don't know the number of records, it
654 will probably be better to set records to two so you can return as many
655 records as you need. Along with records, a few more variables you may wish
656 to set are:
657 records
658 deleted
659 data_file_length
660 index_file_length
661 delete_length
662 check_time
663 Take a look at the public variables in handler.h for more information.
664
665 Called in filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc,
666 sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc,
667 sql_select.cc, sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc,
668 sql_table.cc, sql_union.cc, and sql_update.cc.
669
670 @see
671 filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc, sql_delete.cc,
672 sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc, sql_select.cc,
673 sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_table.cc,
674 sql_union.cc and sql_update.cc
675 */
info(uint flag)676 int ha_example::info(uint flag)
677 {
678 DBUG_ENTER("ha_example::info");
679 DBUG_RETURN(0);
680 }
681
682
683 /**
684 @brief
685 extra() is called whenever the server wishes to send a hint to
686 the storage engine. The myisam engine implements the most hints.
687 ha_innodb.cc has the most exhaustive list of these hints.
688
689 @see
690 ha_innodb.cc
691 */
extra(enum ha_extra_function operation)692 int ha_example::extra(enum ha_extra_function operation)
693 {
694 DBUG_ENTER("ha_example::extra");
695 DBUG_RETURN(0);
696 }
697
698
699 /**
700 @brief
701 Used to delete all rows in a table, including cases of truncate and cases where
702 the optimizer realizes that all rows will be removed as a result of an SQL statement.
703
704 @details
705 Called from item_sum.cc by Item_func_group_concat::clear(),
706 Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
707 Called from sql_delete.cc by mysql_delete().
708 Called from sql_select.cc by JOIN::reinit().
709 Called from sql_union.cc by st_select_lex_unit::exec().
710
711 @see
712 Item_func_group_concat::clear(), Item_sum_count_distinct::clear() and
713 Item_func_group_concat::clear() in item_sum.cc;
714 mysql_delete() in sql_delete.cc;
715 JOIN::reinit() in sql_select.cc and
716 st_select_lex_unit::exec() in sql_union.cc.
717 */
delete_all_rows()718 int ha_example::delete_all_rows()
719 {
720 DBUG_ENTER("ha_example::delete_all_rows");
721 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
722 }
723
724
725 /**
726 @brief
727 Used for handler specific truncate table. The table is locked in
728 exclusive mode and handler is responsible for reseting the auto-
729 increment counter.
730
731 @details
732 Called from Truncate_statement::handler_truncate.
733 Not used if the handlerton supports HTON_CAN_RECREATE, unless this
734 engine can be used as a partition. In this case, it is invoked when
735 a particular partition is to be truncated.
736
737 @see
738 Truncate_statement in sql_truncate.cc
739 Remarks in handler::truncate.
740 */
truncate()741 int ha_example::truncate()
742 {
743 DBUG_ENTER("ha_example::truncate");
744 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
745 }
746
747
748 /**
749 @brief
750 This create a lock on the table. If you are implementing a storage engine
751 that can handle transacations look at ha_berkely.cc to see how you will
752 want to go about doing this. Otherwise you should consider calling flock()
753 here. Hint: Read the section "locking functions for mysql" in lock.cc to understand
754 this.
755
756 @details
757 Called from lock.cc by lock_external() and unlock_external(). Also called
758 from sql_table.cc by copy_data_between_tables().
759
760 @see
761 lock.cc by lock_external() and unlock_external() in lock.cc;
762 the section "locking functions for mysql" in lock.cc;
763 copy_data_between_tables() in sql_table.cc.
764 */
external_lock(THD * thd,int lock_type)765 int ha_example::external_lock(THD *thd, int lock_type)
766 {
767 DBUG_ENTER("ha_example::external_lock");
768 DBUG_RETURN(0);
769 }
770
771
772 /**
773 @brief
774 The idea with handler::store_lock() is: The statement decides which locks
775 should be needed for the table. For updates/deletes/inserts we get WRITE
776 locks, for SELECT... we get read locks.
777
778 @details
779 Before adding the lock into the table lock handler (see thr_lock.c),
780 mysqld calls store lock with the requested locks. Store lock can now
781 modify a write lock to a read lock (or some other lock), ignore the
782 lock (if we don't want to use MySQL table locks at all), or add locks
783 for many tables (like we do when we are using a MERGE handler).
784
785 Berkeley DB, for example, changes all WRITE locks to TL_WRITE_ALLOW_WRITE
786 (which signals that we are doing WRITES, but are still allowing other
787 readers and writers).
788
789 When releasing locks, store_lock() is also called. In this case one
790 usually doesn't have to do anything.
791
792 In some exceptional cases MySQL may send a request for a TL_IGNORE;
793 This means that we are requesting the same lock as last time and this
794 should also be ignored. (This may happen when someone does a flush
795 table when we have opened a part of the tables, in which case mysqld
796 closes and reopens the tables and tries to get the same locks at last
797 time). In the future we will probably try to remove this.
798
799 Called from lock.cc by get_lock_data().
800
801 @note
802 In this method one should NEVER rely on table->in_use, it may, in fact,
803 refer to a different thread! (this happens if get_lock_data() is called
804 from mysql_lock_abort_for_thread() function)
805
806 @see
807 get_lock_data() in lock.cc
808 */
store_lock(THD * thd,THR_LOCK_DATA ** to,enum thr_lock_type lock_type)809 THR_LOCK_DATA **ha_example::store_lock(THD *thd,
810 THR_LOCK_DATA **to,
811 enum thr_lock_type lock_type)
812 {
813 if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
814 lock.type=lock_type;
815 *to++= &lock;
816 return to;
817 }
818
819
820 /**
821 @brief
822 Used to delete a table. By the time delete_table() has been called all
823 opened references to this table will have been closed (and your globally
824 shared references released). The variable name will just be the name of
825 the table. You will need to remove any files you have created at this point.
826
827 @details
828 If you do not implement this, the default delete_table() is called from
829 handler.cc and it will delete all files with the file extensions returned
830 by bas_ext().
831
832 Called from handler.cc by delete_table and ha_create_table(). Only used
833 during create if the table_flag HA_DROP_BEFORE_CREATE was specified for
834 the storage engine.
835
836 @see
837 delete_table and ha_create_table() in handler.cc
838 */
delete_table(const char * name)839 int ha_example::delete_table(const char *name)
840 {
841 DBUG_ENTER("ha_example::delete_table");
842 /* This is not implemented but we want someone to be able that it works. */
843 DBUG_RETURN(0);
844 }
845
846
847 /**
848 @brief
849 Renames a table from one name to another via an alter table call.
850
851 @details
852 If you do not implement this, the default rename_table() is called from
853 handler.cc and it will delete all files with the file extensions returned
854 by bas_ext().
855
856 Called from sql_table.cc by mysql_rename_table().
857
858 @see
859 mysql_rename_table() in sql_table.cc
860 */
rename_table(const char * from,const char * to)861 int ha_example::rename_table(const char * from, const char * to)
862 {
863 DBUG_ENTER("ha_example::rename_table ");
864 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
865 }
866
867
868 /**
869 @brief
870 Given a starting key and an ending key, estimate the number of rows that
871 will exist between the two keys.
872
873 @details
874 end_key may be empty, in which case determine if start_key matches any rows.
875
876 Called from opt_range.cc by check_quick_keys().
877
878 @see
879 check_quick_keys() in opt_range.cc
880 */
records_in_range(uint inx,key_range * min_key,key_range * max_key)881 ha_rows ha_example::records_in_range(uint inx, key_range *min_key,
882 key_range *max_key)
883 {
884 DBUG_ENTER("ha_example::records_in_range");
885 DBUG_RETURN(10); // low number to force index usage
886 }
887
888
889 /**
890 @brief
891 create() is called to create a database. The variable name will have the name
892 of the table.
893
894 @details
895 When create() is called you do not need to worry about
896 opening the table. Also, the .frm file will have already been
897 created so adjusting create_info is not necessary. You can overwrite
898 the .frm file at this point if you wish to change the table
899 definition, but there are no methods currently provided for doing
900 so.
901
902 Called from handle.cc by ha_create_table().
903
904 @see
905 ha_create_table() in handle.cc
906 */
907
create(const char * name,TABLE * table_arg,HA_CREATE_INFO * create_info)908 int ha_example::create(const char *name, TABLE *table_arg,
909 HA_CREATE_INFO *create_info)
910 {
911 DBUG_ENTER("ha_example::create");
912 /*
913 This is not implemented but we want someone to be able to see that it
914 works.
915 */
916 DBUG_RETURN(0);
917 }
918
919
920 struct st_mysql_storage_engine example_storage_engine=
921 { MYSQL_HANDLERTON_INTERFACE_VERSION };
922
923 static ulong srv_enum_var= 0;
924 static ulong srv_ulong_var= 0;
925 static double srv_double_var= 0;
926
927 const char *enum_var_names[]=
928 {
929 "e1", "e2", NullS
930 };
931
932 TYPELIB enum_var_typelib=
933 {
934 array_elements(enum_var_names) - 1, "enum_var_typelib",
935 enum_var_names, NULL
936 };
937
938 static MYSQL_SYSVAR_ENUM(
939 enum_var, // name
940 srv_enum_var, // varname
941 PLUGIN_VAR_RQCMDARG, // opt
942 "Sample ENUM system variable.", // comment
943 NULL, // check
944 NULL, // update
945 0, // def
946 &enum_var_typelib); // typelib
947
948 static MYSQL_SYSVAR_ULONG(
949 ulong_var,
950 srv_ulong_var,
951 PLUGIN_VAR_RQCMDARG,
952 "0..1000",
953 NULL,
954 NULL,
955 8,
956 0,
957 1000,
958 0);
959
960 static MYSQL_SYSVAR_DOUBLE(
961 double_var,
962 srv_double_var,
963 PLUGIN_VAR_RQCMDARG,
964 "0.500000..1000.500000",
965 NULL,
966 NULL,
967 8.5,
968 0.5,
969 1000.5,
970 0); // reserved always 0
971
972 static MYSQL_THDVAR_DOUBLE(
973 double_thdvar,
974 PLUGIN_VAR_RQCMDARG,
975 "0.500000..1000.500000",
976 NULL,
977 NULL,
978 8.5,
979 0.5,
980 1000.5,
981 0);
982
983 static struct st_mysql_sys_var* example_system_variables[]= {
984 MYSQL_SYSVAR(enum_var),
985 MYSQL_SYSVAR(ulong_var),
986 MYSQL_SYSVAR(double_var),
987 MYSQL_SYSVAR(double_thdvar),
988 NULL
989 };
990
991 // this is an example of SHOW_FUNC and of my_snprintf() service
show_func_example(MYSQL_THD thd,struct st_mysql_show_var * var,char * buf)992 static int show_func_example(MYSQL_THD thd, struct st_mysql_show_var *var,
993 char *buf)
994 {
995 var->type= SHOW_CHAR;
996 var->value= buf; // it's of SHOW_VAR_FUNC_BUFF_SIZE bytes
997 my_snprintf(buf, SHOW_VAR_FUNC_BUFF_SIZE,
998 "enum_var is %lu, ulong_var is %lu, "
999 "double_var is %f, %.6b", // %b is a MySQL extension
1000 srv_enum_var, srv_ulong_var, srv_double_var, "really");
1001 return 0;
1002 }
1003
1004 static struct st_mysql_show_var func_status[]=
1005 {
1006 {"example_func_example", (char *)show_func_example, SHOW_FUNC},
1007 {0,0,SHOW_UNDEF}
1008 };
1009
mysql_declare_plugin(example)1010 mysql_declare_plugin(example)
1011 {
1012 MYSQL_STORAGE_ENGINE_PLUGIN,
1013 &example_storage_engine,
1014 "EXAMPLE",
1015 "Brian Aker, MySQL AB",
1016 "Example storage engine",
1017 PLUGIN_LICENSE_GPL,
1018 example_init_func, /* Plugin Init */
1019 NULL, /* Plugin Deinit */
1020 0x0001 /* 0.1 */,
1021 func_status, /* status variables */
1022 example_system_variables, /* system variables */
1023 NULL, /* config options */
1024 0, /* flags */
1025 }
1026 mysql_declare_plugin_end;
1027