如何在TiDB Parser中支持FULL JOIN子句?
在TiDB Parser中添加FULL JOIN支持解决移进/归约冲突问题
问题背景
尝试给TiDB Parser添加FULL JOIN支持时,两种修改方案均导致make执行时出现conflicts: 2 shift/reduce错误。查看y.output发现state 1810中FULL关键字存在移进/归约冲突,可移进至state237,也可归约规则1478。尝试添加%precedence full或复用tableRefPriority未解决问题。
两种修改尝试如下:
尝试一:单独添加FULL JOIN规则
JoinTable: | TableRef "FULL" "JOIN" TableRef "ON" Expression { on := &ast.OnCondition{Expr: $6} $$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $4.(ast.ResultSetNode), Tp: ast.FullJoin, On: on} }
尝试二:扩展JoinType枚举
JoinType: "LEFT" { $$ = ast.LeftJoin } | "RIGHT" { $$ = ast.RightJoin } | "FULL" { $$ = ast.FullJoin }
同时在dml.go中添加枚举及更新Restore方法:
// JoinType is join type, including cross/left/right/full. type JoinType int const ( // CrossJoin is cross join type. CrossJoin JoinType = iota + 1 // LeftJoin is left Join type. LeftJoin // RightJoin is right Join type. RightJoin // FullJoin is full Join type. FullJoin ) // Restore implements Node interface. func (n *Join) Restore(ctx *format.RestoreCtx) error { ... switch n.Tp { case LeftJoin: ctx.WriteKeyWord(" LEFT") case RightJoin: ctx.WriteKeyWord(" RIGHT") case FullJoin: ctx.WriteKeyWord(" FULL") } ... }
冲突原因
- 尝试一单独定义FULL JOIN规则,与原有
JoinTable规则产生语法歧义,导致分析器无法确定匹配路径。 - 尝试二未正确设置
FULL关键字的优先级,使其被其他上下文规则(如FULL TEXT索引相关规则)捕获,引发移进/归约冲突。
解决方案
1. 正确声明关键字优先级
在parser.y的优先级声明区域,添加FULL的优先级,确保其作为JOIN类型时的优先级高于其他冲突规则:
%token FULL // 将FULL的优先级设置为与LEFT、RIGHT一致,且高于可能引发冲突的规则 %precedence LEFT RIGHT FULL %precedence JOIN
2. 复用JoinType规则统一处理JOIN类型
删除尝试一中单独的FULL JOIN规则,确保所有JOIN类型通过JoinType统一匹配,避免规则重复:
JoinTable: TableRef JoinType "JOIN" TableRef "ON" Expression { on := &ast.OnCondition{Expr: $6} $$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $4.(ast.ResultSetNode), Tp: $2.(ast.JoinType), On: on} } // 保留原有其他JoinTable规则(如不带ON、使用USING的场景)
3. 区分FULL关键字的上下文
检查parser.y中是否存在其他使用FULL的规则(如FULLTEXT索引),确保上下文区分:
- 在表定义上下文,
FULL需匹配FULLTEXT规则; - 在JOIN上下文,
FULL需匹配JoinType规则。
Yacc会根据当前语法状态自动区分上下文,只要优先级设置正确即可避免冲突。
验证步骤
- 执行
make parser重新生成解析器,确认无移进/归约冲突提示; - 测试FULL JOIN语句,例如:
验证解析结果是否正确生成SELECT * FROM t1 FULL JOIN t2 ON t1.id = t2.id;ast.FullJoin类型的节点。
内容的提问来源于stack exchange,提问作者xiaonerner0821
相关产品推荐
相关产品推荐

