missing
This commit is contained in:
15
packages/myddas/sqlite3/Android/AndroidManifest.xml
Normal file
15
packages/myddas/sqlite3/Android/AndroidManifest.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.sqlite.app.customsqlite"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
|
||||
<activity android:name="CustomSqlite"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
17
packages/myddas/sqlite3/Android/ant.properties
Normal file
17
packages/myddas/sqlite3/Android/ant.properties
Normal file
@@ -0,0 +1,17 @@
|
||||
# This file is used to override default values used by the Ant build system.
|
||||
#
|
||||
# This file must be checked into Version Control Systems, as it is
|
||||
# integral to the build system of your project.
|
||||
|
||||
# This file is only used by the Ant script.
|
||||
|
||||
# You can use this to override default values such as
|
||||
# 'source.dir' for the location of your java source folder and
|
||||
# 'out.dir' for the location of your output folder.
|
||||
|
||||
# You can also use it define how the release builds are signed by declaring
|
||||
# the following properties:
|
||||
# 'key.store' for the location of your keystore and
|
||||
# 'key.alias' for the name of the key to use.
|
||||
# The password will be asked during the build when you use the 'release' target.
|
||||
|
92
packages/myddas/sqlite3/Android/build.xml
Normal file
92
packages/myddas/sqlite3/Android/build.xml
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="CustomSqlite" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
This is the place to change some Ant specific build properties.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
For other overridable properties, look at the beginning of the rules
|
||||
files in the SDK, at tools/ant/build.xml
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- if sdk.dir was not set from one of the property file, then
|
||||
get it from the ANDROID_HOME env var.
|
||||
This must be done before we load project.properties since
|
||||
the proguard config can use sdk.dir -->
|
||||
<property environment="env" />
|
||||
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||
<isset property="env.ANDROID_HOME" />
|
||||
</condition>
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
This contains project specific properties such as project target, and library
|
||||
dependencies. Lower level build properties are stored in ant.properties
|
||||
(or in .classpath for Eclipse projects).
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Import per project custom build rules if present at the root of the project.
|
||||
This is the place to put custom intermediary targets such as:
|
||||
-pre-build
|
||||
-pre-compile
|
||||
-post-compile (This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||
-post-package
|
||||
-post-build
|
||||
-pre-clean
|
||||
-->
|
||||
<import file="custom_rules.xml" optional="true" />
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<import> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole content of build.xml
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, replacing the <import> task.
|
||||
- customize to your needs.
|
||||
|
||||
***********************
|
||||
****** IMPORTANT ******
|
||||
***********************
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: 1 -->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
</project>
|
4
packages/myddas/sqlite3/Android/jni/Android.mk
Normal file
4
packages/myddas/sqlite3/Android/jni/Android.mk
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(LOCAL_PATH)/sqlite/Android.mk
|
||||
|
1
packages/myddas/sqlite3/Android/jni/Application.mk
Normal file
1
packages/myddas/sqlite3/Android/jni/Application.mk
Normal file
@@ -0,0 +1 @@
|
||||
APP_STL:=stlport_static
|
File diff suppressed because it is too large
Load Diff
10
packages/myddas/sqlite3/Android/local.properties
Normal file
10
packages/myddas/sqlite3/Android/local.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must *NOT* be checked into Version Control Systems,
|
||||
# as it contains information specific to your local configuration.
|
||||
|
||||
# location of the SDK. This is only used by Ant
|
||||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
sdk.dir=/home/dan/adt-bundle-linux-x86-20131030/sdk/
|
20
packages/myddas/sqlite3/Android/proguard-project.txt
Normal file
20
packages/myddas/sqlite3/Android/proguard-project.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
# To enable ProGuard in your project, edit project.properties
|
||||
# to define the proguard.config property as described in that file.
|
||||
#
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
14
packages/myddas/sqlite3/Android/project.properties
Normal file
14
packages/myddas/sqlite3/Android/project.properties
Normal file
@@ -0,0 +1,14 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-19
|
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
36
packages/myddas/sqlite3/Android/res/layout/main.xml
Normal file
36
packages/myddas/sqlite3/Android/res/layout/main.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="CustomSqlite Tests"
|
||||
android:typeface="monospace"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Run the tests"
|
||||
android:onClick="run_the_tests"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_widget"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="<this text should be replaced by the test output>"
|
||||
android:typeface="monospace"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
4
packages/myddas/sqlite3/Android/res/values/strings.xml
Normal file
4
packages/myddas/sqlite3/Android/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">CustomSqlite</string>
|
||||
</resources>
|
@@ -0,0 +1,416 @@
|
||||
|
||||
package org.sqlite.app.customsqlite;
|
||||
|
||||
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.io.FileInputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.lang.InterruptedException;
|
||||
|
||||
import org.sqlite.database.sqlite.SQLiteDatabase;
|
||||
import org.sqlite.database.sqlite.SQLiteStatement;
|
||||
import org.sqlite.database.sqlite.SQLiteDatabaseCorruptException;
|
||||
import org.sqlite.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.content.Context;
|
||||
|
||||
/*
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteStatement;
|
||||
*/
|
||||
|
||||
import org.sqlite.database.DatabaseErrorHandler;
|
||||
class DoNotDeleteErrorHandler implements DatabaseErrorHandler {
|
||||
private static final String TAG = "DoNotDeleteErrorHandler";
|
||||
public void onCorruption(SQLiteDatabase dbObj) {
|
||||
Log.e(TAG, "Corruption reported by sqlite on database: " + dbObj.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public void report_version(){
|
||||
SQLiteDatabase db = null;
|
||||
SQLiteStatement st;
|
||||
String res;
|
||||
|
||||
db = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
|
||||
st = db.compileStatement("SELECT sqlite_version()");
|
||||
res = st.simpleQueryForString();
|
||||
|
||||
myTV.append("SQLite version " + res + "\n\n");
|
||||
}
|
||||
|
||||
public void test_warning(String name, String warning){
|
||||
myTV.append("WARNING:" + name + ": " + warning + "\n");
|
||||
}
|
||||
|
||||
public void test_result(String name, String res, String expected){
|
||||
myTV.append(name + "... ");
|
||||
myNTest++;
|
||||
|
||||
if( res.equals(expected) ){
|
||||
myTV.append("ok\n");
|
||||
} else {
|
||||
myNErr++;
|
||||
myTV.append("FAILED\n");
|
||||
myTV.append(" res= \"" + res + "\"\n");
|
||||
myTV.append(" expected=\"" + expected + "\"\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Test if the database at DB_PATH is encrypted or not. The db
|
||||
** is assumed to be encrypted if the first 6 bytes are anything
|
||||
** other than "SQLite".
|
||||
**
|
||||
** If the test reveals that the db is encrypted, return the string
|
||||
** "encrypted". Otherwise, "unencrypted".
|
||||
*/
|
||||
public String db_is_encrypted() throws Exception {
|
||||
FileInputStream in = new FileInputStream(DB_PATH);
|
||||
|
||||
byte[] buffer = new byte[6];
|
||||
in.read(buffer, 0, 6);
|
||||
|
||||
String res = "encrypted";
|
||||
if( Arrays.equals(buffer, (new String("SQLite")).getBytes()) ){
|
||||
res = "unencrypted";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Test that a database connection may be accessed from a second thread.
|
||||
*/
|
||||
public void thread_test_2(){
|
||||
SQLiteDatabase.deleteDatabase(DB_PATH);
|
||||
final SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
|
||||
|
||||
db.execSQL("CREATE TABLE t1(x, y)");
|
||||
db.execSQL("INSERT INTO t1 VALUES (1, 2), (3, 4)");
|
||||
|
||||
db.enableWriteAheadLogging();
|
||||
db.beginTransactionNonExclusive();
|
||||
db.execSQL("INSERT INTO t1 VALUES (5, 6)");
|
||||
|
||||
Thread t = new Thread( new Runnable() {
|
||||
public void run() {
|
||||
SQLiteStatement st = db.compileStatement("SELECT sum(x+y) FROM t1");
|
||||
String res = st.simpleQueryForString();
|
||||
}
|
||||
});
|
||||
|
||||
t.start();
|
||||
String res = "concurrent";
|
||||
|
||||
int i;
|
||||
for(i=0; i<20 && t.isAlive(); i++){
|
||||
try { Thread.sleep(100); } catch(InterruptedException e) {}
|
||||
}
|
||||
if( t.isAlive() ){ res = "blocked"; }
|
||||
|
||||
db.endTransaction();
|
||||
try { t.join(); } catch(InterruptedException e) {}
|
||||
if( SQLiteDatabase.hasCodec() ){
|
||||
test_result("thread_test_2", res, "blocked");
|
||||
} else {
|
||||
test_result("thread_test_2", res, "concurrent");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Use a Cursor to loop through the results of a SELECT query.
|
||||
*/
|
||||
public void csr_test_2() throws Exception {
|
||||
SQLiteDatabase.deleteDatabase(DB_PATH);
|
||||
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
|
||||
String res = "";
|
||||
String expect = "";
|
||||
int i;
|
||||
int nRow = 0;
|
||||
|
||||
db.execSQL("CREATE TABLE t1(x)");
|
||||
db.execSQL("BEGIN");
|
||||
for(i=0; i<1000; i++){
|
||||
db.execSQL("INSERT INTO t1 VALUES ('one'), ('two'), ('three')");
|
||||
expect += ".one.two.three";
|
||||
}
|
||||
db.execSQL("COMMIT");
|
||||
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("csr_test_1", "c==NULL");
|
||||
}
|
||||
test_result("csr_test_2.1", res, expect);
|
||||
|
||||
db.execSQL("BEGIN");
|
||||
for(i=0; i<1000; i++){
|
||||
db.execSQL("INSERT INTO t1 VALUES (X'123456'), (X'789ABC'), (X'DEF012')");
|
||||
db.execSQL("INSERT INTO t1 VALUES (45), (46), (47)");
|
||||
db.execSQL("INSERT INTO t1 VALUES (8.1), (8.2), (8.3)");
|
||||
db.execSQL("INSERT INTO t1 VALUES (NULL), (NULL), (NULL)");
|
||||
}
|
||||
db.execSQL("COMMIT");
|
||||
|
||||
c = db.rawQuery("SELECT x FROM t1", null);
|
||||
if( c!=null ){
|
||||
boolean bRes;
|
||||
for(bRes=c.moveToFirst(); bRes; bRes=c.moveToNext()) nRow++;
|
||||
}else{
|
||||
test_warning("csr_test_1", "c==NULL");
|
||||
}
|
||||
test_result("csr_test_2.2", "" + nRow, "15000");
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
public String string_from_t1_x(SQLiteDatabase db){
|
||||
String res = "";
|
||||
|
||||
Cursor c = db.rawQuery("SELECT x FROM t1", null);
|
||||
boolean bRes;
|
||||
for(bRes=c.moveToFirst(); bRes; bRes=c.moveToNext()){
|
||||
String x = c.getString(0);
|
||||
res = res + "." + x;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public void csr_test_1() throws Exception {
|
||||
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')");
|
||||
|
||||
res = string_from_t1_x(db);
|
||||
test_result("csr_test_1.1", res, ".one.two.three");
|
||||
|
||||
db.close();
|
||||
test_result("csr_test_1.2", db_is_encrypted(), "unencrypted");
|
||||
}
|
||||
|
||||
public void stmt_jrnl_test_1() throws Exception {
|
||||
SQLiteDatabase.deleteDatabase(DB_PATH);
|
||||
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
|
||||
String res = "";
|
||||
|
||||
db.execSQL("CREATE TABLE t1(x, y UNIQUE)");
|
||||
db.execSQL("BEGIN");
|
||||
db.execSQL("INSERT INTO t1 VALUES(1, 1), (2, 2), (3, 3)");
|
||||
db.execSQL("UPDATE t1 SET y=y+3");
|
||||
db.execSQL("COMMIT");
|
||||
db.close();
|
||||
test_result("stmt_jrnl_test_1.1", "did not crash", "did not crash");
|
||||
}
|
||||
|
||||
|
||||
public void supp_char_test_1() throws Exception {
|
||||
SQLiteDatabase.deleteDatabase(DB_PATH);
|
||||
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
|
||||
String res = "";
|
||||
String smiley = new String( Character.toChars(0x10000) );
|
||||
|
||||
db.execSQL("CREATE TABLE t1(x)");
|
||||
db.execSQL("INSERT INTO t1 VALUES ('a" + smiley + "b')");
|
||||
|
||||
res = string_from_t1_x(db);
|
||||
|
||||
test_result("supp_char_test1." + smiley, res, ".a" + smiley + "b");
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
/*
|
||||
** If this is a SEE build, check that encrypted databases work.
|
||||
*/
|
||||
public void see_test_1() throws Exception {
|
||||
if( !SQLiteDatabase.hasCodec() ) return;
|
||||
|
||||
SQLiteDatabase.deleteDatabase(DB_PATH);
|
||||
String res = "";
|
||||
|
||||
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
|
||||
db.execSQL("PRAGMA key = 'secretkey'");
|
||||
|
||||
db.execSQL("CREATE TABLE t1(x)");
|
||||
db.execSQL("INSERT INTO t1 VALUES ('one'), ('two'), ('three')");
|
||||
|
||||
res = string_from_t1_x(db);
|
||||
test_result("see_test_1.1", res, ".one.two.three");
|
||||
db.close();
|
||||
|
||||
test_result("see_test_1.2", db_is_encrypted(), "encrypted");
|
||||
|
||||
db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
|
||||
db.execSQL("PRAGMA key = 'secretkey'");
|
||||
res = string_from_t1_x(db);
|
||||
test_result("see_test_1.3", res, ".one.two.three");
|
||||
db.close();
|
||||
|
||||
res = "unencrypted";
|
||||
try {
|
||||
db = SQLiteDatabase.openOrCreateDatabase(DB_PATH.getPath(), null);
|
||||
string_from_t1_x(db);
|
||||
} catch ( SQLiteDatabaseCorruptException e ){
|
||||
res = "encrypted";
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
test_result("see_test_1.4", res, "encrypted");
|
||||
|
||||
res = "unencrypted";
|
||||
try {
|
||||
db = SQLiteDatabase.openOrCreateDatabase(DB_PATH.getPath(), null);
|
||||
db.execSQL("PRAGMA key = 'otherkey'");
|
||||
string_from_t1_x(db);
|
||||
} catch ( SQLiteDatabaseCorruptException e ){
|
||||
res = "encrypted";
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
test_result("see_test_1.5", res, "encrypted");
|
||||
}
|
||||
|
||||
class MyHelper extends SQLiteOpenHelper {
|
||||
public MyHelper(Context ctx){
|
||||
super(ctx, DB_PATH.getPath(), null, 1);
|
||||
}
|
||||
public void onConfigure(SQLiteDatabase db){
|
||||
db.execSQL("PRAGMA key = 'secret'");
|
||||
}
|
||||
public void onCreate(SQLiteDatabase db){
|
||||
db.execSQL("CREATE TABLE t1(x)");
|
||||
}
|
||||
public void onUpgrade(SQLiteDatabase db, int iOld, int iNew){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Check that SQLiteOpenHelper works.
|
||||
*/
|
||||
public void helper_test_1() throws Exception {
|
||||
/* SQLiteDatabase.deleteDatabase(DB_PATH); */
|
||||
|
||||
MyHelper helper = new MyHelper(this);
|
||||
SQLiteDatabase db = helper.getWritableDatabase();
|
||||
db.execSQL("INSERT INTO t1 VALUES ('x'), ('y'), ('z')");
|
||||
|
||||
String res = string_from_t1_x(db);
|
||||
test_result("helper.1", res, ".x.y.z");
|
||||
|
||||
helper.close();
|
||||
}
|
||||
|
||||
/*
|
||||
** If this is a SEE build, check that SQLiteOpenHelper still works.
|
||||
*/
|
||||
public void see_test_2() throws Exception {
|
||||
if( !SQLiteDatabase.hasCodec() ) return;
|
||||
SQLiteDatabase.deleteDatabase(DB_PATH);
|
||||
|
||||
MyHelper helper = new MyHelper(this);
|
||||
SQLiteDatabase db = helper.getWritableDatabase();
|
||||
db.execSQL("INSERT INTO t1 VALUES ('x'), ('y'), ('z')");
|
||||
|
||||
String res = string_from_t1_x(db);
|
||||
test_result("see_test_2.1", res, ".x.y.z");
|
||||
test_result("see_test_2.2", db_is_encrypted(), "encrypted");
|
||||
|
||||
helper.close();
|
||||
helper = new MyHelper(this);
|
||||
db = helper.getReadableDatabase();
|
||||
test_result("see_test_2.3", res, ".x.y.z");
|
||||
|
||||
db = helper.getWritableDatabase();
|
||||
test_result("see_test_2.4", res, ".x.y.z");
|
||||
|
||||
test_result("see_test_2.5", db_is_encrypted(), "encrypted");
|
||||
}
|
||||
|
||||
public void run_the_tests(View view){
|
||||
System.loadLibrary("sqliteX");
|
||||
DB_PATH = getApplicationContext().getDatabasePath("test.db");
|
||||
DB_PATH.getParentFile().mkdirs();
|
||||
|
||||
myTV.setText("");
|
||||
myNErr = 0;
|
||||
myNTest = 0;
|
||||
|
||||
try {
|
||||
report_version();
|
||||
helper_test_1();
|
||||
supp_char_test_1();
|
||||
csr_test_1();
|
||||
csr_test_2();
|
||||
thread_test_1();
|
||||
thread_test_2();
|
||||
see_test_1();
|
||||
see_test_2();
|
||||
stmt_jrnl_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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
215
packages/myddas/sqlite3/Android/www/index.wiki
Normal file
215
packages/myddas/sqlite3/Android/www/index.wiki
Normal file
@@ -0,0 +1,215 @@
|
||||
<h1>
|
||||
SQLite Android Bindings
|
||||
</h1>
|
||||
|
||||
<p> The SQLite library is a core part of the Android environment. Java
|
||||
applications and content providers access SQLite using the interface in
|
||||
the
|
||||
<a href="http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html">android.database.sqlite</a> namespace.
|
||||
|
||||
<p> One disadvantage of using Android's built-in SQLite support is that the
|
||||
application is forced to use the version of SQLite that the current version of
|
||||
Android happened to ship with. If your application happens to require a newer
|
||||
version of SQLite, or a build with a custom extension or
|
||||
<a href=http://www.sqlite.org/vfs.html>VFS</a> installed, you're out of luck.
|
||||
|
||||
<p>The code in this project allows an application to use the
|
||||
<a href=http://developer.android.com/tools/sdk/ndk/index.html>Android NDK</a>
|
||||
to build a custom version of SQLite to be shipped with the application while
|
||||
still continuing to use the standard Java interface.
|
||||
|
||||
<h2>Normal Usage</h2>
|
||||
|
||||
<h3>Installation</h3>
|
||||
|
||||
<p>
|
||||
Android API levels 15 (Android 4.0.3) and greater are supported. If
|
||||
targetting API level 16 or greater, use the default "trunk" branch of this
|
||||
project. Or, for API level 15, use the "api-level-15" branch. It is not possible
|
||||
to target an API level lower than 15.
|
||||
|
||||
<p>
|
||||
Copy the following files from this project into the equivalent locations in
|
||||
the application project.
|
||||
|
||||
<pre>
|
||||
jni/Android.mk
|
||||
jni/Application.mk
|
||||
jni/sqlite/* (copy contents of directory recursively)
|
||||
src/org/sqlite/database/* (copy contents of directory recursively)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Following this, the directory structures should contain
|
||||
[/tree?ci=trunk&re=%5ejni%7csrc/org/sqlite/data&expand | these files].
|
||||
|
||||
<p>
|
||||
For API level 15 only, also copy the following:
|
||||
|
||||
<pre>
|
||||
src/org/sqlite/os/* (copy contents of directory recursively)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Directory "jni/sqlite/" contains copies of the sqlite3.h and sqlite3.c
|
||||
source files. Between them, they contain the
|
||||
<a href=http://www.sqlite.org/amalgamation.html>source code for the SQLite
|
||||
library</a>. If necessary, replace these with the source for the specific
|
||||
version of SQLite required. If SQLite is to be compiled with any special
|
||||
pre-processor macros defined, add them to the "jni/sqlite/Android.mk" file
|
||||
(not jni/Android.mk).
|
||||
|
||||
<p>
|
||||
Once the files have been added to the project, run the command "ndk-build"
|
||||
in the root directory of the project. This compiles the native code in
|
||||
the jni/ directory (including the custom SQLite version) to shared libraries
|
||||
that will be deployed to the device along with the application. Assuming
|
||||
it is successful, unless you modify the sources or makefiles within the
|
||||
jni/ directory structure, you should not need to run "ndk-build" again.
|
||||
|
||||
<h3>Application Programming</h3>
|
||||
|
||||
<p>
|
||||
Before using any SQLite related methods or objects, the shared library
|
||||
compiled using the ndk must be loaded into the application using the
|
||||
following code:
|
||||
|
||||
<verbatim>
|
||||
System.loadLibrary("sqliteX");
|
||||
</verbatim>
|
||||
|
||||
<p>
|
||||
One way to ensure that the shared library is loaded early enough is
|
||||
to add it to a "static" block within the declaration of the application's
|
||||
main Activity class.
|
||||
|
||||
<p>
|
||||
The classes that make up the built-in Android SQLite interface reside in
|
||||
the "android.database.sqlite" namespace. This interface provides all of
|
||||
the same classes, except within the "org.sqlite.database.sqlite" namespace.
|
||||
This means that to modify an application to use the custom version of
|
||||
SQLite, all that is usually required is to replace all occurrences
|
||||
"android.database.sqlite" within the source code with
|
||||
"org.sqlite.database.sqlite". For example, the following:
|
||||
|
||||
<verbatim>
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
</verbatim>
|
||||
|
||||
<p>should be replaced with:
|
||||
|
||||
<verbatim>
|
||||
import org.sqlite.database.sqlite.SQLiteDatabase;
|
||||
</verbatim>
|
||||
|
||||
<p>
|
||||
As well as replacing all uses of the classes in the
|
||||
android.database.sqlite.* namespace, the application must also be sure
|
||||
to use the following two:
|
||||
|
||||
<verbatim>
|
||||
org.sqlite.database.SQLException
|
||||
org.sqlite.database.DatabaseErrorHandler
|
||||
</verbatim>
|
||||
|
||||
<p>instead of:
|
||||
|
||||
<verbatim>
|
||||
android.database.SQLException
|
||||
android.database.DatabaseErrorHandler
|
||||
</verbatim>
|
||||
|
||||
<p>Aside from namespace changes, there are other differences from the
|
||||
stock Android interface that applications need to be aware of:
|
||||
|
||||
<ol>
|
||||
<li> The SQLiteStatement.<a href="http://developer.android.com/reference/android/database/sqlite/SQLiteStatement.html#simpleQueryForBlobFileDescriptor()">simpleQueryForBlobFileDescriptor()</a>
|
||||
API is not available.
|
||||
|
||||
<li> The collation sequence "UNICODE" is not available.
|
||||
|
||||
<li> The collation sequence "LOCALIZED", which normally changes with the
|
||||
system's current locale, is always equivalent to SQLite's built
|
||||
in collation BINARY.
|
||||
</ol>
|
||||
|
||||
|
||||
<h2>Using The SQLite Encryption Extension</h2>
|
||||
|
||||
<p>
|
||||
To use the <a href=http://www.sqlite.org/see/doc/trunk/www/readme.wiki>
|
||||
SQLite Encryption Extension</a> (SEE) on Android, replace the sqlite3.c
|
||||
file at "jni/sqlite/sqlite3.c" with a SEE-enabled version (i.e. the
|
||||
concatenation of sqlite3.c and see.c - refer to the link above for
|
||||
details). Next, open the file jni/sqlite/Android.mk and locate the
|
||||
following two lines:
|
||||
|
||||
<verbatim>
|
||||
# If using SEE, uncomment the following:
|
||||
# LOCAL_CFLAGS += -DSQLITE_HAS_CODEC
|
||||
</verbatim>
|
||||
|
||||
<p>
|
||||
Uncomment the second of them, then run "ndk-build" as described above to
|
||||
generate the shared libraries.
|
||||
|
||||
<p>
|
||||
After opening or creating an encrypted database, the application must
|
||||
immediately execute a PRAGMA to configure the encryption key. This must
|
||||
be done before any other database methods are called. For example:
|
||||
|
||||
<verbatim>
|
||||
import org.sqlite.database.sqlite.SQLiteDatabase;
|
||||
|
||||
...
|
||||
|
||||
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase("my.db", null);
|
||||
db.execSQL("PRAGMA key = 'secretkey'");
|
||||
</verbatim>
|
||||
|
||||
<p>
|
||||
Or, if you are using the
|
||||
<a href=http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html>SQLiteOpenHelper</a>
|
||||
helper class, the PRAGMA must be the first thing executed within the
|
||||
onConfigure() callback. For example:
|
||||
|
||||
<verbatim>
|
||||
import org.sqlite.database.sqlite.SQLiteDatabase;
|
||||
import org.sqlite.database.sqlite.SQLiteHelper;
|
||||
|
||||
...
|
||||
|
||||
class MyHelper extends SQLiteOpenHelper {
|
||||
...
|
||||
void onConfigure(SQLiteDatabase db){
|
||||
db.execSQL("PRAGMA key = 'secretkey'");
|
||||
}
|
||||
...
|
||||
}
|
||||
</verbatim>
|
||||
|
||||
<p>
|
||||
Refer to the <a href=http://www.sqlite.org/see/doc/trunk/www/readme.wiki>
|
||||
SEE documentation</a> for further details regarding encryption keys.
|
||||
|
||||
<p>Aside from supporting encrypted databases, SEE-enabled builds behave
|
||||
differently in two more respects:
|
||||
|
||||
<ol>
|
||||
<li> <p>The SQLiteDatabase.<a href="http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#enableWriteAheadLogging()">enableWriteAheadLogging()</a> method does not enable
|
||||
connection pooling. It is not possible for connection pooling to be
|
||||
used with a SEE-enabled build (even if the database is unencrypted).
|
||||
|
||||
<li> <p>In Android, if database corruption is encountered, or if an attempt is
|
||||
made to open a file that is not an SQLite database, the default
|
||||
behaviour is to delete the file and create an empty database file in
|
||||
its place. In a SEE-enabled build, the default behaviour is to throw
|
||||
an exception.<br><br>
|
||||
The reason for this is that supplying an incorrect encryption key
|
||||
is indistinguishable from opening a file that is not a database file.
|
||||
And it seems too dangerous to simply delete the file in this case.
|
||||
<br><br>
|
||||
The default behaviour can be overriden using the
|
||||
<a href="http://developer.android.com/reference/android/database/DatabaseErrorHandler.html">DatabaseErrorHandler</a> interface.
|
||||
|
||||
</ol>
|
Reference in New Issue
Block a user