ANTLR實現的SQL解析器 – OQL

來源:互聯網
上載者:User
OQL
使用ANTLR寫了個SQL解析器,這樣ORM的準系統就比較完整了。幾天的時間比較倉促,所以對於最終目標,還只能算是個雛形。

總體狀況
使用SQL解析器的主要優點:
1. 基於解析之後的文法樹提供使用者操作介面,靈活性非常好,因為達到了對SQL每一部分的完整控制。
2. 對資料庫的適應性。
   首先可以採用標準SQL,以及部分封裝好的特性(例如分頁)、函數(例如主要資料庫都支援的函數,但文法有一定差異的),使用一個適配器Dialect基於文法樹進行翻譯。這樣能滿足絕大部分用途。
   如果確實需要使用某資料庫的特性,可能只需要修改文法描述檔案就能實現,或者對文法樹等作少量修改進行配合。
3. 跟LINQ的比較。
   a. LINQ具備編譯期檢查,與VS整合的優點。
   b. 根據粗略的瞭解,感覺LINQ文法樹操作起來比較繁瑣。
   c. 自己完全把握住了整個解析過程,不會受LINQ文法和文法樹的限制。
   d. 不瞭解LINQ文法樹的開放性,即結構的穩定、相容性。例如以後添加新的特性,是否會影響到文法樹的結構?
   類似LINQ to Hinbernate一樣,只將LINQ當作查詢的輸入,而使用自己的ORM實現持久化,中間的可控能力會比較強。雖然LINQ與OQL在功能上重合,只是各有優缺點而已,並且可以採用不錯的結合點。

目前的主要缺點:
1. 基於SQL Server的文法。
2. AST文法樹看起來以及實現上不大流暢,運算式類體繫結構理的不大清楚。
3. 資料庫Dialect的機制不好。

以後的目標:
1. 多資料庫支援。
   不管是純粹ORM操作,還是OQL或者SQL,都能由資料庫dialect自動翻譯。
2. 文法: 基於標準DML文法,添加必要的特性。
   a. 分頁,預計使用select distinct? range(start, end) column1, column2..這樣的方式,由資料庫dialect向各特定資料庫SQL文法進行翻譯。SQL Server 2000這種不完整支援的,由dialect輔助完成。
   b. 標準函數,常用的SQL 92標準函數應當都能向各個資料庫進行翻譯,還可以提取一些其它函數,主流資料庫都支援且能夠進行翻譯的。
3. 標準化Query Hints。
   目的是在OQL中提供一個效能調優的機會,針對主要Query Hints進行提取,由dialect翻譯成各資料庫特定文法。
4. Object Query / 標準SQL Query功能。
   a. 不象Hibernate要求純粹的物件模型,OQL使用DomainClass1 inner join DomainClass2 on ...這樣的方式。缺點是物件模型的內部結構被暴露,但更具靈活性。以後考慮對物件模型的自動支援,也就是可以使用各種混合方式進行開發。還允許DomainClass和Database Table混合寫在OQL中,用於滿足類似many-to-many的關聯表不會建立DomainClass,又不想用對象屬性建立雙向映射關係的情況。
   b. 程式先給出查詢語句,OQL解析出文法樹,基於文法樹再動態修改,例如根據介面的選擇添加查詢條件、排序方式、需要的欄位等。進一步,一些非必要的關聯關係能夠在運行時自動、動態確定。
   c. 基於文法樹進行修改的靈活性,應當能夠提供比較靈活的AOP功能,例如AOP方式的資料許可權控制。

下一步代辦事項:
1. 項目中將使用者介面和必要的功能特性進行完善。
2. 文法樹結構的完善,運算式類體系的完善,資料庫Dialect、O-R Mapping等與OQL結合的機制以及職責的梳理完善。
3. 標準化,主流資料庫Dialect。
4. 文法最佳化(重點是解析效能)。

目前文法大致描述:
Statement: SelectStatement | UnionStatement | InsertStatement | UpdateStatement | DeleteStatement;
SelectStatement: SelectClause FromClause? WhereClause? (GroupByClause Having?)? OrderByClause?;

SelectClause: Columns+;
Column: '*'? | Identifier '.*'
             | Expressions Alias?
//MathOperator為數學運算子,例如+, -, *, /, %
Expressions: Expression (MathOperator Expression)*;
//Identifier為欄位/屬性名稱,Constant為常量,包括系統變數例如@@identity之類以及字串等
//Case .. When 語句當作Function處理
Expression: Identifier | Constant | UserVariable | Function | SelectStatement | UnionStatement;

//Where子句採用較標準的運算文法樹形式,類EBNF描述
WhereClause: Condition;
Condition: SubCondition ((AND ^ | OR ^) SubCondition)*
SubCondition: '(' Condition ')' | Predicate;
Predicate: Expressions (
        ComparisonOperator Expressions //ComparisonOperator為>, <=, !>, Like等比較子
        | IS NOT? NULL
        | IN '(' Expressions (',' Expressions)* ')'
        | BETWEEN Expressions AND Expressions
        | IN '(' (SelectStatement | UnionStatement) ')'
    ) |
    EXISTS '(' (SelectStatement | UnionStatement) ')';

整體:
  

Select子句:                                                        Where子句:
                                  

解析效能測試:
下面這個SQL應該能夠代表絕大部分普通查詢情況,迴圈解析1000次,所用時間在480-600ms之間。其中{0}, {1}是在迴圈中替換為當前計數,使每次解析的SQL不一樣。這樣普通情況下,把解析後的文法樹進行緩衝已經沒有太多必要。Select 12, 'ada {0} And >0""' As c1, (select 1), @UserName, case when a=1 then 1 else 0 end, sum(a) as Total
From Sys_User a, Sys_Org b
inner join Sys_Org_View c on c.Org_Id=b.Org_Id and (ccc={1})
Where cast(a.User_Id as varchar)=b.User_Id or (a=b and Total between 100 And 1000)
Group bY a, b
haViNg Total between 100 And 1000
Order By a, DDD Desc, A asc

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.