Skip to content

Commit

Permalink
Merge branch 'common-src' into master-src
Browse files Browse the repository at this point in the history
Fixes:
- #193: workaround for Android db locking/closing issue
- #144: convert array parameters to string to match Web SQL
- #199: fix double-precision REAL values in result for iOS version
- #150/#153: close Android db before removing from map
- Fix truncation in iOS query result in case of UNICODE NULL (\0 or \u0000) (ref: PR #170)
- Some fixes for error handling to be consistent with Web SQL (ref: PR #170)

Testing ONLY:
- #147: testing with UNICODE line separator
- #195: Reproduce issue with double-precision REAL number on WP(8) ONLY
  • Loading branch information
Chris Brody committed Mar 10, 2015
2 parents 829fd9c + 364ce55 commit 45112b8
Show file tree
Hide file tree
Showing 7 changed files with 591 additions and 303 deletions.
31 changes: 19 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ License for iOS version: MIT only

## Status

- Please use the [Cordova-SQLitePlugin forum](http://groups.google.com/group/Cordova-SQLitePlugin) or [raise a new issue](https://github.com/brodysoft/Cordova-SQLitePlugin/issues/new) for community support
- SQLCipher integration is not supported by this project, will be supported in a separate project.
- SQLCipher integration is not supported by this project, to be supported in a separate project.

## Announcements

Expand Down Expand Up @@ -46,6 +45,7 @@ License for iOS version: MIT only
- The db version, display name, and size parameter values are not supported and will be ignored.
- The sqlite plugin will not work before the callback for the "deviceready" event has been fired, as described in **Usage**.
- The Android version cannot work with more than 100 open db files due to its threading model.
- UNICODE line separator (`\u2028`) is currently not supported and known to be broken in iOS version.

## Limited support (testing needed)

Expand Down Expand Up @@ -86,6 +86,20 @@ function onDeviceReady() {

**NOTE:** The database file name should include the extension, if desired.

### Workaround for Android db locking issue

An [issue was reported](https://github.com/brodysoft/Cordova-SQLitePlugin/issues/193), as observed by several people that on some newer versions of the Android, if the app is stopped or aborted without closing the db then:
- (sometimes) there is an unexpected db lock
- the data that was inserted before is lost.

It is suspected that this issue is caused by [this Android sqlite commit](https://github.com/android/platform_external_sqlite/commit/d4f30d0d1544f8967ee5763c4a1680cb0553039f), which references and includes the sqlite commit at: http://www.sqlite.org/src/info/6c4c2b7dba

The workaround is enabled by opening the database like:

```js
var db = window.sqlitePlugin.openDatabase({name: "my.db", androidLockWorkaround: 1});
```

### Pre-populated database

For Android & iOS (*only*): put the database file in the `www` directory and open the database like:
Expand Down Expand Up @@ -356,20 +370,13 @@ If you still cannot get something to work:
- if the issue is with *adding* data to a table, that the test program includes the statements you used to open the database and create the table;
- if the issue is with *retrieving* data from a table, that the test program includes the statements you used to open the database, create the table, and enter the data you are trying to retrieve.

Then you can post the issue to the [Cordova-SQLitePlugin forum](http://groups.google.com/group/Cordova-SQLitePlugin) or [raise a new issue](https://github.com/brodysoft/Cordova-SQLitePlugin/issues/new).
Then you can [raise the new issue](https://github.com/brodysoft/Cordova-SQLitePlugin/issues/new).

## Community forum

If you have any questions about the plugin please post it to the [Cordova-SQLitePlugin forum](http://groups.google.com/group/Cordova-SQLitePlugin).

## Support priorities

**High priority:**

1. Stability is first: immediate resolution or workaround for stability issues (crashing) is the goal.
2. Correctness: any issue with correctness should result in a new testcase together with the bug fix.

**Low priority:** issues with the API or application integration will be given lower priority until the Cordova 3.0 integration is finished for Windows Phone 8. Pull requests are very welcome for these kinds of issues.
**NOTE:** Please report all bugs at [brodysoft / Cordova-SQLitePlugin / issues](https://github.com/brodysoft/Cordova-SQLitePlugin/issues) so they can be tracked properly.

# Unit tests

Expand Down Expand Up @@ -442,7 +449,7 @@ The adapter is now part of [PouchDB](http://pouchdb.com/) thanks to [@nolanlawso
**IMPORTANT NOTE:** It is better to push your change(s) from a separate branch. Sometimes they need to be reworked before acceptance. Otherwise your `master` branch could become a real mess if rework is needed.

- Testimonials of apps that are using this plugin would be especially helpful.
- Reporting issues to the [Cordova-SQLitePlugin forum](http://groups.google.com/group/Cordova-SQLitePlugin) can help improve the quality of this plugin.
- Reporting issues at [brodysoft / Cordova-SQLitePlugin / issues](https://github.com/brodysoft/Cordova-SQLitePlugin/issues) can help improve the quality of this plugin.
- Patches with bug fixes are helpful, especially when submitted with test code.
- Other enhancements welcome for consideration, when submitted with test code and will work for all supported platforms. Increase of complexity should be avoided.
- All contributions may be reused by [@brodybits (Chris Brody)](https://github.com/brodybits) under another license in the future. Efforts will be taken to give credit for major contributions but it will not be guaranteed.
Expand Down
102 changes: 77 additions & 25 deletions SQLitePlugin.coffee.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,29 @@
## utility functions:

# Errors returned to callbacks must conform to `SqlError` with a code and message.
# Some errors are of type `Error` or `string` and must be converted.
newSQLError = (error, code) ->
sqlError = error
code = 0 if !code # unknown by default
if !sqlError
sqlError = new Error "a plugin had an error but provided no response"
sqlError.code = code
if typeof sqlError is "string"
sqlError = new Error error
sqlError.code = code
if !sqlError.code && sqlError.message
sqlError.code = code
if !sqlError.code && !sqlError.message
sqlError = new Error "an unknown error was returned: " + JSON.stringify(sqlError)
sqlError.code = code
return sqlError
nextTick = window.setImmediate || (fun) ->
window.setTimeout(fun, 0)
return
Expand Down Expand Up @@ -48,7 +71,7 @@
console.log "SQLitePlugin openargs: #{JSON.stringify openargs}"
if !(openargs and openargs['name'])
throw new Error("Cannot create a SQLitePlugin instance without a db name")
throw newSQLError "Cannot create a SQLitePlugin db instance without a db name"
dbname = openargs.name
Expand Down Expand Up @@ -87,15 +110,17 @@
SQLitePlugin::transaction = (fn, error, success) ->
if !@openDBs[@dbname]
error('database not open')
error newSQLError 'database not open'
return
@addTransaction new SQLitePluginTransaction(this, fn, error, success, true, false)
return
SQLitePlugin::readTransaction = (fn, error, success) ->
if !@openDBs[@dbname]
error('database not open')
error newSQLError 'database not open'
return
@addTransaction new SQLitePluginTransaction(this, fn, error, success, true, true)
return
Expand All @@ -112,24 +137,26 @@
SQLitePlugin::open = (success, error) ->
onSuccess = () => success this
unless @dbname of @openDBs
@openDBs[@dbname] = true
cordova.exec onSuccess, error, "SQLitePlugin", "open", [ @openargs ]
else
if @dbname of @openDBs
###
for a re-open run onSuccess async so that the openDatabase return value
can be used in the success handler as an alternative to the handler's
db argument
###
nextTick () -> onSuccess();
nextTick () -> onSuccess()
else
@openDBs[@dbname] = true
cordova.exec onSuccess, error, "SQLitePlugin", "open", [ @openargs ]
return
SQLitePlugin::close = (success, error) ->
#console.log "SQLitePlugin.prototype.close"
if @dbname of @openDBs
if txLocks[@dbname] && txLocks[@dbname].inProgress
error(new Error('database cannot be closed while a transaction is in progress'))
error newSQLError 'database cannot be closed while a transaction is in progress'
return
delete @openDBs[@dbname]
Expand All @@ -143,7 +170,7 @@
myerror = (t, e) -> if !!error then error e
myfn = (tx) ->
tx.executeSql(statement, params, mysuccess, myerror)
tx.addStatement(statement, params, mysuccess, myerror)
return
@addTransaction new SQLitePluginTransaction(this, myfn, null, null, false, false)
Expand All @@ -162,7 +189,7 @@
prevents us from stalling our txQueue if somebody passes a
false value for fn.
###
throw new Error("transaction expected a function")
throw newSQLError "transaction expected a function"
@db = db
@fn = fn
Expand All @@ -173,8 +200,8 @@
@executes = []
if txlock
@executeSql "BEGIN", [], null, (tx, err) ->
throw new Error("unable to begin transaction: " + err.message)
@addStatement "BEGIN", [], null, (tx, err) ->
throw newSQLError "unable to begin transaction: " + err.message, err.code
return
Expand All @@ -189,25 +216,46 @@
txLocks[@db.dbname].inProgress = false
@db.startNextTransaction()
if @error
@error err
@error newSQLError err
return
SQLitePluginTransaction::executeSql = (sql, values, success, error) ->
if @finalized
throw {message: 'InvalidStateError: DOM Exception 11: This transaction is already finalized. Transactions are committed after its success or failure handlers are called. If you are using a Promise to handle callbacks, be aware that implementations following the A+ standard adhere to run-to-completion semantics and so Promise resolution occurs on a subsequent tick and therefore after the transaction commits.', code: 11}
return
if @readOnly && READ_ONLY_REGEX.test(sql)
@handleStatementFailure(error, {message: 'invalid sql for a read-only transaction'})
return
@addStatement(sql, values, success, error)
return
# This method adds the SQL statement to the transaction queue but does not check for
# finalization since it is used to execute COMMIT and ROLLBACK.
SQLitePluginTransaction::addStatement = (sql, values, success, error) ->
qid = @executes.length
params = []
if !!values && values.constructor == Array
for v in values
t = typeof v
params.push (
if v == null || v == undefined || t == 'number' || t == 'string' then v
else if v instanceof Blob then v.valueOf()
else v.toString()
)
@executes.push
success: success
error: error
qid: qid
sql: sql
params: values || []
#params: values || []
params: params
return
Expand All @@ -232,9 +280,9 @@
SQLitePluginTransaction::handleStatementFailure = (handler, response) ->
if !handler
throw new Error "a statement with no error handler failed: " + response.message
if handler(this, response)
throw new Error "a statement error callback did not return false"
throw newSQLError "a statement with no error handler failed: " + response.message, response.code
if handler(this, response) isnt false
throw newSQLError "a statement error callback did not return false: " + response.message, response.code
return
SQLitePluginTransaction::run = ->
Expand All @@ -252,9 +300,10 @@
if didSucceed
tx.handleStatementSuccess batchExecutes[index].success, response
else
tx.handleStatementFailure batchExecutes[index].error, response
tx.handleStatementFailure batchExecutes[index].error, newSQLError(response)
catch err
txFailure = err unless txFailure
if !txFailure
txFailure = newSQLError(err)
if --waiting == 0
if txFailure
Expand Down Expand Up @@ -323,13 +372,13 @@
failed = (tx, err) ->
txLocks[tx.db.dbname].inProgress = false
tx.db.startNextTransaction()
if tx.error then tx.error new Error("error while trying to roll back: " + err.message)
if tx.error then tx.error newSQLError("error while trying to roll back: " + err.message, err.code)
return
@finalized = true
if @txlock
@executeSql "ROLLBACK", [], succeeded, failed
@addStatement "ROLLBACK", [], succeeded, failed
@run()
else
succeeded(tx)
Expand All @@ -349,13 +398,13 @@
failed = (tx, err) ->
txLocks[tx.db.dbname].inProgress = false
tx.db.startNextTransaction()
if tx.error then tx.error new Error("error while trying to commit: " + err.message)
if tx.error then tx.error newSQLError("error while trying to commit: " + err.message, err.code)
return
@finalized = true
if @txlock
@executeSql "COMMIT", [], succeeded, failed
@addStatement "COMMIT", [], succeeded, failed
@run()
else
succeeded(tx)
Expand Down Expand Up @@ -401,6 +450,9 @@
if !!openargs.createFromLocation and openargs.createFromLocation == 1
openargs.createFromResource = "1"
if !!openargs.androidLockWorkaround and openargs.androidLockWorkaround == 1
openargs.androidLockWorkaround = 1
new SQLitePlugin openargs, okcb, errorcb
deleteDb: (first, success, error) ->
Expand All @@ -413,7 +465,7 @@
else
#console.log "delete db args: #{JSON.stringify first}"
if !(first and first['name']) then throw new Error("Please specify db name")
if !(first and first['name']) then throw new Error "Please specify db name"
args.path = first.name
dblocation = if !!first.location then dblocations[first.location] else null
args.dblocation = dblocation || dblocations[0]
Expand Down
Loading

0 comments on commit 45112b8

Please sign in to comment.