MySQL Source Code Analysis: How a Record Is Determined to Match a WHERE Clause
This article walks through MySQL 8.0.32 source code to explain how the server builds a tree for a WHERE clause, evaluates each condition using classes such as Item_cond_and, Item_cond_or, Item_func_gt, and Item_func_eq, and ultimately decides whether a row satisfies the query.
1. Preparation
We create a test table t1 and insert sample rows, then run the example SQL:
SELECT * FROM t1
WHERE i2 > 20 AND (i1 = 50 OR i1 = 80);2. Overall Introduction
In MySQL the WHERE clause is represented as a tree of Item objects. The tree for the example consists of an Item_cond_and node that connects an Item_func_gt (i2 > 20) and an Item_cond_or (i1 = 50 OR i1 = 80). Each leaf is an Item_func_eq or Item_func_gt that holds an Item_field (the column) and an Item_int (the constant).
3. Source Code Analysis
3.1 ExecuteIteratorQuery()
bool Query_expression::ExecuteIteratorQuery(THD *thd) {
...
for (;;) {
int error = m_root_iterator->Read();
if (error > 0 || thd->is_error())
return true; // fatal error
else if (error < 0)
break; // no more rows
else if (thd->killed) {
thd->send_kill_message();
return true; // aborted by user
}
if (query_result->send_data(thd, *fields))
return true;
...
}
...
}This is the entry point for a SELECT statement. For our example the root iterator is a FilterIterator , which reads rows from the storage engine and then evaluates the WHERE condition.
3.2 FilterIterator::Read()
int FilterIterator::Read() {
for (;;) {
int err = m_source->Read();
if (err != 0) return err;
bool matched = m_condition->val_int();
if (thd()->killed) {
thd()->send_kill_message();
return 1;
}
if (thd()->is_error()) return 1;
if (!matched) {
m_source->UnlockRow();
continue;
}
return 0; // successful row
}
}The iterator reads a row, then calls Item_cond_and::val_int() (the root condition) to decide whether the row matches.
3.3 compare_int_signed()
int Arg_comparator::compare_int_signed() {
longlong val1 = (*left)->val_int();
if (current_thd->is_error()) return 0;
if (!(*left)->null_value) {
longlong val2 = (*right)->val_int();
if (current_thd->is_error()) return 0;
if (!(*right)->null_value) {
if (set_null) owner->null_value = false;
if (val1 < val2) return -1;
if (val1 == val2) return 0;
return 1;
}
}
if (set_null) owner->null_value = true;
return -1;
}This function compares the left‑hand side and right‑hand side integer values of a comparison operator, handling NULLs and returning -1, 0, or 1.
3.4 Arg_comparator::compare()
inline int Arg_comparator::compare() { return (this->*func)(); }The func pointer is set to the appropriate comparison routine (e.g., compare_int_signed ) during query preparation.
3.5 Item_func_gt::val_int()
longlong Item_func_gt::val_int() {
assert(fixed == 1);
int value = cmp.compare();
return value > 0 ? 1 : 0;
}Evaluates the ‘greater‑than’ condition by delegating to the comparator and returns 1 if the left value is larger.
3.6 Item_cond_and::val_int()
longlong Item_cond_and::val_int() {
List_iterator_fast
li(list);
Item *item;
null_value = false;
while ((item = li++)) {
if (!item->val_bool()) {
if (ignore_unknown() || !(null_value = item->null_value))
return 0; // false
}
if (current_thd->is_error()) return error_int();
}
return null_value ? 0 : 1;
}The method iterates over all AND‑connected conditions; all must evaluate to true. If any condition is false and either ignore_unknown() is true or the condition is not NULL, the whole expression returns false. NULL handling is controlled by ignore_unknown() .
3.7 Item_func_eq::val_int()
longlong Item_func_eq::val_int() {
assert(fixed == 1);
int value = cmp.compare();
return value == 0 ? 1 : 0;
}Returns 1 when the left and right operands are equal.
3.8 Item_cond_or::val_int()
longlong Item_cond_or::val_int() {
List_iterator_fast
li(list);
Item *item;
null_value = false;
while ((item = li++)) {
if (item->val_bool()) {
null_value = false;
return 1; // true
}
if (item->null_value) null_value = true;
}
return 0; // false
}The OR node returns true as soon as any sub‑condition evaluates to true; otherwise it returns false, propagating NULL information when needed.
4. Summary
The article demonstrates how MySQL evaluates WHERE clauses that contain AND and OR operators. After a row is fetched, Item_cond_and::val_int() checks that every AND sub‑condition is true, while Item_cond_or::val_int() succeeds if any OR sub‑condition is true. The comparison logic is performed by compare_int_signed() and the surrounding wrapper classes, with careful handling of NULL values via ignore_unknown() and the null_value flag.
Aikesheng Open Source Community
The Aikesheng Open Source Community provides stable, enterprise‑grade MySQL open‑source tools and services, releases a premium open‑source component each year (1024), and continuously operates and maintains them.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.