PostgreSQL 支持 create extenstion 语法创建扩展,扩展能够很方便地将第三方开发的插件集成到 PostgreSQL 数据库中,比如时序数据库 timescaledb 就是作为 PG 的一个扩展集成到数据库系统中,让 PG 能够支持更加强大的时序数据的存储与查询能力。
使用 psql 连接到 pg server,执行创建扩展的语句,如下:
CREATE EXTENSION timescaledb;
上述创建扩展的语句,在 PG 源码中的函数调用关系如下:
PostgresMain()
->exec_simple_query()
->PortalRun()
->PortalRunMulti()
->PortalRunUtility()
->ProcessUtility()
->loader_process_utility_hook() 位于 timescaledb
->standard_ProcessUtility()
->ProcessUtilitySlow()
->CreateExtension()
->CreateExtensionInternal()
在 ProcessUtility() 函数中,调用 loader_process_utility_hook() 函数,该函数位于 /home/pg/git/timescaledb/src/loader/loader.c:475,属于 timescaledb 实现,这个 hook 函数是在 PG 启动时调用 _PG_init()函数进行 hook 的,源码位于 timescaledb 的 loader/loader.c
loader_process_utility_hook() 函数对执行 drop database 语句时做一些检查,然后回到 PG 标准的函数 standard_ProcessUtility()中。
timescaledb 的函数能够被调用,主要是 PG 提供了一些全局钩子函数,在某些动作完成之后,调用这些全局钩子函数,扩展在实现时只需要将全局钩子函数替换成自己的函数实现即可,比如下面的全局钩子函数 ProcessUtility_hook ,PG 中类似这们的全局钩子 hook 还有很多。
/* Hook for plugins to get control in ProcessUtility() */
ProcessUtility_hook_type ProcessUtility_hook = NULL;
CreateExtension() 函数会做一些检查,比如扩展是否已安装。调用 get_extension_oid() 根据扩展名称查已安装扩展表,检查扩展是否已安装。
CreateExtensionInternal()函数是创建扩展的最终逻辑实现的地方,它的主要逻辑如下:
- 读取扩展控制文件 timescaledb.control,位于 /opt/app/postgresql13/share/extension 目录中。
- 获取扩展脚本文件名,通常是一个 sql 文件,调用函数 get_extension_script_filename() 获取,比如:/opt/app/postgresql13/share/extension/timescaledb--2.4.0-dev.sql。
- 调用 InsertExtensionTuple() 插入元数据表 pg_extension,依赖关系表 pg_depend。
- 调用 CreateComments() 插入描述信息表 pg_description。
- 调用 execute_extension_script() 执行安装扩展的脚本文件。文件名:/opt/app/postgresql13/share/extension/timescaledb--2.4.0-dev.sql
- 调用 ApplyExtensionUpdates() 执行额外的扩展更新脚本文件,也可能没有该额外的扩展更新文件。
经过以上这些步骤之后,扩展被正式创建完成。
注:PostgreSQL 源码版本:14