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