Commit 42297969 authored by monty@donna.mysql.com's avatar monty@donna.mysql.com

Automatic primary key for BDB tables

parent 9323e733
monty@tik.mysql.com monty@donna.mysql.com
...@@ -1793,16 +1793,20 @@ Big changes made in @strong{MySQL} Version 3.22.12. ...@@ -1793,16 +1793,20 @@ Big changes made in @strong{MySQL} Version 3.22.12.
@item @strong{MyODBC} (uses ODBC SDK 2.5) --- Gamma @item @strong{MyODBC} (uses ODBC SDK 2.5) --- Gamma
It seems to work well with some programs. It seems to work well with some programs.
@item Replication -- Alpha @item Replication -- Alpha / Beta
We are still working on replication, so don't expect this to be rock We are still working on replication, so don't expect this to be rock
solid yet. On the other hand, some @strong{MySQL} users are already solid yet. On the other hand, some @strong{MySQL} users are already
using this with good results. using this with good results.
@item BDB Tables -- Alpha @item BDB Tables -- Alpha / Beta
The Berkeley DB code is very stable, but we are still improving the interface The Berkeley DB code is very stable, but we are still improving the interface
between @strong{MySQL} and BDB tables, so it will take some time before this between @strong{MySQL} and BDB tables, so it will take some time before this
is as tested as the other table types. is as tested as the other table types.
@item Automatic recovery of MyISAM tables - Alpha.
This only affects the new code that checks if the table was closed properly
on open and executes an automatic check/repair of the table if it wasn't.
@end table @end table
MySQL AB provides e-mail support for paying customers, but the @strong{MySQL} MySQL AB provides e-mail support for paying customers, but the @strong{MySQL}
...@@ -7979,12 +7983,10 @@ you should also compile your code to be multi-threaded! ...@@ -7979,12 +7983,10 @@ you should also compile your code to be multi-threaded!
@node Windows and BDB tables., Windows vs Unix, Windows compiling, Windows @node Windows and BDB tables., Windows vs Unix, Windows compiling, Windows
@subsection Windows and BDB Tables @subsection Windows and BDB Tables
We are working on removing the requirement that one must have a primary We will shortly do a full test on the new BDB interface on Windows.
key in a BDB table. As soon as this is fixed we will throughly test the When this is done we will start to release binary distributions (for
BDB interface by running the @strong{MySQL} benchmark and our internal Windows and UNIX) of @strong{MySQL} that will include support for BDB
test suite on it. When the above is done we will start to release binary tables.
distributions (for Windows and UNIX) of @strong{MySQL} that will include
support for BDB tables.
@cindex Windows, versus UNIX @cindex Windows, versus UNIX
@cindex operating systems, Windows versus UNIX @cindex operating systems, Windows versus UNIX
...@@ -21876,13 +21878,22 @@ Some characteristic of @code{BDB} tables: ...@@ -21876,13 +21878,22 @@ Some characteristic of @code{BDB} tables:
@itemize @bullet @itemize @bullet
@item @item
All @code{BDB} tables must have a primary key. @strong{MySQL} requires a @code{PRIMARY KEY} in each BDB table to be
able to refer to previously read rows; If you don't create on,
@strong{MySQL} will create an maintain a hidden @code{PRIMARY KEY} for
you. The hidden key has a length of 5 bytes and is incremented for each
insert attempt.
@item @item
If all columns you access in a @code{BDB} tables is part of the same index or If all columns you access in a @code{BDB} tables is part of the same index or
part of the the primary key then @strong{MySQL} can execute the query part of the the primary key then @strong{MySQL} can execute the query
without having to access the actual row. In a @code{MyISAM} table the without having to access the actual row. In a @code{MyISAM} table the
above holds only if the columns are part of the same index. above holds only if the columns are part of the same index.
@item @item
The @code{PRIMARY KEY} will be faster than any other key, as the
@code{PRIMARY KEY} is stored together with the row data. As the other keys are
stored as the key data + the @code{PRIMARY KEY}, its important to keep the
@code{PRIMARY KEY} as short as possible to save disk and get better speed.
@item
@code{LOCK TABLES} works on @code{BDB} tables as with other tables. If @code{LOCK TABLES} works on @code{BDB} tables as with other tables. If
you don't use @code{LOCK TABLE}, @strong{MYSQL} will issue an internal you don't use @code{LOCK TABLE}, @strong{MYSQL} will issue an internal
multiple write lock on the table to ensure that the table will be multiple write lock on the table to ensure that the table will be
...@@ -37972,6 +37983,11 @@ though, so 3.23 is not released as a stable version yet. ...@@ -37972,6 +37983,11 @@ though, so 3.23 is not released as a stable version yet.
@appendixsubsec Changes in release 3.23.26 @appendixsubsec Changes in release 3.23.26
@itemize @bullet @itemize @bullet
@item @item
If one don't create a @code{PRIMARY KEY} in a BDB table, a hidden
@code{PRIMARY KEY} will be created.
@item
Added read-only-key optimization to BDB tables.
@item
@code{LEFT JOIN} did in some case prefer a full table scan when one @code{LEFT JOIN} did in some case prefer a full table scan when one
didn't have a @code{WHERE} clause. didn't have a @code{WHERE} clause.
@item @item
...@@ -44,7 +44,7 @@ public: ...@@ -44,7 +44,7 @@ public:
uint8 null_bit; // And position to it uint8 null_bit; // And position to it
struct st_table *table; // Pointer for table struct st_table *table; // Pointer for table
ulong query_id; // For quick test of used fields ulong query_id; // For quick test of used fields
key_map key_start,part_of_key; // Which keys a field is in key_map key_start,part_of_key; // Key is part of these keys.
const char *table_name,*field_name; const char *table_name,*field_name;
utype unireg_check; utype unireg_check;
uint32 field_length; // Length of field uint32 field_length; // Length of field
......
...@@ -331,7 +331,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, ...@@ -331,7 +331,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
if (! indexfile && ! quick_select) if (! indexfile && ! quick_select)
{ {
file->reset(); // QQ; Shouldn't be needed file->reset(); // QQ; Shouldn't be needed
if (table->keyread) // QQ Can be removed after the reset if (sort_form->key_read) // QQ Can be removed after the reset
file->extra(HA_EXTRA_KEYREAD); // QQ is removed file->extra(HA_EXTRA_KEYREAD); // QQ is removed
next_pos=(byte*) 0; /* Find records in sequence */ next_pos=(byte*) 0; /* Find records in sequence */
file->rnd_init(); file->rnd_init();
......
...@@ -21,13 +21,12 @@ ...@@ -21,13 +21,12 @@
- Don't automaticly pack all string keys (To do this we need to modify - Don't automaticly pack all string keys (To do this we need to modify
CREATE TABLE so that one can use the pack_keys argument per key). CREATE TABLE so that one can use the pack_keys argument per key).
- An argument to pack_key that we don't want compression. - An argument to pack_key that we don't want compression.
- Interaction with LOCK TABLES (Monty will fix this)
- DB_DBT_USERMEN should be used for fixed length tables - DB_DBT_USERMEN should be used for fixed length tables
We will need an updated Berkeley DB version for this. We will need an updated Berkeley DB version for this.
- Killing threads that has got a 'deadlock' - Killing threads that has got a 'deadlock'
- SHOW TABLE STATUS should give more information about the table. - SHOW TABLE STATUS should give more information about the table.
- Get a more accurate count of the number of rows. - Get a more accurate count of the number of rows.
- Introduce hidden primary keys for tables without a primary key We could store the found number of rows when the table is scanned.
- We will need a manager thread that calls flush_logs, removes old - We will need a manager thread that calls flush_logs, removes old
logs and makes checkpoints at given intervals. logs and makes checkpoints at given intervals.
- When not using UPDATE IGNORE, don't make a sub transaction but abort - When not using UPDATE IGNORE, don't make a sub transaction but abort
...@@ -203,6 +202,14 @@ const char **ha_berkeley::bas_ext() const ...@@ -203,6 +202,14 @@ const char **ha_berkeley::bas_ext() const
{ static const char *ext[]= { ha_berkeley_ext, NullS }; return ext; } { static const char *ext[]= { ha_berkeley_ext, NullS }; return ext; }
static int
berkeley_cmp_hidden_key(const DBT *new_key, const DBT *saved_key)
{
ulonglong a=uint5korr((char*) new_key->data);
ulonglong b=uint5korr((char*) saved_key->data);
return a < b ? -1 : (a > b ? 1 : 0);
}
static int static int
berkeley_cmp_packed_key(const DBT *new_key, const DBT *saved_key) berkeley_cmp_packed_key(const DBT *new_key, const DBT *saved_key)
{ {
...@@ -232,6 +239,8 @@ berkeley_cmp_packed_key(const DBT *new_key, const DBT *saved_key) ...@@ -232,6 +239,8 @@ berkeley_cmp_packed_key(const DBT *new_key, const DBT *saved_key)
} }
/* The following is not yet used; Should be used for fixed length keys */
static int static int
berkeley_cmp_fix_length_key(const DBT *new_key, const DBT *saved_key) berkeley_cmp_fix_length_key(const DBT *new_key, const DBT *saved_key)
{ {
...@@ -261,19 +270,30 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked) ...@@ -261,19 +270,30 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
int error; int error;
DBUG_ENTER("ha_berkeley::open"); DBUG_ENTER("ha_berkeley::open");
/* Open primary key */
hidden_primary_key=0;
if ((primary_key=table->primary_key) >= MAX_KEY)
{ // No primary key
primary_key=table->keys;
fixed_length_primary_key=1;
ref_length=hidden_primary_key=BDB_HIDDEN_PRIMARY_KEY_LENGTH;
}
key_used_on_scan=primary_key;
/* Need some extra memory in case of packed keys */ /* Need some extra memory in case of packed keys */
uint max_key_length= table->max_key_length + MAX_REF_PARTS*2; uint max_key_length= table->max_key_length + MAX_REF_PARTS*2;
if (!(alloc_ptr= if (!(alloc_ptr=
my_multi_malloc(MYF(MY_WME), my_multi_malloc(MYF(MY_WME),
&key_file, table->keys*sizeof(*key_file), &key_file, (table->keys+1)*sizeof(*key_file),
&key_type, table->keys*sizeof(u_int32_t), &key_type, (table->keys+1)*sizeof(u_int32_t),
&key_buff, max_key_length, &key_buff, max_key_length,
&key_buff2, max_key_length, &key_buff2, max_key_length,
&primary_key_buff, &primary_key_buff,
table->key_info[table->primary_key].key_length, (hidden_primary_key ? 0 :
table->key_info[table->primary_key].key_length),
NullS))) NullS)))
DBUG_RETURN(1); DBUG_RETURN(1);
if (!(rec_buff=my_malloc((alloced_rec_buff_length=table->reclength), if (!(rec_buff=my_malloc((alloced_rec_buff_length=table->rec_buff_length),
MYF(MY_WME)))) MYF(MY_WME))))
{ {
my_free(alloc_ptr,MYF(0)); my_free(alloc_ptr,MYF(0));
...@@ -298,8 +318,9 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked) ...@@ -298,8 +318,9 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
DBUG_RETURN(1); DBUG_RETURN(1);
} }
/* Open primary key */ file->set_bt_compare(file,
file->set_bt_compare(file, berkeley_cmp_packed_key); (hidden_primary_key ? berkeley_cmp_hidden_key :
berkeley_cmp_packed_key));
if ((error=(file->open(file, fn_format(name_buff,name,"", ha_berkeley_ext, if ((error=(file->open(file, fn_format(name_buff,name,"", ha_berkeley_ext,
2 | 4), 2 | 4),
"main", DB_BTREE, open_mode,0)))) "main", DB_BTREE, open_mode,0))))
...@@ -314,26 +335,19 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked) ...@@ -314,26 +335,19 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST); info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
transaction=0; transaction=0;
cursor=0; cursor=0;
key_read=0;
fixed_length_row=!(table->db_create_options & HA_OPTION_PACK_RECORD); fixed_length_row=!(table->db_create_options & HA_OPTION_PACK_RECORD);
/* Open other keys */ /* Open other keys */
bzero((char*) key_file,sizeof(*key_file)*table->keys); bzero((char*) key_file,sizeof(*key_file)*table->keys);
if ((key_used_on_scan=primary_key=table->primary_key) < MAX_KEY) key_file[primary_key]=file;
key_file[primary_key]=file; key_type[primary_key]=DB_NOOVERWRITE;
else // No primary key
{
hidden_primary_key=1;
if (!share->primary_key_inited)
update_auto_primary_key();
}
bzero((char*) &current_row,sizeof(current_row)); bzero((char*) &current_row,sizeof(current_row));
DB **ptr=key_file; DB **ptr=key_file;
for (uint i=0, used_keys=0; i < table->keys ; i++, ptr++) for (uint i=0, used_keys=0; i < table->keys ; i++, ptr++)
{ {
char part[7]; char part[7];
key_type[i]=table->key_info[i].flags & HA_NOSAME ? DB_NOOVERWRITE : 0;
if (i != primary_key) if (i != primary_key)
{ {
if ((error=db_create(ptr, db_env, 0))) if ((error=db_create(ptr, db_env, 0)))
...@@ -343,6 +357,7 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked) ...@@ -343,6 +357,7 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
DBUG_RETURN(1); DBUG_RETURN(1);
} }
sprintf(part,"key%02d",++used_keys); sprintf(part,"key%02d",++used_keys);
key_type[i]=table->key_info[i].flags & HA_NOSAME ? DB_NOOVERWRITE : 0;
(*ptr)->set_bt_compare(*ptr, berkeley_cmp_packed_key); (*ptr)->set_bt_compare(*ptr, berkeley_cmp_packed_key);
if (!(table->key_info[i].flags & HA_NOSAME)) if (!(table->key_info[i].flags & HA_NOSAME))
(*ptr)->set_flags(*ptr, DB_DUP); (*ptr)->set_flags(*ptr, DB_DUP);
...@@ -355,28 +370,34 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked) ...@@ -355,28 +370,34 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
} }
} }
} }
/* Calculate pack_length of primary key */
if (!hidden_primary_key)
{
ref_length=0;
KEY_PART_INFO *key_part= table->key_info[primary_key].key_part;
KEY_PART_INFO *end=key_part+table->key_info[primary_key].key_parts;
for ( ; key_part != end ; key_part++)
ref_length+= key_part->field->max_packed_col_length(key_part->length);
fixed_length_primary_key=
(ref_length == table->key_info[primary_key].key_length);
}
else
{
if (!share->primary_key_inited)
update_auto_primary_key();
}
DBUG_RETURN(0); DBUG_RETURN(0);
} }
void ha_berkeley::initialize(void)
{
/* Calculate pack_length of primary key */
ref_length=0;
KEY_PART_INFO *key_part= table->key_info[primary_key].key_part;
KEY_PART_INFO *end=key_part+table->key_info[primary_key].key_parts;
for ( ; key_part != end ; key_part++)
ref_length+= key_part->field->max_packed_col_length(key_part->length);
fixed_length_primary_key=
(ref_length == table->key_info[primary_key].key_length);
}
int ha_berkeley::close(void) int ha_berkeley::close(void)
{ {
int error,result=0; int error,result=0;
uint keys=table->keys + test(hidden_primary_key);
DBUG_ENTER("ha_berkeley::close"); DBUG_ENTER("ha_berkeley::close");
for (uint i=0; i < table->keys; i++) for (uint i=0; i < keys; i++)
{ {
if (key_file[i] && (error=key_file[i]->close(key_file[i],0))) if (key_file[i] && (error=key_file[i]->close(key_file[i],0)))
result=error; result=error;
...@@ -427,13 +448,20 @@ ulong ha_berkeley::max_row_length(const byte *buf) ...@@ -427,13 +448,20 @@ ulong ha_berkeley::max_row_length(const byte *buf)
pre-allocated. pre-allocated.
*/ */
int ha_berkeley::pack_row(DBT *row, const byte *record) int ha_berkeley::pack_row(DBT *row, const byte *record, bool new_row)
{ {
bzero((char*) row,sizeof(*row)); bzero((char*) row,sizeof(*row));
if (fixed_length_row) if (fixed_length_row)
{ {
row->data=(void*) record; row->data=(void*) record;
row->size=table->reclength; row->size=table->reclength+hidden_primary_key;
if (hidden_primary_key)
{
if (new_row)
get_auto_primary_key(current_ident);
memcpy_fixed((char*) record+table->reclength, (char*) current_ident,
BDB_HIDDEN_PRIMARY_KEY_LENGTH);
}
return 0; return 0;
} }
if (table->blob_fields) if (table->blob_fields)
...@@ -448,6 +476,15 @@ int ha_berkeley::pack_row(DBT *row, const byte *record) ...@@ -448,6 +476,15 @@ int ha_berkeley::pack_row(DBT *row, const byte *record)
for (Field **field=table->field ; *field ; field++) for (Field **field=table->field ; *field ; field++)
ptr=(byte*) (*field)->pack((char*) ptr,record + (*field)->offset()); ptr=(byte*) (*field)->pack((char*) ptr,record + (*field)->offset());
if (hidden_primary_key)
{
if (new_row)
get_auto_primary_key(current_ident);
memcpy_fixed((char*) ptr, (char*) current_ident,
BDB_HIDDEN_PRIMARY_KEY_LENGTH);
ptr+=BDB_HIDDEN_PRIMARY_KEY_LENGTH;
}
row->data=rec_buff; row->data=rec_buff;
row->size= (size_t) (ptr - rec_buff); row->size= (size_t) (ptr - rec_buff);
return 0; return 0;
...@@ -457,7 +494,7 @@ int ha_berkeley::pack_row(DBT *row, const byte *record) ...@@ -457,7 +494,7 @@ int ha_berkeley::pack_row(DBT *row, const byte *record)
void ha_berkeley::unpack_row(char *record, DBT *row) void ha_berkeley::unpack_row(char *record, DBT *row)
{ {
if (fixed_length_row) if (fixed_length_row)
memcpy(record,row->data,table->reclength); memcpy(record,(char*) row->data,table->reclength+hidden_primary_key);
else else
{ {
/* Copy null bits */ /* Copy null bits */
...@@ -470,6 +507,37 @@ void ha_berkeley::unpack_row(char *record, DBT *row) ...@@ -470,6 +507,37 @@ void ha_berkeley::unpack_row(char *record, DBT *row)
} }
/* Store the key and the primary key into the row */
void ha_berkeley::unpack_key(char *record, DBT *key, uint index)
{
KEY *key_info=table->key_info+index;
KEY_PART_INFO *key_part= key_info->key_part,
*end=key_part+key_info->key_parts;
char *pos=(char*) key->data;
for ( ; key_part != end; key_part++)
{
if (key_part->null_bit)
{
if (!*pos++) // Null value
{
/*
We don't need to reset the record data as we will not access it
if the null data is set
*/
record[key_part->null_offset]|=key_part->null_bit;
continue;
}
record[key_part->null_offset]&= ~key_part->null_bit;
}
pos= (char*) key_part->field->unpack(record + key_part->field->offset(),
pos);
}
}
/* /*
Create a packed key from from a row Create a packed key from from a row
This will never fail as the key buffer is pre allocated. This will never fail as the key buffer is pre allocated.
...@@ -478,12 +546,20 @@ void ha_berkeley::unpack_row(char *record, DBT *row) ...@@ -478,12 +546,20 @@ void ha_berkeley::unpack_row(char *record, DBT *row)
DBT *ha_berkeley::pack_key(DBT *key, uint keynr, char *buff, DBT *ha_berkeley::pack_key(DBT *key, uint keynr, char *buff,
const byte *record) const byte *record)
{ {
bzero((char*) key,sizeof(*key));
if (hidden_primary_key && keynr == primary_key)
{
key->data=current_ident;
key->size=BDB_HIDDEN_PRIMARY_KEY_LENGTH;
return key;
}
KEY *key_info=table->key_info+keynr; KEY *key_info=table->key_info+keynr;
KEY_PART_INFO *key_part=key_info->key_part; KEY_PART_INFO *key_part=key_info->key_part;
KEY_PART_INFO *end=key_part+key_info->key_parts; KEY_PART_INFO *end=key_part+key_info->key_parts;
DBUG_ENTER("pack_key"); DBUG_ENTER("pack_key");
bzero((char*) key,sizeof(*key));
key->data=buff; key->data=buff;
key->app_private= key_info; key->app_private= key_info;
...@@ -561,7 +637,7 @@ int ha_berkeley::write_row(byte * record) ...@@ -561,7 +637,7 @@ int ha_berkeley::write_row(byte * record)
update_timestamp(record+table->time_stamp-1); update_timestamp(record+table->time_stamp-1);
if (table->next_number_field && record == table->record[0]) if (table->next_number_field && record == table->record[0])
update_auto_increment(); update_auto_increment();
if ((error=pack_row(&row, record))) if ((error=pack_row(&row, record,1)))
DBUG_RETURN(error); DBUG_RETURN(error);
if (table->keys == 1) if (table->keys == 1)
...@@ -678,7 +754,7 @@ int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed, ...@@ -678,7 +754,7 @@ int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed,
pack_key(&old_key, primary_key, key_buff2, old_row); pack_key(&old_key, primary_key, key_buff2, old_row);
if ((error=remove_key(trans, primary_key, old_row, (DBT *) 0, &old_key))) if ((error=remove_key(trans, primary_key, old_row, (DBT *) 0, &old_key)))
DBUG_RETURN(error); // This should always succeed DBUG_RETURN(error); // This should always succeed
if ((error=pack_row(&row, new_row))) if ((error=pack_row(&row, new_row, 0)))
{ {
// Out of memory (this shouldn't happen!) // Out of memory (this shouldn't happen!)
(void) file->put(file, trans, &old_key, &row, (void) file->put(file, trans, &old_key, &row,
...@@ -697,7 +773,7 @@ int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed, ...@@ -697,7 +773,7 @@ int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed,
else else
{ {
// Primary key didn't change; just update the row data // Primary key didn't change; just update the row data
if ((error=pack_row(&row, new_row))) if ((error=pack_row(&row, new_row, 0)))
DBUG_RETURN(error); DBUG_RETURN(error);
error=file->put(file, trans, prim_key, &row, 0); error=file->put(file, trans, prim_key, &row, 0);
if (error) if (error)
...@@ -719,12 +795,24 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) ...@@ -719,12 +795,24 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
statistic_increment(ha_update_count,&LOCK_status); statistic_increment(ha_update_count,&LOCK_status);
if (table->time_stamp) if (table->time_stamp)
update_timestamp(new_row+table->time_stamp-1); update_timestamp(new_row+table->time_stamp-1);
pack_key(&prim_key, primary_key, key_buff, new_row);
if (hidden_primary_key)
if ((primary_key_changed=key_cmp(primary_key, old_row, new_row))) {
pack_key(&old_prim_key, primary_key, primary_key_buff, old_row); primary_key_changed=0;
else bzero((char*) &prim_key,sizeof(prim_key));
prim_key.data= (void*) current_ident;
prim_key.size=BDB_HIDDEN_PRIMARY_KEY_LENGTH;
old_prim_key=prim_key; old_prim_key=prim_key;
}
else
{
pack_key(&prim_key, primary_key, key_buff, new_row);
if ((primary_key_changed=key_cmp(primary_key, old_row, new_row)))
pack_key(&old_prim_key, primary_key, primary_key_buff, old_row);
else
old_prim_key=prim_key;
}
LINT_INIT(error); LINT_INIT(error);
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++) for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
...@@ -869,9 +957,12 @@ int ha_berkeley::delete_row(const byte * record) ...@@ -869,9 +957,12 @@ int ha_berkeley::delete_row(const byte * record)
DBUG_ENTER("delete_row"); DBUG_ENTER("delete_row");
statistic_increment(ha_delete_count,&LOCK_status); statistic_increment(ha_delete_count,&LOCK_status);
if ((error=pack_row(&row, record))) if ((error=pack_row(&row, record, 0)))
DBUG_RETURN((error)); DBUG_RETURN((error));
pack_key(&prim_key, primary_key, key_buff, record); pack_key(&prim_key, primary_key, key_buff, record);
if (hidden_primary_key)
keys|= (key_map) 1 << primary_key;
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++) for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{ {
DB_TXN *sub_trans; DB_TXN *sub_trans;
...@@ -934,7 +1025,7 @@ int ha_berkeley::index_end() ...@@ -934,7 +1025,7 @@ int ha_berkeley::index_end()
/* What to do after we have read a row based on an index */ /* What to do after we have read a row based on an index */
int ha_berkeley::read_row(int error, char *buf, uint keynr, DBT *row, int ha_berkeley::read_row(int error, char *buf, uint keynr, DBT *row,
bool read_next) DBT *found_key, bool read_next)
{ {
DBUG_ENTER("read_row"); DBUG_ENTER("read_row");
if (error) if (error)
...@@ -944,9 +1035,22 @@ int ha_berkeley::read_row(int error, char *buf, uint keynr, DBT *row, ...@@ -944,9 +1035,22 @@ int ha_berkeley::read_row(int error, char *buf, uint keynr, DBT *row,
table->status=STATUS_NOT_FOUND; table->status=STATUS_NOT_FOUND;
DBUG_RETURN(error); DBUG_RETURN(error);
} }
if (hidden_primary_key)
memcpy_fixed(current_ident,
(char*) row->data+row->size-BDB_HIDDEN_PRIMARY_KEY_LENGTH,
BDB_HIDDEN_PRIMARY_KEY_LENGTH);
table->status=0;
if (keynr != primary_key) if (keynr != primary_key)
{ {
/* We only found the primary key. Now we have to use this to find
the row data */
if (key_read && found_key)
{
unpack_key(buf,found_key,keynr);
if (!hidden_primary_key)
unpack_key(buf,row,primary_key);
DBUG_RETURN(0);
}
DBT key; DBT key;
bzero((char*) &key,sizeof(key)); bzero((char*) &key,sizeof(key));
key.data=key_buff2; key.data=key_buff2;
...@@ -963,7 +1067,6 @@ int ha_berkeley::read_row(int error, char *buf, uint keynr, DBT *row, ...@@ -963,7 +1067,6 @@ int ha_berkeley::read_row(int error, char *buf, uint keynr, DBT *row,
row= &current_row; row= &current_row;
} }
unpack_row(buf,row); unpack_row(buf,row);
table->status=0;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -980,7 +1083,7 @@ int ha_berkeley::index_read_idx(byte * buf, uint keynr, const byte * key, ...@@ -980,7 +1083,7 @@ int ha_berkeley::index_read_idx(byte * buf, uint keynr, const byte * key,
pack_key(&last_key, keynr, key_buff, key, pack_key(&last_key, keynr, key_buff, key,
key_len), key_len),
&current_row,0), &current_row,0),
buf, keynr, &current_row, 0)); buf, keynr, &current_row, &last_key, 0));
} }
...@@ -999,7 +1102,7 @@ int ha_berkeley::index_read(byte * buf, const byte * key, ...@@ -999,7 +1102,7 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
key_buff, key_buff,
key, key_len), key, key_len),
&row, DB_SET), &row, DB_SET),
buf, active_index, &row, 0); buf, active_index, &row, (DBT*) 0, 0);
} }
else else
{ {
...@@ -1009,7 +1112,7 @@ int ha_berkeley::index_read(byte * buf, const byte * key, ...@@ -1009,7 +1112,7 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
memcpy(key_buff2, key_buff, last_key.size); memcpy(key_buff2, key_buff, last_key.size);
((KEY*) last_key.app_private)->handler.bdb_return_if_eq= -1; ((KEY*) last_key.app_private)->handler.bdb_return_if_eq= -1;
error=read_row(cursor->c_get(cursor, &last_key, &row, DB_SET_RANGE), error=read_row(cursor->c_get(cursor, &last_key, &row, DB_SET_RANGE),
buf, active_index, &row, 0); buf, active_index, &row, (DBT*) 0, 0);
((KEY*) last_key.app_private)->handler.bdb_return_if_eq=0; ((KEY*) last_key.app_private)->handler.bdb_return_if_eq=0;
if (!error && find_flag == HA_READ_KEY_EXACT) if (!error && find_flag == HA_READ_KEY_EXACT)
{ {
...@@ -1030,7 +1133,7 @@ int ha_berkeley::index_next(byte * buf) ...@@ -1030,7 +1133,7 @@ int ha_berkeley::index_next(byte * buf)
statistic_increment(ha_read_next_count,&LOCK_status); statistic_increment(ha_read_next_count,&LOCK_status);
bzero((char*) &row,sizeof(row)); bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT), DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT),
buf, active_index, &row ,1)); buf, active_index, &row, &last_key, 1));
} }
int ha_berkeley::index_next_same(byte * buf, const byte *key, uint keylen) int ha_berkeley::index_next_same(byte * buf, const byte *key, uint keylen)
...@@ -1042,11 +1145,11 @@ int ha_berkeley::index_next_same(byte * buf, const byte *key, uint keylen) ...@@ -1042,11 +1145,11 @@ int ha_berkeley::index_next_same(byte * buf, const byte *key, uint keylen)
bzero((char*) &row,sizeof(row)); bzero((char*) &row,sizeof(row));
if (keylen == table->key_info[active_index].key_length) if (keylen == table->key_info[active_index].key_length)
error=read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT_DUP), error=read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT_DUP),
buf, active_index, &row,1); buf, active_index, &row, &last_key, 1);
else else
{ {
error=read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT), error=read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT),
buf, active_index, &row,1); buf, active_index, &row, &last_key, 1);
if (!error && ::key_cmp(table, key, active_index, keylen)) if (!error && ::key_cmp(table, key, active_index, keylen))
error=HA_ERR_END_OF_FILE; error=HA_ERR_END_OF_FILE;
} }
...@@ -1061,7 +1164,7 @@ int ha_berkeley::index_prev(byte * buf) ...@@ -1061,7 +1164,7 @@ int ha_berkeley::index_prev(byte * buf)
statistic_increment(ha_read_prev_count,&LOCK_status); statistic_increment(ha_read_prev_count,&LOCK_status);
bzero((char*) &row,sizeof(row)); bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_PREV), DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_PREV),
buf, active_index, &row,1)); buf, active_index, &row, &last_key, 1));
} }
...@@ -1072,7 +1175,7 @@ int ha_berkeley::index_first(byte * buf) ...@@ -1072,7 +1175,7 @@ int ha_berkeley::index_first(byte * buf)
statistic_increment(ha_read_first_count,&LOCK_status); statistic_increment(ha_read_first_count,&LOCK_status);
bzero((char*) &row,sizeof(row)); bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_FIRST), DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_FIRST),
buf, active_index, &row,0)); buf, active_index, &row, &last_key, 0));
} }
int ha_berkeley::index_last(byte * buf) int ha_berkeley::index_last(byte * buf)
...@@ -1082,7 +1185,7 @@ int ha_berkeley::index_last(byte * buf) ...@@ -1082,7 +1185,7 @@ int ha_berkeley::index_last(byte * buf)
statistic_increment(ha_read_last_count,&LOCK_status); statistic_increment(ha_read_last_count,&LOCK_status);
bzero((char*) &row,sizeof(row)); bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_LAST), DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_LAST),
buf, active_index, &row,0)); buf, active_index, &row, &last_key, 0));
} }
int ha_berkeley::rnd_init(bool scan) int ha_berkeley::rnd_init(bool scan)
...@@ -1103,7 +1206,7 @@ int ha_berkeley::rnd_next(byte *buf) ...@@ -1103,7 +1206,7 @@ int ha_berkeley::rnd_next(byte *buf)
statistic_increment(ha_read_rnd_next_count,&LOCK_status); statistic_increment(ha_read_rnd_next_count,&LOCK_status);
bzero((char*) &row,sizeof(row)); bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT), DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT),
buf, active_index, &row, 1)); buf, active_index, &row, &last_key, 1));
} }
...@@ -1136,13 +1239,18 @@ int ha_berkeley::rnd_pos(byte * buf, byte *pos) ...@@ -1136,13 +1239,18 @@ int ha_berkeley::rnd_pos(byte * buf, byte *pos)
return read_row(file->get(file, transaction, return read_row(file->get(file, transaction,
get_pos(&db_pos, pos), get_pos(&db_pos, pos),
&current_row, 0), &current_row, 0),
buf, active_index, &current_row,0); buf, active_index, &current_row, (DBT*) 0, 0);
} }
void ha_berkeley::position(const byte *record) void ha_berkeley::position(const byte *record)
{ {
DBT key; DBT key;
pack_key(&key, primary_key, ref, record); if (hidden_primary_key)
{
memcpy_fixed(ref, (char*) current_ident, BDB_HIDDEN_PRIMARY_KEY_LENGTH);
}
else
pack_key(&key, primary_key, ref, record);
} }
...@@ -1162,11 +1270,27 @@ void ha_berkeley::info(uint flag) ...@@ -1162,11 +1270,27 @@ void ha_berkeley::info(uint flag)
int ha_berkeley::extra(enum ha_extra_function operation) int ha_berkeley::extra(enum ha_extra_function operation)
{ {
switch (operation) {
case HA_EXTRA_RESET:
case HA_EXTRA_RESET_STATE:
key_read=0;
break;
case HA_EXTRA_KEYREAD:
key_read=1; // Query satisfied with key
break;
case HA_EXTRA_NO_KEYREAD:
key_read=0;
break;
default:
break;
}
return 0; return 0;
} }
int ha_berkeley::reset(void) int ha_berkeley::reset(void)
{ {
key_read=0; // Reset to state after open
return 0; return 0;
} }
...@@ -1280,6 +1404,7 @@ int ha_berkeley::create(const char *name, register TABLE *form, ...@@ -1280,6 +1404,7 @@ int ha_berkeley::create(const char *name, register TABLE *form,
{ {
char name_buff[FN_REFLEN]; char name_buff[FN_REFLEN];
char part[7]; char part[7];
uint index=1;
DBUG_ENTER("ha_berkeley::create"); DBUG_ENTER("ha_berkeley::create");
fn_format(name_buff,name,"", ha_berkeley_ext,2 | 4); fn_format(name_buff,name,"", ha_berkeley_ext,2 | 4);
...@@ -1288,14 +1413,18 @@ int ha_berkeley::create(const char *name, register TABLE *form, ...@@ -1288,14 +1413,18 @@ int ha_berkeley::create(const char *name, register TABLE *form,
if (create_sub_table(name_buff,"main",DB_BTREE,0)) if (create_sub_table(name_buff,"main",DB_BTREE,0))
DBUG_RETURN(1); DBUG_RETURN(1);
primary_key=table->primary_key;
/* Create the keys */ /* Create the keys */
for (uint i=1; i < form->keys; i++) for (uint i=0; i < form->keys; i++)
{ {
sprintf(part,"key%02d",i); if (i != primary_key)
if (create_sub_table(name_buff, part, DB_BTREE, {
(table->key_info[i].flags & HA_NOSAME) ? 0 : sprintf(part,"key%02d",index++);
DB_DUP)) if (create_sub_table(name_buff, part, DB_BTREE,
DBUG_RETURN(1); (table->key_info[i].flags & HA_NOSAME) ? 0 :
DB_DUP))
DBUG_RETURN(1);
}
} }
/* Create the status block to save information from last status command */ /* Create the status block to save information from last status command */
...@@ -1403,7 +1532,7 @@ static BDB_SHARE *get_share(const char *table_name) ...@@ -1403,7 +1532,7 @@ static BDB_SHARE *get_share(const char *table_name)
return 0; return 0;
} }
thr_lock_init(&share->lock); thr_lock_init(&share->lock);
pthread_mutex_init(&share->mutex); pthread_mutex_init(&share->mutex,NULL);
} }
} }
share->use_count++; share->use_count++;
...@@ -1427,17 +1556,17 @@ static void free_share(BDB_SHARE *share) ...@@ -1427,17 +1556,17 @@ static void free_share(BDB_SHARE *share)
void ha_berkeley::update_auto_primary_key() void ha_berkeley::update_auto_primary_key()
{ {
(void) extra(HA_EXTRA_KEYREAD);
pthread_mutex_lock(&share->mutex); pthread_mutex_lock(&share->mutex);
if (!share->primary_key_inited) if (!share->primary_key_inited)
{ {
(void) extra(HA_EXTRA_KEYREAD);
index_init(primary_key); index_init(primary_key);
if (!index_last(table->record[1])) if (!index_last(table->record[1]))
share->auto_ident=current_ident; share->auto_ident=uint5korr(current_ident);
index_end(); index_end();
(void) extra(HA_EXTRA_NO_KEYREAD);
} }
pthread_mutex_unlock(&share->mutex); pthread_mutex_unlock(&share->mutex);
(void) extra(HA_EXTRA_NO_KEYREAD);
} }
#endif /* HAVE_BERKELEY_DB */ #endif /* HAVE_BERKELEY_DB */
...@@ -23,15 +23,18 @@ ...@@ -23,15 +23,18 @@
#include <db.h> #include <db.h>
#define BDB_HIDDEN_PRIMARY_KEY_LENGTH 5
typedef struct st_berkeley_share { typedef struct st_berkeley_share {
ulonglong auto_ident; ulonglong auto_ident;
THR_LOCK lock; THR_LOCK lock;
pthread_mutex_t mutex; pthread_mutex_t mutex;
char *table_name; char *table_name;
uint table_name_length,use_count; uint table_name_length,use_count;
my_bool inited; bool primary_key_inited;
} BDB_SHARE; } BDB_SHARE;
class ha_berkeley: public handler class ha_berkeley: public handler
{ {
THR_LOCK_DATA lock; THR_LOCK_DATA lock;
...@@ -46,13 +49,15 @@ class ha_berkeley: public handler ...@@ -46,13 +49,15 @@ class ha_berkeley: public handler
BDB_SHARE *share; BDB_SHARE *share;
ulong int_option_flag; ulong int_option_flag;
ulong alloced_rec_buff_length; ulong alloced_rec_buff_length;
uint primary_key,last_dup_key; uint primary_key,last_dup_key, hidden_primary_key;
bool fixed_length_row, fixed_length_primary_key, hidden_primary_key; bool fixed_length_row, fixed_length_primary_key, key_read;
bool fix_rec_buff_for_blob(ulong length); bool fix_rec_buff_for_blob(ulong length);
byte current_ident[BDB_HIDDEN_PRIMARY_KEY_LENGTH];
ulong max_row_length(const byte *buf); ulong max_row_length(const byte *buf);
int pack_row(DBT *row,const byte *record); int pack_row(DBT *row,const byte *record, bool new_row);
void unpack_row(char *record, DBT *row); void unpack_row(char *record, DBT *row);
void ha_berkeley::unpack_key(char *record, DBT *key, uint index);
DBT *pack_key(DBT *key, uint keynr, char *buff, const byte *record); DBT *pack_key(DBT *key, uint keynr, char *buff, const byte *record);
DBT *pack_key(DBT *key, uint keynr, char *buff, const byte *key_ptr, DBT *pack_key(DBT *key, uint keynr, char *buff, const byte *key_ptr,
uint key_length); uint key_length);
...@@ -64,7 +69,7 @@ class ha_berkeley: public handler ...@@ -64,7 +69,7 @@ class ha_berkeley: public handler
int update_primary_key(DB_TXN *trans, bool primary_key_changed, int update_primary_key(DB_TXN *trans, bool primary_key_changed,
const byte * old_row, const byte * new_row, const byte * old_row, const byte * new_row,
DBT *prim_key); DBT *prim_key);
int read_row(int error, char *buf, uint keynr, DBT *row, bool); int read_row(int error, char *buf, uint keynr, DBT *row, DBT *key, bool);
DBT *get_pos(DBT *to, byte *pos); DBT *get_pos(DBT *to, byte *pos);
public: public:
...@@ -72,9 +77,8 @@ class ha_berkeley: public handler ...@@ -72,9 +77,8 @@ class ha_berkeley: public handler
int_option_flag(HA_READ_NEXT | HA_READ_PREV | int_option_flag(HA_READ_NEXT | HA_READ_PREV |
HA_REC_NOT_IN_SEQ | HA_REC_NOT_IN_SEQ |
HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER | HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
HA_LONGLONG_KEYS | HA_NULL_KEY | HA_LONGLONG_KEYS | HA_NULL_KEY | HA_HAVE_KEY_READ_ONLY |
HA_BLOB_KEY | HA_BLOB_KEY | HA_NOT_EXACT_COUNT |
HA_REQUIRE_PRIMARY_KEY | HA_NOT_EXACT_COUNT |
HA_PRIMARY_KEY_IN_READ_INDEX | HA_DROP_BEFORE_CREATE), HA_PRIMARY_KEY_IN_READ_INDEX | HA_DROP_BEFORE_CREATE),
last_dup_key((uint) -1) last_dup_key((uint) -1)
{ {
...@@ -84,14 +88,14 @@ class ha_berkeley: public handler ...@@ -84,14 +88,14 @@ class ha_berkeley: public handler
const char **bas_ext() const; const char **bas_ext() const;
ulong option_flag() const { return int_option_flag; } ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; } uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return MAX_KEY; } uint max_keys() const { return MAX_KEY-1; }
uint max_key_parts() const { return MAX_REF_PARTS; } uint max_key_parts() const { return MAX_REF_PARTS; }
uint max_key_length() const { return MAX_KEY_LENGTH; } uint max_key_length() const { return MAX_KEY_LENGTH; }
uint extra_rec_buf_length() { return BDB_HIDDEN_PRIMARY_KEY_LENGTH; }
bool fast_key_read() { return 1;} bool fast_key_read() { return 1;}
bool has_transactions() { return 1;} bool has_transactions() { return 1;}
int open(const char *name, int mode, uint test_if_locked); int open(const char *name, int mode, uint test_if_locked);
void initialize(void);
int close(void); int close(void);
double scan_time(); double scan_time();
int write_row(byte * buf); int write_row(byte * buf);
...@@ -129,6 +133,16 @@ class ha_berkeley: public handler ...@@ -129,6 +133,16 @@ class ha_berkeley: public handler
int delete_table(const char *name); int delete_table(const char *name);
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);
void update_auto_primary_key();
inline void get_auto_primary_key(byte *to)
{
ulonglong tmp;
pthread_mutex_lock(&share->mutex);
share->auto_ident++;
int5store(to,share->auto_ident);
pthread_mutex_unlock(&share->mutex);
}
}; };
extern bool berkeley_skip; extern bool berkeley_skip;
......
...@@ -202,6 +202,7 @@ public: ...@@ -202,6 +202,7 @@ public:
virtual double read_time(ha_rows rows) { return rows; } virtual double read_time(ha_rows rows) { return rows; }
virtual bool fast_key_read() { return 0;} virtual bool fast_key_read() { return 0;}
virtual bool has_transactions(){ return 0;} virtual bool has_transactions(){ return 0;}
virtual uint extra_rec_buf_length() { return 0; }
virtual int index_init(uint idx) { active_index=idx; return 0;} virtual int index_init(uint idx) { active_index=idx; return 0;}
virtual int index_end() {return 0; } virtual int index_end() {return 0; }
......
...@@ -2347,6 +2347,7 @@ bool QUICK_SELECT::unique_key_range() ...@@ -2347,6 +2347,7 @@ bool QUICK_SELECT::unique_key_range()
QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref) QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref)
{ {
table->file->index_end(); // Remove old cursor
QUICK_SELECT *quick=new QUICK_SELECT(table, ref->key, 1); QUICK_SELECT *quick=new QUICK_SELECT(table, ref->key, 1);
KEY *key_info = &table->key_info[ref->key]; KEY *key_info = &table->key_info[ref->key];
KEY_PART *key_part; KEY_PART *key_part;
......
...@@ -1413,11 +1413,17 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, ...@@ -1413,11 +1413,17 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
if (field->query_id != thd->query_id) if (field->query_id != thd->query_id)
{ {
field->query_id=thd->query_id; field->query_id=thd->query_id;
field->table->used_fields++; table->used_fields++;
if (field->part_of_key)
{
if (!(field->part_of_key & table->ref_primary_key))
table->used_keys&=field->part_of_key;
}
else
table->used_keys=0;
} }
else else
thd->dupp_field=field; thd->dupp_field=field;
field->table->used_keys&=field->part_of_key;
} }
if (check_grants && !thd->master_access && check_grant_column(thd,table,name,length)) if (check_grants && !thd->master_access && check_grant_column(thd,table,name,length))
return WRONG_GRANT; return WRONG_GRANT;
...@@ -1659,19 +1665,19 @@ static bool ...@@ -1659,19 +1665,19 @@ static bool
insert_fields(THD *thd,TABLE_LIST *tables, const char *table_name, insert_fields(THD *thd,TABLE_LIST *tables, const char *table_name,
List_iterator<Item> *it) List_iterator<Item> *it)
{ {
TABLE_LIST *table;
uint found; uint found;
DBUG_ENTER("insert_fields"); DBUG_ENTER("insert_fields");
found=0; found=0;
for (table=tables ; table ; table=table->next) for (; tables ; tables=tables->next)
{ {
TABLE *table=tables->table;
if (grant_option && !thd->master_access && if (grant_option && !thd->master_access &&
check_grant_all_columns(thd,SELECT_ACL,table->table) ) check_grant_all_columns(thd,SELECT_ACL,table) )
DBUG_RETURN(-1); DBUG_RETURN(-1);
if (!table_name || !strcmp(table_name,table->name)) if (!table_name || !strcmp(table_name,tables->name))
{ {
Field **ptr=table->table->field,*field; Field **ptr=table->field,*field;
while ((field = *ptr++)) while ((field = *ptr++))
{ {
Item_field *item= new Item_field(field); Item_field *item= new Item_field(field);
...@@ -1682,10 +1688,17 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *table_name, ...@@ -1682,10 +1688,17 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *table_name,
if (field->query_id == thd->query_id) if (field->query_id == thd->query_id)
thd->dupp_field=field; thd->dupp_field=field;
field->query_id=thd->query_id; field->query_id=thd->query_id;
field->table->used_keys&=field->part_of_key;
if (field->part_of_key)
{
if (!(field->part_of_key & table->ref_primary_key))
table->used_keys&=field->part_of_key;
}
else
table->used_keys=0;
} }
/* All fields are used */ /* All fields are used */
table->table->used_fields=table->table->fields; table->used_fields=table->fields;
} }
} }
if (!found) if (!found)
...@@ -1750,6 +1763,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -1750,6 +1763,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
// TODO: This could be optimized to use hashed names if t2 had a hash // TODO: This could be optimized to use hashed names if t2 had a hash
for (j=0 ; j < t2->fields ; j++) for (j=0 ; j < t2->fields ; j++)
{ {
key_map tmp_map;
if (!my_strcasecmp(t1->field[i]->field_name, if (!my_strcasecmp(t1->field[i]->field_name,
t2->field[j]->field_name)) t2->field[j]->field_name))
{ {
...@@ -1760,8 +1774,20 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -1760,8 +1774,20 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
tmp->fix_length_and_dec(); // Update cmp_type tmp->fix_length_and_dec(); // Update cmp_type
tmp->const_item_cache=0; tmp->const_item_cache=0;
cond_and->list.push_back(tmp); cond_and->list.push_back(tmp);
t1->used_keys&= t1->field[i]->part_of_key; if ((tmp_map=t1->field[i]->part_of_key))
t2->used_keys&= t2->field[j]->part_of_key; {
if (!(tmp_map & t1->ref_primary_key))
t1->used_keys&=tmp_map;
}
else
t1->used_keys=0;
if ((tmp_map=t2->field[j]->part_of_key))
{
if (!(tmp_map & t2->ref_primary_key))
t2->used_keys&=tmp_map;
}
else
t2->used_keys=0;
break; break;
} }
} }
......
...@@ -2352,6 +2352,11 @@ make_join_readinfo(JOIN *join,uint options) ...@@ -2352,6 +2352,11 @@ make_join_readinfo(JOIN *join,uint options)
break; break;
case JT_EQ_REF: case JT_EQ_REF:
table->status=STATUS_NO_RECORD; table->status=STATUS_NO_RECORD;
if (tab->select)
{
delete tab->select->quick;
tab->select->quick=0;
}
delete tab->quick; delete tab->quick;
tab->quick=0; tab->quick=0;
table->file->index_init(tab->ref.key); table->file->index_init(tab->ref.key);
...@@ -2365,6 +2370,11 @@ make_join_readinfo(JOIN *join,uint options) ...@@ -2365,6 +2370,11 @@ make_join_readinfo(JOIN *join,uint options)
break; break;
case JT_REF: case JT_REF:
table->status=STATUS_NO_RECORD; table->status=STATUS_NO_RECORD;
if (tab->select)
{
delete tab->select->quick;
tab->select->quick=0;
}
delete tab->quick; delete tab->quick;
tab->quick=0; tab->quick=0;
table->file->index_init(tab->ref.key); table->file->index_init(tab->ref.key);
......
...@@ -207,49 +207,29 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -207,49 +207,29 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
} }
#endif #endif
/* Allocate handler */
if (!(outparam->file= get_new_handler(outparam,outparam->db_type))) if (!(outparam->file= get_new_handler(outparam,outparam->db_type)))
goto err_not_open; goto err_not_open;
error=2;
if (db_stat)
{
int err;
if ((err=(outparam->file->
ha_open(index_file,
(db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
(db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
((db_stat & HA_WAIT_IF_LOCKED) ||
(specialflag & SPECIAL_WAIT_IF_LOCKED)) ?
HA_OPEN_WAIT_IF_LOCKED :
(db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
HA_OPEN_ABORT_IF_LOCKED :
HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
{
/* Set a flag if the table is crashed and it can be auto. repaired */
outparam->crashed=(err == HA_ERR_CRASHED &&
outparam->file->auto_repair() &&
!(ha_open_flags & HA_OPEN_FOR_REPAIR));
goto err_not_open; /* purecov: inspected */
}
}
outparam->db_low_byte_first=outparam->file->low_byte_first();
error=4; error=4;
outparam->reginfo.lock_type= TL_UNLOCK; outparam->reginfo.lock_type= TL_UNLOCK;
outparam->current_lock=F_UNLCK; outparam->current_lock=F_UNLCK;
if (db_stat & HA_OPEN_KEYFILE || (prgflag & DELAYED_OPEN)) records=2; if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN)) records=2;
else records=1; else records=1;
if (prgflag & (READ_ALL+EXTRA_RECORD)) records++; if (prgflag & (READ_ALL+EXTRA_RECORD)) records++;
rec_buff_length=ALIGN_SIZE(outparam->reclength+1); /* QQ: TODO, remove the +1 from below */
rec_buff_length=ALIGN_SIZE(outparam->reclength+1+
outparam->file->extra_rec_buf_length());
if (!(outparam->record[0]= (byte*) if (!(outparam->record[0]= (byte*)
(record = (char *) alloc_root(&outparam->mem_root, (record = (char *) alloc_root(&outparam->mem_root,
rec_buff_length * records)))) rec_buff_length * records))))
goto err; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
record[outparam->reclength]=0; // For purify and ->c_ptr() record[outparam->reclength]=0; // For purify and ->c_ptr()
outparam->rec_buff_length=rec_buff_length; outparam->rec_buff_length=rec_buff_length;
if (my_pread(file,(byte*) record,(uint) outparam->reclength, if (my_pread(file,(byte*) record,(uint) outparam->reclength,
(ulong) (uint2korr(head+6)+uint2korr(head+14)), (ulong) (uint2korr(head+6)+uint2korr(head+14)),
MYF(MY_NABP))) MYF(MY_NABP)))
goto err; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
for (i=0 ; i < records ; i++, record+=rec_buff_length) for (i=0 ; i < records ; i++, record+=rec_buff_length)
{ {
outparam->record[i]=(byte*) record; outparam->record[i]=(byte*) record;
...@@ -265,12 +245,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -265,12 +245,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
} }
VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0))); VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err; if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open;
if (crypted) if (crypted)
{ {
crypted->decode((char*) head+256,288-256); crypted->decode((char*) head+256,288-256);
if (sint2korr(head+284) != 0) // Should be 0 if (sint2korr(head+284) != 0) // Should be 0
goto err; // Wrong password goto err_not_open; // Wrong password
} }
outparam->fields= uint2korr(head+258); outparam->fields= uint2korr(head+258);
...@@ -292,13 +272,13 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -292,13 +272,13 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(outparam->fields+interval_parts+ (outparam->fields+interval_parts+
keys+3)*sizeof(my_string)+ keys+3)*sizeof(my_string)+
(n_length+int_length))))) (n_length+int_length)))))
goto err; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
outparam->field=field_ptr; outparam->field=field_ptr;
read_length=((uint) (outparam->fields*11)+pos+ read_length=((uint) (outparam->fields*11)+pos+
(uint) (n_length+int_length)); (uint) (n_length+int_length));
if (read_string(file,(gptr*) &disk_buff,read_length)) if (read_string(file,(gptr*) &disk_buff,read_length))
goto err; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
if (crypted) if (crypted)
{ {
crypted->decode((char*) disk_buff,read_length); crypted->decode((char*) disk_buff,read_length);
...@@ -321,6 +301,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -321,6 +301,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (keynames) if (keynames)
fix_type_pointers(&int_array,&outparam->keynames,1,&keynames); fix_type_pointers(&int_array,&outparam->keynames,1,&keynames);
VOID(my_close(file,MYF(MY_WME))); VOID(my_close(file,MYF(MY_WME)));
file= -1;
record=(char*) outparam->record[0]-1; /* Fieldstart = 1 */ record=(char*) outparam->record[0]-1; /* Fieldstart = 1 */
if (null_field_first) if (null_field_first)
...@@ -426,7 +407,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -426,7 +407,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(uint) key_part->length); (uint) key_part->length);
#ifdef EXTRA_DEBUG #ifdef EXTRA_DEBUG
if (key_part->fieldnr > outparam->fields) if (key_part->fieldnr > outparam->fields)
goto err; // sanity check goto err_not_open; // sanity check
#endif #endif
if (key_part->fieldnr) if (key_part->fieldnr)
{ // Should always be true ! { // Should always be true !
...@@ -494,6 +475,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -494,6 +475,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(outparam->keys_in_use & ((key_map) 1 << primary_key))) (outparam->keys_in_use & ((key_map) 1 << primary_key)))
{ {
outparam->primary_key=primary_key; outparam->primary_key=primary_key;
if (outparam->file->option_flag() & HA_PRIMARY_KEY_IN_READ_INDEX)
outparam->ref_primary_key= (key_map) 1 << primary_key;
/*
If we are using an integer as the primary key then allow the user to
refer to it as '_rowid'
*/
if (outparam->key_info[primary_key].key_parts == 1) if (outparam->key_info[primary_key].key_parts == 1)
{ {
Field *field= outparam->key_info[primary_key].key_part[0].field; Field *field= outparam->key_info[primary_key].key_part[0].field;
...@@ -505,6 +492,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -505,6 +492,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->primary_key = MAX_KEY; // we do not have a primary key outparam->primary_key = MAX_KEY; // we do not have a primary key
} }
x_free((gptr) disk_buff); x_free((gptr) disk_buff);
disk_buff=0;
if (new_field_pack_flag <= 1) if (new_field_pack_flag <= 1)
{ /* Old file format with default null */ { /* Old file format with default null */
uint null_length=(outparam->null_fields+7)/8; uint null_length=(outparam->null_fields+7)/8;
...@@ -523,7 +511,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -523,7 +511,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(Field_blob**) alloc_root(&outparam->mem_root, (Field_blob**) alloc_root(&outparam->mem_root,
(uint) (outparam->blob_fields+1)* (uint) (outparam->blob_fields+1)*
sizeof(Field_blob*)))) sizeof(Field_blob*))))
goto err; goto err_not_open;
for (ptr=outparam->field ; *ptr ; ptr++) for (ptr=outparam->field ; *ptr ; ptr++)
{ {
if ((*ptr)->flags & BLOB_FLAG) if ((*ptr)->flags & BLOB_FLAG)
...@@ -535,22 +523,43 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -535,22 +523,43 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->blob_field= outparam->blob_field=
(Field_blob**) (outparam->field+outparam->fields); // Point at null ptr (Field_blob**) (outparam->field+outparam->fields); // Point at null ptr
/* The table struct is now initialzed; Open the table */
error=2;
if (db_stat)
{
int err;
if ((err=(outparam->file->
ha_open(index_file,
(db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
(db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
((db_stat & HA_WAIT_IF_LOCKED) ||
(specialflag & SPECIAL_WAIT_IF_LOCKED)) ?
HA_OPEN_WAIT_IF_LOCKED :
(db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
HA_OPEN_ABORT_IF_LOCKED :
HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
{
/* Set a flag if the table is crashed and it can be auto. repaired */
outparam->crashed=(err == HA_ERR_CRASHED &&
outparam->file->auto_repair() &&
!(ha_open_flags & HA_OPEN_FOR_REPAIR));
goto err_not_open; /* purecov: inspected */
}
}
outparam->db_low_byte_first=outparam->file->low_byte_first();
my_pthread_setspecific_ptr(THR_MALLOC,old_root); my_pthread_setspecific_ptr(THR_MALLOC,old_root);
opened_tables++; opened_tables++;
#ifndef DBUG_OFF #ifndef DBUG_OFF
if (use_hash) if (use_hash)
(void) hash_check(&outparam->name_hash); (void) hash_check(&outparam->name_hash);
#endif #endif
if (db_stat)
outparam->file->initialize();
DBUG_RETURN (0); DBUG_RETURN (0);
err:
if (outparam->file && db_stat)
(void) outparam->file->close();
err_not_open: err_not_open:
x_free((gptr) disk_buff); x_free((gptr) disk_buff);
VOID(my_close(file,MYF(MY_WME))); if (file > 0)
VOID(my_close(file,MYF(MY_WME)));
err_end: /* Here when no file */ err_end: /* Here when no file */
delete crypted; delete crypted;
......
...@@ -113,7 +113,7 @@ struct st_table { ...@@ -113,7 +113,7 @@ struct st_table {
byte *record_pointers; /* If sorted in memory */ byte *record_pointers; /* If sorted in memory */
ha_rows found_records; /* How many records in sort */ ha_rows found_records; /* How many records in sort */
ORDER *group; ORDER *group;
key_map quick_keys,used_keys; key_map quick_keys, used_keys, ref_primary_key;
ha_rows quick_rows[MAX_KEY]; ha_rows quick_rows[MAX_KEY];
uint quick_key_parts[MAX_KEY]; uint quick_key_parts[MAX_KEY];
key_part_map const_key_parts[MAX_KEY]; key_part_map const_key_parts[MAX_KEY];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment