This commit is contained in:
Vítor Santos Costa 2018-03-26 23:12:48 +01:00
parent 29af01c288
commit e3ac349a0d
86 changed files with 24 additions and 14229 deletions

View File

@ -68,7 +68,7 @@ open_asset(VFS_t *me, const char *fname, const char *io_mode, int sno) {
__android_log_print(ANDROID_LOG_INFO, "YAPDroid", "open %s-%s <%s>", fname, me->prefix,io_mode); __android_log_print(ANDROID_LOG_INFO, "YAPDroid", "open %s-%s <%s>", fname, me->prefix,io_mode);
if (strchr(io_mode, 'B')) { if (strchr(io_mode, 'B')) {
mode = AASSET_MODE_BUFFER; mode = AASSET_MODE_BUFFER;
} else {[lib] } else {
mode = AASSET_MODE_UNKNOWN; mode = AASSET_MODE_UNKNOWN;
} }
GLOBAL_Stream[sno].name = Yap_LookupAtom(fname); GLOBAL_Stream[sno].name = Yap_LookupAtom(fname);

View File

@ -182,7 +182,7 @@ DBMS(show_databases)(Connection,database(Databases)) :-
DBMS(result_set)(Mode), DBMS(result_set)(Mode),
'$write_or_not'('SHOW DATABASES'), '$write_or_not'('SHOW DATABASES'),
c_DBMS(query)('SHOW DATABASES',ResultSet,Conn,Mode,_), c_DBMS(query)('SHOW DATABASES',ResultSet,Conn,Mode,_),
!,c_DBMS(row)(ResultSet,1,[Databases]). !,DBMS(row)(ResultSet,1,[Databases]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View File

@ -174,6 +174,7 @@
nonvar(Module). nonvar(Module).
% Prevent the error of given an atom that has no value % Prevent the error of given an atom that has no value
'$error_checks'(get_value(Connection,Con)) :- !, '$error_checks'(get_value(Connection,Con)) :- !,
writeln(user_error,get_value(Connection,Con)),
% This also prevents the case of giving the number of the connection % This also prevents the case of giving the number of the connection
% as an argument % as an argument
atom(Connection), atom(Connection),
@ -181,11 +182,3 @@
get_value(Connection,Value), get_value(Connection,Value),
Value \== []. Value \== [].
% Prevent the error of given an atom that has no value
'$error_checks'(get_value(Conn,Connection)) :- !,
% This also prevents the case of giving the number of the connection
% as an argument
atom(Conn),
var(Connection),
get_value(Conn,Value),
Value \== [].

View File

@ -393,14 +393,14 @@
% Only for making the error tests in all of the calls to % Only for making the error tests in all of the calls to
% get_value/2 % get_value/2
'$get_value'(Connection,Con) :- '$get_value'(Connection,Con) :-
'$error_checks'(get_value(Connection,Con)), %'$error_checks'(get_value(Connection,Con)),
get_value(Connection,Con). get_value(Connection,Con).
'$check_fields'([],[]). '$check_fields'([],[]).
'$check_fields'(['$const$'(_)|TAtt],[_|TFields]):- '$check_fields'(['$const$'(_)|TAtt],[_|TFields]):-
'$check_fields'(TAtt,TFields). '$check_fields'(TAtt,TFields).
% um campo auto_incrementavel, é sempre parte da chave, e como é auto % um campo auto_incrementavel, <EFBFBD> sempre parte da chave, e como <20> auto
% pode-se dar valores NULOS % pode-se dar valores NULOS
'$check_fields'([att(_,Name)|TAtt],[property(Name,_,1,1)|TFields]):-!, '$check_fields'([att(_,Name)|TAtt],[property(Name,_,1,1)|TFields]):-!,
'$check_fields'(TAtt,TFields). '$check_fields'(TAtt,TFields).

View File

@ -77,7 +77,6 @@ static Int c_sqlite3_get_database(USES_REGS1);
static Int c_sqlite3_change_database(USES_REGS1); static Int c_sqlite3_change_database(USES_REGS1);
static Int c_sqlite3_connect(USES_REGS1) { static Int c_sqlite3_connect(USES_REGS1) {
printf("hello darkness\n");
Term arg_file = Deref(ARG1); Term arg_file = Deref(ARG1);
Term arg_db = ARG4; Term arg_db = ARG4;
@ -85,11 +84,13 @@ static Int c_sqlite3_connect(USES_REGS1) {
sqlite3 *db; sqlite3 *db;
const char *file = AtomName(AtomOfTerm(arg_file)); const char *file = AtomName(AtomOfTerm(arg_file));
__android_log_print(ANDROID_LOG_INFO, "YAPDroid", "connect sqlite3 %s",file);
CALL_SQLITE(ARG1, open(file, &db)); CALL_SQLITE(ARG1, open(file, &db));
__android_log_print(ANDROID_LOG_INFO, "YAPDroid", "connect sqlite3 %p",db);
if (!Yap_unify(arg_db, MkAddressTerm(db))) { if (!Yap_unify(arg_db, MkAddressTerm(db))) {
return FALSE; return false;
} else { } else {
/* Criar um novo no na lista de ligacoes*/ /* Criar um novo no na lista de ligacoes*/
new = myddas_util_add_connection(db, NULL, API_SQLITE3); new = myddas_util_add_connection(db, NULL, API_SQLITE3);
@ -98,9 +99,9 @@ static Int c_sqlite3_connect(USES_REGS1) {
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "ERROR: ** c_db_my_connect ** Error allocating memory\n"); fprintf(stderr, "ERROR: ** c_db_my_connect ** Error allocating memory\n");
#endif #endif
return FALSE; return false;
} }
return TRUE; return true;
} }
} }
@ -276,6 +277,7 @@ static Int c_sqlite3_number_of_fields(USES_REGS1) {
const char *relation = AtomName(AtomOfTerm(arg_relation)); const char *relation = AtomName(AtomOfTerm(arg_relation));
sqlite3 *db = AddressOfTerm(arg_db); sqlite3 *db = AddressOfTerm(arg_db);
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
__android_log_print(ANDROID_LOG_INFO, "YAPDroid", " sqlite3 relation %s",relation);
char sql[256]; char sql[256];
@ -288,7 +290,11 @@ static Int c_sqlite3_number_of_fields(USES_REGS1) {
CALL_SQLITE(ARG1, finalize(stmt)); CALL_SQLITE(ARG1, finalize(stmt));
return Yap_unify(arg_fields, MkIntegerTerm(fields)); __android_log_print(ANDROID_LOG_INFO, "YAPDroid", " sqlite3 fields %d",fields);
return Yap_unify(arg_fields, MkIntegerTerm(fields));
} }
/* db_get_attributes_types: RelName x connection -> TypesList */ /* db_get_attributes_types: RelName x connection -> TypesList */
@ -301,6 +307,7 @@ static Int c_sqlite3_get_attributes_types(USES_REGS1) {
sqlite3 *db = (sqlite3 *)IntegerOfTerm(arg_db); sqlite3 *db = (sqlite3 *)IntegerOfTerm(arg_db);
char sql[256]; char sql[256];
int row; int row;
__android_log_print(ANDROID_LOG_INFO, "YAPDroid", " sqlite3 reelation %s get_attributes",relation);
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
@ -341,7 +348,8 @@ static Int c_sqlite3_get_attributes_types(USES_REGS1) {
tm = "?"; tm = "?";
break; break;
} }
list = Yap_MkNewPairTerm(); __android_log_print(ANDROID_LOG_INFO, "YAPDroid", " sqlite3 attributes %s:%s ",sqlite3_column_name(stmt, row),tm);
list = Yap_MkNewPairTerm();
*tfp = list; *tfp = list;
RepPair(list)[0] = MkAtomTerm(Yap_LookupAtom(tm)); RepPair(list)[0] = MkAtomTerm(Yap_LookupAtom(tm));
tfp = RepPair(list) + 1; tfp = RepPair(list) + 1;
@ -664,9 +672,14 @@ static void Yap_InitBackMYDDAS_SQLITE3Preds(void) {
} }
X_API void init_sqlite3(void) { X_API void init_sqlite3(void) {
Term cm = CurrentModule;
CurrentModule = MkAtomTerm(Yap_LookupAtom("myddas_sqlite3"));
Yap_InitMYDDAS_SQLITE3Preds(); Yap_InitMYDDAS_SQLITE3Preds();
Yap_InitBackMYDDAS_SQLITE3Preds(); Yap_InitBackMYDDAS_SQLITE3Preds();
CurrentModule = cm;
} }

View File

@ -1,15 +0,0 @@
<?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>

View File

@ -1,17 +0,0 @@
# 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.

View File

@ -1,92 +0,0 @@
<?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>

View File

@ -1,4 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(LOCAL_PATH)/sqlite/Android.mk

View File

@ -1 +0,0 @@
APP_STL:=stlport_static

View File

@ -1,76 +0,0 @@
/*
* Copyright 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
#ifndef NATIVEHELPER_ALOGPRIV_H_
#define NATIVEHELPER_ALOGPRIV_H_
#include <android/log.h>
#ifndef LOG_NDEBUG
#ifdef NDEBUG
#define LOG_NDEBUG 1
#else
#define LOG_NDEBUG 0
#endif
#endif
/*
* Basic log message macros intended to emulate the behavior of log/log.h
* in system core. This should be dependent only on ndk exposed logging
* functionality.
*/
#ifndef ALOG
#define ALOG(priority, tag, fmt...) \
__android_log_print(ANDROID_##priority, tag, fmt)
#endif
#ifndef ALOGV
#if LOG_NDEBUG
#define ALOGV(...) ((void)0)
#else
#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#endif
#endif
#ifndef ALOGD
#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGI
#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGW
#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGE
#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
#endif
/*
** Not quite the same as the core android LOG_FATAL_IF (which also
** sends a SIGTRAP), but close enough.
*/
#define LOG_FATAL_IF(bCond, zErr) if( bCond ) ALOGE(zErr);
#endif

View File

@ -1,44 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
# If using SEE, uncomment the following:
# LOCAL_CFLAGS += -DSQLITE_HAS_CODEC
# This is important - it causes SQLite to use memory for temp files. Since
# Android has no globally writable temp directory, if this is not defined the
# application throws an exception when it tries to create a temp file.
#
LOCAL_CFLAGS += -DSQLITE_TEMP_STORE=3
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 += -DHAVE_STRCHRNUL=0
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
LOCAL_SRC_FILES += sqlite3.c
LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/nativehelper/
LOCAL_MODULE:= libsqliteX
LOCAL_LDLIBS += -ldl -llog
include $(BUILD_SHARED_LIBRARY)

View File

@ -1,341 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "JNIHelp"
#include "JniConstants.h"
#include "JNIHelp.h"
#include "ALog-priv.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <string>
/**
* Equivalent to ScopedLocalRef, but for C_JNIEnv instead. (And slightly more powerful.)
*/
template<typename T>
class scoped_local_ref {
public:
scoped_local_ref(C_JNIEnv* env, T localRef = NULL)
: mEnv(env), mLocalRef(localRef)
{
}
~scoped_local_ref() {
reset();
}
void reset(T localRef = NULL) {
if (mLocalRef != NULL) {
(*mEnv)->DeleteLocalRef(reinterpret_cast<JNIEnv*>(mEnv), mLocalRef);
mLocalRef = localRef;
}
}
T get() const {
return mLocalRef;
}
private:
C_JNIEnv* mEnv;
T mLocalRef;
// Disallow copy and assignment.
scoped_local_ref(const scoped_local_ref&);
void operator=(const scoped_local_ref&);
};
static jclass findClass(C_JNIEnv* env, const char* className) {
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
return (*env)->FindClass(e, className);
}
extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods)
{
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
ALOGV("Registering %s's %d native methods...", className, numMethods);
scoped_local_ref<jclass> c(env, findClass(env, className));
if (c.get() == NULL) {
char* msg;
asprintf(&msg, "Native registration unable to find class '%s'; aborting...", className);
e->FatalError(msg);
}
if ((*env)->RegisterNatives(e, c.get(), gMethods, numMethods) < 0) {
char* msg;
asprintf(&msg, "RegisterNatives failed for '%s'; aborting...", className);
e->FatalError(msg);
}
return 0;
}
/*
* Returns a human-readable summary of an exception object. The buffer will
* be populated with the "binary" class name and, if present, the
* exception message.
*/
static bool getExceptionSummary(C_JNIEnv* env, jthrowable exception, std::string& result) {
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
/* get the name of the exception's class */
scoped_local_ref<jclass> exceptionClass(env, (*env)->GetObjectClass(e, exception)); // can't fail
scoped_local_ref<jclass> classClass(env,
(*env)->GetObjectClass(e, exceptionClass.get())); // java.lang.Class, can't fail
jmethodID classGetNameMethod =
(*env)->GetMethodID(e, classClass.get(), "getName", "()Ljava/lang/String;");
scoped_local_ref<jstring> classNameStr(env,
(jstring) (*env)->CallObjectMethod(e, exceptionClass.get(), classGetNameMethod));
if (classNameStr.get() == NULL) {
(*env)->ExceptionClear(e);
result = "<error getting class name>";
return false;
}
const char* classNameChars = (*env)->GetStringUTFChars(e, classNameStr.get(), NULL);
if (classNameChars == NULL) {
(*env)->ExceptionClear(e);
result = "<error getting class name UTF-8>";
return false;
}
result += classNameChars;
(*env)->ReleaseStringUTFChars(e, classNameStr.get(), classNameChars);
/* if the exception has a detail message, get that */
jmethodID getMessage =
(*env)->GetMethodID(e, exceptionClass.get(), "getMessage", "()Ljava/lang/String;");
scoped_local_ref<jstring> messageStr(env,
(jstring) (*env)->CallObjectMethod(e, exception, getMessage));
if (messageStr.get() == NULL) {
return true;
}
result += ": ";
const char* messageChars = (*env)->GetStringUTFChars(e, messageStr.get(), NULL);
if (messageChars != NULL) {
result += messageChars;
(*env)->ReleaseStringUTFChars(e, messageStr.get(), messageChars);
} else {
result += "<error getting message>";
(*env)->ExceptionClear(e); // clear OOM
}
return true;
}
/*
* Returns an exception (with stack trace) as a string.
*/
static bool getStackTrace(C_JNIEnv* env, jthrowable exception, std::string& result) {
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
scoped_local_ref<jclass> stringWriterClass(env, findClass(env, "java/io/StringWriter"));
if (stringWriterClass.get() == NULL) {
return false;
}
jmethodID stringWriterCtor = (*env)->GetMethodID(e, stringWriterClass.get(), "<init>", "()V");
jmethodID stringWriterToStringMethod =
(*env)->GetMethodID(e, stringWriterClass.get(), "toString", "()Ljava/lang/String;");
scoped_local_ref<jclass> printWriterClass(env, findClass(env, "java/io/PrintWriter"));
if (printWriterClass.get() == NULL) {
return false;
}
jmethodID printWriterCtor =
(*env)->GetMethodID(e, printWriterClass.get(), "<init>", "(Ljava/io/Writer;)V");
scoped_local_ref<jobject> stringWriter(env,
(*env)->NewObject(e, stringWriterClass.get(), stringWriterCtor));
if (stringWriter.get() == NULL) {
return false;
}
jobject printWriter =
(*env)->NewObject(e, printWriterClass.get(), printWriterCtor, stringWriter.get());
if (printWriter == NULL) {
return false;
}
scoped_local_ref<jclass> exceptionClass(env, (*env)->GetObjectClass(e, exception)); // can't fail
jmethodID printStackTraceMethod =
(*env)->GetMethodID(e, exceptionClass.get(), "printStackTrace", "(Ljava/io/PrintWriter;)V");
(*env)->CallVoidMethod(e, exception, printStackTraceMethod, printWriter);
if ((*env)->ExceptionCheck(e)) {
return false;
}
scoped_local_ref<jstring> messageStr(env,
(jstring) (*env)->CallObjectMethod(e, stringWriter.get(), stringWriterToStringMethod));
if (messageStr.get() == NULL) {
return false;
}
const char* utfChars = (*env)->GetStringUTFChars(e, messageStr.get(), NULL);
if (utfChars == NULL) {
return false;
}
result = utfChars;
(*env)->ReleaseStringUTFChars(e, messageStr.get(), utfChars);
return true;
}
extern "C" int jniThrowException(C_JNIEnv* env, const char* className, const char* msg) {
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
if ((*env)->ExceptionCheck(e)) {
/* TODO: consider creating the new exception with this as "cause" */
scoped_local_ref<jthrowable> exception(env, (*env)->ExceptionOccurred(e));
(*env)->ExceptionClear(e);
if (exception.get() != NULL) {
std::string text;
getExceptionSummary(env, exception.get(), text);
ALOGW("Discarding pending exception (%s) to throw %s", text.c_str(), className);
}
}
scoped_local_ref<jclass> exceptionClass(env, findClass(env, className));
if (exceptionClass.get() == NULL) {
ALOGE("Unable to find exception class %s", className);
/* ClassNotFoundException now pending */
return -1;
}
if ((*env)->ThrowNew(e, exceptionClass.get(), msg) != JNI_OK) {
ALOGE("Failed throwing '%s' '%s'", className, msg);
/* an exception, most likely OOM, will now be pending */
return -1;
}
return 0;
}
int jniThrowExceptionFmt(C_JNIEnv* env, const char* className, const char* fmt, va_list args) {
char msgBuf[512];
vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
return jniThrowException(env, className, msgBuf);
}
int jniThrowNullPointerException(C_JNIEnv* env, const char* msg) {
return jniThrowException(env, "java/lang/NullPointerException", msg);
}
int jniThrowRuntimeException(C_JNIEnv* env, const char* msg) {
return jniThrowException(env, "java/lang/RuntimeException", msg);
}
int jniThrowIOException(C_JNIEnv* env, int errnum) {
char buffer[80];
const char* message = jniStrError(errnum, buffer, sizeof(buffer));
return jniThrowException(env, "java/io/IOException", message);
}
static std::string jniGetStackTrace(C_JNIEnv* env, jthrowable exception) {
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
scoped_local_ref<jthrowable> currentException(env, (*env)->ExceptionOccurred(e));
if (exception == NULL) {
exception = currentException.get();
if (exception == NULL) {
return "<no pending exception>";
}
}
if (currentException.get() != NULL) {
(*env)->ExceptionClear(e);
}
std::string trace;
if (!getStackTrace(env, exception, trace)) {
(*env)->ExceptionClear(e);
getExceptionSummary(env, exception, trace);
}
if (currentException.get() != NULL) {
(*env)->Throw(e, currentException.get()); // rethrow
}
return trace;
}
void jniLogException(C_JNIEnv* env, int priority, const char* tag, jthrowable exception) {
std::string trace(jniGetStackTrace(env, exception));
__android_log_write(priority, tag, trace.c_str());
}
const char* jniStrError(int errnum, char* buf, size_t buflen) {
#if __GLIBC__
// Note: glibc has a nonstandard strerror_r that returns char* rather than POSIX's int.
// char *strerror_r(int errnum, char *buf, size_t n);
return strerror_r(errnum, buf, buflen);
#else
char *rc = strerror_r(errnum, buf, buflen);
if (rc != NULL) {
// (POSIX only guarantees a value other than 0. The safest
// way to implement this function is to use C++ and overload on the
// type of strerror_r to accurately distinguish GNU from POSIX.)
snprintf(buf, buflen, "errno %d", errnum);
}
return buf;
#endif
}
jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd) {
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
static jmethodID ctor = e->GetMethodID(JniConstants::fileDescriptorClass, "<init>", "()V");
jobject fileDescriptor = (*env)->NewObject(e, JniConstants::fileDescriptorClass, ctor);
// NOTE: NewObject ensures that an OutOfMemoryError will be seen by the Java
// caller if the alloc fails, so we just return NULL when that happens.
if (fileDescriptor != NULL) {
jniSetFileDescriptorOfFD(env, fileDescriptor, fd);
}
return fileDescriptor;
}
int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor) {
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
static jfieldID fid = e->GetFieldID(JniConstants::fileDescriptorClass, "descriptor", "I");
if (fileDescriptor != NULL) {
return (*env)->GetIntField(e, fileDescriptor, fid);
} else {
return -1;
}
}
void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor, int value) {
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
static jfieldID fid = e->GetFieldID(JniConstants::fileDescriptorClass, "descriptor", "I");
(*env)->SetIntField(e, fileDescriptor, fid, value);
}
jobject jniGetReferent(C_JNIEnv* env, jobject ref) {
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
static jmethodID get = e->GetMethodID(JniConstants::referenceClass, "get", "()Ljava/lang/Object;");
return (*env)->CallObjectMethod(e, ref, get);
}

