1. 程式人生 > >PostgreSQL函式VARIADIC引數處理

PostgreSQL函式VARIADIC引數處理

PG函式支援可變引數,就是引數模式關鍵字 VARIADIC,但有很多的限制,看起來很美,用起來一點都不方便。

1、示例

CREATE OR REPLACE FUNCTION test_v(p1 int, VARIADIC p2 any[])
RETURNS void AS
$test_v$
BEGIN
NULL;
END;
$test_v$
LANGUAGE plpgsql; 

這裡,VARIADIC引數必須是陣列,而陣列

2、使用

呼叫方式1

SELECT test_v(1,2,3);

呼叫方式2

SELECT test_v(1,VARIADIC '{2,3,4}'::int[]);

第一種方式其實在語義層會轉換成第二種方式,這些邏輯在函式 ParseFuncOrColumn

中,有興趣可以自行檢視。

3、第二種呼叫方式的語法

  | func_name '(' VARIADIC func_arg_expr opt_sort_clause ')'
    {
      FuncCall *n = makeFuncCall($1, list_make1($4), @1);
      n->func_variadic = true;
      n->agg_order = $5;
      $$ = (Node *)n;
    }
  | func_name '(' func_arg_list ',' VARIADIC func_arg_expr opt_sort_clause ')'
    {
      FuncCall *n = makeFuncCall($1, lappend($3, $6), @1);
      n->func_variadic = true;
      n->agg_order = $7;
      $$ = (Node *)n;
    }

只是指定這是VARIADIC函式呼叫,引數並沒有特別處理。

4、實際引數列表

在語法層,第一張呼叫方式有三個常量引數:整型 整型 整型,而第二種則是兩個引數:整型 整型陣列。第一種呼叫方式在上邊說的 ParseFuncOrColumn 函式中,後兩者合併為一個引數:陣列表示式(ArrayExpr)。

5、不能多種引數型別混合

我們可以實現 func(int, int, int ...),但無法實現 func(int, text, int, text ...),陣列不允許這麼做,在語義層就會報錯無法繼續。

當然,這個限制並不會影響我們使用PG,並不會因為它函式就沒法定義。主要的影響是遷移,比如Oracle應用會用到decode這樣的函式,在現有機制下,並沒有比較完美的方案去實現。

6、PL/pgSQL

文件中似乎沒有提到PL/pgSQL對VARIADIC引數的支援(也許有,沒仔細看),但它是可以處理的。而且從上邊看,VARIADIC引數最後傳遞的是一個數組而已,不是什麼特別的東西。

迴歸測試中的示例:

-- test variadic functions
create or replace function vari(variadic int[])
returns void as $$
begin
  for i in array_lower($1,1)..array_upper($1,1) loop
    raise notice '%', $1[i];
  end loop; end;
$$ language plpgsql;

所以很多時候,文件未提及的東西需要我們自己去發掘。

7、C語言函式

pg_num_nonnulls 就是一個處理VARIADIC引數很好的示例程式碼,定義在 src/backend/utils/adt