com.hazelcast.org.apache.calcite.sql.SqlMatchRecognize Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.org.apache.calcite.sql;
import com.hazelcast.org.apache.calcite.sql.parser.SqlParserPos;
import com.hazelcast.org.apache.calcite.sql.util.SqlBasicVisitor;
import com.hazelcast.org.apache.calcite.sql.util.SqlVisitor;
import com.hazelcast.org.apache.calcite.sql.validate.SqlValidator;
import com.hazelcast.org.apache.calcite.sql.validate.SqlValidatorScope;
import com.hazelcast.org.apache.calcite.util.ImmutableNullableList;
import com.hazelcast.com.google.common.base.Preconditions;
import com.hazelcast.org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List;
import java.util.Objects;
/**
* SqlNode for MATCH_RECOGNIZE clause.
*/
public class SqlMatchRecognize extends SqlCall {
public static final int OPERAND_TABLE_REF = 0;
public static final int OPERAND_PATTERN = 1;
public static final int OPERAND_STRICT_START = 2;
public static final int OPERAND_STRICT_END = 3;
public static final int OPERAND_PATTERN_DEFINES = 4;
public static final int OPERAND_MEASURES = 5;
public static final int OPERAND_AFTER = 6;
public static final int OPERAND_SUBSET = 7;
public static final int OPERAND_ROWS_PER_MATCH = 8;
public static final int OPERAND_PARTITION_BY = 9;
public static final int OPERAND_ORDER_BY = 10;
public static final int OPERAND_INTERVAL = 11;
public static final SqlPrefixOperator SKIP_TO_FIRST =
new SqlPrefixOperator("SKIP TO FIRST", SqlKind.SKIP_TO_FIRST, 20, null,
null, null);
public static final SqlPrefixOperator SKIP_TO_LAST =
new SqlPrefixOperator("SKIP TO LAST", SqlKind.SKIP_TO_LAST, 20, null,
null, null);
//~ Instance fields -------------------------------------------
private SqlNode tableRef;
private SqlNode pattern;
private SqlLiteral strictStart;
private SqlLiteral strictEnd;
private SqlNodeList patternDefList;
private SqlNodeList measureList;
private @Nullable SqlNode after;
private SqlNodeList subsetList;
private @Nullable SqlLiteral rowsPerMatch;
private SqlNodeList partitionList;
private SqlNodeList orderList;
private @Nullable SqlLiteral interval;
/** Creates a SqlMatchRecognize. */
public SqlMatchRecognize(SqlParserPos pos, SqlNode tableRef, SqlNode pattern,
SqlLiteral strictStart, SqlLiteral strictEnd, SqlNodeList patternDefList,
SqlNodeList measureList, @Nullable SqlNode after, SqlNodeList subsetList,
@Nullable SqlLiteral rowsPerMatch, SqlNodeList partitionList,
SqlNodeList orderList, @Nullable SqlLiteral interval) {
super(pos);
this.tableRef = Objects.requireNonNull(tableRef, "tableRef");
this.pattern = Objects.requireNonNull(pattern, "pattern");
this.strictStart = strictStart;
this.strictEnd = strictEnd;
this.patternDefList = Objects.requireNonNull(patternDefList, "patternDefList");
Preconditions.checkArgument(patternDefList.size() > 0);
this.measureList = Objects.requireNonNull(measureList, "measureList");
this.after = after;
this.subsetList = subsetList;
Preconditions.checkArgument(rowsPerMatch == null
|| rowsPerMatch.value instanceof RowsPerMatchOption);
this.rowsPerMatch = rowsPerMatch;
this.partitionList = Objects.requireNonNull(partitionList, "partitionList");
this.orderList = Objects.requireNonNull(orderList, "orderList");
this.interval = interval;
}
// ~ Methods
@Override public SqlOperator getOperator() {
return SqlMatchRecognizeOperator.INSTANCE;
}
@Override public SqlKind getKind() {
return SqlKind.MATCH_RECOGNIZE;
}
@SuppressWarnings("nullness")
@Override public List getOperandList() {
return ImmutableNullableList.of(tableRef, pattern, strictStart, strictEnd,
patternDefList, measureList, after, subsetList, rowsPerMatch, partitionList, orderList,
interval);
}
@Override public void unparse(SqlWriter writer, int leftPrec,
int rightPrec) {
getOperator().unparse(writer, this, 0, 0);
}
@Override public void validate(SqlValidator validator, SqlValidatorScope scope) {
validator.validateMatchRecognize(this);
}
@SuppressWarnings("assignment.type.incompatible")
@Override public void setOperand(int i, @Nullable SqlNode operand) {
switch (i) {
case OPERAND_TABLE_REF:
tableRef = Objects.requireNonNull(operand, "operand");
break;
case OPERAND_PATTERN:
pattern = operand;
break;
case OPERAND_STRICT_START:
strictStart = (SqlLiteral) operand;
break;
case OPERAND_STRICT_END:
strictEnd = (SqlLiteral) operand;
break;
case OPERAND_PATTERN_DEFINES:
patternDefList = Objects.requireNonNull((SqlNodeList) operand);
Preconditions.checkArgument(patternDefList.size() > 0);
break;
case OPERAND_MEASURES:
measureList = Objects.requireNonNull((SqlNodeList) operand);
break;
case OPERAND_AFTER:
after = operand;
break;
case OPERAND_SUBSET:
subsetList = (SqlNodeList) operand;
break;
case OPERAND_ROWS_PER_MATCH:
rowsPerMatch = (SqlLiteral) operand;
Preconditions.checkArgument(rowsPerMatch == null
|| rowsPerMatch.value instanceof RowsPerMatchOption);
break;
case OPERAND_PARTITION_BY:
partitionList = (SqlNodeList) operand;
break;
case OPERAND_ORDER_BY:
orderList = (SqlNodeList) operand;
break;
case OPERAND_INTERVAL:
interval = (SqlLiteral) operand;
break;
default:
throw new AssertionError(i);
}
}
public SqlNode getTableRef() {
return tableRef;
}
public SqlNode getPattern() {
return pattern;
}
public SqlLiteral getStrictStart() {
return strictStart;
}
public SqlLiteral getStrictEnd() {
return strictEnd;
}
public SqlNodeList getPatternDefList() {
return patternDefList;
}
public SqlNodeList getMeasureList() {
return measureList;
}
public @Nullable SqlNode getAfter() {
return after;
}
public SqlNodeList getSubsetList() {
return subsetList;
}
public @Nullable SqlLiteral getRowsPerMatch() {
return rowsPerMatch;
}
public SqlNodeList getPartitionList() {
return partitionList;
}
public SqlNodeList getOrderList() {
return orderList;
}
public @Nullable SqlLiteral getInterval() {
return interval;
}
/**
* Options for {@code ROWS PER MATCH}.
*/
public enum RowsPerMatchOption {
ONE_ROW("ONE ROW PER MATCH"),
ALL_ROWS("ALL ROWS PER MATCH");
private final String sql;
RowsPerMatchOption(String sql) {
this.sql = sql;
}
@Override public String toString() {
return sql;
}
public SqlLiteral symbol(SqlParserPos pos) {
return SqlLiteral.createSymbol(this, pos);
}
}
/**
* Options for {@code AFTER MATCH} clause.
*/
public enum AfterOption implements Symbolizable {
SKIP_TO_NEXT_ROW("SKIP TO NEXT ROW"),
SKIP_PAST_LAST_ROW("SKIP PAST LAST ROW");
private final String sql;
AfterOption(String sql) {
this.sql = sql;
}
@Override public String toString() {
return sql;
}
}
/**
* An operator describing a MATCH_RECOGNIZE specification.
*/
public static class SqlMatchRecognizeOperator extends SqlOperator {
public static final SqlMatchRecognizeOperator INSTANCE =
new SqlMatchRecognizeOperator();
private SqlMatchRecognizeOperator() {
super("MATCH_RECOGNIZE", SqlKind.MATCH_RECOGNIZE, 2, true, null, null, null);
}
@Override public SqlSyntax getSyntax() {
return SqlSyntax.SPECIAL;
}
@SuppressWarnings("argument.type.incompatible")
@Override public SqlCall createCall(
@Nullable SqlLiteral functionQualifier,
SqlParserPos pos,
@Nullable SqlNode... operands) {
assert functionQualifier == null;
assert operands.length == 12;
return new SqlMatchRecognize(pos, operands[0], operands[1],
(SqlLiteral) operands[2], (SqlLiteral) operands[3],
(SqlNodeList) operands[4], (SqlNodeList) operands[5], operands[6],
(SqlNodeList) operands[7], (SqlLiteral) operands[8],
(SqlNodeList) operands[9], (SqlNodeList) operands[10], (SqlLiteral) operands[11]);
}
@Override public void acceptCall(
SqlVisitor visitor,
SqlCall call,
boolean onlyExpressions,
SqlBasicVisitor.ArgHandler argHandler) {
if (onlyExpressions) {
List operands = call.getOperandList();
for (int i = 0; i < operands.size(); i++) {
SqlNode operand = operands.get(i);
if (operand == null) {
continue;
}
argHandler.visitChild(visitor, call, i, operand);
}
} else {
super.acceptCall(visitor, call, onlyExpressions, argHandler);
}
}
@Override public void validateCall(
SqlCall call,
SqlValidator validator,
SqlValidatorScope scope,
SqlValidatorScope operandScope) {
validator.validateMatchRecognize(call);
}
@Override public void unparse(
SqlWriter writer,
SqlCall call,
int leftPrec,
int rightPrec) {
final SqlMatchRecognize pattern = (SqlMatchRecognize) call;
pattern.tableRef.unparse(writer, 0, 0);
final SqlWriter.Frame mrFrame = writer.startFunCall("MATCH_RECOGNIZE");
if (pattern.partitionList != null && pattern.partitionList.size() > 0) {
writer.newlineAndIndent();
writer.sep("PARTITION BY");
final SqlWriter.Frame partitionFrame = writer.startList("", "");
pattern.partitionList.unparse(writer, 0, 0);
writer.endList(partitionFrame);
}
if (pattern.orderList != null && pattern.orderList.size() > 0) {
writer.newlineAndIndent();
writer.sep("ORDER BY");
writer.list(SqlWriter.FrameTypeEnum.ORDER_BY_LIST, SqlWriter.COMMA,
pattern.orderList);
}
if (pattern.measureList != null && pattern.measureList.size() > 0) {
writer.newlineAndIndent();
writer.sep("MEASURES");
final SqlWriter.Frame measureFrame = writer.startList("", "");
pattern.measureList.unparse(writer, 0, 0);
writer.endList(measureFrame);
}
SqlLiteral rowsPerMatch = pattern.rowsPerMatch;
if (rowsPerMatch != null) {
writer.newlineAndIndent();
rowsPerMatch.unparse(writer, 0, 0);
}
SqlNode after = pattern.after;
if (after != null) {
writer.newlineAndIndent();
writer.sep("AFTER MATCH");
after.unparse(writer, 0, 0);
}
writer.newlineAndIndent();
writer.sep("PATTERN");
SqlWriter.Frame patternFrame = writer.startList("(", ")");
if (pattern.strictStart.booleanValue()) {
writer.sep("^");
}
pattern.pattern.unparse(writer, 0, 0);
if (pattern.strictEnd.booleanValue()) {
writer.sep("$");
}
writer.endList(patternFrame);
SqlLiteral interval = pattern.interval;
if (interval != null) {
writer.sep("WITHIN");
interval.unparse(writer, 0, 0);
}
if (pattern.subsetList != null && pattern.subsetList.size() > 0) {
writer.newlineAndIndent();
writer.sep("SUBSET");
SqlWriter.Frame subsetFrame = writer.startList("", "");
pattern.subsetList.unparse(writer, 0, 0);
writer.endList(subsetFrame);
}
writer.newlineAndIndent();
writer.sep("DEFINE");
final SqlWriter.Frame patternDefFrame = writer.startList("", "");
final SqlNodeList newDefineList = new SqlNodeList(SqlParserPos.ZERO);
for (SqlNode node : pattern.getPatternDefList()) {
final SqlCall call2 = (SqlCall) node;
// swap the position of alias position in AS operator
newDefineList.add(
call2.getOperator().createCall(SqlParserPos.ZERO, call2.operand(1),
call2.operand(0)));
}
newDefineList.unparse(writer, 0, 0);
writer.endList(patternDefFrame);
writer.endList(mrFrame);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy