@Spongcer
2015-04-10T06:50:06.000000Z
字数 2935
阅读 1995
PG canonicalize_qual
/** canonicalize_qual* Convert a qualification expression to the most useful form.** The name of this routine is a holdover from a time when it would try to* force the expression into canonical AND-of-ORs or OR-of-ANDs form.* Eventually, we recognized that that had more theoretical purity than* actual usefulness, and so now the transformation doesn't involve any* notion of reaching a canonical form.** NOTE: we assume the input has already been through eval_const_expressions* and therefore possesses AND/OR flatness. Formerly this function included* its own flattening logic, but that requires a useless extra pass over the* tree.** Returns the modified qualification.*//** 对WHERE语句或ON语句中的条件进行规范化,从集合的角度对AND和OR两个操作做合并分解。*/Expr *canonicalize_qual(Expr *qual){Expr *newqual;/* Quick exit for empty qual */if (qual == NULL)return NULL;/** Pull up redundant subclauses in OR-of-AND trees. We do this only* within the top-level AND/OR structure; there's no point in looking* deeper.*//** 查找重复的OR操作,即化简条件语句。* 假设WHERE条件为:* (A=1 AND B=1) OR (A=1 AND C=1)* 可以化简为:* A=1 AND (B=1 OR C=1)** 另外,这个函数中做了将树状的AND或OR语句平面化(flatten,或拉平)的工作,* 这两个工作主要体现在pull_ands()和pull_ors()两个函数中。*/newqual = find_duplicate_ors(qual);return newqual;}/** find_duplicate_ors* Given a qualification tree with the NOTs pushed down, search for* OR clauses to which the inverse OR distributive law might apply.* Only the top-level AND/OR structure is searched.** Returns the modified qualification. AND/OR flatness is preserved.*/static Expr *find_duplicate_ors(Expr *qual){/** “分支一:or_clause”** 如果WHERE表达式中的主操作是OR,例如是如下形式:* A=1 OR B=1 OR (C=1 AND D=1)* 那么参数qual指针实际指向一个BoolExpr结构体。* typedef struct BoolExpr* {* Expr xpr; = 略* BoolExprType boolop; = OR_EXPR,即对下面的3个进行OR操作* List *args; = 3个,分别是A=1和 B=1和(C=1 AND D=1)* } BoolExpr;** 这里的args是一个list,其中的3个元素的类型分别如下:* 第一个是比较操作,类型是OpExpr* 第二个是比较操作,类型是OpExpr* 第三个是AND操作,是一个AND_EXPR类型的BoolExpr,递归调用时会处理*/if (or_clause((Node *) qual)){List *orlist = NIL;ListCell *temp;/* Recurse *//** 对BoolExpr中的三个条件分别进行递归处理。* 在这里需要重点关注上例中的AND_EXPR类型的BoolExpr,因为在递归调用中,他将* 触发下一个分支(分支二)。*/foreach(temp, ((BoolExpr *) qual)->args)orlist = lappend(orlist, find_duplicate_ors(lfirst(temp)));/** Don't need pull_ors() since this routine will never introduce an OR* where there wasn't one before.***这个原因没理解。****/return process_duplicate_ors(orlist);}/** “分支二:and_clause”** 这里主要做了两个操作:* 1) 如果子语句中有OR类型的子语句,则递归调用find_duplicate_ors,因为 子OR语句中* 或许也能提取公共项。* 2) 对AND操作进行拉平。*/else if (and_clause((Node *) qual)){List *andlist = NIL;ListCell *temp;/* Recurse *//** 子语句中存在一系列OR的情况。* 例如对于:* A=1 AND ((B=1 AND C=1) OR (B=1 AND D=1))* 这里的qual指针指向一个AND_EXPR类型的BoolExpr结构体,则** typedef struct BoolExpr* {* Expr xpr; = 略* BoolExprType boolop; = AND_EXPR,即对下面的2个进行AND操作* List *args; = 2个,分别是“A=1”和 “((B=1 AND C=1) OR (B=1 AND D=1))”* } BoolExpr;** 对于其中的“((B=1 AND C=1) OR (B=1 AND D=1))”,在递归调用中,* 会进入“分支一:or_clause”,进而转换为:* B=1 AND (C=1 OR D=1)*/foreach(temp, ((BoolExpr *) qual)->args)andlist = lappend(andlist, find_duplicate_ors(lfirst(temp)));/* Flatten any ANDs introduced just below here *//** 拉平。** 因为主语句是AND类型,子语句也是AND类型,所以可以直接把子语句拉到父节点。**/andlist = pull_ands(andlist);/* The AND list can't get shorter, so result is always an AND */return make_andclause(andlist);}elsereturn qual;}