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