mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 740218 - Support transactions in sqlitebridge and use them. r=gcp,rnewman,lucasr
This commit is contained in:
parent
8ee2ed5550
commit
e196e635a6
@ -41,6 +41,9 @@
|
||||
#include "mozilla/layers/PLayers.h"
|
||||
#include "mozilla/layers/ShadowLayers.h"
|
||||
|
||||
#define MOZ_DUMP_PAINTING 1
|
||||
#define MOZ_LAYERS_HAVE_LOG 1
|
||||
|
||||
#include "ImageLayers.h"
|
||||
#include "Layers.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
@ -54,6 +54,8 @@
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
#define MOZ_DUMP_PAINTING 1
|
||||
|
||||
#if defined(DEBUG) || defined(PR_LOGGING)
|
||||
# include <stdio.h> // FILE
|
||||
# include "prlog.h"
|
||||
|
@ -71,6 +71,8 @@
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define MOZ_DUMP_PAINTING 1
|
||||
|
||||
#include "imgIEncoder.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "prmem.h"
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "nsAutoRef.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#define MOZ_DUMP_PAINTING 1
|
||||
|
||||
typedef struct _cairo_surface cairo_surface_t;
|
||||
typedef struct _cairo_user_data_key cairo_user_data_key_t;
|
||||
|
@ -47,6 +47,8 @@
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#endif
|
||||
|
||||
#define MOZ_DUMP_PAINTING 1
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::gfx;
|
||||
|
@ -44,6 +44,8 @@
|
||||
#include "ImageLayers.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
#define MOZ_DUMP_PAINTING 1
|
||||
|
||||
class gfxDrawable;
|
||||
class nsIntRegion;
|
||||
struct nsIntRect;
|
||||
|
@ -227,6 +227,7 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
|
||||
}
|
||||
|
||||
fprintf(aOutput, "</ul>");
|
||||
printf_stderr("DL: %s", aOutput);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -112,6 +112,8 @@
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#define MOZ_DUMP_PAINTING 1
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsXULPopupManager.h"
|
||||
#endif
|
||||
@ -1347,7 +1349,7 @@ nsLayoutUtils::CombineBreakType(PRUint8 aOrigBreakType,
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
#include <stdio.h>
|
||||
|
||||
static bool gDumpEventList = false;
|
||||
static bool gDumpEventList = true;
|
||||
int gPaintCount = 0;
|
||||
#endif
|
||||
|
||||
@ -1361,9 +1363,10 @@ nsLayoutUtils::GetRemoteContentIds(nsIFrame* aFrame,
|
||||
false);
|
||||
nsDisplayList list;
|
||||
|
||||
nsIFrame* rootScrollFrame =
|
||||
aFrame->PresContext()->PresShell()->GetRootScrollFrame();
|
||||
|
||||
if (aIgnoreRootScrollFrame) {
|
||||
nsIFrame* rootScrollFrame =
|
||||
aFrame->PresContext()->PresShell()->GetRootScrollFrame();
|
||||
if (rootScrollFrame) {
|
||||
builder.SetIgnoreScrollFrame(rootScrollFrame);
|
||||
}
|
||||
@ -1413,14 +1416,25 @@ nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
|
||||
builder.IgnorePaintSuppression();
|
||||
}
|
||||
|
||||
nsIFrame* rootScrollFrame =
|
||||
aFrame->PresContext()->PresShell()->GetRootScrollFrame();
|
||||
if (aIgnoreRootScrollFrame) {
|
||||
nsIFrame* rootScrollFrame =
|
||||
aFrame->PresContext()->PresShell()->GetRootScrollFrame();
|
||||
if (rootScrollFrame) {
|
||||
builder.SetIgnoreScrollFrame(rootScrollFrame);
|
||||
}
|
||||
}
|
||||
|
||||
nsRect displayport;
|
||||
if (rootScrollFrame) {
|
||||
nsIContent* content = rootScrollFrame->GetContent();
|
||||
bool usingDisplayPort = GetDisplayPort(content, &displayport);
|
||||
if (usingDisplayPort) {
|
||||
//printf_stderr(" xxx Setting display port %i%,%i,%i,%i",
|
||||
// displayport.x, displayport.y, displayport.width, displayport.height);
|
||||
builder.SetDisplayPort(displayport);
|
||||
}
|
||||
}
|
||||
|
||||
builder.EnterPresShell(aFrame, target);
|
||||
|
||||
nsresult rv =
|
||||
@ -1431,8 +1445,11 @@ nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (gDumpEventList) {
|
||||
fprintf(stdout, "Event handling --- (%d,%d):\n", aRect.x, aRect.y);
|
||||
nsFrame::PrintDisplayList(&builder, list);
|
||||
printf_stderr("Event handling --- (%d,%d):\n", aRect.x, aRect.y);
|
||||
FILE *handle;
|
||||
handle = fopen("/sdcard/test.txt","rw");
|
||||
nsFrame::PrintDisplayList(&builder, list, handle);
|
||||
fclose(handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2020,8 +2020,11 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
// area even if the scrollframe itself doesn't.
|
||||
if (child != aBuilder->GetIgnoreScrollFrame()) {
|
||||
nsRect childDirty;
|
||||
if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect()))
|
||||
nsRect overflow = child->GetVisualOverflowRect();
|
||||
|
||||
if (!childDirty.IntersectRect(dirty, overflow)) {
|
||||
return NS_OK;
|
||||
}
|
||||
// Usually we could set dirty to childDirty now but there's no
|
||||
// benefit, and it can be confusing. It can especially confuse
|
||||
// situations where we're going to ignore a scrollframe's clipping;
|
||||
|
@ -152,17 +152,14 @@ public class FormHistoryProvider extends GeckoProvider {
|
||||
if (!values.containsKey(FormHistory.GUID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String guid = values.getAsString(FormHistory.GUID);
|
||||
try {
|
||||
if (guid == null) {
|
||||
db.delete(TABLE_DELETED_FORM_HISTORY, WHERE_GUID_IS_NULL, null);
|
||||
return;
|
||||
}
|
||||
String[] args = new String[] { guid };
|
||||
db.delete(TABLE_DELETED_FORM_HISTORY, WHERE_GUID_IS_VALUE, args);
|
||||
} catch(SQLiteBridgeException ex) {
|
||||
Log.w(getLogTag(), "Error removing entry with GUID " + guid, ex);
|
||||
if (guid == null) {
|
||||
db.delete(TABLE_DELETED_FORM_HISTORY, WHERE_GUID_IS_NULL, null);
|
||||
return;
|
||||
}
|
||||
String[] args = new String[] { guid };
|
||||
db.delete(TABLE_DELETED_FORM_HISTORY, WHERE_GUID_IS_VALUE, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -10,6 +10,8 @@ import java.io.IOException;
|
||||
import java.lang.IllegalArgumentException;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Random;
|
||||
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
@ -59,6 +61,30 @@ public abstract class GeckoProvider extends ContentProvider {
|
||||
private HashMap<String, SQLiteBridge> mDatabasePerProfile;
|
||||
protected Context mContext = null;
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (mDatabasePerProfile == null)
|
||||
return;
|
||||
|
||||
Collection<SQLiteBridge> bridges = mDatabasePerProfile.values();
|
||||
Iterator<SQLiteBridge> it = bridges.iterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
SQLiteBridge bridge = it.next();
|
||||
if (bridge != null) {
|
||||
try {
|
||||
bridge.close();
|
||||
} catch (Exception ex) { }
|
||||
}
|
||||
}
|
||||
|
||||
mDatabasePerProfile = null;
|
||||
}
|
||||
|
||||
public void finalize() {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
protected void setLogTag(String aLogTag) {
|
||||
mLogTag = aLogTag;
|
||||
}
|
||||
@ -91,11 +117,14 @@ public abstract class GeckoProvider extends ContentProvider {
|
||||
String resourcePath = context.getPackageResourcePath();
|
||||
GeckoAppShell.loadSQLiteLibs(context, resourcePath);
|
||||
GeckoAppShell.loadNSSLibs(context, resourcePath);
|
||||
bridge = new SQLiteBridge(databasePath);
|
||||
bridge = SQLiteBridge.openDatabase(databasePath, null, 0);
|
||||
int version = bridge.getVersion();
|
||||
Log.i(mLogTag, version + " == " + mDBVersion);
|
||||
dbNeedsSetup = version != mDBVersion;
|
||||
} catch(SQLiteBridgeException ex) {
|
||||
} catch (SQLiteBridgeException ex) {
|
||||
// close the database
|
||||
if (bridge != null)
|
||||
bridge.close();
|
||||
|
||||
// this will throw if the database can't be found
|
||||
// we should attempt to set it up if Gecko is running
|
||||
dbNeedsSetup = true;
|
||||
@ -117,7 +146,8 @@ public abstract class GeckoProvider extends ContentProvider {
|
||||
bridge = null;
|
||||
initGecko();
|
||||
}
|
||||
mDatabasePerProfile.put(databasePath, bridge);
|
||||
if (bridge != null)
|
||||
mDatabasePerProfile.put(databasePath, bridge);
|
||||
|
||||
return bridge;
|
||||
}
|
||||
@ -204,6 +234,7 @@ public abstract class GeckoProvider extends ContentProvider {
|
||||
deleted = db.delete(getTable(uri), selection, selectionArgs);
|
||||
} catch (SQLiteBridgeException ex) {
|
||||
Log.e(mLogTag, "Error deleting record", ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return deleted;
|
||||
@ -222,17 +253,65 @@ public abstract class GeckoProvider extends ContentProvider {
|
||||
|
||||
setupDefaults(uri, values);
|
||||
|
||||
onPreInsert(values, uri, db);
|
||||
|
||||
boolean useTransaction = !db.inTransaction();
|
||||
try {
|
||||
if (useTransaction) {
|
||||
db.beginTransaction();
|
||||
}
|
||||
|
||||
// onPreInsert does a check for the item in the deleted table in some cases
|
||||
// so we put it inside this transaction
|
||||
onPreInsert(values, uri, db);
|
||||
id = db.insert(getTable(uri), null, values);
|
||||
} catch(SQLiteBridgeException ex) {
|
||||
|
||||
if (useTransaction) {
|
||||
db.setTransactionSuccessful();
|
||||
}
|
||||
} catch (SQLiteBridgeException ex) {
|
||||
Log.e(mLogTag, "Error inserting in db", ex);
|
||||
throw ex;
|
||||
} finally {
|
||||
if (useTransaction) {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
return ContentUris.withAppendedId(uri, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bulkInsert(Uri uri, ContentValues[] allValues) {
|
||||
final SQLiteBridge db = getDatabase(uri);
|
||||
// If we can not get a SQLiteBridge instance, its likely that the database
|
||||
// has not been set up and Gecko is not running. We return 0 and expect
|
||||
// callers to try again later
|
||||
if (db == null)
|
||||
return 0;
|
||||
|
||||
long id = -1;
|
||||
int rowsAdded = 0;
|
||||
|
||||
String table = getTable(uri);
|
||||
|
||||
try {
|
||||
db.beginTransaction();
|
||||
for (ContentValues initialValues : allValues) {
|
||||
ContentValues values = new ContentValues(initialValues);
|
||||
setupDefaults(uri, values);
|
||||
onPreInsert(values, uri, db);
|
||||
id = db.insert(table, null, values);
|
||||
rowsAdded++;
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
} catch (SQLiteBridgeException ex) {
|
||||
Log.e(mLogTag, "Error inserting in db", ex);
|
||||
throw ex;
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
return rowsAdded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String selection,
|
||||
String[] selectionArgs) {
|
||||
@ -249,8 +328,9 @@ public abstract class GeckoProvider extends ContentProvider {
|
||||
|
||||
try {
|
||||
updated = db.update(getTable(uri), values, selection, selectionArgs);
|
||||
} catch(SQLiteBridgeException ex) {
|
||||
} catch (SQLiteBridgeException ex) {
|
||||
Log.e(mLogTag, "Error updating table", ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return updated;
|
||||
@ -275,6 +355,7 @@ public abstract class GeckoProvider extends ContentProvider {
|
||||
onPostQuery(cursor, uri, db);
|
||||
} catch (SQLiteBridgeException ex) {
|
||||
Log.e(mLogTag, "Error querying database", ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
|
@ -217,16 +217,12 @@ public class PasswordsProvider extends GeckoProvider {
|
||||
public void onPreInsert(ContentValues values, Uri uri, SQLiteBridge db) {
|
||||
if (values.containsKey(Passwords.GUID)) {
|
||||
String guid = values.getAsString(Passwords.GUID);
|
||||
try {
|
||||
if (guid == null) {
|
||||
db.delete(TABLE_DELETED_PASSWORDS, WHERE_GUID_IS_NULL, null);
|
||||
return;
|
||||
}
|
||||
String[] args = new String[] { guid };
|
||||
db.delete(TABLE_DELETED_PASSWORDS, WHERE_GUID_IS_VALUE, args);
|
||||
} catch(SQLiteBridgeException ex) {
|
||||
Log.w(getLogTag(), "Error removing entry with GUID " + guid, ex);
|
||||
if (guid == null) {
|
||||
db.delete(TABLE_DELETED_PASSWORDS, WHERE_GUID_IS_NULL, null);
|
||||
return;
|
||||
}
|
||||
String[] args = new String[] { guid };
|
||||
db.delete(TABLE_DELETED_PASSWORDS, WHERE_GUID_IS_VALUE, args);
|
||||
}
|
||||
|
||||
if (values.containsKey(Passwords.ENCRYPTED_PASSWORD)) {
|
||||
|
@ -8,14 +8,17 @@ import org.mozilla.gecko.sqlite.SQLiteBridgeException;
|
||||
import org.mozilla.gecko.sqlite.MatrixBlobCursor;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.database.DatabaseErrorHandler;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.String;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import android.util.Log;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
@ -27,12 +30,17 @@ import java.util.Set;
|
||||
public class SQLiteBridge {
|
||||
private static final String LOGTAG = "SQLiteBridge";
|
||||
|
||||
// Path to the database. We reopen it every query.
|
||||
// Path to the database. If this database was not opened with openDatabase, we reopen it every query.
|
||||
private String mDb;
|
||||
// pointer to the database if it was opened with openDatabase
|
||||
protected long mDbPointer = 0;
|
||||
|
||||
// Values remembered after a query.
|
||||
private long[] mQueryResults;
|
||||
|
||||
private boolean mTransactionSuccess = false;
|
||||
private boolean mInTransaction = false;
|
||||
|
||||
private static final int RESULT_INSERT_ROW_ID = 0;
|
||||
private static final int RESULT_ROWS_CHANGED = 1;
|
||||
|
||||
@ -41,6 +49,13 @@ public class SQLiteBridge {
|
||||
String[] aParams,
|
||||
long[] aUpdateResult)
|
||||
throws SQLiteBridgeException;
|
||||
private static native MatrixBlobCursor sqliteCallWithDb(long aDb, String aQuery,
|
||||
String[] aParams,
|
||||
long[] aUpdateResult)
|
||||
throws SQLiteBridgeException;
|
||||
private static native long openDatabase(String aDb)
|
||||
throws SQLiteBridgeException;
|
||||
private static native void closeDatabase(long aDb);
|
||||
|
||||
// Takes the path to the database we want to access.
|
||||
public SQLiteBridge(String aDb) throws SQLiteBridgeException {
|
||||
@ -204,10 +219,92 @@ public class SQLiteBridge {
|
||||
// are not supported.
|
||||
private Cursor internalQuery(String aQuery, String[] aParams)
|
||||
throws SQLiteBridgeException {
|
||||
|
||||
mQueryResults = new long[2];
|
||||
if (isOpen()) {
|
||||
return sqliteCallWithDb(mDbPointer, aQuery, aParams, mQueryResults);
|
||||
}
|
||||
return sqliteCall(mDb, aQuery, aParams, mQueryResults);
|
||||
}
|
||||
|
||||
// nop, provided for API compatibility with SQLiteDatabase.
|
||||
public void close() { }
|
||||
/*
|
||||
* The second two parameters here are just provided for compatbility with SQLiteDatabase
|
||||
* Support for them is not currently implemented
|
||||
*/
|
||||
public static SQLiteBridge openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags)
|
||||
throws SQLiteException {
|
||||
SQLiteBridge bridge = null;
|
||||
try {
|
||||
bridge = new SQLiteBridge(path);
|
||||
bridge.mDbPointer = bridge.openDatabase(path);
|
||||
} catch(SQLiteBridgeException ex) {
|
||||
// catch and rethrow as a SQLiteException to match SQLiteDatabase
|
||||
throw new SQLiteException(ex.getMessage());
|
||||
}
|
||||
return bridge;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (isOpen()) {
|
||||
closeDatabase(mDbPointer);
|
||||
}
|
||||
mDbPointer = 0;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return mDbPointer > 0;
|
||||
}
|
||||
|
||||
public void beginTransaction() throws SQLiteBridgeException {
|
||||
if (inTransaction()) {
|
||||
throw new SQLiteBridgeException("Nested transactions are not supported");
|
||||
}
|
||||
execSQL("BEGIN EXCLUSIVE");
|
||||
mTransactionSuccess = false;
|
||||
mInTransaction = true;
|
||||
}
|
||||
|
||||
public void beginTransactionNonExclusive() throws SQLiteBridgeException {
|
||||
if (inTransaction()) {
|
||||
throw new SQLiteBridgeException("Nested transactions are not supported");
|
||||
}
|
||||
execSQL("BEGIN IMMEDIATE");
|
||||
mTransactionSuccess = false;
|
||||
mInTransaction = true;
|
||||
}
|
||||
|
||||
public void endTransaction() {
|
||||
if (!inTransaction())
|
||||
return;
|
||||
|
||||
try {
|
||||
if (mTransactionSuccess) {
|
||||
execSQL("COMMIT TRANSACTION");
|
||||
} else {
|
||||
execSQL("ROLLBACK TRANSACTION");
|
||||
}
|
||||
} catch(SQLiteBridgeException ex) {
|
||||
Log.e(LOGTAG, "Error ending transaction", ex);
|
||||
}
|
||||
mInTransaction = false;
|
||||
mTransactionSuccess = false;
|
||||
}
|
||||
|
||||
public void setTransactionSuccessful() throws SQLiteBridgeException {
|
||||
if (!inTransaction()) {
|
||||
throw new SQLiteBridgeException("setTransactionSuccessful called outside a transaction");
|
||||
}
|
||||
mTransactionSuccess = true;
|
||||
}
|
||||
|
||||
public boolean inTransaction() {
|
||||
return mInTransaction;
|
||||
}
|
||||
|
||||
public void finalize() {
|
||||
if (isOpen()) {
|
||||
Log.e(LOGTAG, "Bridge finalized without closing the database");
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,11 +37,11 @@
|
||||
|
||||
package org.mozilla.gecko.sqlite;
|
||||
|
||||
public class SQLiteBridgeException extends Exception {
|
||||
public class SQLiteBridgeException extends RuntimeException {
|
||||
static final long serialVersionUID = 1L;
|
||||
|
||||
public SQLiteBridgeException() {}
|
||||
public SQLiteBridgeException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,27 +168,94 @@ Java_org_mozilla_gecko_sqlite_SQLiteBridge_sqliteCall(JNIEnv* jenv, jclass,
|
||||
{
|
||||
JNI_Setup(jenv);
|
||||
|
||||
int rc;
|
||||
jobject jCursor = NULL;
|
||||
const char* dbPath;
|
||||
sqlite3 *db;
|
||||
char* errorMsg;
|
||||
|
||||
dbPath = jenv->GetStringUTFChars(jDb, NULL);
|
||||
rc = f_sqlite3_open(dbPath, &db);
|
||||
jenv->ReleaseStringUTFChars(jDb, dbPath);
|
||||
if (rc != SQLITE_OK) {
|
||||
asprintf(&errorMsg, "Can't open database: %s\n", f_sqlite3_errmsg(db));
|
||||
LOG("Error in SQLiteBridge: %s\n", errorMsg);
|
||||
JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException", errorMsg);
|
||||
free(errorMsg);
|
||||
} else {
|
||||
jCursor = sqliteInternalCall(jenv, db, jQuery, jParams, jQueryRes);
|
||||
}
|
||||
f_sqlite3_close(db);
|
||||
return jCursor;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT jobject JNICALL
|
||||
Java_org_mozilla_gecko_sqlite_SQLiteBridge_sqliteCallWithDb(JNIEnv* jenv, jclass,
|
||||
jlong jDb,
|
||||
jstring jQuery,
|
||||
jobjectArray jParams,
|
||||
jlongArray jQueryRes)
|
||||
{
|
||||
JNI_Setup(jenv);
|
||||
|
||||
jobject jCursor = NULL;
|
||||
sqlite3 *db = (sqlite3*)jDb;
|
||||
jCursor = sqliteInternalCall(jenv, db, jQuery, jParams, jQueryRes);
|
||||
return jCursor;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT jlong JNICALL
|
||||
Java_org_mozilla_gecko_sqlite_SQLiteBridge_openDatabase(JNIEnv* jenv, jclass,
|
||||
jstring jDb)
|
||||
{
|
||||
JNI_Setup(jenv);
|
||||
|
||||
int rc;
|
||||
const char* dbPath;
|
||||
sqlite3 *db;
|
||||
char* errorMsg;
|
||||
|
||||
dbPath = jenv->GetStringUTFChars(jDb, NULL);
|
||||
rc = f_sqlite3_open(dbPath, &db);
|
||||
jenv->ReleaseStringUTFChars(jDb, dbPath);
|
||||
if (rc != SQLITE_OK) {
|
||||
asprintf(&errorMsg, "Can't open database: %s\n", f_sqlite3_errmsg(db));
|
||||
LOG("Error in SQLiteBridge: %s\n", errorMsg);
|
||||
JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException", errorMsg);
|
||||
free(errorMsg);
|
||||
}
|
||||
return (jlong)db;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT void JNICALL
|
||||
Java_org_mozilla_gecko_sqlite_SQLiteBridge_closeDatabase(JNIEnv* jenv, jclass,
|
||||
jlong jDb)
|
||||
{
|
||||
JNI_Setup(jenv);
|
||||
|
||||
sqlite3 *db = (sqlite3*)jDb;
|
||||
f_sqlite3_close(db);
|
||||
}
|
||||
|
||||
static jobject
|
||||
sqliteInternalCall(JNIEnv* jenv,
|
||||
sqlite3 *db,
|
||||
jstring jQuery,
|
||||
jobjectArray jParams,
|
||||
jlongArray jQueryRes)
|
||||
{
|
||||
JNI_Setup(jenv);
|
||||
|
||||
jobject jCursor = NULL;
|
||||
char* errorMsg;
|
||||
jsize numPars = 0;
|
||||
|
||||
const char* queryStr;
|
||||
queryStr = jenv->GetStringUTFChars(jQuery, NULL);
|
||||
|
||||
const char* dbPath;
|
||||
dbPath = jenv->GetStringUTFChars(jDb, NULL);
|
||||
|
||||
const char *pzTail;
|
||||
sqlite3_stmt *ppStmt;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
rc = f_sqlite3_open(dbPath, &db);
|
||||
jenv->ReleaseStringUTFChars(jDb, dbPath);
|
||||
|
||||
if (rc != SQLITE_OK) {
|
||||
asprintf(&errorMsg, "Can't open database: %s\n", f_sqlite3_errmsg(db));
|
||||
goto error_close;
|
||||
}
|
||||
const char* queryStr;
|
||||
queryStr = jenv->GetStringUTFChars(jQuery, NULL);
|
||||
|
||||
rc = f_sqlite3_prepare_v2(db, queryStr, -1, &ppStmt, &pzTail);
|
||||
if (rc != SQLITE_OK || ppStmt == NULL) {
|
||||
@ -353,11 +420,9 @@ Java_org_mozilla_gecko_sqlite_SQLiteBridge_sqliteCall(JNIEnv* jenv, jclass,
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
f_sqlite3_close(db);
|
||||
return jCursor;
|
||||
|
||||
error_close:
|
||||
f_sqlite3_close(db);
|
||||
LOG("Error in SQLiteBridge: %s\n", errorMsg);
|
||||
JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException", errorMsg);
|
||||
free(errorMsg);
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "sqlite3.h"
|
||||
|
||||
void setup_sqlite_functions(void *sqlite_handle);
|
||||
static jobject sqliteInternalCall(JNIEnv* jenv, sqlite3 *db, jstring jQuery, jobjectArray jParams, jlongArray jQueryRes);
|
||||
|
||||
#define SQLITE_WRAPPER(name, return_type, args...) \
|
||||
typedef return_type (*name ## _t)(args); \
|
||||
|
Loading…
Reference in New Issue
Block a user