1 概述
1.1 语义分析的目的
- 语义分析的目的
上文提到,PostgreSQL接收SQL语句时,会生成1个语法解析树,语法解析树存储了SQL语法中的关键信息。比如,在语法INSERT INTO t1 VALUES(1, 'data1')中,解析结果可说明:
- 这是一条用于插入数据的INSERT语法
- 数据将插入t1表中
- 要插入的数据是
(1, 'data1') - …
但是,数据库执行时,还需要更多的关键信息才行,比如,在INSERT INTO t1 VALUES(1, 'data1')的语法树中,PostgreSQL需要获取一些关键信息: - 数据库中是否有表叫t1
- t1表有几列,每列的的数据类型是什么
- 语法中的值
(1, 'data1')是否符合t1表的定义 - …
1.2 本文的目标
本文以几个常见且简单的语法为例,介绍语义分析的详细功能
- CREATE TABLE ..
- SELECT .. FROM ..
- INSERT INTO ..
- DELETE FROM ..
1.3 语义分析的调用关系
exec_simple_query
pg_parse_query
pg_analyze_and_rewrite
parse_analyze
1.1 整体流程
// 语义分析
exec_simple_query
pg_parse_query
pg_analyze_and_rewrite
parse_analyze
transformTopLevelStmt
transformOptionalSelectInto
transformStmt
transformInsertStmt
exec_simple_query()
pg_parse_query()
for (;;):
pg_analyze_and_rewrite()
Query *query = parse_analyze(Node *parsetree)
List *querytree_list = pg_rewrite_query(query)
pg_plan_queries()
PortalRun()
1.2 分析器
Query *parse_analyze(Node *parseTree)
ParseState *pstate = make_parsestate()
Query *query = query = transformTopLevelStmt(pstate, parseTree)
query = transformStmt(pstate, parseTree) /* 对各种类型语法进行语义分析 */
Query *result
switch nodeTag(parseTree) {
case T_InsertStmt:
result = transformInsertStmt(pstate, (InsertStmt *) parseTree)
case T_DeleteStmt:
result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree)
case T_UpdateStmt:
result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree)
case T_SelectStmt:
SelectStmt *n = (SelectStmt *) parseTree;
if n->valuesLists:
transformValuesClause(pstate, n)
else if n->op == SETOP_NONE:
result = transformSelectStmt(pstate, n)
case T_DeclareCursorStmt:
...
case T_ExplainStmt:
...
case T_CreateTableAsStmt:
...
default:
result = makeNode(Query)
result->commandType = CMD_UTILITY
result->utilityStmt = (Node *) parseTree
}
return result;
1.3 SELECT 分析
Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
Query *qry = makeNode(Query)
if stmt->withClause:
qry->cteList = transformWithClause(pstate, stmt->withClause)
transformFromClause(pstate, stmt->fromClause)
qry->targetList = transformTargetList(pstate, stmt->targetList)
markTargetListOrigins(pstate, qry->targetList)
Node *qual = transformWhereClause(pstate, stmt->whereClause)
qry->havingQual = transformWhereClause(pstate, stmt->havingClause)
qry->sortClause = transformSortClause(pstate, stmt->sortClause, &qry->targetList)
qry->groupClause = transformGroupClause(pstate, stmt->groupClause, &qry->groupingSets, &qry->targetList, qry->sortClause)
qry->distinctClause = transformDistinctOnClause(pstate, stmt->distinctClause, &qry->targetList, qry->sortClause)
qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset)
qry->limitCount = transformLimitClause(pstate, stmt->limitCount)
qry->windowClause = transformWindowDefinitions(pstate, pstate->p_windowdefs, &qry->targetList)
qry->jointree = makeFromExpr(pstate->p_joinlist, qual)
if pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual:
parseCheckAggregates(pstate, qry)
assign_query_collations(pstate, qry)
return qry