Source code: postgresql/jdbc2/Statement.java
1 package postgresql.jdbc2;
2
3 // IMPORTANT NOTE: This file implements the JDBC 2 version of the driver.
4 // If you make any modifications to this file, you must make sure that the
5 // changes are also made (if relevent) to the related JDBC 1 class in the
6 // postgresql.jdbc1 package.
7
8 import java.sql.*;
9 import java.util.Vector;
10 import postgresql.util.*;
11
12 /**
13 * A Statement object is used for executing a static SQL statement and
14 * obtaining the results produced by it.
15 *
16 * <p>Only one ResultSet per Statement can be open at any point in time.
17 * Therefore, if the reading of one ResultSet is interleaved with the
18 * reading of another, each must have been generated by different
19 * Statements. All statement execute methods implicitly close a
20 * statement's current ResultSet if an open one exists.
21 *
22 * @see java.sql.Statement
23 * @see ResultSet
24 */
25 public class Statement implements java.sql.Statement
26 {
27 Connection connection; // The connection who created us
28 java.sql.ResultSet result = null; // The current results
29 SQLWarning warnings = null; // The warnings chain.
30 int timeout = 0; // The timeout for a query (not used)
31 boolean escapeProcessing = true;// escape processing flag
32 private Vector batch=null;
33
34 /**
35 * Constructor for a Statement. It simply sets the connection
36 * that created us.
37 *
38 * @param c the Connection instantation that creates us
39 */
40 public Statement (Connection c)
41 {
42 connection = c;
43 }
44
45 /**
46 * Execute a SQL statement that retruns a single ResultSet
47 *
48 * @param sql typically a static SQL SELECT statement
49 * @return a ResulSet that contains the data produced by the query
50 * @exception SQLException if a database access error occurs
51 */
52 public java.sql.ResultSet executeQuery(String sql) throws SQLException
53 {
54 this.execute(sql);
55 while (result != null && !((postgresql.ResultSet)result).reallyResultSet())
56 result = ((postgresql.ResultSet)result).getNext();
57 if (result == null)
58 throw new PSQLException("postgresql.stat.noresult");
59 return result;
60 }
61
62 /**
63 * Execute a SQL INSERT, UPDATE or DELETE statement. In addition
64 * SQL statements that return nothing such as SQL DDL statements
65 * can be executed
66 *
67 * @param sql a SQL statement
68 * @return either a row count, or 0 for SQL commands
69 * @exception SQLException if a database access error occurs
70 */
71 public int executeUpdate(String sql) throws SQLException
72 {
73 this.execute(sql);
74 if (((postgresql.ResultSet)result).reallyResultSet())
75 throw new PSQLException("postgresql.stat.result");
76 return this.getUpdateCount();
77 }
78
79 /**
80 * In many cases, it is desirable to immediately release a
81 * Statement's database and JDBC resources instead of waiting
82 * for this to happen when it is automatically closed. The
83 * close method provides this immediate release.
84 *
85 * <p><B>Note:</B> A Statement is automatically closed when it is
86 * garbage collected. When a Statement is closed, its current
87 * ResultSet, if one exists, is also closed.
88 *
89 * @exception SQLException if a database access error occurs (why?)
90 */
91 public void close() throws SQLException
92 {
93 result = null;
94 }
95
96 /**
97 * The maxFieldSize limit (in bytes) is the maximum amount of
98 * data returned for any column value; it only applies to
99 * BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR and LONGVARCHAR
100 * columns. If the limit is exceeded, the excess data is silently
101 * discarded.
102 *
103 * @return the current max column size limit; zero means unlimited
104 * @exception SQLException if a database access error occurs
105 */
106 public int getMaxFieldSize() throws SQLException
107 {
108 return 8192; // We cannot change this
109 }
110
111 /**
112 * Sets the maxFieldSize - NOT! - We throw an SQLException just
113 * to inform them to stop doing this.
114 *
115 * @param max the new max column size limit; zero means unlimited
116 * @exception SQLException if a database access error occurs
117 */
118 public void setMaxFieldSize(int max) throws SQLException
119 {
120 throw new PSQLException("postgresql.stat.maxfieldsize");
121 }
122
123 /**
124 * The maxRows limit is set to limit the number of rows that
125 * any ResultSet can contain. If the limit is exceeded, the
126 * excess rows are silently dropped.
127 *
128 * @return the current maximum row limit; zero means unlimited
129 * @exception SQLException if a database access error occurs
130 */
131 public int getMaxRows() throws SQLException
132 {
133 return connection.maxrows;
134 }
135
136 /**
137 * Set the maximum number of rows
138 *
139 * @param max the new max rows limit; zero means unlimited
140 * @exception SQLException if a database access error occurs
141 * @see getMaxRows
142 */
143 public void setMaxRows(int max) throws SQLException
144 {
145 connection.maxrows = max;
146 }
147
148 /**
149 * If escape scanning is on (the default), the driver will do escape
150 * substitution before sending the SQL to the database.
151 *
152 * @param enable true to enable; false to disable
153 * @exception SQLException if a database access error occurs
154 */
155 public void setEscapeProcessing(boolean enable) throws SQLException
156 {
157 escapeProcessing = enable;
158 }
159
160 /**
161 * The queryTimeout limit is the number of seconds the driver
162 * will wait for a Statement to execute. If the limit is
163 * exceeded, a SQLException is thrown.
164 *
165 * @return the current query timeout limit in seconds; 0 = unlimited
166 * @exception SQLException if a database access error occurs
167 */
168 public int getQueryTimeout() throws SQLException
169 {
170 return timeout;
171 }
172
173 /**
174 * Sets the queryTimeout limit
175 *
176 * @param seconds - the new query timeout limit in seconds
177 * @exception SQLException if a database access error occurs
178 */
179 public void setQueryTimeout(int seconds) throws SQLException
180 {
181 timeout = seconds;
182 }
183
184 /**
185 * Cancel can be used by one thread to cancel a statement that
186 * is being executed by another thread. However, PostgreSQL is
187 * a sync. sort of thing, so this really has no meaning - we
188 * define it as a no-op (i.e. you can't cancel, but there is no
189 * error if you try.)
190 *
191 * 6.4 introduced a cancel operation, but we have not implemented it
192 * yet. Sometime before 6.5, this method will be implemented.
193 *
194 * @exception SQLException only because thats the spec.
195 */
196 public void cancel() throws SQLException
197 {
198 // No-op
199 }
200
201 /**
202 * The first warning reported by calls on this Statement is
203 * returned. A Statement's execute methods clear its SQLWarning
204 * chain. Subsequent Statement warnings will be chained to this
205 * SQLWarning.
206 *
207 * <p>The Warning chain is automatically cleared each time a statement
208 * is (re)executed.
209 *
210 * <p><B>Note:</B> If you are processing a ResultSet then any warnings
211 * associated with ResultSet reads will be chained on the ResultSet
212 * object.
213 *
214 * @return the first SQLWarning on null
215 * @exception SQLException if a database access error occurs
216 */
217 public SQLWarning getWarnings() throws SQLException
218 {
219 return warnings;
220 }
221
222 /**
223 * After this call, getWarnings returns null until a new warning
224 * is reported for this Statement.
225 *
226 * @exception SQLException if a database access error occurs (why?)
227 */
228 public void clearWarnings() throws SQLException
229 {
230 warnings = null;
231 }
232
233 /**
234 * setCursorName defines the SQL cursor name that will be used by
235 * subsequent execute methods. This name can then be used in SQL
236 * positioned update/delete statements to identify the current row
237 * in the ResultSet generated by this statement. If a database
238 * doesn't support positioned update/delete, this method is a
239 * no-op.
240 *
241 * <p><B>Note:</B> By definition, positioned update/delete execution
242 * must be done by a different Statement than the one which
243 * generated the ResultSet being used for positioning. Also, cursor
244 * names must be unique within a Connection.
245 *
246 * <p>We throw an additional constriction. There can only be one
247 * cursor active at any one time.
248 *
249 * @param name the new cursor name
250 * @exception SQLException if a database access error occurs
251 */
252 public void setCursorName(String name) throws SQLException
253 {
254 connection.setCursorName(name);
255 }
256
257 /**
258 * Execute a SQL statement that may return multiple results. We
259 * don't have to worry about this since we do not support multiple
260 * ResultSets. You can use getResultSet or getUpdateCount to
261 * retrieve the result.
262 *
263 * @param sql any SQL statement
264 * @return true if the next result is a ResulSet, false if it is
265 * an update count or there are no more results
266 * @exception SQLException if a database access error occurs
267 */
268 public boolean execute(String sql) throws SQLException
269 {
270 result = connection.ExecSQL(sql);
271 return (result != null && ((postgresql.ResultSet)result).reallyResultSet());
272 }
273
274 /**
275 * getResultSet returns the current result as a ResultSet. It
276 * should only be called once per result.
277 *
278 * @return the current result set; null if there are no more
279 * @exception SQLException if a database access error occurs (why?)
280 */
281 public java.sql.ResultSet getResultSet() throws SQLException
282 {
283 return result;
284 }
285
286 /**
287 * getUpdateCount returns the current result as an update count,
288 * if the result is a ResultSet or there are no more results, -1
289 * is returned. It should only be called once per result.
290 *
291 * @return the current result as an update count.
292 * @exception SQLException if a database access error occurs
293 */
294 public int getUpdateCount() throws SQLException
295 {
296 if (result == null) return -1;
297 if (((postgresql.ResultSet)result).reallyResultSet()) return -1;
298 return ((postgresql.ResultSet)result).getResultCount();
299 }
300
301 /**
302 * getMoreResults moves to a Statement's next result. If it returns
303 * true, this result is a ResulSet.
304 *
305 * @return true if the next ResultSet is valid
306 * @exception SQLException if a database access error occurs
307 */
308 public boolean getMoreResults() throws SQLException
309 {
310 result = ((postgresql.ResultSet)result).getNext();
311 return (result != null && ((postgresql.ResultSet)result).reallyResultSet());
312 }
313
314 /**
315 * Returns the status message from the current Result.<p>
316 * This is used internally by the driver.
317 *
318 * @return status message from backend
319 */
320 public String getResultStatusString()
321 {
322 if(result == null)
323 return null;
324 return ((postgresql.ResultSet)result).getStatusString();
325 }
326
327 // ** JDBC 2 Extensions **
328
329 public void addBatch(String sql) throws SQLException
330 {
331 if(batch==null)
332 batch=new Vector();
333 batch.addElement(sql);
334 }
335
336 public void clearBatch() throws SQLException
337 {
338 if(batch!=null)
339 batch.removeAllElements();
340 }
341
342 public int[] executeBatch() throws SQLException
343 {
344 if(batch==null || batch.isEmpty())
345 throw new PSQLException("postgresql.stat.batch.empty");
346
347 int size=batch.size();
348 int[] result=new int[size];
349 int i=0;
350 this.execute("begin"); // PTM: check this when autoCommit is false
351 try {
352 for(i=0;i<size;i++)
353 result[i]=this.executeUpdate((String)batch.elementAt(i));
354 this.execute("commit"); // PTM: check this
355 } catch(SQLException e) {
356 this.execute("abort"); // PTM: check this
357 throw new PSQLException("postgresql.stat.batch.error",new Integer(i),batch.elementAt(i));
358 }
359 return result;
360 }
361
362 public java.sql.Connection getConnection() throws SQLException
363 {
364 return (java.sql.Connection)connection;
365 }
366
367 public int getFetchDirection() throws SQLException
368 {
369 throw postgresql.Driver.notImplemented();
370 }
371
372 public int getFetchSize() throws SQLException
373 {
374 throw postgresql.Driver.notImplemented();
375 }
376
377 public int getKeysetSize() throws SQLException
378 {
379 throw postgresql.Driver.notImplemented();
380 }
381
382 public int getResultSetConcurrency() throws SQLException
383 {
384 throw postgresql.Driver.notImplemented();
385 }
386
387 public int getResultSetType() throws SQLException
388 {
389 throw postgresql.Driver.notImplemented();
390 }
391
392 public void setFetchDirection(int direction) throws SQLException
393 {
394 throw postgresql.Driver.notImplemented();
395 }
396
397 public void setFetchSize(int rows) throws SQLException
398 {
399 throw postgresql.Driver.notImplemented();
400 }
401
402 public void setKeysetSize(int keys) throws SQLException
403 {
404 throw postgresql.Driver.notImplemented();
405 }
406
407 public void setResultSetConcurrency(int value) throws SQLException
408 {
409 throw postgresql.Driver.notImplemented();
410 }
411
412 public void setResultSetType(int value) throws SQLException
413 {
414 throw postgresql.Driver.notImplemented();
415 }
416
417
418 }