Skip to content

Commit

Permalink
QQL AS operator priority fixed; null constants fixes (#269)
Browse files Browse the repository at this point in the history
  • Loading branch information
Romkisel authored Feb 19, 2024
1 parent 62e1ded commit e901c54
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -219,40 +219,66 @@ static CompiledConstant compute(ArithmeticFunction function, CompiledConstant le
if (leftType.getNativeTypeSize() == 8 || rightType.getNativeTypeSize() == 8) {
long a = left.getLong();
long b = right.getLong();
return new CompiledConstant(StandardTypes.INT64_CONTAINER.getType(false), compute(function, a, b));
long res = compute(function, a, b);
return new CompiledConstant(
StandardTypes.INT64_CONTAINER.getType(true),
TimebaseTypes.isNull(res) ? null : res
);
} else {
int a = left.getInteger();
int b = right.getInteger();
return new CompiledConstant(StandardTypes.INT32_CONTAINER.getType(false), compute(function, a, b));
int res = compute(function, a, b);
return new CompiledConstant(
StandardTypes.INT32_CONTAINER.getType(true),
TimebaseTypes.isNull(res) ? null : res
);
}
}

static CompiledConstant computeDateTimeAndInteger(ArithmeticFunction function, CompiledConstant left, CompiledConstant right) {
long a = left.getLong();
long b = right.getLong();
return new CompiledConstant(StandardTypes.DATE_TIME_CONTAINER.getType(false), compute(function, a, b));
long res = compute(function, a, b);
return new CompiledConstant(StandardTypes.DATE_TIME_CONTAINER.getType(true), TimebaseTypes.isNull(res) ? null : res);
}

static CompiledConstant computeDateTimeAndDateTime(ArithmeticFunction function, CompiledConstant left, CompiledConstant right) {
long a = left.getLong();
long b = right.getLong();
return new CompiledConstant(StandardTypes.INT64_CONTAINER.getType(false), compute(function, a, b));
long res = compute(function, a, b);
return new CompiledConstant(StandardTypes.INT64_CONTAINER.getType(true), TimebaseTypes.isNull(res) ? null : res);
}

static CompiledConstant computeVarcharAndVarchar(ArithmeticFunction function, CompiledConstant left, CompiledConstant right) {
String a = left.getString();
String b = right.getString();
if (function == ArithmeticFunction.ADD) {
return new CompiledConstant(StandardTypes.UTF8_CONTAINER.getType(true), a + b);
}

throw new IllegalStateException("Invalid function for varchar and varchar arguments: " + function);
}

static CompiledConstant compute(ArithmeticFunction function, CompiledConstant left, CompiledConstant right,
FloatDataType leftType, FloatDataType rightType) {
if (leftType.isDecimal64() || rightType.isDecimal64()) {
@Decimal long a = left.getDecimalLong();
@Decimal long b = right.getDecimalLong();
return new CompiledConstant(StandardTypes.DECIMAL64_CONTAINER.getType(false), computeDecimal(function, a, b), true);
long res = computeDecimal(function, a, b);
return new CompiledConstant(StandardTypes.DECIMAL64_CONTAINER.getType(true), TimebaseTypes.isDecimalNull(res) ? null : res, true);
} else {
double a = left.getDouble();
double b = right.getDouble();
return new CompiledConstant(StandardTypes.FLOAT64_CONTAINER.getType(false), compute(function, a, b));
double res = compute(function, a, b);
return new CompiledConstant(StandardTypes.FLOAT64_CONTAINER.getType(true), TimebaseTypes.isNull(res) ? null : res);
}
}

static int compute(ArithmeticFunction function, int a, int b, boolean swap) {
if (TimebaseTypes.isNull(a) || TimebaseTypes.isNull(b)) {
return TimebaseTypes.INT32_NULL;
}

switch (function) {
case ADD:
return a + b;
Expand All @@ -274,6 +300,10 @@ static int compute(ArithmeticFunction function, int a, int b) {
}

static long compute(ArithmeticFunction function, long a, long b, boolean swap) {
if (TimebaseTypes.isNull(a) || TimebaseTypes.isNull(b)) {
return TimebaseTypes.INT64_NULL;
}

switch (function) {
case ADD:
return a + b;
Expand All @@ -295,6 +325,10 @@ static long compute(ArithmeticFunction function, long a, long b) {
}

static double compute(ArithmeticFunction function, double a, double b, boolean swap) {
if (TimebaseTypes.isNull(a) || TimebaseTypes.isNull(b)) {
return Double.NaN;
}

switch (function) {
case ADD:
return a + b;
Expand All @@ -315,6 +349,10 @@ static double compute(ArithmeticFunction function, double a, double b) {

@Decimal
static long computeDecimal(ArithmeticFunction function, @Decimal long a, @Decimal long b, boolean swap) {
if (TimebaseTypes.isDecimalNull(a) || TimebaseTypes.isDecimalNull(b)) {
return TimebaseTypes.DECIMAL64_NULL;
}

switch (function) {
case ADD:
return add(a, b);
Expand Down Expand Up @@ -510,4 +548,4 @@ static IntegerArrayList compute(ArithmeticFunction function, IntegerArrayList a,
return list;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ public static int computeDistance(DataType source, DataType target) {
}

public static int hashcode(DataType dataType) {
if (dataType == null) {
return 0;
}

int result = dataType.getClass().hashCode();
if (dataType instanceof ArrayDataType) {
result = 31 * result + hashcode(((ArrayDataType) dataType).getElementDataType());
Expand Down Expand Up @@ -103,4 +107,4 @@ public static boolean isTimestampAndTimestamp(DataType left, DataType right) {
return TimebaseTypes.isDateTimeOrDateTimeArray(left) && TimebaseTypes.isDateTimeOrDateTimeArray(right);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,30 @@ public static boolean isCompatibleWithoutConversion (DataType from, Da
DataType e2 = ((ArrayDataType) to).getElementDataType();
return e1.getClass() == e2.getClass() && Objects.equals(e1.getEncoding(), e2.getEncoding());
}

if (from == null || to == null) {
return true;
}

return (to.getClass () == from.getClass ());
}

public static boolean isStrictCompatibleWithoutConversion(DataType actual, DataType required) {
if (!isCompatibleWithoutConversion(actual, required)) {
return false;
}

if (actual instanceof IntegerDataType && required instanceof IntegerDataType) {
return ((IntegerDataType) actual).getSize() == ((IntegerDataType) required).getSize();
}

if (actual instanceof FloatDataType && required instanceof FloatDataType) {
return ((FloatDataType) actual).getScale() == ((FloatDataType) required).getScale();
}

return true;
}

private static boolean isDecimal64(FloatDataType floatDataType) {
return floatDataType.getScale() == FloatDataType.SCALE_DECIMAL64;
}
Expand Down Expand Up @@ -200,4 +221,4 @@ public static Object lookUpType (Environment e, TypeIdentifier id) {
public static Object lookUpType (Environment e, String name) {
return (e.lookUp (NamedObjectType.TYPE, name, Element.NO_LOCATION));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,84 +232,84 @@ private CompiledExpression compileComplexExpression(ComplexExpression e, DataTyp

private CompiledConstant compileConstant(Constant e, DataType expectedType) {
if (e instanceof BooleanConstant)
return (new CompiledConstant(StandardTypes.CLEAN_BOOLEAN, ((BooleanConstant) e).value));
return (new CompiledConstant(StandardTypes.NULLABLE_BOOLEAN, ((BooleanConstant) e).value));

if (e instanceof IntegerConstant) {
long value = ((IntegerConstant) e).value;

if (expectedType instanceof FloatDataType)
return (new CompiledConstant(StandardTypes.CLEAN_DECIMAL, Long.toString(value)));
return (new CompiledConstant(StandardTypes.NULLABLE_DECIMAL, Long.toString(value)));
else if (expectedType instanceof IntegerDataType)
return (new CompiledConstant(expectedType, value));

if (value > Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
return new CompiledConstant(StandardTypes.INT32_CONTAINER.getType(false), value);
return new CompiledConstant(StandardTypes.INT32_CONTAINER.getType(true), value);
} else {
return new CompiledConstant(StandardTypes.INT64_CONTAINER.getType(false), value);
return new CompiledConstant(StandardTypes.INT64_CONTAINER.getType(true), value);
}
}

if (e instanceof LongConstant) {
long value = ((LongConstant) e).value;

if (expectedType instanceof FloatDataType)
return (new CompiledConstant(StandardTypes.CLEAN_DECIMAL, Long.toString(value)));
return (new CompiledConstant(StandardTypes.NULLABLE_DECIMAL, Long.toString(value)));
else if (expectedType instanceof IntegerDataType)
return (new CompiledConstant(expectedType, value));
return new CompiledConstant(StandardTypes.INT64_CONTAINER.getType(false), value);
return new CompiledConstant(StandardTypes.INT64_CONTAINER.getType(true), value);
}

if (e instanceof FloatConstant) {
if (!(expectedType instanceof FloatDataType)) {
if (((FloatConstant) e).isDecimal64()) {
return new CompiledConstant(StandardTypes.CLEAN_DECIMAL, ((FloatConstant) e).toFloatString());
return new CompiledConstant(StandardTypes.NULLABLE_DECIMAL, ((FloatConstant) e).toFloatString());
} else {
return new CompiledConstant(StandardTypes.CLEAN_FLOAT, ((FloatConstant) e).toFloatString());
return new CompiledConstant(StandardTypes.NULLABLE_FLOAT, ((FloatConstant) e).toFloatString());
}
} else if (((FloatDataType) expectedType).isDecimal64()) {
return new CompiledConstant(StandardTypes.CLEAN_DECIMAL, ((FloatConstant) e).toFloatString());
return new CompiledConstant(StandardTypes.NULLABLE_DECIMAL, ((FloatConstant) e).toFloatString());
} else {
return new CompiledConstant(StandardTypes.CLEAN_FLOAT, ((FloatConstant) e).toFloatString());
return new CompiledConstant(StandardTypes.NULLABLE_FLOAT, ((FloatConstant) e).toFloatString());
}
}

if (e instanceof StringConstant)
return (new CompiledConstant(StandardTypes.CLEAN_VARCHAR, ((StringConstant) e).value));
return (new CompiledConstant(StandardTypes.NULLABLE_VARCHAR, ((StringConstant) e).value));

if (e instanceof DateConstant)
return (
new CompiledConstant(
StandardTypes.CLEAN_TIMESTAMP,
StandardTypes.NULLABLE_TIMESTAMP,
((DateConstant) e).nanoseconds / 1000000
)
);

if (e instanceof TimeConstant)
return (
new CompiledConstant(
StandardTypes.CLEAN_TIMEOFDAY,
StandardTypes.NULLABLE_TIMEOFDAY,
(int) (((TimeConstant) e).nanoseconds / 1000000)
)
);

if (e instanceof BinConstant)
return (
new CompiledConstant(
StandardTypes.CLEAN_BINARY,
StandardTypes.NULLABLE_BINARY,
((BinConstant) e).bytes
)
);

if (e instanceof CharConstant)
return (
new CompiledConstant(
StandardTypes.CLEAN_CHAR,
StandardTypes.NULLABLE_CHAR,
((CharConstant) e).ch
)
);

if (e instanceof TimeIntervalConstant) {
return new CompiledConstant(StandardTypes.INT64_CONTAINER.getType(false), ((TimeIntervalConstant) e).getTimeStampMs());
return new CompiledConstant(StandardTypes.INT64_CONTAINER.getType(true), ((TimeIntervalConstant) e).getTimeStampMs());
}

if (e instanceof Null) {
Expand Down Expand Up @@ -434,9 +434,9 @@ private CompiledExpression convertIfNecessary(
CompiledConstant c = (CompiledConstant) x;

if (((FloatDataType) ot).isDecimal64()) {
return new CompiledConstant(StandardTypes.CLEAN_DECIMAL, c.getString());
return new CompiledConstant(StandardTypes.NULLABLE_DECIMAL, c.getString());
} else {
return new CompiledConstant(StandardTypes.CLEAN_FLOAT, c.getString());
return new CompiledConstant(StandardTypes.NULLABLE_FLOAT, c.getString());
}
}

Expand All @@ -448,9 +448,9 @@ private CompiledExpression convertIfNecessary(
} else if (xt instanceof FloatDataType && ot instanceof FloatDataType) {
if (x instanceof CompiledConstant) {
if (!((FloatDataType) xt).isDecimal64() && ((FloatDataType) ot).isDecimal64()) {
return new CompiledConstant(StandardTypes.CLEAN_DECIMAL, ((CompiledConstant) x).getString());
return new CompiledConstant(StandardTypes.NULLABLE_DECIMAL, ((CompiledConstant) x).getString());
} else if (((FloatDataType) xt).isDecimal64() && !((FloatDataType) ot).isDecimal64()) {
return new CompiledConstant(StandardTypes.CLEAN_FLOAT, ((CompiledConstant) x).getString());
return new CompiledConstant(StandardTypes.NULLABLE_FLOAT, ((CompiledConstant) x).getString());
}
} else if (!(other instanceof CompiledConstant) && ((FloatDataType) xt).isDecimal64()
&& !((FloatDataType) ot).isDecimal64()) {
Expand Down Expand Up @@ -983,10 +983,10 @@ private CompiledIfExpression compileIfExpression(IfExpression ifExpression, Data
compile(ifExpression.elseExpression, expectedType) : new CompiledConstant(expectedType, null);

DataType outputType = getOutputTypeOfExpressions(Arrays.asList(compiledThen, compiledElse));
if (isNullLiteral(compiledThen)) {
if (isUntypedNullLiteral(compiledThen)) {
compiledThen = new CompiledConstant(outputType, null);
}
if (isNullLiteral(compiledElse)) {
if (isUntypedNullLiteral(compiledElse)) {
compiledElse = new CompiledConstant(outputType, null);
}

Expand Down Expand Up @@ -1021,11 +1021,11 @@ private CompiledCaseExpression compileCaseExpression(CaseExpression e, DataType
List<CompiledExpression<?>> outputExpressions = new ArrayList<>(compiledThens);
outputExpressions.add(compiledElse);
DataType outputType = getOutputTypeOfExpressions(outputExpressions);
if (isNullLiteral(compiledElse)) {
if (isUntypedNullLiteral(compiledElse)) {
compiledElse = new CompiledConstant(outputType, null);
}
for (int i = 0; i < compiledThens.size(); ++i) {
if (isNullLiteral(compiledThens.get(i))) {
if (isUntypedNullLiteral(compiledThens.get(i))) {
compiledThens.set(i, new CompiledConstant(outputType, null));
}

Expand All @@ -1050,21 +1050,25 @@ private CompiledCaseExpression compileCaseExpression(CaseExpression e, DataType
private DataType getOutputTypeOfExpressions(List<CompiledExpression<?>> expressions) {
for (int i = 0; i < expressions.size(); ++i) {
CompiledExpression<?> e = expressions.get(i);
if (!isNullLiteral(e)) {
if (!isUntypedNullLiteral(e)) {
return e.type;
}
}

return null;
}

private boolean isUntypedNullLiteral(CompiledExpression<?> e) {
return isNullLiteral(e) && e.type == null;
}

private boolean isNullLiteral(CompiledExpression<?> e) {
return e instanceof CompiledConstant && ((CompiledConstant) e).value == null;
return e instanceof CompiledConstant && ((CompiledConstant) e).isNull();
}

private void validateConditionTypes(Expression e, DataType actual, DataType required) {
if (actual != null && required != null) {
if (!isCompatibleWithoutConversion(actual, required)) {
if (!QQLCompiler.isStrictCompatibleWithoutConversion(actual, required)) {
throw new UnexpectedTypeException(e, actual, required);
} else if (actual instanceof ClassDataType && required instanceof ClassDataType) {
if (isCastRequired((ClassDataType) actual, (ClassDataType) required)) {
Expand All @@ -1073,7 +1077,7 @@ private void validateConditionTypes(Expression e, DataType actual, DataType requ
} else if (actual instanceof ArrayDataType && required instanceof ArrayDataType) {
DataType actualArrayType = ((ArrayDataType) actual).getElementDataType();
DataType requiredArrayType = ((ArrayDataType) required).getElementDataType();
if (!isCompatibleWithoutConversion(actualArrayType, requiredArrayType)) {
if (!QQLCompiler.isStrictCompatibleWithoutConversion(actualArrayType, requiredArrayType)) {
throw new UnexpectedTypeException(e, actualArrayType, requiredArrayType);
} else if (actualArrayType instanceof ClassDataType && requiredArrayType instanceof ClassDataType) {
if (isCastRequired((ClassDataType) actualArrayType, (ClassDataType) requiredArrayType)) {
Expand Down Expand Up @@ -2029,7 +2033,10 @@ private boolean isNamedExpression(Expression e) {
private CompiledExpression<DataType> compileCastExpression(AsExpression e) {
CompiledExpression<DataType> parent = compile(e.expression, null);

DataType castDataType = getCastDataType(e, parent.type);
DataType castDataType = getCastDataType(e, parent.type == null || parent.type.isNullable());
if (isNullLiteral(parent)) {
return new CompiledConstant(castDataType, null);
}

if (castDataType == null) {
throw new CompilationException("Unknown target data type.", e);
Expand Down Expand Up @@ -2107,9 +2114,9 @@ private boolean isCastRequired(ClassDataType sourceType, ClassDataType type) {
return !Arrays.equals(sourceType.getDescriptors(), type.getDescriptors());
}

private DataType getCastDataType(AsExpression e, DataType parentType) {
private DataType getCastDataType(AsExpression e, boolean isNullable) {
if (e.castType instanceof CastTypeIdExpression) {
return compileCastTypeIdExpression((CastTypeIdExpression) e.castType, parentType.isNullable());
return compileCastTypeIdExpression((CastTypeIdExpression) e.castType, isNullable);
} else if (e.castType instanceof CastObjectTypeExpression) {
CastObjectTypeExpression castObjectType = (CastObjectTypeExpression) e.castType;
return new ClassDataType(
Expand All @@ -2122,13 +2129,13 @@ private DataType getCastDataType(AsExpression e, DataType parentType) {

if (castTypeIds.size() > 1) {
return new ArrayDataType(
parentType.isNullable(),
isNullable,
new ClassDataType(true, collectDescriptors(castTypeIds))
);
} else {
return new ArrayDataType(
parentType.isNullable(),
compileCastTypeIdExpression(castTypeIds.get(0), parentType.isNullable())
isNullable,
compileCastTypeIdExpression(castTypeIds.get(0), isNullable)
);
}
}
Expand Down
Loading

0 comments on commit e901c54

Please sign in to comment.