mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
be093c81a7
The ROWNUM() function is for SELECT mapped to JOIN->accepted_rows, which is incremented for each accepted rows. For Filesort, update, insert, delete and load data, we map ROWNUM() to internal variables incremented when the table is changed. The connection between the row counter and Item_func_rownum is done in sql_select.cc::fix_items_after_optimize() and sql_insert.cc::fix_rownum_pointers() When ROWNUM() is used anywhere in query, the optimization to ignore ORDER BY in sub queries are disabled. This was done to get the following common Oracle query to work: select * from (select * from t1 order by a desc) as t where rownum() <= 2; MDEV-3926 "Wrong result with GROUP BY ... WITH ROLLUP" contains a discussion about this topic. LIMIT optimization is enabled when in a top level WHERE clause comparing ROWNUM() with a numerical constant using any of the following expressions: - ROWNUM() < # - ROWNUM() <= # - ROWNUM() = 1 ROWNUM() can be also be the right argument to the comparison function. LIMIT optimization is done in two cases: - For the current sub query when the ROWNUM comparison is done on the top level: SELECT * from t1 WHERE rownum() <= 2 AND t1.a > 0 - For an inner sub query, when the upper level has only a ROWNUM comparison in the WHERE clause: SELECT * from (select * from t1) as t WHERE rownum() <= 2 In Oracle mode, one can also use ROWNUM without parentheses. Other things: - Fixed bug where the optimizer tries to optimize away sub queries with RAND_TABLE_BIT set (non-deterministic queries). Now these sub queries will not be converted to joins. This bug fix was also needed to get rownum() working inside subqueries. - In remove_const() remove setting simple_order to FALSE if ROLLUP is USED. This code was disable a long time ago because of wrong assignment in the following code. Instead we set simple_order to false if RAND_TABLE_BIT was used in the SELECT list. This ensures that we don't delete ORDER BY if the result set is not deterministic, like in 'SELECT RAND() AS 'r' FROM t1 ORDER BY r'; - Updated parameters for Sort_param::init_for_filesort() to be able to provide filesort with information where the number of accepted rows should be stored - Reordered fields in class Filesort to optimize storage layout - Added new error messsage to tell that a function can't be used in HAVING - Added field 'with_rownum' to THD to mark that ROWNUM() is used in the query. Co-author: Oleksandr Byelkin <sanja@mariadb.com> LIMIT optimization for sub query
245 lines
7 KiB
C++
245 lines
7 KiB
C++
/* Copyright (c) 2006, 2010, 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
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
|
|
|
#ifndef FILESORT_INCLUDED
|
|
#define FILESORT_INCLUDED
|
|
|
|
#include "my_base.h" /* ha_rows */
|
|
#include "sql_alloc.h"
|
|
#include "filesort_utils.h"
|
|
|
|
class SQL_SELECT;
|
|
class THD;
|
|
struct TABLE;
|
|
class Filesort_tracker;
|
|
struct SORT_FIELD;
|
|
struct SORT_FIELD_ATTR;
|
|
typedef struct st_order ORDER;
|
|
class JOIN;
|
|
class Addon_fields;
|
|
class Sort_keys;
|
|
|
|
|
|
/**
|
|
Sorting related info.
|
|
To be extended by another WL to include complete filesort implementation.
|
|
*/
|
|
class Filesort: public Sql_alloc
|
|
{
|
|
public:
|
|
/** List of expressions to order the table by */
|
|
ORDER *order;
|
|
/** Number of records to return */
|
|
ha_rows limit;
|
|
/** ORDER BY list with some precalculated info for filesort */
|
|
SORT_FIELD *sortorder;
|
|
/* Used with ROWNUM. Contains the number of rows filesort has found so far */
|
|
ha_rows *accepted_rows;
|
|
/** select to use for getting records */
|
|
SQL_SELECT *select;
|
|
|
|
/** TRUE <=> free select on destruction */
|
|
bool own_select;
|
|
/** TRUE means we are using Priority Queue for order by with limit. */
|
|
bool using_pq;
|
|
/*
|
|
TRUE means sort operation must produce table rowids.
|
|
FALSE means that it halso has an option of producing {sort_key,
|
|
addon_fields} pairs.
|
|
*/
|
|
bool sort_positions;
|
|
/*
|
|
TRUE means all the fields of table of whose bitmap read_set is set
|
|
need to be read while reading records in the sort buffer.
|
|
FALSE otherwise
|
|
*/
|
|
bool set_all_read_bits;
|
|
|
|
Filesort_tracker *tracker;
|
|
Sort_keys *sort_keys;
|
|
|
|
/* Unpack temp table columns to base table columns*/
|
|
void (*unpack)(TABLE *);
|
|
|
|
Filesort(ORDER *order_arg, ha_rows limit_arg, bool sort_positions_arg,
|
|
SQL_SELECT *select_arg):
|
|
order(order_arg),
|
|
limit(limit_arg),
|
|
sortorder(NULL),
|
|
accepted_rows(0),
|
|
select(select_arg),
|
|
own_select(false),
|
|
using_pq(false),
|
|
sort_positions(sort_positions_arg),
|
|
set_all_read_bits(false),
|
|
sort_keys(NULL),
|
|
unpack(NULL)
|
|
{
|
|
DBUG_ASSERT(order);
|
|
};
|
|
|
|
~Filesort() { cleanup(); }
|
|
/* Prepare ORDER BY list for sorting. */
|
|
Sort_keys* make_sortorder(THD *thd, JOIN *join, table_map first_table_bit);
|
|
|
|
private:
|
|
void cleanup();
|
|
};
|
|
|
|
|
|
class SORT_INFO
|
|
{
|
|
/// Buffer for sorting keys.
|
|
Filesort_buffer filesort_buffer;
|
|
|
|
public:
|
|
SORT_INFO()
|
|
:addon_fields(NULL), record_pointers(0),
|
|
sort_keys(NULL),
|
|
sorted_result_in_fsbuf(FALSE)
|
|
{
|
|
buffpek.str= 0;
|
|
my_b_clear(&io_cache);
|
|
}
|
|
|
|
~SORT_INFO();
|
|
|
|
void free_data()
|
|
{
|
|
close_cached_file(&io_cache);
|
|
free_addon_buff();
|
|
my_free(record_pointers);
|
|
my_free(buffpek.str);
|
|
my_free(addon_fields);
|
|
free_sort_buffer();
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
free_data();
|
|
record_pointers= 0;
|
|
buffpek.str= 0;
|
|
addon_fields= 0;
|
|
sorted_result_in_fsbuf= false;
|
|
}
|
|
|
|
void free_addon_buff();
|
|
|
|
IO_CACHE io_cache; /* If sorted through filesort */
|
|
LEX_STRING buffpek; /* Buffer for buffpek structures */
|
|
Addon_fields *addon_fields; /* Addon field descriptors */
|
|
uchar *record_pointers; /* If sorted in memory */
|
|
Sort_keys *sort_keys; /* Sort key descriptors*/
|
|
|
|
/**
|
|
If the entire result of filesort fits in memory, we skip the merge phase.
|
|
We may leave the result in filesort_buffer
|
|
(indicated by sorted_result_in_fsbuf), or we may strip away
|
|
the sort keys, and copy the sorted result into a new buffer.
|
|
@see save_index()
|
|
*/
|
|
bool sorted_result_in_fsbuf;
|
|
|
|
/*
|
|
How many rows in final result.
|
|
Also how many rows in record_pointers, if used
|
|
*/
|
|
ha_rows return_rows;
|
|
ha_rows examined_rows; /* How many rows read */
|
|
ha_rows found_rows; /* How many rows was accepted */
|
|
|
|
/** Sort filesort_buffer */
|
|
void sort_buffer(Sort_param *param, uint count)
|
|
{ filesort_buffer.sort_buffer(param, count); }
|
|
|
|
uchar **get_sort_keys()
|
|
{ return filesort_buffer.get_sort_keys(); }
|
|
|
|
uchar *get_sorted_record(uint ix)
|
|
{ return filesort_buffer.get_sorted_record(ix); }
|
|
|
|
uchar *alloc_sort_buffer(uint num_records, uint record_length)
|
|
{ return filesort_buffer.alloc_sort_buffer(num_records, record_length); }
|
|
|
|
void free_sort_buffer()
|
|
{ filesort_buffer.free_sort_buffer(); }
|
|
|
|
bool isfull() const
|
|
{ return filesort_buffer.isfull(); }
|
|
void init_record_pointers()
|
|
{ filesort_buffer.init_record_pointers(); }
|
|
void init_next_record_pointer()
|
|
{ filesort_buffer.init_next_record_pointer(); }
|
|
uchar *get_next_record_pointer()
|
|
{ return filesort_buffer.get_next_record_pointer(); }
|
|
void adjust_next_record_pointer(uint val)
|
|
{ filesort_buffer.adjust_next_record_pointer(val); }
|
|
|
|
Bounds_checked_array<uchar> get_raw_buf()
|
|
{ return filesort_buffer.get_raw_buf(); }
|
|
|
|
size_t sort_buffer_size() const
|
|
{ return filesort_buffer.sort_buffer_size(); }
|
|
|
|
bool is_allocated() const
|
|
{ return filesort_buffer.is_allocated(); }
|
|
void set_sort_length(uint val)
|
|
{ filesort_buffer.set_sort_length(val); }
|
|
uint get_sort_length() const
|
|
{ return filesort_buffer.get_sort_length(); }
|
|
|
|
bool has_filesort_result_in_memory() const
|
|
{
|
|
return record_pointers || sorted_result_in_fsbuf;
|
|
}
|
|
|
|
/// Are we using "addon fields"?
|
|
bool using_addon_fields() const
|
|
{
|
|
return addon_fields != NULL;
|
|
}
|
|
|
|
/// Are we using "packed addon fields"?
|
|
bool using_packed_addons();
|
|
|
|
/**
|
|
Copies (unpacks) values appended to sorted fields from a buffer back to
|
|
their regular positions specified by the Field::ptr pointers.
|
|
@param buff Buffer which to unpack the value from
|
|
*/
|
|
template<bool Packed_addon_fields>
|
|
inline void unpack_addon_fields(uchar *buff);
|
|
|
|
bool using_packed_sortkeys();
|
|
|
|
friend SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
|
|
Filesort_tracker* tracker, JOIN *join,
|
|
table_map first_table_bit);
|
|
};
|
|
|
|
SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
|
|
Filesort_tracker* tracker, JOIN *join=NULL,
|
|
table_map first_table_bit=0);
|
|
|
|
bool filesort_use_addons(TABLE *table, uint sortlength,
|
|
uint *length, uint *fields, uint *null_fields,
|
|
uint *m_packable_length);
|
|
|
|
void change_double_for_sort(double nr,uchar *to);
|
|
void store_length(uchar *to, uint length, uint pack_length);
|
|
void
|
|
reverse_key(uchar *to, const SORT_FIELD_ATTR *sort_field);
|
|
|
|
#endif /* FILESORT_INCLUDED */
|