[Metadata] [Editor] Supports transactions to execute multiple non-query SQL (#458)

This commit is contained in:
qianmoQ 2023-10-30 13:17:08 +08:00 committed by GitHub
commit 92ec4338d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 127 additions and 69 deletions

View File

@ -127,6 +127,8 @@ public class SqlBuilder
if (configure.getWhere() != null) {
UpdateBuilder.WHERE(applyUpdateWhere());
}
UpdateBuilder.END();
return UpdateBuilder.SQL();
}
@ -143,6 +145,8 @@ public class SqlBuilder
if (configure.getWhere() != null) {
DeleteBuilder.WHERE(applyUpdateWhere());
}
DeleteBuilder.END();
return DeleteBuilder.SQL();
}
}

View File

@ -403,6 +403,12 @@ abstract class BaseAbstractBuilder<T>
return getSelf();
}
public T END()
{
sql().end = true;
return getSelf();
}
private SQLStatement sql()
{
return sql;
@ -513,6 +519,7 @@ abstract class BaseAbstractBuilder<T>
List<String> columns = new ArrayList<>();
List<List<String>> valuesList = new ArrayList<>();
boolean distinct;
boolean end;
String offset;
String limit;
LimitingRowsStrategy limitingRowsStrategy = LimitingRowsStrategy.NOP;
@ -580,6 +587,9 @@ abstract class BaseAbstractBuilder<T>
for (int i = 0; i < valuesList.size(); i++) {
sqlClause(builder, i > 0 ? "," : "VALUES", valuesList.get(i), "(", ")", ", ");
}
if (end) {
builder.append(";");
}
return builder.toString();
}
@ -588,6 +598,9 @@ abstract class BaseAbstractBuilder<T>
sqlClause(builder, "DELETE FROM", tables, "", "", "");
sqlClause(builder, "WHERE", where, "(", ")", " AND ");
limitingRowsStrategy.appendClause(builder, null, limit);
if (end) {
builder.append(";");
}
return builder.toString();
}
@ -598,6 +611,9 @@ abstract class BaseAbstractBuilder<T>
sqlClause(builder, "SET", sets, "", "", ", ");
sqlClause(builder, "WHERE", where, "(", ")", " AND ");
limitingRowsStrategy.appendClause(builder, null, limit);
if (end) {
builder.append(";");
}
return builder.toString();
}

View File

