Commit e971334e authored by unknown's avatar unknown

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
parents daaddeb6 e78fd1d1
...@@ -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"
...@@ -220,6 +221,12 @@ struct st_connection ...@@ -220,6 +221,12 @@ struct st_connection
MYSQL* util_mysql; MYSQL* util_mysql;
char *name; char *name;
MYSQL_STMT* stmt; 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 connections[128];
struct st_connection* cur_con, *next_con, *connections_end; struct st_connection* cur_con, *next_con, *connections_end;
...@@ -458,7 +465,6 @@ void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {} ...@@ -458,7 +465,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);
...@@ -470,6 +476,56 @@ void handle_error(struct st_command*, ...@@ -470,6 +476,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 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, 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)
...@@ -4498,7 +4554,6 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) ...@@ -4498,7 +4554,6 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql)
} }
/* /*
Run query using MySQL C API Run query using MySQL C API
...@@ -4515,10 +4570,11 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) ...@@ -4515,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 st_connection *cn, 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");
...@@ -4530,14 +4586,26 @@ void run_query_normal(MYSQL *mysql, struct st_command *command, ...@@ -4530,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_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)) if (!(flags & QUERY_REAP_FLAG))
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -5028,8 +5096,9 @@ int util_query(MYSQL* org_mysql, const char* query){ ...@@ -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;
DYNAMIC_STRING ds_result; DYNAMIC_STRING ds_result;
DYNAMIC_STRING ds_warnings; DYNAMIC_STRING ds_warnings;
...@@ -5186,7 +5255,7 @@ void run_query(MYSQL *mysql, struct st_command *command, int flags) ...@@ -5186,7 +5255,7 @@ void run_query(MYSQL *mysql, struct st_command *command, int flags)
match_re(&ps_re, query)) match_re(&ps_re, query))
run_query_stmt(mysql, command, query, query_len, ds, &ds_warnings); run_query_stmt(mysql, command, query, query_len, ds, &ds_warnings);
else else
run_query_normal(mysql, command, flags, query, query_len, run_query_normal(cn, command, flags, query, query_len,
ds, &ds_warnings); ds, &ds_warnings);
if (sp_created) if (sp_created)
...@@ -5651,7 +5720,7 @@ int main(int argc, char **argv) ...@@ -5651,7 +5720,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++;
...@@ -5682,7 +5751,7 @@ int main(int argc, char **argv) ...@@ -5682,7 +5751,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_con, command, flags);
command_executed++; command_executed++;
command->last_argument= command->end; command->last_argument= command->end;
break; break;
...@@ -5708,7 +5777,7 @@ int main(int argc, char **argv) ...@@ -5708,7 +5777,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;
......
...@@ -100,6 +100,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, ...@@ -100,6 +100,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;
thd->current_stmt= stmt;
thd->store_globals(); // Fix if more than one connect thd->store_globals(); // Fix if more than one connect
/* /*
......
...@@ -854,6 +854,33 @@ b a ...@@ -854,6 +854,33 @@ 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;
CREATE TABLE t1 (a int, b int, PRIMARY KEY (a)); CREATE TABLE t1 (a int, b int, PRIMARY KEY (a));
INSERT INTO t1 VALUES (1,1), (2,2), (3,3); INSERT INTO t1 VALUES (1,1), (2,2), (3,3);
explain SELECT t1.b as a, t2.b as c FROM explain SELECT t1.b as a, t2.b as c FROM
......
...@@ -3001,6 +3001,38 @@ field1 field2 ...@@ -3001,6 +3001,38 @@ 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;
create table t1 (df decimal(5,1)); create table t1 (df decimal(5,1));
insert into t1 values(1.1); insert into t1 values(1.1);
insert into t1 values(2.2); insert into t1 values(2.2);
......
# 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
......
...@@ -514,6 +514,81 @@ set max_sort_length=20; ...@@ -514,6 +514,81 @@ set max_sort_length=20;
select a from t1 order by a; select a from t1 order by a;
drop table t1; 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); 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); 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); select a, b from t1 group by a, b order by sum(c);
......
...@@ -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
......
...@@ -1955,6 +1955,39 @@ SELECT field1, field2 ...@@ -1955,6 +1955,39 @@ 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
# #
......
...@@ -1191,6 +1191,8 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, ...@@ -1191,6 +1191,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]);
......
...@@ -3638,10 +3638,37 @@ bool Item_field::fix_fields(THD *thd, Item **reference) ...@@ -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, 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);
}
} }
} }
if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
......
...@@ -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)
...@@ -667,6 +676,7 @@ double Item_in_subselect::val_real() ...@@ -667,6 +676,7 @@ double Item_in_subselect::val_real()
*/ */
DBUG_ASSERT(0); DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
null_value= 0;
if (exec()) if (exec())
{ {
reset(); reset();
...@@ -687,6 +697,7 @@ longlong Item_in_subselect::val_int() ...@@ -687,6 +697,7 @@ longlong Item_in_subselect::val_int()
*/ */
DBUG_ASSERT(0); DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
null_value= 0;
if (exec()) if (exec())
{ {
reset(); reset();
...@@ -707,6 +718,7 @@ String *Item_in_subselect::val_str(String *str) ...@@ -707,6 +718,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();
...@@ -1499,32 +1511,36 @@ int subselect_uniquesubquery_engine::prepare() ...@@ -1499,32 +1511,36 @@ 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;
item->unsigned_flag= sel_item->unsigned_flag; item->unsigned_flag= sel_item->unsigned_flag;
*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;
...@@ -1536,13 +1552,14 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row) ...@@ -1536,13 +1552,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;
} }
} }
......
...@@ -155,6 +155,7 @@ public: ...@@ -155,6 +155,7 @@ public:
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
bool val_bool(); bool val_bool();
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();
...@@ -291,6 +292,7 @@ protected: ...@@ -291,6 +292,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:
...@@ -300,6 +302,7 @@ public: ...@@ -300,6 +302,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
...@@ -317,6 +320,7 @@ public: ...@@ -317,6 +320,7 @@ public:
virtual uint cols()= 0; /* return number of columns in select */ virtual uint cols()= 0; /* return number of columns 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;
......
...@@ -46,7 +46,7 @@ bool Protocol_prep::net_store_data(const char *from, uint length) ...@@ -46,7 +46,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;
...@@ -280,8 +280,8 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) ...@@ -280,8 +280,8 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
} }
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",
...@@ -456,7 +456,7 @@ void net_send_error_packet(THD *thd, uint sql_errno, const char *err) ...@@ -456,7 +456,7 @@ void net_send_error_packet(THD *thd, uint sql_errno, const char *err)
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)
...@@ -479,7 +479,7 @@ char *net_store_length(char *pkg, uint length) ...@@ -479,7 +479,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;
} }
...@@ -488,7 +488,7 @@ char *net_store_data(char *to,int32 from) ...@@ -488,7 +488,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;
} }
...@@ -497,7 +497,7 @@ char *net_store_data(char *to,longlong from) ...@@ -497,7 +497,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;
} }
...@@ -561,7 +561,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) ...@@ -561,7 +561,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
if (flags & SEND_NUM_ROWS) if (flags & SEND_NUM_ROWS)
{ // 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));
} }
......
...@@ -166,7 +166,6 @@ void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, ...@@ -166,7 +166,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); void send_eof(THD *thd);
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);
......
...@@ -1102,6 +1102,12 @@ public: ...@@ -1102,6 +1102,12 @@ public:
struct st_mysql_data **data_tail; struct st_mysql_data **data_tail;
void clear_data_list(); void clear_data_list();
struct st_mysql_data *alloc_new_dataset(); 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 #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