Imported Upstream version 5.3.21
[platform/upstream/libdb.git] / lang / sql / jdbc / SQLite / JDBC2y / JDBCConnection.java
1 package SQLite.JDBC2y;
2
3 import java.sql.Array;
4 import java.sql.Blob;
5 import java.sql.CallableStatement;
6 import java.sql.Clob;
7 import java.sql.DatabaseMetaData;
8 import java.sql.PreparedStatement;
9 import java.sql.ResultSet;
10 import java.sql.SQLException;
11 import java.sql.SQLWarning;
12 import java.sql.Savepoint;
13 import java.sql.Statement;
14 import java.sql.Struct;
15 import java.util.Properties;
16
17 public class JDBCConnection
18     implements java.sql.Connection, SQLite.BusyHandler {
19
20     /**
21      * Open database.
22      */
23     protected DatabaseX db;
24
25     /**
26      * Database URL.
27      */
28     protected String url;
29
30     /**
31      * Character encoding.
32      */
33     protected String enc;
34
35     /**
36      * SQLite 3 VFS to use.
37      */
38     protected String vfs;
39
40     /**
41      * Autocommit flag, true means autocommit.
42      */
43     protected boolean autocommit = true;
44
45     /**
46      * In-transaction flag.
47      * Can be true only when autocommit false.
48      */
49     protected boolean intrans = false;
50
51     /**
52      * Timeout for Database.exec()
53      */
54     protected int timeout = 1000000;
55
56     /**
57      * Use double/julian date representation.
58      */
59     protected boolean useJulian = false;
60
61     /**
62      * File name of database.
63      */
64     private String dbfile = null;
65
66     /**
67      * Reference to meta data or null.
68      */
69     private JDBCDatabaseMetaData meta = null;
70
71     /**
72      * Base time value for timeout handling.
73      */
74     private long t0;
75
76     /**
77      * Database in readonly mode.
78      */
79     private boolean readonly = false;
80
81     /**
82      * Transaction isolation mode.
83      */
84     private int trmode = TRANSACTION_SERIALIZABLE;
85
86     private boolean busy0(DatabaseX db, int count) {
87         if (count <= 1) {
88             t0 = System.currentTimeMillis();
89         }
90         if (db != null) {
91             long t1 = System.currentTimeMillis();
92             if (t1 - t0 > timeout) {
93                 return false;
94             }
95             db.wait(100);
96             return true;
97         }
98         return false;
99     }
100
101     public boolean busy(String table, int count) {
102         return busy0(db, count);
103     }
104
105     protected boolean busy3(DatabaseX db, int count) {
106         if (count <= 1) {
107             t0 = System.currentTimeMillis();
108         }
109         if (db != null) {
110             long t1 = System.currentTimeMillis();
111             if (t1 - t0 > timeout) {
112                 return false;
113             }
114             return true;
115         }
116         return false;
117     }
118
119     private DatabaseX open(boolean readonly) throws SQLException {
120         DatabaseX dbx = null;
121         try {
122             dbx = new DatabaseX();
123             dbx.open(dbfile, readonly ? SQLite.Constants.SQLITE_OPEN_READONLY :
124                      (SQLite.Constants.SQLITE_OPEN_READWRITE |
125                       SQLite.Constants.SQLITE_OPEN_CREATE), vfs);
126             dbx.set_encoding(enc);
127         } catch (SQLite.Exception e) {
128             throw new SQLException(e.toString());
129         }
130         int loop = 0;
131         while (true) {
132             try {
133                 dbx.exec("PRAGMA short_column_names = off;", null);
134                 dbx.exec("PRAGMA full_column_names = on;", null);
135                 dbx.exec("PRAGMA empty_result_callbacks = on;", null);
136                 if (SQLite.Database.version().compareTo("2.6.0") >= 0) {
137                     dbx.exec("PRAGMA show_datatypes = on;", null);
138                 }
139             } catch (SQLite.Exception e) {
140                 if (dbx.last_error() != SQLite.Constants.SQLITE_BUSY ||
141                     !busy0(dbx, ++loop)) {
142                     try {
143                         dbx.close();
144                     } catch (SQLite.Exception ee) {
145                     }
146                     throw new SQLException(e.toString());
147                 }
148                 continue;
149             }
150             break;
151         }
152         return dbx;
153     }
154
155     public JDBCConnection(String url, String enc, String pwd, String drep,
156                           String vfs)
157         throws SQLException {
158         if (url.startsWith("sqlite:/")) {
159             dbfile = url.substring(8);
160         } else if (url.startsWith("jdbc:sqlite:/")) {
161             dbfile = url.substring(13);
162         } else {
163             throw new SQLException("unsupported url");
164         }
165         this.url = url;
166         this.enc = enc;
167         this.vfs = vfs;
168         try {
169             db = open(readonly);
170             try {
171                 if (pwd != null && pwd.length() > 0) {
172                     db.key(pwd);
173                 }
174             } catch (SQLite.Exception se) {
175                 throw new
176                     SQLException("error while setting key: " + se.toString());
177             }
178             db.busy_handler(this);
179         } catch (SQLException e) {
180             if (db != null) {
181                 try {
182                     db.close();
183                 } catch (SQLite.Exception ee) {
184                 }
185             }
186             throw e;
187         }
188         useJulian = drep != null &&
189             (drep.startsWith("j") || drep.startsWith("J"));
190     }
191
192     /* non-standard */
193     public SQLite.Database getSQLiteDatabase() {
194         return db;
195     }
196   
197     public Statement createStatement() {
198         JDBCStatement s = new JDBCStatement(this);
199         return s;
200     }
201
202     public Statement createStatement(int resultSetType,
203                                      int resultSetConcurrency)
204         throws SQLException {
205         if (resultSetType != ResultSet.TYPE_FORWARD_ONLY &&
206             resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE &&
207             resultSetType != ResultSet.TYPE_SCROLL_SENSITIVE) {
208             throw new SQLException("unsupported result set type");
209         }
210         if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY &&
211             resultSetConcurrency != ResultSet.CONCUR_UPDATABLE) {
212             throw new SQLException("unsupported result set concurrency");
213         }
214         JDBCStatement s = new JDBCStatement(this);
215         return s;
216     }
217         
218     public DatabaseMetaData getMetaData() throws SQLException {
219         if (meta == null) {
220             meta = new JDBCDatabaseMetaData(this);
221         }
222         return meta;
223     }
224
225     public void close() throws SQLException {
226         try {
227             rollback();
228         } catch (SQLException e) {
229             /* ignored */
230         }
231         intrans = false;
232         if (db != null) {
233             try {
234                 db.close();
235                 db = null;
236             } catch (SQLite.Exception e) {
237                 throw new SQLException(e.toString());
238             }
239         }
240     }
241
242     public boolean isClosed() throws SQLException {
243         return db == null;
244     }
245
246     public boolean isReadOnly() throws SQLException {
247         return readonly;
248     }
249
250     public void clearWarnings() throws SQLException {
251     }
252
253     public void commit() throws SQLException {
254         if (db == null) {
255             throw new SQLException("stale connection");
256         }
257         if (!intrans) {
258             return;
259         }
260         try {
261             db.exec("COMMIT", null);
262             intrans = false;
263         } catch (SQLite.Exception e) {
264             throw new SQLException(e.toString());
265         }
266     }
267
268     public boolean getAutoCommit() throws SQLException {
269         return autocommit;
270     }
271
272     public String getCatalog() throws SQLException {
273         return null;
274     }
275
276     public int getTransactionIsolation() throws SQLException {
277         return trmode;
278     }
279
280     public SQLWarning getWarnings() throws SQLException {
281         return null;
282     }
283
284     public String nativeSQL(String sql) throws SQLException {
285         throw new SQLException("not supported");
286     }
287
288     public CallableStatement prepareCall(String sql) throws SQLException {
289         throw new SQLException("not supported");
290     }
291
292     public CallableStatement prepareCall(String sql, int x, int y)
293         throws SQLException {
294         throw new SQLException("not supported");
295     }
296
297     public PreparedStatement prepareStatement(String sql) throws SQLException {
298         JDBCPreparedStatement s = new JDBCPreparedStatement(this, sql);
299         return s;
300     }
301
302     public PreparedStatement prepareStatement(String sql, int resultSetType,
303                                               int resultSetConcurrency)
304         throws SQLException {
305         if (resultSetType != ResultSet.TYPE_FORWARD_ONLY &&
306             resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE &&
307             resultSetType != ResultSet.TYPE_SCROLL_SENSITIVE) {
308             throw new SQLException("unsupported result set type");
309         }
310         if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY &&
311             resultSetConcurrency != ResultSet.CONCUR_UPDATABLE) {
312             throw new SQLException("unsupported result set concurrency");
313         }
314         JDBCPreparedStatement s = new JDBCPreparedStatement(this, sql);
315         return s;
316     }
317
318     public void rollback() throws SQLException {
319         if (db == null) {
320             throw new SQLException("stale connection");
321         }
322         if (!intrans) {
323             return;
324         }
325         try {
326             db.exec("ROLLBACK", null);
327             intrans = false;
328         } catch (SQLite.Exception e) {
329             throw new SQLException(e.toString());
330         }
331     }
332
333     public void setAutoCommit(boolean ac) throws SQLException {
334         if (ac && intrans && db != null) {
335             try {
336                 db.exec("ROLLBACK", null);
337             } catch (SQLite.Exception e) {
338                 throw new SQLException(e.toString());
339             } finally {
340                 intrans = false;
341             }
342         }
343         autocommit = ac;
344     }
345
346     public void setCatalog(String catalog) throws SQLException {
347     }
348
349     public void setReadOnly(boolean ro) throws SQLException {
350         if (intrans) {
351             throw new SQLException("incomplete transaction");
352         }
353         if (ro != readonly) {
354             DatabaseX dbx = null;
355             try {
356                 dbx = open(ro);
357                 db.close();
358                 db = dbx;
359                 dbx = null;
360                 readonly = ro;
361             } catch (SQLException e) {
362                 throw e;
363             } catch (SQLite.Exception ee) {
364                 if (dbx != null) {
365                     try {
366                         dbx.close();
367                     } catch (SQLite.Exception eee) {
368                     }
369                 }
370                 throw new SQLException(ee.toString());
371             }
372         }
373     }
374
375     public void setTransactionIsolation(int level) throws SQLException {
376         if (db.is3() && SQLite.JDBC.sharedCache) {
377             String flag = null;
378             if (level == TRANSACTION_READ_UNCOMMITTED &&
379                 trmode != TRANSACTION_READ_UNCOMMITTED) {
380                 flag = "on";
381             } else if (level == TRANSACTION_SERIALIZABLE &&
382                        trmode != TRANSACTION_SERIALIZABLE) {
383                 flag = "off";
384             }
385             if (flag != null) {
386                 try {
387                     db.exec("PRAGMA read_uncommitted = " + flag + ";", null);
388                     trmode = level;
389                 } catch (java.lang.Exception e) {
390                 }
391             }
392         }
393         if (level != trmode) {
394             throw new SQLException("not supported");
395         }
396     }
397
398     public java.util.Map<String, Class<?>> getTypeMap() throws SQLException {
399         throw new SQLException("not supported");
400     }
401
402     public void setTypeMap(java.util.Map map) throws SQLException {
403         throw new SQLException("not supported");
404     }
405   
406     public int getHoldability() throws SQLException {
407         return ResultSet.HOLD_CURSORS_OVER_COMMIT;
408     }
409
410     public void setHoldability(int holdability) throws SQLException {
411         if (holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT) {
412             return;
413         }
414         throw new SQLException("not supported");
415     }
416
417     public Savepoint setSavepoint() throws SQLException {
418         throw new SQLException("not supported");
419     }
420
421     public Savepoint setSavepoint(String name) throws SQLException {
422         throw new SQLException("not supported");
423     }
424
425     public void rollback(Savepoint x) throws SQLException {
426         throw new SQLException("not supported");
427     }
428
429     public void releaseSavepoint(Savepoint x) throws SQLException {
430         throw new SQLException("not supported");
431     }
432
433     public Statement createStatement(int resultSetType,
434                                      int resultSetConcurrency,
435                                      int resultSetHoldability)
436         throws SQLException {
437         if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
438             throw new SQLException("not supported");
439         }
440         return createStatement(resultSetType, resultSetConcurrency);
441     }
442
443     public PreparedStatement prepareStatement(String sql, int resultSetType,
444                                               int resultSetConcurrency,
445                                               int resultSetHoldability)
446         throws SQLException {
447         if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
448             throw new SQLException("not supported");
449         }
450         return prepareStatement(sql, resultSetType, resultSetConcurrency);
451     }
452
453     public CallableStatement prepareCall(String sql, int x, int y, int z)
454         throws SQLException {
455         throw new SQLException("not supported");
456     }
457
458     public PreparedStatement prepareStatement(String sql, int autokeys)
459         throws SQLException {
460         if (autokeys != Statement.NO_GENERATED_KEYS) {
461             throw new SQLException("not supported");
462         }
463         return prepareStatement(sql);
464     }
465
466     public PreparedStatement prepareStatement(String sql, int colIndexes[])
467         throws SQLException {
468         throw new SQLException("not supported");
469     }
470
471     public PreparedStatement prepareStatement(String sql, String columns[])
472         throws SQLException {
473         throw new SQLException("not supported");
474     }
475
476 }
477
478 class DatabaseX extends SQLite.Database {
479
480     static Object lock = new Object();
481
482     public DatabaseX() {
483         super();
484     }
485
486     void wait(int ms) {
487         try {
488             synchronized (lock) {
489                 lock.wait(ms);
490             }
491         } catch (java.lang.Exception e) {
492         }
493     }
494
495     public void exec(String sql, SQLite.Callback cb)
496         throws SQLite.Exception {
497         super.exec(sql, cb);
498         synchronized (lock) {
499             lock.notifyAll();
500         }
501     }
502
503     public void exec(String sql, SQLite.Callback cb, String args[])
504         throws SQLite.Exception {
505         super.exec(sql, cb, args);
506         synchronized (lock) {
507             lock.notifyAll();
508         }
509     }
510
511     public SQLite.TableResult get_table(String sql, String args[])
512         throws SQLite.Exception {
513         SQLite.TableResult ret = super.get_table(sql, args);
514         synchronized (lock) {
515             lock.notifyAll();
516         }
517         return ret;
518     }
519
520     public void get_table(String sql, String args[], SQLite.TableResult tbl)
521         throws SQLite.Exception {
522         super.get_table(sql, args, tbl);
523         synchronized (lock) {
524             lock.notifyAll();
525         }
526     }
527
528 }