[关闭]
@Spongcer 2015-04-10T06:50:06.000000Z 字数 2935 阅读 1751

PostgreSQL-canonicalize_qual

PG canonicalize_qual


  1. /*
  2. * canonicalize_qual
  3. * Convert a qualification expression to the most useful form.
  4. *
  5. * The name of this routine is a holdover from a time when it would try to
  6. * force the expression into canonical AND-of-ORs or OR-of-ANDs form.
  7. * Eventually, we recognized that that had more theoretical purity than
  8. * actual usefulness, and so now the transformation doesn't involve any
  9. * notion of reaching a canonical form.
  10. *
  11. * NOTE: we assume the input has already been through eval_const_expressions
  12. * and therefore possesses AND/OR flatness. Formerly this function included
  13. * its own flattening logic, but that requires a useless extra pass over the
  14. * tree.
  15. *
  16. * Returns the modified qualification.
  17. */
  18. /*
  19. * 对WHERE语句或ON语句中的条件进行规范化,从集合的角度对AND和OR两个操作做合并分解。
  20. */
  21. Expr *
  22. canonicalize_qual(Expr *qual)
  23. {
  24. Expr *newqual;
  25. /* Quick exit for empty qual */
  26. if (qual == NULL)
  27. return NULL;
  28. /*
  29. * Pull up redundant subclauses in OR-of-AND trees. We do this only
  30. * within the top-level AND/OR structure; there's no point in looking
  31. * deeper.
  32. */
  33. /*
  34. * 查找重复的OR操作,即化简条件语句。
  35. * 假设WHERE条件为:
  36. * (A=1 AND B=1) OR (A=1 AND C=1)
  37. * 可以化简为:
  38. * A=1 AND (B=1 OR C=1)
  39. *
  40. * 另外,这个函数中做了将树状的AND或OR语句平面化(flatten,或拉平)的工作,
  41. * 这两个工作主要体现在pull_ands()和pull_ors()两个函数中。
  42. */
  43. newqual = find_duplicate_ors(qual);
  44. return newqual;
  45. }
  46. /*
  47. * find_duplicate_ors
  48. * Given a qualification tree with the NOTs pushed down, search for
  49. * OR clauses to which the inverse OR distributive law might apply.
  50. * Only the top-level AND/OR structure is searched.
  51. *
  52. * Returns the modified qualification. AND/OR flatness is preserved.
  53. */
  54. static Expr *
  55. find_duplicate_ors(Expr *qual)
  56. {
  57. /*
  58. * “分支一:or_clause”
  59. *
  60. * 如果WHERE表达式中的主操作是OR,例如是如下形式:
  61. * A=1 OR B=1 OR (C=1 AND D=1)
  62. * 那么参数qual指针实际指向一个BoolExpr结构体。
  63. * typedef struct BoolExpr
  64. * {
  65. * Expr xpr; = 略
  66. * BoolExprType boolop; = OR_EXPR,即对下面的3个进行OR操作
  67. * List *args; = 3个,分别是A=1和 B=1和(C=1 AND D=1)
  68. * } BoolExpr;
  69. *
  70. * 这里的args是一个list,其中的3个元素的类型分别如下:
  71. * 第一个是比较操作,类型是OpExpr
  72. * 第二个是比较操作,类型是OpExpr
  73. * 第三个是AND操作,是一个AND_EXPR类型的BoolExpr,递归调用时会处理
  74. */
  75. if (or_clause((Node *) qual))
  76. {
  77. List *orlist = NIL;
  78. ListCell *temp;
  79. /* Recurse */
  80. /*
  81. * 对BoolExpr中的三个条件分别进行递归处理。
  82. * 在这里需要重点关注上例中的AND_EXPR类型的BoolExpr,因为在递归调用中,他将
  83. * 触发下一个分支(分支二)。
  84. */
  85. foreach(temp, ((BoolExpr *) qual)->args)
  86. orlist = lappend(orlist, find_duplicate_ors(lfirst(temp)));
  87. /*
  88. * Don't need pull_ors() since this routine will never introduce an OR
  89. * where there wasn't one before.***这个原因没理解。***
  90. */
  91. return process_duplicate_ors(orlist);
  92. }
  93. /*
  94. * “分支二:and_clause”
  95. *
  96. * 这里主要做了两个操作:
  97. * 1) 如果子语句中有OR类型的子语句,则递归调用find_duplicate_ors,因为 子OR语句中
  98. * 或许也能提取公共项。
  99. * 2) 对AND操作进行拉平。
  100. */
  101. else if (and_clause((Node *) qual))
  102. {
  103. List *andlist = NIL;
  104. ListCell *temp;
  105. /* Recurse */
  106. /*
  107. * 子语句中存在一系列OR的情况。
  108. * 例如对于:
  109. * A=1 AND ((B=1 AND C=1) OR (B=1 AND D=1))
  110. * 这里的qual指针指向一个AND_EXPR类型的BoolExpr结构体,则
  111. *
  112. * typedef struct BoolExpr
  113. * {
  114. * Expr xpr; = 略
  115. * BoolExprType boolop; = AND_EXPR,即对下面的2个进行AND操作
  116. * List *args; = 2个,分别是“A=1”和 “((B=1 AND C=1) OR (B=1 AND D=1))”
  117. * } BoolExpr;
  118. *
  119. * 对于其中的“((B=1 AND C=1) OR (B=1 AND D=1))”,在递归调用中,
  120. * 会进入“分支一:or_clause”,进而转换为:
  121. * B=1 AND (C=1 OR D=1)
  122. */
  123. foreach(temp, ((BoolExpr *) qual)->args)
  124. andlist = lappend(andlist, find_duplicate_ors(lfirst(temp)));
  125. /* Flatten any ANDs introduced just below here */
  126. /*
  127. * 拉平。
  128. *
  129. * 因为主语句是AND类型,子语句也是AND类型,所以可以直接把子语句拉到父节点。
  130. *
  131. */
  132. andlist = pull_ands(andlist);
  133. /* The AND list can't get shorter, so result is always an AND */
  134. return make_andclause(andlist);
  135. }
  136. else
  137. return qual;
  138. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注