[TOC]
# <span style="font-size:15px">**擴展的基本定義** </span>
postgresql將多個SQL對象(如新函數、新操作符或新的索引操作符)收集到一個單一的包中,這種單一包有助于簡化數據庫的使用和管理,postgresql稱這樣單一的包為擴展。
擴展的定義至少需要一個包含創建該擴展的對象的SQL命令的腳本文件以及一個指定擴展本身的一些基本屬性的*控制文件*。如果擴展包括 C 代碼,通常還有一個 C 代碼編譯而成的共享庫文件。有了這些文件,則可以通過`CREATE EXTENSION`命令將這些對象加載進數據庫中。
擴展機制也對打包調整一個擴展中所含 SQL 對象定義的修改腳本有規定。例如,如果一個擴展的 1.1 版本比 1.0 版本增加了一個函數并且更改了另一個函數的函數體,該擴展的作者可以提供一個更新腳本來做這兩個更改。那么`ALTER EXTENSION UPDATE`命令可以被用來應用這些更改并且跟蹤在給定數據庫中實際安裝的是該擴展的哪個版本。
# <span style="font-size:15px">**重要概念** </span>
* 擴展只在一個數據庫范圍內可見,因此數據庫集簇范圍的對象(例如數據庫、角色和表空間)不能作為擴展成員;雖然一個表可以是一個擴展的成員,它的輔助對象(例如索引)不會被直接認為是該擴展的成員。因此不能通過`ALTER EXTENSION`命令進行更改
* 模式可以屬于擴展,但是擴展不屬于模式,擴展所對應的模式也可以通過`ALTER EXTENSION`命令進行更改
```
// 查看當前已安裝的擴展及其對應的模式
postgres=# SELECT e.oid,e.extname,n.nspname from pg_extension e JOIN pg_namespace n on e.extnamespace = n.oid;
oid | extname | nspname
-------+--------------------+------------
13566 | plpgsql | pg_catalog
16439 | first_last_agg | public
16446 | pg_trgm | public
16540 | pg_freespacemap | public
16555 | pg_visibility | public
16565 | pg_stat_statements | public
(6 rows)
```
# <span style="font-size:15px">**擴展的優點** </span>
* 擴展的使用不只是運行SQL腳本載入這些“松散”的對象到數據庫,而是postgresql可以將這個擴展的成員對象理解為“一個整體”,因此也可以使用單一的`DROP EXTENSION`命令刪除指定擴展的所有對象,而不需要單獨去維護單個對象的刪除卸載
* 可將業務查詢中高頻使用的業務語句或復雜字段處理方式封裝成擴展進行使用,就可以像內置的特性一樣在數據庫中運行,避免重復造輪子。
* 支持擴展的版本升級以及擴展中的SQL命令的更新
# <span style="font-size:15px">**擴展的基本組成** </span>
* demo--1.0.sql
* 對自定義函數的聲明,在pgsql啟動的時候會執行這個sql。文件命名遵循:`extension--version.sql`(例如:demo--1.0.sql表示擴展demo的1.0版本)
* 默認情況下,腳本文件也被放置在`SHAREDIR/extension`目錄中,但是控制文件中可以為腳本文件指定一個不同的目錄
* SQL腳本文件能夠包含任何 SQL 命令,除了事務控制命令(`BEGIN`、`COMMIT`等)以及不能在一個事務塊中執行的命令(如`VACUUM`)。這是因為腳本文件會被隱式地在一個事務塊中被執行
* demo.c:自定義函數的實現,純C語言,目錄下可包含多個.c文件。
* demo.control
* `CREATE EXTENSION` 命令依賴每一個擴展都有的控制文件,控制文件必須被命名為擴展的名稱加上一個后綴`.control`,并且必須被放在安裝的`SHAREDIR/extension`目錄中
* demo-1.0.control
* 二級控制文件,以`extension--version.control`的風格命名 ,二級控制文件遵循主要控制文件相同的格式。
* 在安裝或更新該擴展的版本時,一個二級控制文件中設置的任何參數將覆蓋主要控制文件中的設置,參數`directory`以及`default_version`不能在二級控制文件中設置。
* Makefile:編譯文件
```
[postgres@izwz91quxhnlkan8kjak5hz contrib]$ ls btree_gin
btree_gin--1.0--1.1.sql btree_gin--1.0.sql btree_gin--1.1--1.2.sql btree_gin--1.2--1.3.sql btree_gin.c btree_gin.control expected Makefile sql
```
## <span style="font-size:15px">**.control文件基本格式** </span>
一個擴展控制文件的格式與`postgresql.conf`文件相同,即是一個`parameter_name = value`賦值的列表,每行一個。允許空行和`#`引入的注釋。注意對任何不是單一詞或數字的值加上引號。
控制文件可以設置下列參數:
* **directory(string)**:包含擴展的SQL腳本文件的目錄。除非給出一個絕對路徑,這個目錄名是相對于安裝的`SHAREDIR`目錄。默認行為等效于指定`directory = extension`
* **default_version(string)**:擴展的默認版本,如果`create extension`中沒有指定,將默認使用這個參數
* **comment(string)**:關于該擴展的注釋。該注釋會在初始創建擴展時應用,但是擴展更新時不會引用該注釋(因為可能會覆蓋用戶增加的注釋)。擴展的注釋也可以通過在腳本文件中寫上[COMMENT](http://postgres.cn/docs/13/sql-comment.html "COMMENT")命令來設置。
* **encoding(string)**:該腳本文件使用的字符集編碼。當腳本文件包含任何非 ASCII 字符時,可以指定這個參數。否則文件都會被假定為數據庫編碼。
* **module_pathname(string)**:該參數告訴PG在執行到用戶自定義函數的時候去這個路徑下找庫文件。
* **requires(string):** 這個擴展依賴的其他擴展名的一個列表,例如`requires = 'foo, bar'`。被依賴的擴展必須先于這個擴展安裝
* **superuser(boolean)**:默認情況下為true,只有超級用戶能夠創建該擴展或者將它更新到一個新版本
* **trusted(boolean)**:默認值為false,如果設置為true,則允許非超級管理員權限的用戶安裝superuser已設置為true的擴展,即對于在當前數據庫上具有`CREATE`特權的任何人,都允許安裝。 當執行`CREATE EXTENSION`的用戶不是超級用戶,但允許通過此參數安裝時,則此安裝或更新腳本作為引導超級用戶運行,而不是作為調用用戶
* **relocatable(boolean)**:擴展的可再定位性,如果支持擴展能被重定位到另一個模式則為true,默認為false。三種支持的可定位性級別:
* 一個完全可重定位的擴展能在任何時候被移動到另一個模式中,即使在它被載入到一個數據庫中之后。這種移動通過`ALTER EXTENSION SET SCHEMA`命令完成,該命令會自動地把所有成員對象重命名到新的模式中,它的控制文件中需要設置`relocatable = true`
* 一個擴展可能在安裝過程中是可重定位的,但是安裝完后就不再可重定位。典型的情況是擴展的腳本文件需要顯式地引用目標模式,例如為 SQL 函數設置`search_path`屬性。對于這樣一種擴展,在其控制文件中設置`relocatable = false`,并且使用`@extschema@`在腳本文件中引用目標模式。在腳本被執行前,所有這個字符串的出現都將被替換為實際的目標模式名。用戶可以使用`CREATE EXTENSION`的`SCHEMA`選項設置目標模式名。
* 如果擴展根本就不支持重定位,在它的控制文件中設置`relocatable = false`,并且還設置`schema`為想要的目標模式的名稱。這將阻止使用`CREATE EXTENSION`的`SCHEMA`選項修改目標模式,除非它指定的是和控制文件中相同的模式。如果該擴展包括關于模式名的內部假設且模式名不能使用`@extschema@`的方法替換,這種選擇通常是必須的。`@extschema@`替換機制在這種情況中也是可用的,不過由于模式名已經被控制文件所決定,它的使用受到了很大的限制。
* **schema(string) :** 這個參數只能為非可重定位擴展設置。它強制擴展被載入到給定的模式中而非其他模式中。只有在初始創建一個擴展時才會參考`schema`參數,擴展更新時則不會參考這個參數
> **控制文件參數補充說明:**
> 1、關于`relocatable`,所有的情況下,腳本文件將被用[search\_path](http://postgres.cn/docs/13/runtime-config-client.html#GUC-SEARCH-PATH)執行,它會被設置為指向目標模式,也就是說`CREATE EXTENSION`做的也是等效的工作:`SET LOCAL search_path TO @extschema@, pg_temp;`
> 2、如果控制文件中給出了`schema`參數,目標模式就由該參數決定,否則目標模式由`CREATE EXTENSION`的`SCHEMA`選項給出,如果以上兩者都沒有給出則會用當前默認的對象創建模式(在調用者`search_path`中的第一個)。當使用擴展文件的`schema`參數時,如果目標模式還不存在將創建它,但是在另外兩種情況下它必須已經存在。
> 3、如果在控制文件中的`requires`中列舉了任何先導擴展,它們的目標模式會被追加到`search_path`的初始設置中,遵循新擴展的目標模式。 這允許新擴展的腳本文件能夠看到它們的對象。
```
[postgres@izwz91quxhnlkan8kjak5hz contrib]$ cat btree_gin/btree_gin.control
# btree_gin extension
comment = 'support for indexing common datatypes in GIN'
default_version = '1.3'
module_pathname = '$libdir/btree_gin'
relocatable = true
trusted = true
```
## <span style="font-size:15px">**Makefile文件基本格式** </span>
postgresql為擴展的安裝提供了一種被稱為PGXS的構建基礎設施,因此簡單的擴展模塊能夠在一個已經安裝的服務器上簡單地編譯。PGXS基礎設施需要應用于擴展的Makefile文件中,這三行總是相同的:
```
EXTENSION = demo # 擴展名稱
DATA = demo--1.0.sql # 擴展安裝的sql腳本文件
# pgsql構建擴展的相關命令,固定即可,無需更改
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
```
# <span style="font-size:15px">**擴展版本更新機制** </span>
可以通過擴展的安裝腳本的每一個發行版本關聯一個版本名稱或者版本號來實現動態的將數據庫從一個版本更新到下一個版本,腳本的名稱遵循`extension--old_version--target_version.sql`模式 (例如`demo--1.0--1.1.sql`包含著把擴展`demo`的版本`1.0`修改成版本`1.1`的命令)
命令`ALTER EXTENSION UPDATE`可以將把一個已安裝的擴展更新到指定的新版本。此外,此命令能夠根據更新腳本的版本序列實現版本更新,例如只有`demo--1.0--1.1.sql`和`demo--1.1--2.0.sql`可用,當前安裝了`1.0`版本并且要求更新到版本`2.0`,`ALTER EXTENSION` 命令將將依次應用它們。
PostgreSQL不對更新腳本的版本名稱的屬性做任何假設,例如`demo--1.0--1.1.sql`,它不知道是否`1.1`遵循`1.0`,它只是匹配可用的版本名稱并遵循需要應用最少更新腳本的路徑。(版本名稱實際上可以是不包含`--`或前綴或后綴的任何字符串`-`)
> **Q:** 那么問題就來了,pgsql無法識別更新腳本的命名規范是否真實有效,是如何通過匹配可用的版本名稱來搜索出可用的更新腳本的**最短路徑**?
> **A:** 通過pgsql的內置系統函數`pg_extension_update_paths`來檢索擴展版本之間的可用更新路徑。
```
// pg_extension_update_paths 函數輸出顯示了擴展版本的每個組合,以及從source版本升級到目標版本時將執行的擴展腳本組合
// 如果路徑為空,則無法升級
postgres=# SELECT * FROM pg_extension_update_paths('first_last_agg');
source | target | path
------------+------------+-----------------------------------------------
0.1.4 | 0.1.2 |
0.1.4 | 0.1.3 |
0.1.4 | 0.1.1 |
0.1.4 | unpackaged |
0.1.4 | 0.1.0 |
0.1.2 | 0.1.4 | 0.1.2--0.1.3--0.1.4
0.1.2 | 0.1.3 | 0.1.2--0.1.3
0.1.2 | 0.1.1 |
0.1.2 | unpackaged |
0.1.2 | 0.1.0 |
0.1.3 | 0.1.4 | 0.1.3--0.1.4
0.1.3 | 0.1.2 |
0.1.3 | 0.1.1 |
0.1.3 | unpackaged |
0.1.3 | 0.1.0 |
0.1.1 | 0.1.4 | 0.1.1--0.1.2--0.1.3--0.1.4
0.1.1 | 0.1.2 | 0.1.1--0.1.2
0.1.1 | 0.1.3 | 0.1.1--0.1.2--0.1.3
0.1.1 | unpackaged |
0.1.1 | 0.1.0 |
unpackaged | 0.1.4 | unpackaged--0.1.0--0.1.1--0.1.2--0.1.3--0.1.4
unpackaged | 0.1.2 | unpackaged--0.1.0--0.1.1--0.1.2
unpackaged | 0.1.3 | unpackaged--0.1.0--0.1.1--0.1.2--0.1.3
unpackaged | 0.1.1 | unpackaged--0.1.0--0.1.1
unpackaged | 0.1.0 | unpackaged--0.1.0
0.1.0 | 0.1.4 | 0.1.0--0.1.1--0.1.2--0.1.3--0.1.4
0.1.0 | 0.1.2 | 0.1.0--0.1.1--0.1.2
0.1.0 | 0.1.3 | 0.1.0--0.1.1--0.1.2--0.1.3
0.1.0 | 0.1.1 | 0.1.0--0.1.1
0.1.0 | unpackaged |
(30 rows)
```
postgresql并不對更新腳本的版本名稱的屬性做任何假設,因此即可以實現版本升級,也可以實現“版本降級”,例如,將腳本命名為`demo--1.1--1.0.sql`。降級更新可能會導致的問題在于,降級腳本存在被意外使用的可能性,因為降級腳本會得到一個較短的路徑,如果降級版本刪除了任何不可替代的對象,這將會得到意想不到的結果。
一個已經存在一段時間的擴展可能存在多個版本。例如,如果你已經發布了擴展`demo`的`1.0`、`1.1`和`1.2`版本,就應該有更新腳本`demo--1.0--1.1.sql`和`demo--1.1--1.2.sql`。`CREATE EXTENSION`能夠自動遵循更新鏈。例如,如果只有腳本文件`demo--1.0.sql`、`demo--1.0--1.1.sql`和`demo--1.1--1.2.sql`可用,那么安裝版本`1.2`的請求會通過按順序運行上述三個腳本來實現。這種處理和先安裝`1.0`然后更新到`1.2`是一樣的(和`ALTER EXTENSION UPDATE`一樣,如果有多條路徑可用則優先選擇最短的)
> 在PostgreSQL10之前,還有必要創建新的腳本文件`demo--1.1.sql`和`demo--1.2.sql`,它們直接構建比較新的擴展版本,或者新的版本無法被直接安裝,而是通過先安裝`1.0`然后更新
如果以這種風格維護的擴展中使用了二級(版本相關的)控制文件,記住每個版本都需要一個控制文件,即使它沒有單獨的安裝腳本,因為該控制文件將決定如何執行到這個版本的隱式更新。例如,如果`demo--1.0.control`指定有`requires = 'bar'`,但`demo`的其他控制文件沒有這樣做,在從`1.0`更新到另一個版本時,該擴展對`bar`的依賴將被刪除。
- PHP
- PHP基礎
- PHP介紹
- 如何理解PHP是弱類型語言
- 超全局變量
- $_SERVER詳解
- 字符串處理函數
- 常用數組函數
- 文件處理函數
- 常用時間函數
- 日歷函數
- 常用url處理函數
- 易混淆函數區別(面試題常見)
- 時間戳
- PHP進階
- PSR規范
- RESTFUL規范
- 面向對象
- 三大基本特征和五大基本原則
- 訪問權限
- static關鍵字
- static關鍵字
- 靜態變量與普通變量
- 靜態方法與普通方法
- const關鍵字
- final關鍵字
- abstract關鍵字
- self、$this、parent::關鍵字
- 接口(interface)
- trait關鍵字
- instanceof關鍵字
- 魔術方法
- 構造函數和析構函數
- 私有屬性的設置獲取
- __toString()方法
- __clone()方法
- __call()方法
- 類的自動加載
- 設計模式詳解
- 關于設計模式的一些建議
- 工廠模式
- 簡單工廠模式
- 工廠方法模式
- 抽象工廠模式
- 區別和適用范圍
- 策略模式
- 單例模式
- HTTP
- 定義
- 特點
- 工作過程
- request
- response
- HTTP狀態碼
- URL
- GET和POST的區別
- HTTPS
- session與cookie
- 排序算法
- 冒泡排序算法
- 二分查找算法
- 直接插入排序算法
- 希爾排序算法
- 選擇排序算法
- 快速排序算法
- 循環算法
- 遞歸與尾遞歸
- 迭代
- 日期相關的類
- DateTimeInterface接口
- DateTime類
- DateTimeImmutable類
- DateInterval類
- DateTimeZone類
- DatePeriod類
- format參數格式
- DateInterval的format格式化參數
- 預定義接口
- ArrayAccess(數組式訪問)接口
- Serializable (序列化)接口
- Traversable(遍歷)接口
- Closure類
- Iterator(迭代器)接口
- IteratorAggregate(聚合迭代器) 接口
- Generator (生成器)接口
- composer
- composer安裝與使用
- python
- python3執行tarfile解壓文件報錯:tarfile.ReadError:file could not be opened successfully
- golang
- 單元測試
- 單元測試框架
- Golang內置testing包
- GoConvey庫
- testify庫
- 打樁與mock
- GoMock框架
- Gomonkey框架
- HTTP Mock
- httpMock
- mux庫/httptest
- 數據庫
- MYSQL
- SQL語言的分類
- 事務(重點)
- 索引
- 存儲過程
- 觸發器
- 視圖
- 導入導出數據庫
- 優化mysql數據庫的方法
- MyISAM與InnoDB區別
- 外連接、內連接的區別
- 物理文件結構
- PostgreSQL
- 編譯安裝
- pgsql常用命令
- pgsql應用目錄(bin目錄)文件結構解析
- pg_ctl
- initdb
- psql
- clusterdb
- cluster命令
- createdb
- dropdb
- createuser
- dropuser
- pg_config
- pg_controldata
- pg_checksums
- pgbench
- pg_basebackup
- pg_dump
- pg_dumpall
- pg_isready
- pg_receivewal
- pg_recvlogical
- pg_resetwal
- pg_restore
- pg_rewind
- pg_test_fsync
- pg_test_timing
- pg_upgrade
- pg_verifybackup
- pg_archivecleanup
- pg_waldump
- postgres
- reindexdb
- vacuumdb
- ecpg
- pgsql數據目錄文件結構解析
- pgsql數據目錄文件結構解析
- postgresql.conf解析
- pgsql系統配置參數說明
- pgsql索引類型
- 四種索引類型解析
- 索引之ctid解析
- 索引相關操作
- pgsql函數解析
- pgsql系統函數解析
- pgsql窗口函數解析
- pgsql聚合函數解析
- pgsql系統表解析
- pg_stat_all_indexes
- pg_stat_all_tables
- pg_statio_all_indexes
- pg_statio_all_tables
- pg_stat_database
- pg_stat_statements
- pg_extension
- pg_available_extensions
- pg_available_extension_versions
- pgsql基本原理
- 進程和內存結構
- 存儲結構
- 數據文件的內部結構
- 垃圾回收機制VACUUM
- 事務日志WAL
- 并發控制
- 介紹
- 事務ID-txid
- 元組結構-Tuple Structure
- 事務狀態記錄-Commit Log (clog)
- 事務快照-Transaction Snapshot
- 事務快照實例
- 事務隔離
- 事務隔離級別
- 讀已提交-Read committed
- 可重復讀-Repeatable read
- 可序列化-Serializable
- 讀未提交-Read uncommitted
- 鎖機制
- 擴展機制解析
- 擴展的定義
- 擴展的安裝方式
- 自定義創建擴展
- 擴展的管理
- 擴展使用實例
- 在pgsql中使用last、first聚合函數
- pgsql模糊查詢不走索引的解決方案
- pgsql的pg_trgm擴展解析與驗證
- 高可用
- LNMP
- LNMP環境搭建
- 一鍵安裝包
- 搭建方法
- 配置文件目錄
- 服務器管理系統
- 寶塔(Linux)
- 安裝與使用
- 開放API
- 自定義apache日志
- 一鍵安裝包LNMP1.5
- LNMP1.5:添加、刪除站點
- LNMP1.5:php多版本切換
- LNMP1.5 部署 thinkphp項目
- Operation not permitted解決方法
- Nginx
- Nginx的產生
- 正向代理和反向代理
- 負載均衡
- Linux常用命令
- 目錄與文件相關命令
- 目錄操作命令
- 文件編輯命令
- 文件查看命令
- 文件查找命令
- 文件權限命令
- 文件上傳下載命令
- 用戶和群組相關命令
- 用戶與用戶組的關系
- 用戶相關的系統配置文件
- 用戶相關命令
- 用戶組相關命令
- 壓縮與解壓相關命令
- .zip格式
- .tar.gz格式
- .gz格式
- .bz2格式
- 查看系統版本
- cpuinfo詳解
- meminfo詳解
- getconf獲取系統信息
- 磁盤空間相關命令
- 查看系統負載情況
- 系統環境變量
- 網絡相關命令
- ip命令詳解
- ip命令格式詳解
- ip address命令詳解
- ip link命令詳解
- ip rule命令詳解
- ip route命令詳解
- nslookup命令詳解
- traceroute命令詳解
- netstat命令詳解
- route命令詳解
- tcpdump命令詳解
- 系統進程相關命令
- ps命令詳解
- pstree命令詳解
- kill命令詳解
- 守護進程-supervisord
- 性能監控相關命令
- top命令詳解
- iostat命令詳解
- pidstat命令詳解
- iotop命令詳解
- mpstat命令詳解
- vmstat命令詳解
- ifstat命令詳解
- sar命令詳解
- iftop命令詳解
- 定時任務相關命令
- ssh登錄遠程主機
- ssh口令登錄
- ssh公鑰登錄
- ssh帶密碼登錄
- ssh端口映射
- ssh配置文件
- ssh安全設置
- 歷史紀錄
- history命令詳解
- linux開啟操作日志記錄
- 拓展
- git
- git初始化本地倉庫-https
- git初始化倉庫-ssh
- git-查看和設置config配置
- docker
- 概念
- docker原理
- docker鏡像原理
- docker Overlay2 文件系統原理
- docker日志原理
- docker日志驅動
- docker容器日志管理
- 原理論證
- 驗證容器的啟動是作為Docker Daemon的子進程
- 驗證syslog類型日志驅動
- 驗證journald類型日志驅動
- 驗證local類型日志驅動
- 修改容器的hostname
- 修改容器的hosts
- 驗證聯合掛載技術
- 驗證啟動多個容器對于磁盤的占用情況
- 驗證寫時復制原理
- 驗證docker內容尋址原理
- docker存儲目錄
- /var/lib/docker目錄
- image目錄
- overlay2目錄
- 數據卷
- 具名掛載和匿名掛載
- 數據卷容器
- Dockerfile詳解
- dockerfile指令詳解
- 實例:構造centos
- 實例:CMD和ENTRYPOINT的區別
- docker網絡詳解
- docker-compose
- 緩存
- redis
- redis的數據類型和應用場景
- redis持久化
- RDB持久化
- AOF持久化
- redis緩存穿透、緩存擊穿、緩存雪崩
- 常見網絡攻擊類型
- CSRF攻擊
- XSS攻擊
- SQL注入
- Cookie攻擊
- 歷史項目經驗
- 圖片上傳項目實例
- 原生php上傳方法實例
- base64圖片流
- tp5的上傳方法封裝實例
- 多級關系的遞歸查詢
- 數組轉樹結構
- thinkphp5.1+ajax實現導出Excel
- JS 刪除數組的某一項
- 判斷是否為索引數組
- ip操作