blob: 97c7a2826400e0966a6db97169a6b500e678f07f [file] [log] [blame]
/*
* 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 org.apache.beam.sdk.extensions.sql.impl.interpreter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.BeamSqlExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.BeamSqlPrimitive;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.arithmetic.BeamSqlDivideExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.arithmetic.BeamSqlMinusExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.arithmetic.BeamSqlModExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.arithmetic.BeamSqlMultiplyExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.arithmetic.BeamSqlPlusExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.date.BeamSqlCurrentDateExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.date.BeamSqlCurrentTimeExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.date.BeamSqlCurrentTimestampExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.date.BeamSqlDatetimeMinusExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.date.BeamSqlDatetimePlusExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.date.BeamSqlIntervalMultiplyExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.logical.BeamSqlAndExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.logical.BeamSqlNotExpression;
import org.apache.beam.sdk.extensions.sql.impl.interpreter.operator.logical.BeamSqlOrExpression;
import org.apache.calcite.avatica.util.TimeUnit;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeSystem;
import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.sql.SqlIntervalQualifier;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.BasicSqlType;
import org.apache.calcite.sql.type.SqlTypeName;
import org.junit.Test;
/** Unit test cases for {@link BeamSqlFnExecutor}. */
public class BeamSqlFnExecutorTest extends BeamSqlFnExecutorTestBase {
@Test
public void testBuildExpression_logical() {
RexNode rexNode;
BeamSqlExpression exp;
rexNode =
rexBuilder.makeCall(
SqlStdOperatorTable.AND,
Arrays.asList(rexBuilder.makeLiteral(true), rexBuilder.makeLiteral(false)));
exp = BeamSqlFnExecutor.buildExpression(rexNode);
assertTrue(exp instanceof BeamSqlAndExpression);
rexNode =
rexBuilder.makeCall(
SqlStdOperatorTable.OR,
Arrays.asList(rexBuilder.makeLiteral(true), rexBuilder.makeLiteral(false)));
exp = BeamSqlFnExecutor.buildExpression(rexNode);
assertTrue(exp instanceof BeamSqlOrExpression);
rexNode =
rexBuilder.makeCall(SqlStdOperatorTable.NOT, Arrays.asList(rexBuilder.makeLiteral(true)));
exp = BeamSqlFnExecutor.buildExpression(rexNode);
assertTrue(exp instanceof BeamSqlNotExpression);
}
@Test(expected = IllegalStateException.class)
public void testBuildExpression_logical_andOr_invalidOperand() {
RexNode rexNode =
rexBuilder.makeCall(
SqlStdOperatorTable.AND,
Arrays.asList(rexBuilder.makeLiteral(true), rexBuilder.makeLiteral("hello")));
BeamSqlFnExecutor.buildExpression(rexNode);
}
@Test(expected = IllegalStateException.class)
public void testBuildExpression_logical_not_invalidOperand() {
RexNode rexNode =
rexBuilder.makeCall(
SqlStdOperatorTable.NOT, Arrays.asList(rexBuilder.makeLiteral("hello")));
BeamSqlFnExecutor.buildExpression(rexNode);
}
@Test
public void testBuildExpression_literal() {
RelDataType realType = new BasicSqlType(RelDataTypeSystem.DEFAULT, SqlTypeName.INTEGER);
RexLiteral rexNode = RexLiteral.fromJdbcString(realType, SqlTypeName.DOUBLE, "1.0");
BeamSqlExpression exp = BeamSqlFnExecutor.buildExpression(rexNode);
assertTrue(exp instanceof BeamSqlPrimitive);
assertEquals(SqlTypeName.INTEGER, exp.getOutputType());
}
@Test(expected = IllegalStateException.class)
public void testBuildExpression_literal_mismatch_type() {
RelDataType realType = new BasicSqlType(RelDataTypeSystem.DEFAULT, SqlTypeName.VARCHAR);
RexLiteral rexNode = RexLiteral.fromJdbcString(realType, SqlTypeName.DOUBLE, "1.0");
BeamSqlFnExecutor.buildExpression(rexNode);
}
@Test
public void testBuildExpression_arithmetic() {
testBuildArithmeticExpression(SqlStdOperatorTable.PLUS, BeamSqlPlusExpression.class);
testBuildArithmeticExpression(SqlStdOperatorTable.MINUS, BeamSqlMinusExpression.class);
testBuildArithmeticExpression(SqlStdOperatorTable.MULTIPLY, BeamSqlMultiplyExpression.class);
testBuildArithmeticExpression(SqlStdOperatorTable.DIVIDE, BeamSqlDivideExpression.class);
testBuildArithmeticExpression(SqlStdOperatorTable.MOD, BeamSqlModExpression.class);
}
private void testBuildArithmeticExpression(
SqlOperator fn, Class<? extends BeamSqlExpression> clazz) {
RexNode rexNode;
BeamSqlExpression exp;
rexNode =
rexBuilder.makeCall(
fn,
Arrays.asList(
rexBuilder.makeBigintLiteral(BigDecimal.ONE),
rexBuilder.makeBigintLiteral(BigDecimal.ONE)));
exp = BeamSqlFnExecutor.buildExpression(rexNode);
assertTrue(exp.getClass().equals(clazz));
}
@Test
public void testBuildExpression_date() {
RexNode rexNode;
BeamSqlExpression exp;
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
calendar.setTime(new Date());
// CURRENT_DATE
rexNode = rexBuilder.makeCall(SqlStdOperatorTable.CURRENT_DATE, Arrays.asList());
exp = BeamSqlFnExecutor.buildExpression(rexNode);
assertTrue(exp instanceof BeamSqlCurrentDateExpression);
// LOCALTIME
rexNode = rexBuilder.makeCall(SqlStdOperatorTable.LOCALTIME, Arrays.asList());
exp = BeamSqlFnExecutor.buildExpression(rexNode);
assertTrue(exp instanceof BeamSqlCurrentTimeExpression);
// LOCALTIMESTAMP
rexNode = rexBuilder.makeCall(SqlStdOperatorTable.LOCALTIMESTAMP, Arrays.asList());
exp = BeamSqlFnExecutor.buildExpression(rexNode);
assertTrue(exp instanceof BeamSqlCurrentTimestampExpression);
// DATETIME_PLUS
rexNode =
rexBuilder.makeCall(
SqlStdOperatorTable.DATETIME_PLUS,
Arrays.<RexNode>asList(
rexBuilder.makeDateLiteral(calendar),
rexBuilder.makeIntervalLiteral(
BigDecimal.TEN,
new SqlIntervalQualifier(TimeUnit.DAY, TimeUnit.DAY, SqlParserPos.ZERO))));
exp = BeamSqlFnExecutor.buildExpression(rexNode);
assertTrue(exp instanceof BeamSqlDatetimePlusExpression);
// * for intervals
rexNode =
rexBuilder.makeCall(
SqlStdOperatorTable.MULTIPLY,
Arrays.<RexNode>asList(
rexBuilder.makeExactLiteral(BigDecimal.ONE),
rexBuilder.makeIntervalLiteral(
BigDecimal.TEN,
new SqlIntervalQualifier(TimeUnit.DAY, TimeUnit.DAY, SqlParserPos.ZERO))));
exp = BeamSqlFnExecutor.buildExpression(rexNode);
assertTrue(exp instanceof BeamSqlIntervalMultiplyExpression);
// minus for dates
rexNode =
rexBuilder.makeCall(
TYPE_FACTORY.createSqlIntervalType(
new SqlIntervalQualifier(TimeUnit.DAY, TimeUnit.DAY, SqlParserPos.ZERO)),
SqlStdOperatorTable.MINUS,
Arrays.asList(
rexBuilder.makeTimestampLiteral(Calendar.getInstance(), 1000),
rexBuilder.makeTimestampLiteral(Calendar.getInstance(), 1000)));
exp = BeamSqlFnExecutor.buildExpression(rexNode);
assertTrue(exp instanceof BeamSqlDatetimeMinusExpression);
}
}