Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 22 additions & 146 deletions src/android-native/src/main/java/io/liteglue/SQLiteAndroidDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
import android.annotation.SuppressLint;

import android.database.Cursor;
import android.database.CursorWindow;
import android.database.sqlite.SQLiteCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteStatement;
Expand All @@ -38,14 +36,6 @@ class SQLiteAndroidDatabase {
private static final Pattern FIRST_WORD = Pattern.compile("^\\s*(\\S+)",
Pattern.CASE_INSENSITIVE);

private static final Pattern WHERE_CLAUSE = Pattern.compile("\\s+WHERE\\s+(.+)$",
Pattern.CASE_INSENSITIVE);

private static final Pattern UPDATE_TABLE_NAME = Pattern.compile("^\\s*UPDATE\\s+(\\S+)",
Pattern.CASE_INSENSITIVE);

private static final Pattern DELETE_TABLE_NAME = Pattern.compile("^\\s*DELETE\\s+FROM\\s+(\\S+)",
Pattern.CASE_INSENSITIVE);

File dbFile;
int openFlags;
Expand Down Expand Up @@ -129,37 +119,29 @@ void executeSqlBatch(String[] queryarr, JSONArray[] jsonparams,
QueryType queryType = getQueryType(query);

if (queryType == QueryType.update || queryType == QueryType.delete) {
if (android.os.Build.VERSION.SDK_INT >= 11) {
SQLiteStatement myStatement = mydb.compileStatement(query);

if (jsonparams != null) {
bindArgsToStatement(myStatement, jsonparams[i]);
}
SQLiteStatement myStatement = mydb.compileStatement(query);

int rowsAffected = -1; // (assuming invalid)

// Use try & catch just in case android.os.Build.VERSION.SDK_INT >= 11 is lying:
try {
rowsAffected = myStatement.executeUpdateDelete();
// Indicate valid results:
needRawQuery = false;
} catch (SQLiteException ex) {
// Indicate problem & stop this query:
errorMessage = ex.getMessage();
FLog.e(SQLitePlugin.TAG, "SQLiteStatement.executeUpdateDelete() failed", ex);
needRawQuery = false;
} catch (Exception ex) {
// Assuming SDK_INT was lying & method not found:
// do nothing here & try again with raw query.
}
if (jsonparams != null) {
bindArgsToStatement(myStatement, jsonparams[i]);
}

if (rowsAffected != -1) {
queryResult = new JSONObject();
queryResult.put("rowsAffected", rowsAffected);
}
} else { // pre-honeycomb
rowsAffectedCompat = countRowsAffectedCompat(queryType, query, jsonparams, mydb, i);
needRowsAffectedCompat = true;
int rowsAffected = -1; // (assuming invalid)

try {
rowsAffected = myStatement.executeUpdateDelete();
// Indicate valid results:
needRawQuery = false;
} catch (SQLiteException ex) {
// Indicate problem & stop this query:
errorMessage = ex.getMessage();
FLog.e(SQLitePlugin.TAG, "SQLiteStatement.executeUpdateDelete() failed", ex);
needRawQuery = false;
}

if (rowsAffected != -1) {
queryResult = new JSONObject();
queryResult.put("rowsAffected", rowsAffected);
}
}

Expand Down Expand Up @@ -273,81 +255,6 @@ void executeSqlBatch(String[] queryarr, JSONArray[] jsonparams,
cbc.success(batchResults);
}

private int countRowsAffectedCompat(QueryType queryType, String query, JSONArray[] jsonparams,
SQLiteDatabase mydb, int i) throws JSONException {
// quick and dirty way to calculate the rowsAffected in pre-Honeycomb. just do a SELECT
// beforehand using the same WHERE clause. might not be perfect, but it's better than nothing
Matcher whereMatcher = WHERE_CLAUSE.matcher(query);

String where = "";

int pos = 0;
while (whereMatcher.find(pos)) {
where = " WHERE " + whereMatcher.group(1);
pos = whereMatcher.start(1);
}
// WHERE clause may be omitted, and also be sure to find the last one,
// e.g. for cases where there's a subquery

// bindings may be in the update clause, so only take the last n
int numQuestionMarks = 0;
for (int j = 0; j < where.length(); j++) {
if (where.charAt(j) == '?') {
numQuestionMarks++;
}
}

JSONArray subParams = null;

if (jsonparams != null) {
// only take the last n of every array of sqlArgs
JSONArray origArray = jsonparams[i];
subParams = new JSONArray();
int startPos = origArray.length() - numQuestionMarks;
for (int j = startPos; j < origArray.length(); j++) {
subParams.put(j - startPos, origArray.get(j));
}
}

if (queryType == QueryType.update) {
Matcher tableMatcher = UPDATE_TABLE_NAME.matcher(query);
if (tableMatcher.find()) {
String table = tableMatcher.group(1);
try {
SQLiteStatement statement = mydb.compileStatement(
"SELECT count(*) FROM " + table + where);

if (subParams != null) {
bindArgsToStatement(statement, subParams);
}

return (int)statement.simpleQueryForLong();
} catch (Exception e) {
// assume we couldn't count for whatever reason, keep going
FLog.e(SQLitePlugin.TAG, "update query failed", e);
}
}
} else { // delete
Matcher tableMatcher = DELETE_TABLE_NAME.matcher(query);
if (tableMatcher.find()) {
String table = tableMatcher.group(1);
try {
SQLiteStatement statement = mydb.compileStatement(
"SELECT count(*) FROM " + table + where);
bindArgsToStatement(statement, subParams);

return (int)statement.simpleQueryForLong();
} catch (Exception e) {
// assume we couldn't count for whatever reason, keep going
FLog.e(SQLitePlugin.TAG, "delete table query failed", e);

}
}
}

return 0;
}

private void bindArgsToStatement(SQLiteStatement myStatement, JSONArray sqlArgs) throws JSONException {
for (int i = 0; i < sqlArgs.length(); i++) {
if (sqlArgs.get(i) instanceof Float || sqlArgs.get(i) instanceof Double) {
Expand Down Expand Up @@ -403,18 +310,7 @@ private JSONObject executeSqlStatementQuery(SQLiteDatabase mydb,
try {
for (int i = 0; i < colCount; ++i) {
key = cur.getColumnName(i);

if (android.os.Build.VERSION.SDK_INT >= 11) {

// Use try & catch just in case android.os.Build.VERSION.SDK_INT >= 11 is lying:
try {
bindPostHoneycomb(row, key, cur, i);
} catch (Exception ex) {
bindPreHoneycomb(row, key, cur, i);
}
} else {
bindPreHoneycomb(row, key, cur, i);
}
bindRow(row, key, cur, i);
}

rowsArrayResult.put(row);
Expand All @@ -439,7 +335,7 @@ private JSONObject executeSqlStatementQuery(SQLiteDatabase mydb,
}

@SuppressLint("NewApi")
private void bindPostHoneycomb(JSONObject row, String key, Cursor cur, int i) throws JSONException {
private void bindRow(JSONObject row, String key, Cursor cur, int i) throws JSONException {
int curType = cur.getType(i);

switch (curType) {
Expand All @@ -462,26 +358,6 @@ private void bindPostHoneycomb(JSONObject row, String key, Cursor cur, int i) th
}
}

private void bindPreHoneycomb(JSONObject row, String key, Cursor cursor, int i) throws JSONException {
// Since cursor.getType() is not available pre-honeycomb, this is
// a workaround so we don't have to bind everything as a string
// Details here: http://stackoverflow.com/q/11658239
SQLiteCursor sqLiteCursor = (SQLiteCursor) cursor;
CursorWindow cursorWindow = sqLiteCursor.getWindow();
int pos = cursor.getPosition();
if (cursorWindow.isNull(pos, i)) {
row.put(key, JSONObject.NULL);
} else if (cursorWindow.isLong(pos, i)) {
row.put(key, cursor.getLong(i));
} else if (cursorWindow.isFloat(pos, i)) {
row.put(key, cursor.getDouble(i));
} else if (cursorWindow.isBlob(pos, i)) {
row.put(key, new String(Base64.encode(cursor.getBlob(i), Base64.DEFAULT)));
} else { // string
row.put(key, cursor.getString(i));
}
}

static QueryType getQueryType(String query) {
Matcher matcher = FIRST_WORD.matcher(query);
if (matcher.find()) {
Expand Down
Loading