这里根据FunctionScan中的functions字段对每一个函数构造用于表达式计算的结构(存储在funcexpr中)和,还要构造函数返回元组的描述符存储在tupdesc中,此时用于存储函数结果集的tuplestoreslate字段为NULL。
上面这些做完以后,就可以根据所涉及的所有函数的FunctionScanPerFuncState结构来构造返回值的TupleDesc(即最后的返回值一定是这几个函数返回值的组合):
例如:
在 FunctionScan 节点的执行过程(ExecFunctionScan 函数)中,将 FunctionNext 传递给 ExecScan函数,FunctionNext函数首先判断tuplestorestate是否为空(首次执行时为空),如果为空则执行函数ExecMakeTableFunctionResult生成所有结果集并存储在tuplestorestate中,此后每次执行节点将调用tuplestore_gettupleslot获取结果集中的一个元组。
最后,FunctionScan节点清理过程需要淸理tuplestorestate结构。
10.ValuesScan 节点VALUES计算由值表达式指定的一个行值或者一组行值。更常见的是把它用来生成一个大型命令内的"常量表", 但是它也可以被独自使用。
当多于一行被指定时,所有行都必须具有相同数量的元素。结果表的列数据类型 由出现在该列的表达式的显式或者推导类型组合决定,决定的规则与UNION相同。
在大型的命令中,在语法上允许VALUES出现在 SELECT出现的任何地方。因为语法把它当做一个 SELECT,可以为一个VALUES 命令使用ORDER BY、 LIMIT(或者等效的FETCH FIRST) 以及OFFSET子句。
我们举例吧,一个纯粹的VALUES命令:
VALUES (1, 'one'), (2, 'two'), (3, 'three');将返回一个具有两列、三行的表。
postgres=# VALUES (1, 'one'), (2, 'two'), (3, 'three'); column1 | column2 ---------+--------- 1 | one 2 | two 3 | three (3 行) postgres=# EXPLAIN VALUES (1, 'one'), (2, 'two'), (3, 'three'); QUERY PLAN -------------------------------------------------------------- Values Scan on "*VALUES*" (cost=0.00..0.04 rows=3 width=36) (1 行)更常用地,VALUES可以被用在一个大型 SQL 命令中。 在INSERT中最常用:
postgres=# insert into test values (1,'xxxx'); INSERT 0 1 postgres=# explain insert into test_new values (1); QUERY PLAN ------------------------------------------------------ Insert on test_new (cost=0.00..0.01 rows=1 width=0) -> Result (cost=0.00..0.01 rows=1 width=0) (2 行)具体的可以看这个:
这样我们就对VALUES子句不陌生了,下面继续说。
ValuesScan节点是用来对VALUES子句给出的元组集合进行扫描(INSERT语句中的VALUES子句走的是RESULT节点)。如下所示,ValuesScan节点中的values_lists存储了VALUES子句中的表达式链表。
typedef struct ValuesScan { Scan scan; List *values_lists; /* list of expression lists */ } ValuesScan;ValuesScan节点的初始化过程(ExeclnitValuesScan函数)处理values_lists中的表达式生成Values表达式,并存储在ValuesScanState的exprlists数组中,array_len记录数组长度,cuxr_idx和
markedJdx用于存储数组中的偏移量。同时还会分配内存上下文rowconext用于表达式计箅(ss.ps.ps_ExprContext本来就是用来做表达式计算的,但是为了防止对于一个过长的VALUES子句发生的内存泄露,使用rowconext对VALUES每一行做统一处理,在每一行处理完成后就使用rowconext释放该段内存。)。
ValuesScan 节点执行过程(ExecValuesScan 函数)调用 ExecScan 实现,ExecScan 通过 ValuesNext获取扫描元组,ValuesNext则通过curr_idx从exprlists中获取需要处理的表达式,并计算出结果元组返回。
由于额外地申请了rowconext上下文,因此在ValuesScan节点清理过程(ExecEndValuesScan函数)中需要释放内存上下文rowcontext。
11.CteScan 节点