Commit bbc9e579 authored by Sergey Vojtovich's avatar Sergey Vojtovich

MDEV-4978 - Server cursor is broken with blobs in the select list,

            ORDER BY does not work

Use "dynamic" row format (instead of "block") for MARIA internal
temporary tables created for cursors.

With "block" row format MARIA may shuffle rows, with "dynamic" row
format records are inserted sequentially (there are no gaps in data
file while we fill temporary tables).

This is needed to preserve row order when scanning materialized cursors.
parent 078388f3
...@@ -7977,4 +7977,43 @@ Warning 1329 No data - zero rows fetched, selected, or processed ...@@ -7977,4 +7977,43 @@ Warning 1329 No data - zero rows fetched, selected, or processed
drop procedure p1; drop procedure p1;
drop procedure p2; drop procedure p2;
drop table t1; drop table t1;
#
# MDEV-4978 - Server cursor is broken with blobs in the select list,
# ORDER BY does not work
#
CREATE TABLE t1(a INT, b BLOB);
INSERT INTO t1 VALUES(1,REPEAT('a',4835)),(2,'b'),(3,'c'),(4,'d'),(5,REPEAT('e',805)),(6,'f');
CREATE PROCEDURE p1()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v1 INT;
DECLARE v2 BLOB;
DECLARE c1 CURSOR FOR SELECT * FROM t1 ORDER BY a;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
OPEN c1;
REPEAT
FETCH c1 INTO v1, v2;
IF NOT done THEN
SELECT v1;
END IF;
UNTIL done END REPEAT;
CLOSE c1;
END|
CALL p1;
v1
1
v1
2
v1
3
v1
4
v1
5
v1
6
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
DROP PROCEDURE p1;
DROP TABLE t1;
# End of 5.5 test # End of 5.5 test
...@@ -9271,4 +9271,35 @@ drop procedure p2; ...@@ -9271,4 +9271,35 @@ drop procedure p2;
drop table t1; drop table t1;
--echo #
--echo # MDEV-4978 - Server cursor is broken with blobs in the select list,
--echo # ORDER BY does not work
--echo #
CREATE TABLE t1(a INT, b BLOB);
INSERT INTO t1 VALUES(1,REPEAT('a',4835)),(2,'b'),(3,'c'),(4,'d'),(5,REPEAT('e',805)),(6,'f');
DELIMITER |;
CREATE PROCEDURE p1()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v1 INT;
DECLARE v2 BLOB;
DECLARE c1 CURSOR FOR SELECT * FROM t1 ORDER BY a;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
OPEN c1;
REPEAT
FETCH c1 INTO v1, v2;
IF NOT done THEN
SELECT v1;
END IF;
UNTIL done END REPEAT;
CLOSE c1;
END|
DELIMITER ;|
CALL p1;
DROP PROCEDURE p1;
DROP TABLE t1;
--echo # End of 5.5 test --echo # End of 5.5 test
...@@ -3496,7 +3496,8 @@ select_materialize_with_stats:: ...@@ -3496,7 +3496,8 @@ select_materialize_with_stats::
create_result_table(THD *thd_arg, List<Item> *column_types, create_result_table(THD *thd_arg, List<Item> *column_types,
bool is_union_distinct, ulonglong options, bool is_union_distinct, ulonglong options,
const char *table_alias, bool bit_fields_as_long, const char *table_alias, bool bit_fields_as_long,
bool create_table) bool create_table,
bool keep_row_order)
{ {
DBUG_ASSERT(table == 0); DBUG_ASSERT(table == 0);
tmp_table_param.field_count= column_types->elements; tmp_table_param.field_count= column_types->elements;
...@@ -3504,7 +3505,8 @@ create_result_table(THD *thd_arg, List<Item> *column_types, ...@@ -3504,7 +3505,8 @@ create_result_table(THD *thd_arg, List<Item> *column_types,
if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types, if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
(ORDER*) 0, is_union_distinct, 1, (ORDER*) 0, is_union_distinct, 1,
options, HA_POS_ERROR, (char*) table_alias))) options, HA_POS_ERROR, (char*) table_alias,
keep_row_order)))
return TRUE; return TRUE;
col_stat= (Column_statistics*) table->in_use->alloc(table->s->fields * col_stat= (Column_statistics*) table->in_use->alloc(table->s->fields *
......
...@@ -3580,7 +3580,8 @@ public: ...@@ -3580,7 +3580,8 @@ public:
bool is_distinct, ulonglong options, bool is_distinct, ulonglong options,
const char *alias, const char *alias,
bool bit_fields_as_long, bool bit_fields_as_long,
bool create_table); bool create_table,
bool keep_row_order= FALSE);
TMP_TABLE_PARAM *get_tmp_table_param() { return &tmp_table_param; } TMP_TABLE_PARAM *get_tmp_table_param() { return &tmp_table_param; }
}; };
...@@ -3650,7 +3651,8 @@ public: ...@@ -3650,7 +3651,8 @@ public:
bool is_distinct, ulonglong options, bool is_distinct, ulonglong options,
const char *alias, const char *alias,
bool bit_fields_as_long, bool bit_fields_as_long,
bool create_table); bool create_table,
bool keep_row_order= FALSE);
bool init_result_table(ulonglong select_options); bool init_result_table(ulonglong select_options);
int send_data(List<Item> &items); int send_data(List<Item> &items);
void cleanup(); void cleanup();
......
...@@ -389,7 +389,7 @@ bool Select_materialize::send_result_set_metadata(List<Item> &list, uint flags) ...@@ -389,7 +389,7 @@ bool Select_materialize::send_result_set_metadata(List<Item> &list, uint flags)
if (create_result_table(unit->thd, unit->get_unit_column_types(), if (create_result_table(unit->thd, unit->get_unit_column_types(),
FALSE, FALSE,
thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS, thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS,
"", FALSE, TRUE)) "", FALSE, TRUE, TRUE))
return TRUE; return TRUE;
materialized_cursor= new (&table->mem_root) materialized_cursor= new (&table->mem_root)
......
...@@ -14572,7 +14572,8 @@ TABLE * ...@@ -14572,7 +14572,8 @@ TABLE *
create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields, ORDER *group, bool distinct, bool save_sum_fields,
ulonglong select_options, ha_rows rows_limit, ulonglong select_options, ha_rows rows_limit,
const char *table_alias, bool do_not_open) const char *table_alias, bool do_not_open,
bool keep_row_order)
{ {
MEM_ROOT *mem_root_save, own_root; MEM_ROOT *mem_root_save, own_root;
TABLE *table; TABLE *table;
...@@ -15375,6 +15376,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, ...@@ -15375,6 +15376,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
share->db_record_offset= 1; share->db_record_offset= 1;
table->used_for_duplicate_elimination= (param->sum_func_count == 0 && table->used_for_duplicate_elimination= (param->sum_func_count == 0 &&
(table->group || table->distinct)); (table->group || table->distinct));
table->keep_row_order= keep_row_order;
if (!do_not_open) if (!do_not_open)
{ {
...@@ -15712,7 +15714,8 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, ...@@ -15712,7 +15714,8 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
table->no_rows ? NO_RECORD : table->no_rows ? NO_RECORD :
(share->reclength < 64 && (share->reclength < 64 &&
!share->blob_fields ? STATIC_RECORD : !share->blob_fields ? STATIC_RECORD :
table->used_for_duplicate_elimination ? table->used_for_duplicate_elimination ||
table->keep_row_order ?
DYNAMIC_RECORD : BLOCK_RECORD), DYNAMIC_RECORD : BLOCK_RECORD),
share->keys, &keydef, share->keys, &keydef,
(uint) (*recinfo-start_recinfo), (uint) (*recinfo-start_recinfo),
......
...@@ -1821,7 +1821,8 @@ void push_index_cond(JOIN_TAB *tab, uint keyno); ...@@ -1821,7 +1821,8 @@ void push_index_cond(JOIN_TAB *tab, uint keyno);
TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields, ORDER *group, bool distinct, bool save_sum_fields,
ulonglong select_options, ha_rows rows_limit, ulonglong select_options, ha_rows rows_limit,
const char* alias, bool do_not_open=FALSE); const char* alias, bool do_not_open=FALSE,
bool keep_row_order= FALSE);
void free_tmp_table(THD *thd, TABLE *entry); void free_tmp_table(THD *thd, TABLE *entry);
bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
ENGINE_COLUMNDEF *start_recinfo, ENGINE_COLUMNDEF *start_recinfo,
......
...@@ -129,6 +129,7 @@ bool select_union::flush() ...@@ -129,6 +129,7 @@ bool select_union::flush()
table_alias name of the temporary table table_alias name of the temporary table
bit_fields_as_long convert bit fields to ulonglong bit_fields_as_long convert bit fields to ulonglong
create_table whether to physically create result table create_table whether to physically create result table
keep_row_order keep rows in order as they were inserted
DESCRIPTION DESCRIPTION
Create a temporary table that is used to store the result of a UNION, Create a temporary table that is used to store the result of a UNION,
...@@ -143,7 +144,8 @@ bool ...@@ -143,7 +144,8 @@ bool
select_union::create_result_table(THD *thd_arg, List<Item> *column_types, select_union::create_result_table(THD *thd_arg, List<Item> *column_types,
bool is_union_distinct, ulonglong options, bool is_union_distinct, ulonglong options,
const char *alias, const char *alias,
bool bit_fields_as_long, bool create_table) bool bit_fields_as_long, bool create_table,
bool keep_row_order)
{ {
DBUG_ASSERT(table == 0); DBUG_ASSERT(table == 0);
tmp_table_param.init(); tmp_table_param.init();
...@@ -153,7 +155,7 @@ select_union::create_result_table(THD *thd_arg, List<Item> *column_types, ...@@ -153,7 +155,7 @@ select_union::create_result_table(THD *thd_arg, List<Item> *column_types,
if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types, if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
(ORDER*) 0, is_union_distinct, 1, (ORDER*) 0, is_union_distinct, 1,
options, HA_POS_ERROR, alias, options, HA_POS_ERROR, alias,
!create_table))) !create_table, keep_row_order)))
return TRUE; return TRUE;
table->keys_in_use_for_query.clear_all(); table->keys_in_use_for_query.clear_all();
......
...@@ -1149,6 +1149,10 @@ public: ...@@ -1149,6 +1149,10 @@ public:
*/ */
bool force_index_group; bool force_index_group;
bool distinct,const_table,no_rows, used_for_duplicate_elimination; bool distinct,const_table,no_rows, used_for_duplicate_elimination;
/**
Forces DYNAMIC Aria row format for internal temporary tables.
*/
bool keep_row_order;
/** /**
If set, the optimizer has found that row retrieval should access index If set, the optimizer has found that row retrieval should access index
......
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