| 1 | /* ============================================================= |
| 2 | * SmallSQL : a free Java DBMS library for the Java(tm) platform |
| 3 | * ============================================================= |
| 4 | * |
| 5 | * (C) Copyright 2004-2006, by Volker Berlin. |
| 6 | * |
| 7 | * Project Info: http://www.smallsql.de/ |
| 8 | * |
| 9 | * This library is free software; you can redistribute it and/or modify it |
| 10 | * under the terms of the GNU Lesser General Public License as published by |
| 11 | * the Free Software Foundation; either version 2.1 of the License, or |
| 12 | * (at your option) any later version. |
| 13 | * |
| 14 | * This library is distributed in the hope that it will be useful, but |
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
| 17 | * License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU Lesser General Public |
| 20 | * License along with this library; if not, write to the Free Software |
| 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, |
| 22 | * USA. |
| 23 | * |
| 24 | * [Java is a trademark or registered trademark of Sun Microsystems, Inc. |
| 25 | * in the United States and other countries.] |
| 26 | * |
| 27 | * --------------- |
| 28 | * SSStatement.java |
| 29 | * --------------- |
| 30 | * Author: Volker Berlin |
| 31 | * |
| 32 | */ |
| 33 | package smallsql.database; |
| 34 | |
| 35 | import java.sql.*; |
| 36 | import java.util.ArrayList; |
| 37 | |
| 38 | |
| 39 | class SSStatement implements Statement { |
| 40 | |
| 41 | final SSConnection con; |
| 42 | Command cmd; |
| 43 | int rsType; |
| 44 | int rsConcurrency; |
| 45 | private int fetchDirection; |
| 46 | private int fetchSize; |
| 47 | private int queryTimeout; |
| 48 | private int maxRows; |
| 49 | private int maxFieldSize; |
| 50 | private ArrayList batches; |
| 51 | private boolean needGeneratedKeys; |
| 52 | private ResultSet generatedKeys; |
| 53 | private int[] generatedKeyIndexes; |
| 54 | private String[] generatedKeyNames; |
| 55 | |
| 56 | |
| 57 | SSStatement( SSConnection con ) throws SQLException{ |
| 58 | this( con, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY ); |
| 59 | } |
| 60 | |
| 61 | SSStatement( SSConnection con, int rsType, int rsConcurrency ) throws SQLException{ |
| 62 | this.con = con; |
| 63 | this.rsType = rsType; |
| 64 | this.rsConcurrency = rsConcurrency; |
| 65 | con.testClosedConnection(); |
| 66 | } |
| 67 | |
| 68 | final public ResultSet executeQuery(String sql) throws SQLException { |
| 69 | executeImpl(sql); |
| 70 | return cmd.getQueryResult(); |
| 71 | } |
| 72 | final public int executeUpdate(String sql) throws SQLException { |
| 73 | executeImpl(sql); |
| 74 | return cmd.getUpdateCount(); |
| 75 | } |
| 76 | final public boolean execute(String sql) throws SQLException { |
| 77 | executeImpl(sql); |
| 78 | return cmd.getResultSet() != null; |
| 79 | } |
| 80 | |
| 81 | final private void executeImpl(String sql) throws SQLException { |
| 82 | generatedKeys = null; |
| 83 | try{ |
| 84 | con.log.println(sql); |
| 85 | SQLParser parser = new SQLParser(); |
| 86 | cmd = parser.parse( con, sql ); |
| 87 | if(maxRows != 0 && (cmd.getMaxRows() == 0 || cmd.getMaxRows() > maxRows)) |
| 88 | cmd.setMaxRows(maxRows); |
| 89 | cmd.execute( con, this); |
| 90 | }catch(Exception e){ |
| 91 | throw Utils.createSQLException(e); |
| 92 | } |
| 93 | needGeneratedKeys = false; |
| 94 | generatedKeyIndexes = null; |
| 95 | generatedKeyNames = null; |
| 96 | } |
| 97 | |
| 98 | final public void close() throws SQLException { |
| 99 | } |
| 100 | final public int getMaxFieldSize() throws SQLException { |
| 101 | return maxFieldSize; |
| 102 | } |
| 103 | final public void setMaxFieldSize(int max) throws SQLException { |
| 104 | maxFieldSize = max; |
| 105 | } |
| 106 | final public int getMaxRows(){ |
| 107 | return maxRows; |
| 108 | } |
| 109 | |
| 110 | |
| 111 | final public void setMaxRows(int max) throws SQLException{ |
| 112 | if(max<0) |
| 113 | throw Utils.createSQLException("Wrong max rows value:"+max); |
| 114 | maxRows = max; |
| 115 | } |
| 116 | |
| 117 | |
| 118 | final public void setEscapeProcessing(boolean enable) throws SQLException { |
| 119 | } |
| 120 | |
| 121 | |
| 122 | final public int getQueryTimeout() throws SQLException { |
| 123 | return queryTimeout; |
| 124 | } |
| 125 | final public void setQueryTimeout(int seconds) throws SQLException { |
| 126 | queryTimeout = seconds; |
| 127 | } |
| 128 | final public void cancel() throws SQLException { |
| 129 | } |
| 130 | final public SQLWarning getWarnings() throws SQLException { |
| 131 | return null; |
| 132 | } |
| 133 | final public void clearWarnings() throws SQLException { |
| 134 | } |
| 135 | final public void setCursorName(String name) throws SQLException { |
| 136 | /**@todo: Implement this java.sql.Statement method*/ |
| 137 | throw new java.lang.UnsupportedOperationException("Method setCursorName() not yet implemented."); |
| 138 | } |
| 139 | final public ResultSet getResultSet() throws SQLException { |
| 140 | return cmd.getResultSet(); |
| 141 | } |
| 142 | |
| 143 | |
| 144 | final public int getUpdateCount() throws SQLException { |
| 145 | return cmd.getUpdateCount(); |
| 146 | } |
| 147 | |
| 148 | |
| 149 | final public boolean getMoreResults() throws SQLException { |
| 150 | return getMoreResults(CLOSE_CURRENT_RESULT); |
| 151 | } |
| 152 | |
| 153 | |
| 154 | final public void setFetchDirection(int direction) throws SQLException { |
| 155 | fetchDirection = direction; |
| 156 | } |
| 157 | final public int getFetchDirection() throws SQLException { |
| 158 | return fetchDirection; |
| 159 | } |
| 160 | final public void setFetchSize(int rows) throws SQLException { |
| 161 | fetchSize = rows; |
| 162 | } |
| 163 | final public int getFetchSize() throws SQLException { |
| 164 | return fetchSize; |
| 165 | } |
| 166 | final public int getResultSetConcurrency() throws SQLException { |
| 167 | return rsConcurrency; |
| 168 | } |
| 169 | final public int getResultSetType() throws SQLException { |
| 170 | return rsType; |
| 171 | } |
| 172 | |
| 173 | |
| 174 | final public void addBatch(String sql){ |
| 175 | if(batches == null) batches = new ArrayList(); |
| 176 | batches.add(sql); |
| 177 | } |
| 178 | |
| 179 | |
| 180 | public void clearBatch(){ |
| 181 | if(batches == null) return; |
| 182 | batches.clear(); |
| 183 | } |
| 184 | |
| 185 | |
| 186 | public int[] executeBatch() throws BatchUpdateException { |
| 187 | if(batches == null) return new int[0]; |
| 188 | final int[] result = new int[batches.size()]; |
| 189 | BatchUpdateException failed = null; |
| 190 | for(int i=0; i<result.length; i++){ |
| 191 | try { |
| 192 | result[i] = executeUpdate((String)batches.get(i)); |
| 193 | } catch (SQLException ex) { |
| 194 | result[i] = EXECUTE_FAILED; |
| 195 | if(failed == null){ |
| 196 | failed = new BatchUpdateException(ex.getMessage(), ex.getSQLState(), ex.getErrorCode(), result); |
| 197 | failed.initCause(ex); |
| 198 | } |
| 199 | failed.setNextException(ex); |
| 200 | } |
| 201 | } |
| 202 | batches.clear(); |
| 203 | if(failed != null) |
| 204 | throw failed; |
| 205 | return result; |
| 206 | } |
| 207 | |
| 208 | |
| 209 | final public Connection getConnection(){ |
| 210 | return con; |
| 211 | } |
| 212 | |
| 213 | |
| 214 | final public boolean getMoreResults(int current) throws SQLException { |
| 215 | switch(current){ |
| 216 | case CLOSE_ALL_RESULTS: |
| 217 | //currently there exists only one ResultSet |
| 218 | case CLOSE_CURRENT_RESULT: |
| 219 | ResultSet rs = cmd.getResultSet(); |
| 220 | cmd.rs = null; |
| 221 | if(rs != null) rs.close(); |
| 222 | break; |
| 223 | case KEEP_CURRENT_RESULT: |
| 224 | break; |
| 225 | default: |
| 226 | throw Utils.createSQLException("Invalid flag value in method getMoreResults:"+current); |
| 227 | } |
| 228 | return false; |
| 229 | } |
| 230 | |
| 231 | |
| 232 | final void setNeedGeneratedKeys(int autoGeneratedKeys) throws SQLException{ |
| 233 | switch(autoGeneratedKeys){ |
| 234 | case NO_GENERATED_KEYS: |
| 235 | break; |
| 236 | case RETURN_GENERATED_KEYS: |
| 237 | needGeneratedKeys = true; |
| 238 | break; |
| 239 | default: |
| 240 | throw Utils.createSQLException("Invalid argument:"+autoGeneratedKeys); |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | |
| 245 | final void setNeedGeneratedKeys(int[] columnIndexes) throws SQLException{ |
| 246 | needGeneratedKeys = columnIndexes != null; |
| 247 | generatedKeyIndexes = columnIndexes; |
| 248 | } |
| 249 | |
| 250 | |
| 251 | final void setNeedGeneratedKeys(String[] columnNames) throws SQLException{ |
| 252 | needGeneratedKeys = columnNames != null; |
| 253 | generatedKeyNames = columnNames; |
| 254 | } |
| 255 | |
| 256 | |
| 257 | final boolean needGeneratedKeys(){ |
| 258 | return needGeneratedKeys; |
| 259 | } |
| 260 | |
| 261 | |
| 262 | final int[] getGeneratedKeyIndexes(){ |
| 263 | return generatedKeyIndexes; |
| 264 | } |
| 265 | |
| 266 | |
| 267 | final String[] getGeneratedKeyNames(){ |
| 268 | return generatedKeyNames; |
| 269 | } |
| 270 | |
| 271 | |
| 272 | /** |
| 273 | * Set on execution the result with the genrated keys. |
| 274 | * @param rs |
| 275 | */ |
| 276 | final void setGeneratedKeys(ResultSet rs){ |
| 277 | generatedKeys = rs; |
| 278 | } |
| 279 | |
| 280 | |
| 281 | final public ResultSet getGeneratedKeys() throws SQLException { |
| 282 | if(generatedKeys == null) |
| 283 | throw Utils.createSQLException("GeneratedKeys not requested"); |
| 284 | return generatedKeys; |
| 285 | } |
| 286 | |
| 287 | |
| 288 | final public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { |
| 289 | setNeedGeneratedKeys(autoGeneratedKeys); |
| 290 | return executeUpdate(sql); |
| 291 | } |
| 292 | |
| 293 | |
| 294 | final public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { |
| 295 | setNeedGeneratedKeys(columnIndexes); |
| 296 | return executeUpdate(sql); |
| 297 | } |
| 298 | |
| 299 | |
| 300 | final public int executeUpdate(String sql, String[] columnNames) throws SQLException { |
| 301 | setNeedGeneratedKeys(columnNames); |
| 302 | return executeUpdate(sql); |
| 303 | } |
| 304 | |
| 305 | |
| 306 | final public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { |
| 307 | setNeedGeneratedKeys(autoGeneratedKeys); |
| 308 | return execute(sql); |
| 309 | } |
| 310 | |
| 311 | |
| 312 | final public boolean execute(String sql, int[] columnIndexes) throws SQLException { |
| 313 | setNeedGeneratedKeys(columnIndexes); |
| 314 | return execute(sql); |
| 315 | } |
| 316 | |
| 317 | |
| 318 | final public boolean execute(String sql, String[] columnNames) throws SQLException { |
| 319 | setNeedGeneratedKeys(columnNames); |
| 320 | return execute(sql); |
| 321 | } |
| 322 | |
| 323 | |
| 324 | final public int getResultSetHoldability() throws SQLException { |
| 325 | /**@todo: Implement this java.sql.Statement method*/ |
| 326 | throw new java.lang.UnsupportedOperationException("Method getResultSetHoldability() not yet implemented."); |
| 327 | } |
| 328 | } |