15 * You should have received a copy of the GNU General Public License |
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/>. |
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 */ |
17 */ |
18 package info.globalcode.sql.dk; |
18 package info.globalcode.sql.dk; |
19 |
19 |
|
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; |
20 import java.sql.PreparedStatement; |
24 import java.sql.PreparedStatement; |
21 import java.sql.SQLException; |
25 import java.sql.SQLException; |
|
26 import java.util.ArrayList; |
22 import java.util.List; |
27 import java.util.List; |
|
28 import java.util.regex.Matcher; |
|
29 import java.util.regex.Pattern; |
23 |
30 |
24 /** |
31 /** |
25 * |
32 * |
26 * @author Ing. František Kučera (frantovo.cz) |
33 * @author Ing. František Kučera (frantovo.cz) |
27 */ |
34 */ |
28 public class SQLCommandNamed extends SQLCommand { |
35 public class SQLCommandNamed extends SQLCommand { |
29 |
36 |
|
37 private static final String PROBLEM_MARK = "<OMG>"; |
|
38 private String namePrefix; |
|
39 private String nameSuffix; |
30 private List<NamedParameter> parameters; |
40 private List<NamedParameter> parameters; |
|
41 private List<NamedParameter> parametersUsed = new ArrayList<>(); |
|
42 private StringBuilder updatedQuery; |
|
43 private Pattern pattern; |
31 |
44 |
32 public SQLCommandNamed(String query, List<NamedParameter> parameters) { |
45 public SQLCommandNamed(String query, List<NamedParameter> parameters, String namePrefix, String nameSuffix) { |
33 super(query); |
46 super(query); |
|
47 this.updatedQuery = new StringBuilder(query.length()); |
34 this.parameters = parameters; |
48 this.parameters = parameters; |
|
49 this.namePrefix = namePrefix; |
|
50 this.nameSuffix = nameSuffix; |
|
51 } |
|
52 |
|
53 @Override |
|
54 public PreparedStatement prepareStatement(Connection c) throws SQLException { |
|
55 buildPattern(); |
|
56 placeParametersAndUpdateQuery(); |
|
57 return c.prepareStatement(updatedQuery.toString()); |
35 } |
58 } |
36 |
59 |
37 @Override |
60 @Override |
38 public void parametrize(PreparedStatement ps) throws SQLException { |
61 public void parametrize(PreparedStatement ps) throws SQLException { |
39 throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
62 int i = 1; |
|
63 for (Parameter p : notNull(parametersUsed)) { |
|
64 ps.setObject(i++, p.getValue(), p.getType()); |
|
65 } |
|
66 } |
|
67 |
|
68 /** |
|
69 * Builds a regexp pattern that matches all parameter names (with prefix/suffix) and which has |
|
70 * one group: parameter name (without prefix/suffix) |
|
71 */ |
|
72 private void buildPattern() { |
|
73 StringBuilder patternString = new StringBuilder(); |
|
74 |
|
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("|"); |
|
81 } |
|
82 } |
|
83 patternString.append(")"); |
|
84 patternString.append(escapeRegEx(nameSuffix)); |
|
85 |
|
86 pattern = Pattern.compile(patternString.toString()); |
|
87 } |
|
88 |
|
89 private void placeParametersAndUpdateQuery() throws SQLException { |
|
90 final String originalQuery = getQuery(); |
|
91 Matcher m = pattern.matcher(originalQuery); |
|
92 |
|
93 int lastPosition = 0; |
|
94 while (m.find(lastPosition)) { |
|
95 String name = m.group(1); |
|
96 |
|
97 updatedQuery.append(originalQuery.substring(lastPosition, m.start())); |
|
98 |
|
99 if (name.isEmpty()) { |
|
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); |
|
103 } |
|
104 |
|
105 updatedQuery.append("?"); |
|
106 |
|
107 parametersUsed.add(findByName(parameters, name)); |
|
108 |
|
109 lastPosition = m.end(); |
|
110 } |
|
111 updatedQuery.append(originalQuery.substring(lastPosition, originalQuery.length())); |
|
112 |
|
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."); |
|
116 } |
|
117 } |
40 } |
118 } |
41 |
119 |
42 @Override |
120 @Override |
43 public List<NamedParameter> getParameters() { |
121 public List<NamedParameter> getParameters() { |
44 return parameters; |
122 return parameters; |