Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@
import static org.apache.calcite.linq4j.tree.ExpressionType.Add;
import static org.apache.calcite.linq4j.tree.ExpressionType.AddChecked;
import static org.apache.calcite.linq4j.tree.ExpressionType.Divide;
import static org.apache.calcite.linq4j.tree.ExpressionType.Divide0Null;
import static org.apache.calcite.linq4j.tree.ExpressionType.Divide0NullChecked;
import static org.apache.calcite.linq4j.tree.ExpressionType.DivideChecked;
import static org.apache.calcite.linq4j.tree.ExpressionType.Equal;
import static org.apache.calcite.linq4j.tree.ExpressionType.GreaterThan;
Expand Down Expand Up @@ -384,6 +386,7 @@
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CHARACTER_LENGTH;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CHAR_LENGTH;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CHECKED_DIVIDE;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CHECKED_DIVIDE_0_NULL;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CHECKED_DIVIDE_INTEGER;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CHECKED_MINUS;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CHECKED_MULTIPLY;
Expand All @@ -410,6 +413,7 @@
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DEGREES;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DENSE_RANK;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DIVIDE;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DIVIDE_0_NULL;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DIVIDE_INTEGER;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.ELEMENT;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EQUALS;
Expand Down Expand Up @@ -478,6 +482,7 @@
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MINUS_DATE;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MOD;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MODE;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MOD_0_NULL;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MULTIPLY;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MULTISET_EXCEPT;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MULTISET_EXCEPT_DISTINCT;
Expand Down Expand Up @@ -828,6 +833,7 @@ void populate1() {
defineBinary(MINUS, Subtract, NullPolicy.STRICT, "minus");
defineBinary(MULTIPLY, Multiply, NullPolicy.STRICT, "multiply");
defineBinary(DIVIDE, Divide, NullPolicy.STRICT, "divide");
defineBinary(DIVIDE_0_NULL, Divide, NullPolicy.SEMI_STRICT, "divide0Null");
defineBinary(DIVIDE_INTEGER, Divide, NullPolicy.STRICT, "divide");
defineUnary(UNARY_MINUS, Negate, NullPolicy.STRICT,
BuiltInMethod.BIG_DECIMAL_NEGATE.getMethodName());
Expand All @@ -839,8 +845,13 @@ void populate1() {
defineBinary(CHECKED_DIVIDE, DivideChecked, NullPolicy.STRICT, "checkedDivide");
defineBinary(CHECKED_DIVIDE_INTEGER, DivideChecked, NullPolicy.STRICT, "checkedDivide");
defineUnary(CHECKED_UNARY_MINUS, NegateChecked, NullPolicy.STRICT, "checkedUnaryMinus");
// nullable division
defineBinary(DIVIDE_0_NULL, Divide0Null, NullPolicy.SEMI_STRICT, "nullableDivide");
defineBinary(CHECKED_DIVIDE_0_NULL, Divide0NullChecked,
NullPolicy.SEMI_STRICT, "checkedNullableDivide");

defineMethod(MOD, BuiltInMethod.MOD.method, NullPolicy.STRICT);
defineMethod(MOD_0_NULL, BuiltInMethod.MOD_0_NULL.method, NullPolicy.SEMI_STRICT);
defineMethod(EXP, BuiltInMethod.EXP.method, NullPolicy.STRICT);
defineMethod(POWER, BuiltInMethod.POWER.method, NullPolicy.STRICT);
defineMethod(POWER_PG, BuiltInMethod.POWER_PG.method, NullPolicy.STRICT);
Expand Down Expand Up @@ -3347,7 +3358,10 @@ private static class BinaryImplementor extends AbstractRexCallImplementor {
}

// For checked arithmetic call the method.
if (CHECKED_OPERATORS.contains(op)) {
if (CHECKED_OPERATORS.contains(op)
|| op.kind == SqlKind.DIVIDE_0_NULL
|| op.kind == SqlKind.MOD_0_NULL
|| op.kind == SqlKind.CHECKED_DIVIDE_0_NULL) {
return Expressions.call(SqlFunctions.class, backupMethodName, argValueList);
}

Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/org/apache/calcite/plan/Strong.java
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ private static Map<SqlKind, Policy> createPolicyMap() {
map.put(SqlKind.CHECKED_MINUS_PREFIX, Policy.ANY);
map.put(SqlKind.CHECKED_TIMES, Policy.ANY);
map.put(SqlKind.CHECKED_DIVIDE, Policy.ANY);
map.put(SqlKind.DIVIDE_0_NULL, Policy.AS_IS);
map.put(SqlKind.MOD_0_NULL, Policy.AS_IS);

map.put(SqlKind.DIVIDE, Policy.ANY);
map.put(SqlKind.CAST, Policy.ANY);
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/org/apache/calcite/rex/RexSimplify.java
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ RexNode simplify(RexNode e, RexUnknownAs unknownAs) {
case MINUS:
case TIMES:
case DIVIDE:
case DIVIDE_0_NULL:
case CHECKED_DIVIDE_0_NULL:
case CHECKED_PLUS:
case CHECKED_MINUS:
case CHECKED_TIMES:
Expand Down Expand Up @@ -457,6 +459,8 @@ private RexNode simplifyArithmetic(RexCall e) {
return simplifyMultiply(e);
case DIVIDE:
case CHECKED_DIVIDE:
case DIVIDE_0_NULL:
case CHECKED_DIVIDE_0_NULL:
return simplifyDivide(e);
default:
throw new IllegalArgumentException("Unsupported arithmetic operation " + e.getKind());
Expand Down
189 changes: 189 additions & 0 deletions core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -2823,6 +2823,147 @@ public static long divide(long b0, BigDecimal b1) {
: ULong.valueOf(UnsignedType.toBigInteger(b0).divide(UnsignedType.toBigInteger(b1)));
}

// nullable divide

public static @Nullable Integer divide0Null(int b0, BigDecimal b1) {
if (b1.equals(BigDecimal.ZERO)) {
return null;
}
return BigDecimal.valueOf(b0)
.divide(b1, RoundingMode.HALF_DOWN).intValue();
}

public static @Nullable Long divide0Null(long b0, BigDecimal b1) {
if (b1.equals(BigDecimal.ZERO)) {
return null;
}
return BigDecimal.valueOf(b0)
.divide(b1, RoundingMode.HALF_DOWN).longValue();
}

public static @Nullable UByte divide0Null(@PolyNull UByte b0,
@PolyNull UByte b1) {
if (b0 == null || b1 == null) {
return castNonNull(null);
} else if (b1.intValue() == 0) {
return null;
} else {
return UByte.valueOf(b0.intValue() / b1.intValue());
}
}

public static @Nullable UShort divide0Null(@PolyNull UShort b0,
@PolyNull UShort b1) {
if (b0 == null || b1 == null) {
return null;
} else if (b1.intValue() == 0) {
return null;
} else {
return UShort.valueOf(b0.intValue() / b1.intValue());
}
}

public static @Nullable UInteger divide0Null(@PolyNull UInteger b0,
@PolyNull UInteger b1) {
if (b0 == null || b1 == null) {
return null;
} else if (b1.longValue() == 0L) {
return null;
} else {
return UInteger.valueOf(b0.longValue() / b1.longValue());
}
}

public static @Nullable ULong divide0Null(@PolyNull ULong b0,
@PolyNull ULong b1) {
if (b0 == null || b1 == null) {
return null;
} else if (b1.equals(ULong.valueOf(0))) {
return null;
} else {
return ULong.valueOf(UnsignedType.toBigInteger(b0).divide(UnsignedType.toBigInteger(b1)));
}
}

/** SQL <code>/</code> operator applied to int values. */
public static @Nullable Integer divide0Null(int b0, int b1) {
if (b1 == 0) {
return null;
} else {
return b0 / b1;
}
}

/** SQL <code>/</code> operator applied to int values; left side may be
* null. */
public static @Nullable Integer divide0Null(@PolyNull Integer b0, int b1) {
if (b0 == null) {
return null;
} else if (b1 == 0) {
return null;
} else {
return b0 / b1;
}
}

/** SQL <code>/</code> operator applied to int values; right side may be
* null. */
public static @Nullable Integer divide0Null(int b0, @PolyNull Integer b1) {
if (b1 == null) {
return null;
} else if (b1 == 0) {
return null;
} else {
return b0 / b1;
}
}

/** SQL <code>/</code> operator applied to nullable int values. */
public static @Nullable Integer divide0Null(@PolyNull Integer b0,
@PolyNull Integer b1) {
if (b0 == null || b1 == null) {
return null;
} else if (b1 == 0) {
return null;
} else {
return b0 / b1;
}
}

/** SQL <code>/</code> operator applied to nullable long and int values. */
public static @Nullable Long divide0Null(Long b0, @PolyNull Integer b1) {
if (b0 == null || b1 == null) {
return null;
} else if (b1 == 0) {
return null;
} else {
return b0.longValue() / b1.longValue();
}
}

/** SQL <code>/</code> operator applied to nullable int and long values. */
public static @Nullable Long divide0Null(@PolyNull Integer b0, @PolyNull Long b1) {
if (b0 == null || b1 == null) {
return null;
} else if (b1 == 0) {
return null;
} else {
return b0.longValue() / b1.longValue();
}
}

/** SQL <code>/</code> operator applied to BigDecimal values. */
public static @Nullable BigDecimal divide0Null(@PolyNull BigDecimal b0,
@PolyNull BigDecimal b1) {
if (b0 == null || b1 == null) {
return null;
} else if (b1.equals(BigDecimal.ZERO)) {
return null;
} else {
return b0.divide(b1, MathContext.DECIMAL64);
}
}

public static byte checkedDivide(byte b0, byte b1) {
return intToByte(b0 / b1);
}
Expand Down Expand Up @@ -3906,6 +4047,54 @@ public static BigDecimal mod(BigDecimal b0, BigDecimal b1) {
return bigDecimals[1];
}

/** SQL nullable <code>MOD</code> operator applied to byte values. */
public static @Nullable Byte mod0Null(byte b0, byte b1) {
if (b1 == 0) {
return null;
}
return (byte) (b0 % b1);
}

/** SQL nullable <code>MOD</code> operator applied to short values. */
public static @Nullable Short mod0Null(short b0, short b1) {
if (b1 == 0) {
return null;
}
return (short) (b0 % b1);
}

/** SQL nullable <code>MOD</code> operator applied to int values. */
public static @Nullable Integer mod0Null(int b0, int b1) {
if (b1 == 0) {
return null;
}
return b0 % b1;
}

/** SQL nullable <code>MOD</code> operator applied to long values. */
public static @Nullable Long mod0Null(long b0, long b1) {
if (b1 == 0L) {
return null;
}
return b0 % b1;
}

public static @Nullable BigDecimal mod0Null(BigDecimal b0, int b1) {
return mod0Null(b0, BigDecimal.valueOf(b1));
}

public static @Nullable BigDecimal mod0Null(int b0, BigDecimal b1) {
return mod(BigDecimal.valueOf(b0), b1);
}

public static @Nullable BigDecimal mod0Null(BigDecimal b0, BigDecimal b1) {
if (b1.equals(BigDecimal.ZERO)) {
return null;
}
final BigDecimal[] bigDecimals = b0.divideAndRemainder(b1);
return bigDecimals[1];
}

// FLOOR

public static double floor(double b0) {
Expand Down
17 changes: 16 additions & 1 deletion core/src/main/java/org/apache/calcite/sql/SqlKind.java
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ public enum SqlKind {
/** Arithmetic remainder operator, "MOD" (and "%" in some dialects). */
MOD,

/** Nullable arithmetic remainder operator which returns NULL when remainder is zero,
* "MOD" (and "%" in some dialects). */
MOD_0_NULL,

/**
* Arithmetic plus operator, "+".
*
Expand Down Expand Up @@ -335,6 +339,16 @@ public enum SqlKind {
*/
CHECKED_DIVIDE,

/**
* Unchecked nullable version of DIVIDE, which produces NULL when dividing by zero.
*/
DIVIDE_0_NULL,

/**
* Checked nullable version of DIVIDE, which produces NULL when dividing by zero.
*/
CHECKED_DIVIDE_0_NULL,

/**
* Alternation operator in a pattern expression within a
* {@code MATCH_RECOGNIZE} clause.
Expand Down Expand Up @@ -1566,7 +1580,8 @@ public enum SqlKind {
CHECKED_PLUS, CHECKED_MINUS, CHECKED_TIMES, CHECKED_DIVIDE);

public static final Set<SqlKind> CHECKED_ARITHMETIC =
EnumSet.of(CHECKED_PLUS, CHECKED_MINUS, CHECKED_TIMES, CHECKED_DIVIDE, CHECKED_MINUS_PREFIX);
EnumSet.of(CHECKED_PLUS, CHECKED_MINUS, CHECKED_TIMES, CHECKED_DIVIDE,
CHECKED_DIVIDE_0_NULL, CHECKED_MINUS_PREFIX);


/**
Expand Down
Loading
Loading