9

TinySQL学习笔记之proj2

 3 years ago
source link: https://studygolang.com/articles/32301
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文主要介绍TinySQL的 proj2 的具体思路以及实现方式

文件tinysql/parser/parser.y:3806

JoinTable:
    /* Use %prec to evaluate production TableRef before cross join */
    TableRef CrossOpt TableRef %prec tableRefPriority
    {
        $$ = *.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), Tp: ast.CrossJoin}
    }
    /* Your code here. */

在上述文件位置追加写入JoinTable的语法定义,测试不通过的case为

select * from t1 join t2 left join t3 on t2.id = t3.id

报错提示为

FAIL: parser_test.go:300: testParserSuite.TestDMLStmt

parser_test.go:426:
    s.RunTest(c, table)
parser_test.go:283:
    c.Assert(err, IsNil, comment)
... value *errors.withStack = line 1 column 29 near "left join t3 on t2.id = t3.id"  ("line 1 column 29 near \"left join t3 on t2.id = t3.id\" ")
... source select * from t1 join t2 left join t3 on t2.id = t3.id

可以看到错误起始位置为 left join 部分,因此需要观测Join语句的定义位置,一个一个项拆解看看需要如何补充。原始定义为 TableRef CrossOpt TableRef %prec tableRefPriority ,拆解出来包括了 TableRef / CrossOpt / %prec / tableRefPriority 这四项

其中 TableRef 的定义位于tinysql/parser/parser.y:3674

TableRef:
    TableFactor
    {
        $$ = $1
    }
|    JoinTable
    {
        $$ = $1
    }

因此表引用要么就是 TableFactor ,要么就是 JoinTable 。关于 TableFactor 的定义,可以看tinysql/parser/parser.y:3684,这里不在进一步展开,这个结构主要是对单表进行定义。结合 JoinTable 的定义可以看到这两个语法结构的定义是相互引用的。回到上面不通过的case

t1 join t2 left join t3 on t2.id = t3.id

其中, t1 join t2 部分可以被已经定义的 JoinTable 结构给正确解释,主要的问题在于根据当前的定义,没有办法解释后面的 left join t3 on t2.id = t3.id 这部分内容,包括了连接符和连接条件。把 t1 join t2 看做是一个 TableRef 表引用,对这部分进行字面意义的拆解的话,这里可以解释为

TableRef $连接类型 "JOIN" TableRef "ON" $连接条件

那么,找到上下文中的关于连接类型的定义, JoinType

JoinType:
    "LEFT"
    {
        $$ = ast.LeftJoin
    }
|    "RIGHT"
    {
        $$ = ast.RightJoin
    }

关于连接条件,其实表现形式是和Select语句中的 WHERE t2.id = t3.id 类似的,而参考与Select处理相关的 WhereClause 的定义tinysql/parser/parser.y:5290

WhereClause:
    "WHERE" Expression
    {
        $$ = $2
    }

可以看到,条件部分部分被定义为了表达式 Expression ,那么在 JoinTable 里面也可以直接用表达式 Expression 来定义,因此拆解完毕之后,需要补充的定义如下:

TableRef JoinType "JOIN" TableRef "ON" Expression

这样我们就完成了对于 t1 join t2 left join t3 on t2.id = t3.id 的适配,那么接下来就是要确定如何处理这部分的语法,从 JoinTable 的原定义中,可以看到语法中的 JoinTable 对应的是go中的 ast.Join 结构,那么在tinysql/parser/ast/dml.go:56可以找到定义如下:

// Join represents table join.
type Join struct {
    node

    // Left table can be TableSource or JoinNode.
    Left ResultSetNode
    // Right table can be TableSource or JoinNode or nil.
    Right ResultSetNode
    // Tp represents join type.
    Tp JoinType
    // On represents join on condition.
    On *OnCondition
}

这里我们需要对 ast.Join.Leftast.Join.Rightast.Join.Tpast.Join.On 进行赋值,参考原始定义中的写法进行定义如下:

JoinTable:
    /* Use %prec to evaluate production TableRef before cross join */
    TableRef CrossOpt TableRef %prec tableRefPriority
    {
        $$ = *.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), Tp: ast.CrossJoin}
    }
    /* Your code here. */
|   TableRef JoinType "JOIN" TableRef "ON" Expression %prec tableRefPriority
    {
        $$ = *.Join{
            Left: $1.(ast.ResultSetNode),   // 这里取出第1个部分TableRef的值作为Left
            Right: $4.(ast.ResultSetNode),  // 这里取出第4个部分TableRef的值作为Right
            Tp: $2.(ast.JoinType),          // 这里取出第2部分的JoinType的值作为Tp
            On: *.OnCondition{Expr: $6.(ast.ExprNode)}, // 这里是我们新增的部分,标识条件,即第6部分Expression的值
        }
    }

$$ 表示本节点的值, $[n] 标识结构中第n的部分的值,从1开始。

有疑问加站长微信联系(非本文作者)

eUjI7rn.png!mobile

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK