YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense alongwiththisprogram;ifnot,writetotheFreeSoftware
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
/* subselect Item */
#include"item.h" #include"sql_queue.h"
class st_select_lex; class st_select_lex_unit; class JOIN; class select_result_interceptor; class subselect_engine; class subselect_hash_sj_engine; class Item_bool_func2; class Comp_creator; class With_element; class Field_pair;
typedefclass st_select_lex SELECT_LEX;
/** Conveniencetypedefusedinthisfile,andfurtherusedbyanyfiles includingthisfile.
*/ typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); class Cached_item; class Subq_materialization_tracker; class Explain_subq_materialization;
/* base class for subselects */
class Item_subselect :public Item_result_field, protected Used_tables_and_const_cache
{ /* SettoTRUEifthevalueisassignedforthesubselect FALSE:subquerynotexecutedorthesubqueryreturnsanemptyresult
*/ bool value_assigned; bool own_engine; /* the engine was not taken from other Item_subselect */ protected: /* thread handler, will be assigned in fix_fields only */
THD *thd; /* old engine if engine was changed */
subselect_engine *old_engine; /* allowed number of columns (1 for single value subqueries) */
uint max_columns; /* where subquery is placed */
enum_parsing_place parsing_place; /* work with 'substitution' */ bool have_to_be_excluded;
bool inside_first_fix_fields; bool done_first_fix_fields;
Item *expr_cache; /* SettoTRUEifatoptimizationorexecutiontimewedeterminethatthis item'svalueisaconstant.Weneedthismemberbecauseitisnotpossible tosubstitute'this'withaconstantitem.
*/ bool forced_const; /* Set to the result of the last call of is_expensive() */ bool expensive_fl; #ifndef DBUG_OFF /* Count the number of times this subquery predicate has been executed. */
uint exec_counter; #endif public: /* UsedinsideItem_subselect::fix_fields()accordingtothisscenario: >Item_subselect::fix_fields >engine->prepare >child_join->prepare (Herewerealizeweneedtodotherewriteandset substitution=somenewItem,eg.Item_in_optimizer) <child_join->prepare <engine->prepare *ref=substitution; substitution=NULL; <Item_subselect::fix_fields
*/ /* TODO make this protected member again. */
Item *substitution; /* engine that perform execution of subselect (single select or union) */ /* TODO make this protected member again. */
subselect_engine *engine; /* unit of subquery */
st_select_lex_unit *unit; /* Cached buffers used when calling filesort in sub queries */
Filesort_buffer filesort_buffer;
LEX_STRING sortbuffer; /* A reference from inside subquery predicate to somewhere outside of it */ class Ref_to_outside : public Sql_alloc
{ public:
st_select_lex *select; /* Select where the reference is pointing to */ /* Whatisbeingreferred.ThismaybeNULLwhenwe'rereferringtoan aggregatefunction.
*/
Item *item;
}; /* Referencesfromwithinthissubquerytosomewhereoutsideofit(i.e.to parentselect,grandparentselect,etc)
*/
List<Ref_to_outside> upper_refs;
st_select_lex *parent_select;
/* used in static ALL/ANY optimization */ class select_max_min_finder_subselect; class Item_maxmin_subselect :public Item_singlerow_subselect
{ protected: bool max; bool was_values; // Set if we have found at least one row public:
Item_maxmin_subselect(THD *thd, Item_subselect *parent,
st_select_lex *select_lex, bool max); void print(String *str, enum_query_type query_type) override; void cleanup() override; bool any_value() { return was_values; } void register_value() { was_values= TRUE; } void reset_value_registration() override { was_values= FALSE; } void no_rows_in_result() override;
};
/* exists subselect */
class Item_exists_subselect :public Item_subselect
{ protected:
Item_func_not *upper_not; bool value; /* value of this item (boolean: exists/not-exists) */
public: /* Usedbysubqueryoptimizationstokeeptrackaboutinwhichclausethis subquerypredicateislocated: NO_JOIN_NEST-thepredicateisanAND-partoftheWHERE joinnestpointer-thepredicateisanAND-partofONexpression ofajoinnest NULL-forallotherlocations
*/
TABLE_LIST *emb_on_expr_nest; /** ReferenceontheItem_in_optimizerwrapperofthissubquery
*/
Item_in_optimizer *optimizer; /* true if we got this from EXISTS or to IN */ bool exists_transformed;
/* PossiblemethodstoexecuteanINpredicate.Thesearesetbytheoptimizer basedonuser-setoptimizerswitches,semanticanalysisandcostcomparison.
*/ #define SUBS_NOT_TRANSFORMED 0/* No execution method was chosen for this IN. */ /* The Final decision about the strategy is made. */ #define SUBS_STRATEGY_CHOSEN 1 #define SUBS_SEMI_JOIN 2/* IN was converted to semi-join. */ #define SUBS_IN_TO_EXISTS 4/* IN was converted to correlated EXISTS. */ #define SUBS_MATERIALIZATION 8/* Execute IN via subquery materialization. */ /* Partial matching substrategies of MATERIALIZATION. */ #define SUBS_PARTIAL_MATCH_ROWID_MERGE 16 #define SUBS_PARTIAL_MATCH_TABLE_SCAN 32 /* ALL/ANY will be transformed with max/min optimization */ /* The subquery has not aggregates, transform it into a MAX/MIN query. */ #define SUBS_MAXMIN_INJECTED 64 /* The subquery has aggregates, use a special max/min subselect engine. */ #define SUBS_MAXMIN_ENGINE 128
/* expr&optimizerusedinsubselectrewritingtostoreItemfor allJOINinUNION
*/
Item *expr; bool was_null; /* A bitmap of possible execution strategies for an IN predicate. */
uchar in_strategy; /* Tracker collecting execution parameters of a materialized subquery */
Subq_materialization_tracker *materialization_tracker; protected: /* Used to trigger on/off conditions that were pushed down to subselect */ bool *pushed_cond_guards;
Comp_creator *func;
public: /* Priority of this predicate in the convert-to-semi-join-nest process. */ int sj_convert_priority; /* May be TRUE only for the candidates to semi-join conversion */ bool do_not_convert_to_sj; /* Typesofleft_exprandsubquery'sselectlistallowtoperformsubquery materialization.Currently,wesetthistoFALSEwhenitaswellcould beTRUE.ThisistobeproperlyaddressedwithfixforBUG#36752.
*/ bool types_allow_materialization;
class subselect_engine: public Sql_alloc, public Type_handler_hybrid_field_type
{ protected:
select_result_interceptor *result; /* results storage class */
THD *thd; /* pointer to current THD */
Item_subselect *item; /* item, that use this engine */ bool maybe_null; /* may be null (first item in select) */ public:
class subselect_uniquesubquery_engine: public subselect_engine
{ protected:
st_join_table *tab;
Item *cond; /* The WHERE condition of subselect */ /* TRUE<=>lastexecutionproducedemptyset.Validonlywhenleft expressionisNULL.
*/ bool empty_result_set; public:
// constructor can assign THD because it will be called after JOIN::prepare
subselect_uniquesubquery_engine(THD *thd_arg, st_join_table *tab_arg,
Item_in_subselect *subs, Item *where)
:subselect_engine(subs, 0), tab(tab_arg), cond(where)
{
thd= thd_arg;
DBUG_ASSERT(subs);
}
~subselect_uniquesubquery_engine(); void cleanup() override; int prepare(THD *) override; bool fix_length_and_dec(Item_cache** row) override; int exec() override;
uint cols() const override { return1; }
uint8 uncacheable() override { return UNCACHEABLE_DEPENDENT_INJECTED; } void exclude() override;
table_map upper_select_const_tables() override { return0; } void print(String *str, enum_query_type query_type) override; bool change_result(Item_subselect *si,
select_result_interceptor *result, bool temp= FALSE) override; bool no_tables() const override; int index_lookup(); /* TIMOUR: this method needs refactoring. */ int scan_table(); bool copy_ref_key(bool skip_constants); bool no_rows() override { return empty_result_set; }
enum_engine_type engine_type() override { return UNIQUESUBQUERY_ENGINE; }
};
class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
{ /* FALSE for 'ref', TRUE for 'ref-or-null'. */ bool check_null; /* The"having"clause.Thisclause(furtherreferredtoas"artificial having")wasinsertedbysubquerytransformationcode.Itcontains Item(s)thathaveaside-effect:theyrecordwhetherthesubqueryhas producedarowwithNULLcertaincomponents.Weneedtouseitforcases like (oe1,oe2)IN(SELECTt.key,t.no_keyFROMt1) wherewedoindexlookupont.key=oe1butneedalsotocheckifthere wasarowsuchthatt.no_keyISNULL. NOTE:Thisiscurrentlyhereandnotintheuniquesubquery_engine.Ideally itshouldhavebeeninuniquesubquery_engineinordertoallowexecutionof subquerieslike (oe1,oe2)IN(SELECTprimary_key,non_key_maybe_null_fieldFROMtbl)
class subselect_hash_sj_engine : public subselect_engine
{ public: /* The table into which the subquery is materialized. */
TABLE *tmp_table; /* TRUE if the subquery was materialized into a temp table. */ bool is_materialized; /* Theoldenginealreadychosenatparsetimeandstoredinpermanentmemory. Throughthismemberwecanre-createandre-preparematerialize_joinfor eachexecutionofapreparedstatement.Wealsoreusethefunctionality ofsubselect_single_select_engine::[prepare|cols].
*/
subselect_single_select_engine *materialize_engine; /* QEPtoexecutethesubqueryandmaterializeitsresultintoa temporarytable.Createdduringthefirstcalltoexec().
*/
JOIN *materialize_join; /* Aconjunctionofalltheequalityconditionsbetweenallpairsofexpressions thatareargumentsofanINpredicate.Weneedthesetopost-filtersome INresultsbecauseindexlookupssometimesmatchvaluesthatareactually notequaltothesearchkeyinSQLterms.
*/
Item_cond_and *semi_join_conds;
Name_resolution_context *semi_join_conds_context;
bool init(List<Item> *tmp_columns, uint subquery_id); void cleanup() override; int prepare(THD *) override; int exec() override; void print(String *str, enum_query_type query_type) override;
uint cols() const override { return materialize_engine->cols(); }
uint8 uncacheable() override { return materialize_engine->uncacheable(); }
table_map upper_select_const_tables() override { return0; } bool no_rows() override { return !tmp_table->file->stats.records; }
enum_engine_type engine_type() override { return HASH_SJ_ENGINE; } /* TODO:factoroutallthesemethodsinabasesubselect_index_engineclass becauseallofthemhavedummyimplementationsandshouldneverbecalled.
*/ bool fix_length_and_dec(Item_cache** row) override;//=>base class void exclude() override; //=>base class //=>base class bool change_result(Item_subselect *si,
select_result_interceptor *result, bool temp= FALSE) override; bool no_tables() const override;//=>base class /* Possible execution strategies that can be used to compute hash semi-join.*/ enum exec_strategy {
UNDEFINED= 0,
COMPLETE_MATCH, /* Use regular index lookups. */
PARTIAL_MATCH, /* Use some partial matching strategy. */
PARTIAL_MATCH_MERGE, /* Use partial matching through index merging. */
PARTIAL_MATCH_SCAN, /* Use partial matching through table scan. */
SINGLE_COLUMN_MATCH, /* Use simplified matching when there is only
one field involved. */
CONST_RETURN_NULL, /* The result of IN predicate is constant NULL */
IMPOSSIBLE /* Subquery materialization is not applicable. */
};
protected: /* The engine used to compute the IN predicate. */
subselect_engine *lookup_engine; /* Keyparts of the only non-NULL composite index in a rowid merge. */
MY_BITMAP non_null_key_parts; /* Keyparts of the single column indexes with NULL, one keypart per index. */
MY_BITMAP partial_match_key_parts;
uint count_partial_match_columns;
uint count_null_only_columns;
uint count_columns_with_nulls; /* The chosen execution strategy. Computed after materialization. */
exec_strategy strategy;
exec_strategy get_strategy_using_schema();
exec_strategy get_strategy_using_data();
ulonglong rowid_merge_buff_size(bool has_non_null_key, bool has_covering_null_row,
MY_BITMAP *partial_match_key_parts); void choose_partial_match_strategy(uint field_count, bool has_non_null_key, bool has_covering_null_row,
MY_BITMAP *partial_match_key_parts); bool make_semi_join_conds();
subselect_uniquesubquery_engine* make_unique_engine();
class Ordered_key : public Sql_alloc
{ protected: /* Indexofthekeyinanarrayofkeys.Thisindexallowsto construct(sub)setsofkeysrepresentedbybitmaps.
*/
uint keyid; /* The table being indexed. */
TABLE *tbl; /* The columns being indexed. */
Item_field **key_columns; /* Number of elements in 'key_columns' (number of key parts). */
uint key_column_count; /* Anexpression,orsequenceofexpressionsthatformsthesearchkey. ThesearchkeyisasequencewhenitisItem_row.Eachelementofthe sequenceisaccessibleviaItem::element_index(inti).
*/
Item *search_key;
/* Value index related members. */ /* Theactualvalueindex,consistsofasortedsequenceofrownumbers.
*/
rownum_t *key_buff; /* Number of elements in key_buff. */
ha_rows key_buff_elements; /* Current element in 'key_buff'. */
ha_rows cur_key_idx; /* Mappingfromrownumberstorowids.Theelementrow_num_to_rowid[i] containsabufferwiththerowidfortherownumbered'i'. Thememoryforthismemberisnotmaintainedbythisclassbecause allOrdered_keyindexesofthesametablesharethesamemapping.
*/
uchar *row_num_to_rowid; /* Asequenceofpredicatestocomparethesearchkeywiththecorresponding columnsofatablerowfromtheindex.
*/
Item_func_lt **compare_pred;
/* Null index related members. */
MY_BITMAP null_key; /* Count of NULLs per column. */
ha_rows null_count; /* The row number that contains the first NULL in a column. */
rownum_t min_null_row; /* The row number that contains the last NULL in a column. */
rownum_t max_null_row;
protected: bool alloc_keys_buffers(); /* Quicksortcomparisonfunctionthatcomparestworowsofthesametable indentfiedwiththeirrownumbers.
*/ int cmp_keys_by_row_data(const rownum_t a, const rownum_t b) const; staticint cmp_keys_by_row_data_and_rownum(void *key, constvoid *a, constvoid *b);
/* Positionthecurrentelementatthefirstrowthatmatchesthekey. Thekeyitselfispropagatedbyevaluatingthecurrentvalue(s)of this->search_key.
*/ bool lookup(); /* Move the current index cursor to the first key. */ void first()
{
DBUG_ASSERT(key_buff_elements);
cur_key_idx= 0;
} /* TODO */ bool next_same(); /* Move the current index cursor to the next key. */ bool next()
{
DBUG_ASSERT(key_buff_elements); if (cur_key_idx < key_buff_elements - 1)
{
++cur_key_idx; returnTRUE;
} returnFALSE;
}; /* Return the current index element. */
rownum_t current() const
{
DBUG_ASSERT(key_buff_elements && cur_key_idx < key_buff_elements); return key_buff[cur_key_idx];
}
class subselect_partial_match_engine : public subselect_engine
{ protected: /* The temporary table that contains a materialized subquery. */
TABLE *tmp_table; /* TheengineusedtocheckwhetheranINpredicateisTRUEornot.Ifnot TRUE,thensubselect_rowid_merge_enginefurtherdistinguishesbetween FALSEandUNKNOWN.
*/
subselect_uniquesubquery_engine *lookup_engine; /* A list of equalities between each pair of IN operands. */
List<Item> *equi_join_conds; /* TrueifthereisanallNULLrowintmp_table.Ifso,thenifthereis nocompletematch,thereisaguaranteedpartialmatch.
*/ bool has_covering_null_row;
constchar *get_exec_strategy() const
{ switch (exec_strategy)
{ case Strategy::UNDEFINED: return"undefined"; case Strategy::COMPLETE_MATCH: return"index_lookup"; case Strategy::PARTIAL_MATCH_MERGE: return"index_lookup;array merge for partial match"; case Strategy::PARTIAL_MATCH_SCAN: return"index_lookup;full scan for partial match"; case Strategy::SINGLE_COLUMN_MATCH: return"null-aware index_lookup"; case Strategy::CONST_RETURN_NULL: return"return NULL"; default: return"unsupported";
}
}
};
#endif/* ITEM_SUBSELECT_INCLUDED */
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.44 Sekunden
(vorverarbeitet am 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.