294 lines
10 KiB
C++
294 lines
10 KiB
C++
#ifndef SQL_REF_ROW_ITERATORS_H
|
|
#define SQL_REF_ROW_ITERATORS_H
|
|
|
|
/* Copyright (c) 2018, 2019, 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, version 2.0,
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is also distributed with certain software (including
|
|
but not limited to OpenSSL) that is licensed under separate terms,
|
|
as designated in a particular file or component or in included license
|
|
documentation. The authors of MySQL hereby grant you an additional
|
|
permission to link the program and your derivative works with the
|
|
separately licensed software that they have included with MySQL.
|
|
|
|
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, version 2.0, 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-1301 USA */
|
|
|
|
#include <sys/types.h>
|
|
#include <memory>
|
|
|
|
#include "my_alloc.h"
|
|
#include "my_inttypes.h"
|
|
#include "sql/basic_row_iterators.h"
|
|
#include "sql/row_iterator.h"
|
|
#include "sql/sql_sort.h"
|
|
|
|
class QEP_TAB;
|
|
class THD;
|
|
struct TABLE;
|
|
struct TABLE_REF;
|
|
|
|
/**
|
|
For each record on the left side of a join (given in Init()), returns one or
|
|
more matching rows from the given table, i.e., WHERE column=\<ref\>.
|
|
*/
|
|
template <bool Reverse>
|
|
class RefIterator final : public TableRowIterator {
|
|
public:
|
|
// "examined_rows", if not nullptr, is incremented for each successful Read().
|
|
RefIterator(THD *thd, TABLE *table, TABLE_REF *ref, bool use_order,
|
|
QEP_TAB *qep_tab, ha_rows *examined_rows);
|
|
|
|
bool Init() override;
|
|
int Read() override;
|
|
std::vector<std::string> DebugString() const override;
|
|
|
|
private:
|
|
TABLE_REF *const m_ref;
|
|
const bool m_use_order;
|
|
QEP_TAB *const m_qep_tab;
|
|
ha_rows *const m_examined_rows;
|
|
bool m_first_record_since_init;
|
|
};
|
|
|
|
/**
|
|
Like RefIterator, but after it's returned all its rows, will also search for
|
|
rows that match NULL, i.e., WHERE column=\<ref\> OR column IS NULL.
|
|
*/
|
|
class RefOrNullIterator final : public TableRowIterator {
|
|
public:
|
|
// "examined_rows", if not nullptr, is incremented for each successful Read().
|
|
RefOrNullIterator(THD *thd, TABLE *table, TABLE_REF *ref, bool use_order,
|
|
QEP_TAB *qep_tab, ha_rows *examined_rows);
|
|
|
|
bool Init() override;
|
|
int Read() override;
|
|
std::vector<std::string> DebugString() const override;
|
|
|
|
private:
|
|
TABLE_REF *const m_ref;
|
|
const bool m_use_order;
|
|
bool m_reading_first_row;
|
|
QEP_TAB *const m_qep_tab;
|
|
ha_rows *const m_examined_rows;
|
|
};
|
|
|
|
/**
|
|
Like RefIterator, but used in situations where we're guaranteed to have
|
|
exactly zero or one rows for each reference (due to e.g. unique constraints).
|
|
It adds extra buffering to reduce the number of calls to the storage engine in
|
|
the case where many consecutive rows on the left side contain the same value.
|
|
*/
|
|
class EQRefIterator final : public TableRowIterator {
|
|
public:
|
|
// "examined_rows", if not nullptr, is incremented for each successful Read().
|
|
EQRefIterator(THD *thd, TABLE *table, TABLE_REF *ref, bool use_order,
|
|
ha_rows *examined_rows);
|
|
|
|
bool Init() override;
|
|
int Read() override;
|
|
void UnlockRow() override;
|
|
std::vector<std::string> DebugString() const override;
|
|
|
|
// Performance schema batch mode on EQRefIterator does not make any sense,
|
|
// since it (by definition) can never scan more than one row. Normally,
|
|
// we should not get this (for nested loop joins, PFS batch mode is not
|
|
// enabled if the innermost iterator is an EQRefIterator); however,
|
|
// we cannot DBUG_ASSERT(false), since it could happen if we only have
|
|
// a single table. Thus, just ignore the call should it happen.
|
|
void StartPSIBatchMode() override {}
|
|
|
|
private:
|
|
TABLE_REF *const m_ref;
|
|
const bool m_use_order;
|
|
bool m_first_record_since_init;
|
|
ha_rows *const m_examined_rows;
|
|
};
|
|
|
|
/**
|
|
An iterator that reads from a table where only a single row is known to be
|
|
matching, no matter what's on the left side, i.e., WHERE column=\<const\>.
|
|
*/
|
|
class ConstIterator final : public TableRowIterator {
|
|
public:
|
|
// "examined_rows", if not nullptr, is incremented for each successful Read().
|
|
ConstIterator(THD *thd, TABLE *table, TABLE_REF *table_ref,
|
|
ha_rows *examined_rows);
|
|
|
|
bool Init() override;
|
|
int Read() override;
|
|
|
|
/**
|
|
Rows from const tables are read once but potentially used
|
|
multiple times during execution of a query.
|
|
Ensure such rows are never unlocked during query execution.
|
|
*/
|
|
void UnlockRow() override {}
|
|
|
|
std::vector<std::string> DebugString() const override;
|
|
|
|
private:
|
|
TABLE_REF *const m_ref;
|
|
bool m_first_record_since_init;
|
|
ha_rows *const m_examined_rows;
|
|
};
|
|
|
|
/** An iterator that does a search through a full-text index. */
|
|
class FullTextSearchIterator final : public TableRowIterator {
|
|
public:
|
|
// "examined_rows", if not nullptr, is incremented for each successful Read().
|
|
FullTextSearchIterator(THD *thd, TABLE *table, TABLE_REF *ref, bool use_order,
|
|
ha_rows *examined_rows);
|
|
~FullTextSearchIterator() override;
|
|
|
|
bool Init() override;
|
|
int Read() override;
|
|
std::vector<std::string> DebugString() const override;
|
|
|
|
private:
|
|
TABLE_REF *const m_ref;
|
|
const bool m_use_order;
|
|
ha_rows *const m_examined_rows;
|
|
};
|
|
|
|
/*
|
|
This is for QS_DYNAMIC_RANGE, i.e., "Range checked for each
|
|
record". The trace for the range analysis below this point will
|
|
be printed with different ranges for every record to the left of
|
|
this table in the join; the range optimizer can either select any
|
|
QUICK_SELECT_I (aka IndexRangeScanIterator) or a full table
|
|
scan, and any Read() is just proxied over to that.
|
|
|
|
Note in particular that this means the range optimizer will be
|
|
executed anew on every single call to Init(), and modify the
|
|
query plan accordingly! It is not clear whether this is an actual
|
|
win in a typical query.
|
|
*/
|
|
class DynamicRangeIterator final : public TableRowIterator {
|
|
public:
|
|
// "examined_rows", if not nullptr, is incremented for each successful Read().
|
|
DynamicRangeIterator(THD *thd, TABLE *table, QEP_TAB *qep_tab,
|
|
ha_rows *examined_rows);
|
|
|
|
bool Init() override;
|
|
int Read() override;
|
|
std::vector<std::string> DebugString() const override;
|
|
|
|
private:
|
|
QEP_TAB *m_qep_tab;
|
|
|
|
unique_ptr_destroy_only<RowIterator> m_iterator;
|
|
|
|
/**
|
|
Used by optimizer tracing to decide whether or not dynamic range
|
|
analysis of this select has been traced already. If optimizer
|
|
trace option DYNAMIC_RANGE is enabled, range analysis will be
|
|
traced with different ranges for every record to the left of this
|
|
table in the join. If disabled, range analysis will only be traced
|
|
for the first range.
|
|
*/
|
|
bool m_quick_traced_before = false;
|
|
|
|
ha_rows *const m_examined_rows;
|
|
};
|
|
|
|
/**
|
|
Read a table *assumed* to be included in execution of a pushed join.
|
|
This is the counterpart of RefIterator / EQRefIterator for child
|
|
tables in a pushed join.
|
|
|
|
When the table access is performed as part of the pushed join,
|
|
all 'linked' child colums are prefetched together with the parent row.
|
|
The handler will then only format the row as required by MySQL and set
|
|
table status accordingly.
|
|
|
|
However, there may be situations where the prepared pushed join was not
|
|
executed as assumed. It is the responsibility of the handler to handle
|
|
these situation by letting @c ha_index_read_pushed() then effectively do a
|
|
plain old' index_read_map(..., HA_READ_KEY_EXACT);
|
|
*/
|
|
class PushedJoinRefIterator final : public TableRowIterator {
|
|
public:
|
|
// "examined_rows", if not nullptr, is incremented for each successful Read().
|
|
PushedJoinRefIterator(THD *thd, TABLE *table, TABLE_REF *ref, bool use_order,
|
|
ha_rows *examined_rows);
|
|
|
|
bool Init() override;
|
|
int Read() override;
|
|
std::vector<std::string> DebugString() const override;
|
|
|
|
private:
|
|
TABLE_REF *const m_ref;
|
|
const bool m_use_order;
|
|
bool m_first_record_since_init;
|
|
ha_rows *const m_examined_rows;
|
|
};
|
|
|
|
/**
|
|
An iterator that switches between another iterator (typically a RefIterator
|
|
or similar) and a TableScanIterator.
|
|
|
|
This is used when predicates have been pushed down into an IN subquery
|
|
and then created ref accesses, but said predicates should not be checked for
|
|
a NULL value (so we need to revert to table scans). See
|
|
QEP_TAB::pick_table_access_method() for a more thorough explanation.
|
|
*/
|
|
class AlternativeIterator final : public RowIterator {
|
|
public:
|
|
// Takes ownership of "source", and is responsible for
|
|
// calling Init() on it, but does not hold the memory.
|
|
AlternativeIterator(THD *thd, TABLE *table, QEP_TAB *qep_tab,
|
|
ha_rows *examined_rows,
|
|
unique_ptr_destroy_only<RowIterator> source,
|
|
TABLE_REF *ref);
|
|
|
|
bool Init() override;
|
|
|
|
int Read() override { return m_iterator->Read(); }
|
|
|
|
void SetNullRowFlag(bool is_null_row) override {
|
|
// Init() may not have been called yet, so just forward to both iterators.
|
|
m_source_iterator->SetNullRowFlag(is_null_row);
|
|
m_table_scan_iterator->SetNullRowFlag(is_null_row);
|
|
}
|
|
|
|
void UnlockRow() override { m_iterator->UnlockRow(); }
|
|
|
|
std::vector<Child> children() const override {
|
|
return std::vector<Child>{{m_source_iterator.get(), ""},
|
|
{m_table_scan_iterator.get(), ""}};
|
|
}
|
|
|
|
std::vector<std::string> DebugString() const override;
|
|
|
|
private:
|
|
// The reference value with condition guards that we are switching on.
|
|
TABLE_REF *m_ref;
|
|
|
|
// If any of these are false during Init(), we are having a NULL IN ( ... ),
|
|
// and need to fall back to table scan. Extracted from m_ref.
|
|
std::vector<bool *> m_applicable_cond_guards;
|
|
|
|
// Points to either m_source_iterator or m_table_scan_iterator,
|
|
// depending on the value of applicable_cond_guards. Set up during Init().
|
|
RowIterator *m_iterator = nullptr;
|
|
|
|
// The iterator we are normally reading records from (a RefIterator or
|
|
// similar).
|
|
unique_ptr_destroy_only<RowIterator> m_source_iterator;
|
|
|
|
// Our fallback iterator (possibly wrapped in a TimingIterator).
|
|
unique_ptr_destroy_only<RowIterator> m_table_scan_iterator;
|
|
};
|
|
|
|
#endif // SQL_REF_ROW_ITERATORS_H
|