Skip to content

Commit

Permalink
Merge pull request #785 from Enaium-Fork/dev
Browse files Browse the repository at this point in the history
Optimize SQLite Dialect
  • Loading branch information
babyfish-ct authored Nov 15, 2024
2 parents 0514ae6 + d0dffe4 commit 46adc20
Show file tree
Hide file tree
Showing 16 changed files with 942 additions and 29 deletions.
3 changes: 3 additions & 0 deletions project/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ lombok = "1.18.30"
mapstruct = "1.5.3.Final"
mysql = "8.0.29"
postgresql = "42.3.6"
sqlite = "3.47.0.0"
slf4j = "1.7.36"
spring = "5.3.20"
springBoot = "2.7.0"
Expand Down Expand Up @@ -76,6 +77,8 @@ mysql-connector-java = { group = "mysql", name = "mysql-connector-java", version

postgresql = { group = "org.postgresql", name = "postgresql", version.ref = "postgresql" }

sqlite = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqlite" }

slf4j-api = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" }

spring-core = { group = "org.springframework", name = "spring-core", version.ref = "spring" }
Expand Down
1 change: 1 addition & 0 deletions project/jimmer-sql/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies {
testImplementation(libs.h2)
testImplementation(libs.mysql.connector.java)
testImplementation(libs.postgresql)
testImplementation(libs.sqlite)
testImplementation(libs.kafka.connect.api)
testImplementation(libs.javax.validation.api)
testImplementation(libs.hibernate.validation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ public <T extends Table<?>> T getTable() {
return (T)table;
}

public ImmutableType getType() {
return type;
}

public TableImplementor<?> getTableImplementor() {
TableImplementor<?> tableImplementor = this.tableImplementor;
if (tableImplementor == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,10 @@ private void renderDirectly(SqlBuilder builder, boolean logicalDeleted) {
if (getSqlClient().getDialect().isDeletedAliasRequired()) {
builder.sql(" ").sql(table.getAlias());
}
builder
.from()
.sql(table.getImmutableType().getTableName(getSqlClient().getMetadataStrategy()))
.sql(" ")
.sql(table.getAlias());
builder.from().sql(table.getImmutableType().getTableName(getSqlClient().getMetadataStrategy()));
if (getSqlClient().getDialect().isDeleteAliasSupported()) {
builder.sql(" ").sql(table.getAlias());
}
}
if (predicate != null) {
builder.enter(SqlBuilder.ScopeType.WHERE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,10 @@ private void renderTo(@NotNull SqlBuilder builder, Collection<Object> ids) {
this.accept(new VisitorImpl(builder.getAstContext(), dialect));
builder
.sql("update ")
.sql(table.getImmutableType().getTableName(getSqlClient().getMetadataStrategy()))
.sql(" ");
.sql(table.getImmutableType().getTableName(getSqlClient().getMetadataStrategy()));

if (getSqlClient().getDialect().isUpdateAliasSupported()) {
builder.sql(table.getAlias());
builder.sql(" ").sql(table.getAlias());
}

UpdateJoin updateJoin = dialect.getUpdateJoin();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,6 @@ public static void renderCmp(
builder.sqlClient()
);

// final Dialect dialect = builder.sqlClient().getDialect();
// final String sql = builder.builder.toString();
// if (alias.equals("tb_1_") && ((sql.startsWith("delete") && !dialect.isDeleteAliasSupported()) || (sql.startsWith("update") && !dialect.isUpdateAliasSupported()))) {
// alias = propExpressionImplementor.getTable().getImmutableType().getTableName(builder.sqlClient().getMetadataStrategy());
// }

valueGetters = ValueGetter.alias(alias, valueGetters);
}
renderCmp(operator, valueGetters, value, builder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import org.babyfish.jimmer.sql.ast.impl.AstContext;
import org.babyfish.jimmer.sql.ast.impl.AstVisitor;
import org.babyfish.jimmer.sql.ast.impl.util.AbstractDataManager;
import org.babyfish.jimmer.sql.runtime.ExecutionPurpose;
import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor;
import org.babyfish.jimmer.sql.runtime.SqlBuilder;
import org.babyfish.jimmer.sql.runtime.TableUsedState;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -46,7 +48,15 @@ public MergedNode(AbstractMutableStatementImpl statement, ImmutableProp joinProp
} else {
middleTableAlias = null;
}
alias = ctx.allocateTableAlias();
String alias = ctx.allocateTableAlias();
final JSqlClientImplementor sqlClient = statement.getSqlClient();
if (alias.equals("tb_1_") && sqlClient != null &&
(!sqlClient.getDialect().isUpdateAliasSupported() && ctx.getPurpose().toString().startsWith("UPDATE") ||
(!sqlClient.getDialect().isDeleteAliasSupported() && ctx.getPurpose().toString().startsWith("DELETE")))
) {
alias = statement.getType().getTableName(sqlClient.getMetadataStrategy());
}
this.alias = alias;
}

TableImplementor<?> table(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
package org.babyfish.jimmer.sql.dialect;

//public class SQLiteDialect extends DefaultDialect {
// @Override
// public boolean isDeleteAliasSupported() {
// return false;
// }
//
// @Override
// public boolean isUpdateAliasSupported() {
// return false;
// }
//}
import org.jetbrains.annotations.Nullable;

public class SQLiteDialect extends DefaultDialect {
@Override
public boolean isDeleteAliasSupported() {
return false;
}

@Override
public boolean isUpdateAliasSupported() {
return false;
}

@Override
public UpdateJoin getUpdateJoin() {
return new UpdateJoin(false, UpdateJoin.From.AS_JOIN);
}

@Override
public boolean isUpsertSupported() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@
import org.junit.jupiter.api.BeforeEach;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.*;
import java.io.Reader;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
Expand Down Expand Up @@ -244,6 +243,32 @@ protected static void initDatabase(Connection con) {
}
}

protected static void initDatabase(Connection conn, String name) {
final InputStream stream = AbstractTest.class.getClassLoader().getResourceAsStream(name);
if (stream == null) {
throw new IllegalStateException("Cannot load '" + name + "'");
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
String line;
StringBuilder sql = new StringBuilder();
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.isEmpty() || line.startsWith("--")) {
continue;
}
sql.append(line).append(" ");
if (line.endsWith(";")) {
try (Statement stmt = conn.createStatement()) {
stmt.executeUpdate(sql.toString());
sql.setLength(0);
}
}
}
} catch (IOException | SQLException e) {
e.printStackTrace();
}
}

protected void setAutoIds(Class<?> entityType, Object ... args) {
autoIdMap.put(entityType, new AutoIds(Arrays.asList(args.clone())));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ public static void assumeOracleDatabase() {
"123456"
);

public static final DataSource SQLITE_DATA_SOURCE =
new SimpleDriverDataSource(
new org.sqlite.JDBC(),
"jdbc:sqlite:./build/sqlite.db"
);

public static final DataSource ORACLE_DATA_SOURCE;

static {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package org.babyfish.jimmer.sql.sqlite;

import org.babyfish.jimmer.sql.JoinType;
import org.babyfish.jimmer.sql.common.AbstractMutationTest;
import org.babyfish.jimmer.sql.common.NativeDatabases;
import org.babyfish.jimmer.sql.dialect.SQLiteDialect;
import org.babyfish.jimmer.sql.exception.ExecutionException;
import org.babyfish.jimmer.sql.model.AuthorTableEx;
import org.babyfish.jimmer.sql.model.BookTable;
import org.babyfish.jimmer.sql.model.BookTableEx;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.babyfish.jimmer.sql.common.Constants.*;

public class SQLiteDMLTest extends AbstractMutationTest {
@BeforeAll
public static void beforeAll() {
jdbc(NativeDatabases.SQLITE_DATA_SOURCE, false, con -> initDatabase(con, "database-sqlite.sql"));
}

@Test
public void testUpdateJoinBySQLite() {
executeAndExpectRowCount(
NativeDatabases.SQLITE_DATA_SOURCE,
getLambdaClient(
it -> it.setDialect(new SQLiteDialect())
).createUpdate(AuthorTableEx.class, (u, author) -> {
u.set(author.firstName(), author.firstName().concat("*"));
u.where(author.books().store().name().eq("MANNING"));
}),
ctx -> {
ctx.statement(it -> {
it.sql(
"update AUTHOR " +
"set FIRST_NAME = concat(AUTHOR.FIRST_NAME, ?) " +
"from BOOK_AUTHOR_MAPPING tb_2_ " +
"inner join BOOK tb_3_ on tb_2_.BOOK_ID = tb_3_.ID " +
"inner join BOOK_STORE tb_4_ on " +
"tb_3_.STORE_ID = tb_4_.ID " +
"where " +
"AUTHOR.ID = tb_2_.AUTHOR_ID " +
"and " +
"tb_4_.NAME = ?"
);
it.variables("*", "MANNING");
});
}
);
}

@Test
public void testUpdateJoinByPostgresErrorByOuterJoin() {
executeAndExpectRowCount(
NativeDatabases.SQLITE_DATA_SOURCE,
getLambdaClient(
it -> it.setDialect(new SQLiteDialect())
).createUpdate(AuthorTableEx.class, (u, author) -> {
u.set(author.firstName(), author.firstName().concat("*"));
u.where(author.books(JoinType.LEFT).store().name().eq("MANNING"));
}),
ctx -> {
ctx.throwable(it -> {
it.type(ExecutionException.class);
it.message(
"The first level table joins cannot be outer join because current dialect " +
"'org.babyfish.jimmer.sql.dialect.SQLiteDialect' " +
"indicates that the first level table joins in update statement must be " +
"rendered as 'from' clause, but there is a first level table join whose " +
"join type is outer: 'Author.books(left)'."
);
});
}
);
}

@Test
public void testUpdateWithFilter() {
executeAndExpectRowCount(
NativeDatabases.SQLITE_DATA_SOURCE,
getLambdaClient(
it -> it.setDialect(new SQLiteDialect())
).createUpdate(BookTable.class, (u, book) -> {
u.set(book.name(), book.name().concat("*"));
u.where(book.name().ilike("Learning GraphQL"));
}),
ctx -> {
ctx.statement(it -> {
it.sql(
"update BOOK " +
"set NAME = concat(BOOK.NAME, ?) " +
"where lower(BOOK.NAME) like ?"
);
});
}
);
}

@Test
public void testDelete() {
executeAndExpectRowCount(
NativeDatabases.SQLITE_DATA_SOURCE,
getLambdaClient(
it -> it.setDialect(new SQLiteDialect())
).createDelete(BookTable.class, (d, book) -> {
d.where(book.name().eq("Learning GraphQL"));
d.disableDissociation();
}),
ctx -> {
ctx.statement(it -> {
it.sql("delete from BOOK where BOOK.NAME = ?");
it.variables("Learning GraphQL");
});
ctx.rowCount(3);
}
);
}

@Test
public void testDeleteWithJoin() {
executeAndExpectRowCount(
NativeDatabases.SQLITE_DATA_SOURCE,
getLambdaClient(
it -> it.setDialect(new SQLiteDialect())
).createDelete(BookTableEx.class, (d, book) -> {
d.where(book.store().name().eq("MANNING"));
}),
ctx -> {
ctx.statement(it -> {
it.sql(
"select distinct BOOK.ID " +
"from BOOK BOOK " +
"inner join BOOK_STORE tb_2_ on BOOK.STORE_ID = tb_2_.ID " +
"where tb_2_.NAME = ?"
);
it.variables("MANNING");
});
ctx.statement(it -> {
it.sql("delete from BOOK_AUTHOR_MAPPING where BOOK_ID in (?, ?, ?)");
it.unorderedVariables(graphQLInActionId1, graphQLInActionId2, graphQLInActionId3);
});
ctx.statement(it -> {
it.sql("delete from BOOK where ID in (?, ?, ?)");
it.unorderedVariables(graphQLInActionId1, graphQLInActionId2, graphQLInActionId3);
});
ctx.rowCount(6);
}
);
}
}
Loading

0 comments on commit 46adc20

Please sign in to comment.