From b28b478d0fd82a126d7c100ae4c1fc6e72dd2824 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Wed, 2 Dec 2020 11:39:51 +0100 Subject: [PATCH] [jOOQ/jOOQ#11070] Propagate type nullability through API - WIP --- .../src/main/java/org/jooq/impl/Coalesce.java | 7 ++- jOOQ/src/main/java/org/jooq/impl/DSL.java | 12 ++-- jOOQ/src/main/java/org/jooq/impl/Ntile.java | 2 +- jOOQ/src/main/java/org/jooq/impl/NullIf.java | 2 +- jOOQ/src/main/java/org/jooq/impl/Nvl.java | 2 +- jOOQ/src/main/java/org/jooq/impl/Nvl2.java | 2 +- .../jooq/impl/PositionalWindowFunction.java | 2 +- .../java/org/jooq/impl/RankingFunction.java | 2 +- .../main/java/org/jooq/impl/RowNumber.java | 2 +- jOOQ/src/main/java/org/jooq/impl/Tools.java | 55 +++++++++++++++++++ jOOQ/src/main/java/org/jooq/impl/Val.java | 8 ++- 11 files changed, 79 insertions(+), 17 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/Coalesce.java b/jOOQ/src/main/java/org/jooq/impl/Coalesce.java index 64aca3f3bd..9d8fcc9eb7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Coalesce.java +++ b/jOOQ/src/main/java/org/jooq/impl/Coalesce.java @@ -38,6 +38,7 @@ package org.jooq.impl; import static org.jooq.impl.Names.N_COALESCE; +import static org.jooq.impl.Tools.anyNotNull; import org.jooq.Context; import org.jooq.DataType; @@ -54,9 +55,9 @@ final class Coalesce extends AbstractField { private static final long serialVersionUID = -4546488210418866103L; private final Field[] fields; - @SuppressWarnings("unchecked") - Coalesce(DataType dataType, Field[] fields) { - super(N_COALESCE, dataType); + @SuppressWarnings({ "unchecked", "rawtypes" }) + Coalesce(Field[] fields) { + super(N_COALESCE, (DataType) anyNotNull(fields)); this.fields = (Field[]) fields; } diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index 29583f31df..b28b722b17 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -107,8 +107,10 @@ import static org.jooq.impl.RankingFunction.RankingType.CUME_DIST; import static org.jooq.impl.RankingFunction.RankingType.DENSE_RANK; import static org.jooq.impl.RankingFunction.RankingType.PERCENT_RANK; import static org.jooq.impl.RankingFunction.RankingType.RANK; +import static org.jooq.impl.SQLDataType.INTEGER; import static org.jooq.impl.SQLDataType.JSON; import static org.jooq.impl.SQLDataType.JSONB; +import static org.jooq.impl.SQLDataType.NUMERIC; import static org.jooq.impl.SQLDataType.TIMESTAMP; import static org.jooq.impl.Tools.EMPTY_FIELD; import static org.jooq.impl.Tools.combine; @@ -14529,7 +14531,7 @@ public class DSL { // Java 8 is stricter than Java 7 with respect to generics and overload // resolution (http://stackoverflow.com/q/5361513/521799) static Field coalesce0(Field field, Field... fields) { - return new Coalesce<>(nullSafeDataType(field), nullSafe(combine(field, fields))); + return new Coalesce<>(nullSafe(combine(field, fields))); } /** @@ -22277,7 +22279,7 @@ public class DSL { @NotNull @Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE }) public static WindowOverStep rank() { - return new RankingFunction<>(RANK, SQLDataType.INTEGER); + return new RankingFunction<>(RANK, INTEGER); } /** @@ -22286,7 +22288,7 @@ public class DSL { @NotNull @Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE }) public static WindowOverStep denseRank() { - return new RankingFunction<>(DENSE_RANK, SQLDataType.INTEGER); + return new RankingFunction<>(DENSE_RANK, INTEGER); } /** @@ -22295,7 +22297,7 @@ public class DSL { @NotNull @Support({ CUBRID, H2, MARIADB, MYSQL, POSTGRES, SQLITE }) public static WindowOverStep percentRank() { - return new RankingFunction<>(PERCENT_RANK, SQLDataType.NUMERIC); + return new RankingFunction<>(PERCENT_RANK, NUMERIC); } /** @@ -22304,7 +22306,7 @@ public class DSL { @NotNull @Support({ CUBRID, H2, MARIADB, MYSQL, POSTGRES, SQLITE }) public static WindowOverStep cumeDist() { - return new RankingFunction<>(CUME_DIST, SQLDataType.NUMERIC); + return new RankingFunction<>(CUME_DIST, NUMERIC); } /** diff --git a/jOOQ/src/main/java/org/jooq/impl/Ntile.java b/jOOQ/src/main/java/org/jooq/impl/Ntile.java index 11346202ab..5b574b74de 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Ntile.java +++ b/jOOQ/src/main/java/org/jooq/impl/Ntile.java @@ -55,7 +55,7 @@ final class Ntile extends AbstractWindowFunction { private final Field tiles; Ntile(Field tiles) { - super(N_NTILE, INTEGER); + super(N_NTILE, INTEGER.notNull()); this.tiles = tiles; } diff --git a/jOOQ/src/main/java/org/jooq/impl/NullIf.java b/jOOQ/src/main/java/org/jooq/impl/NullIf.java index 8ae63def35..b268181b6c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/NullIf.java +++ b/jOOQ/src/main/java/org/jooq/impl/NullIf.java @@ -58,7 +58,7 @@ final class NullIf extends AbstractField { private final Field arg2; NullIf(Field arg1, Field arg2) { - super(N_NULLIF, arg1.getDataType()); + super(N_NULLIF, arg1.getDataType().null_()); this.arg1 = arg1; this.arg2 = arg2; diff --git a/jOOQ/src/main/java/org/jooq/impl/Nvl.java b/jOOQ/src/main/java/org/jooq/impl/Nvl.java index 52d0daa34b..957457d809 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Nvl.java +++ b/jOOQ/src/main/java/org/jooq/impl/Nvl.java @@ -60,7 +60,7 @@ final class Nvl extends AbstractField { private final Field arg2; Nvl(Field arg1, Field arg2) { - super(N_NVL, arg1.getDataType()); + super(N_NVL, Tools.anyNotNull(arg1, arg2)); this.arg1 = arg1; this.arg2 = arg2; diff --git a/jOOQ/src/main/java/org/jooq/impl/Nvl2.java b/jOOQ/src/main/java/org/jooq/impl/Nvl2.java index dd54290d7d..aa822f6efa 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Nvl2.java +++ b/jOOQ/src/main/java/org/jooq/impl/Nvl2.java @@ -58,7 +58,7 @@ final class Nvl2 extends AbstractField { private final Field arg3; Nvl2(Field arg1, Field arg2, Field arg3) { - super(N_NVL2, arg2.getDataType()); + super(N_NVL2, !arg1.getDataType().nullable() ? arg2.getDataType() : Tools.allNotNull(arg2, arg3)); this.arg1 = arg1; this.arg2 = arg2; diff --git a/jOOQ/src/main/java/org/jooq/impl/PositionalWindowFunction.java b/jOOQ/src/main/java/org/jooq/impl/PositionalWindowFunction.java index 4d89aec2b9..09ba08b6b1 100644 --- a/jOOQ/src/main/java/org/jooq/impl/PositionalWindowFunction.java +++ b/jOOQ/src/main/java/org/jooq/impl/PositionalWindowFunction.java @@ -65,7 +65,7 @@ final class PositionalWindowFunction extends AbstractWindowFunction { } PositionalWindowFunction(PositionalFunctionType functionType, Field arg, Field offset, Field defaultValue) { - super(functionType.name, arg.getDataType()); + super(functionType.name, arg.getDataType().null_()); this.functionType = functionType; this.arg = arg; diff --git a/jOOQ/src/main/java/org/jooq/impl/RankingFunction.java b/jOOQ/src/main/java/org/jooq/impl/RankingFunction.java index 538d9c2be3..8437570d4c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/RankingFunction.java +++ b/jOOQ/src/main/java/org/jooq/impl/RankingFunction.java @@ -79,7 +79,7 @@ final class RankingFunction extends AbstractWindowFunction { private final RankingType rankingType; RankingFunction(RankingType rankingType, DataType type) { - super(rankingType.name, type); + super(rankingType.name, type.notNull()); this.rankingType = rankingType; } diff --git a/jOOQ/src/main/java/org/jooq/impl/RowNumber.java b/jOOQ/src/main/java/org/jooq/impl/RowNumber.java index 9a02b574db..2b3cd9147e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/RowNumber.java +++ b/jOOQ/src/main/java/org/jooq/impl/RowNumber.java @@ -55,7 +55,7 @@ final class RowNumber extends AbstractWindowFunction { private static final long serialVersionUID = -7318928420486422195L; RowNumber() { - super(N_ROW_NUMBER, INTEGER); + super(N_ROW_NUMBER, INTEGER.notNull()); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 5e2619fbf0..a4fae6507d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -155,6 +155,7 @@ import static org.jooq.impl.SQLDataType.BLOB; import static org.jooq.impl.SQLDataType.CLOB; import static org.jooq.impl.SQLDataType.JSON; import static org.jooq.impl.SQLDataType.JSONB; +import static org.jooq.impl.SQLDataType.OTHER; import static org.jooq.impl.SQLDataType.VARCHAR; import static org.jooq.impl.SQLDataType.XML; import static org.jooq.impl.Tools.DataCacheKey.DATA_REFLECTION_CACHE_GET_ANNOTATED_GETTER; @@ -5898,4 +5899,58 @@ final class Tools { return result; } + + static final DataType allNotNull(Field f1, Field f2) { + DataType result = f1.getDataType(); + + if (result.nullable()) + return result; + else if (f2.getDataType().nullable()) + return result.null_(); + else + return result; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + static final DataType allNotNull(Field... fields) { + if (fields == null || fields.length == 0) + return (DataType) OTHER; + + DataType result = fields[0].getDataType(); + if (result.nullable()) + return result; + + for (int i = 1; i < fields.length; i++) + if (fields[i].getDataType().nullable()) + return result.null_(); + + return result; + } + + static final DataType anyNotNull(Field f1, Field f2) { + DataType result = f1.getDataType(); + + if (!result.nullable()) + return result; + else if (!f2.getDataType().nullable()) + return result.notNull(); + else + return result; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + static final DataType anyNotNull(Field... fields) { + if (fields == null || fields.length == 0) + return (DataType) OTHER; + + DataType result = fields[0].getDataType(); + if (!result.nullable()) + return result; + + for (int i = 1; i < fields.length; i++) + if (!fields[i].getDataType().nullable()) + return result.notNull(); + + return result; + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/Val.java b/jOOQ/src/main/java/org/jooq/impl/Val.java index d8d952c45d..55dc508ffe 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Val.java +++ b/jOOQ/src/main/java/org/jooq/impl/Val.java @@ -67,11 +67,15 @@ final class Val extends AbstractParam { private static final ConcurrentHashMap, Object> legacyWarnings = new ConcurrentHashMap<>(); Val(T value, DataType type) { - super(value, type); + super(value, type(value, type)); } Val(T value, DataType type, String paramName) { - super(value, type, paramName); + super(value, type(value, type), paramName); + } + + private static final DataType type(T value, DataType type) { + return value == null ? type.null_() : type.notNull(); } // ------------------------------------------------------------------------