SQLProcessor.java

biz/hammurapi/sql/SQLProcessor.java

Violations

Inspector Message Severity Location
Java Inspector 048 Copyrights information should be present in each file. 1
Java Inspector 015 Do not change parameter value. For comprehensibility, formal parameters should be final 2 1264:61
Java Inspector 015 Do not change parameter value. For comprehensibility, formal parameters should be final 2 1366:78
Java Inspector 015 Do not change parameter value. For comprehensibility, formal parameters should be final 2 1367:78
Java Inspector 018 Empty try block 2 1308:25
Java Inspector 049 Use a Collection instead of arrays Object[] 2 800:17
Java Inspector 049 Use a Collection instead of arrays Object[] 2 871:17
Java Inspector 049 Use a Collection instead of arrays Object[] 2 1099:17
Java Inspector 049 Use a Collection instead of arrays Object[] 2 1124:17
Java Inspector 049 Use a Collection instead of arrays Object[] 2 1205:17
Java Inspector 068 Do not use System.out and System.err to output logging messages. Use loggers instead. 2 1337:67
Java Inspector 068 Do not use System.out and System.err to output logging messages. Use loggers instead. 2 1378:75
Java Inspector 070-A Cyclomatic complexity is too high: 15, maximum allowed is 12 2 181:9
Java Inspector 073 [java.lang.StringBuffer] In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . 2 406:49
Java Inspector 073 [java.lang.StringBuffer] In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . 2 443:52
Java Inspector 081 Avoid static collections, they can grow in size over time. 2 1138:9
Java Inspector 089 Parameter dataSource documentation is too short. It is only 1 words. Should be at least 3 words. 2 84:9
Java Inspector 089 Parameter connection is not documented 2 106:9
Java Inspector 089 Parameter str is not documented 2 116:9
Java Inspector 089 Return value documentation is too short. It is only 1 words. Should be at least 3 words. 2 129:9
Java Inspector 089 Undocumented method 2 144:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 164:9
Java Inspector 089 Parameter rowProcessor documentation is too short. It is only 1 words. Should be at least 3 words. 2 164:9
Java Inspector 089 Undocumented method 2 252:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 271:9
Java Inspector 089 Parameter resourceName is not documented 2 327:9
Java Inspector 089 Parameter parameterizer is not documented 2 327:9
Java Inspector 089 Parameter rowProcessor is not documented 2 327:9
Java Inspector 089 Parameter resourceName is not documented 2 340:9
Java Inspector 089 Parameter parameterizer is not documented 2 340:9
Java Inspector 089 Method is not properly documented 2 399:9
Java Inspector 089 Undocumented method 2 458:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 477:9
Java Inspector 089 Undocumented method 2 481:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 500:9
Java Inspector 089 Javadoc contains tag for non-existent parameter projector 2 500:9
Java Inspector 089 Undocumented method 2 520:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 538:9
Java Inspector 089 Undocumented method 2 542:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 560:9
Java Inspector 089 Undocumented parameter delegate 2 560:9
Java Inspector 089 Undocumented method 2 564:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 585:9
Java Inspector 089 Undocumented method 2 589:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 609:9
Java Inspector 089 Undocumented method 2 613:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 634:9
Java Inspector 089 Undocumented method 2 638:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 653:9
Java Inspector 089 Undocumented method 2 658:41
Java Inspector 089 Undocumented method 2 671:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 685:9
Java Inspector 089 Undocumented method 2 691:41
Java Inspector 089 Undocumented method 2 704:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 719:9
Java Inspector 089 Undocumented method 2 725:41
Java Inspector 089 Undocumented method 2 738:9
Java Inspector 089 Parameter parameterizer documentation is too short. It is only 1 words. Should be at least 3 words. 2 755:9
Java Inspector 089 Undocumented method 2 762:41
Java Inspector 089 Undocumented method 2 778:17
Java Inspector 089 Undocumented method 2 787:9
Java Inspector 089 Method is not properly documented 2 799:9
Java Inspector 089 Undocumented parameter sql 2 799:9
Java Inspector 089 Parameter parameterizer is not documented 2 799:9
Java Inspector 089 Javadoc contains tag for non-existent parameter string 2 799:9
Java Inspector 089 Method return value is not properly documented 2 799:9
Java Inspector 089 Undocumented method 2 805:41
Java Inspector 089 Undocumented method 2 817:9
Java Inspector 089 Undocumented parameter sql 2 828:9
Java Inspector 089 Parameter parameterizer is not documented 2 828:9
Java Inspector 089 Undocumented parameter columnMap 2 828:9
Java Inspector 089 Javadoc contains tag for non-existent parameter string 2 828:9
Java Inspector 089 Undocumented method 2 833:41
Java Inspector 089 Undocumented method 2 859:9
Java Inspector 089 Method is not properly documented 2 869:9
Java Inspector 089 Parameter sql is not documented 2 869:9
Java Inspector 089 Parameter parameterizer is not documented 2 869:9
Java Inspector 089 Undocumented parameter theInterface 2 869:9
Java Inspector 089 Undocumented method 2 876:41
Java Inspector 089 Undocumented method 2 888:9
Java Inspector 089 Method is not properly documented 2 898:9
Java Inspector 089 Parameter sql is not documented 2 898:9
Java Inspector 089 Parameter parameterizer is not documented 2 898:9
Java Inspector 089 Undocumented method 2 904:41
Java Inspector 089 Undocumented method 2 913:9
Java Inspector 089 Method is not properly documented 2 923:9
Java Inspector 089 Parameter sql is not documented 2 923:9
Java Inspector 089 Parameter parameterizer is not documented 2 923:9
Java Inspector 089 Undocumented method 2 929:41
Java Inspector 089 Undocumented method 2 938:9
Java Inspector 089 Method is not properly documented 2 948:9
Java Inspector 089 Parameter sql is not documented 2 948:9
Java Inspector 089 Parameter parameterizer is not documented 2 948:9
Java Inspector 089 Undocumented method 2 954:41
Java Inspector 089 Undocumented method 2 963:9
Java Inspector 089 Method is not properly documented 2 973:9
Java Inspector 089 Parameter sql is not documented 2 973:9
Java Inspector 089 Parameter parameterizer is not documented 2 973:9
Java Inspector 089 Undocumented method 2 979:41
Java Inspector 089 Undocumented method 2 988:9
Java Inspector 089 Method is not properly documented 2 998:9
Java Inspector 089 Parameter sql is not documented 2 998:9
Java Inspector 089 Parameter parameterizer is not documented 2 998:9
Java Inspector 089 Undocumented method 2 1004:41
Java Inspector 089 Undocumented method 2 1013:9
Java Inspector 089 Method is not properly documented 2 1023:9
Java Inspector 089 Parameter sql is not documented 2 1023:9
Java Inspector 089 Parameter parameterizer is not documented 2 1023:9
Java Inspector 089 Undocumented method 2 1029:41
Java Inspector 089 Undocumented method 2 1038:9
Java Inspector 089 Method is not properly documented 2 1048:9
Java Inspector 089 Parameter sql is not documented 2 1048:9
Java Inspector 089 Parameter parameterizer is not documented 2 1048:9
Java Inspector 089 Undocumented method 2 1054:41
Java Inspector 089 Undocumented method 2 1063:9
Java Inspector 089 Method is not properly documented 2 1073:9
Java Inspector 089 Parameter sql is not documented 2 1073:9
Java Inspector 089 Parameter parameterizer is not documented 2 1073:9
Java Inspector 089 Undocumented method 2 1079:41
Java Inspector 089 Undocumented method 2 1088:9
Java Inspector 089 Method is not properly documented 2 1098:9
Java Inspector 089 Parameter sql is not documented 2 1098:9
Java Inspector 089 Parameter parameterizer is not documented 2 1098:9
Java Inspector 089 Undocumented method 2 1104:41
Java Inspector 089 Undocumented method 2 1113:9
Java Inspector 089 Method is not properly documented 2 1123:9
Java Inspector 089 Parameter sql is not documented 2 1123:9
Java Inspector 089 Parameter parameterizer is not documented 2 1123:9
Java Inspector 089 Undocumented method 2 1129:41
Java Inspector 089 Parameter className is not documented 2 1159:9
Java Inspector 089 Method return value is not properly documented 2 1159:9
Java Inspector 089 Undocumented method 2 1163:9
Java Inspector 089 Method is not properly documented 2 1173:9
Java Inspector 089 Parameter sql is not documented 2 1173:9
Java Inspector 089 Parameter parameterizer is not documented 2 1173:9
Java Inspector 089 Undocumented method 2 1179:41
Java Inspector 089 Undocumented method 2 1193:9
Java Inspector 089 Method is not properly documented 2 1203:9
Java Inspector 089 Undocumented parameter sql 2 1203:9
Java Inspector 089 Parameter parameterizer is not documented 2 1203:9
Java Inspector 089 Undocumented parameter theInterface 2 1203:9
Java Inspector 089 Undocumented parameter delegate 2 1203:9
Java Inspector 089 Javadoc contains tag for non-existent parameter string 2 1203:9
Java Inspector 089 Method return value is not properly documented 2 1203:9
Java Inspector 089 Undocumented method 2 1210:41
Java Inspector 089 Method return value is not properly documented 2 1234:9
Java Inspector 089 Method is not properly documented 2 1261:9
Java Inspector 089 Parameter con is not documented 2 1261:9
Java Inspector 089 Parameter primaryKeysTable is not documented 2 1261:9
Java Inspector 089 Parameter keyName is not documented 2 1261:9
Java Inspector 089 Method return value is not properly documented 2 1261:9
Java Inspector 089 Undocumented method 2 1263:25
Java Inspector 089 Undocumented method 2 1276:41
Java Inspector 089 Undocumented method 2 1282:41
Java Inspector 089 Non-private, non-local types shall be documented 2 1289:19
Java Inspector 089 Undocumented method 2 1294:9
Java Inspector 089 Undocumented method 2 1365:57
Java Inspector 089 Undocumented method 2 1377:49
Java Inspector 089 Undocumented method 2 1388:9
Java Inspector 089 Undocumented method 2 1391:5
Java Inspector 089 Undocumented method 2 1395:9
Java Inspector 089 Undocumented method 2 1399:9
Java Inspector 089 Undocumented method 2 1424:9
Java Inspector 024 Avoid hardwired character literals 3 376:39
Java Inspector 025 Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] 3 1316:49
Java Inspector 025 Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] 3 1318:54
Java Inspector 025 Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] 3 1362:41
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 212:58
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 242:58
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 296:66
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 307:58
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 450:66
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1141:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1141:42
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1142:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1142:39
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1143:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1143:41
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1144:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1144:39
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1145:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1145:38
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1146:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1146:40
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1147:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1147:41
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1148:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1148:40
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1149:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1149:39
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1150:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1150:51
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1151:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1151:51
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1273:33
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1273:75
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1277:75
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1278:68
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1278:95
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1283:68
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1283:100
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1304:31
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1305:60
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1305:77
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1305:83
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1314:67
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1317:56
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1318:57
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1327:51
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1334:63
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1337:81
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1337:95
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1337:112
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1359:49
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1363:57
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1366:84
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1367:85
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1373:49
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1375:49
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1378:89
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1378:103
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 1378:120
Java Inspector 040 Parameter name connection clashes with field name in SQLProcessor 3 138:39
Java Inspector 046 Empty statements 3 1308:29
Java Inspector 051 It is good practice to call in any case super() in a constructor. 3 84:9
Java Inspector 051 It is good practice to call in any case super() in a constructor. 3 106:9
Java Inspector 090 Unnecessary else part in if. The main part terminates control flow (return, break, throw, or continue). 3 412:65
Java Inspector 090 Unnecessary else part in if. The main part terminates control flow (return, break, throw, or continue). 3 449:33

Source code

1/*
2 * hgcommons 9
3 * Hammurapi Group Common Library
4 * Copyright (C) 2003 Hammurapi Group
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * URL: http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/hammurapi-group/products/products/hgcommons/index.html
21 * e-Mail: support@hammurapi.biz
22 */
23package biz.hammurapi.sql;
24
25import java.io.IOException;
26import java.io.InputStream;
27import java.io.InputStreamReader;
28import java.io.Reader;
29import java.io.StringWriter;
30import java.sql.Connection;
31import java.sql.DriverManager;
32import java.sql.PreparedStatement;
33import java.sql.ResultSet;
34import java.sql.ResultSetMetaData;
35import java.sql.SQLException;
36import java.sql.Statement;
37import java.util.ArrayList;
38import java.util.Collection;
39import java.util.HashMap;
40import java.util.Map;
41import java.util.Properties;
42
43import javax.sql.DataSource;
44
45import biz.hammurapi.config.ConfigurationException;
46import biz.hammurapi.config.Context;
47import biz.hammurapi.config.DomConfigFactory;
48import biz.hammurapi.config.MapContext;
49import biz.hammurapi.config.PropertyParser;
50import biz.hammurapi.metrics.MeasurementCategoryFactory;
51import biz.hammurapi.metrics.TimeIntervalCategory;
52import biz.hammurapi.sql.hsqldb.HsqldbInMemoryDataSource;
53import biz.hammurapi.sql.syntax.StatementFragment;
54import biz.hammurapi.util.ExceptionSink;
55
56
57/**
58 * This class contains methods to process SQL statements in more convenient
59 * way comparing to standard JDBC.
60 * @author Pavel Vlasov
61 * @version $Revision: 1.14 $
62 */
63public class SQLProcessor {
64 private DataSource dataSource;
65 private Connection connection;
66 private PropertyParser propertyParser;
67 private TimeIntervalCategory timeIntervalCategory=MeasurementCategoryFactory.getTimeIntervalCategory(SQLProcessor.class);
68 private Context nameMap;
69
70 /**
71 * If SQLProcessor constructed with this constructor
72 * then it obtains connection from the datasource, processes
73 * request and closes connection.
74 * @param dataSource DataSource
75 * @param nameMap NameMap allows to write parameterized SQL statements
76 * like "SELECT ${AMOUNT} FROM ${ACCOUNT} WHERE ${ANUM}=? AND CLOSED=1"
77 * nameMap shall contain mapping from AMOUNT, ACCOUNT and ANUM to actual
78 * database field names. If nameMap doesn't contain mapping for some
79 * properties then property names will be used as property values.
80 * See {@link biz.hammurapi.config.PropertyParser}.
81 * One property value can contain a reference to another property.
82 * If nameMap is null then no property parsing will happen.
83 */
84 public SQLProcessor(DataSource dataSource, Context nameMap) {
85 this(nameMap);
86 this.dataSource=dataSource;
87 }
88
89 /**
90 * @param nameMap
91 */
92 private SQLProcessor(Context nameMap) {
93 super();
94 this.nameMap=nameMap;
95 if (nameMap!=null) {
96 propertyParser=new PropertyParser(nameMap, true);
97 }
98 }
99
100 /**
101 * If SQLProcessor created with this constructor then is doesn't
102 * close the connection after processing.
103 * @param connection
104 * @param nameMap See {@link biz.hammurapi.sql.SQLProcessor#SQLProcessor(DataSource, Properties)}
105 */
106 public SQLProcessor(Connection connection, Context nameMap) {
107 this(nameMap);
108 this.connection=connection;
109 }
110
111 /**
112 * Replaces ${<property name>} with property value. See {@link biz.hammurapi.config.PropertyParser}
113 * @param str
114 * @return parsed string
115 */
116 public String parse(String str) {
117 if (propertyParser==null) {
118 return str;
119 }
120
121 return propertyParser.parse(str);
122 }
123
124 /**
125 * Returns connection if you need it for JDBC calls outside of the SQLProcessor
126 * @return Connection
127 * @throws SQLException
128 */
129 public Connection getConnection() throws SQLException {
130 return connection==null ? dataSource==null ? null : dataSource.getConnection() : connection;
131 }
132
133 /**
134 * Closes connection if it was provided by DataSource. Does nothing otherwise.
135 * @param connection Connection to release.
136 * @throws SQLException
137 */
138 public void releaseConnection(Connection connection) throws SQLException {
139 if (this.connection==null && connection!=null) {
140 connection.close();
141 }
142 }
143
144 public void processSelect(StatementFragment fragment, RowProcessor rowProcessor) throws SQLException {
145 processSelect(fragment.toSqlString(), fragment, rowProcessor);
146 }
147
148 /**
149 * Processes SQL SELECT statement in the following way:
150 * <UL>
151 * <li>Obtains connection</li>
152 * <LI>If parameterizer==null creates Statement, creates PreparedStatement otherwise</li>
153 * <LI>Invokes parameterizer.parameterize() if parameterizer is not null</li>
154 * <li>Iterates through result set and invokes rowProcessor.process() on each row</li>
155 * <li>If there was no rows and rowProcess is instance of {@link RowProcessorEx} then rowProcessor.onEmptyResultSet() is invoked</li>
156 * <li>ResultSet, Statement and connection are properly released</li>
157 * </UL>
158 *
159 * @param sql SQL statment to execute
160 * @param parameterizer Parameterizer
161 * @param rowProcessor RowProcessor
162 * @throws SQLException
163 */
164 public void processSelect(String sql, Parameterizer parameterizer, RowProcessor rowProcessor) throws SQLException {
165 Connection con=getConnection();
166 try {
167 processSelect(con, sql, parameterizer, rowProcessor);
168 } finally {
169 releaseConnection(con);
170 }
171 }
172
173 /**
174 * @param con
175 * @param sql
176 * @param parameterizer
177 * @param rowProcessor
178 * @param releaseConnection
179 * @throws SQLException
180 */
181 private void processSelect(Connection con, String sql, Parameterizer parameterizer, RowProcessor rowProcessor) throws SQLException {
182 long start = timeIntervalCategory==null ? 0 : timeIntervalCategory.getTime();
183 if (parameterizer==null) {
184 Statement statement=con.createStatement();
185 try {
186 ResultSet rs=statement.executeQuery(parse(sql));
187 if (propertyParser!=null) {
188 rs = new ResultSetProxy(this, rs);
189 }
190
191 try {
192 if (rowProcessor instanceof MetadataAwareRowProcessor) {
193 ((MetadataAwareRowProcessor) rowProcessor).processMetadata(rs.getMetaData());
194 }
195
196 boolean isEmpty=true;
197
198 while (rs.next()) {
199 isEmpty=false;
200 if (!rowProcessor.process(rs)) {
201 break;
202 }
203 }
204
205 if (isEmpty && rowProcessor instanceof RowProcessorEx) {
206 ((RowProcessorEx) rowProcessor).onEmptyResultSet();
207 }
208 } finally {
209 rs.close();
210 }
211 } catch (SQLException e) {
212 throw new SQLExceptionEx("Failed to execute statement: "+sql, e);
213 } finally {
214 statement.close();
215 }
216 } else {
217 PreparedStatement statement=con.prepareStatement(parse(sql));
218 parameterizer.parameterize(statement, 1);
219 try {
220 ResultSet rs=statement.executeQuery();
221 try {
222 if (rowProcessor instanceof MetadataAwareRowProcessor) {
223 ((MetadataAwareRowProcessor) rowProcessor).processMetadata(rs.getMetaData());
224 }
225
226 boolean isEmpty=true;
227
228 while (rs.next()) {
229 isEmpty=false;
230 if (!rowProcessor.process(propertyParser==null ? rs : new ResultSetProxy(this, rs))) {
231 break;
232 }
233 }
234
235 if (isEmpty && rowProcessor instanceof RowProcessorEx) {
236 ((RowProcessorEx) rowProcessor).onEmptyResultSet();
237 }
238 } finally {
239 rs.close();
240 }
241 } catch (SQLException e) {
242 throw new SQLExceptionEx("Failed to execute statement: "+sql, e);
243 } finally {
244 statement.close();
245 }
246 }
247 if (timeIntervalCategory!=null) {
248 timeIntervalCategory.addInterval(sql, start);
249 }
250 }
251
252 public int processUpdate(StatementFragment fragment) throws SQLException {
253 return processUpdate(fragment.toSqlString(), fragment);
254 }
255
256 /**
257 * Processes SQL INSERT, UPDATE or DELETE statement in the following way:
258 * <UL>
259 * <li>Obtains connection</li>
260 * <LI>If parameterizer==null creates Statement, creates PreparedStatement otherwise</li>
261 * <LI>Invokes parameterizer.parameterize() if parameterizer is not null</li>
262 * <li>Executes update</li>
263 * <li>ResultSet, Statement and connection are properly released</li>
264 * </UL>
265 *
266 * @param sql SQL statment to execute
267 * @param parameterizer Parameterizer
268 * @return Number of updates. See {@link Statement#executeUpdate(java.lang.String)}
269 * @throws SQLException
270 */
271 public int processUpdate(String sql, Parameterizer parameterizer) throws SQLException {
272 Connection con=getConnection();
273 try {
274 return processUpdate(con, sql, parameterizer);
275 } finally {
276 releaseConnection(con);
277 }
278 }
279
280 /**
281 * @param con
282 * @param sql
283 * @param parameterizer
284 * @return
285 * @throws SQLException
286 */
287 private int processUpdate(Connection con, String sql, Parameterizer parameterizer) throws SQLException {
288 long start = timeIntervalCategory==null ? 0 : timeIntervalCategory.getTime();
289 String parsedSql = parse(sql);
290 try {
291 if (parameterizer==null) {
292 Statement statement=con.createStatement();
293 try {
294 return statement.executeUpdate(parsedSql);
295 } catch (SQLException e) {
296 throw new SQLExceptionEx("Failed to execute statement: "+parsedSql, e);
297 } finally {
298 statement.close();
299 }
300 }
301
302 PreparedStatement statement=con.prepareStatement(parsedSql);
303 try {
304 parameterizer.parameterize(statement, 1);
305 return statement.executeUpdate();
306 } catch (SQLException e) {
307 throw new SQLExceptionEx("Failed to execute statement: "+parsedSql, e);
308 } finally {
309 statement.close();
310 }
311 } finally {
312 if (timeIntervalCategory!=null) {
313 timeIntervalCategory.addInterval(parsedSql, start);
314 }
315 }
316 }
317
318 /**
319 * Processes SELECT statement read from resource file. Suitable for huge SQL statements or SQL statements
320 * maintained by other developers.
321 * @param resourceName
322 * @param parameterizer
323 * @param rowProcessor
324 * @throws SQLException
325 * @throws IOException
326 */
327 public void processResourceSelect(String resourceName, Parameterizer parameterizer, RowProcessor rowProcessor) throws SQLException, IOException {
328 processSelect(resourceToString(resourceName), parameterizer, rowProcessor);
329 }
330
331 /**
332 * Processes SELECT statement read from resource file. Suitable for huge SQL statements or SQL statements
333 * maintained by other developers.
334 * @param resourceName
335 * @param parameterizer
336 * @return Number of updates. See {@link Statement#executeUpdate(java.lang.String)}
337 * @throws SQLException
338 * @throws IOException
339 */
340 public int processResourceUpdate(String resourceName, Parameterizer parameterizer) throws SQLException, IOException {
341 return processUpdate(resourceToString(resourceName), parameterizer);
342 }
343
344 private String resourceToString(String resourceName) throws IOException {
345 InputStream in=getClass().getClassLoader().getResourceAsStream(resourceName);
346 if (in==null) {
347 return null;
348 }
349
350 StringWriter sw=new StringWriter();
351 try {
352 char[] buf=new char[1024];
353 Reader r=new InputStreamReader(in);
354 try {
355 int len;
356 while((len=r.read(buf))!=-1) {
357 sw.write(buf, 0, len);
358 }
359 } finally {
360 r.close();
361 }
362 } finally {
363 sw.close();
364 }
365 return sw.toString();
366 }
367
368 /**
369 * Excecutes script with ; as statement separator
370 * @param reader Script source
371 * @throws IOException
372 * @throws SQLException
373 * @see SQLProcessor#executeScript(Reader, char)
374 */
375 public void executeScript(Reader reader) throws IOException, SQLException {
376 executeScript(reader, ';');
377 }
378
379 /**
380 * Executes series of SQL statement read from reader and separated by statementSeparator
381 * @param reader Script source
382 * @param statementSeparator Statement separator
383 * @throws IOException
384 * @throws SQLException
385 */
386 public void executeScript(Reader reader, char statementSeparator) throws IOException, SQLException {
387 executeScript(reader, statementSeparator, null);
388 }
389
390 /**
391 *
392 * @param reader Script source
393 * @param statementSeparator Statement separator
394 * @param exceptionSink Exception sink. Consumes exceptions thrown by individual statements. If sink is null then exception is
395 * rethrown and script execution terminates.
396 * @throws IOException
397 * @throws SQLException
398 */
399 public void executeScript(Reader reader, char statementSeparator, ExceptionSink exceptionSink) throws IOException, SQLException {
400 if (reader!=null) {
401 Connection con=getConnection();
402 try {
403 Statement stmt=con.createStatement();
404 try {
405 try {
406 StringBuffer sb=new StringBuffer();
407 int ch;
408 while ((ch=reader.read())!=-1) {
409 if (ch==statementSeparator) {
410 // Double separator is replaced with one e.g. ;; -> ;
411 int nextCh=reader.read();
412 if (nextCh==-1) {
413 break;
414 } else if (nextCh==statementSeparator) {
415 sb.append((char) nextCh);
416 } else {
417 executeBuffer(stmt, sb, exceptionSink);
418 sb=new StringBuffer();
419 sb.append((char) nextCh);
420 }
421 } else {
422 sb.append((char) ch);
423 }
424 }
425 executeBuffer(stmt, sb, exceptionSink);
426 } finally {
427 reader.close();
428 }
429 } finally {
430 stmt.close();
431 }
432 } finally {
433 releaseConnection(con);
434 }
435 }
436 }
437
438 /**
439 * @param stmt
440 * @param sb
441 * @throws SQLException
442 */
443 private void executeBuffer(Statement stmt, StringBuffer sb, ExceptionSink exceptionSink) throws SQLException {
444 String sql=sb.toString().trim();
445 if (sql.length()!=0) {
446 try {
447 stmt.execute(sql);
448 } catch (SQLException e) {
449 if (exceptionSink == null) {
450 throw new SQLExceptionEx("SQL: "+sql, e);
451 } else {
452 exceptionSink.consume(sql, e);
453 }
454 }
455 }
456 }
457
458 public Collection project(StatementFragment fragment, Projector projector) {
459 return project(fragment.toSqlString(), fragment, projector);
460 }
461
462 /**
463 * Executes SQL statement and returns collection backed by the database.
464 * @param sql Select statement to execute
465 * @param parameterizer Parameterizer
466 * @param projector Projector which instantiates objects. It is null then projector
467 * which projects row to collection will be used.
468 * @return Collection backed by the database. The collection doesn't hold
469 * any SQL resources open, neither it keeps any refernces to created objects.
470 * It keeps only references to the SQLProcessor, parameterizer
471 * and projector. Thus any call to one of collection methods retursn 'fresh'
472 * results from the database.
473 *
474 * Iterators created by this collection open ResultSet and close it when
475 * Iterator.hasNext() returns false.
476 */
477 public Collection project(String sql, Parameterizer parameterizer, Projector projector) {
478 return new ResultSetCollection(this, parse(sql), parameterizer, projector==null ? defaultProjector : projector);
479 }
480
481 public Collection project(StatementFragment fragment) {
482 return project(fragment.toSqlString(), fragment);
483 }
484
485 /**
486 * Executes SQL statement and returns collection backed by the database.
487 * Rows are projected to collection of field values.
488 * @param sql Select statement to execute
489 * @param parameterizer Parameterizer
490 * @param projector Projector which instantiates objects. It is null then projector
491 * which projects row to collection will be used.
492 * @return Collection backed by the database. The collection doesn't hold
493 * any SQL resources open, neither it keeps any refernces to created objects.
494 * It keeps only references to the SQLProcessor and parameterizer. Thus any call to one of collection methods retursn 'fresh'
495 * results from the database.
496 *
497 * Iterators created by this collection open ResultSet and close it when
498 * Iterator.hasNext() returns false.
499 */
500 public Collection project(String sql, Parameterizer parameterizer) {
501 return new ResultSetCollection(this, parse(sql), parameterizer, defaultProjector);
502 }
503
504 /**
505 * Executes SQL statement and returns collection backed by the database.
506 * @param sql Select statement to execute
507 * @return Collection backed by the database. The collection doesn't hold
508 * any SQL resources open, neither it keeps any refernces to created objects.
509 * It keeps only references to the SQLProcessor.
510 * Thus any call to one of collection methods retursn 'fresh'
511 * results from the database.
512 *
513 * Iterators created by this collection open ResultSet and close it when
514 * Iterator.hasNext() returns false.
515 */
516 public Collection project(String sql) {
517 return new ResultSetCollection(this, parse(sql), null, defaultProjector);
518 }
519
520 public Collection project(StatementFragment fragment, Class theInterface) {
521 return project(fragment.toSqlString(), fragment, theInterface);
522 }
523
524 /**
525 * Executes SQL statement and returns collection backed by the database.
526 * @param sql Select statement to execute
527 * @param parameterizer Parameterizer
528 * @param theInterface Iterface to implement
529 * @return Collection backed by the database. The collection doesn't hold
530 * any SQL resources open, neither it keeps any refernces to created objects.
531 * It keeps only references to the SQLProcessor, parameterizer
532 * and projector. Thus any call to one of collection methods retursn 'fresh'
533 * results from the database.
534 *
535 * Iterators created by this collection open ResultSet and close it when
536 * Iterator.hasNext() returns false.
537 */
538 public Collection project(String sql, Parameterizer parameterizer, Class theInterface) {
539 return new ResultSetCollection(this, parse(sql), parameterizer, new InterfaceProjector(theInterface, null));
540 }
541
542 public Collection project(StatementFragment fragment, Class theInterface, Object delegate) {
543 return project(fragment.toSqlString(), fragment, theInterface, delegate);
544 }
545
546 /**
547 * Executes SQL statement and returns collection backed by the database.
548 * @param sql Select statement to execute
549 * @param parameterizer Parameterizer
550 * @param theInterface Interface to implement
551 * @return Collection backed by the database. The collection doesn't hold
552 * any SQL resources open, neither it keeps any refernces to created objects.
553 * It keeps only references to the SQLProcessor, parameterizer
554 * and projector. Thus any call to one of collection methods retursn 'fresh'
555 * results from the database.
556 *
557 * Iterators created by this collection open ResultSet and close it when
558 * Iterator.hasNext() returns false.
559 */
560 public Collection project(String sql, Parameterizer parameterizer, Class theInterface, Object delegate) {
561 return new ResultSetCollection(this, parse(sql), parameterizer, new InterfaceProjector(theInterface, delegate, null));
562 }
563
564 public Collection project(StatementFragment fragment, Projector projector, int pageNum, int pageSize) {
565 return project(fragment.toSqlString(), fragment, projector, pageNum, pageSize);
566 }
567
568 /**
569 * Executes SQL statement and returns collection backed by the database.
570 * @param sql Select statement to execute
571 * @param parameterizer Parameterizer
572 * @param projector Projector which instantiates objects. If it is null
573 * then projector which projects row to collection will be used
574 * @param pageSize Maximum number of records to return
575 * @param pageNum Number of page. Starts with 1.
576 * @return Collection backed by the database. The collection doesn't hold
577 * any SQL resources open, neither it keeps any refernces to created objects.
578 * It keeps only references to the SQLProcessor, parameterizer
579 * and projector. Thus any call to one of collection methods retursn 'fresh'
580 * results from the database.
581 *
582 * Iterators created by this collection open ResultSet and close it when
583 * Iterator.hasNext() returns false.
584 */
585 public Collection project(String sql, Parameterizer parameterizer, Projector projector, int pageNum, int pageSize) {
586 return new ResultSetCollection(this, parse(sql), parameterizer, projector==null ? defaultProjector : projector, pageNum, pageSize);
587 }
588
589 public Collection project(StatementFragment fragment, Class theInterface, int pageNum, int pageSize) {
590 return project(fragment.toSqlString(), fragment, theInterface, pageNum, pageSize);
591 }
592
593 /**
594 * Executes SQL statement and returns collection backed by the database.
595 * @param sql Select statement to execute
596 * @param parameterizer Parameterizer
597 * @param theInterface Interface to implement
598 * @param pageSize Maximum number of records to return
599 * @param pageNum Number of page. Starts with 1.
600 * @return Collection backed by the database. The collection doesn't hold
601 * any SQL resources open, neither it keeps any refernces to created objects.
602 * It keeps only references to the SQLProcessor, parameterizer
603 * and projector. Thus any call to one of collection methods retursn 'fresh'
604 * results from the database.
605 *
606 * Iterators created by this collection open ResultSet and close it when
607 * Iterator.hasNext() returns false.
608 */
609 public Collection project(String sql, Parameterizer parameterizer, Class theInterface, int pageNum, int pageSize) {
610 return new ResultSetCollection(this, parse(sql), parameterizer, new InterfaceProjector(theInterface, null), pageNum, pageSize);
611 }
612
613 public Collection project(StatementFragment fragment, Class theInterface, Object delegate, int pageNum, int pageSize) {
614 return project(fragment.toSqlString(), fragment, theInterface, delegate, pageNum, pageSize);
615 }
616
617 /**
618 * Executes SQL statement and returns collection backed by the database.
619 * @param sql Select statement to execute
620 * @param parameterizer Parameterizer
621 * @param theInterface Interface to implement
622 * @param delegate Object to delegate invocations which didn't match field getters/setters
623 * @param pageSize Maximum number of records to return
624 * @param pageNum Number of page. Starts with 1.
625 * @return Collection backed by the database. The collection doesn't hold
626 * any SQL resources open, neither it keeps any refernces to created objects.
627 * It keeps only references to the SQLProcessor, parameterizer
628 * and projector. Thus any call to one of collection methods retursn 'fresh'
629 * results from the database.
630 *
631 * Iterators created by this collection open ResultSet and close it when
632 * Iterator.hasNext() returns false.
633 */
634 public Collection project(String sql, Parameterizer parameterizer, Class theInterface, Object delegate, int pageNum, int pageSize) {
635 return new ResultSetCollection(this, parse(sql), parameterizer, new InterfaceProjector(theInterface, delegate, null), pageNum, pageSize);
636 }
637
638 public Collection project(StatementFragment fragment, final Projector projector, final Collection receiver) throws SQLException {
639 return project(fragment.toSqlString(), fragment, projector, receiver);
640 }
641
642 /**
643 * Executes SQL statement and puts results to receiver
644 * @param sql Select statement to execute
645 * @param parameterizer Parameterizer
646 * @param projector Projector which instantiates objects. If it is null then
647 * projector which projects row to collection will be used
648 * @param receiver Collection to put results to
649 * @return receiver with added objects. Convenient for calls like
650 * Iterator it=processor.project(..., new LinkedList());
651 * @throws SQLException
652 */
653 public Collection project(final String sql, final Parameterizer parameterizer, final Projector projector, final Collection receiver) throws SQLException {
654 processSelect(
655 sql,
656 parameterizer,
657 new RowProcessor() {
658 public boolean process(ResultSet rs) throws SQLException {
659 Object o = (projector==null ? defaultProjector : projector).project(rs);
660 if (o instanceof DataAccessObject) {
661 ((DataAccessObject) o).setSQLProcessor(SQLProcessor.this);
662 }
663 receiver.add(o);
664 return true;
665 }
666 });
667
668 return receiver;
669 }
670
671 public Collection project(StatementFragment fragment, final Class theInterface, final Collection receiver) throws SQLException {
672 return project(fragment.toSqlString(), fragment, theInterface, receiver);
673 }
674
675 /**
676 * Executes SQL statement and puts results to receiver
677 * @param sql Select statement to execute
678 * @param parameterizer Parameterizer
679 * @param theInterface Interface to implement
680 * @param receiver Collection to put results to
681 * @return receiver with added objects. Convenient for calls like
682 * Iterator it=processor.project(..., new LinkedList());
683 * @throws SQLException
684 */
685 public Collection project(final String sql, final Parameterizer parameterizer, final Class theInterface, final Collection receiver) throws SQLException {
686 final Projector projector=new InterfaceProjector(theInterface, null);
687 processSelect(
688 sql,
689 parameterizer,
690 new RowProcessor() {
691 public boolean process(ResultSet rs) throws SQLException {
692 Object o = projector.project(rs);
693 if (o instanceof DataAccessObject) {
694 ((DataAccessObject) o).setSQLProcessor(SQLProcessor.this);
695 }
696 receiver.add(o);
697 return true;
698 }
699 });
700
701 return receiver;
702 }
703
704 public Collection project(StatementFragment fragment, final Class theInterface, Object delegate, final Collection receiver) throws SQLException {
705 return project(fragment.toSqlString(), fragment, theInterface, delegate, receiver);
706 }
707
708 /**
709 * Executes SQL statement and puts results to receiver
710 * @param sql Select statement to execute
711 * @param parameterizer Parameterizer
712 * @param theInterface Interface to implement
713 * @param delegate Object to delegate invocations which didn't match field getters/setters.
714 * @param receiver Collection to put results to
715 * @return receiver with added objects. Convenient for calls like
716 * Iterator it=processor.project(..., new LinkedList());
717 * @throws SQLException
718 */
719 public Collection project(final String sql, final Parameterizer parameterizer, final Class theInterface, Object delegate, final Collection receiver) throws SQLException {
720 final Projector projector=new InterfaceProjector(theInterface, delegate, null);
721 processSelect(
722 sql,
723 parameterizer,
724 new RowProcessor() {
725 public boolean process(ResultSet rs) throws SQLException {
726 Object o = projector.project(rs);
727 if (o instanceof DataAccessObject) {
728 ((DataAccessObject) o).setSQLProcessor(SQLProcessor.this);
729 }
730 receiver.add(o);
731 return true;
732 }
733 });
734
735 return receiver;
736 }
737
738 public Collection project(StatementFragment fragment, final Projector projector, final Collection receiver, final int pageSize, final int pageNum) throws SQLException {
739 return project(fragment.toSqlString(), fragment, projector, receiver, pageSize, pageNum);
740 }
741
742 /**
743 * Executes SQL statement and puts results to receiver
744 * @param sql Select statement to execute
745 * @param parameterizer Parameterizer
746 * @param projector Projector which instantiates objects. If it is null then
747 * projector which projects row to collection will be used.
748 * @param receiver Collection to put results to
749 * @param pageSize Maximum number of records to return
750 * @param pageNum Number of page. Starts with 1.
751 * @return receiver with added objects. Convenient for calls like
752 * Iterator it=processor.project(..., new LinkedList());
753 * @throws SQLException
754 */
755 public Collection project(final String sql, final Parameterizer parameterizer, final Projector projector, final Collection receiver, final int pageSize, final int pageNum) throws SQLException {
756 final int[] counter={0};
757
758 processSelect(
759 sql,
760 parameterizer,
761 new RowProcessor() {
762 public boolean process(ResultSet rs) throws SQLException {
763 if (++counter[0]>(pageNum-1)*pageSize && counter[0]<=pageNum*pageSize) {
764 Object o = (projector==null ? defaultProjector : projector).project(rs);
765 if (o instanceof DataAccessObject) {
766 ((DataAccessObject) o).setSQLProcessor(SQLProcessor.this);
767 }
768 receiver.add(o);
769 }
770 return true;
771 }
772 });
773
774 return receiver;
775 }
776
777 private Projector defaultProjector=new Projector() {
778 public Object project(ResultSet rs) throws SQLException {
779 Collection ret=new ArrayList();
780 for (int i=1, j=rs.getMetaData().getColumnCount(); i <= j; i++) {
781 ret.add(rs.getObject(i));
782 }
783 return ret;
784 }
785 };
786
787 public Object projectSingleObject(StatementFragment fragment, final Projector projector) throws SQLException {
788 return projectSingleObject(fragment.toSqlString(), fragment, projector);
789 }
790
791 /**
792 * @param string
793 * @param parameterizer
794 * @param projector Projector. If it is null then projector which projects
795 * row to collection will be used.
796 * @return
797 * @throws SQLException
798 */
799 public Object projectSingleObject(String sql, Parameterizer parameterizer, final Projector projector) throws SQLException {
800 final Object[] ret={null};
801 processSelect(
802 sql,
803 parameterizer,
804 new RowProcessor() {
805 public boolean process(ResultSet rs) throws SQLException {
806 ret[0] = (projector==null ? defaultProjector : projector).project(rs);
807 if (ret[0] instanceof DataAccessObject) {
808 ((DataAccessObject) ret[0]).setSQLProcessor(SQLProcessor.this);
809 }
810 return false;
811 }
812 });
813
814 return ret[0];
815 }
816
817 public void inject(StatementFragment fragment, final Map columnMap, final Object target) throws SQLException {
818 inject(fragment.toSqlString(), fragment, columnMap, target);
819 }
820
821 /**
822 * Executes query and injects values from the first row to target object.
823 * @param string
824 * @param parameterizer
825 * @param target Object to inject values to
826 * @throws SQLException
827 */
828 public void inject(String sql, Parameterizer parameterizer, final Map columnMap, final Object target) throws SQLException {
829 processSelect(
830 sql,
831 parameterizer,
832 new RowProcessor() {
833 public boolean process(ResultSet rs) throws SQLException {
834 ResultSetMetaData metaData = rs.getMetaData();
835 Map contextMap=new HashMap();
836 for (int i=1, cc=metaData.getColumnCount(); i<=cc; i++) {
837 String colName=metaData.getColumnName(i);
838 String propertyName=BaseReflectionProjector.propertyName(colName);
839
840 if (columnMap!=null && columnMap.containsKey(propertyName)) {
841 propertyName=(String) columnMap.get(propertyName);
842 }
843
844 if (propertyName!=null) {
845 contextMap.put(propertyName, rs.getObject(colName));
846 }
847 }
848
849 try {
850 DomConfigFactory.inject(target, new MapContext(contextMap));
851 } catch (ConfigurationException e) {
852 throw new SQLExceptionEx(e);
853 }
854 return false;
855 }
856 });
857 }
858
859 public Object projectSingleObject(StatementFragment fragment, Class theInterface) throws SQLException {
860 return projectSingleObject(fragment.toSqlString(), fragment, theInterface);
861 }
862
863 /**
864 * @param sql
865 * @param parameterizer
866 * @return Object representing first row
867 * @throws SQLException
868 */
869 public Object projectSingleObject(String sql, Parameterizer parameterizer, Class theInterface) throws SQLException {
870 final Projector projector=new InterfaceProjector(theInterface, null);
871 final Object[] ret={null};
872 processSelect(
873 sql,
874 parameterizer,
875 new RowProcessor() {
876 public boolean process(ResultSet rs) throws SQLException {
877 ret[0] = projector.project(rs);
878 if (ret[0] instanceof DataAccessObject) {
879 ((DataAccessObject) ret[0]).setSQLProcessor(SQLProcessor.this);
880 }
881 return false;
882 }
883 });
884
885 return ret[0];
886 }
887
888 public boolean projectSingleBoolean(StatementFragment fragment) throws SQLException {
889 return projectSingleBoolean(fragment.toSqlString(), fragment);
890 }
891
892 /**
893 * @param sql
894 * @param parameterizer
895 * @return boolean value of the first column of the first row or 'false' if there are no rows.
896 * @throws SQLException
897 */
898 public boolean projectSingleBoolean(String sql, Parameterizer parameterizer) throws SQLException {
899 final boolean[] ret={false};
900 processSelect(
901 sql,
902 parameterizer,
903 new RowProcessor() {
904 public boolean process(ResultSet rs) throws SQLException {
905 ret[0] = rs.getBoolean(1);
906 return false;
907 }
908 });
909
910 return ret[0];
911 }
912
913 public byte projectSingleByte(StatementFragment fragment) throws SQLException {
914 return projectSingleByte(fragment.toSqlString(), fragment);
915 }
916
917 /**
918 * @param sql
919 * @param parameterizer
920 * @return byte value of the first column of the first row or 0 if there are no rows.
921 * @throws SQLException
922 */
923 public byte projectSingleByte(String sql, Parameterizer parameterizer) throws SQLException {
924 final byte[] ret={0};
925 processSelect(
926 sql,
927 parameterizer,
928 new RowProcessor() {
929 public boolean process(ResultSet rs) throws SQLException {
930 ret[0] = rs.getByte(1);
931 return false;
932 }
933 });
934
935 return ret[0];
936 }
937
938 public byte[] projectSingleBytes(StatementFragment fragment) throws SQLException {
939 return projectSingleBytes(fragment.toSqlString(), fragment);
940 }
941
942 /**
943 * @param sql
944 * @param parameterizer
945 * @return byte[] value of the first column of the first row or null if there are no rows.
946 * @throws SQLException
947 */
948 public byte[] projectSingleBytes(String sql, Parameterizer parameterizer) throws SQLException {
949 final byte[][] ret={null};
950 processSelect(
951 sql,
952 parameterizer,
953 new RowProcessor() {
954 public boolean process(ResultSet rs) throws SQLException {
955 ret[0] = rs.getBytes(1);
956 return false;
957 }
958 });
959
960 return ret[0];
961 }
962
963 public int projectSingleInt(StatementFragment fragment) throws SQLException {
964 return projectSingleInt(fragment.toSqlString(), fragment);
965 }
966
967 /**
968 * @param sql
969 * @param parameterizer
970 * @return int value of the first column of the first row or 0 if there are no rows.
971 * @throws SQLException
972 */
973 public int projectSingleInt(String sql, Parameterizer parameterizer) throws SQLException {
974 final int[] ret={0};
975 processSelect(
976 sql,
977 parameterizer,
978 new RowProcessor() {
979 public boolean process(ResultSet rs) throws SQLException {
980 ret[0] = rs.getInt(1);
981 return false;
982 }
983 });
984
985 return ret[0];
986 }
987
988 public short projectSingleShort(StatementFragment fragment) throws SQLException {
989 return projectSingleShort(fragment.toSqlString(), fragment);
990 }
991
992 /**
993 * @param sql
994 * @param parameterizer
995 * @return short value of the first column of the first row or 0 if there are no rows.
996 * @throws SQLException
997 */
998 public short projectSingleShort(String sql, Parameterizer parameterizer) throws SQLException {
999 final short[] ret={0};
1000 processSelect(
1001 sql,
1002 parameterizer,
1003 new RowProcessor() {
1004 public boolean process(ResultSet rs) throws SQLException {
1005 ret[0] = rs.getShort(1);
1006 return false;
1007 }
1008 });
1009
1010 return ret[0];
1011 }
1012
1013 public double projectSingleDouble(StatementFragment fragment) throws SQLException {
1014 return projectSingleDouble(fragment.toSqlString(), fragment);
1015 }
1016
1017 /**
1018 * @param sql
1019 * @param parameterizer
1020 * @return double value of the first column of the first row or 0 if there are no rows.
1021 * @throws SQLException
1022 */
1023 public double projectSingleDouble(String sql, Parameterizer parameterizer) throws SQLException {
1024 final double[] ret={0};
1025 processSelect(
1026 sql,
1027 parameterizer,
1028 new RowProcessor() {
1029 public boolean process(ResultSet rs) throws SQLException {
1030 ret[0] = rs.getDouble(1);
1031 return false;
1032 }
1033 });
1034
1035 return ret[0];
1036 }
1037
1038 public float projectSingleFloat(StatementFragment fragment) throws SQLException {
1039 return projectSingleFloat(fragment.toSqlString(), fragment);
1040 }
1041
1042 /**
1043 * @param sql
1044 * @param parameterizer
1045 * @return float value of the first column of the first row or 0 if there are no rows.
1046 * @throws SQLException
1047 */
1048 public float projectSingleFloat(String sql, Parameterizer parameterizer) throws SQLException {
1049 final float[] ret={0};
1050 processSelect(
1051 sql,
1052 parameterizer,
1053 new RowProcessor() {
1054 public boolean process(ResultSet rs) throws SQLException {
1055 ret[0] = rs.getFloat(1);
1056 return false;
1057 }
1058 });
1059
1060 return ret[0];
1061 }
1062
1063 public long projectSingleLong(StatementFragment fragment) throws SQLException {
1064 return projectSingleLong(fragment.toSqlString(), fragment);
1065 }
1066
1067 /**
1068 * @param sql
1069 * @param parameterizer
1070 * @return long value of the first column of the first row or 0 if there are no rows.
1071 * @throws SQLException
1072 */
1073 public long projectSingleLong(String sql, Parameterizer parameterizer) throws SQLException {
1074 final long[] ret={0};
1075 processSelect(
1076 sql,
1077 parameterizer,
1078 new RowProcessor() {
1079 public boolean process(ResultSet rs) throws SQLException {
1080 ret[0] = rs.getLong(1);
1081 return false;
1082 }
1083 });
1084
1085 return ret[0];
1086 }
1087
1088 public String projectSingleString(StatementFragment fragment) throws SQLException {
1089 return projectSingleString(fragment.toSqlString(), fragment);
1090 }
1091
1092 /**
1093 * @param sql
1094 * @param parameterizer
1095 * @return String value of the first column of the first row or null if there are no rows.
1096 * @throws SQLException
1097 */
1098 public String projectSingleString(String sql, Parameterizer parameterizer) throws SQLException {
1099 final String[] ret={null};
1100 processSelect(
1101 sql,
1102 parameterizer,
1103 new RowProcessor() {
1104 public boolean process(ResultSet rs) throws SQLException {
1105 ret[0] = rs.getString(1);
1106 return false;
1107 }
1108 });
1109
1110 return ret[0];
1111 }
1112
1113 public Object projectSingleObject(StatementFragment fragment) throws SQLException {
1114 return projectSingleObject(fragment.toSqlString(), fragment);
1115 }
1116
1117 /**
1118 * @param sql
1119 * @param parameterizer
1120 * @return object value of the first column of the first row or null if there are no rows.
1121 * @throws SQLException
1122 */
1123 public Object projectSingleObject(String sql, Parameterizer parameterizer) throws SQLException {
1124 final Object[] ret={null};
1125 processSelect(
1126 sql,
1127 parameterizer,
1128 new RowProcessor() {
1129 public boolean process(ResultSet rs) throws SQLException {
1130 ret[0] = rs.getObject(1);
1131 return false;
1132 }
1133 });
1134
1135 return ret[0];
1136 }
1137
1138 private static Map methodMap=new HashMap();
1139
1140 static {
1141 methodMap.put("boolean", "projectSingleBoolean");
1142 methodMap.put("byte", "projectSingleByte");
1143 methodMap.put("byte[]", "projectSingleBytes");
1144 methodMap.put("char", "projectSingleChar");
1145 methodMap.put("int", "projectSingleInt");
1146 methodMap.put("short", "projectSingleShort");
1147 methodMap.put("double", "projectSingleDouble");
1148 methodMap.put("float", "projectSingleFloat");
1149 methodMap.put("long", "projectSingleLong");
1150 methodMap.put("java.lang.String", "projectSingleString");
1151 methodMap.put("java.lang.Object", "projectSingleObject");
1152 }
1153
1154 /**
1155 * Finds projectSingleXXX method for a particular type.
1156 * @param className
1157 * @return
1158 */
1159 public static String findProjectSingleMethodName(String className) {
1160 return (String) methodMap.get(className);
1161 }
1162
1163 public char projectSingleChar(StatementFragment fragment) throws SQLException {
1164 return projectSingleChar(fragment.toSqlString(), fragment);
1165 }
1166
1167 /**
1168 * @param sql
1169 * @param parameterizer
1170 * @return char value of the first column of the first row or 0 if there are no rows.
1171 * @throws SQLException
1172 */
1173 public char projectSingleChar(String sql, Parameterizer parameterizer) throws SQLException {
1174 final char[] ret={0};
1175 processSelect(
1176 sql,
1177 parameterizer,
1178 new RowProcessor() {
1179 public boolean process(ResultSet rs) throws SQLException {
1180 String str=rs.getString(1);
1181 if (str!=null && str.length()>0) {
1182 ret[0]=str.charAt(0);
1183 }
1184 return false;
1185 }
1186 });
1187
1188 return ret[0];
1189 }
1190
1191
1192
1193 public Object projectSingleObject(StatementFragment fragment, Class theInterface, Object delegate) throws SQLException {
1194 return projectSingleObject(fragment.toSqlString(), fragment, theInterface, delegate);
1195 }
1196
1197 /**
1198 * @param string
1199 * @param parameterizer
1200 * @return
1201 * @throws SQLException
1202 */
1203 public Object projectSingleObject(String sql, Parameterizer parameterizer, Class theInterface, Object delegate) throws SQLException {
1204 final Projector projector=new InterfaceProjector(theInterface, delegate, null);
1205 final Object[] ret={null};
1206 processSelect(
1207 sql,
1208 parameterizer,
1209 new RowProcessor() {
1210 public boolean process(ResultSet rs) throws SQLException {
1211 ret[0] = projector.project(rs);
1212 if (ret[0] instanceof DataAccessObject) {
1213 ((DataAccessObject) ret[0]).setSQLProcessor(SQLProcessor.this);
1214 }
1215 return false;
1216 }
1217 });
1218
1219 return ret[0];
1220 }
1221
1222 /**
1223 * Generates primary key.
1224 * @param primaryKeysTable Table holding primary keys counters. DDL:
1225 * <PRE>CREATE TABLE <I>table name</I> (
1226 KEY_NAME VARCHAR(50) NOT NULL
1227 , KEY_VALUE INTEGER DEFAULT '0' NOT NULL
1228 , PRIMARY KEY (KEY_NAME)
1229);</PRE>
1230 * @param keyName Key name
1231 * @return
1232 * @throws SQLException
1233 */
1234 public int nextPK(final String primaryKeysTable, final String keyName) throws SQLException {
1235 final Connection con=getConnection();
1236 try {
1237 boolean ac=con.getAutoCommit();
1238 try {
1239 con.setAutoCommit(false);
1240 int value = nextPK(con, primaryKeysTable, keyName);
1241 con.commit();
1242 return value;
1243 } catch (SQLException e) {
1244 con.rollback();
1245 throw e;
1246 } finally {
1247 con.setAutoCommit(ac);
1248 }
1249 } finally {
1250 releaseConnection(con);
1251 }
1252 }
1253
1254 /**
1255 * @param con
1256 * @param primaryKeysTable
1257 * @param keyName
1258 * @return
1259 * @throws SQLException
1260 */
1261 public int nextPK(final Connection con, final String primaryKeysTable, final String keyName) throws SQLException {
1262 final Parameterizer parameterizer=new Parameterizer() {
1263 public int parameterize(PreparedStatement preparedStatement, int idx) throws SQLException {
1264 preparedStatement.setString(idx++, keyName);
1265 return idx;
1266 }
1267 };
1268
1269 final int[] value={0};
1270
1271 processSelect(
1272 con,
1273 "SELECT KEY_VALUE FROM "+primaryKeysTable+" WHERE KEY_NAME=?",
1274 parameterizer,
1275 new RowProcessorEx() {
1276 public boolean process(ResultSet resultSet) throws SQLException {
1277 value[0]=resultSet.getInt("KEY_VALUE")+1;
1278 processUpdate(con, "UPDATE "+primaryKeysTable+" SET KEY_VALUE=KEY_VALUE+1 WHERE KEY_NAME=?", parameterizer);
1279 return false;
1280 }
1281
1282 public void onEmptyResultSet() throws SQLException {
1283 processUpdate(con, "INSERT INTO "+primaryKeysTable+" (KEY_NAME, KEY_VALUE) VALUES (?, 0)", parameterizer);
1284 }
1285 });
1286 return value[0];
1287 }
1288
1289 interface Person {
1290 String getFirstName();
1291 String getLastName();
1292 }
1293
1294 public static void main(final String[] args) throws Exception {
1295 doCool();
1296 doDull();
1297 }
1298
1299 /**
1300 * @throws ClassNotFoundException
1301 * @throws SQLException
1302 */
1303 private static void doDull() throws ClassNotFoundException, SQLException {
1304 Class.forName("org.hsqldb.jdbcDriver");
1305 Connection con=DriverManager.getConnection("jdbc:hsqldb:.", "sa", "");
1306 try {
1307 Statement st=con.createStatement();
1308 try {
1309 //st.executeUpdate("create table people (first_name varchar(200), last_name varchar(200))");
1310 } finally {
1311 st.close();
1312 }
1313
1314 PreparedStatement ps=con.prepareStatement("insert into people (first_name, last_name) values (?, ?)");
1315 try {
1316 for (int i=0; i<20; i++) {
1317 ps.setString(1,"Pavel-" + i);
1318 ps.setString(2, "Vlasov");
1319 ps.execute();
1320 }
1321 } finally {
1322 ps.close();
1323 }
1324
1325 Statement st1=con.createStatement();
1326 try {
1327 st1.executeUpdate("insert into people (first_name, last_name) values ('Olga', 'Vlasov')");
1328 } finally {
1329 st1.close();
1330 }
1331
1332 Statement st2=con.createStatement();
1333 try {
1334 ResultSet rs=st2.executeQuery("select * from people");
1335 try {
1336 while (rs.next()) {
1337 System.out.println(rs.getString("FIRST_NAME")+" "+rs.getString("LAST_NAME"));
1338 }
1339 } finally {
1340 rs.close();
1341 }
1342 } finally {
1343 st2.close();
1344 }
1345 } finally {
1346 con.close();
1347 }
1348 }
1349
1350 /**
1351 * @throws ClassNotFoundException
1352 * @throws IOException
1353 * @throws SQLException
1354 */
1355 private static void doCool() throws ClassNotFoundException, IOException, SQLException {
1356 HsqldbInMemoryDataSource ds=new HsqldbInMemoryDataSource((Reader) null);
1357 try {
1358 SQLProcessor processor=new SQLProcessor(ds, null);
1359 processor.processUpdate("create table people (first_name varchar(200), last_name varchar(200))", null);
1360
1361 final int[] counter={0};
1362 for (int i=0; i<20; i++) {
1363 processor.processUpdate("insert into people (first_name, last_name) values (?, ?)",
1364 new Parameterizer() {
1365 public int parameterize(PreparedStatement ps, int idx) throws SQLException {
1366 ps.setString(idx++,"Dhawal "+ ++counter[0]);
1367 ps.setString(idx++, "Manwatkar");
1368 return idx;
1369 }
1370 });
1371 }
1372
1373 processor.processUpdate("insert into people (first_name, last_name) values ('Pavel', 'Vlasov')", null);
1374
1375 processor.processSelect("select * from people", null,
1376 new RowProcessor() {
1377 public boolean process(ResultSet rs) throws SQLException {
1378 System.out.println(rs.getString("FIRST_NAME")+" "+rs.getString("LAST_NAME"));
1379 return true;
1380 }
1381 });
1382
1383 } finally {
1384 ds.shutdown();
1385 }
1386 }
1387
1388 public TimeIntervalCategory getTimeIntervalCategory() {
1389 return timeIntervalCategory;
1390 }
1391 public void setTimeIntervalCategory(TimeIntervalCategory timeIntervalCategory) {
1392 this.timeIntervalCategory = timeIntervalCategory;
1393 }
1394
1395 public Context getNameMap() {
1396 return nameMap;
1397 }
1398
1399 public void executeTransaction(Transaction transaction) throws SQLException {
1400 Connection con=getConnection();
1401 try {
1402 boolean ac=con.getAutoCommit();
1403 try {
1404 con.setAutoCommit(false);
1405 SQLProcessor processor=new SQLProcessor(con, nameMap);
1406 try {
1407 if (transaction.execute(processor)) {
1408 con.commit();
1409 } else {
1410 con.rollback();
1411 }
1412 } catch (SQLException e) {
1413 con.rollback();
1414 throw e;
1415 }
1416 } finally {
1417 con.setAutoCommit(ac);
1418 }
1419 } finally {
1420 releaseConnection(con);
1421 }
1422 }
1423
1424 protected DataSource getDataSource() {
1425 return dataSource;
1426 }
1427}
1428