SQLite Android Bindings
Check-in [409082dd02]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add support for SEE, SQLite's encryption extension.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | openseedatabase
Files: files | file ages | folders
SHA1: 409082dd022e00be70f0fc9497926550927b21d8
User & Date: dan 2013-12-23 18:23:37
Context
2013-12-24
10:14
Add extra SEE tests. Leaf check-in: 6f17178a68 user: dan tags: openseedatabase
2013-12-23
18:23
Add support for SEE, SQLite's encryption extension. check-in: 409082dd02 user: dan tags: openseedatabase
07:33
Add extra required utility functions to ExtraUtils.java. check-in: be6acc5363 user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to jni/Android.mk.

3
4
5
6
7
8
9

10
11
12
13
14
15
16
17
18
19
20
21
22







23
24
25
26
27
28
29
30
31

LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
LOCAL_CFLAGS += -U__APPLE__
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
LOCAL_CPPFLAGS += -Wno-conversion-null


ifeq ($(TARGET_ARCH), arm)
	LOCAL_CFLAGS += -DPACKED="__attribute__ ((packed))"
else
	LOCAL_CFLAGS += -DPACKED=""
endif

LOCAL_SRC_FILES:=                             \
	android_database_SQLiteCommon.cpp     \
	android_database_SQLiteConnection.cpp \
	android_database_SQLiteGlobal.cpp     \
	android_database_SQLiteDebug.cpp      \
	JNIHelp.cpp JniConstants.cpp          \







	sqlite3.c

LOCAL_C_INCLUDES += nativehelper/

LOCAL_MODULE:= libsqliteX
LOCAL_LDLIBS += -ldl -llog 

include $(BUILD_SHARED_LIBRARY)








>












|
>
>
>
>
>
>
>
|








3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
LOCAL_CFLAGS += -U__APPLE__
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
LOCAL_CPPFLAGS += -Wno-conversion-null


ifeq ($(TARGET_ARCH), arm)
	LOCAL_CFLAGS += -DPACKED="__attribute__ ((packed))"
else
	LOCAL_CFLAGS += -DPACKED=""
endif

LOCAL_SRC_FILES:=                             \
	android_database_SQLiteCommon.cpp     \
	android_database_SQLiteConnection.cpp \
	android_database_SQLiteGlobal.cpp     \
	android_database_SQLiteDebug.cpp      \
	JNIHelp.cpp JniConstants.cpp

#
# For a SEE build, add the SEE sources to the tree and uncomment the first
# two of the following three lines.

#LOCAL_SRC_FILES += sqlite3-see.c
#LOCAL_CFLAGS    += -DSQLITE_HAS_CODEC
LOCAL_SRC_FILES += sqlite3.c

LOCAL_C_INCLUDES += nativehelper/

LOCAL_MODULE:= libsqliteX
LOCAL_LDLIBS += -ldl -llog 

include $(BUILD_SHARED_LIBRARY)

Changes to jni/android_database_SQLiteConnection.cpp.

849
850
851
852
853
854
855
























856
857
858
859
860
861
862
...
905
906
907
908
909
910
911


912
913
914
915
916
917
918
        sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback,
                connection);
    } else {
        sqlite3_progress_handler(connection->db, 0, NULL, NULL);
    }
}


























static JNINativeMethod sMethods[] =
{
    /* name, signature, funcPtr */
    { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)I",
            (void*)nativeOpen },
    { "nativeClose", "(I)V",
................................................................................
            (void*)nativeExecuteForCursorWindow },
    { "nativeGetDbLookaside", "(I)I",
            (void*)nativeGetDbLookaside },
    { "nativeCancel", "(I)V",
            (void*)nativeCancel },
    { "nativeResetCancel", "(IZ)V",
            (void*)nativeResetCancel },


};

#define FIND_CLASS(var, className) \
        var = env->FindClass(className); \
        LOG_FATAL_IF(! var, "Unable to find class " className);

#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>







849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
...
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
        sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback,
                connection);
    } else {
        sqlite3_progress_handler(connection->db, 0, NULL, NULL);
    }
}

