Skip to content

Commit

Permalink
Merge branch 'master-src' into master-rc
Browse files Browse the repository at this point in the history
CHANGES:
- Use per-db state to properly handle transactions requested on a database that is being opened (#184).
- Report an error upon attempt to close database multiple times.

TEST:
- Reproduce BUGs #204/#209
- Expand some existing scenarios
- Prepare test suite for upcoming fixes and improvements (#184/#204/#209/#210/#211/#213)
  • Loading branch information
Chris Brody committed Mar 18, 2015
2 parents 5510324 + 393e5e8 commit bf39e6b
Show file tree
Hide file tree
Showing 8 changed files with 605 additions and 160 deletions.
37 changes: 28 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Cordova/PhoneGap SQLitePlugin

Native interface to sqlite in a Cordova/PhoneGap plugin for Android/iOS/WP(8), with API similar to HTML5/[Web SQL API](http://www.w3.org/TR/webdatabase/)
Native interface to sqlite in a Cordova/PhoneGap plugin for Android/iOS/WP(8), with API similar to HTML5/[Web SQL API](http://www.w3.org/TR/webdatabase/).

License for Android & WP(8) versions: MIT or Apache 2.0

Expand Down Expand Up @@ -99,30 +99,41 @@ An [issue was reported](https://github.com/brodysoft/Cordova-SQLitePlugin/issues

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:
There is an optional workaround that simply closes and reopens the database file at the end of every transaction that is committed. The workaround is enabled by opening the database like:

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

**NOTE:** This workaround is *only* applied when using `db.transaction()` or `db.readTransaction()`, *not* applied when running `executeSql()` on the database object.

### Pre-populated database

For Android & iOS (*only*): put the database file in the `www` directory and open the database like:

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

or to disable iCloud backup:

```js
db = sqlitePlugin.openDatabase({name: "my.db", location: 2, createFromLocation: 1});
```

**IMPORTANT NOTES:**

- Put the pre-populated database file in the `www` subdirectory. This should work well with using the Cordova CLI to support both Android & iOS versions.
- The pre-populated database file name must match **exactly** the file name given in `openDatabase`. The automatic extension has been completely eliminated.
- The pre-populated database file is ignored if the database file with the same name already exists in your database file location.

**TIP:** If you don't see the data from the pre-populated database file, completely remove your app and try it again!

## Background processing

The threading model depends on which version is used:
- For Android & WP(8), one background thread per db (always);
- for iOS, background processing using a thread pool (always).
- For Android & WP(8), one background thread per db;
- for iOS, background processing using a thread pool.

# Sample with PRAGMA feature

Expand Down Expand Up @@ -195,7 +206,7 @@ function onDeviceReady() {
}
```

This case will also works with Safari (WebKit), assuming you replace window.sqlitePlugin.openDatabase with window.openDatabase.
This case will also works with Safari (WebKit), assuming you replace `window.sqlitePlugin.openDatabase` with `window.openDatabase`.

## Delete a database

Expand All @@ -207,9 +218,17 @@ window.sqlitePlugin.deleteDatabase({name: "my.db", location: 1}, successcb, erro

# Installing

**NOTE:** This plugin is now prepared to be installed using the `cordova` tool.
## Easy install with plugman tool

For Android:

plugman install --platform android --project path.to.my.project.folder --plugin https://github.com/brodysoft/Cordova-sqlcipher-adaptor

For iOS:

plugman install --platform ios --project path.to.my.project.folder --plugin https://github.com/brodysoft/Cordova-sqlcipher-adaptor

## Easy install with cordova tool
## Easy install with Cordova CLI tool

npm install -g cordova # if you don't have cordova
cordova create MyProjectFolder com.my.project MyProject && cd MyProjectFolder # if you are just starting
Expand Down
106 changes: 74 additions & 32 deletions SQLitePlugin.coffee.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# SQLitePlugin in Markdown (litcoffee)
# SQLite plugin in Markdown (litcoffee)

#### Use coffee compiler to compile this directly into Javascript

#### License for common script: MIT or Apache

# Top-level SQLitePlugin objects
# Top-level SQLite plugin objects

## root window object:

Expand All @@ -14,8 +14,19 @@

READ_ONLY_REGEX = /^\s*(?:drop|delete|insert|update|create)\s/i

# per-db state
DB_STATE_INIT = "INIT"
DB_STATE_OPEN = "OPEN"

## global(s):

# per-db map of locking and queueing
# XXX NOTE: This is NOT cleaned up when a db is closed and/or deleted.
# If the record is simply removed when a db is closed or deleted,
# it will cause some test failures and may break large-scale
# applications that repeatedly open and close the database.
# [BUG #210] TODO: better to abort and clean up the pending transaction state.
# XXX TBD this will be renamed and include some more per-db state.
txLocks = {}

## utility functions:
Expand Down Expand Up @@ -63,12 +74,14 @@
else
return fun.call this, []

## SQLitePlugin db-connection
## SQLite plugin db-connection handle

#### NOTE: there can be multipe SQLitePlugin db-connection handles per open db.

#### SQLitePlugin object is defined by a constructor function and prototype member functions:
#### SQLite plugin db connection handle object is defined by a constructor function and prototype member functions:

SQLitePlugin = (openargs, openSuccess, openError) ->
console.log "SQLitePlugin openargs: #{JSON.stringify openargs}"
# console.log "SQLitePlugin openargs: #{JSON.stringify openargs}"

if !(openargs and openargs['name'])
throw newSQLError "Cannot create a SQLitePlugin db instance without a db name"
Expand All @@ -95,17 +108,21 @@
return

SQLitePlugin::databaseFeatures = isSQLitePluginDatabase: true

# Keep track of state of open db connections
# XXX TBD this will be moved and renamed or
# combined with txLocks.
SQLitePlugin::openDBs = {}

SQLitePlugin::addTransaction = (t) ->
if !txLocks[@dbname]
txLocks[@dbname] = {
queue: []
inProgress: false
}
txLocks[@dbname].queue.push t
@startNextTransaction()
if @dbname of @openDBs && @openDBs[@dbname] isnt DB_STATE_INIT
@startNextTransaction()
return

SQLitePlugin::transaction = (fn, error, success) ->
Expand All @@ -129,43 +146,70 @@

nextTick () ->
txLock = txLocks[self.dbname]
if txLock.queue.length > 0 && !txLock.inProgress
if !txLock
# XXX TBD TODO (BUG #210/??): abort all pending transactions with error cb
return

else if txLock.queue.length > 0 && !txLock.inProgress
txLock.inProgress = true
txLock.queue.shift().start()
return

return

SQLitePlugin::open = (success, error) ->
onSuccess = () => success this
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()
# for a re-open run the success cb async so that the openDatabase return value
# can be used in the success handler as an alternative to the handler's
# db argument
nextTick =>
success @
return

else
@openDBs[@dbname] = true
cordova.exec onSuccess, error, "SQLitePlugin", "open", [ @openargs ]
opensuccesscb = =>
# NOTE: the db state is NOT stored (in @openDBs) if the db was closed or deleted.

# XXX TODO [BUG #210]:
#if !@openDBs[@dbname] then call open error cb, and abort pending tx if any

if @dbname of @openDBs
@openDBs[@dbname] = DB_STATE_OPEN
success @

txLock = txLocks[@dbname]
if !!txLock && txLock.queue.length > 0 && !txLock.inProgress
@startNextTransaction()
return

# store initial DB state:
@openDBs[@dbname] = DB_STATE_INIT

cordova.exec opensuccesscb, 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 newSQLError 'database cannot be closed while a transaction is in progress'
return

# XXX [BUG #209] closing one db handle disables other handles to same db
delete @openDBs[@dbname]

# XXX [BUG #210] TODO: when closing or deleting a db, abort any pending transactions (with error callback)
cordova.exec success, error, "SQLitePlugin", "close", [ { path: @dbname } ]

else
nextTick -> error()

return

SQLitePlugin::executeSql = (statement, params, success, error) ->
# XXX TODO: better to capture the result, and report it once
# the transaction has completely finished.
# This would fix BUG #204 (cannot close db in db.executeSql() callback).
mysuccess = (t, r) -> if !!success then success r
myerror = (t, e) -> if !!error then error e

Expand All @@ -176,11 +220,8 @@
@addTransaction new SQLitePluginTransaction(this, myfn, null, null, false, false)
return

## SQLitePluginTransaction object for batching:
## SQLite plugin transaction object for batching:

###
Transaction batching object:
###
SQLitePluginTransaction = (db, fn, error, success, txlock, readOnly) ->
if typeof(fn) != "function"
###
Expand Down Expand Up @@ -210,9 +251,7 @@
@fn this
@run()
catch err
###
If "fn" throws, we must report the whole transaction as failed.
###
# If "fn" throws, we must report the whole transaction as failed.
txLocks[@db.dbname].inProgress = false
@db.startNextTransaction()
if @error
Expand Down Expand Up @@ -254,7 +293,6 @@
qid: qid

sql: sql
#params: values || []
params: params

return
Expand Down Expand Up @@ -309,10 +347,8 @@
if txFailure
tx.abort txFailure
else if tx.executes.length > 0
###
new requests have been issued by the callback
handlers, so run another batch.
###
# new requests have been issued by the callback
# handlers, so run another batch.
tx.run()
else
tx.finish()
Expand Down Expand Up @@ -470,6 +506,7 @@
dblocation = if !!first.location then dblocations[first.location] else null
args.dblocation = dblocation || dblocations[0]

# XXX [BUG #210] TODO: when closing or deleting a db, abort any pending transactions (with error callback)
delete SQLitePlugin::openDBs[args.path]
cordova.exec success, error, "SQLitePlugin", "delete", [ args ]

Expand All @@ -482,3 +519,8 @@
openDatabase: SQLiteFactory.opendb
deleteDatabase: SQLiteFactory.deleteDb

## vim directives

#### vim: set filetype=coffee :
#### vim: set expandtab :

4 changes: 3 additions & 1 deletion plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
<header-file src="src/ios/SQLitePlugin.h" />
<source-file src="src/ios/SQLitePlugin.m" />
<framework src="libsqlite3.dylib" />

</platform>

<!-- wp8 using dlls [should work but not tested on wp7]
Expand All @@ -81,6 +82,7 @@
<source-file src="src/wp/SQLitePlugin.cs" />
<framework src="src/wp/cs-sqlite-dll/SQLiteWPNative.dll" custom="true" />
</platform>
-->

Expand Down Expand Up @@ -183,4 +185,4 @@

</platform>

</plugin>
</plugin> <!-- vim: set expandtab : -->
2 changes: 1 addition & 1 deletion src/android/org/pgsqlite/SQLitePlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -960,4 +960,4 @@ private static enum QueryType {
rollback,
other
}
}
} /* vim: set expandtab : */
2 changes: 1 addition & 1 deletion src/ios/SQLitePlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ typedef int WebSQLError;

+(NSString*)getBlobAsBase64String:(const char*) blob_chars
withlength:(int) blob_length;
@end
@end /* vim: set expandtab : */
2 changes: 1 addition & 1 deletion src/ios/SQLitePlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -586,4 +586,4 @@ +(NSString*)getBlobAsBase64String:(const char*)blob_chars
return result;
}

@end
@end /* vim: set expandtab : */
Loading

0 comments on commit bf39e6b

Please sign in to comment.