💻 深耕数据库内核架构设计与开发十余年,曾主导多款高性能分布式数据库内核研发,攻克高并发、低延迟等核心技术难题。现倾力打造《从零手写数据库》系列教程,首次系统性公开数据库内核源码级实现细节!
一、概述
在SQL语法解析中,select子句和from子句中都支持别名语法,也就是属性列名称、数据表名称或者子查询等都可以进行重命名操作,
这就需要在一些处理流程上做相应的匹配,主要涉及以下改动点:
目标列与数据源表的对应关系; 查询结果与数据源表的对应关系; 查询结果显示时的标题。
二、目标列与数据源表的对应
目标列需要与它命名域对应的数据源表关联起来,
比如SQL查询 “select a.id, b.id from student a, student b;”,
虽然两个数据源来自同一个实际的数据表student,但是两个目标列对应不同的数据源表,不同的数据源表在执行过程中查询的结果是不一样的。
因此在目标列结构中新增数据源的成员,在逻辑执行计划阶段与对应的数据源表关联起来。
typedef struct TargetElement
{
Node *tblRefInfo;
}TargetElement;
在处理添加目标列和检查目标列时,会在数据源表中检查目标列是否存在,此时目标列中记录对应的数据源表信息。
在下面两个函数中增加数据源表的关联动作。
int AddOneRelationAttributes(TableRefInfo *tblRefInfo, QueryStmt *queryStmt)
te->tblRefInfo = (Node*)tblRefInfo;
int CheckOneAttribute(TargetElement *te, char *attrName, TableRefInfo *tblRefInfo)
te->tblRefInfo = (Node*)tblRefInfo;
另外,目标列的别名信息为空时,将它赋值为数据源表中的属性列名称,使得结果显示时可以统一使用目标列的别名字段。
int CheckAttributes(TargetElement *te, QueryStmt *queryStmt)
if(te->alias == NULL)
te->alias = refNode->sub_name;
三、查询结果与数据源表的对应
如上节的举例,一个实际的数据表会作为多个数据源表来查询,每个数据源表都会产生查询结果,因此查询结果集中的每个结果需要与数据源表进行关联,而不是与实际的数据表关联。
typedef struct ResultNode
{
Node *tblRefInfo;
}ResultNode;
因此在查询结果结构中新增数据源成员,来记录结果的来源表。
在扫描操作产生一条查询结果时,将数据源表信息也记录到结果节点当中。
Node* ExecSeqScan(Node *planNode)
result->tblRefInfo = seqScan->tblRefInfoNode;
相同的数据表,在不同数据源查询中的结果不同,所以在结果集上的运算需要按数据源来获取对应的值。
在投影操作时,根据目标列获取对应的数据源表的查询结果时,也根据目标列对应的数据源在结果集中查找。
ResultNode* GetResultNodeFromList(TargetElement *te, List *resultList)
if(te->tblRefInfo == resNode->tblRefInfo)
四、查询结果标题显示
在客户端显示查询结果时,结果的标题显示应该是目标列的别名,而不是数据表的属性列,如果没有指定别名时,才显示为属性列名称。
void ShowTableHead(List *targetList)
snprintf(buf + bufOffset, PORT_BUFFER_SIZE - bufOffset, "|%-*s", te->attr->maxWidth, te->alias);
五、概述
本节修改内容在目录exam_48下的 plan.c, excutor.c和portal.c文件中。
🌟 点赞收藏,分享给身边的技术伙伴,关注我们,持续获取数据库内核开发的硬核干货!一起从源码级实现到分布式架构,解锁数据库技术的每一个核心细节!🚀【手写数据库内核miniToadb】第81讲 数据字典的持久化存储




