summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <holyfoot/hf@mysql.com/deer.(none)>2006-11-16 23:16:44 +0400
committerunknown <holyfoot/hf@mysql.com/deer.(none)>2006-11-16 23:16:44 +0400
commite971334eced6516f92ea5b63b06ac703e145192b (patch)
tree5400912843b70b171dc06c8cdc96a6f3329a25db
parentdaaddeb656c26c685962fef69d19e7f264620e2b (diff)
parente78fd1d14b7b151c4968702a28292d1d41b4f2ea (diff)
downloadmariadb-git-e971334eced6516f92ea5b63b06ac703e145192b.tar.gz
Merge mysql.com:/home/hf/work/mysql-4.1-mrg
into mysql.com:/home/hf/work/mysql-5.0-mrg client/mysqltest.c: Auto merged mysql-test/t/flush.test: Auto merged mysql-test/t/flush_block_commit.test: Auto merged mysql-test/t/innodb-deadlock.test: Auto merged mysql-test/t/innodb-lock.test: Auto merged mysql-test/t/lock_multi.test: Auto merged mysql-test/t/rename.test: Auto merged mysql-test/t/show_check.test: Auto merged mysql-test/t/status.test: Auto merged sql/item.cc: Auto merged sql/protocol.h: Auto merged sql-common/client.c: Auto merged Makefile.am: merging BitKeeper/deleted/.del-mysql_client.test: merging include/mysql.h: SCCS merged libmysql/libmysql.c: merging libmysqld/lib_sql.cc: merging mysql-test/r/order_by.result: SCCS merged mysql-test/r/subselect.result: SCCS merged mysql-test/t/order_by.test: merging mysql-test/t/subselect.test: SCCS merged sql/item_subselect.cc: merging sql/item_subselect.h: merging sql/protocol.cc: merging sql/sql_class.h: merging
-rw-r--r--client/mysqltest.c89
-rw-r--r--libmysqld/lib_sql.cc1
-rw-r--r--mysql-test/r/order_by.result27
-rw-r--r--mysql-test/r/subselect.result32
-rw-r--r--mysql-test/t/bdb-deadlock.test8
-rw-r--r--mysql-test/t/flush.test8
-rw-r--r--mysql-test/t/flush_block_commit.test3
-rw-r--r--mysql-test/t/innodb-deadlock.test2
-rw-r--r--mysql-test/t/innodb-lock.test2
-rw-r--r--mysql-test/t/lock_multi.test8
-rw-r--r--mysql-test/t/order_by.test75
-rw-r--r--mysql-test/t/rename.test4
-rw-r--r--mysql-test/t/show_check.test3
-rw-r--r--mysql-test/t/status.test7
-rw-r--r--mysql-test/t/subselect.test33
-rw-r--r--sql-common/client.c2
-rw-r--r--sql/item.cc33
-rw-r--r--sql/item_subselect.cc35
-rw-r--r--sql/item_subselect.h4
-rw-r--r--sql/protocol.cc16
-rw-r--r--sql/protocol.h1
-rw-r--r--sql/sql_class.h6
22 files changed, 324 insertions, 75 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 561bc541c74..433810934d6 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -29,6 +29,7 @@
Matt Wagner <matt@mysql.com>
Monty
Jani
+ Holyfoot
*/
#define MTEST_VERSION "3.0"
@@ -220,6 +221,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;
@@ -458,7 +465,6 @@ void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; }
my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
#endif
-
void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
int len);
void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
@@ -470,6 +476,56 @@ void handle_error(struct st_command*,
void handle_no_error(struct st_command*);
+#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 st_connection *cn= (struct st_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 st_connection *cn, const char *q, int q_len,
+ int flags)
+{
+ pthread_t tid;
+
+ if (flags & QUERY_REAP_FLAG)
+ 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*/
void do_eval(DYNAMIC_STRING *query_eval, const char *query,
const char *query_end, my_bool pass_through_escape_chars)
@@ -4498,7 +4554,6 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql)
}
-
/*
Run query using MySQL C API
@@ -4515,10 +4570,11 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql)
error - function will not return
*/
-void run_query_normal(MYSQL *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)
{
+ MYSQL *mysql= &cn->mysql;
MYSQL_RES *res= 0;
int err= 0, counter= 0;
DBUG_ENTER("run_query_normal");
@@ -4530,14 +4586,26 @@ void run_query_normal(MYSQL *mysql, struct st_command *command,
/*
Send the query
*/
- if (mysql_send_query(mysql, query, query_len))
+ if (do_send_query(cn, query, query_len, flags))
{
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
mysql_sqlstate(mysql), ds);
goto end;
}
}
-
+#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_FLAG)
+ {
+ pthread_mutex_lock(&cn->mutex);
+ while (!cn->query_done)
+ pthread_cond_wait(&cn->cond, &cn->mutex);
+ pthread_mutex_unlock(&cn->mutex);
+ }
+#endif /*EMBEDDED_LIBRARY*/
if (!(flags & QUERY_REAP_FLAG))
DBUG_VOID_RETURN;
@@ -5028,8 +5096,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;
@@ -5186,7 +5255,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)
@@ -5651,7 +5720,7 @@ int main(int argc, char **argv)
strmake(command->require_file, save_file, sizeof(save_file));
save_file[0]= 0;
}
- run_query(&cur_con->mysql, command, QUERY_REAP_FLAG|QUERY_SEND_FLAG);
+ run_query(cur_con, command, QUERY_REAP_FLAG|QUERY_SEND_FLAG);
display_result_vertically= old_display_result_vertically;
command->last_argument= command->end;
command_executed++;
@@ -5682,7 +5751,7 @@ int main(int argc, char **argv)
strmake(command->require_file, save_file, sizeof(save_file));
save_file[0]= 0;
}
- run_query(&cur_con->mysql, command, flags);
+ run_query(cur_con, command, flags);
command_executed++;
command->last_argument= command->end;
break;
@@ -5708,7 +5777,7 @@ int main(int argc, char **argv)
the query and read the result some time later when reap instruction
is given on this connection.
*/
- run_query(&cur_con->mysql, command, QUERY_SEND_FLAG);
+ run_query(cur_con, command, QUERY_SEND_FLAG);
command_executed++;
command->last_argument= command->end;
break;
diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
index 98c75dfe719..a88c0b135db 100644
--- a/libmysqld/lib_sql.cc
+++ b/libmysqld/lib_sql.cc
@@ -100,6 +100,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;
+ thd->current_stmt= stmt;
thd->store_globals(); // Fix if more than one connect
/*
diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result
index 64653de5e9c..be29b310434 100644
--- a/mysql-test/r/order_by.result
+++ b/mysql-test/r/order_by.result
@@ -854,6 +854,33 @@ 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;
CREATE TABLE t1 (a int, b int, PRIMARY KEY (a));
INSERT INTO t1 VALUES (1,1), (2,2), (3,3);
explain SELECT t1.b as a, t2.b as c FROM
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index ec9fc2c307b..37f871a4c7c 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -3001,6 +3001,38 @@ 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;
+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;
create table t1 (df decimal(5,1));
insert into t1 values(1.1);
insert into t1 values(2.2);
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 95ba633fefd..3a4f2f2f5f2 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 ebb48242a4d..4412b2c357c 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 33e268ccb11..d3eeee3b41c 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/order_by.test b/mysql-test/t/order_by.test
index 1104c859ab8..ff75186f64e 100644
--- a/mysql-test/t/order_by.test
+++ b/mysql-test/t/order_by.test
@@ -514,6 +514,81 @@ set max_sort_length=20;
select a from t1 order by a;
drop table t1;
+#
+# Bug #7331
+#
+
+create table t1 (
+ `sid` decimal(8,0) default null,
+ `wnid` varchar(11) not null default '',
+ key `wnid14` (`wnid`(4)),
+ key `wnid` (`wnid`)
+) engine=myisam default charset=latin1;
+
+insert into t1 (`sid`, `wnid`) values
+('10100','01019000000'),('37986','01019000000'),('37987','01019010000'),
+('39560','01019090000'),('37989','01019000000'),('37990','01019011000'),
+('37991','01019011000'),('37992','01019019000'),('37993','01019030000'),
+('37994','01019090000'),('475','02070000000'),('25253','02071100000'),
+('25255','02071100000'),('25256','02071110000'),('25258','02071130000'),
+('25259','02071190000'),('25260','02071200000'),('25261','02071210000'),
+('25262','02071290000'),('25263','02071300000'),('25264','02071310000'),
+('25265','02071310000'),('25266','02071320000'),('25267','02071320000'),
+('25269','02071330000'),('25270','02071340000'),('25271','02071350000'),
+('25272','02071360000'),('25273','02071370000'),('25281','02071391000'),
+('25282','02071391000'),('25283','02071399000'),('25284','02071400000'),
+('25285','02071410000'),('25286','02071410000'),('25287','02071420000'),
+('25288','02071420000'),('25291','02071430000'),('25290','02071440000'),
+('25292','02071450000'),('25293','02071460000'),('25294','02071470000'),
+('25295','02071491000'),('25296','02071491000'),('25297','02071499000');
+
+explain select * from t1 where wnid like '0101%' order by wnid;
+
+select * from t1 where wnid like '0101%' order by wnid;
+
+drop table t1;
+
+#
+# Bug #7672 - a wrong result for a select query in braces followed by order by
+#
+
+CREATE TABLE t1 (a int);
+INSERT INTO t1 VALUES (2), (1), (1), (2), (1);
+SELECT a FROM t1 ORDER BY a;
+(SELECT a FROM t1) ORDER BY a;
+DROP TABLE t1;
+
+#
+# Bug #18767: global ORDER BY applied to a SELECT with ORDER BY either was
+# ignored or 'concatened' to the latter.
+
+CREATE TABLE t1 (a int, b int);
+INSERT INTO t1 VALUES (1,30), (2,20), (1,10), (2,30), (1,20), (2,10);
+
+(SELECT b,a FROM t1 ORDER BY a,b) ORDER BY b,a;
+(SELECT b FROM t1 ORDER BY b DESC) ORDER BY b ASC;
+(SELECT b,a FROM t1 ORDER BY b,a) ORDER BY a,b;
+(SELECT b,a FROM t1 ORDER by b,a LIMIT 3) ORDER by a,b;
+
+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
create table t1 (a int not null, b int not null, c int not null);
insert t1 values (1,1,1),(1,1,2),(1,2,1);
select a, b from t1 group by a, b order by sum(c);
diff --git a/mysql-test/t/rename.test b/mysql-test/t/rename.test
index 09a02344203..fce37d8466d 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 849be577893..369ae9bff65 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 1a71425d2a7..9d5adf57f81 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
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index dee5b1e4fb0..d62b0e77952 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -1955,6 +1955,39 @@ 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;
+
+#
+# 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-common/client.c b/sql-common/client.c
index fc913f3f3cf..5d17f3cc5c6 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -1191,6 +1191,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/item.cc b/sql/item.cc
index f3081551299..3864ee966c4 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3638,10 +3638,37 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
Item** res= find_item_in_list(this, thd->lex->current_select->item_list,
&counter, REPORT_EXCEPT_NOT_FOUND,
&not_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);
+ }
}
}
if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 0ad517609c9..5251bb91a70 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)
@@ -667,6 +676,7 @@ double Item_in_subselect::val_real()
*/
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
+ null_value= 0;
if (exec())
{
reset();
@@ -687,6 +697,7 @@ longlong Item_in_subselect::val_int()
*/
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
+ null_value= 0;
if (exec())
{
reset();
@@ -707,6 +718,7 @@ String *Item_in_subselect::val_str(String *str)
*/
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
+ null_value= 0;
if (exec())
{
reset();
@@ -1499,32 +1511,36 @@ int subselect_uniquesubquery_engine::prepare()
return 1;
}
-static Item_result set_row(List<Item> &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> &item_list, Item_cache **row)
{
- Item_result res_type= STRING_RESULT;
Item *sel_item;
List_iterator_fast<Item> 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;
item->unsigned_flag= sel_item->unsigned_flag;
*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;
@@ -1536,13 +1552,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 45df4f3880d..a48ff3e2429 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -155,6 +155,7 @@ public:
my_decimal *val_decimal(my_decimal *);
bool val_bool();
enum Item_result result_type() const;
+ enum_field_types field_type() const;
void fix_length_and_dec();
uint cols();
@@ -291,6 +292,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:
@@ -300,6 +302,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
@@ -317,6 +320,7 @@ public:
virtual uint cols()= 0; /* return number of columns 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;
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 5de24ebdcb3..e7a8d493341 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -46,7 +46,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;
@@ -280,8 +280,8 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
}
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",
@@ -456,7 +456,7 @@ void net_send_error_packet(THD *thd, uint sql_errno, const char *err)
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)
@@ -479,7 +479,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;
}
@@ -488,7 +488,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;
}
@@ -497,7 +497,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;
}
@@ -561,7 +561,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
if (flags & SEND_NUM_ROWS)
{ // 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));
}
diff --git a/sql/protocol.h b/sql/protocol.h
index 85c22724b74..7e2bc1516ec 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -166,7 +166,6 @@ void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
const char *info=0);
void send_eof(THD *thd);
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);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index c7bdfbd7ea7..35ed07f2d0b 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1102,6 +1102,12 @@ public:
struct st_mysql_data **data_tail;
void clear_data_list();
struct st_mysql_data *alloc_new_dataset();
+ /*
+ 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