3 * Copyright © 2013 František Kučera (frantovo.cz)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package info.globalcode.sql.dk;
20 import static info.globalcode.sql.dk.Functions.notNull;
21 import static info.globalcode.sql.dk.Functions.escapeRegEx;
22 import static info.globalcode.sql.dk.Functions.findByName;
23 import java.sql.Connection;
24 import java.sql.PreparedStatement;
25 import java.sql.SQLException;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
33 * @author Ing. František Kučera (frantovo.cz)
35 public class SQLCommandNamed extends SQLCommand {
37 private static final String PROBLEM_MARK = "<OMG>";
38 private String namePrefix;
39 private String nameSuffix;
40 private List<NamedParameter> parameters;
41 private List<NamedParameter> parametersUsed = new ArrayList<>();
42 private StringBuilder updatedQuery;
43 private Pattern pattern;
45 public SQLCommandNamed(String query, List<NamedParameter> parameters, String namePrefix, String nameSuffix) {
47 this.updatedQuery = new StringBuilder(query.length());
48 this.parameters = parameters;
49 this.namePrefix = namePrefix;
50 this.nameSuffix = nameSuffix;
54 public PreparedStatement prepareStatement(Connection c) throws SQLException {
56 placeParametersAndUpdateQuery();
57 return c.prepareStatement(updatedQuery.toString());
61 public void parametrize(PreparedStatement ps) throws SQLException {
63 for (Parameter p : notNull(parametersUsed)) {
64 ps.setObject(i++, p.getValue(), p.getType());
69 * Builds a regexp pattern that matches all parameter names (with prefix/suffix) and which has
70 * one group: parameter name (without prefix/suffix)
72 private void buildPattern() {
73 StringBuilder patternString = new StringBuilder();
75 patternString.append(escapeRegEx(namePrefix));
76 patternString.append("(");
77 for (int i = 0; i < parameters.size(); i++) {
78 patternString.append(escapeRegEx(parameters.get(i).getName()));
79 if (i < parameters.size()) {
80 patternString.append("|");
83 patternString.append(")");
84 patternString.append(escapeRegEx(nameSuffix));
86 pattern = Pattern.compile(patternString.toString());
89 private void placeParametersAndUpdateQuery() throws SQLException {
90 final String originalQuery = getQuery();
91 Matcher m = pattern.matcher(originalQuery);
94 while (m.find(lastPosition)) {
95 String name = m.group(1);
97 updatedQuery.append(originalQuery.substring(lastPosition, m.start()));
100 updatedQuery.append(PROBLEM_MARK);
101 updatedQuery.append(originalQuery.substring(m.end(), originalQuery.length()));
102 throw new SQLException("Named parameter (near " + PROBLEM_MARK + ") is not defined: " + updatedQuery);
105 updatedQuery.append("?");
107 parametersUsed.add(findByName(parameters, name));
109 lastPosition = m.end();
111 updatedQuery.append(originalQuery.substring(lastPosition, originalQuery.length()));
113 for (NamedParameter definedParameter : parameters) {
114 if (findByName(parametersUsed, definedParameter.getName()) == null) {
115 throw new SQLException("Parameter " + definedParameter.getName() + " is defined but not used in the query.");
121 public List<NamedParameter> getParameters() {