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