Return three possibly None nodes: one for those parts of self that should be included in the WHERE clause, one for those parts of self that must be included in the HAVING clause, and one for those parts that refer to window functions.
(self, negated=False, must_group_by=False)
| 38 | conditional = True |
| 39 | |
| 40 | def split_having_qualify(self, negated=False, must_group_by=False): |
| 41 | """ |
| 42 | Return three possibly None nodes: one for those parts of self that |
| 43 | should be included in the WHERE clause, one for those parts of self |
| 44 | that must be included in the HAVING clause, and one for those parts |
| 45 | that refer to window functions. |
| 46 | """ |
| 47 | if not self.contains_aggregate and not self.contains_over_clause: |
| 48 | return self, None, None |
| 49 | in_negated = negated ^ self.negated |
| 50 | # Whether or not children must be connected in the same filtering |
| 51 | # clause (WHERE > HAVING > QUALIFY) to maintain logical semantic. |
| 52 | must_remain_connected = ( |
| 53 | (in_negated and self.connector == AND) |
| 54 | or (not in_negated and self.connector == OR) |
| 55 | or self.connector == XOR |
| 56 | ) |
| 57 | if ( |
| 58 | must_remain_connected |
| 59 | and self.contains_aggregate |
| 60 | and not self.contains_over_clause |
| 61 | ): |
| 62 | # It's must cheaper to short-circuit and stash everything in the |
| 63 | # HAVING clause than split children if possible. |
| 64 | return None, self, None |
| 65 | where_parts = [] |
| 66 | having_parts = [] |
| 67 | qualify_parts = [] |
| 68 | for c in self.children: |
| 69 | if hasattr(c, "split_having_qualify"): |
| 70 | where_part, having_part, qualify_part = c.split_having_qualify( |
| 71 | in_negated, must_group_by |
| 72 | ) |
| 73 | if where_part is not None: |
| 74 | where_parts.append(where_part) |
| 75 | if having_part is not None: |
| 76 | having_parts.append(having_part) |
| 77 | if qualify_part is not None: |
| 78 | qualify_parts.append(qualify_part) |
| 79 | elif c.contains_over_clause: |
| 80 | qualify_parts.append(c) |
| 81 | elif c.contains_aggregate: |
| 82 | having_parts.append(c) |
| 83 | else: |
| 84 | where_parts.append(c) |
| 85 | if must_remain_connected and qualify_parts: |
| 86 | # Disjunctive heterogeneous predicates can be pushed down to |
| 87 | # qualify as long as no conditional aggregation is involved. |
| 88 | if not where_parts or (where_parts and not must_group_by): |
| 89 | return None, None, self |
| 90 | elif where_parts: |
| 91 | # In theory this should only be enforced when dealing with |
| 92 | # where_parts containing predicates against multi-valued |
| 93 | # relationships that could affect aggregation results but this |
| 94 | # is complex to infer properly. |
| 95 | raise NotImplementedError( |
| 96 | "Heterogeneous disjunctive predicates against window functions are " |
| 97 | "not implemented when performing conditional aggregation." |
no test coverage detected