Loading sql/sql_class.h +28 −17 Original line number Diff line number Diff line Loading @@ -1112,6 +1112,13 @@ class select_result :public Sql_alloc { unit= u; return 0; } /* Because of peculiarities of prepared statements protocol we need to know number of columns in the result set (if there is a result set) apart from sending columns metadata. */ virtual uint field_count(List<Item> &fields) const { return fields.elements; } virtual bool send_fields(List<Item> &list,uint flag)=0; virtual bool send_data(List<Item> &items)=0; virtual bool initialize_tables (JOIN *join=0) { return 0; } Loading @@ -1126,6 +1133,20 @@ class select_result :public Sql_alloc { }; /* Base class for select_result descendands which intercept and transform result set rows. As the rows are not sent to the client, sending of result set metadata should be suppressed as well. */ class select_result_interceptor: public select_result { public: uint field_count(List<Item> &fields) const { return 0; } bool send_fields(List<Item> &fields, uint flag) { return FALSE; } }; class select_send :public select_result { public: select_send() {} Loading @@ -1135,7 +1156,7 @@ class select_send :public select_result { }; class select_to_file :public select_result { class select_to_file :public select_result_interceptor { protected: sql_exchange *exchange; File file; Loading @@ -1147,7 +1168,6 @@ class select_to_file :public select_result { select_to_file(sql_exchange *ex) :exchange(ex), file(-1),row_count(0L) { path[0]=0; } ~select_to_file(); bool send_fields(List<Item> &list, uint flag) { return 0; } void send_error(uint errcode,const char *err); bool send_eof(); void cleanup(); Loading @@ -1174,7 +1194,7 @@ class select_dump :public select_to_file { }; class select_insert :public select_result { class select_insert :public select_result_interceptor { public: TABLE *table; List<Item> *fields; Loading @@ -1190,8 +1210,6 @@ class select_insert :public select_result { } ~select_insert(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); void send_error(uint errcode,const char *err); bool send_eof(); Loading Loading @@ -1274,7 +1292,7 @@ class TMP_TABLE_PARAM :public Sql_alloc } }; class select_union :public select_result { class select_union :public select_result_interceptor { public: TABLE *table; COPY_INFO info; Loading @@ -1283,8 +1301,6 @@ class select_union :public select_result { select_union(TABLE *table_par); ~select_union(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); bool send_eof(); bool flush(); Loading @@ -1292,13 +1308,12 @@ class select_union :public select_result { }; /* Base subselect interface class */ class select_subselect :public select_result class select_subselect :public select_result_interceptor { protected: Item_subselect *item; public: select_subselect(Item_subselect *item); bool send_fields(List<Item> &list, uint flag) { return 0; }; bool send_data(List<Item> &items)=0; bool send_eof() { return 0; }; }; Loading Loading @@ -1435,7 +1450,7 @@ class Unique :public Sql_alloc }; class multi_delete :public select_result class multi_delete :public select_result_interceptor { TABLE_LIST *delete_tables, *table_being_deleted; Unique **tempfiles; Loading @@ -1448,8 +1463,6 @@ class multi_delete :public select_result multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); Loading @@ -1458,7 +1471,7 @@ class multi_delete :public select_result }; class multi_update :public select_result class multi_update :public select_result_interceptor { TABLE_LIST *all_tables, *update_tables, *table_being_updated; THD *thd; Loading @@ -1477,7 +1490,6 @@ class multi_update :public select_result List<Item> *values, enum_duplicates handle_duplicates); ~multi_update(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); Loading @@ -1486,7 +1498,7 @@ class multi_update :public select_result }; class select_dumpvar :public select_result { class select_dumpvar :public select_result_interceptor { ha_rows row_count; public: List<LEX_STRING> var_list; Loading @@ -1494,7 +1506,6 @@ class select_dumpvar :public select_result { select_dumpvar(void) { var_list.empty(); vars.empty(); row_count=0;} ~select_dumpvar() {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) {return 0;} bool send_data(List<Item> &items); bool send_eof(); void cleanup(); Loading sql/sql_prepare.cc +13 −2 Original line number Diff line number Diff line Loading @@ -1064,6 +1064,12 @@ static int mysql_test_select(Prepared_statement *stmt, DBUG_RETURN(1); #endif if (!lex->result && !(lex->result= new (&stmt->mem_root) select_send)) { send_error(thd); goto err; } if (open_and_lock_tables(thd, tables)) { send_error(thd); Loading @@ -1087,8 +1093,13 @@ static int mysql_test_select(Prepared_statement *stmt, } else { if (send_prep_stmt(stmt, lex->select_lex.item_list.elements) || thd->protocol_simple.send_fields(&lex->select_lex.item_list, 0) List<Item> &fields= lex->select_lex.item_list; /* We can use lex->result as it should've been prepared in unit->prepare call above. */ if (send_prep_stmt(stmt, lex->result->field_count(fields)) || lex->result->send_fields(fields, 0) #ifndef EMBEDDED_LIBRARY || net_flush(&thd->net) #endif Loading tests/client_test.c +18 −0 Original line number Diff line number Diff line Loading @@ -10625,6 +10625,23 @@ static void test_bug6058() } static void test_bug6059() { MYSQL_STMT *stmt; const char *stmt_text; int rc; myheader("test_bug6059"); stmt_text= "SELECT 'foo' INTO OUTFILE 'x.3'"; stmt= mysql_stmt_init(mysql); rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); DIE_UNLESS(mysql_stmt_field_count(stmt) == 0); mysql_stmt_close(stmt); } /* Read and parse arguments and MySQL options from my.cnf Loading Loading @@ -10938,6 +10955,7 @@ int main(int argc, char **argv) prepared statements */ test_bug6049(); /* check support for negative TIME values */ test_bug6058(); /* check support for 0000-00-00 dates */ test_bug6059(); /* correct metadata for SELECT ... INTO OUTFILE */ /* XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. Loading Loading
sql/sql_class.h +28 −17 Original line number Diff line number Diff line Loading @@ -1112,6 +1112,13 @@ class select_result :public Sql_alloc { unit= u; return 0; } /* Because of peculiarities of prepared statements protocol we need to know number of columns in the result set (if there is a result set) apart from sending columns metadata. */ virtual uint field_count(List<Item> &fields) const { return fields.elements; } virtual bool send_fields(List<Item> &list,uint flag)=0; virtual bool send_data(List<Item> &items)=0; virtual bool initialize_tables (JOIN *join=0) { return 0; } Loading @@ -1126,6 +1133,20 @@ class select_result :public Sql_alloc { }; /* Base class for select_result descendands which intercept and transform result set rows. As the rows are not sent to the client, sending of result set metadata should be suppressed as well. */ class select_result_interceptor: public select_result { public: uint field_count(List<Item> &fields) const { return 0; } bool send_fields(List<Item> &fields, uint flag) { return FALSE; } }; class select_send :public select_result { public: select_send() {} Loading @@ -1135,7 +1156,7 @@ class select_send :public select_result { }; class select_to_file :public select_result { class select_to_file :public select_result_interceptor { protected: sql_exchange *exchange; File file; Loading @@ -1147,7 +1168,6 @@ class select_to_file :public select_result { select_to_file(sql_exchange *ex) :exchange(ex), file(-1),row_count(0L) { path[0]=0; } ~select_to_file(); bool send_fields(List<Item> &list, uint flag) { return 0; } void send_error(uint errcode,const char *err); bool send_eof(); void cleanup(); Loading @@ -1174,7 +1194,7 @@ class select_dump :public select_to_file { }; class select_insert :public select_result { class select_insert :public select_result_interceptor { public: TABLE *table; List<Item> *fields; Loading @@ -1190,8 +1210,6 @@ class select_insert :public select_result { } ~select_insert(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); void send_error(uint errcode,const char *err); bool send_eof(); Loading Loading @@ -1274,7 +1292,7 @@ class TMP_TABLE_PARAM :public Sql_alloc } }; class select_union :public select_result { class select_union :public select_result_interceptor { public: TABLE *table; COPY_INFO info; Loading @@ -1283,8 +1301,6 @@ class select_union :public select_result { select_union(TABLE *table_par); ~select_union(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); bool send_eof(); bool flush(); Loading @@ -1292,13 +1308,12 @@ class select_union :public select_result { }; /* Base subselect interface class */ class select_subselect :public select_result class select_subselect :public select_result_interceptor { protected: Item_subselect *item; public: select_subselect(Item_subselect *item); bool send_fields(List<Item> &list, uint flag) { return 0; }; bool send_data(List<Item> &items)=0; bool send_eof() { return 0; }; }; Loading Loading @@ -1435,7 +1450,7 @@ class Unique :public Sql_alloc }; class multi_delete :public select_result class multi_delete :public select_result_interceptor { TABLE_LIST *delete_tables, *table_being_deleted; Unique **tempfiles; Loading @@ -1448,8 +1463,6 @@ class multi_delete :public select_result multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); Loading @@ -1458,7 +1471,7 @@ class multi_delete :public select_result }; class multi_update :public select_result class multi_update :public select_result_interceptor { TABLE_LIST *all_tables, *update_tables, *table_being_updated; THD *thd; Loading @@ -1477,7 +1490,6 @@ class multi_update :public select_result List<Item> *values, enum_duplicates handle_duplicates); ~multi_update(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); Loading @@ -1486,7 +1498,7 @@ class multi_update :public select_result }; class select_dumpvar :public select_result { class select_dumpvar :public select_result_interceptor { ha_rows row_count; public: List<LEX_STRING> var_list; Loading @@ -1494,7 +1506,6 @@ class select_dumpvar :public select_result { select_dumpvar(void) { var_list.empty(); vars.empty(); row_count=0;} ~select_dumpvar() {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) {return 0;} bool send_data(List<Item> &items); bool send_eof(); void cleanup(); Loading
sql/sql_prepare.cc +13 −2 Original line number Diff line number Diff line Loading @@ -1064,6 +1064,12 @@ static int mysql_test_select(Prepared_statement *stmt, DBUG_RETURN(1); #endif if (!lex->result && !(lex->result= new (&stmt->mem_root) select_send)) { send_error(thd); goto err; } if (open_and_lock_tables(thd, tables)) { send_error(thd); Loading @@ -1087,8 +1093,13 @@ static int mysql_test_select(Prepared_statement *stmt, } else { if (send_prep_stmt(stmt, lex->select_lex.item_list.elements) || thd->protocol_simple.send_fields(&lex->select_lex.item_list, 0) List<Item> &fields= lex->select_lex.item_list; /* We can use lex->result as it should've been prepared in unit->prepare call above. */ if (send_prep_stmt(stmt, lex->result->field_count(fields)) || lex->result->send_fields(fields, 0) #ifndef EMBEDDED_LIBRARY || net_flush(&thd->net) #endif Loading
tests/client_test.c +18 −0 Original line number Diff line number Diff line Loading @@ -10625,6 +10625,23 @@ static void test_bug6058() } static void test_bug6059() { MYSQL_STMT *stmt; const char *stmt_text; int rc; myheader("test_bug6059"); stmt_text= "SELECT 'foo' INTO OUTFILE 'x.3'"; stmt= mysql_stmt_init(mysql); rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); DIE_UNLESS(mysql_stmt_field_count(stmt) == 0); mysql_stmt_close(stmt); } /* Read and parse arguments and MySQL options from my.cnf Loading Loading @@ -10938,6 +10955,7 @@ int main(int argc, char **argv) prepared statements */ test_bug6049(); /* check support for negative TIME values */ test_bug6058(); /* check support for 0000-00-00 dates */ test_bug6059(); /* correct metadata for SELECT ... INTO OUTFILE */ /* XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. Loading