* subquery_is_pushdown_safe - is a subquery safe for pushing down quals? * * subquery is the particular component query being checked. topquery * is the top component of a set-operations tree (the same Query if no * set-op is involved). * * Conditions checked here: * * 1. If the subquery has a LIMIT clause, we must not push down any quals, * since that could change the set of rows return
| 4085 | * behavior with DISTINCT. |
| 4086 | */ |
| 4087 | static bool |
| 4088 | subquery_is_pushdown_safe(Query *subquery, Query *topquery, |
| 4089 | pushdown_safety_info *safetyInfo) |
| 4090 | { |
| 4091 | SetOperationStmt *topop; |
| 4092 | |
| 4093 | /* Check point 1 */ |
| 4094 | if (subquery->limitOffset != NULL || subquery->limitCount != NULL) |
| 4095 | return false; |
| 4096 | |
| 4097 | /* Check point 6 */ |
| 4098 | if (subquery->groupClause && subquery->groupingSets) |
| 4099 | return false; |
| 4100 | |
| 4101 | /* Check points 3, 4, and 5 */ |
| 4102 | if (subquery->distinctClause || |
| 4103 | subquery->hasWindowFuncs || |
| 4104 | subquery->hasTargetSRFs) |
| 4105 | safetyInfo->unsafeVolatile = true; |
| 4106 | |
| 4107 | /* |
| 4108 | * If we're at a leaf query, check for unsafe expressions in its target |
| 4109 | * list, and mark any unsafe ones in unsafeColumns[]. (Non-leaf nodes in |
| 4110 | * setop trees have only simple Vars in their tlists, so no need to check |
| 4111 | * them.) |
| 4112 | */ |
| 4113 | if (subquery->setOperations == NULL) |
| 4114 | check_output_expressions(subquery, safetyInfo); |
| 4115 | |
| 4116 | /* Are we at top level, or looking at a setop component? */ |
| 4117 | if (subquery == topquery) |
| 4118 | { |
| 4119 | /* Top level, so check any component queries */ |
| 4120 | if (subquery->setOperations != NULL) |
| 4121 | if (!recurse_pushdown_safe(subquery->setOperations, topquery, |
| 4122 | safetyInfo)) |
| 4123 | return false; |
| 4124 | } |
| 4125 | else |
| 4126 | { |
| 4127 | /* Setop component must not have more components (too weird) */ |
| 4128 | if (subquery->setOperations != NULL) |
| 4129 | return false; |
| 4130 | /* Check whether setop component output types match top level */ |
| 4131 | topop = castNode(SetOperationStmt, topquery->setOperations); |
| 4132 | Assert(topop); |
| 4133 | compare_tlist_datatypes(subquery->targetList, |
| 4134 | topop->colTypes, |
| 4135 | safetyInfo); |
| 4136 | } |
| 4137 | return true; |
| 4138 | } |
| 4139 | |
| 4140 | /* |
| 4141 | * Helper routine to recurse through setOperations tree |
no test coverage detected