【问题标题】:Parser for Oracle SQLOracle SQL 解析器
【发布时间】:2011-04-20 19:48:09
【问题描述】:

对于我当前的项目,我需要一个解析 Oracle SQL 语句的 SQL 解析器。 目前我一直在使用 jsqlparser,它适用于简单的查询。但是当出现特定函数时(例如 cast() 或 (+)),解析器就会失败。

谁能推荐一个完全符合 Oracle SQL 的解析器?

最好, 会

【问题讨论】:

  • 你到底想从这个解析器中得到什么?
  • 如果我得到语句的 AST 基本上就足够了,因为我已经为 jsqlparser 编写了我的访问者,如果有更好的,我将需要适应新的解析器。
  • AST 自动语句调优?

标签: sql oracle parsing


【解决方案1】:

ANTLR (v3, v4) 解析器生成器已经为它编写了许多 Oracle SQL 和 PL/SQL 语法;有关详细信息,请参阅grammar list (v3)。其中:

  • 我使用了 Andrey Kharitonkin 的 “用于 ANTLR v3 的 Oracle PL/SQL 语法”;从内存上看,它支持 8i 时代的大多数 SQL 和 PL/SQL 语法,还有一些出现在 9i 和 10g 中的零碎代码
  • Patrick Higgins 的 “PL/SQL” 语法较新,并声称支持大多数 11g 语法,但它似乎只是吞下大多数 DML 语句 - 如果您对 SQL 特别感兴趣,它就不太有用

【讨论】:

  • “语法列表”链接已损坏
  • 已更新。看起来事情在 ANTLR 4 发布后有所改变。
【解决方案2】:

在解决了同样的问题后,我设法让 SQL 解析器工作:

我的代码如下所示:

import oracle.jdeveloper.db.DatabaseConnections;
import oracle.javatools.db.sql.SQLQueryBuilder;
import oracle.javatools.db.Database;
...
// load the database connections
// this is specific to Oracle SQL developer
DatabaseConnections connections = DatabaseConnections.getPrivateInstance(
    (new File("src/test/resources/connection.xml")).toURI().toURL(),
    "somePassword");
// get the one we are interested in
Database database = connections.getDatabase("the-name-of-a-sqldeveloper-connection");
SQLQueryBuilder queryBuilder = SQLQueryBuilderFactory.createBuilder(
      database, new Schema("OPTIONAL_SCHEMA"), "select * from some_table");

实现这项工作的挑战是:

  • 获取 Oracle SQL Developer 是一项挑战。为此,您需要破解 Oracle SQL Developer 创建的文件以保持这些连接;上例中的 connection.xml 如下所示:
<?xml version = '1.0' encoding = 'UTF-8'?>
<References xmlns="http://xmlns.oracle.com/adf/jndi">
   <Reference name="the-name-of-a-sqldeveloper-connection"     className="oracle.jdeveloper.db.adapter.DatabaseProvider" xmlns="">
      <Factory      className="oracle.jdevimpl.db.adapter.DatabaseProviderFactory1212"/>
  <RefAddresses>
     <StringRefAddr addrType="password">
        <Contents>HSx10FtlsPc=</Contents>
     </StringRefAddr>
     <StringRefAddr addrType="oraDriverType">
        <Contents>thin</Contents>
     </StringRefAddr>
...

要获取此类文件,您需要深入了解存储 Oracle SQL Developer 设置的文件夹,然后将该内容复制粘贴到您自己的文件中。

现在,假设你能做到这一点,那么问题和我对最终解决方案感到失望的地方:

  • 构建器中的 API 不错,但解析会执行查询执行(这可能是个大问题 - 在我的情况下,我需要快速解析)。
  • API 未正式公开。由于无法在此处引用准确的措辞,我得到了一个 Oracle 答复,指出没有官方支持的 Oracle 解析器(暗示的原因是这是一项非常有价值的技术,不会出售或许可)。
  • 虽然这更像是一种 hack 而不是一种解决方案,但我意识到它可能对某些情况有用(不是我的)。我认为,从技术和法律角度来看,在现实生活场景中使用它可能存在很高的风险。

我发布此答案的原因是为了促使社区关注拥有 Oracle SQL 解析器是完全可行的这一事实,也许有一天 Oracle 会考虑将解析器作为一种竞争优势(我是肯定有用户愿意支付一些费用来获得许可证)。

