| 135 | |
| 136 | protected: |
| 137 | void formatQueryImpl(WriteBuffer & ostr, const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override |
| 138 | { |
| 139 | ostr << toString(kind); |
| 140 | |
| 141 | if (ast_settings) |
| 142 | { |
| 143 | ostr << ' '; |
| 144 | ast_settings->format(ostr, settings, state, frame); |
| 145 | } |
| 146 | |
| 147 | if (query) |
| 148 | { |
| 149 | ostr << settings.nl_or_ws; |
| 150 | |
| 151 | /// When trailing output options (SETTINGS, FORMAT, etc.) follow the EXPLAIN body, |
| 152 | /// and the inner query is not an ASTQueryWithOutput (e.g. a bare SELECT or UNION), |
| 153 | /// we must wrap it in parentheses. Otherwise the trailing SETTINGS clause would be |
| 154 | /// consumed by the inner SELECT during re-parsing. |
| 155 | /// For inner ASTQueryWithOutput queries (like CREATE TABLE), the flag propagates |
| 156 | /// through the frame and is handled by each query's own `formatQueryImpl`. |
| 157 | /// INSERT queries also don't need wrapping: wrapping INSERT in parens would |
| 158 | /// produce `(INSERT ...)` which cannot be parsed back. |
| 159 | bool need_parens = frame.has_trailing_output_options |
| 160 | && !dynamic_cast<const ASTQueryWithOutput *>(query.get()) |
| 161 | && query->getQueryKind() != QueryKind::Insert |
| 162 | && query->getQueryKind() != QueryKind::AsyncInsertFlush; |
| 163 | if (need_parens) |
| 164 | ostr << "("; |
| 165 | query->format(ostr, settings, state, frame); |
| 166 | if (need_parens) |
| 167 | ostr << ")"; |
| 168 | } |
| 169 | if (table_function) |
| 170 | { |
| 171 | ostr << settings.nl_or_ws; |
| 172 | table_function->format(ostr, settings, state, frame); |
| 173 | } |
| 174 | if (table_override) |
| 175 | { |
| 176 | ostr << settings.nl_or_ws; |
| 177 | table_override->format(ostr, settings, state, frame); |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | private: |
| 182 | ExplainKind kind; |
nothing calls this directly
no test coverage detected