Skip to content
Open
Changes from 2 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,44 @@ 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) {
try {
return invokeHiddenExecSqlMethod(db, sql, bindArgs);
} catch (android.database.SQLException e) {
Comment thread
TYZRPVX marked this conversation as resolved.
Outdated
logger.trace(e, "reflection failed, call origin method, sql {}", sql);
Comment thread
TYZRPVX marked this conversation as resolved.
Outdated
db.execSQL(sql, bindArgs);
return null;
}
}

private static int invokeHiddenExecSqlMethod(SQLiteDatabase db, String sql, Object[] bindArgs) throws android.database.SQLException {
try {
if (hiddenExecSqlMethod != null) {
Object result = hiddenExecSqlMethod.invoke(db, sql, bindArgs);
logger.trace("invoke hidden execSql method result: {}", result);
return (int) result;
} else {
throw new android.database.SQLException("reflection get method error");
}
} catch (InvocationTargetException | IllegalAccessException e) {
// reflection cannot work, set method null, no need invoke anymore
Comment thread
TYZRPVX marked this conversation as resolved.
hiddenExecSqlMethod = null;
throw new android.database.SQLException("reflection invoke error", e);
Comment thread
TYZRPVX marked this conversation as resolved.
Outdated
}
}

private static Method hiddenExecSqlMethod() {
Comment thread
TYZRPVX marked this conversation as resolved.
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