summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Docs/manual.texi7
-rw-r--r--include/mysql_com.h1
-rw-r--r--myisam/mi_extra.c2
-rw-r--r--mysql-test/r/bdb.result22
-rw-r--r--mysql-test/r/group_by.result27
-rw-r--r--mysql-test/t/bdb.test16
-rw-r--r--mysql-test/t/group_by.test17
-rw-r--r--sql/ha_berkeley.cc9
-rw-r--r--sql/handler.cc5
-rw-r--r--sql/records.cc1
-rw-r--r--sql/sql_analyse.cc6
-rw-r--r--sql/sql_base.cc4
-rw-r--r--sql/sql_delete.cc61
-rw-r--r--sql/sql_select.cc6
-rw-r--r--sql/sql_update.cc6
15 files changed, 126 insertions, 64 deletions
diff --git a/Docs/manual.texi b/Docs/manual.texi
index 481529886bf..e8d882acb0e 100644
--- a/Docs/manual.texi
+++ b/Docs/manual.texi
@@ -48135,6 +48135,13 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}.
@itemize @bullet
@item
+Fixed bug in multi table delete.
+@item
+Fixed bug in @code{SELECT CONCAT(argument-list) ... GROUP BY 1}.
+@item
+@code{SELECT .. INSERT} did a full rollback in case of an error. Fixed
+so that we only rollback the last statement.
+@item
Fixed bug with empty expression for boolean fulltext search.
@item
Fixed core dump bug in updating fulltext key from/to @code{NULL}.
diff --git a/include/mysql_com.h b/include/mysql_com.h
index eb3671ddfbd..cc887cc7c83 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -108,6 +108,7 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY,
struct st_vio; /* Only C */
typedef struct st_vio Vio;
+#define MAX_CHAR_WIDTH 255 // Max length for a CHAR colum
#define MAX_BLOB_WIDTH 8192 // Default width for blob
typedef struct st_net {
diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c
index 4044535e527..21cd9919ada 100644
--- a/myisam/mi_extra.c
+++ b/myisam/mi_extra.c
@@ -51,7 +51,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function)
if (info->opt_flag & MEMMAP_USED)
madvise(share->file_map,share->state.state.data_file_length,MADV_RANDOM);
#endif
- info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
+ info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
info->quick_mode=0;
/* Fall through */
diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result
index e553105fcc7..7374e936c36 100644
--- a/mysql-test/r/bdb.result
+++ b/mysql-test/r/bdb.result
@@ -1101,3 +1101,25 @@ INFO_NOTE
select INFO_NOTE from t1 where STR_DATE > '20010610';
INFO_NOTE
drop table t1;
+create table t1 (a int not null, b int, primary key (a)) type =bdb;
+create table t2 (a int not null, b int, primary key (a)) type =bdb;
+insert into t1 values (2, 3),(1, 7),(10, 7);
+insert into t2 values (2, 3),(1, 7),(10, 7);
+select * from t1;
+a b
+1 7
+2 3
+10 7
+select * from t2;
+a b
+1 7
+2 3
+10 7
+delete t1, t2 from t1, t2 where t1.a = t2.a;
+select * from t1;
+a b
+select * from t2;
+a b
+select * from t2;
+a b
+drop table t1,t2;
diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result
index a67298c73c0..9845e12ef5f 100644
--- a/mysql-test/r/group_by.result
+++ b/mysql-test/r/group_by.result
@@ -344,3 +344,30 @@ a 1
b 1
SET SQL_BIG_TABLES=0;
drop table t1;
+CREATE TABLE t1 (
+`a` char(193) default NULL,
+`b` char(63) default NULL
+);
+INSERT INTO t1 VALUES ('abc','def'),('hij','klm');
+SELECT CONCAT(a, b) FROM t1 GROUP BY 1;
+CONCAT(a, b)
+abcdef
+hijklm
+SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1;
+CONCAT(a, b) count(*)
+abcdef 1
+hijklm 1
+SELECT CONCAT(a, b),count(distinct a) FROM t1 GROUP BY 1;
+CONCAT(a, b) count(distinct a)
+abcdef 1
+hijklm 1
+SELECT 1 FROM t1 GROUP BY CONCAT(a, b);
+1
+1
+1
+INSERT INTO t1 values ('hij','klm');
+SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1;
+CONCAT(a, b) count(*)
+abcdef 1
+hijklm 2
+DROP TABLE t1;
diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test
index 50698bb8df6..0df93b5f220 100644
--- a/mysql-test/t/bdb.test
+++ b/mysql-test/t/bdb.test
@@ -767,3 +767,19 @@ select INFO_NOTE from t1 where STR_DATE = '20010610';
select INFO_NOTE from t1 where STR_DATE < '20010610';
select INFO_NOTE from t1 where STR_DATE > '20010610';
drop table t1;
+
+#
+# Test problem with multi table delete which quickly shows up with bdb tables.
+#
+
+create table t1 (a int not null, b int, primary key (a)) type =bdb;
+create table t2 (a int not null, b int, primary key (a)) type =bdb;
+insert into t1 values (2, 3),(1, 7),(10, 7);
+insert into t2 values (2, 3),(1, 7),(10, 7);
+select * from t1;
+select * from t2;
+delete t1, t2 from t1, t2 where t1.a = t2.a;
+select * from t1;
+select * from t2;
+select * from t2;
+drop table t1,t2;
diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test
index b98505e06b9..17ad9588f1b 100644
--- a/mysql-test/t/group_by.test
+++ b/mysql-test/t/group_by.test
@@ -266,3 +266,20 @@ SELECT binary a FROM t1 GROUP BY 1;
SELECT binary a,count(*) FROM t1 GROUP BY 1;
SET SQL_BIG_TABLES=0;
drop table t1;
+
+#
+# Test of key >= 256 bytes
+#
+
+CREATE TABLE t1 (
+ `a` char(193) default NULL,
+ `b` char(63) default NULL
+);
+INSERT INTO t1 VALUES ('abc','def'),('hij','klm');
+SELECT CONCAT(a, b) FROM t1 GROUP BY 1;
+SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1;
+SELECT CONCAT(a, b),count(distinct a) FROM t1 GROUP BY 1;
+SELECT 1 FROM t1 GROUP BY CONCAT(a, b);
+INSERT INTO t1 values ('hij','klm');
+SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1;
+DROP TABLE t1;
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 6a9187a7cb2..614d1b5abf5 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -1596,12 +1596,13 @@ int ha_berkeley::rnd_pos(byte * buf, byte *pos)
{
DBT db_pos;
statistic_increment(ha_read_rnd_count,&LOCK_status);
+ DBUG_ENTER("ha_berkeley::rnd_pos");
active_index= (uint) -1; // Don't delete via cursor
- return read_row(file->get(file, transaction,
- get_pos(&db_pos, pos),
- &current_row, 0),
- (char*) buf, primary_key, &current_row, (DBT*) 0, 0);
+ DBUG_RETURN(read_row(file->get(file, transaction,
+ get_pos(&db_pos, pos),
+ &current_row, 0),
+ (char*) buf, primary_key, &current_row, (DBT*) 0, 0));
}
void ha_berkeley::position(const byte *record)
diff --git a/sql/handler.cc b/sql/handler.cc
index 52d65edf0d4..e56bdb916bf 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -425,9 +425,8 @@ int handler::ha_open(const char *name, int mode, int test_if_locked)
{
if (table->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
table->db_stat|=HA_READ_ONLY;
- }
- if (!error)
- {
+ (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
+
if (!alloc_root_inited(&table->mem_root)) // If temporary table
ref=(byte*) sql_alloc(ALIGN_SIZE(ref_length)*2);
else
diff --git a/sql/records.cc b/sql/records.cc
index 395acbba47d..f156fdaf406 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -86,6 +86,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
}
else if (table->record_pointers)
{
+ DBUG_PRINT("info",("using record_pointers"));
table->file->rnd_init(0);
info->cache_pos=table->record_pointers;
info->cache_end=info->cache_pos+ table->found_records*info->ref_length;
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 795b63ac281..df8a8f1fdde 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -890,7 +890,7 @@ int collect_string(String *element,
int collect_real(double *element, element_count count __attribute__((unused)),
TREE_INFO *info)
{
- char buff[255];
+ char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff));
if (info->found)
@@ -909,7 +909,7 @@ int collect_longlong(longlong *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
{
- char buff[255];
+ char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff));
if (info->found)
@@ -928,7 +928,7 @@ int collect_ulonglong(ulonglong *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
{
- char buff[255];
+ char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff));
if (info->found)
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 88239eecf3c..a8be2d8b8f5 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -300,6 +300,7 @@ static void free_cache_entry(TABLE *table)
void free_io_cache(TABLE *table)
{
+ DBUG_ENTER("free_io_cache");
if (table->io_cache)
{
close_cached_file(table->io_cache);
@@ -311,6 +312,7 @@ void free_io_cache(TABLE *table)
my_free((gptr) table->record_pointers,MYF(0));
table->record_pointers=0;
}
+ DBUG_VOID_RETURN;
}
/* Close all tables which aren't in use by any thread */
@@ -1301,7 +1303,6 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
if (error)
goto err;
}
- (void) entry->file->extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
DBUG_RETURN(0);
err:
DBUG_RETURN(1);
@@ -1499,7 +1500,6 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
DBUG_RETURN(0);
}
- tmp_table->file->extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
tmp_table->reginfo.lock_type=TL_WRITE; // Simulate locked
tmp_table->tmp_table = (tmp_table->file->has_transactions() ?
TRANSACTIONAL_TMP_TABLE : TMP_TABLE);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index d9a7c4e5b55..2a7824eae68 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -98,7 +98,6 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
DBUG_RETURN(1);
}
}
- (void) table->file->extra(HA_EXTRA_NO_READCHECK);
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_QUICK);
@@ -157,8 +156,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
}
thd->proc_info="end";
end_read_record(&info);
- /* if (order) free_io_cache(table); */ /* QQ Should not be needed */
- (void) table->file->extra(HA_EXTRA_READCHECK);
+ free_io_cache(table); // Will not do any harm
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_NORMAL);
@@ -219,15 +217,11 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
not_trans_safe=false;
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
- (void) dt->table->file->extra(HA_EXTRA_NO_READCHECK);
/* Don't use key read with MULTI-TABLE-DELETE */
- (void) dt->table->file->extra(HA_EXTRA_NO_KEYREAD);
dt->table->used_keys=0;
for (dt=dt->next ; dt ; dt=dt->next,counter++)
{
TABLE *table=dt->table;
- (void) table->file->extra(HA_EXTRA_NO_READCHECK);
- (void) table->file->extra(HA_EXTRA_NO_KEYREAD);
table->used_keys=0;
tempfiles[counter] = new Unique (refposcmp2,
(void *) &table->file->ref_length,
@@ -291,13 +285,12 @@ multi_delete::initialize_tables(JOIN *join)
multi_delete::~multi_delete()
{
- /* Add back EXTRA_READCHECK; In 4.0.1 we shouldn't need this anymore */
for (table_being_deleted=delete_tables ;
table_being_deleted ;
table_being_deleted=table_being_deleted->next)
{
TABLE *t=table_being_deleted->table;
- (void) t->file->extra(HA_EXTRA_READCHECK);
+ free_io_cache(t); // Alloced by unique
t->no_keyread=0;
}
@@ -353,19 +346,17 @@ void multi_delete::send_error(uint errcode,const char *err)
/* First send error what ever it is ... */
::send_error(&thd->net,errcode,err);
- /* reset used flags */
-// delete_tables->table->no_keyread=0;
-
/* If nothing deleted return */
if (!deleted)
return;
+
/* Below can happen when thread is killed early ... */
if (!table_being_deleted)
table_being_deleted=delete_tables;
/*
- If rows from the first table only has been deleted and it is transactional,
- just do rollback.
+ If rows from the first table only has been deleted and it is
+ transactional, just do rollback.
The same if all tables are transactional, regardless of where we are.
In all other cases do attempt deletes ...
*/
@@ -411,27 +402,6 @@ int multi_delete::do_deletes (bool from_send_error)
break;
}
-#if USE_REGENERATE_TABLE
- // nice little optimization ....
- // but Monty has to fix generate_table...
- // This will not work for transactional tables because for other types
- // records is not absolute
- if (num_of_positions == table->file->records)
- {
- TABLE_LIST table_list;
- bzero((char*) &table_list,sizeof(table_list));
- table_list.name=table->table_name;
- table_list.real_name=table_being_deleted->real_name;
- table_list.table=table;
- table_list.grant=table->grant;
- table_list.db = table_being_deleted->db;
- error=generate_table(thd,&table_list,(TABLE *)0);
- if (error <= 0) {error = 1; break;}
- deleted += num_of_positions;
- continue;
- }
-#endif /* USE_REGENERATE_TABLE */
-
READ_RECORD info;
init_read_record(&info,thd,table,NULL,0,0);
while (!(error=info.read_record(&info)) &&
@@ -452,15 +422,19 @@ int multi_delete::do_deletes (bool from_send_error)
}
+/*
+ return: 0 sucess
+ 1 error
+*/
+
bool multi_delete::send_eof()
{
- thd->proc_info="deleting from reference tables"; /* out: 1 if error, 0 if success */
+ thd->proc_info="deleting from reference tables";
/* Does deletes for the last n - 1 tables, returns 0 if ok */
- int error = do_deletes(false); /* do_deletes returns 0 if success */
+ int error = do_deletes(false); // returns 0 if success
/* reset used flags */
-// delete_tables->table->no_keyread=0; // Will stay in comment until Monty approves changes
thd->proc_info="end";
if (error)
{
@@ -468,11 +442,12 @@ bool multi_delete::send_eof()
return 1;
}
- /* Write the SQL statement to the binlog if we deleted
- rows and we succeeded, or also in an error case when there
- was a non-transaction-safe table involved, since
- modifications in it cannot be rolled back. */
-
+ /*
+ Write the SQL statement to the binlog if we deleted
+ rows and we succeeded, or also in an error case when there
+ was a non-transaction-safe table involved, since
+ modifications in it cannot be rolled back.
+ */
if (deleted || not_trans_safe)
{
mysql_update_log.write(thd,thd->query,thd->query_length);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 9cda33d20d0..31c349d199b 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3447,7 +3447,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!param->quick_group)
group=0; // Can't use group key
else for (ORDER *tmp=group ; tmp ; tmp=tmp->next)
+ {
(*tmp->item)->marker=4; // Store null in key
+ if ((*tmp->item)->max_length >= MAX_CHAR_WIDTH)
+ using_unique_constraint=1;
+ }
if (param->group_length >= MAX_BLOB_WIDTH)
using_unique_constraint=1;
if (group)
@@ -3852,7 +3856,6 @@ static bool open_tmp_table(TABLE *table)
return(1);
}
/* VOID(ha_lock(table,F_WRLCK)); */ /* Single thread table */
- (void) table->file->extra(HA_EXTRA_NO_READCHECK); /* Not needed */
(void) table->file->extra(HA_EXTRA_QUICK); /* Faster */
return(0);
}
@@ -5651,7 +5654,6 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
DBUG_ENTER("remove_duplicates");
entry->reginfo.lock_type=TL_WRITE;
- entry->file->extra(HA_EXTRA_NO_READCHECK);
/* Calculate how many saved fields there is in list */
field_count=0;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index b9cf7478e0c..4f2bca88ce0 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -257,8 +257,6 @@ int mysql_update(THD *thd,
}
}
- if (!(test_flags & TEST_READCHECK)) /* For debugging */
- VOID(table->file->extra(HA_EXTRA_NO_READCHECK));
if (handle_duplicates == DUP_IGNORE)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
init_read_record(&info,thd,table,select,0,1);
@@ -303,7 +301,6 @@ int mysql_update(THD *thd,
}
end_read_record(&info);
thd->proc_info="end";
- VOID(table->file->extra(HA_EXTRA_READCHECK));
VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY));
table->time_stamp=save_time_stamp; // Restore auto timestamp pointer
using_transactions=table->file->has_transactions();
@@ -362,7 +359,6 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
for (TABLE_LIST *dt=ut ; dt ; dt=dt->next,counter++)
{
TABLE *table=ut->table;
- (void) ut->table->file->extra(HA_EXTRA_NO_READCHECK);
(void) ut->table->file->extra(HA_EXTRA_NO_KEYREAD);
dt->table->used_keys=0;
if (table->timestamp_field)
@@ -521,14 +517,12 @@ multi_update::initialize_tables(JOIN *join)
multi_update::~multi_update()
{
- /* Add back EXTRA_READCHECK; In 4.0.1 we shouldn't need this anymore */
int counter = 0;
for (table_being_updated=update_tables ;
table_being_updated ;
counter++, table_being_updated=table_being_updated->next)
{
TABLE *table=table_being_updated->table;
- (void)table->file->extra(HA_EXTRA_READCHECK);
if (error)
table->time_stamp=save_time_stamps[counter];
}