mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
A fix and a test case for Bug#9520 "SELECT DISTINCT crashes server
with cursor". The patch refactors do_select/sub_select functions, which implement the nested loop algorithm, and reuses them to fetch rows for cursors as well. Pushing with view.test failing (--ps-protocol).
This commit is contained in:
@ -2223,7 +2223,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
|
|||||||
my_pthread_setprio(pthread_self(), QUERY_PRIOR);
|
my_pthread_setprio(pthread_self(), QUERY_PRIOR);
|
||||||
|
|
||||||
thd->protocol= &thd->protocol_prep; // Switch to binary protocol
|
thd->protocol= &thd->protocol_prep; // Switch to binary protocol
|
||||||
(void) stmt->cursor->fetch(num_rows);
|
stmt->cursor->fetch(num_rows);
|
||||||
thd->protocol= &thd->protocol_simple; // Use normal protocol
|
thd->protocol= &thd->protocol_simple; // Use normal protocol
|
||||||
|
|
||||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -91,7 +91,15 @@ enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
|
|||||||
|
|
||||||
class JOIN;
|
class JOIN;
|
||||||
|
|
||||||
typedef int (*Next_select_func)(JOIN *,struct st_join_table *,bool);
|
enum enum_nested_loop_state
|
||||||
|
{
|
||||||
|
NESTED_LOOP_KILLED= -2, NESTED_LOOP_ERROR= -1,
|
||||||
|
NESTED_LOOP_OK= 0, NESTED_LOOP_NO_MORE_ROWS= 1,
|
||||||
|
NESTED_LOOP_QUERY_LIMIT= 3, NESTED_LOOP_CURSOR_LIMIT= 4
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum_nested_loop_state
|
||||||
|
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
|
||||||
typedef int (*Read_record_func)(struct st_join_table *tab);
|
typedef int (*Read_record_func)(struct st_join_table *tab);
|
||||||
|
|
||||||
|
|
||||||
@ -162,6 +170,11 @@ class JOIN :public Sql_alloc
|
|||||||
uint send_group_parts;
|
uint send_group_parts;
|
||||||
bool sort_and_group,first_record,full_join,group, no_field_update;
|
bool sort_and_group,first_record,full_join,group, no_field_update;
|
||||||
bool do_send_rows;
|
bool do_send_rows;
|
||||||
|
/*
|
||||||
|
TRUE when we want to resume nested loop iterations when
|
||||||
|
fetching data from a cursor
|
||||||
|
*/
|
||||||
|
bool resume_nested_loop;
|
||||||
table_map const_table_map,found_const_table_map,outer_join;
|
table_map const_table_map,found_const_table_map,outer_join;
|
||||||
ha_rows send_records,found_records,examined_rows,row_limit, select_limit;
|
ha_rows send_records,found_records,examined_rows,row_limit, select_limit;
|
||||||
/*
|
/*
|
||||||
@ -263,6 +276,7 @@ class JOIN :public Sql_alloc
|
|||||||
sort_and_group= 0;
|
sort_and_group= 0;
|
||||||
first_record= 0;
|
first_record= 0;
|
||||||
do_send_rows= 1;
|
do_send_rows= 1;
|
||||||
|
resume_nested_loop= FALSE;
|
||||||
send_records= 0;
|
send_records= 0;
|
||||||
found_records= 0;
|
found_records= 0;
|
||||||
fetch_limit= HA_POS_ERROR;
|
fetch_limit= HA_POS_ERROR;
|
||||||
@ -374,7 +388,7 @@ public:
|
|||||||
void reset_thd(THD *thd);
|
void reset_thd(THD *thd);
|
||||||
|
|
||||||
int open(JOIN *join);
|
int open(JOIN *join);
|
||||||
int fetch(ulong num_rows);
|
void fetch(ulong num_rows);
|
||||||
void reset() { join= 0; }
|
void reset() { join= 0; }
|
||||||
bool is_open() const { return join != 0; }
|
bool is_open() const { return join != 0; }
|
||||||
void close();
|
void close();
|
||||||
|
@ -12854,6 +12854,59 @@ static void test_bug9159()
|
|||||||
myquery(rc);
|
myquery(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Crash when opening a cursor to a query with DISTICNT and no key */
|
||||||
|
|
||||||
|
static void test_bug9520()
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt;
|
||||||
|
MYSQL_BIND bind[1];
|
||||||
|
char a[6];
|
||||||
|
ulong a_len;
|
||||||
|
int rc, row_count= 0;
|
||||||
|
|
||||||
|
myheader("test_bug9520");
|
||||||
|
|
||||||
|
mysql_query(mysql, "drop table if exists t1");
|
||||||
|
mysql_query(mysql, "create table t1 (a char(5), b char(5), c char(5),"
|
||||||
|
" primary key (a, b, c))");
|
||||||
|
rc= mysql_query(mysql, "insert into t1 values ('x', 'y', 'z'), "
|
||||||
|
" ('a', 'b', 'c'), ('k', 'l', 'm')");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
stmt= open_cursor("select distinct b from t1");
|
||||||
|
|
||||||
|
/*
|
||||||
|
Not crashes with:
|
||||||
|
stmt= open_cursor("select distinct a from t1");
|
||||||
|
*/
|
||||||
|
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
bzero(bind, sizeof(bind));
|
||||||
|
bind[0].buffer_type= MYSQL_TYPE_STRING;
|
||||||
|
bind[0].buffer= (char*) a;
|
||||||
|
bind[0].buffer_length= sizeof(a);
|
||||||
|
bind[0].length= &a_len;
|
||||||
|
|
||||||
|
mysql_stmt_bind_result(stmt, bind);
|
||||||
|
|
||||||
|
while (!(rc= mysql_stmt_fetch(stmt)))
|
||||||
|
row_count++;
|
||||||
|
|
||||||
|
DIE_UNLESS(rc == MYSQL_NO_DATA);
|
||||||
|
|
||||||
|
printf("Fetched %d rows\n", row_count);
|
||||||
|
DBUG_ASSERT(row_count == 3);
|
||||||
|
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "drop table t1");
|
||||||
|
myquery(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read and parse arguments and MySQL options from my.cnf
|
Read and parse arguments and MySQL options from my.cnf
|
||||||
*/
|
*/
|
||||||
@ -13079,6 +13132,7 @@ static struct my_tests_st my_tests[]= {
|
|||||||
{ "test_bug8722", test_bug8722 },
|
{ "test_bug8722", test_bug8722 },
|
||||||
{ "test_bug8880", test_bug8880 },
|
{ "test_bug8880", test_bug8880 },
|
||||||
{ "test_bug9159", test_bug9159 },
|
{ "test_bug9159", test_bug9159 },
|
||||||
|
{ "test_bug9520", test_bug9520 },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user