THSS-DB / TDB

Educational Database Management System for Software School of Tsinghua University
Mulan Permissive Software License, Version 2
13 stars 17 forks source link

feat: [lab3] support table alias in join clause #14

Closed hotwords123 closed 4 months ago

hotwords123 commented 4 months ago

目前代码不支持 JOIN 子句中使用表别名,涉及多表连接时不方便书写 SQL 语句。考虑扩充 SQL 解析的文法,在 join_list 支持形如 table_name table_aliastable_name AS table_alias 的语法,同时重构文法中对表别名的处理方式,提升代码复用性。

修改后,连接操作的 SQL 可以使用别名简化,例如

SELECT * FROM join_table_1 a
INNER JOIN join_table_2 b ON b.id = a.id
INNER JOIN join_table_3 c ON c.id = b.id
WHERE a.name = 'a';

同时也更方便进行 self-join,例如

SELECT * FROM join_table_1 a
INNER JOIN join_table_1 b ON b.id = a.id + 1;
hotwords123 commented 4 months ago

进一步实现时发现当前代码对于 table alias 的处理会导致 self-join 时出错。在 RowTuple 类中,判断当前表是否为 TupleCellSpec 对应的表只使用了 table name,这样如果一个表在查询中出现了两次(但是有不同的别名)会导致找不到正确的 RowTuple(总是返回 JoinTuple 中的第一个)。

目前的解决方法是,使用 table alias 而非 table name 作为单个查询中表的唯一标识符(即关系代数中关系的重命名)。例如,在 SELECT * FROM table a INNER JOIN table2 b INNER JOIN table 中,可用的三个表的 alias 分别为 a, btable,使用这三个 alias 指代查询中出现的三个表是没有歧义的。需要注意,不允许单个查询中出现重名 alias,同时将表重命名后就不能使用原来的名字引用表(和关系代数中相同,这也和 PostgreSQL 的实现一致)。

考虑到之前的 lab 中基本不涉及别名操作(只有单表操作),同时 SQL 分析时已经相对于后续逻辑较为透明地实现了 field 的解析,引入这些修改大概率不会 break 掉前面 lab 中已经实现的部分(实现合理的话)。如果查询中没有重复表,也没有使用 table alias,上述修改对程序行为理论上不会有影响。

为了实现上述修改,我在 cce8920 中修改了 SelectStmt 的解析逻辑,在 4b8c7ac 中修改了 RowTuple 匹配表的逻辑,使之与上面的 spec 一致。

修改之后,实现完本次 lab 可以支持这样的 JOIN 语句:

TDB > SELECT * FROM join_table_1 a INNER JOIN join_table_2 b ON b.id = a.id INNER JOIN join_table_3 c ON c.id = b.id WHERE a.name = 'a';
  a.id | a.name |   b.id |  b.num |   c.id | c.num2
     1 |      a |      1 |      2 |      1 |    120
Cost time: 658377 ns

TDB > SELECT * FROM join_table_1 a INNER JOIN join_table_1 b ON b.id = a.id + 1;
  a.id | a.name |   b.id | b.name
     1 |      a |      2 |      b
     2 |      b |      3 |      c
Cost time: 282253 ns

之前的代码在 IndexScanPhysicalOperator 构造和调用 set_schema 时存在一些问题,没有传入 table alias,引入上述修改会导致后续 RowTuple 拿不到数据,在 0d69221 中修复了这一问题。考虑到兼容性问题(原先构造函数并不要求传入,为保持接口一致性考虑分开传入),在 0f1497d 设置了 table alias 的默认值,同时加入了调用 set_table_alias 方法的提示信息。


在 debug 过程中,还发现代码中一个清理操作错误导致的 segmentation fault,也在 d49b8aa 中修复。