诡异的 unnest 函数

news/2024/7/3 10:26:25

为什么80%的码农都做不了架构师?>>>   hot3.png

发现函数 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

转载于:https://my.oschina.net/quanzl/blog/552427


http://www.niftyadmin.cn/n/1974373.html

相关文章

简简单单小文章-声明

前言 好长时间也没写文章了,原因有很多,就不在这说了,好不容易有个空了就拿起了java基础翻看着,然后也就有了这篇文章。 正文 java中常用的声明有三种方式,那么这三种方式有什么区别呢?对于jvm熟悉的朋友…

2014-11-6Android学习------Spinner下拉选择框控件学习(二)---监听事件

写一篇文章很辛苦啊!!! 转载请注明,联系请邮件nlp30508qq.com 我学习Android都是结合源代码去学习,这样比较直观,非常清楚的看清效果,觉得很好,今天的学习源码是网上找的源码 百度搜…

[python]代码中包含中文,提示:SyntaxError: Non-ASCII character '\xcd'

解决方法: 把文件编码方式改为gbk即可。在代码开头写上: # codinggbk 转载于:https://www.cnblogs.com/sophia194910/p/5085218.html

一文彻底搞懂正向代理和反向代理

前言 多长时间不写博客了?反正一双手是数不过来了,今天就顺手写点小知识点。主要想说的是正向代理和反向代理。 正文 代理 首先先说概念: 代理的概念是什么呢? 百度百科提供的说明: 代理服务器(Proxy S…

2014-11-6Android学习------在手机上用鼠标绘图的处理---贝塞尔曲线(一)

写一篇文章很辛苦啊!!! 转载请注明,联系请邮件nlp30508qq.com 我学习Android都是结合源代码去学习,这样比较直观,非常清楚的看清效果,觉得很好,今天的学习源码是网上找的源码 百度搜…

JPA数据操作汇总,常用的数据操作方法都在这了

前言 写博客总结,最近公司进新人,写了个内部文档顺便整理了一下jap的数据操作demo 正文 第一种方式: 根据客户名称查询客户,使用jpql的形式查询,配置jpql语句,使用的Query注解 Query(value"from …

nginx将svn请求转发到apache实现svn http请求

需要安装apache libapache2-svn模块,nginx,svn。安装过程略过。 记录比较重要几点(不按先后): 安装apache的svn模块 sudo apt-get install libapache2-svn apahce的svn模块,通过他实现svn权限等问题。 apt-get …

树形结构的遍历过程全遍历

前言 树形结构是项目开发中常常用到的一种结构,也是一种经典的数据结构,比如说常见的二叉树,红黑树等,今天要说的不是基础的数据结构,是业务中用到的树形数据结构。 正文 先来看看业务是什么吧! 业务 如…