View File

@ -1,139 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "JniConstants"
#include "ALog-priv.h"
#include "JniConstants.h"
#include "ScopedLocalRef.h"
#include <stdlib.h>
jclass JniConstants::bidiRunClass;
jclass JniConstants::bigDecimalClass;
jclass JniConstants::booleanClass;
jclass JniConstants::byteArrayClass;
jclass JniConstants::byteClass;
jclass JniConstants::calendarClass;
jclass JniConstants::characterClass;
jclass JniConstants::charsetICUClass;
jclass JniConstants::constructorClass;
jclass JniConstants::deflaterClass;
jclass JniConstants::doubleClass;
jclass JniConstants::errnoExceptionClass;
jclass JniConstants::fieldClass;
jclass JniConstants::fieldPositionIteratorClass;
jclass JniConstants::fileDescriptorClass;
jclass JniConstants::floatClass;
jclass JniConstants::gaiExceptionClass;
jclass JniConstants::inet6AddressClass;
jclass JniConstants::inetAddressClass;
jclass JniConstants::inetSocketAddressClass;
jclass JniConstants::inetUnixAddressClass;
jclass JniConstants::inflaterClass;
jclass JniConstants::inputStreamClass;
jclass JniConstants::integerClass;
jclass JniConstants::localeDataClass;
jclass JniConstants::longClass;
jclass JniConstants::methodClass;
jclass JniConstants::mutableIntClass;
jclass JniConstants::mutableLongClass;
jclass JniConstants::objectClass;
jclass JniConstants::objectArrayClass;
jclass JniConstants::outputStreamClass;
jclass JniConstants::parsePositionClass;
jclass JniConstants::patternSyntaxExceptionClass;
jclass JniConstants::realToStringClass;
jclass JniConstants::referenceClass;
jclass JniConstants::shortClass;
jclass JniConstants::socketClass;
jclass JniConstants::socketImplClass;
jclass JniConstants::stringClass;
jclass JniConstants::structAddrinfoClass;
jclass JniConstants::structFlockClass;
jclass JniConstants::structGroupReqClass;
jclass JniConstants::structLingerClass;
jclass JniConstants::structPasswdClass;
jclass JniConstants::structPollfdClass;
jclass JniConstants::structStatClass;
jclass JniConstants::structStatVfsClass;
jclass JniConstants::structTimevalClass;
jclass JniConstants::structUcredClass;
jclass JniConstants::structUtsnameClass;
static jclass findClass(JNIEnv* env, const char* name) {
ScopedLocalRef<jclass> localClass(env, env->FindClass(name));
jclass result = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
if (result == NULL) {
ALOGE("failed to find class '%s'", name);
abort();
}
return result;
}
void JniConstants::init(JNIEnv* env) {
bidiRunClass = findClass(env, "java/text/Bidi$Run");
bigDecimalClass = findClass(env, "java/math/BigDecimal");
booleanClass = findClass(env, "java/lang/Boolean");
byteClass = findClass(env, "java/lang/Byte");
byteArrayClass = findClass(env, "[B");
calendarClass = findClass(env, "java/util/Calendar");
characterClass = findClass(env, "java/lang/Character");
charsetICUClass = findClass(env, "java/nio/charset/CharsetICU");
constructorClass = findClass(env, "java/lang/reflect/Constructor");
floatClass = findClass(env, "java/lang/Float");
deflaterClass = findClass(env, "java/util/zip/Deflater");
doubleClass = findClass(env, "java/lang/Double");
errnoExceptionClass = findClass(env, "libcore/io/ErrnoException");
fieldClass = findClass(env, "java/lang/reflect/Field");
fieldPositionIteratorClass = findClass(env, "libcore/icu/NativeDecimalFormat$FieldPositionIterator");
fileDescriptorClass = findClass(env, "java/io/FileDescriptor");
gaiExceptionClass = findClass(env, "libcore/io/GaiException");
inet6AddressClass = findClass(env, "java/net/Inet6Address");
inetAddressClass = findClass(env, "java/net/InetAddress");
inetSocketAddressClass = findClass(env, "java/net/InetSocketAddress");
inetUnixAddressClass = findClass(env, "java/net/InetUnixAddress");
inflaterClass = findClass(env, "java/util/zip/Inflater");
inputStreamClass = findClass(env, "java/io/InputStream");
integerClass = findClass(env, "java/lang/Integer");
localeDataClass = findClass(env, "libcore/icu/LocaleData");
longClass = findClass(env, "java/lang/Long");
methodClass = findClass(env, "java/lang/reflect/Method");
mutableIntClass = findClass(env, "libcore/util/MutableInt");
mutableLongClass = findClass(env, "libcore/util/MutableLong");
objectClass = findClass(env, "java/lang/Object");
objectArrayClass = findClass(env, "[Ljava/lang/Object;");
outputStreamClass = findClass(env, "java/io/OutputStream");
parsePositionClass = findClass(env, "java/text/ParsePosition");
patternSyntaxExceptionClass = findClass(env, "java/util/regex/PatternSyntaxException");
realToStringClass = findClass(env, "java/lang/RealToString");
referenceClass = findClass(env, "java/lang/ref/Reference");
shortClass = findClass(env, "java/lang/Short");
socketClass = findClass(env, "java/net/Socket");
socketImplClass = findClass(env, "java/net/SocketImpl");
stringClass = findClass(env, "java/lang/String");
structAddrinfoClass = findClass(env, "libcore/io/StructAddrinfo");
structFlockClass = findClass(env, "libcore/io/StructFlock");
structGroupReqClass = findClass(env, "libcore/io/StructGroupReq");
structLingerClass = findClass(env, "libcore/io/StructLinger");
structPasswdClass = findClass(env, "libcore/io/StructPasswd");
structPollfdClass = findClass(env, "libcore/io/StructPollfd");
structStatClass = findClass(env, "libcore/io/StructStat");
structStatVfsClass = findClass(env, "libcore/io/StructStatVfs");
structTimevalClass = findClass(env, "libcore/io/StructTimeval");
structUcredClass = findClass(env, "libcore/io/StructUcred");
structUtsnameClass = findClass(env, "libcore/io/StructUtsname");
}

View File

@ -1,40 +0,0 @@
All the files in this directory are copied from stock android. The following
files:
JniConstants.cpp
JNIHelp.cpp
ALog-priv.h
are copied in from Android's libnativehelper module (altogether less than 1000
lines of code). The remainder are from the core framework (directory
/frameworks/base/core/jni).
Notes on changes:
The ashmem_XXX() interfaces are used for the various "xxxForBlobDescriptor()"
API functions. The code in libcutils for this seems to be platform
dependent - some platforms have kernel support, others have a user space
implementation. So these functions are not supported for now.
The original SQLiteConnection.cpp uses AndroidRuntime::genJNIEnv() to obtain a
pointer to the current threads environment. Changed to store a pointer to the
process JavaVM (Android allows only one) as a global variable. Then retrieve
the JNIEnv as needed using GetEnv().
Replaced uses of class String8 with std::string in SQLiteConnection.cpp and a
few other places.
The stock Android code to populate CursorWindow containers with the results of
a SELECT statement uses a C++ interface that is not available to NDK builds. So
this code is rewritten to call the CursorWindow java interface via JNI methods.
This is the largest source code change. See function
nativeExecuteForCursorWindow() in file android_database_SQLiteConnection.cpp
for details.
The "LOCALIZED" collation and some miscellaneous user-functions added by the
sqlite3_android.cpp module are not included. A collation called LOCALIZED
that is equivalent to BINARY is added instead to keep various things working.
This should not cause serious problems - class SQLiteConnection always
runs "REINDEX LOCALIZED" immediately after opening a connection.

View File

@ -1,138 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
#include "android_database_SQLiteCommon.h"
namespace android {
/* throw a SQLiteException with a message appropriate for the error in handle */
void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
throw_sqlite3_exception(env, handle, NULL);
}
/* throw a SQLiteException with the given message */
void throw_sqlite3_exception(JNIEnv* env, const char* message) {
throw_sqlite3_exception(env, NULL, message);
}
/* throw a SQLiteException with a message appropriate for the error in handle
concatenated with the given message
*/
void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message) {
if (handle) {
// get the error code and message from the SQLite connection
// the error message may contain more information than the error code
// because it is based on the extended error code rather than the simplified
// error code that SQLite normally returns.
throw_sqlite3_exception(env, sqlite3_extended_errcode(handle),
sqlite3_errmsg(handle), message);
} else {
// we use SQLITE_OK so that a generic SQLiteException is thrown;
// any code not specified in the switch statement below would do.
throw_sqlite3_exception(env, SQLITE_OK, "unknown error", message);
}
}
/* throw a SQLiteException for a given error code
* should only be used when the database connection is not available because the
* error information will not be quite as rich */
void throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message) {
throw_sqlite3_exception(env, errcode, "unknown error", message);
}
/* throw a SQLiteException for a given error code, sqlite3message, and
user message
*/
void throw_sqlite3_exception(JNIEnv* env, int errcode,
const char* sqlite3Message, const char* message) {
const char* exceptionClass;
switch (errcode & 0xff) { /* mask off extended error code */
case SQLITE_IOERR:
exceptionClass = "org/sqlite/database/sqlite/SQLiteDiskIOException";
break;
case SQLITE_CORRUPT:
case SQLITE_NOTADB: // treat "unsupported file format" error as corruption also
exceptionClass = "org/sqlite/database/sqlite/SQLiteDatabaseCorruptException";
break;
case SQLITE_CONSTRAINT:
exceptionClass = "org/sqlite/database/sqlite/SQLiteConstraintException";
break;
case SQLITE_ABORT:
exceptionClass = "org/sqlite/database/sqlite/SQLiteAbortException";
break;
case SQLITE_DONE:
exceptionClass = "org/sqlite/database/sqlite/SQLiteDoneException";
sqlite3Message = NULL; // SQLite error message is irrelevant in this case
break;
case SQLITE_FULL:
exceptionClass = "org/sqlite/database/sqlite/SQLiteFullException";
break;
case SQLITE_MISUSE:
exceptionClass = "org/sqlite/database/sqlite/SQLiteMisuseException";
break;
case SQLITE_PERM:
exceptionClass = "org/sqlite/database/sqlite/SQLiteAccessPermException";
break;
case SQLITE_BUSY:
exceptionClass = "org/sqlite/database/sqlite/SQLiteDatabaseLockedException";
break;
case SQLITE_LOCKED:
exceptionClass = "org/sqlite/database/sqlite/SQLiteTableLockedException";
break;
case SQLITE_READONLY:
exceptionClass = "org/sqlite/database/sqlite/SQLiteReadOnlyDatabaseException";
break;
case SQLITE_CANTOPEN:
exceptionClass = "org/sqlite/database/sqlite/SQLiteCantOpenDatabaseException";
break;
case SQLITE_TOOBIG:
exceptionClass = "org/sqlite/database/sqlite/SQLiteBlobTooBigException";
break;
case SQLITE_RANGE:
exceptionClass = "org/sqlite/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException";
break;
case SQLITE_NOMEM:
exceptionClass = "org/sqlite/database/sqlite/SQLiteOutOfMemoryException";
break;
case SQLITE_MISMATCH:
exceptionClass = "org/sqlite/database/sqlite/SQLiteDatatypeMismatchException";
break;
case SQLITE_INTERRUPT:
exceptionClass = "android/os/OperationCanceledException";
break;
default:
exceptionClass = "org/sqlite/database/sqlite/SQLiteException";
break;
}
if (sqlite3Message) {
char *zFullmsg = sqlite3_mprintf(
"%s (code %d)%s%s", sqlite3Message, errcode,
(message ? ": " : ""), (message ? message : "")
);
jniThrowException(env, exceptionClass, zFullmsg);
sqlite3_free(zFullmsg);
} else {
jniThrowException(env, exceptionClass, message);
}
}
} // namespace android

View File

@ -1,55 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
#ifndef _ANDROID_DATABASE_SQLITE_COMMON_H
#define _ANDROID_DATABASE_SQLITE_COMMON_H
#include <jni.h>
#include <JNIHelp.h>
#include <sqlite3.h>
// Special log tags defined in SQLiteDebug.java.
#define SQLITE_LOG_TAG "SQLiteLog"
#define SQLITE_TRACE_TAG "SQLiteStatements"
#define SQLITE_PROFILE_TAG "SQLiteTime"
namespace android {
/* throw a SQLiteException with a message appropriate for the error in handle */
void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle);
/* throw a SQLiteException with the given message */
void throw_sqlite3_exception(JNIEnv* env, const char* message);
/* throw a SQLiteException with a message appropriate for the error in handle
concatenated with the given message
*/
void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message);
/* throw a SQLiteException for a given error code */
void throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message);
void throw_sqlite3_exception(JNIEnv* env, int errcode,
const char* sqlite3Message, const char* message);
}
#endif // _ANDROID_DATABASE_SQLITE_COMMON_H

View File

@ -1,92 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
#define LOG_TAG "SQLiteDebug"
#include <jni.h>
#include <JNIHelp.h>
#include <ALog-priv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sqlite3.h>
namespace android {
static struct {
jfieldID memoryUsed;
jfieldID pageCacheOverflow;
jfieldID largestMemAlloc;
} gSQLiteDebugPagerStatsClassInfo;
static void nativeGetPagerStats(JNIEnv *env, jobject clazz, jobject statsObj)
{
int memoryUsed;
int pageCacheOverflow;
int largestMemAlloc;
int unused;
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &memoryUsed, &unused, 0);
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &unused, &largestMemAlloc, 0);
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &pageCacheOverflow, &unused, 0);
env->SetIntField(statsObj, gSQLiteDebugPagerStatsClassInfo.memoryUsed, memoryUsed);
env->SetIntField(statsObj, gSQLiteDebugPagerStatsClassInfo.pageCacheOverflow,
pageCacheOverflow);
env->SetIntField(statsObj, gSQLiteDebugPagerStatsClassInfo.largestMemAlloc, largestMemAlloc);
}
/*
* JNI registration.
*/
static JNINativeMethod gMethods[] =
{
{ "nativeGetPagerStats", "(Lorg/sqlite/database/sqlite/SQLiteDebug$PagerStats;)V",
(void*) nativeGetPagerStats },
};
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
LOG_FATAL_IF(! var, "Unable to find class " className);
#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
int register_android_database_SQLiteDebug(JNIEnv *env)
{
jclass clazz;
FIND_CLASS(clazz, "org/sqlite/database/sqlite/SQLiteDebug$PagerStats");
GET_FIELD_ID(gSQLiteDebugPagerStatsClassInfo.memoryUsed, clazz,
"memoryUsed", "I");
GET_FIELD_ID(gSQLiteDebugPagerStatsClassInfo.largestMemAlloc, clazz,
"largestMemAlloc", "I");
GET_FIELD_ID(gSQLiteDebugPagerStatsClassInfo.pageCacheOverflow, clazz,
"pageCacheOverflow", "I");
return jniRegisterNativeMethods(env, "org/sqlite/database/sqlite/SQLiteDebug",
gMethods, NELEM(gMethods));
}
} // namespace android

View File

@ -1,99 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
#define LOG_TAG "SQLiteGlobal"
#include <jni.h>
#include <JNIHelp.h>
#include "ALog-priv.h"
#include <sqlite3.h>
#if 0
#include <sqlite3_android.h>
#endif
#include "android_database_SQLiteCommon.h"
namespace android {
// Limit heap to 8MB for now. This is 4 times the maximum cursor window
// size, as has been used by the original code in SQLiteDatabase for
// a long time.
static const int SOFT_HEAP_LIMIT = 8 * 1024 * 1024;
// Called each time a message is logged.
static void sqliteLogCallback(void* data, int iErrCode, const char* zMsg) {
bool verboseLog = !!data;
if (iErrCode == 0 || iErrCode == SQLITE_CONSTRAINT || iErrCode == SQLITE_SCHEMA) {
if (verboseLog) {
ALOG(LOG_VERBOSE, SQLITE_LOG_TAG, "(%d) %s\n", iErrCode, zMsg);
}
} else {
ALOG(LOG_ERROR, SQLITE_LOG_TAG, "(%d) %s\n", iErrCode, zMsg);
}
}
// Sets the global SQLite configuration.
// This must be called before any other SQLite functions are called.
static void sqliteInitialize() {
// Enable multi-threaded mode. In this mode, SQLite is safe to use by multiple
// threads as long as no two threads use the same database connection at the same
// time (which we guarantee in the SQLite database wrappers).
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
// Redirect SQLite log messages to the Android log.
#if 0
bool verboseLog = android_util_Log_isVerboseLogEnabled(SQLITE_LOG_TAG);
#endif
bool verboseLog = false;
sqlite3_config(SQLITE_CONFIG_LOG, &sqliteLogCallback, verboseLog ? (void*)1 : NULL);
// The soft heap limit prevents the page cache allocations from growing
// beyond the given limit, no matter what the max page cache sizes are
// set to. The limit does not, as of 3.5.0, affect any other allocations.
sqlite3_soft_heap_limit(SOFT_HEAP_LIMIT);
// Initialize SQLite.
sqlite3_initialize();
}
static jint nativeReleaseMemory(JNIEnv* env, jclass clazz) {
return sqlite3_release_memory(SOFT_HEAP_LIMIT);
}
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
{ "nativeReleaseMemory", "()I",
(void*)nativeReleaseMemory },
};
int register_android_database_SQLiteGlobal(JNIEnv *env)
{
sqliteInitialize();
return jniRegisterNativeMethods(env, "org/sqlite/database/sqlite/SQLiteGlobal",
sMethods, NELEM(sMethods));
}
} // namespace android

View File

