選單

【投稿】Rust開發postgres擴充套件

本文投稿自知乎專欄:https://zhuanlan。zhihu。com/p/414566217

前言

Rust 語言是一門通用系統級程式語言,無GC且能保證記憶體安全、併發安全和高效能而著稱。自2008年開始由 Graydon Hoare 私人研發,2009年得到 Mozilla 贊助,2010年首次釋出 0。1。0 版本,用於Servo 引擎的研發,於 2015年5月15號釋出 1。0 版本。自發布以來,截止到2021 年的今天,經歷六年的發展,Rust 得到穩步上升,已逐漸趨於成熟穩定。至 2016 年開始,截止到 2021年,Rust 連續五年成為 StackOverflow 語言榜上最受歡迎的語言[1]。2021年 2 月 9 號,Rust 基金會宣佈成立。華為、AWS、Google、微軟、Mozilla、Facebook 等科技行業領軍巨頭加入 Rust 基金會,成為白金成員,以致力於在全球範圍內推廣和發展 Rust 語言。

官方網如此介紹 Rust : 一門賦予每個人 構建可靠且高效軟體能力的語言。Rust 語言有三大優勢值得大家關注:

高效能。Rust 速度驚人且記憶體利用率極高。由於沒有執行時和垃圾回收,它能夠勝任對效能要求特別高的服務,可以在嵌入式裝置上執行,還能輕鬆和其他語言整合。

可靠性。Rust 豐富的型別系統和所有權模型保證了記憶體安全和執行緒安全,讓您在編譯期就能夠消除各種各樣的錯誤。

生產力。Rust 擁有出色的文件、友好的編譯器和清晰的錯誤提示資訊, 還集成了一流的工具——包管理器和構建工具, 智慧地自動補全和型別檢驗的多編輯器支援, 以及自動格式化程式碼等等。

Rust 和 C 都是硬體直接抽象

Rust 和 C 都是直接對硬體的抽象,都可看作一種「可移植彙編程式」。Rust 和 C 都能控制資料結構的記憶體佈局、整數大小、棧與堆記憶體分配、指標間接定址等,並且一般都能翻譯成可理解的機器程式碼,編譯器很少插入 “魔法”。即便 Rust 比 C 有更高層次的結構,如迭代器、特質(trait)和智慧指標,它們也被設計為可預測地最佳化為簡單的機器程式碼(又稱 “零成本抽象”)。Rust的型別的記憶體佈局很簡單,例如,可增長的字串String 和 Vec 正好是。Rust沒有任何像 Cpp裡的 移動 或 複製建構函式 這樣的概念,所以物件的傳遞保證不會比傳遞指標或 memcpy 更復雜。

總的來說,Rust有媲美C的高效能,同時又具有高效的開發生產力,同時透過FFI可以高效的和其他語言如C進行混合程式設計或互相呼叫。本篇文章主要介紹如何利用Rust開發postgres extension。

部署開發環境

配置RUST開發環境

參考 rust-lang。org/tools/ins IDE 推薦 code。visualstudio。com/ + rls。booyaa。wtf/

配置postgres開發環境

ubuntu

Red hat

cargo pgx 子命令安裝

接下來執行命令。

這個命令會下載版本v10,v11,v12,v13的postgres然後編譯到目錄中。這個下載步驟是必須的,因為後續pgx會為每中版本的postgres的header檔案生成對應的Rust bindings,以及後續pgx 的測試框架中也會用到。

開發一個簡單的extension

建立一個extension專案

使用下面命令建立一個名為my_extension的專案

命令執行後,會生成如下一個目錄結構

src/lib。rs內容如下

可以看到pgx已經預設給出了最簡單的擴充套件實現。  宏所修飾的函式就是我們要實現的extension函式, ,  是pgx已經為我們寫好了的測試模組,用於編寫相關測試程式碼。

pgx預設已經給我們寫好了名為 hello_my_extension 的extension,功能很簡單,就是返回 “Hello, my_extension” 字串

執行extension

使用cargo pgx run 後跟引數pg13或pg10或pg11或pg12,對應不同的postgres版本,cargo pgx run會把extension編譯為一個 。so 共享庫檔案,複製到對應版本的 ~/。pgx/ 目錄中,然後啟動Postgres例項,透過psql連線到和extension同名的資料庫上。編譯完成後,開發者就會處於psql的shell介面中,可以呼叫extension進行測試了。

這裡我們執行  得到輸出如下:

可以看到最後進入了名為my_extension的psql介面中。接下來建立EXTENSION並呼叫,可以看到正常輸出字串

Array

Rust的Vec型別對應 postgrs中的ARRAY[]:: ,如果某個擴充套件函式要返回多個相同型別的value,可以使用Vec進行返回,如下例中的 static_names 和 static_names_2d,最終在psql終端呼叫後返回的是單行單列。如果某個擴充套件返回的是一個Iterator,那麼返回的是一個多行單列資料,參見下面例子中的 static_names_iter 和 static_names_2d_iter。

程式碼

驗證

執行 cargo pgx run pg13

完整程式碼

完整程式碼

AGGREGATE擴充套件

Postgres可以透過 CREATE AGGREGATE 定義一個新的聚集函式。一個簡單的聚集函式包含一個或兩個普通的函式:

狀態轉移函式 sfunc

可選的最終計算函式 ffunc

可能還需要定義聚集函式內部狀態的資料型別 stype

內部函式狀態初始值 initcond ,是一個型別text的值。

那麼我們只需參考上面的樣例 開發對應的 sfunc, ffunc ,stype,然後再使用 CREATE AGGREGATE 建立聚集函式。

建立擴充套件

執行下面命令

定義內部狀態型別 stype

型別 IntegerAvgState 用於聚集函式計算過程中儲存中間狀態資料

狀態轉移函式 sfunc

最終計算函式 ffunc

建立聚集函式

完整程式碼

驗證聚集函式

執行  進入到postgres的psql命令列介面,然後執行下面操作

完整程式碼

完整程式碼

TOPN AGGREGATE擴充套件

現在我們實現一個稍微複雜一些的聚集函式,求表中某列value最大的10個數值,經典的方法就是採用最小堆實現。Rust標準庫中 BinaryHeap 預設是最大堆,透過使用 Reverse 進行封裝,就可以得到一個最小堆。

建立擴充套件

定義內部狀態型別 stype

為 TopState 實現 acc方法,用於狀態轉移,更新最小堆

狀態轉移函式 sfunc

最終計算函式 ffunc

建立聚集函式 MYMAXN

驗證聚集函式 MYMAXN

執行  進入到postgres的psql命令列介面 執行下面sql命令建立測試資料

得到測試資料如下

執行聚集函式MYMAXN

詳細程式碼

注意

如果沒有指定 initcond,則在建立extension的時候會報如下的錯誤提示

升級版TOPN

同時返回表中中指定列最大的n個值和最小的n個值。在原有的資料結構中新增一個最大堆即可。

定義內部狀態型別 stype

為 TopState 實現 acc方法,用於狀態轉移,更新最小堆

狀態轉移函式 sfunc

最終計算函式 ffunc

建立聚集函式 MYMAXN

驗證聚集函式 MYMAXN

完整程式碼

完整程式碼

【投稿】Rust開發postgres擴充套件