1 package SQLite.JDBC2z1;
2 
3 import java.sql.BatchUpdateException;
4 import java.sql.Connection;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7 import java.sql.SQLFeatureNotSupportedException;
8 import java.sql.SQLWarning;
9 import java.sql.Statement;
10 import java.util.ArrayList;
11 
12 public class JDBCStatement implements java.sql.Statement {
13 
14     protected JDBCConnection conn;
15     protected JDBCResultSet rs;
16     protected int updcnt;
17     protected int maxrows = 0;
18     private ArrayList<String> batch;
19 
JDBCStatement(JDBCConnection conn)20     public JDBCStatement(JDBCConnection conn) {
21 	this.conn = conn;
22 	this.updcnt = 0;
23 	this.rs = null;
24 	this.batch = null;
25     }
26 
27     @Override
setFetchSize(int fetchSize)28     public void setFetchSize(int fetchSize) throws SQLException {
29 	if (fetchSize != 1) {
30 	    throw new SQLException("fetch size not 1");
31 	}
32     }
33 
34     @Override
getFetchSize()35     public int getFetchSize() throws SQLException {
36 	return 1;
37     }
38 
39     @Override
getMaxRows()40     public int getMaxRows() throws SQLException {
41 	return maxrows;
42     }
43 
44     @Override
setMaxRows(int max)45     public void setMaxRows(int max) throws SQLException {
46 	if (max < 0) {
47 	    throw new SQLException("max must be >= 0 (was " + max + ")");
48 	}
49 	maxrows = max;
50     }
51 
52     @Override
setFetchDirection(int fetchDirection)53     public void setFetchDirection(int fetchDirection) throws SQLException {
54 	throw new SQLException("not supported");
55     }
56 
57     @Override
getFetchDirection()58     public int getFetchDirection() throws SQLException {
59 	return ResultSet.FETCH_UNKNOWN;
60     }
61 
62     @Override
getResultSetConcurrency()63     public int getResultSetConcurrency() throws SQLException {
64 	return ResultSet.CONCUR_READ_ONLY;
65     }
66 
67     @Override
getResultSetType()68     public int getResultSetType() throws SQLException {
69 	return ResultSet.TYPE_SCROLL_INSENSITIVE;
70     }
71 
72     @Override
setQueryTimeout(int seconds)73     public void setQueryTimeout(int seconds) throws SQLException {
74 	if (isClosed()) {
75 	    throw new SQLException("can't set query timeout on " +
76 				   "a closed statement");
77 	} else if (seconds < 0) {
78 	    throw new SQLException("can't set a query timeout of " +
79 				   "less than 0 seconds");
80 	} else if (seconds == 0) {
81 	    conn.timeout = 5000;
82 	} else {
83 	    conn.timeout = seconds * 1000;
84 	}
85     }
86 
87     @Override
getQueryTimeout()88     public int getQueryTimeout() throws SQLException {
89 	return conn.timeout / 1000;
90     }
91 
92     @Override
getResultSet()93     public ResultSet getResultSet() throws SQLException {
94 	return rs;
95     }
96 
executeQuery(String sql, String args[], boolean updonly)97     ResultSet executeQuery(String sql, String args[], boolean updonly)
98 	throws SQLException {
99 	SQLite.TableResult tr = null;
100 	if (rs != null) {
101 	    rs.close();
102 	    rs = null;
103 	}
104 	updcnt = -1;
105 	if (conn == null || conn.db == null) {
106 	    throw new SQLException("stale connection");
107 	}
108 	int busy = 0;
109 	boolean starttrans = !conn.autocommit && !conn.intrans;
110 	while (true) {
111 	    try {
112 		if (starttrans) {
113 		    conn.db.exec("BEGIN TRANSACTION", null);
114 		    conn.intrans = true;
115 		}
116 		if (args == null) {
117 		    if (updonly) {
118 			conn.db.exec(sql, null);
119 		    } else {
120 			tr = conn.db.get_table(sql, maxrows);
121 		    }
122 		} else {
123 		    if (updonly) {
124 			conn.db.exec(sql, null, args);
125 		    } else {
126 			tr = conn.db.get_table(sql, maxrows, args);
127 		    }
128 		}
129 		updcnt = (int) conn.db.changes();
130 	    } catch (SQLite.Exception e) {
131 		if (conn.db.is3() &&
132 		    conn.db.last_error() == SQLite.Constants.SQLITE_BUSY &&
133 		    conn.busy3(conn.db, ++busy)) {
134 		    try {
135 			if (starttrans && conn.intrans) {
136 			    conn.db.exec("ROLLBACK", null);
137 			    conn.intrans = false;
138 			}
139 		    } catch (SQLite.Exception ee) {
140 		    }
141 		    try {
142 			int ms = 20 + busy * 10;
143 			if (ms > 1000) {
144 			    ms = 1000;
145 			}
146 			synchronized (this) {
147 			    this.wait(ms);
148 			}
149 		    } catch (java.lang.Exception eee) {
150 		    }
151 		    continue;
152 		}
153 		throw new SQLException(e);
154 	    }
155 	    break;
156 	}
157 	if (!updonly && tr == null) {
158 	    throw new SQLException("no result set produced");
159 	}
160 	if (!updonly && tr != null) {
161 	    rs = new JDBCResultSet(new TableResultX(tr), this);
162 	}
163 	return rs;
164     }
165 
166     @Override
executeQuery(String sql)167     public ResultSet executeQuery(String sql) throws SQLException {
168 	return executeQuery(sql, null, false);
169     }
170 
171     @Override
execute(String sql)172     public boolean execute(String sql) throws SQLException {
173 	return executeQuery(sql) != null;
174     }
175 
176     @Override
cancel()177     public void cancel() throws SQLException {
178 	if (conn == null || conn.db == null) {
179 	    throw new SQLException("stale connection");
180 	}
181 	conn.db.interrupt();
182     }
183 
184     @Override
clearWarnings()185     public void clearWarnings() throws SQLException {
186     }
187 
188     @Override
getConnection()189     public Connection getConnection() throws SQLException {
190 	return conn;
191     }
192 
193     @Override
addBatch(String sql)194     public void addBatch(String sql) throws SQLException {
195 	if (batch == null) {
196 	    batch = new ArrayList<String>(1);
197 	}
198 	batch.add(sql);
199     }
200 
201     @Override
executeBatch()202     public int[] executeBatch() throws SQLException {
203 	if (batch == null) {
204 	    return new int[0];
205 	}
206 	int[] ret = new int[batch.size()];
207 	for (int i = 0; i < ret.length; i++) {
208 	    ret[i] = EXECUTE_FAILED;
209 	}
210 	int errs = 0;
211 	Exception cause = null;
212 	for (int i = 0; i < ret.length; i++) {
213 	    try {
214 		execute(batch.get(i));
215 		ret[i] = updcnt;
216 	    } catch (SQLException e) {
217 		++errs;
218 		if (cause == null) {
219 		    cause = e;
220 		}
221 	    }
222 	}
223 	if (errs > 0) {
224 	    throw new BatchUpdateException("batch failed", ret, cause);
225 	}
226 	return ret;
227     }
228 
229     @Override
clearBatch()230     public void clearBatch() throws SQLException {
231 	if (batch != null) {
232 	    batch.clear();
233 	    batch = null;
234 	}
235     }
236 
237     @Override
close()238     public void close() throws SQLException {
239 	clearBatch();
240 	conn = null;
241     }
242 
243     @Override
executeUpdate(String sql)244     public int executeUpdate(String sql) throws SQLException {
245 	executeQuery(sql, null, true);
246 	return updcnt;
247     }
248 
249     @Override
getMaxFieldSize()250     public int getMaxFieldSize() throws SQLException {
251 	return 0;
252     }
253 
254     @Override
getMoreResults()255     public boolean getMoreResults() throws SQLException {
256 	if (rs != null) {
257 	    rs.close();
258 	    rs = null;
259 	}
260 	return false;
261     }
262 
263     @Override
getUpdateCount()264     public int getUpdateCount() throws SQLException {
265 	return updcnt;
266     }
267 
268     @Override
getWarnings()269     public SQLWarning getWarnings() throws SQLException {
270 	return null;
271     }
272 
273     @Override
setCursorName(String name)274     public void setCursorName(String name) throws SQLException {
275 	throw new SQLFeatureNotSupportedException();
276     }
277 
278     @Override
setEscapeProcessing(boolean enable)279     public void setEscapeProcessing(boolean enable) throws SQLException {
280 	throw new SQLException("not supported");
281     }
282 
283     @Override
setMaxFieldSize(int max)284     public void setMaxFieldSize(int max) throws SQLException {
285 	throw new SQLException("not supported");
286     }
287 
288     @Override
getMoreResults(int x)289     public boolean getMoreResults(int x) throws SQLException {
290 	throw new SQLFeatureNotSupportedException();
291     }
292 
293     @Override
getGeneratedKeys()294     public ResultSet getGeneratedKeys() throws SQLException {
295 	throw new SQLFeatureNotSupportedException();
296     }
297 
298     @Override
executeUpdate(String sql, int autokeys)299     public int executeUpdate(String sql, int autokeys)
300 	throws SQLException {
301 	if (autokeys != Statement.NO_GENERATED_KEYS) {
302 	    throw new SQLFeatureNotSupportedException("generated keys not supported");
303 	}
304 	return executeUpdate(sql);
305     }
306 
307     @Override
executeUpdate(String sql, int colIndexes[])308     public int executeUpdate(String sql, int colIndexes[])
309 	throws SQLException {
310 	throw new SQLFeatureNotSupportedException();
311     }
312 
313     @Override
executeUpdate(String sql, String colIndexes[])314     public int executeUpdate(String sql, String colIndexes[])
315 	throws SQLException {
316 	throw new SQLFeatureNotSupportedException();
317     }
318 
319     @Override
execute(String sql, int autokeys)320     public boolean execute(String sql, int autokeys)
321 	throws SQLException {
322 	if (autokeys != Statement.NO_GENERATED_KEYS) {
323 	    throw new SQLFeatureNotSupportedException("autogenerated keys not supported");
324 	}
325 	return execute(sql);
326     }
327 
328     @Override
execute(String sql, int colIndexes[])329     public boolean execute(String sql, int colIndexes[])
330 	throws SQLException {
331 	throw new SQLFeatureNotSupportedException();
332     }
333 
334     @Override
execute(String sql, String colIndexes[])335     public boolean execute(String sql, String colIndexes[])
336 	throws SQLException {
337 	throw new SQLFeatureNotSupportedException();
338     }
339 
340     @Override
getResultSetHoldability()341     public int getResultSetHoldability() throws SQLException {
342 	return ResultSet.HOLD_CURSORS_OVER_COMMIT;
343     }
344 
345     @Override
isClosed()346     public boolean isClosed() throws SQLException {
347 	return conn == null;
348     }
349 
350     @Override
setPoolable(boolean yes)351     public void setPoolable(boolean yes) throws SQLException {
352 	if (yes) {
353 	    throw new SQLException("poolable statements not supported");
354 	}
355     }
356 
357     @Override
isPoolable()358     public boolean isPoolable() throws SQLException {
359 	return false;
360     }
361 
362     @Override
unwrap(java.lang.Class<T> iface)363     public <T> T unwrap(java.lang.Class<T> iface) throws SQLException {
364 	throw new SQLException("unsupported");
365     }
366 
367     @Override
isWrapperFor(java.lang.Class iface)368     public boolean isWrapperFor(java.lang.Class iface) throws SQLException {
369 	return false;
370     }
371 
372     @Override
closeOnCompletion()373     public void closeOnCompletion() throws SQLException {
374 	throw new SQLFeatureNotSupportedException();
375     }
376 
377     @Override
isCloseOnCompletion()378     public boolean isCloseOnCompletion() throws SQLException {
379 	throw new SQLFeatureNotSupportedException();
380     }
381 
382 }
383