diff --git a/src/sqlancer/feldera/FelderaProvider.java b/src/sqlancer/feldera/FelderaProvider.java index 6451584d3..bb08f51a4 100644 --- a/src/sqlancer/feldera/FelderaProvider.java +++ b/src/sqlancer/feldera/FelderaProvider.java @@ -47,8 +47,8 @@ protected void checkViewsAreValid(FelderaGlobalState globalState) { @Override public void generateDatabase(FelderaGlobalState globalState) throws Exception { - createTables(globalState, Randomly.fromOptions(4, 5, 6)); - createViews(globalState, Randomly.fromOptions(4, 5, 6)); + createTables(globalState, Randomly.fromOptions(8, 10, 12)); + createViews(globalState, Randomly.fromOptions(8, 10, 12)); prepareTables(globalState); } diff --git a/src/sqlancer/feldera/FelderaSchema.java b/src/sqlancer/feldera/FelderaSchema.java index f55641544..3d2311405 100644 --- a/src/sqlancer/feldera/FelderaSchema.java +++ b/src/sqlancer/feldera/FelderaSchema.java @@ -1,9 +1,6 @@ package sqlancer.feldera; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; import sqlancer.Randomly; @@ -33,39 +30,6 @@ public FelderaSchema addTable(FelderaTable table) { return new FelderaSchema(tables, this.pipelineName); } - public static FelderaDataType getColumnType(String typeString) { - switch (typeString.toUpperCase()) { - case "BOOLEAN": - return FelderaDataType.BOOLEAN; - case "TINYINT": - return FelderaDataType.TINYINT; - case "SMALLINT": - return FelderaDataType.SMALLINT; - case "INT": - return FelderaDataType.INT; - case "BIGINT": - return FelderaDataType.BIGINT; - case "VARCHAR": - return FelderaDataType.VARCHAR; - case "CHAR": - return FelderaDataType.CHAR; - case "NULL": - return FelderaDataType.NULL; - case "TIME": - return FelderaDataType.TIME; - case "DATE": - return FelderaDataType.DATE; - case "TIMESTAMP": - return FelderaDataType.TIMESTAMP; - case "REAL": - return FelderaDataType.REAL; - case "DOUBLE": - return FelderaDataType.DOUBLE; - default: - throw new AssertionError(typeString); - } - } - public static FelderaSchema fromConnection(FelderaConnection con) throws Exception { return new FelderaSchema(new ArrayList<>(), con.getPipelineName()); } @@ -83,16 +47,14 @@ public String getPipelineName() { } public enum FelderaDataType { - BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, VARCHAR, CHAR, NULL, TIME, DATE, TIMESTAMP, - // DECIMAL, + BOOLEAN, INT, VARCHAR, CHAR, NULL, TIME, DATE, TIMESTAMP, DECIMAL, FLOAT, ANY, + // VARIANT, // VARBINARY, // INTERVAL, // GEOMETRY, // ROW, - // ARRAY, // MAP, - // VARIANT, - REAL, DOUBLE; + ARRAY; public static FelderaDataType getRandomNumericType() { return Randomly @@ -101,12 +63,9 @@ public static FelderaDataType getRandomNumericType() { public boolean isNumeric() { switch (this) { - case REAL: - case DOUBLE: - case TINYINT: - case SMALLINT: + case FLOAT: case INT: - case BIGINT: + case DECIMAL: return true; default: return false; @@ -114,13 +73,47 @@ public boolean isNumeric() { } public static FelderaDataType getRandomNonNullType() { - return Randomly.fromList( - Arrays.stream(values()).filter(t -> t != FelderaDataType.NULL).collect(Collectors.toList())); + return Randomly.fromList(Arrays.stream(values()) + .filter(t -> t != FelderaDataType.NULL && t != FelderaDataType.ANY).collect(Collectors.toList())); + } + + public static FelderaDataType[] nonNullValues() { + return Arrays.stream(values()).filter(t -> t != FelderaDataType.NULL && t != FelderaDataType.ANY) + .toArray(FelderaDataType[]::new); } public static FelderaDataType getRandomType() { return Randomly.fromOptions(values()); } + } + + public static class FelderaCompositeDataType { + private final FelderaDataType dataType; + private final int size; + private final int scale; + private final FelderaCompositeDataType elementType; + + public FelderaCompositeDataType(FelderaDataType dataType, int size, int scale) { + this.dataType = dataType; + this.size = size; + this.scale = scale; + this.elementType = null; + } + + public static FelderaCompositeDataType arrayOf(FelderaDataType elementType) { + return new FelderaCompositeDataType(FelderaDataType.ARRAY, getRandomFromPrimitiveType(elementType)); + } + + public FelderaCompositeDataType(FelderaDataType dataType, FelderaCompositeDataType elementType) { + if (dataType != FelderaDataType.ARRAY) { + throw new IllegalArgumentException("dataType must be ARRAY"); + } + + this.dataType = dataType; + this.scale = -1; + this.size = -1; + this.elementType = elementType; + } public FelderaExpression getRandomConstant(FelderaGlobalState globalState) { if (Randomly.getBooleanWithSmallProbability()) { @@ -129,29 +122,144 @@ public FelderaExpression getRandomConstant(FelderaGlobalState globalState) { return FelderaConstant.getRandomConstant(globalState, this); } + + public boolean isNumeric() { + return this.getPrimitiveType().isNumeric(); + } + + public FelderaCompositeDataType getElementType() { + return this.elementType; + } + + public static FelderaCompositeDataType getBooleanType() { + return FelderaCompositeDataType.getRandomFromPrimitiveType(FelderaDataType.BOOLEAN); + } + + public static FelderaCompositeDataType getRandomVarcharType() { + return FelderaCompositeDataType.getRandomFromPrimitiveType(FelderaDataType.VARCHAR); + } + + public static FelderaCompositeDataType getRandomNumericType() { + FelderaDataType type = FelderaDataType.getRandomNumericType(); + return FelderaCompositeDataType.getRandomFromPrimitiveType(type); + } + + public FelderaDataType getPrimitiveType() { + return dataType; + } + + public int getSize() { + return size; + } + + public int getScale() { + return scale; + } + + public boolean isArray() { + return dataType == FelderaDataType.ARRAY; + } + + public static FelderaCompositeDataType getRandomFromPrimitiveType(FelderaDataType type) { + int size = -1; + int scale = -1; + switch (type) { + case FLOAT: + size = Randomly.fromOptions(32, 64); + return new FelderaCompositeDataType(type, size, scale); + case INT: + size = Randomly.fromOptions(8, 16, 32, 64); + return new FelderaCompositeDataType(type, size, scale); + case ARRAY: + return new FelderaCompositeDataType(type, FelderaCompositeDataType.getRandomWithoutNull()); + case DECIMAL: + scale = (int) Randomly.getNotCachedInteger(0, 10); + size = (int) Randomly.getNotCachedInteger(scale, 25); + return new FelderaCompositeDataType(type, size, scale); + case CHAR: + size = (int) Randomly.getNotCachedInteger(1, 10); + return new FelderaCompositeDataType(type, size, scale); + case VARCHAR: + if (Randomly.getBoolean()) { + size = (int) Randomly.getNotCachedInteger(1, 30); + } + return new FelderaCompositeDataType(type, size, scale); + default: + return new FelderaCompositeDataType(type, size, scale); + } + } + + public static FelderaCompositeDataType getRandomWithoutNull() { + FelderaDataType type = FelderaDataType.getRandomNonNullType(); + return FelderaCompositeDataType.getRandomFromPrimitiveType(type); + } + + @Override + public String toString() { + switch (dataType) { + case INT: + switch (size) { + case 8: + return "TINYINT"; + case 16: + return "SMALLINT"; + case 32: + return "INT"; + case 64: + return "BIGINT"; + default: + throw new AssertionError(dataType.toString() + scale); + } + case FLOAT: + switch (size) { + case 32: + return "REAL"; + case 64: + return "DOUBLE"; + default: + throw new AssertionError(dataType.toString() + scale); + } + case ARRAY: + if (elementType == null) { + throw new AssertionError(this); + } + return elementType + " ARRAY"; + case CHAR: + return "CHAR(" + size + ")"; + case VARCHAR: + if (size == -1) { + return "VARCHAR"; + } + return "VARCHAR(" + size + ")"; + case DECIMAL: + return "DECIMAL(" + size + ", " + scale + ")"; + default: + return dataType.toString(); + } + } } public static class FelderaFieldColumn extends FelderaColumn { - public FelderaFieldColumn(String name, FelderaDataType columnType) { + public FelderaFieldColumn(String name, FelderaCompositeDataType columnType) { super(name, columnType); } - public FelderaFieldColumn(String name, FelderaDataType columnType, boolean isNullable) { + public FelderaFieldColumn(String name, FelderaCompositeDataType columnType, boolean isNullable) { super(name, columnType, isNullable); // Note to self: later, assert that the Field column isn't something like INTERVAL } } - public static class FelderaColumn extends AbstractTableColumn { + public static class FelderaColumn extends AbstractTableColumn { private final boolean isNullable; - public FelderaColumn(String name, FelderaDataType columnType) { + public FelderaColumn(String name, FelderaCompositeDataType columnType) { super(name, null, columnType); this.isNullable = false; } - public FelderaColumn(String name, FelderaDataType columnType, boolean isNullable) { + public FelderaColumn(String name, FelderaCompositeDataType columnType, boolean isNullable) { super(name, null, columnType); this.isNullable = isNullable; } @@ -161,7 +269,7 @@ public FelderaColumnReference asColumnReference() { } public static FelderaColumn createDummy(String name) { - return new FelderaColumn(name, FelderaDataType.getRandomType()); + return new FelderaColumn(name, FelderaCompositeDataType.getRandomWithoutNull()); } public boolean isNullable() { diff --git a/src/sqlancer/feldera/ast/FelderaAggregate.java b/src/sqlancer/feldera/ast/FelderaAggregate.java index 410fc97d5..d43fb0f1c 100644 --- a/src/sqlancer/feldera/ast/FelderaAggregate.java +++ b/src/sqlancer/feldera/ast/FelderaAggregate.java @@ -13,13 +13,14 @@ public class FelderaAggregate implements FelderaExpression { private boolean blackbox; public enum FelderaAggregateFunction { - AVG(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.DOUBLE), - COUNT(FelderaSchema.FelderaDataType.values()), EVERY(FelderaSchema.FelderaDataType.BOOLEAN), - MAX(FelderaSchema.FelderaDataType.values()), MIN(FelderaSchema.FelderaDataType.values()), + AVG(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.FLOAT), + COUNT(FelderaSchema.FelderaDataType.nonNullValues()), EVERY(FelderaSchema.FelderaDataType.BOOLEAN), + MAX(FelderaSchema.FelderaDataType.nonNullValues()), MIN(FelderaSchema.FelderaDataType.nonNullValues()), SOME(FelderaSchema.FelderaDataType.BOOLEAN), - SUM(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.DOUBLE), - STDDEV(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.DOUBLE), - STDDEV_POP(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.DOUBLE),; + SUM(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.FLOAT), + STDDEV(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.FLOAT), + STDDEV_POP(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.FLOAT), + COUNTIF(FelderaSchema.FelderaDataType.BOOLEAN); private final FelderaSchema.FelderaDataType[] supportedReturnTypes; @@ -27,16 +28,17 @@ public enum FelderaAggregateFunction { this.supportedReturnTypes = supportedReturnTypes.clone(); } - public List getTypes(FelderaSchema.FelderaDataType returnType) { + public List getTypes( + FelderaSchema.FelderaCompositeDataType returnType) { return Collections.singletonList(returnType); } - public boolean supportsReturnType(FelderaSchema.FelderaDataType returnType) { - return Arrays.stream(supportedReturnTypes).anyMatch(t -> t == returnType) + public boolean supportsReturnType(FelderaSchema.FelderaCompositeDataType returnType) { + return Arrays.stream(supportedReturnTypes).anyMatch(t -> t == returnType.getPrimitiveType()) || supportedReturnTypes.length == 0; } - public static List getAggregates(FelderaSchema.FelderaDataType type) { + public static List getAggregates(FelderaSchema.FelderaCompositeDataType type) { return Arrays.stream(values()).filter(p -> p.supportsReturnType(type)).collect(Collectors.toList()); } } diff --git a/src/sqlancer/feldera/ast/FelderaCast.java b/src/sqlancer/feldera/ast/FelderaCast.java index e66f40920..62d66daed 100644 --- a/src/sqlancer/feldera/ast/FelderaCast.java +++ b/src/sqlancer/feldera/ast/FelderaCast.java @@ -4,9 +4,9 @@ public class FelderaCast implements FelderaExpression { private final FelderaExpression expr; - private final FelderaSchema.FelderaDataType type; + private final FelderaSchema.FelderaCompositeDataType type; - public FelderaCast(FelderaExpression expr, FelderaSchema.FelderaDataType type) { + public FelderaCast(FelderaExpression expr, FelderaSchema.FelderaCompositeDataType type) { this.expr = expr; this.type = type; } diff --git a/src/sqlancer/feldera/ast/FelderaConstant.java b/src/sqlancer/feldera/ast/FelderaConstant.java index f7050ac8e..f2cb90a28 100644 --- a/src/sqlancer/feldera/ast/FelderaConstant.java +++ b/src/sqlancer/feldera/ast/FelderaConstant.java @@ -3,10 +3,14 @@ import sqlancer.Randomly; import sqlancer.feldera.FelderaGlobalState; import sqlancer.feldera.FelderaSchema; +import sqlancer.feldera.FelderaToStringVisitor; import java.math.BigDecimal; import java.math.RoundingMode; +import java.nio.charset.CharsetEncoder; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; public abstract class FelderaConstant implements FelderaExpression { private FelderaConstant() { @@ -18,40 +22,100 @@ private static double round(double number, int places) { return decimal.doubleValue(); } - public static FelderaConstant getRandomConstant(FelderaGlobalState globalState, - FelderaSchema.FelderaDataType type) { - switch (type) { + public static FelderaExpression getRandomConstant(FelderaGlobalState globalState, + FelderaSchema.FelderaCompositeDataType type) { + switch (type.getPrimitiveType()) { case BOOLEAN: return new FelderaBooleanConstant(Randomly.getBoolean()); - case TINYINT: - return FelderaIntConstant.getRandom(globalState, 8); - case SMALLINT: - return FelderaIntConstant.getRandom(globalState, 16); case INT: - return FelderaIntConstant.getRandom(globalState, 32); - case BIGINT: - return FelderaIntConstant.getRandom(globalState, 64); + return FelderaIntConstant.getRandom(globalState, type.getSize()); case VARCHAR: - return FelderaVarcharConstant.getRandom(globalState); + return FelderaVarcharConstant.getRandom(globalState, type.getSize()); case CHAR: - return FelderaCharConstant.getRandom(globalState); + return FelderaCharConstant.getRandom(globalState, type.getSize()); case NULL: return new FelderaNullConstant(); case TIME: - return FelderaTimeConstant.getRandom(globalState); + return new FelderaCast(FelderaTimeConstant.getRandom(globalState), type); case DATE: - return FelderaDateConstant.getRandom(globalState); + return new FelderaCast(FelderaDateConstant.getRandom(globalState), type); case TIMESTAMP: - return FelderaTimestampConstant.getRandom(globalState); - case REAL: - return FelderaRealConstant.getRandom(globalState); - case DOUBLE: - return FelderaDoubleConstant.getRandom(globalState); + return new FelderaCast(FelderaTimestampConstant.getRandom(globalState), type); + case FLOAT: + return FelderaFloatConstant.getRandom(globalState, type.getSize()); + case DECIMAL: + return FelderaDecimalConstant.getRandom(globalState, type.getSize(), type.getScale()); + case ARRAY: + return FelderaArrayConstant.getRandom(globalState, type.getElementType()); default: throw new AssertionError(type); } } + public static class FelderaArrayConstant extends FelderaConstant { + private final List array; + + public FelderaArrayConstant(List array) { + this.array = array; + } + + public List getValue() { + return array; + } + + public static FelderaArrayConstant getRandom(FelderaGlobalState globalState, + FelderaSchema.FelderaCompositeDataType type) { + int size = Randomly.fromOptions(1, 2, 3); + List array = new ArrayList<>(size); + + for (int i = 0; i < size; i++) { + FelderaExpression expr = getRandomConstant(globalState, type); + array.add(FelderaToStringVisitor.asString(expr)); + } + + return new FelderaArrayConstant(array); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("array["); + for (int i = 0; i < array.size(); i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(array.get(i)); + } + + sb.append("]"); + return sb.toString(); + } + } + + public static class FelderaDecimalConstant extends FelderaConstant { + private final BigDecimal value; + + public FelderaDecimalConstant(BigDecimal value) { + this.value = value; + } + + public BigDecimal getValue() { + return this.value; + } + + public static FelderaDecimalConstant getRandom(FelderaGlobalState globalState, int size, int scale) { + // unsure what to do about size for now + BigDecimal value = globalState.getRandomly().getRandomBigDecimal().setScale(scale, RoundingMode.HALF_UP) + .add(BigDecimal.ONE); + + return new FelderaDecimalConstant(value); + } + + @Override + public String toString() { + return value.toPlainString(); + } + } + public static class FelderaTimeConstant extends FelderaConstant { private final String value; @@ -157,10 +221,10 @@ public static FelderaIntConstant getRandom(FelderaGlobalState globalState, int b } } - public static class FelderaDoubleConstant extends FelderaConstant { + public static class FelderaFloatConstant extends FelderaConstant { private final double value; - public FelderaDoubleConstant(double value) { + public FelderaFloatConstant(double value) { this.value = value; } @@ -178,36 +242,16 @@ public String toString() { return String.valueOf(value); } - public static FelderaDoubleConstant getRandom(FelderaGlobalState globalState) { - return new FelderaDoubleConstant( - FelderaConstant.round(globalState.getRandomly().getFiniteDouble() + 1.0, 10)); - } - } - - public static class FelderaRealConstant extends FelderaConstant { - private final float value; - - public FelderaRealConstant(float value) { - this.value = value; - } - - public float getValue() { - return value; - } - - @Override - public String toString() { - if (value == Float.POSITIVE_INFINITY) { - return "'+Inf'"; - } else if (value == Float.NEGATIVE_INFINITY) { - return "'-Inf'"; + public static FelderaFloatConstant getRandom(FelderaGlobalState globalState, int size) { + double value = globalState.getRandomly().getFiniteDouble() + 1.0; + switch (size) { + case 32: + return new FelderaFloatConstant(FelderaConstant.round(value, 5)); + case 64: + return new FelderaFloatConstant(FelderaConstant.round(value, 10)); + default: + throw new AssertionError(size); } - return String.valueOf(value); - } - - public static FelderaRealConstant getRandom(FelderaGlobalState globalState) { - return new FelderaRealConstant( - ((float) FelderaConstant.round(globalState.getRandomly().getFiniteDouble() + 1.0, 5))); } } @@ -248,16 +292,33 @@ public static FelderaVarcharConstant getRandom(FelderaGlobalState globalState) { return new FelderaVarcharConstant(randomString); } + + public static FelderaVarcharConstant getRandom(FelderaGlobalState globalState, int size) { + if (size < 0) { + return FelderaVarcharConstant.getRandom(globalState); + } + + StringBuilder sb = new StringBuilder(); + CharsetEncoder encoder = StandardCharsets.ISO_8859_1.newEncoder(); + while (sb.length() < size) { + char ch = globalState.getRandomly().getAlphabeticChar().charAt(0); + if (encoder.canEncode(ch)) { + sb.append(ch); + } + } + + return new FelderaVarcharConstant(sb.toString()); + } } public static class FelderaCharConstant extends FelderaConstant { - private final char value; + private final String value; - public FelderaCharConstant(char value) { + public FelderaCharConstant(String value) { this.value = value; } - public char getValue() { + public String getValue() { return value; } @@ -266,13 +327,22 @@ public String toString() { return "'" + this.value + "'"; } - public static FelderaCharConstant getRandom(FelderaGlobalState globalState) { - char ch = globalState.getRandomly().getAlphabeticChar().charAt(0); - while (true) { - if (StandardCharsets.ISO_8859_1.newEncoder().canEncode(ch)) { - return new FelderaCharConstant(ch); + public static FelderaCharConstant getRandom(FelderaGlobalState globalState, int length) { + StringBuilder sb = new StringBuilder(); + CharsetEncoder encoder = StandardCharsets.ISO_8859_1.newEncoder(); + + for (int i = 0; i < length; i++) { + for (int attempts = 0; attempts < 10; attempts++) { + char ch = globalState.getRandomly().getAlphabeticChar().charAt(0); + if (encoder.canEncode(ch)) { + sb.append(ch); + break; + } } + sb.append("x"); } + + return new FelderaCharConstant(sb.toString()); } } @@ -301,8 +371,8 @@ public static FelderaExpression createVarcharConstant(String text) { return new FelderaVarcharConstant(text); } - public static FelderaExpression createDoubleConstant(double val) { - return new FelderaDoubleConstant(val); + public static FelderaExpression createFloatConstant(double val) { + return new FelderaFloatConstant(val); } public static FelderaExpression createIntConstant(long val) { diff --git a/src/sqlancer/feldera/ast/FelderaFunction.java b/src/sqlancer/feldera/ast/FelderaFunction.java index 204d8712e..73aeb55c8 100644 --- a/src/sqlancer/feldera/ast/FelderaFunction.java +++ b/src/sqlancer/feldera/ast/FelderaFunction.java @@ -4,6 +4,7 @@ import sqlancer.feldera.gen.FelderaExpressionGenerator; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -27,54 +28,134 @@ public enum FelderaFunction { TRIM(FelderaSchema.FelderaDataType.VARCHAR, FelderaSchema.FelderaDataType.VARCHAR), UPPER(FelderaSchema.FelderaDataType.VARCHAR, FelderaSchema.FelderaDataType.VARCHAR), - // Double - ABS(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - CEIL(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - FLOOR(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - TRUNCATE1("TRUNCATE", FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - // TRUNCATE2("TRUNCATE", FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE, + // Float + ABS(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + CEIL(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + FLOOR(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + TRUNCATE1("TRUNCATE", FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + // TRUNCATE2("TRUNCATE", FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT, // FelderaSchema.FelderaDataType.INT), - ROUND1("ROUND", FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - // ROUND2("ROUND", FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE, + ROUND1("ROUND", FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + // ROUND2("ROUND", FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT, // FelderaSchema.FelderaDataType.INT), - POWER(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE, - FelderaSchema.FelderaDataType.DOUBLE), - POWER2("POWER", FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.INT, + POWER(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT, + FelderaSchema.FelderaDataType.FLOAT), + POWER2("POWER", FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.INT), - SQRT(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - EXP(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - LN(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - LOG(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - LOG10(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - IS_INF(FelderaSchema.FelderaDataType.BOOLEAN, FelderaSchema.FelderaDataType.DOUBLE), - IS_NAN(FelderaSchema.FelderaDataType.BOOLEAN, FelderaSchema.FelderaDataType.DOUBLE), - SIN(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - COS(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - TAN(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - COT(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - SEC(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - CSC(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - ASIN(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - ACOS(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - ATAN(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - ATAN2(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE, - FelderaSchema.FelderaDataType.DOUBLE), - DEGREES(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - RADIANS(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - CBRT(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - SINH(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - COSH(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - TANH(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - COTH(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - SECH(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - CSCH(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - ASINH(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - ACOSH(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), - ATANH(FelderaSchema.FelderaDataType.DOUBLE, FelderaSchema.FelderaDataType.DOUBLE), + SQRT(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + EXP(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + LN(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + LOG(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + LOG10(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + IS_INF(FelderaSchema.FelderaDataType.BOOLEAN, FelderaSchema.FelderaDataType.FLOAT), + IS_NAN(FelderaSchema.FelderaDataType.BOOLEAN, FelderaSchema.FelderaDataType.FLOAT), + SIN(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + COS(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + TAN(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + COT(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + SEC(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + CSC(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + ASIN(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + ACOS(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + ATAN(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + ATAN2(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT, + FelderaSchema.FelderaDataType.FLOAT), + DEGREES(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + RADIANS(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + CBRT(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + SINH(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + COSH(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + TANH(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + COTH(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + SECH(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + CSCH(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + ASINH(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + ACOSH(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + ATANH(FelderaSchema.FelderaDataType.FLOAT, FelderaSchema.FelderaDataType.FLOAT), + + // Decimal + ABS_DECIMAL("ABS", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + CEIL_DECIMAL("CEIL", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + FLOOR_DECIMAL("FLOOR", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + TRUNCATE1_DECIMAL("TRUNCATE", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + // TRUNCATE2_DECIMAL("TRUNCATE", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL, + // FelderaSchema.FelderaDataType.INT), + ROUND1_DECIMAL("ROUND", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + // ROUND2_DECIMAL("ROUND", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL, + // FelderaSchema.FelderaDataType.INT), + POWER_DECIMAL("POWER", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL, + FelderaSchema.FelderaDataType.DECIMAL), + POWER2_DECIMAL("POWER", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.INT, + FelderaSchema.FelderaDataType.INT), + SQRT_DECIMAL("SQRT", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + EXP_DECIMAL("EXP", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + LN_DECIMAL("LN", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + LOG_DECIMAL("LOG", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + LOG10_DECIMAL("LOG10", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + IS_INF_DECIMAL("IS_INF", FelderaSchema.FelderaDataType.BOOLEAN, FelderaSchema.FelderaDataType.DECIMAL), + IS_NAN_DECIMAL("IS_NAN", FelderaSchema.FelderaDataType.BOOLEAN, FelderaSchema.FelderaDataType.DECIMAL), + SIN_DECIMAL("SIN", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + COS_DECIMAL("COS", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + TAN_DECIMAL("TAN", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + COT_DECIMAL("COT", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + SEC_DECIMAL("SEC", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + CSC_DECIMAL("CSC", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + ASIN_DECIMAL("ASIN", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + ACOS_DECIMAL("ACOS", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + ATAN_DECIMAL("ATAN", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + ATAN2_DECIMAL("ATAN2", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL, + FelderaSchema.FelderaDataType.DECIMAL), + DEGREES_DECIMAL("DEGREES", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + RADIANS_DECIMAL("RADIANS", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + CBRT_DECIMAL("CBRT", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + SINH_DECIMAL("SINH", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + COSH_DECIMAL("COSH", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + TANH_DECIMAL("TANH", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + COTH_DECIMAL("COTH", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + SECH_DECIMAL("SECH", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + CSCH_DECIMAL("CSCH", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + ASINH_DECIMAL("ASINH", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + ACOSH_DECIMAL("ACOSH", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), + ATANH_DECIMAL("ATANH", FelderaSchema.FelderaDataType.DECIMAL, FelderaSchema.FelderaDataType.DECIMAL), // Int - ABS_INT("abs", FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.INT), - MOD(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.INT),; + ABS_INT("ABS", FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.INT), + MOD(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.INT), + + // ARRAY + ARRAY(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ANY), + ARRAY_APPEND(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ARRAY, + FelderaSchema.FelderaDataType.ANY), + ARRAY_CONCAT(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ARRAY, + FelderaSchema.FelderaDataType.ARRAY), + ARRAY_COMPACT(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ARRAY), + ARRAY_CONTAINS(FelderaSchema.FelderaDataType.BOOLEAN, FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ANY), + ARRAY_DISTINCT(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ARRAY), + ARRAY_EXCEPT(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ARRAY, + FelderaSchema.FelderaDataType.ARRAY), + ARRAY_INTERSECT(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ARRAY, + FelderaSchema.FelderaDataType.ARRAY), + ARRAY_SIZE(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.ARRAY), + ARRAY_LENGTH(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.ARRAY), + ARRAY_MAX(FelderaSchema.FelderaDataType.ANY, FelderaSchema.FelderaDataType.ARRAY), + ARRAY_MIN(FelderaSchema.FelderaDataType.ANY, FelderaSchema.FelderaDataType.ARRAY), + ARRAYS_OVERLAP(FelderaSchema.FelderaDataType.BOOLEAN, FelderaSchema.FelderaDataType.ARRAY, + FelderaSchema.FelderaDataType.ARRAY), + ARRAY_POSITION(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.ARRAY, + FelderaSchema.FelderaDataType.ANY), + ARRAY_PREPEND(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ARRAY, + FelderaSchema.FelderaDataType.ANY), + ARRAY_REMOVE(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ARRAY, + FelderaSchema.FelderaDataType.ANY), + ARRAY_REVERSE(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ARRAY), + ARRAY_REPEAT(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ANY, + FelderaSchema.FelderaDataType.INT), + ARRAY_TO_STRING(FelderaSchema.FelderaDataType.VARCHAR, FelderaSchema.FelderaDataType.ARRAY, + FelderaSchema.FelderaDataType.CHAR), + ARRAY_UNION(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ARRAY, + FelderaSchema.FelderaDataType.ARRAY), + CARDINALITY(FelderaSchema.FelderaDataType.INT, FelderaSchema.FelderaDataType.ARRAY), + SORT_ARRAY(FelderaSchema.FelderaDataType.ARRAY, FelderaSchema.FelderaDataType.ARRAY),; private FelderaSchema.FelderaDataType returnType; private FelderaSchema.FelderaDataType[] argumentTypes; @@ -99,8 +180,8 @@ public enum FelderaFunction { this.argumentTypes = argumentTypes.clone(); } - public boolean isCompatibleWithReturnType(FelderaSchema.FelderaDataType dataType) { - return this.returnType == dataType; + public boolean isCompatibleWithReturnType(FelderaSchema.FelderaCompositeDataType dataType) { + return this.returnType == dataType.getPrimitiveType(); } public String getFunctionName() { @@ -111,25 +192,48 @@ public FelderaSchema.FelderaDataType[] getArgumentTypes() { return argumentTypes; } - public FelderaFunctionCall getCall(FelderaSchema.FelderaDataType returnType, FelderaExpressionGenerator gen, + public FelderaFunctionCall getCall(FelderaSchema.FelderaCompositeDataType type, FelderaExpressionGenerator gen, int depth) { FelderaSchema.FelderaDataType[] argumentTypes = getArgumentTypes(); - List arguments = getArgumentsForReturnType(gen, depth, argumentTypes, returnType); + List arguments = getArgumentsForReturnType(gen, depth, argumentTypes, type); return new FelderaFunctionCall(this, arguments); } List getArgumentsForReturnType(FelderaExpressionGenerator gen, int depth, - FelderaSchema.FelderaDataType[] argumentTypes, FelderaSchema.FelderaDataType returnType) { + FelderaSchema.FelderaDataType[] argumentTypes, FelderaSchema.FelderaCompositeDataType type) { List arguments = new ArrayList<>(); + FelderaSchema.FelderaCompositeDataType arrayType; + FelderaSchema.FelderaCompositeDataType arrayElementType; + if (type.isArray()) { + arrayElementType = type.getElementType(); + } else { + arrayElementType = FelderaSchema.FelderaCompositeDataType.getRandomWithoutNull(); + } + + if (this.returnType == FelderaSchema.FelderaDataType.ARRAY) { + arrayType = type; + } else { + arrayType = new FelderaSchema.FelderaCompositeDataType(FelderaSchema.FelderaDataType.ARRAY, arrayElementType); + } for (FelderaSchema.FelderaDataType arg : argumentTypes) { - arguments.add(gen.generateExpression(arg, depth + 1)); + switch (arg) { + case ARRAY: + arguments.add(gen.generateConstant(arrayType)); + continue; + case ANY: + arguments.add(gen.generateConstant(arrayElementType)); + continue; + default: + arguments.add(gen.generateExpression(FelderaSchema.FelderaCompositeDataType.getRandomFromPrimitiveType(arg), + depth + 1)); + } } return arguments; } - public static List getFunctionCompatibleWith(FelderaSchema.FelderaDataType returnType) { + public static List getFunctionCompatibleWith(FelderaSchema.FelderaCompositeDataType returnType) { return Stream.of(values()).filter(f -> f.isCompatibleWithReturnType(returnType)).collect(Collectors.toList()); } } diff --git a/src/sqlancer/feldera/ast/FelderaJoin.java b/src/sqlancer/feldera/ast/FelderaJoin.java index f56af719c..eb2f07455 100644 --- a/src/sqlancer/feldera/ast/FelderaJoin.java +++ b/src/sqlancer/feldera/ast/FelderaJoin.java @@ -13,7 +13,9 @@ public class FelderaJoin private FelderaExpression onCondition; public enum FelderaJoinType { - INNER, NATURAL, LEFT, RIGHT; + INNER, + // NATURAL, + LEFT, RIGHT; public static FelderaJoinType getRandom() { return Randomly.fromOptions(values()); diff --git a/src/sqlancer/feldera/client/HttpRequests.java b/src/sqlancer/feldera/client/HttpRequests.java index cbd9aa07e..554ee0b8d 100644 --- a/src/sqlancer/feldera/client/HttpRequests.java +++ b/src/sqlancer/feldera/client/HttpRequests.java @@ -10,10 +10,13 @@ import java.net.http.HttpTimeoutException; import java.time.Duration; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; public class HttpRequests { private final String baseUrl; private final ObjectMapper objectMapper; + private final Logger logger = Logger.getLogger(this.getClass().getName()); private final HttpClient httpClient; public HttpRequests(String baseUrl) { @@ -57,7 +60,9 @@ private void validateResponse(HttpResponse response) throws Exception { private String sendRequest(HttpRequest request) throws Exception { try { + logger.log(Level.FINEST, "making request: " + request.toString()); HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + logger.log(Level.FINEST, "got response: " + response.toString()); validateResponse(response); return response.body(); } catch (HttpTimeoutException e) { diff --git a/src/sqlancer/feldera/gen/FelderaCommon.java b/src/sqlancer/feldera/gen/FelderaCommon.java index af7f12061..b2bb62269 100644 --- a/src/sqlancer/feldera/gen/FelderaCommon.java +++ b/src/sqlancer/feldera/gen/FelderaCommon.java @@ -6,7 +6,8 @@ public class FelderaCommon { private FelderaCommon() { } - public static void appendDataType(FelderaSchema.FelderaDataType type, StringBuilder sb) throws AssertionError { + public static void appendDataType(FelderaSchema.FelderaCompositeDataType type, StringBuilder sb) + throws AssertionError { sb.append(type.toString()); } } diff --git a/src/sqlancer/feldera/gen/FelderaExpressionGenerator.java b/src/sqlancer/feldera/gen/FelderaExpressionGenerator.java index 83b978319..cc1ef063b 100644 --- a/src/sqlancer/feldera/gen/FelderaExpressionGenerator.java +++ b/src/sqlancer/feldera/gen/FelderaExpressionGenerator.java @@ -11,8 +11,8 @@ import java.util.*; import java.util.stream.Collectors; -public final class FelderaExpressionGenerator - extends TypedExpressionGenerator +public final class FelderaExpressionGenerator extends + TypedExpressionGenerator implements NoRECGenerator { @@ -30,7 +30,7 @@ private enum BooleanExpression { } private FelderaExpression getBinaryComparison(int depth) { - FelderaSchema.FelderaDataType type = getRandomType(); + FelderaSchema.FelderaCompositeDataType type = getRandomType(); FelderaExpression left = generateExpression(type, depth + 1); FelderaExpression right = generateExpression(type, depth + 1); return new FelderaBinaryComparisonOperation(left, right, @@ -43,7 +43,8 @@ private FelderaExpression generateBooleanExpression(int depth) { switch (exprType) { case NOT: - return new FelderaUnaryPrefixOperation(generateExpression(FelderaSchema.FelderaDataType.BOOLEAN, depth + 1), + return new FelderaUnaryPrefixOperation( + generateExpression(FelderaSchema.FelderaCompositeDataType.getBooleanType(), depth + 1), FelderaUnaryPrefixOperation.FelderaUnaryPrefixOperator.NOT); case COMPARISON: return getBinaryComparison(depth); @@ -52,7 +53,10 @@ private FelderaExpression generateBooleanExpression(int depth) { Randomly.fromOptions(FelderaUnaryPostfixOperation.FelderaUnaryPostfixOperator.IS_NULL, FelderaUnaryPostfixOperation.FelderaUnaryPostfixOperator.IS_NOT_NULL)); case BETWEEN: - FelderaSchema.FelderaDataType type = getRandomType(); + FelderaSchema.FelderaCompositeDataType type = getRandomType(); + if (type.isArray()) { + type = FelderaSchema.FelderaCompositeDataType.getBooleanType(); + } expr = generateExpression(type, depth + 1); FelderaExpression left = generateExpression(type, depth + 1); FelderaExpression right = generateExpression(type, depth + 1); @@ -64,14 +68,15 @@ private FelderaExpression generateBooleanExpression(int depth) { } private FelderaExpression generateStringExpression(int depth) { - FelderaSchema.FelderaDataType type = FelderaSchema.FelderaDataType.VARCHAR; + FelderaSchema.FelderaCompositeDataType type = FelderaSchema.FelderaCompositeDataType.getRandomVarcharType(); List applicableFunctions = FelderaFunction.getFunctionCompatibleWith(type); if (!applicableFunctions.isEmpty()) { FelderaFunction function = Randomly.fromList(applicableFunctions); return function.getCall(type, this, depth + 1); } - return generateLeafNode(FelderaSchema.FelderaDataType.VARCHAR); + return generateLeafNode(FelderaSchema.FelderaCompositeDataType + .getRandomFromPrimitiveType(FelderaSchema.FelderaDataType.VARCHAR)); } private FelderaExpression generateIntegerString() { @@ -82,27 +87,25 @@ private FelderaExpression generateIntegerString() { return new FelderaConstant.FelderaVarcharConstant(s); } - private FelderaExpression getBinaryArithmeticOperation(FelderaSchema.FelderaDataType type, int depth) { - if (Randomly.getBoolean()) { - type = FelderaSchema.FelderaDataType.getRandomNumericType(); - } + private FelderaExpression getBinaryArithmeticOperation(FelderaSchema.FelderaCompositeDataType type, int depth) { return new FelderaBinaryArithmeticOperation(generateExpression(type, depth + 1), generateExpression(type, depth + 1), FelderaBinaryArithmeticOperation.FelderaBinaryArithmeticOperator.getRandom()); } @Override - protected FelderaSchema.FelderaDataType getRandomType() { - return FelderaSchema.FelderaDataType.getRandomNonNullType(); + protected FelderaSchema.FelderaCompositeDataType getRandomType() { + return FelderaSchema.FelderaCompositeDataType.getRandomWithoutNull(); } @Override - protected boolean canGenerateColumnOfType(FelderaSchema.FelderaDataType type) { + protected boolean canGenerateColumnOfType(FelderaSchema.FelderaCompositeDataType type) { List columns = filterColumns(type); return !columns.isEmpty(); } - private FelderaExpression getAggregate(FelderaSchema.FelderaDataType type) throws IndexOutOfBoundsException { + private FelderaExpression getAggregate(FelderaSchema.FelderaCompositeDataType type) + throws IndexOutOfBoundsException { FelderaAggregate.FelderaAggregateFunction agg = Randomly .fromList(FelderaAggregate.FelderaAggregateFunction.getAggregates(type)); return generateArgsForAggregate(type, agg); @@ -117,21 +120,34 @@ public FelderaExpression generateAggregate() { } } - private FelderaAggregate generateArgsForAggregate(FelderaSchema.FelderaDataType type, + private FelderaAggregate generateArgsForAggregate(FelderaSchema.FelderaCompositeDataType type, FelderaAggregate.FelderaAggregateFunction agg) { - List types = agg.getTypes(type); + List types = agg.getTypes(type); List args = new ArrayList<>(); allowAggregates = false; - for (FelderaSchema.FelderaDataType argType : types) { + for (FelderaSchema.FelderaCompositeDataType argType : types) { args.add(generateExpression(argType)); } return new FelderaAggregate(agg, args); + } + private FelderaExpression generateArrayExpression(FelderaSchema.FelderaCompositeDataType type, int depth) { + if (depth >= maxDepth) { + return generateLeafNode(type); + } + + List applicableFunctions = FelderaFunction.getFunctionCompatibleWith(type); + if (!applicableFunctions.isEmpty()) { + FelderaFunction function = Randomly.fromList(applicableFunctions); + return function.getCall(type, this, depth + 1); + } + + return generateLeafNode(type); } @Override - public FelderaExpression generateExpression(FelderaSchema.FelderaDataType type, int depth) { + public FelderaExpression generateExpression(FelderaSchema.FelderaCompositeDataType type, int depth) { if (depth >= maxDepth) { return generateLeafNode(type); } @@ -149,42 +165,41 @@ public FelderaExpression generateExpression(FelderaSchema.FelderaDataType type, } } if (type.isNumeric() && Randomly.getBooleanWithSmallProbability()) { - FelderaSchema.FelderaDataType randomType = FelderaSchema.FelderaDataType.getRandomType(); + FelderaSchema.FelderaCompositeDataType randomType = FelderaSchema.FelderaCompositeDataType + .getRandomWithoutNull(); FelderaExpression expr; - if (randomType == FelderaSchema.FelderaDataType.VARCHAR) { + if (randomType.getPrimitiveType() == FelderaSchema.FelderaDataType.VARCHAR) { expr = generateIntegerString(); } else if (!randomType.isNumeric()) { - expr = generateExpression(FelderaSchema.FelderaDataType.getRandomNumericType(), depth + 1); + expr = generateExpression(FelderaSchema.FelderaCompositeDataType.getRandomNumericType(), depth + 1); } else { expr = generateExpression(randomType, depth + 1); } return new FelderaCast(expr, type); } - switch (type) { + switch (type.getPrimitiveType()) { + case ARRAY: + return generateArrayExpression(type, depth + 1); + case DATE: + case TIMESTAMP: + case TIME: + case CHAR: + return generateLeafNode(type); case BOOLEAN: return generateBooleanExpression(depth); case VARCHAR: return generateStringExpression(depth); - case TINYINT: - case SMALLINT: case INT: - case BIGINT: - case REAL: - case DOUBLE: + case FLOAT: + case DECIMAL: return getBinaryArithmeticOperation(type, depth); - case DATE: - case TIMESTAMP: - case TIME: - case CHAR: - FelderaExpression expr = FelderaConstant.getRandomConstant(globalState, type); - return new FelderaCast(expr, type); default: throw new AssertionError(type); } } - List filterColumns(FelderaSchema.FelderaDataType type) { + List filterColumns(FelderaSchema.FelderaCompositeDataType type) { if (columns == null) { return Collections.emptyList(); } else { @@ -193,7 +208,7 @@ List filterColumns(FelderaSchema.FelderaDataType ty } @Override - protected FelderaExpression generateColumn(FelderaSchema.FelderaDataType type) { + protected FelderaExpression generateColumn(FelderaSchema.FelderaCompositeDataType type) { // HACK: if no col of such type exists, generate constant value instead List colsOfType = filterColumns(type); if (colsOfType.isEmpty()) { @@ -205,13 +220,13 @@ protected FelderaExpression generateColumn(FelderaSchema.FelderaDataType type) { } @Override - public FelderaExpression generateConstant(FelderaSchema.FelderaDataType type) { + public FelderaExpression generateConstant(FelderaSchema.FelderaCompositeDataType type) { return type.getRandomConstant(globalState); } @Override public FelderaExpression generatePredicate() { - return generateExpression(FelderaSchema.FelderaDataType.BOOLEAN, 0); + return generateExpression(FelderaSchema.FelderaCompositeDataType.getBooleanType(), 0); } @Override @@ -235,7 +250,8 @@ public FelderaExpressionGenerator setTablesAndColumns( @Override public FelderaExpression generateBooleanExpression() { - return generateExpression(FelderaSchema.FelderaDataType.BOOLEAN); + return generateExpression(FelderaSchema.FelderaCompositeDataType + .getRandomFromPrimitiveType(FelderaSchema.FelderaDataType.BOOLEAN)); } @Override @@ -291,9 +307,9 @@ public List getRandomJoinClauses(List t // natural join is incompatible with other joins // because it needs unique column names // while other joins will produce duplicate column names - if (nrJoinClauses > 1) { - options.remove(FelderaJoin.FelderaJoinType.NATURAL); - } +// if (nrJoinClauses > 1) { +// options.remove(FelderaJoin.FelderaJoinType.NATURAL); +// } for (int i = 0; i < nrJoinClauses; i++) { FelderaExpression joinClause = generatePredicate(); FelderaTableReference leftTable = Randomly.fromList(tablesRef); @@ -302,10 +318,10 @@ public List getRandomJoinClauses(List t tablesRef.remove(rightTable); FelderaJoin.FelderaJoinType selectedOption = Randomly.fromList(options); - if (selectedOption == FelderaJoin.FelderaJoinType.NATURAL) { - // NATURAL joins do not have an ON clause - joinClause = null; - } +// if (selectedOption == FelderaJoin.FelderaJoinType.NATURAL) { +// // NATURAL joins do not have an ON clause +// joinClause = null; +// } FelderaJoin j = new FelderaJoin(leftTable, rightTable, selectedOption, joinClause); joinStatements.add(j); diff --git a/src/sqlancer/feldera/gen/FelderaTableGenerator.java b/src/sqlancer/feldera/gen/FelderaTableGenerator.java index 419471c00..117881c59 100644 --- a/src/sqlancer/feldera/gen/FelderaTableGenerator.java +++ b/src/sqlancer/feldera/gen/FelderaTableGenerator.java @@ -42,7 +42,7 @@ public FelderaOtherQuery generate() { private void createField(String name) throws AssertionError { sb.append(name); sb.append(" "); - FelderaSchema.FelderaDataType type = FelderaSchema.FelderaDataType.getRandomNonNullType(); + FelderaSchema.FelderaCompositeDataType type = FelderaSchema.FelderaCompositeDataType.getRandomWithoutNull(); FelderaCommon.appendDataType(type, sb); FelderaSchema.FelderaFieldColumn c = new FelderaSchema.FelderaFieldColumn(name, type); c.setTable(table); diff --git a/test/sqlancer/dbms/TestConfig.java b/test/sqlancer/dbms/TestConfig.java index 92de68fe9..08157efc9 100644 --- a/test/sqlancer/dbms/TestConfig.java +++ b/test/sqlancer/dbms/TestConfig.java @@ -10,6 +10,7 @@ public class TestConfig { public static final String DATABEND_ENV = "DATABEND_AVAILABLE"; public static final String DATAFUSION_ENV = "DATAFUSION_AVAILABLE"; public static final String DORIS_ENV = "DORIS_AVAILABLE"; + public static final String FELDERA_ENV = "FELDERA_AVAILABLE"; public static final String MARIADB_ENV = "MARIADB_AVAILABLE"; public static final String MATERIALIZE_ENV = "MATERIALIZE_AVAILABLE"; public static final String MYSQL_ENV = "MYSQL_AVAILABLE"; diff --git a/test/sqlancer/dbms/TestFeldera.java b/test/sqlancer/dbms/TestFeldera.java new file mode 100644 index 000000000..1439486e1 --- /dev/null +++ b/test/sqlancer/dbms/TestFeldera.java @@ -0,0 +1,18 @@ +package sqlancer.dbms; + +import org.junit.jupiter.api.Test; +import sqlancer.Main; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +public class TestFeldera { + @Test + public void testFelderaNoREC() { + assumeTrue(TestConfig.isEnvironmentTrue(TestConfig.FELDERA_ENV)); + assertEquals(0, Main.executeMain("--num-threads", "16", + "--timeout-seconds", TestConfig.SECONDS, + "feldera", + "--oracle", "NOREC")); + } +}