static void nativeSetSeeKey(JNIEnv *pEnv, jobject clazz, jint connectionPtr, jstring zKey){
  SQLiteConnection* p = reinterpret_cast<SQLiteConnection*>(connectionPtr);
  sqlite3_stmt *pStmt = 0;
  int rc;

  const char *zUtf8 = pEnv->GetStringUTFChars(zKey, 0);
  char *zSql = sqlite3_mprintf("PRAGMA key = '%q'", zUtf8);

  ALOG(LOG_ERROR, SQLITE_TRACE_TAG, "nativeSetSeeKey: %s", zSql);

  rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
  if( rc==SQLITE_OK ){
    sqlite3_step(pStmt);
    rc = sqlite3_finalize(pStmt);
  }
  
  pEnv->ReleaseStringUTFChars(zKey, zUtf8);
  sqlite3_free(zSql);

  if( rc!=SQLITE_OK ){
    char *zErr = sqlite3_mprintf("nativeSetSeeKey %d \"%s\"", rc, sqlite3_errmsg(p->db));
    throw_sqlite3_exception(pEnv, p->db, zErr);
  }
}

static JNINativeMethod sMethods[] =
{
    /* name, signature, funcPtr */
    { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)I",
            (void*)nativeOpen },
    { "nativeClose", "(I)V",
................................................................................
            (void*)nativeExecuteForCursorWindow },
    { "nativeGetDbLookaside", "(I)I",
            (void*)nativeGetDbLookaside },
    { "nativeCancel", "(I)V",
            (void*)nativeCancel },
    { "nativeResetCancel", "(IZ)V",
            (void*)nativeResetCancel },

    { "nativeSetSeeKey", "(ILjava/lang/String;)V", (void*)nativeSetSeeKey },
};

#define FIND_CLASS(var, className) \
        var = env->FindClass(className); \
        LOG_FATAL_IF(! var, "Unable to find class " className);

#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \

Changes to src/org/sqlite/app/customsqlite/CustomSqlite.java.

3
4
5
6
7
8
9




10
11
12
13
14
15
16
..
18
19
20
21
22
23
24


25
26
27
28
29
30
31
..
56
57
58
59
60
61
62



























63
64
65
66
67

68
69
70
71
72
73
74
75
..
80
81
82
83
84
85
86
87



























88
89


90
91
92
93
94
95
96
97


98
99
100
101
102
103
104
105
106
107

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;





import org.sqlite.database.sqlite.SQLiteDatabase;
import org.sqlite.database.sqlite.SQLiteStatement;

import android.database.Cursor;

/*
import android.database.sqlite.SQLiteDatabase;
................................................................................
*/

public class CustomSqlite extends Activity
{
  private TextView myTV;          /* Text view widget */
  private int myNTest;            /* Number of tests attempted */
  private int myNErr;             /* Number of tests failed */



  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    myTV = (TextView)findViewById(R.id.tv_widget);
................................................................................
    } else {
      myNErr++;
      myTV.append("FAILED\n");
      myTV.append("   res=     \"" + res + "\"\n");
      myTV.append("   expected=\"" + expected + "\"\n");
    }
  }




























  /*
  ** Use a Cursor to loop through the results of a SELECT query.
  */
  public void csr_test_1(){

    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
    String res = "";

    db.execSQL("CREATE TABLE t1(x)");
    db.execSQL("INSERT INTO t1 VALUES ('one'), ('two'), ('three')");
    
    Cursor c = db.rawQuery("SELECT x FROM t1", null);
    if( c!=null ){
................................................................................
      }
    }else{
      test_warning("csr_test_1", "c==NULL");
    }

    test_result("csr_test_1", res, ".one.two.three");
  }




























  public void run_the_tests(View view){
    System.loadLibrary("sqliteX");



    myTV.setText("");
    myNErr = 0;
    myNTest = 0;

    try {
      report_version();
      csr_test_1();



      myTV.append("\n" + myNErr + " errors from " + myNTest + " tests\n");
    } catch(Exception e) {
      myTV.append("Exception: " + e.toString() + "\n");
      myTV.append(android.util.Log.getStackTraceString(e) + "\n");
    }
  }
}









>
>
>
>







 







>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





>
|







 








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>








>
>










3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import java.io.File;

import java.lang.InterruptedException;

import org.sqlite.database.sqlite.SQLiteDatabase;
import org.sqlite.database.sqlite.SQLiteStatement;

import android.database.Cursor;

/*
import android.database.sqlite.SQLiteDatabase;
................................................................................
*/

public class CustomSqlite extends Activity
{
  private TextView myTV;          /* Text view widget */
  private int myNTest;            /* Number of tests attempted */
  private int myNErr;             /* Number of tests failed */

