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.mysql.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.MySQLStatementBaseVisitor;
28  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.AggregationFunctionContext;
29  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.AliasContext;
30  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.AssignmentContext;
31  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.AssignmentValueContext;
32  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.AssignmentValuesContext;
33  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.BitExprContext;
34  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.BitValueLiteralsContext;
35  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.BlobValueContext;
36  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.BooleanLiteralsContext;
37  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.BooleanPrimaryContext;
38  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CaseExpressionContext;
39  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CaseWhenContext;
40  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CastFunctionContext;
41  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CastTypeContext;
42  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CharFunctionContext;
43  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CollateClauseContext;
44  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ColumnNameContext;
45  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ColumnNamesContext;
46  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ColumnRefContext;
47  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CombineClauseContext;
48  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CompleteRegularFunctionContext;
49  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ConstraintNameContext;
50  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ConvertFunctionContext;
51  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CteClauseContext;
52  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CurrentUserFunctionContext;
53  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DataTypeContext;
54  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DeleteContext;
55  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DuplicateSpecificationContext;
56  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.EngineRefContext;
57  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.EscapedTableReferenceContext;
58  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ExprContext;
59  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ExtractFunctionContext;
60  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.FieldLengthContext;
61  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.FieldsContext;
62  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.FromClauseContext;
63  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.FunctionCallContext;
64  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.FunctionNameContext;
65  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.GroupByClauseContext;
66  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.GroupConcatFunctionContext;
67  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.HavingClauseContext;
68  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.HexadecimalLiteralsContext;
69  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.IdentifierContext;
70  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.IndexNameContext;
71  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.InsertContext;
72  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.InsertIdentifierContext;
73  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.InsertSelectClauseContext;
74  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.InsertValuesClauseContext;
75  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.IntervalExpressionContext;
76  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.JoinSpecificationContext;
77  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.JoinedTableContext;
78  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.JsonFunctionContext;
79  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.JsonFunctionNameContext;
80  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.LimitClauseContext;
81  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.LimitOffsetContext;
82  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.LimitRowCountContext;
83  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.LiteralsContext;
84  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.LockClauseContext;
85  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.LockClauseListContext;
86  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.MatchExpressionContext;
87  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.MultipleTablesClauseContext;
88  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.NaturalJoinTypeContext;
89  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.NullValueLiteralsContext;
90  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.NumberLiteralsContext;
91  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.OnDuplicateKeyClauseContext;
92  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.OrderByClauseContext;
93  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.OrderByItemContext;
94  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.OwnerContext;
95  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ParameterMarkerContext;
96  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.PositionFunctionContext;
97  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.PrecisionContext;
98  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.PredicateContext;
99  import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ProjectionContext;
100 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ProjectionsContext;
101 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.QualifiedShorthandContext;
102 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.QueryExpressionBodyContext;
103 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.QueryExpressionContext;
104 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.QueryExpressionParensContext;
105 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.QueryPrimaryContext;
106 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.QuerySpecificationContext;
107 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.RegularFunctionContext;
108 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ReplaceContext;
109 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ReplaceSelectClauseContext;
110 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ReplaceValuesClauseContext;
111 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.RowConstructorListContext;
112 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SchemaNameContext;
113 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectContext;
114 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectSpecificationContext;
115 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectWithIntoContext;
116 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SetAssignmentsClauseContext;
117 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ShorthandRegularFunctionContext;
118 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SimpleExprContext;
119 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SingleTableClauseContext;
120 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SpecialFunctionContext;
121 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.StringLiteralsContext;
122 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.String_Context;
123 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SubqueryContext;
124 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SubstringFunctionContext;
125 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SystemVariableContext;
126 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableAliasRefListContext;
127 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableFactorContext;
128 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableIdentOptWildContext;
129 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableListContext;
130 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableNameContext;
131 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableReferenceContext;
132 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableReferencesContext;
133 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableStatementContext;
134 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableValueConstructorContext;
135 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TemporalLiteralsContext;
136 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TimeStampDiffFunctionContext;
137 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TrimFunctionContext;
138 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TypeDatetimePrecisionContext;
139 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UdfFunctionContext;
140 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UpdateContext;
141 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UserVariableContext;
142 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ValuesFunctionContext;
143 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.VariableContext;
144 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ViewNameContext;
145 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ViewNamesContext;
146 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WeightStringFunctionContext;
147 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WhereClauseContext;
148 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WithClauseContext;
149 import org.apache.shardingsphere.sql.parser.sql.common.enums.AggregationType;
150 import org.apache.shardingsphere.sql.parser.sql.common.enums.CombineType;
151 import org.apache.shardingsphere.sql.parser.sql.common.enums.JoinType;
152 import org.apache.shardingsphere.sql.parser.sql.common.enums.OrderDirection;
153 import org.apache.shardingsphere.sql.parser.sql.common.enums.ParameterMarkerType;
154 import org.apache.shardingsphere.sql.parser.sql.common.enums.SubqueryType;
155 import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.VariableSegment;
156 import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.constraint.ConstraintSegment;
157 import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.engine.EngineSegment;
158 import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.index.IndexNameSegment;
159 import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.index.IndexSegment;
160 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.ColumnAssignmentSegment;
161 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.InsertValuesSegment;
162 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.SetAssignmentSegment;
163 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
164 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.InsertColumnsSegment;
165 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.OnDuplicateKeyColumnsSegment;
166 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.combine.CombineSegment;
167 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BetweenExpression;
168 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOperationExpression;
169 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.CaseWhenExpression;
170 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.CollateExpression;
171 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExistsSubqueryExpression;
172 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
173 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.FunctionSegment;
174 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
175 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ListExpression;
176 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.NotExpression;
177 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.RowExpression;
178 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.UnaryOperationExpression;
179 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ValuesExpression;
180 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.CommonExpressionSegment;
181 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.CommonTableExpressionSegment;
182 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.LiteralExpressionSegment;
183 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
184 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.SimpleExpressionSegment;
185 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubqueryExpressionSegment;
186 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubquerySegment;
187 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.AggregationDistinctProjectionSegment;
188 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.AggregationProjectionSegment;
189 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
190 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ExpressionProjectionSegment;
191 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
192 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionsSegment;
193 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ShorthandProjectionSegment;
194 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.SubqueryProjectionSegment;
195 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.GroupBySegment;
196 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.OrderBySegment;
197 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.item.ColumnOrderByItemSegment;
198 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.item.ExpressionOrderByItemSegment;
199 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.item.IndexOrderByItemSegment;
200 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.item.OrderByItemSegment;
201 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.PaginationValueSegment;
202 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.LimitSegment;
203 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.NumberLiteralLimitValueSegment;
204 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.ParameterMarkerLimitValueSegment;
205 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.HavingSegment;
206 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.LockSegment;
207 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.WhereSegment;
208 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.AliasSegment;
209 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.DataTypeLengthSegment;
210 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.DataTypeSegment;
211 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.DatabaseSegment;
212 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.OwnerSegment;
213 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.ParameterMarkerSegment;
214 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.ParenthesesSegment;
215 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WindowSegment;
216 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WithSegment;
217 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.DeleteMultiTableSegment;
218 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.IndexHintSegment;
219 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.JoinTableSegment;
220 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
221 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SubqueryTableSegment;
222 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableNameSegment;
223 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
224 import org.apache.shardingsphere.sql.parser.sql.common.util.SQLUtils;
225 import org.apache.shardingsphere.sql.parser.sql.common.value.collection.CollectionValue;
226 import org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
227 import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.BooleanLiteralValue;
228 import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.NullLiteralValue;
229 import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.NumberLiteralValue;
230 import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.OtherLiteralValue;
231 import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.StringLiteralValue;
232 import org.apache.shardingsphere.sql.parser.sql.common.value.parametermarker.ParameterMarkerValue;
233 import org.apache.shardingsphere.sql.parser.sql.dialect.segment.mysql.match.MatchAgainstExpression;
234 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLDeleteStatement;
235 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLInsertStatement;
236 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLSelectStatement;
237 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLUpdateStatement;
238 
239 import java.math.BigDecimal;
240 import java.util.ArrayList;
241 import java.util.Collection;
242 import java.util.Collections;
243 import java.util.LinkedList;
244 import java.util.List;
245 import java.util.stream.Collectors;
246 
247 /**
248  * Statement visitor for MySQL.
249  */
250 @Getter(AccessLevel.PROTECTED)
251 public abstract class MySQLStatementVisitor extends MySQLStatementBaseVisitor<ASTNode> {
252     
253     private final Collection<ParameterMarkerSegment> parameterMarkerSegments = new LinkedList<>();
254     
255     @Override
256     public final ASTNode visitParameterMarker(final ParameterMarkerContext ctx) {
257         return new ParameterMarkerValue(parameterMarkerSegments.size(), ParameterMarkerType.QUESTION);
258     }
259     
260     @Override
261     public final ASTNode visitLiterals(final LiteralsContext ctx) {
262         if (null != ctx.stringLiterals()) {
263             return visit(ctx.stringLiterals());
264         }
265         if (null != ctx.numberLiterals()) {
266             return visit(ctx.numberLiterals());
267         }
268         if (null != ctx.temporalLiterals()) {
269             return visit(ctx.temporalLiterals());
270         }
271         if (null != ctx.hexadecimalLiterals()) {
272             return visit(ctx.hexadecimalLiterals());
273         }
274         if (null != ctx.bitValueLiterals()) {
275             return visit(ctx.bitValueLiterals());
276         }
277         if (null != ctx.booleanLiterals()) {
278             return visit(ctx.booleanLiterals());
279         }
280         if (null != ctx.nullValueLiterals()) {
281             return visit(ctx.nullValueLiterals());
282         }
283         throw new IllegalStateException("Literals must have string, number, dateTime, hex, bit, boolean or null.");
284     }
285     
286     @Override
287     public final ASTNode visitStringLiterals(final StringLiteralsContext ctx) {
288         return new StringLiteralValue(ctx.getText());
289     }
290     
291     @Override
292     public ASTNode visitString_(final String_Context ctx) {
293         return new StringLiteralValue(ctx.getText());
294     }
295     
296     @Override
297     public final ASTNode visitNumberLiterals(final NumberLiteralsContext ctx) {
298         return new NumberLiteralValue(ctx.getText());
299     }
300     
301     @Override
302     public ASTNode visitTemporalLiterals(final TemporalLiteralsContext ctx) {
303         // TODO deal with TemporalLiterals
304         return new OtherLiteralValue(ctx.getText());
305     }
306     
307     @Override
308     public final ASTNode visitHexadecimalLiterals(final HexadecimalLiteralsContext ctx) {
309         // TODO deal with hexadecimalLiterals
310         return new OtherLiteralValue(ctx.getText());
311     }
312     
313     @Override
314     public final ASTNode visitBitValueLiterals(final BitValueLiteralsContext ctx) {
315         // TODO deal with bitValueLiterals
316         return new OtherLiteralValue(ctx.getText());
317     }
318     
319     @Override
320     public final ASTNode visitBooleanLiterals(final BooleanLiteralsContext ctx) {
321         return new BooleanLiteralValue(ctx.getText());
322     }
323     
324     @Override
325     public final ASTNode visitNullValueLiterals(final NullValueLiteralsContext ctx) {
326         return new NullLiteralValue(ctx.getText());
327     }
328     
329     @Override
330     public final ASTNode visitIdentifier(final IdentifierContext ctx) {
331         return new IdentifierValue(ctx.getText());
332     }
333     
334     @Override
335     public final ASTNode visitSchemaName(final SchemaNameContext ctx) {
336         return new DatabaseSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (IdentifierValue) visit(ctx.identifier()));
337     }
338     
339     @Override
340     public final ASTNode visitTableName(final TableNameContext ctx) {
341         SimpleTableSegment result = new SimpleTableSegment(new TableNameSegment(ctx.name().getStart().getStartIndex(),
342                 ctx.name().getStop().getStopIndex(), new IdentifierValue(ctx.name().identifier().getText())));
343         OwnerContext owner = ctx.owner();
344         if (null != owner) {
345             result.setOwner((OwnerSegment) visit(owner));
346         }
347         return result;
348     }
349     
350     @Override
351     public final ASTNode visitViewName(final ViewNameContext ctx) {
352         SimpleTableSegment result = new SimpleTableSegment(new TableNameSegment(ctx.identifier().getStart().getStartIndex(),
353                 ctx.identifier().getStop().getStopIndex(), new IdentifierValue(ctx.identifier().getText())));
354         OwnerContext owner = ctx.owner();
355         if (null != owner) {
356             result.setOwner((OwnerSegment) visit(owner));
357         }
358         return result;
359     }
360     
361     @Override
362     public final ASTNode visitOwner(final OwnerContext ctx) {
363         return new OwnerSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (IdentifierValue) visit(ctx.identifier()));
364     }
365     
366     @Override
367     public ASTNode visitFunctionName(final FunctionNameContext ctx) {
368         FunctionSegment result = new FunctionSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.identifier().IDENTIFIER_().getText(), ctx.getText());
369         if (null != ctx.owner()) {
370             result.setOwner((OwnerSegment) visit(ctx.owner()));
371         }
372         return result;
373     }
374     
375     @Override
376     public final ASTNode visitColumnName(final ColumnNameContext ctx) {
377         return new ColumnSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (IdentifierValue) visit(ctx.identifier()));
378     }
379     
380     @Override
381     public final ASTNode visitIndexName(final IndexNameContext ctx) {
382         IndexNameSegment indexName = new IndexNameSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (IdentifierValue) visit(ctx.identifier()));
383         return new IndexSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), indexName);
384     }
385     
386     @Override
387     public ASTNode visitTableList(final TableListContext ctx) {
388         CollectionValue<SimpleTableSegment> result = new CollectionValue<>();
389         for (TableNameContext each : ctx.tableName()) {
390             result.getValue().add((SimpleTableSegment) visit(each));
391         }
392         return result;
393     }
394     
395     @Override
396     public final ASTNode visitViewNames(final ViewNamesContext ctx) {
397         CollectionValue<SimpleTableSegment> result = new CollectionValue<>();
398         for (ViewNameContext each : ctx.viewName()) {
399             result.getValue().add((SimpleTableSegment) visit(each));
400         }
401         return result;
402     }
403     
404     @Override
405     public final ASTNode visitColumnNames(final ColumnNamesContext ctx) {
406         CollectionValue<ColumnSegment> result = new CollectionValue<>();
407         for (ColumnNameContext each : ctx.columnName()) {
408             result.getValue().add((ColumnSegment) visit(each));
409         }
410         return result;
411     }
412     
413     @Override
414     public final ASTNode visitExpr(final ExprContext ctx) {
415         if (null != ctx.booleanPrimary()) {
416             return visit(ctx.booleanPrimary());
417         }
418         if (null != ctx.XOR()) {
419             return createBinaryOperationExpression(ctx, "XOR");
420         }
421         if (null != ctx.andOperator()) {
422             return createBinaryOperationExpression(ctx, ctx.andOperator().getText());
423         }
424         if (null != ctx.orOperator()) {
425             return createBinaryOperationExpression(ctx, ctx.orOperator().getText());
426         }
427         return new NotExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.expr(0)), false);
428     }
429     
430     private BinaryOperationExpression createBinaryOperationExpression(final ExprContext ctx, final String operator) {
431         ExpressionSegment left = (ExpressionSegment) visit(ctx.expr(0));
432         ExpressionSegment right = (ExpressionSegment) visit(ctx.expr(1));
433         String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
434         return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
435     }
436     
437     @Override
438     public final ASTNode visitBooleanPrimary(final BooleanPrimaryContext ctx) {
439         if (null != ctx.IS()) {
440             // TODO optimize operatorToken
441             String rightText = "";
442             if (null != ctx.NOT()) {
443                 rightText = rightText.concat(ctx.start.getInputStream().getText(new Interval(ctx.NOT().getSymbol().getStartIndex(),
444                         ctx.NOT().getSymbol().getStopIndex()))).concat(" ");
445             }
446             Token operatorToken = null;
447             if (null != ctx.NULL()) {
448                 operatorToken = ctx.NULL().getSymbol();
449             }
450             if (null != ctx.TRUE()) {
451                 operatorToken = ctx.TRUE().getSymbol();
452             }
453             if (null != ctx.FALSE()) {
454                 operatorToken = ctx.FALSE().getSymbol();
455             }
456             int startIndex = null == operatorToken ? ctx.IS().getSymbol().getStopIndex() + 2 : operatorToken.getStartIndex();
457             rightText = rightText.concat(ctx.start.getInputStream().getText(new Interval(startIndex, ctx.stop.getStopIndex())));
458             ExpressionSegment right = new LiteralExpressionSegment(ctx.IS().getSymbol().getStopIndex() + 2, ctx.stop.getStopIndex(), rightText);
459             String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
460             ExpressionSegment left = (ExpressionSegment) visit(ctx.booleanPrimary());
461             String operator = "IS";
462             return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
463         }
464         if (null != ctx.comparisonOperator() || null != ctx.SAFE_EQ_()) {
465             return createCompareSegment(ctx);
466         }
467         if (null != ctx.MEMBER()) {
468             int startIndex = ctx.MEMBER().getSymbol().getStopIndex() + 5;
469             int endIndex = ctx.stop.getStopIndex() - 1;
470             String rightText = ctx.start.getInputStream().getText(new Interval(startIndex, endIndex));
471             ExpressionSegment right = new ExpressionProjectionSegment(startIndex, endIndex, rightText);
472             String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
473             ExpressionSegment left = (ExpressionSegment) visit(ctx.booleanPrimary());
474             String operator = "MEMBER OF";
475             return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
476         }
477         if (null != ctx.assignmentOperator()) {
478             return createAssignmentSegment(ctx);
479         }
480         return visit(ctx.predicate());
481     }
482     
483     private ASTNode createAssignmentSegment(final BooleanPrimaryContext ctx) {
484         ExpressionSegment left = (ExpressionSegment) visit(ctx.booleanPrimary());
485         ExpressionSegment right = (ExpressionSegment) visit(ctx.predicate());
486         String operator = ctx.assignmentOperator().getText();
487         String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
488         return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
489     }
490     
491     private ASTNode createCompareSegment(final BooleanPrimaryContext ctx) {
492         ExpressionSegment left = (ExpressionSegment) visit(ctx.booleanPrimary());
493         ExpressionSegment right;
494         if (null != ctx.predicate()) {
495             right = (ExpressionSegment) visit(ctx.predicate());
496         } else {
497             right = new SubqueryExpressionSegment(
498                     new SubquerySegment(ctx.subquery().start.getStartIndex(), ctx.subquery().stop.getStopIndex(), (MySQLSelectStatement) visit(ctx.subquery()), getOriginalText(ctx.subquery())));
499         }
500         String operator = null == ctx.SAFE_EQ_() ? ctx.comparisonOperator().getText() : ctx.SAFE_EQ_().getText();
501         String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
502         return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
503     }
504     
505     @Override
506     public final ASTNode visitPredicate(final PredicateContext ctx) {
507         if (null != ctx.IN()) {
508             return createInSegment(ctx);
509         }
510         if (null != ctx.BETWEEN()) {
511             return createBetweenSegment(ctx);
512         }
513         if (null != ctx.LIKE()) {
514             return createBinaryOperationExpressionFromLike(ctx);
515         }
516         if (null != ctx.REGEXP()) {
517             return createBinaryOperationExpressionFromRegexp(ctx);
518         }
519         if (null != ctx.RLIKE()) {
520             return createBinaryOperationExpressionFromRlike(ctx);
521         }
522         return visit(ctx.bitExpr(0));
523     }
524     
525     private InExpression createInSegment(final PredicateContext ctx) {
526         boolean not = null != ctx.NOT();
527         ExpressionSegment left = (ExpressionSegment) visit(ctx.bitExpr(0));
528         ExpressionSegment right;
529         if (null != ctx.subquery()) {
530             right = new SubqueryExpressionSegment(
531                     new SubquerySegment(ctx.subquery().start.getStartIndex(), ctx.subquery().stop.getStopIndex(), (MySQLSelectStatement) visit(ctx.subquery()), getOriginalText(ctx.subquery())));
532         } else {
533             right = new ListExpression(ctx.LP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex());
534             for (ExprContext each : ctx.expr()) {
535                 ((ListExpression) right).getItems().add((ExpressionSegment) visit(each));
536             }
537         }
538         return new InExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, not);
539     }
540     
541     private BinaryOperationExpression createBinaryOperationExpressionFromLike(final PredicateContext ctx) {
542         ExpressionSegment left = (ExpressionSegment) visit(ctx.bitExpr(0));
543         String operator;
544         ExpressionSegment right;
545         if (null != ctx.SOUNDS()) {
546             right = (ExpressionSegment) visit(ctx.bitExpr(1));
547             operator = "SOUNDS LIKE";
548         } else {
549             ListExpression listExpression = new ListExpression(ctx.simpleExpr(0).start.getStartIndex(), ctx.simpleExpr().get(ctx.simpleExpr().size() - 1).stop.getStopIndex());
550             for (SimpleExprContext each : ctx.simpleExpr()) {
551                 listExpression.getItems().add((ExpressionSegment) visit(each));
552             }
553             right = listExpression;
554             operator = null == ctx.NOT() ? "LIKE" : "NOT LIKE";
555         }
556         String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
557         return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
558     }
559     
560     private BinaryOperationExpression createBinaryOperationExpressionFromRegexp(final PredicateContext ctx) {
561         ExpressionSegment left = (ExpressionSegment) visit(ctx.bitExpr(0));
562         ExpressionSegment right = (ExpressionSegment) visit(ctx.bitExpr(1));
563         String operator = null == ctx.NOT() ? "REGEXP" : "NOT REGEXP";
564         String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
565         return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
566     }
567     
568     private BinaryOperationExpression createBinaryOperationExpressionFromRlike(final PredicateContext ctx) {
569         ExpressionSegment left = (ExpressionSegment) visit(ctx.bitExpr(0));
570         ExpressionSegment right = (ExpressionSegment) visit(ctx.bitExpr(1));
571         String operator = null == ctx.NOT() ? "RLIKE" : "NOT RLIKE";
572         String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
573         return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
574     }
575     
576     private BetweenExpression createBetweenSegment(final PredicateContext ctx) {
577         ExpressionSegment left = (ExpressionSegment) visit(ctx.bitExpr(0));
578         ExpressionSegment between = (ExpressionSegment) visit(ctx.bitExpr(1));
579         ExpressionSegment and = (ExpressionSegment) visit(ctx.predicate());
580         boolean not = null != ctx.NOT();
581         return new BetweenExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, between, and, not);
582     }
583     
584     @Override
585     public final ASTNode visitBitExpr(final BitExprContext ctx) {
586         if (null != ctx.simpleExpr()) {
587             return visit(ctx.simpleExpr());
588         }
589         ExpressionSegment left = (ExpressionSegment) visit(ctx.getChild(0));
590         ExpressionSegment right = (ExpressionSegment) visit(ctx.getChild(2));
591         String operator = ctx.getChild(1).getText();
592         String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
593         return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
594     }
595     
596     @Override
597     public final ASTNode visitSimpleExpr(final SimpleExprContext ctx) {
598         int startIndex = ctx.start.getStartIndex();
599         int stopIndex = ctx.stop.getStopIndex();
600         if (null != ctx.subquery()) {
601             SubquerySegment subquerySegment = new SubquerySegment(ctx.subquery().getStart().getStartIndex(), ctx.subquery().getStop().getStopIndex(), (MySQLSelectStatement) visit(ctx.subquery()),
602                     getOriginalText(ctx.subquery()));
603             if (null != ctx.EXISTS()) {
604                 subquerySegment.setSubqueryType(SubqueryType.EXISTS_SUBQUERY);
605                 return new ExistsSubqueryExpression(startIndex, stopIndex, subquerySegment);
606             }
607             return new SubqueryExpressionSegment(subquerySegment);
608         }
609         if (null != ctx.parameterMarker()) {
610             ParameterMarkerValue parameterMarker = (ParameterMarkerValue) visit(ctx.parameterMarker());
611             ParameterMarkerExpressionSegment result = new ParameterMarkerExpressionSegment(startIndex, stopIndex, parameterMarker.getValue(), parameterMarker.getType());
612             parameterMarkerSegments.add(result);
613             return result;
614         }
615         if (null != ctx.literals()) {
616             return SQLUtils.createLiteralExpression(visit(ctx.literals()), startIndex, stopIndex, ctx.literals().start.getInputStream().getText(new Interval(startIndex, stopIndex)));
617         }
618         if (null != ctx.intervalExpression()) {
619             return visit(ctx.intervalExpression());
620         }
621         if (null != ctx.functionCall()) {
622             return visit(ctx.functionCall());
623         }
624         if (null != ctx.collateClause()) {
625             if (null != ctx.simpleExpr()) {
626                 ExpressionSegment expr = (ExpressionSegment) visit(ctx.simpleExpr(0));
627                 return new CollateExpression(startIndex, stopIndex, (SimpleExpressionSegment) visit(ctx.collateClause()), expr);
628             }
629             return new CollateExpression(startIndex, stopIndex, (SimpleExpressionSegment) visit(ctx.collateClause()), null);
630         }
631         if (null != ctx.columnRef()) {
632             return visit(ctx.columnRef());
633         }
634         if (null != ctx.matchExpression()) {
635             return visit(ctx.matchExpression());
636         }
637         if (null != ctx.notOperator()) {
638             ASTNode expression = visit(ctx.simpleExpr(0));
639             if (expression instanceof ExistsSubqueryExpression) {
640                 ((ExistsSubqueryExpression) expression).setNot(true);
641                 return expression;
642             }
643             return new NotExpression(startIndex, stopIndex, (ExpressionSegment) expression, "!".equalsIgnoreCase(ctx.notOperator().getText()));
644         }
645         if (null != ctx.LP_() && 1 == ctx.expr().size()) {
646             ASTNode result = visit(ctx.expr(0));
647             if (result instanceof ColumnSegment) {
648                 ((ColumnSegment) result).getParentheses().add(new ParenthesesSegment(ctx.LP_().getSymbol().getStartIndex(), ctx.LP_().getSymbol().getStopIndex(), true));
649                 ((ColumnSegment) result).getParentheses().add(new ParenthesesSegment(ctx.RP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex(), false));
650             }
651             return result;
652         }
653         if (null != ctx.VERTICAL_BAR_() && 2 == ctx.VERTICAL_BAR_().size()) {
654             ExpressionSegment left = (ExpressionSegment) visit(ctx.simpleExpr(0));
655             ExpressionSegment right = (ExpressionSegment) visit(ctx.simpleExpr(1));
656             String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
657             return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, ctx.VERTICAL_BAR_(0).getText().concat(ctx.VERTICAL_BAR_(1).getText()), text);
658         }
659         return visitRemainSimpleExpr(ctx);
660     }
661     
662     @Override
663     public ASTNode visitColumnRef(final ColumnRefContext ctx) {
664         int identifierCount = ctx.identifier().size();
665         ColumnSegment result;
666         if (1 == identifierCount) {
667             result = new ColumnSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (IdentifierValue) visit(ctx.identifier(0)));
668         } else if (2 == identifierCount) {
669             result = new ColumnSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (IdentifierValue) visit(ctx.identifier(1)));
670             result.setOwner(new OwnerSegment(ctx.identifier(0).start.getStartIndex(), ctx.identifier(0).stop.getStopIndex(), (IdentifierValue) visit(ctx.identifier(0))));
671         } else {
672             result = new ColumnSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (IdentifierValue) visit(ctx.identifier(2)));
673             OwnerSegment owner = new OwnerSegment(ctx.identifier(1).start.getStartIndex(), ctx.identifier(1).stop.getStopIndex(), (IdentifierValue) visit(ctx.identifier(1)));
674             owner.setOwner(new OwnerSegment(ctx.identifier(0).start.getStartIndex(), ctx.identifier(0).stop.getStopIndex(), (IdentifierValue) visit(ctx.identifier(0))));
675             result.setOwner(owner);
676         }
677         return result;
678     }
679     
680     @Override
681     public ASTNode visitSubquery(final SubqueryContext ctx) {
682         return visit(ctx.queryExpressionParens());
683     }
684     
685     @Override
686     public ASTNode visitQueryExpressionParens(final QueryExpressionParensContext ctx) {
687         if (null != ctx.queryExpressionParens()) {
688             return visit(ctx.queryExpressionParens());
689         }
690         MySQLSelectStatement result = (MySQLSelectStatement) visit(ctx.queryExpression());
691         if (null != ctx.lockClauseList()) {
692             result.setLock((LockSegment) visit(ctx.lockClauseList()));
693         }
694         result.addParameterMarkerSegments(getParameterMarkerSegments());
695         return result;
696     }
697     
698     @Override
699     public ASTNode visitLockClauseList(final LockClauseListContext ctx) {
700         LockSegment result = new LockSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex());
701         for (LockClauseContext each : ctx.lockClause()) {
702             if (null != each.tableLockingList()) {
703                 result.getTables().addAll(generateTablesFromTableAliasRefList(each.tableLockingList().tableAliasRefList()));
704             }
705         }
706         return result;
707     }
708     
709     @Override
710     public ASTNode visitQueryExpression(final QueryExpressionContext ctx) {
711         MySQLSelectStatement result;
712         if (null != ctx.queryExpressionBody()) {
713             result = (MySQLSelectStatement) visit(ctx.queryExpressionBody());
714         } else {
715             result = (MySQLSelectStatement) visit(ctx.queryExpressionParens());
716         }
717         if (null != ctx.orderByClause()) {
718             result.setOrderBy((OrderBySegment) visit(ctx.orderByClause()));
719         }
720         if (null != ctx.limitClause()) {
721             result.setLimit((LimitSegment) visit(ctx.limitClause()));
722         }
723         if (null != result && null != ctx.withClause()) {
724             result.setWithSegment((WithSegment) visit(ctx.withClause()));
725         }
726         return result;
727     }
728     
729     @Override
730     public ASTNode visitSelectWithInto(final SelectWithIntoContext ctx) {
731         if (null != ctx.selectWithInto()) {
732             return visit(ctx.selectWithInto());
733         }
734         MySQLSelectStatement result = (MySQLSelectStatement) visit(ctx.queryExpression());
735         if (null != ctx.lockClauseList()) {
736             result.setLock((LockSegment) visit(ctx.lockClauseList()));
737         }
738         return result;
739     }
740     
741     @Override
742     public ASTNode visitWithClause(final WithClauseContext ctx) {
743         Collection<CommonTableExpressionSegment> commonTableExpressions = new LinkedList<>();
744         for (CteClauseContext each : ctx.cteClause()) {
745             commonTableExpressions.add((CommonTableExpressionSegment) visit(each));
746         }
747         return new WithSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), commonTableExpressions);
748     }
749     
750     @SuppressWarnings("unchecked")
751     @Override
752     public ASTNode visitCteClause(final CteClauseContext ctx) {
753         CommonTableExpressionSegment result = new CommonTableExpressionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (IdentifierValue) visit(ctx.identifier()),
754                 new SubquerySegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (MySQLSelectStatement) visit(ctx.subquery()), getOriginalText(ctx.subquery())));
755         if (null != ctx.columnNames()) {
756             CollectionValue<ColumnSegment> columns = (CollectionValue<ColumnSegment>) visit(ctx.columnNames());
757             result.getColumns().addAll(columns.getValue());
758         }
759         return result;
760     }
761     
762     @Override
763     public ASTNode visitQueryExpressionBody(final QueryExpressionBodyContext ctx) {
764         if (1 == ctx.getChildCount() && ctx.getChild(0) instanceof QueryPrimaryContext) {
765             return visit(ctx.queryPrimary());
766         }
767         if (null != ctx.queryExpressionBody()) {
768             MySQLSelectStatement result = new MySQLSelectStatement();
769             SubquerySegment left = new SubquerySegment(ctx.queryExpressionBody().start.getStartIndex(), ctx.queryExpressionBody().stop.getStopIndex(),
770                     (MySQLSelectStatement) visit(ctx.queryExpressionBody()), getOriginalText(ctx.queryExpressionBody()));
771             result.setProjections(left.getSelect().getProjections());
772             left.getSelect().getFrom().ifPresent(result::setFrom);
773             ((MySQLSelectStatement) left.getSelect()).getTable().ifPresent(result::setTable);
774             result.setCombine(createCombineSegment(ctx.combineClause(), left));
775             return result;
776         }
777         if (null != ctx.queryExpressionParens()) {
778             MySQLSelectStatement result = new MySQLSelectStatement();
779             SubquerySegment left = new SubquerySegment(ctx.queryExpressionParens().start.getStartIndex(), ctx.queryExpressionParens().stop.getStopIndex(),
780                     (MySQLSelectStatement) visit(ctx.queryExpressionParens()), getOriginalText(ctx.queryExpressionParens()));
781             result.setProjections(left.getSelect().getProjections());
782             left.getSelect().getFrom().ifPresent(result::setFrom);
783             ((MySQLSelectStatement) left.getSelect()).getTable().ifPresent(result::setTable);
784             result.setCombine(createCombineSegment(ctx.combineClause(), left));
785             return result;
786         }
787         return visit(ctx.queryExpressionParens());
788     }
789     
790     private CombineSegment createCombineSegment(final CombineClauseContext ctx, final SubquerySegment left) {
791         CombineType combineType;
792         if (null != ctx.EXCEPT()) {
793             combineType = CombineType.EXCEPT;
794         } else if (null != ctx.INTERSECT()) {
795             combineType = CombineType.INTERSECT;
796         } else {
797             combineType = null == ctx.combineOption() || null == ctx.combineOption().ALL() ? CombineType.UNION : CombineType.UNION_ALL;
798         }
799         ParserRuleContext ruleContext = null == ctx.queryPrimary() ? ctx.queryExpressionParens() : ctx.queryPrimary();
800         SubquerySegment right = new SubquerySegment(ruleContext.start.getStartIndex(), ruleContext.stop.getStopIndex(), (MySQLSelectStatement) visit(ruleContext), getOriginalText(ruleContext));
801         return new CombineSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), left, combineType, right);
802     }
803     
804     @Override
805     public ASTNode visitQuerySpecification(final QuerySpecificationContext ctx) {
806         MySQLSelectStatement result = new MySQLSelectStatement();
807         result.setProjections((ProjectionsSegment) visit(ctx.projections()));
808         if (null != ctx.selectSpecification()) {
809             result.getProjections().setDistinctRow(isDistinct(ctx));
810         }
811         if (null != ctx.fromClause()) {
812             if (null != ctx.fromClause().tableReferences()) {
813                 TableSegment tableSource = (TableSegment) visit(ctx.fromClause().tableReferences());
814                 result.setFrom(tableSource);
815             }
816             if (null != ctx.fromClause().DUAL()) {
817                 TableSegment tableSource = new SimpleTableSegment(new TableNameSegment(ctx.fromClause().DUAL().getSymbol().getStartIndex(),
818                         ctx.fromClause().DUAL().getSymbol().getStopIndex(), new IdentifierValue(ctx.fromClause().DUAL().getText())));
819                 result.setFrom(tableSource);
820             }
821         }
822         if (null != ctx.whereClause()) {
823             result.setWhere((WhereSegment) visit(ctx.whereClause()));
824         }
825         if (null != ctx.groupByClause()) {
826             result.setGroupBy((GroupBySegment) visit(ctx.groupByClause()));
827         }
828         if (null != ctx.havingClause()) {
829             result.setHaving((HavingSegment) visit(ctx.havingClause()));
830         }
831         if (null != ctx.windowClause()) {
832             result.setWindow((WindowSegment) visit(ctx.windowClause()));
833         }
834         return result;
835     }
836     
837     @Override
838     public ASTNode visitTableValueConstructor(final TableValueConstructorContext ctx) {
839         MySQLSelectStatement result = new MySQLSelectStatement();
840         int startIndex = ctx.getStart().getStartIndex();
841         int stopIndex = ctx.getStop().getStopIndex();
842         ValuesExpression valuesExpression = new ValuesExpression(startIndex, stopIndex);
843         valuesExpression.getRowConstructorList().addAll(createRowConstructorList(ctx.rowConstructorList()));
844         result.setProjections(new ProjectionsSegment(startIndex, stopIndex));
845         result.getProjections().getProjections().add(new ExpressionProjectionSegment(startIndex, stopIndex, getOriginalText(ctx), valuesExpression));
846         return result;
847     }
848     
849     private Collection<InsertValuesSegment> createRowConstructorList(final RowConstructorListContext ctx) {
850         Collection<InsertValuesSegment> result = new LinkedList<>();
851         for (AssignmentValuesContext each : ctx.assignmentValues()) {
852             result.add((InsertValuesSegment) visit(each));
853         }
854         return result;
855     }
856     
857     @Override
858     public ASTNode visitTableStatement(final TableStatementContext ctx) {
859         MySQLSelectStatement result = new MySQLSelectStatement();
860         result.setProjections(new ProjectionsSegment(ctx.start.getStartIndex(), ctx.start.getStartIndex()));
861         result.getProjections().getProjections().add(new ShorthandProjectionSegment(ctx.start.getStartIndex(), ctx.start.getStartIndex()));
862         result.setFrom(new SimpleTableSegment(new TableNameSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), new IdentifierValue(ctx.tableName().getText()))));
863         return result;
864     }
865     
866     @Override
867     public ASTNode visitHavingClause(final HavingClauseContext ctx) {
868         ExpressionSegment expr = (ExpressionSegment) visit(ctx.expr());
869         return new HavingSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), expr);
870     }
871     
872     @Override
873     public final ASTNode visitIntervalExpression(final IntervalExpressionContext ctx) {
874         FunctionSegment result = new FunctionSegment(ctx.INTERVAL().getSymbol().getStartIndex(), ctx.INTERVAL().getSymbol().getStopIndex(), ctx.INTERVAL().getText(), ctx.INTERVAL().getText());
875         result.getParameters().add((ExpressionSegment) visit(ctx.intervalValue().expr()));
876         result.getParameters().add(new LiteralExpressionSegment(ctx.intervalValue().intervalUnit().getStart().getStartIndex(), ctx.intervalValue().intervalUnit().getStop().getStopIndex(),
877                 ctx.intervalValue().intervalUnit().getText()));
878         return result;
879     }
880     
881     @Override
882     public final ASTNode visitFunctionCall(final FunctionCallContext ctx) {
883         if (null != ctx.aggregationFunction()) {
884             return visit(ctx.aggregationFunction());
885         }
886         if (null != ctx.specialFunction()) {
887             return visit(ctx.specialFunction());
888         }
889         if (null != ctx.regularFunction()) {
890             return visit(ctx.regularFunction());
891         }
892         if (null != ctx.jsonFunction()) {
893             return visit(ctx.jsonFunction());
894         }
895         if (null != ctx.udfFunction()) {
896             return visit(ctx.udfFunction());
897         }
898         throw new IllegalStateException("FunctionCallContext must have aggregationFunction, regularFunction, specialFunction, jsonFunction or udfFunction.");
899     }
900     
901     @Override
902     public ASTNode visitUdfFunction(final UdfFunctionContext ctx) {
903         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), getOriginalText(ctx), getOriginalText(ctx));
904         if (null != ctx.expr()) {
905             for (ExprContext each : ctx.expr()) {
906                 result.getParameters().add((ExpressionSegment) visit(each));
907             }
908         }
909         return result;
910     }
911     
912     @Override
913     public final ASTNode visitAggregationFunction(final AggregationFunctionContext ctx) {
914         String aggregationType = ctx.aggregationFunctionName().getText();
915         return AggregationType.isAggregationType(aggregationType)
916                 ? createAggregationSegment(ctx, aggregationType)
917                 : new ExpressionProjectionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), getOriginalText(ctx));
918     }
919     
920     @Override
921     public final ASTNode visitJsonFunction(final JsonFunctionContext ctx) {
922         JsonFunctionNameContext functionNameContext = ctx.jsonFunctionName();
923         String functionName;
924         FunctionSegment result;
925         if (null != functionNameContext) {
926             functionName = functionNameContext.getText();
927             result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), functionName, getOriginalText(ctx));
928             for (ExprContext each : ctx.expr()) {
929                 result.getParameters().add((ExpressionSegment) visit(each));
930             }
931         } else if (null != ctx.JSON_SEPARATOR()) {
932             functionName = ctx.JSON_SEPARATOR().getText();
933             result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), functionName, getOriginalText(ctx));
934         } else {
935             functionName = ctx.JSON_UNQUOTED_SEPARATOR().getText();
936             result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), functionName, getOriginalText(ctx));
937         }
938         return result;
939     }
940     
941     private ASTNode createAggregationSegment(final AggregationFunctionContext ctx, final String aggregationType) {
942         AggregationType type = AggregationType.valueOf(aggregationType.toUpperCase());
943         if (null != ctx.distinct()) {
944             AggregationDistinctProjectionSegment result =
945                     new AggregationDistinctProjectionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), type, getOriginalText(ctx), getDistinctExpression(ctx));
946             result.getParameters().addAll(getExpressions(ctx.expr()));
947             return result;
948         }
949         AggregationProjectionSegment result = new AggregationProjectionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), type, getOriginalText(ctx));
950         result.getParameters().addAll(getExpressions(ctx.expr()));
951         return result;
952     }
953     
954     protected Collection<ExpressionSegment> getExpressions(final List<ExprContext> exprList) {
955         if (null == exprList) {
956             return Collections.emptyList();
957         }
958         Collection<ExpressionSegment> result = new ArrayList<>(exprList.size());
959         for (ExprContext each : exprList) {
960             result.add((ExpressionSegment) visit(each));
961         }
962         return result;
963     }
964     
965     private String getDistinctExpression(final AggregationFunctionContext ctx) {
966         StringBuilder result = new StringBuilder();
967         for (int i = 3; i < ctx.getChildCount() - 1; i++) {
968             result.append(ctx.getChild(i).getText());
969         }
970         return result.toString();
971     }
972     
973     @Override
974     public final ASTNode visitSpecialFunction(final SpecialFunctionContext ctx) {
975         if (null != ctx.groupConcatFunction()) {
976             return visit(ctx.groupConcatFunction());
977         }
978         if (null != ctx.windowFunction()) {
979             return visit(ctx.windowFunction());
980         }
981         if (null != ctx.castFunction()) {
982             return visit(ctx.castFunction());
983         }
984         if (null != ctx.convertFunction()) {
985             return visit(ctx.convertFunction());
986         }
987         if (null != ctx.positionFunction()) {
988             return visit(ctx.positionFunction());
989         }
990         if (null != ctx.substringFunction()) {
991             return visit(ctx.substringFunction());
992         }
993         if (null != ctx.extractFunction()) {
994             return visit(ctx.extractFunction());
995         }
996         if (null != ctx.charFunction()) {
997             return visit(ctx.charFunction());
998         }
999         if (null != ctx.trimFunction()) {
1000             return visit(ctx.trimFunction());
1001         }
1002         if (null != ctx.weightStringFunction()) {
1003             return visit(ctx.weightStringFunction());
1004         }
1005         if (null != ctx.valuesFunction()) {
1006             return visit(ctx.valuesFunction());
1007         }
1008         if (null != ctx.currentUserFunction()) {
1009             return visit(ctx.currentUserFunction());
1010         }
1011         if (null != ctx.timeStampDiffFunction()) {
1012             return visit(ctx.timeStampDiffFunction());
1013         }
1014         return new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), getOriginalText(ctx), getOriginalText(ctx));
1015     }
1016     
1017     @Override
1018     public final ASTNode visitGroupConcatFunction(final GroupConcatFunctionContext ctx) {
1019         calculateParameterCount(ctx.expr());
1020         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.GROUP_CONCAT().getText(), getOriginalText(ctx));
1021         for (ExprContext each : ctx.expr()) {
1022             result.getParameters().add((ExpressionSegment) visit(each));
1023         }
1024         return result;
1025     }
1026     
1027     @Override
1028     public final ASTNode visitCastFunction(final CastFunctionContext ctx) {
1029         calculateParameterCount(ctx.expr());
1030         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.CAST().getText(), getOriginalText(ctx));
1031         for (ExprContext each : ctx.expr()) {
1032             ASTNode expr = visit(each);
1033             if (expr instanceof ColumnSegment) {
1034                 result.getParameters().add((ColumnSegment) expr);
1035             } else if (expr instanceof LiteralExpressionSegment) {
1036                 result.getParameters().add((LiteralExpressionSegment) expr);
1037             }
1038         }
1039         if (null != ctx.castType()) {
1040             result.getParameters().add((DataTypeSegment) visit(ctx.castType()));
1041         }
1042         if (null != ctx.DATETIME()) {
1043             DataTypeSegment dataType = new DataTypeSegment();
1044             dataType.setDataTypeName(ctx.DATETIME().getText());
1045             dataType.setStartIndex(ctx.DATETIME().getSymbol().getStartIndex());
1046             dataType.setStopIndex(ctx.DATETIME().getSymbol().getStopIndex());
1047             if (null != ctx.typeDatetimePrecision()) {
1048                 dataType.setDataLength((DataTypeLengthSegment) visit(ctx.typeDatetimePrecision()));
1049             }
1050             result.getParameters().add(dataType);
1051         }
1052         return result;
1053     }
1054     
1055     @Override
1056     public ASTNode visitCastType(final CastTypeContext ctx) {
1057         DataTypeSegment result = new DataTypeSegment();
1058         result.setDataTypeName(ctx.castTypeName.getText());
1059         result.setStartIndex(ctx.start.getStartIndex());
1060         result.setStopIndex(ctx.stop.getStopIndex());
1061         if (null != ctx.fieldLength()) {
1062             DataTypeLengthSegment dataTypeLengthSegment = (DataTypeLengthSegment) visit(ctx.fieldLength());
1063             result.setDataLength(dataTypeLengthSegment);
1064         }
1065         if (null != ctx.precision()) {
1066             DataTypeLengthSegment dataTypeLengthSegment = (DataTypeLengthSegment) visit(ctx.precision());
1067             result.setDataLength(dataTypeLengthSegment);
1068         }
1069         return result;
1070     }
1071     
1072     @Override
1073     public final ASTNode visitConvertFunction(final ConvertFunctionContext ctx) {
1074         calculateParameterCount(Collections.singleton(ctx.expr()));
1075         return new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.CONVERT().getText(), getOriginalText(ctx));
1076     }
1077     
1078     @Override
1079     public final ASTNode visitPositionFunction(final PositionFunctionContext ctx) {
1080         calculateParameterCount(ctx.expr());
1081         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.POSITION().getText(), getOriginalText(ctx));
1082         result.getParameters().add((ExpressionSegment) visit(ctx.expr(0)));
1083         result.getParameters().add((ExpressionSegment) visit(ctx.expr(1)));
1084         return result;
1085     }
1086     
1087     @Override
1088     public final ASTNode visitSubstringFunction(final SubstringFunctionContext ctx) {
1089         FunctionSegment result = new FunctionSegment(
1090                 ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), null == ctx.SUBSTR() ? ctx.SUBSTRING().getText() : ctx.SUBSTR().getText(), getOriginalText(ctx));
1091         result.getParameters().add((ExpressionSegment) visit(ctx.expr()));
1092         for (TerminalNode each : ctx.NUMBER_()) {
1093             result.getParameters().add(new LiteralExpressionSegment(each.getSymbol().getStartIndex(), each.getSymbol().getStopIndex(), new NumberLiteralValue(each.getText()).getValue()));
1094         }
1095         return result;
1096     }
1097     
1098     @Override
1099     public final ASTNode visitExtractFunction(final ExtractFunctionContext ctx) {
1100         calculateParameterCount(Collections.singleton(ctx.expr()));
1101         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.EXTRACT().getText(), getOriginalText(ctx));
1102         result.getParameters().add(new LiteralExpressionSegment(ctx.intervalUnit().getStart().getStartIndex(), ctx.intervalUnit().getStop().getStopIndex(), ctx.intervalUnit().getText()));
1103         result.getParameters().add((ExpressionSegment) visit(ctx.expr()));
1104         return result;
1105     }
1106     
1107     @Override
1108     public final ASTNode visitCharFunction(final CharFunctionContext ctx) {
1109         calculateParameterCount(ctx.expr());
1110         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.CHAR().getText(), getOriginalText(ctx));
1111         for (ExprContext each : ctx.expr()) {
1112             ASTNode expr = visit(each);
1113             result.getParameters().add((ExpressionSegment) expr);
1114         }
1115         return result;
1116     }
1117     
1118     @Override
1119     public final ASTNode visitTrimFunction(final TrimFunctionContext ctx) {
1120         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.TRIM().getText(), getOriginalText(ctx));
1121         if (null != ctx.BOTH()) {
1122             result.getParameters().add(new LiteralExpressionSegment(ctx.BOTH().getSymbol().getStartIndex(), ctx.BOTH().getSymbol().getStopIndex(),
1123                     new OtherLiteralValue(ctx.BOTH().getSymbol().getText()).getValue()));
1124         }
1125         if (null != ctx.TRAILING()) {
1126             result.getParameters().add(new LiteralExpressionSegment(ctx.TRAILING().getSymbol().getStartIndex(), ctx.TRAILING().getSymbol().getStopIndex(),
1127                     new OtherLiteralValue(ctx.TRAILING().getSymbol().getText()).getValue()));
1128         }
1129         if (null != ctx.LEADING()) {
1130             result.getParameters().add(new LiteralExpressionSegment(ctx.LEADING().getSymbol().getStartIndex(), ctx.LEADING().getSymbol().getStopIndex(),
1131                     new OtherLiteralValue(ctx.LEADING().getSymbol().getText()).getValue()));
1132         }
1133         for (ExprContext each : ctx.expr()) {
1134             result.getParameters().add((ExpressionSegment) visit(each));
1135         }
1136         return result;
1137     }
1138     
1139     @Override
1140     public final ASTNode visitWeightStringFunction(final WeightStringFunctionContext ctx) {
1141         calculateParameterCount(Collections.singleton(ctx.expr()));
1142         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.WEIGHT_STRING().getText(), getOriginalText(ctx));
1143         result.getParameters().add((ExpressionSegment) visit(ctx.expr()));
1144         return result;
1145     }
1146     
1147     @Override
1148     public final ASTNode visitValuesFunction(final ValuesFunctionContext ctx) {
1149         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.VALUES().getText(), getOriginalText(ctx));
1150         if (!ctx.columnRefList().columnRef().isEmpty()) {
1151             ColumnSegment columnSegment = (ColumnSegment) visit(ctx.columnRefList().columnRef(0));
1152             result.getParameters().add(columnSegment);
1153         }
1154         return result;
1155     }
1156     
1157     @Override
1158     public final ASTNode visitCurrentUserFunction(final CurrentUserFunctionContext ctx) {
1159         return new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.CURRENT_USER().getText(), getOriginalText(ctx));
1160     }
1161     
1162     @Override
1163     public ASTNode visitTimeStampDiffFunction(final TimeStampDiffFunctionContext ctx) {
1164         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.TIMESTAMPDIFF().getText(), getOriginalText(ctx));
1165         result.getParameters().addAll(getExpressions(ctx.expr()));
1166         return result;
1167     }
1168     
1169     @Override
1170     public final ASTNode visitRegularFunction(final RegularFunctionContext ctx) {
1171         return null == ctx.completeRegularFunction() ? visit(ctx.shorthandRegularFunction()) : visit(ctx.completeRegularFunction());
1172     }
1173     
1174     @Override
1175     public ASTNode visitCompleteRegularFunction(final CompleteRegularFunctionContext ctx) {
1176         FunctionSegment result = new FunctionSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.regularFunctionName().getText(), getOriginalText(ctx));
1177         Collection<ExpressionSegment> expressionSegments = ctx.expr().stream().map(each -> (ExpressionSegment) visit(each)).collect(Collectors.toList());
1178         result.getParameters().addAll(expressionSegments);
1179         return result;
1180     }
1181     
1182     @Override
1183     public ASTNode visitShorthandRegularFunction(final ShorthandRegularFunctionContext ctx) {
1184         String text = getOriginalText(ctx);
1185         FunctionSegment result;
1186         if (null != ctx.CURRENT_TIME()) {
1187             result = new FunctionSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.CURRENT_TIME().getText(), text);
1188             if (null != ctx.NUMBER_()) {
1189                 result.getParameters().add(new LiteralExpressionSegment(ctx.NUMBER_().getSymbol().getStartIndex(), ctx.NUMBER_().getSymbol().getStopIndex(),
1190                         new NumberLiteralValue(ctx.NUMBER_().getText())));
1191             }
1192         } else {
1193             result = new FunctionSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.getText(), text);
1194         }
1195         return result;
1196     }
1197     
1198     private ASTNode visitRemainSimpleExpr(final SimpleExprContext ctx) {
1199         if (null != ctx.caseExpression()) {
1200             return visit(ctx.caseExpression());
1201         }
1202         if (null != ctx.BINARY()) {
1203             return visit(ctx.simpleExpr(0));
1204         }
1205         if (null != ctx.TILDE_()) {
1206             return new UnaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.simpleExpr(0)), "~", ctx.getText());
1207         }
1208         if (null != ctx.variable()) {
1209             return visit(ctx.variable());
1210         }
1211         if (null != ctx.LP_()) {
1212             RowExpression result = new RowExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.getText());
1213             for (ExprContext each : ctx.expr()) {
1214                 result.getItems().add((ExpressionSegment) visit(each));
1215             }
1216             return result;
1217         }
1218         if (null != ctx.RETURNING()) {
1219             ListExpression result = new ListExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex());
1220             result.getItems().add(new LiteralExpressionSegment(ctx.path().start.getStartIndex(), ctx.path().stop.getStopIndex(), ctx.path().getText()));
1221             result.getItems().add(new LiteralExpressionSegment(ctx.RETURNING().getSymbol().getStartIndex(), ctx.RETURNING().getSymbol().getStopIndex(), ctx.RETURNING().getSymbol().getText()));
1222             result.getItems().add((ExpressionSegment) visit(ctx.dataType()));
1223             return result;
1224         }
1225         if (null != ctx.LBE_()) {
1226             return visit(ctx.expr(0));
1227         }
1228         for (ExprContext each : ctx.expr()) {
1229             visit(each);
1230         }
1231         for (SimpleExprContext each : ctx.simpleExpr()) {
1232             visit(each);
1233         }
1234         String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
1235         return new CommonExpressionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), text);
1236     }
1237     
1238     @Override
1239     public ASTNode visitCaseExpression(final CaseExpressionContext ctx) {
1240         Collection<ExpressionSegment> whenExprs = new LinkedList<>();
1241         Collection<ExpressionSegment> thenExprs = new LinkedList<>();
1242         for (CaseWhenContext each : ctx.caseWhen()) {
1243             whenExprs.add((ExpressionSegment) visit(each.expr(0)));
1244             thenExprs.add((ExpressionSegment) visit(each.expr(1)));
1245         }
1246         ExpressionSegment caseExpr = null == ctx.expr() ? null : (ExpressionSegment) visit(ctx.expr());
1247         ExpressionSegment elseExpr = null == ctx.caseElse() ? null : (ExpressionSegment) visit(ctx.caseElse().expr());
1248         return new CaseWhenExpression(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), caseExpr, whenExprs, thenExprs, elseExpr);
1249     }
1250     
1251     @Override
1252     public ASTNode visitVariable(final VariableContext ctx) {
1253         return null == ctx.systemVariable() ? visit(ctx.userVariable()) : visit(ctx.systemVariable());
1254     }
1255     
1256     @Override
1257     public ASTNode visitUserVariable(final UserVariableContext ctx) {
1258         return new VariableSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.textOrIdentifier().getText());
1259     }
1260     
1261     @Override
1262     public ASTNode visitSystemVariable(final SystemVariableContext ctx) {
1263         VariableSegment result = new VariableSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.rvalueSystemVariable().getText());
1264         if (null != ctx.systemVariableScope) {
1265             result.setScope(ctx.systemVariableScope.getText());
1266         }
1267         return result;
1268     }
1269     
1270     @Override
1271     public final ASTNode visitMatchExpression(final MatchExpressionContext ctx) {
1272         ColumnSegment columnSegment = (ColumnSegment) visit(ctx.columnRefList().columnRef(0));
1273         ExpressionSegment expressionSegment = (ExpressionSegment) visit(ctx.expr());
1274         return new MatchAgainstExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), columnSegment, expressionSegment, getOriginalText(ctx.matchSearchModifier()), getOriginalText(ctx));
1275     }
1276     
1277     // TODO :FIXME, sql case id: insert_with_str_to_date
1278     private void calculateParameterCount(final Collection<ExprContext> exprContexts) {
1279         for (ExprContext each : exprContexts) {
1280             visit(each);
1281         }
1282     }
1283     
1284     @Override
1285     public final ASTNode visitDataType(final DataTypeContext ctx) {
1286         DataTypeSegment result = new DataTypeSegment();
1287         result.setDataTypeName(ctx.dataTypeName.getText());
1288         result.setStartIndex(ctx.start.getStartIndex());
1289         result.setStopIndex(ctx.stop.getStopIndex());
1290         if (null != ctx.fieldLength()) {
1291             DataTypeLengthSegment dataTypeLengthSegment = (DataTypeLengthSegment) visit(ctx.fieldLength());
1292             result.setDataLength(dataTypeLengthSegment);
1293         }
1294         if (null != ctx.precision()) {
1295             DataTypeLengthSegment dataTypeLengthSegment = (DataTypeLengthSegment) visit(ctx.precision());
1296             result.setDataLength(dataTypeLengthSegment);
1297         }
1298         return result;
1299     }
1300     
1301     @Override
1302     public ASTNode visitFieldLength(final FieldLengthContext ctx) {
1303         DataTypeLengthSegment result = new DataTypeLengthSegment();
1304         result.setStartIndex(ctx.start.getStartIndex());
1305         result.setStopIndex(ctx.stop.getStartIndex());
1306         result.setPrecision(new BigDecimal(ctx.length.getText()).intValue());
1307         return result;
1308     }
1309     
1310     @Override
1311     public ASTNode visitPrecision(final PrecisionContext ctx) {
1312         DataTypeLengthSegment result = new DataTypeLengthSegment();
1313         result.setStartIndex(ctx.start.getStartIndex());
1314         result.setStopIndex(ctx.stop.getStartIndex());
1315         List<TerminalNode> numbers = ctx.NUMBER_();
1316         result.setPrecision(Integer.parseInt(numbers.get(0).getText()));
1317         result.setScale(Integer.parseInt(numbers.get(1).getText()));
1318         return result;
1319     }
1320     
1321     @Override
1322     public ASTNode visitTypeDatetimePrecision(final TypeDatetimePrecisionContext ctx) {
1323         DataTypeLengthSegment result = new DataTypeLengthSegment();
1324         result.setStartIndex(ctx.start.getStartIndex());
1325         result.setStopIndex(ctx.stop.getStartIndex());
1326         result.setPrecision(Integer.parseInt(ctx.NUMBER_().getText()));
1327         return result;
1328     }
1329     
1330     @Override
1331     public final ASTNode visitOrderByClause(final OrderByClauseContext ctx) {
1332         Collection<OrderByItemSegment> items = new LinkedList<>();
1333         for (OrderByItemContext each : ctx.orderByItem()) {
1334             items.add((OrderByItemSegment) visit(each));
1335         }
1336         return new OrderBySegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), items);
1337     }
1338     
1339     @Override
1340     public final ASTNode visitOrderByItem(final OrderByItemContext ctx) {
1341         OrderDirection orderDirection;
1342         if (null != ctx.direction()) {
1343             orderDirection = null == ctx.direction().DESC() ? OrderDirection.ASC : OrderDirection.DESC;
1344         } else {
1345             orderDirection = OrderDirection.ASC;
1346         }
1347         if (null != ctx.numberLiterals()) {
1348             return new IndexOrderByItemSegment(ctx.numberLiterals().getStart().getStartIndex(), ctx.numberLiterals().getStop().getStopIndex(),
1349                     SQLUtils.getExactlyNumber(ctx.numberLiterals().getText(), 10).intValue(), orderDirection, null);
1350         } else {
1351             ASTNode expr = visitExpr(ctx.expr());
1352             if (expr instanceof ColumnSegment) {
1353                 return new ColumnOrderByItemSegment((ColumnSegment) expr, orderDirection, null);
1354             } else {
1355                 return new ExpressionOrderByItemSegment(ctx.expr().getStart().getStartIndex(),
1356                         ctx.expr().getStop().getStopIndex(), getOriginalText(ctx.expr()), orderDirection, null, (ExpressionSegment) expr);
1357             }
1358         }
1359     }
1360     
1361     @Override
1362     public ASTNode visitInsert(final InsertContext ctx) {
1363         // TODO :FIXME, since there is no segment for insertValuesClause, InsertStatement is created by sub rule.
1364         MySQLInsertStatement result;
1365         if (null != ctx.insertValuesClause()) {
1366             result = (MySQLInsertStatement) visit(ctx.insertValuesClause());
1367         } else if (null != ctx.insertSelectClause()) {
1368             result = (MySQLInsertStatement) visit(ctx.insertSelectClause());
1369         } else {
1370             result = new MySQLInsertStatement();
1371             result.setSetAssignment((SetAssignmentSegment) visit(ctx.setAssignmentsClause()));
1372         }
1373         if (null != ctx.onDuplicateKeyClause()) {
1374             result.setOnDuplicateKeyColumns((OnDuplicateKeyColumnsSegment) visit(ctx.onDuplicateKeyClause()));
1375         }
1376         result.setTable((SimpleTableSegment) visit(ctx.tableName()));
1377         result.addParameterMarkerSegments(getParameterMarkerSegments());
1378         return result;
1379     }
1380     
1381     @Override
1382     public ASTNode visitInsertSelectClause(final InsertSelectClauseContext ctx) {
1383         MySQLInsertStatement result = new MySQLInsertStatement();
1384         result.setInsertSelect(createInsertSelectSegment(ctx));
1385         if (null != ctx.LP_()) {
1386             if (null != ctx.fields()) {
1387                 result.setInsertColumns(new InsertColumnsSegment(ctx.LP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex(), createInsertColumns(ctx.fields())));
1388             } else {
1389                 result.setInsertColumns(new InsertColumnsSegment(ctx.LP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex(), Collections.emptyList()));
1390             }
1391         } else {
1392             result.setInsertColumns(new InsertColumnsSegment(ctx.start.getStartIndex() - 1, ctx.start.getStartIndex() - 1, Collections.emptyList()));
1393         }
1394         return result;
1395     }
1396     
1397     private SubquerySegment createInsertSelectSegment(final InsertSelectClauseContext ctx) {
1398         MySQLSelectStatement selectStatement = (MySQLSelectStatement) visit(ctx.select());
1399         selectStatement.getParameterMarkerSegments().addAll(getParameterMarkerSegments());
1400         return new SubquerySegment(ctx.select().start.getStartIndex(), ctx.select().stop.getStopIndex(), selectStatement, getOriginalText(ctx.select()));
1401     }
1402     
1403     @Override
1404     public ASTNode visitInsertValuesClause(final InsertValuesClauseContext ctx) {
1405         MySQLInsertStatement result = new MySQLInsertStatement();
1406         if (null != ctx.LP_()) {
1407             if (null != ctx.fields()) {
1408                 result.setInsertColumns(new InsertColumnsSegment(ctx.LP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex(), createInsertColumns(ctx.fields())));
1409             } else {
1410                 result.setInsertColumns(new InsertColumnsSegment(ctx.LP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex(), Collections.emptyList()));
1411             }
1412         } else {
1413             result.setInsertColumns(new InsertColumnsSegment(ctx.start.getStartIndex() - 1, ctx.start.getStartIndex() - 1, Collections.emptyList()));
1414         }
1415         result.getValues().addAll(createInsertValuesSegments(ctx.assignmentValues()));
1416         return result;
1417     }
1418     
1419     private Collection<InsertValuesSegment> createInsertValuesSegments(final Collection<AssignmentValuesContext> assignmentValuesContexts) {
1420         Collection<InsertValuesSegment> result = new LinkedList<>();
1421         for (AssignmentValuesContext each : assignmentValuesContexts) {
1422             result.add((InsertValuesSegment) visit(each));
1423         }
1424         return result;
1425     }
1426     
1427     @Override
1428     public ASTNode visitOnDuplicateKeyClause(final OnDuplicateKeyClauseContext ctx) {
1429         Collection<ColumnAssignmentSegment> columns = new LinkedList<>();
1430         for (AssignmentContext each : ctx.assignment()) {
1431             columns.add((ColumnAssignmentSegment) visit(each));
1432         }
1433         return new OnDuplicateKeyColumnsSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), columns);
1434     }
1435     
1436     @Override
1437     public ASTNode visitReplace(final ReplaceContext ctx) {
1438         // TODO :FIXME, since there is no segment for replaceValuesClause, ReplaceStatement is created by sub rule.
1439         MySQLInsertStatement result;
1440         if (null != ctx.replaceValuesClause()) {
1441             result = (MySQLInsertStatement) visit(ctx.replaceValuesClause());
1442         } else if (null != ctx.replaceSelectClause()) {
1443             result = (MySQLInsertStatement) visit(ctx.replaceSelectClause());
1444         } else {
1445             result = new MySQLInsertStatement();
1446             result.setSetAssignment((SetAssignmentSegment) visit(ctx.setAssignmentsClause()));
1447         }
1448         result.setTable((SimpleTableSegment) visit(ctx.tableName()));
1449         result.addParameterMarkerSegments(getParameterMarkerSegments());
1450         return result;
1451     }
1452     
1453     @Override
1454     public ASTNode visitReplaceSelectClause(final ReplaceSelectClauseContext ctx) {
1455         MySQLInsertStatement result = new MySQLInsertStatement();
1456         if (null != ctx.LP_()) {
1457             if (null != ctx.fields()) {
1458                 result.setInsertColumns(new InsertColumnsSegment(ctx.LP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex(), createInsertColumns(ctx.fields())));
1459             } else {
1460                 result.setInsertColumns(new InsertColumnsSegment(ctx.LP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex(), Collections.emptyList()));
1461             }
1462         } else {
1463             result.setInsertColumns(new InsertColumnsSegment(ctx.start.getStartIndex() - 1, ctx.start.getStartIndex() - 1, Collections.emptyList()));
1464         }
1465         result.setInsertSelect(createReplaceSelectSegment(ctx));
1466         return result;
1467     }
1468     
1469     private SubquerySegment createReplaceSelectSegment(final ReplaceSelectClauseContext ctx) {
1470         MySQLSelectStatement selectStatement = (MySQLSelectStatement) visit(ctx.select());
1471         return new SubquerySegment(ctx.select().start.getStartIndex(), ctx.select().stop.getStopIndex(), selectStatement, getOriginalText(ctx.select()));
1472     }
1473     
1474     @Override
1475     public ASTNode visitReplaceValuesClause(final ReplaceValuesClauseContext ctx) {
1476         MySQLInsertStatement result = new MySQLInsertStatement();
1477         if (null != ctx.LP_()) {
1478             if (null != ctx.fields()) {
1479                 result.setInsertColumns(new InsertColumnsSegment(ctx.LP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex(), createInsertColumns(ctx.fields())));
1480             } else {
1481                 result.setInsertColumns(new InsertColumnsSegment(ctx.LP_().getSymbol().getStartIndex(), ctx.RP_().getSymbol().getStopIndex(), Collections.emptyList()));
1482             }
1483         } else {
1484             result.setInsertColumns(new InsertColumnsSegment(ctx.start.getStartIndex() - 1, ctx.start.getStartIndex() - 1, Collections.emptyList()));
1485         }
1486         result.getValues().addAll(createInsertValuesSegments(ctx.assignmentValues()));
1487         return result;
1488     }
1489     
1490     private List<ColumnSegment> createInsertColumns(final FieldsContext fields) {
1491         List<ColumnSegment> result = new LinkedList<>();
1492         for (InsertIdentifierContext each : fields.insertIdentifier()) {
1493             result.add((ColumnSegment) visit(each));
1494         }
1495         return result;
1496     }
1497     
1498     @Override
1499     public ASTNode visitUpdate(final UpdateContext ctx) {
1500         MySQLUpdateStatement result = new MySQLUpdateStatement();
1501         TableSegment tableSegment = (TableSegment) visit(ctx.tableReferences());
1502         result.setTable(tableSegment);
1503         result.setSetAssignment((SetAssignmentSegment) visit(ctx.setAssignmentsClause()));
1504         if (null != ctx.whereClause()) {
1505             result.setWhere((WhereSegment) visit(ctx.whereClause()));
1506         }
1507         if (null != ctx.orderByClause()) {
1508             result.setOrderBy((OrderBySegment) visit(ctx.orderByClause()));
1509         }
1510         if (null != ctx.limitClause()) {
1511             result.setLimit((LimitSegment) visit(ctx.limitClause()));
1512         }
1513         result.addParameterMarkerSegments(getParameterMarkerSegments());
1514         return result;
1515     }
1516     
1517     @Override
1518     public ASTNode visitSetAssignmentsClause(final SetAssignmentsClauseContext ctx) {
1519         Collection<ColumnAssignmentSegment> assignments = new LinkedList<>();
1520         for (AssignmentContext each : ctx.assignment()) {
1521             assignments.add((ColumnAssignmentSegment) visit(each));
1522         }
1523         return new SetAssignmentSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), assignments);
1524     }
1525     
1526     @Override
1527     public ASTNode visitAssignmentValues(final AssignmentValuesContext ctx) {
1528         List<ExpressionSegment> segments = new LinkedList<>();
1529         for (AssignmentValueContext each : ctx.assignmentValue()) {
1530             segments.add((ExpressionSegment) visit(each));
1531         }
1532         return new InsertValuesSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), segments);
1533     }
1534     
1535     @Override
1536     public ASTNode visitAssignment(final AssignmentContext ctx) {
1537         ColumnSegment column = (ColumnSegment) visit(ctx.columnRef());
1538         ExpressionSegment value = (ExpressionSegment) visit(ctx.assignmentValue());
1539         List<ColumnSegment> columnSegments = new LinkedList<>();
1540         columnSegments.add(column);
1541         return new ColumnAssignmentSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), columnSegments, value);
1542     }
1543     
1544     @Override
1545     public ASTNode visitAssignmentValue(final AssignmentValueContext ctx) {
1546         ExprContext expr = ctx.expr();
1547         if (null != expr) {
1548             ASTNode result = visit(expr);
1549             if (result instanceof ColumnSegment) {
1550                 return new CommonExpressionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.getText());
1551             } else {
1552                 return result;
1553             }
1554         }
1555         return new CommonExpressionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.getText());
1556     }
1557     
1558     @Override
1559     public ASTNode visitBlobValue(final BlobValueContext ctx) {
1560         return new StringLiteralValue(ctx.string_().getText());
1561     }
1562     
1563     @Override
1564     public ASTNode visitDelete(final DeleteContext ctx) {
1565         MySQLDeleteStatement result = new MySQLDeleteStatement();
1566         if (null != ctx.multipleTablesClause()) {
1567             result.setTable((TableSegment) visit(ctx.multipleTablesClause()));
1568         } else {
1569             result.setTable((TableSegment) visit(ctx.singleTableClause()));
1570         }
1571         if (null != ctx.whereClause()) {
1572             result.setWhere((WhereSegment) visit(ctx.whereClause()));
1573         }
1574         if (null != ctx.orderByClause()) {
1575             result.setOrderBy((OrderBySegment) visit(ctx.orderByClause()));
1576         }
1577         if (null != ctx.limitClause()) {
1578             result.setLimit((LimitSegment) visit(ctx.limitClause()));
1579         }
1580         result.addParameterMarkerSegments(getParameterMarkerSegments());
1581         return result;
1582     }
1583     
1584     @Override
1585     public ASTNode visitSingleTableClause(final SingleTableClauseContext ctx) {
1586         SimpleTableSegment result = (SimpleTableSegment) visit(ctx.tableName());
1587         if (null != ctx.alias()) {
1588             result.setAlias((AliasSegment) visit(ctx.alias()));
1589         }
1590         return result;
1591     }
1592     
1593     @Override
1594     public ASTNode visitMultipleTablesClause(final MultipleTablesClauseContext ctx) {
1595         DeleteMultiTableSegment result = new DeleteMultiTableSegment();
1596         TableSegment relateTableSource = (TableSegment) visit(ctx.tableReferences());
1597         result.setRelationTable(relateTableSource);
1598         result.setActualDeleteTables(generateTablesFromTableAliasRefList(ctx.tableAliasRefList()));
1599         return result;
1600     }
1601     
1602     private List<SimpleTableSegment> generateTablesFromTableAliasRefList(final TableAliasRefListContext ctx) {
1603         List<SimpleTableSegment> result = new LinkedList<>();
1604         for (TableIdentOptWildContext each : ctx.tableIdentOptWild()) {
1605             result.add((SimpleTableSegment) visit(each.tableName()));
1606         }
1607         return result;
1608     }
1609     
1610     @Override
1611     public ASTNode visitSelect(final SelectContext ctx) {
1612         MySQLSelectStatement result;
1613         if (null != ctx.queryExpression()) {
1614             result = (MySQLSelectStatement) visit(ctx.queryExpression());
1615             if (null != ctx.lockClauseList()) {
1616                 result.setLock((LockSegment) visit(ctx.lockClauseList()));
1617             }
1618         } else if (null != ctx.selectWithInto()) {
1619             result = (MySQLSelectStatement) visit(ctx.selectWithInto());
1620         } else {
1621             result = (MySQLSelectStatement) visit(ctx.getChild(0));
1622         }
1623         result.addParameterMarkerSegments(getParameterMarkerSegments());
1624         return result;
1625     }
1626     
1627     private boolean isDistinct(final QuerySpecificationContext ctx) {
1628         for (SelectSpecificationContext each : ctx.selectSpecification()) {
1629             if (((BooleanLiteralValue) visit(each)).getValue()) {
1630                 return true;
1631             }
1632         }
1633         return false;
1634     }
1635     
1636     @Override
1637     public ASTNode visitSelectSpecification(final SelectSpecificationContext ctx) {
1638         if (null != ctx.duplicateSpecification()) {
1639             return visit(ctx.duplicateSpecification());
1640         }
1641         return new BooleanLiteralValue(false);
1642     }
1643     
1644     @Override
1645     public ASTNode visitDuplicateSpecification(final DuplicateSpecificationContext ctx) {
1646         String text = ctx.getText();
1647         if ("DISTINCT".equalsIgnoreCase(text) || "DISTINCTROW".equalsIgnoreCase(text)) {
1648             return new BooleanLiteralValue(true);
1649         }
1650         return new BooleanLiteralValue(false);
1651     }
1652     
1653     @Override
1654     public ASTNode visitProjections(final ProjectionsContext ctx) {
1655         Collection<ProjectionSegment> projections = new LinkedList<>();
1656         if (null != ctx.unqualifiedShorthand()) {
1657             projections.add(new ShorthandProjectionSegment(ctx.unqualifiedShorthand().getStart().getStartIndex(), ctx.unqualifiedShorthand().getStop().getStopIndex()));
1658         }
1659         for (ProjectionContext each : ctx.projection()) {
1660             projections.add((ProjectionSegment) visit(each));
1661         }
1662         ProjectionsSegment result = new ProjectionsSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex());
1663         result.getProjections().addAll(projections);
1664         return result;
1665     }
1666     
1667     @Override
1668     public ASTNode visitProjection(final ProjectionContext ctx) {
1669         // FIXME :The stop index of project is the stop index of projection, instead of alias.
1670         if (null != ctx.qualifiedShorthand()) {
1671             return createShorthandProjection(ctx.qualifiedShorthand());
1672         }
1673         AliasSegment alias = null == ctx.alias() ? null : (AliasSegment) visit(ctx.alias());
1674         ExpressionSegment exprProjection = (ExpressionSegment) visit(ctx.expr());
1675         if (exprProjection instanceof ColumnSegment) {
1676             ColumnProjectionSegment result = new ColumnProjectionSegment((ColumnSegment) exprProjection);
1677             result.setAlias(alias);
1678             return result;
1679         }
1680         if (exprProjection instanceof SubquerySegment) {
1681             SubquerySegment subquerySegment = (SubquerySegment) exprProjection;
1682             String text = ctx.start.getInputStream().getText(new Interval(subquerySegment.getStartIndex(), subquerySegment.getStopIndex()));
1683             SubqueryProjectionSegment result = new SubqueryProjectionSegment((SubquerySegment) exprProjection, text);
1684             result.setAlias(alias);
1685             return result;
1686         }
1687         if (exprProjection instanceof ExistsSubqueryExpression) {
1688             ExistsSubqueryExpression existsSubqueryExpression = (ExistsSubqueryExpression) exprProjection;
1689             String text = ctx.start.getInputStream().getText(new Interval(existsSubqueryExpression.getStartIndex(), existsSubqueryExpression.getStopIndex()));
1690             SubqueryProjectionSegment result = new SubqueryProjectionSegment(((ExistsSubqueryExpression) exprProjection).getSubquery(), text);
1691             result.setAlias(alias);
1692             return result;
1693         }
1694         return createProjection(ctx, alias, exprProjection);
1695     }
1696     
1697     private ShorthandProjectionSegment createShorthandProjection(final QualifiedShorthandContext shorthand) {
1698         ShorthandProjectionSegment result = new ShorthandProjectionSegment(shorthand.getStart().getStartIndex(), shorthand.getStop().getStopIndex());
1699         IdentifierContext identifier = shorthand.identifier().get(shorthand.identifier().size() - 1);
1700         OwnerSegment owner = new OwnerSegment(identifier.getStart().getStartIndex(), identifier.getStop().getStopIndex(), new IdentifierValue(identifier.getText()));
1701         result.setOwner(owner);
1702         if (shorthand.identifier().size() > 1) {
1703             IdentifierContext schemaIdentifier = shorthand.identifier().get(0);
1704             owner.setOwner(new OwnerSegment(schemaIdentifier.getStart().getStartIndex(), schemaIdentifier.getStop().getStopIndex(), new IdentifierValue(schemaIdentifier.getText())));
1705         }
1706         return result;
1707     }
1708     
1709     @Override
1710     public ASTNode visitAlias(final AliasContext ctx) {
1711         return new AliasSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), new IdentifierValue(ctx.textOrIdentifier().getText()));
1712     }
1713     
1714     private ASTNode createProjection(final ProjectionContext ctx, final AliasSegment alias, final ExpressionSegment projection) {
1715         if (projection instanceof AggregationProjectionSegment) {
1716             ((AggregationProjectionSegment) projection).setAlias(alias);
1717             return projection;
1718         }
1719         if (projection instanceof ExpressionProjectionSegment) {
1720             ((ExpressionProjectionSegment) projection).setAlias(alias);
1721             return projection;
1722         }
1723         if (projection instanceof FunctionSegment) {
1724             FunctionSegment functionSegment = (FunctionSegment) projection;
1725             ExpressionProjectionSegment result = new ExpressionProjectionSegment(functionSegment.getStartIndex(), functionSegment.getStopIndex(), functionSegment.getText(), functionSegment);
1726             result.setAlias(alias);
1727             return result;
1728         }
1729         if (projection instanceof CommonExpressionSegment) {
1730             CommonExpressionSegment segment = (CommonExpressionSegment) projection;
1731             ExpressionProjectionSegment result = new ExpressionProjectionSegment(segment.getStartIndex(), segment.getStopIndex(), segment.getText(), segment);
1732             result.setAlias(alias);
1733             return result;
1734         }
1735         // FIXME :For DISTINCT()
1736         if (projection instanceof ColumnSegment) {
1737             ExpressionProjectionSegment result = new ExpressionProjectionSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), getOriginalText(ctx), projection);
1738             result.setAlias(alias);
1739             return result;
1740         }
1741         if (projection instanceof SubqueryExpressionSegment) {
1742             SubqueryExpressionSegment subqueryExpressionSegment = (SubqueryExpressionSegment) projection;
1743             String text = ctx.start.getInputStream().getText(new Interval(subqueryExpressionSegment.getStartIndex(), subqueryExpressionSegment.getStopIndex()));
1744             SubqueryProjectionSegment result = new SubqueryProjectionSegment(subqueryExpressionSegment.getSubquery(), text);
1745             result.setAlias(alias);
1746             return result;
1747         }
1748         if (projection instanceof BinaryOperationExpression) {
1749             int startIndex = projection.getStartIndex();
1750             int stopIndex = null == alias ? projection.getStopIndex() : alias.getStopIndex();
1751             ExpressionProjectionSegment result = new ExpressionProjectionSegment(startIndex, stopIndex, projection.getText(), projection);
1752             result.setAlias(alias);
1753             return result;
1754         }
1755         if (projection instanceof ParameterMarkerExpressionSegment) {
1756             ParameterMarkerExpressionSegment result = (ParameterMarkerExpressionSegment) projection;
1757             result.setAlias(alias);
1758             return projection;
1759         }
1760         if (projection instanceof CaseWhenExpression || projection instanceof VariableSegment || projection instanceof BetweenExpression || projection instanceof InExpression
1761                 || projection instanceof CollateExpression || projection instanceof NotExpression) {
1762             return createExpressionProjectionSegment(ctx, alias, projection);
1763         }
1764         LiteralExpressionSegment column = (LiteralExpressionSegment) projection;
1765         ExpressionProjectionSegment result = null == alias
1766                 ? new ExpressionProjectionSegment(column.getStartIndex(), column.getStopIndex(), String.valueOf(column.getLiterals()), column)
1767                 : new ExpressionProjectionSegment(column.getStartIndex(), ctx.alias().stop.getStopIndex(), String.valueOf(column.getLiterals()), column);
1768         result.setAlias(alias);
1769         return result;
1770     }
1771     
1772     private ExpressionProjectionSegment createExpressionProjectionSegment(final ProjectionContext ctx, final AliasSegment alias, final ExpressionSegment projection) {
1773         ExpressionProjectionSegment result = new ExpressionProjectionSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), getOriginalText(ctx.expr()), projection);
1774         result.setAlias(alias);
1775         return result;
1776     }
1777     
1778     @Override
1779     public ASTNode visitFromClause(final FromClauseContext ctx) {
1780         return visit(ctx.tableReferences());
1781     }
1782     
1783     @Override
1784     public ASTNode visitTableReferences(final TableReferencesContext ctx) {
1785         TableSegment result = (TableSegment) visit(ctx.tableReference(0));
1786         if (ctx.tableReference().size() > 1) {
1787             for (int i = 1; i < ctx.tableReference().size(); i++) {
1788                 result = generateJoinTableSourceFromEscapedTableReference(ctx.tableReference(i), result);
1789             }
1790         }
1791         return result;
1792     }
1793     
1794     private JoinTableSegment generateJoinTableSourceFromEscapedTableReference(final TableReferenceContext ctx, final TableSegment tableSegment) {
1795         JoinTableSegment result = new JoinTableSegment();
1796         result.setStartIndex(tableSegment.getStartIndex());
1797         result.setStopIndex(ctx.stop.getStopIndex());
1798         result.setLeft(tableSegment);
1799         result.setJoinType(JoinType.COMMA.name());
1800         result.setRight((TableSegment) visit(ctx));
1801         return result;
1802     }
1803     
1804     @Override
1805     public ASTNode visitEscapedTableReference(final EscapedTableReferenceContext ctx) {
1806         TableSegment result;
1807         TableSegment left;
1808         left = (TableSegment) visit(ctx.tableFactor());
1809         for (JoinedTableContext each : ctx.joinedTable()) {
1810             left = visitJoinedTable(each, left);
1811         }
1812         result = left;
1813         return result;
1814     }
1815     
1816     @Override
1817     public ASTNode visitTableReference(final TableReferenceContext ctx) {
1818         TableSegment result;
1819         TableSegment left;
1820         left = null == ctx.tableFactor() ? (TableSegment) visit(ctx.escapedTableReference()) : (TableSegment) visit(ctx.tableFactor());
1821         for (JoinedTableContext each : ctx.joinedTable()) {
1822             left = visitJoinedTable(each, left);
1823         }
1824         result = left;
1825         return result;
1826     }
1827     
1828     @Override
1829     public ASTNode visitTableFactor(final TableFactorContext ctx) {
1830         if (null != ctx.subquery()) {
1831             MySQLSelectStatement subquery = (MySQLSelectStatement) visit(ctx.subquery());
1832             SubquerySegment subquerySegment = new SubquerySegment(ctx.subquery().start.getStartIndex(), ctx.subquery().stop.getStopIndex(), subquery, getOriginalText(ctx.subquery()));
1833             SubqueryTableSegment result = new SubqueryTableSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), subquerySegment);
1834             if (null != ctx.alias()) {
1835                 result.setAlias((AliasSegment) visit(ctx.alias()));
1836             }
1837             return result;
1838         }
1839         if (null != ctx.tableName()) {
1840             SimpleTableSegment result = (SimpleTableSegment) visit(ctx.tableName());
1841             if (null != ctx.alias()) {
1842                 result.setAlias((AliasSegment) visit(ctx.alias()));
1843             }
1844             if (null != ctx.indexHintList()) {
1845                 ctx.indexHintList().indexHint().forEach(each -> result.getIndexHintSegments().add((IndexHintSegment) visit(each)));
1846             }
1847             return result;
1848         }
1849         return visit(ctx.tableReferences());
1850     }
1851     
1852     private JoinTableSegment visitJoinedTable(final JoinedTableContext ctx, final TableSegment tableSegment) {
1853         JoinTableSegment result = new JoinTableSegment();
1854         result.setLeft(tableSegment);
1855         result.setStartIndex(tableSegment.getStartIndex());
1856         result.setStopIndex(ctx.stop.getStopIndex());
1857         result.setJoinType(getJoinType(ctx));
1858         result.setNatural(null != ctx.naturalJoinType());
1859         TableSegment right = null == ctx.tableFactor() ? (TableSegment) visit(ctx.tableReference()) : (TableSegment) visit(ctx.tableFactor());
1860         result.setRight(right);
1861         return null == ctx.joinSpecification() ? result : visitJoinSpecification(ctx.joinSpecification(), result);
1862     }
1863     
1864     private String getJoinType(final JoinedTableContext ctx) {
1865         if (null != ctx.innerJoinType()) {
1866             return JoinType.INNER.name();
1867         }
1868         if (null != ctx.outerJoinType()) {
1869             return null == ctx.outerJoinType().LEFT() ? JoinType.RIGHT.name() : JoinType.LEFT.name();
1870         }
1871         if (null != ctx.naturalJoinType()) {
1872             return getNaturalJoinType(ctx.naturalJoinType());
1873         }
1874         return JoinType.COMMA.name();
1875     }
1876     
1877     private String getNaturalJoinType(final NaturalJoinTypeContext ctx) {
1878         if (null != ctx.LEFT()) {
1879             return JoinType.LEFT.name();
1880         }
1881         if (null != ctx.RIGHT()) {
1882             return JoinType.RIGHT.name();
1883         }
1884         return JoinType.INNER.name();
1885     }
1886     
1887     private JoinTableSegment visitJoinSpecification(final JoinSpecificationContext ctx, final JoinTableSegment result) {
1888         if (null != ctx.expr()) {
1889             ExpressionSegment condition = (ExpressionSegment) visit(ctx.expr());
1890             result.setCondition(condition);
1891         }
1892         if (null != ctx.USING()) {
1893             result.setUsing(ctx.columnNames().columnName().stream().map(each -> (ColumnSegment) visit(each)).collect(Collectors.toList()));
1894         }
1895         return result;
1896     }
1897     
1898     @Override
1899     public ASTNode visitWhereClause(final WhereClauseContext ctx) {
1900         ASTNode segment = visit(ctx.expr());
1901         return new WhereSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (ExpressionSegment) segment);
1902     }
1903     
1904     @Override
1905     public ASTNode visitGroupByClause(final GroupByClauseContext ctx) {
1906         Collection<OrderByItemSegment> items = new LinkedList<>();
1907         for (OrderByItemContext each : ctx.orderByItem()) {
1908             items.add((OrderByItemSegment) visit(each));
1909         }
1910         return new GroupBySegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), items);
1911     }
1912     
1913     @Override
1914     public ASTNode visitLimitClause(final LimitClauseContext ctx) {
1915         if (null == ctx.limitOffset()) {
1916             return new LimitSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), null, (PaginationValueSegment) visit(ctx.limitRowCount()));
1917         }
1918         PaginationValueSegment rowCount;
1919         PaginationValueSegment offset;
1920         if (null != ctx.OFFSET()) {
1921             rowCount = (PaginationValueSegment) visit(ctx.limitRowCount());
1922             offset = (PaginationValueSegment) visit(ctx.limitOffset());
1923         } else {
1924             offset = (PaginationValueSegment) visit(ctx.limitOffset());
1925             rowCount = (PaginationValueSegment) visit(ctx.limitRowCount());
1926         }
1927         return new LimitSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), offset, rowCount);
1928     }
1929     
1930     @Override
1931     public ASTNode visitLimitRowCount(final LimitRowCountContext ctx) {
1932         if (null != ctx.numberLiterals()) {
1933             return new NumberLiteralLimitValueSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ((NumberLiteralValue) visit(ctx.numberLiterals())).getValue().longValue());
1934         }
1935         ParameterMarkerSegment result = new ParameterMarkerLimitValueSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(),
1936                 ((ParameterMarkerValue) visit(ctx.parameterMarker())).getValue());
1937         parameterMarkerSegments.add(result);
1938         return result;
1939     }
1940     
1941     @Override
1942     public final ASTNode visitConstraintName(final ConstraintNameContext ctx) {
1943         return new ConstraintSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (IdentifierValue) visit(ctx.identifier()));
1944     }
1945     
1946     @Override
1947     public ASTNode visitLimitOffset(final LimitOffsetContext ctx) {
1948         if (null != ctx.numberLiterals()) {
1949             return new NumberLiteralLimitValueSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ((NumberLiteralValue) visit(ctx.numberLiterals())).getValue().longValue());
1950         }
1951         ParameterMarkerSegment result = new ParameterMarkerLimitValueSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(),
1952                 ((ParameterMarkerValue) visit(ctx.parameterMarker())).getValue());
1953         parameterMarkerSegments.add(result);
1954         return result;
1955     }
1956     
1957     @Override
1958     public ASTNode visitCollateClause(final CollateClauseContext ctx) {
1959         if (null != ctx.collationName()) {
1960             return new LiteralExpressionSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.collationName().textOrIdentifier().getText());
1961         }
1962         ParameterMarkerExpressionSegment segment = new ParameterMarkerExpressionSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(),
1963                 ((ParameterMarkerValue) visit(ctx.parameterMarker())).getValue());
1964         parameterMarkerSegments.add(segment);
1965         return segment;
1966     }
1967     
1968     @Override
1969     public ASTNode visitEngineRef(final EngineRefContext ctx) {
1970         return new EngineSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), SQLUtils.getExactlyValue(ctx.textOrIdentifier().getText()));
1971     }
1972     
1973     protected String getOriginalText(final ParserRuleContext ctx) {
1974         return ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
1975     }
1976 }