作者楊中科
CowNew
開源團(tuán)隊(duì)網(wǎng)站
http://www.cownew.com
論壇
http://www.cownew.com/newpeng/?
轉(zhuǎn)載請保留此信息
一、HQL代碼的構(gòu)建。
(1)首先將hibernate中的src目錄下的代碼解壓。
(2)安裝配置好antlr。
(3)把grammar目錄下的三個.g文件(hql.g,hql-sql.g,sql-gen.g)解壓到一個目錄,然后從命令行進(jìn)入此目錄,依次運(yùn)行"java antlr.Tool hql.g","java antlr.Tool hql-sql.g","java antlr.Tool sql-gen.g",將生成的java代碼拷貝到源代碼的org.hibernate.hql.antlr下。
二、讓我們從QueryTranslatorImpl開始分析,當(dāng)調(diào)用session.find('...')的時候?qū){(diào)用QueryTranslatorImpl的compile方法來解析hql語句為sql語句。compile則主要是調(diào)用的doCompile方法。
// PHASE 1 : Parse the HQL into an AST.
HqlParser parser = parse( true );
// PHASE 2 : Analyze the HQL AST, and produce an SQL AST.
HqlSqlWalker w = analyze( parser, collectionRole );
sqlAst = ( Statement ) w.getAST();
generate( ( QueryNode ) sqlAst );
queryLoader = new QueryLoader( this, factory, w.getSelectClause() );
parse的主要代碼:
private HqlParser parse(boolean filter)
?HqlParser parser = HqlParser.getInstance( hql );
?parser.statement();
?AST hqlAst = parser.getAST();
??return parser;
}
analyze的主要代碼:
private HqlSqlWalker analyze(HqlParser parser, String collectionRole) throws QueryException, RecognitionException {
?HqlSqlWalker w = new HqlSqlWalker( this, factory, parser, tokenReplacements, collectionRole );
?AST hqlAst = parser.getAST();
?w.statement( hqlAst );
?return w;
}
generate的主要代碼:
private void generate(AST sqlAst) throws QueryException, RecognitionException {
?SqlGenerator gen = new SqlGenerator(factory);
?gen.statement( sqlAst );
?sql = gen.getSQL();
}
可以看到主要是三步:調(diào)用parse方法將hql解析成AST,調(diào)用analyze根據(jù)上一步生成的AST生成SQLAST,調(diào)用generate根據(jù)上一步生成的SQL AST生成sql語句, 調(diào)用w.getSelectClause()就得到sql語句了。
“用parser把a(bǔ)st抽取出來,再用treeparser進(jìn)行動作的double pass builder模式,解耦了parser和generation,再配合template,是antlr推薦的最佳模式。”-《看Hibernate3如何解釋HQL語言》
1、三個語法文件的作用:
“
hibernate的hql grammar文件一共有三個,在/grammar目錄下:
?? 1.hql.g?? 定義token類和parser類,將hql解釋成hql的抽象語法樹(ast)
?? 2.hql-sql.g? 定義tree walker ,將hql ast轉(zhuǎn)化為sql ast,將生成模塊與hibernate解耦。
?? 3.sql-gen.g 定義tree walker,從sql ast生成sql
”-《看Hibernate3如何解釋HQL語言》
2、
逐步分析:
(1)parse方法:
HqlParser是從hql.g生成的HqlBaseParser繼承來的,主要實(shí)現(xiàn)了HqlBaseParser定義的幾個模版方法,傳入的是hql語句,傳出的是HQL AST。
(2)analyze:
HqlSqlWalker是從hql-sql.g生成的HqlSqlBaseWalker繼承來的,HqlSqlBaseWalker又是從TreeParser繼承的,主要實(shí)現(xiàn)了HqlSqlBaseWalker定義的幾個模版方法,傳入的是HQL AST,傳出的是SQL AST。
hql-sql.g比hql.g簡單許多了,因?yàn)閔ql-sql.g已經(jīng)為我們生成了HQL AST了,hql-sql.g需要做的就是把HQL AST組裝成強(qiáng)類型的SQL AST,此處大量引用了hql.g中定義的Vocabulary。
比如:
query!
?: #( QUERY { beforeStatement( "select", SELECT ); }
???// The first phase places the FROM first to make processing the SELECT simpler.
???#(SELECT_FROM
????f:fromClause
????(s:selectClause)?
???)
???(w:whereClause)?
???(g:groupClause)?
???(o:orderClause)?
??) {
??// Antlr note: #x_in refers to the input AST, #x refers to the output AST
??#query = #([SELECT,"SELECT"], #s, #f, #w, #g, #o);
??beforeStatementCompletion( "select" );
??processQuery( #s, #query );
??afterStatementCompletion( "select" );
?}
?;
這里主要就是在調(diào)用模版方法拼狀強(qiáng)類型的SQL AST(異構(gòu)AST)。所有的節(jié)點(diǎn)都定義在org.hibernate.hql.ast.tree中。
與第一部的HqlParser用戶幾乎不用寫任何代碼相反,我們需要完成我們從HqlSqlBaseWalker繼承來的HqlSqlWalker的那些模版方法。
(3)generate方法:
遍歷SQL AST,輸出sql語句。SqlGenerator是從sql-gen.g生成的SqlGeneratorBase繼承來的。輸入的是SQL AST,輸出的是SQL語句。我個人認(rèn)為這一步也可以通過全部書寫代碼完成,可能更清晰,更靈活。
selectExpr
?: e:selectAtom { out(e); }
?| count
?| #(CONSTRUCTOR (DOT | IDENT) ( selectColumn )+ )
?| methodCall
?| aggregate
?| c:constant { out(c); }
?| arithmeticExpr
?| PARAM { out("?"); }
?| sn:SQL_NODE { out(sn); }
?| { out("("); } selectStatement { out(")"); }
其中的out("(");就是在拼裝代碼。