1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.sql.parser.clickhouse.visitor.statement;
19
20 import lombok.AccessLevel;
21 import lombok.Getter;
22 import lombok.RequiredArgsConstructor;
23 import org.antlr.v4.runtime.ParserRuleContext;
24 import org.antlr.v4.runtime.Token;
25 import org.antlr.v4.runtime.misc.Interval;
26 import org.antlr.v4.runtime.tree.TerminalNode;
27 import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
28 import org.apache.shardingsphere.sql.parser.api.ASTNode;
29 import org.apache.shardingsphere.sql.parser.autogen.ClickHouseStatementBaseVisitor;
30 import org.apache.shardingsphere.sql.parser.autogen.ClickHouseStatementParser;
31 import org.apache.shardingsphere.sql.parser.statement.core.enums.AggregationType;
32 import org.apache.shardingsphere.sql.parser.statement.core.enums.OrderDirection;
33 import org.apache.shardingsphere.sql.parser.statement.core.enums.ParameterMarkerType;
34 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
35 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BetweenExpression;
36 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
37 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
38 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment;
39 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.InExpression;
40 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ListExpression;
41 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.NotExpression;
42 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.complex.CommonExpressionSegment;
43 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
44 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
45 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment;
46 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
47 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationDistinctProjectionSegment;
48 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationProjectionSegment;
49 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ExpressionProjectionSegment;
50 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.OrderBySegment;
51 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.ColumnOrderByItemSegment;
52 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.IndexOrderByItemSegment;
53 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.OrderByItemSegment;
54 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.DataTypeLengthSegment;
55 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.DataTypeSegment;
56 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment;
57 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.ParameterMarkerSegment;
58 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
59 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableNameSegment;
60 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
61 import org.apache.shardingsphere.sql.parser.statement.core.util.SQLUtils;
62 import org.apache.shardingsphere.sql.parser.statement.core.value.collection.CollectionValue;
63 import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
64 import org.apache.shardingsphere.sql.parser.statement.core.value.keyword.KeywordValue;
65 import org.apache.shardingsphere.sql.parser.statement.core.value.literal.impl.BooleanLiteralValue;
66 import org.apache.shardingsphere.sql.parser.statement.core.value.literal.impl.NullLiteralValue;
67 import org.apache.shardingsphere.sql.parser.statement.core.value.literal.impl.NumberLiteralValue;
68 import org.apache.shardingsphere.sql.parser.statement.core.value.literal.impl.OtherLiteralValue;
69 import org.apache.shardingsphere.sql.parser.statement.core.value.literal.impl.StringLiteralValue;
70 import org.apache.shardingsphere.sql.parser.statement.core.value.parametermarker.ParameterMarkerValue;
71
72 import java.util.Collection;
73 import java.util.Collections;
74 import java.util.LinkedList;
75 import java.util.List;
76 import java.util.stream.Collectors;
77
78
79
80
81 @RequiredArgsConstructor
82 @Getter(AccessLevel.PROTECTED)
83 public abstract class ClickHouseStatementVisitor extends ClickHouseStatementBaseVisitor<ASTNode> {
84
85 private final DatabaseType databaseType;
86
87 private final Collection<ParameterMarkerSegment> parameterMarkerSegments = new LinkedList<>();
88
89 @Override
90 public final ASTNode visitParameterMarker(final ClickHouseStatementParser.ParameterMarkerContext ctx) {
91 return new ParameterMarkerValue(parameterMarkerSegments.size(), ParameterMarkerType.QUESTION);
92 }
93
94 @Override
95 public final ASTNode visitLiterals(final ClickHouseStatementParser.LiteralsContext ctx) {
96 if (null != ctx.stringLiterals()) {
97 return visit(ctx.stringLiterals());
98 }
99 if (null != ctx.numberLiterals()) {
100 return visit(ctx.numberLiterals());
101 }
102 if (null != ctx.hexadecimalLiterals()) {
103 return visit(ctx.hexadecimalLiterals());
104 }
105 if (null != ctx.bitValueLiterals()) {
106 return visit(ctx.bitValueLiterals());
107 }
108 if (null != ctx.booleanLiterals()) {
109 return visit(ctx.booleanLiterals());
110 }
111 if (null != ctx.nullValueLiterals()) {
112 return visit(ctx.nullValueLiterals());
113 }
114 throw new IllegalStateException("Literals must have string, number, dateTime, hex, bit, boolean or null.");
115 }
116
117 @Override
118 public final ASTNode visitStringLiterals(final ClickHouseStatementParser.StringLiteralsContext ctx) {
119 return new StringLiteralValue(ctx.getText());
120 }
121
122 @Override
123 public final ASTNode visitNumberLiterals(final ClickHouseStatementParser.NumberLiteralsContext ctx) {
124 return new NumberLiteralValue(ctx.getText());
125 }
126
127 @Override
128 public final ASTNode visitHexadecimalLiterals(final ClickHouseStatementParser.HexadecimalLiteralsContext ctx) {
129
130 return new OtherLiteralValue(ctx.getText());
131 }
132
133 @Override
134 public final ASTNode visitBitValueLiterals(final ClickHouseStatementParser.BitValueLiteralsContext ctx) {
135
136 return new OtherLiteralValue(ctx.getText());
137 }
138
139 @Override
140 public final ASTNode visitBooleanLiterals(final ClickHouseStatementParser.BooleanLiteralsContext ctx) {
141
142 return new BooleanLiteralValue(ctx.getText());
143 }
144
145 @Override
146 public final ASTNode visitNullValueLiterals(final ClickHouseStatementParser.NullValueLiteralsContext ctx) {
147 return new NullLiteralValue(ctx.getText());
148 }
149
150 @Override
151 public final ASTNode visitIdentifier(final ClickHouseStatementParser.IdentifierContext ctx) {
152 ClickHouseStatementParser.UnreservedWordContext unreservedWord = ctx.unreservedWord();
153 return null == unreservedWord ? new IdentifierValue(ctx.getText()) : visit(unreservedWord);
154 }
155
156 @Override
157 public final ASTNode visitUnreservedWord(final ClickHouseStatementParser.UnreservedWordContext ctx) {
158 return new IdentifierValue(ctx.getText());
159 }
160
161 @Override
162 public final ASTNode visitSchemaName(final ClickHouseStatementParser.SchemaNameContext ctx) {
163 return visit(ctx.identifier());
164 }
165
166 @Override
167 public final ASTNode visitTableName(final ClickHouseStatementParser.TableNameContext ctx) {
168 SimpleTableSegment result = new SimpleTableSegment(new TableNameSegment(ctx.name().getStart().getStartIndex(), ctx.name().getStop().getStopIndex(), (IdentifierValue) visit(ctx.name())));
169 ClickHouseStatementParser.OwnerContext owner = ctx.owner();
170 if (null != owner) {
171 result.setOwner(new OwnerSegment(owner.getStart().getStartIndex(), owner.getStop().getStopIndex(), (IdentifierValue) visit(owner.identifier())));
172 }
173 return result;
174 }
175
176 @Override
177 public final ASTNode visitColumnName(final ClickHouseStatementParser.ColumnNameContext ctx) {
178 ColumnSegment result = new ColumnSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (IdentifierValue) visit(ctx.name()));
179 ClickHouseStatementParser.OwnerContext owner = ctx.owner();
180 if (null != owner) {
181 result.setOwner(new OwnerSegment(owner.getStart().getStartIndex(), owner.getStop().getStopIndex(), (IdentifierValue) visit(owner.identifier())));
182 }
183 return result;
184 }
185
186 @Override
187 public final ASTNode visitTableNames(final ClickHouseStatementParser.TableNamesContext ctx) {
188 CollectionValue<SimpleTableSegment> result = new CollectionValue<>();
189 for (ClickHouseStatementParser.TableNameContext each : ctx.tableName()) {
190 result.getValue().add((SimpleTableSegment) visit(each));
191 }
192 return result;
193 }
194
195 @Override
196 public final ASTNode visitColumnNames(final ClickHouseStatementParser.ColumnNamesContext ctx) {
197 CollectionValue<ColumnSegment> result = new CollectionValue<>();
198 for (ClickHouseStatementParser.ColumnNameContext each : ctx.columnName()) {
199 result.getValue().add((ColumnSegment) visit(each));
200 }
201 return result;
202 }
203
204 @Override
205 public final ASTNode visitExpr(final ClickHouseStatementParser.ExprContext ctx) {
206 if (null != ctx.booleanPrimary()) {
207 return visit(ctx.booleanPrimary());
208 }
209 if (null != ctx.LP_()) {
210 return visit(ctx.expr(0));
211 }
212 if (null != ctx.andOperator()) {
213 return createBinaryOperationExpression(ctx, ctx.andOperator().getText());
214 }
215 if (null != ctx.orOperator()) {
216 return createBinaryOperationExpression(ctx, ctx.orOperator().getText());
217 }
218 return new NotExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.expr(0)), false);
219 }
220
221 private ASTNode createBinaryOperationExpression(final ClickHouseStatementParser.ExprContext ctx, final String operator) {
222 ExpressionSegment left = (ExpressionSegment) visit(ctx.expr(0));
223 ExpressionSegment right = (ExpressionSegment) visit(ctx.expr(1));
224 String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
225 return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
226 }
227
228 @Override
229 public final ASTNode visitBooleanPrimary(final ClickHouseStatementParser.BooleanPrimaryContext ctx) {
230 if (null != ctx.IS()) {
231 String rightText = "";
232 if (null != ctx.NOT()) {
233 rightText = rightText.concat(ctx.start.getInputStream().getText(new Interval(ctx.NOT().getSymbol().getStartIndex(),
234 ctx.NOT().getSymbol().getStopIndex()))).concat(" ");
235 }
236 Token operatorToken = null;
237 if (null != ctx.NULL()) {
238 operatorToken = ctx.NULL().getSymbol();
239 }
240 if (null != ctx.TRUE()) {
241 operatorToken = ctx.TRUE().getSymbol();
242 }
243 if (null != ctx.FALSE()) {
244 operatorToken = ctx.FALSE().getSymbol();
245 }
246 int startIndex = null == operatorToken ? ctx.IS().getSymbol().getStopIndex() + 2 : operatorToken.getStartIndex();
247 rightText = rightText.concat(ctx.start.getInputStream().getText(new Interval(startIndex, ctx.stop.getStopIndex())));
248 ExpressionSegment right = new LiteralExpressionSegment(ctx.IS().getSymbol().getStopIndex() + 2, ctx.stop.getStopIndex(), rightText);
249 String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
250 ExpressionSegment left = (ExpressionSegment) visit(ctx.booleanPrimary());
251 String operator = "IS";
252 return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
253 }
254 if (null != ctx.comparisonOperator() || null != ctx.SAFE_EQ_()) {
255 return createCompareSegment(ctx);
256 }
257 return visit(ctx.predicate());
258 }
259
260 private ASTNode createCompareSegment(final ClickHouseStatementParser.BooleanPrimaryContext ctx) {
261 ExpressionSegment left = (ExpressionSegment) visit(ctx.booleanPrimary());
262 ExpressionSegment right;
263 if (null != ctx.predicate()) {
264 right = (ExpressionSegment) visit(ctx.predicate());
265 } else {
266 right = (ExpressionSegment) visit(ctx.subquery());
267 }
268 String operator = null == ctx.SAFE_EQ_() ? ctx.comparisonOperator().getText() : ctx.SAFE_EQ_().getText();
269 String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
270 return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
271 }
272
273 @Override
274 public final ASTNode visitPredicate(final ClickHouseStatementParser.PredicateContext ctx) {
275 if (null != ctx.IN()) {
276 return createInSegment(ctx);
277 }
278 if (null != ctx.BETWEEN()) {
279 return createBetweenSegment(ctx);
280 }
281 if (null != ctx.LIKE()) {
282 return createBinaryOperationExpressionFromLike(ctx);
283 }
284 return visit(ctx.bitExpr(0));
285 }
286
287 private BinaryOperationExpression createBinaryOperationExpressionFromLike(final ClickHouseStatementParser.PredicateContext ctx) {
288 ExpressionSegment left = (ExpressionSegment) visit(ctx.bitExpr(0));
289 ListExpression right = new ListExpression(ctx.simpleExpr(0).start.getStartIndex(), ctx.simpleExpr().get(ctx.simpleExpr().size() - 1).stop.getStopIndex());
290 for (ClickHouseStatementParser.SimpleExprContext each : ctx.simpleExpr()) {
291 right.getItems().add((ExpressionSegment) visit(each));
292 }
293 String operator = null == ctx.NOT() ? "LIKE" : "NOT LIKE";
294 String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
295 return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
296 }
297
298 private InExpression createInSegment(final ClickHouseStatementParser.PredicateContext ctx) {
299 ExpressionSegment left = (ExpressionSegment) visit(ctx.bitExpr(0));
300 ExpressionSegment right;
301 if (null != ctx.subquery()) {
302 right = new SubqueryExpressionSegment(new SubquerySegment(ctx.subquery().start.getStartIndex(), ctx.subquery().stop.getStopIndex(), (SelectStatement) visit(ctx.subquery()),
303 getOriginalText(ctx.subquery())));
304 } else {
305 ListExpression listExpression = new ListExpression(ctx.LP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex());
306 for (ClickHouseStatementParser.ExprContext each : ctx.expr()) {
307 listExpression.getItems().add((ExpressionSegment) visit(each));
308 }
309 right = listExpression;
310 }
311 boolean not = null != ctx.NOT();
312 return new InExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, not);
313 }
314
315 private BetweenExpression createBetweenSegment(final ClickHouseStatementParser.PredicateContext ctx) {
316 ExpressionSegment left = (ExpressionSegment) visit(ctx.bitExpr(0));
317 ExpressionSegment between = (ExpressionSegment) visit(ctx.bitExpr(1));
318 ExpressionSegment and = (ExpressionSegment) visit(ctx.predicate());
319 boolean not = null != ctx.NOT();
320 return new BetweenExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, between, and, not);
321 }
322
323 @Override
324 public final ASTNode visitBitExpr(final ClickHouseStatementParser.BitExprContext ctx) {
325 if (null != ctx.simpleExpr()) {
326 return createExpressionSegment(visit(ctx.simpleExpr()), ctx);
327 }
328 ExpressionSegment left = (ExpressionSegment) visit(ctx.getChild(0));
329 ExpressionSegment right = (ExpressionSegment) visit(ctx.getChild(2));
330 String operator = ctx.getChild(1).getText();
331 String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
332 return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
333 }
334
335 private ASTNode createExpressionSegment(final ASTNode astNode, final ParserRuleContext context) {
336 if (astNode instanceof StringLiteralValue) {
337 return new LiteralExpressionSegment(context.start.getStartIndex(), context.stop.getStopIndex(), ((StringLiteralValue) astNode).getValue());
338 }
339 if (astNode instanceof NumberLiteralValue) {
340 return new LiteralExpressionSegment(context.start.getStartIndex(), context.stop.getStopIndex(), ((NumberLiteralValue) astNode).getValue());
341 }
342 if (astNode instanceof BooleanLiteralValue) {
343 return new LiteralExpressionSegment(context.start.getStartIndex(), context.stop.getStopIndex(), ((BooleanLiteralValue) astNode).getValue());
344 }
345 if (astNode instanceof ParameterMarkerValue) {
346 ParameterMarkerValue parameterMarker = (ParameterMarkerValue) astNode;
347 ParameterMarkerExpressionSegment segment = new ParameterMarkerExpressionSegment(context.start.getStartIndex(), context.stop.getStopIndex(),
348 parameterMarker.getValue(), parameterMarker.getType());
349 parameterMarkerSegments.add(segment);
350 return segment;
351 }
352 if (astNode instanceof SubquerySegment) {
353 return new SubqueryExpressionSegment((SubquerySegment) astNode);
354 }
355 if (astNode instanceof OtherLiteralValue) {
356 return new CommonExpressionSegment(context.getStart().getStartIndex(), context.getStop().getStopIndex(), ((OtherLiteralValue) astNode).getValue());
357 }
358 return astNode;
359 }
360
361 @Override
362 public final ASTNode visitSimpleExpr(final ClickHouseStatementParser.SimpleExprContext ctx) {
363 int startIndex = ctx.getStart().getStartIndex();
364 int stopIndex = ctx.getStop().getStopIndex();
365 if (null != ctx.subquery()) {
366 return new SubquerySegment(startIndex, stopIndex, (SelectStatement) visit(ctx.subquery()), getOriginalText(ctx.subquery()));
367 }
368 if (null != ctx.parameterMarker()) {
369 ParameterMarkerValue parameterMarker = (ParameterMarkerValue) visit(ctx.parameterMarker());
370 ParameterMarkerExpressionSegment segment = new ParameterMarkerExpressionSegment(startIndex, stopIndex, parameterMarker.getValue(), parameterMarker.getType());
371 parameterMarkerSegments.add(segment);
372 return segment;
373 }
374 if (null != ctx.literals()) {
375 return SQLUtils.createLiteralExpression(visit(ctx.literals()), startIndex, stopIndex, ctx.literals().start.getInputStream().getText(new Interval(startIndex, stopIndex)));
376 }
377 if (null != ctx.functionCall()) {
378 return visit(ctx.functionCall());
379 }
380 if (null != ctx.columnName()) {
381 return visit(ctx.columnName());
382 }
383 return new CommonExpressionSegment(startIndex, stopIndex, ctx.getText());
384 }
385
386 @Override
387 public final ASTNode visitIntervalExpression(final ClickHouseStatementParser.IntervalExpressionContext ctx) {
388 calculateParameterCount(Collections.singleton(ctx.expr()));
389 return new ExpressionProjectionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), getOriginalText(ctx));
390 }
391
392 @Override
393 public final ASTNode visitFunctionCall(final ClickHouseStatementParser.FunctionCallContext ctx) {
394 if (null != ctx.aggregationFunction()) {
395 return visit(ctx.aggregationFunction());
396 }
397 if (null != ctx.specialFunction()) {
398 return visit(ctx.specialFunction());
399 }
400 if (null != ctx.regularFunction()) {
401 return visit(ctx.regularFunction());
402 }
403 throw new IllegalStateException("FunctionCallContext must have aggregationFunction, regularFunction or specialFunction.");
404 }
405
406 @Override
407 public final ASTNode visitAggregationFunction(final ClickHouseStatementParser.AggregationFunctionContext ctx) {
408 String aggregationType = ctx.aggregationFunctionName().getText();
409 return AggregationType.isAggregationType(aggregationType)
410 ? createAggregationSegment(ctx, aggregationType)
411 : new ExpressionProjectionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), getOriginalText(ctx));
412 }
413
414 private ASTNode createAggregationSegment(final ClickHouseStatementParser.AggregationFunctionContext ctx, final String aggregationType) {
415 AggregationType type = AggregationType.valueOf(aggregationType.toUpperCase());
416 if (null != ctx.distinct()) {
417 AggregationDistinctProjectionSegment result =
418 new AggregationDistinctProjectionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), type, getOriginalText(ctx), getDistinctExpression(ctx));
419 result.getParameters().addAll(getExpressions(ctx));
420 return result;
421 }
422 AggregationProjectionSegment result = new AggregationProjectionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), type, getOriginalText(ctx));
423 result.getParameters().addAll(getExpressions(ctx));
424 return result;
425 }
426
427 private Collection<ExpressionSegment> getExpressions(final ClickHouseStatementParser.AggregationFunctionContext ctx) {
428 if (null == ctx.expr()) {
429 return Collections.emptyList();
430 }
431 Collection<ExpressionSegment> result = new LinkedList<>();
432 for (ClickHouseStatementParser.ExprContext each : ctx.expr()) {
433 result.add((ExpressionSegment) visit(each));
434 }
435 return result;
436 }
437
438 private String getDistinctExpression(final ClickHouseStatementParser.AggregationFunctionContext ctx) {
439 StringBuilder result = new StringBuilder();
440 for (int i = 3; i < ctx.getChildCount() - 1; i++) {
441 result.append(ctx.getChild(i).getText());
442 }
443 return result.toString();
444 }
445
446 @Override
447 public final ASTNode visitSpecialFunction(final ClickHouseStatementParser.SpecialFunctionContext ctx) {
448 if (null != ctx.castFunction()) {
449 return visit(ctx.castFunction());
450 }
451 return new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.getChild(0).getChild(0).getText(), getOriginalText(ctx));
452 }
453
454 @Override
455 public final ASTNode visitCastFunction(final ClickHouseStatementParser.CastFunctionContext ctx) {
456 calculateParameterCount(Collections.singleton(ctx.expr()));
457 FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.CAST().getText(), getOriginalText(ctx));
458 ASTNode exprSegment = visit(ctx.expr());
459 if (exprSegment instanceof ColumnSegment) {
460 result.getParameters().add((ColumnSegment) exprSegment);
461 } else if (exprSegment instanceof LiteralExpressionSegment) {
462 result.getParameters().add((LiteralExpressionSegment) exprSegment);
463 }
464 result.getParameters().add((DataTypeSegment) visit(ctx.dataType()));
465 return result;
466 }
467
468 @Override
469 public final ASTNode visitRegularFunction(final ClickHouseStatementParser.RegularFunctionContext ctx) {
470 FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.regularFunctionName().getText(), getOriginalText(ctx));
471 Collection<ExpressionSegment> expressionSegments = ctx.expr().stream().map(each -> (ExpressionSegment) visit(each)).collect(Collectors.toList());
472 result.getParameters().addAll(expressionSegments);
473 return result;
474 }
475
476 @Override
477 public final ASTNode visitDataTypeName(final ClickHouseStatementParser.DataTypeNameContext ctx) {
478 Collection<String> dataTypeNames = new LinkedList<>();
479 for (int i = 0; i < ctx.getChildCount(); i++) {
480 dataTypeNames.add(ctx.getChild(i).getText());
481 }
482 return new KeywordValue(String.join(" ", dataTypeNames));
483 }
484
485
486 private void calculateParameterCount(final Collection<ClickHouseStatementParser.ExprContext> exprContexts) {
487 for (ClickHouseStatementParser.ExprContext each : exprContexts) {
488 visit(each);
489 }
490 }
491
492 @Override
493 public final ASTNode visitOrderByClause(final ClickHouseStatementParser.OrderByClauseContext ctx) {
494 Collection<OrderByItemSegment> items = new LinkedList<>();
495 for (ClickHouseStatementParser.OrderByItemContext each : ctx.orderByItem()) {
496 items.add((OrderByItemSegment) visit(each));
497 }
498 return new OrderBySegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), items);
499 }
500
501 @Override
502 public final ASTNode visitOrderByItem(final ClickHouseStatementParser.OrderByItemContext ctx) {
503 OrderDirection orderDirection = null == ctx.DESC() ? OrderDirection.ASC : OrderDirection.DESC;
504 if (null != ctx.columnName()) {
505 ColumnSegment column = (ColumnSegment) visit(ctx.columnName());
506 return new ColumnOrderByItemSegment(column, orderDirection, null);
507 }
508 return new IndexOrderByItemSegment(ctx.numberLiterals().getStart().getStartIndex(), ctx.numberLiterals().getStop().getStopIndex(),
509 SQLUtils.getExactlyNumber(ctx.numberLiterals().getText(), 10).intValue(), orderDirection, null);
510 }
511
512 @Override
513 public final ASTNode visitDataType(final ClickHouseStatementParser.DataTypeContext ctx) {
514 DataTypeSegment result = new DataTypeSegment();
515 result.setDataTypeName(((KeywordValue) visit(ctx.dataTypeName())).getValue());
516 result.setStartIndex(ctx.start.getStartIndex());
517 result.setStopIndex(ctx.stop.getStopIndex());
518 if (null != ctx.dataTypeLength()) {
519 DataTypeLengthSegment dataTypeLengthSegment = (DataTypeLengthSegment) visit(ctx.dataTypeLength());
520 result.setDataLength(dataTypeLengthSegment);
521 }
522 return result;
523 }
524
525 @Override
526 public final ASTNode visitDataTypeLength(final ClickHouseStatementParser.DataTypeLengthContext ctx) {
527 DataTypeLengthSegment result = new DataTypeLengthSegment();
528 result.setStartIndex(ctx.start.getStartIndex());
529 result.setStopIndex(ctx.stop.getStartIndex());
530 List<TerminalNode> numbers = ctx.NUMBER_();
531 if (numbers.size() == 1) {
532 result.setPrecision(Integer.parseInt(numbers.get(0).getText()));
533 }
534 if (numbers.size() == 2) {
535 result.setPrecision(Integer.parseInt(numbers.get(0).getText()));
536 result.setScale(Integer.parseInt(numbers.get(1).getText()));
537 }
538 return result;
539 }
540
541
542
543
544
545
546
547 protected String getOriginalText(final ParserRuleContext ctx) {
548 return ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
549 }
550
551 }