【讨论】:

    【解决方案3】:

    请问,为什么不使用 Oracle 解析器?

    create global temporary table plans as select * from table(dbms_xplan.display_cursor());
    --/
    declare
    c number;
    i varchar2(30);
    l number;
    stmt varchar2(4000);
    begin
    delete from plans;
    stmt:= 'select z.* from z,skew1 where z.z = skew1.fillblocks';
    l:= length(stmt);
    c:=dbms_sql.open_cursor();
    dbms_sql.parse (c, stmt,dbms_sql.native);
    select distinct sql_id into i from v$open_cursor where sid in (select sid from v$mystat) and substr(sql_text,1,l) = substr(stmt,1,l);
    insert into plans select * from table(dbms_xplan.display_cursor(i));
    dbms_output.put_Line ('sql_id:'||i);
    end;
    /
    select * from plans;
    
    PLAN_TABLE_OUTPUT                                                             
    ----------------------------------------------------------------------------  
    SQL_ID  97qc3ynmw1pa4, child number 0                                         
    -------------------------------------                                         
    select z.* from z,skew1 where z.z = skew1.fillblocks                          
    
    Plan hash value: 942457544                                                    
    
    ----------------------------------------------------------------------------  
    | Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |  
    ----------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT   |       |       |       |    85 (100)|          |  
    |*  1 |  HASH JOIN         |       |     1 |   410 |    85   (2)| 00:00:02 |  
    |   2 |   TABLE ACCESS FULL| Z     |     1 |     9 |     2   (0)| 00:00:01 |  
    |   3 |   TABLE ACCESS FULL| SKEW1 |  6000 |  2349K|    82   (0)| 00:00:01 |  
    ----------------------------------------------------------------------------  
    
    Predicate Information (identified by operation id):                           
    ---------------------------------------------------                           
    
       1 - access("Z"."Z"=INTERNAL_FUNCTION("SKEW1"."FILLBLOCKS"))   
    

    您确实需要一个 oracle 数据库连接。如果输出是您想要的,这是获得您想要的最简单的方法,而无需为轮子重新发明其他颜色。在此示例中,我将 sql 限制为 4000 个字符,但您可以将 varchar2 的 pl/sql 数组输入到 dbms_sql.parse 函数中,这样做可以让您解析难以想象的大小的 sql。

    【讨论】:

    • 我其实只有sql语句,没有别的。所以我真的仅限于静态分析 SQL。我需要回答的问题包括,该 sql 语句中有哪些表。
    【解决方案4】:

    你考虑过General SQL Parser吗?我自己没有任何经验,但浏览他们的网站它有潜力。就我个人而言,我已经在 Eclipse Data Tools Platform 的解析器上推出了自己的构建(抱歉,我不能分享,它是专有的),但现在我必须评估我上面链接的那个,因为它声称对 Oracle SQL 的覆盖范围比我的解析器可以。

    【讨论】:

    • 是的,我还发现了他们的网站,并且已经尝试使用这个解析器解析一些查询。但是他们的试用版只允许解析 2000 个字符,所以我无法完全测试和评估是否值得购买。所以我在想也许有人知道一些好的选择或有一些经验可以分享:)
    • 我最终决定获得这个解析器的许可证。到目前为止看起来还不错,但已经在其语法中发现了一个错误。
    • 看看他们对修复错误的反应会很有趣。
    • 他们不是很敏感,一周后第一个人联系了我,并为我提供了一个下载“改进”版本解析器的链接。再次尝试并没有解决我的问题。再次联系他,已经6个多星期没有得到任何回复..
    【解决方案5】:

    鉴于甲骨文公司无法使 SQL 和 PL/SQL VM 的 SQL 解析器在两者具有不同的 SQL 解析器时保持同步,因此第三方不太可能创建“完全兼容”的解析器。

    您要从查询中提取哪些数据? Oracle 数据库本身可能具有其他工具,可以让您在不先解析查询的情况下提取该信息。

    【讨论】:

    • 我不需要解析 PL/SQL,而且我仅限于 sql 语句(不能访问数据库)。
    • 我不是在谈论 PL/SQL 解析器。 Oracle 在内部有单独的 PL/SQL 和 SQL VM。多年来,他们每个人都有自己的 SQL 解析器。多年来,您会发现无法在 PL/SQL 块中嵌入特定的有效 SQL 语句,因为 PL/SQL VM 的 SQL 解析器无法解析它。但是,当您将相同的 SQL 语句传递给 SQL VM 时,SQL VM 的 SQL 解析器就没有问题了。这不再是问题,因为两个 VM 共享一个 SQL 解析器。但它确实显示了跟上 SQL 语法发展的难度。
    • 感谢您的信息。这就是为什么我说我只需要一个 SQL 解析器。他们无法使两个不同的解析器保持同步的问题,不影响第三方创建可以处理所有 SQL 的解析器的可行性。
    【解决方案6】:

    我们的DMS Software Reengineering Toolkit 可以通过 Oracle PLSQL 解析器或 SQL 2011 解析器获得。 DMS 提供一个解析器,构建一个 AST,让您可以任意调查/转换树,如果您想这样做,还可以将 AST 重新生成为源代码。

    您可以通过从网站下载 PLSQL 格式化程序来测试解析器;使用相同的底层 DMS 机制;只是不分析/转换树。

    您可能需要将 SQL 语句包装在一个简单的 PLSQL 过程中。

    【讨论】:

    • Flagger:您可以有礼貌地解释一下您为什么回答这个问题。它直接回答了OP的问题。
    【解决方案7】:

    试试这个http://www.ibrezina.net/OracleSQL.tgz。它是 Oracle 的 PL/SQL 的 ANTLR3.3 语法。该语法适用于 C 目标,但可以轻松转换为 Java 或 C#。您的任务,查询中包含的表列表已作为示例包含在内。

    【讨论】:

    • 我不会说它很容易将其转换为 C#。至少不适合 C# 程序员。
    猜你喜欢
    • 2021-12-28
    • 1970-01-01
    • 2012-08-15
    • 2013-10-14
    • 2012-06-14
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 2019-07-29
    相关资源
    最近更新 更多