发现函数 unnest 定义如下:
CREATE OR REPLACE FUNCTION unnest(anyarray) RETURNS SETOF anyelement AS 'array_unnest' LANGUAGE internal IMMUTABLE STRICT COST 1 ROWS 100;
为了可读性,这是还原后的SQL 语句,实际上它是在 pg_proc.h 中定义的:
DATA(insert OID = 2331 ( unnest PGNSP PGUID 12 1 100 0 0 f f f f t t i 1 0 2283 "2277" _null_ _null_ _null_ _null_ array_unnest _null_ _null_ _null_ ));
运行一下:
postgres=# select unnest(array[10,20]); unnest -------- 10 20 (2 rows) postgres=#
很正常是吧,换种方式:
postgres=# SELECT unnest(array[10,20],array['foo','bar'],array[1.0]); ERROR: function unnest(integer[], text[], numeric[]) does not exist LINE 1: SELECT unnest(array[10,20],array['foo','bar'],array[1.0]); ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts. postgres=#
这也正常对吧,只支持一个参数嘛,再换种方式:
postgres=# SELECT * FROM unnest(array[10,20],array['foo','bar'],array[1.0]); unnest | unnest | unnest --------+--------+-------- 10 | foo | 1.0 20 | bar | (2 rows) postgres=#
发生了什么事?
代码(parse_clause.c)在这里:
if (IsA(fexpr, FuncCall)) { FuncCall *fc = (FuncCall *) fexpr; if (list_length(fc->funcname) == 1 && strcmp(strVal(linitial(fc->funcname)), "unnest") == 0 && list_length(fc->args) > 1 && fc->agg_order == NIL && fc->agg_filter == NULL && !fc->agg_star && !fc->agg_distinct && !fc->func_variadic && fc->over == NULL && coldeflist == NIL) { ListCell *lc; foreach(lc, fc->args) { Node *arg = (Node *) lfirst(lc); FuncCall *newfc; newfc = makeFuncCall(SystemFuncName("unnest"), list_make1(arg), fc->location); ... // 更多
在 FROM 子句里边的函数调用叫做 RangeFunction,而只有这个 unnest 做了特殊处理,实际上三个参数函数被调用了三次。
如果我们有类似处理需求,这是一个可以参考的手段。
语法引擎(gram.y)代码如下:
from_list: table_ref { $$ = list_make1($1); } | from_list ',' table_ref { $$ = lappend($1, $3); } ; /* * table_ref is where an alias clause can be attached. */ table_ref: relation_expr opt_alias_clause ... // 省略 | func_table func_alias_clause { RangeFunction *n = (RangeFunction *) $1; n->alias = linitial($2); n->coldeflist = lsecond($2); $$ = (Node *) n; }
By, PostgreSQL中国用户会,http://postgres.cn