乐趣区

关于tidb:TinySQL学习笔记之proj2

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

文件 tinysql/parser/parser.y:3806

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

$$示意本节点的值,$[n]标识构造中第 n 的局部的值,从 1 开始。

退出移动版