【问题标题】:PostgreSQL syntax check without running the query不运行查询的 PostgreSQL 语法检查
【发布时间】:2012-01-06 11:33:18
【问题描述】:

我想验证包含 sql 查询的文件的语法,然后才能将它们提交到我的 CVS 项目中。

为了做到这一点,我有一个 commitinfo 脚本,但我无法确定 sql 命令是否有效。 psql 似乎没有空运行模式,从语法(源代码中)构建我自己的 postgresql-dialact 测试器似乎很长。

脚本可能包含多个查询,因此不能将EXPLAIN 包裹起来。

有什么提示吗?

【问题讨论】:

  • 我在 postgresql 块上存在与 SP 相关的问题,直到它未被调用时才被验证
  • @triclosan:你可能对plpgsql lint 感兴趣,它正好解决了这个缺点。 Pavel Stěhule 是主要开发人员。看到这个blog post
  • 我对 postgres 不是很有经验,所以这可能是一个糟糕的解决方法,不值得真正回答,但我只是在脚本末尾添加了一个垃圾行,我知道这会导致错误.如果它遇到的第一个错误是垃圾行,我可以有理由相信脚本的其余部分是好的。与事务不同,它保留序列值,对于简单的脚本,它比下载另一个实用程序更快、更容易。

标签: sql parsing postgresql syntax cvs


【解决方案1】:

我最近编写了一个实用程序来静态检查 PostgreSQL 的 SQL 语法。它利用 ecpg(用于 postgres 的嵌入式 SQL C 预处理器)来检查 SQL 语法,因此它使用内置于 Postgres 本身的完全相同的解析器。

您可以在 github 上查看:http://github.com/markdrago/pgsanity。您可以略读一下 README,以更好地了解它的工作原理并获得如何安装它的指导。下面是一个如何使用 pgsanity 的简短示例:

$ pgsanity good1.sql good2.sql bad.sql
bad.sql: line 1: ERROR: syntax error at or near "bogus_token"

$ find -name '*.sql' | xargs pgsanity
./sql/bad1.sql: line 59: ERROR: syntax error at or near ";"
./sql/bad2.sql: line 41: ERROR: syntax error at or near "insert"
./sql/bad3.sql: line 57: ERROR: syntax error at or near "update"

【讨论】:

  • 这看起来很有帮助。我会尽快检查一下
  • 感谢 pgsanity!它真的很方便。有没有办法在 systastic (github.com/scrooloose/syntastic) 中使用 pgsanity?在 vim 中保存文件时自动运行检查真的很棒。
  • @虽然我敢打赌,将它添加到 syntastic 中并不难。我从未使用过 syntastic,也没有 vim foo 自己添加它。但是由于 pgsanity 在成功时返回 0 或在失败时返回非零,我敢打赌它会相对容易添加。
  • 伟大的工具@MarkDrago 在我经历了 小时 的调试失败后拯救了我。 :-)
  • 看起来这不再被开发了。对吗?
【解决方案2】:

使用这个技巧来验证 PostgreSQL 代码语法:

DO $SYNTAX_CHECK$ BEGIN RETURN;
    -- insert your SQL code here
END; $SYNTAX_CHECK$;

函数is_sql(sql text)

【讨论】:

  • 这个技巧太棒了! PostgreSQL 将验证块中所有 SQL 代码的语法,但由于开始时的 RETURN,它实际上并没有执行。不错!
  • 接受的答案很好。但这很好而且毫不费力。
  • 最好知道这是什么语法。它定义了一个函数,对吗?
  • 如果查询中包含commit;会不会没有副作用?
  • @samvel1024 是的,commit 不会运行。您可以通过以下实验进行验证:CREATE TABLE foo(id int); DO $$ BEGIN RETURN; BEGIN; INSERT INTO foo VALUES (1); COMMIT; END; $$; SELECT * FROM foo;。即使你将事务的BEGIN 移到DO 块之外,事务仍然不会被提交。
【解决方案3】:

一种方法是将其放入最后回滚的事务中:

BEGIN;
<query>;
<query>;
<query>;
ROLLBACK;

请注意,有些效果无法回滚,例如 dblink 调用,或写入文件系统或递增序列的任何内容。

我建议克隆您的数据库以进行测试。

【讨论】:

  • 这只能通过活动连接来完成。我宁愿进行静态检查。如果我的 sql 中有 BEGIN 语句,这不会中断吗?
  • @RobAu:额外的BEGIN; 将被忽略。将发出WARNING
  • @RobAu:静态检查不适用于动态查询。嗯:不总是。你唯一能做的就是沙盒和祈祷。
  • 这是一个非常糟糕的主意。有大量有效的 sql 语句会根据数据库的状态抛出错误。事务也适用于 CRUD,但不是架构更改,这也是 SQL
【解决方案4】:

EXPLAIN(不带 ANALYZE)将解析查询并准备执行计划,而不实际执行它。

https://www.postgresql.org/docs/current/static/sql-explain.html

【讨论】:

  • 感谢您花时间写一个答案,但正如我已经在问题中解释的那样,我不能使用 EXPLAIN。
【解决方案5】:

我通常使用Mimer online SQL validator,唯一的事情是它检查标准SQL的SQL语法:

  • SQL-92
  • SQL-99
  • SQL-03

并不特定于 PostgreSQL ...但是,如果您按照标准编写代码,则可以使用它并且它运行良好...

【讨论】:

  • 这样做的好处是您可以更轻松地切换数据库。我喜欢 postgres,近年来它变得更好了,但很长一段时间以来,它的基本理念似乎是“标准?我们要去的地方,我们不需要标准。”
  • 缺点是如果你的表名或列名有大写字母之类的,这些标识符需要写在引号中,我认为这不是其他数据库的约定。
【解决方案6】:

验证 SQL 语法的绝妙实用程序:SQL Fiddle

支持 MySQL、Oracle、PostgreSQL、SQLite、MS SQL。

【讨论】:

    【解决方案7】:

    你可以把它包起来 SELECT 1 ( &lt;your query&gt; ) AS a WHERE 1 = 0;

    验证会失败,但实际上不会执行。这是一个示例查询计划:

    Result  (cost=0.00..0.01 rows=1 width=0)
      One-Time Filter: false
    

    【讨论】:

    • 如何在一个选择中包装多个sql语句?
    • 你能运行多个选择语句吗?或者你可以在开头使用 WITH 块。
    【解决方案8】:

    您可以在 postgresql 函数旁边运行查询并最终引发异常。所有更改都将回滚。例如:

    CREATE OR REPLACE FUNCTION run_test(_sp character varying)
      RETURNS character varying AS
    $BODY$
    BEGIN
      EXECUTE 'SELECT ' || _sp;
      RAISE EXCEPTION '#OK';
    EXCEPTION
      WHEN others THEN
        RETURN SQLERRM;
    END;
    $BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    

    另一种解决方案 - plpgsql_check 扩展 (on github),pgpsql_lint 的下一个化身

    【讨论】:

    • 您可以编写一个返回 void 的包装器并将所有 DML 包含到设置环境中,运行特定的函数和查询,然后以“RAISE EXCEPTION”退出。尝试用谷歌搜索一些 pgunit。他们使用这样的技术
    猜你喜欢
    • 1970-01-01
    • 2022-10-05
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 2013-03-14
    • 1970-01-01
    • 2012-01-02
    相关资源
    最近更新 更多