From 4b39af8eb95c7b20ea64f8c15aba4305b5ee369a Mon Sep 17 00:00:00 2001 From: Zoran Zaric Date: Mon, 30 Oct 2017 10:14:05 +0100 Subject: [PATCH] Initial commit --- .classpath | 36 ++++ .project | 23 +++ .settings/org.eclipse.core.resources.prefs | 6 + .settings/org.eclipse.jdt.core.prefs | 5 + .settings/org.eclipse.m2e.core.prefs | 4 + .settings/org.jboss.ide.eclipse.as.core.prefs | 2 + pom.xml | 110 +++++++++++ .../tools/sql/SqlExecutionException.java | 19 ++ .../java/at/compax/tools/sql/SqlExecutor.java | 184 ++++++++++++++++++ .../java/at/compax/tools/sql/main/Main.java | 115 +++++++++++ .../tools/sql/model/QueryParameter.java | 21 ++ .../compax/tools/sql/model/QueryResult.java | 45 +++++ .../at/compax/tools/sql/model/Result.java | 14 ++ .../at/compax/tools/sql/model/UserError.java | 41 ++++ 14 files changed, 625 insertions(+) create mode 100644 .classpath create mode 100644 .project create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 .settings/org.jboss.ide.eclipse.as.core.prefs create mode 100644 pom.xml create mode 100644 src/main/java/at/compax/tools/sql/SqlExecutionException.java create mode 100644 src/main/java/at/compax/tools/sql/SqlExecutor.java create mode 100644 src/main/java/at/compax/tools/sql/main/Main.java create mode 100644 src/main/java/at/compax/tools/sql/model/QueryParameter.java create mode 100644 src/main/java/at/compax/tools/sql/model/QueryResult.java create mode 100644 src/main/java/at/compax/tools/sql/model/Result.java create mode 100644 src/main/java/at/compax/tools/sql/model/UserError.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..e43402f --- /dev/null +++ b/.classpath @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..6b57791 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + frog-runner + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..29abf99 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..ec4300d --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/.settings/org.jboss.ide.eclipse.as.core.prefs b/.settings/org.jboss.ide.eclipse.as.core.prefs new file mode 100644 index 0000000..cf3aa3a --- /dev/null +++ b/.settings/org.jboss.ide.eclipse.as.core.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.jboss.ide.eclipse.as.core.singledeployable.deployableList= diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..e5a666b --- /dev/null +++ b/pom.xml @@ -0,0 +1,110 @@ + + 4.0.0 + at.compax.tools + frog-runner + 0.0.1-SNAPSHOT + + UTF-8 + + + 2.3.2 + 2.9 + + 2.5 + 3.6.8.Final + 4.8.2 + 1.2.14 + 1.16.18 + 1.8.5 + 2.0-cr-1 + 11.2.0.2.0 + 2.5.0 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.version} + true + + 1.7 + 1.7 + true + true + + **/*Test.java + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${compiler.plugin.version} + + 1.7 + 1.7 + + + + + + + + oracle + ojdbc6 + ${oracleDriver.version} + compile + + + org.projectlombok + lombok + ${lombok.version} + compile + + + log4j + log4j + ${log4j.version} + jar + compile + + + com.fasterxml.jackson.core + jackson-databind + 2.8.4 + + + junit + junit + ${junit.version} + test + + + + + + public + http://nexus.int.compax.at:8081/nexus/content/groups/public/ + + + compax + http://nexus.int.compax.at:8081/nexus/content/repositories/compax + + + + + compax-snapshot + http://nexus.int.compax.at:8081/nexus/content/repositories/compax-snapshot + + + + + compax-thirdparty + http://nexus.int.compax.at:8081/nexus/content/repositories/thirdparty + + + \ No newline at end of file diff --git a/src/main/java/at/compax/tools/sql/SqlExecutionException.java b/src/main/java/at/compax/tools/sql/SqlExecutionException.java new file mode 100644 index 0000000..9f25d1a --- /dev/null +++ b/src/main/java/at/compax/tools/sql/SqlExecutionException.java @@ -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 userErrors; + private Throwable cause; +} diff --git a/src/main/java/at/compax/tools/sql/SqlExecutor.java b/src/main/java/at/compax/tools/sql/SqlExecutor.java new file mode 100644 index 0000000..472d9fd --- /dev/null +++ b/src/main/java/at/compax/tools/sql/SqlExecutor.java @@ -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 rows = new Vector(); + while (rs.next()) { + RowBuilder rowBuilder = Row.builder(); + List columns = new Vector(); + + 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 userErrors = new Vector(); + if (warnings != null) { + userErrors = parseUserErrors(conn); + String message = String.format("Errors while executing SQL \"%s\"", sql); + throw new SqlExecutionException(message, userErrors); + } + } + + private static List 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 userErrors = new Vector(); + Vector lines = new Vector(); + + 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(); + } + + 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; + } +} diff --git a/src/main/java/at/compax/tools/sql/main/Main.java b/src/main/java/at/compax/tools/sql/main/Main.java new file mode 100644 index 0000000..7b68bd5 --- /dev/null +++ b/src/main/java/at/compax/tools/sql/main/Main.java @@ -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))); + } +} diff --git a/src/main/java/at/compax/tools/sql/model/QueryParameter.java b/src/main/java/at/compax/tools/sql/model/QueryParameter.java new file mode 100644 index 0000000..5aefa42 --- /dev/null +++ b/src/main/java/at/compax/tools/sql/model/QueryParameter.java @@ -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 parameters; +} diff --git a/src/main/java/at/compax/tools/sql/model/QueryResult.java b/src/main/java/at/compax/tools/sql/model/QueryResult.java new file mode 100644 index 0000000..5d68dda --- /dev/null +++ b/src/main/java/at/compax/tools/sql/model/QueryResult.java @@ -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 columns; + } + + @JsonProperty("rows") + private List rows; + @JsonProperty("userErrors") + private List userErrors; + @JsonProperty("exception") + private String exception; + @JsonProperty("exceptionMessage") + private String exceptionMessage; +} diff --git a/src/main/java/at/compax/tools/sql/model/Result.java b/src/main/java/at/compax/tools/sql/model/Result.java new file mode 100644 index 0000000..681a589 --- /dev/null +++ b/src/main/java/at/compax/tools/sql/model/Result.java @@ -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 userErrors; +} diff --git a/src/main/java/at/compax/tools/sql/model/UserError.java b/src/main/java/at/compax/tools/sql/model/UserError.java new file mode 100644 index 0000000..ac71a9d --- /dev/null +++ b/src/main/java/at/compax/tools/sql/model/UserError.java @@ -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 lines; + +}