如鵬網 大學生計算機學習社區

          CowNew開源團隊

          http://www.cownew.com 郵件請聯系 about521 at 163.com

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            363 隨筆 :: 2 文章 :: 808 評論 :: 0 Trackbacks

          作者楊中科

          CowNew 開源團隊網站 http://www.cownew.com

          論壇 http://www.cownew.com/newpeng/?

          轉載請保留此信息

          一、HQL代碼的構建。
          (1)首先將hibernate中的src目錄下的代碼解壓。
          (2)安裝配置好antlr。
          (3)把grammar目錄下的三個.g文件(hql.g,hql-sql.g,sql-gen.g)解壓到一個目錄,然后從命令行進入此目錄,依次運行"java antlr.Tool hql.g","java antlr.Tool hql-sql.g","java antlr.Tool sql-gen.g",將生成的java代碼拷貝到源代碼的org.hibernate.hql.antlr下。
          二、讓我們從QueryTranslatorImpl開始分析,當調用session.find('...')的時候將會調用QueryTranslatorImpl的compile方法來解析hql語句為sql語句。compile則主要是調用的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();
          }

          可以看到主要是三步:調用parse方法將hql解析成AST,調用analyze根據上一步生成的AST生成SQLAST,調用generate根據上一步生成的SQL AST生成sql語句, 調用w.getSelectClause()就得到sql語句了。
          “用parser把ast抽取出來,再用treeparser進行動作的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轉化為sql ast,將生成模塊與hibernate解耦。
          ?? 3.sql-gen.g 定義tree walker,從sql ast生成sql
          ”-《看Hibernate3如何解釋HQL語言》
          2、
          逐步分析:
          (1)parse方法:
          HqlParser是從hql.g生成的HqlBaseParser繼承來的,主要實現了HqlBaseParser定義的幾個模版方法,傳入的是hql語句,傳出的是HQL AST。
          (2)analyze:
          HqlSqlWalker是從hql-sql.g生成的HqlSqlBaseWalker繼承來的,HqlSqlBaseWalker又是從TreeParser繼承的,主要實現了HqlSqlBaseWalker定義的幾個模版方法,傳入的是HQL AST,傳出的是SQL AST。
          hql-sql.g比hql.g簡單許多了,因為hql-sql.g已經為我們生成了HQL AST了,hql-sql.g需要做的就是把HQL AST組裝成強類型的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" );
          ?}
          ?;
          這里主要就是在調用模版方法拼狀強類型的SQL AST(異構AST)。所有的節點都定義在org.hibernate.hql.ast.tree中。
          與第一部的HqlParser用戶幾乎不用寫任何代碼相反,我們需要完成我們從HqlSqlBaseWalker繼承來的HqlSqlWalker的那些模版方法。
          (3)generate方法:
          遍歷SQL AST,輸出sql語句。SqlGenerator是從sql-gen.g生成的SqlGeneratorBase繼承來的。輸入的是SQL AST,輸出的是SQL語句。我個人認為這一步也可以通過全部書寫代碼完成,可能更清晰,更靈活。
          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("(");就是在拼裝代碼。

          posted on 2006-06-02 00:56 CowNew開源團隊 閱讀(4978) 評論(2)  編輯  收藏

          評論

          # re: CowNew開源學習文檔-hibernate 的HQL源碼分析1 2006-06-02 10:03 人要有夢想
          其實說白了就是使用antlr做詞法語法分析。
          HQL->HQL AST->SQL AST->SQL  回復  更多評論
            

          # re: CowNew開源學習文檔-hibernate 的HQL源碼分析1 2007-06-29 09:56 大灰狼
          小弟請教一個問題: 在oracle中有一個NUMBER(2)字段,里面有一個記錄存有值2;現寫一個hql語句,.....where typelevel=2或typelevel<>2為什么都不起作用,要不該怎么寫?  回復  更多評論
            


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 双城市| 鄯善县| 黔西县| 普安县| 辰溪县| 嘉义市| 扎鲁特旗| 杭州市| 贵州省| 威海市| 丘北县| 泾川县| 梁山县| 无棣县| 陆良县| 武清区| 佛山市| 萨嘎县| 西和县| 湟中县| 南华县| 苏州市| 高淳县| 北安市| 广平县| 宁晋县| 报价| 留坝县| 红安县| 政和县| 鲜城| 河池市| 梨树县| 贡嘎县| 中阳县| 阳春市| 芦山县| 五常市| 新余市| 安远县| 上饶市|