💻 深耕数据库内核架构设计与开发十余年,曾主导多款高性能分布式数据库内核研发,攻克高并发、低延迟等核心技术难题。现倾力打造《从零手写数据库》系列教程,首次系统性公开数据库内核源码级实现细节!
一、概述
当表达式出现在select子句时,作为目标列一种类型,表达式的结果需要在投影操作执行时计算得出,最终拼接在查询结果中。
二、查询结果处理
将查询结果组装时,原来目标列只有常量和属性列的类型,增加表达式节点类型处理分支。
Node* FormTargetResult(Node *targetList, Node *resultList)
case T_Expr:
((Expr*)te->val)->srcData = resultList;
resValue = ExprEvaluation(te->val);
offset += FormColumnData(te->attr, resValue, tempBuf + offset, PAGE_MAX_SIZE - offset);
break;
将结果集记录到表达式结构中,调用表达式计算函数计算表达式的值,并将它拼接到查询结果当中。
三、仅select子句支持
有一种SQL形式,它只有select子句和表达式,表达式可以是常量表达式或者其它运算表达式,比如常用于检测数据库是否正常的“select 1; ”。
这类型的SQL语句,不能迭代循环查询,只需要执行一次即可。
在查询执行计划的顶层投影节点中增加是否执行一次的标记。
typedef struct ProjectNode
{
int isOnlyOnce;
}ProjectNode;
在投影执行函数中,当投影节点的子节点为空时,说明只有select子句,只执行一次,当下次迭代进入时返回空,即结束迭代执行。
Node* ExecProject(Node *planNode)
if(prjPlanNode->isOnlyOnce)
{
return NULL;
}
if(prjPlanNode->subNode != NULL)
{
}
else
{
/* only select */
prjPlanNode->isOnlyOnce = 1;
}
另外,在生成执行计划时,当没有where子句时,选择操作节点也是可选节点,顶层投影节点的下层节点为其它存在的节点。
if(selectNode != NULL)
{
selectNode->subNode = subNode;
}
else
{
prjNode->subNode = subNode;
}
四、结果表头显示
在SQL的查询结果显示时,有一种特殊的情况,如果目标列是表达式或者常量时,如果没有给它别名时,结果列的名称就需要内部生成,有些数据库直接显示为表达式的原字符串,在这里定义为固定名称。
#define DEFAULT_COLUMN_HEAD "-column-"
当目标列名称为表达示或常量时,调用下面函数生成一个属性信息结构,其中名称为固定字符串,而属性的数据类型依据常量的类型,或者表达示中子节点常量或属性列的类型。
AttrInfo* EstimateAttr(TargetElement *te)
在显示查询结果时,会根据这个属性信息来解析目标列的值。
五、目标列表达式计算
当select子句中目标列为表达式时,在查询结果组装时,需要计算表达式的值。在select子句中的表达式一般非逻辑表达式,计算结果为具体的数据值。
Node* FormTargetResult(Node *targetList, Node *resultList)
case T_Expr:
((Expr*)te->val)->srcData = resultList;
resValue = ExprEvaluation(te->val);
offset += FormColumnData(te->attr, resValue, tempBuf + offset, PAGE_MAX_SIZE - offset);
break;
在组装处理时,增加表达式分支处理,将表达式计算的结果值作为当前目标列的值组装到结果中。
六、总结
本节内容实现代码在exam_50目录下。
【手写数据库核心揭秘系列】第87讲 逻辑表达式,运算符处理函数集合
【手写数据库核心揭秘系列】第86讲 比较运算符的实现,基本数据类型的比较操作算子集合




