暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

POSTGRESQL的SQL美化器

飞象数据 2020-01-03
2638

SQL是一种查询语言,通常很容易阅读。但是,如果人们不能正确规范查询的格式,那么SQL也会是一场噩梦。这就是为什么开发人员通常使用SQL美化器,将不美观的查询转换成格式良好的字符串的原因。网络上有各种工具可以实现这一点。

可以仅仅使用PostgreSQL的板载工具来达到同样的效果吗?答案是肯定的。这篇文章将告诉你如何做到这一点。

PostgreSQL是如何处理视图的

在PostgreSQL中,视图不是以纯文本形式存储的。相反,它以机器可读的二进制格式存储在系统表中:

test=# \d pg_rewriteTable "pg_catalog.pg_rewrite"   Column   |    Type      | Collation | Nullable | Default------------+--------------+-----------+----------+--------- oid        | oid          |           | not null | rulename   | name         |           | not null | ev_class   | oid          |           | not null | ev_type    | "char"       |           | not null | ev_enabled | "char"       |           | not null | is_instead | boolean      |           | not null | ev_qual    | pg_node_tree | C         | not null | ev_action  | pg_node_tree | C         | not null | Indexes:  "pg_rewrite_oid_index" UNIQUE, btree (oid)  "pg_rewrite_rel_rulename_index" UNIQUE, btree (ev_class, rulename)

pg_node_tree数据类型包含这里所有不可思议的地方。这很有意义,因为在查询执行期间可以更直接地访问数据。此外,它允许PostgreSQL在不破坏视图的情况下轻松地处理字段名的更改等。在内部,PostgreSQL只使用对象ID,因此名称等都不重要。视图不会因为重命名表或字段而无效。

但是,如果使用\d+:那么PostgreSQL如何以可读的格式提供视图的定义呢?答案是:PostgreSQL再次重新组合查询。此机制可用于格式化SQL字符串并将其转换为更漂亮的内容。

请记住:该机制从未打算这样做,但是它很好地说明了可以做什么。

将视图转换为适当的查询字符串

pg_get_viewdef函数以字符串的形式返回视图的定义。我们可以利用它。让我们看看下面的函数:

CREATE OR REPLACE FUNCTION format_sql(text)RETURNS text AS$$   DECLARE      v_ugly_string       ALIAS FOR $1;      v_beauty            text;      v_tmp_name          text;   BEGIN      -- 让我们创建一个唯一的视图名称      v_tmp_name := 'temp_' || md5(v_ugly_string);      EXECUTE 'CREATE TEMPORARY VIEW ' ||      v_tmp_name || ' AS ' || v_ugly_string;       -- 神奇的地方发生在这里      SELECT pg_get_viewdef(v_tmp_name) INTO v_beauty;       -- 清楚临时对象      EXECUTE 'DROP VIEW ' || v_tmp_name;      RETURN v_beauty;   EXCEPTION WHEN OTHERS THEN      RAISE EXCEPTION 'you have provided an invalid string: %  %',            sqlstate, sqlerrm;   END;$$ LANGUAGE 'plpgsql';

它的基本作用是将一个字符串转换为临时视图。然后,该视图再次变成字符串并删除。下面是函数的作用:

test=# SELECT format_sql('SELECT * FROM                  pg_tables UNION                    ALL SELECT * FROM          pg_tables');            format_sql-------------------------------SELECT pg_tables.schemaname,+       pg_tables.tablename, +       pg_tables.tableowner, +       pg_tables.tablespace, +       pg_tables.hasindexes, +       pg_tables.hasrules, +       pg_tables.hastriggers, +       pg_tables.rowsecurity + FROM  pg_tables + UNION ALL + SELECT pg_tables.schemaname,+       pg_tables.tablename, +       pg_tables.tableowner, +             pg_tables.tablespace, +       pg_tables.hasindexes, +       pg_tables.hasrules, +       pg_tables.hastriggers, +       pg_tables.rowsecurity + FROM  pg_tables;(1 row)

如你所见,该字符串以正确的格式返回。PostgreSQL甚至会为你解析“*”,并将其转换为适当的字段列表。你在这里看到的是psql在出现换行时添加了+。我们可以轻松地修复它,并告诉psql更改其行为:

test=# \pset format unalignedOutput format is unaligned. test=# SELECT format_sql('SELECT * FROM                 pg_tables UNION               ALL                SELECT * FROM                    pg_tables'); format_sqlSELECT pg_tables.schemaname,       pg_tables.tablename,       pg_tables.tableowner,       pg_tables.tablespace,       pg_tables.hasindexes,       pg_tables.hasrules,       pg_tables.hastriggers,       pg_tables.rowsecurity FROM  pg_tables UNION ALL  SELECT pg_tables.schemaname,       pg_tables.tablename,       pg_tables.tableowner,       pg_tables.tablespace,       pg_tables.hasindexes,       pg_tables.hasrules,       pg_tables.hastriggers,       pg_tables.rowsecurity FROM pg_tables;(1 row)

PostgreSQL为我们创建了一个漂亮的SQL字符串。

此解决方案的局限性

当然,这种方法有几个限制。首先,只有在你提供了一个实际上有可能被执行的查询时,这个函数才会起作用。如果表不存在,将抛出一个错误:

test=# SELECT format_sql('SELECT * FROM not_there');ERROR: you have provided an invalid string: 42P01 / relation "not_there" does not exist
CONTEXT: PL/pgSQL function format_sql(text) line 19 at RAISE

这可以看作是一个特性,也可以看作是一个问题——这取决于你试图实现的目标。此外,注释将被删除。这是无法避免的。

进一步阅读

如果你想了解更多有关于PostgreSQL中视图的信息,强烈建议你阅读有关视图和行级安全性的文章

如果你想了解更多关于视图和依赖跟踪的信息,请查看我们的相关文章。

本文翻译自:https://www.cybertec-postgresql.com/en/abusing-postgresql-as-an-sql-beautifier/

文章转载自飞象数据,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论