Skip to content
Merged
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
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,13 @@ Since SQL dialects differ widely, each DBMS to be tested requires a separate imp
| TDEngine | Removed | Untyped | We removed the TDEngine implementation since all but one of our bug reports were still unaddressed five months after we reported them. |
| OceanBase | Working | Untyped | |
| YugabyteDB | Working | Typed (YSQL), Untyped (YCQL) | YSQL implementation based on Postgres code. YCQL implementation is primitive for now and uses Cassandra JDBC driver as a proxy interface. |
| Databend | Working | Typed | |
| QuestDB | Working | Untyped, Generic | The implementation of QuestDB is still WIP, current version covers very basic data types, operations and SQL keywords. |
| Databend | Working | Typed | |
| QuestDB | Working | Untyped, Generic | The implementation of QuestDB is still WIP, current version covers very basic data types, operations and SQL keywords. |
| CnosDB |Working | Typed | The implementation of CnosDB currently uses Restful API. |
| Materialize |Working | Typed |
| Apache Doris | Preliminary | Typed | This is a preliminary implementation, which only contains the common logic of Doris. We have found some errors through it, and hope to improve it in the future.
| Apache Doris | Preliminary | Typed | This is a preliminary implementation, which only contains the common logic of Doris. We have found some errors through it, and hope to improve it in the future.
| Presto | Preliminary | Typed | This is a preliminary implementation, only basic types supported.



# Using SQLancer
Expand Down
7 changes: 6 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@
<artifactId>duckdb_jdbc</artifactId>
<version>0.5.1</version>
</dependency>
<dependency>
<groupId>com.facebook.presto</groupId>
<artifactId>presto-jdbc</artifactId>
<version>0.283</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
Expand Down Expand Up @@ -467,4 +472,4 @@
</build>
</profile>
</profiles>
</project>
</project>
1 change: 1 addition & 0 deletions src/check_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def verify_all_dbs(name_to_files: dict[str:List[str]]):
name_to_files["MySQL"] = get_java_files(os.path.join(cwd, "src", "sqlancer", "mysql"))
name_to_files["OceanBase"] = get_java_files(os.path.join(cwd, "src", "sqlancer", "oceanbase"))
name_to_files["Postgres"] = get_java_files(os.path.join(cwd, "src", "sqlancer", "postgres"))
name_to_files["Presto"] = get_java_files(os.path.join(cwd, "src", "sqlancer", "presto"))
name_to_files["QuestDB"] = get_java_files(os.path.join(cwd, "src", "sqlancer", "questdb"))
name_to_files["SQLite3"] = get_java_files(os.path.join(cwd, "src", "sqlancer", "sqlite3"))
name_to_files["TiDB"] = get_java_files(os.path.join(cwd, "src", "sqlancer", "tidb"))
Expand Down
2 changes: 2 additions & 0 deletions src/sqlancer/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import sqlancer.mysql.MySQLProvider;
import sqlancer.oceanbase.OceanBaseProvider;
import sqlancer.postgres.PostgresProvider;
import sqlancer.presto.PrestoProvider;
import sqlancer.questdb.QuestDBProvider;
import sqlancer.sqlite3.SQLite3Provider;
import sqlancer.stonedb.StoneDBProvider;
Expand Down Expand Up @@ -719,6 +720,7 @@ private static void checkForIssue799(List<DatabaseProvider<?, ?, ?>> providers)
providers.add(new MongoDBProvider());
providers.add(new MySQLProvider());
providers.add(new OceanBaseProvider());
providers.add(new PrestoProvider());
providers.add(new PostgresProvider());
providers.add(new QuestDBProvider());
providers.add(new SQLite3Provider());
Expand Down
40 changes: 40 additions & 0 deletions src/sqlancer/presto/PrestoConstantUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package sqlancer.presto;

import java.math.BigDecimal;
import java.math.RoundingMode;

public final class PrestoConstantUtils {

private PrestoConstantUtils() {
}

public static String removeNoneAscii(String str) {
return str.replaceAll("[^\\x00-\\x7F]", "");
}

public static String removeNonePrintable(String str) { // All Control Char
return str.replaceAll("[\\p{C}]", "");
}

public static String removeOthersControlChar(String str) { // Some Control Char
return str.replaceAll("[\\p{Cntrl}\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]", "");
}

public static String removeAllControlChars(String str) {
return removeOthersControlChar(removeNonePrintable(str)).replaceAll("[\\r\\n\\t]", "");
}

public static BigDecimal getDecimal(double val, int scale, int precision) {
int part = precision - scale;
// long part
long lng = (long) val;
// decimal places
double d1 = val - lng;
String xStr = Long.toString(lng);
String substring = xStr.substring(xStr.length() - part);
long newX = substring.isEmpty() ? 0 : Long.parseLong(substring);
double finalD = newX + d1;
return new BigDecimal(finalD).setScale(scale, RoundingMode.CEILING);
}

}
127 changes: 127 additions & 0 deletions src/sqlancer/presto/PrestoErrors.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package sqlancer.presto;

import sqlancer.common.query.ExpectedErrors;

