diff options
author | unknown <acurtis@xiphis.org> | 2005-12-21 10:18:40 -0800 |
---|---|---|
committer | unknown <acurtis@xiphis.org> | 2005-12-21 10:18:40 -0800 |
commit | 613dd50a33ac3e64073abdbdae66ce3a93e69e30 (patch) | |
tree | d777ca5871199d389af93e8cbe06e1bdbc16a10b /sql/examples | |
parent | 9c81773b37a5ec1a689632e3161ae6b9d1fdeb46 (diff) | |
download | mariadb-git-613dd50a33ac3e64073abdbdae66ce3a93e69e30.tar.gz |
Finalize storage engine plugins
Give BerkeleyDB savepoints
Remove "enum db_type" from most of the code
storage/example/ha_example.h:
Rename: sql/examples/ha_example.h -> storage/example/ha_example.h
storage/csv/ha_tina.h:
Rename: sql/examples/ha_tina.h -> storage/csv/ha_tina.h
config/ac-macros/storage.m4:
if hton name is "no", then we don't install it as a builtin
configure.in:
pluggable changes
include/plugin.h:
version field
mysql-test/r/bdb.result:
savepoint results copied from innodb test
mysql-test/r/information_schema.result:
PLUGINS information schema
mysql-test/r/information_schema_db.result:
PLUGINS information schema
mysql-test/t/bdb.test:
savepoint test copied from innodb test
sql/Makefile.am:
tina and example are not here anymore
sql/authors.h:
minor tweek
sql/ha_archive.cc:
remove unwanted handlerton entries
sql/ha_berkeley.cc:
remove unwanted handlerton entries
support for savepoints
changes to show logs
sql/ha_blackhole.cc:
remove unwanted handlerton entries
sql/ha_federated.cc:
remove unwanted handlerton entries
sql/ha_heap.cc:
remove unwanted handlerton entries
sql/ha_innodb.cc:
remove unwanted handlerton entries
changes for show status
sql/ha_myisam.cc:
remove unwanted handlerton entries
sql/ha_myisammrg.cc:
remove unwanted handlerton entries
sql/ha_ndbcluster.cc:
remove unwanted handlerton entries
changes to stat_print
sql/ha_partition.cc:
remove unwanted handlerton entries
bye bye enum db_type
sql/ha_partition.h:
bye bye enum db_type
sql/handler.cc:
remove unwanted handlerton entries
bye bye enum db_type
sql/handler.h:
remove unwanted handlerton entries
bye bye enum db_type
changes to stat_print_fn
sql/item_sum.cc:
bye bye enum db_type
sql/log.cc:
remove unwanted handlerton entries
sql/mysql_priv.h:
bye bye enum db_type
sql/mysqld.cc:
bye bye enum db_type
reorder plugin initialization
sql/set_var.cc:
bye bye enum db_type
sql/set_var.h:
bye bye enum db_type
sql/sql_base.cc:
bye bye enum db_type
sql/sql_cache.cc:
bye bye enum db_type
sql/sql_class.h:
bye bye enum db_type
sql/sql_delete.cc:
bye bye enum db_type
sql/sql_insert.cc:
bye bye enum db_type
sql/sql_lex.h:
show plugin
sql/sql_parse.cc:
bye bye enum db_type
sql/sql_partition.cc:
bye bye enum db_type
sql/sql_plugin.cc:
loadable storage engines
sql/sql_plugin.h:
loadable storage engines
sql/sql_rename.cc:
bye bye enum db_type
sql/sql_select.cc:
bye bye enum db_type
sql/sql_show.cc:
SHOW PLUGIN
PLUGINS information schema
changes to show engines
sql/sql_table.cc:
bye bye enum db_type
sql/sql_view.cc:
bye bye enum db_type
sql/sql_view.h:
bye bye enum db_type
sql/sql_yacc.yy:
bye bye enum db_type
sql/table.cc:
bye bye enum db_type
sql/table.h:
bye bye enum db_type
sql/unireg.cc:
bye bye enum db_type
storage/csv/ha_tina.cc:
make tina into a loadable plugin
storage/example/ha_example.cc:
make into a plugin
storage/csv/Makefile.am:
New BitKeeper file ``storage/csv/Makefile.am''
storage/example/Makefile.am:
New BitKeeper file ``storage/example/Makefile.am''
Diffstat (limited to 'sql/examples')
-rw-r--r-- | sql/examples/ha_example.cc | 715 | ||||
-rw-r--r-- | sql/examples/ha_example.h | 155 | ||||
-rw-r--r-- | sql/examples/ha_tina.cc | 935 | ||||
-rw-r--r-- | sql/examples/ha_tina.h | 130 |
4 files changed, 0 insertions, 1935 deletions
diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc deleted file mode 100644 index 5b32b549e8d..00000000000 --- a/sql/examples/ha_example.cc +++ /dev/null @@ -1,715 +0,0 @@ -/* Copyright (C) 2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* - ha_example is a stubbed storage engine. It does nothing at this point. It - will let you create/open/delete tables but that is all. You can enable it - in your buld by doing the following during your build process: - ./configure --with-example-storage-engine - - Once this is done mysql will let you create tables with: - CREATE TABLE A (...) ENGINE=EXAMPLE; - - The example is setup to use table locks. It implements an example "SHARE" - that is inserted into a hash by table name. You can use this to store - information of state that any example handler object will be able to see - if it is using the same table. - - Please read the object definition in ha_example.h before reading the rest - if this file. - - To get an idea of what occurs here is an example select that would do a - scan of an entire table: - ha_example::store_lock - ha_example::external_lock - ha_example::info - ha_example::rnd_init - ha_example::extra - ENUM HA_EXTRA_CACHE Cash record in HA_rrnd() - ha_example::rnd_next - ha_example::rnd_next - ha_example::rnd_next - ha_example::rnd_next - ha_example::rnd_next - ha_example::rnd_next - ha_example::rnd_next - ha_example::rnd_next - ha_example::rnd_next - ha_example::extra - ENUM HA_EXTRA_NO_CACHE End cacheing of records (def) - ha_example::external_lock - ha_example::extra - ENUM HA_EXTRA_RESET Reset database to after open - - In the above example has 9 row called before rnd_next signalled that it was - at the end of its data. In the above example the table was already opened - (or you would have seen a call to ha_example::open(). Calls to - ha_example::extra() are hints as to what will be occuring to the request. - - Happy coding! - -Brian -*/ - -#ifdef USE_PRAGMA_IMPLEMENTATION -#pragma implementation // gcc: Class implementation -#endif - -#include "../mysql_priv.h" - -#include "ha_example.h" - -static handler* example_create_handler(TABLE_SHARE *table); - -handlerton example_hton= { - "EXAMPLE", - SHOW_OPTION_YES, - "Example storage engine", - DB_TYPE_EXAMPLE_DB, - NULL, /* We do need to write one! */ - 0, /* slot */ - 0, /* savepoint size. */ - NULL, /* close_connection */ - NULL, /* savepoint */ - NULL, /* rollback to savepoint */ - NULL, /* release savepoint */ - NULL, /* commit */ - NULL, /* rollback */ - NULL, /* prepare */ - NULL, /* recover */ - NULL, /* commit_by_xid */ - NULL, /* rollback_by_xid */ - NULL, /* create_cursor_read_view */ - NULL, /* set_cursor_read_view */ - NULL, /* close_cursor_read_view */ - example_create_handler, /* Create a new handler */ - NULL, /* Drop a database */ - NULL, /* Panic call */ - NULL, /* Release temporary latches */ - NULL, /* Update Statistics */ - NULL, /* Start Consistent Snapshot */ - NULL, /* Flush logs */ - NULL, /* Show status */ - NULL, /* Replication Report Sent Binlog */ - HTON_CAN_RECREATE -}; - -/* Variables for example share methods */ -static HASH example_open_tables; // Hash used to track open tables -pthread_mutex_t example_mutex; // This is the mutex we use to init the hash -static int example_init= 0; // Variable for checking the init state of hash - - -/* - Function we use in the creation of our hash to get key. -*/ -static byte* example_get_key(EXAMPLE_SHARE *share,uint *length, - my_bool not_used __attribute__((unused))) -{ - *length=share->table_name_length; - return (byte*) share->table_name; -} - - -/* - Example of simple lock controls. The "share" it creates is structure we will - pass to each example handler. Do you have to have one of these? Well, you have - pieces that are used for locking, and they are needed to function. -*/ -static EXAMPLE_SHARE *get_share(const char *table_name, TABLE *table) -{ - EXAMPLE_SHARE *share; - uint length; - char *tmp_name; - - /* - So why does this exist? There is no way currently to init a storage engine. - Innodb and BDB both have modifications to the server to allow them to - do this. Since you will not want to do this, this is probably the next - best method. - */ - if (!example_init) - { - /* Hijack a mutex for init'ing the storage engine */ - pthread_mutex_lock(&LOCK_mysql_create_db); - if (!example_init) - { - example_init++; - VOID(pthread_mutex_init(&example_mutex,MY_MUTEX_INIT_FAST)); - (void) hash_init(&example_open_tables,system_charset_info,32,0,0, - (hash_get_key) example_get_key,0,0); - } - pthread_mutex_unlock(&LOCK_mysql_create_db); - } - pthread_mutex_lock(&example_mutex); - length=(uint) strlen(table_name); - - if (!(share=(EXAMPLE_SHARE*) hash_search(&example_open_tables, - (byte*) table_name, - length))) - { - if (!(share=(EXAMPLE_SHARE *) - my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), - &share, sizeof(*share), - &tmp_name, length+1, - NullS))) - { - pthread_mutex_unlock(&example_mutex); - return NULL; - } - - share->use_count=0; - share->table_name_length=length; - share->table_name=tmp_name; - strmov(share->table_name,table_name); - if (my_hash_insert(&example_open_tables, (byte*) share)) - goto error; - thr_lock_init(&share->lock); - pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST); - } - share->use_count++; - pthread_mutex_unlock(&example_mutex); - - return share; - -error: - pthread_mutex_destroy(&share->mutex); - pthread_mutex_unlock(&example_mutex); - my_free((gptr) share, MYF(0)); - - return NULL; -} - - -/* - Free lock controls. We call this whenever we close a table. If the table had - the last reference to the share then we free memory associated with it. -*/ -static int free_share(EXAMPLE_SHARE *share) -{ - pthread_mutex_lock(&example_mutex); - if (!--share->use_count) - { - hash_delete(&example_open_tables, (byte*) share); - thr_lock_delete(&share->lock); - pthread_mutex_destroy(&share->mutex); - my_free((gptr) share, MYF(0)); - } - pthread_mutex_unlock(&example_mutex); - - return 0; -} - - -static handler* example_create_handler(TABLE_SHARE *table) -{ - return new ha_example(table); -} - - -ha_example::ha_example(TABLE_SHARE *table_arg) - :handler(&example_hton, table_arg) -{} - -/* - If frm_error() is called then we will use this to to find out what file extentions - exist for the storage engine. This is also used by the default rename_table and - delete_table method in handler.cc. -*/ -static const char *ha_example_exts[] = { - NullS -}; - -const char **ha_example::bas_ext() const -{ - return ha_example_exts; -} - - -/* - Used for opening tables. The name will be the name of the file. - A table is opened when it needs to be opened. For instance - when a request comes in for a select on the table (tables are not - open and closed for each request, they are cached). - - Called from handler.cc by handler::ha_open(). The server opens all tables by - calling ha_open() which then calls the handler specific open(). -*/ -int ha_example::open(const char *name, int mode, uint test_if_locked) -{ - DBUG_ENTER("ha_example::open"); - - if (!(share = get_share(name, table))) - DBUG_RETURN(1); - thr_lock_data_init(&share->lock,&lock,NULL); - - DBUG_RETURN(0); -} - - -/* - Closes a table. We call the free_share() function to free any resources - that we have allocated in the "shared" structure. - - Called from sql_base.cc, sql_select.cc, and table.cc. - In sql_select.cc it is only used to close up temporary tables or during - the process where a temporary table is converted over to being a - myisam table. - For sql_base.cc look at close_data_tables(). -*/ -int ha_example::close(void) -{ - DBUG_ENTER("ha_example::close"); - DBUG_RETURN(free_share(share)); -} - - -/* - write_row() inserts a row. No extra() hint is given currently if a bulk load - is happeneding. buf() is a byte array of data. You can use the field - information to extract the data from the native byte array type. - Example of this would be: - for (Field **field=table->field ; *field ; field++) - { - ... - } - - See ha_tina.cc for an example of extracting all of the data as strings. - ha_berekly.cc has an example of how to store it intact by "packing" it - for ha_berkeley's own native storage type. - - See the note for update_row() on auto_increments and timestamps. This - case also applied to write_row(). - - Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc, - sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc. -*/ -int ha_example::write_row(byte * buf) -{ - DBUG_ENTER("ha_example::write_row"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - - -/* - Yes, update_row() does what you expect, it updates a row. old_data will have - the previous row record in it, while new_data will have the newest data in - it. - Keep in mind that the server can do updates based on ordering if an ORDER BY - clause was used. Consecutive ordering is not guarenteed. - Currently new_data will not have an updated auto_increament record, or - and updated timestamp field. You can do these for example by doing these: - if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) - table->timestamp_field->set_time(); - if (table->next_number_field && record == table->record[0]) - update_auto_increment(); - - Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc. -*/ -int ha_example::update_row(const byte * old_data, byte * new_data) -{ - - DBUG_ENTER("ha_example::update_row"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - - -/* - This will delete a row. buf will contain a copy of the row to be deleted. - The server will call this right after the current row has been called (from - either a previous rnd_nexT() or index call). - If you keep a pointer to the last row or can access a primary key it will - make doing the deletion quite a bit easier. - Keep in mind that the server does no guarentee consecutive deletions. ORDER BY - clauses can be used. - - Called in sql_acl.cc and sql_udf.cc to manage internal table information. - Called in sql_delete.cc, sql_insert.cc, and sql_select.cc. In sql_select it is - used for removing duplicates while in insert it is used for REPLACE calls. -*/ -int ha_example::delete_row(const byte * buf) -{ - DBUG_ENTER("ha_example::delete_row"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - - -/* - Positions an index cursor to the index specified in the handle. Fetches the - row if available. If the key value is null, begin at the first key of the - index. -*/ -int ha_example::index_read(byte * buf, const byte * key, - uint key_len __attribute__((unused)), - enum ha_rkey_function find_flag - __attribute__((unused))) -{ - DBUG_ENTER("ha_example::index_read"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - - -/* - Positions an index cursor to the index specified in key. Fetches the - row if any. This is only used to read whole keys. -*/ -int ha_example::index_read_idx(byte * buf, uint index, const byte * key, - uint key_len __attribute__((unused)), - enum ha_rkey_function find_flag - __attribute__((unused))) -{ - DBUG_ENTER("ha_example::index_read_idx"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - - -/* - Used to read forward through the index. -*/ -int ha_example::index_next(byte * buf) -{ - DBUG_ENTER("ha_example::index_next"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - - -/* - Used to read backwards through the index. -*/ -int ha_example::index_prev(byte * buf) -{ - DBUG_ENTER("ha_example::index_prev"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - - -/* - index_first() asks for the first key in the index. - - Called from opt_range.cc, opt_sum.cc, sql_handler.cc, - and sql_select.cc. -*/ -int ha_example::index_first(byte * buf) -{ - DBUG_ENTER("ha_example::index_first"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - - -/* - index_last() asks for the last key in the index. - - Called from opt_range.cc, opt_sum.cc, sql_handler.cc, - and sql_select.cc. -*/ -int ha_example::index_last(byte * buf) -{ - DBUG_ENTER("ha_example::index_last"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - - -/* - rnd_init() is called when the system wants the storage engine to do a table - scan. - See the example in the introduction at the top of this file to see when - rnd_init() is called. - - Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc, - and sql_update.cc. -*/ -int ha_example::rnd_init(bool scan) -{ - DBUG_ENTER("ha_example::rnd_init"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - -int ha_example::rnd_end() -{ - DBUG_ENTER("ha_example::rnd_end"); - DBUG_RETURN(0); -} - -/* - This is called for each row of the table scan. When you run out of records - you should return HA_ERR_END_OF_FILE. Fill buff up with the row information. - The Field structure for the table is the key to getting data into buf - in a manner that will allow the server to understand it. - - Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc, - and sql_update.cc. -*/ -int ha_example::rnd_next(byte *buf) -{ - DBUG_ENTER("ha_example::rnd_next"); - DBUG_RETURN(HA_ERR_END_OF_FILE); -} - - -/* - position() is called after each call to rnd_next() if the data needs - to be ordered. You can do something like the following to store - the position: - my_store_ptr(ref, ref_length, current_position); - - The server uses ref to store data. ref_length in the above case is - the size needed to store current_position. ref is just a byte array - that the server will maintain. If you are using offsets to mark rows, then - current_position should be the offset. If it is a primary key like in - BDB, then it needs to be a primary key. - - Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc. -*/ -void ha_example::position(const byte *record) -{ - DBUG_ENTER("ha_example::position"); - DBUG_VOID_RETURN; -} - - -/* - This is like rnd_next, but you are given a position to use - to determine the row. The position will be of the type that you stored in - ref. You can use ha_get_ptr(pos,ref_length) to retrieve whatever key - or position you saved when position() was called. - Called from filesort.cc records.cc sql_insert.cc sql_select.cc sql_update.cc. -*/ -int ha_example::rnd_pos(byte * buf, byte *pos) -{ - DBUG_ENTER("ha_example::rnd_pos"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - - -/* - ::info() is used to return information to the optimizer. - see my_base.h for the complete description - - Currently this table handler doesn't implement most of the fields - really needed. SHOW also makes use of this data - Another note, you will probably want to have the following in your - code: - if (records < 2) - records = 2; - The reason is that the server will optimize for cases of only a single - record. If in a table scan you don't know the number of records - it will probably be better to set records to two so you can return - as many records as you need. - Along with records a few more variables you may wish to set are: - records - deleted - data_file_length - index_file_length - delete_length - check_time - Take a look at the public variables in handler.h for more information. - - Called in: - filesort.cc - ha_heap.cc - item_sum.cc - opt_sum.cc - sql_delete.cc - sql_delete.cc - sql_derived.cc - sql_select.cc - sql_select.cc - sql_select.cc - sql_select.cc - sql_select.cc - sql_show.cc - sql_show.cc - sql_show.cc - sql_show.cc - sql_table.cc - sql_union.cc - sql_update.cc - -*/ -void ha_example::info(uint flag) -{ - DBUG_ENTER("ha_example::info"); - DBUG_VOID_RETURN; -} - - -/* - extra() is called whenever the server wishes to send a hint to - the storage engine. The myisam engine implements the most hints. - ha_innodb.cc has the most exhaustive list of these hints. -*/ -int ha_example::extra(enum ha_extra_function operation) -{ - DBUG_ENTER("ha_example::extra"); - DBUG_RETURN(0); -} - - -/* - Deprecated and likely to be removed in the future. Storage engines normally - just make a call like: - ha_example::extra(HA_EXTRA_RESET); - to handle it. -*/ -int ha_example::reset(void) -{ - DBUG_ENTER("ha_example::reset"); - DBUG_RETURN(0); -} - - -/* - Used to delete all rows in a table. Both for cases of truncate and - for cases where the optimizer realizes that all rows will be - removed as a result of a SQL statement. - - Called from item_sum.cc by Item_func_group_concat::clear(), - Item_sum_count_distinct::clear(), and Item_func_group_concat::clear(). - Called from sql_delete.cc by mysql_delete(). - Called from sql_select.cc by JOIN::reinit(). - Called from sql_union.cc by st_select_lex_unit::exec(). -*/ -int ha_example::delete_all_rows() -{ - DBUG_ENTER("ha_example::delete_all_rows"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - - -/* - First you should go read the section "locking functions for mysql" in - lock.cc to understand this. - This create a lock on the table. If you are implementing a storage engine - that can handle transacations look at ha_berkely.cc to see how you will - want to goo about doing this. Otherwise you should consider calling flock() - here. - - Called from lock.cc by lock_external() and unlock_external(). Also called - from sql_table.cc by copy_data_between_tables(). -*/ -int ha_example::external_lock(THD *thd, int lock_type) -{ - DBUG_ENTER("ha_example::external_lock"); - DBUG_RETURN(0); -} - - -/* - The idea with handler::store_lock() is the following: - - The statement decided which locks we should need for the table - for updates/deletes/inserts we get WRITE locks, for SELECT... we get - read locks. - - Before adding the lock into the table lock handler (see thr_lock.c) - mysqld calls store lock with the requested locks. Store lock can now - modify a write lock to a read lock (or some other lock), ignore the - lock (if we don't want to use MySQL table locks at all) or add locks - for many tables (like we do when we are using a MERGE handler). - - Berkeley DB for example changes all WRITE locks to TL_WRITE_ALLOW_WRITE - (which signals that we are doing WRITES, but we are still allowing other - reader's and writer's. - - When releasing locks, store_lock() are also called. In this case one - usually doesn't have to do anything. - - In some exceptional cases MySQL may send a request for a TL_IGNORE; - This means that we are requesting the same lock as last time and this - should also be ignored. (This may happen when someone does a flush - table when we have opened a part of the tables, in which case mysqld - closes and reopens the tables and tries to get the same locks at last - time). In the future we will probably try to remove this. - - Called from lock.cc by get_lock_data(). -*/ -THR_LOCK_DATA **ha_example::store_lock(THD *thd, - THR_LOCK_DATA **to, - enum thr_lock_type lock_type) -{ - if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) - lock.type=lock_type; - *to++= &lock; - return to; -} - -/* - Used to delete a table. By the time delete_table() has been called all - opened references to this table will have been closed (and your globally - shared references released. The variable name will just be the name of - the table. You will need to remove any files you have created at this point. - - If you do not implement this, the default delete_table() is called from - handler.cc and it will delete all files with the file extentions returned - by bas_ext(). - - Called from handler.cc by delete_table and ha_create_table(). Only used - during create if the table_flag HA_DROP_BEFORE_CREATE was specified for - the storage engine. -*/ -int ha_example::delete_table(const char *name) -{ - DBUG_ENTER("ha_example::delete_table"); - /* This is not implemented but we want someone to be able that it works. */ - DBUG_RETURN(0); -} - -/* - Renames a table from one name to another from alter table call. - - If you do not implement this, the default rename_table() is called from - handler.cc and it will delete all files with the file extentions returned - by bas_ext(). - - Called from sql_table.cc by mysql_rename_table(). -*/ -int ha_example::rename_table(const char * from, const char * to) -{ - DBUG_ENTER("ha_example::rename_table "); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); -} - -/* - Given a starting key, and an ending key estimate the number of rows that - will exist between the two. end_key may be empty which in case determine - if start_key matches any rows. - - Called from opt_range.cc by check_quick_keys(). -*/ -ha_rows ha_example::records_in_range(uint inx, key_range *min_key, - key_range *max_key) -{ - DBUG_ENTER("ha_example::records_in_range"); - DBUG_RETURN(10); // low number to force index usage -} - - -/* - create() is called to create a database. The variable name will have the name - of the table. When create() is called you do not need to worry about opening - the table. Also, the FRM file will have already been created so adjusting - create_info will not do you any good. You can overwrite the frm file at this - point if you wish to change the table definition, but there are no methods - currently provided for doing that. - - Called from handle.cc by ha_create_table(). -*/ -int ha_example::create(const char *name, TABLE *table_arg, - HA_CREATE_INFO *create_info) -{ - DBUG_ENTER("ha_example::create"); - /* This is not implemented but we want someone to be able that it works. */ - DBUG_RETURN(0); -} diff --git a/sql/examples/ha_example.h b/sql/examples/ha_example.h deleted file mode 100644 index 139a50a3281..00000000000 --- a/sql/examples/ha_example.h +++ /dev/null @@ -1,155 +0,0 @@ -/* Copyright (C) 2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* - Please read ha_exmple.cc before reading this file. - Please keep in mind that the example storage engine implements all methods - that are required to be implemented. handler.h has a full list of methods - that you can implement. -*/ - -#ifdef USE_PRAGMA_INTERFACE -#pragma interface /* gcc class implementation */ -#endif - -/* - EXAMPLE_SHARE is a structure that will be shared amoung all open handlers - The example implements the minimum of what you will probably need. -*/ -typedef struct st_example_share { - char *table_name; - uint table_name_length,use_count; - pthread_mutex_t mutex; - THR_LOCK lock; -} EXAMPLE_SHARE; - -/* - Class definition for the storage engine -*/ -class ha_example: public handler -{ - THR_LOCK_DATA lock; /* MySQL lock */ - EXAMPLE_SHARE *share; /* Shared lock info */ - -public: - ha_example(TABLE_SHARE *table_arg); - ~ha_example() - { - } - /* The name that will be used for display purposes */ - const char *table_type() const { return "EXAMPLE"; } - /* - The name of the index type that will be used for display - don't implement this method unless you really have indexes - */ - const char *index_type(uint inx) { return "HASH"; } - const char **bas_ext() const; - /* - This is a list of flags that says what the storage engine - implements. The current table flags are documented in - handler.h - */ - ulong table_flags() const - { - return 0; - } - /* - This is a bitmap of flags that says how the storage engine - implements indexes. The current index flags are documented in - handler.h. If you do not implement indexes, just return zero - here. - - part is the key part to check. First key part is 0 - If all_parts it's set, MySQL want to know the flags for the combined - index up to and including 'part'. - */ - ulong index_flags(uint inx, uint part, bool all_parts) const - { - return 0; - } - /* - unireg.cc will call the following to make sure that the storage engine can - handle the data it is about to send. - - Return *real* limits of your storage engine here. MySQL will do - min(your_limits, MySQL_limits) automatically - - There is no need to implement ..._key_... methods if you don't suport - indexes. - */ - uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; } - uint max_supported_keys() const { return 0; } - uint max_supported_key_parts() const { return 0; } - uint max_supported_key_length() const { return 0; } - /* - Called in test_quick_select to determine if indexes should be used. - */ - virtual double scan_time() { return (double) (records+deleted) / 20.0+10; } - /* - The next method will never be called if you do not implement indexes. - */ - virtual double read_time(ha_rows rows) { return (double) rows / 20.0+1; } - - /* - Everything below are methods that we implment in ha_example.cc. - - Most of these methods are not obligatory, skip them and - MySQL will treat them as not implemented - */ - int open(const char *name, int mode, uint test_if_locked); // required - int close(void); // required - - int write_row(byte * buf); - int update_row(const byte * old_data, byte * new_data); - int delete_row(const byte * buf); - int index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - int index_read_idx(byte * buf, uint idx, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - int index_next(byte * buf); - int index_prev(byte * buf); - int index_first(byte * buf); - int index_last(byte * buf); - /* - unlike index_init(), rnd_init() can be called two times - without rnd_end() in between (it only makes sense if scan=1). - then the second call should prepare for the new table scan - (e.g if rnd_init allocates the cursor, second call should - position it to the start of the table, no need to deallocate - and allocate it again - */ - int rnd_init(bool scan); //required - int rnd_end(); - int rnd_next(byte *buf); //required - int rnd_pos(byte * buf, byte *pos); //required - void position(const byte *record); //required - void info(uint); //required - - int extra(enum ha_extra_function operation); - int reset(void); - int external_lock(THD *thd, int lock_type); //required - int delete_all_rows(void); - ha_rows records_in_range(uint inx, key_range *min_key, - key_range *max_key); - int delete_table(const char *from); - int rename_table(const char * from, const char * to); - int create(const char *name, TABLE *form, - HA_CREATE_INFO *create_info); //required - - THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, - enum thr_lock_type lock_type); //required -}; - diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc deleted file mode 100644 index 4f2dc0b5cac..00000000000 --- a/sql/examples/ha_tina.cc +++ /dev/null @@ -1,935 +0,0 @@ -/* Copyright (C) 2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* - Make sure to look at ha_tina.h for more details. - - First off, this is a play thing for me, there are a number of things - wrong with it: - *) It was designed for csv and therefore its performance is highly - questionable. - *) Indexes have not been implemented. This is because the files can - be traded in and out of the table directory without having to worry - about rebuilding anything. - *) NULLs and "" are treated equally (like a spreadsheet). - *) There was in the beginning no point to anyone seeing this other - then me, so there is a good chance that I haven't quite documented - it well. - *) Less design, more "make it work" - - Now there are a few cool things with it: - *) Errors can result in corrupted data files. - *) Data files can be read by spreadsheets directly. - -TODO: - *) Move to a block system for larger files - *) Error recovery, its all there, just need to finish it - *) Document how the chains work. - - -Brian -*/ - -#ifdef USE_PRAGMA_IMPLEMENTATION -#pragma implementation // gcc: Class implementation -#endif - -#include "mysql_priv.h" - -#include "ha_tina.h" -#include <sys/mman.h> - -/* Stuff for shares */ -pthread_mutex_t tina_mutex; -static HASH tina_open_tables; -static int tina_init= 0; -static handler *tina_create_handler(TABLE_SHARE *table); - -handlerton tina_hton= { - "CSV", - SHOW_OPTION_YES, - "CSV storage engine", - DB_TYPE_CSV_DB, - NULL, /* One needs to be written! */ - 0, /* slot */ - 0, /* savepoint size. */ - NULL, /* close_connection */ - NULL, /* savepoint */ - NULL, /* rollback to savepoint */ - NULL, /* release savepoint */ - NULL, /* commit */ - NULL, /* rollback */ - NULL, /* prepare */ - NULL, /* recover */ - NULL, /* commit_by_xid */ - NULL, /* rollback_by_xid */ - NULL, /* create_cursor_read_view */ - NULL, /* set_cursor_read_view */ - NULL, /* close_cursor_read_view */ - tina_create_handler, /* Create a new handler */ - NULL, /* Drop a database */ - tina_end, /* Panic call */ - NULL, /* Release temporary latches */ - NULL, /* Update Statistics */ - NULL, /* Start Consistent Snapshot */ - NULL, /* Flush logs */ - NULL, /* Show status */ - NULL, /* Replication Report Sent Binlog */ - HTON_CAN_RECREATE -}; - -/***************************************************************************** - ** TINA tables - *****************************************************************************/ - -/* - Used for sorting chains with qsort(). -*/ -int sort_set (tina_set *a, tina_set *b) -{ - /* - We assume that intervals do not intersect. So, it is enought to compare - any two points. Here we take start of intervals for comparison. - */ - return ( a->begin > b->begin ? -1 : ( a->begin < b->begin ? 1 : 0 ) ); -} - -static byte* tina_get_key(TINA_SHARE *share,uint *length, - my_bool not_used __attribute__((unused))) -{ - *length=share->table_name_length; - return (byte*) share->table_name; -} - -/* - Reloads the mmap file. -*/ -int get_mmap(TINA_SHARE *share, int write) -{ - DBUG_ENTER("ha_tina::get_mmap"); - if (share->mapped_file && my_munmap(share->mapped_file, - share->file_stat.st_size)) - DBUG_RETURN(1); - - if (my_fstat(share->data_file, &share->file_stat, MYF(MY_WME)) == -1) - DBUG_RETURN(1); - - if (share->file_stat.st_size) - { - if (write) - share->mapped_file= (byte *)my_mmap(NULL, share->file_stat.st_size, - PROT_READ|PROT_WRITE, MAP_SHARED, - share->data_file, 0); - else - share->mapped_file= (byte *)my_mmap(NULL, share->file_stat.st_size, - PROT_READ, MAP_PRIVATE, - share->data_file, 0); - if ((share->mapped_file ==(caddr_t)-1)) - { - /* - Bad idea you think? See the problem is that nothing actually checks - the return value of ::rnd_init(), so tossing an error is about - it for us. - Never going to happen right? :) - */ - my_message(errno, "Woops, blew up opening a mapped file", 0); - DBUG_ASSERT(0); - DBUG_RETURN(1); - } - } - else - share->mapped_file= NULL; - - DBUG_RETURN(0); -} - -/* - Simple lock controls. -*/ -static TINA_SHARE *get_share(const char *table_name, TABLE *table) -{ - TINA_SHARE *share; - char *tmp_name; - uint length; - - if (!tina_init) - { - /* Hijack a mutex for init'ing the storage engine */ - pthread_mutex_lock(&LOCK_mysql_create_db); - if (!tina_init) - { - tina_init++; - VOID(pthread_mutex_init(&tina_mutex,MY_MUTEX_INIT_FAST)); - (void) hash_init(&tina_open_tables,system_charset_info,32,0,0, - (hash_get_key) tina_get_key,0,0); - } - pthread_mutex_unlock(&LOCK_mysql_create_db); - } - pthread_mutex_lock(&tina_mutex); - length=(uint) strlen(table_name); - if (!(share=(TINA_SHARE*) hash_search(&tina_open_tables, - (byte*) table_name, - length))) - { - char data_file_name[FN_REFLEN]; - if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), - &share, sizeof(*share), - &tmp_name, length+1, - NullS)) - { - pthread_mutex_unlock(&tina_mutex); - return NULL; - } - - share->use_count= 0; - share->table_name_length= length; - share->table_name= tmp_name; - strmov(share->table_name, table_name); - fn_format(data_file_name, table_name, "", ".CSV", - MY_REPLACE_EXT|MY_UNPACK_FILENAME); - if (my_hash_insert(&tina_open_tables, (byte*) share)) - goto error; - thr_lock_init(&share->lock); - pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST); - - if ((share->data_file= my_open(data_file_name, O_RDWR|O_APPEND, - MYF(0))) == -1) - goto error2; - - /* - We only use share->data_file for writing, so we scan to - the end to append - */ - if (my_seek(share->data_file, 0, SEEK_END, MYF(0)) == MY_FILEPOS_ERROR) - goto error2; - - share->mapped_file= NULL; // We don't know the state as we just allocated it - if (get_mmap(share, 0) > 0) - goto error3; - } - share->use_count++; - pthread_mutex_unlock(&tina_mutex); - - return share; - -error3: - my_close(share->data_file,MYF(0)); -error2: - thr_lock_delete(&share->lock); - pthread_mutex_destroy(&share->mutex); -error: - pthread_mutex_unlock(&tina_mutex); - my_free((gptr) share, MYF(0)); - - return NULL; -} - - -/* - Free lock controls. -*/ -static int free_share(TINA_SHARE *share) -{ - DBUG_ENTER("ha_tina::free_share"); - pthread_mutex_lock(&tina_mutex); - int result_code= 0; - if (!--share->use_count){ - /* Drop the mapped file */ - if (share->mapped_file) - my_munmap(share->mapped_file, share->file_stat.st_size); - result_code= my_close(share->data_file,MYF(0)); - hash_delete(&tina_open_tables, (byte*) share); - thr_lock_delete(&share->lock); - pthread_mutex_destroy(&share->mutex); - my_free((gptr) share, MYF(0)); - } - pthread_mutex_unlock(&tina_mutex); - - DBUG_RETURN(result_code); -} - -int tina_end(ha_panic_function type) -{ - if (tina_init) - { - hash_free(&tina_open_tables); - VOID(pthread_mutex_destroy(&tina_mutex)); - } - tina_init= 0; - return 0; -} - -/* - Finds the end of a line. - Currently only supports files written on a UNIX OS. -*/ -byte * find_eoln(byte *data, off_t begin, off_t end) -{ - for (off_t x= begin; x < end; x++) - if (data[x] == '\n') - return data + x; - - return 0; -} - - -static handler *tina_create_handler(TABLE_SHARE *table) -{ - return new ha_tina(table); -} - - -ha_tina::ha_tina(TABLE_SHARE *table_arg) - :handler(&tina_hton, table_arg), - /* - These definitions are found in handler.h - They are not probably completely right. - */ - current_position(0), next_position(0), chain_alloced(0), - chain_size(DEFAULT_CHAIN_LENGTH), records_is_known(0) -{ - /* Set our original buffers from pre-allocated memory */ - buffer.set(byte_buffer, IO_SIZE, system_charset_info); - chain= chain_buffer; -} - -/* - Encode a buffer into the quoted format. -*/ - -int ha_tina::encode_quote(byte *buf) -{ - char attribute_buffer[1024]; - String attribute(attribute_buffer, sizeof(attribute_buffer), &my_charset_bin); - - buffer.length(0); - for (Field **field=table->field ; *field ; field++) - { - const char *ptr; - const char *end_ptr; - - (*field)->val_str(&attribute,&attribute); - ptr= attribute.ptr(); - end_ptr= attribute.length() + ptr; - - buffer.append('"'); - - while (ptr < end_ptr) - { - if (*ptr == '"') - { - buffer.append('\\'); - buffer.append('"'); - *ptr++; - } - else if (*ptr == '\r') - { - buffer.append('\\'); - buffer.append('r'); - *ptr++; - } - else if (*ptr == '\\') - { - buffer.append('\\'); - buffer.append('\\'); - *ptr++; - } - else if (*ptr == '\n') - { - buffer.append('\\'); - buffer.append('n'); - *ptr++; - } - else - buffer.append(*ptr++); - } - buffer.append('"'); - buffer.append(','); - } - // Remove the comma, add a line feed - buffer.length(buffer.length() - 1); - buffer.append('\n'); - //buffer.replace(buffer.length(), 0, "\n", 1); - - return (buffer.length()); -} - -/* - chain_append() adds delete positions to the chain that we use to keep - track of space. Then the chain will be used to cleanup "holes", occured - due to deletes and updates. -*/ -int ha_tina::chain_append() -{ - if ( chain_ptr != chain && (chain_ptr -1)->end == current_position) - (chain_ptr -1)->end= next_position; - else - { - /* We set up for the next position */ - if ((off_t)(chain_ptr - chain) == (chain_size -1)) - { - off_t location= chain_ptr - chain; - chain_size += DEFAULT_CHAIN_LENGTH; - if (chain_alloced) - { - /* Must cast since my_malloc unlike malloc doesn't have a void ptr */ - if ((chain= (tina_set *) my_realloc((gptr)chain, - chain_size, MYF(MY_WME))) == NULL) - return -1; - } - else - { - tina_set *ptr= (tina_set *) my_malloc(chain_size * sizeof(tina_set), - MYF(MY_WME)); - memcpy(ptr, chain, DEFAULT_CHAIN_LENGTH * sizeof(tina_set)); - chain= ptr; - chain_alloced++; - } - chain_ptr= chain + location; - } - chain_ptr->begin= current_position; - chain_ptr->end= next_position; - chain_ptr++; - } - - return 0; -} - - -/* - Scans for a row. -*/ -int ha_tina::find_current_row(byte *buf) -{ - byte *mapped_ptr= (byte *)share->mapped_file + current_position; - byte *end_ptr; - DBUG_ENTER("ha_tina::find_current_row"); - - /* EOF should be counted as new line */ - if ((end_ptr= find_eoln(share->mapped_file, current_position, - share->file_stat.st_size)) == 0) - DBUG_RETURN(HA_ERR_END_OF_FILE); - - for (Field **field=table->field ; *field ; field++) - { - buffer.length(0); - mapped_ptr++; // Increment past the first quote - for(;mapped_ptr != end_ptr; mapped_ptr++) - { - // Need to convert line feeds! - if (*mapped_ptr == '"' && - (((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) || - (mapped_ptr == end_ptr -1 ))) - { - mapped_ptr += 2; // Move past the , and the " - break; - } - if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1)) - { - mapped_ptr++; - if (*mapped_ptr == 'r') - buffer.append('\r'); - else if (*mapped_ptr == 'n' ) - buffer.append('\n'); - else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"')) - buffer.append(*mapped_ptr); - else /* This could only happed with an externally created file */ - { - buffer.append('\\'); - buffer.append(*mapped_ptr); - } - } - else - buffer.append(*mapped_ptr); - } - (*field)->store(buffer.ptr(), buffer.length(), system_charset_info); - } - next_position= (end_ptr - share->mapped_file)+1; - /* Maybe use \N for null? */ - memset(buf, 0, table->s->null_bytes); /* We do not implement nulls! */ - - DBUG_RETURN(0); -} - -/* - If frm_error() is called in table.cc this is called to find out what file - extensions exist for this handler. -*/ -static const char *ha_tina_exts[] = { - ".CSV", - NullS -}; - -const char **ha_tina::bas_ext() const -{ - return ha_tina_exts; -} - - -/* - Open a database file. Keep in mind that tables are caches, so - this will not be called for every request. Any sort of positions - that need to be reset should be kept in the ::extra() call. -*/ -int ha_tina::open(const char *name, int mode, uint test_if_locked) -{ - DBUG_ENTER("ha_tina::open"); - - if (!(share= get_share(name, table))) - DBUG_RETURN(1); - thr_lock_data_init(&share->lock,&lock,NULL); - ref_length=sizeof(off_t); - - DBUG_RETURN(0); -} - - -/* - Close a database file. We remove ourselves from the shared strucutre. - If it is empty we destroy it and free the mapped file. -*/ -int ha_tina::close(void) -{ - DBUG_ENTER("ha_tina::close"); - DBUG_RETURN(free_share(share)); -} - -/* - This is an INSERT. At the moment this handler just seeks to the end - of the file and appends the data. In an error case it really should - just truncate to the original position (this is not done yet). -*/ -int ha_tina::write_row(byte * buf) -{ - int size; - DBUG_ENTER("ha_tina::write_row"); - - statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status); - - if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) - table->timestamp_field->set_time(); - - size= encode_quote(buf); - - if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP))) - DBUG_RETURN(-1); - - /* - Ok, this is means that we will be doing potentially bad things - during a bulk insert on some OS'es. What we need is a cleanup - call for ::write_row that would let us fix up everything after the bulk - insert. The archive handler does this with an extra mutx call, which - might be a solution for this. - */ - if (get_mmap(share, 0) > 0) - DBUG_RETURN(-1); - records++; - DBUG_RETURN(0); -} - - -/* - This is called for an update. - Make sure you put in code to increment the auto increment, also - update any timestamp data. Currently auto increment is not being - fixed since autoincrements have yet to be added to this table handler. - This will be called in a table scan right before the previous ::rnd_next() - call. -*/ -int ha_tina::update_row(const byte * old_data, byte * new_data) -{ - int size; - DBUG_ENTER("ha_tina::update_row"); - - statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, - &LOCK_status); - - if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) - table->timestamp_field->set_time(); - - size= encode_quote(new_data); - - if (chain_append()) - DBUG_RETURN(-1); - - if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP))) - DBUG_RETURN(-1); - DBUG_RETURN(0); -} - - -/* - Deletes a row. First the database will find the row, and then call this - method. In the case of a table scan, the previous call to this will be - the ::rnd_next() that found this row. - The exception to this is an ORDER BY. This will cause the table handler - to walk the table noting the positions of all rows that match a query. - The table will then be deleted/positioned based on the ORDER (so RANDOM, - DESC, ASC). -*/ -int ha_tina::delete_row(const byte * buf) -{ - DBUG_ENTER("ha_tina::delete_row"); - statistic_increment(table->in_use->status_var.ha_delete_count, - &LOCK_status); - - if (chain_append()) - DBUG_RETURN(-1); - - --records; - - DBUG_RETURN(0); -} - -/* - Fill buf with value from key. Simply this is used for a single index read - with a key. -*/ -int ha_tina::index_read(byte * buf, const byte * key, - uint key_len __attribute__((unused)), - enum ha_rkey_function find_flag - __attribute__((unused))) -{ - DBUG_ENTER("ha_tina::index_read"); - DBUG_ASSERT(0); - DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); -} - -/* - Fill buf with value from key. Simply this is used for a single index read - with a key. - Whatever the current key is we will use it. This is what will be in "index". -*/ -int ha_tina::index_read_idx(byte * buf, uint index, const byte * key, - uint key_len __attribute__((unused)), - enum ha_rkey_function find_flag - __attribute__((unused))) -{ - DBUG_ENTER("ha_tina::index_read_idx"); - DBUG_ASSERT(0); - DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); -} - - -/* - Read the next position in the index. -*/ -int ha_tina::index_next(byte * buf) -{ - DBUG_ENTER("ha_tina::index_next"); - DBUG_ASSERT(0); - DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); -} - -/* - Read the previous position in the index. -*/ -int ha_tina::index_prev(byte * buf) -{ - DBUG_ENTER("ha_tina::index_prev"); - DBUG_ASSERT(0); - DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); -} - -/* - Read the first position in the index -*/ -int ha_tina::index_first(byte * buf) -{ - DBUG_ENTER("ha_tina::index_first"); - DBUG_ASSERT(0); - DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); -} - -/* - Read the last position in the index - With this we don't need to do a filesort() with index. - We just read the last row and call previous. -*/ -int ha_tina::index_last(byte * buf) -{ - DBUG_ENTER("ha_tina::index_last"); - DBUG_ASSERT(0); - DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); -} - -/* - All table scans call this first. - The order of a table scan is: - - ha_tina::store_lock - ha_tina::external_lock - ha_tina::info - ha_tina::rnd_init - ha_tina::extra - ENUM HA_EXTRA_CACHE Cash record in HA_rrnd() - ha_tina::rnd_next - ha_tina::rnd_next - ha_tina::rnd_next - ha_tina::rnd_next - ha_tina::rnd_next - ha_tina::rnd_next - ha_tina::rnd_next - ha_tina::rnd_next - ha_tina::rnd_next - ha_tina::extra - ENUM HA_EXTRA_NO_CACHE End cacheing of records (def) - ha_tina::external_lock - ha_tina::extra - ENUM HA_EXTRA_RESET Reset database to after open - - Each call to ::rnd_next() represents a row returned in the can. When no more - rows can be returned, rnd_next() returns a value of HA_ERR_END_OF_FILE. - The ::info() call is just for the optimizer. - -*/ - -int ha_tina::rnd_init(bool scan) -{ - DBUG_ENTER("ha_tina::rnd_init"); - - current_position= next_position= 0; - records= 0; - records_is_known= 0; - chain_ptr= chain; -#ifdef HAVE_MADVISE - if (scan) - (void) madvise(share->mapped_file, share->file_stat.st_size, - MADV_SEQUENTIAL); -#endif - - DBUG_RETURN(0); -} - -/* - ::rnd_next() does all the heavy lifting for a table scan. You will need to - populate *buf with the correct field data. You can walk the field to - determine at what position you should store the data (take a look at how - ::find_current_row() works). The structure is something like: - 0Foo Dog Friend - The first offset is for the first attribute. All space before that is - reserved for null count. - Basically this works as a mask for which rows are nulled (compared to just - empty). - This table handler doesn't do nulls and does not know the difference between - NULL and "". This is ok since this table handler is for spreadsheets and - they don't know about them either :) -*/ -int ha_tina::rnd_next(byte *buf) -{ - DBUG_ENTER("ha_tina::rnd_next"); - - statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, - &LOCK_status); - - current_position= next_position; - if (!share->mapped_file) - DBUG_RETURN(HA_ERR_END_OF_FILE); - if (HA_ERR_END_OF_FILE == find_current_row(buf) ) - DBUG_RETURN(HA_ERR_END_OF_FILE); - - records++; - DBUG_RETURN(0); -} - -/* - In the case of an order by rows will need to be sorted. - ::position() is called after each call to ::rnd_next(), - the data it stores is to a byte array. You can store this - data via my_store_ptr(). ref_length is a variable defined to the - class that is the sizeof() of position being stored. In our case - its just a position. Look at the bdb code if you want to see a case - where something other then a number is stored. -*/ -void ha_tina::position(const byte *record) -{ - DBUG_ENTER("ha_tina::position"); - my_store_ptr(ref, ref_length, current_position); - DBUG_VOID_RETURN; -} - - -/* - Used to fetch a row from a posiion stored with ::position(). - my_get_ptr() retrieves the data for you. -*/ - -int ha_tina::rnd_pos(byte * buf, byte *pos) -{ - DBUG_ENTER("ha_tina::rnd_pos"); - statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, - &LOCK_status); - current_position= my_get_ptr(pos,ref_length); - DBUG_RETURN(find_current_row(buf)); -} - -/* - ::info() is used to return information to the optimizer. - Currently this table handler doesn't implement most of the fields - really needed. SHOW also makes use of this data -*/ -void ha_tina::info(uint flag) -{ - DBUG_ENTER("ha_tina::info"); - /* This is a lie, but you don't want the optimizer to see zero or 1 */ - if (!records_is_known && records < 2) - records= 2; - DBUG_VOID_RETURN; -} - -/* - Grab bag of flags that are sent to the able handler every so often. - HA_EXTRA_RESET and HA_EXTRA_RESET_STATE are the most frequently called. - You are not required to implement any of these. -*/ -int ha_tina::extra(enum ha_extra_function operation) -{ - DBUG_ENTER("ha_tina::extra"); - DBUG_RETURN(0); -} - -/* - This is no longer used. -*/ -int ha_tina::reset(void) -{ - DBUG_ENTER("ha_tina::reset"); - ha_tina::extra(HA_EXTRA_RESET); - DBUG_RETURN(0); -} - - -/* - Called after each table scan. In particular after deletes, - and updates. In the last case we employ chain of deleted - slots to clean up all of the dead space we have collected while - performing deletes/updates. -*/ -int ha_tina::rnd_end() -{ - DBUG_ENTER("ha_tina::rnd_end"); - - records_is_known= 1; - - /* First position will be truncate position, second will be increment */ - if ((chain_ptr - chain) > 0) - { - tina_set *ptr; - off_t length; - - /* - Setting up writable map, this will contain all of the data after the - get_mmap call that we have added to the file. - */ - if (get_mmap(share, 1) > 0) - DBUG_RETURN(-1); - length= share->file_stat.st_size; - - /* - The sort handles updates/deletes with random orders. - It also sorts so that we move the final blocks to the - beginning so that we move the smallest amount of data possible. - */ - qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), - (qsort_cmp)sort_set); - for (ptr= chain; ptr < chain_ptr; ptr++) - { - memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end, - length - (size_t)ptr->end); - length= length - (size_t)(ptr->end - ptr->begin); - } - - /* Truncate the file to the new size */ - if (my_chsize(share->data_file, length, 0, MYF(MY_WME))) - DBUG_RETURN(-1); - - if (my_munmap(share->mapped_file, length)) - DBUG_RETURN(-1); - - /* We set it to null so that get_mmap() won't try to unmap it */ - share->mapped_file= NULL; - if (get_mmap(share, 0) > 0) - DBUG_RETURN(-1); - } - - DBUG_RETURN(0); -} - - -/* - DELETE without WHERE calls this -*/ - -int ha_tina::delete_all_rows() -{ - DBUG_ENTER("ha_tina::delete_all_rows"); - - if (!records_is_known) - return (my_errno=HA_ERR_WRONG_COMMAND); - - int rc= my_chsize(share->data_file, 0, 0, MYF(MY_WME)); - - if (get_mmap(share, 0) > 0) - DBUG_RETURN(-1); - - records=0; - DBUG_RETURN(rc); -} - -/* - Always called by the start of a transaction (or by "lock tables"); -*/ -int ha_tina::external_lock(THD *thd, int lock_type) -{ - DBUG_ENTER("ha_tina::external_lock"); - DBUG_RETURN(0); // No external locking -} - -/* - Called by the database to lock the table. Keep in mind that this - is an internal lock. -*/ -THR_LOCK_DATA **ha_tina::store_lock(THD *thd, - THR_LOCK_DATA **to, - enum thr_lock_type lock_type) -{ - if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) - lock.type=lock_type; - *to++= &lock; - return to; -} - -/* - Create a table. You do not want to leave the table open after a call to - this (the database will call ::open() if it needs to). -*/ - -int ha_tina::create(const char *name, TABLE *table_arg, - HA_CREATE_INFO *create_info) -{ - char name_buff[FN_REFLEN]; - File create_file; - DBUG_ENTER("ha_tina::create"); - - if ((create_file= my_create(fn_format(name_buff, name, "", ".CSV", - MY_REPLACE_EXT|MY_UNPACK_FILENAME),0, - O_RDWR | O_TRUNC,MYF(MY_WME))) < 0) - DBUG_RETURN(-1); - - my_close(create_file,MYF(0)); - - DBUG_RETURN(0); -} - diff --git a/sql/examples/ha_tina.h b/sql/examples/ha_tina.h deleted file mode 100644 index c46750fb703..00000000000 --- a/sql/examples/ha_tina.h +++ /dev/null @@ -1,130 +0,0 @@ -/* Copyright (C) 2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <my_dir.h> - -#define DEFAULT_CHAIN_LENGTH 512 - -typedef struct st_tina_share { - char *table_name; - byte *mapped_file; /* mapped region of file */ - uint table_name_length,use_count; - MY_STAT file_stat; /* Stat information for the data file */ - File data_file; /* Current open data file */ - pthread_mutex_t mutex; - THR_LOCK lock; -} TINA_SHARE; - -typedef struct tina_set { - off_t begin; - off_t end; -}; - -class ha_tina: public handler -{ - THR_LOCK_DATA lock; /* MySQL lock */ - TINA_SHARE *share; /* Shared lock info */ - off_t current_position; /* Current position in the file during a file scan */ - off_t next_position; /* Next position in the file scan */ - byte byte_buffer[IO_SIZE]; - String buffer; - /* - The chain contains "holes" in the file, occured because of - deletes/updates. It is used in rnd_end() to get rid of them - in the end of the query. - */ - tina_set chain_buffer[DEFAULT_CHAIN_LENGTH]; - tina_set *chain; - tina_set *chain_ptr; - byte chain_alloced; - uint32 chain_size; - bool records_is_known; - -public: - ha_tina(TABLE_SHARE *table_arg); - ~ha_tina() - { - if (chain_alloced) - my_free((gptr)chain,0); - } - const char *table_type() const { return "CSV"; } - const char *index_type(uint inx) { return "NONE"; } - const char **bas_ext() const; - ulong table_flags() const - { - return (HA_REC_NOT_IN_SEQ | HA_NOT_EXACT_COUNT | - HA_NO_AUTO_INCREMENT ); - } - ulong index_flags(uint idx, uint part, bool all_parts) const - { - /* We will never have indexes so this will never be called(AKA we return zero) */ - return 0; - } - uint max_record_length() const { return HA_MAX_REC_LENGTH; } - uint max_keys() const { return 0; } - uint max_key_parts() const { return 0; } - uint max_key_length() const { return 0; } - /* - Called in test_quick_select to determine if indexes should be used. - */ - virtual double scan_time() { return (double) (records+deleted) / 20.0+10; } - /* The next method will never be called */ - virtual bool fast_key_read() { return 1;} - /* - TODO: return actual upper bound of number of records in the table. - (e.g. save number of records seen on full table scan and/or use file size - as upper bound) - */ - ha_rows estimate_rows_upper_bound() { return HA_POS_ERROR; } - - int open(const char *name, int mode, uint test_if_locked); - int close(void); - int write_row(byte * buf); - int update_row(const byte * old_data, byte * new_data); - int delete_row(const byte * buf); - int index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - int index_read_idx(byte * buf, uint idx, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - int index_next(byte * buf); - int index_prev(byte * buf); - int index_first(byte * buf); - int index_last(byte * buf); - int rnd_init(bool scan=1); - int rnd_next(byte *buf); - int rnd_pos(byte * buf, byte *pos); - int rnd_end(); - void position(const byte *record); - void info(uint); - int extra(enum ha_extra_function operation); - int reset(void); - int external_lock(THD *thd, int lock_type); - int delete_all_rows(void); - int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); - - THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, - enum thr_lock_type lock_type); - - /* The following methods were added just for TINA */ - int encode_quote(byte *buf); - int find_current_row(byte *buf); - int chain_append(); -}; - -int tina_end(ha_panic_function type); - |