Initial commit

This commit is contained in:
2017-10-30 10:14:05 +01:00
parent cfa1e0eac6
commit 4b39af8eb9
14 changed files with 625 additions and 0 deletions

View 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;
}

View 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;
}
}

View 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)));
}
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}