2021SC@SDUSC
ASTNode中的异常
为了能更好地观察ASTNode这个操作树的结构,我使用了一个带子查询的hql
select * from test where id in (select * from test);
然后呢,我就看到了这个
我们集中关注children
,里面居然有一个TOK_INSERT
?明明是一个查询语句为什么会有insert
?
只能决心彻底理清这个树的结构了,于是就有了一段痛苦的翻阅过程……
ASTNode的具体结构
每一个节点都有以下几个特征:
- 有一个“名字”,在debug的图里也能看到
- 以列表
children
存储子节点 - 有一个叫做
childrenIndex
的字段
我在梳理结构时,还记录这个节点有没有被父节点说明为“childrenIndex”。如果有,则用(child)
标注。经过漫长的翻阅,结果如下(注意,我用引号标出并不代表它们仅仅是一个字符串,而是为了与系统的枚举量区别开来而已):
TOK_QUERY
TOK_FROM(child)
TOK_TABREF(child)
TOK_TABLENAME(child)
"test"
TOK_INSERT
TOK_DESTINATION
TOK_DIR(child)
TOK_TMP_FILE(child)
TOK_SELECT(child)
TOK_SELEXPR
TOK_ALLCOLREF(child)
TOK_WHERE
TOK_SUBQUERY_EXPR
TOK_SUBQUERY_OP(child)
KW_IN(child)
TOK_QUERY
TOK_FROM
TOK_TABREF(child)
TOK_TABNAME(child)
"test"(child)
TOK_INSERT(child)
TOK_DESTINATION
TOK_DIR(child)
TOK_TMP_FILE(child)
TOK_SELECT(child)
TOK_SELEXPR
TOK_ALLCOLREF(child)
TOK_TABLE_OR_COL
"id"
并不是所有的节点的childrenIndex
都会正确地指向某一个子节点。有时候会出现childrenIndex
超出children
的情况。
一头雾水。不过好在我的队友曾经查到过相关的资料,给我指出了重要的一点:TOK_INSERT
其实是查询主体。那么处于第二层的TOK_FROM
应当是hql中的最外层from
,一看hql结构,也能合理地解释它为何很快就能在叶节点中找到test
。
这样,我们可以放心地去着重分析TOK_INSERT
部分
TOK_INSERT
以下都是在讨论TOK_INSERT
为根的子树了
TOK_INSERT
TOK_DESTINATION
TOK_DIR(child)
TOK_TMP_FILE(child)
TOK_SELECT(child)
TOK_SELEXPR
TOK_ALLCOLREF(child)
TOK_WHERE
TOK_SUBQUERY_EXPR
TOK_SUBQUERY_OP(child)
KW_IN(child)
TOK_QUERY
TOK_FROM
TOK_TABREF(child)
TOK_TABNAME(child)
"test"(child)
TOK_INSERT(child)
TOK_DESTINATION
TOK_DIR(child)
TOK_TMP_FILE(child)
TOK_SELECT(child)
TOK_SELEXPR
TOK_ALLCOLREF(child)
TOK_TABLE_OR_COL
"id"
经队友指点,TOK_DESTINATION
是查询暂存相关的内容,TOK_SELECT
当然也不会有什么内容了,TOK_ALLCOLREF
的英文所指和贴合hql语句嘛。
TOK_WHERE
下有明显TOK_SUBQUERY_EXPR
,应该是对应我的子查询的。
TOK_SUBQUERY_OP
指明了这个子查询的操作,KW_IN
这样的格式在之前其实见到过哦。最后的TOK_TABLE_OR_COL
和其中的叶子节点"id"充分表达了where
的内容。
而同层的TOK_QUERY
则是一个子查询了,结构和外层很相似,你仍然可以见到"test"
的出现。
总览
这即是树的结构了,最让我意想不到的是主体查询被加在TOK_INSERT
里这件事。
这个树除了之前提到的属性之外,还有parent
属性。这个树的结构是存在上下翻飞,来回读取的可能的。