From f1bc25f5332633b528309b4301e6b5ad3bc89957 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 19 Oct 2006 23:05:53 -0700 Subject: Fixed bug #23478. If elements a not top-level IN subquery were accessed by an index and the subquery result set included a NULL value then the quantified predicate that contained the subquery was evaluated to NULL when it should return a non-null value. mysql-test/r/subselect.result: Added a test case for bug #23478. mysql-test/t/subselect.test: Added a test case for bug #23478. --- mysql-test/r/subselect.result | 15 +++++++++++++++ mysql-test/t/subselect.test | 17 +++++++++++++++++ sql/item_subselect.cc | 3 +++ 3 files changed, 35 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index ad847b5f156..28fbfc86657 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2982,3 +2982,18 @@ field1 field2 1 1 1 3 DROP TABLE t1, t2; +CREATE TABLE t1(a int, INDEX (a)); +INSERT INTO t1 VALUES (1), (3), (5), (7); +INSERT INTO t1 VALUES (NULL); +CREATE TABLE t2(a int); +INSERT INTO t2 VALUES (1),(2),(3); +EXPLAIN SELECT a, a IN (SELECT a FROM t1) FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 +2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 2 Using index +SELECT a, a IN (SELECT a FROM t1) FROM t2; +a a IN (SELECT a FROM t1) +1 1 +2 NULL +3 1 +DROP TABLE t1,t2; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 6defa8b16a5..ac035c72d18 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1948,4 +1948,21 @@ SELECT field1, field2 DROP TABLE t1, t2; +# +# Bug #23478: not top-level IN subquery returning a non-empty result set +# with possible NULL values by index access from the outer query +# + +CREATE TABLE t1(a int, INDEX (a)); +INSERT INTO t1 VALUES (1), (3), (5), (7); +INSERT INTO t1 VALUES (NULL); + +CREATE TABLE t2(a int); +INSERT INTO t2 VALUES (1),(2),(3); + +EXPLAIN SELECT a, a IN (SELECT a FROM t1) FROM t2; +SELECT a, a IN (SELECT a FROM t1) FROM t2; + +DROP TABLE t1,t2; + # End of 4.1 tests diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index f3be0663af8..1ab81d1862d 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -610,6 +610,7 @@ double Item_in_subselect::val() */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); + null_value= 0; if (exec()) { reset(); @@ -625,6 +626,7 @@ double Item_in_subselect::val() longlong Item_in_subselect::val_int() { DBUG_ASSERT(fixed == 1); + null_value= 0; if (exec()) { reset(); @@ -645,6 +647,7 @@ String *Item_in_subselect::val_str(String *str) */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); + null_value= 0; if (exec()) { reset(); -- cgit v1.2.1 From 0b861d92230e5718ddb82a2bd3be074e541bf552 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 23 Oct 2006 15:02:51 +0500 Subject: WL#3475 (Threads for the embedded server in mysqltest) Necessary code added to mysqltest.c. Disabled tests are available now. client/mysqltest.c: do_send_query function implemented, so now 'send' command will be run in separate thread for the embedded server. Mutex and condition added to the 'connection' struct for syncronisation purposes. Yes it'd be easier if we had pthread_join() command libmysql/libmysql.c: this isn't actually needed and causes problems in embedded server mysql-test/t/bdb-deadlock.test: test is available for the embedded server now mysql-test/t/flush.test: test is available for the embedded server now mysql-test/t/flush_block_commit.test: test is available for the embedded server now mysql-test/t/innodb-deadlock.test: test is available for the embedded server now mysql-test/t/innodb-lock.test: test is available for the embedded server now mysql-test/t/lock_multi.test: test is available for the embedded server now mysql-test/t/rename.test: test is available for the embedded server now mysql-test/t/show_check.test: test is available for the embedded server now mysql-test/t/status.test: test is available for the embedded server now --- client/mysqltest.c | 102 ++++++++++++++++++++++++++++++----- libmysql/libmysql.c | 7 --- mysql-test/t/bdb-deadlock.test | 8 --- mysql-test/t/flush.test | 8 --- mysql-test/t/flush_block_commit.test | 3 -- mysql-test/t/innodb-deadlock.test | 2 - mysql-test/t/innodb-lock.test | 2 - mysql-test/t/lock_multi.test | 8 --- mysql-test/t/rename.test | 4 -- mysql-test/t/show_check.test | 3 +- mysql-test/t/status.test | 7 --- 11 files changed, 90 insertions(+), 64 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index ad0f9f857bb..6889ae1a84c 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -23,6 +23,7 @@ * Matt Wagner * Monty * Jani + * Holyfoot **/ /********************************************************************** @@ -215,6 +216,12 @@ struct connection { MYSQL mysql; char *name; + + const char *cur_query; + int cur_query_len; + pthread_mutex_t mutex; + pthread_cond_t cond; + int query_done; }; typedef struct @@ -461,6 +468,57 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int len); static int handle_no_error(struct st_query *q); +#ifdef EMBEDDED_LIBRARY +/* + send_one_query executes query in separate thread what is + necessary in embedded library to run 'send' in proper way. + This implementation doesn't handle errors returned + by mysql_send_query. It's technically possible, though + i don't see where it is needed. +*/ +pthread_handler_decl(send_one_query, arg) +{ + struct connection *cn= (struct connection*)arg; + + mysql_thread_init(); + VOID(mysql_send_query(&cn->mysql, cn->cur_query, cn->cur_query_len)); + + mysql_thread_end(); + pthread_mutex_lock(&cn->mutex); + cn->query_done= 1; + VOID(pthread_cond_signal(&cn->cond)); + pthread_mutex_unlock(&cn->mutex); + pthread_exit(0); + return 0; +} + +static int do_send_query(struct connection *cn, const char *q, int q_len, + int flags) +{ + pthread_t tid; + + if (flags & QUERY_REAP) + return mysql_send_query(&cn->mysql, q, q_len); + + if (pthread_mutex_init(&cn->mutex, NULL) || + pthread_cond_init(&cn->cond, NULL)) + die("Error in the thread library"); + + cn->cur_query= q; + cn->cur_query_len= q_len; + cn->query_done= 0; + if (pthread_create(&tid, NULL, send_one_query, (void*)cn)) + die("Cannot start new thread for query"); + + return 0; +} + +#else /*EMBEDDED_LIBRARY*/ + +#define do_send_query(cn,q,q_len,flags) mysql_send_query(&cn->mysql, q, q_len) + +#endif /*EMBEDDED_LIBRARY*/ + static void do_eval(DYNAMIC_STRING* query_eval, const char *query) { const char *p; @@ -1849,7 +1907,7 @@ int close_connection(struct st_query *q) #ifndef EMBEDDED_LIBRARY if (q->type == Q_DIRTY_CLOSE) { - if (con->mysql.net.vio) + while (con->mysql.net.vio) { vio_delete(con->mysql.net.vio); con->mysql.net.vio = 0; @@ -2767,15 +2825,17 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) * the result will be read - for regular query, both bits must be on */ -static int run_query_normal(MYSQL *mysql, struct st_query *q, int flags); -static int run_query_stmt (MYSQL *mysql, struct st_query *q, int flags); +static int run_query_normal(struct connection *cn, struct st_query *q, + int flags); +static int run_query_stmt (struct connection *cn, struct st_query *q, + int flags); static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds); static int run_query_stmt_handle_error(char *query, struct st_query *q, MYSQL_STMT *stmt, DYNAMIC_STRING *ds); static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, DYNAMIC_STRING *ds); -static int run_query(MYSQL *mysql, struct st_query *q, int flags) +static int run_query(struct connection *cn, struct st_query *q, int flags) { /* @@ -2791,13 +2851,15 @@ static int run_query(MYSQL *mysql, struct st_query *q, int flags) if (ps_protocol_enabled && disable_info && (flags & QUERY_SEND) && (flags & QUERY_REAP) && ps_match_re(q->query)) - return run_query_stmt(mysql, q, flags); - return run_query_normal(mysql, q, flags); + return run_query_stmt(cn, q, flags); + return run_query_normal(cn, q, flags); } -static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) +static int run_query_normal(struct connection *cn, struct st_query* q, + int flags) { + MYSQL *mysql= &cn->mysql; MYSQL_RES* res= 0; uint i; int error= 0, err= 0, counter= 0; @@ -2833,11 +2895,24 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) if (flags & QUERY_SEND) { - got_error_on_send= mysql_send_query(mysql, query, query_len); + got_error_on_send= do_send_query(cn, query, query_len, flags); if (got_error_on_send && q->expected_errno[0].type == ERR_EMPTY) die("unable to send query '%s' (mysql_errno=%d , errno=%d)", query, mysql_errno(mysql), errno); } +#ifdef EMBEDDED_LIBRARY + /* + Here we handle 'reap' command, so we need to check if the + query's thread was finished and probably wait + */ + else if (flags & QUERY_REAP) + { + pthread_mutex_lock(&cn->mutex); + if (!cn->query_done) + pthread_cond_wait(&cn->cond, &cn->mutex); + pthread_mutex_unlock(&cn->mutex); + } +#endif /*EMBEDDED_LIBRARY*/ do { @@ -3038,8 +3113,9 @@ end: complete SEND+REAP */ -static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) +static int run_query_stmt(struct connection *cn, struct st_query *q, int flags) { + MYSQL *mysql= &cn->mysql; int error= 0; /* Function return code if "goto end;" */ int err; /* Temporary storage of return code from calls */ int query_len, got_error_on_execute; @@ -3095,7 +3171,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) C API. */ if ((err= mysql_stmt_prepare(stmt, query, query_len)) == CR_NO_PREPARE_STMT) - return run_query_normal(mysql, q, flags); + return run_query_normal(cn, q, flags); if (err != 0) { @@ -3922,7 +3998,7 @@ int main(int argc, char **argv) q->require_file=require_file; save_file[0]=0; } - error|= run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND); + error|= run_query(cur_con, q, QUERY_REAP|QUERY_SEND); display_result_vertically= old_display_result_vertically; q->last_argument= q->end; query_executed= 1; @@ -3949,7 +4025,7 @@ int main(int argc, char **argv) q->require_file=require_file; save_file[0]=0; } - error |= run_query(&cur_con->mysql, q, flags); + error |= run_query(cur_con, q, flags); query_executed= 1; q->last_argument= q->end; break; @@ -3970,7 +4046,7 @@ int main(int argc, char **argv) query and read the result some time later when reap instruction is given on this connection. */ - error |= run_query(&cur_con->mysql, q, QUERY_SEND); + error |= run_query(cur_con, q, QUERY_SEND); query_executed= 1; q->last_argument= q->end; break; diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 91c0b6b8864..5577ecdb556 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -4395,13 +4395,6 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); DBUG_RETURN(1); } - if (result->data) - { - free_root(&result->alloc, MYF(MY_KEEP_PREALLOC)); - result->data= NULL; - result->rows= 0; - stmt->data_cursor= NULL; - } if (stmt->update_max_length && !stmt->bind_result_done) { diff --git a/mysql-test/t/bdb-deadlock.test b/mysql-test/t/bdb-deadlock.test index 88243cfc860..b48648e0fd0 100644 --- a/mysql-test/t/bdb-deadlock.test +++ b/mysql-test/t/bdb-deadlock.test @@ -1,11 +1,3 @@ -# This test doesn't work with the embedded version as this code -# assumes that one query is running while we are doing queries on -# a second connection. -# This would work if mysqltest run would be threaded and handle each -# connection in a separate thread. -# - --- source include/not_embedded.inc -- source include/have_bdb.inc connect (con1,localhost,root,,); diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test index aedf8e85b65..8fe62ecac01 100644 --- a/mysql-test/t/flush.test +++ b/mysql-test/t/flush.test @@ -1,11 +1,3 @@ -# This test doesn't work with the embedded version as this code -# assumes that one query is running while we are doing queries on -# a second connection. -# This would work if mysqltest run would be threaded and handle each -# connection in a separate thread. -# --- source include/not_embedded.inc - connect (con1,localhost,root,,); connect (con2,localhost,root,,); connection con1; diff --git a/mysql-test/t/flush_block_commit.test b/mysql-test/t/flush_block_commit.test index 1e7ecd2548c..0c1d2b82df6 100644 --- a/mysql-test/t/flush_block_commit.test +++ b/mysql-test/t/flush_block_commit.test @@ -3,9 +3,6 @@ # We verify that we did not introduce a deadlock. # This is intended to mimick how mysqldump and innobackup work. -# This test doesn't work with the embedded server --- source include/not_embedded.inc - # And it requires InnoDB -- source include/have_innodb.inc diff --git a/mysql-test/t/innodb-deadlock.test b/mysql-test/t/innodb-deadlock.test index 41741942963..81acfba5c93 100644 --- a/mysql-test/t/innodb-deadlock.test +++ b/mysql-test/t/innodb-deadlock.test @@ -1,6 +1,4 @@ -- source include/have_innodb.inc -# Can't test this with embedded server --- source include/not_embedded.inc connect (con1,localhost,root,,); connect (con2,localhost,root,,); diff --git a/mysql-test/t/innodb-lock.test b/mysql-test/t/innodb-lock.test index 55a712fef9b..eacf7e562be 100644 --- a/mysql-test/t/innodb-lock.test +++ b/mysql-test/t/innodb-lock.test @@ -1,6 +1,4 @@ -- source include/have_innodb.inc -# Can't test this with embedded server --- source include/not_embedded.inc # # Check and select innodb lock type diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index 2e40aeaccb7..32e7f4234c4 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -1,11 +1,3 @@ -# This test doesn't work with the embedded version as this code -# assumes that one query is running while we are doing queries on -# a second connection. -# This would work if mysqltest run would be threaded and handle each -# connection in a separate thread. -# --- source include/not_embedded.inc - --disable_warnings drop table if exists t1,t2; --enable_warnings diff --git a/mysql-test/t/rename.test b/mysql-test/t/rename.test index 5caecef176e..ad9921d2cf0 100644 --- a/mysql-test/t/rename.test +++ b/mysql-test/t/rename.test @@ -2,10 +2,6 @@ # Test of rename table # -# Test requires concurrent connections, which can't be tested on embedded -# server --- source include/not_embedded.inc - --disable_warnings drop table if exists t0,t1,t2,t3,t4; # Clear up from other tests (to ensure that SHOW TABLES below is right) diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index d70903adbc4..8be676d9a35 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -1,5 +1,4 @@ -# Requires use of multiple simultaneous connections, not supported with -# embedded server testing +# Uses GRANT commands that usually disabled in embedded server -- source include/not_embedded.inc # diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 7fea51c9327..df8da26df57 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -1,10 +1,3 @@ -# This test doesn't work with the embedded version as this code -# assumes that one query is running while we are doing queries on -# a second connection. -# This would work if mysqltest run would be threaded and handle each -# connection in a separate thread. -# ---source include/not_embedded.inc # PS causes different statistics --disable_ps_protocol -- cgit v1.2.1 From 6ce7b1b2258fbda8ddaccfc24f49d7f89b83abb0 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 24 Oct 2006 12:35:32 +0500 Subject: merging fix client/mysqltest.c: wrong 'while' was added instead of 'if' --- client/mysqltest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 6889ae1a84c..3294612f7cc 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1907,7 +1907,7 @@ int close_connection(struct st_query *q) #ifndef EMBEDDED_LIBRARY if (q->type == Q_DIRTY_CLOSE) { - while (con->mysql.net.vio) + if (con->mysql.net.vio) { vio_delete(con->mysql.net.vio); con->mysql.net.vio = 0; @@ -2908,7 +2908,7 @@ static int run_query_normal(struct connection *cn, struct st_query* q, else if (flags & QUERY_REAP) { pthread_mutex_lock(&cn->mutex); - if (!cn->query_done) + while (!cn->query_done) pthread_cond_wait(&cn->cond, &cn->mutex); pthread_mutex_unlock(&cn->mutex); } -- cgit v1.2.1 From 92224b8726b7eb8ace3bf4fa0284c25c476242cc Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 24 Oct 2006 17:19:02 +0500 Subject: Bug #23427 (incompatible ABI change) the incompatibility was caused by current_stmt member added to the MYSQL structure. It's possible to move it to THD structure instead which saves ABI include/mysql.h: member moved to the THD structure libmysqld/lib_sql.cc: now we use THD member here sql/sql_class.h: current_stmt member added for the embedded server --- include/mysql.h | 6 ------ libmysqld/lib_sql.cc | 10 +++++----- sql/sql_class.h | 6 ++++++ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index 143f6752c46..89e861864df 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -270,12 +270,6 @@ typedef struct st_mysql from mysql_stmt_close if close had to cancel result set of this object. */ my_bool *unbuffered_fetch_owner; - /* - In embedded server it points to the statement that is processed - in the current query. We store some results directly in statement - fields then. - */ - struct st_mysql_stmt *current_stmt; } MYSQL; typedef struct st_mysql_res { diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 1a3e10f08a8..64bc37fb40d 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -94,7 +94,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, mysql->affected_rows= ~(my_ulonglong) 0; mysql->field_count= 0; net->last_errno= 0; - mysql->current_stmt= stmt; + thd->current_stmt= stmt; thd->store_globals(); // Fix if more than one connect /* @@ -644,8 +644,8 @@ bool Protocol::send_fields(List *list, uint flag) DBUG_RETURN(0); field_count= list->elements; - field_alloc= mysql->current_stmt ? &mysql->current_stmt->mem_root : - &mysql->field_alloc; + field_alloc= thd->current_stmt ? &thd->current_stmt->mem_root : + &mysql->field_alloc; if (!(client_field= mysql->fields= (MYSQL_FIELD *)alloc_root(field_alloc, sizeof(MYSQL_FIELD) * field_count))) @@ -751,8 +751,8 @@ bool Protocol_prep::write() { MYSQL *mysql= thd->mysql; - if (mysql->current_stmt) - data= &mysql->current_stmt->result; + if (thd->current_stmt) + data= &thd->current_stmt->result; else { if (!(data= (MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), diff --git a/sql/sql_class.h b/sql/sql_class.h index cc90de2a6ea..ed161de55de 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -686,6 +686,12 @@ public: char *extra_data; ulong extra_length; String query_rest; + /* + In embedded server it points to the statement that is processed + in the current query. We store some results directly in statement + fields then. + */ + struct st_mysql_stmt *current_stmt; #endif NET net; // client connection descriptor MEM_ROOT warn_root; // For warnings and errors -- cgit v1.2.1 From f8ba4f1fad03021aaaf50c38436c1fc5c5838ad8 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Nov 2006 18:48:16 +0200 Subject: Bug #22457: Column alias in ORDER BY works, but not if in an expression The parser is allocating Item_field for references by name in ORDER BY expressions. Such expressions however may point not only to Item_field in the select list (or to a table column) but also to an arbitrary Item. This causes Item_field::fix_fields to throw an error about missing column. The fix substitutes Item_field for the reference with an Item_ref when not pointing to Item_field. mysql-test/r/order_by.result: Bug #22457: Column alias in ORDER BY works, but not if in an expression - test case mysql-test/t/order_by.test: Bug #22457: Column alias in ORDER BY works, but not if in an expression - test case sql/item.cc: Bug #22457: Column alias in ORDER BY works, but not if in an expression - transform the Item_field made by the parser into Item_ref if it doesn't point to Item_field and it is in allowed context --- mysql-test/r/order_by.result | 27 +++++++++++++++++++++++++++ mysql-test/t/order_by.test | 16 ++++++++++++++++ sql/item.cc | 33 ++++++++++++++++++++++++++++++--- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 8126e223f55..320bb89b62e 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -820,3 +820,30 @@ b a 20 1 10 2 DROP TABLE t1; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +SELECT a + 1 AS num FROM t1 ORDER BY 30 - num; +num +3 +2 +SELECT CONCAT('test', a) AS str FROM t1 ORDER BY UPPER(str); +str +test1 +test2 +SELECT a + 1 AS num FROM t1 GROUP BY 30 - num; +num +3 +2 +SELECT a + 1 AS num FROM t1 HAVING 30 - num; +num +2 +3 +SELECT a + 1 AS num, num + 1 FROM t1; +ERROR 42S22: Unknown column 'num' in 'field list' +SELECT a + 1 AS num, (select num + 2 FROM t1 LIMIT 1) FROM t1; +num (select num + 2 FROM t1 LIMIT 1) +2 4 +3 5 +SELECT a.a + 1 AS num FROM t1 a JOIN t1 b ON num = b.a; +ERROR 42S22: Unknown column 'num' in 'on clause' +DROP TABLE t1; diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 1664afc70f9..a8024be7032 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -559,4 +559,20 @@ INSERT INTO t1 VALUES (1,30), (2,20), (1,10), (2,30), (1,20), (2,10); DROP TABLE t1; +# +# Bug #22457: Column alias in ORDER BY works, but not if in an expression +# + +CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); +SELECT a + 1 AS num FROM t1 ORDER BY 30 - num; +SELECT CONCAT('test', a) AS str FROM t1 ORDER BY UPPER(str); +SELECT a + 1 AS num FROM t1 GROUP BY 30 - num; +SELECT a + 1 AS num FROM t1 HAVING 30 - num; +--error 1054 +SELECT a + 1 AS num, num + 1 FROM t1; +SELECT a + 1 AS num, (select num + 2 FROM t1 LIMIT 1) FROM t1; +--error 1054 +SELECT a.a + 1 AS num FROM t1 a JOIN t1 b ON num = b.a; +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/item.cc b/sql/item.cc index 94f0a24fcc3..45d7856b2c1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1761,10 +1761,37 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) Item** res= find_item_in_list(this, thd->lex->current_select->item_list, &counter, REPORT_EXCEPT_NOT_FOUND, ¬_used); - if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM) + if (res != (Item **)not_found_item) { - set_field((*((Item_field**)res))->field); - return 0; + if ((*res)->type() == Item::FIELD_ITEM) + { + /* + It's an Item_field referencing another Item_field in the select + list. + use the field from the Item_field in the select list and leave + the Item_field instance in place. + */ + set_field((*((Item_field**)res))->field); + return 0; + } + else + { + /* + It's not an Item_field in the select list so we must make a new + Item_ref to point to the Item in the select list and replace the + Item_field created by the parser with the new Item_ref. + */ + Item_ref *rf= new Item_ref(db_name,table_name,field_name); + if (!rf) + return 1; + thd->change_item_tree(ref, rf); + /* + Because Item_ref never substitutes itself with other items + in Item_ref::fix_fields(), we can safely use the original + pointer to it even after fix_fields() + */ + return rf->fix_fields(thd, tables, ref) || rf->check_cols(1); + } } } -- cgit v1.2.1 From 7881866a948ffa174a9ee3f81633de291b4c4433 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Nov 2006 18:16:17 +0200 Subject: Bug #11032: getObject() returns a String for a sub-query of type datetime - When returning metadata for scalar subqueries the actual type of the column was calculated based on the value type, which limits the actual type of a scalar subselect to the set of (currently) 3 basic types : integer, double precision or string. This is the reason that columns of types other then the basic ones (e.g. date/time) are reported as being of the corresponding basic type. Fixed by storing/returning information for the column type in addition to the result type. mysql-test/r/subselect.result: Bug #11032: getObject() returns a String for a sub-query of type datetime - test case mysql-test/t/subselect.test: Bug #11032: getObject() returns a String for a sub-query of type datetime - test case sql/item_subselect.cc: Bug #11032: getObject() returns a String for a sub-query of type datetime - store and return the field type as well in addition to result type for single row subqueries sql/item_subselect.h: Bug #11032: getObject() returns a String for a sub-query of type datetime - store and return the field type as well in addition to result type for single row subqueries --- mysql-test/r/subselect.result | 17 +++++++++++++++++ mysql-test/t/subselect.test | 16 ++++++++++++++++ sql/item_subselect.cc | 34 ++++++++++++++++++++++++---------- sql/item_subselect.h | 7 +++++++ 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 28fbfc86657..a3d1bafcb0d 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2997,3 +2997,20 @@ a a IN (SELECT a FROM t1) 2 NULL 3 1 DROP TABLE t1,t2; +CREATE TABLE t1 (a DATETIME); +INSERT INTO t1 VALUES ('1998-09-23'), ('2003-03-25'); +CREATE TABLE t2 AS SELECT +(SELECT a FROM t1 WHERE a < '2000-01-01') AS sub_a +FROM t1 WHERE a > '2000-01-01'; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `sub_a` datetime default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CREATE TABLE t3 AS (SELECT a FROM t1 WHERE a < '2000-01-01') UNION (SELECT a FROM t1 WHERE a > '2000-01-01'); +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `a` datetime default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1,t2,t3; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index ac035c72d18..11b7fcc4d8f 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1965,4 +1965,20 @@ SELECT a, a IN (SELECT a FROM t1) FROM t2; DROP TABLE t1,t2; +# +# Bug #11302: getObject() returns a String for a sub-query of type datetime +# +CREATE TABLE t1 (a DATETIME); +INSERT INTO t1 VALUES ('1998-09-23'), ('2003-03-25'); + +CREATE TABLE t2 AS SELECT + (SELECT a FROM t1 WHERE a < '2000-01-01') AS sub_a + FROM t1 WHERE a > '2000-01-01'; +SHOW CREATE TABLE t2; + +CREATE TABLE t3 AS (SELECT a FROM t1 WHERE a < '2000-01-01') UNION (SELECT a FROM t1 WHERE a > '2000-01-01'); +SHOW CREATE TABLE t3; + +DROP TABLE t1,t2,t3; + # End of 4.1 tests diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 1ab81d1862d..cd1f8f83821 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -391,6 +391,15 @@ enum Item_result Item_singlerow_subselect::result_type() const return engine->type(); } +/* + Don't rely on the result type to calculate field type. + Ask the engine instead. +*/ +enum_field_types Item_singlerow_subselect::field_type() const +{ + return engine->field_type(); +} + void Item_singlerow_subselect::fix_length_and_dec() { if ((max_columns= engine->cols()) == 1) @@ -1357,31 +1366,35 @@ int subselect_uniquesubquery_engine::prepare() return 1; } -static Item_result set_row(List &item_list, Item *item, - Item_cache **row, bool *maybe_null) +/* + makes storage for the output values for the subquery and calcuates + their data and column types and their nullability. +*/ +void subselect_engine::set_row(List &item_list, Item_cache **row) { - Item_result res_type= STRING_RESULT; Item *sel_item; List_iterator_fast li(item_list); + res_type= STRING_RESULT; + res_field_type= FIELD_TYPE_VAR_STRING; for (uint i= 0; (sel_item= li++); i++) { item->max_length= sel_item->max_length; res_type= sel_item->result_type(); + res_field_type= sel_item->field_type(); item->decimals= sel_item->decimals; - *maybe_null= sel_item->maybe_null; + maybe_null= sel_item->maybe_null; if (!(row[i]= Item_cache::get_cache(res_type))) - return STRING_RESULT; // we should return something + return; row[i]->setup(sel_item); } if (item_list.elements > 1) res_type= ROW_RESULT; - return res_type; } void subselect_single_select_engine::fix_length_and_dec(Item_cache **row) { DBUG_ASSERT(row || select_lex->item_list.elements==1); - res_type= set_row(select_lex->item_list, item, row, &maybe_null); + set_row(select_lex->item_list, row); item->collation.set(row[0]->collation); if (cols() != 1) maybe_null= 0; @@ -1393,13 +1406,14 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row) if (unit->first_select()->item_list.elements == 1) { - res_type= set_row(unit->types, item, row, &maybe_null); + set_row(unit->types, row); item->collation.set(row[0]->collation); } else { - bool fake= 0; - res_type= set_row(unit->types, item, row, &fake); + bool maybe_null_saved= maybe_null; + set_row(unit->types, row); + maybe_null= maybe_null_saved; } } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 93171ad64a1..7b064bfe92c 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -142,6 +142,7 @@ public: longlong val_int (); String *val_str (String *); enum Item_result result_type() const; + enum_field_types field_type() const; void fix_length_and_dec(); uint cols(); @@ -273,6 +274,7 @@ protected: THD *thd; /* pointer to current THD */ Item_subselect *item; /* item, that use this engine */ enum Item_result res_type; /* type of results */ + enum_field_types res_field_type; /* column type of the results */ bool maybe_null; /* may be null (first item in select) */ public: @@ -282,6 +284,7 @@ public: result= res; item= si; res_type= STRING_RESULT; + res_field_type= FIELD_TYPE_VAR_STRING; maybe_null= 0; } virtual ~subselect_engine() {}; // to satisfy compiler @@ -296,6 +299,7 @@ public: virtual uint cols()= 0; /* return number of columnss in select */ virtual uint8 uncacheable()= 0; /* query is uncacheable */ enum Item_result type() { return res_type; } + enum_field_types field_type() { return res_field_type; } virtual void exclude()= 0; bool may_be_null() { return maybe_null; }; virtual table_map upper_select_const_tables()= 0; @@ -303,6 +307,9 @@ public: virtual void print(String *str)= 0; virtual int change_item(Item_subselect *si, select_subselect *result)= 0; virtual bool no_tables()= 0; + +protected: + void set_row(List &item_list, Item_cache **row); }; -- cgit v1.2.1 From b73a83220d7150ed001435c2e06b535844bd30b2 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Nov 2006 15:15:56 +0200 Subject: Make a new test target for autopush.pl to run memory based tests --- Makefile.am | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Makefile.am b/Makefile.am index 2aefbd05283..48f84269313 100644 --- a/Makefile.am +++ b/Makefile.am @@ -124,3 +124,10 @@ test-force-pl: cd mysql-test; \ ./mysql-test-run.pl --force && \ ./mysql-test-run.pl --ps-protocol --force + +#used by autopush.pl to run memory based tests +test-force-mem: + cd mysql-test; \ + ./mysql-test-run.pl --force --mem && \ + ./mysql-test-run.pl --ps-protocol --force --mem + -- cgit v1.2.1 From e04385d87dc6d7aaae6abadbe9f51376a3247e1e Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 13 Nov 2006 12:28:55 +0200 Subject: Bug #19216: Client crashes on long SELECT The server sends a number of columns to the client. It uses a limited "fast" function for that instead of the general one. This fast function cannot send numbers larger than 2 bytes. This causes the client to expect smaller number of columns. The client writes outside of the allocated memory buffer as a result. Fixed the server to use the general function to send column count. Fixed the client to check the column count before writing column data. mysql-test/t/mysql_client.test: Bug #19216: Client crashes on long SELECT - test case sql/protocol.cc: Bug #19216: Client crashes on long SELECT - renamed the function for bether comprehention and made it local - used the right (non-local) function to transfer the column count in Protocol::send_fields sql/protocol.h: Bug #19216: Client crashes on long SELECT - made optimized net_store_length local sql-common/client.c: Bug #19216: Client crashes on long SELECT - fixed the client to check for older servers (without the fix). --- mysql-test/t/mysql_client.test | 18 ++++++++++++++++++ sql-common/client.c | 2 ++ sql/protocol.cc | 18 +++++++++--------- sql/protocol.h | 1 - 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/mysql-test/t/mysql_client.test b/mysql-test/t/mysql_client.test index b382357dacf..7bd7c762c5c 100644 --- a/mysql-test/t/mysql_client.test +++ b/mysql-test/t/mysql_client.test @@ -33,3 +33,21 @@ # --exec echo 'help' | $MYSQL > $MYSQLTEST_VARDIR/tmp/bug20328.tmp --exec echo 'help ' | $MYSQL > $MYSQLTEST_VARDIR/tmp/bug20328.tmp + +# +# Bug #19216: Client crashes on long SELECT +# +--exec echo "select" > $MYSQLTEST_VARDIR/tmp/b19216.tmp +# 3400 * 20 makes 68000 columns that is more than the max number that can fit +# in a 16 bit number. +let $i= 3400; +while ($i) +{ + --exec echo "'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'," >> $MYSQLTEST_VARDIR/tmp/b19216.tmp + dec $i; +} + +--exec echo "'b';" >> $MYSQLTEST_VARDIR/tmp/b19216.tmp +--disable_query_log +--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/b19216.tmp >/dev/null +--enable_query_log diff --git a/sql-common/client.c b/sql-common/client.c index ff5f1ef150a..fb32eea33c7 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1173,6 +1173,8 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, for (row=data->data; row ; row = row->next,field++) { uchar *pos; + /* fields count may be wrong */ + DBUG_ASSERT ((field - result) < fields); cli_fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7); field->catalog = strdup_root(alloc,(char*) row->data[0]); field->db = strdup_root(alloc,(char*) row->data[1]); diff --git a/sql/protocol.cc b/sql/protocol.cc index a2287740f1e..7c7dfaf7bef 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -43,7 +43,7 @@ bool Protocol_prep::net_store_data(const char *from, uint length) packet->realloc(packet_length+9+length)) return 1; char *to=(char*) net_store_length((char*) packet->ptr()+packet_length, - (ulonglong) length); + length); memcpy(to,from,length); packet->length((uint) (to+length-packet->ptr())); return 0; @@ -297,8 +297,8 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) DBUG_VOID_RETURN; buff[0]=0; // No fields - pos=net_store_length(buff+1,(ulonglong) affected_rows); - pos=net_store_length(pos, (ulonglong) id); + pos=net_store_length(buff+1,affected_rows); + pos=net_store_length(pos, id); if (thd->client_capabilities & CLIENT_PROTOCOL_41) { DBUG_PRINT("info", @@ -416,7 +416,7 @@ bool send_old_password_request(THD *thd) ulonglong for bigger numbers. */ -char *net_store_length(char *pkg, uint length) +static char *net_store_length_fast(char *pkg, uint length) { uchar *packet=(uchar*) pkg; if (length < 251) @@ -439,7 +439,7 @@ char *net_store_length(char *pkg, uint length) char *net_store_data(char *to,const char *from, uint length) { - to=net_store_length(to,length); + to=net_store_length_fast(to,length); memcpy(to,from,length); return to+length; } @@ -448,7 +448,7 @@ char *net_store_data(char *to,int32 from) { char buff[20]; uint length=(uint) (int10_to_str(from,buff,10)-buff); - to=net_store_length(to,length); + to=net_store_length_fast(to,length); memcpy(to,buff,length); return to+length; } @@ -457,7 +457,7 @@ char *net_store_data(char *to,longlong from) { char buff[22]; uint length=(uint) (longlong10_to_str(from,buff,10)-buff); - to=net_store_length(to,length); + to=net_store_length_fast(to,length); memcpy(to,buff,length); return to+length; } @@ -520,7 +520,7 @@ bool Protocol::send_fields(List *list, uint flag) if (flag & 1) { // Packet with number of elements - char *pos=net_store_length(buff, (uint) list->elements); + char *pos=net_store_length(buff, list->elements); (void) my_net_write(&thd->net, buff,(uint) (pos-buff)); } @@ -648,7 +648,7 @@ bool Protocol::send_records_num(List *list, ulonglong records) { char *pos; char buff[20]; - pos=net_store_length(buff, (uint) list->elements); + pos=net_store_length(buff, list->elements); pos=net_store_length(pos, records); return my_net_write(&thd->net, buff,(uint) (pos-buff)); } diff --git a/sql/protocol.h b/sql/protocol.h index 32d6acccddf..ce3adb41df5 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -177,7 +177,6 @@ void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, const char *info=0); void send_eof(THD *thd, bool no_flush=0); bool send_old_password_request(THD *thd); -char *net_store_length(char *packet,uint length); char *net_store_data(char *to,const char *from, uint length); char *net_store_data(char *to,int32 from); char *net_store_data(char *to,longlong from); -- cgit v1.2.1 From aa681ccfb9ced774fd29cbdfe069a44090a17bd4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 16 Nov 2006 21:23:34 +0400 Subject: merging --- client/mysqltest.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index f2f2dc85d72..b73ee831cf3 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -183,18 +183,6 @@ DYNAMIC_ARRAY q_lines; #include "sslopt-vars.h" -struct connection -{ - MYSQL mysql; - char *name; - - const char *cur_query; - int cur_query_len; - pthread_mutex_t mutex; - pthread_cond_t cond; - int query_done; -}; - struct { int read_lines,current_line; @@ -234,6 +222,12 @@ struct st_connection MYSQL* util_mysql; char *name; MYSQL_STMT* stmt; + + const char *cur_query; + int cur_query_len; + pthread_mutex_t mutex; + pthread_cond_t cond; + int query_done; }; struct st_connection connections[128]; struct st_connection* cur_con, *next_con, *connections_end; @@ -493,7 +487,7 @@ void handle_no_error(struct st_command*); */ pthread_handler_decl(send_one_query, arg) { - struct connection *cn= (struct connection*)arg; + struct st_connection *cn= (struct st_connection*)arg; mysql_thread_init(); VOID(mysql_send_query(&cn->mysql, cn->cur_query, cn->cur_query_len)); @@ -507,7 +501,7 @@ pthread_handler_decl(send_one_query, arg) return 0; } -static int do_send_query(struct connection *cn, const char *q, int q_len, +static int do_send_query(struct st_connection *cn, const char *q, int q_len, int flags) { pthread_t tid; @@ -4570,7 +4564,7 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) error - function will not return */ -void run_query_normal(struct connection *cn, *mysql, struct st_command *command, +void run_query_normal(struct st_connection *cn, struct st_command *command, int flags, char *query, int query_len, DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings) { @@ -4598,7 +4592,7 @@ void run_query_normal(struct connection *cn, *mysql, struct st_command *command, Here we handle 'reap' command, so we need to check if the query's thread was finished and probably wait */ - else if (flags & QUERY_REAP) + else if (flags & QUERY_REAP_FLAG) { pthread_mutex_lock(&cn->mutex); while (!cn->query_done) @@ -5096,8 +5090,9 @@ int util_query(MYSQL* org_mysql, const char* query){ */ -void run_query(MYSQL *mysql, struct st_command *command, int flags) +void run_query(struct st_connection *cn, struct st_command *command, int flags) { + MYSQL *mysql= &cn->mysql; DYNAMIC_STRING *ds; DYNAMIC_STRING ds_result; DYNAMIC_STRING ds_warnings; @@ -5254,7 +5249,7 @@ void run_query(MYSQL *mysql, struct st_command *command, int flags) match_re(&ps_re, query)) run_query_stmt(mysql, command, query, query_len, ds, &ds_warnings); else - run_query_normal(mysql, command, flags, query, query_len, + run_query_normal(cn, command, flags, query, query_len, ds, &ds_warnings); if (sp_created) @@ -5746,7 +5741,7 @@ int main(int argc, char **argv) strmake(command->require_file, save_file, sizeof(save_file)); save_file[0]= 0; } - run_query(cur, command, flags); + run_query(cur_con, command, flags); command_executed++; command->last_argument= command->end; break; -- cgit v1.2.1 From 5a0cf28a597cc843b1591f63009fe1caa1984ae1 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 16 Nov 2006 23:00:48 +0400 Subject: merging --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 48f84269313..12a867c1ad7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -126,7 +126,7 @@ test-force-pl: ./mysql-test-run.pl --ps-protocol --force #used by autopush.pl to run memory based tests -test-force-mem: +test-force-pl-mem: cd mysql-test; \ ./mysql-test-run.pl --force --mem && \ ./mysql-test-run.pl --ps-protocol --force --mem -- cgit v1.2.1