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