View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.sql.parser.sql92.visitor.statement.type;
19  
20  import org.antlr.v4.runtime.misc.Interval;
21  import org.apache.shardingsphere.sql.parser.api.ASTNode;
22  import org.apache.shardingsphere.sql.parser.api.visitor.statement.type.DMLStatementVisitor;
23  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.AliasContext;
24  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.AssignmentContext;
25  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.AssignmentValueContext;
26  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.AssignmentValuesContext;
27  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.ColumnNamesContext;
28  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.CombineClauseContext;
29  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.DeleteContext;
30  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.DuplicateSpecificationContext;
31  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.EscapedTableReferenceContext;
32  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.ExprContext;
33  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.FromClauseContext;
34  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.GroupByClauseContext;
35  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.HavingClauseContext;
36  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.InsertContext;
37  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.InsertValuesClauseContext;
38  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.JoinSpecificationContext;
39  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.JoinedTableContext;
40  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.OrderByItemContext;
41  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.ProjectionContext;
42  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.ProjectionsContext;
43  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.QualifiedShorthandContext;
44  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.SelectClauseContext;
45  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.SelectContext;
46  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.SelectSpecificationContext;
47  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.SetAssignmentsClauseContext;
48  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.SingleTableClauseContext;
49  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.SubqueryContext;
50  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.TableFactorContext;
51  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.TableReferenceContext;
52  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.TableReferencesContext;
53  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.UpdateContext;
54  import org.apache.shardingsphere.sql.parser.autogen.SQL92StatementParser.WhereClauseContext;
55  import org.apache.shardingsphere.sql.parser.sql92.visitor.statement.SQL92StatementVisitor;
56  import org.apache.shardingsphere.sql.parser.statement.core.enums.JoinType;
57  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.ColumnAssignmentSegment;
58  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.InsertValuesSegment;
59  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.SetAssignmentSegment;
60  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
61  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.InsertColumnsSegment;
62  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
63  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
64  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment;
65  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.complex.CommonExpressionSegment;
66  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
67  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment;
68  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
69  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationProjectionSegment;
70  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment;
71  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ExpressionProjectionSegment;
72  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionSegment;
73  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionsSegment;
74  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ShorthandProjectionSegment;
75  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.SubqueryProjectionSegment;
76  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.GroupBySegment;
77  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.OrderBySegment;
78  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.OrderByItemSegment;
79  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.HavingSegment;
80  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment;
81  import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.AliasSegment;
82  import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment;
83  import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.JoinTableSegment;
84  import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
85  import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SubqueryTableSegment;
86  import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableSegment;
87  import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.DeleteStatement;
88  import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.InsertStatement;
89  import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
90  import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.UpdateStatement;
91  import org.apache.shardingsphere.sql.parser.statement.core.value.collection.CollectionValue;
92  import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
93  import org.apache.shardingsphere.sql.parser.statement.core.value.literal.impl.BooleanLiteralValue;
94  
95  import java.util.Collection;
96  import java.util.Collections;
97  import java.util.LinkedList;
98  import java.util.List;
99  import java.util.stream.Collectors;
100 
101 /**
102  * DML statement visitor for SQL92.
103  */
104 public final class SQL92DMLStatementVisitor extends SQL92StatementVisitor implements DMLStatementVisitor {
105     
106     @Override
107     public ASTNode visitInsert(final InsertContext ctx) {
108         InsertStatement result = (InsertStatement) visit(ctx.insertValuesClause());
109         result.setTable((SimpleTableSegment) visit(ctx.tableName()));
110         result.addParameterMarkers(getParameterMarkerSegments());
111         return result;
112     }
113     
114     @SuppressWarnings("unchecked")
115     @Override
116     public ASTNode visitInsertValuesClause(final InsertValuesClauseContext ctx) {
117         InsertStatement result = new InsertStatement();
118         if (null != ctx.columnNames()) {
119             ColumnNamesContext columnNames = ctx.columnNames();
120             CollectionValue<ColumnSegment> columnSegments = (CollectionValue<ColumnSegment>) visit(columnNames);
121             result.setInsertColumns(new InsertColumnsSegment(columnNames.start.getStartIndex(), columnNames.stop.getStopIndex(), columnSegments.getValue()));
122         } else {
123             result.setInsertColumns(new InsertColumnsSegment(ctx.start.getStartIndex() - 1, ctx.start.getStartIndex() - 1, Collections.emptyList()));
124         }
125         result.getValues().addAll(createInsertValuesSegments(ctx.assignmentValues()));
126         return result;
127     }
128     
129     private Collection<InsertValuesSegment> createInsertValuesSegments(final Collection<AssignmentValuesContext> assignmentValuesContexts) {
130         Collection<InsertValuesSegment> result = new LinkedList<>();
131         for (AssignmentValuesContext each : assignmentValuesContexts) {
132             result.add((InsertValuesSegment) visit(each));
133         }
134         return result;
135     }
136     
137     @Override
138     public ASTNode visitUpdate(final UpdateContext ctx) {
139         UpdateStatement result = new UpdateStatement();
140         result.setTable((TableSegment) visit(ctx.tableReferences()));
141         result.setSetAssignment((SetAssignmentSegment) visit(ctx.setAssignmentsClause()));
142         if (null != ctx.whereClause()) {
143             result.setWhere((WhereSegment) visit(ctx.whereClause()));
144         }
145         result.addParameterMarkers(getParameterMarkerSegments());
146         return result;
147     }
148     
149     @Override
150     public ASTNode visitSetAssignmentsClause(final SetAssignmentsClauseContext ctx) {
151         Collection<ColumnAssignmentSegment> assignments = new LinkedList<>();
152         for (AssignmentContext each : ctx.assignment()) {
153             assignments.add((ColumnAssignmentSegment) visit(each));
154         }
155         return new SetAssignmentSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), assignments);
156     }
157     
158     @Override
159     public ASTNode visitAssignmentValues(final AssignmentValuesContext ctx) {
160         List<ExpressionSegment> segments = new LinkedList<>();
161         for (AssignmentValueContext each : ctx.assignmentValue()) {
162             segments.add((ExpressionSegment) visit(each));
163         }
164         return new InsertValuesSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), segments);
165     }
166     
167     @Override
168     public ASTNode visitAssignment(final AssignmentContext ctx) {
169         ColumnSegment column = (ColumnSegment) visitColumnName(ctx.columnName());
170         List<ColumnSegment> columnSegments = new LinkedList<>();
171         columnSegments.add(column);
172         ExpressionSegment value = (ExpressionSegment) visit(ctx.assignmentValue());
173         ColumnAssignmentSegment result = new ColumnAssignmentSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), columnSegments, value);
174         result.getColumns().add(column);
175         return result;
176     }
177     
178     @Override
179     public ASTNode visitAssignmentValue(final AssignmentValueContext ctx) {
180         ExprContext expr = ctx.expr();
181         if (null != expr) {
182             return visit(expr);
183         }
184         return new CommonExpressionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.getText());
185     }
186     
187     @Override
188     public ASTNode visitDelete(final DeleteContext ctx) {
189         DeleteStatement result = new DeleteStatement();
190         result.setTable((TableSegment) visit(ctx.singleTableClause()));
191         if (null != ctx.whereClause()) {
192             result.setWhere((WhereSegment) visit(ctx.whereClause()));
193         }
194         result.addParameterMarkers(getParameterMarkerSegments());
195         return result;
196     }
197     
198     @Override
199     public ASTNode visitSingleTableClause(final SingleTableClauseContext ctx) {
200         SimpleTableSegment result = (SimpleTableSegment) visit(ctx.tableName());
201         if (null != ctx.alias()) {
202             result.setAlias((AliasSegment) visit(ctx.alias()));
203         }
204         return result;
205     }
206     
207     @Override
208     public ASTNode visitSelect(final SelectContext ctx) {
209         // TODO :Unsupported for withClause.
210         SelectStatement result = (SelectStatement) visit(ctx.combineClause());
211         result.addParameterMarkers(getParameterMarkerSegments());
212         return result;
213     }
214     
215     @Override
216     public ASTNode visitCombineClause(final CombineClauseContext ctx) {
217         // TODO :Unsupported for union SQL.
218         return visit(ctx.selectClause(0));
219     }
220     
221     @Override
222     public ASTNode visitSelectClause(final SelectClauseContext ctx) {
223         SelectStatement result = new SelectStatement();
224         result.setProjections((ProjectionsSegment) visit(ctx.projections()));
225         if (!ctx.selectSpecification().isEmpty()) {
226             result.getProjections().setDistinctRow(isDistinct(ctx.selectSpecification().get(0)));
227         }
228         if (null != ctx.fromClause()) {
229             TableSegment tableSegment = (TableSegment) visit(ctx.fromClause());
230             result.setFrom(tableSegment);
231         }
232         if (null != ctx.whereClause()) {
233             result.setWhere((WhereSegment) visit(ctx.whereClause()));
234         }
235         if (null != ctx.groupByClause()) {
236             result.setGroupBy((GroupBySegment) visit(ctx.groupByClause()));
237         }
238         if (null != ctx.orderByClause()) {
239             result.setOrderBy((OrderBySegment) visit(ctx.orderByClause()));
240         }
241         if (null != ctx.havingClause()) {
242             result.setHaving((HavingSegment) visit(ctx.havingClause()));
243         }
244         return result;
245     }
246     
247     @Override
248     public ASTNode visitHavingClause(final HavingClauseContext ctx) {
249         ExpressionSegment expr = (ExpressionSegment) visit(ctx.expr());
250         return new HavingSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), expr);
251     }
252     
253     private boolean isDistinct(final SelectSpecificationContext ctx) {
254         return ((BooleanLiteralValue) visit(ctx.duplicateSpecification())).getValue();
255     }
256     
257     @Override
258     public ASTNode visitDuplicateSpecification(final DuplicateSpecificationContext ctx) {
259         return new BooleanLiteralValue(null != ctx.DISTINCT());
260     }
261     
262     @Override
263     public ASTNode visitProjections(final ProjectionsContext ctx) {
264         Collection<ProjectionSegment> projections = new LinkedList<>();
265         if (null != ctx.unqualifiedShorthand()) {
266             projections.add(new ShorthandProjectionSegment(ctx.unqualifiedShorthand().getStart().getStartIndex(), ctx.unqualifiedShorthand().getStop().getStopIndex()));
267         }
268         for (ProjectionContext each : ctx.projection()) {
269             projections.add((ProjectionSegment) visit(each));
270         }
271         ProjectionsSegment result = new ProjectionsSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex());
272         result.getProjections().addAll(projections);
273         return result;
274     }
275     
276     @Override
277     public ASTNode visitProjection(final ProjectionContext ctx) {
278         // FIXME :The stop index of project is the stop index of projection, instead of alias.
279         if (null != ctx.qualifiedShorthand()) {
280             QualifiedShorthandContext shorthand = ctx.qualifiedShorthand();
281             ShorthandProjectionSegment result = new ShorthandProjectionSegment(shorthand.getStart().getStartIndex(), shorthand.getStop().getStopIndex());
282             IdentifierValue identifier = new IdentifierValue(shorthand.identifier().getText());
283             result.setOwner(new OwnerSegment(shorthand.identifier().getStart().getStartIndex(), shorthand.identifier().getStop().getStopIndex(), identifier));
284             return result;
285         }
286         AliasSegment alias = null == ctx.alias() ? null : (AliasSegment) visit(ctx.alias());
287         if (null != ctx.columnName()) {
288             ColumnSegment column = (ColumnSegment) visit(ctx.columnName());
289             ColumnProjectionSegment result = new ColumnProjectionSegment(column);
290             result.setAlias(alias);
291             return result;
292         }
293         return createProjection(ctx, alias);
294     }
295     
296     @Override
297     public ASTNode visitAlias(final AliasContext ctx) {
298         return null == ctx.identifier()
299                 ? new AliasSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), new IdentifierValue(ctx.STRING_().getText()))
300                 : new AliasSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (IdentifierValue) visit(ctx.identifier()));
301     }
302     
303     private ASTNode createProjection(final ProjectionContext ctx, final AliasSegment alias) {
304         ASTNode projection = visit(ctx.expr());
305         if (projection instanceof AggregationProjectionSegment) {
306             ((AggregationProjectionSegment) projection).setAlias(alias);
307             return projection;
308         }
309         if (projection instanceof ExpressionProjectionSegment) {
310             ((ExpressionProjectionSegment) projection).setAlias(alias);
311             return projection;
312         }
313         if (projection instanceof FunctionSegment) {
314             FunctionSegment segment = (FunctionSegment) projection;
315             ExpressionProjectionSegment result = new ExpressionProjectionSegment(segment.getStartIndex(), segment.getStopIndex(), segment.getText(), segment);
316             result.setAlias(alias);
317             return result;
318         }
319         if (projection instanceof CommonExpressionSegment) {
320             CommonExpressionSegment segment = (CommonExpressionSegment) projection;
321             ExpressionProjectionSegment result = new ExpressionProjectionSegment(segment.getStartIndex(), segment.getStopIndex(), segment.getText(), segment);
322             result.setAlias(alias);
323             return result;
324         }
325         // FIXME :For DISTINCT()
326         if (projection instanceof ColumnSegment) {
327             ExpressionProjectionSegment result = new ExpressionProjectionSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), getOriginalText(ctx), (ColumnSegment) projection);
328             result.setAlias(alias);
329             return result;
330         }
331         if (projection instanceof SubqueryExpressionSegment) {
332             SubqueryExpressionSegment subqueryExpressionSegment = (SubqueryExpressionSegment) projection;
333             String text = ctx.start.getInputStream().getText(new Interval(subqueryExpressionSegment.getStartIndex(), subqueryExpressionSegment.getStopIndex()));
334             SubqueryProjectionSegment result = new SubqueryProjectionSegment(((SubqueryExpressionSegment) projection).getSubquery(), text);
335             result.setAlias(alias);
336             return result;
337         }
338         if (projection instanceof BinaryOperationExpression) {
339             BinaryOperationExpression binaryExpression = (BinaryOperationExpression) projection;
340             int startIndex = binaryExpression.getStartIndex();
341             int stopIndex = null == alias ? binaryExpression.getStopIndex() : alias.getStopIndex();
342             ExpressionProjectionSegment result = new ExpressionProjectionSegment(startIndex, stopIndex, binaryExpression.getText(), binaryExpression);
343             result.setAlias(alias);
344             return result;
345         }
346         if (projection instanceof ParameterMarkerExpressionSegment) {
347             ParameterMarkerExpressionSegment result = (ParameterMarkerExpressionSegment) projection;
348             result.setAlias(alias);
349             return projection;
350         }
351         ExpressionSegment column = (ExpressionSegment) projection;
352         ExpressionProjectionSegment result = null == alias ? new ExpressionProjectionSegment(column.getStartIndex(), column.getStopIndex(), String.valueOf(column.getText()), column)
353                 : new ExpressionProjectionSegment(column.getStartIndex(), ctx.alias().stop.getStopIndex(), String.valueOf(column.getText()), column);
354         result.setAlias(alias);
355         return result;
356     }
357     
358     @Override
359     public ASTNode visitFromClause(final FromClauseContext ctx) {
360         return visit(ctx.tableReferences());
361     }
362     
363     @Override
364     public ASTNode visitTableReferences(final TableReferencesContext ctx) {
365         TableSegment result = (TableSegment) visit(ctx.escapedTableReference(0));
366         if (ctx.escapedTableReference().size() > 1) {
367             for (int i = 1; i < ctx.escapedTableReference().size(); i++) {
368                 result = generateJoinTableSourceFromEscapedTableReference(ctx.escapedTableReference(i), result);
369             }
370         }
371         return result;
372     }
373     
374     private JoinTableSegment generateJoinTableSourceFromEscapedTableReference(final EscapedTableReferenceContext ctx, final TableSegment tableSegment) {
375         JoinTableSegment result = new JoinTableSegment();
376         result.setStartIndex(tableSegment.getStartIndex());
377         result.setStopIndex(ctx.stop.getStopIndex());
378         result.setLeft(tableSegment);
379         result.setRight((TableSegment) visit(ctx));
380         result.setJoinType(JoinType.COMMA.name());
381         return result;
382     }
383     
384     @Override
385     public ASTNode visitEscapedTableReference(final EscapedTableReferenceContext ctx) {
386         return visit(ctx.tableReference());
387     }
388     
389     @Override
390     public ASTNode visitTableReference(final TableReferenceContext ctx) {
391         TableSegment result;
392         TableSegment left;
393         left = (TableSegment) visit(ctx.tableFactor());
394         if (!ctx.joinedTable().isEmpty()) {
395             for (JoinedTableContext each : ctx.joinedTable()) {
396                 left = visitJoinedTable(each, left);
397             }
398         }
399         result = left;
400         return result;
401     }
402     
403     @Override
404     public ASTNode visitTableFactor(final TableFactorContext ctx) {
405         if (null != ctx.subquery()) {
406             SelectStatement subquery = (SelectStatement) visit(ctx.subquery());
407             SubquerySegment subquerySegment = new SubquerySegment(ctx.subquery().start.getStartIndex(), ctx.subquery().stop.getStopIndex(), subquery, getOriginalText(ctx.subquery()));
408             SubqueryTableSegment result = new SubqueryTableSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), subquerySegment);
409             if (null != ctx.alias()) {
410                 result.setAlias((AliasSegment) visit(ctx.alias()));
411             }
412             return result;
413         }
414         if (null != ctx.tableName()) {
415             SimpleTableSegment result = (SimpleTableSegment) visit(ctx.tableName());
416             if (null != ctx.alias()) {
417                 result.setAlias((AliasSegment) visit(ctx.alias()));
418             }
419             return result;
420         }
421         return visit(ctx.tableReferences());
422     }
423     
424     private JoinTableSegment visitJoinedTable(final JoinedTableContext ctx, final TableSegment tableSegment) {
425         JoinTableSegment result = new JoinTableSegment();
426         result.setLeft(tableSegment);
427         result.setStartIndex(tableSegment.getStartIndex());
428         result.setStopIndex(ctx.stop.getStopIndex());
429         TableSegment right = (TableSegment) visit(ctx.tableFactor());
430         result.setRight(right);
431         result.setJoinType(getJoinType(ctx));
432         if (null != ctx.joinSpecification()) {
433             visitJoinSpecification(ctx.joinSpecification(), result);
434         }
435         return result;
436     }
437     
438     private String getJoinType(final JoinedTableContext ctx) {
439         if (null != ctx.LEFT()) {
440             return JoinType.LEFT.name();
441         } else if (null != ctx.RIGHT()) {
442             return JoinType.RIGHT.name();
443         } else if (null != ctx.INNER()) {
444             return JoinType.INNER.name();
445         } else if (null != ctx.CROSS()) {
446             return JoinType.CROSS.name();
447         }
448         return JoinType.INNER.name();
449     }
450     
451     private void visitJoinSpecification(final JoinSpecificationContext ctx, final JoinTableSegment joinTableSource) {
452         if (null != ctx.expr()) {
453             ExpressionSegment condition = (ExpressionSegment) visit(ctx.expr());
454             joinTableSource.setCondition(condition);
455         }
456         if (null != ctx.USING()) {
457             joinTableSource.setUsing(ctx.columnNames().columnName().stream().map(each -> (ColumnSegment) visit(each)).collect(Collectors.toList()));
458         }
459     }
460     
461     @Override
462     public ASTNode visitWhereClause(final WhereClauseContext ctx) {
463         ExpressionSegment segment = (ExpressionSegment) visit(ctx.expr());
464         return new WhereSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), segment);
465     }
466     
467     @Override
468     public ASTNode visitGroupByClause(final GroupByClauseContext ctx) {
469         Collection<OrderByItemSegment> items = new LinkedList<>();
470         for (OrderByItemContext each : ctx.orderByItem()) {
471             items.add((OrderByItemSegment) visit(each));
472         }
473         return new GroupBySegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), items);
474     }
475     
476     @Override
477     public ASTNode visitSubquery(final SubqueryContext ctx) {
478         return visit(ctx.combineClause());
479     }
480 }