support named parameters v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Tue, 24 Dec 2013 01:38:55 +0100
branchv_0
changeset 49 b4c74461d0f9
parent 48 28735e71a1da
child 50 074b81e5fa7c
support named parameters
java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java
java/sql-dk/src/info/globalcode/sql/dk/NamedParameter.java
java/sql-dk/src/info/globalcode/sql/dk/SQLCommandNamed.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:
--- 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() + "}";
+	}
 }
--- 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 = "<OMG>";
+	private String namePrefix;
+	private String nameSuffix;
 	private List<NamedParameter> parameters;
+	private List<NamedParameter> parametersUsed = new ArrayList<>();
+	private StringBuilder updatedQuery;
+	private Pattern pattern;
 
-	public SQLCommandNamed(String query, List<NamedParameter> parameters) {
+	public SQLCommandNamed(String query, List<NamedParameter> 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