Skip to content

Fixed UpdateBuilder.update() / DeleteBuilder.delete() always return 0 when WAL enabled #143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.j256.ormlite.android;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -31,6 +33,8 @@ public class AndroidCompiledStatement implements CompiledStatement {
private static final String[] NO_STRING_ARGS = new String[0];
private static final ApiCompatibility apiCompatibility = ApiCompatibilityUtils.getCompatibility();

private static Method hiddenExecSqlMethod;

private final String sql;
private final SQLiteDatabase db;
private final StatementType type;
Expand All @@ -42,6 +46,10 @@ public class AndroidCompiledStatement implements CompiledStatement {
private Integer max;
private CancellationHook cancellationHook;

static {
hiddenExecSqlMethod = hiddenExecSqlMethod();
}

public AndroidCompiledStatement(String sql, SQLiteDatabase db, StatementType type, boolean cancelQueriesEnabled,
boolean cacheStore) {
this.sql = sql;
Expand Down Expand Up @@ -214,11 +222,18 @@ public String toString() {
*/
static int execSql(SQLiteDatabase db, String label, String finalSql, Object[] argArray) throws SQLException {
try {
db.execSQL(finalSql, argArray);
Integer result = execSqlCompatibly(db, finalSql, argArray);
// reflection sql method returns will >= 0, public API will return null
if (result != null && result >= 0) {
logger.trace("executing statement using reflection {} changed {} rows: {}", label, result, finalSql);
return result;
}
} catch (android.database.SQLException e) {
throw new SQLException("Problems executing " + label + " Android statement: " + finalSql, e);
}

int result;

SQLiteStatement stmt = null;
try {
// ask sqlite how many rows were just changed
Expand All @@ -236,6 +251,45 @@ static int execSql(SQLiteDatabase db, String label, String finalSql, Object[] ar
return result;
}

/**
* Use reflection first, when reflection error, use origin method without return code
* @return modified rows count
*/
private static Integer execSqlCompatibly(SQLiteDatabase db, String sql, Object[] bindArgs) {
Integer result = invokeHiddenExecSqlMethod(db, sql, bindArgs);
if (result == null) {
logger.trace("reflection failed, call origin method, sql {}", sql);
db.execSQL(sql, bindArgs);
}
return result;
}

private static Integer invokeHiddenExecSqlMethod(SQLiteDatabase db, String sql, Object[] bindArgs) {
try {
if (hiddenExecSqlMethod != null) {
Object result = hiddenExecSqlMethod.invoke(db, sql, bindArgs);
logger.trace("invoke hidden execSql method result: {}", result);
return (int) result;
} else {
logger.trace("reflection get method error");
return null;
}
} catch (InvocationTargetException | IllegalAccessException e) {
// reflection cannot work, set method null, no need invoke anymore
logger.trace("reflection invoke error");
hiddenExecSqlMethod = null;
return null;
}
}

private static Method hiddenExecSqlMethod() {
try {
return SQLiteDatabase.class.getMethod("executeSql", String.class, Object[].class);
} catch (NoSuchMethodException e) {
return null;
}
}

private void isInPrep() throws SQLException {
if (cursor != null) {
throw new SQLException("Query already run. Cannot add argument values.");
Expand Down