解析SQL语句比解析类C语言更麻烦?

本文首发在我的博客上:http://www.liuhaifeng.com/2009/12/sql-parser-n-c-parser.html

 

最近想做一个SQL语句解析器,换句话说想给自己的系统加上类似SQL语句的查询引擎。我之前做过一个解析类似C语言语法的解析器,可以解析 C/C++里的运算表达式,if…else…等基本语句。我以为做个SQL语句的解析器应该是很相似的,结果却发现还是有很大区别。我一度怀疑SQL解析 器要更复杂一些。

 

类C语言的语法还是很规整的,拿表达式来说,它要么是单独一句,要么就是被括号括着,也即它有着较明确的起始界限。比如if(x > 100 && y > 50)…这样一句,当碰到“(”时即转入解析表达式的状态,到遇到“)”时表达式结束,这毫无悬念。但在SQL里,可能有这种情况:select * from tb where x > 100 and y > 50 order by x;这时where条件的表达式终止不是很明显了,或许你可以说以order by结束,但如果没有order by,而是limit呢?所以说SQL里表达式解析的情况要复杂一些了,因为它的语法不是十分规整。

 

对于字段列表,情况也比较复杂。字段列表里可以包含的情况有:普通字段列表、带表名的字段列表、函数、简单运算表达式等,而这些又均可以有as重命名部分,函数、表达式里又可以引用字段名。

 

还有一个比解析类C语言麻烦的地方就是,SQL里多了个倒引号“`”,且并非必用,这又是它不规整的一个表现。一般用程序自动生成SQL语句或碰到表名、字段名正好是SQL保留关键字时为消除歧义而加上倒引号,而一般人写SQL语句时,多数是懒得加这个的。

 

SQL里的“*”号是又一个麻烦。它既可以做通配,又可以做运算符。比如select * from tb;这里的“*”是通配符,表示取所有字段,而select 10*10;则表示取10与10相乘的结果。这是一个不小的混乱,在类C语言里一般找不到这么灵活的语法。C语言是灵活的,但它的语法是相当严谨的。细翻 C语言,运算符全部是符号,标示符则不允许任何除下划线以外的符号;C++里仅有“new”算一个例外,它虽然是个单词,却属于运算符。而在SQL里用单 词做运算符却又非常常见,像“and”、“or”等。

 

最后想说的是像“order by”、“left join”这样的词组式的关键字。词组式的关键词应用在C语言里几乎没有。C语言的else if其实可以忽视,把后面的if理解为else语句即可。我把惯用的C语言缩进格式修改一下或许你就一下子明白else if只是两个语句碰到了一块:

if(expr){

//...

} else

if(expr2) {

//...

} else {

//...

}

上面的代码格式一目了然,else与if只是上演一场奇遇而已。至于C++/Java中类似public static这样的组合,它们是分别表意,而通常没有组合意义,最多是组合冲突。组合表意会使语言解析的难度提高一个层次,一般的编译器分析完词法,就可 以分析语法了;加入词语组合后这中间就不得不多一道工序,做词组分析。相应的语法分析自然也要随之调整。

 

当然,SQL里的词组还是比较简单、有限的,在预处理时进行合并也是可以的。SQL语言也并不是非常复杂,只是如果想着把解析类C语言的方法搬过来套用,就会有不少麻烦了。

 

综上所述,SQL语言结构上终止不明确,运算符与标示符界限不明确,符号有歧义,又有许多词组,使得它的解析与类C语言的解析有很大不同,必须单独对待,切务小看了简单的SQL语言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值