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<Item> 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<Item> 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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
