查询通过 TCP/IP 或 Unix Domain 套接字以数据包的形式到达后端。 它被加载到一个字符串中,然后传递给解析器, 其中词法扫描器 scan.l 将查询分解为记号(token)。解析器使用 gram.y 和这些记号来识别查询类型,并加载相应的查询特定结构,如 CreateStmt 或 SelectStmt。
然后语句被识别为复杂语句(SELECT / INSERT / UPDATE / DELETE)或简单语句,例如 CREATE ROLE、ANALYZE 等。不需要执行器的简单实用命令由 commands 模块中的语句特定函数处理。 复杂语句需要更多的处理。
解析器接收复杂查询,并创建一个 Query 结构,其中包含复杂查询使用的所有元素。 Query.jointree 保存 FROM 和 WHERE 子句,由 transformFromClause() 和 transformWhereClause() 填充。 查询中引用的每个表由一个 RangeTblEntry 表示, 它们链接在一起形成查询的范围表,由 transformFromClause() 生成。 Query.rtable 保存查询的范围表。
某些查询,如 SELECT, 返回数据列。其他查询,如 INSERT 和 UPDATE, 指定由查询修改的列。这些列引用被转换为 TargetEntry 条目,它们链接在一起组成查询的目标列表。 目标列表存储在 Query.targetList 中,由 transformTargetList() 生成。
其他查询元素,如聚集(SUM())、GROUP BY 和 ORDER BY 也存储在各自的 Query 字段中。
下一步是由可能适用于查询的任何视图或规则对 Query 进行修改。 这由重写系统执行。
优化器使用 Query 结构来确定 RangeTable 中每个表的最佳连接顺序和连接类型, 利用 Query.jointree(FROM 和 WHERE 子句)来考虑最优的索引使用。
path 模块随后生成一个最优的 Plan, 其中包含执行查询所需的操作。然后 Plan 被传递给执行器执行, 并将结果返回给客户端。Plan 实际上是一组节点, 以树形结构排列,有一个顶层节点和各种子节点作为子元素。
还有许多其他模块支持这一基本功能。 您可以通过点击流程图来访问它们。