1.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/SQLCommandNamed.java Tue Dec 24 01:20:57 2013 +0100
1.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/SQLCommandNamed.java Tue Dec 24 01:38:55 2013 +0100
1.3 @@ -17,9 +17,16 @@
1.4 */
1.5 package info.globalcode.sql.dk;
1.6
1.7 +import static info.globalcode.sql.dk.Functions.notNull;
1.8 +import static info.globalcode.sql.dk.Functions.escapeRegEx;
1.9 +import static info.globalcode.sql.dk.Functions.findByName;
1.10 +import java.sql.Connection;
1.11 import java.sql.PreparedStatement;
1.12 import java.sql.SQLException;
1.13 +import java.util.ArrayList;
1.14 import java.util.List;
1.15 +import java.util.regex.Matcher;
1.16 +import java.util.regex.Pattern;
1.17
1.18 /**
1.19 *
1.20 @@ -27,16 +34,87 @@
1.21 */
1.22 public class SQLCommandNamed extends SQLCommand {
1.23
1.24 + private static final String PROBLEM_MARK = "<OMG>";
1.25 + private String namePrefix;
1.26 + private String nameSuffix;
1.27 private List<NamedParameter> parameters;
1.28 + private List<NamedParameter> parametersUsed = new ArrayList<>();
1.29 + private StringBuilder updatedQuery;
1.30 + private Pattern pattern;
1.31
1.32 - public SQLCommandNamed(String query, List<NamedParameter> parameters) {
1.33 + public SQLCommandNamed(String query, List<NamedParameter> parameters, String namePrefix, String nameSuffix) {
1.34 super(query);
1.35 + this.updatedQuery = new StringBuilder(query.length());
1.36 this.parameters = parameters;
1.37 + this.namePrefix = namePrefix;
1.38 + this.nameSuffix = nameSuffix;
1.39 + }
1.40 +
1.41 + @Override
1.42 + public PreparedStatement prepareStatement(Connection c) throws SQLException {
1.43 + buildPattern();
1.44 + placeParametersAndUpdateQuery();
1.45 + return c.prepareStatement(updatedQuery.toString());
1.46 }
1.47
1.48 @Override
1.49 public void parametrize(PreparedStatement ps) throws SQLException {
1.50 - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1.51 + int i = 1;
1.52 + for (Parameter p : notNull(parametersUsed)) {
1.53 + ps.setObject(i++, p.getValue(), p.getType());
1.54 + }
1.55 + }
1.56 +
1.57 + /**
1.58 + * Builds a regexp pattern that matches all parameter names (with prefix/suffix) and which has
1.59 + * one group: parameter name (without prefix/suffix)
1.60 + */
1.61 + private void buildPattern() {
1.62 + StringBuilder patternString = new StringBuilder();
1.63 +
1.64 + patternString.append(escapeRegEx(namePrefix));
1.65 + patternString.append("(");
1.66 + for (int i = 0; i < parameters.size(); i++) {
1.67 + patternString.append(escapeRegEx(parameters.get(i).getName()));
1.68 + if (i < parameters.size()) {
1.69 + patternString.append("|");
1.70 + }
1.71 + }
1.72 + patternString.append(")");
1.73 + patternString.append(escapeRegEx(nameSuffix));
1.74 +
1.75 + pattern = Pattern.compile(patternString.toString());
1.76 + }
1.77 +
1.78 + private void placeParametersAndUpdateQuery() throws SQLException {
1.79 + final String originalQuery = getQuery();
1.80 + Matcher m = pattern.matcher(originalQuery);
1.81 +
1.82 + int lastPosition = 0;
1.83 + while (m.find(lastPosition)) {
1.84 + String name = m.group(1);
1.85 +
1.86 + updatedQuery.append(originalQuery.substring(lastPosition, m.start()));
1.87 +
1.88 + if (name.isEmpty()) {
1.89 + updatedQuery.append(PROBLEM_MARK);
1.90 + updatedQuery.append(originalQuery.substring(m.end(), originalQuery.length()));
1.91 + throw new SQLException("Named parameter (near " + PROBLEM_MARK + ") is not defined: " + updatedQuery);
1.92 + }
1.93 +
1.94 + updatedQuery.append("?");
1.95 +
1.96 + parametersUsed.add(findByName(parameters, name));
1.97 +
1.98 + lastPosition = m.end();
1.99 + }
1.100 + updatedQuery.append(originalQuery.substring(lastPosition, originalQuery.length()));
1.101 +
1.102 + for (NamedParameter definedParameter : parameters) {
1.103 + if (findByName(parametersUsed, definedParameter.getName()) == null) {
1.104 + throw new SQLException("Parameter " + definedParameter.getName() + " is defined but not used in the query.");
1.105 + }
1.106 + }
1.107 }
1.108
1.109 @Override