  File DB_PATH;

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    myTV = (TextView)findViewById(R.id.tv_widget);
................................................................................
    } else {
      myNErr++;
      myTV.append("FAILED\n");
      myTV.append("   res=     \"" + res + "\"\n");
      myTV.append("   expected=\"" + expected + "\"\n");
    }
  }

  /*
  ** Test that a database connection may be accessed from a second thread.
  */
  public void thread_test_1(){
    SQLiteDatabase.deleteDatabase(DB_PATH);
    final SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);

    String db_path2 = DB_PATH.toString() + "2";

    db.execSQL("CREATE TABLE t1(x, y)");
    db.execSQL("INSERT INTO t1 VALUES (1, 2), (3, 4)");

    Thread t = new Thread( new Runnable() {
      public void run() {
        SQLiteStatement st = db.compileStatement("SELECT sum(x+y) FROM t1");
        String res = st.simpleQueryForString();
        test_result("thread_test_1", res, "10");
      }
    });

    t.start();
    try {
      t.join();
    } catch (InterruptedException e) {
    }
  }

  /*
  ** Use a Cursor to loop through the results of a SELECT query.
  */
  public void csr_test_1(){
    SQLiteDatabase.deleteDatabase(DB_PATH);
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
    String res = "";

    db.execSQL("CREATE TABLE t1(x)");
    db.execSQL("INSERT INTO t1 VALUES ('one'), ('two'), ('three')");
    
    Cursor c = db.rawQuery("SELECT x FROM t1", null);
    if( c!=null ){
................................................................................
      }
    }else{
      test_warning("csr_test_1", "c==NULL");
    }

    test_result("csr_test_1", res, ".one.two.three");
  }

  /*
  ** Check that using openSeeDatabase() creates encrypted databases. 
  */
  public void see_test_1(){
    SQLiteDatabase.deleteDatabase(DB_PATH);
    String res = "";
    SQLiteDatabase db = SQLiteDatabase.openSeeDatabase(
        DB_PATH.getPath(), "secretkey", null, SQLiteDatabase.CREATE_IF_NECESSARY, null
    );

    db.execSQL("CREATE TABLE t1(x)");
    db.execSQL("INSERT INTO t1 VALUES ('one'), ('two'), ('three')");
    
    Cursor c = db.rawQuery("SELECT x FROM t1", null);
    if( c!=null ){
      boolean bRes;
      for(bRes=c.moveToFirst(); bRes; bRes=c.moveToNext()){
        String x = c.getString(0);
        res = res + "." + x;
      }
    }else{
      test_warning("see_test_1", "c==NULL");
    }

    test_result("see_test_1", res, ".one.two.three");
  }

  public void run_the_tests(View view){
    System.loadLibrary("sqliteX");
    DB_PATH = getApplicationContext().getDatabasePath("test.db");
    DB_PATH.mkdirs();

    myTV.setText("");
    myNErr = 0;
    myNTest = 0;

    try {
      report_version();
      csr_test_1();
      thread_test_1();
      see_test_1();

      myTV.append("\n" + myNErr + " errors from " + myNTest + " tests\n");
    } catch(Exception e) {
      myTV.append("Exception: " + e.toString() + "\n");
      myTV.append(android.util.Log.getStackTraceString(e) + "\n");
    }
  }
}


Changes to src/org/sqlite/database/sqlite/SQLiteConnection.java.

153
154
155
156
157
158
159

160
161
162
163
164
165
166
...
206
207
208
209
210
211
212





213
214
215
216
217
218
219
...
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
            int connectionPtr, int statementPtr);
    private static native long nativeExecuteForCursorWindow(
            int connectionPtr, int statementPtr, CursorWindow win,
            int startPos, int requiredPos, boolean countAllRows);
    private static native int nativeGetDbLookaside(int connectionPtr);
    private static native void nativeCancel(int connectionPtr);
    private static native void nativeResetCancel(int connectionPtr, boolean cancelable);


    private SQLiteConnection(SQLiteConnectionPool pool,
            SQLiteDatabaseConfiguration configuration,
            int connectionId, boolean primaryConnection) {
        mPool = pool;
        mConfiguration = new SQLiteDatabaseConfiguration(configuration);
        mConnectionId = connectionId;
................................................................................
        dispose(false);
    }

    private void open() {
        mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags,
                mConfiguration.label,
                SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);






        setPageSize();
        setForeignKeyModeFromConfiguration();
        setWalModeFromConfiguration();
        setJournalSizeLimit();
        setAutoCheckpointInterval();
        setLocaleFromConfiguration();
................................................................................
                & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
        boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);

        // Update configuration parameters.
        mConfiguration.updateParametersFrom(configuration);

        // Update prepared statement cache size.
        mPreparedStatementCache.resize(configuration.maxSqlCacheSize);

        // Update foreign key mode.
        if (foreignKeyModeChanged) {
            setForeignKeyModeFromConfiguration();
        }

        // Update WAL.







