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.sql.common.enums.AggregationType;
61  import org.apache.shardingsphere.sql.parser.sql.common.enums.OrderDirection;
62  import org.apache.shardingsphere.sql.parser.sql.common.enums.ParameterMarkerType;
63  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
64  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BetweenExpression;
65  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOperationExpression;
66  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
67  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.FunctionSegment;
68  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
69  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ListExpression;
70  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.NotExpression;
71  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.CommonExpressionSegment;
72  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.LiteralExpressionSegment;
73  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
74  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubqueryExpressionSegment;
75  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubquerySegment;
76  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.AggregationDistinctProjectionSegment;
77  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.AggregationProjectionSegment;
78  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ExpressionProjectionSegment;
79  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.OrderBySegment;
80  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.item.ColumnOrderByItemSegment;
81  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.item.IndexOrderByItemSegment;
82  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.item.OrderByItemSegment;
83  import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.DataTypeLengthSegment;
84  import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.DataTypeSegment;
85  import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.OwnerSegment;
86  import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.ParameterMarkerSegment;
87  import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
88  import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableNameSegment;
89  import org.apache.shardingsphere.sql.parser.sql.common.util.SQLUtils;
90  import org.apache.shardingsphere.sql.parser.sql.common.value.collection.CollectionValue;
91  import org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
92  import org.apache.shardingsphere.sql.parser.sql.common.value.keyword.KeywordValue;
93  import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.BooleanLiteralValue;
94  import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.NullLiteralValue;
95  import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.NumberLiteralValue;
96  import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.OtherLiteralValue;
97  import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.StringLiteralValue;
98  import org.apache.shardingsphere.sql.parser.sql.common.value.parametermarker.ParameterMarkerValue;
99  import org.apache.shardingsphere.sql.parser.sql.dialect.statement.sql92.dml.SQL92SelectStatement;
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.concat(ctx.start.getInputStream().getText(new Interval(ctx.NOT().getSymbol().getStartIndex(),
259                         ctx.NOT().getSymbol().getStopIndex()))).concat(" ");
260             }
261             Token operatorToken = null;
262             if (null != ctx.NULL()) {
263                 operatorToken = ctx.NULL().getSymbol();
264             }
265             if (null != ctx.TRUE()) {
266                 operatorToken = ctx.TRUE().getSymbol();
267             }
268             if (null != ctx.FALSE()) {
269                 operatorToken = ctx.FALSE().getSymbol();
270             }
271             int startIndex = null == operatorToken ? ctx.IS().getSymbol().getStopIndex() + 2 : operatorToken.getStartIndex();
272             rightText = rightText.concat(ctx.start.getInputStream().getText(new Interval(startIndex, ctx.stop.getStopIndex())));
273             ExpressionSegment right = new LiteralExpressionSegment(ctx.IS().getSymbol().getStopIndex() + 2, ctx.stop.getStopIndex(), rightText);
274             String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
275             ExpressionSegment left = (ExpressionSegment) visit(ctx.booleanPrimary());
276             String operator = "IS";
277             return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
278         }
279         if (null != ctx.comparisonOperator() || null != ctx.SAFE_EQ_()) {
280             return createCompareSegment(ctx);
281         }
282         return visit(ctx.predicate());
283     }
284     
285     private ASTNode createCompareSegment(final BooleanPrimaryContext ctx) {
286         ExpressionSegment left = (ExpressionSegment) visit(ctx.booleanPrimary());
287         ExpressionSegment right;
288         if (null != ctx.predicate()) {
289             right = (ExpressionSegment) visit(ctx.predicate());
290         } else {
291             right = (ExpressionSegment) visit(ctx.subquery());
292         }
293         String operator = null == ctx.SAFE_EQ_() ? ctx.comparisonOperator().getText() : ctx.SAFE_EQ_().getText();
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     @Override
299     public final ASTNode visitPredicate(final PredicateContext ctx) {
300         if (null != ctx.IN()) {
301             return createInSegment(ctx);
302         }
303         if (null != ctx.BETWEEN()) {
304             return createBetweenSegment(ctx);
305         }
306         if (null != ctx.LIKE()) {
307             return createBinaryOperationExpressionFromLike(ctx);
308         }
309         return visit(ctx.bitExpr(0));
310     }
311     
312     private BinaryOperationExpression createBinaryOperationExpressionFromLike(final PredicateContext ctx) {
313         ExpressionSegment left = (ExpressionSegment) visit(ctx.bitExpr(0));
314         ListExpression right = new ListExpression(ctx.simpleExpr(0).start.getStartIndex(), ctx.simpleExpr().get(ctx.simpleExpr().size() - 1).stop.getStopIndex());
315         for (SimpleExprContext each : ctx.simpleExpr()) {
316             right.getItems().add((ExpressionSegment) visit(each));
317         }
318         String operator = null == ctx.NOT() ? "LIKE" : "NOT LIKE";
319         String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
320         return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
321     }
322     
323     private InExpression createInSegment(final PredicateContext ctx) {
324         ExpressionSegment left = (ExpressionSegment) visit(ctx.bitExpr(0));
325         ExpressionSegment right;
326         if (null != ctx.subquery()) {
327             right = new SubqueryExpressionSegment(new SubquerySegment(ctx.subquery().start.getStartIndex(), ctx.subquery().stop.getStopIndex(), (SQL92SelectStatement) visit(ctx.subquery()),
328                     getOriginalText(ctx.subquery())));
329         } else {
330             ListExpression listExpression = new ListExpression(ctx.LP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex());
331             for (ExprContext each : ctx.expr()) {
332                 listExpression.getItems().add((ExpressionSegment) visit(each));
333             }
334             right = listExpression;
335         }
336         boolean not = null != ctx.NOT();
337         return new InExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, not);
338     }
339     
340     private BetweenExpression createBetweenSegment(final PredicateContext ctx) {
341         ExpressionSegment left = (ExpressionSegment) visit(ctx.bitExpr(0));
342         ExpressionSegment between = (ExpressionSegment) visit(ctx.bitExpr(1));
343         ExpressionSegment and = (ExpressionSegment) visit(ctx.predicate());
344         boolean not = null != ctx.NOT();
345         return new BetweenExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, between, and, not);
346     }
347     
348     @Override
349     public final ASTNode visitBitExpr(final BitExprContext ctx) {
350         if (null != ctx.simpleExpr()) {
351             return createExpressionSegment(visit(ctx.simpleExpr()), ctx);
352         }
353         ExpressionSegment left = (ExpressionSegment) visit(ctx.getChild(0));
354         ExpressionSegment right = (ExpressionSegment) visit(ctx.getChild(2));
355         String operator = ctx.getChild(1).getText();
356         String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
357         return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
358     }
359     
360     private ASTNode createExpressionSegment(final ASTNode astNode, final ParserRuleContext context) {
361         if (astNode instanceof StringLiteralValue) {
362             return new LiteralExpressionSegment(context.start.getStartIndex(), context.stop.getStopIndex(), ((StringLiteralValue) astNode).getValue());
363         }
364         if (astNode instanceof NumberLiteralValue) {
365             return new LiteralExpressionSegment(context.start.getStartIndex(), context.stop.getStopIndex(), ((NumberLiteralValue) astNode).getValue());
366         }
367         if (astNode instanceof BooleanLiteralValue) {
368             return new LiteralExpressionSegment(context.start.getStartIndex(), context.stop.getStopIndex(), ((BooleanLiteralValue) astNode).getValue());
369         }
370         if (astNode instanceof ParameterMarkerValue) {
371             ParameterMarkerValue parameterMarker = (ParameterMarkerValue) astNode;
372             ParameterMarkerExpressionSegment segment = new ParameterMarkerExpressionSegment(context.start.getStartIndex(), context.stop.getStopIndex(),
373                     parameterMarker.getValue(), parameterMarker.getType());
374             parameterMarkerSegments.add(segment);
375             return segment;
376         }
377         if (astNode instanceof SubquerySegment) {
378             return new SubqueryExpressionSegment((SubquerySegment) astNode);
379         }
380         if (astNode instanceof OtherLiteralValue) {
381             return new CommonExpressionSegment(context.getStart().getStartIndex(), context.getStop().getStopIndex(), ((OtherLiteralValue) astNode).getValue());
382         }
383         return astNode;
384     }
385     
386     @Override
387     public final ASTNode visitSimpleExpr(final SimpleExprContext ctx) {
388         int startIndex = ctx.getStart().getStartIndex();
389         int stopIndex = ctx.getStop().getStopIndex();
390         if (null != ctx.subquery()) {
391             return new SubquerySegment(startIndex, stopIndex, (SQL92SelectStatement) visit(ctx.subquery()), getOriginalText(ctx.subquery()));
392         }
393         if (null != ctx.parameterMarker()) {
394             ParameterMarkerValue parameterMarker = (ParameterMarkerValue) visit(ctx.parameterMarker());
395             ParameterMarkerExpressionSegment segment = new ParameterMarkerExpressionSegment(startIndex, stopIndex, parameterMarker.getValue(), parameterMarker.getType());
396             parameterMarkerSegments.add(segment);
397             return segment;
398         }
399         if (null != ctx.literals()) {
400             return SQLUtils.createLiteralExpression(visit(ctx.literals()), startIndex, stopIndex, ctx.literals().start.getInputStream().getText(new Interval(startIndex, stopIndex)));
401         }
402         if (null != ctx.functionCall()) {
403             return visit(ctx.functionCall());
404         }
405         if (null != ctx.columnName()) {
406             return visit(ctx.columnName());
407         }
408         return new CommonExpressionSegment(startIndex, stopIndex, ctx.getText());
409     }
410     
411     @Override
412     public final ASTNode visitIntervalExpression(final IntervalExpressionContext ctx) {
413         calculateParameterCount(Collections.singleton(ctx.expr()));
414         return new ExpressionProjectionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), getOriginalText(ctx));
415     }
416     
417     @Override
418     public final ASTNode visitFunctionCall(final FunctionCallContext ctx) {
419         if (null != ctx.aggregationFunction()) {
420             return visit(ctx.aggregationFunction());
421         }
422         if (null != ctx.specialFunction()) {
423             return visit(ctx.specialFunction());
424         }
425         if (null != ctx.regularFunction()) {
426             return visit(ctx.regularFunction());
427         }
428         throw new IllegalStateException("FunctionCallContext must have aggregationFunction, regularFunction or specialFunction.");
429     }
430     
431     @Override
432     public final ASTNode visitAggregationFunction(final AggregationFunctionContext ctx) {
433         String aggregationType = ctx.aggregationFunctionName().getText();
434         return AggregationType.isAggregationType(aggregationType)
435                 ? createAggregationSegment(ctx, aggregationType)
436                 : new ExpressionProjectionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), getOriginalText(ctx));
437     }
438     
439     private ASTNode createAggregationSegment(final AggregationFunctionContext ctx, final String aggregationType) {
440         AggregationType type = AggregationType.valueOf(aggregationType.toUpperCase());
441         if (null != ctx.distinct()) {
442             AggregationDistinctProjectionSegment result =
443                     new AggregationDistinctProjectionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), type, getOriginalText(ctx), getDistinctExpression(ctx));
444             result.getParameters().addAll(getExpressions(ctx));
445             return result;
446         }
447         AggregationProjectionSegment result = new AggregationProjectionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), type, getOriginalText(ctx));
448         result.getParameters().addAll(getExpressions(ctx));
449         return result;
450     }
451     
452     private Collection<ExpressionSegment> getExpressions(final AggregationFunctionContext ctx) {
453         if (null == ctx.expr()) {
454             return Collections.emptyList();
455         }
456         Collection<ExpressionSegment> result = new LinkedList<>();
457         for (ExprContext each : ctx.expr()) {
458             result.add((ExpressionSegment) visit(each));
459         }
460         return result;
461     }
462     
463     private String getDistinctExpression(final AggregationFunctionContext ctx) {
464         StringBuilder result = new StringBuilder();
465         for (int i = 3; i < ctx.getChildCount() - 1; i++) {
466             result.append(ctx.getChild(i).getText());
467         }
468         return result.toString();
469     }
470     
471     @Override
472     public final ASTNode visitSpecialFunction(final SpecialFunctionContext ctx) {
473         if (null != ctx.castFunction()) {
474             return visit(ctx.castFunction());
475         }
476         return new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.getChild(0).getChild(0).getText(), getOriginalText(ctx));
477     }
478     
479     @Override
480     public final ASTNode visitCastFunction(final CastFunctionContext ctx) {
481         calculateParameterCount(Collections.singleton(ctx.expr()));
482         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.CAST().getText(), getOriginalText(ctx));
483         ASTNode exprSegment = visit(ctx.expr());
484         if (exprSegment instanceof ColumnSegment) {
485             result.getParameters().add((ColumnSegment) exprSegment);
486         } else if (exprSegment instanceof LiteralExpressionSegment) {
487             result.getParameters().add((LiteralExpressionSegment) exprSegment);
488         }
489         result.getParameters().add((DataTypeSegment) visit(ctx.dataType()));
490         return result;
491     }
492     
493     @Override
494     public final ASTNode visitRegularFunction(final RegularFunctionContext ctx) {
495         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.regularFunctionName().getText(), getOriginalText(ctx));
496         Collection<ExpressionSegment> expressionSegments = ctx.expr().stream().map(each -> (ExpressionSegment) visit(each)).collect(Collectors.toList());
497         result.getParameters().addAll(expressionSegments);
498         return result;
499     }
500     
501     @Override
502     public final ASTNode visitDataTypeName(final DataTypeNameContext ctx) {
503         Collection<String> dataTypeNames = new LinkedList<>();
504         for (int i = 0; i < ctx.getChildCount(); i++) {
505             dataTypeNames.add(ctx.getChild(i).getText());
506         }
507         return new KeywordValue(String.join(" ", dataTypeNames));
508     }
509     
510     // TODO :FIXME, sql case id: insert_with_str_to_date
511     private void calculateParameterCount(final Collection<ExprContext> exprContexts) {
512         for (ExprContext each : exprContexts) {
513             visit(each);
514         }
515     }
516     
517     @Override
518     public final ASTNode visitOrderByClause(final OrderByClauseContext ctx) {
519         Collection<OrderByItemSegment> items = new LinkedList<>();
520         for (OrderByItemContext each : ctx.orderByItem()) {
521             items.add((OrderByItemSegment) visit(each));
522         }
523         return new OrderBySegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), items);
524     }
525     
526     @Override
527     public final ASTNode visitOrderByItem(final OrderByItemContext ctx) {
528         OrderDirection orderDirection = null == ctx.DESC() ? OrderDirection.ASC : OrderDirection.DESC;
529         if (null != ctx.columnName()) {
530             ColumnSegment column = (ColumnSegment) visit(ctx.columnName());
531             return new ColumnOrderByItemSegment(column, orderDirection, null);
532         }
533         return new IndexOrderByItemSegment(ctx.numberLiterals().getStart().getStartIndex(), ctx.numberLiterals().getStop().getStopIndex(),
534                 SQLUtils.getExactlyNumber(ctx.numberLiterals().getText(), 10).intValue(), orderDirection, null);
535     }
536     
537     @Override
538     public final ASTNode visitDataType(final DataTypeContext ctx) {
539         DataTypeSegment result = new DataTypeSegment();
540         result.setDataTypeName(((KeywordValue) visit(ctx.dataTypeName())).getValue());
541         result.setStartIndex(ctx.start.getStartIndex());
542         result.setStopIndex(ctx.stop.getStopIndex());
543         if (null != ctx.dataTypeLength()) {
544             DataTypeLengthSegment dataTypeLengthSegment = (DataTypeLengthSegment) visit(ctx.dataTypeLength());
545             result.setDataLength(dataTypeLengthSegment);
546         }
547         return result;
548     }
549     
550     @Override
551     public final ASTNode visitDataTypeLength(final DataTypeLengthContext ctx) {
552         DataTypeLengthSegment result = new DataTypeLengthSegment();
553         result.setStartIndex(ctx.start.getStartIndex());
554         result.setStopIndex(ctx.stop.getStartIndex());
555         List<TerminalNode> numbers = ctx.NUMBER_();
556         if (numbers.size() == 1) {
557             result.setPrecision(Integer.parseInt(numbers.get(0).getText()));
558         }
559         if (numbers.size() == 2) {
560             result.setPrecision(Integer.parseInt(numbers.get(0).getText()));
561             result.setScale(Integer.parseInt(numbers.get(1).getText()));
562         }
563         return result;
564     }
565     
566     /**
567      * Get original text.
568      *
569      * @param ctx context
570      * @return original text
571      */
572     protected String getOriginalText(final ParserRuleContext ctx) {
573         return ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
574     }
575 }