@ -5,7 +5,7 @@ import java.util.List;
public class DeleteBuilder
{
private static final ThreadLocal<BaseBuilder> localSQL = new ThreadLocal<>();
private static String symbol = " OR ";
private static String symbol = " AND ";
static {
BEGIN();
@ -40,6 +40,11 @@ public class DeleteBuilder
sql().WHERE(String.join(symbol, conditions));
}
public static void END()
{
sql().END();
}
public static String SQL()
{
try {

View File

@ -60,9 +60,15 @@ public class UpdateBuilder
sql().AND();
}
public static void END()
{
sql().END();
}
public static String SQL()
{
try {
sql().END();
return sql().toString();
}
finally {

View File

@ -180,33 +180,22 @@ public class TableServiceImpl
Configure updateConfigure = source.toConfigure();
updateConfigure.setFormat(FormatType.NONE);
plugin.connect(updateConfigure);
SqlBody body = SqlBody.builder()
.type(SqlType.UPDATE)
.database(table.getDatabase().getName())
.table(table.getName())
.columns(configure.getColumns())
.where(applyColumns(table, configure).stream()
.distinct()
.collect(Collectors.toList()))
.build();
String sql = new SqlBuilder(body).getSql();
Response response;
if (configure.isPreview()) {
response = Response.builder()
.isSuccessful(true)
.isConnected(true)
.headers(Lists.newArrayList())
.columns(Lists.newArrayList())
.types(Lists.newArrayList())
.content(sql)
List<String> allSql = Lists.newArrayList();
configure.getColumns().forEach(v -> {
SqlBody body = SqlBody.builder()
.type(SqlType.UPDATE)
.database(table.getDatabase().getName())
.table(table.getName())
.columns(Arrays.asList(v))
.where(applyColumns(table, configure, v)
.stream()
.distinct()
.collect(Collectors.toList()))
.build();
}
else {
response = plugin.execute(sql);
plugin.destroy();
response.setContent(sql);
}
return CommonResponse.success(response);
allSql.add(new SqlBuilder(body).getSql());
});
String sql = String.join("\n\n", allSql);
return CommonResponse.success(getResponse(configure, plugin, sql));
}
catch (Exception ex) {
return CommonResponse.failure(ExceptionUtils.getMessage(ex));
@ -228,37 +217,33 @@ public class TableServiceImpl
Configure updateConfigure = source.toConfigure();
updateConfigure.setFormat(FormatType.NONE);
plugin.connect(updateConfigure);
SqlBody body = SqlBody.builder()
.type(SqlType.DELETE)
.database(table.getDatabase().getName())
.table(table.getName())
.where(applyColumns(table, configure))
.build();
String sql = new SqlBuilder(body).getSql();
Response response;
if (configure.isPreview()) {
response = Response.builder()
.isSuccessful(true)
.isConnected(true)
.headers(Lists.newArrayList())
.columns(Lists.newArrayList())
.types(Lists.newArrayList())
.content(sql)
List<String> allSql = Lists.newArrayList();
configure.getColumns().forEach(v -> {
SqlBody body = SqlBody.builder()
.type(SqlType.DELETE)
.database(table.getDatabase().getName())
.table(table.getName())
.where(applyColumns(table, configure, v))
.build();
}
else {
response = plugin.execute(sql);
plugin.destroy();
response.setContent(sql);
}
return CommonResponse.success(response);
allSql.add(new SqlBuilder(body).getSql());
});
String sql = String.join("\n\n", allSql);
return CommonResponse.success(getResponse(configure, plugin, sql));
}
catch (Exception ex) {
return CommonResponse.failure(ExceptionUtils.getMessage(ex));
}
}
private List<SqlColumn> applyColumns(TableEntity table, TableFilter configure)
/**
* Applies the columns of a table to a given configuration.
*
* @param table the table entity containing the columns
* @param configure the table filter configuration to apply the columns to
* @param column the SQL column to apply
* @return a list of SQL columns that match the applied configuration
*/
private List<SqlColumn> applyColumns(TableEntity table, TableFilter configure, SqlColumn column)
{
List<SqlColumn> wheres = Lists.newArrayList();
List<ColumnEntity> originColumns = table.getColumns()
@ -267,25 +252,50 @@ public class TableServiceImpl
.collect(Collectors.toList());
if (originColumns.size() > 0) {
// If the table contains a primary key, update the data using the primary key as a condition
originColumns.forEach(item -> configure.getColumns()
.stream()
.forEach(v -> wheres.add(SqlColumn.builder()
.column(item.getName())
.operator(SqlOperator.EQ)
.value(String.valueOf(v.getOriginal().get(item.getName())))
.build())));
originColumns.forEach(item -> wheres.add(SqlColumn.builder()
.column(item.getName())
.operator(SqlOperator.EQ)
.value(String.valueOf(column.getOriginal().get(item.getName())))
.build()));
}
else {
// If the current data does not have a primary key, it is updated based on all data columns
table.getColumns()
.forEach(item -> configure.getColumns()
.stream()
.forEach(v -> wheres.add(SqlColumn.builder()
.column(item.getName())
.operator(SqlOperator.EQ)
.value(String.valueOf(v.getOriginal().get(item.getName())))
.build())));
.forEach(item -> wheres.add(SqlColumn.builder()
.column(item.getName())
.operator(SqlOperator.EQ)
.value(String.valueOf(column.getOriginal().get(item.getName())))
.build()));
}
return wheres;
}
/**
* Retrieves a response based on the provided table filter, plugin, and SQL query.
*
* @param configure the table filter to configure the response
* @param plugin the plugin to execute the SQL query
* @param sql the SQL query to execute
* @return the response containing the result of the SQL query
*/
private Response getResponse(TableFilter configure, Plugin plugin, String sql)
{
Response response;
if (configure.isPreview()) {
response = Response.builder()
.isSuccessful(true)
.isConnected(true)
.headers(Lists.newArrayList())
.columns(Lists.newArrayList())
.types(Lists.newArrayList())
.content(sql)
.build();
}
else {
response = plugin.execute(sql);
plugin.destroy();
response.setContent(sql);
}
return response;
}
}

View File

@ -11,10 +11,10 @@ import io.edurt.datacap.spi.model.Time;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -47,11 +47,11 @@ public class JdbcAdapter
Connection connection = (Connection) this.jdbcConnection.getConnection();
JdbcConfigure configure = (JdbcConfigure) this.jdbcConnection.getConfigure();
if (response.getIsConnected()) {
try (PreparedStatement statement = connection.prepareStatement(content)) {
try (Statement statement = connection.createStatement()) {
List<String> headers = new ArrayList<>();
List<String> types = new ArrayList<>();
List<Object> columns = new ArrayList<>();
try (ResultSet resultSet = statement.executeQuery()) {
try (ResultSet resultSet = statement.executeQuery(content)) {
boolean isPresent = true;
JdbcColumn jdbcColumn = new JdbcColumn(resultSet);
while (resultSet.next()) {
@ -75,10 +75,27 @@ public class JdbcAdapter
headers.add("result");
types.add(Integer.class.getSimpleName());
List<Object> _columns = new ArrayList<>();
_columns.add(statement.executeUpdate());
connection.setAutoCommit(false);
String[] parts = content.replaceAll("[\\r\\n|\\r|\\n]+", " ")
.split("(?<=\\);)|(?<=\\r\\n)|(?<=\\r)|(?<=\\n)|(?<=\\n;)|(?<=\\r;)|(?<=\\r\\n;)|(?<=;)");
int count = 0;
for (String part : parts) {
if (!part.trim().isEmpty()) {
count += statement.executeUpdate(part);
}
}
_columns.add(count);
connection.commit();
columns.add(handlerFormatter(configure.getFormat(), headers, _columns));
}
catch (SQLException updateEx) {
try {
connection.rollback();
}
catch (SQLException rollbackEx) {
log.error("Rollback failed ", rollbackEx);
throw new SQLException(rollbackEx);
}
throw new SQLException(updateEx);
}
}