franta-hg@16: /** franta-hg@16: * SQL-DK franta-hg@16: * Copyright © 2013 František Kučera (frantovo.cz) franta-hg@16: * franta-hg@16: * This program is free software: you can redistribute it and/or modify franta-hg@16: * it under the terms of the GNU General Public License as published by franta-hg@16: * the Free Software Foundation, either version 3 of the License, or franta-hg@16: * (at your option) any later version. franta-hg@16: * franta-hg@16: * This program is distributed in the hope that it will be useful, franta-hg@16: * but WITHOUT ANY WARRANTY; without even the implied warranty of franta-hg@16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the franta-hg@16: * GNU General Public License for more details. franta-hg@16: * franta-hg@16: * You should have received a copy of the GNU General Public License franta-hg@16: * along with this program. If not, see . franta-hg@16: */ franta-hg@1: package info.globalcode.sql.dk; franta-hg@1: franta-hg@49: import static info.globalcode.sql.dk.Functions.notNull; franta-hg@49: import static info.globalcode.sql.dk.Functions.escapeRegEx; franta-hg@49: import static info.globalcode.sql.dk.Functions.findByName; franta-hg@49: import java.sql.Connection; franta-hg@1: import java.sql.PreparedStatement; franta-hg@34: import java.sql.SQLException; franta-hg@49: import java.util.ArrayList; franta-hg@34: import java.util.List; franta-hg@49: import java.util.regex.Matcher; franta-hg@49: import java.util.regex.Pattern; franta-hg@1: franta-hg@1: /** franta-hg@1: * franta-hg@1: * @author Ing. František Kučera (frantovo.cz) franta-hg@1: */ franta-hg@1: public class SQLCommandNamed extends SQLCommand { franta-hg@1: franta-hg@49: private static final String PROBLEM_MARK = ""; franta-hg@49: private String namePrefix; franta-hg@49: private String nameSuffix; franta-hg@34: private List parameters; franta-hg@49: private List parametersUsed = new ArrayList<>(); franta-hg@49: private StringBuilder updatedQuery; franta-hg@49: private Pattern pattern; franta-hg@34: franta-hg@49: public SQLCommandNamed(String query, List parameters, String namePrefix, String nameSuffix) { franta-hg@37: super(query); franta-hg@49: this.updatedQuery = new StringBuilder(query.length()); franta-hg@34: this.parameters = parameters; franta-hg@49: this.namePrefix = namePrefix; franta-hg@49: this.nameSuffix = nameSuffix; franta-hg@49: } franta-hg@49: franta-hg@49: @Override franta-hg@49: public PreparedStatement prepareStatement(Connection c) throws SQLException { franta-hg@49: buildPattern(); franta-hg@49: placeParametersAndUpdateQuery(); franta-hg@49: return c.prepareStatement(updatedQuery.toString()); franta-hg@34: } franta-hg@34: franta-hg@1: @Override franta-hg@34: public void parametrize(PreparedStatement ps) throws SQLException { franta-hg@49: int i = 1; franta-hg@49: for (Parameter p : notNull(parametersUsed)) { franta-hg@49: ps.setObject(i++, p.getValue(), p.getType()); franta-hg@49: } franta-hg@49: } franta-hg@49: franta-hg@49: /** franta-hg@49: * Builds a regexp pattern that matches all parameter names (with prefix/suffix) and which has franta-hg@49: * one group: parameter name (without prefix/suffix) franta-hg@49: */ franta-hg@49: private void buildPattern() { franta-hg@49: StringBuilder patternString = new StringBuilder(); franta-hg@49: franta-hg@49: patternString.append(escapeRegEx(namePrefix)); franta-hg@49: patternString.append("("); franta-hg@49: for (int i = 0; i < parameters.size(); i++) { franta-hg@49: patternString.append(escapeRegEx(parameters.get(i).getName())); franta-hg@49: if (i < parameters.size()) { franta-hg@49: patternString.append("|"); franta-hg@49: } franta-hg@49: } franta-hg@49: patternString.append(")"); franta-hg@49: patternString.append(escapeRegEx(nameSuffix)); franta-hg@49: franta-hg@49: pattern = Pattern.compile(patternString.toString()); franta-hg@49: } franta-hg@49: franta-hg@49: private void placeParametersAndUpdateQuery() throws SQLException { franta-hg@49: final String originalQuery = getQuery(); franta-hg@49: Matcher m = pattern.matcher(originalQuery); franta-hg@49: franta-hg@49: int lastPosition = 0; franta-hg@49: while (m.find(lastPosition)) { franta-hg@49: String name = m.group(1); franta-hg@49: franta-hg@49: updatedQuery.append(originalQuery.substring(lastPosition, m.start())); franta-hg@49: franta-hg@49: if (name.isEmpty()) { franta-hg@49: updatedQuery.append(PROBLEM_MARK); franta-hg@49: updatedQuery.append(originalQuery.substring(m.end(), originalQuery.length())); franta-hg@49: throw new SQLException("Named parameter (near " + PROBLEM_MARK + ") is not defined: " + updatedQuery); franta-hg@49: } franta-hg@49: franta-hg@49: updatedQuery.append("?"); franta-hg@49: franta-hg@49: parametersUsed.add(findByName(parameters, name)); franta-hg@49: franta-hg@49: lastPosition = m.end(); franta-hg@49: } franta-hg@49: updatedQuery.append(originalQuery.substring(lastPosition, originalQuery.length())); franta-hg@49: franta-hg@49: for (NamedParameter definedParameter : parameters) { franta-hg@49: if (findByName(parametersUsed, definedParameter.getName()) == null) { franta-hg@49: throw new SQLException("Parameter " + definedParameter.getName() + " is defined but not used in the query."); franta-hg@49: } franta-hg@49: } franta-hg@1: } franta-hg@34: franta-hg@34: @Override franta-hg@34: public List getParameters() { franta-hg@34: return parameters; franta-hg@34: } franta-hg@1: }