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
+ true
+ true
+
+ **/*Test.java
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${compiler.plugin.version}
+
+
+ 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