All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.sitebricks.persist.sql.Sql Maven / Gradle / Ivy

There is a newer version: 0.8.11
Show newest version
package com.google.sitebricks.persist.sql;

import com.google.common.collect.ImmutableMap;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A simplified API to execute SQL statements against. This is what the
 * EntityStore itself uses to manage the SQL interface. Use this as a low-level,
 * implementation-specific API, as needed.
 *
 * @author [email protected] (Dhanji R. Prasanna)
 */
public class Sql {
  static final Pattern NAMED_ARG_PATTERN = Pattern.compile("(@[\\w_]+)",
      Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
  private final Connection connection;

  public Sql(Connection connection) {
    this.connection = connection;
  }

  public void execute(String sql) {
    query(sql);
  }

  public void execute(String sql, Map params) {
    query(sql, params);
  }

  public ResultSet query(String sql) {
    return query(sql, ImmutableMap.of());
  }

  public ResultSet query(String sql, Map params) {
    try {
      Matcher matcher = Sql.NAMED_ARG_PATTERN.matcher(sql);

      Map positionalParams = toPositionalMap(params, matcher);

      matcher.reset();
      sql = matcher.replaceAll("?");

      PreparedStatement statement = connection.prepareStatement(sql);

      for (int i = 1; i <= positionalParams.size(); i++) {
        statement.setObject(i, positionalParams.get(i));
      }

      if (statement.execute())
        return statement.getResultSet();
      else {
        statement.close();
        return null;
      }

    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  static Map toPositionalMap(Map params, Matcher matcher) {
    boolean find = matcher.find();
    Map positionalParams = new HashMap();
    int index = 1;
    while (find) {
      Object value = params.get(matcher.group().substring(1));
      if (value == null) {
        throw new IllegalArgumentException("Named parameter map for SQL statement did" +
            " not contain required parameter: " + matcher.group());
      }

      positionalParams.put(index, value);
      find = matcher.find(matcher.end());
      index++;
    }
    return positionalParams;
  }

  public boolean tableExists(String name) {
    try {
      boolean exists = connection.getMetaData().getTables(null, null, name, null).next();

      // Try upper-case object name in case there is some provider-specific weirdness.
      if (!exists)
        return connection.getMetaData().getTables(null, null, name.toUpperCase(), null).next();
      else
        return exists;
    } catch (SQLException e) {
      throw new RuntimeException(e);
    }
  }

  public List> list(String sql) {
    return list(sql, ImmutableMap.of());
  }

  public List> list(String sql, Map params) {
    ResultSet resultSet = query(sql, params);

    try {
      ResultSetMetaData metaData = resultSet.getMetaData();
      List> list = new ArrayList>();
      int count = metaData.getColumnCount();

      while (resultSet.next()) {
        Map row = new HashMap();
        for (int i = 1; i <= count; i++) {
          String column = metaData.getColumnName(i).toLowerCase();

          row.put(column, resultSet.getObject(column));
        }

        list.add(row);
      }

      return list;
    } catch (SQLException e) {
      throw new RuntimeException(e);
    } finally {
      try {
        resultSet.close();
      } catch (SQLException e) {
        // This is bad! Log it everywhere possible.
        e.printStackTrace(System.err);
        LoggerFactory.getLogger(SqlPersister.class).error("Unable to release SQL connection", e);
      }
    }
  }

  /**
   * Returns the current underlying JDBC connection.
   */
  public Connection connection() {
    return connection;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy