mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
A patch for Bug#11763413 (56115: SELECT doesn't work in
prepared statements with cursor protocol). The problem was a bug in Materialized-cursor implementation. Materialized_cursor::open() called send_result_metadata() with items pointing to already closed table. The fix is to send metadata when the table is still open. NOTE: this is a "partial" fix: metadata are different with and without --cursor-protocol, but that's a different large problem, one indication of which is reported as Bug 24176.
This commit is contained in:
@ -3731,5 +3731,19 @@ CREATE TABLE t1 (a INT);
|
|||||||
BEGIN;
|
BEGIN;
|
||||||
PREPARE stmt1 FROM "SELECT * FROM t1";
|
PREPARE stmt1 FROM "SELECT * FROM t1";
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
#
|
#
|
||||||
# End of 6.0 tests.
|
# Bug#56115: invalid memory reads when PS selecting from
|
||||||
|
# information_schema tables
|
||||||
|
# Bug#58701: crash in Field::make_field, cursor-protocol
|
||||||
|
#
|
||||||
|
# NOTE: MTR should be run both with --ps-protocol and --cursor-protocol.
|
||||||
|
#
|
||||||
|
|
||||||
|
SELECT *
|
||||||
|
FROM (SELECT 1 UNION SELECT 2) t;
|
||||||
|
1
|
||||||
|
1
|
||||||
|
2
|
||||||
|
#
|
||||||
|
# End of 5.5 tests.
|
||||||
|
@ -3344,7 +3344,21 @@ connection default;
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
|
||||||
|
--echo
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 6.0 tests.
|
--echo # Bug#56115: invalid memory reads when PS selecting from
|
||||||
|
--echo # information_schema tables
|
||||||
|
--echo # Bug#58701: crash in Field::make_field, cursor-protocol
|
||||||
|
--echo #
|
||||||
|
--echo # NOTE: MTR should be run both with --ps-protocol and --cursor-protocol.
|
||||||
|
--echo #
|
||||||
|
--echo
|
||||||
|
|
||||||
|
SELECT *
|
||||||
|
FROM (SELECT 1 UNION SELECT 2) t;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 5.5 tests.
|
||||||
|
|
||||||
###########################################################################
|
###########################################################################
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2005-2006 MySQL AB
|
/* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -46,7 +46,7 @@ class Materialized_cursor: public Server_side_cursor
|
|||||||
public:
|
public:
|
||||||
Materialized_cursor(select_result *result, TABLE *table);
|
Materialized_cursor(select_result *result, TABLE *table);
|
||||||
|
|
||||||
int fill_item_list(THD *thd, List<Item> &send_result_set_metadata);
|
int send_result_set_metadata(THD *thd, List<Item> &send_result_set_metadata);
|
||||||
virtual bool is_open() const { return table != 0; }
|
virtual bool is_open() const { return table != 0; }
|
||||||
virtual int open(JOIN *join __attribute__((unused)));
|
virtual int open(JOIN *join __attribute__((unused)));
|
||||||
virtual void fetch(ulong num_rows);
|
virtual void fetch(ulong num_rows);
|
||||||
@ -133,7 +133,13 @@ int mysql_open_cursor(THD *thd, select_result *result,
|
|||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
if (result_materialize->materialized_cursor)
|
if (result_materialize->materialized_cursor)
|
||||||
|
{
|
||||||
|
/* Rollback metadata in the client-server protocol. */
|
||||||
|
result_materialize->abort_result_set();
|
||||||
|
|
||||||
delete result_materialize->materialized_cursor;
|
delete result_materialize->materialized_cursor;
|
||||||
|
}
|
||||||
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +148,12 @@ int mysql_open_cursor(THD *thd, select_result *result,
|
|||||||
Materialized_cursor *materialized_cursor=
|
Materialized_cursor *materialized_cursor=
|
||||||
result_materialize->materialized_cursor;
|
result_materialize->materialized_cursor;
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: close_thread_tables() has been called in
|
||||||
|
mysql_execute_command(), so all tables except from the cursor
|
||||||
|
temporary table have been closed.
|
||||||
|
*/
|
||||||
|
|
||||||
if ((rc= materialized_cursor->open(0)))
|
if ((rc= materialized_cursor->open(0)))
|
||||||
{
|
{
|
||||||
delete materialized_cursor;
|
delete materialized_cursor;
|
||||||
@ -202,14 +214,16 @@ Materialized_cursor::Materialized_cursor(select_result *result_arg,
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Preserve the original metadata that would be sent to the client.
|
Preserve the original metadata to be sent to the client.
|
||||||
|
Initiate sending of the original metadata to the client
|
||||||
|
(call Protocol::send_result_set_metadata()).
|
||||||
|
|
||||||
@param thd Thread identifier.
|
@param thd Thread identifier.
|
||||||
@param send_result_set_metadata List of fields that would be sent.
|
@param send_result_set_metadata List of fields that would be sent.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int Materialized_cursor::fill_item_list(THD *thd,
|
int Materialized_cursor::send_result_set_metadata(
|
||||||
List<Item> &send_result_set_metadata)
|
THD *thd, List<Item> &send_result_set_metadata)
|
||||||
{
|
{
|
||||||
Query_arena backup_arena;
|
Query_arena backup_arena;
|
||||||
int rc;
|
int rc;
|
||||||
@ -241,6 +255,14 @@ int Materialized_cursor::fill_item_list(THD *thd,
|
|||||||
ident->db_name= thd->strdup(send_field.db_name);
|
ident->db_name= thd->strdup(send_field.db_name);
|
||||||
ident->table_name= thd->strdup(send_field.table_name);
|
ident->table_name= thd->strdup(send_field.table_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Original metadata result set should be sent here. After
|
||||||
|
mysql_execute_command() is finished, item_list can not be used for
|
||||||
|
sending metadata, because it references closed table.
|
||||||
|
*/
|
||||||
|
rc= result->send_result_set_metadata(item_list, Protocol::SEND_NUM_ROWS);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
thd->restore_active_arena(this, &backup_arena);
|
thd->restore_active_arena(this, &backup_arena);
|
||||||
/* Check for thd->is_error() in case of OOM */
|
/* Check for thd->is_error() in case of OOM */
|
||||||
@ -253,31 +275,29 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused)))
|
|||||||
THD *thd= fake_unit.thd;
|
THD *thd= fake_unit.thd;
|
||||||
int rc;
|
int rc;
|
||||||
Query_arena backup_arena;
|
Query_arena backup_arena;
|
||||||
|
|
||||||
thd->set_n_backup_active_arena(this, &backup_arena);
|
thd->set_n_backup_active_arena(this, &backup_arena);
|
||||||
/* Create a list of fields and start sequential scan */
|
|
||||||
|
/* Create a list of fields and start sequential scan. */
|
||||||
|
|
||||||
rc= result->prepare(item_list, &fake_unit);
|
rc= result->prepare(item_list, &fake_unit);
|
||||||
if (!rc && !(rc= table->file->ha_rnd_init(TRUE)))
|
rc= !rc && table->file->ha_rnd_init(TRUE);
|
||||||
is_rnd_inited= 1;
|
is_rnd_inited= !rc;
|
||||||
|
|
||||||
thd->restore_active_arena(this, &backup_arena);
|
thd->restore_active_arena(this, &backup_arena);
|
||||||
if (rc == 0)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Now send the result set metadata to the client. We need to
|
|
||||||
do it here, as in Select_materialize::send_result_set_metadata the items
|
|
||||||
for column types are not yet created (send_result_set_metadata requires
|
|
||||||
a list of items). The new types may differ from the original
|
|
||||||
ones sent at prepare if some of them were altered by MySQL
|
|
||||||
HEAP tables mechanism -- used when create_tmp_field_from_item
|
|
||||||
may alter the original column type.
|
|
||||||
|
|
||||||
We can't simply supply SEND_EOF flag to send_result_set_metadata, because
|
/* Commit or rollback metadata in the client-server protocol. */
|
||||||
send_result_set_metadata doesn't flush the network buffer.
|
|
||||||
*/
|
if (!rc)
|
||||||
rc= result->send_result_set_metadata(item_list, Protocol::SEND_NUM_ROWS);
|
{
|
||||||
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
|
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
|
||||||
result->send_eof();
|
result->send_eof();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result->abort_result_set();
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,13 +390,14 @@ bool Select_materialize::send_result_set_metadata(List<Item> &list, uint flags)
|
|||||||
materialized_cursor= new (&table->mem_root)
|
materialized_cursor= new (&table->mem_root)
|
||||||
Materialized_cursor(result, table);
|
Materialized_cursor(result, table);
|
||||||
|
|
||||||
if (! materialized_cursor)
|
if (!materialized_cursor)
|
||||||
{
|
{
|
||||||
free_tmp_table(table->in_use, table);
|
free_tmp_table(table->in_use, table);
|
||||||
table= 0;
|
table= 0;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (materialized_cursor->fill_item_list(unit->thd, list))
|
|
||||||
|
if (materialized_cursor->send_result_set_metadata(unit->thd, list))
|
||||||
{
|
{
|
||||||
delete materialized_cursor;
|
delete materialized_cursor;
|
||||||
table= 0;
|
table= 0;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -15694,8 +15694,11 @@ static void test_bug13488()
|
|||||||
check_execute(stmt1, rc);
|
check_execute(stmt1, rc);
|
||||||
|
|
||||||
if (!opt_silent)
|
if (!opt_silent)
|
||||||
printf("data is: %s", (f1 == 1 && f2 == 1 && f3 == 2)?"OK":
|
{
|
||||||
"wrong");
|
printf("data: f1: %d; f2: %d; f3: %d\n", f1, f2, f3);
|
||||||
|
printf("data is: %s\n",
|
||||||
|
(f1 == 1 && f2 == 1 && f3 == 2) ? "OK" : "wrong");
|
||||||
|
}
|
||||||
DIE_UNLESS(f1 == 1 && f2 == 1 && f3 == 2);
|
DIE_UNLESS(f1 == 1 && f2 == 1 && f3 == 2);
|
||||||
rc= mysql_query(mysql, "drop table t1, t2");
|
rc= mysql_query(mysql, "drop table t1, t2");
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
Reference in New Issue
Block a user