带你读 MySQL 源码:Where 条件怎么过滤记录?( 三 )


带你读 MySQL 源码:Where 条件怎么过滤记录?

文章插图
对于 where 条件 i2 > 20,longlong val1 = (*left)->val_int() 中的 *left 表示 i2 字段 。
读取 id = 2 的记录:
i2 字段值为 NULL,if (!(*left)->null_value) 条件不成立,执行流程直接来到 if (set_null) owner->null_value = https://www.isolves.com/it/sjk/MYSQL/2023-05-26/true,把 where 条件的 null_value 设置为 true,表示对于当前读取的记录,where 条件包含 NULL 值 。
然后,return -1,compare_int_signed() 方法执行结束 。
读取 id = 3 记录:
i2 字段值为 31(即 val1 = 31),if (!(*left)->null_value) 条件成立,执行流程进入该 if 分支 。
对于 where 条件 i2 > 20,longlong val2 = (*right)->val_int() 中的 *right 表示大于号右边的 20(即 val2 = 20),if (!(*right)->null_value) 条件成立,进入该 if 分支:
if (set_null) owner->null_value = https://www.isolves.com/it/sjk/MYSQL/2023-05-26/false,把 where 条件的 null_value 设置为 false,表示对于当前读取的记录,where 条件不包含 NULL 值 。
  • if (val1 < val2),val1 = 31 大于 val2 = 20,if 条件不成立 。
  • if (val1 == val2),val1 = 31 大于 val2 20,if 条件不成立 。
  • return 1,因为 val1 = 31 大于 val2 = 20,返回 1,表示当前读取的记录匹配 where 条件 i2 > 20 。
Arg_comparator::compare()// sql/item_cmpfunc.hinline int compare() { return (this->*func)(); }Arg_comparator::compare() 只有一行代码,就是调用 *func 方法,比较两个值的大小 。
func 属性保存了用于比较两个值大小的方法的地址,在 Arg_comparator::set_cmp_func(...) 中赋值 。
对于示例 SQL 来说,where 条件中的 i1、i2 字段类型都是 int,func 属性保存的是用于比较两个整数大小的 Arg_comparator::compare_int_signed() 方法的地址 。(this->*func)() 调用的方法就是 Arg_comparator::compare_int_signed() 。
Item_func_gt::val_int()// sql/item_cmpfunc.cclonglong Item_func_gt::val_int() {assert(fixed == 1);int value = https://www.isolves.com/it/sjk/MYSQL/2023-05-26/cmp.compare();return value > 0 ? 1 : 0;}这里调用的 cmp.compare() 就是上一小节介绍的 Arg_comparator::compare() 方法 。
对于示例 SQL 来说,Arg_comparator::compare() 会调用 Arg_comparator::compare_int_signed() 方法,返回值只有 3 种:
  • -1:表示 where 条件操作符左边的值小于右边的值 。
  • 0:表示 where 条件操作符左边的值等于右边的值 。
  • 1:表示 where 条件操作符左边的值大于右边的值 。
我们以 id = 3 的记录和示例 SQL 的 where 条件 i2 > 20 为例,介绍 Item_func_gt::val_int() 的逻辑:
带你读 MySQL 源码:Where 条件怎么过滤记录?

文章插图
i2 字段值为 31,对 where 条件 i2 > 20 调用 cmp.compare(),得到的返回值为 1(即 value = https://www.isolves.com/it/sjk/MYSQL/2023-05-26/1) 。
value > 0 ? 1 : 0 表达式的值为 1,这就是 Item_func_ge::val_int() 的返回值,表示 id = 3 的记录匹配 where 条件 i2 > 20 。
Item_cond_and::val_int()// sql/item_cmpfunc.cclonglong Item_cond_and::val_int() {assert(fixed == 1);// and 连接的 N 个 where 条件都保存到 list 中// 根据 list 构造迭代器List_iterator_fast<Item> li(list);Item *item;null_value = https://www.isolves.com/it/sjk/MYSQL/2023-05-26/false;// 迭代 where 条件while ((item = li++)) {if (!item->val_bool()) {if (ignore_unknown() || !(null_value = item->null_value))return 0;// return false}if (current_thd->is_error()) return error_int();}return null_value ? 0 : 1;}Item_cond_and::val_int() 的逻辑:
  • 判断当前读取的记录是否匹配 Item_cond_and 对象所代表的 and 连接的 N 个 where 条件(N >= 2) 。
  • 如果对每个条件调用 item->val_bool() 的返回值都是 true,说明记录匹配 and 连接的 N 个 where 条件 。
  • 如果对某一个或多个条件调用 item->val_bool() 的返回值是 false,就说明记录不匹配 and 连接的 N 个 where 条件 。
由于 if (ignore_unknown() || !(null_value = https://www.isolves.com/it/sjk/MYSQL/2023-05-26/item->null_value)) 中的 ignore_unknown() 用于控制 where 条件中包含 NULL 值时怎么处理,我们需要展开介绍 Item_cond_and::val_int() 的代码 。
想要深入了解 Item_cond_and::val_int() 代码细节的读者朋友,可以做个心理建设:内容有点长(但不会太长) 。


推荐阅读