Commit a3bee835 authored by Michael Widenius's avatar Michael Widenius

Fixed lp:970528 "Server crashes in my_strnncollsp_simple on LEFT JOIN with CSV table, TEXT field"

The main problem was a bug in CSV where it provided wrong statistics (it claimed the table was empty when it wasn't)
I also fixed wrong freeing of blob's in the CSV handler. (Any call to handler::read_first_row() on a CSV table with blobs would fail)



mysql-test/r/csv.result:
  Added new test case
mysql-test/r/partition_innodb.result:
  Updated test results after fixing bug with impossible partitions and const tables
mysql-test/t/csv.test:
  Added new test case
sql/sql_select.cc:
  Cleaned up code for handling of partitions.
  Fixed also a bug where we didn't threat a table with impossible partitions as a const table.
storage/csv/ha_tina.cc:
  Allocate blobroot onces.
parent 9b8542a4
...@@ -5415,4 +5415,17 @@ foo ...@@ -5415,4 +5415,17 @@ foo
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 ( b TEXT NOT NULL ) ENGINE=MYISAM;
INSERT INTO t1 VALUES ('x'),('y');
CREATE TABLE t2 ( a VARCHAR(1) NOT NULL ) ENGINE=CSV;
INSERT INTO t2 VALUES ('r'),('t');
SELECT * FROM t2 ORDER BY a;
a
r
t
SELECT * FROM t1 LEFT JOIN t2 ON ( b = a );
b a
x NULL
y NULL
drop table t1,t2;
End of 5.1 tests End of 5.1 tests
...@@ -48,13 +48,13 @@ insert INTO t1 VALUES (110); ...@@ -48,13 +48,13 @@ insert INTO t1 VALUES (110);
ERROR HY000: Table has no partition for value 110 ERROR HY000: Table has no partition for value 110
EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > 90; EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > 90;
id select_type table partitions type possible_keys key key_len ref rows Extra id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 0 Using where 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= 90; EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= 90;
id select_type table partitions type possible_keys key key_len ref rows Extra id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 0 Using where 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = 90; EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = 90;
id select_type table partitions type possible_keys key key_len ref rows Extra id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 0 Using where 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = 89; EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = 89;
id select_type table partitions type possible_keys key key_len ref rows Extra id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p90 ALL NULL NULL NULL NULL 3 Using where 1 SIMPLE t1 p90 ALL NULL NULL NULL NULL 3 Using where
...@@ -63,16 +63,16 @@ id select_type table partitions type possible_keys key key_len ref rows Extra ...@@ -63,16 +63,16 @@ id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p90 ALL NULL NULL NULL NULL 3 Using where 1 SIMPLE t1 p90 ALL NULL NULL NULL NULL 3 Using where
EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > 89; EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > 89;
id select_type table partitions type possible_keys key key_len ref rows Extra id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 0 Using where 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = 100; EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = 100;
id select_type table partitions type possible_keys key key_len ref rows Extra id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 0 Using where 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= 100; EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= 100;
id select_type table partitions type possible_keys key key_len ref rows Extra id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 0 Using where 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > 100; EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > 100;
id select_type table partitions type possible_keys key key_len ref rows Extra id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 0 Using where 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
DROP TABLE t1; DROP TABLE t1;
# #
# Bug#50104: Partitioned table with just 1 partion works with fk # Bug#50104: Partitioned table with just 1 partion works with fk
......
...@@ -1820,5 +1820,20 @@ INSERT INTO t1 VALUES(-1); ...@@ -1820,5 +1820,20 @@ INSERT INTO t1 VALUES(-1);
SELECT * FROM t1; SELECT * FROM t1;
DROP TABLE t1; DROP TABLE t1;
#
# Bug#970528
# Server crashes in my_strnncollsp_simple on LEFT JOIN with CSV table,
# TEXT field
#
CREATE TABLE t1 ( b TEXT NOT NULL ) ENGINE=MYISAM;
INSERT INTO t1 VALUES ('x'),('y');
CREATE TABLE t2 ( a VARCHAR(1) NOT NULL ) ENGINE=CSV;
INSERT INTO t2 VALUES ('r'),('t');
SELECT * FROM t2 ORDER BY a;
SELECT * FROM t1 LEFT JOIN t2 ON ( b = a );
drop table t1,t2;
--echo End of 5.1 tests --echo End of 5.1 tests
...@@ -2691,6 +2691,11 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, ...@@ -2691,6 +2691,11 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
table_vector[i]=s->table=table=tables->table; table_vector[i]=s->table=table=tables->table;
table->pos_in_table_list= tables; table->pos_in_table_list= tables;
error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
#ifdef WITH_PARTITION_STORAGE_ENGINE
const bool no_partitions_used= table->no_partitions_used;
#else
const bool no_partitions_used= FALSE;
#endif
DBUG_EXECUTE_IF("bug11747970_raise_error", DBUG_EXECUTE_IF("bug11747970_raise_error",
{ {
...@@ -2724,11 +2729,9 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, ...@@ -2724,11 +2729,9 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
if (*s->on_expr_ref) if (*s->on_expr_ref)
{ {
/* s is the only inner table of an outer join */ /* s is the only inner table of an outer join */
#ifdef WITH_PARTITION_STORAGE_ENGINE if (((!table->file->stats.records &&
if ((!table->file->stats.records || table->no_partitions_used) && !embedding) (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) ||
#else no_partitions_used) && !embedding)
if (!table->file->stats.records && !embedding)
#endif
{ // Empty table { // Empty table
s->dependent= 0; // Ignore LEFT JOIN depend. s->dependent= 0; // Ignore LEFT JOIN depend.
no_rows_const_tables |= table->map; no_rows_const_tables |= table->map;
...@@ -2756,15 +2759,11 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, ...@@ -2756,15 +2759,11 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
while (embedding); while (embedding);
continue; continue;
} }
#ifdef WITH_PARTITION_STORAGE_ENGINE if ((table->s->system ||
const bool no_partitions_used= table->no_partitions_used; (table->file->stats.records <= 1 &&
#else (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) ||
const bool no_partitions_used= FALSE;
#endif
if ((table->s->system || table->file->stats.records <= 1 ||
no_partitions_used) && no_partitions_used) &&
!s->dependent && !s->dependent &&
(table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
!table->fulltext_searched && !join->no_const_tables) !table->fulltext_searched && !join->no_const_tables)
{ {
set_position(join,const_count++,s,(KEYUSE*) 0); set_position(join,const_count++,s,(KEYUSE*) 0);
......
...@@ -854,6 +854,7 @@ int ha_tina::open(const char *name, int mode, uint open_options) ...@@ -854,6 +854,7 @@ int ha_tina::open(const char *name, int mode, uint open_options)
*/ */
thr_lock_data_init(&share->lock, &lock, (void*) this); thr_lock_data_init(&share->lock, &lock, (void*) this);
ref_length= sizeof(my_off_t); ref_length= sizeof(my_off_t);
init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
share->lock.get_status= tina_get_status; share->lock.get_status= tina_get_status;
share->lock.update_status= tina_update_status; share->lock.update_status= tina_update_status;
...@@ -871,6 +872,7 @@ int ha_tina::close(void) ...@@ -871,6 +872,7 @@ int ha_tina::close(void)
{ {
int rc= 0; int rc= 0;
DBUG_ENTER("ha_tina::close"); DBUG_ENTER("ha_tina::close");
free_root(&blobroot, MYF(0));
rc= my_close(data_file, MYF(0)); rc= my_close(data_file, MYF(0));
DBUG_RETURN(free_share(share) || rc); DBUG_RETURN(free_share(share) || rc);
} }
...@@ -1086,11 +1088,9 @@ int ha_tina::rnd_init(bool scan) ...@@ -1086,11 +1088,9 @@ int ha_tina::rnd_init(bool scan)
current_position= next_position= 0; current_position= next_position= 0;
stats.records= 0; stats.records= 0;
records_is_known= 0; records_is_known= found_end_of_file= 0;
chain_ptr= chain; chain_ptr= chain;
init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -1122,10 +1122,16 @@ int ha_tina::rnd_next(uchar *buf) ...@@ -1122,10 +1122,16 @@ int ha_tina::rnd_next(uchar *buf)
/* don't scan an empty file */ /* don't scan an empty file */
if (!local_saved_data_file_length) if (!local_saved_data_file_length)
{
found_end_of_file= 1;
DBUG_RETURN(HA_ERR_END_OF_FILE); DBUG_RETURN(HA_ERR_END_OF_FILE);
}
if ((rc= find_current_row(buf))) if ((rc= find_current_row(buf)))
{
DBUG_PRINT("warning", ("got error %d while reading file", rc));
found_end_of_file= (rc == HA_ERR_END_OF_FILE);
DBUG_RETURN(rc); DBUG_RETURN(rc);
}
stats.records++; stats.records++;
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -1220,8 +1226,7 @@ int ha_tina::rnd_end() ...@@ -1220,8 +1226,7 @@ int ha_tina::rnd_end()
my_off_t file_buffer_start= 0; my_off_t file_buffer_start= 0;
DBUG_ENTER("ha_tina::rnd_end"); DBUG_ENTER("ha_tina::rnd_end");
free_root(&blobroot, MYF(0)); records_is_known= found_end_of_file;
records_is_known= 1;
if ((chain_ptr - chain) > 0) if ((chain_ptr - chain) > 0)
{ {
...@@ -1394,8 +1399,6 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1394,8 +1399,6 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt)
/* set current position to the beginning of the file */ /* set current position to the beginning of the file */
current_position= next_position= 0; current_position= next_position= 0;
init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
/* Read the file row-by-row. If everything is ok, repair is not needed. */ /* Read the file row-by-row. If everything is ok, repair is not needed. */
while (!(rc= find_current_row(buf))) while (!(rc= find_current_row(buf)))
{ {
...@@ -1603,8 +1606,6 @@ int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1603,8 +1606,6 @@ int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt)
/* set current position to the beginning of the file */ /* set current position to the beginning of the file */
current_position= next_position= 0; current_position= next_position= 0;
init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
/* Read the file row-by-row. If everything is ok, repair is not needed. */ /* Read the file row-by-row. If everything is ok, repair is not needed. */
while (!(rc= find_current_row(buf))) while (!(rc= find_current_row(buf)))
{ {
...@@ -1628,6 +1629,13 @@ int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1628,6 +1629,13 @@ int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt)
} }
int ha_tina::reset(void)
{
free_root(&blobroot, MYF(0));
return 0;
}
bool ha_tina::check_if_incompatible_data(HA_CREATE_INFO *info, bool ha_tina::check_if_incompatible_data(HA_CREATE_INFO *info,
uint table_changes) uint table_changes)
{ {
......
...@@ -84,7 +84,7 @@ class ha_tina: public handler ...@@ -84,7 +84,7 @@ class ha_tina: public handler
uchar chain_alloced; uchar chain_alloced;
uint32 chain_size; uint32 chain_size;
uint local_data_file_version; /* Saved version of the data file used */ uint local_data_file_version; /* Saved version of the data file used */
bool records_is_known; bool records_is_known, found_end_of_file;
MEM_ROOT blobroot; MEM_ROOT blobroot;
private: private:
...@@ -156,6 +156,7 @@ class ha_tina: public handler ...@@ -156,6 +156,7 @@ class ha_tina: public handler
bool auto_repair() const { return 1; } bool auto_repair() const { return 1; }
void position(const uchar *record); void position(const uchar *record);
int info(uint); int info(uint);
int reset();
int extra(enum ha_extra_function operation); int extra(enum ha_extra_function operation);
int delete_all_rows(void); int delete_all_rows(void);
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
......
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