mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
followup to handler cleanup
mysql-test/r/bdb.result: bug#4000 mysql-test/t/bdb.test: bug#4000 sql/sql_select.cc: cleanup
This commit is contained in:
@ -1181,3 +1181,12 @@ a
|
|||||||
A
|
A
|
||||||
a
|
a
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
set autocommit=0;
|
||||||
|
create table t1(b varchar(30)) engine=bdb;
|
||||||
|
insert into t1 values ('one');
|
||||||
|
commit;
|
||||||
|
select b FROM t1 outer_table where
|
||||||
|
exists (select 'two' from t1 where 'two' = outer_table.b);
|
||||||
|
b
|
||||||
|
drop table t1;
|
||||||
|
set autocommit=1;
|
||||||
|
@ -822,3 +822,28 @@ alter table t1 modify a char(10) binary;
|
|||||||
explain select a from t1;
|
explain select a from t1;
|
||||||
select a from t1;
|
select a from t1;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug #4000: problem with active cursor.
|
||||||
|
#
|
||||||
|
|
||||||
|
set autocommit=0;
|
||||||
|
create table t1(b varchar(30)) engine=bdb;
|
||||||
|
insert into t1 values ('one');
|
||||||
|
commit;
|
||||||
|
select b FROM t1 outer_table where
|
||||||
|
exists (select 'two' from t1 where 'two' = outer_table.b);
|
||||||
|
drop table t1;
|
||||||
|
set autocommit=1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug #4089: subselect and open cursor.
|
||||||
|
#
|
||||||
|
|
||||||
|
#create table t1(a int primary key, b varchar(30)) engine=bdb;
|
||||||
|
#insert into t1 values (1,'one'), (2,'two'), (3,'three'), (4,'four');
|
||||||
|
#create table t2 like t1;
|
||||||
|
#insert into t2 (a, b)
|
||||||
|
# select a, b from t1 where (a, b) in (select a, b from t1);
|
||||||
|
#select * from t2;
|
||||||
|
#drop table t1, t2;
|
||||||
|
@ -481,13 +481,13 @@ int ha_archive::update_row(const byte * old_data, byte * new_data)
|
|||||||
{
|
{
|
||||||
|
|
||||||
DBUG_ENTER("ha_archive::update_row");
|
DBUG_ENTER("ha_archive::update_row");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ha_archive::delete_row(const byte * buf)
|
int ha_archive::delete_row(const byte * buf)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_archive::delete_row");
|
DBUG_ENTER("ha_archive::delete_row");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ha_archive::index_read(byte * buf, const byte * key,
|
int ha_archive::index_read(byte * buf, const byte * key,
|
||||||
@ -496,7 +496,7 @@ int ha_archive::index_read(byte * buf, const byte * key,
|
|||||||
__attribute__((unused)))
|
__attribute__((unused)))
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_archive::index_read");
|
DBUG_ENTER("ha_archive::index_read");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ha_archive::index_read_idx(byte * buf, uint index, const byte * key,
|
int ha_archive::index_read_idx(byte * buf, uint index, const byte * key,
|
||||||
@ -505,32 +505,32 @@ int ha_archive::index_read_idx(byte * buf, uint index, const byte * key,
|
|||||||
__attribute__((unused)))
|
__attribute__((unused)))
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_archive::index_read_idx");
|
DBUG_ENTER("ha_archive::index_read_idx");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ha_archive::index_next(byte * buf)
|
int ha_archive::index_next(byte * buf)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_archive::index_next");
|
DBUG_ENTER("ha_archive::index_next");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ha_archive::index_prev(byte * buf)
|
int ha_archive::index_prev(byte * buf)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_archive::index_prev");
|
DBUG_ENTER("ha_archive::index_prev");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ha_archive::index_first(byte * buf)
|
int ha_archive::index_first(byte * buf)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_archive::index_first");
|
DBUG_ENTER("ha_archive::index_first");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ha_archive::index_last(byte * buf)
|
int ha_archive::index_last(byte * buf)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_archive::index_last");
|
DBUG_ENTER("ha_archive::index_last");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -581,6 +581,6 @@ ha_rows ha_archive::records_in_range(int inx,
|
|||||||
enum ha_rkey_function end_search_flag)
|
enum ha_rkey_function end_search_flag)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_archive::records_in_range ");
|
DBUG_ENTER("ha_archive::records_in_range ");
|
||||||
DBUG_RETURN(records); // HA_ERR_NOT_IMPLEMENTED
|
DBUG_RETURN(records); // HA_ERR_WRONG_COMMAND
|
||||||
}
|
}
|
||||||
#endif /* HAVE_ARCHIVE_DB */
|
#endif /* HAVE_ARCHIVE_DB */
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Please read ha_archive.cc first. If you are looking for more general
|
Please read ha_archive.cc first. If you are looking for more general
|
||||||
answers on how storage engines work, look at ha_example.cc and
|
answers on how storage engines work, look at ha_example.cc and
|
||||||
ha_example.h.
|
ha_example.h.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ typedef struct st_archive_share {
|
|||||||
bool dirty; /* Flag for if a flush should occur */
|
bool dirty; /* Flag for if a flush should occur */
|
||||||
} ARCHIVE_SHARE;
|
} ARCHIVE_SHARE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Version for file format.
|
Version for file format.
|
||||||
1 - Initial Version
|
1 - Initial Version
|
||||||
*/
|
*/
|
||||||
@ -61,7 +61,7 @@ public:
|
|||||||
/* The size of the offset value we will use for position() */
|
/* The size of the offset value we will use for position() */
|
||||||
ref_length = sizeof(z_off_t);
|
ref_length = sizeof(z_off_t);
|
||||||
}
|
}
|
||||||
~ha_archive()
|
~ha_archive()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
const char *table_type() const { return "ARCHIVE"; }
|
const char *table_type() const { return "ARCHIVE"; }
|
||||||
@ -69,21 +69,18 @@ public:
|
|||||||
const char **bas_ext() const;
|
const char **bas_ext() const;
|
||||||
ulong table_flags() const
|
ulong table_flags() const
|
||||||
{
|
{
|
||||||
return (HA_REC_NOT_IN_SEQ | HA_NOT_EXACT_COUNT | HA_NO_WRITE_DELAYED |
|
return (HA_REC_NOT_IN_SEQ | HA_NOT_EXACT_COUNT | HA_NO_AUTO_INCREMENT |
|
||||||
HA_NO_AUTO_INCREMENT);
|
HA_FILE_BASED);
|
||||||
}
|
}
|
||||||
ulong index_flags(uint inx) const
|
ulong index_flags(uint idx, uint part) const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
This is just a default, there is no real limit as far as
|
Have to put something here, there is no real limit as far as
|
||||||
archive is concerned.
|
archive is concerned.
|
||||||
*/
|
*/
|
||||||
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
|
uint max_supported_record_length() const { return UINT_MAX; }
|
||||||
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.
|
Called in test_quick_select to determine if indexes should be used.
|
||||||
*/
|
*/
|
||||||
|
@ -14,24 +14,24 @@
|
|||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
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
|
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
|
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:
|
in your buld by doing the following during your build process:
|
||||||
./configure --with-example-storage-engine
|
./configure --with-example-storage-engine
|
||||||
|
|
||||||
Once this is done mysql will let you create tables with:
|
Once this is done mysql will let you create tables with:
|
||||||
CREATE TABLE A (...) ENGINE=EXAMPLE;
|
CREATE TABLE A (...) ENGINE=EXAMPLE;
|
||||||
|
|
||||||
The example is setup to use table locks. It implements an example "SHARE"
|
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
|
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
|
information of state that any example handler object will be able to see
|
||||||
if it is using the same table.
|
if it is using the same table.
|
||||||
|
|
||||||
Please read the object definition in ha_example.h before reading the rest
|
Please read the object definition in ha_example.h before reading the rest
|
||||||
if this file.
|
if this file.
|
||||||
|
|
||||||
To get an idea of what occurs here is an example select that would do a
|
To get an idea of what occurs here is an example select that would do a
|
||||||
scan of an entire table:
|
scan of an entire table:
|
||||||
ha_example::store_lock
|
ha_example::store_lock
|
||||||
ha_example::external_lock
|
ha_example::external_lock
|
||||||
@ -50,13 +50,13 @@
|
|||||||
ha_example::rnd_next
|
ha_example::rnd_next
|
||||||
ha_example::extra
|
ha_example::extra
|
||||||
ENUM HA_EXTRA_NO_CACHE End cacheing of records (def)
|
ENUM HA_EXTRA_NO_CACHE End cacheing of records (def)
|
||||||
ha_example::external_lock
|
ha_example::external_lock
|
||||||
ha_example::extra
|
ha_example::extra
|
||||||
ENUM HA_EXTRA_RESET Reset database to after open
|
ENUM HA_EXTRA_RESET Reset database to after open
|
||||||
|
|
||||||
In the above example has 9 row called before rnd_next signalled that it was
|
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
|
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
|
(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.
|
ha_example::extra() are hints as to what will be occuring to the request.
|
||||||
|
|
||||||
Happy coding!
|
Happy coding!
|
||||||
@ -92,7 +92,7 @@ static byte* example_get_key(EXAMPLE_SHARE *share,uint *length,
|
|||||||
/*
|
/*
|
||||||
Example of simple lock controls. The "share" it creates is structure we will
|
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
|
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.
|
pieces that are used for locking, and they are needed to function.
|
||||||
*/
|
*/
|
||||||
static EXAMPLE_SHARE *get_share(const char *table_name, TABLE *table)
|
static EXAMPLE_SHARE *get_share(const char *table_name, TABLE *table)
|
||||||
{
|
{
|
||||||
@ -130,7 +130,7 @@ static EXAMPLE_SHARE *get_share(const char *table_name, TABLE *table)
|
|||||||
my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
|
my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
|
||||||
&share, sizeof(*share),
|
&share, sizeof(*share),
|
||||||
&tmp_name, length+1,
|
&tmp_name, length+1,
|
||||||
NullS)))
|
NullS)))
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(&example_mutex);
|
pthread_mutex_unlock(&example_mutex);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -161,7 +161,7 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Free lock controls. We call this whenever we close a table. If the table had
|
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.
|
the last reference to the share then we free memory associated with it.
|
||||||
*/
|
*/
|
||||||
@ -182,7 +182,7 @@ static int free_share(EXAMPLE_SHARE *share)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If frm_error() is called then we will use this to to find out what file extentions
|
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
|
exist for the storage engine. This is also used by the default rename_table and
|
||||||
delete_table method in handler.cc.
|
delete_table method in handler.cc.
|
||||||
*/
|
*/
|
||||||
@ -190,10 +190,10 @@ const char **ha_example::bas_ext() const
|
|||||||
{ static const char *ext[]= { NullS }; return ext; }
|
{ static const char *ext[]= { NullS }; return ext; }
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Used for opening tables. The name will be the name of the file.
|
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
|
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
|
when a request comes in for a select on the table (tables are not
|
||||||
open and closed for each request, they are cached).
|
open and closed for each request, they are cached).
|
||||||
|
|
||||||
Called from handler.cc by handler::ha_open(). The server opens all tables by
|
Called from handler.cc by handler::ha_open(). The server opens all tables by
|
||||||
@ -212,12 +212,12 @@ int ha_example::open(const char *name, int mode, uint test_if_locked)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Closes a table. We call the free_share() function to free any resources
|
Closes a table. We call the free_share() function to free any resources
|
||||||
that we have allocated in the "shared" structure.
|
that we have allocated in the "shared" structure.
|
||||||
|
|
||||||
Called from sql_base.cc, sql_select.cc, and table.cc.
|
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
|
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
|
the process where a temporary table is converted over to being a
|
||||||
myisam table.
|
myisam table.
|
||||||
For sql_base.cc look at close_data_tables().
|
For sql_base.cc look at close_data_tables().
|
||||||
*/
|
*/
|
||||||
@ -230,7 +230,7 @@ int ha_example::close(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
write_row() inserts a row. No extra() hint is given currently if a bulk load
|
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
|
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.
|
information to extract the data from the native byte array type.
|
||||||
Example of this would be:
|
Example of this would be:
|
||||||
for (Field **field=table->field ; *field ; field++)
|
for (Field **field=table->field ; *field ; field++)
|
||||||
@ -238,20 +238,20 @@ int ha_example::close(void)
|
|||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
See ha_tina.cc for an example of extracting all of the data as strings.
|
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
|
ha_berekly.cc has an example of how to store it intact by "packing" it
|
||||||
for ha_berkeley's own native storage type.
|
for ha_berkeley's own native storage type.
|
||||||
|
|
||||||
See the note for update_row() on auto_increments and timestamps. This
|
See the note for update_row() on auto_increments and timestamps. This
|
||||||
case also applied to write_row().
|
case also applied to write_row().
|
||||||
|
|
||||||
Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
|
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.
|
sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
|
||||||
*/
|
*/
|
||||||
int ha_example::write_row(byte * buf)
|
int ha_example::write_row(byte * buf)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::write_row");
|
DBUG_ENTER("ha_example::write_row");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ int ha_example::update_row(const byte * old_data, byte * new_data)
|
|||||||
{
|
{
|
||||||
|
|
||||||
DBUG_ENTER("ha_example::update_row");
|
DBUG_ENTER("ha_example::update_row");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -282,8 +282,8 @@ int ha_example::update_row(const byte * old_data, byte * new_data)
|
|||||||
This will delete a row. buf will contain a copy of the row to be deleted.
|
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
|
The server will call this right after the current row has been called (from
|
||||||
either a previous rnd_nexT() or index call).
|
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
|
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.
|
make doing the deletion quite a bit easier.
|
||||||
Keep in mind that the server does no guarentee consecutive deletions. ORDER BY
|
Keep in mind that the server does no guarentee consecutive deletions. ORDER BY
|
||||||
clauses can be used.
|
clauses can be used.
|
||||||
|
|
||||||
@ -294,7 +294,7 @@ int ha_example::update_row(const byte * old_data, byte * new_data)
|
|||||||
int ha_example::delete_row(const byte * buf)
|
int ha_example::delete_row(const byte * buf)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::delete_row");
|
DBUG_ENTER("ha_example::delete_row");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -309,7 +309,7 @@ int ha_example::index_read(byte * buf, const byte * key,
|
|||||||
__attribute__((unused)))
|
__attribute__((unused)))
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::index_read");
|
DBUG_ENTER("ha_example::index_read");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -323,7 +323,7 @@ int ha_example::index_read_idx(byte * buf, uint index, const byte * key,
|
|||||||
__attribute__((unused)))
|
__attribute__((unused)))
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::index_read_idx");
|
DBUG_ENTER("ha_example::index_read_idx");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -333,7 +333,7 @@ int ha_example::index_read_idx(byte * buf, uint index, const byte * key,
|
|||||||
int ha_example::index_next(byte * buf)
|
int ha_example::index_next(byte * buf)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::index_next");
|
DBUG_ENTER("ha_example::index_next");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -343,40 +343,40 @@ int ha_example::index_next(byte * buf)
|
|||||||
int ha_example::index_prev(byte * buf)
|
int ha_example::index_prev(byte * buf)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::index_prev");
|
DBUG_ENTER("ha_example::index_prev");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
index_first() asks for the first key in the index.
|
index_first() asks for the first key in the index.
|
||||||
|
|
||||||
Called from opt_range.cc, opt_sum.cc, sql_handler.cc,
|
Called from opt_range.cc, opt_sum.cc, sql_handler.cc,
|
||||||
and sql_select.cc.
|
and sql_select.cc.
|
||||||
*/
|
*/
|
||||||
int ha_example::index_first(byte * buf)
|
int ha_example::index_first(byte * buf)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::index_first");
|
DBUG_ENTER("ha_example::index_first");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
index_last() asks for the last key in the index.
|
index_last() asks for the last key in the index.
|
||||||
|
|
||||||
Called from opt_range.cc, opt_sum.cc, sql_handler.cc,
|
Called from opt_range.cc, opt_sum.cc, sql_handler.cc,
|
||||||
and sql_select.cc.
|
and sql_select.cc.
|
||||||
*/
|
*/
|
||||||
int ha_example::index_last(byte * buf)
|
int ha_example::index_last(byte * buf)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::index_last");
|
DBUG_ENTER("ha_example::index_last");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
rnd_init() is called when the system wants the storage engine to do a table
|
rnd_init() is called when the system wants the storage engine to do a table
|
||||||
scan.
|
scan.
|
||||||
See the example in the introduction at the top of this file to see when
|
See the example in the introduction at the top of this file to see when
|
||||||
rnd_init() is called.
|
rnd_init() is called.
|
||||||
|
|
||||||
Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
|
Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
|
||||||
@ -385,11 +385,16 @@ int ha_example::index_last(byte * buf)
|
|||||||
int ha_example::rnd_init(bool scan)
|
int ha_example::rnd_init(bool scan)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::rnd_init");
|
DBUG_ENTER("ha_example::rnd_init");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
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
|
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.
|
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
|
The Field structure for the table is the key to getting data into buf
|
||||||
@ -415,8 +420,8 @@ int ha_example::rnd_next(byte *buf)
|
|||||||
the size needed to store current_position. ref is just a byte array
|
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
|
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
|
current_position should be the offset. If it is a primary key like in
|
||||||
BDB, then it needs to be a primary key.
|
BDB, then it needs to be a primary key.
|
||||||
|
|
||||||
Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc.
|
Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc.
|
||||||
*/
|
*/
|
||||||
void ha_example::position(const byte *record)
|
void ha_example::position(const byte *record)
|
||||||
@ -436,7 +441,7 @@ void ha_example::position(const byte *record)
|
|||||||
int ha_example::rnd_pos(byte * buf, byte *pos)
|
int ha_example::rnd_pos(byte * buf, byte *pos)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::rnd_pos");
|
DBUG_ENTER("ha_example::rnd_pos");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -449,9 +454,9 @@ int ha_example::rnd_pos(byte * buf, byte *pos)
|
|||||||
if (records < 2)
|
if (records < 2)
|
||||||
records = 2;
|
records = 2;
|
||||||
The reason is that the server will optimize for cases of only a single
|
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
|
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
|
it will probably be better to set records to two so you can return
|
||||||
as many records as you need.
|
as many records as you need.
|
||||||
Along with records a few more variables you may wish to set are:
|
Along with records a few more variables you may wish to set are:
|
||||||
records
|
records
|
||||||
deleted
|
deleted
|
||||||
@ -518,9 +523,9 @@ int ha_example::reset(void)
|
|||||||
/*
|
/*
|
||||||
Used to delete all rows in a table. Both for cases of truncate and
|
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
|
for cases where the optimizer realizes that all rows will be
|
||||||
removed as a result of a SQL statement.
|
removed as a result of a SQL statement.
|
||||||
|
|
||||||
Called from item_sum.cc by Item_func_group_concat::clear(),
|
Called from item_sum.cc by Item_func_group_concat::clear(),
|
||||||
Item_sum_count_distinct::clear(), and 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_delete.cc by mysql_delete().
|
||||||
Called from sql_select.cc by JOIN::reinit().
|
Called from sql_select.cc by JOIN::reinit().
|
||||||
@ -529,12 +534,12 @@ int ha_example::reset(void)
|
|||||||
int ha_example::delete_all_rows()
|
int ha_example::delete_all_rows()
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::delete_all_rows");
|
DBUG_ENTER("ha_example::delete_all_rows");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
First you should go read the section "locking functions for mysql" in
|
First you should go read the section "locking functions for mysql" in
|
||||||
lock.cc to understand this.
|
lock.cc to understand this.
|
||||||
This create a lock on the table. If you are implementing a storage engine
|
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
|
that can handle transacations look at ha_berkely.cc to see how you will
|
||||||
@ -564,7 +569,7 @@ int ha_example::external_lock(THD *thd, int lock_type)
|
|||||||
lock (if we don't want to use MySQL table locks at all) or add locks
|
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).
|
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
|
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
|
(which signals that we are doing WRITES, but we are still allowing other
|
||||||
reader's and writer's.
|
reader's and writer's.
|
||||||
|
|
||||||
@ -591,9 +596,9 @@ THR_LOCK_DATA **ha_example::store_lock(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Used to delete a table. By the time delete_table() has been called all
|
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
|
opened references to this table will have been closed (and your globally
|
||||||
shared references released. The variable name will just be the name of
|
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.
|
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
|
If you do not implement this, the default delete_table() is called from
|
||||||
@ -623,10 +628,10 @@ int ha_example::delete_table(const char *name)
|
|||||||
int ha_example::rename_table(const char * from, const char * to)
|
int ha_example::rename_table(const char * from, const char * to)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::rename_table ");
|
DBUG_ENTER("ha_example::rename_table ");
|
||||||
DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Given a starting key, and an ending key estimate the number of rows that
|
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
|
will exist between the two. end_key may be empty which in case determine
|
||||||
if start_key matches any rows.
|
if start_key matches any rows.
|
||||||
@ -644,14 +649,14 @@ ha_rows ha_example::records_in_range(uint inx, key_range *min_key,
|
|||||||
/*
|
/*
|
||||||
create() is called to create a database. The variable name will have the name
|
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
|
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
|
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
|
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
|
point if you wish to change the table definition, but there are no methods
|
||||||
currently provided for doing that.
|
currently provided for doing that.
|
||||||
|
|
||||||
Called from handle.cc by ha_create_table().
|
Called from handle.cc by ha_create_table().
|
||||||
*/
|
*/
|
||||||
int ha_example::create(const char *name, TABLE *table_arg,
|
int ha_example::create(const char *name, TABLE *table_arg,
|
||||||
HA_CREATE_INFO *create_info)
|
HA_CREATE_INFO *create_info)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_example::create");
|
DBUG_ENTER("ha_example::create");
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Please read ha_exmple.cc before reading this file.
|
Please read ha_exmple.cc before reading this file.
|
||||||
Please keep in mind that the example storage engine implements all methods
|
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 are required to be implemented. handler.h has a full list of methods
|
||||||
@ -48,55 +48,68 @@ public:
|
|||||||
ha_example(TABLE *table): handler(table)
|
ha_example(TABLE *table): handler(table)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
~ha_example()
|
~ha_example()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
/* The name that will be used for display purposes */
|
/* The name that will be used for display purposes */
|
||||||
const char *table_type() const { return "EXAMPLE"; }
|
const char *table_type() const { return "EXAMPLE"; }
|
||||||
/* The name of the index type that will be used for display */
|
/*
|
||||||
const char *index_type(uint inx) { return "NONE"; }
|
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;
|
const char **bas_ext() const;
|
||||||
/*
|
/*
|
||||||
This is a list of flags that says what the storage engine
|
This is a list of flags that says what the storage engine
|
||||||
implements. The current table flags are documented in
|
implements. The current table flags are documented in
|
||||||
table_flags.
|
handler.h
|
||||||
*/
|
*/
|
||||||
ulong table_flags() const
|
ulong table_flags() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
This is a list of flags that says how the storage engine
|
This is a list of flags that says how the storage engine
|
||||||
implements indexes. The current index flags are documented in
|
implements indexes. The current index flags are documented in
|
||||||
handler.h. If you do not implement indexes, just return zero
|
handler.h. If you do not implement indexes, just return zero
|
||||||
here.
|
here.
|
||||||
*/
|
*/
|
||||||
ulong index_flags(uint inx) const
|
ulong index_flags(uint inx, uint part) const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
unireg.cc will call the following to make sure that the storage engine can
|
unireg.cc will call the following to make sure that the storage engine can
|
||||||
handle the data it is about to send.
|
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_record_length() const { return HA_MAX_REC_LENGTH; }
|
uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; }
|
||||||
uint max_keys() const { return 0; }
|
uint max_supported_keys() const { return 0; }
|
||||||
uint max_key_parts() const { return 0; }
|
uint max_supported_key_parts() const { return 0; }
|
||||||
uint max_key_length() const { return 0; }
|
uint max_supported_key_length() const { return 0; }
|
||||||
/*
|
/*
|
||||||
Called in test_quick_select to determine if indexes should be used.
|
Called in test_quick_select to determine if indexes should be used.
|
||||||
*/
|
*/
|
||||||
virtual double scan_time() { return (double) (records+deleted) / 20.0+10; }
|
virtual double scan_time() { return (double) (records+deleted) / 20.0+10; }
|
||||||
/*
|
/*
|
||||||
The next method will never be called if you do not implement indexes.
|
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; }
|
virtual double read_time(ha_rows rows) { return (double) rows / 20.0+1; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Everything below are methods that we implment in ha_example.cc.
|
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);
|
int open(const char *name, int mode, uint test_if_locked); // required
|
||||||
int close(void);
|
int close(void); // required
|
||||||
|
|
||||||
int write_row(byte * buf);
|
int write_row(byte * buf);
|
||||||
int update_row(const byte * old_data, byte * new_data);
|
int update_row(const byte * old_data, byte * new_data);
|
||||||
int delete_row(const byte * buf);
|
int delete_row(const byte * buf);
|
||||||
@ -108,21 +121,32 @@ public:
|
|||||||
int index_prev(byte * buf);
|
int index_prev(byte * buf);
|
||||||
int index_first(byte * buf);
|
int index_first(byte * buf);
|
||||||
int index_last(byte * buf);
|
int index_last(byte * buf);
|
||||||
int rnd_init(bool scan=1);
|
/*
|
||||||
int rnd_next(byte *buf);
|
unlike index_init(), rnd_init() can be called two times
|
||||||
int rnd_pos(byte * buf, byte *pos);
|
without rnd_end() in between (it only makes sense if scan=1).
|
||||||
void position(const byte *record);
|
then the second call should prepare for the new table scan
|
||||||
void info(uint);
|
(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 extra(enum ha_extra_function operation);
|
||||||
int reset(void);
|
int reset(void);
|
||||||
int external_lock(THD *thd, int lock_type);
|
int external_lock(THD *thd, int lock_type); //required
|
||||||
int delete_all_rows(void);
|
int delete_all_rows(void);
|
||||||
ha_rows records_in_range(uint inx, key_range *min_key,
|
ha_rows records_in_range(uint inx, key_range *min_key,
|
||||||
key_range *max_key);
|
key_range *max_key);
|
||||||
int delete_table(const char *from);
|
int delete_table(const char *from);
|
||||||
int rename_table(const char * from, const char * to);
|
int rename_table(const char * from, const char * to);
|
||||||
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
|
int create(const char *name, TABLE *form,
|
||||||
|
HA_CREATE_INFO *create_info); //required
|
||||||
|
|
||||||
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
||||||
enum thr_lock_type lock_type);
|
enum thr_lock_type lock_type); //required
|
||||||
};
|
};
|
||||||
|
@ -1583,7 +1583,7 @@ int ha_berkeley::index_last(byte * buf)
|
|||||||
int ha_berkeley::rnd_init(bool scan)
|
int ha_berkeley::rnd_init(bool scan)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("rnd_init");
|
DBUG_ENTER("rnd_init");
|
||||||
DBUG_ASSERT(active_index==MAX_KEY);
|
//DBUG_ASSERT(active_index==MAX_KEY);
|
||||||
current_row.flags=DB_DBT_REALLOC;
|
current_row.flags=DB_DBT_REALLOC;
|
||||||
DBUG_RETURN(index_init(primary_key));
|
DBUG_RETURN(index_init(primary_key));
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ class ha_berkeley: public handler
|
|||||||
public:
|
public:
|
||||||
ha_berkeley(TABLE *table): handler(table), alloc_ptr(0),rec_buff(0), file(0),
|
ha_berkeley(TABLE *table): handler(table), alloc_ptr(0),rec_buff(0), file(0),
|
||||||
int_table_flags(HA_REC_NOT_IN_SEQ | HA_FAST_KEY_READ |
|
int_table_flags(HA_REC_NOT_IN_SEQ | HA_FAST_KEY_READ |
|
||||||
HA_NULL_IN_KEY | HA_BLOB_KEY | HA_NOT_EXACT_COUNT |
|
HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_NOT_EXACT_COUNT |
|
||||||
HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED |
|
HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED |
|
||||||
HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX),
|
HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX),
|
||||||
changed_rows(0),last_dup_key((uint) -1),version(0),using_ignore(0) {}
|
changed_rows(0),last_dup_key((uint) -1),version(0),using_ignore(0) {}
|
||||||
|
@ -3872,12 +3872,8 @@ JOIN::join_free(bool full)
|
|||||||
{
|
{
|
||||||
for (tab= join_tab, end= tab+tables; tab != end; tab++)
|
for (tab= join_tab, end= tab+tables; tab != end; tab++)
|
||||||
{
|
{
|
||||||
if (tab->table)
|
if (tab->table && tab->table->file->inited == handler::RND)
|
||||||
{
|
|
||||||
/* Don't free index if we are using read_record */
|
|
||||||
if (tab->table->file->inited==handler::RND)
|
|
||||||
tab->table->file->ha_rnd_end();
|
tab->table->file->ha_rnd_end();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user