Skip to content

Android, fix crash. Avoid concurrent execute update cursor in Sqlite #973

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

Merged
merged 4 commits into from
Jun 5, 2025
Merged
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
49 changes: 47 additions & 2 deletions android/src/main/java/com/genexus/db/DataStoreProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.sql.SQLException;
import java.util.Date;
import java.util.concurrent.locks.ReentrantLock;

import com.genexus.*;
import com.genexus.db.driver.DataSource;
Expand Down Expand Up @@ -164,10 +165,54 @@ public void executeBatch(int cursorIdx)
{
execute(cursorIdx, null, false);
}

static ReentrantLock lockExecute = new ReentrantLock();

public synchronized void execute(int cursorIdx, Object[] parms)
{
execute(cursorIdx, parms, true);
}
DataSource ds = getDataSourceNoException();
if(ds!=null && ds.jdbcIntegrity==false)
{
// If the JDBC integrity is disabled (XBASE_TINT), SQLIte is in autocommit mode.
// we need to lock the execute method to avoid concurrency issues.
// for example, the postExecute method (select changes()) cause exception in Android SQLite.
// it happends with execute sql statements like from diferent threads, like using procedures submit.
Cursor cursor = cursors[cursorIdx];
if (cursor instanceof UpdateCursor) // if the cursor is an UpdateCursor, we need to lock the execute method.
{
AndroidLog.debug("execute UpdateCursor cursorIdx : " + cursorIdx);
long timeStampStart = System.currentTimeMillis();
lockExecute.lock();
long timeStampLock = System.currentTimeMillis();
AndroidLog.debug("START execute UpdateCursor afterlock cursorIdx: " + cursorIdx + " Waiting time ms: " + (timeStampLock - timeStampStart));
try
{
// execute the cursor with the parameters.
execute(cursorIdx, parms, true);
}
finally
{
lockExecute.unlock();
}
long timeStampEnd = System.currentTimeMillis();
AndroidLog.debug("END execute UpdateCursor cursorIdx: " + cursorIdx+ " Execute time ms: " + (timeStampEnd - timeStampLock));
}
else
{
// if the cursor is not an UpdateCursor, we can execute it without locking.
long timeStampStart = System.currentTimeMillis();
execute(cursorIdx, parms, true);
long timeStampEnd = System.currentTimeMillis();
AndroidLog.debug("END execute cursorIdx: " + cursorIdx+ " Execute time ms: " + (timeStampEnd - timeStampStart));
}
}
else
{
// default case, we execute the cursor with the parameters.
execute(cursorIdx, parms, true);
}

}

private void execute(int cursorIdx, Object[] parms, boolean preExecute)
{
Expand Down
Loading