>







 







>
>
>
>
>







 







|







153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
            int connectionPtr, int statementPtr);
    private static native long nativeExecuteForCursorWindow(
            int connectionPtr, int statementPtr, CursorWindow win,
            int startPos, int requiredPos, boolean countAllRows);
    private static native int nativeGetDbLookaside(int connectionPtr);
    private static native void nativeCancel(int connectionPtr);
    private static native void nativeResetCancel(int connectionPtr, boolean cancelable);
    private static native void nativeSetSeeKey(int connectionPtr, String key);

    private SQLiteConnection(SQLiteConnectionPool pool,
            SQLiteDatabaseConfiguration configuration,
            int connectionId, boolean primaryConnection) {
        mPool = pool;
        mConfiguration = new SQLiteDatabaseConfiguration(configuration);
        mConnectionId = connectionId;
................................................................................
        dispose(false);
    }

    private void open() {
        mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags,
                mConfiguration.label,
                SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);

        if( mConfiguration.bSee ){
          nativeSetSeeKey(mConnectionPtr, mConfiguration.seekey);
          mConfiguration.setSeeKey(null);
        }

        setPageSize();
        setForeignKeyModeFromConfiguration();
        setWalModeFromConfiguration();
        setJournalSizeLimit();
        setAutoCheckpointInterval();
        setLocaleFromConfiguration();
................................................................................
                & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
        boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);

        // Update configuration parameters.
        mConfiguration.updateParametersFrom(configuration);

        // Update prepared statement cache size.
        /* mPreparedStatementCache.resize(configuration.maxSqlCacheSize); */

        // Update foreign key mode.
        if (foreignKeyModeChanged) {
            setForeignKeyModeFromConfiguration();
        }

        // Update WAL.

Changes to src/org/sqlite/database/sqlite/SQLiteConnectionPool.java.

180
181
182
183
184
185
186


187
188
189
190
191
192
193

    // Might throw
    private void open() {
        // Open the primary connection.
        // This might throw if the database is corrupt.
        mAvailablePrimaryConnection = openConnectionLocked(mConfiguration,
                true /*primaryConnection*/); // might throw



        // Mark the pool as being open for business.
        mIsOpen = true;
        mCloseGuard.open("close");
    }

    /**







>
>







180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195

    // Might throw
    private void open() {
        // Open the primary connection.
        // This might throw if the database is corrupt.
        mAvailablePrimaryConnection = openConnectionLocked(mConfiguration,
                true /*primaryConnection*/); // might throw

        mConfiguration.setSeeKey(null);

        // Mark the pool as being open for business.
        mIsOpen = true;
        mCloseGuard.open("close");
    }

    /**

Changes to src/org/sqlite/database/sqlite/SQLiteDatabase.java.

691
692
693
694
695
696
697














698
699
700
701
702
703
704
...
713
714
715
716
717
718
719

720
721
722
723
724
725
726
...
732
733
734
735
736
737
738


739
740
741
742
743
744
745
746
747
748
749
750
751

752
753
754
755
756
757
758
     */
    public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
            DatabaseErrorHandler errorHandler) {
        SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler);
        db.open();
        return db;
    }















    /**
     * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
     */
    public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {
        return openOrCreateDatabase(file.getPath(), factory);
    }
................................................................................
    /**
     * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler).
     */
    public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory,
            DatabaseErrorHandler errorHandler) {
        return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler);
    }


    /**
     * Deletes a database including its journal file and other auxiliary files
     * that may have been created by the database engine.
     *
     * @param file The database file path.
     * @return True if the database was successfully deleted.
................................................................................

        boolean deleted = false;
        deleted |= file.delete();
        deleted |= new File(file.getPath() + "-journal").delete();
        deleted |= new File(file.getPath() + "-shm").delete();
        deleted |= new File(file.getPath() + "-wal").delete();



        File dir = file.getParentFile();
        if (dir != null) {
            final String prefix = file.getName() + "-mj";
            final FileFilter filter = new FileFilter() {
                @Override
                public boolean accept(File candidate) {
                    return candidate.getName().startsWith(prefix);
                }
            };
            for (File masterJournal : dir.listFiles(filter)) {
                deleted |= masterJournal.delete();
            }
        }

        return deleted;
    }

    /**
     * Reopens the database in read-write mode.
     * If the database is already read-write, does nothing.
     *







>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>







 







>
>













>







691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
...
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
     */
    public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
            DatabaseErrorHandler errorHandler) {
        SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler);
        db.open();
        return db;
    }

    public static SQLiteDatabase openSeeDatabase(
      String path, 
      String key, 
      CursorFactory factory, 
      int flags, 
      DatabaseErrorHandler errorHandler
    ){
      SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler);
      db.mConfigurationLocked.setSeeKey(key);
      db.open();
      db.mConfigurationLocked.setSeeKey(null);
      return db;
    }

    /**
     * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
     */
    public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {
        return openOrCreateDatabase(file.getPath(), factory);
    }