public final class PrestoErrors {

private PrestoErrors() {
}

public static void addExpressionErrors(ExpectedErrors errors) {
// Presto errors
errors.add("cannot be applied to");
errors.add("LIKE expression must evaluate to a varchar");
errors.add("JOIN ON clause must evaluate to a boolean");
// errors.add("Unexpected parameters");

// SELECT SUM(count) FROM (SELECT
// CAST((-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000
// IS NOT NULL AND
// -179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000)
// AS BIGINT)as count FROM t0) as res
errors.add("Decimal overflow");
errors.add("multiplication overflow");
errors.add("addition overflow");
errors.add("subtraction overflow");

// cast
// errors.add("Cannot cast");
errors.add("Value cannot be cast to");
errors.add("Cannot cast DECIMAL");
errors.add("Cannot cast BIGINT");
errors.add("Cannot cast INTEGER");

// TODO: check
errors.add("io.airlift.slice.Slice cannot be cast to java.lang.Number");
errors.add("Cannot cast java.lang.Long to io.airlift.slice.Slice");
errors.add("Unexpected subquery expression in logical plan");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like an internal error?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some errors that occur in certain versions of Presto.
Some of them are analyzed by the Presto team and they will not be addressed in the near future.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


// 9223372036854775808
errors.add("Invalid numeric literal");

errors.add("Division by zero");
errors.add("/ by zero");

errors.add("Cannot subtract hour, minutes or seconds from a date");
errors.add("Cannot add hour, minutes or seconds to a date");

errors.add("DECIMAL scale must be in range");
errors.add("multiplication overflow");
errors.add("addition overflow");
errors.add("subtraction overflow");
errors.add("Decimal overflow");
errors.add("IN value and list items must be the same type");
errors.add("is not a valid timestamp literal");
errors.add("Unknown time-zone ID");
errors.add("GROUP BY position");

// ARRAY
errors.add("Unknown type: ARRAY");
}

private static void addRegexErrors(ExpectedErrors errors) {
errors.add("missing ]");
errors.add("missing )");
errors.add("invalid escape sequence");
errors.add("no argument for repetition operator: ");
errors.add("bad repetition operator");
errors.add("trailing \\");
errors.add("invalid perl operator");
errors.add("invalid character class range");
errors.add("width is not integer");
}

private static void addFunctionErrors(ExpectedErrors errors) {
errors.add("SUBSTRING cannot handle negative lengths");
errors.add("is undefined outside [-1,1]"); // ACOS etc
errors.add("invalid type specifier"); // PRINTF
errors.add("argument index out of range"); // PRINTF
errors.add("invalid format string"); // PRINTF
errors.add("number is too big"); // PRINTF
errors.add("Like pattern must not end with escape character!"); // LIKE
errors.add("Could not choose a best candidate function for the function call \"date_part"); // date_part
errors.add("extract specifier"); // date_part
errors.add("not recognized"); // date_part
errors.add("not supported"); // date_part
errors.add("Failed to cast");
errors.add("Conversion Error");
errors.add("Could not cast value");
errors.add("Insufficient padding in RPAD"); // RPAD
errors.add("Could not choose a best candidate function for the function call"); // monthname
errors.add("expected a numeric precision field"); // ROUND
errors.add("with non-constant precision is not supported"); // ROUND
}

// TODO: cover presto error
public static void addInsertErrors(ExpectedErrors errors) {
addRegexErrors(errors);
addFunctionErrors(errors);

errors.add("NOT NULL constraint failed");
errors.add("PRIMARY KEY or UNIQUE constraint violated");
errors.add("duplicate key");
errors.add("can't be cast because the value is out of range for the destination type");
errors.add("Could not convert string");
errors.add("Unimplemented type for cast");
errors.add("field value out of range");
errors.add("CHECK constraint failed");
errors.add("Cannot explicitly insert values into rowid column"); // TODO: don't insert into rowid
errors.add(" Column with name rowid does not exist!"); // currently, there doesn't seem to way to determine if
// the table has a primary key
errors.add("Could not cast value");
errors.add("create unique index, table contains duplicate data");
errors.add("Failed to cast");

errors.add("Values rows have mismatched types");
errors.add("Mismatch at column");
errors.add("This connector does not support updates or deletes");
errors.add("Values rows have mismatched types");
errors.add("Invalid numeric literal");

}

public static void addGroupByErrors(ExpectedErrors errors) {
errors.add("must be an aggregate expression or appear in GROUP BY clause");
}

}
25 changes: 25 additions & 0 deletions src/sqlancer/presto/PrestoExpressionToNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package sqlancer.presto;

import java.util.List;
import java.util.stream.Collectors;

import sqlancer.common.ast.newast.Node;
import sqlancer.presto.ast.PrestoExpression;

public final class PrestoExpressionToNode {

private PrestoExpressionToNode() {

}

@SuppressWarnings("unchecked")
public static Node<PrestoExpression> cast(PrestoExpression expression) {
return (Node<PrestoExpression>) expression;
}

@SuppressWarnings("unchecked")
public static List<Node<PrestoExpression>> casts(List<PrestoExpression> expressions) {
return expressions.stream().map(e -> (Node<PrestoExpression>) e).collect(Collectors.toList());
}

}
13 changes: 13 additions & 0 deletions src/sqlancer/presto/PrestoGlobalState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package sqlancer.presto;

import java.sql.SQLException;

import sqlancer.SQLGlobalState;

public class PrestoGlobalState extends SQLGlobalState<PrestoOptions, PrestoSchema> {

@Override
protected PrestoSchema readSchema() throws SQLException {
return PrestoSchema.fromConnection(getConnection(), getDatabaseName());
}
}
Loading