跟我一起读postgresql源码(十六)——Executor(查询执行模块之——control节点(下))

先看一个ModifyTable节点的例子:

postgres=# explain update test_01 set id = 5 where name = 'xxx'; QUERY PLAN --------------------------------------------------------------- Update on test_01 (cost=0.00..23.75 rows=6 width=48) -> Seq Scan on test_01 (cost=0.00..23.75 rows=6 width=48) Filter: ((name)::text = 'xxx'::text) (3 rows)

你可能疑惑为啥上面的查询计划里面没有"ModifyTable"这样的字眼,下面是explain.c文件中的一段:

case T_ModifyTable: sname = "ModifyTable"; switch (((ModifyTable *) plan)->operation) { case CMD_INSERT: pname = operation = "Insert"; break; case CMD_UPDATE: pname = operation = "Update"; break; case CMD_DELETE: pname = operation = "Delete"; break; default: pname = "???"; break; } break;

由此我们可以看到,对于ModifyTable节点,explain会判断是增删改中的哪一种从而作出判断。所以当在explain中看到INSERT、Update和Delete时,我们就知道这是走了ModifyTable节点。

那这里,我们还要再解释ModifyTable节点么?解释下吧:

* Apply rows produced by subplan(s) to result table(s), * by inserting, updating, or deleting.

也就是说,我先从下层的subplan中获得rows,然后根据命令类型选择是insert, update还是delete操作。所以我们可以知道,这是一个顶层节点,它下面是查询节点(就是SELECT)。这也符合我们以前一直说的,所有的增删改查其实都是SELECT!

typedef struct ModifyTable { Plan plan; CmdType operation; /* INSERT, UPDATE, or DELETE */ bool canSetTag; /* do we set the command tag/es_processed? */ Index nominalRelation; /* Parent RT index for use of EXPLAIN */ List *resultRelations; /* integer list of RT indexes */ int resultRelIndex; /* index of first resultRel in plan's list */ List *plans; /* plan(s) producing source data */ List *withCheckOptionLists; /* per-target-table WCO lists */ List *returningLists; /* per-target-table RETURNING tlists */ List *fdwPrivLists; /* per-target-table FDW private data lists */ List *rowMarks; /* PlanRowMarks (non-locking only) */ int epqParam; /* ID of Param for EvalPlanQual re-eval */ OnConflictAction onConflictAction; /* ON CONFLICT action */ List *arbiterIndexes; /* List of ON CONFLICT arbiter index OIDs */ List *onConflictSet; /* SET for INSERT ON CONFLICT DO UPDATE */ Node *onConflictWhere; /* WHERE for ON CONFLICT UPDATE */ Index exclRelRTI; /* RTI of the EXCLUDED pseudo relation */ List *exclRelTlist; /* tlist of the EXCLUDED pseudo relation */ } ModifyTable;

由于ModifyTable节点涉及的操作比较多,这里稍微解释下ModifyTable中的一些字段。

withCheckOptionLists字段

这个和视图相关,我们知道创建视图有这样的用法:

CREATE VIEW xxx_view AS query WITH CHECK OPTION

在postgres中,对创建语句中带有WITH CHECK OPTION的VIEW,在通过视图进行的操作(增删改),必须也能通过该视图看到操作后的结果。

也就是说:

对于INSERT,那么加的这条记录在视图查询后必须可以看到。

对于UPDATE,修改完的结果也必须能通过该视图看到。

对于DELETE,只能删除视图里有显示的记录。

因此对这一类操作,我们在操作表/视图的时候,要在(INSERT/UPDATE/DELETE的)WHERE条件中加上WITH OPTION中的条件。

returningLists字段

这个很简单,因为postgres的语法中有类似以下的用法:

DELETE FROM xxx_table WHERE condition RETURNING xxx; UPDATE xxx_table SET a = '123' WHERE condition RETURNING xxx; INSERT INTO xxx_table VALUES (somevalues) RETURNING xxx;

是的,postgres的RETURNING子句可以返回修改的行,所以对于含有RETURNING子句的查询,除了在对表中的数据进行INSERT/UPDATE/DELETE,还要额外返回一些行。即还要有额外的输出。

fdwPrivLists字段

Postgres支持访问外部数据库的嘛,所以这个字段提供对fdw的处理的支持。

rowMarks字段

这个和行锁相关,针对SELECT的LOCK子句:

FOR lock_strength [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ]

具体见这里:

onConflictAction、arbiterIndexes、arbiterIndexes和onConflictWhere字段

是的,对于INSERT操作,我们有以下语法(用于支持INSERT中发生的冲突):

INSERT INTO table_name VALUES (somevalues) ON CONFLICT [ conflict_target ] conflict_action 并且 conflict_action 是以下之一: DO NOTHING DO UPDATE SET { column_name = { expression | DEFAULT } | ( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) | ( column_name [, ...] ) = ( sub-SELECT ) } [, ...] [ WHERE condition ]

这样一看,很容易对的上了。

exclRelRTI、exclRelTlist字段

对于建表语句有以下子句:

EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) index_parameters [ WHERE ( predicate ) ]

EXCLUDE子句指定一个排除约束,它保证如果任意两行在指定列或表达式上使用指定操作符进行比较,不是所有的比较都将会返回TRUE。具体见:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdgxf.html