private int ExecSQL(string sql, sqlite3 db, params object[] paramArgs) { var t = Factory.StartNew(()=> { sqlite3_stmt command = null; try { command = BuildCommand(db, sql, paramArgs); LastErrorCode = command.step(); if (LastErrorCode == SQLiteResult.ERROR) { throw new CouchbaseLiteException("SQLite error: " + raw.sqlite3_errmsg(db), StatusCode.DbError); } } catch (ugly.sqlite3_exception e) { Log.E(TAG, "Error {0}, {1} ({2}) executing sql '{3}'".Fmt(e.errcode, db.extended_errcode(), raw.sqlite3_errmsg(db), sql), e); LastErrorCode = e.errcode; throw new CouchbaseLiteException(String.Format("Error executing sql '{0}'", sql), e) { Code = StatusCode.DbError }; } finally { if(command != null) { command.Dispose(); } } }, _cts.Token); try { //FIXME.JHB: This wait should be optional (API change) t.Wait(30000, _cts.Token); } catch (AggregateException ex) { throw ex.InnerException; } catch (OperationCanceledException) { //Closing the storage engine will cause the factory to stop processing, but still //accept new jobs into the scheduler. If execution has gotten here, it means that //ExecSQL was called after Close, and the job will be ignored. Might consider //subclassing the factory to avoid this awkward behavior Log.D(TAG, "StorageEngine closed, canceling operation"); return 0; } if (t.Status != TaskStatus.RanToCompletion) { Log.E(TAG, "ExecSQL timed out waiting for Task #{0}", t.Id); throw new CouchbaseLiteException("ExecSQL timed out", StatusCode.InternalServerError); } return db.changes(); }
private int ExecSQL(string sql, sqlite3 db, params object[] paramArgs) { Log.To.TaskScheduling.V(TAG, "Scheduling ExecSQL"); var t = Factory.StartNew(()=> { Log.To.TaskScheduling.V(TAG, "Running ExecSQL"); sqlite3_stmt command = null; try { command = BuildCommand(db, sql, paramArgs); LastErrorCode = command.step(); if (LastErrorCode == raw.SQLITE_ERROR) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.DbError, TAG, "SQLite error in ExecSQL: {0}", raw.sqlite3_errmsg(db)); } } catch (ugly.sqlite3_exception e) { Log.To.Database.E(TAG, String.Format("Error {0}, {1} ({2}) executing sql '{3}'", e.errcode, db.extended_errcode(), raw.sqlite3_errmsg(db), sql), e); LastErrorCode = e.errcode; throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.DbError, TAG, "Error {0}, {1} ({2}) executing sql '{3}'", e.errcode, db.extended_errcode(), raw.sqlite3_errmsg(db), sql); } finally { if(command != null) { command.Dispose(); } } }, _cts.Token); try { t.Wait(_cts.Token); } catch (AggregateException ex) { throw ex.InnerException; } catch (OperationCanceledException) { //Closing the storage engine will cause the factory to stop processing, but still //accept new jobs into the scheduler. If execution has gotten here, it means that //ExecSQL was called after Close, and the job will be ignored. Might consider //subclassing the factory to avoid this awkward behavior Log.To.Database.I(TAG, "StorageEngine closed, canceling operation"); return 0; } return db.changes(); }