Initial commit
This commit is contained in:
19
src/main/java/at/compax/tools/sql/SqlExecutionException.java
Normal file
19
src/main/java/at/compax/tools/sql/SqlExecutionException.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package at.compax.tools.sql;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import at.compax.tools.sql.model.UserError;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SqlExecutionException extends Exception {
|
||||
private static final long serialVersionUID = 3684929762067312606L;
|
||||
|
||||
private final String message;
|
||||
private final List<UserError> userErrors;
|
||||
private Throwable cause;
|
||||
}
|
184
src/main/java/at/compax/tools/sql/SqlExecutor.java
Normal file
184
src/main/java/at/compax/tools/sql/SqlExecutor.java
Normal file
@@ -0,0 +1,184 @@
|
||||
package at.compax.tools.sql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
import at.compax.tools.sql.model.QueryParameter;
|
||||
import at.compax.tools.sql.model.QueryResult;
|
||||
import at.compax.tools.sql.model.QueryResult.QueryResultBuilder;
|
||||
import at.compax.tools.sql.model.QueryResult.Row;
|
||||
import at.compax.tools.sql.model.QueryResult.Row.Column;
|
||||
import at.compax.tools.sql.model.QueryResult.Row.Column.ColumnBuilder;
|
||||
import at.compax.tools.sql.model.QueryResult.Row.RowBuilder;
|
||||
import at.compax.tools.sql.model.Result;
|
||||
import at.compax.tools.sql.model.Result.ResultBuilder;
|
||||
import at.compax.tools.sql.model.UserError;
|
||||
import at.compax.tools.sql.model.UserError.MessageLine;
|
||||
import at.compax.tools.sql.model.UserError.UserErrorBuilder;
|
||||
import lombok.Cleanup;
|
||||
import lombok.extern.log4j.Log4j;
|
||||
|
||||
@Log4j
|
||||
public class SqlExecutor {
|
||||
public static Result execute(Connection conn, String sql) throws SQLException, JsonProcessingException {
|
||||
log.trace("SQL: " + sql.trim());
|
||||
|
||||
@Cleanup
|
||||
Statement stmt = conn.createStatement();
|
||||
|
||||
stmt.execute(sql.trim());
|
||||
log.info("Executed");
|
||||
|
||||
ResultBuilder resultBuilder = Result.builder();
|
||||
|
||||
try {
|
||||
handleUserErrors(conn, sql, stmt);
|
||||
} catch (SqlExecutionException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
resultBuilder.userErrors(e.getUserErrors());
|
||||
}
|
||||
|
||||
return resultBuilder.build();
|
||||
}
|
||||
|
||||
public static QueryResult executeQuery(Connection conn, QueryParameter parameters) throws SQLException {
|
||||
return executeQuery(conn, parameters.getSql(), parameters.getParameters());
|
||||
}
|
||||
|
||||
public static QueryResult executeQuery(Connection conn, String sql, Object... parameters) throws SQLException {
|
||||
log.trace("SQL: " + sql.trim());
|
||||
|
||||
@Cleanup
|
||||
PreparedStatement stmt = conn.prepareStatement(sql);
|
||||
|
||||
int parameterIndex = 1;
|
||||
for (Object object : parameters) {
|
||||
if (object instanceof String) {
|
||||
stmt.setString(parameterIndex++, (String) object);
|
||||
} else if (object instanceof Integer || object instanceof Long) {
|
||||
stmt.setLong(parameterIndex++, (Long) object);
|
||||
} else {
|
||||
String message = "Unhandled paramter type: " + object.getClass().getName();
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Cleanup
|
||||
ResultSet rs = null;
|
||||
QueryResultBuilder queryResultBuilder = QueryResult.builder();
|
||||
try {
|
||||
rs = stmt.executeQuery();
|
||||
} catch (SQLException e) {
|
||||
return queryResultBuilder //
|
||||
.exception(e.getClass().getName()) //
|
||||
.exceptionMessage(e.getMessage()) //
|
||||
.build();
|
||||
}
|
||||
|
||||
try {
|
||||
handleUserErrors(conn, sql, stmt);
|
||||
} catch (SqlExecutionException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
|
||||
return queryResultBuilder.userErrors(e.getUserErrors()).build();
|
||||
}
|
||||
|
||||
List<Row> rows = new Vector<Row>();
|
||||
while (rs.next()) {
|
||||
RowBuilder rowBuilder = Row.builder();
|
||||
List<Column> columns = new Vector<Column>();
|
||||
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
|
||||
for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
|
||||
ColumnBuilder columnBuilder = Column.builder();
|
||||
columnBuilder.name(metaData.getColumnLabel(columnIndex));
|
||||
|
||||
int columnType = metaData.getColumnType(columnIndex);
|
||||
if (columnType == Types.VARCHAR) {
|
||||
columnBuilder.value(rs.getString(columnIndex));
|
||||
} else if (columnType == Types.NUMERIC) {
|
||||
columnBuilder.value(rs.getLong(columnIndex));
|
||||
} else {
|
||||
String message = "Unhandled column type type: " + columnType;
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
|
||||
columns.add(columnBuilder.build());
|
||||
}
|
||||
|
||||
rowBuilder.columns(columns);
|
||||
rows.add(rowBuilder.build());
|
||||
}
|
||||
|
||||
return queryResultBuilder.rows(rows).build();
|
||||
}
|
||||
|
||||
private static void handleUserErrors(Connection conn, String sql, Statement stmt)
|
||||
throws SQLException, SqlExecutionException {
|
||||
SQLWarning warnings = stmt.getWarnings();
|
||||
List<UserError> userErrors = new Vector<UserError>();
|
||||
if (warnings != null) {
|
||||
userErrors = parseUserErrors(conn);
|
||||
String message = String.format("Errors while executing SQL \"%s\"", sql);
|
||||
throw new SqlExecutionException(message, userErrors);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<UserError> parseUserErrors(Connection conn) throws SQLException {
|
||||
String userErrorsSql = "select name, type, sequence, line, position, text, attribute, message_number from user_errors where type <> 'JAVA CLASS' order by sequence";
|
||||
boolean first = true;
|
||||
|
||||
Vector<UserError> userErrors = new Vector<UserError>();
|
||||
Vector<MessageLine> lines = new Vector<UserError.MessageLine>();
|
||||
|
||||
UserErrorBuilder builder = UserError.builder();
|
||||
|
||||
@Cleanup
|
||||
PreparedStatement userErrorsStmt = conn.prepareStatement(userErrorsSql);
|
||||
@Cleanup
|
||||
ResultSet userErrorsRs = userErrorsStmt.executeQuery();
|
||||
|
||||
while (userErrorsRs.next()) {
|
||||
long messageNumber = userErrorsRs.getLong("message_number");
|
||||
if (messageNumber != 0) {
|
||||
if (!first) {
|
||||
builder.lines(lines);
|
||||
userErrors.add(builder.build());
|
||||
first = false;
|
||||
|
||||
builder = UserError.builder();
|
||||
lines = new Vector<UserError.MessageLine>();
|
||||
}
|
||||
|
||||
builder.name(userErrorsRs.getString("name"));
|
||||
builder.type(userErrorsRs.getString("type"));
|
||||
}
|
||||
|
||||
lines.add(UserError.MessageLine.builder() //
|
||||
.sequence(userErrorsRs.getLong("sequence")) //
|
||||
.line(userErrorsRs.getLong("line")) //
|
||||
.position(userErrorsRs.getLong("position")) //
|
||||
.text(userErrorsRs.getString("text")) //
|
||||
.attribute(userErrorsRs.getString("attribute")) //
|
||||
.messageNumber(userErrorsRs.getLong("message_number")) //
|
||||
.build());
|
||||
}
|
||||
|
||||
builder.lines(lines);
|
||||
userErrors.add(builder.build());
|
||||
|
||||
return userErrors;
|
||||
}
|
||||
}
|
115
src/main/java/at/compax/tools/sql/main/Main.java
Normal file
115
src/main/java/at/compax/tools/sql/main/Main.java
Normal file
@@ -0,0 +1,115 @@
|
||||
package at.compax.tools.sql.main;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.log4j.BasicConfigurator;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.LogManager;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import at.compax.tools.sql.SqlExecutionException;
|
||||
import at.compax.tools.sql.SqlExecutor;
|
||||
import at.compax.tools.sql.model.QueryResult;
|
||||
import at.compax.tools.sql.model.Result;
|
||||
import at.compax.tools.sql.model.UserError;
|
||||
import lombok.Cleanup;
|
||||
import lombok.extern.log4j.Log4j;
|
||||
|
||||
@Log4j
|
||||
public class Main {
|
||||
|
||||
private static Connection getConnection(String dbIp, long port, String sid, String username, String password) {
|
||||
log.debug("Establishing conneciton...");
|
||||
Connection conn = null;
|
||||
|
||||
String jdbcConnection = String.format("jdbc:oracle:thin:@%s:%d:%s", dbIp, port, sid);
|
||||
|
||||
try {
|
||||
conn = DriverManager.getConnection(jdbcConnection, username, password);
|
||||
conn.setAutoCommit(false);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Couldn't connect to database", e);
|
||||
}
|
||||
|
||||
log.debug("Established conneciton!");
|
||||
return conn;
|
||||
}
|
||||
|
||||
private static QueryResult executeExampleQueryWithException(Connection conn)
|
||||
throws SQLException, JsonProcessingException {
|
||||
String sql = "SELECT id, version, workspac FROM s_settings";
|
||||
return SqlExecutor.executeQuery(conn, sql);
|
||||
}
|
||||
|
||||
private static QueryResult executeExampleQueryWithoutParameter(Connection conn)
|
||||
throws SQLException, JsonProcessingException {
|
||||
String sql = "SELECT id, version, workspace FROM s_settings";
|
||||
return SqlExecutor.executeQuery(conn, sql);
|
||||
}
|
||||
|
||||
private static QueryResult executeExampleQueryWithParameter(Connection conn)
|
||||
throws SQLException, JsonProcessingException {
|
||||
String sql = "select client from k_clients where id = ?";
|
||||
return SqlExecutor.executeQuery(conn, sql, 1L);
|
||||
}
|
||||
|
||||
private static Result compileExampleSpec(Connection conn) throws SQLException, JsonProcessingException {
|
||||
String specSql = "CREATE OR REPLACE PACKAGE aax2_wedel\n" + "AS\n"
|
||||
+ " PROCEDURE create_cli_migration_workflow(p_customer d_customers.id%type, p_migration_date date);\n"
|
||||
+ "END aax2_wedel;";
|
||||
|
||||
return SqlExecutor.execute(conn, specSql);
|
||||
}
|
||||
|
||||
private static Result compileExampleSpecWithErrors(Connection conn) throws SQLException, JsonProcessingException {
|
||||
String specSql = "CREATE OR REPLACE PACKAGE aax2_wedel\n" + "AS\n"
|
||||
+ " PROCEDURE create_cli_migration_workflow(p_customer d_customers.id%typ, p_migration_date date);\n"
|
||||
+ "END aax2_wedel;";
|
||||
|
||||
return SqlExecutor.execute(conn, specSql);
|
||||
}
|
||||
|
||||
private static void handleSqlExecutionException(SqlExecutionException e) throws JsonProcessingException {
|
||||
for (UserError userError : e.getUserErrors()) {
|
||||
log.debug(userError.toString());
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
System.out.println(mapper.writeValueAsString(userError));
|
||||
}
|
||||
}
|
||||
|
||||
private static String readFromStdIn() throws IOException {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
|
||||
String line;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
BasicConfigurator.configure();
|
||||
LogManager.getLogger("at.compax.tools.sql.main").setLevel(Level.ALL);
|
||||
LogManager.getLogger("at.compax.tools.sql").setLevel(Level.ALL);
|
||||
|
||||
// String stdInSql = readFromStdIn();
|
||||
|
||||
@Cleanup
|
||||
Connection conn = getConnection("172.19.13.66", 1521L, "aax2qc", "aax2qc", "aax2qc");
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
System.out.println(mapper.writeValueAsString(compileExampleSpec(conn)));
|
||||
System.out.println(mapper.writeValueAsString(compileExampleSpecWithErrors(conn)));
|
||||
System.out.println(mapper.writeValueAsString(executeExampleQueryWithException(conn)));
|
||||
System.out.println(mapper.writeValueAsString(executeExampleQueryWithoutParameter(conn)));
|
||||
System.out.println(mapper.writeValueAsString(executeExampleQueryWithParameter(conn)));
|
||||
}
|
||||
}
|
21
src/main/java/at/compax/tools/sql/model/QueryParameter.java
Normal file
21
src/main/java/at/compax/tools/sql/model/QueryParameter.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package at.compax.tools.sql.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
@ToString
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class QueryParameter {
|
||||
@JsonProperty("sql")
|
||||
private String sql;
|
||||
@JsonProperty("parameters")
|
||||
private List<Object> parameters;
|
||||
}
|
45
src/main/java/at/compax/tools/sql/model/QueryResult.java
Normal file
45
src/main/java/at/compax/tools/sql/model/QueryResult.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package at.compax.tools.sql.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@ToString
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class QueryResult {
|
||||
@Getter
|
||||
@Builder
|
||||
@ToString
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class Row {
|
||||
@Getter
|
||||
@Builder
|
||||
@ToString
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class Column {
|
||||
@JsonProperty("name")
|
||||
private String name;
|
||||
@JsonProperty("value")
|
||||
private Object value;
|
||||
}
|
||||
|
||||
@JsonProperty("columns")
|
||||
private List<Column> columns;
|
||||
}
|
||||
|
||||
@JsonProperty("rows")
|
||||
private List<Row> rows;
|
||||
@JsonProperty("userErrors")
|
||||
private List<UserError> userErrors;
|
||||
@JsonProperty("exception")
|
||||
private String exception;
|
||||
@JsonProperty("exceptionMessage")
|
||||
private String exceptionMessage;
|
||||
}
|
14
src/main/java/at/compax/tools/sql/model/Result.java
Normal file
14
src/main/java/at/compax/tools/sql/model/Result.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package at.compax.tools.sql.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
@ToString
|
||||
public class Result {
|
||||
private List<UserError> userErrors;
|
||||
}
|
41
src/main/java/at/compax/tools/sql/model/UserError.java
Normal file
41
src/main/java/at/compax/tools/sql/model/UserError.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package at.compax.tools.sql.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@ToString
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class UserError {
|
||||
@Getter
|
||||
@Builder
|
||||
@ToString
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class MessageLine {
|
||||
private Long sequence;
|
||||
@JsonProperty("line")
|
||||
private Long line;
|
||||
@JsonProperty("position")
|
||||
private Long position;
|
||||
@JsonProperty("text")
|
||||
private String text;
|
||||
@JsonProperty("attribute")
|
||||
private String attribute;
|
||||
private Long messageNumber;
|
||||
}
|
||||
|
||||
@JsonProperty("name")
|
||||
private String name;
|
||||
@JsonProperty("type")
|
||||
private String type;
|
||||
@JsonProperty("lines")
|
||||
private List<MessageLine> lines;
|
||||
|
||||
}
|
Reference in New Issue
Block a user