Commit 17c238a1 authored by unknown's avatar unknown

Merge bk@192.168.21.1:mysql-4.1

into  mysql.com:/home/hf/work/mysql-4.1-mrg


include/mysql.h:
  Auto merged
mysql-test/r/subselect.result:
  Auto merged
mysql-test/t/rename.test:
  Auto merged
mysql-test/t/subselect.test:
  Auto merged
sql-common/client.c:
  Auto merged
sql/sql_class.h:
  Auto merged
Makefile.am:
  merging
client/mysqltest.c:
  merging
mysql-test/t/mysql_client.test:
  merging
parents 6bd194d7 e56742d7
...@@ -125,7 +125,9 @@ test-force-pl: ...@@ -125,7 +125,9 @@ test-force-pl:
./mysql-test-run.pl --force && \ ./mysql-test-run.pl --force && \
./mysql-test-run.pl --ps-protocol --force ./mysql-test-run.pl --ps-protocol --force
test-force-pl-mem: #used by autopush.pl to run memory based tests
test-force-mem:
cd mysql-test; \ cd mysql-test; \
./mysql-test-run.pl --force --mem && \ ./mysql-test-run.pl --force --mem && \
./mysql-test-run.pl --ps-protocol --force --mem ./mysql-test-run.pl --ps-protocol --force --mem
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
Matt Wagner <matt@mysql.com> Matt Wagner <matt@mysql.com>
Monty Monty
Jani Jani
Holyfoot
*/ */
#define MTEST_VERSION "3.0" #define MTEST_VERSION "3.0"
...@@ -182,6 +183,18 @@ DYNAMIC_ARRAY q_lines; ...@@ -182,6 +183,18 @@ DYNAMIC_ARRAY q_lines;
#include "sslopt-vars.h" #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 struct
{ {
int read_lines,current_line; int read_lines,current_line;
...@@ -459,7 +472,6 @@ void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {} ...@@ -459,7 +472,6 @@ void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; } int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; }
my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
#endif #endif
void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
int len); int len);
void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val); void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
...@@ -471,6 +483,56 @@ void handle_error(struct st_command*, ...@@ -471,6 +483,56 @@ void handle_error(struct st_command*,
void handle_no_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 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_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, void do_eval(DYNAMIC_STRING *query_eval, const char *query,
const char *query_end, my_bool pass_through_escape_chars) const char *query_end, my_bool pass_through_escape_chars)
...@@ -4492,7 +4554,6 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) ...@@ -4492,7 +4554,6 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql)
} }
/* /*
Run query using MySQL C API Run query using MySQL C API
...@@ -4509,10 +4570,11 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) ...@@ -4509,10 +4570,11 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql)
error - function will not return error - function will not return
*/ */
void run_query_normal(MYSQL *mysql, struct st_command *command, void run_query_normal(struct connection *cn, *mysql, struct st_command *command,
int flags, char *query, int query_len, int flags, char *query, int query_len,
DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings) DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings)
{ {
MYSQL *mysql= &cn->mysql;
MYSQL_RES *res= 0; MYSQL_RES *res= 0;
int err= 0, counter= 0; int err= 0, counter= 0;
DBUG_ENTER("run_query_normal"); DBUG_ENTER("run_query_normal");
...@@ -4524,14 +4586,26 @@ void run_query_normal(MYSQL *mysql, struct st_command *command, ...@@ -4524,14 +4586,26 @@ void run_query_normal(MYSQL *mysql, struct st_command *command,
/* /*
Send the query 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), handle_error(command, mysql_errno(mysql), mysql_error(mysql),
mysql_sqlstate(mysql), ds); mysql_sqlstate(mysql), ds);
goto end; 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)
{
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)) if (!(flags & QUERY_REAP_FLAG))
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -5641,7 +5715,7 @@ int main(int argc, char **argv) ...@@ -5641,7 +5715,7 @@ int main(int argc, char **argv)
strmake(command->require_file, save_file, sizeof(save_file)); strmake(command->require_file, save_file, sizeof(save_file));
save_file[0]= 0; 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; display_result_vertically= old_display_result_vertically;
command->last_argument= command->end; command->last_argument= command->end;
command_executed++; command_executed++;
...@@ -5672,7 +5746,7 @@ int main(int argc, char **argv) ...@@ -5672,7 +5746,7 @@ int main(int argc, char **argv)
strmake(command->require_file, save_file, sizeof(save_file)); strmake(command->require_file, save_file, sizeof(save_file));
save_file[0]= 0; save_file[0]= 0;
} }
run_query(&cur_con->mysql, command, flags); run_query(cur, command, flags);
command_executed++; command_executed++;
command->last_argument= command->end; command->last_argument= command->end;
break; break;
...@@ -5698,7 +5772,7 @@ int main(int argc, char **argv) ...@@ -5698,7 +5772,7 @@ int main(int argc, char **argv)
the query and read the result some time later when reap instruction the query and read the result some time later when reap instruction
is given on this connection. 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_executed++;
command->last_argument= command->end; command->last_argument= command->end;
break; break;
......
...@@ -281,12 +281,6 @@ typedef struct st_mysql ...@@ -281,12 +281,6 @@ typedef struct st_mysql
from mysql_stmt_close if close had to cancel result set of this object. from mysql_stmt_close if close had to cancel result set of this object.
*/ */
my_bool *unbuffered_fetch_owner; 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; } MYSQL;
typedef struct st_mysql_res { typedef struct st_mysql_res {
......
...@@ -4395,13 +4395,6 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) ...@@ -4395,13 +4395,6 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
DBUG_RETURN(1); 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) if (stmt->update_max_length && !stmt->bind_result_done)
{ {
......
...@@ -94,7 +94,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, ...@@ -94,7 +94,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
mysql->affected_rows= ~(my_ulonglong) 0; mysql->affected_rows= ~(my_ulonglong) 0;
mysql->field_count= 0; mysql->field_count= 0;
net->last_errno= 0; net->last_errno= 0;
mysql->current_stmt= stmt; thd->current_stmt= stmt;
thd->store_globals(); // Fix if more than one connect thd->store_globals(); // Fix if more than one connect
/* /*
...@@ -644,8 +644,8 @@ bool Protocol::send_fields(List<Item> *list, uint flag) ...@@ -644,8 +644,8 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
DBUG_RETURN(0); DBUG_RETURN(0);
field_count= list->elements; field_count= list->elements;
field_alloc= mysql->current_stmt ? &mysql->current_stmt->mem_root : field_alloc= thd->current_stmt ? &thd->current_stmt->mem_root :
&mysql->field_alloc; &mysql->field_alloc;
if (!(client_field= mysql->fields= if (!(client_field= mysql->fields=
(MYSQL_FIELD *)alloc_root(field_alloc, (MYSQL_FIELD *)alloc_root(field_alloc,
sizeof(MYSQL_FIELD) * field_count))) sizeof(MYSQL_FIELD) * field_count)))
...@@ -751,8 +751,8 @@ bool Protocol_prep::write() ...@@ -751,8 +751,8 @@ bool Protocol_prep::write()
{ {
MYSQL *mysql= thd->mysql; MYSQL *mysql= thd->mysql;
if (mysql->current_stmt) if (thd->current_stmt)
data= &mysql->current_stmt->result; data= &thd->current_stmt->result;
else else
{ {
if (!(data= (MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), if (!(data= (MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
......
...@@ -820,3 +820,30 @@ b a ...@@ -820,3 +820,30 @@ b a
20 1 20 1
10 2 10 2
DROP TABLE t1; 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;
...@@ -2981,3 +2981,35 @@ field1 field2 ...@@ -2981,3 +2981,35 @@ field1 field2
1 1 1 1
1 3 1 3
DROP TABLE t1, t2; 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;
# 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 -- source include/have_bdb.inc
connect (con1,localhost,root,,); connect (con1,localhost,root,,);
......
# 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 (con1,localhost,root,,);
connect (con2,localhost,root,,); connect (con2,localhost,root,,);
connection con1; connection con1;
......
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
# We verify that we did not introduce a deadlock. # We verify that we did not introduce a deadlock.
# This is intended to mimick how mysqldump and innobackup work. # 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 # And it requires InnoDB
-- source include/have_innodb.inc -- source include/have_innodb.inc
......
-- source include/have_innodb.inc -- source include/have_innodb.inc
# Can't test this with embedded server
-- source include/not_embedded.inc
connect (con1,localhost,root,,); connect (con1,localhost,root,,);
connect (con2,localhost,root,,); connect (con2,localhost,root,,);
......
-- source include/have_innodb.inc -- source include/have_innodb.inc
# Can't test this with embedded server
-- source include/not_embedded.inc
# #
# Check and select innodb lock type # Check and select innodb lock type
......
# 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 --disable_warnings
drop table if exists t1,t2; drop table if exists t1,t2;
--enable_warnings --enable_warnings
......
...@@ -34,6 +34,24 @@ ...@@ -34,6 +34,24 @@
--exec echo 'help' | $MYSQL > $MYSQLTEST_VARDIR/tmp/bug20328.tmp --exec echo 'help' | $MYSQL > $MYSQLTEST_VARDIR/tmp/bug20328.tmp
--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
# #
# Bug#17583: mysql drops connection when stdout is not writable # Bug#17583: mysql drops connection when stdout is not writable
# #
...@@ -51,4 +69,21 @@ select count(*) from t17583; ...@@ -51,4 +69,21 @@ select count(*) from t17583;
--exec echo "select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; " |$MYSQL test >&- --exec echo "select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; " |$MYSQL test >&-
drop table t17583; drop table t17583;
#
# 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
--echo End of 4.1 tests. --echo End of 4.1 tests.
...@@ -559,4 +559,20 @@ INSERT INTO t1 VALUES (1,30), (2,20), (1,10), (2,30), (1,20), (2,10); ...@@ -559,4 +559,20 @@ INSERT INTO t1 VALUES (1,30), (2,20), (1,10), (2,30), (1,20), (2,10);
DROP TABLE t1; 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 # End of 4.1 tests
...@@ -2,10 +2,6 @@ ...@@ -2,10 +2,6 @@
# Test of rename table # Test of rename table
# #
# Test requires concurrent connections, which can't be tested on embedded
# server
-- source include/not_embedded.inc
--disable_warnings --disable_warnings
drop table if exists t0,t1,t2,t3,t4; drop table if exists t0,t1,t2,t3,t4;
# Clear up from other tests (to ensure that SHOW TABLES below is right) # Clear up from other tests (to ensure that SHOW TABLES below is right)
......
# Requires use of multiple simultaneous connections, not supported with # Uses GRANT commands that usually disabled in embedded server
# embedded server testing
-- source include/not_embedded.inc -- source include/not_embedded.inc
# #
......
# 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 # PS causes different statistics
--disable_ps_protocol --disable_ps_protocol
......
...@@ -1948,4 +1948,37 @@ SELECT field1, field2 ...@@ -1948,4 +1948,37 @@ SELECT field1, field2
DROP TABLE t1, t2; 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 # End of 4.1 tests
...@@ -1173,6 +1173,8 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, ...@@ -1173,6 +1173,8 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
for (row=data->data; row ; row = row->next,field++) for (row=data->data; row ; row = row->next,field++)
{ {
uchar *pos; uchar *pos;
/* fields count may be wrong */
DBUG_ASSERT ((field - result) < fields);
cli_fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7); cli_fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7);
field->catalog = strdup_root(alloc,(char*) row->data[0]); field->catalog = strdup_root(alloc,(char*) row->data[0]);
field->db = strdup_root(alloc,(char*) row->data[1]); field->db = strdup_root(alloc,(char*) row->data[1]);
......
...@@ -1761,10 +1761,37 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -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, Item** res= find_item_in_list(this, thd->lex->current_select->item_list,
&counter, REPORT_EXCEPT_NOT_FOUND, &counter, REPORT_EXCEPT_NOT_FOUND,
&not_used); &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); if ((*res)->type() == Item::FIELD_ITEM)
return 0; {
/*
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);
}
} }
} }
......
...@@ -391,6 +391,15 @@ enum Item_result Item_singlerow_subselect::result_type() const ...@@ -391,6 +391,15 @@ enum Item_result Item_singlerow_subselect::result_type() const
return engine->type(); 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() void Item_singlerow_subselect::fix_length_and_dec()
{ {
if ((max_columns= engine->cols()) == 1) if ((max_columns= engine->cols()) == 1)
...@@ -610,6 +619,7 @@ double Item_in_subselect::val() ...@@ -610,6 +619,7 @@ double Item_in_subselect::val()
*/ */
DBUG_ASSERT(0); DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
null_value= 0;
if (exec()) if (exec())
{ {
reset(); reset();
...@@ -625,6 +635,7 @@ double Item_in_subselect::val() ...@@ -625,6 +635,7 @@ double Item_in_subselect::val()
longlong Item_in_subselect::val_int() longlong Item_in_subselect::val_int()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
null_value= 0;
if (exec()) if (exec())
{ {
reset(); reset();
...@@ -645,6 +656,7 @@ String *Item_in_subselect::val_str(String *str) ...@@ -645,6 +656,7 @@ String *Item_in_subselect::val_str(String *str)
*/ */
DBUG_ASSERT(0); DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
null_value= 0;
if (exec()) if (exec())
{ {
reset(); reset();
...@@ -1354,31 +1366,35 @@ int subselect_uniquesubquery_engine::prepare() ...@@ -1354,31 +1366,35 @@ int subselect_uniquesubquery_engine::prepare()
return 1; 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; Item *sel_item;
List_iterator_fast<Item> li(item_list); 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++) for (uint i= 0; (sel_item= li++); i++)
{ {
item->max_length= sel_item->max_length; item->max_length= sel_item->max_length;
res_type= sel_item->result_type(); res_type= sel_item->result_type();
res_field_type= sel_item->field_type();
item->decimals= sel_item->decimals; 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))) if (!(row[i]= Item_cache::get_cache(res_type)))
return STRING_RESULT; // we should return something return;
row[i]->setup(sel_item); row[i]->setup(sel_item);
} }
if (item_list.elements > 1) if (item_list.elements > 1)
res_type= ROW_RESULT; res_type= ROW_RESULT;
return res_type;
} }
void subselect_single_select_engine::fix_length_and_dec(Item_cache **row) void subselect_single_select_engine::fix_length_and_dec(Item_cache **row)
{ {
DBUG_ASSERT(row || select_lex->item_list.elements==1); 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); item->collation.set(row[0]->collation);
if (cols() != 1) if (cols() != 1)
maybe_null= 0; maybe_null= 0;
...@@ -1390,13 +1406,14 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row) ...@@ -1390,13 +1406,14 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row)
if (unit->first_select()->item_list.elements == 1) 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); item->collation.set(row[0]->collation);
} }
else else
{ {
bool fake= 0; bool maybe_null_saved= maybe_null;
res_type= set_row(unit->types, item, row, &fake); set_row(unit->types, row);
maybe_null= maybe_null_saved;
} }
} }
......
...@@ -142,6 +142,7 @@ public: ...@@ -142,6 +142,7 @@ public:
longlong val_int (); longlong val_int ();
String *val_str (String *); String *val_str (String *);
enum Item_result result_type() const; enum Item_result result_type() const;
enum_field_types field_type() const;
void fix_length_and_dec(); void fix_length_and_dec();
uint cols(); uint cols();
...@@ -273,6 +274,7 @@ protected: ...@@ -273,6 +274,7 @@ protected:
THD *thd; /* pointer to current THD */ THD *thd; /* pointer to current THD */
Item_subselect *item; /* item, that use this engine */ Item_subselect *item; /* item, that use this engine */
enum Item_result res_type; /* type of results */ 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) */ bool maybe_null; /* may be null (first item in select) */
public: public:
...@@ -282,6 +284,7 @@ public: ...@@ -282,6 +284,7 @@ public:
result= res; result= res;
item= si; item= si;
res_type= STRING_RESULT; res_type= STRING_RESULT;
res_field_type= FIELD_TYPE_VAR_STRING;
maybe_null= 0; maybe_null= 0;
} }
virtual ~subselect_engine() {}; // to satisfy compiler virtual ~subselect_engine() {}; // to satisfy compiler
...@@ -296,6 +299,7 @@ public: ...@@ -296,6 +299,7 @@ public:
virtual uint cols()= 0; /* return number of columnss in select */ virtual uint cols()= 0; /* return number of columnss in select */
virtual uint8 uncacheable()= 0; /* query is uncacheable */ virtual uint8 uncacheable()= 0; /* query is uncacheable */
enum Item_result type() { return res_type; } enum Item_result type() { return res_type; }
enum_field_types field_type() { return res_field_type; }
virtual void exclude()= 0; virtual void exclude()= 0;
bool may_be_null() { return maybe_null; }; bool may_be_null() { return maybe_null; };
virtual table_map upper_select_const_tables()= 0; virtual table_map upper_select_const_tables()= 0;
...@@ -303,6 +307,9 @@ public: ...@@ -303,6 +307,9 @@ public:
virtual void print(String *str)= 0; virtual void print(String *str)= 0;
virtual int change_item(Item_subselect *si, select_subselect *result)= 0; virtual int change_item(Item_subselect *si, select_subselect *result)= 0;
virtual bool no_tables()= 0; virtual bool no_tables()= 0;
protected:
void set_row(List<Item> &item_list, Item_cache **row);
}; };
......
...@@ -43,7 +43,7 @@ bool Protocol_prep::net_store_data(const char *from, uint length) ...@@ -43,7 +43,7 @@ bool Protocol_prep::net_store_data(const char *from, uint length)
packet->realloc(packet_length+9+length)) packet->realloc(packet_length+9+length))
return 1; return 1;
char *to=(char*) net_store_length((char*) packet->ptr()+packet_length, char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
(ulonglong) length); length);
memcpy(to,from,length); memcpy(to,from,length);
packet->length((uint) (to+length-packet->ptr())); packet->length((uint) (to+length-packet->ptr()));
return 0; return 0;
...@@ -297,8 +297,8 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) ...@@ -297,8 +297,8 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
buff[0]=0; // No fields buff[0]=0; // No fields
pos=net_store_length(buff+1,(ulonglong) affected_rows); pos=net_store_length(buff+1,affected_rows);
pos=net_store_length(pos, (ulonglong) id); pos=net_store_length(pos, id);
if (thd->client_capabilities & CLIENT_PROTOCOL_41) if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{ {
DBUG_PRINT("info", DBUG_PRINT("info",
...@@ -416,7 +416,7 @@ bool send_old_password_request(THD *thd) ...@@ -416,7 +416,7 @@ bool send_old_password_request(THD *thd)
ulonglong for bigger numbers. 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; uchar *packet=(uchar*) pkg;
if (length < 251) if (length < 251)
...@@ -439,7 +439,7 @@ char *net_store_length(char *pkg, uint length) ...@@ -439,7 +439,7 @@ char *net_store_length(char *pkg, uint length)
char *net_store_data(char *to,const char *from, 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); memcpy(to,from,length);
return to+length; return to+length;
} }
...@@ -448,7 +448,7 @@ char *net_store_data(char *to,int32 from) ...@@ -448,7 +448,7 @@ char *net_store_data(char *to,int32 from)
{ {
char buff[20]; char buff[20];
uint length=(uint) (int10_to_str(from,buff,10)-buff); 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); memcpy(to,buff,length);
return to+length; return to+length;
} }
...@@ -457,7 +457,7 @@ char *net_store_data(char *to,longlong from) ...@@ -457,7 +457,7 @@ char *net_store_data(char *to,longlong from)
{ {
char buff[22]; char buff[22];
uint length=(uint) (longlong10_to_str(from,buff,10)-buff); 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); memcpy(to,buff,length);
return to+length; return to+length;
} }
...@@ -520,7 +520,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag) ...@@ -520,7 +520,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
if (flag & 1) if (flag & 1)
{ // Packet with number of elements { // 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)); (void) my_net_write(&thd->net, buff,(uint) (pos-buff));
} }
...@@ -648,7 +648,7 @@ bool Protocol::send_records_num(List<Item> *list, ulonglong records) ...@@ -648,7 +648,7 @@ bool Protocol::send_records_num(List<Item> *list, ulonglong records)
{ {
char *pos; char *pos;
char buff[20]; char buff[20];
pos=net_store_length(buff, (uint) list->elements); pos=net_store_length(buff, list->elements);
pos=net_store_length(pos, records); pos=net_store_length(pos, records);
return my_net_write(&thd->net, buff,(uint) (pos-buff)); return my_net_write(&thd->net, buff,(uint) (pos-buff));
} }
......
...@@ -177,7 +177,6 @@ void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, ...@@ -177,7 +177,6 @@ void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
const char *info=0); const char *info=0);
void send_eof(THD *thd, bool no_flush=0); void send_eof(THD *thd, bool no_flush=0);
bool send_old_password_request(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,const char *from, uint length);
char *net_store_data(char *to,int32 from); char *net_store_data(char *to,int32 from);
char *net_store_data(char *to,longlong from); char *net_store_data(char *to,longlong from);
......
...@@ -686,6 +686,12 @@ public: ...@@ -686,6 +686,12 @@ public:
char *extra_data; char *extra_data;
ulong extra_length; ulong extra_length;
String query_rest; 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 #endif
NET net; // client connection descriptor NET net; // client connection descriptor
MEM_ROOT warn_root; // For warnings and errors MEM_ROOT warn_root; // For warnings and errors
......
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