Skip to content

Commit 7df77fc

Browse files
authored
Android, fix crash. Avoid concurrent execute update cursor in Sqlite (#973)
Crash en app de Novartis con Sqlite en proc getpages2 https://issues.genexus.dev/viewissue.aspx?204648
1 parent ee4c52b commit 7df77fc

File tree

1 file changed

+47
-2
lines changed

1 file changed

+47
-2
lines changed

android/src/main/java/com/genexus/db/DataStoreProvider.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.sql.SQLException;
44
import java.util.Date;
5+
import java.util.concurrent.locks.ReentrantLock;
56

67
import com.genexus.*;
78
import com.genexus.db.driver.DataSource;
@@ -164,10 +165,54 @@ public void executeBatch(int cursorIdx)
164165
{
165166
execute(cursorIdx, null, false);
166167
}
168+
169+
static ReentrantLock lockExecute = new ReentrantLock();
170+
167171
public synchronized void execute(int cursorIdx, Object[] parms)
168172
{
169-
execute(cursorIdx, parms, true);
170-
}
173+
DataSource ds = getDataSourceNoException();
174+
if(ds!=null && ds.jdbcIntegrity==false)
175+
{
176+
// If the JDBC integrity is disabled (XBASE_TINT), SQLIte is in autocommit mode.
177+
// we need to lock the execute method to avoid concurrency issues.
178+
// for example, the postExecute method (select changes()) cause exception in Android SQLite.
179+
// it happends with execute sql statements like from diferent threads, like using procedures submit.
180+
Cursor cursor = cursors[cursorIdx];
181+
if (cursor instanceof UpdateCursor) // if the cursor is an UpdateCursor, we need to lock the execute method.
182+
{
183+
AndroidLog.debug("execute UpdateCursor cursorIdx : " + cursorIdx);
184+
long timeStampStart = System.currentTimeMillis();
185+
lockExecute.lock();
186+
long timeStampLock = System.currentTimeMillis();
187+
AndroidLog.debug("START execute UpdateCursor afterlock cursorIdx: " + cursorIdx + " Waiting time ms: " + (timeStampLock - timeStampStart));
188+
try
189+
{
190+
// execute the cursor with the parameters.
191+
execute(cursorIdx, parms, true);
192+
}
193+
finally
194+
{
195+
lockExecute.unlock();
196+
}
197+
long timeStampEnd = System.currentTimeMillis();
198+
AndroidLog.debug("END execute UpdateCursor cursorIdx: " + cursorIdx+ " Execute time ms: " + (timeStampEnd - timeStampLock));
199+
}
200+
else
201+
{
202+
// if the cursor is not an UpdateCursor, we can execute it without locking.
203+
long timeStampStart = System.currentTimeMillis();
204+
execute(cursorIdx, parms, true);
205+
long timeStampEnd = System.currentTimeMillis();
206+
AndroidLog.debug("END execute cursorIdx: " + cursorIdx+ " Execute time ms: " + (timeStampEnd - timeStampStart));
207+
}
208+
}
209+
else
210+
{
211+
// default case, we execute the cursor with the parameters.
212+
execute(cursorIdx, parms, true);
213+
}
214+
215+
}
171216

172217
private void execute(int cursorIdx, Object[] parms, boolean preExecute)
173218
{

0 commit comments

Comments
 (0)