package org.geotools.sql; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.Date; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.geotools.util.logging.Logging; /** * Builder class for creating prepared statements. * * @author Justin Deoliveira, OpenGeo * */ public class SqlUtil { static final Logger LOGGER = Logging.getLogger(SqlUtil.class); public static class PreparedStatementBuilder { PreparedStatement ps; int pos = 1; StringBuilder log = new StringBuilder(); public PreparedStatementBuilder(PreparedStatement ps) throws SQLException { this.ps = ps; } public PreparedStatementBuilder(Connection conn, String sql) throws SQLException { this(conn.prepareStatement(sql)); log.append(sql); } public PreparedStatementBuilder set(Long l) throws SQLException { log(l); ps.setLong(pos++, l); return this; } public PreparedStatementBuilder set(Integer i) throws SQLException { log(i); if (i != null) { ps.setInt(pos++, i); } else { ps.setNull(pos++, Types.INTEGER); } return this; } public PreparedStatementBuilder set(Double d) throws SQLException { log(d); if (d != null) { ps.setDouble(pos++, d); } else { ps.setNull(pos++, Types.DOUBLE); } return this; } public PreparedStatementBuilder set(String s) throws SQLException { log(s); ps.setString(pos++, s); return this; } public PreparedStatementBuilder set(Boolean b) throws SQLException { log(b); ps.setBoolean(pos++, b); return this; } public PreparedStatementBuilder set(Date d) throws SQLException { log(d); ps.setDate(pos++, d != null ? new java.sql.Date(d.getTime()) : null); return this; } public PreparedStatementBuilder set(byte[] b) throws SQLException { log(b); ps.setBytes(pos++, b); //ps.setBinaryStream(pos++, is); return this; } public PreparedStatementBuilder log(Level l) { LOGGER.log(l, log.toString()); return this; } public PreparedStatement statement() { return ps; } void log(Object v) { log.append("\n").append(" ").append(pos).append(" = ").append(v); } } public static void runScript(InputStream stream, Connection cx) throws SQLException{ BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); Statement st = cx.createStatement(); try { StringBuilder buf = new StringBuilder(); String sql = reader.readLine(); while (sql != null) { sql = sql.trim(); if (!sql.isEmpty() && !sql.startsWith("--")) { buf.append(sql).append(" "); if (sql.endsWith(";")) { String stmt = buf.toString(); boolean skipError = stmt.startsWith("?"); if (skipError) { stmt = stmt.replaceAll("^\\? *" ,""); } LOGGER.fine(stmt); st.addBatch(stmt); buf.setLength(0); } } sql = reader.readLine(); } st.executeBatch(); } catch(IOException e) { throw new SQLException(e); } finally { try { stream.close(); } catch (IOException e) { LOGGER.log(Level.FINER, e.getMessage(), e); } try { st.close(); } catch (SQLException e) { LOGGER.log(Level.WARNING, "Error closing statement", e); } } } private static final Pattern PROPERTY_PATTERN = Pattern.compile("\\$\\{(.+?)\\}"); public static void runScript(InputStream stream, Connection cx, Map<String, String> properties) throws SQLException{ BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); Statement st = cx.createStatement(); int insideBlock = 0; try { StringBuilder buf = new StringBuilder(); String sql = reader.readLine(); while (sql != null) { sql = sql.trim(); if (!sql.isEmpty() && !sql.startsWith("--")) { buf.append(sql).append(" "); if (sql.startsWith("BEGIN")) { insideBlock++; } else if (insideBlock > 0 && sql.startsWith("END")) { insideBlock--; } if (sql.endsWith(";") && insideBlock==0) { Matcher matcher = PROPERTY_PATTERN.matcher(buf); while (matcher.find()) { String propertyName = matcher.group(1); String propertyValue = properties.get(propertyName); if (propertyValue == null) { throw new RuntimeException("Missing property " + propertyName + " for sql script"); } else { buf.replace(matcher.start(), matcher.end(), propertyValue); matcher.reset(); } } String stmt = buf.toString(); LOGGER.fine(stmt); st.addBatch(stmt); buf.setLength(0); } } sql = reader.readLine(); } st.executeBatch(); } catch(IOException e) { throw new SQLException(e); } finally { try { stream.close(); } catch (IOException e) { LOGGER.log(Level.FINER, e.getMessage(), e); } try { st.close(); } catch (SQLException e) { LOGGER.log(Level.WARNING, "Error closing statement", e); } } } public static PreparedStatementBuilder prepare(Connection conn, String sql) throws SQLException { return new PreparedStatementBuilder(conn, sql); } public static PreparedStatementBuilder prepare(PreparedStatement st) throws SQLException { return new PreparedStatementBuilder(st); } }