扩展
扩展
扩展在 PostgreSQL 9.1 中实现,以便更轻松地打包对 PostgreSQL 的补充。扩展可以打包用户可见的函数,或使用 PostgreSQL 中的钩子来修改数据库执行某些过程的方式。
扩展构建者对未来功能的愿望清单
此列表最初是在 PgCon 2018 的非正式会议期间编写的。请随时添加其他请求和/或澄清这些请求。
版本控制
- 如何在同一个 PostgreSQL 集群中处理不同数据库中的多个版本?
- 如何在升级时处理旧版本的卸载?
- 当前系统由于钩子执行方式(使用指向其他扩展的指针)而无法真正卸载。
- 核心代码是否应该注册钩子并管理它们的调用,而不是依赖扩展对彼此友好并传递钩子?
- 如何在升级期间处理之前版本中定义的扩展定义的 GUC?
文档/调试改进
- 目前,钩子在整个代码库中相对难以找到(
ack _hook
似乎是人们用来做这件事的方法)我们如何才能更轻松地找到扩展可能想要使用的所有钩子,并改进关于它们可能对什么有用/为什么存在的文档? - 我们如何在安装/升级时通过 PL/PGSQL 提供更好的错误消息?它们目前过于简短,无法真正轻松地理解发生了什么错误。
依赖检查和安装改进
- 目前,我们按照在
shared_preload_libraries
变量中指定的顺序加载扩展,我们是否应该改为检查依赖项并根据依赖项对它们进行排序? - 我们能否改进如何检查扩展的依赖项?
- 这应该如何与版本控制交互?
- 我们能否以某种方式对扩展版本进行排序,无论是通用排序还是扩展定义的排序,以便依赖项可以进行>/</=类型的版本检查?
- 或者,扩展是否应该列出它们的功能,以便我们改为依赖扩展的功能而不是版本?
安装/卸载/目录改进
- 我们是否应该允许在安装扩展时自动将某些内容添加到
shared_preload_libraries
中,而不是必须在配置文件中指定? - 是否应该为扩展提供一个共享目录,并确定哪些版本安装在哪些数据库中?
新钩子?
- 一个需要考虑的主要问题是:我们是否应该放弃扩展的钩子式集成,采用另一种模型?这种模型可能是什么样的?
- 可能的新的钩子列表,请根据需要添加新的钩子。
- 表文件扩展钩子
关于 9.1 版中原始扩展补丁集的说明
一系列补丁为 PostgreSQL 的转储和恢复实现了扩展支持。为了实现这一目标,需要做很多事情,而且现在的补丁相当大。这是累积分支的 diffstat
$ git diff master..|diffstat contrib/adminpack/Makefile | 3 contrib/adminpack/adminpack.control.in | 3 contrib/btree_gin/Makefile | 3 contrib/btree_gin/btree_gin.control.in | 3 contrib/btree_gin/btree_gin.sql.in | 2 contrib/btree_gin/expected/install_btree_gin.out | 2 contrib/btree_gin/sql/install_btree_gin.sql | 4 contrib/btree_gist/Makefile | 3 contrib/btree_gist/btree_gist.control.in | 3 contrib/btree_gist/btree_gist.sql.in | 2 contrib/btree_gist/expected/init.out | 2 contrib/btree_gist/sql/init.sql | 4 contrib/chkpass/Makefile | 3 contrib/chkpass/chkpass.control.in | 3 contrib/chkpass/chkpass.sql.in | 2 contrib/citext/Makefile | 3 contrib/citext/citext.control.in | 3 contrib/citext/citext.sql.in | 2 contrib/citext/expected/citext.out | 3 contrib/citext/expected/citext_1.out | 3 contrib/citext/sql/citext.sql | 4 contrib/cube/Makefile | 3 contrib/cube/cube.control.in | 3 contrib/cube/cube.sql.in | 2 contrib/cube/expected/cube.out | 2 contrib/cube/expected/cube_1.out | 2 contrib/cube/expected/cube_2.out | 2 contrib/cube/sql/cube.sql | 4 contrib/dblink/Makefile | 2 contrib/dblink/dblink.control.in | 3 contrib/dblink/dblink.sql.in | 2 contrib/dblink/expected/dblink.out | 2 contrib/dblink/sql/dblink.sql | 4 contrib/dict_int/Makefile | 3 contrib/dict_int/dict_int.control.in | 3 contrib/dict_int/dict_int.sql.in | 2 contrib/dict_int/expected/dict_int.out | 2 contrib/dict_int/sql/dict_int.sql | 4 contrib/dict_xsyn/Makefile | 3 contrib/dict_xsyn/dict_xsyn.control.in | 3 contrib/dict_xsyn/dict_xsyn.sql.in | 2 contrib/dict_xsyn/expected/dict_xsyn.out | 2 contrib/dict_xsyn/sql/dict_xsyn.sql | 4 contrib/earthdistance/Makefile | 3 contrib/earthdistance/earthdistance.control.in | 3 contrib/earthdistance/earthdistance.sql.in | 2 contrib/earthdistance/expected/earthdistance.out | 3 contrib/earthdistance/sql/earthdistance.sql | 6 contrib/fuzzystrmatch/Makefile | 3 contrib/fuzzystrmatch/fuzzystrmatch.control.in | 3 contrib/fuzzystrmatch/fuzzystrmatch.sql.in | 2 contrib/hstore/Makefile | 17 + contrib/hstore/expected/hstore.out | 6 contrib/hstore/hstore.control.in | 3 contrib/hstore/hstore.sql.in | 2 contrib/hstore/sql/hstore.sql | 6 contrib/intagg/Makefile | 3 contrib/intagg/int_aggregate.control.in | 3 contrib/intarray/Makefile | 3 contrib/intarray/_int.sql.in | 2 contrib/intarray/expected/_int.out | 2 contrib/intarray/intarray.control.in | 5 contrib/intarray/sql/_int.sql | 4 contrib/isn/Makefile | 3 contrib/isn/isn.control.in | 3 contrib/isn/isn.sql.in | 2 contrib/lo/Makefile | 3 contrib/lo/lo.control.in | 3 contrib/lo/lo.sql.in | 2 contrib/ltree/Makefile | 3 contrib/ltree/expected/ltree.out | 2 contrib/ltree/ltree.control.in | 3 contrib/ltree/ltree.sql.in | 2 contrib/ltree/sql/ltree.sql | 4 contrib/pageinspect/Makefile | 3 contrib/pageinspect/pageinspect.control.in | 3 contrib/pageinspect/pageinspect.sql.in | 2 contrib/pg_buffercache/Makefile | 3 contrib/pg_buffercache/pg_buffercache.control.in | 3 contrib/pg_buffercache/pg_buffercache.sql.in | 2 contrib/pg_freespacemap/Makefile | 3 contrib/pg_freespacemap/pg_freespacemap.control.in | 3 contrib/pg_freespacemap/pg_freespacemap.sql.in | 2 contrib/pg_stat_statements/Makefile | 3 contrib/pg_stat_statements/pg_stat_statements.control.in | 8 contrib/pg_stat_statements/pg_stat_statements.sql.in | 2 contrib/pg_trgm/Makefile | 3 contrib/pg_trgm/expected/pg_trgm.out | 2 contrib/pg_trgm/pg_trgm.control.in | 3 contrib/pg_trgm/pg_trgm.sql.in | 2 contrib/pg_trgm/sql/pg_trgm.sql | 4 contrib/pgcrypto/Makefile | 2 contrib/pgcrypto/expected/init.out | 2 contrib/pgcrypto/pgcrypto.control.in | 3 contrib/pgcrypto/pgcrypto.sql.in | 2 contrib/pgcrypto/sql/init.sql | 4 contrib/pgrowlocks/Makefile | 3 contrib/pgrowlocks/pgrowlocks.control.in | 3 contrib/pgrowlocks/pgrowlocks.sql.in | 2 contrib/pgstattuple/Makefile | 3 contrib/pgstattuple/pgstattuple.control.in | 3 contrib/pgstattuple/pgstattuple.sql.in | 2 contrib/seg/Makefile | 3 contrib/seg/expected/seg.out | 2 contrib/seg/expected/seg_1.out | 2 contrib/seg/seg.control.in | 3 contrib/seg/seg.sql.in | 2 contrib/seg/sql/seg.sql | 4 contrib/spi/Makefile | 4 contrib/spi/auto_username.control.in | 4 contrib/spi/autoinc.control.in | 3 contrib/spi/autoinc.sql.in | 2 contrib/spi/insert_username.sql.in | 2 contrib/spi/moddatetime.control.in | 3 contrib/spi/moddatetime.sql.in | 2 contrib/spi/refint.control.in | 3 contrib/spi/refint.sql.in | 2 contrib/spi/timetravel.control.in | 3 contrib/spi/timetravel.sql.in | 2 contrib/sslinfo/Makefile | 3 contrib/sslinfo/sslinfo.control.in | 3 contrib/sslinfo/sslinfo.sql.in | 2 contrib/tablefunc/Makefile | 3 contrib/tablefunc/expected/tablefunc.out | 2 contrib/tablefunc/sql/tablefunc.sql | 4 contrib/tablefunc/tablefunc.control.in | 3 contrib/tablefunc/tablefunc.sql.in | 2 contrib/test_parser/Makefile | 3 contrib/test_parser/expected/test_parser.out | 2 contrib/test_parser/sql/test_parser.sql | 4 contrib/test_parser/test_parser.control.in | 3 contrib/test_parser/test_parser.sql.in | 2 contrib/tsearch2/Makefile | 3 contrib/tsearch2/expected/tsearch2.out | 2 contrib/tsearch2/expected/tsearch2_1.out | 2 contrib/tsearch2/sql/tsearch2.sql | 4 contrib/tsearch2/tsearch2.control.in | 3 contrib/tsearch2/tsearch2.sql.in | 2 contrib/unaccent/Makefile | 3 contrib/unaccent/expected/unaccent.out | 2 contrib/unaccent/sql/unaccent.sql | 4 contrib/unaccent/unaccent.control.in | 3 contrib/unaccent/unaccent.sql.in | 2 contrib/uuid-ossp/Makefile | 3 contrib/uuid-ossp/uuid-ossp.control.in | 3 contrib/uuid-ossp/uuid-ossp.sql.in | 2 contrib/xml2/Makefile | 3 contrib/xml2/expected/xml2.out | 2 contrib/xml2/expected/xml2_1.out | 2 contrib/xml2/pgxml.sql.in | 2 contrib/xml2/sql/xml2.sql | 4 contrib/xml2/xml2.control.in | 4 doc/src/sgml/catalogs.sgml | 131 ++++++++++++++ doc/src/sgml/extend.sgml | 118 ++++++++++++ doc/src/sgml/func.sgml | 123 +++++++++++++ doc/src/sgml/ref/allfiles.sgml | 2 doc/src/sgml/ref/alter_conversion.sgml | 10 + doc/src/sgml/ref/alter_opclass.sgml | 10 + doc/src/sgml/ref/alter_operator.sgml | 10 + doc/src/sgml/ref/alter_opfamily.sgml | 10 + doc/src/sgml/ref/alter_tsconfig.sgml | 10 + doc/src/sgml/ref/alter_tsdictionary.sgml | 10 + doc/src/sgml/ref/alter_tsparser.sgml | 10 + doc/src/sgml/ref/alter_tstemplate.sgml | 10 + doc/src/sgml/ref/create_extension.sgml | 144 +++++++++++++++ doc/src/sgml/ref/drop_extension.sgml | 115 ++++++++++++ doc/src/sgml/reference.sgml | 2 doc/src/sgml/xfunc.sgml | 30 +++ src/backend/access/transam/xlog.c | 97 ---------- src/backend/catalog/Makefile | 1 src/backend/catalog/dependency.c | 140 +++++++++++---- src/backend/catalog/heap.c | 23 +- src/backend/catalog/namespace.c | 27 ++ src/backend/catalog/objectaddress.c | 14 + src/backend/catalog/pg_aggregate.c | 7 src/backend/catalog/pg_conversion.c | 7 src/backend/catalog/pg_depend.c | 109 +++++++++++ src/backend/catalog/pg_namespace.c | 13 + src/backend/catalog/pg_operator.c | 7 src/backend/catalog/pg_proc.c | 7 src/backend/catalog/pg_type.c | 8 src/backend/catalog/system_views.sql | 3 src/backend/commands/Makefile | 3 src/backend/commands/alter.c | 226 ++++++++++++++++++++++++ src/backend/commands/comment.c | 6 src/backend/commands/conversioncmds.c | 50 +++++ src/backend/commands/extension.c | 1322 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/backend/commands/foreigncmds.c | 19 ++ src/backend/commands/functioncmds.c | 39 ++-- src/backend/commands/opclasscmds.c | 170 ++++++++++++++++++ src/backend/commands/operatorcmds.c | 51 +++++ src/backend/commands/proclang.c | 7 src/backend/commands/tsearchcmds.c | 194 ++++++++++++++++++++ src/backend/commands/typecmds.c | 17 + src/backend/nodes/copyfuncs.c | 29 +++ src/backend/nodes/equalfuncs.c | 25 ++ src/backend/parser/gram.y | 169 +++++++++++++++++- src/backend/rewrite/rewriteDefine.c | 7 src/backend/tcop/utility.c | 42 ++++ src/backend/utils/adt/genfile.c | 130 +++++++++++++- src/backend/utils/init/postinit.c | 4 src/backend/utils/misc/Makefile | 2 src/backend/utils/misc/cfparser.c | 115 ++++++++++++ src/backend/utils/misc/guc-file.l | 25 +- src/backend/utils/misc/guc.c | 160 +++++++++++++++-- src/bin/pg_dump/common.c | 6 src/bin/pg_dump/pg_dump.c | 543 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/bin/pg_dump/pg_dump.h | 11 + src/bin/pg_dump/pg_dump_sort.c | 7 src/bin/psql/command.c | 3 src/bin/psql/describe.c | 50 +++++ src/bin/psql/describe.h | 3 src/bin/psql/help.c | 1 src/include/catalog/dependency.h | 40 ++++ src/include/catalog/indexing.h | 6 src/include/catalog/namespace.h | 2 src/include/catalog/pg_extension.h | 61 ++++++ src/include/catalog/pg_proc.h | 21 +- src/include/catalog/toasting.h | 1 src/include/commands/alter.h | 9 src/include/commands/conversioncmds.h | 3 src/include/commands/defrem.h | 15 + src/include/commands/extension.h | 70 +++++++ src/include/commands/typecmds.h | 1 src/include/nodes/nodes.h | 2 src/include/nodes/parsenodes.h | 21 ++ src/include/parser/kwlist.h | 1 src/include/utils/builtins.h | 7 src/include/utils/cfparser.h | 18 + src/include/utils/genfile.h | 22 ++ src/include/utils/guc.h | 11 + src/makefiles/pgxs.mk | 23 ++ 232 files changed, 5042 insertions(+), 383 deletions(-)
概述
扩展补丁必须考虑到转储和恢复支持。关于完成的所有操作都是为了这个目的,那里几乎没有额外的操作。目标是让 pg_dump
不输出扩展的安装脚本,该脚本与数据库对象分开维护。这样,当需要升级扩展时,也可以更容易地恢复。我们希望在转储中看到的是
CREATE EXTENSION citext WITH SCHEMA foo NO USER DATA;
对于模式支持,请参阅上面的讨论。
一些扩展将安装用户可以编辑数据的表,或使用命令和函数来更改用户的数据。这里的想法是数据会发生变化,并且我们希望将它们作为转储的一部分,因为这些数据的维护不是在扩展的 SCM 中进行的,而是在数据库中进行的。
用户界面
psql
既有 \dx
用于列出已安装的扩展,也有 \dx+
用于列出已安装的和可用的扩展。
dfontaine=# \dx List of extensions Schema | Name | Version | Description --------+--------------------+----------+------------------------------------------------------------------------- utils | adminpack | 9.1devel | Administrative functions for PostgreSQL utils | seg | 9.1devel | data type for representing line segments, or floating point intervals utils | refint | 9.1devel | functions for implementing referential integrity utils | hstore | 9.1devel | storing sets of key/value pairs utils | pg_freespacemap | 9.1devel | examine the free space map (FSM) utils | pgstattuple | 9.1devel | obtain tuple-level statistics utils | citext | 9.1devel | case-insensitive character string type utils | dict_int | 9.1devel | example of an add-on dictionary template for full-text search utils | pg_trgm | 9.1devel | determine the similarity of text, with indexing support utils | pageinspect | 9.1devel | inspect the contents of database pages at a low level utils | pgcrypto | 9.1devel | cryptographic functions utils | intarray | 9.1devel | one-dimensional arrays of integers: functions, operators, index support utils | test_parser | 9.1devel | example of a custom parser for full-text search utils | pg_stat_statements | 9.1devel | tracking execution statistics of all SQL statements executed utils | int_aggregate | 9.1devel | integer aggregator and an enumerator (obsolete) utils | tablefunc | 9.1devel | various functions that return tables, including crosstab(text sql) utils | chkpass | 9.1devel | Store crypt()ed passwords utils | lo | 9.1devel | managing Large Objects utils | dblink | 9.1devel | connect to other PostgreSQL databases from within a database utils | timetravel | 9.1devel | functions for implementing time travel utils | pgrowlocks | 9.1devel | show row locking information for a specified table utils | pg_buffercache | 9.1devel | examine the shared buffer cache in real time utils | btree_gin | 9.1devel | GIN support for common types BTree operators utils | moddatetime | 9.1devel | functions for tracking last modification time utils | unaccent | 9.1devel | text search dictionary that removes accents utils | cube | 9.1devel | data type for representing multidimensional cubes utils | dict_xsyn | 9.1devel | example of an add-on dictionary template for full-text search utils | ltree | 9.1devel | data type for hierarchical tree-like structure utils | btree_gist | 9.1devel | GiST support for common types BTree operators utils | earthdistance | 9.1devel | calculating great circle distances on the surface of the Earth utils | autoinc | 9.1devel | functions for autoincrementing fields utils | tsearch2 | 9.1devel | backwards-compatible text search functionality (pre-8.3) utils | auto_username | 9.1devel | functions for tracking who changed a table utils | fuzzystrmatch | 9.1devel | determine similarities and distance between strings utils | isn | 9.1devel | data types for the international product numbering standards (35 rows)
pg_extension_objects()
函数对于最终用户和想要轻松找到其对象 oid 以管理升级(例如)的扩展作者非常有用。
dfontaine=# select * from pg_extension_objects('unaccent'); class | classid | objid | objdesc ----------------+---------+-------+--------------------------------------------------------------------- pg_extension | 3996 | 18009 | extension unaccent pg_proc | 1255 | 18010 | function utils.unaccent(regdictionary,text) pg_proc | 1255 | 18011 | function utils.unaccent(text) pg_proc | 1255 | 18012 | function utils.unaccent_init(internal) pg_proc | 1255 | 18013 | function utils.unaccent_lexize(internal,internal,internal,internal) pg_ts_template | 3764 | 18014 | text search template unaccent pg_ts_dict | 3600 | 18015 | text search dictionary unaccent (7 rows)
目录、系统视图、函数
目录在这里只有最少的信息。所有与扩展相关的操作都只能由超级用户执行,我们只需要一个名称、一个版本字符串和一个 custom_variable_classes
设置,如后文所述。
dfontaine=# \d pg_extension Table "pg_catalog.pg_extension" Column | Type | Modifiers --------------+------+----------- extname | name | not null extversion | text | custom_class | text | Indexes: "pg_extension_name_index" UNIQUE, btree (extname) "pg_extension_oid_index" UNIQUE, btree (oid)
pg_extensions
系统视图还将列出可用的扩展,并提供一个“已安装”列来对这些扩展进行排序
dfontaine=# \d pg_extensions View "pg_catalog.pg_extensions" Column | Type | Modifiers -------------------------+---------+----------- name | name | version | text | custom_variable_classes | text | comment | text | installed | boolean |
一些实用程序函数可用,供扩展创作使用。有关详细信息,请参阅后文。
dfontaine=# \df pg_ext* List of functions Schema | Name | Result data type | Argument data types | Type ------------+-----------------------------+------------------+------------------------------------------------------------------------------------------------------------+-------- pg_catalog | pg_extension_flag_dump | boolean | oid | normal pg_catalog | pg_extension_objects | SETOF record | name name, OUT class regclass, OUT classid oid, OUT objid oid, OUT objdesc text | normal pg_catalog | pg_extension_with_user_data | boolean | | normal pg_catalog | pg_extensions | SETOF record | OUT name name, OUT version text, OUT custom_variable_classes text, OUT comment text, OUT installed boolean | normal (4 rows)
命令
基本上,您可以创建和删除扩展,还可以修改扩展。
dfontaine=# \h create extension Command: CREATE EXTENSION Description: define and install a new extension Syntax: CREATE EXTENSION extension_name [ [ WITH ] [ [ NO ] USER DATA ] [ SCHEMA [=] schema ] [ ENCODING [=] encoding ]
dfontaine=# \h drop extension Command: DROP EXTENSION Description: remove a tablespace Syntax: DROP EXTENSION [ IF EXISTS ] extension_name [ CASCADE | RESTRICT ]
此外
ALTER EXTENSION extension_name SET SCHEMA schema_name;
用户数据和扩展
扩展补丁的目标是让 pg_dump
*不*关心扩展的对象,因为它们在某个存储库中维护,而不是在数据库中维护。这里有一个例外,当扩展安装用户可以编辑的表(或任何东西,实际上)时,无论是直接编辑还是通过扩展提供的某些工具来编辑。现在,我们也需要转储这些表。
扩展作者有一个函数,他们可以从其脚本中调用该函数来标记一些需要转储的对象,文档包含此示例
+ DO $$ + BEGIN + IF pg_extension_with_user_data() THEN + create schema foo; + create table foo.bar(id serial primary key); + perform pg_extension_flag_dump('foo.bar_id_seq'::regclass); + perform pg_extension_flag_dump('foo.bar::regclass); + END IF; + END; + $$;
这些标志将使 pg_dump
分别转储对象。想法是,对象与其扩展之间的依赖关系从 DEPENDENCY_INTERNAL
(不转储)更改为 DEPENDENCY_NORMAL
(转储)。
模式和扩展
在 -hackers 列表中有人要求提供模式支持,这只是一个简单地搜索和替换扩展脚本中的 @extschema@
占位符,用用户在 CREATE EXTENSION
命令中输入的模式替换它,该模式默认为“public”。
另一个补丁提出了 ALTER EXTENSION SET SCHEMA
命令:我们能够跟踪所有扩展的对象,因此我们能够对所有对象运行 SET SCHEMA
命令。这是一个可选的“糖”设施,被认为很有价值 :)
pg_dump 支持
pg_dump
命令已经打过补丁,因此它不会考虑任何对扩展的 oid 具有直接 DEPENDENDY_INTERNAL
pg_depend
条目的对象。这是所有工作的唯一目标。
当然,我们有一些特殊情况需要考虑,否则它就不会有趣,例如以下情况
! if (g_fout->remoteVersion >= 90100) ! { ! /* ! * So we want the namespaces, but we want to filter out any ! * namespace created by an extension's script. That's unless the ! * user went over his head and created objects into the extension's ! * schema: we now want the schema not to be filtered out to avoid: ! * ! * pg_dump: schema with OID 77869 does not exist ! */ ! appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, " ! "(%s nspowner) AS rolname, " ! "n.nspacl " ! " FROM pg_namespace n " ! " WHERE n.nspname != 'information_schema' " ! " AND CASE WHEN (SELECT count(*) " ! " FROM pg_depend " ! " WHERE refobjid = n.oid and deptype != 'p') > 0 " ! " THEN EXISTS( " ! "WITH RECURSIVE depends AS ( " ! " select n.oid as nsp, objid, refobjid, array[refobjid] as deps " ! " from pg_depend " ! " where refobjid = n.oid and deptype != 'p' " ! " UNION ALL " ! " select p.nsp, p.objid, d.refobjid, deps || d.refobjid " ! " from pg_depend d JOIN depends p ON d.objid = p.objid " ! " where d.deptype != 'p' and not d.refobjid = any(deps) " ! " and not (d.refclassid = 'pg_extension'::regclass and d.deptype = 'n') " ! ") " ! " SELECT nsp, objid, array_agg(distinct refobjid) " ! " FROM depends " ! "GROUP BY nsp, objid " ! " HAVING NOT array_agg(distinct refobjid) && array(select oid from pg_extension) " ! ") " ! " ELSE true " ! " END " ! "UNION ALL " ! "SELECT n.tableoid, n.oid, n.nspname, " ! "(%s nspowner) AS rolname, " ! "nspacl FROM pg_namespace n " ! "WHERE n.nspname = 'information_schema'", ! username_subquery, ! username_subquery); ! } ! else ! { ! appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, " ! "(%s nspowner) AS rolname, " ! "nspacl FROM pg_namespace", ! username_subquery); ! }
通常,它比这简单得多,就像操作符族示例一样
! if (g_fout->remoteVersion >= 90100) ! { ! appendPQExpBuffer(query, "SELECT o.tableoid, o.oid, o.opfname, " ! "o.opfnamespace, " ! "(%s opfowner) AS rolname " ! "FROM pg_opfamily o " ! "LEFT JOIN pg_depend d ON d.objid = o.oid and d.deptype = 'i' " ! "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass " ! "LEFT JOIN pg_extension x ON d.refobjid = x.oid " ! "WHERE x.oid IS NULL", ! username_subquery); ! } ! else ! { ! appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, " ! "opfnamespace, " ! "(%s opfowner) AS rolname " ! "FROM pg_opfamily", ! username_subquery); ! }
使用 DEPENDENCY_INTERNAL
实现使实现 pg_dump
支持变得非常简单。
扩展创作
与您在打补丁之前需要做的事情相比,作为扩展作者,您现在只需要做很少的额外事情。您必须提供将最终进入 pg_extension
目录的元数据,这就是新的 .control
文件的作用。pgxs
Makefile 中也支持这一点。contrib
中的所有这些更改都与之有关。
控制文件
允许将扩展注册到目录中。最小的元数据和语法支持(使用 recovery.conf
解析器)、固定预期位置(与 SQL 脚本并排)、pgxs
支持
$ cat contrib/citext/citext.control.in # citext comment = 'case-insensitive character string type' version = 'EXTVERSION'
$ grep EXT contrib/citext/Makefile EXTENSION = $(MODULES) EXTVERSION = $(VERSION)
一些更复杂的示例。首先,一个脚本,其名称与扩展名称不同,其次,一些更多变量。
$ cat contrib/intarray/intarray.control.in # intarray comment = 'one-dimensional arrays of integers: functions, operators, index support' version = 'EXTVERSION' script = '_int.sql'
$ cat contrib/pg_stat_statements/pg_stat_statements.control.in # pg_stat_statements comment = 'tracking execution statistics of all SQL statements executed' version = 'EXTVERSION' custom_variable_classes = 'pg_stat_statements' pg_stat_statements.max = '1000' pg_stat_statements.track = 'top' pg_stat_statements.track_utility = 'true' pg_stat_statements.save = 'true'
custom_variable_classes
此 GUC 明显是扩展作者的工具。用户将能够编辑其 postgresql.conf
文件并在那里设置自定义类别的各个设置,但如果我们能够自动管理,则最好不要将自定义变量类别公开给用户。
dfontaine=# create extension pg_stat_statements; NOTICE: Extension 'pg_stat_statements' SET custom_variable_classes TO 'pg_stat_statements,pg_stat_statements' NOTICE: Extension 'pg_stat_statements' SET pg_stat_statements.max TO '1000': please edit '/home/dfontaine/pgsql/exts/data/postgresql.conf'. NOTICE: Extension 'pg_stat_statements' SET pg_stat_statements.track TO 'top': please edit '/home/dfontaine/pgsql/exts/data/postgresql.conf'. NOTICE: Extension 'pg_stat_statements' SET pg_stat_statements.track_utility TO 'true': please edit '/home/dfontaine/pgsql/exts/data/postgresql.conf'. NOTICE: Extension 'pg_stat_statements' SET pg_stat_statements.save TO 'true': please edit '/home/dfontaine/pgsql/exts/data/postgresql.conf'. NOTICE: Installing extension 'pg_stat_statements' from '/home/dfontaine/pgsql/exts/share/contrib/pg_stat_statements.sql', in schema public, with user data CREATE EXTENSION
之后,custom_variable_classes
会存储在 pg_extension
目录中,并在后端创建时动态设置。在补丁中,GUC 管理已更改为 SUSET。为此,我们在辅助存储中保留 GUC 占位符,并且当 custom_variable_classes
发生变化时,我们能够将这些占位符合并到主列表中。
代码设计和补丁系列
像往常一样,补丁在不断增长,有人要求将其一部分分开,以便于审查。我们现在有 5 个补丁,它们之间存在一些依赖关系。
cfparser \ } extension \ pg_execute_from_file() / } alter_extension / set_schema /
扩展补丁仅使用 cfparser
和 pg_execute_from_file()
部分生成,以便于测试。set schema
是单独生成的,并且是独立的,alter_extension
补丁是在扩展和 set_schema
补丁之上的增量补丁,以便于讨论 API。
使用 http://git.postgresql.org/gitweb?p=postgresql-extension.git;a=summary 上的 Git 存储库应该方便得多。
跟踪扩展对象
backend/commands/extension.c
文件使用一些新的后端静态变量来跟踪对象的创建并添加依赖关系
/* * create_extension is only set when running a CREATE EXTENSION command, it * allows to register the (INTERNAL) dependencies between the pg_extension * row and the SQL objects created by its installation script. * * For that to work out, all CREATE commands have been modified so that they * will inquire about create_extension and call recordDependencyOn() when * it's set. */ extern ObjectAddress CreateExtensionAddress; bool create_extension; bool create_extension_with_user_data;
cfparser
补丁的这一部分允许从代码中的其他地方重用 recovery.conf
行解析器函数。
pg_execute_from_files()
该函数将在内存中加载文件内容,然后应用占位符,然后使用 SPI,就像它是一个单个查询字符串一样,它确实有点像。这意味着扩展脚本不能嵌入 BEGIN/COMMIT
命令。
extension,主要补丁
此主要补丁包含用于 pg_dump
对扩展的支持的大部分工作,并为脚本文件提出了一个唯一的占位符,@extschema@
。
set_schema
支持补丁,用于能够轻松地将所有扩展对象移动到另一个模式中。
/* + * Generic function to change the namespace of a given object, for simple + * cases (won't work for tables or functions, objects which have more than 2 + * key-attributes to use when searching for their syscache entries --- we + * don't want nor need to get this generic here). + * + * The AlterFooNamespace() calls just above will call a function whose job + * is to lookup the arguments for the generic function here. + * + * Relation must already by open, it's the responsibility of the caller to + * close it. + */ + void + AlterObjectNamespace(Relation rel, int cacheId, + Oid classId, Oid objid, Oid nspOid, + int Anum_name, int Anum_namespace, int Anum_owner, + AclObjectKind acl_kind, + bool superuser_only)
因此,我们有以下支持
+ ALTER CONVERSION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable> + ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> SET SCHEMA <replaceable>new_schema</replaceable> + ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } ) SET SCHEMA <replaceable>new_schema</replaceable> + ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> SET SCHEMA <replaceable>new_schema</replaceable> + ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable> + ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable> + ALTER TEXT SEARCH PARSER <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable> + ALTER TEXT SEARCH TEMPLATE <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
alter extension
从之前的支持开始,我们现在能够使用 ALTER EXTENSION citext SET SCHEMA utils
。