# HG changeset patch # User František Kučera # Date 1387845535 -3600 # Node ID b4c74461d0f969189cb64e3d2a0182c8e9892f48 # Parent 28735e71a1daa9cf7538d114fb990706e9afe99e support named parameters diff -r 28735e71a1da -r b4c74461d0f9 java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java --- a/java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java Tue Dec 24 01:20:57 2013 +0100 +++ b/java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java Tue Dec 24 01:38:55 2013 +0100 @@ -87,7 +87,7 @@ arg = args[i]; if (arg.startsWith(options.getNamePrefix()) && arg.endsWith(options.getNameSuffix())) { // Named parameters: - String paramName = arg.substring(options.getNamePrefix().length()); + String paramName = arg.substring(options.getNamePrefix().length(), arg.length() - options.getNameSuffix().length()); String paramValue = fetchNext(args, ++i); options.addNamedParameter(new NamedParameter(paramName, paramValue, namedTypes.get(paramName))); } else { // Numbered parameters: diff -r 28735e71a1da -r b4c74461d0f9 java/sql-dk/src/info/globalcode/sql/dk/NamedParameter.java --- a/java/sql-dk/src/info/globalcode/sql/dk/NamedParameter.java Tue Dec 24 01:20:57 2013 +0100 +++ b/java/sql-dk/src/info/globalcode/sql/dk/NamedParameter.java Tue Dec 24 01:38:55 2013 +0100 @@ -17,11 +17,13 @@ */ package info.globalcode.sql.dk; +import info.globalcode.sql.dk.configuration.NameIdentified; + /** * * @author Ing. František Kučera (frantovo.cz) */ -public class NamedParameter extends Parameter { +public class NamedParameter extends Parameter implements NameIdentified { private String name; @@ -37,4 +39,9 @@ public void setName(String name) { this.name = name; } + + @Override + public String toString() { + return "NamedParameter {" + name + " = " + getValue() + "; " + getType() + "}"; + } } diff -r 28735e71a1da -r b4c74461d0f9 java/sql-dk/src/info/globalcode/sql/dk/SQLCommandNamed.java --- a/java/sql-dk/src/info/globalcode/sql/dk/SQLCommandNamed.java Tue Dec 24 01:20:57 2013 +0100 +++ b/java/sql-dk/src/info/globalcode/sql/dk/SQLCommandNamed.java Tue Dec 24 01:38:55 2013 +0100 @@ -17,9 +17,16 @@ */ package info.globalcode.sql.dk; +import static info.globalcode.sql.dk.Functions.notNull; +import static info.globalcode.sql.dk.Functions.escapeRegEx; +import static info.globalcode.sql.dk.Functions.findByName; +import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @@ -27,16 +34,87 @@ */ public class SQLCommandNamed extends SQLCommand { + private static final String PROBLEM_MARK = ""; + private String namePrefix; + private String nameSuffix; private List parameters; + private List parametersUsed = new ArrayList<>(); + private StringBuilder updatedQuery; + private Pattern pattern; - public SQLCommandNamed(String query, List parameters) { + public SQLCommandNamed(String query, List parameters, String namePrefix, String nameSuffix) { super(query); + this.updatedQuery = new StringBuilder(query.length()); this.parameters = parameters; + this.namePrefix = namePrefix; + this.nameSuffix = nameSuffix; + } + + @Override + public PreparedStatement prepareStatement(Connection c) throws SQLException { + buildPattern(); + placeParametersAndUpdateQuery(); + return c.prepareStatement(updatedQuery.toString()); } @Override public void parametrize(PreparedStatement ps) throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + int i = 1; + for (Parameter p : notNull(parametersUsed)) { + ps.setObject(i++, p.getValue(), p.getType()); + } + } + + /** + * Builds a regexp pattern that matches all parameter names (with prefix/suffix) and which has + * one group: parameter name (without prefix/suffix) + */ + private void buildPattern() { + StringBuilder patternString = new StringBuilder(); + + patternString.append(escapeRegEx(namePrefix)); + patternString.append("("); + for (int i = 0; i < parameters.size(); i++) { + patternString.append(escapeRegEx(parameters.get(i).getName())); + if (i < parameters.size()) { + patternString.append("|"); + } + } + patternString.append(")"); + patternString.append(escapeRegEx(nameSuffix)); + + pattern = Pattern.compile(patternString.toString()); + } + + private void placeParametersAndUpdateQuery() throws SQLException { + final String originalQuery = getQuery(); + Matcher m = pattern.matcher(originalQuery); + + int lastPosition = 0; + while (m.find(lastPosition)) { + String name = m.group(1); + + updatedQuery.append(originalQuery.substring(lastPosition, m.start())); + + if (name.isEmpty()) { + updatedQuery.append(PROBLEM_MARK); + updatedQuery.append(originalQuery.substring(m.end(), originalQuery.length())); + throw new SQLException("Named parameter (near " + PROBLEM_MARK + ") is not defined: " + updatedQuery); + } + + updatedQuery.append("?"); + + parametersUsed.add(findByName(parameters, name)); + + lastPosition = m.end(); + } + updatedQuery.append(originalQuery.substring(lastPosition, originalQuery.length())); + + for (NamedParameter definedParameter : parameters) { + if (findByName(parametersUsed, definedParameter.getName()) == null) { + throw new SQLException("Parameter " + definedParameter.getName() + " is defined but not used in the query."); + } + } } @Override