@ -1,191 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* JNI helper functions.
*
* This file may be included by C or C++ code, which is trouble because jni.h
* uses different typedefs for JNIEnv in each language.
*
* TODO: remove C support.
*/
#ifndef NATIVEHELPER_JNIHELP_H_
#define NATIVEHELPER_JNIHELP_H_
#include "jni.h"
#include <unistd.h>
#ifndef NELEM
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
* Register one or more native methods with a particular class.
* "className" looks like "java/lang/String". Aborts on failure.
* TODO: fix all callers and change the return type to void.
*/
int jniRegisterNativeMethods(C_JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods);
/*
* Throw an exception with the specified class and an optional message.
*
* The "className" argument will be passed directly to FindClass, which
* takes strings with slashes (e.g. "java/lang/Object").
*
* If an exception is currently pending, we log a warning message and
* clear it.
*
* Returns 0 on success, nonzero if something failed (e.g. the exception
* class couldn't be found, so *an* exception will still be pending).
*
* Currently aborts the VM if it can't throw the exception.
*/
int jniThrowException(C_JNIEnv* env, const char* className, const char* msg);
/*
* Throw a java.lang.NullPointerException, with an optional message.
*/
int jniThrowNullPointerException(C_JNIEnv* env, const char* msg);
/*
* Throw a java.lang.RuntimeException, with an optional message.
*/
int jniThrowRuntimeException(C_JNIEnv* env, const char* msg);
/*
* Throw a java.io.IOException, generating the message from errno.
*/
int jniThrowIOException(C_JNIEnv* env, int errnum);
/*
* Return a pointer to a locale-dependent error string explaining errno
* value 'errnum'. The returned pointer may or may not be equal to 'buf'.
* This function is thread-safe (unlike strerror) and portable (unlike
* strerror_r).
*/
const char* jniStrError(int errnum, char* buf, size_t buflen);
/*
* Returns a new java.io.FileDescriptor for the given int fd.
*/
jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd);
/*
* Returns the int fd from a java.io.FileDescriptor.
*/
int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor);
/*
* Sets the int fd in a java.io.FileDescriptor.
*/
void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor, int value);
/*
* Returns the reference from a java.lang.ref.Reference.
*/
jobject jniGetReferent(C_JNIEnv* env, jobject ref);
/*
* Log a message and an exception.
* If exception is NULL, logs the current exception in the JNI environment.
*/
void jniLogException(C_JNIEnv* env, int priority, const char* tag, jthrowable exception);
#ifdef __cplusplus
}
#endif
/*
* For C++ code, we provide inlines that map to the C functions. g++ always
* inlines these, even on non-optimized builds.
*/
#if defined(__cplusplus)
inline int jniRegisterNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) {
return jniRegisterNativeMethods(&env->functions, className, gMethods, numMethods);
}
inline int jniThrowException(JNIEnv* env, const char* className, const char* msg) {
return jniThrowException(&env->functions, className, msg);
}
extern "C" int jniThrowExceptionFmt(C_JNIEnv* env, const char* className, const char* fmt, va_list args);
/*
* Equivalent to jniThrowException but with a printf-like format string and
* variable-length argument list. This is only available in C++.
*/
inline int jniThrowExceptionFmt(JNIEnv* env, const char* className, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
return jniThrowExceptionFmt(&env->functions, className, fmt, args);
va_end(args);
}
inline int jniThrowNullPointerException(JNIEnv* env, const char* msg) {
return jniThrowNullPointerException(&env->functions, msg);
}
inline int jniThrowRuntimeException(JNIEnv* env, const char* msg) {
return jniThrowRuntimeException(&env->functions, msg);
}
inline int jniThrowIOException(JNIEnv* env, int errnum) {
return jniThrowIOException(&env->functions, errnum);
}
inline jobject jniCreateFileDescriptor(JNIEnv* env, int fd) {
return jniCreateFileDescriptor(&env->functions, fd);
}
inline int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
return jniGetFDFromFileDescriptor(&env->functions, fileDescriptor);
}
inline void jniSetFileDescriptorOfFD(JNIEnv* env, jobject fileDescriptor, int value) {
jniSetFileDescriptorOfFD(&env->functions, fileDescriptor, value);
}
inline jobject jniGetReferent(JNIEnv* env, jobject ref) {
return jniGetReferent(&env->functions, ref);
}
inline void jniLogException(JNIEnv* env, int priority, const char* tag, jthrowable exception = NULL) {
jniLogException(&env->functions, priority, tag, exception);
}
#endif
/*
* TEMP_FAILURE_RETRY is defined by some, but not all, versions of
* <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
* not already defined, then define it here.
*/
#ifndef TEMP_FAILURE_RETRY
/* Used to retry syscalls that can return EINTR. */
#define TEMP_FAILURE_RETRY(exp) ({ \
typeof (exp) _rc; \
do { \
_rc = (exp); \
} while (_rc == -1 && errno == EINTR); \
_rc; })
#endif
#endif /* NATIVEHELPER_JNIHELP_H_ */

View File

@ -1,99 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef JNI_CONSTANTS_H_included
#define JNI_CONSTANTS_H_included
#include "JNIHelp.h"
/**
* A cache to avoid calling FindClass at runtime.
*
* Class lookup is relatively expensive (2.5us on passion-eng at the time of writing), so we do
* all such lookups eagerly at startup. This means that code that never uses, say,
* java.util.zip.Deflater still has to pay for the lookup, but it means that on a device the cost
* is definitely paid during boot and amortized. A central cache also removes the temptation to
* dynamically call FindClass rather than add a small cache to each file that needs one. Another
* cost is that each class cached here requires a global reference, though in practice we save
* enough by not having a global reference for each file that uses a class such as java.lang.String
* which is used in several files.
*
* FindClass is still called in a couple of situations: when throwing exceptions, and in some of
* the serialization code. The former is clearly not a performance case, and we're currently
* assuming that neither is the latter.
*
* TODO: similar arguments hold for field and method IDs; we should cache them centrally too.
*/
struct JniConstants {
static void init(JNIEnv* env);
static jclass bidiRunClass;
static jclass bigDecimalClass;
static jclass booleanClass;
static jclass byteArrayClass;
static jclass byteClass;
static jclass calendarClass;
static jclass characterClass;
static jclass charsetICUClass;
static jclass constructorClass;
static jclass deflaterClass;
static jclass doubleClass;
static jclass errnoExceptionClass;
static jclass fieldClass;
static jclass fieldPositionIteratorClass;
static jclass fileDescriptorClass;
static jclass floatClass;
static jclass gaiExceptionClass;
static jclass inet6AddressClass;
static jclass inetAddressClass;
static jclass inetSocketAddressClass;
static jclass inetUnixAddressClass;
static jclass inflaterClass;
static jclass inputStreamClass;
static jclass integerClass;
static jclass localeDataClass;
static jclass longClass;
static jclass methodClass;
static jclass mutableIntClass;
static jclass mutableLongClass;
static jclass objectClass;
static jclass objectArrayClass;
static jclass outputStreamClass;
static jclass parsePositionClass;
static jclass patternSyntaxExceptionClass;
static jclass realToStringClass;
static jclass referenceClass;
static jclass shortClass;
static jclass socketClass;
static jclass socketImplClass;
static jclass stringClass;
static jclass structAddrinfoClass;
static jclass structFlockClass;
static jclass structGroupReqClass;
static jclass structLingerClass;
static jclass structPasswdClass;
static jclass structPollfdClass;
static jclass structStatClass;
static jclass structStatVfsClass;
static jclass structTimevalClass;
static jclass structUcredClass;
static jclass structUtsnameClass;
};
#define NATIVE_METHOD(className, functionName, signature) \
{ #functionName, signature, reinterpret_cast<void*>(className ## _ ## functionName) }
#endif // JNI_CONSTANTS_H_included

View File

@ -1,63 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SCOPED_LOCAL_REF_H_included
#define SCOPED_LOCAL_REF_H_included
#include "jni.h"
#include <stddef.h>
// A smart pointer that deletes a JNI local reference when it goes out of scope.
template<typename T>
class ScopedLocalRef {
public:
ScopedLocalRef(JNIEnv* env, T localRef) : mEnv(env), mLocalRef(localRef) {
}
~ScopedLocalRef() {
reset();
}
void reset(T ptr = NULL) {
if (ptr != mLocalRef) {
if (mLocalRef != NULL) {
mEnv->DeleteLocalRef(mLocalRef);
}
mLocalRef = ptr;
}
}
T release() __attribute__((warn_unused_result)) {
T localRef = mLocalRef;
mLocalRef = NULL;
return localRef;
}
T get() const {
return mLocalRef;
}
private:
JNIEnv* mEnv;
T mLocalRef;
// Disallow copy and assignment.
ScopedLocalRef(const ScopedLocalRef&);
void operator=(const ScopedLocalRef&);
};
#endif // SCOPED_LOCAL_REF_H_included

View File

@ -1,10 +0,0 @@
# 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/

View File

@ -1,20 +0,0 @@
# 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 *;
#}

View File

@ -1,14 +0,0 @@
# 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.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,36 +0,0 @@
<?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="&lt;this text should be replaced by the test output&gt;"
android:typeface="monospace"
/>
</LinearLayout>
</ScrollView>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">CustomSqlite</string>
</resources>

View File

@ -1,416 +0,0 @@
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");
}
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database;
import org.sqlite.database.sqlite.SQLiteDatabase;
/**
* An interface to let the apps define the actions to take when the following errors are detected
* database corruption
*/
public interface DatabaseErrorHandler {
/**
* defines the method to be invoked when database corruption is detected.
* @param dbObj the {@link SQLiteDatabase} object representing the database on which corruption
* is detected.
*/
void onCorruption(SQLiteDatabase dbObj);
}

View File

@ -1,117 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database;
import java.io.File;
import java.util.List;
import org.sqlite.database.sqlite.SQLiteDatabase;
import org.sqlite.database.sqlite.SQLiteException;
import android.util.Log;
import android.util.Pair;
/**
* Default class used to define the actions to take when the database corruption is reported
* by sqlite.
* <p>
* An application can specify an implementation of {@link DatabaseErrorHandler} on the
* following:
* <ul>
* <li>{@link SQLiteDatabase#openOrCreateDatabase(String,
* org.sqlite.database.sqlite.SQLiteDatabase.CursorFactory, DatabaseErrorHandler)}</li>
* <li>{@link SQLiteDatabase#openDatabase(String,
* org.sqlite.database.sqlite.SQLiteDatabase.CursorFactory, int, DatabaseErrorHandler)}</li>
* </ul>
* The specified {@link DatabaseErrorHandler} is used to handle database corruption errors, if they
* occur.
* <p>
* If null is specified for DatabaeErrorHandler param in the above calls, then this class is used
* as the default {@link DatabaseErrorHandler}.
*/
public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler {
private static final String TAG = "DefaultDatabaseErrorHandler";
/**
* defines the default method to be invoked when database corruption is detected.
* @param dbObj the {@link SQLiteDatabase} object representing the database on which corruption
* is detected.
*/
public void onCorruption(SQLiteDatabase dbObj) {
Log.e(TAG, "Corruption reported by sqlite on database: " + dbObj.getPath());
// If this is a SEE build, do not delete any database files.
//
if( SQLiteDatabase.hasCodec() ) return;
// is the corruption detected even before database could be 'opened'?
if (!dbObj.isOpen()) {
// database files are not even openable. delete this database file.
// NOTE if the database has attached databases, then any of them could be corrupt.
// and not deleting all of them could cause corrupted database file to remain and
// make the application crash on database open operation. To avoid this problem,
// the application should provide its own {@link DatabaseErrorHandler} impl class
// to delete ALL files of the database (including the attached databases).
deleteDatabaseFile(dbObj.getPath());
return;
}
List<Pair<String, String>> attachedDbs = null;
try {
// Close the database, which will cause subsequent operations to fail.
// before that, get the attached database list first.
try {
attachedDbs = dbObj.getAttachedDbs();
} catch (SQLiteException e) {
/* ignore */
}
try {
dbObj.close();
} catch (SQLiteException e) {
/* ignore */
}
} finally {
// Delete all files of this corrupt database and/or attached databases
if (attachedDbs != null) {
for (Pair<String, String> p : attachedDbs) {
deleteDatabaseFile(p.second);
}
} else {
// attachedDbs = null is possible when the database is so corrupt that even
// "PRAGMA database_list;" also fails. delete the main database file
deleteDatabaseFile(dbObj.getPath());
}
}
}
private void deleteDatabaseFile(String fileName) {
if (fileName.equalsIgnoreCase(":memory:") || fileName.trim().length() == 0) {
return;
}
Log.e(TAG, "deleting the database file: " + fileName);
try {
SQLiteDatabase.deleteDatabase(new File(fileName));
} catch (Exception e) {
/* print warning and ignore exception */
Log.w(TAG, "delete failed: " + e.getMessage());
}
}
}

View File

