2021SC@SDUSC
概述
我负责的PostgreSQL代码部分:查询的编译与执行 此篇博客分析内容:目标属性的语义分析 上篇博客,我分析了from子句的语义分析,大体了解了PostgreSQL是如何处理范围表以及表与表之间的连接,此片博客接着向下分析,在确定了范围表后,又该如何取得目标属性呢?
目标属性的语义分析
处理目标属性的入口函数是TransformTargetList函数,TransformTargetList函数通过调用函数TransformTargetEntry来处理分析树的目标属性中的每一项。对于目标属性中任何一项都会调用函数makeTargetentry创建TargetEntry结构体用来存储和组织。TransformTargetList函数返回p_target,而再通过查询语义分析的函数transformSelectStmt将直接把transformTargetList函数的返回值作为目标属性赋值给targetList字段
TransformTargetList函数
ResTarget结构体
typedef struct ResTarget
{
NodeTag type;
char *name;
List *indirection;
Node *val;
int location;
} ResTarget;
transformTargetList函数是处理目标属性的入口函数,通过调用transformTargetEntry来处理目标属性。transformTargetList函数的参数由两个ParseState(在上上篇博客PostgreSQL–语义分析-ParseState分析过)和分析树的targetList字段指向的链表(在上上篇博客PostgreSQL–语义分析-Query分析过)
List *
transformTargetList(ParseState *pstate, List *targetlist,
ParseExprKind exprKind)
{
List *p_target = NIL;
bool expand_star;
ListCell *o_target;
foreach(o_target, targetlist)
{
ResTarget *res = (ResTarget *) lfirst(o_target);
if (expand_star)
{
if (IsA(res->val, ColumnRef))
{
ColumnRef *cref = (ColumnRef *) res->val;
if (IsA(llast(cref->fields), A_Star))
{
p_target = list_concat(p_target,
ExpandColumnRefStar(pstate,
cref,
true));
continue;
}
}
ExpandColumnRefStar函数的作用:用来处理select中包含的情况,将展开成目标表的具体每一个列信息
A_Indirection结构体 typedef struct A_Indirection { NodeTag type;//节点类型 Node *arg; //存储被选择的目标列名 List *indirection;//存储的是例如A_Indices节点(具体A_Indices结构体见下), A_Star节点等。用于select语句包含数组的情况 } A_Indirection;
PostgreSQL允许将字段定义成变长的多维数组。 数组类型可以是任何基本类型或用户定义类型,枚举类型或复合类型。 目前还不支持域的数组。 SELECT pay_by_quarter[3] FROM sal_emp; //select语句中包含数组的情况 SELECT schedule[1:2][2] FROM sal_emp WHERE name = ‘Bill’;//select语句中包含切片的情况
else if (IsA(res->val, A_Indirection))
{
A_Indirection *ind = (A_Indirection *) res->val;
if (IsA(llast(ind->indirection), A_Star))
{
p_target = list_concat(p_target,
ExpandIndirectionStar(pstate,
ind,
true,
exprKind));
continue;
}
}
}
A_Indices结构体 typedef struct A_Indices { NodeTag type;//节点类型 bool is_slice; //判断是否是切片 Node *lidx; //如果是切片,则存储切片的下边界 Node *uidx; //如果是切片,则存储切片的下标或者上边界 } A_Indices;
p_target = lappend(p_target,
transformTargetEntry(pstate,
res->val,
NULL,
exprKind,
res->name,
false));
}
return p_target;
}
TransformTargetEntry函数
对于每一个目标属性生成TargetEntry结构体
transformTargetEntry(ParseState *pstate,
Node *node,
Node *expr,
ParseExprKind exprKind,
char *colname,
bool resjunk)
{
if (expr == NULL)
{
if (exprKind == EXPR_KIND_UPDATE_SOURCE && IsA(node, SetToDefault))
expr = node;
else
expr = transformExpr(pstate, node, exprKind);
}
if (colname == NULL && !resjunk)
{
colname = FigureColname(node);
}
return makeTargetEntry((Expr *) expr,
(AttrNumber) pstate->p_next_resno++,
colname,
resjunk);
}
makeTargetEntry函数
makeTargetEntry函数由transformTargetEntry调用用来创建结构体:TargetEntry。 makeTargetEntry函数的作用是将一个ResTarget结构体的链表转换成一个TargetEntry结构体的链表,而每一个TargetEntry表示查询树中的一个目标属性
TargetEntry *
makeTargetEntry(Expr *expr,
AttrNumber resno,
char *resname,
bool resjunk)
{
TargetEntry *tle = makeNode(TargetEntry);
tle->expr = expr;
tle->resno = resno;
tle->resname = resname;
tle->ressortgroupref = 0;
tle->resorigtbl = InvalidOid;
tle->resorigcol = 0;
tle->resjunk = resjunk;
return tle;
}
TargetEntry结构体
严格来说TargetEntry并不是一个表达式,因为它不能被表达式计算函数处理,但PostgreSQL仍将它视为一种表达式,因为把目标属性作为一个表达式树进行处理会很方便
typedef struct TargetEntry
{
Expr xpr;
Expr *expr;
AttrNumber resno;
char *resname;
Index ressortgroupref;
Oid resorigtbl;
AttrNumber resorigcol;
bool resjunk;
} TargetEntry;
TransformExpr函数
当ResTarget val字段没有*则为ResTarget的val字段中的数据类型生成表达式结构
transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
{
Node *result;
ParseExprKind sv_expr_kind;
Assert(exprKind != EXPR_KIND_NONE);
sv_expr_kind = pstate->p_expr_kind;
pstate->p_expr_kind = exprKind;
result = transformExprRecurse(pstate, expr);
pstate->p_expr_kind = sv_expr_kind;
return result;
}
Var结构体
typedef struct Var
{
Expr xpr;
Index varno;
AttrNumber varattno;
Oid vartype;
int32 vartypmod;
Oid varcollid;
Index varlevelsup;
Index varnoold;
AttrNumber varoattno;
int location;
} Var;
Where子句的语义分析
TransformWhereClause函数
在函数 transformWhereClause中,其会调用 transformExpr 来处理该where子句,并对该子句进行递归处理,由transformExprRecurse 函数完成此递归处理,并将其处理的结果作为 ParseState中 jointree的结果。
transformWhereClause(ParseState *pstate, Node *clause,
ParseExprKind exprKind, const char *constructName)
{
Node *qual;
if (clause == NULL)
return NULL;
qual = transformExpr(pstate, clause, exprKind);
return qual;
}
语义分析部分总结
截止此篇博客,我们已经分析完了PostgreSQL中select语句中三个主要子句:select,from ,where的语义分析过程
select子句 | 解析分析树中的目标属性表达式并生成TargetEntry结构体存储目标属性 |
---|
from子句 | 解析分析树中的from表达式,根据from子句中出现的表,视图,子查询,函数或者连接表达式生成范围表 | where子句 | 解析分析树中的where Clause字段,转换为一棵表达式树然后包装成FromExpr结构存入查询树的jointree |
|