Skip to content

Commit

Permalink
IGNITE-21171 SQL Calcite: Fix column nullability for data types with …
Browse files Browse the repository at this point in the history
…precession or scale - Fixes #11154.

Signed-off-by: Aleksey Plekhanov <plehanov.alex@gmail.com>
  • Loading branch information
alex-plekhanov committed Jan 25, 2024
1 parent e4993b8 commit e2662a2
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,8 @@ private KeyValDescriptor(String name, GridQueryProperty desc, boolean isKey, int
f,
storageType,
desc != null && desc.precision() != -1 ? desc.precision() : PRECISION_NOT_SPECIFIED,
desc != null && desc.scale() != -1 ? desc.scale() : SCALE_NOT_SPECIFIED
desc != null && desc.scale() != -1 ? desc.scale() : SCALE_NOT_SPECIFIED,
desc == null || !desc.notNull()
);
}

Expand Down Expand Up @@ -785,7 +786,9 @@ private FieldDescriptor(GridQueryProperty desc, int fieldIdx) {
if (logicalType == null) {
logicalType = TypeUtils.sqlType(f, storageType,
desc.precision() == -1 ? PRECISION_NOT_SPECIFIED : desc.precision(),
desc.scale() == -1 ? SCALE_NOT_SPECIFIED : desc.scale());
desc.scale() == -1 ? SCALE_NOT_SPECIFIED : desc.scale(),
!desc.notNull()
);
}

return logicalType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ private SystemViewColumnDescriptorImpl(String name, Class<?> type, int fieldIdx,
/** {@inheritDoc} */
@Override public RelDataType logicalType(IgniteTypeFactory f) {
if (logicalType == null)
logicalType = TypeUtils.sqlType(f, type, PRECISION_NOT_SPECIFIED, SCALE_NOT_SPECIFIED);
logicalType = TypeUtils.sqlType(f, type, PRECISION_NOT_SPECIFIED, SCALE_NOT_SPECIFIED, true);

return logicalType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,22 @@ private static RelDataType createRowType(IgniteTypeFactory typeFactory, List<Rel
}

/** */
public static RelDataType sqlType(IgniteTypeFactory typeFactory, Class<?> cls, int precision, int scale) {
public static RelDataType sqlType(
IgniteTypeFactory typeFactory,
Class<?> cls,
int precision,
int scale,
boolean nullability
) {
RelDataType javaType = typeFactory.createJavaType(cls);

if (javaType.getSqlTypeName().allowsPrecScale(true, true) &&
(precision != RelDataType.PRECISION_NOT_SPECIFIED || scale != RelDataType.SCALE_NOT_SPECIFIED))
return typeFactory.createSqlType(javaType.getSqlTypeName(), precision, scale);
(precision != RelDataType.PRECISION_NOT_SPECIFIED || scale != RelDataType.SCALE_NOT_SPECIFIED)) {
return typeFactory.createTypeWithNullability(
typeFactory.createSqlType(javaType.getSqlTypeName(), precision, scale), nullability);
}

return sqlType(typeFactory, javaType);
return typeFactory.createTypeWithNullability(sqlType(typeFactory, javaType), nullability);
}

/** */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ public class QueryMetadataIntegrationTest extends AbstractBasicIntegrationTest {
@Test
public void testJoin() throws Exception {
executeSql("CREATE TABLE tbl1 (id DECIMAL(10, 2), val VARCHAR, val2 BIGINT, ts TIMESTAMP(14), PRIMARY KEY(id, val))");
executeSql("CREATE TABLE tbl2 (id DECIMAL(10, 2), val VARCHAR, val2 BIGINT, ts TIMESTAMP(14), PRIMARY KEY(id, val))");
executeSql("CREATE TABLE tbl2 (id DECIMAL(10, 2) NOT NULL, val VARCHAR, val2 BIGINT, ts TIMESTAMP(14), " +
"PRIMARY KEY(id, val))");

checker("select * from tbl1 inner join tbl2 on (tbl1.id > tbl2.id and tbl1.id <> ?) " +
"where tbl1.id > ? and tbl2.val like ? or tbl1.ts = ?")
.addMeta(
builder -> builder
.add("PUBLIC", "TBL1", BigDecimal.class, "ID", 10, 2, false)
.add("PUBLIC", "TBL1", BigDecimal.class, "ID", 10, 2, true)
.add("PUBLIC", "TBL1", String.class, "VAL", true)
.add("PUBLIC", "TBL1", Long.class, "VAL2", 19, 0, true)
.add("PUBLIC", "TBL1", java.sql.Timestamp.class, "TS", 0, SCALE_NOT_SPECIFIED, true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,35 @@ public void createTableAsSelectFromDistributedTable() {
assertEquals(100L, sql("select count(*) from my_table2").get(0).get(0));
}

/**
* Creates table with nullabale/not nullable columns and checks nullability.
*/
@Test
public void createTableWithNullability() {
List<String> dataTypes = F.asList("INT", "FLOAT", "DOUBLE", "DECIMAL", "DECIMAL(10,2)", "VARCHAR",
"VARCHAR(10)", "CHAR", "CHAR(10)", "DATE", "TIME", "TIMESTAMP", "BINARY", "BINARY(10)", "VARBINARY",
"VARBINARY(10)", "UUID", "OTHER");

for (String dataType : dataTypes) {
try {
sql("CREATE TABLE my_table (id INT PRIMARY KEY, val " + dataType + ')');
sql("INSERT INTO my_table(id, val) VALUES (0, NULL)");
}
finally {
sql("DROP TABLE my_table");
}

try {
sql("CREATE TABLE my_table (id INT PRIMARY KEY, val " + dataType + " NOT NULL)");
assertThrows("INSERT INTO my_table(id, val) VALUES (0, NULL)", IgniteSQLException.class,
"does not allow NULLs");
}
finally {
sql("DROP TABLE my_table");
}
}
}

/**
* Drops a table created in a default schema.
*/
Expand Down Expand Up @@ -741,7 +770,7 @@ public void alterTableAddNotNullColumn() {
sql("alter table my_table add column val2 varchar not null");

assertThrows("insert into my_table (id, val, val2) values (0, '1', null)", IgniteSQLException.class,
"Null value is not allowed");
"does not allow NULLs");

sql("insert into my_table (id, val, val2) values (0, '1', '2')");

Expand Down Expand Up @@ -850,7 +879,7 @@ public void alterTableDropAddColumn() {
assertEquals("2", res.get(0).get(2));

assertThrows("insert into my_table (id, val, val2) values (1, '2', null)", IgniteSQLException.class,
"Null value is not allowed");
"does not allow NULLs");

sql("insert into my_table (id, val, val2) values (1, '2', '3')");

Expand Down

0 comments on commit e2662a2

Please sign in to comment.