最终成绩:240/240
本次在比赛中负责update、order by、group by、drop table、聚合运算、一次插入多条数据、NULL类型、子查询、复杂子查询和表达式10个模块共130分,具体代码见lyxiong0/miniob (github.com)。
题目要求:
insert into t3 values (1,1),(2,2),(3,3);
一次插入的数据有一个失败则整个语句失败
代码在src/observer/storage/default/default_storage_stage.cpp:178
思路:
一种摆烂的做法是内部定义一个测试不可能用到的字符,例如"Eu83"当作NULL存储…考虑到这么做没有意义,还是采用了其他正常一些的做法:
代码位置src/observer/storage/common/table.cpp:407
简单子查询和复杂子查询的区别在于复杂子查询功能上支持多层、支持运算符左右两侧都是子查询以及关联子查询,而子查询本身支持的语法只有简单的select /列、聚合/ from /表/ where …
代码src/observer/sql/parser/yacc_sql.y:910
由于子查询采用了递归调用do_select的方法实现,那怎么把外部查询的每一行数据拿去跟内部查询比较呢?这里采用了一种语义转换的方法,把关联子查询等价成包含主表的多表group by。例如select * from t1 where t1.v1 > (select t2.v2 from t2 where t2.v3 = t1.v1);中子查询部分相当于select t1.v1, max(t2.v2) from t1, t2 where t2.v3 = t1.v1 group by t1.v1。这种语义转换是我自己想的,没有去找资料验证,不保证正确性。
细节上,在ExecuteStage类里增加了is_related成员,由于ExecuteStage生命周期贯穿整个Sever运行期间,在此需要注意在每个SCF_SELECT调用do_select之前将is_related置为false。is_related成员的作用在于做一个合法性判断,在非关联子查询的情况下,子查询结果查过一列都是非法的。
代码src/observer/sql/executor/execute_stage.cpp:751
由于测试数据量很小,这里直接采用了快排的方法。
代码src/observer/sql/executor/execute_stage.cpp:1712
group by利用了哈希桶的方法,定义std::unordered_map
哈希桶思路很好理解,这里唯一的问题就是怎么利用group by的列信息给每一行构造一个哈希值。首先我们给调用STL中hash模板,给每一个类型(StringValue/IntValue/FloatValue)都定义一个to_hash方法。再给Tuple类也定义一个to_hash方法,传入参数为生成哈希值所包括的列,实现上将传入的每个列对应TupleValue的哈希值做一个异或操作(比较常见,换成与/或操作可能也行?),生成Tuple所对应的哈希值。
代码src/observer/sql/executor/execute_stage.cpp:1320
这里将id/number/id.id/左右括号全部视作单个字符串,按输入顺序存储,通过字符串数组中字符串个数是否与select中以逗号分割的个数是否相同判断为字符串还是普通select,若是字符串则进行计算。