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