├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── antlr4 │ └── io │ │ └── github │ │ └── melin │ │ └── sqlflow │ │ └── parser │ │ └── antlr4 │ │ ├── SqlFlowLexer.g4 │ │ └── SqlFlowParser.g4 └── java │ └── io │ └── github │ └── melin │ └── sqlflow │ ├── AstVisitor.java │ ├── DefaultExpressionTraversalVisitor.java │ ├── DefaultTraversalVisitor.java │ ├── SqlFlowException.java │ ├── analyzer │ ├── Analysis.java │ ├── Analyzer.java │ ├── CanonicalizationAware.java │ ├── CorrelationSupport.java │ ├── ExpressionAnalysis.java │ ├── ExpressionAnalyzer.java │ ├── ExpressionTreeUtils.java │ ├── Field.java │ ├── FieldId.java │ ├── Output.java │ ├── OutputColumn.java │ ├── PatternRecognitionAnalyzer.java │ ├── QueryType.java │ ├── RelationId.java │ ├── RelationType.java │ ├── ResolvedField.java │ ├── Scope.java │ ├── ScopeReferenceExtractor.java │ ├── SemanticExceptions.java │ └── StatementAnalyzer.java │ ├── function │ ├── InvocationConvention.java │ ├── OperatorMethodHandle.java │ └── OperatorType.java │ ├── metadata │ ├── MetadataService.java │ ├── MetadataUtil.java │ ├── QualifiedObjectName.java │ ├── SchemaTable.java │ ├── SimpleMetadataService.java │ ├── ViewColumn.java │ └── ViewDefinition.java │ ├── parser │ ├── AbstractSqlParser.java │ ├── AntlrCaches.java │ ├── AstBuilder.java │ ├── Origin.java │ ├── ParseErrorListener.java │ ├── ParseException.java │ ├── ParserUtils.java │ ├── ParsingException.java │ ├── ParsingOptions.java │ ├── SqlFlowParser.java │ └── UpperCaseCharStream.java │ ├── tree │ ├── AllColumns.java │ ├── LikeClause.java │ ├── NaturalJoin.java │ ├── Node.java │ ├── NodeLocation.java │ ├── NodeRef.java │ ├── OrderBy.java │ ├── PathElement.java │ ├── PathSpecification.java │ ├── ProcessingMode.java │ ├── Property.java │ ├── QualifiedName.java │ ├── QueryPeriod.java │ ├── Select.java │ ├── SelectItem.java │ ├── SingleColumn.java │ ├── SortItem.java │ ├── TableElement.java │ ├── TableSubquery.java │ ├── UpdateAssignment.java │ ├── Values.java │ ├── With.java │ ├── WithQuery.java │ ├── expression │ │ ├── AllRows.java │ │ ├── ArithmeticBinaryExpression.java │ │ ├── ArithmeticUnaryExpression.java │ │ ├── ArrayConstructor.java │ │ ├── AtTimeZone.java │ │ ├── BetweenPredicate.java │ │ ├── BindExpression.java │ │ ├── Cast.java │ │ ├── CoalesceExpression.java │ │ ├── ComparisonExpression.java │ │ ├── CurrentCatalog.java │ │ ├── CurrentPath.java │ │ ├── CurrentSchema.java │ │ ├── CurrentTime.java │ │ ├── CurrentUser.java │ │ ├── DereferenceExpression.java │ │ ├── ExistsPredicate.java │ │ ├── Expression.java │ │ ├── Extract.java │ │ ├── FieldReference.java │ │ ├── Format.java │ │ ├── FunctionCall.java │ │ ├── GroupingOperation.java │ │ ├── Identifier.java │ │ ├── IfExpression.java │ │ ├── InListExpression.java │ │ ├── InPredicate.java │ │ ├── IsNotNullPredicate.java │ │ ├── IsNullPredicate.java │ │ ├── LabelDereference.java │ │ ├── LambdaArgumentDeclaration.java │ │ ├── LambdaExpression.java │ │ ├── LikePredicate.java │ │ ├── LogicalExpression.java │ │ ├── NotExpression.java │ │ ├── NullIfExpression.java │ │ ├── Parameter.java │ │ ├── QuantifiedComparisonExpression.java │ │ ├── Row.java │ │ ├── SearchedCaseExpression.java │ │ ├── SimpleCaseExpression.java │ │ ├── SubqueryExpression.java │ │ ├── SubscriptExpression.java │ │ ├── SymbolReference.java │ │ ├── TryExpression.java │ │ ├── WhenClause.java │ │ └── WindowOperation.java │ ├── filter │ │ ├── FetchFirst.java │ │ ├── Limit.java │ │ └── Offset.java │ ├── group │ │ ├── Cube.java │ │ ├── GroupBy.java │ │ ├── GroupingElement.java │ │ ├── GroupingSets.java │ │ ├── Rollup.java │ │ └── SimpleGroupBy.java │ ├── join │ │ ├── Join.java │ │ ├── JoinCriteria.java │ │ ├── JoinOn.java │ │ └── JoinUsing.java │ ├── literal │ │ ├── BinaryLiteral.java │ │ ├── BooleanLiteral.java │ │ ├── CharLiteral.java │ │ ├── DecimalLiteral.java │ │ ├── DoubleLiteral.java │ │ ├── GenericLiteral.java │ │ ├── IntervalLiteral.java │ │ ├── Literal.java │ │ ├── LongLiteral.java │ │ ├── NullLiteral.java │ │ ├── StringLiteral.java │ │ ├── TimeLiteral.java │ │ └── TimestampLiteral.java │ ├── merge │ │ ├── MergeCase.java │ │ ├── MergeDelete.java │ │ ├── MergeInsert.java │ │ └── MergeUpdate.java │ ├── relation │ │ ├── AliasedRelation.java │ │ ├── Except.java │ │ ├── Intersect.java │ │ ├── Lateral.java │ │ ├── QueryBody.java │ │ ├── QuerySpecification.java │ │ ├── Relation.java │ │ ├── SampledRelation.java │ │ ├── SetOperation.java │ │ ├── Table.java │ │ ├── Union.java │ │ └── Unnest.java │ ├── statement │ │ ├── CreateMaterializedView.java │ │ ├── CreateTableAsSelect.java │ │ ├── CreateView.java │ │ ├── Delete.java │ │ ├── Insert.java │ │ ├── Merge.java │ │ ├── Query.java │ │ ├── Statement.java │ │ └── Update.java │ ├── type │ │ ├── DataType.java │ │ ├── DataTypeParameter.java │ │ ├── DateTimeDataType.java │ │ ├── GenericDataType.java │ │ ├── IntervalDayTimeDataType.java │ │ ├── NumericParameter.java │ │ ├── RowDataType.java │ │ └── TypeParameter.java │ └── window │ │ ├── FrameBound.java │ │ ├── MeasureDefinition.java │ │ ├── SkipTo.java │ │ ├── SubsetDefinition.java │ │ ├── VariableDefinition.java │ │ ├── Window.java │ │ ├── WindowDefinition.java │ │ ├── WindowFrame.java │ │ ├── WindowReference.java │ │ ├── WindowSpecification.java │ │ └── rowPattern │ │ ├── AnchorPattern.java │ │ ├── EmptyPattern.java │ │ ├── ExcludedPattern.java │ │ ├── OneOrMoreQuantifier.java │ │ ├── PatternAlternation.java │ │ ├── PatternConcatenation.java │ │ ├── PatternPermutation.java │ │ ├── PatternQuantifier.java │ │ ├── PatternRecognitionRelation.java │ │ ├── PatternSearchMode.java │ │ ├── PatternVariable.java │ │ ├── QuantifiedPattern.java │ │ ├── RangeQuantifier.java │ │ ├── RowPattern.java │ │ ├── ZeroOrMoreQuantifier.java │ │ └── ZeroOrOneQuantifier.java │ ├── type │ ├── RowType.java │ ├── Type.java │ └── UnknownType.java │ └── util │ ├── AstUtils.java │ ├── JsonUtils.java │ └── NodeUtils.java └── test ├── java └── io │ └── github │ └── melin │ └── sqlflow │ └── parser │ ├── AbstractSqlLineageTest.java │ ├── flink │ ├── JdbcQueryMetadataService.java │ └── SimpleFlinkMetadataService.java │ ├── presto │ ├── PrestoSqlLineageTest.java │ └── SimplePrestoMetadataService.java │ └── spark │ ├── SimpleSparkMetadataService.java │ ├── SparkSqlLineageTest.java │ └── SparkSqlLineageTest1.java ├── kotlin └── io │ └── github │ └── melin │ └── sqlflow │ └── parser │ └── flink │ ├── FlinkSqlLineageTest.kt │ ├── FlinkSqlLineageTest1.kt │ ├── FlinkSqlLineageTest2.kt │ └── FlinkSqlLineageTest3.kt └── resources ├── examples └── flink │ ├── createView.sql │ ├── flink.sql │ ├── insertFromSelectQueries.sql │ ├── selectAggregation.sql │ ├── selectDistinct.sql │ ├── selectJoin.sql │ ├── selectPatternRecognition.sql │ ├── selectWhere.sql │ ├── selectWindowTVF.sql │ └── selectWithClause.sql └── flink-test.sql /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | target 3 | bee.iml 4 | .DS_Store 5 | gen 6 | *.tokens -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/DefaultExpressionTraversalVisitor.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow; 2 | 3 | import io.github.melin.sqlflow.tree.expression.SubqueryExpression; 4 | 5 | /** 6 | * When walking Expressions, don't traverse into SubqueryExpressions 7 | */ 8 | public abstract class DefaultExpressionTraversalVisitor 9 | extends DefaultTraversalVisitor { 10 | @Override 11 | public Void visitSubqueryExpression(SubqueryExpression node, C context) { 12 | // Don't traverse into Subqueries within an Expression 13 | return null; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/SqlFlowException.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow; 2 | 3 | import io.github.melin.sqlflow.tree.NodeLocation; 4 | 5 | import java.util.Optional; 6 | 7 | import static java.lang.String.format; 8 | import static java.util.Objects.requireNonNull; 9 | 10 | /** 11 | * huaixin 2021/12/22 11:43 AM 12 | */ 13 | public class SqlFlowException extends RuntimeException { 14 | 15 | private final Optional location; 16 | 17 | public SqlFlowException(String message) { 18 | this(Optional.empty(), message, null); 19 | } 20 | 21 | public SqlFlowException(String message, Throwable cause) { 22 | this(Optional.empty(), message, cause); 23 | } 24 | 25 | public SqlFlowException(Optional location, String message, Throwable cause) { 26 | super(message, cause); 27 | this.location = requireNonNull(location, "location is null"); 28 | } 29 | 30 | public Optional getLocation() { 31 | return location; 32 | } 33 | 34 | @Override 35 | public String getMessage() { 36 | String message = getRawMessage(); 37 | if (location.isPresent()) { 38 | message = format("line %s:%s: %s", location.get().getLineNumber(), location.get().getColumnNumber(), message); 39 | } 40 | return message; 41 | } 42 | 43 | public String getRawMessage() { 44 | String message = super.getMessage(); 45 | if (message == null && getCause() != null) { 46 | message = getCause().getMessage(); 47 | } 48 | return message; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/analyzer/Analyzer.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.analyzer; 2 | 3 | import io.github.melin.sqlflow.metadata.MetadataService; 4 | import io.github.melin.sqlflow.tree.expression.Expression; 5 | import io.github.melin.sqlflow.tree.expression.FunctionCall; 6 | import io.github.melin.sqlflow.tree.expression.GroupingOperation; 7 | import com.google.common.collect.ImmutableList; 8 | import com.google.common.collect.Iterables; 9 | 10 | import java.util.List; 11 | 12 | import static io.github.melin.sqlflow.analyzer.ExpressionTreeUtils.*; 13 | import static io.github.melin.sqlflow.analyzer.SemanticExceptions.semanticException; 14 | 15 | public class Analyzer { 16 | 17 | static void verifyNoAggregateWindowOrGroupingFunctions(MetadataService metadataService, Expression predicate, String clause) { 18 | List aggregates = extractAggregateFunctions(ImmutableList.of(predicate), metadataService); 19 | 20 | List windowExpressions = extractWindowExpressions(ImmutableList.of(predicate)); 21 | 22 | List groupingOperations = extractExpressions(ImmutableList.of(predicate), GroupingOperation.class); 23 | 24 | List found = ImmutableList.copyOf(Iterables.concat( 25 | aggregates, 26 | windowExpressions, 27 | groupingOperations)); 28 | 29 | if (!found.isEmpty()) { 30 | throw semanticException(predicate, "%s cannot contain aggregations, window functions or grouping operations: %s", clause, found); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/analyzer/CorrelationSupport.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.analyzer; 2 | 3 | /** 4 | * huaixin 2021/12/25 11:12 AM 5 | */ 6 | public enum CorrelationSupport { 7 | ALLOWED, 8 | DISALLOWED 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/analyzer/FieldId.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.analyzer; 2 | 3 | import java.util.Objects; 4 | 5 | import static com.google.common.base.MoreObjects.toStringHelper; 6 | import static com.google.common.base.Preconditions.checkArgument; 7 | import static java.util.Objects.requireNonNull; 8 | 9 | public final class FieldId { 10 | public static FieldId from(ResolvedField field) { 11 | requireNonNull(field, "field is null"); 12 | 13 | Scope sourceScope = field.getScope(); 14 | RelationType relationType = sourceScope.getRelationType(); 15 | return new FieldId(sourceScope.getRelationId(), relationType.indexOf(field.getField())); 16 | } 17 | 18 | private final RelationId relationId; 19 | private final int fieldIndex; 20 | 21 | public FieldId(RelationId relationId, int fieldIndex) { 22 | this.relationId = requireNonNull(relationId, "relationId is null"); 23 | 24 | checkArgument(fieldIndex >= 0, "fieldIndex must be non-negative, got: %s", fieldIndex); 25 | this.fieldIndex = fieldIndex; 26 | } 27 | 28 | public RelationId getRelationId() { 29 | return relationId; 30 | } 31 | 32 | /** 33 | * Returns {@link RelationType#indexOf(Field) field index} of the field in the containing relation. 34 | */ 35 | public int getFieldIndex() { 36 | return fieldIndex; 37 | } 38 | 39 | @Override 40 | public boolean equals(Object o) { 41 | if (this == o) { 42 | return true; 43 | } 44 | if (o == null || getClass() != o.getClass()) { 45 | return false; 46 | } 47 | FieldId fieldId = (FieldId) o; 48 | return fieldIndex == fieldId.fieldIndex && 49 | Objects.equals(relationId, fieldId.relationId); 50 | } 51 | 52 | @Override 53 | public int hashCode() { 54 | return Objects.hash(relationId, fieldIndex); 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return toStringHelper(this) 60 | .addValue(relationId) 61 | .addValue(fieldIndex) 62 | .toString(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/analyzer/OutputColumn.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.analyzer; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.google.common.collect.ImmutableSet; 6 | 7 | import javax.annotation.concurrent.Immutable; 8 | import java.util.Objects; 9 | import java.util.Set; 10 | 11 | import static java.util.Objects.requireNonNull; 12 | 13 | @Immutable 14 | public final class OutputColumn { 15 | private final String column; 16 | private final Set sourceColumns; 17 | 18 | @JsonCreator 19 | public OutputColumn(@JsonProperty("column") String column, @JsonProperty("sourceColumns") Set sourceColumns) { 20 | this.column = requireNonNull(column, "column is null"); 21 | this.sourceColumns = ImmutableSet.copyOf(requireNonNull(sourceColumns, "sourceColumns is null")); 22 | } 23 | 24 | @JsonProperty 25 | public String getColumn() { 26 | return column; 27 | } 28 | 29 | @JsonProperty 30 | public Set getSourceColumns() { 31 | return sourceColumns; 32 | } 33 | 34 | @Override 35 | public int hashCode() { 36 | return Objects.hash(column, sourceColumns); 37 | } 38 | 39 | @Override 40 | public boolean equals(Object obj) { 41 | if (obj == this) { 42 | return true; 43 | } 44 | if ((obj == null) || (getClass() != obj.getClass())) { 45 | return false; 46 | } 47 | OutputColumn entry = (OutputColumn) obj; 48 | return Objects.equals(column, entry.column) && 49 | Objects.equals(sourceColumns, entry.sourceColumns); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/analyzer/QueryType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.github.melin.sqlflow.analyzer; 15 | 16 | public enum QueryType 17 | { 18 | DESCRIBE, 19 | EXPLAIN, 20 | OTHERS, 21 | /**/; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/analyzer/ResolvedField.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.analyzer; 2 | 3 | import javax.annotation.concurrent.Immutable; 4 | 5 | import static java.util.Objects.requireNonNull; 6 | 7 | @Immutable 8 | public class ResolvedField { 9 | private final Scope scope; 10 | private final Field field; 11 | private final int hierarchyFieldIndex; 12 | private final int relationFieldIndex; 13 | private final boolean local; 14 | 15 | public ResolvedField(Scope scope, Field field, int hierarchyFieldIndex, int relationFieldIndex, boolean local) { 16 | this.scope = requireNonNull(scope, "scope is null"); 17 | this.field = requireNonNull(field, "field is null"); 18 | this.hierarchyFieldIndex = hierarchyFieldIndex; 19 | this.relationFieldIndex = relationFieldIndex; 20 | this.local = local; 21 | } 22 | 23 | public FieldId getFieldId() { 24 | return FieldId.from(this); 25 | } 26 | 27 | public Scope getScope() { 28 | return scope; 29 | } 30 | 31 | public boolean isLocal() { 32 | return local; 33 | } 34 | 35 | public int getHierarchyFieldIndex() { 36 | return hierarchyFieldIndex; 37 | } 38 | 39 | public int getRelationFieldIndex() { 40 | return relationFieldIndex; 41 | } 42 | 43 | public Field getField() { 44 | return field; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/analyzer/ScopeReferenceExtractor.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.analyzer; 2 | 3 | import io.github.melin.sqlflow.tree.Node; 4 | import io.github.melin.sqlflow.tree.NodeRef; 5 | import io.github.melin.sqlflow.tree.expression.Expression; 6 | import io.github.melin.sqlflow.util.AstUtils; 7 | 8 | import java.util.Map; 9 | import java.util.Objects; 10 | import java.util.stream.Stream; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * Extract expressions that are references to a given scope. 16 | */ 17 | final class ScopeReferenceExtractor { 18 | private ScopeReferenceExtractor() { 19 | } 20 | 21 | public static boolean hasReferencesToScope(Node node, Analysis analysis, Scope scope) { 22 | return getReferencesToScope(node, analysis, scope).findAny().isPresent(); 23 | } 24 | 25 | public static Stream getReferencesToScope(Node node, Analysis analysis, Scope scope) { 26 | Map, ResolvedField> columnReferences = analysis.getColumnReferenceFields(); 27 | 28 | return AstUtils.preOrder(node) 29 | .filter(Expression.class::isInstance) 30 | .map(Expression.class::cast) 31 | .filter(expression -> columnReferences.containsKey(NodeRef.of(expression))) 32 | .filter(expression -> isReferenceToScope(expression, scope, columnReferences)); 33 | } 34 | 35 | private static boolean isReferenceToScope(Expression node, Scope scope, Map, ResolvedField> columnReferences) { 36 | ResolvedField field = columnReferences.get(NodeRef.of(node)); 37 | requireNonNull(field, () -> "No Field for " + node); 38 | return isFieldFromScope(field.getFieldId(), scope); 39 | } 40 | 41 | public static boolean isFieldFromScope(FieldId field, Scope scope) { 42 | return Objects.equals(field.getRelationId(), scope.getRelationId()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/analyzer/SemanticExceptions.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.analyzer; 2 | 3 | import io.github.melin.sqlflow.SqlFlowException; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.QualifiedName; 6 | import io.github.melin.sqlflow.tree.expression.Expression; 7 | 8 | import static java.lang.String.format; 9 | 10 | /** 11 | * huaixin 2021/12/24 11:34 AM 12 | */ 13 | public class SemanticExceptions { 14 | 15 | private SemanticExceptions() { 16 | } 17 | 18 | public static SqlFlowException missingAttributeException(Expression node, QualifiedName name) { 19 | throw semanticException(node, "Column '%s' cannot be resolved", name); 20 | } 21 | 22 | public static SqlFlowException ambiguousAttributeException(Expression node, QualifiedName name) { 23 | throw semanticException(node, "Column '%s' is ambiguous", name); 24 | } 25 | 26 | public static SqlFlowException semanticException(Node node, String format, Object... args) { 27 | return semanticException(node, null, format, args); 28 | } 29 | 30 | public static SqlFlowException semanticException(Node node, Throwable cause, String format, Object... args) { 31 | throw new SqlFlowException(ExpressionTreeUtils.extractLocation(node), format(format, args), cause); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/function/OperatorMethodHandle.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.function; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | 5 | public class OperatorMethodHandle 6 | { 7 | private final InvocationConvention callingConvention; 8 | private final MethodHandle methodHandle; 9 | 10 | public OperatorMethodHandle(InvocationConvention callingConvention, MethodHandle methodHandle) 11 | { 12 | this.callingConvention = callingConvention; 13 | this.methodHandle = methodHandle; 14 | } 15 | 16 | public InvocationConvention getCallingConvention() 17 | { 18 | return callingConvention; 19 | } 20 | 21 | public MethodHandle getMethodHandle() 22 | { 23 | return methodHandle; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/function/OperatorType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.github.melin.sqlflow.function; 15 | 16 | public enum OperatorType 17 | { 18 | ADD("+", 2), 19 | SUBTRACT("-", 2), 20 | MULTIPLY("*", 2), 21 | DIVIDE("/", 2), 22 | MODULUS("%", 2), 23 | NEGATION("-", 1), 24 | EQUAL("=", 2), 25 | /** 26 | * Normal comparison operator, but unordered values such as NaN are placed after all normal values. 27 | */ 28 | COMPARISON_UNORDERED_LAST("COMPARISON_UNORDERED_LAST", 2), 29 | /** 30 | * Normal comparison operator, but unordered values such as NaN are placed before all normal values. 31 | */ 32 | COMPARISON_UNORDERED_FIRST("COMPARISON_UNORDERED_FIRST", 2), 33 | LESS_THAN("<", 2), 34 | LESS_THAN_OR_EQUAL("<=", 2), 35 | CAST("CAST", 1), 36 | SUBSCRIPT("[]", 2), 37 | HASH_CODE("HASH CODE", 1), 38 | SATURATED_FLOOR_CAST("SATURATED FLOOR CAST", 1), 39 | IS_DISTINCT_FROM("IS DISTINCT FROM", 2), 40 | XX_HASH_64("XX HASH 64", 1), 41 | INDETERMINATE("INDETERMINATE", 1); 42 | 43 | private final String operator; 44 | private final int argumentCount; 45 | 46 | OperatorType(String operator, int argumentCount) 47 | { 48 | this.operator = operator; 49 | this.argumentCount = argumentCount; 50 | } 51 | 52 | public String getOperator() 53 | { 54 | return operator; 55 | } 56 | 57 | public int getArgumentCount() 58 | { 59 | return argumentCount; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/metadata/MetadataService.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.metadata; 2 | 3 | import io.github.melin.sqlflow.tree.QualifiedName; 4 | 5 | import java.util.Optional; 6 | 7 | /** 8 | * huaixin 2021/12/22 10:05 AM 9 | */ 10 | public interface MetadataService { 11 | 12 | Optional getSchema(); 13 | 14 | Optional getCatalog(); 15 | 16 | /** 17 | * Is the named function an aggregation function? This does not need type parameters 18 | * because overloads between aggregation and other function types are not allowed. 19 | */ 20 | boolean isAggregationFunction(QualifiedName name); 21 | 22 | Optional getTableSchema(QualifiedObjectName targetTable); 23 | 24 | Optional getView(QualifiedObjectName viewName); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/metadata/MetadataUtil.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.metadata; 2 | 3 | import io.github.melin.sqlflow.SqlFlowException; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.QualifiedName; 6 | import io.github.melin.sqlflow.analyzer.SemanticExceptions; 7 | import com.google.common.collect.Lists; 8 | 9 | import java.util.List; 10 | 11 | import static com.google.common.base.Preconditions.checkArgument; 12 | import static java.lang.String.format; 13 | import static java.util.Locale.ENGLISH; 14 | import static java.util.Objects.requireNonNull; 15 | 16 | /** 17 | * huaixin 2021/12/24 11:28 AM 18 | */ 19 | public class MetadataUtil { 20 | 21 | public static QualifiedObjectName createQualifiedObjectName(MetadataService metadataService, Node node, QualifiedName name) { 22 | requireNonNull(metadataService, "metadata is null"); 23 | requireNonNull(name, "name is null"); 24 | if (name.getParts().size() > 3) { 25 | throw new SqlFlowException(format("Too many dots in table name: %s", name)); 26 | } 27 | 28 | List parts = Lists.reverse(name.getParts()); 29 | String objectName = parts.get(0); 30 | String schemaName = (parts.size() > 1) ? parts.get(1) : metadataService.getSchema().orElseThrow(() -> 31 | SemanticExceptions.semanticException(node, "Schema must be specified when session schema is not set")); 32 | String catalogName = (parts.size() > 2) ? parts.get(2) : null; 33 | 34 | return new QualifiedObjectName(catalogName, schemaName, objectName); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/metadata/QualifiedObjectName.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.metadata; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonValue; 5 | import com.google.common.base.Splitter; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import javax.annotation.concurrent.Immutable; 9 | import java.util.Objects; 10 | 11 | import static com.google.common.base.Preconditions.checkArgument; 12 | import static java.util.Objects.requireNonNull; 13 | 14 | @Immutable 15 | public class QualifiedObjectName { 16 | @JsonCreator 17 | public static QualifiedObjectName valueOf(String name) { 18 | requireNonNull(name, "name is null"); 19 | 20 | ImmutableList ids = ImmutableList.copyOf(Splitter.on('.').split(name)); 21 | if (ids.size() == 3) { 22 | return new QualifiedObjectName(ids.get(0), ids.get(1), ids.get(2)); 23 | } else { 24 | return new QualifiedObjectName(null, ids.get(0), ids.get(1)); 25 | } 26 | } 27 | 28 | private final String catalogName; 29 | private final String schemaName; 30 | private final String objectName; 31 | 32 | public QualifiedObjectName(String catalogName, String schemaName, String objectName) { 33 | this.catalogName = catalogName; 34 | this.schemaName = schemaName; 35 | this.objectName = objectName; 36 | } 37 | 38 | public String getCatalogName() { 39 | return catalogName; 40 | } 41 | 42 | public String getSchemaName() { 43 | return schemaName; 44 | } 45 | 46 | public String getObjectName() { 47 | return objectName; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object obj) { 52 | if (obj == this) { 53 | return true; 54 | } 55 | if ((obj == null) || (getClass() != obj.getClass())) { 56 | return false; 57 | } 58 | QualifiedObjectName o = (QualifiedObjectName) obj; 59 | return Objects.equals(catalogName, o.catalogName) && 60 | Objects.equals(schemaName, o.schemaName) && 61 | Objects.equals(objectName, o.objectName); 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | return Objects.hash(catalogName, schemaName, objectName); 67 | } 68 | 69 | @JsonValue 70 | @Override 71 | public String toString() { 72 | if (catalogName != null) { 73 | return catalogName + '.' + schemaName + '.' + objectName; 74 | } else { 75 | return schemaName + '.' + objectName; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/metadata/SchemaTable.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.metadata; 2 | 3 | import java.util.List; 4 | 5 | import static com.google.common.collect.MoreCollectors.toOptional; 6 | 7 | public final class SchemaTable { 8 | 9 | private final String catalogName; 10 | 11 | private final String schemaName; 12 | 13 | private final String tableName; 14 | 15 | private List columns; 16 | 17 | public SchemaTable(String catalogName, String schemaName, String tableName, List columns) { 18 | this.catalogName = catalogName; 19 | this.schemaName = schemaName; 20 | this.tableName = tableName; 21 | this.columns = columns; 22 | } 23 | 24 | public SchemaTable(String schemaName, String tableName, List columns) { 25 | this.catalogName = null; 26 | this.schemaName = schemaName; 27 | this.tableName = tableName; 28 | this.columns = columns; 29 | } 30 | 31 | public SchemaTable(String tableName, List columns) { 32 | this.catalogName = null; 33 | this.schemaName = null; 34 | this.tableName = tableName; 35 | this.columns = columns; 36 | } 37 | 38 | public String getTableName() { 39 | return tableName; 40 | } 41 | 42 | public List getColumns() { 43 | return columns; 44 | } 45 | 46 | public void setColumns(List columns) { 47 | this.columns = columns; 48 | } 49 | 50 | public String getColumn(String name) { 51 | return columns.stream() 52 | .filter(column -> column.equals(name)) 53 | .collect(toOptional()) 54 | .orElseThrow(() -> new IllegalArgumentException("Invalid column name: " + name)); 55 | } 56 | 57 | public String toString() { 58 | if (catalogName != null) { 59 | return catalogName + '.' + schemaName + '.' + tableName; 60 | } else if (schemaName != null) { 61 | return schemaName + '.' + tableName; 62 | } else { 63 | return tableName; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/metadata/SimpleMetadataService.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.metadata; 2 | 3 | import io.github.melin.sqlflow.tree.QualifiedName; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Optional; 8 | 9 | /** 10 | * huaixin 2021/12/25 6:13 PM 11 | */ 12 | public class SimpleMetadataService implements MetadataService { 13 | 14 | private final List tables = new ArrayList<>(); 15 | 16 | private final Optional defaultSchema; 17 | 18 | private final Optional defaultCatalog; 19 | 20 | public SimpleMetadataService(String schema) { 21 | this.defaultCatalog = Optional.empty(); 22 | this.defaultSchema = Optional.of(schema); 23 | } 24 | 25 | public SimpleMetadataService(String defaultCatalog, String defaultSchema) { 26 | this.defaultCatalog = Optional.of(defaultCatalog); 27 | this.defaultSchema = Optional.of(defaultSchema); 28 | } 29 | 30 | public MetadataService addTableMetadata(List schemaTables) { 31 | tables.addAll(schemaTables); 32 | return this; 33 | } 34 | 35 | public MetadataService addTableMetadata(SchemaTable schemaTable) { 36 | tables.add(schemaTable); 37 | return this; 38 | } 39 | 40 | @Override 41 | public Optional getSchema() { 42 | return defaultSchema; 43 | } 44 | 45 | @Override 46 | public Optional getCatalog() { 47 | return defaultCatalog; 48 | } 49 | 50 | @Override 51 | public boolean isAggregationFunction(QualifiedName name) { 52 | return false; 53 | } 54 | 55 | @Override 56 | public Optional getTableSchema(QualifiedObjectName table) { 57 | for (SchemaTable schemaTable : tables) { 58 | if (schemaTable.toString().equalsIgnoreCase(table.toString())) { 59 | return Optional.of(schemaTable); 60 | } 61 | } 62 | 63 | return Optional.empty(); 64 | } 65 | 66 | @Override 67 | public Optional getView(QualifiedObjectName viewName) { 68 | return Optional.empty(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/metadata/ViewColumn.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.metadata; 2 | 3 | import io.github.melin.sqlflow.type.Type; 4 | 5 | import java.util.Objects; 6 | 7 | import static java.util.Objects.requireNonNull; 8 | 9 | /** 10 | * huaixin 2021/12/25 5:36 PM 11 | */ 12 | public final class ViewColumn { 13 | private final String name; 14 | private final Type type; 15 | 16 | public ViewColumn(String name, Type type) { 17 | this.name = requireNonNull(name, "name is null"); 18 | this.type = requireNonNull(type, "type is null"); 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public Type getType() { 26 | return type; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return name + " " + type; 32 | } 33 | 34 | @Override 35 | public boolean equals(Object o) { 36 | if (this == o) { 37 | return true; 38 | } 39 | if (o == null || getClass() != o.getClass()) { 40 | return false; 41 | } 42 | ViewColumn that = (ViewColumn) o; 43 | return Objects.equals(name, that.name) && Objects.equals(type, that.type); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return Objects.hash(name, type); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/metadata/ViewDefinition.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.metadata; 2 | 3 | import com.google.common.collect.Lists; 4 | 5 | import java.util.List; 6 | import java.util.Optional; 7 | 8 | import static com.google.common.base.MoreObjects.toStringHelper; 9 | import static com.google.common.base.Preconditions.checkArgument; 10 | import static java.util.Objects.requireNonNull; 11 | 12 | /** 13 | * huaixin 2021/12/25 5:35 PM 14 | */ 15 | public class ViewDefinition { 16 | private final String originalSql; 17 | private final Optional catalog; 18 | private final Optional schema; 19 | private final List columns; 20 | private final Optional comment; 21 | 22 | public ViewDefinition( 23 | String originalSql, 24 | Optional catalog, 25 | Optional schema, 26 | List columns, 27 | Optional comment) { 28 | this.originalSql = requireNonNull(originalSql, "originalSql is null"); 29 | this.catalog = requireNonNull(catalog, "catalog is null"); 30 | this.schema = requireNonNull(schema, "schema is null"); 31 | this.columns = Lists.newArrayList(requireNonNull(columns, "columns is null")); 32 | this.comment = requireNonNull(comment, "comment is null"); 33 | checkArgument(schema == null || catalog.isPresent(), "catalog must be present if schema is present"); 34 | checkArgument(!columns.isEmpty(), "columns list is empty"); 35 | } 36 | 37 | public String getOriginalSql() { 38 | return originalSql; 39 | } 40 | 41 | public Optional getCatalog() { 42 | return catalog; 43 | } 44 | 45 | public Optional getSchema() { 46 | return schema; 47 | } 48 | 49 | public List getColumns() { 50 | return columns; 51 | } 52 | 53 | public Optional getComment() { 54 | return comment; 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return toStringHelper(this).omitNullValues() 60 | .add("originalSql", originalSql) 61 | .add("catalog", catalog.orElse(null)) 62 | .add("schema", schema.orElse(null)) 63 | .add("columns", columns) 64 | .add("comment", comment.orElse(null)) 65 | .toString(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/parser/AbstractSqlParser.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser; 2 | 3 | import io.github.melin.sqlflow.parser.antlr4.SqlFlowParser; 4 | 5 | import java.util.concurrent.atomic.AtomicReference; 6 | 7 | public class AbstractSqlParser { 8 | private static AtomicReference parserCaches = 9 | new AtomicReference<>(new AntlrCaches(SqlFlowParser._ATN)); 10 | 11 | /** 12 | * Install the parser caches into the given parser. 13 | * 14 | * This method should be called before parsing any input. 15 | */ 16 | public static void installCaches(SqlFlowParser parser) { 17 | parserCaches.get().installCaches(parser); 18 | } 19 | 20 | /** 21 | * Drop the existing parser caches and create a new one. 22 | * 23 | * ANTLR retains caches in its parser that are never released. This speeds 24 | * up parsing of future input, but it can consume a lot of memory depending 25 | * on the input seen so far. 26 | * 27 | * This method provides a mechanism to free the retained caches, which can 28 | * be useful after parsing very large SQL inputs, especially if those large 29 | * inputs are unlikely to be similar to future inputs seen by the driver. 30 | */ 31 | public static void refreshParserCaches() { 32 | parserCaches.set(new AntlrCaches(SqlFlowParser._ATN)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/parser/AntlrCaches.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser; 2 | 3 | import org.antlr.v4.runtime.Parser; 4 | import org.antlr.v4.runtime.atn.ATN; 5 | import org.antlr.v4.runtime.atn.ParserATNSimulator; 6 | import org.antlr.v4.runtime.atn.PredictionContextCache; 7 | import org.antlr.v4.runtime.dfa.DFA; 8 | 9 | public class AntlrCaches { 10 | 11 | public static final String RELEASE_ANTLR_CACHE_AFTER_PARSING = "releaseAntlrCacheAfterParsing"; 12 | 13 | private final ATN atn; 14 | 15 | private final PredictionContextCache predictionContextCache = new PredictionContextCache(); 16 | 17 | private final DFA[] decisionToDFA; 18 | 19 | public AntlrCaches(ATN atn) { 20 | this.atn = atn; 21 | this.decisionToDFA = makeDecisionToDFA(this.atn); 22 | } 23 | 24 | public void installCaches(Parser parser) { 25 | parser.setInterpreter(new ParserATNSimulator(parser, atn, decisionToDFA, predictionContextCache)); 26 | } 27 | 28 | private DFA[] makeDecisionToDFA(ATN atn) { 29 | DFA[] decisionToDFA = new DFA[atn.getNumberOfDecisions()]; 30 | for (int i = 0, len = atn.getNumberOfDecisions(); i < len; i++) { 31 | decisionToDFA[i] = new DFA(atn.getDecisionState(i), i); 32 | } 33 | return decisionToDFA; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/parser/Origin.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser; 2 | 3 | public class Origin { 4 | private int line; 5 | private int startPosition; 6 | 7 | public Origin(int line, int startPosition) { 8 | this.line = line; 9 | this.startPosition = startPosition; 10 | } 11 | 12 | public int getLine() { 13 | return line; 14 | } 15 | 16 | public void setLine(int line) { 17 | this.line = line; 18 | } 19 | 20 | public int getStartPosition() { 21 | return startPosition; 22 | } 23 | 24 | public void setStartPosition(int startPosition) { 25 | this.startPosition = startPosition; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/parser/ParseErrorListener.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser; 2 | 3 | import org.antlr.v4.runtime.BaseErrorListener; 4 | import org.antlr.v4.runtime.RecognitionException; 5 | import org.antlr.v4.runtime.Recognizer; 6 | 7 | public class ParseErrorListener extends BaseErrorListener { 8 | 9 | @Override 10 | public void syntaxError(Recognizer recognizer, 11 | Object offendingSymbol, int line, int charPositionInLine, 12 | String msg, RecognitionException e) { 13 | Origin position = new Origin(line, charPositionInLine); 14 | throw new ParseException(msg, position, position); 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/parser/ParseException.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | public class ParseException extends RuntimeException { 6 | private String command; 7 | private String message; 8 | private Origin start; 9 | private Origin stop; 10 | 11 | public ParseException(String message, Origin start, Origin stop) { 12 | this.message = message; 13 | this.start = start; 14 | this.stop = stop; 15 | } 16 | 17 | public ParseException(String command, String message, Origin start, Origin stop) { 18 | this.command = command; 19 | this.message = message; 20 | this.start = start; 21 | this.stop = stop; 22 | } 23 | 24 | @Override 25 | public String getMessage() { 26 | StringBuilder builder = new StringBuilder(); 27 | builder.append("\n").append(message); 28 | if (start != null) { 29 | builder.append("(line " + start.getLine() + ", pos " + start.getStartPosition() + ")\n"); 30 | if (StringUtils.isNotBlank(command)) { 31 | String[] lines = command.split("\n"); 32 | builder.append("\n== SQL ==\n"); 33 | for (int i=0; i 0, "line must be > 0"); 16 | checkArgument(column > 0, "column must be > 0"); 17 | 18 | this.line = line; 19 | this.column = column; 20 | } 21 | 22 | public ParsingException(String message) { 23 | this(message, null, 1, 1); 24 | } 25 | 26 | public ParsingException(String message, NodeLocation nodeLocation) { 27 | this(message, null, nodeLocation.getLineNumber(), nodeLocation.getColumnNumber()); 28 | } 29 | 30 | public int getLineNumber() { 31 | return line; 32 | } 33 | 34 | public int getColumnNumber() { 35 | return column; 36 | } 37 | 38 | public String getErrorMessage() { 39 | return super.getMessage(); 40 | } 41 | 42 | @Override 43 | public String getMessage() { 44 | return format("line %s:%s: %s", getLineNumber(), getColumnNumber(), getErrorMessage()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/parser/ParsingOptions.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser; 2 | 3 | import static java.util.Objects.requireNonNull; 4 | 5 | /** 6 | * huaixin 2021/12/21 1:28 PM 7 | */ 8 | public class ParsingOptions { 9 | public enum DecimalLiteralTreatment { 10 | AS_DOUBLE, 11 | AS_DECIMAL, 12 | REJECT 13 | } 14 | 15 | private final DecimalLiteralTreatment decimalLiteralTreatment; 16 | 17 | public ParsingOptions() { 18 | this(DecimalLiteralTreatment.REJECT); 19 | } 20 | 21 | public ParsingOptions(DecimalLiteralTreatment decimalLiteralTreatment) { 22 | this.decimalLiteralTreatment = requireNonNull(decimalLiteralTreatment, "decimalLiteralTreatment is null"); 23 | } 24 | 25 | public DecimalLiteralTreatment getDecimalLiteralTreatment() { 26 | return decimalLiteralTreatment; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/parser/UpperCaseCharStream.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser; 2 | 3 | import org.antlr.v4.runtime.CharStream; 4 | import org.antlr.v4.runtime.CodePointCharStream; 5 | import org.antlr.v4.runtime.IntStream; 6 | import org.antlr.v4.runtime.misc.Interval; 7 | 8 | public class UpperCaseCharStream implements CharStream { 9 | 10 | private CodePointCharStream wrapped; 11 | 12 | public UpperCaseCharStream(CodePointCharStream wrapped) { 13 | this.wrapped = wrapped; 14 | } 15 | 16 | @Override 17 | public void consume() { 18 | wrapped.consume(); 19 | } 20 | 21 | @Override 22 | public int LA(int i) { 23 | int la = wrapped.LA(i); 24 | if(la == 0 || la == IntStream.EOF) { 25 | return la; 26 | } else { 27 | return Character.toUpperCase(la); 28 | } 29 | } 30 | 31 | @Override 32 | public String getText(Interval interval) { 33 | if (size() > 0 && (interval.b - interval.a >= 0)) { 34 | return wrapped.getText(interval); 35 | } else { 36 | return ""; 37 | } 38 | } 39 | 40 | @Override 41 | public int mark() { 42 | return wrapped.mark(); 43 | } 44 | 45 | @Override 46 | public void release(int i) { 47 | wrapped.release(i); 48 | } 49 | 50 | @Override 51 | public int index() { 52 | return wrapped.index(); 53 | } 54 | 55 | @Override 56 | public void seek(int i) { 57 | wrapped.seek(i); 58 | } 59 | 60 | @Override 61 | public int size() { 62 | return wrapped.size(); 63 | } 64 | 65 | @Override 66 | public String getSourceName() { 67 | return wrapped.getSourceName(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/NaturalJoin.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import io.github.melin.sqlflow.tree.join.JoinCriteria; 4 | import com.google.common.collect.ImmutableList; 5 | 6 | import java.util.List; 7 | 8 | import static com.google.common.base.MoreObjects.toStringHelper; 9 | 10 | /** 11 | * huaixin 2021/12/19 11:02 AM 12 | */ 13 | public class NaturalJoin extends JoinCriteria { 14 | @Override 15 | public boolean equals(Object obj) { 16 | if (this == obj) { 17 | return true; 18 | } 19 | return (obj != null) && (getClass() == obj.getClass()); 20 | } 21 | 22 | @Override 23 | public int hashCode() { 24 | return getClass().hashCode(); 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return toStringHelper(this).toString(); 30 | } 31 | 32 | @Override 33 | public List getNodes() { 34 | return ImmutableList.of(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/Node.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | 5 | import java.util.List; 6 | import java.util.Optional; 7 | 8 | import static java.util.Objects.requireNonNull; 9 | 10 | /** 11 | * huaixin 2021/12/18 9:52 PM 12 | */ 13 | public abstract class Node { 14 | private final Optional location; 15 | 16 | protected Node(Optional location) { 17 | this.location = requireNonNull(location, "location is null"); 18 | } 19 | 20 | /** 21 | * Accessible for {@link AstVisitor}, use {@link AstVisitor#process(Node, Object)} instead. 22 | */ 23 | public R accept(AstVisitor visitor, C context) { 24 | return visitor.visitNode(this, context); 25 | } 26 | 27 | public Optional getLocation() { 28 | return location; 29 | } 30 | 31 | public abstract List getChildren(); 32 | 33 | // Force subclasses to have a proper equals and hashcode implementation 34 | @Override 35 | public abstract int hashCode(); 36 | 37 | @Override 38 | public abstract boolean equals(Object obj); 39 | 40 | /** 41 | * Compare with another node by considering internal state excluding any Node returned by getChildren() 42 | */ 43 | public boolean shallowEquals(Node other) { 44 | throw new UnsupportedOperationException("not yet implemented: " + getClass().getName()); 45 | } 46 | 47 | public static boolean sameClass(Node left, Node right) { 48 | if (left == right) { 49 | return true; 50 | } 51 | 52 | return left.getClass() == right.getClass(); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/NodeLocation.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import java.util.Objects; 4 | 5 | import static com.google.common.base.Preconditions.checkArgument; 6 | 7 | /** 8 | * huaixin 2021/12/18 9:52 PM 9 | */ 10 | public final class NodeLocation { 11 | private final int line; 12 | private final int column; 13 | private final int startIndex; 14 | private final int stopIndex; 15 | 16 | public NodeLocation(int line, int column, int startIndex, int stopIndex) { 17 | checkArgument(line >= 1, "line must be at least one, got: %s", line); 18 | checkArgument(column >= 1, "column must be at least one, got: %s", column); 19 | 20 | this.line = line; 21 | this.column = column; 22 | this.startIndex = startIndex; 23 | this.stopIndex = stopIndex; 24 | } 25 | 26 | public int getLineNumber() { 27 | return line; 28 | } 29 | 30 | public int getColumnNumber() { 31 | return column; 32 | } 33 | 34 | public int getStartIndex() { 35 | return startIndex; 36 | } 37 | 38 | public int getStopIndex() { 39 | return stopIndex; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "(" + 45 | "line=" + line + 46 | ", column=" + column + 47 | ", startIndex=" + startIndex + 48 | ", stopIndex=" + stopIndex + 49 | ')'; 50 | } 51 | 52 | @Override 53 | public boolean equals(Object o) { 54 | if (this == o) { 55 | return true; 56 | } 57 | if (o == null || getClass() != o.getClass()) { 58 | return false; 59 | } 60 | NodeLocation that = (NodeLocation) o; 61 | return line == that.line && 62 | column == that.column && 63 | startIndex == that.startIndex && 64 | stopIndex == that.stopIndex; 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return Objects.hash(line, column, startIndex, stopIndex); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/NodeRef.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import static java.lang.String.format; 4 | import static java.lang.System.identityHashCode; 5 | import static java.util.Objects.requireNonNull; 6 | 7 | /** 8 | * huaixin 2021/12/24 11:19 AM 9 | */ 10 | public final class NodeRef { 11 | public static NodeRef of(T node) { 12 | return new NodeRef<>(node); 13 | } 14 | 15 | private final T node; 16 | 17 | private NodeRef(T node) { 18 | this.node = requireNonNull(node, "node is null"); 19 | } 20 | 21 | public T getNode() { 22 | return node; 23 | } 24 | 25 | @Override 26 | public boolean equals(Object o) { 27 | if (this == o) { 28 | return true; 29 | } 30 | if (o == null || getClass() != o.getClass()) { 31 | return false; 32 | } 33 | NodeRef other = (NodeRef) o; 34 | return node == other.node; 35 | } 36 | 37 | @Override 38 | public int hashCode() { 39 | return identityHashCode(node); 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return format( 45 | "@%s: %s", 46 | Integer.toHexString(identityHashCode(node)), 47 | node); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/OrderBy.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import com.google.common.collect.ImmutableList; 5 | 6 | import java.util.List; 7 | import java.util.Objects; 8 | import java.util.Optional; 9 | 10 | import static com.google.common.base.MoreObjects.toStringHelper; 11 | import static com.google.common.base.Preconditions.checkArgument; 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/18 10:08 PM 16 | */ 17 | public class OrderBy 18 | extends Node { 19 | private final List sortItems; 20 | 21 | public OrderBy(List sortItems) { 22 | this(Optional.empty(), sortItems); 23 | } 24 | 25 | public OrderBy(NodeLocation location, List sortItems) { 26 | this(Optional.of(location), sortItems); 27 | } 28 | 29 | private OrderBy(Optional location, List sortItems) { 30 | super(location); 31 | requireNonNull(sortItems, "sortItems is null"); 32 | checkArgument(!sortItems.isEmpty(), "sortItems should not be empty"); 33 | this.sortItems = ImmutableList.copyOf(sortItems); 34 | } 35 | 36 | public List getSortItems() { 37 | return sortItems; 38 | } 39 | 40 | @Override 41 | public R accept(AstVisitor visitor, C context) { 42 | return visitor.visitOrderBy(this, context); 43 | } 44 | 45 | @Override 46 | public List getChildren() { 47 | return sortItems; 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return toStringHelper(this) 53 | .add("sortItems", sortItems) 54 | .toString(); 55 | } 56 | 57 | @Override 58 | public boolean equals(Object obj) { 59 | if (this == obj) { 60 | return true; 61 | } 62 | if ((obj == null) || (getClass() != obj.getClass())) { 63 | return false; 64 | } 65 | OrderBy o = (OrderBy) obj; 66 | return Objects.equals(sortItems, o.sortItems); 67 | } 68 | 69 | @Override 70 | public int hashCode() { 71 | return Objects.hash(sortItems); 72 | } 73 | 74 | @Override 75 | public boolean shallowEquals(Node other) { 76 | return sameClass(this, other); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/PathSpecification.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import com.google.common.annotations.VisibleForTesting; 5 | import com.google.common.base.Joiner; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 1:31 PM 16 | */ 17 | public final class PathSpecification extends Node { 18 | private List path; 19 | 20 | public PathSpecification(NodeLocation location, List path) { 21 | this(Optional.of(location), path); 22 | } 23 | 24 | @VisibleForTesting 25 | public PathSpecification(Optional location, List path) { 26 | super(location); 27 | this.path = ImmutableList.copyOf(requireNonNull(path, "path is null")); 28 | } 29 | 30 | public List getPath() { 31 | return path; 32 | } 33 | 34 | @Override 35 | public R accept(AstVisitor visitor, C context) { 36 | return visitor.visitPathSpecification(this, context); 37 | } 38 | 39 | @Override 40 | public List getChildren() { 41 | return path; 42 | } 43 | 44 | @Override 45 | public boolean equals(Object obj) { 46 | if (this == obj) { 47 | return true; 48 | } 49 | if ((obj == null) || (getClass() != obj.getClass())) { 50 | return false; 51 | } 52 | PathSpecification o = (PathSpecification) obj; 53 | return Objects.equals(path, o.path); 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | return Objects.hash(path); 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return Joiner.on(", ").join(path); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/ProcessingMode.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import com.google.common.collect.ImmutableList; 5 | 6 | import java.util.List; 7 | import java.util.Objects; 8 | import java.util.Optional; 9 | 10 | import static com.google.common.base.MoreObjects.toStringHelper; 11 | import static java.util.Objects.requireNonNull; 12 | 13 | /** 14 | * huaixin 2021/12/21 11:02 AM 15 | */ 16 | public final class ProcessingMode 17 | extends Node { 18 | private final Mode mode; 19 | 20 | public ProcessingMode(NodeLocation location, Mode mode) { 21 | this(Optional.of(location), mode); 22 | } 23 | 24 | public ProcessingMode(Optional location, Mode mode) { 25 | super(location); 26 | this.mode = requireNonNull(mode, "mode is null"); 27 | } 28 | 29 | public Mode getMode() { 30 | return mode; 31 | } 32 | 33 | @Override 34 | public R accept(AstVisitor visitor, C context) { 35 | return visitor.visitProcessingMode(this, context); 36 | } 37 | 38 | @Override 39 | public List getChildren() { 40 | return ImmutableList.of(); 41 | } 42 | 43 | @Override 44 | public boolean equals(Object obj) { 45 | if (this == obj) { 46 | return true; 47 | } 48 | if ((obj == null) || (getClass() != obj.getClass())) { 49 | return false; 50 | } 51 | return mode == ((ProcessingMode) obj).mode; 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | return Objects.hash(mode); 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return toStringHelper(this) 62 | .add("mode", mode) 63 | .toString(); 64 | } 65 | 66 | public enum Mode { 67 | RUNNING, FINAL 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/Property.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Expression; 5 | import io.github.melin.sqlflow.tree.expression.Identifier; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.MoreObjects.toStringHelper; 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/21 12:42 PM 17 | */ 18 | public class Property 19 | extends Node { 20 | private final Identifier name; 21 | private final Expression value; 22 | 23 | public Property(Identifier name, Expression value) { 24 | this(Optional.empty(), name, value); 25 | } 26 | 27 | public Property(NodeLocation location, Identifier name, Expression value) { 28 | this(Optional.of(location), name, value); 29 | } 30 | 31 | private Property(Optional location, Identifier name, Expression value) { 32 | super(location); 33 | this.name = requireNonNull(name, "name is null"); 34 | this.value = requireNonNull(value, "value is null"); 35 | } 36 | 37 | public Identifier getName() { 38 | return name; 39 | } 40 | 41 | public Expression getValue() { 42 | return value; 43 | } 44 | 45 | @Override 46 | public R accept(AstVisitor visitor, C context) { 47 | return visitor.visitProperty(this, context); 48 | } 49 | 50 | @Override 51 | public List getChildren() { 52 | return ImmutableList.of(name, value); 53 | } 54 | 55 | @Override 56 | public boolean equals(Object obj) { 57 | if (this == obj) { 58 | return true; 59 | } 60 | if (obj == null || getClass() != obj.getClass()) { 61 | return false; 62 | } 63 | Property other = (Property) obj; 64 | return Objects.equals(name, other.name) && 65 | Objects.equals(value, other.value); 66 | } 67 | 68 | @Override 69 | public int hashCode() { 70 | return Objects.hash(name, value); 71 | } 72 | 73 | @Override 74 | public String toString() { 75 | return toStringHelper(this) 76 | .add("name", name) 77 | .add("value", value) 78 | .toString(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/SelectItem.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import java.util.Optional; 4 | 5 | /** 6 | * huaixin 2021/12/18 11:16 PM 7 | */ 8 | public abstract class SelectItem 9 | extends Node { 10 | protected SelectItem(Optional location) { 11 | super(location); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/TableElement.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | 5 | import java.util.Optional; 6 | 7 | /** 8 | * huaixin 2021/12/21 1:35 PM 9 | */ 10 | public abstract class TableElement extends Node { 11 | public TableElement(Optional location) { 12 | super(location); 13 | } 14 | 15 | @Override 16 | public R accept(AstVisitor visitor, C context) { 17 | return visitor.visitTableElement(this, context); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/TableSubquery.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.relation.QueryBody; 5 | import io.github.melin.sqlflow.tree.statement.Query; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.MoreObjects.toStringHelper; 13 | 14 | /** 15 | * huaixin 2021/12/18 11:21 PM 16 | */ 17 | public class TableSubquery extends QueryBody { 18 | private final Query query; 19 | 20 | public TableSubquery(Query query) { 21 | this(Optional.empty(), query); 22 | } 23 | 24 | public TableSubquery(NodeLocation location, Query query) { 25 | this(Optional.of(location), query); 26 | } 27 | 28 | private TableSubquery(Optional location, Query query) { 29 | super(location); 30 | this.query = query; 31 | } 32 | 33 | public Query getQuery() { 34 | return query; 35 | } 36 | 37 | @Override 38 | public R accept(AstVisitor visitor, C context) { 39 | return visitor.visitTableSubquery(this, context); 40 | } 41 | 42 | @Override 43 | public List getChildren() { 44 | return ImmutableList.of(query); 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return toStringHelper(this) 50 | .addValue(query) 51 | .toString(); 52 | } 53 | 54 | @Override 55 | public boolean equals(Object o) { 56 | if (this == o) { 57 | return true; 58 | } 59 | if (o == null || getClass() != o.getClass()) { 60 | return false; 61 | } 62 | 63 | TableSubquery tableSubquery = (TableSubquery) o; 64 | return Objects.equals(query, tableSubquery.query); 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return query.hashCode(); 70 | } 71 | 72 | @Override 73 | public boolean shallowEquals(Node other) { 74 | return sameClass(this, other); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/UpdateAssignment.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Expression; 5 | import io.github.melin.sqlflow.tree.expression.Identifier; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.lang.String.format; 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/21 12:58 PM 17 | */ 18 | public class UpdateAssignment extends Node { 19 | private final Identifier name; 20 | private final Expression value; 21 | 22 | public UpdateAssignment(Identifier name, Expression value) { 23 | this(Optional.empty(), name, value); 24 | } 25 | 26 | public UpdateAssignment(NodeLocation location, Identifier name, Expression value) { 27 | this(Optional.of(location), name, value); 28 | } 29 | 30 | private UpdateAssignment(Optional location, Identifier name, Expression value) { 31 | super(location); 32 | this.name = requireNonNull(name, "name is null"); 33 | this.value = requireNonNull(value, "value is null"); 34 | } 35 | 36 | public Identifier getName() { 37 | return name; 38 | } 39 | 40 | public Expression getValue() { 41 | return value; 42 | } 43 | 44 | @Override 45 | public R accept(AstVisitor visitor, C context) { 46 | return visitor.visitUpdateAssignment(this, context); 47 | } 48 | 49 | @Override 50 | public List getChildren() { 51 | return ImmutableList.of(name, value); 52 | } 53 | 54 | @Override 55 | public boolean equals(Object obj) { 56 | if (this == obj) { 57 | return true; 58 | } 59 | if (obj == null || getClass() != obj.getClass()) { 60 | return false; 61 | } 62 | UpdateAssignment other = (UpdateAssignment) obj; 63 | return Objects.equals(name, other.name) && 64 | Objects.equals(value, other.value); 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return Objects.hash(name, value); 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return format("%s = %s", name, value); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/Values.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Expression; 5 | import io.github.melin.sqlflow.tree.relation.QueryBody; 6 | import com.google.common.base.Joiner; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.Optional; 12 | 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/21 1:11 PM 17 | */ 18 | public final class Values extends QueryBody { 19 | private final List rows; 20 | 21 | public Values(List rows) { 22 | this(Optional.empty(), rows); 23 | } 24 | 25 | public Values(NodeLocation location, List rows) { 26 | this(Optional.of(location), rows); 27 | } 28 | 29 | private Values(Optional location, List rows) { 30 | super(location); 31 | requireNonNull(rows, "rows is null"); 32 | this.rows = ImmutableList.copyOf(rows); 33 | } 34 | 35 | public List getRows() { 36 | return rows; 37 | } 38 | 39 | @Override 40 | public R accept(AstVisitor visitor, C context) { 41 | return visitor.visitValues(this, context); 42 | } 43 | 44 | @Override 45 | public List getChildren() { 46 | return rows; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "(" + Joiner.on(", ").join(rows) + ")"; 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | return Objects.hash(rows); 57 | } 58 | 59 | @Override 60 | public boolean equals(Object obj) { 61 | if (this == obj) { 62 | return true; 63 | } 64 | if (obj == null || getClass() != obj.getClass()) { 65 | return false; 66 | } 67 | Values other = (Values) obj; 68 | return Objects.equals(this.rows, other.rows); 69 | } 70 | 71 | @Override 72 | public boolean shallowEquals(Node other) { 73 | return sameClass(this, other); 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/AllRows.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | /** 12 | * huaixin 2021/12/21 10:46 AM 13 | */ 14 | public class AllRows 15 | extends Expression { 16 | public AllRows() { 17 | this(Optional.empty()); 18 | } 19 | 20 | public AllRows(NodeLocation location) { 21 | this(Optional.of(location)); 22 | } 23 | 24 | public AllRows(Optional location) { 25 | super(location); 26 | } 27 | 28 | @Override 29 | public R accept(AstVisitor visitor, C context) { 30 | return visitor.visitAllRows(this, context); 31 | } 32 | 33 | @Override 34 | public List getChildren() { 35 | return ImmutableList.of(); 36 | } 37 | 38 | @Override 39 | public boolean equals(Object o) { 40 | if (this == o) { 41 | return true; 42 | } 43 | return (o != null) && (getClass() == o.getClass()); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return getClass().hashCode(); 49 | } 50 | 51 | @Override 52 | public boolean shallowEquals(Node other) { 53 | return sameClass(this, other); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/ArrayConstructor.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 10:47 AM 16 | */ 17 | public class ArrayConstructor extends Expression { 18 | public static final String ARRAY_CONSTRUCTOR = "ARRAY_CONSTRUCTOR"; 19 | 20 | private final List values; 21 | 22 | public ArrayConstructor(List values) { 23 | this(Optional.empty(), values); 24 | } 25 | 26 | public ArrayConstructor(NodeLocation location, List values) { 27 | this(Optional.of(location), values); 28 | } 29 | 30 | private ArrayConstructor(Optional location, List values) { 31 | super(location); 32 | requireNonNull(values, "values is null"); 33 | this.values = ImmutableList.copyOf(values); 34 | } 35 | 36 | public List getValues() { 37 | return values; 38 | } 39 | 40 | @Override 41 | public R accept(AstVisitor visitor, C context) { 42 | return visitor.visitArrayConstructor(this, context); 43 | } 44 | 45 | @Override 46 | public List getChildren() { 47 | return values; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) { 53 | return true; 54 | } 55 | if (o == null || getClass() != o.getClass()) { 56 | return false; 57 | } 58 | 59 | ArrayConstructor that = (ArrayConstructor) o; 60 | return Objects.equals(values, that.values); 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return values.hashCode(); 66 | } 67 | 68 | @Override 69 | public boolean shallowEquals(Node other) { 70 | return Node.sameClass(this, other); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/CoalesceExpression.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.Preconditions.checkArgument; 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/21 11:25 AM 17 | */ 18 | public class CoalesceExpression extends Expression { 19 | private final List operands; 20 | 21 | public CoalesceExpression(Expression first, Expression second, Expression... additional) { 22 | this(Optional.empty(), ImmutableList.builder() 23 | .add(first, second) 24 | .add(additional) 25 | .build()); 26 | } 27 | 28 | public CoalesceExpression(List operands) { 29 | this(Optional.empty(), operands); 30 | } 31 | 32 | public CoalesceExpression(NodeLocation location, List operands) { 33 | this(Optional.of(location), operands); 34 | } 35 | 36 | private CoalesceExpression(Optional location, List operands) { 37 | super(location); 38 | requireNonNull(operands, "operands is null"); 39 | checkArgument(operands.size() >= 2, "must have at least two operands"); 40 | 41 | this.operands = ImmutableList.copyOf(operands); 42 | } 43 | 44 | public List getOperands() { 45 | return operands; 46 | } 47 | 48 | @Override 49 | public R accept(AstVisitor visitor, C context) { 50 | return visitor.visitCoalesceExpression(this, context); 51 | } 52 | 53 | @Override 54 | public List getChildren() { 55 | return operands; 56 | } 57 | 58 | @Override 59 | public boolean equals(Object o) { 60 | if (this == o) { 61 | return true; 62 | } 63 | if (o == null || getClass() != o.getClass()) { 64 | return false; 65 | } 66 | 67 | CoalesceExpression that = (CoalesceExpression) o; 68 | return Objects.equals(operands, that.operands); 69 | } 70 | 71 | @Override 72 | public int hashCode() { 73 | return operands.hashCode(); 74 | } 75 | 76 | @Override 77 | public boolean shallowEquals(Node other) { 78 | return Node.sameClass(this, other); 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/CurrentCatalog.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | /** 12 | * huaixin 2021/12/21 10:36 AM 13 | */ 14 | public class CurrentCatalog extends Expression { 15 | public CurrentCatalog(NodeLocation location) { 16 | this(Optional.of(location)); 17 | } 18 | 19 | private CurrentCatalog(Optional location) { 20 | super(location); 21 | } 22 | 23 | @Override 24 | public List getChildren() { 25 | return ImmutableList.of(); 26 | } 27 | 28 | @Override 29 | public R accept(AstVisitor visitor, C context) { 30 | return visitor.visitCurrentCatalog(this, context); 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | return getClass().hashCode(); 36 | } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | if (this == obj) { 41 | return true; 42 | } 43 | if ((obj == null) || (getClass() != obj.getClass())) { 44 | return false; 45 | } 46 | return true; 47 | } 48 | 49 | @Override 50 | public boolean shallowEquals(Node other) { 51 | return Node.sameClass(this, other); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/CurrentPath.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | /** 12 | * huaixin 2021/12/21 10:36 AM 13 | */ 14 | public class CurrentPath extends Expression { 15 | public CurrentPath(NodeLocation location) { 16 | this(Optional.of(location)); 17 | } 18 | 19 | private CurrentPath(Optional location) { 20 | super(location); 21 | } 22 | 23 | @Override 24 | public List getChildren() { 25 | return ImmutableList.of(); 26 | } 27 | 28 | @Override 29 | public R accept(AstVisitor visitor, C context) { 30 | return visitor.visitCurrentPath(this, context); 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | return getClass().hashCode(); 36 | } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | if (this == obj) { 41 | return true; 42 | } 43 | if ((obj == null) || (getClass() != obj.getClass())) { 44 | return false; 45 | } 46 | return true; 47 | } 48 | 49 | @Override 50 | public boolean shallowEquals(Node other) { 51 | return Node.sameClass(this, other); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/CurrentSchema.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | /** 12 | * huaixin 2021/12/21 10:37 AM 13 | */ 14 | public class CurrentSchema extends Expression { 15 | public CurrentSchema(NodeLocation location) { 16 | this(Optional.of(location)); 17 | } 18 | 19 | private CurrentSchema(Optional location) { 20 | super(location); 21 | } 22 | 23 | @Override 24 | public List getChildren() { 25 | return ImmutableList.of(); 26 | } 27 | 28 | @Override 29 | public R accept(AstVisitor visitor, C context) { 30 | return visitor.visitCurrentSchema(this, context); 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | return getClass().hashCode(); 36 | } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | if (this == obj) { 41 | return true; 42 | } 43 | if ((obj == null) || (getClass() != obj.getClass())) { 44 | return false; 45 | } 46 | return true; 47 | } 48 | 49 | @Override 50 | public boolean shallowEquals(Node other) { 51 | return Node.sameClass(this, other); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/CurrentUser.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | /** 12 | * huaixin 2021/12/21 10:41 AM 13 | */ 14 | public class CurrentUser 15 | extends Expression { 16 | public CurrentUser() { 17 | this(Optional.empty()); 18 | } 19 | 20 | public CurrentUser(NodeLocation location) { 21 | this(Optional.of(location)); 22 | } 23 | 24 | private CurrentUser(Optional location) { 25 | super(location); 26 | } 27 | 28 | @Override 29 | public List getChildren() { 30 | return ImmutableList.of(); 31 | } 32 | 33 | @Override 34 | public R accept(AstVisitor visitor, C context) { 35 | return visitor.visitCurrentUser(this, context); 36 | } 37 | 38 | @Override 39 | public int hashCode() { 40 | return getClass().hashCode(); 41 | } 42 | 43 | @Override 44 | public boolean equals(Object obj) { 45 | if (this == obj) { 46 | return true; 47 | } 48 | if ((obj == null) || (getClass() != obj.getClass())) { 49 | return false; 50 | } 51 | return true; 52 | } 53 | 54 | @Override 55 | public boolean shallowEquals(Node other) { 56 | return Node.sameClass(this, other); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/ExistsPredicate.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 10:52 AM 16 | */ 17 | public class ExistsPredicate extends Expression { 18 | private final Expression subquery; 19 | 20 | public ExistsPredicate(Expression subquery) { 21 | this(Optional.empty(), subquery); 22 | } 23 | 24 | public ExistsPredicate(NodeLocation location, Expression subquery) { 25 | this(Optional.of(location), subquery); 26 | } 27 | 28 | private ExistsPredicate(Optional location, Expression subquery) { 29 | super(location); 30 | requireNonNull(subquery, "subquery is null"); 31 | this.subquery = subquery; 32 | } 33 | 34 | public Expression getSubquery() { 35 | return subquery; 36 | } 37 | 38 | @Override 39 | public R accept(AstVisitor visitor, C context) { 40 | return visitor.visitExists(this, context); 41 | } 42 | 43 | @Override 44 | public List getChildren() { 45 | return ImmutableList.of(subquery); 46 | } 47 | 48 | @Override 49 | public boolean equals(Object o) { 50 | if (this == o) { 51 | return true; 52 | } 53 | if (o == null || getClass() != o.getClass()) { 54 | return false; 55 | } 56 | 57 | ExistsPredicate that = (ExistsPredicate) o; 58 | return Objects.equals(subquery, that.subquery); 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return subquery.hashCode(); 64 | } 65 | 66 | @Override 67 | public boolean shallowEquals(Node other) { 68 | return Node.sameClass(this, other); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/Expression.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * huaixin 2021/12/18 9:54 PM 11 | */ 12 | public abstract class Expression 13 | extends Node { 14 | public Expression(Optional location) { 15 | super(location); 16 | } 17 | 18 | /** 19 | * Accessible for {@link AstVisitor}, use {@link AstVisitor#process(Node, Object)} instead. 20 | */ 21 | @Override 22 | public R accept(AstVisitor visitor, C context) { 23 | return visitor.visitExpression(this, context); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/FieldReference.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import com.google.common.collect.ImmutableList; 6 | 7 | import java.util.List; 8 | import java.util.Optional; 9 | 10 | import static com.google.common.base.Preconditions.checkArgument; 11 | 12 | /** 13 | * huaixin 2021/12/24 10:32 PM 14 | */ 15 | public class FieldReference 16 | extends Expression { 17 | private final int fieldIndex; 18 | 19 | public FieldReference(int fieldIndex) { 20 | super(Optional.empty()); 21 | checkArgument(fieldIndex >= 0, "fieldIndex must be >= 0"); 22 | 23 | this.fieldIndex = fieldIndex; 24 | } 25 | 26 | public int getFieldIndex() { 27 | return fieldIndex; 28 | } 29 | 30 | @Override 31 | public R accept(AstVisitor visitor, C context) { 32 | return visitor.visitFieldReference(this, context); 33 | } 34 | 35 | @Override 36 | public List getChildren() { 37 | return ImmutableList.of(); 38 | } 39 | 40 | @Override 41 | public boolean equals(Object o) { 42 | if (this == o) { 43 | return true; 44 | } 45 | if (o == null || getClass() != o.getClass()) { 46 | return false; 47 | } 48 | 49 | FieldReference that = (FieldReference) o; 50 | 51 | return fieldIndex == that.fieldIndex; 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | return fieldIndex; 57 | } 58 | 59 | @Override 60 | public boolean shallowEquals(Node other) { 61 | if (!Node.sameClass(this, other)) { 62 | return false; 63 | } 64 | 65 | return fieldIndex == ((FieldReference) other).fieldIndex; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/Format.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.Preconditions.checkArgument; 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/21 10:39 AM 17 | */ 18 | public class Format extends Expression { 19 | private final List arguments; 20 | 21 | public Format(List arguments) { 22 | this(Optional.empty(), arguments); 23 | } 24 | 25 | public Format(NodeLocation location, List arguments) { 26 | this(Optional.of(location), arguments); 27 | } 28 | 29 | private Format(Optional location, List arguments) { 30 | super(location); 31 | requireNonNull(arguments, "arguments is null"); 32 | checkArgument(arguments.size() >= 2, "must have at least two arguments"); 33 | this.arguments = ImmutableList.copyOf(arguments); 34 | } 35 | 36 | public List getArguments() { 37 | return arguments; 38 | } 39 | 40 | @Override 41 | public R accept(AstVisitor visitor, C context) { 42 | return visitor.visitFormat(this, context); 43 | } 44 | 45 | @Override 46 | public List getChildren() { 47 | return arguments; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object obj) { 52 | if (this == obj) { 53 | return true; 54 | } 55 | if (obj == null || getClass() != obj.getClass()) { 56 | return false; 57 | } 58 | 59 | Format o = (Format) obj; 60 | return Objects.equals(arguments, o.arguments); 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return Objects.hash(arguments); 66 | } 67 | 68 | @Override 69 | public boolean shallowEquals(Node other) { 70 | return Node.sameClass(this, other); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/GroupingOperation.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import io.github.melin.sqlflow.tree.QualifiedName; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.Preconditions.checkArgument; 13 | import static com.google.common.collect.ImmutableList.toImmutableList; 14 | import static java.util.Objects.requireNonNull; 15 | 16 | /** 17 | * huaixin 2021/12/21 10:57 AM 18 | */ 19 | public class GroupingOperation 20 | extends Expression { 21 | private final List groupingColumns; 22 | 23 | public GroupingOperation(Optional location, List groupingColumns) { 24 | super(location); 25 | requireNonNull(groupingColumns); 26 | checkArgument(!groupingColumns.isEmpty(), "grouping operation columns cannot be empty"); 27 | this.groupingColumns = groupingColumns.stream() 28 | .map(DereferenceExpression::from) 29 | .collect(toImmutableList()); 30 | } 31 | 32 | public List getGroupingColumns() { 33 | return groupingColumns; 34 | } 35 | 36 | @Override 37 | public R accept(AstVisitor visitor, C context) { 38 | return visitor.visitGroupingOperation(this, context); 39 | } 40 | 41 | @Override 42 | public List getChildren() { 43 | return groupingColumns; 44 | } 45 | 46 | @Override 47 | public boolean equals(Object o) { 48 | if (this == o) { 49 | return true; 50 | } 51 | if (o == null || getClass() != o.getClass()) { 52 | return false; 53 | } 54 | GroupingOperation other = (GroupingOperation) o; 55 | return Objects.equals(groupingColumns, other.groupingColumns); 56 | } 57 | 58 | @Override 59 | public int hashCode() { 60 | return Objects.hash(groupingColumns); 61 | } 62 | 63 | @Override 64 | public boolean shallowEquals(Node other) { 65 | return Node.sameClass(this, other); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/InListExpression.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.Preconditions.checkArgument; 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/21 11:26 AM 17 | */ 18 | public class InListExpression extends Expression { 19 | private final List values; 20 | 21 | public InListExpression(List values) { 22 | this(Optional.empty(), values); 23 | } 24 | 25 | public InListExpression(NodeLocation location, List values) { 26 | this(Optional.of(location), values); 27 | } 28 | 29 | private InListExpression(Optional location, List values) { 30 | super(location); 31 | requireNonNull(values, "values is null"); 32 | checkArgument(!values.isEmpty(), "values cannot be empty"); 33 | this.values = ImmutableList.copyOf(values); 34 | } 35 | 36 | public List getValues() { 37 | return values; 38 | } 39 | 40 | @Override 41 | public R accept(AstVisitor visitor, C context) { 42 | return visitor.visitInListExpression(this, context); 43 | } 44 | 45 | @Override 46 | public List getChildren() { 47 | return values; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) { 53 | return true; 54 | } 55 | if (o == null || getClass() != o.getClass()) { 56 | return false; 57 | } 58 | 59 | InListExpression that = (InListExpression) o; 60 | return Objects.equals(values, that.values); 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return values.hashCode(); 66 | } 67 | 68 | @Override 69 | public boolean shallowEquals(Node other) { 70 | return sameClass(this, other); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/InPredicate.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | /** 13 | * huaixin 2021/12/21 11:07 AM 14 | */ 15 | public class InPredicate extends Expression { 16 | private final Expression value; 17 | private final Expression valueList; 18 | 19 | public InPredicate(Expression value, Expression valueList) { 20 | this(Optional.empty(), value, valueList); 21 | } 22 | 23 | public InPredicate(NodeLocation location, Expression value, Expression valueList) { 24 | this(Optional.of(location), value, valueList); 25 | } 26 | 27 | private InPredicate(Optional location, Expression value, Expression valueList) { 28 | super(location); 29 | this.value = value; 30 | this.valueList = valueList; 31 | } 32 | 33 | public Expression getValue() { 34 | return value; 35 | } 36 | 37 | public Expression getValueList() { 38 | return valueList; 39 | } 40 | 41 | @Override 42 | public R accept(AstVisitor visitor, C context) { 43 | return visitor.visitInPredicate(this, context); 44 | } 45 | 46 | @Override 47 | public List getChildren() { 48 | return ImmutableList.of(value, valueList); 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) { 54 | return true; 55 | } 56 | if (o == null || getClass() != o.getClass()) { 57 | return false; 58 | } 59 | 60 | InPredicate that = (InPredicate) o; 61 | return Objects.equals(value, that.value) && 62 | Objects.equals(valueList, that.valueList); 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | return Objects.hash(value, valueList); 68 | } 69 | 70 | @Override 71 | public boolean shallowEquals(Node other) { 72 | return Node.sameClass(this, other); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/IsNotNullPredicate.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 11:23 AM 16 | */ 17 | public class IsNotNullPredicate extends Expression { 18 | private final Expression value; 19 | 20 | public IsNotNullPredicate(Expression value) { 21 | this(Optional.empty(), value); 22 | } 23 | 24 | public IsNotNullPredicate(NodeLocation location, Expression value) { 25 | this(Optional.of(location), value); 26 | } 27 | 28 | private IsNotNullPredicate(Optional location, Expression value) { 29 | super(location); 30 | requireNonNull(value, "value is null"); 31 | this.value = value; 32 | } 33 | 34 | public Expression getValue() { 35 | return value; 36 | } 37 | 38 | @Override 39 | public R accept(AstVisitor visitor, C context) { 40 | return visitor.visitIsNotNullPredicate(this, context); 41 | } 42 | 43 | @Override 44 | public List getChildren() { 45 | return ImmutableList.of(value); 46 | } 47 | 48 | @Override 49 | public boolean equals(Object o) { 50 | if (this == o) { 51 | return true; 52 | } 53 | if (o == null || getClass() != o.getClass()) { 54 | return false; 55 | } 56 | 57 | IsNotNullPredicate that = (IsNotNullPredicate) o; 58 | return Objects.equals(value, that.value); 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return value.hashCode(); 64 | } 65 | 66 | @Override 67 | public boolean shallowEquals(Node other) { 68 | return Node.sameClass(this, other); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/IsNullPredicate.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 11:22 AM 16 | */ 17 | public class IsNullPredicate extends Expression { 18 | private final Expression value; 19 | 20 | public IsNullPredicate(Expression value) { 21 | this(Optional.empty(), value); 22 | } 23 | 24 | public IsNullPredicate(NodeLocation location, Expression value) { 25 | this(Optional.of(location), value); 26 | } 27 | 28 | private IsNullPredicate(Optional location, Expression value) { 29 | super(location); 30 | requireNonNull(value, "value is null"); 31 | this.value = value; 32 | } 33 | 34 | public Expression getValue() { 35 | return value; 36 | } 37 | 38 | @Override 39 | public R accept(AstVisitor visitor, C context) { 40 | return visitor.visitIsNullPredicate(this, context); 41 | } 42 | 43 | @Override 44 | public List getChildren() { 45 | return ImmutableList.of(value); 46 | } 47 | 48 | @Override 49 | public boolean equals(Object o) { 50 | if (this == o) { 51 | return true; 52 | } 53 | if (o == null || getClass() != o.getClass()) { 54 | return false; 55 | } 56 | 57 | IsNullPredicate that = (IsNullPredicate) o; 58 | return Objects.equals(value, that.value); 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return value.hashCode(); 64 | } 65 | 66 | @Override 67 | public boolean shallowEquals(Node other) { 68 | return Node.sameClass(this, other); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/LabelDereference.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import com.google.common.collect.ImmutableList; 6 | 7 | import java.util.List; 8 | import java.util.Objects; 9 | import java.util.Optional; 10 | 11 | import static java.util.Objects.requireNonNull; 12 | 13 | /** 14 | * huaixin 2021/12/21 11:42 AM 15 | */ 16 | public class LabelDereference extends Expression { 17 | private final String label; 18 | private final Optional reference; 19 | 20 | public LabelDereference(String label, SymbolReference reference) { 21 | this(label, Optional.of(requireNonNull(reference, "reference is null"))); 22 | } 23 | 24 | public LabelDereference(String label) { 25 | this(label, Optional.empty()); 26 | } 27 | 28 | public LabelDereference(String label, Optional reference) { 29 | super(Optional.empty()); 30 | this.label = requireNonNull(label, "label is null"); 31 | this.reference = requireNonNull(reference, "reference is null"); 32 | } 33 | 34 | public String getLabel() { 35 | return label; 36 | } 37 | 38 | public Optional getReference() { 39 | return reference; 40 | } 41 | 42 | @Override 43 | public R accept(AstVisitor visitor, C context) { 44 | return visitor.visitLabelDereference(this, context); 45 | } 46 | 47 | @Override 48 | public List getChildren() { 49 | return reference.>map(ImmutableList::of).orElseGet(ImmutableList::of); 50 | } 51 | 52 | @Override 53 | public boolean equals(Object o) { 54 | if (this == o) { 55 | return true; 56 | } 57 | if (o == null || getClass() != o.getClass()) { 58 | return false; 59 | } 60 | LabelDereference that = (LabelDereference) o; 61 | return Objects.equals(label, that.label) && 62 | Objects.equals(reference, that.reference); 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | return Objects.hash(label, reference); 68 | } 69 | 70 | @Override 71 | public boolean shallowEquals(Node other) { 72 | if (!sameClass(this, other)) { 73 | return false; 74 | } 75 | 76 | return label.equals(((LabelDereference) other).label); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/LambdaArgumentDeclaration.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import com.google.common.collect.ImmutableList; 6 | 7 | import java.util.List; 8 | import java.util.Objects; 9 | import java.util.Optional; 10 | 11 | /** 12 | * huaixin 2021/12/21 10:56 AM 13 | */ 14 | public class LambdaArgumentDeclaration 15 | extends Expression { 16 | private final Identifier name; 17 | 18 | public LambdaArgumentDeclaration(Identifier name) { 19 | super(Optional.empty()); 20 | this.name = name; 21 | } 22 | 23 | public Identifier getName() { 24 | return name; 25 | } 26 | 27 | @Override 28 | public R accept(AstVisitor visitor, C context) { 29 | return visitor.visitLambdaArgumentDeclaration(this, context); 30 | } 31 | 32 | @Override 33 | public List getChildren() { 34 | return ImmutableList.of(); 35 | } 36 | 37 | @Override 38 | public boolean equals(Object o) { 39 | if (this == o) { 40 | return true; 41 | } 42 | if (o == null || getClass() != o.getClass()) { 43 | return false; 44 | } 45 | LambdaArgumentDeclaration that = (LambdaArgumentDeclaration) o; 46 | return Objects.equals(name, that.name); 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | return Objects.hash(name); 52 | } 53 | 54 | @Override 55 | public boolean shallowEquals(Node other) { 56 | if (!Node.sameClass(this, other)) { 57 | return false; 58 | } 59 | 60 | return name.equals(((LambdaArgumentDeclaration) other).getName()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/NotExpression.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 11:15 AM 16 | */ 17 | public class NotExpression extends Expression { 18 | private final Expression value; 19 | 20 | public NotExpression(Expression value) { 21 | this(Optional.empty(), value); 22 | } 23 | 24 | public NotExpression(NodeLocation location, Expression value) { 25 | this(Optional.of(location), value); 26 | } 27 | 28 | private NotExpression(Optional location, Expression value) { 29 | super(location); 30 | requireNonNull(value, "value is null"); 31 | this.value = value; 32 | } 33 | 34 | public Expression getValue() { 35 | return value; 36 | } 37 | 38 | @Override 39 | public R accept(AstVisitor visitor, C context) { 40 | return visitor.visitNotExpression(this, context); 41 | } 42 | 43 | @Override 44 | public List getChildren() { 45 | return ImmutableList.of(value); 46 | } 47 | 48 | @Override 49 | public boolean equals(Object o) { 50 | if (this == o) { 51 | return true; 52 | } 53 | if (o == null || getClass() != o.getClass()) { 54 | return false; 55 | } 56 | 57 | NotExpression that = (NotExpression) o; 58 | return Objects.equals(value, that.value); 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return value.hashCode(); 64 | } 65 | 66 | @Override 67 | public boolean shallowEquals(Node other) { 68 | return Node.sameClass(this, other); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/NullIfExpression.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | /** 13 | * huaixin 2021/12/21 11:16 AM 14 | */ 15 | public class NullIfExpression extends Expression { 16 | private final Expression first; 17 | private final Expression second; 18 | 19 | public NullIfExpression(Expression first, Expression second) { 20 | this(Optional.empty(), first, second); 21 | } 22 | 23 | public NullIfExpression(NodeLocation location, Expression first, Expression second) { 24 | this(Optional.of(location), first, second); 25 | } 26 | 27 | private NullIfExpression(Optional location, Expression first, Expression second) { 28 | super(location); 29 | this.first = first; 30 | this.second = second; 31 | } 32 | 33 | public Expression getFirst() { 34 | return first; 35 | } 36 | 37 | public Expression getSecond() { 38 | return second; 39 | } 40 | 41 | @Override 42 | public R accept(AstVisitor visitor, C context) { 43 | return visitor.visitNullIfExpression(this, context); 44 | } 45 | 46 | @Override 47 | public List getChildren() { 48 | return ImmutableList.of(first, second); 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) { 54 | return true; 55 | } 56 | if (o == null || getClass() != o.getClass()) { 57 | return false; 58 | } 59 | 60 | NullIfExpression that = (NullIfExpression) o; 61 | return Objects.equals(first, that.first) && 62 | Objects.equals(second, that.second); 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | return Objects.hash(first, second); 68 | } 69 | 70 | @Override 71 | public boolean shallowEquals(Node other) { 72 | return Node.sameClass(this, other); 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/Parameter.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | /** 13 | * huaixin 2021/12/21 1:02 PM 14 | */ 15 | public class Parameter extends Expression { 16 | private final int position; 17 | 18 | public Parameter(int id) { 19 | this(Optional.empty(), id); 20 | } 21 | 22 | public Parameter(NodeLocation location, int id) { 23 | this(Optional.of(location), id); 24 | } 25 | 26 | private Parameter(Optional location, int position) { 27 | super(location); 28 | this.position = position; 29 | } 30 | 31 | public int getPosition() { 32 | return position; 33 | } 34 | 35 | @Override 36 | public R accept(AstVisitor visitor, C context) { 37 | return visitor.visitParameter(this, context); 38 | } 39 | 40 | @Override 41 | public List getChildren() { 42 | return ImmutableList.of(); 43 | } 44 | 45 | @Override 46 | public boolean equals(Object o) { 47 | if (this == o) { 48 | return true; 49 | } 50 | if (o == null || getClass() != o.getClass()) { 51 | return false; 52 | } 53 | 54 | Parameter that = (Parameter) o; 55 | return Objects.equals(position, that.position); 56 | } 57 | 58 | @Override 59 | public int hashCode() { 60 | return position; 61 | } 62 | 63 | @Override 64 | public boolean shallowEquals(Node other) { 65 | if (!sameClass(this, other)) { 66 | return false; 67 | } 68 | 69 | return position == ((Parameter) other).position; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/Row.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 10:20 AM 16 | */ 17 | public final class Row extends Expression { 18 | private final List items; 19 | 20 | public Row(List items) { 21 | this(Optional.empty(), items); 22 | } 23 | 24 | public Row(NodeLocation location, List items) { 25 | this(Optional.of(location), items); 26 | } 27 | 28 | private Row(Optional location, List items) { 29 | super(location); 30 | requireNonNull(items, "items is null"); 31 | this.items = ImmutableList.copyOf(items); 32 | } 33 | 34 | public List getItems() { 35 | return items; 36 | } 37 | 38 | @Override 39 | public R accept(AstVisitor visitor, C context) { 40 | return visitor.visitRow(this, context); 41 | } 42 | 43 | @Override 44 | public List getChildren() { 45 | return items; 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | return Objects.hash(items); 51 | } 52 | 53 | @Override 54 | public boolean equals(Object obj) { 55 | if (this == obj) { 56 | return true; 57 | } 58 | if (obj == null || getClass() != obj.getClass()) { 59 | return false; 60 | } 61 | Row other = (Row) obj; 62 | return Objects.equals(this.items, other.items); 63 | } 64 | 65 | @Override 66 | public boolean shallowEquals(Node other) { 67 | return Node.sameClass(this, other); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/SubqueryExpression.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import io.github.melin.sqlflow.tree.statement.Query; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.Optional; 12 | 13 | /** 14 | * huaixin 2021/12/21 10:51 AM 15 | */ 16 | public class SubqueryExpression 17 | extends Expression { 18 | private final Query query; 19 | 20 | public SubqueryExpression(Query query) { 21 | this(Optional.empty(), query); 22 | } 23 | 24 | public SubqueryExpression(NodeLocation location, Query query) { 25 | this(Optional.of(location), query); 26 | } 27 | 28 | private SubqueryExpression(Optional location, Query query) { 29 | super(location); 30 | this.query = query; 31 | } 32 | 33 | public Query getQuery() { 34 | return query; 35 | } 36 | 37 | @Override 38 | public R accept(AstVisitor visitor, C context) { 39 | return visitor.visitSubqueryExpression(this, context); 40 | } 41 | 42 | @Override 43 | public List getChildren() { 44 | return ImmutableList.of(query); 45 | } 46 | 47 | @Override 48 | public boolean equals(Object o) { 49 | if (this == o) { 50 | return true; 51 | } 52 | if (o == null || getClass() != o.getClass()) { 53 | return false; 54 | } 55 | 56 | SubqueryExpression that = (SubqueryExpression) o; 57 | return Objects.equals(query, that.query); 58 | } 59 | 60 | @Override 61 | public int hashCode() { 62 | return query.hashCode(); 63 | } 64 | 65 | @Override 66 | public boolean shallowEquals(Node other) { 67 | return sameClass(this, other); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/SubscriptExpression.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 10:50 AM 16 | */ 17 | public class SubscriptExpression extends Expression { 18 | private final Expression base; 19 | private final Expression index; 20 | 21 | public SubscriptExpression(Expression base, Expression index) { 22 | this(Optional.empty(), base, index); 23 | } 24 | 25 | public SubscriptExpression(NodeLocation location, Expression base, Expression index) { 26 | this(Optional.of(location), base, index); 27 | } 28 | 29 | private SubscriptExpression(Optional location, Expression base, Expression index) { 30 | super(location); 31 | this.base = requireNonNull(base, "base is null"); 32 | this.index = requireNonNull(index, "index is null"); 33 | } 34 | 35 | @Override 36 | public R accept(AstVisitor visitor, C context) { 37 | return visitor.visitSubscriptExpression(this, context); 38 | } 39 | 40 | @Override 41 | public List getChildren() { 42 | return ImmutableList.of(base, index); 43 | } 44 | 45 | public Expression getBase() { 46 | return base; 47 | } 48 | 49 | public Expression getIndex() { 50 | return index; 51 | } 52 | 53 | @Override 54 | public boolean equals(Object o) { 55 | if (this == o) { 56 | return true; 57 | } 58 | if (o == null || getClass() != o.getClass()) { 59 | return false; 60 | } 61 | 62 | SubscriptExpression that = (SubscriptExpression) o; 63 | 64 | return Objects.equals(this.base, that.base) && Objects.equals(this.index, that.index); 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return Objects.hash(base, index); 70 | } 71 | 72 | @Override 73 | public boolean shallowEquals(Node other) { 74 | return Node.sameClass(this, other); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/SymbolReference.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import com.google.common.collect.ImmutableList; 6 | 7 | import java.util.List; 8 | import java.util.Objects; 9 | import java.util.Optional; 10 | 11 | /** 12 | * huaixin 2021/12/21 11:42 AM 13 | */ 14 | public class SymbolReference extends Expression { 15 | private final String name; 16 | 17 | public SymbolReference(String name) { 18 | super(Optional.empty()); 19 | this.name = name; 20 | } 21 | 22 | public String getName() { 23 | return name; 24 | } 25 | 26 | @Override 27 | public R accept(AstVisitor visitor, C context) { 28 | return visitor.visitSymbolReference(this, context); 29 | } 30 | 31 | @Override 32 | public List getChildren() { 33 | return ImmutableList.of(); 34 | } 35 | 36 | @Override 37 | public boolean equals(Object o) { 38 | if (this == o) { 39 | return true; 40 | } 41 | if (o == null || getClass() != o.getClass()) { 42 | return false; 43 | } 44 | SymbolReference that = (SymbolReference) o; 45 | return Objects.equals(name, that.name); 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | return Objects.hash(name); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/TryExpression.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 10:53 AM 16 | */ 17 | public class TryExpression 18 | extends Expression { 19 | private final Expression innerExpression; 20 | 21 | public TryExpression(Expression innerExpression) { 22 | this(Optional.empty(), innerExpression); 23 | } 24 | 25 | public TryExpression(NodeLocation location, Expression innerExpression) { 26 | this(Optional.of(location), innerExpression); 27 | } 28 | 29 | private TryExpression(Optional location, Expression innerExpression) { 30 | super(location); 31 | this.innerExpression = requireNonNull(innerExpression, "innerExpression is null"); 32 | } 33 | 34 | public Expression getInnerExpression() { 35 | return innerExpression; 36 | } 37 | 38 | @Override 39 | public R accept(AstVisitor visitor, C context) { 40 | return visitor.visitTryExpression(this, context); 41 | } 42 | 43 | @Override 44 | public List getChildren() { 45 | return ImmutableList.of(innerExpression); 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | if (this == obj) { 51 | return true; 52 | } 53 | if ((obj == null) || (getClass() != obj.getClass())) { 54 | return false; 55 | } 56 | TryExpression o = (TryExpression) obj; 57 | return Objects.equals(innerExpression, o.innerExpression); 58 | } 59 | 60 | @Override 61 | public int hashCode() { 62 | return Objects.hash(innerExpression); 63 | } 64 | 65 | @Override 66 | public boolean shallowEquals(Node other) { 67 | return Node.sameClass(this, other); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/expression/WhenClause.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.expression; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | /** 13 | * huaixin 2021/12/21 11:06 AM 14 | */ 15 | public class WhenClause 16 | extends Expression { 17 | private final Expression operand; 18 | private final Expression result; 19 | 20 | public WhenClause(Expression operand, Expression result) { 21 | this(Optional.empty(), operand, result); 22 | } 23 | 24 | public WhenClause(NodeLocation location, Expression operand, Expression result) { 25 | this(Optional.of(location), operand, result); 26 | } 27 | 28 | private WhenClause(Optional location, Expression operand, Expression result) { 29 | super(location); 30 | this.operand = operand; 31 | this.result = result; 32 | } 33 | 34 | public Expression getOperand() { 35 | return operand; 36 | } 37 | 38 | public Expression getResult() { 39 | return result; 40 | } 41 | 42 | @Override 43 | public R accept(AstVisitor visitor, C context) { 44 | return visitor.visitWhenClause(this, context); 45 | } 46 | 47 | @Override 48 | public List getChildren() { 49 | return ImmutableList.of(operand, result); 50 | } 51 | 52 | @Override 53 | public boolean equals(Object o) { 54 | if (this == o) { 55 | return true; 56 | } 57 | if (o == null || getClass() != o.getClass()) { 58 | return false; 59 | } 60 | 61 | WhenClause that = (WhenClause) o; 62 | return Objects.equals(operand, that.operand) && 63 | Objects.equals(result, that.result); 64 | } 65 | 66 | @Override 67 | public int hashCode() { 68 | return Objects.hash(operand, result); 69 | } 70 | 71 | @Override 72 | public boolean shallowEquals(Node other) { 73 | return Node.sameClass(this, other); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/filter/Offset.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.filter; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Expression; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | import io.github.melin.sqlflow.tree.literal.LongLiteral; 8 | import com.google.common.collect.ImmutableList; 9 | 10 | import java.util.List; 11 | import java.util.Objects; 12 | import java.util.Optional; 13 | 14 | import static com.google.common.base.MoreObjects.toStringHelper; 15 | import static com.google.common.base.Preconditions.checkArgument; 16 | 17 | /** 18 | * huaixin 2021/12/19 9:35 PM 19 | */ 20 | public class Offset extends Node { 21 | private final Expression rowCount; 22 | 23 | public Offset(Expression rowCount) { 24 | this(Optional.empty(), rowCount); 25 | } 26 | 27 | public Offset(NodeLocation location, Expression rowCount) { 28 | this(Optional.of(location), rowCount); 29 | } 30 | 31 | public Offset(Optional location, Expression rowCount) { 32 | super(location); 33 | checkArgument(rowCount instanceof LongLiteral, 34 | "unexpected rowCount class: %s", 35 | rowCount.getClass().getSimpleName()); 36 | this.rowCount = rowCount; 37 | } 38 | 39 | public Expression getRowCount() { 40 | return rowCount; 41 | } 42 | 43 | @Override 44 | public R accept(AstVisitor visitor, C context) { 45 | return visitor.visitOffset(this, context); 46 | } 47 | 48 | @Override 49 | public List getChildren() { 50 | return ImmutableList.of(rowCount); 51 | } 52 | 53 | @Override 54 | public boolean equals(Object obj) { 55 | if (this == obj) { 56 | return true; 57 | } 58 | if ((obj == null) || (getClass() != obj.getClass())) { 59 | return false; 60 | } 61 | Offset o = (Offset) obj; 62 | return Objects.equals(rowCount, o.rowCount); 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | return Objects.hash(rowCount); 68 | } 69 | 70 | @Override 71 | public String toString() { 72 | return toStringHelper(this) 73 | .add("rowCount", rowCount) 74 | .toString(); 75 | } 76 | 77 | @Override 78 | public boolean shallowEquals(Node other) { 79 | return sameClass(this, other); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/group/Cube.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.group; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Expression; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.Optional; 12 | 13 | import static com.google.common.base.MoreObjects.toStringHelper; 14 | import static java.util.Objects.requireNonNull; 15 | 16 | /** 17 | * huaixin 2021/12/21 10:02 AM 18 | */ 19 | public final class Cube extends GroupingElement { 20 | private final List columns; 21 | 22 | public Cube(List columns) { 23 | this(Optional.empty(), columns); 24 | } 25 | 26 | public Cube(NodeLocation location, List columns) { 27 | this(Optional.of(location), columns); 28 | } 29 | 30 | private Cube(Optional location, List columns) { 31 | super(location); 32 | this.columns = ImmutableList.copyOf(requireNonNull(columns, "columns is null")); 33 | } 34 | 35 | @Override 36 | public List getExpressions() { 37 | return columns; 38 | } 39 | 40 | @Override 41 | public R accept(AstVisitor visitor, C context) { 42 | return visitor.visitCube(this, context); 43 | } 44 | 45 | @Override 46 | public List getChildren() { 47 | return ImmutableList.of(); 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) { 53 | return true; 54 | } 55 | if (o == null || getClass() != o.getClass()) { 56 | return false; 57 | } 58 | Cube cube = (Cube) o; 59 | return Objects.equals(columns, cube.columns); 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | return Objects.hash(columns); 65 | } 66 | 67 | @Override 68 | public String toString() { 69 | return toStringHelper(this).add("columns", columns).toString(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/group/GroupingElement.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.group; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Expression; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | /** 12 | * huaixin 2021/12/18 11:23 PM 13 | */ 14 | public abstract class GroupingElement 15 | extends Node { 16 | protected GroupingElement(Optional location) { 17 | super(location); 18 | } 19 | 20 | public abstract List getExpressions(); 21 | 22 | @Override 23 | public R accept(AstVisitor visitor, C context) { 24 | return visitor.visitGroupingElement(this, context); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/group/Rollup.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.group; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Expression; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.Optional; 12 | 13 | import static com.google.common.base.MoreObjects.toStringHelper; 14 | import static java.util.Objects.requireNonNull; 15 | 16 | /** 17 | * huaixin 2021/12/21 10:05 AM 18 | */ 19 | public final class Rollup extends GroupingElement { 20 | private final List columns; 21 | 22 | public Rollup(List columns) { 23 | this(Optional.empty(), columns); 24 | } 25 | 26 | public Rollup(NodeLocation location, List columns) { 27 | this(Optional.of(location), columns); 28 | } 29 | 30 | private Rollup(Optional location, List columns) { 31 | super(location); 32 | this.columns = ImmutableList.copyOf(requireNonNull(columns, "columns is null")); 33 | } 34 | 35 | @Override 36 | public List getExpressions() { 37 | return columns; 38 | } 39 | 40 | @Override 41 | public R accept(AstVisitor visitor, C context) { 42 | return visitor.visitRollup(this, context); 43 | } 44 | 45 | @Override 46 | public List getChildren() { 47 | return ImmutableList.of(); 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) { 53 | return true; 54 | } 55 | if (o == null || getClass() != o.getClass()) { 56 | return false; 57 | } 58 | Rollup rollup = (Rollup) o; 59 | return Objects.equals(columns, rollup.columns); 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | return Objects.hash(columns); 65 | } 66 | 67 | @Override 68 | public String toString() { 69 | return toStringHelper(this) 70 | .add("columns", columns) 71 | .toString(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/group/SimpleGroupBy.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.group; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Expression; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.Optional; 12 | 13 | import static com.google.common.base.MoreObjects.toStringHelper; 14 | import static java.util.Objects.requireNonNull; 15 | 16 | /** 17 | * huaixin 2021/12/21 10:01 AM 18 | */ 19 | public final class SimpleGroupBy extends GroupingElement { 20 | private final List columns; 21 | 22 | public SimpleGroupBy(List simpleGroupByExpressions) { 23 | this(Optional.empty(), simpleGroupByExpressions); 24 | } 25 | 26 | public SimpleGroupBy(NodeLocation location, List simpleGroupByExpressions) { 27 | this(Optional.of(location), simpleGroupByExpressions); 28 | } 29 | 30 | private SimpleGroupBy(Optional location, List simpleGroupByExpressions) { 31 | super(location); 32 | this.columns = ImmutableList.copyOf(requireNonNull(simpleGroupByExpressions, "simpleGroupByExpressions is null")); 33 | } 34 | 35 | @Override 36 | public List getExpressions() { 37 | return columns; 38 | } 39 | 40 | @Override 41 | public R accept(AstVisitor visitor, C context) { 42 | return visitor.visitSimpleGroupBy(this, context); 43 | } 44 | 45 | @Override 46 | public List getChildren() { 47 | return columns; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) { 53 | return true; 54 | } 55 | if (o == null || getClass() != o.getClass()) { 56 | return false; 57 | } 58 | SimpleGroupBy that = (SimpleGroupBy) o; 59 | return Objects.equals(columns, that.columns); 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | return Objects.hash(columns); 65 | } 66 | 67 | @Override 68 | public String toString() { 69 | return toStringHelper(this) 70 | .add("columns", columns) 71 | .toString(); 72 | } 73 | 74 | @Override 75 | public boolean shallowEquals(Node other) { 76 | return sameClass(this, other); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/join/JoinCriteria.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.join; 2 | 3 | import io.github.melin.sqlflow.tree.Node; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * huaixin 2021/12/19 12:10 AM 9 | */ 10 | public abstract class JoinCriteria 11 | { 12 | // Force subclasses to have a proper equals and hashcode implementation 13 | @Override 14 | public abstract boolean equals(Object obj); 15 | 16 | @Override 17 | public abstract int hashCode(); 18 | 19 | @Override 20 | public abstract String toString(); 21 | 22 | public abstract List getNodes(); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/join/JoinOn.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.join; 2 | 3 | import io.github.melin.sqlflow.tree.expression.Expression; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import com.google.common.collect.ImmutableList; 6 | 7 | import java.util.List; 8 | import java.util.Objects; 9 | 10 | import static com.google.common.base.MoreObjects.toStringHelper; 11 | import static java.util.Objects.requireNonNull; 12 | 13 | /** 14 | * huaixin 2021/12/19 11:02 AM 15 | */ 16 | public class JoinOn extends JoinCriteria { 17 | private final Expression expression; 18 | 19 | public JoinOn(Expression expression) { 20 | this.expression = requireNonNull(expression, "expression is null"); 21 | } 22 | 23 | public Expression getExpression() { 24 | return expression; 25 | } 26 | 27 | @Override 28 | public boolean equals(Object obj) { 29 | if (this == obj) { 30 | return true; 31 | } 32 | if ((obj == null) || (getClass() != obj.getClass())) { 33 | return false; 34 | } 35 | JoinOn o = (JoinOn) obj; 36 | return Objects.equals(expression, o.expression); 37 | } 38 | 39 | @Override 40 | public int hashCode() { 41 | return Objects.hash(expression); 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return toStringHelper(this) 47 | .addValue(expression) 48 | .toString(); 49 | } 50 | 51 | @Override 52 | public List getNodes() { 53 | return ImmutableList.of(expression); 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/join/JoinUsing.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.join; 2 | 3 | import io.github.melin.sqlflow.tree.expression.Identifier; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import com.google.common.collect.ImmutableList; 6 | 7 | import java.util.List; 8 | import java.util.Objects; 9 | 10 | import static com.google.common.base.MoreObjects.toStringHelper; 11 | import static com.google.common.base.Preconditions.checkArgument; 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/19 11:03 AM 16 | */ 17 | public class JoinUsing extends JoinCriteria { 18 | private final List columns; 19 | 20 | public JoinUsing(List columns) { 21 | requireNonNull(columns, "columns is null"); 22 | checkArgument(!columns.isEmpty(), "columns is empty"); 23 | this.columns = ImmutableList.copyOf(columns); 24 | } 25 | 26 | public List getColumns() { 27 | return columns; 28 | } 29 | 30 | @Override 31 | public boolean equals(Object obj) { 32 | if (this == obj) { 33 | return true; 34 | } 35 | if (obj == null || getClass() != obj.getClass()) { 36 | return false; 37 | } 38 | JoinUsing o = (JoinUsing) obj; 39 | return Objects.equals(columns, o.columns); 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | return Objects.hash(columns); 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return toStringHelper(this) 50 | .addValue(columns) 51 | .toString(); 52 | } 53 | 54 | @Override 55 | public List getNodes() { 56 | return ImmutableList.of(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/literal/BooleanLiteral.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.literal; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | 7 | import java.util.Objects; 8 | import java.util.Optional; 9 | 10 | import static com.google.common.base.Preconditions.checkArgument; 11 | import static java.util.Locale.ENGLISH; 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/19 9:31 PM 16 | */ 17 | public class BooleanLiteral 18 | extends Literal { 19 | public static final BooleanLiteral TRUE_LITERAL = new BooleanLiteral(Optional.empty(), "true"); 20 | public static final BooleanLiteral FALSE_LITERAL = new BooleanLiteral(Optional.empty(), "false"); 21 | 22 | private final boolean value; 23 | 24 | public BooleanLiteral(String value) { 25 | this(Optional.empty(), value); 26 | } 27 | 28 | public BooleanLiteral(NodeLocation location, String value) { 29 | this(Optional.of(location), value); 30 | } 31 | 32 | private BooleanLiteral(Optional location, String value) { 33 | super(location); 34 | requireNonNull(value, "value is null"); 35 | checkArgument(value.toLowerCase(ENGLISH).equals("true") || value.toLowerCase(ENGLISH).equals("false")); 36 | 37 | this.value = value.toLowerCase(ENGLISH).equals("true"); 38 | } 39 | 40 | public boolean getValue() { 41 | return value; 42 | } 43 | 44 | @Override 45 | public R accept(AstVisitor visitor, C context) { 46 | return visitor.visitBooleanLiteral(this, context); 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | return Objects.hash(value); 52 | } 53 | 54 | @Override 55 | public boolean equals(Object obj) { 56 | if (this == obj) { 57 | return true; 58 | } 59 | if (obj == null || getClass() != obj.getClass()) { 60 | return false; 61 | } 62 | BooleanLiteral other = (BooleanLiteral) obj; 63 | return Objects.equals(this.value, other.value); 64 | } 65 | 66 | @Override 67 | public boolean shallowEquals(Node other) { 68 | if (!Node.sameClass(this, other)) { 69 | return false; 70 | } 71 | 72 | return value == ((BooleanLiteral) other).value; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/literal/CharLiteral.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.literal; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.base.CharMatcher; 7 | import io.airlift.slice.Slice; 8 | 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static io.airlift.slice.Slices.utf8Slice; 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/19 9:27 PM 17 | */ 18 | public class CharLiteral extends Literal { 19 | private final String value; 20 | private final Slice slice; 21 | 22 | public CharLiteral(String value) { 23 | this(Optional.empty(), value); 24 | } 25 | 26 | public CharLiteral(NodeLocation location, String value) { 27 | this(Optional.of(location), value); 28 | } 29 | 30 | public CharLiteral(Optional location, String value) { 31 | super(location); 32 | requireNonNull(value, "value is null"); 33 | this.value = value; 34 | this.slice = utf8Slice(CharMatcher.is(' ').trimTrailingFrom(value)); 35 | } 36 | 37 | public String getValue() { 38 | return value; 39 | } 40 | 41 | public Slice getSlice() { 42 | return slice; 43 | } 44 | 45 | @Override 46 | public R accept(AstVisitor visitor, C context) { 47 | return visitor.visitCharLiteral(this, context); 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) { 53 | return true; 54 | } 55 | if (o == null || getClass() != o.getClass()) { 56 | return false; 57 | } 58 | CharLiteral that = (CharLiteral) o; 59 | return Objects.equals(value, that.value); 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | return Objects.hash(value); 65 | } 66 | 67 | @Override 68 | public boolean shallowEquals(Node other) { 69 | if (!Node.sameClass(this, other)) { 70 | return false; 71 | } 72 | 73 | return Objects.equals(value, ((CharLiteral) other).value); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/literal/DecimalLiteral.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.literal; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | 7 | import java.util.Objects; 8 | import java.util.Optional; 9 | 10 | import static java.util.Objects.requireNonNull; 11 | 12 | /** 13 | * huaixin 2021/12/19 9:22 PM 14 | */ 15 | public class DecimalLiteral extends Literal { 16 | private final String value; 17 | 18 | public DecimalLiteral(String value) { 19 | this(Optional.empty(), value); 20 | } 21 | 22 | public DecimalLiteral(NodeLocation location, String value) { 23 | this(Optional.of(location), value); 24 | } 25 | 26 | public DecimalLiteral(Optional location, String value) { 27 | super(location); 28 | this.value = requireNonNull(value, "value is null"); 29 | } 30 | 31 | public String getValue() { 32 | return value; 33 | } 34 | 35 | @Override 36 | public R accept(AstVisitor visitor, C context) { 37 | return visitor.visitDecimalLiteral(this, context); 38 | } 39 | 40 | @Override 41 | public boolean equals(Object o) { 42 | if (this == o) { 43 | return true; 44 | } 45 | if (o == null || getClass() != o.getClass()) { 46 | return false; 47 | } 48 | DecimalLiteral that = (DecimalLiteral) o; 49 | return Objects.equals(value, that.value); 50 | } 51 | 52 | @Override 53 | public int hashCode() { 54 | return Objects.hash(value); 55 | } 56 | 57 | @Override 58 | public boolean shallowEquals(Node other) { 59 | if (!sameClass(this, other)) { 60 | return false; 61 | } 62 | 63 | DecimalLiteral otherLiteral = (DecimalLiteral) other; 64 | return value.equals(otherLiteral.value); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/literal/DoubleLiteral.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.literal; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | 7 | import java.util.Optional; 8 | 9 | import static java.util.Objects.requireNonNull; 10 | 11 | /** 12 | * huaixin 2021/12/19 9:21 PM 13 | */ 14 | public class DoubleLiteral extends Literal { 15 | private final double value; 16 | 17 | public DoubleLiteral(String value) { 18 | this(Optional.empty(), value); 19 | } 20 | 21 | public DoubleLiteral(NodeLocation location, String value) { 22 | this(Optional.of(location), value); 23 | } 24 | 25 | private DoubleLiteral(Optional location, String value) { 26 | super(location); 27 | requireNonNull(value, "value is null"); 28 | this.value = Double.parseDouble(value); 29 | } 30 | 31 | public double getValue() { 32 | return value; 33 | } 34 | 35 | @Override 36 | public R accept(AstVisitor visitor, C context) { 37 | return visitor.visitDoubleLiteral(this, context); 38 | } 39 | 40 | @Override 41 | public boolean equals(Object o) { 42 | if (this == o) { 43 | return true; 44 | } 45 | if (o == null || getClass() != o.getClass()) { 46 | return false; 47 | } 48 | 49 | DoubleLiteral that = (DoubleLiteral) o; 50 | 51 | if (Double.compare(that.value, value) != 0) { 52 | return false; 53 | } 54 | 55 | return true; 56 | } 57 | 58 | @SuppressWarnings("UnaryPlus") 59 | @Override 60 | public int hashCode() { 61 | long temp = value != +0.0d ? Double.doubleToLongBits(value) : 0L; 62 | return (int) (temp ^ (temp >>> 32)); 63 | } 64 | 65 | @Override 66 | public boolean shallowEquals(Node other) { 67 | if (!sameClass(this, other)) { 68 | return false; 69 | } 70 | 71 | return value == ((DoubleLiteral) other).value; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/literal/Literal.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.literal; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Expression; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | import java.util.Optional; 11 | 12 | /** 13 | * huaixin 2021/12/19 9:18 PM 14 | */ 15 | public abstract class Literal 16 | extends Expression { 17 | protected Literal(Optional location) { 18 | super(location); 19 | } 20 | 21 | @Override 22 | public R accept(AstVisitor visitor, C context) { 23 | return visitor.visitLiteral(this, context); 24 | } 25 | 26 | @Override 27 | public List getChildren() { 28 | return ImmutableList.of(); 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/literal/LongLiteral.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.literal; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.parser.ParsingException; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | 8 | import java.util.Optional; 9 | 10 | import static java.util.Objects.requireNonNull; 11 | 12 | /** 13 | * huaixin 2021/12/19 9:18 PM 14 | */ 15 | public class LongLiteral extends Literal { 16 | private final long value; 17 | 18 | public LongLiteral(String value) { 19 | this(Optional.empty(), value); 20 | } 21 | 22 | public LongLiteral(NodeLocation location, String value) { 23 | this(Optional.of(location), value); 24 | } 25 | 26 | private LongLiteral(Optional location, String value) { 27 | super(location); 28 | requireNonNull(value, "value is null"); 29 | try { 30 | this.value = Long.parseLong(value); 31 | } catch (NumberFormatException e) { 32 | throw new ParsingException("Invalid numeric literal: " + value); 33 | } 34 | } 35 | 36 | public long getValue() { 37 | return value; 38 | } 39 | 40 | @Override 41 | public R accept(AstVisitor visitor, C context) { 42 | return visitor.visitLongLiteral(this, context); 43 | } 44 | 45 | @Override 46 | public boolean equals(Object o) { 47 | if (this == o) { 48 | return true; 49 | } 50 | if (o == null || getClass() != o.getClass()) { 51 | return false; 52 | } 53 | 54 | LongLiteral that = (LongLiteral) o; 55 | 56 | if (value != that.value) { 57 | return false; 58 | } 59 | 60 | return true; 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return (int) (value ^ (value >>> 32)); 66 | } 67 | 68 | @Override 69 | public boolean shallowEquals(Node other) { 70 | if (!sameClass(this, other)) { 71 | return false; 72 | } 73 | 74 | return value == ((LongLiteral) other).value; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/literal/NullLiteral.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.literal; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * huaixin 2021/12/19 9:32 PM 11 | */ 12 | public class NullLiteral 13 | extends Literal { 14 | public NullLiteral() { 15 | super(Optional.empty()); 16 | } 17 | 18 | public NullLiteral(NodeLocation location) { 19 | super(Optional.of(location)); 20 | } 21 | 22 | @Override 23 | public R accept(AstVisitor visitor, C context) { 24 | return visitor.visitNullLiteral(this, context); 25 | } 26 | 27 | @Override 28 | public boolean equals(Object o) { 29 | if (this == o) { 30 | return true; 31 | } 32 | if (o == null || getClass() != o.getClass()) { 33 | return false; 34 | } 35 | 36 | return true; 37 | } 38 | 39 | @Override 40 | public int hashCode() { 41 | return getClass().hashCode(); 42 | } 43 | 44 | @Override 45 | public boolean shallowEquals(Node other) { 46 | return Node.sameClass(this, other); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/literal/StringLiteral.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.literal; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import io.airlift.slice.Slice; 7 | 8 | import java.util.Objects; 9 | import java.util.Optional; 10 | 11 | import static io.airlift.slice.Slices.utf8Slice; 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/19 9:18 PM 16 | */ 17 | public class StringLiteral 18 | extends Literal { 19 | private final String value; 20 | private final Slice slice; 21 | 22 | public StringLiteral(String value) { 23 | this(Optional.empty(), value); 24 | } 25 | 26 | public StringLiteral(NodeLocation location, String value) { 27 | this(Optional.of(location), value); 28 | } 29 | 30 | private StringLiteral(Optional location, String value) { 31 | super(location); 32 | requireNonNull(value, "value is null"); 33 | this.value = value; 34 | this.slice = utf8Slice(value); 35 | } 36 | 37 | public String getValue() { 38 | return value; 39 | } 40 | 41 | public Slice getSlice() { 42 | return slice; 43 | } 44 | 45 | @Override 46 | public R accept(AstVisitor visitor, C context) { 47 | return visitor.visitStringLiteral(this, context); 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) { 53 | return true; 54 | } 55 | if (o == null || getClass() != o.getClass()) { 56 | return false; 57 | } 58 | 59 | StringLiteral that = (StringLiteral) o; 60 | return Objects.equals(value, that.value); 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return value.hashCode(); 66 | } 67 | 68 | @Override 69 | public boolean shallowEquals(Node other) { 70 | if (!sameClass(this, other)) { 71 | return false; 72 | } 73 | 74 | return Objects.equals(value, ((StringLiteral) other).value); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/literal/TimeLiteral.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.literal; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | 7 | import java.util.Objects; 8 | import java.util.Optional; 9 | 10 | import static java.util.Objects.requireNonNull; 11 | 12 | /** 13 | * huaixin 2021/12/19 9:25 PM 14 | */ 15 | public class TimeLiteral extends Literal { 16 | private final String value; 17 | 18 | public TimeLiteral(String value) { 19 | this(Optional.empty(), value); 20 | } 21 | 22 | public TimeLiteral(NodeLocation location, String value) { 23 | this(Optional.of(location), value); 24 | } 25 | 26 | private TimeLiteral(Optional location, String value) { 27 | super(location); 28 | requireNonNull(value, "value is null"); 29 | this.value = value; 30 | } 31 | 32 | public String getValue() { 33 | return value; 34 | } 35 | 36 | @Override 37 | public R accept(AstVisitor visitor, C context) { 38 | return visitor.visitTimeLiteral(this, context); 39 | } 40 | 41 | @Override 42 | public boolean equals(Object o) { 43 | if (this == o) { 44 | return true; 45 | } 46 | if (o == null || getClass() != o.getClass()) { 47 | return false; 48 | } 49 | 50 | TimeLiteral that = (TimeLiteral) o; 51 | return Objects.equals(value, that.value); 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | return value.hashCode(); 57 | } 58 | 59 | @Override 60 | public boolean shallowEquals(Node other) { 61 | if (!Node.sameClass(this, other)) { 62 | return false; 63 | } 64 | 65 | TimeLiteral otherLiteral = (TimeLiteral) other; 66 | return Objects.equals(this.value, otherLiteral.value); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/literal/TimestampLiteral.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.literal; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | 7 | import java.util.Objects; 8 | import java.util.Optional; 9 | 10 | import static java.util.Objects.requireNonNull; 11 | 12 | /** 13 | * huaixin 2021/12/19 9:25 PM 14 | */ 15 | public class TimestampLiteral extends Literal { 16 | private final String value; 17 | 18 | public TimestampLiteral(String value) { 19 | this(Optional.empty(), value); 20 | } 21 | 22 | public TimestampLiteral(NodeLocation location, String value) { 23 | this(Optional.of(location), value); 24 | } 25 | 26 | private TimestampLiteral(Optional location, String value) { 27 | super(location); 28 | requireNonNull(value, "value is null"); 29 | 30 | this.value = value; 31 | } 32 | 33 | public String getValue() { 34 | return value; 35 | } 36 | 37 | @Override 38 | public R accept(AstVisitor visitor, C context) { 39 | return visitor.visitTimestampLiteral(this, context); 40 | } 41 | 42 | @Override 43 | public boolean equals(Object o) { 44 | if (this == o) { 45 | return true; 46 | } 47 | if (o == null || getClass() != o.getClass()) { 48 | return false; 49 | } 50 | 51 | TimestampLiteral that = (TimestampLiteral) o; 52 | return Objects.equals(value, that.value); 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return value.hashCode(); 58 | } 59 | 60 | @Override 61 | public boolean shallowEquals(Node other) { 62 | if (!sameClass(this, other)) { 63 | return false; 64 | } 65 | 66 | TimestampLiteral otherLiteral = (TimestampLiteral) other; 67 | return value.equals(otherLiteral.value); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/merge/MergeCase.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.merge; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Identifier; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | import io.github.melin.sqlflow.tree.expression.Expression; 8 | 9 | import java.util.List; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 12:52 PM 16 | */ 17 | public abstract class MergeCase extends Node { 18 | protected final Optional expression; 19 | 20 | protected MergeCase(Optional location, Optional expression) { 21 | super(location); 22 | this.expression = requireNonNull(expression, "expression is null"); 23 | } 24 | 25 | public Optional getExpression() { 26 | return expression; 27 | } 28 | 29 | @Override 30 | public R accept(AstVisitor visitor, C context) { 31 | return visitor.visitMergeCase(this, context); 32 | } 33 | 34 | public abstract List getSetColumns(); 35 | 36 | public abstract List getSetExpressions(); 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/merge/MergeDelete.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.merge; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Identifier; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | import io.github.melin.sqlflow.tree.expression.Expression; 8 | import com.google.common.collect.ImmutableList; 9 | 10 | import java.util.List; 11 | import java.util.Objects; 12 | import java.util.Optional; 13 | 14 | import static com.google.common.base.MoreObjects.toStringHelper; 15 | 16 | /** 17 | * huaixin 2021/12/21 12:55 PM 18 | */ 19 | public class MergeDelete 20 | extends MergeCase { 21 | public MergeDelete(Optional expression) { 22 | this(Optional.empty(), expression); 23 | } 24 | 25 | public MergeDelete(NodeLocation location, Optional expression) { 26 | super(Optional.of(location), expression); 27 | } 28 | 29 | public MergeDelete(Optional location, Optional expression) { 30 | super(location, expression); 31 | } 32 | 33 | @Override 34 | public R accept(AstVisitor visitor, C context) { 35 | return visitor.visitMergeDelete(this, context); 36 | } 37 | 38 | @Override 39 | public List getSetColumns() { 40 | return ImmutableList.of(); 41 | } 42 | 43 | @Override 44 | public List getSetExpressions() { 45 | return ImmutableList.of(); 46 | } 47 | 48 | @Override 49 | public List getChildren() { 50 | return expression.map(ImmutableList::of).orElseGet(ImmutableList::of); 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | return Objects.hash(expression); 56 | } 57 | 58 | @Override 59 | public boolean equals(Object obj) { 60 | if (this == obj) { 61 | return true; 62 | } 63 | if ((obj == null) || (getClass() != obj.getClass())) { 64 | return false; 65 | } 66 | MergeDelete mergeDelete = (MergeDelete) obj; 67 | return Objects.equals(expression, mergeDelete.expression); 68 | } 69 | 70 | @Override 71 | public String toString() { 72 | return toStringHelper(this) 73 | .add("expression", expression.orElse(null)) 74 | .omitNullValues() 75 | .toString(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/relation/Lateral.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.relation; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import io.github.melin.sqlflow.tree.statement.Query; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.Optional; 12 | 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/21 1:12 PM 17 | */ 18 | public final class Lateral extends Relation { 19 | private final Query query; 20 | 21 | public Lateral(Query query) { 22 | this(Optional.empty(), query); 23 | } 24 | 25 | public Lateral(NodeLocation location, Query query) { 26 | this(Optional.of(location), query); 27 | } 28 | 29 | private Lateral(Optional location, Query query) { 30 | super(location); 31 | this.query = requireNonNull(query, "query is null"); 32 | } 33 | 34 | public Query getQuery() { 35 | return query; 36 | } 37 | 38 | @Override 39 | public R accept(AstVisitor visitor, C context) { 40 | return visitor.visitLateral(this, context); 41 | } 42 | 43 | @Override 44 | public List getChildren() { 45 | return ImmutableList.of(query); 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return "LATERAL(" + query + ")"; 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | return Objects.hash(query); 56 | } 57 | 58 | @Override 59 | public boolean equals(Object obj) { 60 | if (this == obj) { 61 | return true; 62 | } 63 | if (obj == null || getClass() != obj.getClass()) { 64 | return false; 65 | } 66 | Lateral other = (Lateral) obj; 67 | return Objects.equals(this.query, other.query); 68 | } 69 | 70 | @Override 71 | public boolean shallowEquals(Node other) { 72 | return Node.sameClass(this, other); 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/relation/QueryBody.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.relation; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.NodeLocation; 5 | 6 | import java.util.Optional; 7 | 8 | /** 9 | * huaixin 2021/12/18 10:06 PM 10 | */ 11 | public abstract class QueryBody 12 | extends Relation { 13 | protected QueryBody(Optional location) { 14 | super(location); 15 | } 16 | 17 | @Override 18 | public R accept(AstVisitor visitor, C context) { 19 | return visitor.visitQueryBody(this, context); 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/relation/Relation.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.relation; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * huaixin 2021/12/18 10:06 PM 11 | */ 12 | public abstract class Relation extends Node { 13 | public Relation(Optional location) { 14 | super(location); 15 | } 16 | 17 | @Override 18 | public R accept(AstVisitor visitor, C context) { 19 | return visitor.visitRelation(this, context); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/relation/SetOperation.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.relation; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.NodeLocation; 5 | 6 | import java.util.List; 7 | import java.util.Optional; 8 | 9 | /** 10 | * huaixin 2021/12/21 1:07 PM 11 | */ 12 | public abstract class SetOperation extends QueryBody { 13 | private final boolean distinct; 14 | 15 | protected SetOperation(Optional location, boolean distinct) { 16 | super(location); 17 | this.distinct = distinct; 18 | } 19 | 20 | public boolean isDistinct() { 21 | return distinct; 22 | } 23 | 24 | @Override 25 | public R accept(AstVisitor visitor, C context) { 26 | return visitor.visitSetOperation(this, context); 27 | } 28 | 29 | public abstract List getRelations(); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/statement/Statement.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.statement; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * huaixin 2021/12/18 10:03 PM 11 | */ 12 | public abstract class Statement 13 | extends Node { 14 | protected Statement(Optional location) { 15 | super(location); 16 | } 17 | 18 | @Override 19 | public R accept(AstVisitor visitor, C context) { 20 | return visitor.visitStatement(this, context); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/type/DataType.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.type; 2 | 3 | import io.github.melin.sqlflow.tree.NodeLocation; 4 | import io.github.melin.sqlflow.tree.expression.Expression; 5 | 6 | import java.util.Optional; 7 | 8 | /** 9 | * huaixin 2021/12/21 10:55 AM 10 | */ 11 | public abstract class DataType extends Expression { 12 | public DataType(Optional location) { 13 | super(location); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/type/DataTypeParameter.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.type; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * huaixin 2021/12/21 11:31 AM 11 | */ 12 | public abstract class DataTypeParameter extends Node { 13 | protected DataTypeParameter(Optional location) { 14 | super(location); 15 | } 16 | 17 | @Override 18 | public R accept(AstVisitor visitor, C context) { 19 | return visitor.visitDataTypeParameter(this, context); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/type/GenericDataType.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.type; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Identifier; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.Optional; 12 | 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/21 11:30 AM 17 | */ 18 | public class GenericDataType extends DataType { 19 | private final Identifier name; 20 | private final List arguments; 21 | 22 | public GenericDataType(NodeLocation location, Identifier name, List arguments) { 23 | super(Optional.of(location)); 24 | this.name = requireNonNull(name, "name is null"); 25 | this.arguments = requireNonNull(arguments, "arguments is null"); 26 | } 27 | 28 | public GenericDataType(Optional location, Identifier name, List arguments) { 29 | super(location); 30 | this.name = requireNonNull(name, "name is null"); 31 | this.arguments = requireNonNull(arguments, "arguments is null"); 32 | } 33 | 34 | public Identifier getName() { 35 | return name; 36 | } 37 | 38 | public List getArguments() { 39 | return arguments; 40 | } 41 | 42 | @Override 43 | public List getChildren() { 44 | return ImmutableList.builder() 45 | .add(name) 46 | .addAll(arguments) 47 | .build(); 48 | } 49 | 50 | @Override 51 | public R accept(AstVisitor visitor, C context) { 52 | return visitor.visitGenericDataType(this, context); 53 | } 54 | 55 | @Override 56 | public boolean equals(Object o) { 57 | if (this == o) { 58 | return true; 59 | } 60 | if (o == null || getClass() != o.getClass()) { 61 | return false; 62 | } 63 | GenericDataType that = (GenericDataType) o; 64 | return name.equals(that.name) && 65 | arguments.equals(that.arguments); 66 | } 67 | 68 | @Override 69 | public int hashCode() { 70 | return Objects.hash(name, arguments); 71 | } 72 | 73 | @Override 74 | public boolean shallowEquals(Node other) { 75 | return sameClass(this, other); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/type/IntervalDayTimeDataType.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.type; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 11:33 AM 16 | */ 17 | public class IntervalDayTimeDataType extends DataType { 18 | public enum Field { 19 | YEAR, 20 | MONTH, 21 | DAY, 22 | HOUR, 23 | MINUTE, 24 | SECOND, 25 | } 26 | 27 | private final Field from; 28 | private final Field to; 29 | 30 | public IntervalDayTimeDataType(NodeLocation location, Field from, Field to) { 31 | this(Optional.of(location), from, to); 32 | } 33 | 34 | public IntervalDayTimeDataType(Optional location, Field from, Field to) { 35 | super(location); 36 | this.from = requireNonNull(from, "from is null"); 37 | this.to = requireNonNull(to, "to is null"); 38 | } 39 | 40 | public Field getFrom() { 41 | return from; 42 | } 43 | 44 | public Field getTo() { 45 | return to; 46 | } 47 | 48 | @Override 49 | public R accept(AstVisitor visitor, C context) { 50 | return visitor.visitIntervalDataType(this, context); 51 | } 52 | 53 | @Override 54 | public List getChildren() { 55 | return ImmutableList.of(); 56 | } 57 | 58 | @Override 59 | public boolean equals(Object o) { 60 | if (this == o) { 61 | return true; 62 | } 63 | if (o == null || getClass() != o.getClass()) { 64 | return false; 65 | } 66 | IntervalDayTimeDataType that = (IntervalDayTimeDataType) o; 67 | return from == that.from && 68 | to == that.to; 69 | } 70 | 71 | @Override 72 | public int hashCode() { 73 | return Objects.hash(from, to); 74 | } 75 | 76 | @Override 77 | public boolean shallowEquals(Node other) { 78 | if (!sameClass(this, other)) { 79 | return false; 80 | } 81 | 82 | IntervalDayTimeDataType otherType = (IntervalDayTimeDataType) other; 83 | return from.equals(otherType.from) && 84 | to == otherType.to; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/type/NumericParameter.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.type; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * huaixin 2021/12/21 11:32 AM 16 | */ 17 | public class NumericParameter extends DataTypeParameter { 18 | private final String value; 19 | 20 | public NumericParameter(NodeLocation location, String value) { 21 | this(Optional.of(location), value); 22 | } 23 | 24 | public NumericParameter(Optional location, String value) { 25 | super(location); 26 | this.value = requireNonNull(value, "value is null"); 27 | } 28 | 29 | public String getValue() { 30 | return value; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return value; 36 | } 37 | 38 | @Override 39 | public List getChildren() { 40 | return ImmutableList.of(); 41 | } 42 | 43 | @Override 44 | public R accept(AstVisitor visitor, C context) { 45 | return visitor.visitNumericTypeParameter(this, context); 46 | } 47 | 48 | @Override 49 | public boolean equals(Object o) { 50 | if (this == o) { 51 | return true; 52 | } 53 | if (o == null || getClass() != o.getClass()) { 54 | return false; 55 | } 56 | NumericParameter that = (NumericParameter) o; 57 | return value.equals(that.value); 58 | } 59 | 60 | @Override 61 | public int hashCode() { 62 | return Objects.hash(value); 63 | } 64 | 65 | @Override 66 | public boolean shallowEquals(Node other) { 67 | if (!Node.sameClass(this, other)) { 68 | return false; 69 | } 70 | 71 | return Objects.equals(value, ((NumericParameter) other).value); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/type/TypeParameter.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.type; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import com.google.common.collect.ImmutableList; 6 | 7 | import java.util.List; 8 | import java.util.Objects; 9 | import java.util.Optional; 10 | 11 | import static java.util.Objects.requireNonNull; 12 | 13 | /** 14 | * huaixin 2021/12/21 11:35 AM 15 | */ 16 | public class TypeParameter extends DataTypeParameter { 17 | private final DataType type; 18 | 19 | public TypeParameter(DataType type) { 20 | super(Optional.empty()); 21 | this.type = requireNonNull(type, "type is null"); 22 | } 23 | 24 | public DataType getValue() { 25 | return type; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return type.toString(); 31 | } 32 | 33 | @Override 34 | public List getChildren() { 35 | return ImmutableList.of(type); 36 | } 37 | 38 | @Override 39 | public R accept(AstVisitor visitor, C context) { 40 | return visitor.visitTypeParameter(this, context); 41 | } 42 | 43 | @Override 44 | public boolean equals(Object o) { 45 | if (this == o) { 46 | return true; 47 | } 48 | if (o == null || getClass() != o.getClass()) { 49 | return false; 50 | } 51 | TypeParameter that = (TypeParameter) o; 52 | return type.equals(that.type); 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return Objects.hash(type); 58 | } 59 | 60 | @Override 61 | public boolean shallowEquals(Node other) { 62 | return sameClass(this, other); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/Window.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window; 2 | 3 | /** 4 | * huaixin 2021/12/19 9:46 PM 5 | */ 6 | public interface Window { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/WindowReference.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Identifier; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.Optional; 12 | 13 | import static com.google.common.base.MoreObjects.toStringHelper; 14 | import static java.util.Objects.requireNonNull; 15 | 16 | /** 17 | * huaixin 2021/12/19 9:48 PM 18 | */ 19 | public class WindowReference extends Node implements Window { 20 | private final Identifier name; 21 | 22 | public WindowReference(Identifier name) { 23 | this(Optional.empty(), name); 24 | } 25 | 26 | public WindowReference(NodeLocation location, Identifier name) { 27 | this(Optional.of(location), name); 28 | } 29 | 30 | private WindowReference(Optional location, Identifier name) { 31 | super(location); 32 | this.name = requireNonNull(name, "name is null"); 33 | } 34 | 35 | public Identifier getName() { 36 | return name; 37 | } 38 | 39 | @Override 40 | public R accept(AstVisitor visitor, C context) { 41 | return visitor.visitWindowReference(this, context); 42 | } 43 | 44 | @Override 45 | public List getChildren() { 46 | return ImmutableList.of(name); 47 | } 48 | 49 | @Override 50 | public boolean equals(Object obj) { 51 | if (this == obj) { 52 | return true; 53 | } 54 | if ((obj == null) || (getClass() != obj.getClass())) { 55 | return false; 56 | } 57 | WindowReference o = (WindowReference) obj; 58 | return Objects.equals(name, o.name); 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return Objects.hash(name); 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return toStringHelper(this) 69 | .add("name", name) 70 | .toString(); 71 | } 72 | 73 | @Override 74 | public boolean shallowEquals(Node other) { 75 | return sameClass(this, other); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/AnchorPattern.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.MoreObjects.toStringHelper; 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/19 10:11 PM 17 | */ 18 | public class AnchorPattern extends RowPattern { 19 | public enum Type { 20 | PARTITION_START, 21 | PARTITION_END 22 | } 23 | 24 | private final Type type; 25 | 26 | public AnchorPattern(NodeLocation location, Type type) { 27 | this(Optional.of(location), type); 28 | } 29 | 30 | private AnchorPattern(Optional location, Type type) { 31 | super(location); 32 | this.type = requireNonNull(type, "type is null"); 33 | } 34 | 35 | public Type getType() { 36 | return type; 37 | } 38 | 39 | @Override 40 | public R accept(AstVisitor visitor, C context) { 41 | return visitor.visitAnchorPattern(this, context); 42 | } 43 | 44 | @Override 45 | public List getChildren() { 46 | return ImmutableList.of(); 47 | } 48 | 49 | @Override 50 | public boolean equals(Object obj) { 51 | if (this == obj) { 52 | return true; 53 | } 54 | if ((obj == null) || (getClass() != obj.getClass())) { 55 | return false; 56 | } 57 | AnchorPattern o = (AnchorPattern) obj; 58 | return Objects.equals(type, o.type); 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return getClass().hashCode(); 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return toStringHelper(this) 69 | .add("type", type) 70 | .toString(); 71 | } 72 | 73 | @Override 74 | public boolean shallowEquals(Node other) { 75 | return sameClass(this, other); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/EmptyPattern.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | import static com.google.common.base.MoreObjects.toStringHelper; 12 | 13 | /** 14 | * huaixin 2021/12/19 10:11 PM 15 | */ 16 | public class EmptyPattern extends RowPattern { 17 | public EmptyPattern(NodeLocation location) { 18 | this(Optional.of(location)); 19 | } 20 | 21 | private EmptyPattern(Optional location) { 22 | super(location); 23 | } 24 | 25 | @Override 26 | public R accept(AstVisitor visitor, C context) { 27 | return visitor.visitEmptyPattern(this, context); 28 | } 29 | 30 | @Override 31 | public List getChildren() { 32 | return ImmutableList.of(); 33 | } 34 | 35 | @Override 36 | public boolean equals(Object obj) { 37 | if (this == obj) { 38 | return true; 39 | } 40 | if ((obj == null) || (getClass() != obj.getClass())) { 41 | return false; 42 | } 43 | return true; 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return getClass().hashCode(); 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return toStringHelper(this) 54 | .toString(); 55 | } 56 | 57 | @Override 58 | public boolean shallowEquals(Node other) { 59 | return sameClass(this, other); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/ExcludedPattern.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.MoreObjects.toStringHelper; 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/19 10:12 PM 17 | */ 18 | public class ExcludedPattern extends RowPattern { 19 | 20 | private final RowPattern pattern; 21 | 22 | public ExcludedPattern(NodeLocation location, RowPattern pattern) { 23 | this(Optional.of(location), pattern); 24 | } 25 | 26 | private ExcludedPattern(Optional location, RowPattern pattern) { 27 | super(location); 28 | this.pattern = requireNonNull(pattern, "pattern is null"); 29 | } 30 | 31 | public RowPattern getPattern() { 32 | return pattern; 33 | } 34 | 35 | @Override 36 | public R accept(AstVisitor visitor, C context) { 37 | return visitor.visitExcludedPattern(this, context); 38 | } 39 | 40 | @Override 41 | public List getChildren() { 42 | return ImmutableList.of(pattern); 43 | } 44 | 45 | @Override 46 | public boolean equals(Object obj) { 47 | if (this == obj) { 48 | return true; 49 | } 50 | if ((obj == null) || (getClass() != obj.getClass())) { 51 | return false; 52 | } 53 | ExcludedPattern o = (ExcludedPattern) obj; 54 | return Objects.equals(pattern, o.pattern); 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return Objects.hash(pattern); 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return toStringHelper(this) 65 | .add("pattern", pattern) 66 | .toString(); 67 | } 68 | 69 | @Override 70 | public boolean shallowEquals(Node other) { 71 | return sameClass(this, other); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/OneOrMoreQuantifier.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.NodeLocation; 5 | 6 | import java.util.Optional; 7 | 8 | /** 9 | * huaixin 2021/12/19 10:17 PM 10 | */ 11 | public class OneOrMoreQuantifier extends PatternQuantifier { 12 | public OneOrMoreQuantifier(boolean greedy) { 13 | this(Optional.empty(), greedy); 14 | } 15 | 16 | public OneOrMoreQuantifier(NodeLocation location, boolean greedy) { 17 | this(Optional.of(location), greedy); 18 | } 19 | 20 | public OneOrMoreQuantifier(Optional location, boolean greedy) { 21 | super(location, greedy); 22 | } 23 | 24 | @Override 25 | public R accept(AstVisitor visitor, C context) { 26 | return visitor.visitOneOrMoreQuantifier(this, context); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/PatternAlternation.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.MoreObjects.toStringHelper; 13 | import static com.google.common.base.Preconditions.checkArgument; 14 | import static java.util.Objects.requireNonNull; 15 | 16 | /** 17 | * huaixin 2021/12/19 10:07 PM 18 | */ 19 | public class PatternAlternation extends RowPattern { 20 | private final List patterns; 21 | 22 | public PatternAlternation(NodeLocation location, List patterns) { 23 | this(Optional.of(location), patterns); 24 | } 25 | 26 | private PatternAlternation(Optional location, List patterns) { 27 | super(location); 28 | this.patterns = requireNonNull(patterns, "patterns is null"); 29 | checkArgument(!patterns.isEmpty(), "patterns list is empty"); 30 | } 31 | 32 | public List getPatterns() { 33 | return patterns; 34 | } 35 | 36 | @Override 37 | public R accept(AstVisitor visitor, C context) { 38 | return visitor.visitPatternAlternation(this, context); 39 | } 40 | 41 | @Override 42 | public List getChildren() { 43 | return ImmutableList.copyOf(patterns); 44 | } 45 | 46 | @Override 47 | public boolean equals(Object obj) { 48 | if (this == obj) { 49 | return true; 50 | } 51 | if ((obj == null) || (getClass() != obj.getClass())) { 52 | return false; 53 | } 54 | PatternAlternation o = (PatternAlternation) obj; 55 | return Objects.equals(patterns, o.patterns); 56 | } 57 | 58 | @Override 59 | public int hashCode() { 60 | return Objects.hash(patterns); 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return toStringHelper(this) 66 | .add("patterns", patterns) 67 | .toString(); 68 | } 69 | 70 | @Override 71 | public boolean shallowEquals(Node other) { 72 | return sameClass(this, other); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/PatternConcatenation.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.MoreObjects.toStringHelper; 13 | import static com.google.common.base.Preconditions.checkArgument; 14 | import static java.util.Objects.requireNonNull; 15 | 16 | /** 17 | * huaixin 2021/12/19 10:08 PM 18 | */ 19 | public class PatternConcatenation extends RowPattern { 20 | private final List patterns; 21 | 22 | public PatternConcatenation(NodeLocation location, List patterns) { 23 | this(Optional.of(location), patterns); 24 | } 25 | 26 | private PatternConcatenation(Optional location, List patterns) { 27 | super(location); 28 | this.patterns = requireNonNull(patterns, "patterns is null"); 29 | checkArgument(!patterns.isEmpty(), "patterns list is empty"); 30 | } 31 | 32 | public List getPatterns() { 33 | return patterns; 34 | } 35 | 36 | @Override 37 | public R accept(AstVisitor visitor, C context) { 38 | return visitor.visitPatternConcatenation(this, context); 39 | } 40 | 41 | @Override 42 | public List getChildren() { 43 | return ImmutableList.copyOf(patterns); 44 | } 45 | 46 | @Override 47 | public boolean equals(Object obj) { 48 | if (this == obj) { 49 | return true; 50 | } 51 | if ((obj == null) || (getClass() != obj.getClass())) { 52 | return false; 53 | } 54 | PatternConcatenation o = (PatternConcatenation) obj; 55 | return Objects.equals(patterns, o.patterns); 56 | } 57 | 58 | @Override 59 | public int hashCode() { 60 | return Objects.hash(patterns); 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return toStringHelper(this) 66 | .add("patterns", patterns) 67 | .toString(); 68 | } 69 | 70 | @Override 71 | public boolean shallowEquals(Node other) { 72 | return sameClass(this, other); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/PatternPermutation.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.MoreObjects.toStringHelper; 13 | import static com.google.common.base.Preconditions.checkArgument; 14 | import static java.util.Objects.requireNonNull; 15 | 16 | /** 17 | * huaixin 2021/12/19 10:14 PM 18 | */ 19 | public class PatternPermutation extends RowPattern { 20 | private final List patterns; 21 | 22 | public PatternPermutation(NodeLocation location, List patterns) 23 | { 24 | this(Optional.of(location), patterns); 25 | } 26 | 27 | private PatternPermutation(Optional location, List patterns) 28 | { 29 | super(location); 30 | this.patterns = requireNonNull(patterns, "patterns is null"); 31 | checkArgument(!patterns.isEmpty(), "patterns list is empty"); 32 | } 33 | 34 | public List getPatterns() 35 | { 36 | return patterns; 37 | } 38 | 39 | @Override 40 | public R accept(AstVisitor visitor, C context) 41 | { 42 | return visitor.visitPatternPermutation(this, context); 43 | } 44 | 45 | @Override 46 | public List getChildren() 47 | { 48 | return ImmutableList.copyOf(patterns); 49 | } 50 | 51 | @Override 52 | public boolean equals(Object obj) 53 | { 54 | if (this == obj) { 55 | return true; 56 | } 57 | if ((obj == null) || (getClass() != obj.getClass())) { 58 | return false; 59 | } 60 | PatternPermutation o = (PatternPermutation) obj; 61 | return Objects.equals(patterns, o.patterns); 62 | } 63 | 64 | @Override 65 | public int hashCode() 66 | { 67 | return Objects.hash(patterns); 68 | } 69 | 70 | @Override 71 | public String toString() 72 | { 73 | return toStringHelper(this) 74 | .add("patterns", patterns) 75 | .toString(); 76 | } 77 | 78 | @Override 79 | public boolean shallowEquals(Node other) 80 | { 81 | return Node.sameClass(this, other); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/PatternQuantifier.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.MoreObjects.toStringHelper; 13 | 14 | /** 15 | * huaixin 2021/12/19 10:09 PM 16 | */ 17 | public abstract class PatternQuantifier extends Node { 18 | private final boolean greedy; 19 | 20 | protected PatternQuantifier(Optional location, boolean greedy) { 21 | super(location); 22 | this.greedy = greedy; 23 | } 24 | 25 | public boolean isGreedy() { 26 | return greedy; 27 | } 28 | 29 | @Override 30 | public R accept(AstVisitor visitor, C context) { 31 | return visitor.visitPatternQuantifier(this, context); 32 | } 33 | 34 | @Override 35 | public List getChildren() { 36 | return ImmutableList.of(); 37 | } 38 | 39 | @Override 40 | public boolean equals(Object obj) { 41 | if (this == obj) { 42 | return true; 43 | } 44 | if ((obj == null) || (getClass() != obj.getClass())) { 45 | return false; 46 | } 47 | PatternQuantifier o = (PatternQuantifier) obj; 48 | return greedy == o.greedy; 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | return Objects.hash(greedy); 54 | } 55 | 56 | @Override 57 | public boolean shallowEquals(Node other) { 58 | if (!sameClass(this, other)) { 59 | return false; 60 | } 61 | 62 | PatternQuantifier otherNode = (PatternQuantifier) other; 63 | return greedy == otherNode.greedy; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return toStringHelper(this) 69 | .add("greedy", greedy) 70 | .toString(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/PatternSearchMode.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | import com.google.common.collect.ImmutableList; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | import static com.google.common.base.MoreObjects.toStringHelper; 13 | import static java.util.Objects.requireNonNull; 14 | 15 | /** 16 | * huaixin 2021/12/19 9:52 PM 17 | */ 18 | public final class PatternSearchMode extends Node { 19 | private final Mode mode; 20 | 21 | public PatternSearchMode(Mode mode) { 22 | this(Optional.empty(), mode); 23 | } 24 | 25 | public PatternSearchMode(NodeLocation location, Mode mode) { 26 | this(Optional.of(location), mode); 27 | } 28 | 29 | public PatternSearchMode(Optional location, Mode mode) { 30 | super(location); 31 | this.mode = requireNonNull(mode, "mode is null"); 32 | } 33 | 34 | public Mode getMode() { 35 | return mode; 36 | } 37 | 38 | @Override 39 | public R accept(AstVisitor visitor, C context) { 40 | return visitor.visitPatternSearchMode(this, context); 41 | } 42 | 43 | @Override 44 | public List getChildren() { 45 | return ImmutableList.of(); 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | if (this == obj) { 51 | return true; 52 | } 53 | if ((obj == null) || (getClass() != obj.getClass())) { 54 | return false; 55 | } 56 | return mode == ((PatternSearchMode) obj).mode; 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return Objects.hash(mode); 62 | } 63 | 64 | @Override 65 | public String toString() { 66 | return toStringHelper(this) 67 | .add("mode", mode) 68 | .toString(); 69 | } 70 | 71 | @Override 72 | public boolean shallowEquals(Node other) { 73 | if (!sameClass(this, other)) { 74 | return false; 75 | } 76 | 77 | return mode == ((PatternSearchMode) other).mode; 78 | } 79 | 80 | public enum Mode { 81 | INITIAL, SEEK 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/PatternVariable.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.expression.Identifier; 5 | import io.github.melin.sqlflow.tree.Node; 6 | import io.github.melin.sqlflow.tree.NodeLocation; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.Optional; 12 | 13 | import static com.google.common.base.MoreObjects.toStringHelper; 14 | import static java.util.Objects.requireNonNull; 15 | 16 | /** 17 | * huaixin 2021/12/19 10:15 PM 18 | */ 19 | public class PatternVariable extends RowPattern { 20 | private final Identifier name; 21 | 22 | public PatternVariable(NodeLocation location, Identifier name) { 23 | this(Optional.of(location), name); 24 | } 25 | 26 | private PatternVariable(Optional location, Identifier name) { 27 | super(location); 28 | this.name = requireNonNull(name, "name is null"); 29 | } 30 | 31 | public Identifier getName() { 32 | return name; 33 | } 34 | 35 | @Override 36 | public R accept(AstVisitor visitor, C context) { 37 | return visitor.visitPatternVariable(this, context); 38 | } 39 | 40 | @Override 41 | public List getChildren() { 42 | return ImmutableList.of(name); 43 | } 44 | 45 | @Override 46 | public boolean equals(Object obj) { 47 | if (this == obj) { 48 | return true; 49 | } 50 | if ((obj == null) || (getClass() != obj.getClass())) { 51 | return false; 52 | } 53 | PatternVariable o = (PatternVariable) obj; 54 | return Objects.equals(name, o.name); 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return Objects.hash(name); 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return toStringHelper(this) 65 | .add("name", name) 66 | .toString(); 67 | } 68 | 69 | @Override 70 | public boolean shallowEquals(Node other) { 71 | return sameClass(this, other); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/RowPattern.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.Node; 5 | import io.github.melin.sqlflow.tree.NodeLocation; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * huaixin 2021/12/19 9:58 PM 11 | */ 12 | public abstract class RowPattern extends Node { 13 | protected RowPattern(Optional location) { 14 | super(location); 15 | } 16 | 17 | @Override 18 | public R accept(AstVisitor visitor, C context) { 19 | return visitor.visitRowPattern(this, context); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/ZeroOrMoreQuantifier.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.NodeLocation; 5 | 6 | import java.util.Optional; 7 | 8 | /** 9 | * huaixin 2021/12/19 10:16 PM 10 | */ 11 | public class ZeroOrMoreQuantifier extends PatternQuantifier { 12 | public ZeroOrMoreQuantifier(boolean greedy) { 13 | this(Optional.empty(), greedy); 14 | } 15 | 16 | public ZeroOrMoreQuantifier(NodeLocation location, boolean greedy) { 17 | this(Optional.of(location), greedy); 18 | } 19 | 20 | public ZeroOrMoreQuantifier(Optional location, boolean greedy) { 21 | super(location, greedy); 22 | } 23 | 24 | @Override 25 | public R accept(AstVisitor visitor, C context) { 26 | return visitor.visitZeroOrMoreQuantifier(this, context); 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/tree/window/rowPattern/ZeroOrOneQuantifier.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.tree.window.rowPattern; 2 | 3 | import io.github.melin.sqlflow.AstVisitor; 4 | import io.github.melin.sqlflow.tree.NodeLocation; 5 | 6 | import java.util.Optional; 7 | 8 | /** 9 | * huaixin 2021/12/19 10:16 PM 10 | */ 11 | public class ZeroOrOneQuantifier extends PatternQuantifier { 12 | public ZeroOrOneQuantifier(boolean greedy) { 13 | this(Optional.empty(), greedy); 14 | } 15 | 16 | public ZeroOrOneQuantifier(NodeLocation location, boolean greedy) { 17 | this(Optional.of(location), greedy); 18 | } 19 | 20 | public ZeroOrOneQuantifier(Optional location, boolean greedy) { 21 | super(location, greedy); 22 | } 23 | 24 | @Override 25 | public R accept(AstVisitor visitor, C context) { 26 | return visitor.visitZeroOrOneQuantifier(this, context); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/type/Type.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.type; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * huaixin 2021/12/25 10:58 AM 7 | */ 8 | public interface Type { 9 | 10 | /** 11 | * For parameterized types returns the list of parameters. 12 | */ 13 | List getTypeParameters(); 14 | 15 | /** 16 | * Returns the name of this type that should be displayed to end-users. 17 | */ 18 | String getDisplayName(); 19 | 20 | /** 21 | * True if the type supports equalTo and hash. 22 | */ 23 | boolean isComparable(); 24 | 25 | /** 26 | * True if the type supports compareTo. 27 | */ 28 | boolean isOrderable(); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/type/UnknownType.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.type; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * huaixin 2021/12/25 3:54 PM 7 | */ 8 | public class UnknownType implements Type { 9 | public static final UnknownType UNKNOWN = new UnknownType(); 10 | 11 | public static final String NAME = "unknown"; 12 | 13 | @Override 14 | public List getTypeParameters() { 15 | return null; 16 | } 17 | 18 | @Override 19 | public String getDisplayName() { 20 | return null; 21 | } 22 | 23 | @Override 24 | public boolean isComparable() { 25 | return true; 26 | } 27 | 28 | @Override 29 | public boolean isOrderable() { 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/github/melin/sqlflow/util/NodeUtils.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.util; 2 | 3 | import io.github.melin.sqlflow.tree.OrderBy; 4 | import io.github.melin.sqlflow.tree.Property; 5 | import io.github.melin.sqlflow.tree.SortItem; 6 | import io.github.melin.sqlflow.tree.expression.Expression; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.Optional; 12 | 13 | import static com.google.common.collect.ImmutableMap.toImmutableMap; 14 | 15 | public final class NodeUtils { 16 | private NodeUtils() { 17 | } 18 | 19 | public static List getSortItemsFromOrderBy(Optional orderBy) { 20 | return orderBy.map(OrderBy::getSortItems).orElse(ImmutableList.of()); 21 | } 22 | 23 | public static Map mapFromProperties(List properties) { 24 | return properties.stream().collect(toImmutableMap( 25 | property -> property.getName().getValue(), 26 | Property::getValue)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/io/github/melin/sqlflow/parser/AbstractSqlLineageTest.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser; 2 | 3 | import io.github.melin.sqlflow.analyzer.Analysis; 4 | import io.github.melin.sqlflow.analyzer.OutputColumn; 5 | 6 | import static org.assertj.core.api.Assertions.assertThat; 7 | 8 | /** 9 | * huaixin 2021/12/26 9:06 PM 10 | */ 11 | public abstract class AbstractSqlLineageTest { 12 | 13 | protected void assertLineage(Analysis analysis, OutputColumn... outputColumns) 14 | throws Exception { 15 | 16 | if (outputColumns.length != 0) { 17 | assertThat(analysis.getTarget().get().getColumns().get()) 18 | .containsExactly(outputColumns); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/io/github/melin/sqlflow/parser/flink/JdbcQueryMetadataService.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser.flink; 2 | 3 | import io.github.melin.sqlflow.metadata.MetadataService; 4 | import io.github.melin.sqlflow.metadata.QualifiedObjectName; 5 | import io.github.melin.sqlflow.metadata.SchemaTable; 6 | import io.github.melin.sqlflow.metadata.ViewDefinition; 7 | import io.github.melin.sqlflow.tree.QualifiedName; 8 | 9 | import java.util.Optional; 10 | 11 | public class JdbcQueryMetadataService implements MetadataService { 12 | 13 | @Override 14 | public Optional getSchema() { 15 | return Optional.empty(); 16 | } 17 | 18 | @Override 19 | public Optional getCatalog() { 20 | return Optional.empty(); 21 | } 22 | 23 | @Override 24 | public boolean isAggregationFunction(QualifiedName name) { 25 | return false; 26 | } 27 | 28 | @Override 29 | public Optional getTableSchema(QualifiedObjectName targetTable) { 30 | return Optional.empty(); 31 | } 32 | 33 | @Override 34 | public Optional getView(QualifiedObjectName viewName) { 35 | return Optional.empty(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/io/github/melin/sqlflow/parser/presto/PrestoSqlLineageTest.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser.presto; 2 | 3 | import io.github.melin.sqlflow.analyzer.Analysis; 4 | import io.github.melin.sqlflow.analyzer.OutputColumn; 5 | import io.github.melin.sqlflow.analyzer.StatementAnalyzer; 6 | import io.github.melin.sqlflow.metadata.QualifiedObjectName; 7 | import io.github.melin.sqlflow.parser.AbstractSqlLineageTest; 8 | import io.github.melin.sqlflow.parser.SqlFlowParser; 9 | import io.github.melin.sqlflow.tree.statement.Statement; 10 | import com.google.common.collect.ImmutableSet; 11 | import org.junit.Test; 12 | 13 | import java.util.Optional; 14 | 15 | import static java.util.Collections.emptyMap; 16 | 17 | /** 18 | * huaixin 2021/12/18 11:13 PM 19 | */ 20 | public class PrestoSqlLineageTest extends AbstractSqlLineageTest { 21 | 22 | protected static final SqlFlowParser SQL_PARSER = new SqlFlowParser(); 23 | 24 | @Test 25 | public void testInsertInto() throws Exception { 26 | String sql = "insert into Demo select concat(a.COL1, '-', a.COL2), " + 27 | "sum(a.row_num * 1.00000) as num " + 28 | "from test a where ds='201912' group by type"; 29 | Statement statement = SQL_PARSER.createStatement(sql); 30 | 31 | Analysis analysis = new Analysis(statement, emptyMap()); 32 | StatementAnalyzer statementAnalyzer = new StatementAnalyzer( 33 | analysis, new SimplePrestoMetadataService(), SQL_PARSER, false); 34 | 35 | statementAnalyzer.analyze(statement, Optional.empty()); 36 | 37 | //System.out.println(MapperUtils.toJSONString(analysis.getTarget().get())); 38 | 39 | assertLineage(analysis, new OutputColumn("NAME", ImmutableSet.of( 40 | new Analysis.SourceColumn(QualifiedObjectName.valueOf("default.test"), "COL1"), 41 | new Analysis.SourceColumn(QualifiedObjectName.valueOf("default.test"), "COL2") 42 | )), new OutputColumn("row_num", ImmutableSet.of( 43 | new Analysis.SourceColumn(QualifiedObjectName.valueOf("default.test"), "row_num") 44 | ))); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/io/github/melin/sqlflow/parser/presto/SimplePrestoMetadataService.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser.presto; 2 | 3 | import io.github.melin.sqlflow.metadata.MetadataService; 4 | import io.github.melin.sqlflow.metadata.QualifiedObjectName; 5 | import io.github.melin.sqlflow.metadata.SchemaTable; 6 | import io.github.melin.sqlflow.metadata.ViewDefinition; 7 | import io.github.melin.sqlflow.tree.QualifiedName; 8 | import com.google.common.collect.Lists; 9 | 10 | import java.util.List; 11 | import java.util.Optional; 12 | 13 | /** 14 | * huaixin 2021/12/25 6:13 PM 15 | */ 16 | public class SimplePrestoMetadataService implements MetadataService { 17 | 18 | @Override 19 | public Optional getSchema() { 20 | return Optional.of("default"); 21 | } 22 | 23 | @Override 24 | public Optional getCatalog() { 25 | return Optional.empty(); 26 | } 27 | 28 | @Override 29 | public boolean isAggregationFunction(QualifiedName name) { 30 | return false; 31 | } 32 | 33 | @Override 34 | public Optional getTableSchema(QualifiedObjectName table) { 35 | if (table.getObjectName().equals("test")) { 36 | List columns = Lists.newArrayList(); 37 | columns.add("COL1"); 38 | columns.add("COL2"); 39 | columns.add("type"); 40 | columns.add("row_num"); 41 | columns.add("ds"); 42 | 43 | return Optional.of(new SchemaTable("default", "test", columns)); 44 | } else if (table.getObjectName().equals("Demo")) { 45 | List columns = Lists.newArrayList(); 46 | columns.add("NAME"); 47 | columns.add("row_num"); 48 | 49 | return Optional.of(new SchemaTable("default", "Demo", columns)); 50 | } 51 | return Optional.empty(); 52 | } 53 | 54 | @Override 55 | public Optional getView(QualifiedObjectName viewName) { 56 | return Optional.empty(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/io/github/melin/sqlflow/parser/spark/SimpleSparkMetadataService.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser.spark; 2 | 3 | import io.github.melin.sqlflow.metadata.MetadataService; 4 | import io.github.melin.sqlflow.metadata.QualifiedObjectName; 5 | import io.github.melin.sqlflow.metadata.SchemaTable; 6 | import io.github.melin.sqlflow.metadata.ViewDefinition; 7 | import io.github.melin.sqlflow.tree.QualifiedName; 8 | import com.google.common.collect.Lists; 9 | 10 | import java.util.List; 11 | import java.util.Optional; 12 | 13 | /** 14 | * huaixin 2021/12/25 6:13 PM 15 | */ 16 | public class SimpleSparkMetadataService implements MetadataService { 17 | @Override 18 | public Optional getSchema() { 19 | return Optional.of("default"); 20 | } 21 | 22 | @Override 23 | public Optional getCatalog() { 24 | return Optional.empty(); 25 | } 26 | 27 | @Override 28 | public boolean isAggregationFunction(QualifiedName name) { 29 | return false; 30 | } 31 | 32 | @Override 33 | public Optional getTableSchema(QualifiedObjectName table) { 34 | if (table.getObjectName().equalsIgnoreCase("test")) { 35 | List columns = Lists.newArrayList(); 36 | columns.add("col1"); 37 | columns.add("col2"); 38 | columns.add("type"); 39 | columns.add("row_num"); 40 | columns.add("desc"); 41 | columns.add("ds"); 42 | 43 | return Optional.of(new SchemaTable("test", columns)); 44 | } else if (table.getObjectName().equalsIgnoreCase("demo")) { 45 | List columns = Lists.newArrayList(); 46 | columns.add("name"); 47 | columns.add("row_num"); 48 | columns.add("data_store_time"); 49 | 50 | return Optional.of(new SchemaTable("demo", columns)); 51 | } 52 | return Optional.empty(); 53 | } 54 | 55 | @Override 56 | public Optional getView(QualifiedObjectName viewName) { 57 | return Optional.empty(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/io/github/melin/sqlflow/parser/spark/SparkSqlLineageTest.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser.spark; 2 | 3 | import io.github.melin.sqlflow.analyzer.Analysis; 4 | import io.github.melin.sqlflow.analyzer.StatementAnalyzer; 5 | import io.github.melin.sqlflow.parser.AbstractSqlLineageTest; 6 | import io.github.melin.sqlflow.parser.SqlFlowParser; 7 | import io.github.melin.sqlflow.tree.statement.Statement; 8 | import io.github.melin.sqlflow.util.JsonUtils; 9 | import org.junit.Test; 10 | 11 | import java.util.Optional; 12 | 13 | import static java.util.Collections.emptyMap; 14 | 15 | /** 16 | * huaixin 2021/12/18 11:13 PM 17 | */ 18 | public class SparkSqlLineageTest extends AbstractSqlLineageTest { 19 | 20 | protected static final SqlFlowParser SQL_PARSER = new SqlFlowParser(); 21 | 22 | @Test 23 | public void testInsertInto() throws Exception { 24 | String sql = "with sdfa as (select concat(a.COL1, '-', a.COL2), a.desc," + 25 | "substr(current_timestamp(),1,19) AS data_store_time, current_date - INTERVAL 10 MINUTE as dd " + 26 | "from db1.test a where ds='201912') insert overwrite table db2.Demo select * from sdfa"; 27 | Statement statement = SQL_PARSER.createStatement(sql); 28 | 29 | Analysis analysis = new Analysis(statement, emptyMap()); 30 | StatementAnalyzer statementAnalyzer = new StatementAnalyzer(analysis, new SimpleSparkMetadataService(), SQL_PARSER); 31 | 32 | statementAnalyzer.analyze(statement, Optional.empty()); 33 | 34 | //System.out.println(SqlFormatter.formatSql(statement)); 35 | System.out.println(JsonUtils.toJSONString(analysis.getTarget().get())); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/io/github/melin/sqlflow/parser/spark/SparkSqlLineageTest1.java: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser.spark; 2 | 3 | import io.github.melin.sqlflow.analyzer.Analysis; 4 | import io.github.melin.sqlflow.analyzer.StatementAnalyzer; 5 | import io.github.melin.sqlflow.parser.AbstractSqlLineageTest; 6 | import io.github.melin.sqlflow.parser.SqlFlowParser; 7 | import io.github.melin.sqlflow.tree.statement.Statement; 8 | import io.github.melin.sqlflow.util.JsonUtils; 9 | import org.junit.Test; 10 | 11 | import java.util.Optional; 12 | 13 | import static java.util.Collections.emptyMap; 14 | 15 | /** 16 | * huaixin 2021/12/18 11:13 PM 17 | */ 18 | public class SparkSqlLineageTest1 extends AbstractSqlLineageTest { 19 | 20 | protected static final SqlFlowParser SQL_PARSER = new SqlFlowParser(); 21 | 22 | @Test 23 | public void testCreateView() throws Exception { 24 | String sql = "CREATE VIEW IF NOT EXISTS `MDM_VIEW_PRODUCT_ENRICHMENT_TRANSLATE` AS\n" + 25 | "\n" + 26 | " select concat(a.col1, '-', a.col2) tez, a.row_num from db1.test a where ds='201912'"; 27 | Statement statement = SQL_PARSER.createStatement(sql); 28 | 29 | Analysis analysis = new Analysis(statement, emptyMap()); 30 | StatementAnalyzer statementAnalyzer = new StatementAnalyzer(analysis, new SimpleSparkMetadataService(), SQL_PARSER); 31 | 32 | statementAnalyzer.analyze(statement, Optional.empty()); 33 | 34 | //System.out.println(SqlFormatter.formatSql(statement)); 35 | System.out.println(JsonUtils.toJSONString(analysis.getTarget().get())); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/kotlin/io/github/melin/sqlflow/parser/flink/FlinkSqlLineageTest3.kt: -------------------------------------------------------------------------------- 1 | package io.github.melin.sqlflow.parser.flink 2 | 3 | import io.github.melin.sqlflow.analyzer.Analysis 4 | import io.github.melin.sqlflow.analyzer.StatementAnalyzer 5 | import io.github.melin.sqlflow.metadata.SchemaTable 6 | import io.github.melin.sqlflow.metadata.SimpleMetadataService 7 | import io.github.melin.sqlflow.parser.SqlFlowParser 8 | import io.github.melin.sqlflow.util.JsonUtils 9 | import io.github.melin.superior.common.relational.create.CreateTable 10 | import io.github.melin.superior.common.relational.dml.InsertTable 11 | import io.github.melin.superior.parser.spark.SparkSqlHelper 12 | import org.assertj.core.util.Lists 13 | import org.junit.Test 14 | import java.util.* 15 | 16 | class FlinkSqlLineageTest3 { 17 | 18 | protected val SQL_PARSER = SqlFlowParser() 19 | 20 | @Test 21 | @Throws(Exception::class) 22 | fun testInsertInto() { 23 | val script = """ 24 | INSERT overwrite TABLE ads_trans_elecric_w 25 | SELECT t1.prov, 26 | current_timestamp() data_store_time, 27 | regexp_replace(t2.eltct_desc, 'sdf','') eltct_desc 28 | from dws_eltct_pro_w t1 29 | LEFT JOIN dwd_pub_fill_w t2 30 | t2 on t1.pro_id = t2.pro_id 31 | and t1.week_end = t2.week_end 32 | 33 | """.trimIndent() 34 | 35 | val statement = SQL_PARSER.createStatement(script) 36 | val analysis = Analysis(statement, emptyMap()) 37 | val statementAnalyzer = StatementAnalyzer( 38 | analysis, 39 | SimpleFlinkMetadataService(), SQL_PARSER 40 | ) 41 | statementAnalyzer.analyze(statement, Optional.empty()) 42 | 43 | System.out.println(JsonUtils.toJSONString(analysis.getTarget().get())); 44 | } 45 | } -------------------------------------------------------------------------------- /src/test/resources/examples/flink/createView.sql: -------------------------------------------------------------------------------- 1 | CREATE VIEW v AS 2 | SELECT 3 | col1 4 | FROM 5 | tbl; 6 | 7 | CREATE TEMPORARY VIEW v AS 8 | SELECT 9 | col1 10 | FROM 11 | tbl; 12 | 13 | CREATE VIEW v COMMENT 'this is a view' AS 14 | SELECT 15 | col1 16 | FROM 17 | tbl; 18 | 19 | CREATE VIEW v(col1, col2) AS 20 | SELECT 21 | col3, 22 | col4 23 | FROM 24 | tbl; 25 | 26 | CREATE VIEW v(col1, col2) COMMENT 'this is a view' AS 27 | SELECT 28 | col3, 29 | col4 30 | FROM 31 | tbl; 32 | 33 | CREATE TEMPORARY VIEW IF NOT EXISTS v AS 34 | SELECT 35 | col1 36 | FROM 37 | tbl; 38 | 39 | CREATE TEMPORARY VIEW browsers AS 40 | SELECT 41 | REGEXP_EXTRACT(user_agent,'[^\/]+') AS browser, 42 | status_code, 43 | log_time 44 | FROM 45 | server_logs; 46 | 47 | CREATE VIEW server_logs_window_1m AS 48 | SELECT 49 | TUMBLE_START(log_time, INTERVAL '1' MINUTE) AS window_start, 50 | TUMBLE_ROWTIME(log_time, INTERVAL '1' MINUTE) AS window_end, 51 | SUM(size) AS total_size, 52 | COUNT(*) AS num_requests 53 | FROM 54 | server_logs 55 | GROUP BY 56 | TUMBLE(log_time, INTERVAL '1' MINUTE); -------------------------------------------------------------------------------- /src/test/resources/examples/flink/flink.sql: -------------------------------------------------------------------------------- 1 | WITH orders_with_total AS ( 2 | SELECT order_id, price + tax AS total 3 | FROM Orders 4 | ) 5 | SELECT order_id, SUM(total) 6 | FROM orders_with_total 7 | GROUP BY order_id; 8 | 9 | SELECT order_id, price + tax FROM Orders; -------------------------------------------------------------------------------- /src/test/resources/examples/flink/insertFromSelectQueries.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO country_page_view 2 | SELECT `user`, 3 | cnt 4 | FROM page_view_source; 5 | 6 | INSERT INTO catalog1.db1.country_page_view 7 | SELECT `user`, 8 | cnt 9 | FROM page_view_source; 10 | 11 | 12 | --- Execute InsertStatement 13 | INSERT INTO country_page_view PARTITION (`date` = '2019-8-30', country = 'China') 14 | SELECT `user`, 15 | cnt 16 | FROM page_view_source; 17 | 18 | --- Partition Clause: Static Partition 19 | INSERT INTO country_page_view PARTITION (`date` = '2019-8-30', country = 'China') 20 | SELECT `user`, 21 | cnt 22 | FROM page_view_source; 23 | 24 | --- Partition Clause: Dynamic Partition 25 | INSERT INTO country_page_view PARTITION (`date` = '2019-8-30') 26 | SELECT `user`, 27 | cnt, 28 | country 29 | FROM page_view_source; 30 | 31 | --- Column List Statement 32 | INSERT INTO country_page_view PARTITION (`date` = '2019-8-30', country = 'China') (`date`, country) 33 | SELECT `user`, 34 | cnt 35 | FROM page_view_source; 36 | 37 | --- Insert Method: OverWrite 38 | INSERT OVERWRITE country_page_view PARTITION (`date` = '2019-8-30') 39 | SELECT `user`, 40 | cnt, 41 | country 42 | FROM page_view_source; 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/test/resources/examples/flink/selectDistinct.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT order_id, price + tax FROM Orders; 2 | 3 | SELECT DISTINCT order_id, price FROM (VALUES (1, 2.0), (2, 3.1)) AS t (order_id, price); 4 | 5 | SELECT DISTINCT price + tax FROM Orders WHERE id = 10; 6 | 7 | SELECT DISTINCT PRETTY_PRINT(order_id) FROM Orders; -------------------------------------------------------------------------------- /src/test/resources/examples/flink/selectWhere.sql: -------------------------------------------------------------------------------- 1 | SELECT id, age FROM table1 WHERE age IS NOT NULL; 2 | 3 | SELECT id, age FROM table1 WHERE age IS NOT DISTINCT FROM 12; 4 | 5 | SELECT id, age FROM table1 WHERE age BETWEEN SYMMETRIC 25 AND 18; 6 | 7 | SELECT id, age FROM table1 WHERE age NOT LIKE "%aa_d%" ESCAPE "a"; 8 | 9 | SELECT addr FROM table1 WHERE addr NOT SIMILAR TO '%(123|yz)%' ESCAPE "y"; 10 | 11 | SELECT id, age FROM table1 WHERE age NOT IN (18,19,20); 12 | 13 | SELECT id FROM table1 WHERE id NOT IN ( SELECT * FROM table2 ); 14 | 15 | SELECT S,SNAME 16 | FROM S 17 | WHERE NOT EXISTS 18 | (SELECT * 19 | FROM C 20 | WHERE NOT EXISTS 21 | (SELECT * 22 | FROM SC 23 | WHERE SC.S=S.S AND SC.C=C.C)); 24 | 25 | SELECT id, age FROM table1 WHERE age > 18 OR id = 1; 26 | 27 | SELECT id, age FROM table1 WHERE age > 18 AND id > 10; -------------------------------------------------------------------------------- /src/test/resources/examples/flink/selectWindowTVF.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM TABLE( 2 | TUMBLE( 3 | DATA => TABLE Bid, 4 | TIMECOL => DESCRIPTOR(bidtime), 5 | SIZE => INTERVAL '10' MINUTES 6 | ) 7 | ); 8 | 9 | SELECT window_start, 10 | window_end, 11 | SUM(price) 12 | FROM TABLE( 13 | TUMBLE( 14 | TABLE Bid, 15 | DESCRIPTOR(bidtime), 16 | INTERVAL '10' MINUTES 17 | ) 18 | ) 19 | GROUP BY window_start, window_end; 20 | 21 | SELECT * FROM TABLE( 22 | HOP(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES, INTERVAL '10' MINUTES)); 23 | 24 | SELECT * FROM TABLE( 25 | HOP( 26 | DATA => TABLE Bid, 27 | TIMECOL => DESCRIPTOR(bidtime), 28 | SLIDE => INTERVAL '5' MINUTES, 29 | SIZE => INTERVAL '10' MINUTES 30 | ) 31 | ); 32 | 33 | SELECT * FROM TABLE( 34 | CUMULATE( 35 | DATA => TABLE Bid, 36 | TIMECOL => DESCRIPTOR(bidtime), 37 | STEP => INTERVAL '2' MINUTES, 38 | SIZE => INTERVAL '10' MINUTES 39 | ) 40 | ); 41 | 42 | SELECT window_start, 43 | window_end, 44 | SUM(price) 45 | FROM TABLE( 46 | CUMULATE( 47 | TABLE Bid, 48 | DESCRIPTOR(bidtime), 49 | INTERVAL '2' MINUTES, 50 | INTERVAL '10' MINUTES 51 | )) 52 | GROUP BY window_start, window_end; 53 | -------------------------------------------------------------------------------- /src/test/resources/examples/flink/selectWithClause.sql: -------------------------------------------------------------------------------- 1 | WITH orders_with_total AS ( 2 | SELECT order_id, price + tax AS total 3 | FROM Orders 4 | ) 5 | SELECT order_id, SUM(total) 6 | FROM orders_with_total 7 | GROUP BY order_id; --------------------------------------------------------------------------------