................................................................................
    /**
     * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler).
     */
    public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory,
            DatabaseErrorHandler errorHandler) {
        return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler);
    }


    /**
     * Deletes a database including its journal file and other auxiliary files
     * that may have been created by the database engine.
     *
     * @param file The database file path.
     * @return True if the database was successfully deleted.
................................................................................

        boolean deleted = false;
        deleted |= file.delete();
        deleted |= new File(file.getPath() + "-journal").delete();
        deleted |= new File(file.getPath() + "-shm").delete();
        deleted |= new File(file.getPath() + "-wal").delete();

        /* TODO: This is throwing a NullPointerException. Do not know why. */
        /*
        File dir = file.getParentFile();
        if (dir != null) {
            final String prefix = file.getName() + "-mj";
            final FileFilter filter = new FileFilter() {
                @Override
                public boolean accept(File candidate) {
                    return candidate.getName().startsWith(prefix);
                }
            };
            for (File masterJournal : dir.listFiles(filter)) {
                deleted |= masterJournal.delete();
            }
        }
        */
        return deleted;
    }

    /**
     * Reopens the database in read-write mode.
     * If the database is already read-write, does nothing.
     *

Changes to src/org/sqlite/database/sqlite/SQLiteDatabaseConfiguration.java.

85
86
87
88
89
90
91















92
93
94
95
96
97
98
...
104
105
106
107
108
109
110




111
112
113
114
115
116
117
...
119
120
121
122
123
124
125



126
127
128
129
130
131
132

    /**
     * The custom functions to register.
     */
    public final ArrayList<SQLiteCustomFunction> customFunctions =
            new ArrayList<SQLiteCustomFunction>();
















    /**
     * Creates a database configuration with the required parameters for opening a
     * database and default values for all other parameters.
     *
     * @param path The database path.
     * @param openFlags Open flags for the database, such as {@link SQLiteDatabase#OPEN_READWRITE}.
     */
................................................................................
        this.path = path;
        label = stripPathForLogs(path);
        this.openFlags = openFlags;

        // Set default values for optional parameters.
        maxSqlCacheSize = 25;
        locale = Locale.getDefault();




    }

    /**
     * Creates a database configuration as a copy of another configuration.
     *
     * @param other The other configuration.
     */
................................................................................
        if (other == null) {
            throw new IllegalArgumentException("other must not be null.");
        }

        this.path = other.path;
        this.label = other.label;
        updateParametersFrom(other);



    }

    /**
     * Updates the non-immutable parameters of this configuration object
     * from the other configuration object.
     *
     * @param other The object from which to copy the parameters.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>







 







>
>
>







85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

    /**
     * The custom functions to register.
     */
    public final ArrayList<SQLiteCustomFunction> customFunctions =
            new ArrayList<SQLiteCustomFunction>();


    /*
    ** The following two variables are used by the SEE extension.
    */
    public boolean bSee;
    public String seekey;

    /*
    ** Function to set SEE related variables.
    */
    public void setSeeKey(String key){
      bSee = true;
      seekey = key;
    }

    /**
     * Creates a database configuration with the required parameters for opening a
     * database and default values for all other parameters.
     *
     * @param path The database path.
     * @param openFlags Open flags for the database, such as {@link SQLiteDatabase#OPEN_READWRITE}.
     */
................................................................................
        this.path = path;
        label = stripPathForLogs(path);
        this.openFlags = openFlags;

        // Set default values for optional parameters.
        maxSqlCacheSize = 25;
        locale = Locale.getDefault();

        // Set default values for SEE parameters (default is unencrypted).
        bSee = false;
        seekey = null;
    }

    /**
     * Creates a database configuration as a copy of another configuration.
     *
     * @param other The other configuration.
     */
................................................................................
        if (other == null) {
            throw new IllegalArgumentException("other must not be null.");
        }

        this.path = other.path;
        this.label = other.label;
        updateParametersFrom(other);

        this.bSee = other.bSee;
        this.seekey = other.seekey;
    }

    /**
     * Updates the non-immutable parameters of this configuration object
     * from the other configuration object.
     *
     * @param other The object from which to copy the parameters.