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,"?")));
}