/* * 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.calcite.sql.type; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.rel.type.RelDataTypeField; import org.apache.calcite.rel.type.RelDataTypeFieldImpl; import org.apache.calcite.rel.type.RelRecordType; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; /** * Test for {@link SqlTypeFactoryImpl}. */ class SqlTypeFactoryTest { @Test void testLeastRestrictiveWithAny() { SqlTypeFixture f = new SqlTypeFixture(); RelDataType leastRestrictive = f.typeFactory.leastRestrictive(Lists.newArrayList(f.sqlBigInt, f.sqlAny)); assertThat(leastRestrictive.getSqlTypeName(), is(SqlTypeName.ANY)); } @Test void testLeastRestrictiveWithNumbers() { SqlTypeFixture f = new SqlTypeFixture(); RelDataType leastRestrictive = f.typeFactory.leastRestrictive(Lists.newArrayList(f.sqlBigInt, f.sqlInt)); assertThat(leastRestrictive.getSqlTypeName(), is(SqlTypeName.BIGINT)); } @Test void testLeastRestrictiveWithNullability() { SqlTypeFixture f = new SqlTypeFixture(); RelDataType leastRestrictive = f.typeFactory.leastRestrictive(Lists.newArrayList(f.sqlVarcharNullable, f.sqlAny)); assertThat(leastRestrictive.getSqlTypeName(), is(SqlTypeName.ANY)); assertThat(leastRestrictive.isNullable(), is(true)); } /** Test case for * <a href="https://issues.apache.org/jira/browse/CALCITE-2994">[CALCITE-2994] * Least restrictive type among structs does not consider nullability</a>. */ @Test void testLeastRestrictiveWithNullableStruct() { SqlTypeFixture f = new SqlTypeFixture(); RelDataType leastRestrictive = f.typeFactory.leastRestrictive(ImmutableList.of(f.structOfIntNullable, f.structOfInt)); assertThat(leastRestrictive.getSqlTypeName(), is(SqlTypeName.ROW)); assertThat(leastRestrictive.isNullable(), is(true)); } @Test void testLeastRestrictiveWithNull() { SqlTypeFixture f = new SqlTypeFixture(); RelDataType leastRestrictive = f.typeFactory.leastRestrictive(Lists.newArrayList(f.sqlNull, f.sqlNull)); assertThat(leastRestrictive.getSqlTypeName(), is(SqlTypeName.NULL)); assertThat(leastRestrictive.isNullable(), is(true)); } /** Unit test for {@link SqlTypeUtil#comparePrecision(int, int)} * and {@link SqlTypeUtil#maxPrecision(int, int)}. */ @Test void testMaxPrecision() { final int un = RelDataType.PRECISION_NOT_SPECIFIED; checkPrecision(1, 1, 1, 0); checkPrecision(2, 1, 2, 1); checkPrecision(2, 100, 100, -1); checkPrecision(2, un, un, -1); checkPrecision(un, 2, un, 1); checkPrecision(un, un, un, 0); } /** Unit test for {@link ArraySqlType#getPrecedenceList()}. */ @Test void testArrayPrecedenceList() { SqlTypeFixture f = new SqlTypeFixture(); assertThat(checkPrecendenceList(f.arrayBigInt, f.arrayBigInt, f.arrayFloat), is(3)); assertThat( checkPrecendenceList(f.arrayOfArrayBigInt, f.arrayOfArrayBigInt, f.arrayOfArrayFloat), is(3)); assertThat(checkPrecendenceList(f.sqlBigInt, f.sqlBigInt, f.sqlFloat), is(3)); assertThat( checkPrecendenceList(f.multisetBigInt, f.multisetBigInt, f.multisetFloat), is(3)); assertThat( checkPrecendenceList(f.arrayBigInt, f.arrayBigInt, f.arrayBigIntNullable), is(0)); try { int i = checkPrecendenceList(f.arrayBigInt, f.sqlBigInt, f.sqlInt); fail("Expected assert, got " + i); } catch (IllegalArgumentException e) { assertThat(e.getMessage(), is("must contain type: BIGINT")); } } private int checkPrecendenceList(RelDataType t, RelDataType type1, RelDataType type2) { return t.getPrecedenceList().compareTypePrecedence(type1, type2); } private void checkPrecision(int p0, int p1, int expectedMax, int expectedComparison) { assertThat(SqlTypeUtil.maxPrecision(p0, p1), is(expectedMax)); assertThat(SqlTypeUtil.maxPrecision(p1, p0), is(expectedMax)); assertThat(SqlTypeUtil.maxPrecision(p0, p0), is(p0)); assertThat(SqlTypeUtil.maxPrecision(p1, p1), is(p1)); assertThat(SqlTypeUtil.comparePrecision(p0, p1), is(expectedComparison)); assertThat(SqlTypeUtil.comparePrecision(p0, p0), is(0)); assertThat(SqlTypeUtil.comparePrecision(p1, p1), is(0)); } /** Test case for * <a href="https://issues.apache.org/jira/browse/CALCITE-2464">[CALCITE-2464] * Allow to set nullability for columns of structured types</a>. */ @Test void createStructTypeWithNullability() { SqlTypeFixture f = new SqlTypeFixture(); RelDataTypeFactory typeFactory = f.typeFactory; List<RelDataTypeField> fields = new ArrayList<>(); RelDataTypeField field0 = new RelDataTypeFieldImpl( "i", 0, typeFactory.createSqlType(SqlTypeName.INTEGER)); RelDataTypeField field1 = new RelDataTypeFieldImpl( "s", 1, typeFactory.createSqlType(SqlTypeName.VARCHAR)); fields.add(field0); fields.add(field1); final RelDataType recordType = new RelRecordType(fields); // nullable false by default final RelDataType copyRecordType = typeFactory.createTypeWithNullability(recordType, true); assertFalse(recordType.isNullable()); assertTrue(copyRecordType.isNullable()); } /** Test case for * <a href="https://issues.apache.org/jira/browse/CALCITE-3429">[CALCITE-3429] * AssertionError thrown for user-defined table function with map argument</a>. */ @Test void testCreateTypeWithJavaMapType() { SqlTypeFixture f = new SqlTypeFixture(); RelDataType relDataType = f.typeFactory.createJavaType(Map.class); assertThat(relDataType.getSqlTypeName(), is(SqlTypeName.MAP)); assertThat(relDataType.getKeyType().getSqlTypeName(), is(SqlTypeName.ANY)); try { f.typeFactory.createSqlType(SqlTypeName.MAP); fail(); } catch (AssertionError e) { assertThat(e.getMessage(), is("use createMapType() instead")); } } /** Test case for * <a href="https://issues.apache.org/jira/browse/CALCITE-3924">[CALCITE-3924] * Fix flakey test to handle TIMESTAMP and TIMESTAMP(0) correctly</a>. */ @Test void testCreateSqlTypeWithPrecision() { SqlTypeFixture f = new SqlTypeFixture(); checkCreateSqlTypeWithPrecision(f.typeFactory, SqlTypeName.TIME); checkCreateSqlTypeWithPrecision(f.typeFactory, SqlTypeName.TIMESTAMP); checkCreateSqlTypeWithPrecision(f.typeFactory, SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE); checkCreateSqlTypeWithPrecision(f.typeFactory, SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE); } private void checkCreateSqlTypeWithPrecision( RelDataTypeFactory typeFactory, SqlTypeName sqlTypeName) { RelDataType ts = typeFactory.createSqlType(sqlTypeName); RelDataType tsWithoutPrecision = typeFactory.createSqlType(sqlTypeName, -1); RelDataType tsWithPrecision0 = typeFactory.createSqlType(sqlTypeName, 0); RelDataType tsWithPrecision1 = typeFactory.createSqlType(sqlTypeName, 1); RelDataType tsWithPrecision2 = typeFactory.createSqlType(sqlTypeName, 2); RelDataType tsWithPrecision3 = typeFactory.createSqlType(sqlTypeName, 3); // for instance, 8 exceeds max precision for timestamp which is 3 RelDataType tsWithPrecision8 = typeFactory.createSqlType(sqlTypeName, 8); assertThat(ts.toString(), is(sqlTypeName.getName() + "(0)")); assertThat(ts.getFullTypeString(), is(sqlTypeName.getName() + "(0) NOT NULL")); assertThat(tsWithoutPrecision.toString(), is(sqlTypeName.getName())); assertThat(tsWithoutPrecision.getFullTypeString(), is(sqlTypeName.getName() + " NOT NULL")); assertThat(tsWithPrecision0.toString(), is(sqlTypeName.getName() + "(0)")); assertThat(tsWithPrecision0.getFullTypeString(), is(sqlTypeName.getName() + "(0) NOT NULL")); assertThat(tsWithPrecision1.toString(), is(sqlTypeName.getName() + "(1)")); assertThat(tsWithPrecision1.getFullTypeString(), is(sqlTypeName.getName() + "(1) NOT NULL")); assertThat(tsWithPrecision2.toString(), is(sqlTypeName.getName() + "(2)")); assertThat(tsWithPrecision2.getFullTypeString(), is(sqlTypeName.getName() + "(2) NOT NULL")); assertThat(tsWithPrecision3.toString(), is(sqlTypeName.getName() + "(3)")); assertThat(tsWithPrecision3.getFullTypeString(), is(sqlTypeName.getName() + "(3) NOT NULL")); assertThat(tsWithPrecision8.toString(), is(sqlTypeName.getName() + "(3)")); assertThat(tsWithPrecision8.getFullTypeString(), is(sqlTypeName.getName() + "(3) NOT NULL")); assertThat(ts != tsWithoutPrecision, is(true)); assertThat(ts == tsWithPrecision0, is(true)); assertThat(tsWithPrecision3 == tsWithPrecision8, is(true)); } }