@ -1,176 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database;
import android.database.Cursor;
import android.database.CursorWindow;
/* import org.apache.commons.codec.binary.Hex; */
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import org.sqlite.database.sqlite.SQLiteAbortException;
import org.sqlite.database.sqlite.SQLiteConstraintException;
import org.sqlite.database.sqlite.SQLiteDatabase;
import org.sqlite.database.sqlite.SQLiteDatabaseCorruptException;
import org.sqlite.database.sqlite.SQLiteDiskIOException;
import org.sqlite.database.sqlite.SQLiteException;
import org.sqlite.database.sqlite.SQLiteFullException;
import org.sqlite.database.sqlite.SQLiteProgram;
import org.sqlite.database.sqlite.SQLiteStatement;
import android.os.OperationCanceledException;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;
import android.util.Log;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.text.Collator;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* Static utility methods for dealing with databases and {@link Cursor}s.
*/
public class ExtraUtils {
private static final String TAG = "ExtraUtils";
private static final boolean DEBUG = false;
/** One of the values returned by {@link #getSqlStatementType(String)}. */
public static final int STATEMENT_SELECT = 1;
/** One of the values returned by {@link #getSqlStatementType(String)}. */
public static final int STATEMENT_UPDATE = 2;
/** One of the values returned by {@link #getSqlStatementType(String)}. */
public static final int STATEMENT_ATTACH = 3;
/** One of the values returned by {@link #getSqlStatementType(String)}. */
public static final int STATEMENT_BEGIN = 4;
/** One of the values returned by {@link #getSqlStatementType(String)}. */
public static final int STATEMENT_COMMIT = 5;
/** One of the values returned by {@link #getSqlStatementType(String)}. */
public static final int STATEMENT_ABORT = 6;
/** One of the values returned by {@link #getSqlStatementType(String)}. */
public static final int STATEMENT_PRAGMA = 7;
/** One of the values returned by {@link #getSqlStatementType(String)}. */
public static final int STATEMENT_DDL = 8;
/** One of the values returned by {@link #getSqlStatementType(String)}. */
public static final int STATEMENT_UNPREPARED = 9;
/** One of the values returned by {@link #getSqlStatementType(String)}. */
public static final int STATEMENT_OTHER = 99;
/**
* Returns column index of "_id" column, or -1 if not found.
*/
public static int findRowIdColumnIndex(String[] columnNames) {
int length = columnNames.length;
for (int i = 0; i < length; i++) {
if (columnNames[i].equals("_id")) {
return i;
}
}
return -1;
}
/**
* Picks a start position for {@link Cursor#fillWindow} such that the
* window will contain the requested row and a useful range of rows
* around it.
*
* When the data set is too large to fit in a cursor window, seeking the
* cursor can become a very expensive operation since we have to run the
* query again when we move outside the bounds of the current window.
*
* We try to choose a start position for the cursor window such that
* 1/3 of the window's capacity is used to hold rows before the requested
* position and 2/3 of the window's capacity is used to hold rows after the
* requested position.
*
* @param cursorPosition The row index of the row we want to get.
* @param cursorWindowCapacity The estimated number of rows that can fit in
* a cursor window, or 0 if unknown.
* @return The recommended start position, always less than or equal to
* the requested row.
* @hide
*/
public static int cursorPickFillWindowStartPosition(
int cursorPosition, int cursorWindowCapacity) {
return Math.max(cursorPosition - cursorWindowCapacity / 3, 0);
}
/**
* Returns data type of the given object's value.
*<p>
* Returned values are
* <ul>
* <li>{@link Cursor#FIELD_TYPE_NULL}</li>
* <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
* <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
* <li>{@link Cursor#FIELD_TYPE_STRING}</li>
* <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
*</ul>
*</p>
*
* @param obj the object whose value type is to be returned
* @return object value type
*/
public static int getTypeOfObject(Object obj) {
if (obj == null) {
return Cursor.FIELD_TYPE_NULL;
} else if (obj instanceof byte[]) {
return Cursor.FIELD_TYPE_BLOB;
} else if (obj instanceof Float || obj instanceof Double) {
return Cursor.FIELD_TYPE_FLOAT;
} else if (obj instanceof Long || obj instanceof Integer
|| obj instanceof Short || obj instanceof Byte) {
return Cursor.FIELD_TYPE_INTEGER;
} else {
return Cursor.FIELD_TYPE_STRING;
}
}
/**
* Utility method to run the query on the db and return the value in the
* first column of the first row.
*/
public static long longForQuery(
SQLiteDatabase db, String query, String[] selectionArgs
) {
SQLiteStatement prog = db.compileStatement(query);
try {
return longForQuery(prog, selectionArgs);
} finally {
prog.close();
}
}
/**
* Utility method to run the pre-compiled query and return the value in the
* first column of the first row.
*/
public static long longForQuery(
SQLiteStatement prog, String[] selectionArgs
) {
prog.bindAllArgsAsStrings(selectionArgs);
return prog.simpleQueryForLong();
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database;
/**
* An exception that indicates there was an error with SQL parsing or execution.
*/
public class SQLException extends RuntimeException {
public SQLException() {
}
public SQLException(String error) {
super(error);
}
public SQLException(String error, Throwable cause) {
super(error, cause);
}
}

View File

@ -1,235 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import android.util.Log;
/**
* CloseGuard is a mechanism for flagging implicit finalizer cleanup of
* resources that should have been cleaned up by explicit close
* methods (aka "explicit termination methods" in Effective Java).
* <p>
* A simple example: <pre> {@code
* class Foo {
*
* private final CloseGuard guard = CloseGuard.get();
*
* ...
*
* public Foo() {
* ...;
* guard.open("cleanup");
* }
*
* public void cleanup() {
* guard.close();
* ...;
* }
*
* protected void finalize() throws Throwable {
* try {
* if (guard != null) {
* guard.warnIfOpen();
* }
* cleanup();
* } finally {
* super.finalize();
* }
* }
* }
* }</pre>
*
* In usage where the resource to be explicitly cleaned up are
* allocated after object construction, CloseGuard protection can
* be deferred. For example: <pre> {@code
* class Bar {
*
* private final CloseGuard guard = CloseGuard.get();
*
* ...
*
* public Bar() {
* ...;
* }
*
* public void connect() {
* ...;
* guard.open("cleanup");
* }
*
* public void cleanup() {
* guard.close();
* ...;
* }
*
* protected void finalize() throws Throwable {
* try {
* if (guard != null) {
* guard.warnIfOpen();
* }
* cleanup();
* } finally {
* super.finalize();
* }
* }
* }
* }</pre>
*
* When used in a constructor calls to {@code open} should occur at
* the end of the constructor since an exception that would cause
* abrupt termination of the constructor will mean that the user will
* not have a reference to the object to cleanup explicitly. When used
* in a method, the call to {@code open} should occur just after
* resource acquisition.
*
* <p>
*
* Note that the null check on {@code guard} in the finalizer is to
* cover cases where a constructor throws an exception causing the
* {@code guard} to be uninitialized.
*
* @hide
*/
public final class CloseGuard {
/**
* Instance used when CloseGuard is disabled to avoid allocation.
*/
private static final CloseGuard NOOP = new CloseGuard();
/**
* Enabled by default so we can catch issues early in VM startup.
* Note, however, that Android disables this early in its startup,
* but enables it with DropBoxing for system apps on debug builds.
*/
private static volatile boolean ENABLED = true;
/**
* Hook for customizing how CloseGuard issues are reported.
*/
private static volatile Reporter REPORTER = new DefaultReporter();
/**
* Returns a CloseGuard instance. If CloseGuard is enabled, {@code
* #open(String)} can be used to set up the instance to warn on
* failure to close. If CloseGuard is disabled, a non-null no-op
* instance is returned.
*/
public static CloseGuard get() {
if (!ENABLED) {
return NOOP;
}
return new CloseGuard();
}
/**
* Used to enable or disable CloseGuard. Note that CloseGuard only
* warns if it is enabled for both allocation and finalization.
*/
public static void setEnabled(boolean enabled) {
ENABLED = enabled;
}
/**
* Used to replace default Reporter used to warn of CloseGuard
* violations. Must be non-null.
*/
public static void setReporter(Reporter reporter) {
if (reporter == null) {
throw new NullPointerException("reporter == null");
}
REPORTER = reporter;
}
/**
* Returns non-null CloseGuard.Reporter.
*/
public static Reporter getReporter() {
return REPORTER;
}
private CloseGuard() {}
/**
* If CloseGuard is enabled, {@code open} initializes the instance
* with a warning that the caller should have explicitly called the
* {@code closer} method instead of relying on finalization.
*
* @param closer non-null name of explicit termination method
* @throws NullPointerException if closer is null, regardless of
* whether or not CloseGuard is enabled
*/
public void open(String closer) {
// always perform the check for valid API usage...
if (closer == null) {
throw new NullPointerException("closer == null");
}
// ...but avoid allocating an allocationSite if disabled
if (this == NOOP || !ENABLED) {
return;
}
String message = "Explicit termination method '" + closer + "' not called";
allocationSite = new Throwable(message);
}
private Throwable allocationSite;
/**
* Marks this CloseGuard instance as closed to avoid warnings on
* finalization.
*/
public void close() {
allocationSite = null;
}
/**
* If CloseGuard is enabled, logs a warning if the caller did not
* properly cleanup by calling an explicit close method
* before finalization. If CloseGuard is disabled, no action is
* performed.
*/
public void warnIfOpen() {
if (allocationSite == null || !ENABLED) {
return;
}
String message =
("A resource was acquired at attached stack trace but never released. "
+ "See java.io.Closeable for information on avoiding resource leaks.");
REPORTER.report(message, allocationSite);
}
/**
* Interface to allow customization of reporting behavior.
*/
public static interface Reporter {
public void report (String message, Throwable allocationSite);
}
/**
* Default Reporter which reports CloseGuard violations to the log.
*/
private static final class DefaultReporter implements Reporter {
@Override public void report (String message, Throwable allocationSite) {
Log.w(message, allocationSite);
}
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* An exception that indicates that garbage-collector is finalizing a database object
* that is not explicitly closed
* @hide
*/
public class DatabaseObjectNotClosedException extends RuntimeException {
private static final String s = "Application did not close the cursor or database object " +
"that was opened here";
public DatabaseObjectNotClosedException() {
super(s);
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* An exception that indicates that the SQLite program was aborted.
* This can happen either through a call to ABORT in a trigger,
* or as the result of using the ABORT conflict clause.
*/
public class SQLiteAbortException extends SQLiteException {
public SQLiteAbortException() {}
public SQLiteAbortException(String error) {
super(error);
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* This exception class is used when sqlite can't access the database file
* due to lack of permissions on the file.
*/
public class SQLiteAccessPermException extends SQLiteException {
public SQLiteAccessPermException() {}
public SQLiteAccessPermException(String error) {
super(error);
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* Thrown if the the bind or column parameter index is out of range
*/
public class SQLiteBindOrColumnIndexOutOfRangeException extends SQLiteException {
public SQLiteBindOrColumnIndexOutOfRangeException() {}
public SQLiteBindOrColumnIndexOutOfRangeException(String error) {
super(error);
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
public class SQLiteBlobTooBigException extends SQLiteException {
public SQLiteBlobTooBigException() {}
public SQLiteBlobTooBigException(String error) {
super(error);
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
public class SQLiteCantOpenDatabaseException extends SQLiteException {
public SQLiteCantOpenDatabaseException() {}
public SQLiteCantOpenDatabaseException(String error) {
super(error);
}
}

View File

@ -1,112 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import java.io.Closeable;
/**
* An object created from a SQLiteDatabase that can be closed.
*
* This class implements a primitive reference counting scheme for database objects.
*/
public abstract class SQLiteClosable implements Closeable {
private int mReferenceCount = 1;
/**
* Called when the last reference to the object was released by
* a call to {@link #releaseReference()} or {@link #close()}.
*/
protected abstract void onAllReferencesReleased();
/**
* Called when the last reference to the object was released by
* a call to {@link #releaseReferenceFromContainer()}.
*
* @deprecated Do not use.
*/
@Deprecated
protected void onAllReferencesReleasedFromContainer() {
onAllReferencesReleased();
}
/**
* Acquires a reference to the object.
*
* @throws IllegalStateException if the last reference to the object has already
* been released.
*/
public void acquireReference() {
synchronized(this) {
if (mReferenceCount <= 0) {
throw new IllegalStateException(
"attempt to re-open an already-closed object: " + this);
}
mReferenceCount++;
}
}
/**
* Releases a reference to the object, closing the object if the last reference
* was released.
*
* @see #onAllReferencesReleased()
*/
public void releaseReference() {
boolean refCountIsZero = false;
synchronized(this) {
refCountIsZero = --mReferenceCount == 0;
}
if (refCountIsZero) {
onAllReferencesReleased();
}
}
/**
* Releases a reference to the object that was owned by the container of the object,
* closing the object if the last reference was released.
*
* @see #onAllReferencesReleasedFromContainer()
* @deprecated Do not use.
*/
@Deprecated
public void releaseReferenceFromContainer() {
boolean refCountIsZero = false;
synchronized(this) {
refCountIsZero = --mReferenceCount == 0;
}
if (refCountIsZero) {
onAllReferencesReleasedFromContainer();
}
}
/**
* Releases a reference to the object, closing the object if the last reference
* was released.
*
* Calling this method is equivalent to calling {@link #releaseReference}.
*
* @see #releaseReference()
* @see #onAllReferencesReleased()
*/
public void close() {
releaseReference();
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* An exception that indicates that an integrity constraint was violated.
*/
public class SQLiteConstraintException extends SQLiteException {
public SQLiteConstraintException() {}
public SQLiteConstraintException(String error) {
super(error);
}
}

View File

@ -1,318 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import org.sqlite.database.ExtraUtils;
import android.database.AbstractWindowedCursor;
import android.database.CursorWindow;
import android.os.StrictMode;
import android.util.Log;
import java.util.HashMap;
import java.util.Map;
/**
* A Cursor implementation that exposes results from a query on a
* {@link SQLiteDatabase}.
*
* SQLiteCursor is not internally synchronized so code using a SQLiteCursor from multiple
* threads should perform its own synchronization when using the SQLiteCursor.
*/
public class SQLiteCursor extends AbstractWindowedCursor {
static final String TAG = "SQLiteCursor";
static final int NO_COUNT = -1;
/** The name of the table to edit */
private final String mEditTable;
/** The names of the columns in the rows */
private final String[] mColumns;
/** The query object for the cursor */
private final SQLiteQuery mQuery;
/** The compiled query this cursor came from */
private final SQLiteCursorDriver mDriver;
/** The number of rows in the cursor */
private int mCount = NO_COUNT;
/** The number of rows that can fit in the cursor window, 0 if unknown */
private int mCursorWindowCapacity;
/** A mapping of column names to column indices, to speed up lookups */
private Map<String, Integer> mColumnNameMap;
/** Used to find out where a cursor was allocated in case it never got released. */
private final Throwable mStackTrace;
/**
* Execute a query and provide access to its result set through a Cursor
* interface. For a query such as: {@code SELECT name, birth, phone FROM
* myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth,
* phone) would be in the projection argument and everything from
* {@code FROM} onward would be in the params argument.
*
* @param db a reference to a Database object that is already constructed
* and opened. This param is not used any longer
* @param editTable the name of the table used for this query
* @param query the rest of the query terms
* cursor is finalized
* @deprecated use {@link #SQLiteCursor(SQLiteCursorDriver, String, SQLiteQuery)} instead
*/
@Deprecated
public SQLiteCursor(SQLiteDatabase db, SQLiteCursorDriver driver,
String editTable, SQLiteQuery query) {
this(driver, editTable, query);
}
/**
* Execute a query and provide access to its result set through a Cursor
* interface. For a query such as: {@code SELECT name, birth, phone FROM
* myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth,
* phone) would be in the projection argument and everything from
* {@code FROM} onward would be in the params argument.
*
* @param editTable the name of the table used for this query
* @param query the {@link SQLiteQuery} object associated with this cursor object.
*/
public SQLiteCursor(SQLiteCursorDriver driver, String editTable, SQLiteQuery query) {
if (query == null) {
throw new IllegalArgumentException("query object cannot be null");
}
if (/* StrictMode.vmSqliteObjectLeaksEnabled() */ false ) {
mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
} else {
mStackTrace = null;
}
mDriver = driver;
mEditTable = editTable;
mColumnNameMap = null;
mQuery = query;
mColumns = query.getColumnNames();
//mRowIdColumnIndex = ExtraUtils.findRowIdColumnIndex(mColumns);
// try {
// Field field = AbstractCursor.class.getDeclaredField("mRowIdColumnIndex");
// field.setInt(this, ExtraUtils.findRowIdColumnIndex(mColumns));
// } catch (NoSuchFieldException nfe) {
// ;//loaded in system with api level 23 or later
// } catch (IllegalAccessException e) {
// ;//iae
// } catch (IllegalArgumentException e) {
// ;//iae
// }
}
/**
* Get the database that this cursor is associated with.
* @return the SQLiteDatabase that this cursor is associated with.
*/
public SQLiteDatabase getDatabase() {
return mQuery.getDatabase();
}
@Override
public boolean onMove(int oldPosition, int newPosition) {
// Make sure the row at newPosition is present in the window
if (mWindow == null || newPosition < mWindow.getStartPosition() ||
newPosition >= (mWindow.getStartPosition() + mWindow.getNumRows())) {
fillWindow(newPosition);
}
return true;
}
@Override
public int getCount() {
if (mCount == NO_COUNT) {
fillWindow(0);
}
return mCount;
}
/*
** The AbstractWindowClass contains protected methods clearOrCreateWindow() and
** closeWindow(), which are used by the android.database.sqlite.* version of this
** class. But, since they are marked with "@hide", the following replacement
** versions are required.
*/
private void awc_clearOrCreateWindow(String name){
CursorWindow win = getWindow();
if( win==null ){
win = new CursorWindow(name);
setWindow(win);
}else{
win.clear();
}
}
private void awc_closeWindow(){
setWindow(null);
}
private void fillWindow(int requiredPos) {
awc_clearOrCreateWindow(getDatabase().getPath());
try {
if (mCount == NO_COUNT) {
int startPos = ExtraUtils.cursorPickFillWindowStartPosition(requiredPos, 0);
mCount = mQuery.fillWindow(mWindow, startPos, requiredPos, true);
mCursorWindowCapacity = mWindow.getNumRows();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "received count(*) from native_fill_window: " + mCount);
}
} else {
int startPos = ExtraUtils.cursorPickFillWindowStartPosition(requiredPos,
mCursorWindowCapacity);
mQuery.fillWindow(mWindow, startPos, requiredPos, false);
}
} catch (RuntimeException ex) {
// Close the cursor window if the query failed and therefore will
// not produce any results. This helps to avoid accidentally leaking
// the cursor window if the client does not correctly handle exceptions
// and fails to close the cursor.
awc_closeWindow();
throw ex;
}
}
@Override
public int getColumnIndex(String columnName) {
// Create mColumnNameMap on demand
if (mColumnNameMap == null) {
String[] columns = mColumns;
int columnCount = columns.length;
HashMap<String, Integer> map = new HashMap<String, Integer>(columnCount, 1);
for (int i = 0; i < columnCount; i++) {
map.put(columns[i], i);
}
mColumnNameMap = map;
}
// Hack according to bug 903852
final int periodIndex = columnName.lastIndexOf('.');
if (periodIndex != -1) {
Exception e = new Exception();
Log.e(TAG, "requesting column name with table name -- " + columnName, e);
columnName = columnName.substring(periodIndex + 1);
}
Integer i = mColumnNameMap.get(columnName);
if (i != null) {
return i.intValue();
} else {
return -1;
}
}
@Override
public String[] getColumnNames() {
return mColumns;
}
@Override
public void deactivate() {
super.deactivate();
mDriver.cursorDeactivated();
}
@Override
public void close() {
super.close();
synchronized (this) {
mQuery.close();
mDriver.cursorClosed();
}
}
@Override
public boolean requery() {
if (isClosed()) {
return false;
}
synchronized (this) {
if (!mQuery.getDatabase().isOpen()) {
return false;
}
if (mWindow != null) {
mWindow.clear();
}
mPos = -1;
mCount = NO_COUNT;
mDriver.cursorRequeried(this);
}
try {
return super.requery();
} catch (IllegalStateException e) {
// for backwards compatibility, just return false
Log.w(TAG, "requery() failed " + e.getMessage(), e);
return false;
}
}
@Override
public void setWindow(CursorWindow window) {
super.setWindow(window);
mCount = NO_COUNT;
}
/**
* Changes the selection arguments. The new values take effect after a call to requery().
*/
public void setSelectionArguments(String[] selectionArgs) {
mDriver.setBindArguments(selectionArgs);
}
/**
* Release the native resources, if they haven't been released yet.
*/
@Override
protected void finalize() {
try {
// if the cursor hasn't been closed yet, close it first
if (mWindow != null) {
/*
if (mStackTrace != null) {
String sql = mQuery.getSql();
int len = sql.length();
StrictMode.onSqliteObjectLeaked(
"Finalizing a Cursor that has not been deactivated or closed. " +
"database = " + mQuery.getDatabase().getLabel() +
", table = " + mEditTable +
", query = " + sql.substring(0, (len > 1000) ? 1000 : len),
mStackTrace);
}
*/
close();
}
} finally {
super.finalize();
}
}
}

View File

@ -1,60 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import android.database.Cursor;
import org.sqlite.database.sqlite.SQLiteDatabase.CursorFactory;
/**
* A driver for SQLiteCursors that is used to create them and gets notified
* by the cursors it creates on significant events in their lifetimes.
*/
public interface SQLiteCursorDriver {
/**
* Executes the query returning a Cursor over the result set.
*
* @param factory The CursorFactory to use when creating the Cursors, or
* null if standard SQLiteCursors should be returned.
* @return a Cursor over the result set
*/
Cursor query(CursorFactory factory, String[] bindArgs);
/**
* Called by a SQLiteCursor when it is released.
*/
void cursorDeactivated();
/**
* Called by a SQLiteCursor when it is requeried.
*/
void cursorRequeried(Cursor cursor);
/**
* Called by a SQLiteCursor when it it closed to destroy this object as well.
*/
void cursorClosed();
/**
* Set new bind arguments. These will take effect in cursorRequeried().
* @param bindArgs the new arguments
*/
public void setBindArguments(String[] bindArgs);
}

View File

@ -1,57 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* Describes a custom SQL function.
*
* @hide
*/
public final class SQLiteCustomFunction {
public final String name;
public final int numArgs;
public final SQLiteDatabase.CustomFunction callback;
/**
* Create custom function.
*
* @param name The name of the sqlite3 function.
* @param numArgs The number of arguments for the function, or -1 to
* support any number of arguments.
* @param callback The callback to invoke when the function is executed.
*/
public SQLiteCustomFunction(String name, int numArgs,
SQLiteDatabase.CustomFunction callback) {
if (name == null) {
throw new IllegalArgumentException("name must not be null.");
}
this.name = name;
this.numArgs = numArgs;
this.callback = callback;
}
// Called from native.
@SuppressWarnings("unused")
private void dispatchCallback(String[] args) {
callback.callback(args);
}
}

View File

@ -1,169 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import java.util.ArrayList;
import java.util.Locale;
import java.util.regex.Pattern;
/**
* Describes how to configure a database.
* <p>
* The purpose of this object is to keep track of all of the little
* configuration settings that are applied to a database after it
* is opened so that they can be applied to all connections in the
* connection pool uniformly.
* </p><p>
* Each connection maintains its own copy of this object so it can
* keep track of which settings have already been applied.
* </p>
*
* @hide
*/
public final class SQLiteDatabaseConfiguration {
// The pattern we use to strip email addresses from database paths
// when constructing a label to use in log messages.
private static final Pattern EMAIL_IN_DB_PATTERN =
Pattern.compile("[\\w\\.\\-]+@[\\w\\.\\-]+");
/**
* Special path used by in-memory databases.
*/
public static final String MEMORY_DB_PATH = ":memory:";
/**
* The database path.
*/
public final String path;
/**
* The label to use to describe the database when it appears in logs.
* This is derived from the path but is stripped to remove PII.
*/
public final String label;
/**
* The flags used to open the database.
*/
public int openFlags;
/**
* The maximum size of the prepared statement cache for each database connection.
* Must be non-negative.
*
* Default is 25.
*/
public int maxSqlCacheSize;
/**
* The database locale.
*
* Default is the value returned by {@link Locale#getDefault()}.
*/
public Locale locale;
/**
* True if foreign key constraints are enabled.
*
* Default is false.
*/
public boolean foreignKeyConstraintsEnabled;
/**
* 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}.
*/
public SQLiteDatabaseConfiguration(String path, int openFlags) {
if (path == null) {
throw new IllegalArgumentException("path must not be null.");
}
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.
*/
public SQLiteDatabaseConfiguration(SQLiteDatabaseConfiguration other) {
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.
*/
public void updateParametersFrom(SQLiteDatabaseConfiguration other) {
if (other == null) {
throw new IllegalArgumentException("other must not be null.");
}
if (!path.equals(other.path)) {
throw new IllegalArgumentException("other configuration must refer to "
+ "the same database.");
}
openFlags = other.openFlags;
maxSqlCacheSize = other.maxSqlCacheSize;
locale = other.locale;
foreignKeyConstraintsEnabled = other.foreignKeyConstraintsEnabled;
customFunctions.clear();
customFunctions.addAll(other.customFunctions);
}
/**
* Returns true if the database is in-memory.
* @return True if the database is in-memory.
*/
public boolean isInMemoryDb() {
return path.equalsIgnoreCase(MEMORY_DB_PATH);
}
private static String stripPathForLogs(String path) {
if (path.indexOf('@') == -1) {
return path;
}
return EMAIL_IN_DB_PATTERN.matcher(path).replaceAll("XX@YY");
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* An exception that indicates that the SQLite database file is corrupt.
*/
public class SQLiteDatabaseCorruptException extends SQLiteException {
public SQLiteDatabaseCorruptException() {}
public SQLiteDatabaseCorruptException(String error) {
super(error);
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* Thrown if the database engine was unable to acquire the
* database locks it needs to do its job. If the statement is a [COMMIT]
* or occurs outside of an explicit transaction, then you can retry the
* statement. If the statement is not a [COMMIT] and occurs within a
* explicit transaction then you should rollback the transaction before
* continuing.
*/
public class SQLiteDatabaseLockedException extends SQLiteException {
public SQLiteDatabaseLockedException() {}
public SQLiteDatabaseLockedException(String error) {
super(error);
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
public class SQLiteDatatypeMismatchException extends SQLiteException {
public SQLiteDatatypeMismatchException() {}
public SQLiteDatatypeMismatchException(String error) {
super(error);
}
}

View File

@ -1,176 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import java.util.ArrayList;
import android.os.Build;
/* import android.os.SystemProperties; */
import android.util.Log;
import android.util.Printer;
/**
* Provides debugging info about all SQLite databases running in the current process.
*
* {@hide}
*/
public final class SQLiteDebug {
private static native void nativeGetPagerStats(PagerStats stats);
/**
* Controls the printing of informational SQL log messages.
*
* Enable using "adb shell setprop log.tag.SQLiteLog VERBOSE".
*/
public static final boolean DEBUG_SQL_LOG =
Log.isLoggable("SQLiteLog", Log.VERBOSE);
/**
* Controls the printing of SQL statements as they are executed.
*
* Enable using "adb shell setprop log.tag.SQLiteStatements VERBOSE".
*/
public static final boolean DEBUG_SQL_STATEMENTS =
Log.isLoggable("SQLiteStatements", Log.VERBOSE);
/**
* Controls the printing of wall-clock time taken to execute SQL statements
* as they are executed.
*
* Enable using "adb shell setprop log.tag.SQLiteTime VERBOSE".
*/
public static final boolean DEBUG_SQL_TIME =
Log.isLoggable("SQLiteTime", Log.VERBOSE);
/**
* True to enable database performance testing instrumentation.
* @hide
*/
public static final boolean DEBUG_LOG_SLOW_QUERIES = false;
private SQLiteDebug() {
}
/**
* Determines whether a query should be logged.
*
* Reads the "db.log.slow_query_threshold" system property, which can be changed
* by the user at any time. If the value is zero, then all queries will
* be considered slow. If the value does not exist or is negative, then no queries will
* be considered slow.
*
* This value can be changed dynamically while the system is running.
* For example, "adb shell setprop db.log.slow_query_threshold 200" will
* log all queries that take 200ms or longer to run.
* @hide
*/
public static final boolean shouldLogSlowQuery(long elapsedTimeMillis) {
int slowQueryMillis = 10000;
return slowQueryMillis >= 0 && elapsedTimeMillis >= slowQueryMillis;
}
/**
* Contains statistics about the active pagers in the current process.
*
* @see #nativeGetPagerStats(PagerStats)
*/
public static class PagerStats {
/** the current amount of memory checked out by sqlite using sqlite3_malloc().
* documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
*/
public int memoryUsed;
/** the number of bytes of page cache allocation which could not be sattisfied by the
* SQLITE_CONFIG_PAGECACHE buffer and where forced to overflow to sqlite3_malloc().
* The returned value includes allocations that overflowed because they where too large
* (they were larger than the "sz" parameter to SQLITE_CONFIG_PAGECACHE) and allocations
* that overflowed because no space was left in the page cache.
* documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
*/
public int pageCacheOverflow;
/** records the largest memory allocation request handed to sqlite3.
* documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
*/
public int largestMemAlloc;
/** a list of {@link DbStats} - one for each main database opened by the applications
* running on the android device
*/
public ArrayList<DbStats> dbStats;
}
/**
* contains statistics about a database
*/
public static class DbStats {
/** name of the database */
public String dbName;
/** the page size for the database */
public long pageSize;
/** the database size */
public long dbSize;
/** documented here http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html */
public int lookaside;
/** statement cache stats: hits/misses/cachesize */
public String cache;
public DbStats(String dbName, long pageCount, long pageSize, int lookaside,
int hits, int misses, int cachesize) {
this.dbName = dbName;
this.pageSize = pageSize / 1024;
dbSize = (pageCount * pageSize) / 1024;
this.lookaside = lookaside;
this.cache = hits + "/" + misses + "/" + cachesize;
}
}
/**
* return all pager and database stats for the current process.
* @return {@link PagerStats}
*/
public static PagerStats getDatabaseInfo() {
PagerStats stats = new PagerStats();
nativeGetPagerStats(stats);
stats.dbStats = SQLiteDatabase.getDbStats();
return stats;
}
/**
* Dumps detailed information about all databases used by the process.
* @param printer The printer for dumping database state.
* @param args Command-line arguments supplied to dumpsys dbinfo
*/
public static void dump(Printer printer, String[] args) {
boolean verbose = false;
for (String arg : args) {
if (arg.equals("-v")) {
verbose = true;
}
}
SQLiteDatabase.dumpAll(printer, verbose);
}
}

View File

@ -1,87 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import android.database.Cursor;
import org.sqlite.database.sqlite.SQLiteDatabase.CursorFactory;
import android.os.CancellationSignal;
/**
* A cursor driver that uses the given query directly.
*
* @hide
*/
public final class SQLiteDirectCursorDriver implements SQLiteCursorDriver {
private final SQLiteDatabase mDatabase;
private final String mEditTable;
private final String mSql;
private final CancellationSignal mCancellationSignal;
private SQLiteQuery mQuery;
public SQLiteDirectCursorDriver(SQLiteDatabase db, String sql, String editTable,
CancellationSignal cancellationSignal) {
mDatabase = db;
mEditTable = editTable;
mSql = sql;
mCancellationSignal = cancellationSignal;
}
public Cursor query(CursorFactory factory, String[] selectionArgs) {
final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
final Cursor cursor;
try {
query.bindAllArgsAsStrings(selectionArgs);
if (factory == null) {
cursor = new SQLiteCursor(this, mEditTable, query);
} else {
cursor = factory.newCursor(mDatabase, this, mEditTable, query);
}
} catch (RuntimeException ex) {
query.close();
throw ex;
}
mQuery = query;
return cursor;
}
public void cursorClosed() {
// Do nothing
}
public void setBindArguments(String[] bindArgs) {
mQuery.bindAllArgsAsStrings(bindArgs);
}
public void cursorDeactivated() {
// Do nothing
}
public void cursorRequeried(Cursor cursor) {
// Do nothing
}
@Override
public String toString() {
return "SQLiteDirectCursorDriver: " + mSql;
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* An exception that indicates that an IO error occured while accessing the
* SQLite database file.
*/
public class SQLiteDiskIOException extends SQLiteException {
public SQLiteDiskIOException() {}
public SQLiteDiskIOException(String error) {
super(error);
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* An exception that indicates that the SQLite program is done.
* Thrown when an operation that expects a row (such as {@link
* SQLiteStatement#simpleQueryForString} or {@link
* SQLiteStatement#simpleQueryForLong}) does not get one.
*/
public class SQLiteDoneException extends SQLiteException {
public SQLiteDoneException() {}
public SQLiteDoneException(String error) {
super(error);
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import org.sqlite.database.SQLException;
/**
* A SQLite exception that indicates there was an error with SQL parsing or execution.
*/
public class SQLiteException extends SQLException {
public SQLiteException() {
}
public SQLiteException(String error) {
super(error);
}
public SQLiteException(String error, Throwable cause) {
super(error, cause);
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* An exception that indicates that the SQLite database is full.
*/
public class SQLiteFullException extends SQLiteException {
public SQLiteFullException() {}
public SQLiteFullException(String error) {
super(error);
}
}

View File

@ -1,117 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import android.content.res.Resources;
import android.os.StatFs;
/* import android.os.SystemProperties; */
/**
* Provides access to SQLite functions that affect all database connection,
* such as memory management.
*
* The native code associated with SQLiteGlobal is also sets global configuration options
* using sqlite3_config() then calls sqlite3_initialize() to ensure that the SQLite
* library is properly initialized exactly once before any other framework or application
* code has a chance to run.
*
* Verbose SQLite logging is enabled if the "log.tag.SQLiteLog" property is set to "V".
* (per {@link SQLiteDebug#DEBUG_SQL_LOG}).
*
* @hide
*/
public final class SQLiteGlobal {
private static final String TAG = "SQLiteGlobal";
private static final Object sLock = new Object();
private static int sDefaultPageSize;
private static native int nativeReleaseMemory();
private SQLiteGlobal() {
}
/**
* Attempts to release memory by pruning the SQLite page cache and other
* internal data structures.
*
* @return The number of bytes that were freed.
*/
public static int releaseMemory() {
return nativeReleaseMemory();
}
/**
* Gets the default page size to use when creating a database.
*/
public static int getDefaultPageSize() {
synchronized (sLock) {
if (sDefaultPageSize == 0) {
sDefaultPageSize = new StatFs("/data").getBlockSize();
}
return 1024;
}
}
/**
* Gets the default journal mode when WAL is not in use.
*/
public static String getDefaultJournalMode() {
return "delete";
}
/**
* Gets the journal size limit in bytes.
*/
public static int getJournalSizeLimit() {
return 10000;
}
/**
* Gets the default database synchronization mode when WAL is not in use.
*/
public static String getDefaultSyncMode() {
return "normal";
}
/**
* Gets the database synchronization mode when in WAL mode.
*/
public static String getWALSyncMode() {
return "normal";
}
/**
* Gets the WAL auto-checkpoint integer in database pages.
*/
public static int getWALAutoCheckpoint() {
int value = 1000;
return Math.max(1, value);
}
/**
* Gets the connection pool size when in WAL mode.
*/
public static int getWALConnectionPoolSize() {
int value = 10;
return Math.max(2, value);
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* This error can occur if the application creates a SQLiteStatement object and allows multiple
* threads in the application use it at the same time.
* Sqlite returns this error if bind and execute methods on this object occur at the same time
* from multiple threads, like so:
* thread # 1: in execute() method of the SQLiteStatement object
* while thread # 2: is in bind..() on the same object.
*</p>
* FIX this by NEVER sharing the same SQLiteStatement object between threads.
* Create a local instance of the SQLiteStatement whenever it is needed, use it and close it ASAP.
* NEVER make it globally available.
*/
public class SQLiteMisuseException extends SQLiteException {
public SQLiteMisuseException() {}
public SQLiteMisuseException(String error) {
super(error);
}
}

View File

@ -1,383 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import android.content.Context;
import org.sqlite.database.DatabaseErrorHandler;
import org.sqlite.database.DefaultDatabaseErrorHandler;
import org.sqlite.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;
/**
* A helper class to manage database creation and version management.
*
* <p>You create a subclass implementing {@link #onCreate}, {@link #onUpgrade} and
* optionally {@link #onOpen}, and this class takes care of opening the database
* if it exists, creating it if it does not, and upgrading it as necessary.
* Transactions are used to make sure the database is always in a sensible state.
*
* <p>This class makes it easy for {@link android.content.ContentProvider}
* implementations to defer opening and upgrading the database until first use,
* to avoid blocking application startup with long-running database upgrades.
*
* <p>For an example, see the NotePadProvider class in the NotePad sample application,
* in the <em>samples/</em> directory of the SDK.</p>
*
* <p class="note"><strong>Note:</strong> this class assumes
* monotonically increasing version numbers for upgrades.</p>
*/
public abstract class SQLiteOpenHelper {
private static final String TAG = SQLiteOpenHelper.class.getSimpleName();
// When true, getReadableDatabase returns a read-only database if it is just being opened.
// The database handle is reopened in read/write mode when getWritableDatabase is called.
// We leave this behavior disabled in production because it is inefficient and breaks
// many applications. For debugging purposes it can be useful to turn on strict
// read-only semantics to catch applications that call getReadableDatabase when they really
// wanted getWritableDatabase.
private static final boolean DEBUG_STRICT_READONLY = false;
private final Context mContext;
private final String mName;
private final CursorFactory mFactory;
private final int mNewVersion;
private SQLiteDatabase mDatabase;
private boolean mIsInitializing;
private boolean mEnableWriteAheadLogging;
private final DatabaseErrorHandler mErrorHandler;
/**
* Create a helper object to create, open, and/or manage a database.
* This method always returns very quickly. The database is not actually
* created or opened until one of {@link #getWritableDatabase} or
* {@link #getReadableDatabase} is called.
*
* @param context to use to open or create the database
* @param name of the database file, or null for an in-memory database
* @param factory to use for creating cursor objects, or null for the default
* @param version number of the database (starting at 1); if the database is older,
* {@link #onUpgrade} will be used to upgrade the database; if the database is
* newer, {@link #onDowngrade} will be used to downgrade the database
*/
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
this(context, name, factory, version, null);
}
/**
* Create a helper object to create, open, and/or manage a database.
* The database is not actually created or opened until one of
* {@link #getWritableDatabase} or {@link #getReadableDatabase} is called.
*
* <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
* used to handle corruption when sqlite reports database corruption.</p>
*
* @param context to use to open or create the database
* @param name of the database file, or null for an in-memory database
* @param factory to use for creating cursor objects, or null for the default
* @param version number of the database (starting at 1); if the database is older,
* {@link #onUpgrade} will be used to upgrade the database; if the database is
* newer, {@link #onDowngrade} will be used to downgrade the database
* @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
* corruption, or null to use the default error handler.
*/
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
DatabaseErrorHandler errorHandler) {
if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
mContext = context;
mName = name;
mFactory = factory;
mNewVersion = version;
mErrorHandler = errorHandler;
}
/**
* Return the name of the SQLite database being opened, as given to
* the constructor.
*/
public String getDatabaseName() {
return mName;
}
/**
* Enables or disables the use of write-ahead logging for the database.
*
* Write-ahead logging cannot be used with read-only databases so the value of
* this flag is ignored if the database is opened read-only.
*
* @param enabled True if write-ahead logging should be enabled, false if it
* should be disabled.
*
* @see SQLiteDatabase#enableWriteAheadLogging()
*/
public void setWriteAheadLoggingEnabled(boolean enabled) {
synchronized (this) {
if (mEnableWriteAheadLogging != enabled) {
if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
if (enabled) {
mDatabase.enableWriteAheadLogging();
} else {
mDatabase.disableWriteAheadLogging();
}
}
mEnableWriteAheadLogging = enabled;
}
}
}
/**
* Create and/or open a database that will be used for reading and writing.
* The first time this is called, the database will be opened and
* {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be
* called.
*
* <p>Once opened successfully, the database is cached, so you can
* call this method every time you need to write to the database.
* (Make sure to call {@link #close} when you no longer need the database.)
* Errors such as bad permissions or a full disk may cause this method
* to fail, but future attempts may succeed if the problem is fixed.</p>
*
* <p class="caution">Database upgrade may take a long time, you
* should not call this method from the application main thread, including
* from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
*
* @throws SQLiteException if the database cannot be opened for writing
* @return a read/write database object valid until {@link #close} is called
*/
public SQLiteDatabase getWritableDatabase() {
synchronized (this) {
return getDatabaseLocked(true);
}
}
/**
* Create and/or open a database. This will be the same object returned by
* {@link #getWritableDatabase} unless some problem, such as a full disk,
* requires the database to be opened read-only. In that case, a read-only
* database object will be returned. If the problem is fixed, a future call
* to {@link #getWritableDatabase} may succeed, in which case the read-only
* database object will be closed and the read/write object will be returned
* in the future.
*
* <p class="caution">Like {@link #getWritableDatabase}, this method may
* take a long time to return, so you should not call it from the
* application main thread, including from
* {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
*
* @throws SQLiteException if the database cannot be opened
* @return a database object valid until {@link #getWritableDatabase}
* or {@link #close} is called.
*/
public SQLiteDatabase getReadableDatabase() {
synchronized (this) {
return getDatabaseLocked(false);
}
}
private SQLiteDatabase getDatabaseLocked(boolean writable) {
if (mDatabase != null) {
if (!mDatabase.isOpen()) {
// Darn! The user closed the database by calling mDatabase.close().
mDatabase = null;
} else if (!writable || !mDatabase.isReadOnly()) {
// The database is already open for business.
return mDatabase;
}
}
if (mIsInitializing) {
throw new IllegalStateException("getDatabase called recursively");
}
SQLiteDatabase db = mDatabase;
try {
mIsInitializing = true;
if (db != null) {
if (writable && db.isReadOnly()) {
db.reopenReadWrite();
}
} else if (mName == null) {
db = SQLiteDatabase.create(null);
} else {
try {
if (DEBUG_STRICT_READONLY && !writable) {
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
} else {
db = SQLiteDatabase.openOrCreateDatabase(
mName, mFactory, mErrorHandler
);
}
} catch (SQLiteException ex) {
if (writable) {
throw ex;
}
Log.e(TAG, "Couldn't open " + mName
+ " for writing (will try read-only):", ex);
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
}
}
onConfigure(db);
final int version = db.getVersion();
if (version != mNewVersion) {
if (db.isReadOnly()) {
throw new SQLiteException("Can't upgrade read-only database from version " +
db.getVersion() + " to " + mNewVersion + ": " + mName);
}
db.beginTransaction();
try {
if (version == 0) {
onCreate(db);
} else {
if (version > mNewVersion) {
onDowngrade(db, version, mNewVersion);
} else {
onUpgrade(db, version, mNewVersion);
}
}
db.setVersion(mNewVersion);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
onOpen(db);
if (db.isReadOnly()) {
Log.w(TAG, "Opened " + mName + " in read-only mode");
}
mDatabase = db;
return db;
} finally {
mIsInitializing = false;
if (db != null && db != mDatabase) {
db.close();
}
}
}
/**
* Close any open database object.
*/
public synchronized void close() {
if (mIsInitializing) throw new IllegalStateException("Closed during initialization");
if (mDatabase != null && mDatabase.isOpen()) {
mDatabase.close();
mDatabase = null;
}
}
/**
* Called when the database connection is being configured, to enable features
* such as write-ahead logging or foreign key support.
* <p>
* This method is called before {@link #onCreate}, {@link #onUpgrade},
* {@link #onDowngrade}, or {@link #onOpen} are called. It should not modify
* the database except to configure the database connection as required.
* </p><p>
* This method should only call methods that configure the parameters of the
* database connection, such as {@link SQLiteDatabase#enableWriteAheadLogging}
* {@link SQLiteDatabase#setForeignKeyConstraintsEnabled},
* {@link SQLiteDatabase#setLocale}, {@link SQLiteDatabase#setMaximumSize},
* or executing PRAGMA statements.
* </p>
*
* @param db The database.
*/
public void onConfigure(SQLiteDatabase db) {}
/**
* Called when the database is created for the first time. This is where the
* creation of tables and the initial population of the tables should happen.
*
* @param db The database.
*/
public abstract void onCreate(SQLiteDatabase db);
/**
* Called when the database needs to be upgraded. The implementation
* should use this method to drop tables, add tables, or do anything else it
* needs to upgrade to the new schema version.
*
* <p>
* The SQLite ALTER TABLE documentation can be found
* <a href="http://sqlite.org/lang_altertable.html">here</a>. If you add new columns
* you can use ALTER TABLE to insert them into a live table. If you rename or remove columns
* you can use ALTER TABLE to rename the old table, then create the new table and then
* populate the new table with the contents of the old table.
* </p><p>
* This method executes within a transaction. If an exception is thrown, all changes
* will automatically be rolled back.
* </p>
*
* @param db The database.
* @param oldVersion The old database version.
* @param newVersion The new database version.
*/
public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);
/**
* Called when the database needs to be downgraded. This is strictly similar to
* {@link #onUpgrade} method, but is called whenever current version is newer than requested one.
* However, this method is not abstract, so it is not mandatory for a customer to
* implement it. If not overridden, default implementation will reject downgrade and
* throws SQLiteException
*
* <p>
* This method executes within a transaction. If an exception is thrown, all changes
* will automatically be rolled back.
* </p>
*
* @param db The database.
* @param oldVersion The old database version.
* @param newVersion The new database version.
*/
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
throw new SQLiteException("Can't downgrade database from version " +
oldVersion + " to " + newVersion);
}
/**
* Called when the database has been opened. The implementation
* should check {@link SQLiteDatabase#isReadOnly} before updating the
* database.
* <p>
* This method is called after the database connection has been configured
* and after the database schema has been created, upgraded or downgraded as necessary.
* If the database connection must be configured in some way before the schema
* is created, upgraded, or downgraded, do it in {@link #onConfigure} instead.
* </p>
*
* @param db The database.
*/
public void onOpen(SQLiteDatabase db) {}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
public class SQLiteOutOfMemoryException extends SQLiteException {
public SQLiteOutOfMemoryException() {}
public SQLiteOutOfMemoryException(String error) {
super(error);
}
}

View File

@ -1,222 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import android.database.DatabaseUtils;
import android.os.CancellationSignal;
import java.util.Arrays;
/**
* A base class for compiled SQLite programs.
* <p>
* This class is not thread-safe.
* </p>
*/
public abstract class SQLiteProgram extends SQLiteClosable {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private final SQLiteDatabase mDatabase;
private final String mSql;
private final boolean mReadOnly;
private final String[] mColumnNames;
private final int mNumParameters;
private final Object[] mBindArgs;
SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs,
CancellationSignal cancellationSignalForPrepare) {
mDatabase = db;
mSql = sql.trim();
int n = DatabaseUtils.getSqlStatementType(mSql);
switch (n) {
case DatabaseUtils.STATEMENT_BEGIN:
case DatabaseUtils.STATEMENT_COMMIT:
case DatabaseUtils.STATEMENT_ABORT:
mReadOnly = false;
mColumnNames = EMPTY_STRING_ARRAY;
mNumParameters = 0;
break;
default:
boolean assumeReadOnly = (n == DatabaseUtils.STATEMENT_SELECT);
SQLiteStatementInfo info = new SQLiteStatementInfo();
db.getThreadSession().prepare(mSql,
db.getThreadDefaultConnectionFlags(assumeReadOnly),
cancellationSignalForPrepare, info);
mReadOnly = info.readOnly;
mColumnNames = info.columnNames;
mNumParameters = info.numParameters;
break;
}
if (bindArgs != null && bindArgs.length > mNumParameters) {
throw new IllegalArgumentException("Too many bind arguments. "
+ bindArgs.length + " arguments were provided but the statement needs "
+ mNumParameters + " arguments.");
}
if (mNumParameters != 0) {
mBindArgs = new Object[mNumParameters];
if (bindArgs != null) {
System.arraycopy(bindArgs, 0, mBindArgs, 0, bindArgs.length);
}
} else {
mBindArgs = null;
}
}
final SQLiteDatabase getDatabase() {
return mDatabase;
}
final String getSql() {
return mSql;
}
final Object[] getBindArgs() {
return mBindArgs;
}
final String[] getColumnNames() {
return mColumnNames;
}
/** @hide */
protected final SQLiteSession getSession() {
return mDatabase.getThreadSession();
}
/** @hide */
protected final int getConnectionFlags() {
return mDatabase.getThreadDefaultConnectionFlags(mReadOnly);
}
/** @hide */
protected final void onCorruption() {
mDatabase.onCorruption();
}
/**
* Unimplemented.
* @deprecated This method is deprecated and must not be used.
*/
@Deprecated
public final int getUniqueId() {
return -1;
}
/**
* Bind a NULL value to this statement. The value remains bound until
* {@link #clearBindings} is called.
*
* @param index The 1-based index to the parameter to bind null to
*/
public void bindNull(int index) {
bind(index, null);
}
/**
* Bind a long value to this statement. The value remains bound until
* {@link #clearBindings} is called.
*addToBindArgs
* @param index The 1-based index to the parameter to bind
* @param value The value to bind
*/
public void bindLong(int index, long value) {
bind(index, value);
}
/**
* Bind a double value to this statement. The value remains bound until
* {@link #clearBindings} is called.
*
* @param index The 1-based index to the parameter to bind
* @param value The value to bind
*/
public void bindDouble(int index, double value) {
bind(index, value);
}
/**
* Bind a String value to this statement. The value remains bound until
* {@link #clearBindings} is called.
*
* @param index The 1-based index to the parameter to bind
* @param value The value to bind, must not be null
*/
public void bindString(int index, String value) {
if (value == null) {
throw new IllegalArgumentException("the bind value at index " + index + " is null");
}
bind(index, value);
}
/**
* Bind a byte array value to this statement. The value remains bound until
* {@link #clearBindings} is called.
*
* @param index The 1-based index to the parameter to bind
* @param value The value to bind, must not be null
*/
public void bindBlob(int index, byte[] value) {
if (value == null) {
throw new IllegalArgumentException("the bind value at index " + index + " is null");
}
bind(index, value);
}
/**
* Clears all existing bindings. Unset bindings are treated as NULL.
*/
public void clearBindings() {
if (mBindArgs != null) {
Arrays.fill(mBindArgs, null);
}
}
/**
* Given an array of String bindArgs, this method binds all of them in one single call.
*
* @param bindArgs the String array of bind args, none of which must be null.
*/
public void bindAllArgsAsStrings(String[] bindArgs) {
if (bindArgs != null) {
for (int i = bindArgs.length; i != 0; i--) {
bindString(i, bindArgs[i - 1]);
}
}
}
@Override
protected void onAllReferencesReleased() {
clearBindings();
}
private void bind(int index, Object value) {
if (index < 1 || index > mNumParameters) {
throw new IllegalArgumentException("Cannot bind argument at index "
+ index + " because the index is out of range. "
+ "The statement has " + mNumParameters + " parameters.");
}
mBindArgs[index - 1] = value;
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import android.database.CursorWindow;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.util.Log;
/**
* Represents a query that reads the resulting rows into a {@link SQLiteQuery}.
* This class is used by {@link SQLiteCursor} and isn't useful itself.
* <p>
* This class is not thread-safe.
* </p>
*/
public final class SQLiteQuery extends SQLiteProgram {
private static final String TAG = "SQLiteQuery";
private final CancellationSignal mCancellationSignal;
SQLiteQuery(SQLiteDatabase db, String query, CancellationSignal cancellationSignal) {
super(db, query, null, cancellationSignal);
mCancellationSignal = cancellationSignal;
}
/**
* Reads rows into a buffer.
*
* @param window The window to fill into
* @param startPos The start position for filling the window.
* @param requiredPos The position of a row that MUST be in the window.
* If it won't fit, then the query should discard part of what it filled.
* @param countAllRows True to count all rows that the query would
* return regardless of whether they fit in the window.
* @return Number of rows that were enumerated. Might not be all rows
* unless countAllRows is true.
*
* @throws SQLiteException if an error occurs.
* @throws OperationCanceledException if the operation was canceled.
*/
int fillWindow(CursorWindow window, int startPos, int requiredPos, boolean countAllRows) {
acquireReference();
try {
window.acquireReference();
try {
int numRows = getSession().executeForCursorWindow(getSql(), getBindArgs(),
window, startPos, requiredPos, countAllRows, getConnectionFlags(),
mCancellationSignal);
return numRows;
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
} catch (SQLiteException ex) {
Log.e(TAG, "exception: " + ex.getMessage() + "; query: " + getSql());
throw ex;
} finally {
window.releaseReference();
}
} finally {
releaseReference();
}
}
@Override
public String toString() {
return "SQLiteQuery: " + getSql();
}
}

View File

@ -1,663 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Pattern;
/**
* This is a convience class that helps build SQL queries to be sent to
* {@link SQLiteDatabase} objects.
*/
public class SQLiteQueryBuilder
{
private static final String TAG = "SQLiteQueryBuilder";
private static final Pattern sLimitPattern =
Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
private Map<String, String> mProjectionMap = null;
private String mTables = "";
private StringBuilder mWhereClause = null; // lazily created
private boolean mDistinct;
private SQLiteDatabase.CursorFactory mFactory;
private boolean mStrict;
public SQLiteQueryBuilder() {
mDistinct = false;
mFactory = null;
}
/**
* Mark the query as DISTINCT.
*
* @param distinct if true the query is DISTINCT, otherwise it isn't
*/
public void setDistinct(boolean distinct) {
mDistinct = distinct;
}
/**
* Returns the list of tables being queried
*
* @return the list of tables being queried
*/
public String getTables() {
return mTables;
}
/**
* Sets the list of tables to query. Multiple tables can be specified to perform a join.
* For example:
* setTables("foo, bar")
* setTables("foo LEFT OUTER JOIN bar ON (foo.id = bar.foo_id)")
*
* @param inTables the list of tables to query on
*/
public void setTables(String inTables) {
mTables = inTables;
}
/**
* Append a chunk to the WHERE clause of the query. All chunks appended are surrounded
* by parenthesis and ANDed with the selection passed to {@link #query}. The final
* WHERE clause looks like:
*
* WHERE (&lt;append chunk 1>&lt;append chunk2>) AND (&lt;query() selection parameter>)
*
* @param inWhere the chunk of text to append to the WHERE clause.
*/
public void appendWhere(CharSequence inWhere) {
if (mWhereClause == null) {
mWhereClause = new StringBuilder(inWhere.length() + 16);
}
if (mWhereClause.length() == 0) {
mWhereClause.append('(');
}
mWhereClause.append(inWhere);
}
/**
* Append a chunk to the WHERE clause of the query. All chunks appended are surrounded
* by parenthesis and ANDed with the selection passed to {@link #query}. The final
* WHERE clause looks like:
*
* WHERE (&lt;append chunk 1>&lt;append chunk2>) AND (&lt;query() selection parameter>)
*
* @param inWhere the chunk of text to append to the WHERE clause. it will be escaped
* to avoid SQL injection attacks
*/
public void appendWhereEscapeString(String inWhere) {
if (mWhereClause == null) {
mWhereClause = new StringBuilder(inWhere.length() + 16);
}
if (mWhereClause.length() == 0) {
mWhereClause.append('(');
}
DatabaseUtils.appendEscapedSQLString(mWhereClause, inWhere);
}
/**
* Sets the projection map for the query. The projection map maps
* from column names that the caller passes into query to database
* column names. This is useful for renaming columns as well as
* disambiguating column names when doing joins. For example you
* could map "name" to "people.name". If a projection map is set
* it must contain all column names the user may request, even if
* the key and value are the same.
*
* @param columnMap maps from the user column names to the database column names
*/
public void setProjectionMap(Map<String, String> columnMap) {
mProjectionMap = columnMap;
}
/**
* Sets the cursor factory to be used for the query. You can use
* one factory for all queries on a database but it is normally
* easier to specify the factory when doing this query.
*
* @param factory the factory to use.
*/
public void setCursorFactory(SQLiteDatabase.CursorFactory factory) {
mFactory = factory;
}
/**
* When set, the selection is verified against malicious arguments.
* When using this class to create a statement using
* {@link #buildQueryString(boolean, String, String[], String, String, String, String, String)},
* non-numeric limits will raise an exception. If a projection map is specified, fields
* not in that map will be ignored.
* If this class is used to execute the statement directly using
* {@link #query(SQLiteDatabase, String[], String, String[], String, String, String)}
* or
* {@link #query(SQLiteDatabase, String[], String, String[], String, String, String, String)},
* additionally also parenthesis escaping selection are caught.
*
* To summarize: To get maximum protection against malicious third party apps (for example
* content provider consumers), make sure to do the following:
* <ul>
* <li>Set this value to true</li>
* <li>Use a projection map</li>
* <li>Use one of the query overloads instead of getting the statement as a sql string</li>
* </ul>
* By default, this value is false.
*/
public void setStrict(boolean flag) {
mStrict = flag;
}
/**
* Build an SQL query string from the given clauses.
*
* @param distinct true if you want each row to be unique, false otherwise.
* @param tables The table names to compile the query against.
* @param columns A list of which columns to return. Passing null will
* return all columns, which is discouraged to prevent reading
* data from storage that isn't going to be used.
* @param where A filter declaring which rows to return, formatted as an SQL
* WHERE clause (excluding the WHERE itself). Passing null will
* return all rows for the given URL.
* @param groupBy A filter declaring how to group rows, formatted as an SQL
* GROUP BY clause (excluding the GROUP BY itself). Passing null
* will cause the rows to not be grouped.
* @param having A filter declare which row groups to include in the cursor,
* if row grouping is being used, formatted as an SQL HAVING
* clause (excluding the HAVING itself). Passing null will cause
* all row groups to be included, and is required when row
* grouping is not being used.
* @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
* (excluding the ORDER BY itself). Passing null will use the
* default sort order, which may be unordered.
* @param limit Limits the number of rows returned by the query,
* formatted as LIMIT clause. Passing null denotes no LIMIT clause.
* @return the SQL query string
*/
public static String buildQueryString(
boolean distinct, String tables, String[] columns, String where,
String groupBy, String having, String orderBy, String limit) {
if (TextUtils.isEmpty(groupBy) && !TextUtils.isEmpty(having)) {
throw new IllegalArgumentException(
"HAVING clauses are only permitted when using a groupBy clause");
}
if (!TextUtils.isEmpty(limit) && !sLimitPattern.matcher(limit).matches()) {
throw new IllegalArgumentException("invalid LIMIT clauses:" + limit);
}
StringBuilder query = new StringBuilder(120);
query.append("SELECT ");
if (distinct) {
query.append("DISTINCT ");
}
if (columns != null && columns.length != 0) {
appendColumns(query, columns);
} else {
query.append("* ");
}
query.append("FROM ");
query.append(tables);
appendClause(query, " WHERE ", where);
appendClause(query, " GROUP BY ", groupBy);
appendClause(query, " HAVING ", having);
appendClause(query, " ORDER BY ", orderBy);
appendClause(query, " LIMIT ", limit);
return query.toString();
}
private static void appendClause(StringBuilder s, String name, String clause) {
if (!TextUtils.isEmpty(clause)) {
s.append(name);
s.append(clause);
}
}
/**
* Add the names that are non-null in columns to s, separating
* them with commas.
*/
public static void appendColumns(StringBuilder s, String[] columns) {
int n = columns.length;
for (int i = 0; i < n; i++) {
String column = columns[i];
if (column != null) {
if (i > 0) {
s.append(", ");
}
s.append(column);
}
}
s.append(' ');
}
/**
* Perform a query by combining all current settings and the
* information passed into this method.
*
* @param db the database to query on
* @param projectionIn A list of which columns to return. Passing
* null will return all columns, which is discouraged to prevent
* reading data from storage that isn't going to be used.
* @param selection A filter declaring which rows to return,
* formatted as an SQL WHERE clause (excluding the WHERE
* itself). Passing null will return all rows for the given URL.
* @param selectionArgs You may include ?s in selection, which
* will be replaced by the values from selectionArgs, in order
* that they appear in the selection. The values will be bound
* as Strings.
* @param groupBy A filter declaring how to group rows, formatted
* as an SQL GROUP BY clause (excluding the GROUP BY
* itself). Passing null will cause the rows to not be grouped.
* @param having A filter declare which row groups to include in
* the cursor, if row grouping is being used, formatted as an
* SQL HAVING clause (excluding the HAVING itself). Passing
* null will cause all row groups to be included, and is
* required when row grouping is not being used.
* @param sortOrder How to order the rows, formatted as an SQL
* ORDER BY clause (excluding the ORDER BY itself). Passing null
* will use the default sort order, which may be unordered.
* @return a cursor over the result set
* @see android.content.ContentResolver#query(android.net.Uri, String[],
* String, String[], String)
*/
public Cursor query(SQLiteDatabase db, String[] projectionIn,
String selection, String[] selectionArgs, String groupBy,
String having, String sortOrder) {
return query(db, projectionIn, selection, selectionArgs, groupBy, having, sortOrder,
null /* limit */, null /* cancellationSignal */);
}
/**
* Perform a query by combining all current settings and the
* information passed into this method.
*
* @param db the database to query on
* @param projectionIn A list of which columns to return. Passing
* null will return all columns, which is discouraged to prevent
* reading data from storage that isn't going to be used.
* @param selection A filter declaring which rows to return,
* formatted as an SQL WHERE clause (excluding the WHERE
* itself). Passing null will return all rows for the given URL.
* @param selectionArgs You may include ?s in selection, which
* will be replaced by the values from selectionArgs, in order
* that they appear in the selection. The values will be bound
* as Strings.
* @param groupBy A filter declaring how to group rows, formatted
* as an SQL GROUP BY clause (excluding the GROUP BY
* itself). Passing null will cause the rows to not be grouped.
* @param having A filter declare which row groups to include in
* the cursor, if row grouping is being used, formatted as an
* SQL HAVING clause (excluding the HAVING itself). Passing
* null will cause all row groups to be included, and is
* required when row grouping is not being used.
* @param sortOrder How to order the rows, formatted as an SQL
* ORDER BY clause (excluding the ORDER BY itself). Passing null
* will use the default sort order, which may be unordered.
* @param limit Limits the number of rows returned by the query,
* formatted as LIMIT clause. Passing null denotes no LIMIT clause.
* @return a cursor over the result set
* @see android.content.ContentResolver#query(android.net.Uri, String[],
* String, String[], String)
*/
public Cursor query(SQLiteDatabase db, String[] projectionIn,
String selection, String[] selectionArgs, String groupBy,
String having, String sortOrder, String limit) {
return query(db, projectionIn, selection, selectionArgs,
groupBy, having, sortOrder, limit, null);
}
/**
* Perform a query by combining all current settings and the
* information passed into this method.
*
* @param db the database to query on
* @param projectionIn A list of which columns to return. Passing
* null will return all columns, which is discouraged to prevent
* reading data from storage that isn't going to be used.
* @param selection A filter declaring which rows to return,
* formatted as an SQL WHERE clause (excluding the WHERE
* itself). Passing null will return all rows for the given URL.
* @param selectionArgs You may include ?s in selection, which
* will be replaced by the values from selectionArgs, in order
* that they appear in the selection. The values will be bound
* as Strings.
* @param groupBy A filter declaring how to group rows, formatted
* as an SQL GROUP BY clause (excluding the GROUP BY
* itself). Passing null will cause the rows to not be grouped.
* @param having A filter declare which row groups to include in
* the cursor, if row grouping is being used, formatted as an
* SQL HAVING clause (excluding the HAVING itself). Passing
* null will cause all row groups to be included, and is
* required when row grouping is not being used.
* @param sortOrder How to order the rows, formatted as an SQL
* ORDER BY clause (excluding the ORDER BY itself). Passing null
* will use the default sort order, which may be unordered.
* @param limit Limits the number of rows returned by the query,
* formatted as LIMIT clause. Passing null denotes no LIMIT clause.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
* @return a cursor over the result set
* @see android.content.ContentResolver#query(android.net.Uri, String[],
* String, String[], String)
*/
public Cursor query(SQLiteDatabase db, String[] projectionIn,
String selection, String[] selectionArgs, String groupBy,
String having, String sortOrder, String limit, CancellationSignal cancellationSignal) {
if (mTables == null) {
return null;
}
if (mStrict && selection != null && selection.length() > 0) {
// Validate the user-supplied selection to detect syntactic anomalies
// in the selection string that could indicate a SQL injection attempt.
// The idea is to ensure that the selection clause is a valid SQL expression
// by compiling it twice: once wrapped in parentheses and once as
// originally specified. An attacker cannot create an expression that
// would escape the SQL expression while maintaining balanced parentheses
// in both the wrapped and original forms.
String sqlForValidation = buildQuery(projectionIn, "(" + selection + ")", groupBy,
having, sortOrder, limit);
validateQuerySql(db, sqlForValidation,
cancellationSignal); // will throw if query is invalid
}
String sql = buildQuery(
projectionIn, selection, groupBy, having,
sortOrder, limit);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Performing query: " + sql);
}
return db.rawQueryWithFactory(
mFactory, sql, selectionArgs,
SQLiteDatabase.findEditTable(mTables),
cancellationSignal); // will throw if query is invalid
}
/**
* Verifies that a SQL SELECT statement is valid by compiling it.
* If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
*/
private void validateQuerySql(SQLiteDatabase db, String sql,
CancellationSignal cancellationSignal) {
db.getThreadSession().prepare(sql,
db.getThreadDefaultConnectionFlags(true /*readOnly*/), cancellationSignal, null);
}
/**
* Construct a SELECT statement suitable for use in a group of
* SELECT statements that will be joined through UNION operators
* in buildUnionQuery.
*
* @param projectionIn A list of which columns to return. Passing
* null will return all columns, which is discouraged to
* prevent reading data from storage that isn't going to be
* used.
* @param selection A filter declaring which rows to return,
* formatted as an SQL WHERE clause (excluding the WHERE
* itself). Passing null will return all rows for the given
* URL.
* @param groupBy A filter declaring how to group rows, formatted
* as an SQL GROUP BY clause (excluding the GROUP BY itself).
* Passing null will cause the rows to not be grouped.
* @param having A filter declare which row groups to include in
* the cursor, if row grouping is being used, formatted as an
* SQL HAVING clause (excluding the HAVING itself). Passing
* null will cause all row groups to be included, and is
* required when row grouping is not being used.
* @param sortOrder How to order the rows, formatted as an SQL
* ORDER BY clause (excluding the ORDER BY itself). Passing null
* will use the default sort order, which may be unordered.
* @param limit Limits the number of rows returned by the query,
* formatted as LIMIT clause. Passing null denotes no LIMIT clause.
* @return the resulting SQL SELECT statement
*/
public String buildQuery(
String[] projectionIn, String selection, String groupBy,
String having, String sortOrder, String limit) {
String[] projection = computeProjection(projectionIn);
StringBuilder where = new StringBuilder();
boolean hasBaseWhereClause = mWhereClause != null && mWhereClause.length() > 0;
if (hasBaseWhereClause) {
where.append(mWhereClause.toString());
where.append(')');
}
// Tack on the user's selection, if present.
if (selection != null && selection.length() > 0) {
if (hasBaseWhereClause) {
where.append(" AND ");
}
where.append('(');
where.append(selection);
where.append(')');
}
return buildQueryString(
mDistinct, mTables, projection, where.toString(),
groupBy, having, sortOrder, limit);
}
/**
* @deprecated This method's signature is misleading since no SQL parameter
* substitution is carried out. The selection arguments parameter does not get
* used at all. To avoid confusion, call
* {@link #buildQuery(String[], String, String, String, String, String)} instead.
*/
@Deprecated
public String buildQuery(
String[] projectionIn, String selection, String[] selectionArgs,
String groupBy, String having, String sortOrder, String limit) {
return buildQuery(projectionIn, selection, groupBy, having, sortOrder, limit);
}
/**
* Construct a SELECT statement suitable for use in a group of
* SELECT statements that will be joined through UNION operators
* in buildUnionQuery.
*
* @param typeDiscriminatorColumn the name of the result column
* whose cells will contain the name of the table from which
* each row was drawn.
* @param unionColumns the names of the columns to appear in the
* result. This may include columns that do not appear in the
* table this SELECT is querying (i.e. mTables), but that do
* appear in one of the other tables in the UNION query that we
* are constructing.
* @param columnsPresentInTable a Set of the names of the columns
* that appear in this table (i.e. in the table whose name is
* mTables). Since columns in unionColumns include columns that
* appear only in other tables, we use this array to distinguish
* which ones actually are present. Other columns will have
* NULL values for results from this subquery.
* @param computedColumnsOffset all columns in unionColumns before
* this index are included under the assumption that they're
* computed and therefore won't appear in columnsPresentInTable,
* e.g. "date * 1000 as normalized_date"
* @param typeDiscriminatorValue the value used for the
* type-discriminator column in this subquery
* @param selection A filter declaring which rows to return,
* formatted as an SQL WHERE clause (excluding the WHERE
* itself). Passing null will return all rows for the given
* URL.
* @param groupBy A filter declaring how to group rows, formatted
* as an SQL GROUP BY clause (excluding the GROUP BY itself).
* Passing null will cause the rows to not be grouped.
* @param having A filter declare which row groups to include in
* the cursor, if row grouping is being used, formatted as an
* SQL HAVING clause (excluding the HAVING itself). Passing
* null will cause all row groups to be included, and is
* required when row grouping is not being used.
* @return the resulting SQL SELECT statement
*/
public String buildUnionSubQuery(
String typeDiscriminatorColumn,
String[] unionColumns,
Set<String> columnsPresentInTable,
int computedColumnsOffset,
String typeDiscriminatorValue,
String selection,
String groupBy,
String having) {
int unionColumnsCount = unionColumns.length;
String[] projectionIn = new String[unionColumnsCount];
for (int i = 0; i < unionColumnsCount; i++) {
String unionColumn = unionColumns[i];
if (unionColumn.equals(typeDiscriminatorColumn)) {
projectionIn[i] = "'" + typeDiscriminatorValue + "' AS "
+ typeDiscriminatorColumn;
} else if (i <= computedColumnsOffset
|| columnsPresentInTable.contains(unionColumn)) {
projectionIn[i] = unionColumn;
} else {
projectionIn[i] = "NULL AS " + unionColumn;
}
}
return buildQuery(
projectionIn, selection, groupBy, having,
null /* sortOrder */,
null /* limit */);
}
/**
* @deprecated This method's signature is misleading since no SQL parameter
* substitution is carried out. The selection arguments parameter does not get
* used at all. To avoid confusion, call
* {@link #buildUnionSubQuery}
* instead.
*/
@Deprecated
public String buildUnionSubQuery(
String typeDiscriminatorColumn,
String[] unionColumns,
Set<String> columnsPresentInTable,
int computedColumnsOffset,
String typeDiscriminatorValue,
String selection,
String[] selectionArgs,
String groupBy,
String having) {
return buildUnionSubQuery(
typeDiscriminatorColumn, unionColumns, columnsPresentInTable,
computedColumnsOffset, typeDiscriminatorValue, selection,
groupBy, having);
}
/**
* Given a set of subqueries, all of which are SELECT statements,
* construct a query that returns the union of what those
* subqueries return.
* @param subQueries an array of SQL SELECT statements, all of
* which must have the same columns as the same positions in
* their results
* @param sortOrder How to order the rows, formatted as an SQL
* ORDER BY clause (excluding the ORDER BY itself). Passing
* null will use the default sort order, which may be unordered.
* @param limit The limit clause, which applies to the entire union result set
*
* @return the resulting SQL SELECT statement
*/
public String buildUnionQuery(String[] subQueries, String sortOrder, String limit) {
StringBuilder query = new StringBuilder(128);
int subQueryCount = subQueries.length;
String unionOperator = mDistinct ? " UNION " : " UNION ALL ";
for (int i = 0; i < subQueryCount; i++) {
if (i > 0) {
query.append(unionOperator);
}
query.append(subQueries[i]);
}
appendClause(query, " ORDER BY ", sortOrder);
appendClause(query, " LIMIT ", limit);
return query.toString();
}
private String[] computeProjection(String[] projectionIn) {
if (projectionIn != null && projectionIn.length > 0) {
if (mProjectionMap != null) {
String[] projection = new String[projectionIn.length];
int length = projectionIn.length;
for (int i = 0; i < length; i++) {
String userColumn = projectionIn[i];
String column = mProjectionMap.get(userColumn);
if (column != null) {
projection[i] = column;
continue;
}
if (!mStrict &&
( userColumn.contains(" AS ") || userColumn.contains(" as "))) {
/* A column alias already exist */
projection[i] = userColumn;
continue;
}
throw new IllegalArgumentException("Invalid column "
+ projectionIn[i]);
}
return projection;
} else {
return projectionIn;
}
} else if (mProjectionMap != null) {
// Return all columns in projection map.
Set<Entry<String, String>> entrySet = mProjectionMap.entrySet();
String[] projection = new String[entrySet.size()];
Iterator<Entry<String, String>> entryIter = entrySet.iterator();
int i = 0;
while (entryIter.hasNext()) {
Entry<String, String> entry = entryIter.next();
// Don't include the _count column when people ask for no projection.
if (entry.getKey().equals(BaseColumns._COUNT)) {
continue;
}
projection[i++] = entry.getValue();
}
return projection;
}
return null;
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
public class SQLiteReadOnlyDatabaseException extends SQLiteException {
public SQLiteReadOnlyDatabaseException() {}
public SQLiteReadOnlyDatabaseException(String error) {
super(error);
}
}

View File

@ -1,967 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import android.database.CursorWindow;
import android.database.DatabaseUtils;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
/**
* Provides a single client the ability to use a database.
*
* <h2>About database sessions</h2>
* <p>
* Database access is always performed using a session. The session
* manages the lifecycle of transactions and database connections.
* </p><p>
* Sessions can be used to perform both read-only and read-write operations.
* There is some advantage to knowing when a session is being used for
* read-only purposes because the connection pool can optimize the use
* of the available connections to permit multiple read-only operations
* to execute in parallel whereas read-write operations may need to be serialized.
* </p><p>
* When <em>Write Ahead Logging (WAL)</em> is enabled, the database can
* execute simultaneous read-only and read-write transactions, provided that
* at most one read-write transaction is performed at a time. When WAL is not
* enabled, read-only transactions can execute in parallel but read-write
* transactions are mutually exclusive.
* </p>
*
* <h2>Ownership and concurrency guarantees</h2>
* <p>
* Session objects are not thread-safe. In fact, session objects are thread-bound.
* The {@link SQLiteDatabase} uses a thread-local variable to associate a session
* with each thread for the use of that thread alone. Consequently, each thread
* has its own session object and therefore its own transaction state independent
* of other threads.
* </p><p>
* A thread has at most one session per database. This constraint ensures that
* a thread can never use more than one database connection at a time for a
* given database. As the number of available database connections is limited,
* if a single thread tried to acquire multiple connections for the same database
* at the same time, it might deadlock. Therefore we allow there to be only
* one session (so, at most one connection) per thread per database.
* </p>
*
* <h2>Transactions</h2>
* <p>
* There are two kinds of transaction: implicit transactions and explicit
* transactions.
* </p><p>
* An implicit transaction is created whenever a database operation is requested
* and there is no explicit transaction currently in progress. An implicit transaction
* only lasts for the duration of the database operation in question and then it
* is ended. If the database operation was successful, then its changes are committed.
* </p><p>
* An explicit transaction is started by calling {@link #beginTransaction} and
* specifying the desired transaction mode. Once an explicit transaction has begun,
* all subsequent database operations will be performed as part of that transaction.
* To end an explicit transaction, first call {@link #setTransactionSuccessful} if the
* transaction was successful, then call {@link #end}. If the transaction was
* marked successful, its changes will be committed, otherwise they will be rolled back.
* </p><p>
* Explicit transactions can also be nested. A nested explicit transaction is
* started with {@link #beginTransaction}, marked successful with
* {@link #setTransactionSuccessful}and ended with {@link #endTransaction}.
* If any nested transaction is not marked successful, then the entire transaction
* including all of its nested transactions will be rolled back
* when the outermost transaction is ended.
* </p><p>
* To improve concurrency, an explicit transaction can be yielded by calling
* {@link #yieldTransaction}. If there is contention for use of the database,
* then yielding ends the current transaction, commits its changes, releases the
* database connection for use by another session for a little while, and starts a
* new transaction with the same properties as the original one.
* Changes committed by {@link #yieldTransaction} cannot be rolled back.
* </p><p>
* When a transaction is started, the client can provide a {@link SQLiteTransactionListener}
* to listen for notifications of transaction-related events.
* </p><p>
* Recommended usage:
* <code><pre>
* // First, begin the transaction.
* session.beginTransaction(SQLiteSession.TRANSACTION_MODE_DEFERRED, 0);
* try {
* // Then do stuff...
* session.execute("INSERT INTO ...", null, 0);
*
* // As the very last step before ending the transaction, mark it successful.
* session.setTransactionSuccessful();
* } finally {
* // Finally, end the transaction.
* // This statement will commit the transaction if it was marked successful or
* // roll it back otherwise.
* session.endTransaction();
* }
* </pre></code>
* </p>
*
* <h2>Database connections</h2>
* <p>
* A {@link SQLiteDatabase} can have multiple active sessions at the same
* time. Each session acquires and releases connections to the database
* as needed to perform each requested database transaction. If all connections
* are in use, then database transactions on some sessions will block until a
* connection becomes available.
* </p><p>
* The session acquires a single database connection only for the duration
* of a single (implicit or explicit) database transaction, then releases it.
* This characteristic allows a small pool of database connections to be shared
* efficiently by multiple sessions as long as they are not all trying to perform
* database transactions at the same time.
* </p>
*
* <h2>Responsiveness</h2>
* <p>
* Because there are a limited number of database connections and the session holds
* a database connection for the entire duration of a database transaction,
* it is important to keep transactions short. This is especially important
* for read-write transactions since they may block other transactions
* from executing. Consider calling {@link #yieldTransaction} periodically
* during long-running transactions.
* </p><p>
* Another important consideration is that transactions that take too long to
* run may cause the application UI to become unresponsive. Even if the transaction
* is executed in a background thread, the user will get bored and
* frustrated if the application shows no data for several seconds while
* a transaction runs.
* </p><p>
* Guidelines:
* <ul>
* <li>Do not perform database transactions on the UI thread.</li>
* <li>Keep database transactions as short as possible.</li>
* <li>Simple queries often run faster than complex queries.</li>
* <li>Measure the performance of your database transactions.</li>
* <li>Consider what will happen when the size of the data set grows.
* A query that works well on 100 rows may struggle with 10,000.</li>
* </ul>
*
* <h2>Reentrance</h2>
* <p>
* This class must tolerate reentrant execution of SQLite operations because
* triggers may call custom SQLite functions that perform additional queries.
* </p>
*
* @hide
*/
public final class SQLiteSession {
private final SQLiteConnectionPool mConnectionPool;
private SQLiteConnection mConnection;
private int mConnectionFlags;
private int mConnectionUseCount;
private Transaction mTransactionPool;
private Transaction mTransactionStack;
/**
* Transaction mode: Deferred.
* <p>
* In a deferred transaction, no locks are acquired on the database
* until the first operation is performed. If the first operation is
* read-only, then a <code>SHARED</code> lock is acquired, otherwise
* a <code>RESERVED</code> lock is acquired.
* </p><p>
* While holding a <code>SHARED</code> lock, this session is only allowed to
* read but other sessions are allowed to read or write.
* While holding a <code>RESERVED</code> lock, this session is allowed to read
* or write but other sessions are only allowed to read.
* </p><p>
* Because the lock is only acquired when needed in a deferred transaction,
* it is possible for another session to write to the database first before
* this session has a chance to do anything.
* </p><p>
* Corresponds to the SQLite <code>BEGIN DEFERRED</code> transaction mode.
* </p>
*/
public static final int TRANSACTION_MODE_DEFERRED = 0;
/**
* Transaction mode: Immediate.
* <p>
* When an immediate transaction begins, the session acquires a
* <code>RESERVED</code> lock.
* </p><p>
* While holding a <code>RESERVED</code> lock, this session is allowed to read
* or write but other sessions are only allowed to read.
* </p><p>
* Corresponds to the SQLite <code>BEGIN IMMEDIATE</code> transaction mode.
* </p>
*/
public static final int TRANSACTION_MODE_IMMEDIATE = 1;
/**
* Transaction mode: Exclusive.
* <p>
* When an exclusive transaction begins, the session acquires an
* <code>EXCLUSIVE</code> lock.
* </p><p>
* While holding an <code>EXCLUSIVE</code> lock, this session is allowed to read
* or write but no other sessions are allowed to access the database.
* </p><p>
* Corresponds to the SQLite <code>BEGIN EXCLUSIVE</code> transaction mode.
* </p>
*/
public static final int TRANSACTION_MODE_EXCLUSIVE = 2;
/**
* Creates a session bound to the specified connection pool.
*
* @param connectionPool The connection pool.
*/
public SQLiteSession(SQLiteConnectionPool connectionPool) {
if (connectionPool == null) {
throw new IllegalArgumentException("connectionPool must not be null");
}
mConnectionPool = connectionPool;
}
/**
* Returns true if the session has a transaction in progress.
*
* @return True if the session has a transaction in progress.
*/
public boolean hasTransaction() {
return mTransactionStack != null;
}
/**
* Returns true if the session has a nested transaction in progress.
*
* @return True if the session has a nested transaction in progress.
*/
public boolean hasNestedTransaction() {
return mTransactionStack != null && mTransactionStack.mParent != null;
}
/**
* Returns true if the session has an active database connection.
*
* @return True if the session has an active database connection.
*/
public boolean hasConnection() {
return mConnection != null;
}
/**
* Begins a transaction.
* <p>
* Transactions may nest. If the transaction is not in progress,
* then a database connection is obtained and a new transaction is started.
* Otherwise, a nested transaction is started.
* </p><p>
* Each call to {@link #beginTransaction} must be matched exactly by a call
* to {@link #endTransaction}. To mark a transaction as successful,
* call {@link #setTransactionSuccessful} before calling {@link #endTransaction}.
* If the transaction is not successful, or if any of its nested
* transactions were not successful, then the entire transaction will
* be rolled back when the outermost transaction is ended.
* </p>
*
* @param transactionMode The transaction mode. One of: {@link #TRANSACTION_MODE_DEFERRED},
* {@link #TRANSACTION_MODE_IMMEDIATE}, or {@link #TRANSACTION_MODE_EXCLUSIVE}.
* Ignored when creating a nested transaction.
* @param transactionListener The transaction listener, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
*
* @throws IllegalStateException if {@link #setTransactionSuccessful} has already been
* called for the current transaction.
* @throws SQLiteException if an error occurs.
* @throws OperationCanceledException if the operation was canceled.
*
* @see #setTransactionSuccessful
* @see #yieldTransaction
* @see #endTransaction
*/
public void beginTransaction(int transactionMode,
SQLiteTransactionListener transactionListener, int connectionFlags,
CancellationSignal cancellationSignal) {
throwIfTransactionMarkedSuccessful();
beginTransactionUnchecked(transactionMode, transactionListener, connectionFlags,
cancellationSignal);
}
private void beginTransactionUnchecked(int transactionMode,
SQLiteTransactionListener transactionListener, int connectionFlags,
CancellationSignal cancellationSignal) {
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
}
if (mTransactionStack == null) {
acquireConnection(null, connectionFlags, cancellationSignal); // might throw
}
try {
// Set up the transaction such that we can back out safely
// in case we fail part way.
if (mTransactionStack == null) {
// Execute SQL might throw a runtime exception.
switch (transactionMode) {
case TRANSACTION_MODE_IMMEDIATE:
mConnection.execute("BEGIN IMMEDIATE;", null,
cancellationSignal); // might throw
break;
case TRANSACTION_MODE_EXCLUSIVE:
mConnection.execute("BEGIN EXCLUSIVE;", null,
cancellationSignal); // might throw
break;
default:
mConnection.execute("BEGIN;", null, cancellationSignal); // might throw
break;
}
}
// Listener might throw a runtime exception.
if (transactionListener != null) {
try {
transactionListener.onBegin(); // might throw
} catch (RuntimeException ex) {
if (mTransactionStack == null) {
mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
}
throw ex;
}
}
// Bookkeeping can't throw, except an OOM, which is just too bad...
Transaction transaction = obtainTransaction(transactionMode, transactionListener);
transaction.mParent = mTransactionStack;
mTransactionStack = transaction;
} finally {
if (mTransactionStack == null) {
releaseConnection(); // might throw
}
}
}
/**
* Marks the current transaction as having completed successfully.
* <p>
* This method can be called at most once between {@link #beginTransaction} and
* {@link #endTransaction} to indicate that the changes made by the transaction should be
* committed. If this method is not called, the changes will be rolled back
* when the transaction is ended.
* </p>
*
* @throws IllegalStateException if there is no current transaction, or if
* {@link #setTransactionSuccessful} has already been called for the current transaction.
*
* @see #beginTransaction
* @see #endTransaction
*/
public void setTransactionSuccessful() {
throwIfNoTransaction();
throwIfTransactionMarkedSuccessful();
mTransactionStack.mMarkedSuccessful = true;
}
/**
* Ends the current transaction and commits or rolls back changes.
* <p>
* If this is the outermost transaction (not nested within any other
* transaction), then the changes are committed if {@link #setTransactionSuccessful}
* was called or rolled back otherwise.
* </p><p>
* This method must be called exactly once for each call to {@link #beginTransaction}.
* </p>
*
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
*
* @throws IllegalStateException if there is no current transaction.
* @throws SQLiteException if an error occurs.
* @throws OperationCanceledException if the operation was canceled.
*
* @see #beginTransaction
* @see #setTransactionSuccessful
* @see #yieldTransaction
*/
public void endTransaction(CancellationSignal cancellationSignal) {
throwIfNoTransaction();
assert mConnection != null;
endTransactionUnchecked(cancellationSignal, false);
}
private void endTransactionUnchecked(CancellationSignal cancellationSignal, boolean yielding) {
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
}
final Transaction top = mTransactionStack;
boolean successful = (top.mMarkedSuccessful || yielding) && !top.mChildFailed;
RuntimeException listenerException = null;
final SQLiteTransactionListener listener = top.mListener;
if (listener != null) {
try {
if (successful) {
listener.onCommit(); // might throw
} else {
listener.onRollback(); // might throw
}
} catch (RuntimeException ex) {
listenerException = ex;
successful = false;
}
}
mTransactionStack = top.mParent;
recycleTransaction(top);
if (mTransactionStack != null) {
if (!successful) {
mTransactionStack.mChildFailed = true;
}
} else {
try {
if (successful) {
mConnection.execute("COMMIT;", null, cancellationSignal); // might throw
} else {
mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
}
} finally {
releaseConnection(); // might throw
}
}
if (listenerException != null) {
throw listenerException;
}
}
/**
* Temporarily ends a transaction to let other threads have use of
* the database. Begins a new transaction after a specified delay.
* <p>
* If there are other threads waiting to acquire connections,
* then the current transaction is committed and the database
* connection is released. After a short delay, a new transaction
* is started.
* </p><p>
* The transaction is assumed to be successful so far. Do not call
* {@link #setTransactionSuccessful()} before calling this method.
* This method will fail if the transaction has already been marked
* successful.
* </p><p>
* The changes that were committed by a yield cannot be rolled back later.
* </p><p>
* Before this method was called, there must already have been
* a transaction in progress. When this method returns, there will
* still be a transaction in progress, either the same one as before
* or a new one if the transaction was actually yielded.
* </p><p>
* This method should not be called when there is a nested transaction
* in progress because it is not possible to yield a nested transaction.
* If <code>throwIfNested</code> is true, then attempting to yield
* a nested transaction will throw {@link IllegalStateException}, otherwise
* the method will return <code>false</code> in that case.
* </p><p>
* If there is no nested transaction in progress but a previous nested
* transaction failed, then the transaction is not yielded (because it
* must be rolled back) and this method returns <code>false</code>.
* </p>
*
* @param sleepAfterYieldDelayMillis A delay time to wait after yielding
* the database connection to allow other threads some time to run.
* If the value is less than or equal to zero, there will be no additional
* delay beyond the time it will take to begin a new transaction.
* @param throwIfUnsafe If true, then instead of returning false when no
* transaction is in progress, a nested transaction is in progress, or when
* the transaction has already been marked successful, throws {@link IllegalStateException}.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return True if the transaction was actually yielded.
*
* @throws IllegalStateException if <code>throwIfNested</code> is true and
* there is no current transaction, there is a nested transaction in progress or
* if {@link #setTransactionSuccessful} has already been called for the current transaction.
* @throws SQLiteException if an error occurs.
* @throws OperationCanceledException if the operation was canceled.
*
* @see #beginTransaction
* @see #endTransaction
*/
public boolean yieldTransaction(long sleepAfterYieldDelayMillis, boolean throwIfUnsafe,
CancellationSignal cancellationSignal) {
if (throwIfUnsafe) {
throwIfNoTransaction();
throwIfTransactionMarkedSuccessful();
throwIfNestedTransaction();
} else {
if (mTransactionStack == null || mTransactionStack.mMarkedSuccessful
|| mTransactionStack.mParent != null) {
return false;
}
}
assert mConnection != null;
if (mTransactionStack.mChildFailed) {
return false;
}
return yieldTransactionUnchecked(sleepAfterYieldDelayMillis,
cancellationSignal); // might throw
}
private boolean yieldTransactionUnchecked(long sleepAfterYieldDelayMillis,
CancellationSignal cancellationSignal) {
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
}
if (!mConnectionPool.shouldYieldConnection(mConnection, mConnectionFlags)) {
return false;
}
final int transactionMode = mTransactionStack.mMode;
final SQLiteTransactionListener listener = mTransactionStack.mListener;
final int connectionFlags = mConnectionFlags;
endTransactionUnchecked(cancellationSignal, true); // might throw
if (sleepAfterYieldDelayMillis > 0) {
try {
Thread.sleep(sleepAfterYieldDelayMillis);
} catch (InterruptedException ex) {
// we have been interrupted, that's all we need to do
}
}
beginTransactionUnchecked(transactionMode, listener, connectionFlags,
cancellationSignal); // might throw
return true;
}
/**
* Prepares a statement for execution but does not bind its parameters or execute it.
* <p>
* This method can be used to check for syntax errors during compilation
* prior to execution of the statement. If the {@code outStatementInfo} argument
* is not null, the provided {@link SQLiteStatementInfo} object is populated
* with information about the statement.
* </p><p>
* A prepared statement makes no reference to the arguments that may eventually
* be bound to it, consequently it it possible to cache certain prepared statements
* such as SELECT or INSERT/UPDATE statements. If the statement is cacheable,
* then it will be stored in the cache for later and reused if possible.
* </p>
*
* @param sql The SQL statement to prepare.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @param outStatementInfo The {@link SQLiteStatementInfo} object to populate
* with information about the statement, or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error.
* @throws OperationCanceledException if the operation was canceled.
*/
public void prepare(String sql, int connectionFlags, CancellationSignal cancellationSignal,
SQLiteStatementInfo outStatementInfo) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
mConnection.prepare(sql, outStatementInfo); // might throw
} finally {
releaseConnection(); // might throw
}
}
/**
* Executes a statement that does not return a result.
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
public void execute(String sql, Object[] bindArgs, int connectionFlags,
CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
mConnection.execute(sql, bindArgs, cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
}
/**
* Executes a statement that returns a single <code>long</code> result.
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The value of the first column in the first row of the result set
* as a <code>long</code>, or zero if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
public long executeForLong(String sql, Object[] bindArgs, int connectionFlags,
CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return 0;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForLong(sql, bindArgs, cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
}
/**
* Executes a statement that returns a single {@link String} result.
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The value of the first column in the first row of the result set
* as a <code>String</code>, or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
public String executeForString(String sql, Object[] bindArgs, int connectionFlags,
CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return null;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForString(sql, bindArgs, cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
}
/**
* Executes a statement that returns a single BLOB result as a
* file descriptor to a shared memory region.
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The file descriptor for a shared memory region that contains
* the value of the first column in the first row of the result set as a BLOB,
* or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
int connectionFlags, CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return null;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForBlobFileDescriptor(sql, bindArgs,
cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
}
/**
* Executes a statement that returns a count of the number of rows
* that were changed. Use for UPDATE or DELETE SQL statements.
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The number of rows that were changed.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags,
CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return 0;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForChangedRowCount(sql, bindArgs,
cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
}
/**
* Executes a statement that returns the row id of the last row inserted
* by the statement. Use for INSERT SQL statements.
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The row id of the last row that was inserted, or 0 if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
public long executeForLastInsertedRowId(String sql, Object[] bindArgs, int connectionFlags,
CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return 0;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForLastInsertedRowId(sql, bindArgs,
cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
}
/**
* Executes a statement and populates the specified {@link CursorWindow}
* with a range of results. Returns the number of rows that were counted
* during query execution.
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
* @param window The cursor window to clear and fill.
* @param startPos The start position for filling the window.
* @param requiredPos The position of a row that MUST be in the window.
* If it won't fit, then the query should discard part of what it filled
* so that it does. Must be greater than or equal to <code>startPos</code>.
* @param countAllRows True to count all rows that the query would return
* regagless of whether they fit in the window.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The number of rows that were counted during query execution. Might
* not be all rows in the result set unless <code>countAllRows</code> is true.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
public int executeForCursorWindow(String sql, Object[] bindArgs,
CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
int connectionFlags, CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
if (window == null) {
throw new IllegalArgumentException("window must not be null.");
}
if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
window.clear();
return 0;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForCursorWindow(sql, bindArgs,
window, startPos, requiredPos, countAllRows,
cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
}
/**
* Performs special reinterpretation of certain SQL statements such as "BEGIN",
* "COMMIT" and "ROLLBACK" to ensure that transaction state invariants are
* maintained.
*
* This function is mainly used to support legacy apps that perform their
* own transactions by executing raw SQL rather than calling {@link #beginTransaction}
* and the like.
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return True if the statement was of a special form that was handled here,
* false otherwise.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags,
CancellationSignal cancellationSignal) {
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
}
final int type = DatabaseUtils.getSqlStatementType(sql);
switch (type) {
case DatabaseUtils.STATEMENT_BEGIN:
beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags,
cancellationSignal);
return true;
case DatabaseUtils.STATEMENT_COMMIT:
setTransactionSuccessful();
endTransaction(cancellationSignal);
return true;
case DatabaseUtils.STATEMENT_ABORT:
endTransaction(cancellationSignal);
return true;
}
return false;
}
private void acquireConnection(String sql, int connectionFlags,
CancellationSignal cancellationSignal) {
if (mConnection == null) {
assert mConnectionUseCount == 0;
mConnection = mConnectionPool.acquireConnection(sql, connectionFlags,
cancellationSignal); // might throw
mConnectionFlags = connectionFlags;
}
mConnectionUseCount += 1;
}
private void releaseConnection() {
assert mConnection != null;
assert mConnectionUseCount > 0;
if (--mConnectionUseCount == 0) {
try {
mConnectionPool.releaseConnection(mConnection); // might throw
} finally {
mConnection = null;
}
}
}
private void throwIfNoTransaction() {
if (mTransactionStack == null) {
throw new IllegalStateException("Cannot perform this operation because "
+ "there is no current transaction.");
}
}
private void throwIfTransactionMarkedSuccessful() {
if (mTransactionStack != null && mTransactionStack.mMarkedSuccessful) {
throw new IllegalStateException("Cannot perform this operation because "
+ "the transaction has already been marked successful. The only "
+ "thing you can do now is call endTransaction().");
}
}
private void throwIfNestedTransaction() {
if (hasNestedTransaction()) {
throw new IllegalStateException("Cannot perform this operation because "
+ "a nested transaction is in progress.");
}
}
private Transaction obtainTransaction(int mode, SQLiteTransactionListener listener) {
Transaction transaction = mTransactionPool;
if (transaction != null) {
mTransactionPool = transaction.mParent;
transaction.mParent = null;
transaction.mMarkedSuccessful = false;
transaction.mChildFailed = false;
} else {
transaction = new Transaction();
}
transaction.mMode = mode;
transaction.mListener = listener;
return transaction;
}
private void recycleTransaction(Transaction transaction) {
transaction.mParent = mTransactionPool;
transaction.mListener = null;
mTransactionPool = transaction;
}
private static final class Transaction {
public Transaction mParent;
public int mMode;
public SQLiteTransactionListener mListener;
public boolean mMarkedSuccessful;
public boolean mChildFailed;
}
}

View File

@ -1,167 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import android.os.ParcelFileDescriptor;
/**
* Represents a statement that can be executed against a database. The statement
* cannot return multiple rows or columns, but single value (1 x 1) result sets
* are supported.
* <p>
* This class is not thread-safe.
* </p>
*/
public final class SQLiteStatement extends SQLiteProgram {
SQLiteStatement(SQLiteDatabase db, String sql, Object[] bindArgs) {
super(db, sql, bindArgs, null);
}
/**
* Execute this SQL statement, if it is not a SELECT / INSERT / DELETE / UPDATE, for example
* CREATE / DROP table, view, trigger, index etc.
*
* @throws org.sqlite.database.SQLException If the SQL string is invalid for
* some reason
*/
public void execute() {
acquireReference();
try {
getSession().execute(getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
} finally {
releaseReference();
}
}
/**
* Execute this SQL statement, if the the number of rows affected by execution of this SQL
* statement is of any importance to the caller - for example, UPDATE / DELETE SQL statements.
*
* @return the number of rows affected by this SQL statement execution.
* @throws org.sqlite.database.SQLException If the SQL string is invalid for
* some reason
*/
public int executeUpdateDelete() {
acquireReference();
try {
return getSession().executeForChangedRowCount(
getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
} finally {
releaseReference();
}
}
/**
* Execute this SQL statement and return the ID of the row inserted due to this call.
* The SQL statement should be an INSERT for this to be a useful call.
*
* @return the row ID of the last row inserted, if this insert is successful. -1 otherwise.
*
* @throws org.sqlite.database.SQLException If the SQL string is invalid for
* some reason
*/
public long executeInsert() {
acquireReference();
try {
return getSession().executeForLastInsertedRowId(
getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
} finally {
releaseReference();
}
}
/**
* Execute a statement that returns a 1 by 1 table with a numeric value.
* For example, SELECT COUNT(*) FROM table;
*
* @return The result of the query.
*
* @throws org.sqlite.database.sqlite.SQLiteDoneException if the query returns zero rows
*/
public long simpleQueryForLong() {
acquireReference();
try {
return getSession().executeForLong(
getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
} finally {
releaseReference();
}
}
/**
* Execute a statement that returns a 1 by 1 table with a text value.
* For example, SELECT COUNT(*) FROM table;
*
* @return The result of the query.
*
* @throws org.sqlite.database.sqlite.SQLiteDoneException if the query returns zero rows
*/
public String simpleQueryForString() {
acquireReference();
try {
return getSession().executeForString(
getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
} finally {
releaseReference();
}
}
/**
* Executes a statement that returns a 1 by 1 table with a blob value.
*
* @return A read-only file descriptor for a copy of the blob value, or {@code null}
* if the value is null or could not be read for some reason.
*
* @throws org.sqlite.database.sqlite.SQLiteDoneException if the query returns zero rows
*/
public ParcelFileDescriptor simpleQueryForBlobFileDescriptor() {
acquireReference();
try {
return getSession().executeForBlobFileDescriptor(
getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
} finally {
releaseReference();
}
}
@Override
public String toString() {
return "SQLiteProgram: " + getSql();
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* Describes a SQLite statement.
*
* @hide
*/
public final class SQLiteStatementInfo {
/**
* The number of parameters that the statement has.
*/
public int numParameters;
/**
* The names of all columns in the result set of the statement.
*/
public String[] columnNames;
/**
* True if the statement is read-only.
*/
public boolean readOnly;
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
public class SQLiteTableLockedException extends SQLiteException {
public SQLiteTableLockedException() {}
public SQLiteTableLockedException(String error) {
super(error);
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
/**
* A listener for transaction events.
*/
public interface SQLiteTransactionListener {
/**
* Called immediately after the transaction begins.
*/
void onBegin();
/**
* Called immediately before commiting the transaction.
*/
void onCommit();
/**
* Called if the transaction is about to be rolled back.
*/
void onRollback();
}

View File

@ -1,111 +0,0 @@
/*
* Copyright (C) 2008 Esmertec AG.
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package org.sqlite.database.sqlite;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import org.sqlite.database.sqlite.SQLiteException;
import android.net.Uri;
import android.util.Log;
import android.widget.Toast;
/**
* @hide
*/
public final class SqliteWrapper {
private static final String TAG = "SqliteWrapper";
private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE
= "unable to open database file";
private SqliteWrapper() {
// Forbidden being instantiated.
}
// FIXME: need to optimize this method.
private static boolean isLowMemory(SQLiteException e) {
return e.getMessage().equals(SQLITE_EXCEPTION_DETAIL_MESSAGE);
}
public static void checkSQLiteException(Context context, SQLiteException e) {
if (isLowMemory(e)) {
Toast.makeText(context, "low memory", Toast.LENGTH_SHORT).show();
} else {
throw e;
}
}
public static Cursor query(Context context, ContentResolver resolver, Uri uri,
String[] projection, String selection, String[] selectionArgs, String sortOrder) {
try {
return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when query: ", e);
checkSQLiteException(context, e);
return null;
}
}
public static boolean requery(Context context, Cursor cursor) {
try {
return cursor.requery();
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when requery: ", e);
checkSQLiteException(context, e);
return false;
}
}
public static int update(Context context, ContentResolver resolver, Uri uri,
ContentValues values, String where, String[] selectionArgs) {
try {
return resolver.update(uri, values, where, selectionArgs);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when update: ", e);
checkSQLiteException(context, e);
return -1;
}
}
public static int delete(Context context, ContentResolver resolver, Uri uri,
String where, String[] selectionArgs) {
try {
return resolver.delete(uri, where, selectionArgs);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when delete: ", e);
checkSQLiteException(context, e);
return -1;
}
}
public static Uri insert(Context context, ContentResolver resolver,
Uri uri, ContentValues values) {
try {
return resolver.insert(uri, values);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when insert: ", e);
checkSQLiteException(context, e);
return null;
}
}
}

View File

@ -1,215 +0,0 @@
<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>

View File

@ -1,10 +0,0 @@
Metadata-Version: 1.0
Name: yap
Version: 0.1
Summary: UNKNOWN
Home-page: UNKNOWN
Author: UNKNOWN
Author-email: UNKNOWN
License: UNKNOWN
Description: UNKNOWN
Platform: UNKNOWN

View File

@ -1,14 +0,0 @@
setup.py
yapPYTHON_wrap.cxx
/Users/vsc/github/yap-6.3/packages/python/pl2pl.c
/Users/vsc/github/yap-6.3/packages/python/pl2py.c
/Users/vsc/github/yap-6.3/packages/python/py2pl.c
/Users/vsc/github/yap-6.3/packages/python/pybips.c
/Users/vsc/github/yap-6.3/packages/python/pypreds.c
/Users/vsc/github/yap-6.3/packages/python/python.c
/Users/vsc/github/yap-6.3/packages/swig/yap.i
/Users/vsc/github/yap-6.3/packages/swig/python/yapex.py
/Users/vsc/github/yap-6.3/packages/swig/python/yap.egg-info/PKG-INFO
/Users/vsc/github/yap-6.3/packages/swig/python/yap.egg-info/SOURCES.txt
/Users/vsc/github/yap-6.3/packages/swig/python/yap.egg-info/dependency_links.txt
/Users/vsc/github/yap-6.3/packages/swig/python/yap.egg-info/top_level.txt

View File

@ -1,2 +0,0 @@
yap
yapex

View File

@ -1,10 +0,0 @@
Metadata-Version: 1.0
Name: yapex
Version: 0.1
Summary: UNKNOWN
Home-page: UNKNOWN
Author: UNKNOWN
Author-email: UNKNOWN
License: UNKNOWN
Description: UNKNOWN
Platform: UNKNOWN

View File

@ -1,12 +0,0 @@
setup.py
/Users/vsc/github/yap-6.3/packages/python/pl2pl.c
/Users/vsc/github/yap-6.3/packages/python/pl2py.c
/Users/vsc/github/yap-6.3/packages/python/py2pl.c
/Users/vsc/github/yap-6.3/packages/python/pybips.c
/Users/vsc/github/yap-6.3/packages/python/pypreds.c
/Users/vsc/github/yap-6.3/packages/python/python.c
/Users/vsc/github/yap-6.3/packages/swig/python/yapex.py
/Users/vsc/github/yap-6.3/packages/swig/python/yapex.egg-info/PKG-INFO
/Users/vsc/github/yap-6.3/packages/swig/python/yapex.egg-info/SOURCES.txt
/Users/vsc/github/yap-6.3/packages/swig/python/yapex.egg-info/dependency_links.txt
/Users/vsc/github/yap-6.3/packages/swig/python/yapex.egg-info/top_level.txt

View File

@ -1 +0,0 @@
yapex