| From: | Quan Zongliang <quanzongliang(at)gmail(dot)com> |
|---|---|
| To: | pgsql-zh-general(at)postgresql(dot)org |
| Subject: | 文章分享:诡异的 unnest 函数 |
| Date: | 2015-12-29 02:47:56 |
| Message-ID: | 5681F45C.6040400@gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-zh-general |
函数 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=#
非常不科学的运行成功,三个参数!
在 FROM 子句里边的函数调用叫做 RangeFunction,而只有这个 unnest 做了特殊
处理,实际上三个参数函数被调用了三次。
代码(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);
... // 更多
语法引擎(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;
}
文章结束
即时通讯工具无法保存历史提问,不利于知识共享。
欢迎使用 PostgreSQL中文邮件列表
欢迎使用云栖问答:http://yq.aliyun.com/ask
| From | Date | Subject | |
|---|---|---|---|
| Next Message | 李海龙 | 2015-12-29 02:50:41 | Re: [pgsql-zh-general] 工作机会2015-12-29 |
| Previous Message | 张文升 | 2015-12-29 02:13:07 | Re: 工作机会2015-12-29 |