関数候補選定アルゴリズムの解析と動作確認

環境構築と関数定義

LightDBのorafce拡張機能において、以下のSQLを実行します。

CREATE DOMAIN oracle.clob AS TEXT;

-- バージョン1
CREATE FUNCTION oracle.btrim(text, text)
RETURNS text
AS 'btrim'
LANGUAGE internal STRICT IMMUTABLE;

-- バージョン2
CREATE FUNCTION oracle.btrim(text, char)
RETURNS text
AS 'btrim'
LANGUAGE internal STRICT IMMUTABLE;

-- バージョン3
CREATE FUNCTION oracle.btrim(oracle.clob, varchar)
RETURNS oracle.clob
AS 'MODULE_PATHNAME', 'oracle_btrim'
LANGUAGE C STRICT;

クエリ実行と問題の特定

LightDBのOracleモードで以下のSQLを実行します。

SELECT TRIM('x' FROM 'x'); -- OracleではNULLになるべき
CREATE TABLE foo(a clob);
INSERT INTO foo VALUES ('x');
SELECT TRIM('x' FROM a) FROM foo; -- OracleではNULLにならないべき
-- '::varchar'構文はOracle非対応
SELECT TRIM('x'::varchar FROM a) FROM foo;

このクエリから、btrim(clob, varchar) -> clobが正しく選択されていないことが確認できます。

関数候補選定アルゴリズムの調査

PostgreSQL 13.3における関数解決処理はfunc_get_detail関数内で行われます。LightDBではlt_func_get_detailが使用されます。

主な処理フロー

  • parse_analyze
  • transformFuncCall
  • ParseFuncOrColumn
  • func_get_detail

段階的な候補選定処理

  1. FuncnameGetCandidatesでシステムカタログpg_procから候補関数を取得
  2. 関数引数の変換後、完全一致する関数を検索
  3. 暗黙的な型変換によって引数を調整
  4. func_select_candidateによる最終的な候補選定

具体的な動作確認

現在の状況では以下の引数型と候補関数が存在します。

-- 実際の引数型
(76716, 705)

-- 候補関数の引数型
(76716, 1043) -- clob, varchar
(25, 1042)    -- text, char
(25, 25)      -- text, text

各段階での候補選定処理の結果:

-- 最終候補
(25, 25)      -- text, text

暗黙的型変換の検証

PostgreSQLのルールに従って、以下の暗黙変換が可能:

  • unknownvarchar
  • clobtext
  • unknownchar
  • clobtext
  • unknowntext

スコアリング処理

各候補関数に対するスコアリング結果:

-- 基底型と比較
(25, 25)      -- スコア1
(25, 1042)    -- スコア1
(76716, 1043) -- スコア0

タイプカテゴリによる絞り込み

未知型unknownに対する処理:

  • 文字列カテゴリ'S'として扱われる
  • 優先型はtext

最終的に選定された関数:

btrim(text, text) -> text

タグ: PostgreSQL lightdb SQL function-overloading type-casting

5月16日 18:05 投稿