summaryrefslogtreecommitdiff
path: root/sql/sql_cursor.cc
diff options
context:
space:
mode:
authorAlexander Nozdrin <alexander.nozdrin@oracle.com>2011-03-22 14:48:56 +0300
committerAlexander Nozdrin <alexander.nozdrin@oracle.com>2011-03-22 14:48:56 +0300
commit7117e0635c60f5db23ebb0f4b0866ce93b8ffaed (patch)
tree02b955582a97c6c1aaf1ebd3e887b04520f98302 /sql/sql_cursor.cc
parentb629abf3ae26ef9b828efc1dafa85cb098a987b0 (diff)
downloadmariadb-git-7117e0635c60f5db23ebb0f4b0866ce93b8ffaed.tar.gz
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.
Diffstat (limited to 'sql/sql_cursor.cc')
-rw-r--r--sql/sql_cursor.cc69
1 files changed, 45 insertions, 24 deletions
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
index f607936d5b9..aaf483f7a2f 100644
--- a/sql/sql_cursor.cc
+++ b/sql/sql_cursor.cc
@@ -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
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:
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 int open(JOIN *join __attribute__((unused)));
virtual void fetch(ulong num_rows);
@@ -133,7 +133,13 @@ int mysql_open_cursor(THD *thd, select_result *result,
if (rc)
{
if (result_materialize->materialized_cursor)
+ {
+ /* Rollback metadata in the client-server protocol. */
+ result_materialize->abort_result_set();
+
delete result_materialize->materialized_cursor;
+ }
+
goto end;
}
@@ -142,6 +148,12 @@ int mysql_open_cursor(THD *thd, select_result *result,
Materialized_cursor *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)))
{
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 send_result_set_metadata List of fields that would be sent.
*/
-int Materialized_cursor::fill_item_list(THD *thd,
- List<Item> &send_result_set_metadata)
+int Materialized_cursor::send_result_set_metadata(
+ THD *thd, List<Item> &send_result_set_metadata)
{
Query_arena backup_arena;
int rc;
@@ -241,6 +255,14 @@ int Materialized_cursor::fill_item_list(THD *thd,
ident->db_name= thd->strdup(send_field.db_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:
thd->restore_active_arena(this, &backup_arena);
/* 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;
int rc;
Query_arena 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);
- if (!rc && !(rc= table->file->ha_rnd_init(TRUE)))
- is_rnd_inited= 1;
+ rc= !rc && table->file->ha_rnd_init(TRUE);
+ is_rnd_inited= !rc;
thd->restore_active_arena(this, &backup_arena);
- if (rc == 0)
+
+ /* Commit or rollback metadata in the client-server protocol. */
+
+ if (!rc)
{
- /*
- 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
- send_result_set_metadata doesn't flush the network buffer.
- */
- rc= result->send_result_set_metadata(item_list, Protocol::SEND_NUM_ROWS);
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
result->send_eof();
}
+ else
+ {
+ result->abort_result_set();
+ }
+
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(result, table);
- if (! materialized_cursor)
+ if (!materialized_cursor)
{
free_tmp_table(table->in_use, table);
table= 0;
return TRUE;
}
- if (materialized_cursor->fill_item_list(unit->thd, list))
+
+ if (materialized_cursor->send_result_set_metadata(unit->thd, list))
{
delete materialized_cursor;
table= 0;