hibernate中antlr对于hql与sql的转换源码的一些细节

本文详细介绍了Hibernate5.1.11Final版本中HQL语法树的构建过程,包括对象类如何转换为表名、嵌套查询的处理方式以及HQL与SQL节点之间的转换机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hibernate 5.1.11Final

 

关于hql中的对象类转换成表名。

在from模块里对hql抽象语法树进行匹配的时候,在path()规则会还原在对hql进行语法解析的时候生成的语法树。

public final String  path(AST _t) throws RecognitionException {
   String p;
   
   AST path_AST_in = (_t == ASTNULL) ? null : (AST)_t;
   returnAST = null;
   ASTPair currentAST = new ASTPair();
   AST path_AST = null;
   AST a_AST = null;
   AST a = null;
   AST y_AST = null;
   AST y = null;
   
      p = "???";
      String x = "?x?";
      
   
   try {      // for error handling
      if (_t==null) _t=ASTNULL;
      switch ( _t.getType()) {
      case WEIRD_IDENT:
      case IDENT:
      {
         a = _t==ASTNULL ? null : (AST)_t;
         identifier(_t);
         _t = _retTree;
         a_AST = (AST)returnAST;
         astFactory.addASTChild(currentAST, returnAST);
         p = a.getText();
         path_AST = (AST)currentAST.root;
         break;
      }
      case DOT:
      {
         AST __t475 = _t;
         AST tmp7_AST = null;
         AST tmp7_AST_in = null;
         tmp7_AST = astFactory.create((AST)_t);
         tmp7_AST_in = (AST)_t;
         astFactory.addASTChild(currentAST, tmp7_AST);
         ASTPair __currentAST475 = currentAST.copy();
         currentAST.root = currentAST.child;
         currentAST.child = null;
         match(_t,DOT);
         _t = _t.getFirstChild();
         x=path(_t);
         _t = _retTree;
         astFactory.addASTChild(currentAST, returnAST);
         y = _t==ASTNULL ? null : (AST)_t;
         identifier(_t);
         _t = _retTree;
         y_AST = (AST)returnAST;
         astFactory.addASTChild(currentAST, returnAST);
         currentAST = __currentAST475;
         _t = __t475;
         _t = _t.getNextSibling();
         
                  StringBuilder buf = new StringBuilder();
                  buf.append(x).append(".").append(y.getText());
                  p = buf.toString();
               
         path_AST = (AST)currentAST.root;
         break;
      }
      default:
      {
         throw new NoViableAltException(_t);
      }
      }
   }
   catch (RecognitionException ex) {
      reportError(ex);
      if (_t!=null) {_t = _t.getNextSibling();}
   }
   returnAST = path_AST;
   _retTree = _t;
   return p;
}

在此处,当没有匹配到点’.’的时候,也就是匹配到的是常量的时候会直接返回牡丹石如果匹配到的点,那么需要对当前的子树进行中序遍历,还原此处的类名全称,在此处匹配完点之后会继续通过path()规则去匹配其子节点,达到递归中序遍历该子树的目的。

相应的,不断匹配点,直到匹配到字符串常量x的时候,会紧接着得到当前字符串的兄弟节点字符串为y,当前子树的字符串凭借为x.y,之后不断向前拼接字符串,最后可以平成为完整的类。

在得到完整的类路径之后,会在from的规则fromElement()方法下createFromElement()方法中根据类名获得对应的tableName,也就是表名。

 

关于嵌套的处理

在sql语句常常存在嵌套的存在,在HqlSqlWalker给出了解决的方案。

以from模块为例子,在sql的抽象语法树中,每一个from子树都会有一个fromClause作为其父节点,每个fromClause都存在一个level属性代表其代表第几层嵌套。

同时在HqlSqlBaseWalker中给出了一个堆栈来存放当前所正在解析的fromClause节点,每次在准备进行一轮新的from解析的时候都会将当前fromClause节点入栈,结束之后出栈,达到迅速获得当前fromClause上下文的目的。同时,也在fromClause中选择一个set来存放其子from模块。

 

关于hql节点与sql节点的转换

Hql节点的生成以词法解析的结果得到的Token为依据来产生对应的语法树节点。

public AST create(Token var1) {
    AST var2 = this.create(var1.getType());
    if (var2 != null) {
        var2.initialize(var1);
    }

    return var2;
}

 

sql节点的生成以hql语法树节点的类型(int值)为依据,来产生对应的sql语法树节点。

public AST create(AST var1) {
    if (var1 == null) {
        return null;
    } else {
        AST var2 = this.create(var1.getType());
        if (var2 != null) {
            var2.initialize(var1);
        }

        return var2;
    }
}

由此可以达到hql节点与sql节点的同样语意的转换。

 

关于hql赋值参数的语句

Hql中赋值支持冒号加变量名,当在转换过程中匹配表达式的时候匹配到了冒号或者问号,则会开始参数的匹配,如果存在冒号或者带数字的问号,则会作为带名称的参数加入到语法树中,而单纯的问号只是作为普通的参数节点加入的语法树中。

protected AST generateNamedParameter(AST delimiterNode, AST nameNode) throws SemanticException {
   return (AST)astFactory.make( (new ASTArray(1)).add(astFactory.create(NAMED_PARAM,nameNode.getText())));
}

protected AST generatePositionalParameter(AST inputNode) throws SemanticException {
   return (AST)astFactory.make( (new ASTArray(1)).add(astFactory.create(PARAM,"?")));
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值