PostgreSQL code Analysis, query optimization section.
A Blog:http://blog.csdn.net/shujiezhang of understanding
Related Posts: PostgreSQL code Analysis, query optimization section, process_duplicate_ors
/ *
* 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.
* /
/ *
* Normalize the conditions in the WHERE statement or the ON statement, and merge and decompose the two operations AND and OR from the perspective of the set.
* /
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.
* /
/ *
* Find repeated OR operations, that is, simplify conditional statements.
* Assume that the WHERE condition is:
* (A = 1 AND B = 1) OR (A = 1 AND C = 1)
* Can be simplified to:
* A = 1 AND (B = 1 OR C = 1)
*
* In addition, this function does the work of flattening (or flattening) the tree-like AND or OR statement,
* These two tasks are mainly reflected in the two functions pull_ands () and 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)
{
/ *
* "Branch one: or_clause"
*
* If the main operation in the WHERE expression is OR, for example in the following form:
* A = 1 OR B = 1 OR (C = 1 AND D = 1)
* Then the parameter qual pointer actually points to a BoolExpr structure.
typedef struct BoolExpr
{
Expr xpr; = omitted
BoolExprType boolop; = OR_EXPR, that is, OR the following 3
List * args; = 3, A = 1 and B = 1 and (C = 1 AND D = 1)
} BoolExpr;
*
* The args here is a list, and the types of the three elements are as follows:
* The first is a comparison operation, the type is OpExpr
* The second is the comparison operation, the type is OpExpr
* The third is the AND operation, which is a BoolExpr of type AND_EXPR, which will be processed when recursively called
*
* Zhang Daming's blog: http://blog.csdn.net/shujiezhang
* /
if (or_clause ((Node *) qual))
{
List * orlist = NIL;
ListCell * temp;
/ * Recurse * /
/ *
* Recursively process the three conditions in BoolExpr.
* Here you need to focus on the BoolExpr of the AND_EXPR type in the above example, because in the recursive call, he will
* Trigger the next branch (Branch 2).
* /
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. *** This reason is not understood. ***
* /
/ * For details, see the blog post "Analysis of PostgreSQL Code, Query Optimization, process_duplicate_ors" * /
return process_duplicate_ors (orlist);
}
/ *
* "Branch 2: and_clause"
*
* There are two main operations:
* 1) If there is an OR type sub-statement in the sub-statement, find_duplicate_ors is called recursively, because
* Perhaps public items can also be extracted.
* 2) Level the AND operation.
* /
else if (and_clause ((Node *) qual))
{
List * andlist = NIL;
ListCell * temp;
/ * Recurse * /
/ *
* There is a series of OR in the sub-statement.
* For example:
* A = 1 AND ((B = 1 AND C = 1) OR (B = 1 AND D = 1))
* The qual pointer here points to a BoolExpr structure of type AND_EXPR, then
*
typedef struct BoolExpr
{
Expr xpr; = omitted
BoolExprType boolop; = AND_EXPR, that is, perform an AND operation on the following 2
List * args; = 2, which are "A = 1" and "((B = 1 AND C = 1) OR (B = 1 AND D = 1))"
} BoolExpr;
*
* For "((B = 1 AND C = 1) OR (B = 1 AND D = 1))", in recursive
* Will enter "branch one: or_clause", and then converted to:
* B = 1 AND (C = 1 OR D = 1)
*
* Zhang Daming's blog: http://blog.csdn.net/shujiezhang
* /
foreach (temp, ((BoolExpr *) qual)-> args)
andlist = lappend (andlist, find_duplicate_ors (lfirst (temp)));
/ * Flatten any ANDs introduced just below here * /
/ *
* Flatten.
*
* Because the main statement is of type AND and the sub-statement is of type AND, you can directly pull the sub-statement to the parent node.
*
* /
andlist = pull_ands (andlist);
/ * The AND list can't get shorter, so result is always an AND * /
return make_andclause (andlist);
}
else
return qual;
}
PostgreSQL code Analysis, query optimization section.
A Blog:http://blog.csdn.net/shujiezhang of understanding
Related Posts: PostgreSQL code Analysis, query optimization section, process_duplicate_ors
PostgreSQL code Analysis, query optimization section, canonicalize_qual