diff --git a/README.md b/README.md index 27895818a..c12d9c92e 100644 --- a/README.md +++ b/README.md @@ -120,12 +120,13 @@ See the [Sample section](#sample) for a sample with a more detailed explanation. - REGEXP support (Android/iOS) - Pre-populated database (Android/iOS/Windows) - Amazon Fire-OS is dropped due to lack of support by Cordova. Android version should be used to deploy to Fire-OS 5.0(+) devices. For reference: [cordova/cordova-discuss#32 (comment)](https://github.com/cordova/cordova-discuss/issues/32#issuecomment-167021676) -- Windows version includes a customized version of the performant C++ [doo / SQLite3-WinRT](https://github.com/doo/SQLite3-WinRT) component and has the following limitations: +- Windows version includes a customized version of the performant C++ [doo / SQLite3-WinRT](https://github.com/doo/SQLite3-WinRT) component and has the following _known_ limitations: - Issue with UNICODE `\u0000` character (same as `\0`) - No background processing - INCORRECT error code (0) and INCONSISTENT error message (missing actual error info) in error callbacks ref: [litehelpers/Cordova-sqlite-storage#539](https://github.com/litehelpers/Cordova-sqlite-storage/issues/539) - - Issue with emojis and other 4-octet UTF-8 characters (apparently not stored correctly) + - Issue with emojis and other 4-octet UTF-8 characters (apparently not stored correctly) ref: [litehelpers/Cordova-sqlite-storage#564](https://github.com/litehelpers/Cordova-sqlite-storage/issues/564) - Not possible to read BLOB column values + - Issue with `undefined` SQL parameter argument value described below - It is **not** possible to use this plugin with the default "Any CPU" target. A specific target CPU type **must** be specified when building an app with this plugin. - FTS3, FTS4, and R-Tree support is tested working OK in this version (for all target platforms in this version branch Android/iOS/Windows) - Android is supported back to SDK 10 (a.k.a. Gingerbread, Android 2.3.3); support for older versions is available upon request. @@ -320,7 +321,10 @@ As "strongly recommended" by [Web SQL Database API 8.5 SQL injection](https://ww - It is possible to request a SQL statement list such as "SELECT 1; SELECT 2" within a single SQL statement string, however the plugin will only execute the first statement and silently ignore the others ref: [litehelpers/Cordova-sqlite-storage#551](https://github.com/litehelpers/Cordova-sqlite-storage/issues/551) - It is possible to insert multiple rows like: `transaction.executeSql('INSERT INTO MyTable VALUES (?,?),(?,?)', ['Alice', 101, 'Betty', 102]);` which was not supported by SQLite 3.6.19 as referenced by [Web SQL API section 5](https://www.w3.org/TR/webdatabase/#web-sql). The iOS WebKit Web SQL implementation seems to support this as well. - Unlike the HTML5/[Web SQL API](http://www.w3.org/TR/webdatabase/) this plugin handles executeSql calls with too few parameters without error reporting. In case of too many parameters this plugin reports error code 0 (SQLError.UNKNOWN_ERR) while Android/iOS (WebKit) Web SQL correctly reports error code 5 (SQLError.SYNTAX_ERR) ref: https://www.w3.org/TR/webdatabase/#dom-sqlexception-code-syntax -- Known issue(s) with handling of `Infinity` values (positive or negative) and certain ASCII/UNICODE characters as described below. +- Issues with positive and negative `Infinity` SQL parameter argument values are treated like `null` by this plugin on Android and iOS ref: [litehelpers/Cordova-sqlite-storage#405](https://github.com/litehelpers/Cordova-sqlite-storage/issues/405) +- Positive and negative `Infinity` result values cause a crash on iOS ref: [litehelpers/Cordova-sqlite-storage#405](https://github.com/litehelpers/Cordova-sqlite-storage/issues/405) +- Windows version fails with an error in case an `undefined` SQL parameter argument value is used. +- Known issue(s) with of certain ASCII/UNICODE characters as described below. - Boolean `true` and `false` values are handled by converting them to the "true" and "false" TEXT string values, same as WebKit Web SQL on Android and iOS. This does not seem to be 100% correct as discussed in: [litehelpers/Cordova-sqlite-storage#545](https://github.com/litehelpers/Cordova-sqlite-storage/issues/545) - Certain errors such as CREATE VIRTUAL TABLE USING bogus module are reported with error code 5 (SQLError.SYNTAX_ERR) on Android and iOS. This happens to be the case for WebKit Web SQL (Android/iOS). - A number of uncategorized errors are reported with error code 5 (SQLError.SYNTAX_ERR) on Android and iOS by both WebKit Web SQL and this plugin. @@ -340,6 +344,8 @@ See **Security of sensitive data** in the [Security](#security) section above. - In case a transaction function throws an exception, the message and code if present are reported by the plugin but *not* by (WebKit) Web SQL. - SQL error messages are inconsistent on Windows. - There are some other differences in the SQL error messages reported by WebKit Web SQL and this plugin. +- `SELECT TYPEOF(?) as myresult` with integer SQL parameter argument value such as `0`, `101`, `-101`, or `1234567890123` (BIG INTEGER) returns `integer` in case of this plugin or `real` in case of (WebKit) Web SQL. However integer values are stored correctly in columns with no type affinity in case of both (WebKit) Web SQL and this plugin. +- Operations such as `SELECT ? as myresult` or `SELECT TYPEOF(?) as myresult` seems to treat `null`, `undefined`, INTEGER, REAL, +/- `Infinity`, and `NaN` parameter argument values like TEXT string values on Android in case the built-in Android database (`androidDatabaseImplementation: 2` setting) is used. However the plugin does seem to store and retrieve all such parameter argument values except for +/- `Infinity` values correctly on all platforms including Android with the `androidDatabaseImplementation: 2` setting enabled. @@ -350,7 +356,7 @@ See **Security of sensitive data** in the [Security](#security) section above. - The Android and Windows versions do not always handle four-byte UTF-8 characters emoji characters such as `\u1F603` (SMILING FACE, MOUTH OPEN) correctly ref: [litehelpers/Cordova-sqlite-storage#564](https://github.com/litehelpers/Cordova-sqlite-storage/issues/564). It is sometimes possible to store and retrieve such characters but certain operations hex conversions do not work properly with the default [Android-sqlite-connector](https://github.com/liteglue/Android-sqlite-connector) database implementation. It is suspected that such characters would be stored incorrectly in the Android and Windows versions. This is not an issue in case the built-in Android database is used (using the `androidDatabaseImplementation: 2` setting in `window.sqlitePlugin.openDatabase`) - INSERT statement that affects multiple rows (due to SELECT cause or using TRIGGER(s), for example) reports incorrect rowsAffected on Android in case the built-in Android database used (using the `androidDatabaseImplementation` option in `window.sqlitePlugin.openDatabase`) - Memory issue observed when adding a large number of records due to the JSON implementation which is improved in [litehelpers / Cordova-sqlite-evcore-extbuild-free](https://github.com/litehelpers/Cordova-sqlite-evcore-extbuild-free) (available with GPL or commercial license options) -- Infinity (positive or negative) values are not supported (known to be broken on Android, may cause a crash on iOS ref: [litehelpers/Cordova-sqlite-storage#405](https://github.com/litehelpers/Cordova-sqlite-storage/issues/405)) +- Infinity (positive or negative) values are not supported on Android or iOS due to issues described above including a possible crash on iOS ref: [litehelpers/Cordova-sqlite-storage#405](https://github.com/litehelpers/Cordova-sqlite-storage/issues/405) - A stability issue was reported on the iOS version when in use together with [SockJS](http://sockjs.org/) client such as [pusher-js](https://github.com/pusher/pusher-js) at the same time (see [litehelpers/Cordova-sqlite-storage#196](https://github.com/litehelpers/Cordova-sqlite-storage/issues/196)). The workaround is to call sqlite functions and [SockJS](http://sockjs.org/) client functions in separate ticks (using setTimeout with 0 timeout). - SQL errors are reported with an INCORRECT error code (0) on Windows ref: [litehelpers/Cordova-sqlite-storage#539](https://github.com/litehelpers/Cordova-sqlite-storage/issues/539). In certain cases SQL errors are also reported with error code 0 on Android in case the built-in Android database is used (using the `androidDatabaseImplementation: 2` setting in `window.sqlitePlugin.openDatabase`). - Possible crash on Android when using Unicode emoji _and other 4-octet UTF-8_ characters due to [Android bug 81341](https://code.google.com/p/android/issues/detail?id=81341), which *should* be fixed in Android 6.x @@ -396,7 +402,6 @@ Some more limitations are tracked in the [open Cordova-sqlite-storage documentat - location reloads and changes/multi-page apps - Use within [InAppBrowser](http://docs.phonegap.com/en/edge/cordova_inappbrowser_inappbrowser.md.html) - Use within an iframe (see [litehelpers/Cordova-sqlite-storage#368 (comment)](https://github.com/litehelpers/Cordova-sqlite-storage/issues/368#issuecomment-154046367)) -- Infinity and NaN values - Maximum record size supported - Actual behavior when using SAVEPOINT(s) - R-Tree is not fully tested with Android diff --git a/spec/www/spec/db-tx-sql-select-value-test.js b/spec/www/spec/db-tx-sql-select-value-test.js index 8eafc9ca2..cfe0c0c71 100644 --- a/spec/www/spec/db-tx-sql-select-value-test.js +++ b/spec/www/spec/db-tx-sql-select-value-test.js @@ -94,31 +94,1140 @@ var mytests = function() { }); }); - describe(suiteName + 'Infinity value manipulation results', function() { + // Truthy string + // ref: https://developer.mozilla.org/en-US/docs/Glossary/Truthy + it(suiteName + 'SELECT TYPEOF(?) with ["abc"] parameter argument', function(done) { + var db = openDatabase('SELECT-TYPEOF-with-abc-TEXT-string-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(?) as myresult', [null], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('null'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + // Falsy string + // ref: https://developer.mozilla.org/en-US/docs/Glossary/Falsy + + it(suiteName + "SELECT TYPEOF('') (INLINE empty string) parameter argument", function(done) { + var db = openDatabase('SELECT-TYPEOF-with-inline-empty-TEXT-string-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql("SELECT TYPEOF('') as myresult", null, function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe('text'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + "SELECT UPPER('') (INLINE empty string) parameter argument", function(done) { + var db = openDatabase('SELECT-UPPER-with-inline-empty-TEXT-string-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql("SELECT UPPER('') as myresult", null, function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(''); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + "SELECT '' (INLINE empty string) parameter argument", function(done) { + var db = openDatabase('SELECT-UPPER-with-inline-empty-TEXT-string-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql("SELECT '' as myresult", null, function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(''); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + // TBD for some reason on Android plugin with androidDatabaseImplementation:2 setting + // TYPEOF returns text + + it(suiteName + 'SELECT TYPEOF(?) with [null] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-TYPEOF-with-null-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(?) as myresult', [null], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('null'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ? with [null] parameter argument [returns text in case of androidDatabaseImplementation: 2; BROKEN for Windows]', function(done) { + var db = openDatabase('SELECT-with-null-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ? as myresult', [null], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe(''); + else + expect(rs.rows.item(0).myresult).toBe(null); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT TYPEOF(?) with [undefined] parameter argument [returns text in case of Android (WebKit) Web SQL or androidDatabaseImplementation: 2; BROKEN for Windows]', function(done) { + if (isWP8) pending('SKIP for WP8'); // SKIP for now + + var db = openDatabase('SELECT-TYPEOF-with-undefined-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(?) as myresult', [undefined], function(ignored, rs) { + if (isWindows) expect('Windows plugin version FIXED please update this test').toBe('--'); + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if ((isWebSql && isAndroid) || (!isWebSql && isAndroid && isImpl2)) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('null'); + done(); + }); + }, function(error) { + // ERROR in case of Windows: + if (isWindows) { + expect(error).toBeDefined(); + expect(error.code).toBeDefined(); + expect(error.message).toBeDefined(); + expect(error.code).toBe(0); + expect(error.message).toMatch(/a statement with no error handler failed: Unsupported argument type: undefined/); + return done(); + } + + // OTHERWISE + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ? with [undefined] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + if (isWP8) pending('SKIP for WP8'); // SKIP for now + + var db = openDatabase('SELECT-with-undefined-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ? as myresult', [undefined], function(ignored, rs) { + if (isWindows) expect('Windows plugin version FIXED please update this test').toBe('--'); + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (isWebSql && isAndroid) + expect(rs.rows.item(0).myresult).toBe('undefined'); + else if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe(''); + else + expect(rs.rows.item(0).myresult).toBe(null); + done(); + }); + }, function(error) { + // ERROR in case of Windows: + if (isWindows) { + expect(error).toBeDefined(); + expect(error.code).toBeDefined(); + expect(error.message).toBeDefined(); + expect(error.code).toBe(0); + expect(error.message).toMatch(/a statement with no error handler failed: Unsupported argument type: undefined/); + return done(); + } + + // OTHERWISE + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + // Truthy number values + // ref: https://developer.mozilla.org/en-US/docs/Glossary/Truthy + + // TBD for some reason Android/iOS WebKit Web SQL implementation returns + // TYPEOF(?) with integer parameter arg value as 'real' + // though it DOES apparently handle integer parameter arg value as + // an integer. + + it(suiteName + 'SELECT TYPEOF(101) INLINE', function(done) { + var db = openDatabase('SELECT-TYPEOF-101-inline.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(101) as myresult', [], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe('integer'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ABS(101) INLINE', function(done) { + var db = openDatabase('SELECT-ABS-101-inline.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ABS(101) as myresult', [], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(101); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT 101 INLINE', function(done) { + var db = openDatabase('SELECT-minus-101-inline.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT 101 as myresult', [], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(101); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT TYPEOF(-101) INLINE', function(done) { + var db = openDatabase('SELECT-TYPEOF-minus-101-inline.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(-101) as myresult', [], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe('integer'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ABS(-101) INLINE', function(done) { + var db = openDatabase('SELECT-ABS-minus-101-inline.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ABS(-101) as myresult', [], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(101); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT -101 INLINE', function(done) { + var db = openDatabase('SELECT-minus-101-inline.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT -101 as myresult', [], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(-101); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT TYPEOF(?) with [101] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-TYPEOF-with-101-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(?) as myresult', [101], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (isWebSql) + expect(rs.rows.item(0).myresult).toBe('real'); + else if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('integer'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ABS(?) with [101] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-ABS-with-101-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ABS(?) as myresult', [101], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(101); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ? with [101] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-with-101-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ? as myresult', [101], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('101'); + else + expect(rs.rows.item(0).myresult).toBe(101); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT TYPEOF(?) with [-101] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-TYPEOF-with-minus-101-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(?) as myresult', [-101], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (isWebSql) + expect(rs.rows.item(0).myresult).toBe('real'); + else if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('integer'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ABS(?) with [-101] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-ABS-with-minus-101-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ABS(?) as myresult', [-101], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(101); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ? with [-101] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-with-minus-101-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ? as myresult', [-101], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('-101'); + else + expect(rs.rows.item(0).myresult).toBe(-101); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT TYPEOF(?) with [123.456] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-TYPEOF-123.456.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(?) as myresult', [123.456], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('real'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ABS(?) with [123.456] parameter argument', function(done) { + var db = openDatabase('SELECT-ABS-123.456.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ABS(?) as myresult', [123.456], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(123.456); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ? with [123.456] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-123.456.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ? as myresult', [123.456], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('123.456'); + else + expect(rs.rows.item(0).myresult).toBe(123.456); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT TYPEOF(?) with [-123.456] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-TYPEOF-minus-123.456.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(?) as myresult', [-123.456], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('real'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ABS(?) with [-123.456] parameter argument', function(done) { + var db = openDatabase('SELECT-ABS-minus-123.456.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ABS(?) as myresult', [-123.456], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(123.456); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ? with [-123.456] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-minus-123.456.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ? as myresult', [-123.456], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('-123.456'); + else + expect(rs.rows.item(0).myresult).toBe(-123.456); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT TYPEOF(?) with [1234567890123] (BIG INTEGER) parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-TYPEOF-1234567890123.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(?) as myresult', [1234567890123], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (isWebSql) + expect(rs.rows.item(0).myresult).toBe('real'); + else if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('integer'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ABS(?) with [1234567890123] (BIG INTEGER) parameter argument', function(done) { + var db = openDatabase('SELECT-ABS-with-1234567890123-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ABS(?) as myresult', [1234567890123], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(1234567890123); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ? with [1234567890123] (BIG INTEGER) parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-with-1234567890123-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ? as myresult', [1234567890123], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('1234567890123'); + else + expect(rs.rows.item(0).myresult).toBe(1234567890123); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT TYPEOF(?) with [-1234567890123] (BIG INTEGER) parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-TYPEOF-minus-1234567890123.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(?) as myresult', [-1234567890123], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (isWebSql) + expect(rs.rows.item(0).myresult).toBe('real'); + else if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('integer'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ABS(?) with [-1234567890123] (BIG INTEGER) parameter argument', function(done) { + var db = openDatabase('SELECT-ABS-with-minus-1234567890123-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ABS(?) as myresult', [-1234567890123], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(1234567890123); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ? with [-1234567890123] (BIG INTEGER) parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-with-minus-1234567890123-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ? as myresult', [-1234567890123], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('-1234567890123'); + else + expect(rs.rows.item(0).myresult).toBe(-1234567890123); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + // Falsy number value + // ref: https://developer.mozilla.org/en-US/docs/Glossary/Falsy + + it(suiteName + 'SELECT TYPEOF(?) with [0] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-TYPEOF-with-0-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(?) as myresult', [0], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (isWebSql) + expect(rs.rows.item(0).myresult).toBe('real'); + else if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('integer'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ABS(?) with [0] parameter argument', function(done) { + var db = openDatabase('SELECT-ABS-with-0-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ABS(?) as myresult', [0], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(0); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ? with [0] parameter argument', function(done) { + var db = openDatabase('SELECT-with-0-argument.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ? as myresult', [0], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('0'); + else + expect(rs.rows.item(0).myresult).toBe(0); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT TYPEOF(?) with [0.0] parameter argument [returns text in case of androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-TYPEOF-0.0.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT TYPEOF(?) as myresult', [0.0], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (isWebSql) + expect(rs.rows.item(0).myresult).toBe('real'); + else if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('integer'); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ABS(?) with [0.0] parameter argument', function(done) { + var db = openDatabase('SELECT-ABS-0.0.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ABS(?) as myresult', [0.0], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe(0); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT ? with [0.0] parameter argument', function(done) { + var db = openDatabase('SELECT-0.0.db'); + expect(db).toBeDefined(); + + db.transaction(function(tx) { + tx.executeSql('SELECT ? as myresult', [0.0], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('0'); + else + expect(rs.rows.item(0).myresult).toBe(0); + done(); + }); + }, function(error) { + expect(false).toBe(true); + expect(error.message).toBe('--'); + done(); + }); + }, MYTIMEOUT); + + describe(suiteName + 'Infinity/NaN value test(s)', function() { + + // Android/iOS plugin BROKEN: + // - CRASH on iOS as reported in litehelpers/Cordova-sqlite-storage#405 + // - Android version returns result with missing row + it(suiteName + "SELECT ABS(?) with '9e999' (Infinity) parameter argument" + + ((!isWebSql && isAndroid) ? ' [Android PLUGIN BROKEN: result with missing row]' : ''), function(done) { + if (isWP8) pending('SKIP for WP8'); // (no callback received) + if (!isWebSql && !isAndroid && !isWindows && !isWP8) pending('SKIP for iOS plugin due to CRASH'); + + var db = openDatabase('SELECT-ABS-Infinite-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT ABS(?) AS myresult', ['9e999'], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + + if (!isWebSql && !isWindows && isAndroid) + expect(rs.rows.length).toBe(0); + else + expect(rs.rows.length).toBe(1); + + if (isWebSql || isWindows) + expect(rs.rows.item(0).myresult).toBe(Infinity); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + "SELECT -ABS(?) with '9e999' (Infinity) parameter argument" + + ((!isWebSql && isAndroid) ? ' [Android PLUGIN BROKEN: missing result]' : ''), function(done) { + if (isWP8) pending('SKIP for WP8'); // (no callback received) + if (!isWebSql && !isAndroid && !isWindows && !isWP8) pending('SKIP for iOS plugin due to CRASH'); + + var db = openDatabase('SELECT-ABS-Infinite-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT -ABS(?) AS myresult', ['9e999'], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + + if (!isWebSql && !isWindows && isAndroid) + expect(rs.rows.length).toBe(0); + else + expect(rs.rows.length).toBe(1); + + if (isWebSql || isWindows) + expect(rs.rows.item(0).myresult).toBe(-Infinity); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + "SELECT UPPER(ABS(?)) with ['9e999'] (Infinity) parameter argument (reference test)", function(done) { + var db = openDatabase('SELECT-UPPER-ABS-Infinite-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT UPPER(ABS(?)) AS myresult', ['9e999'], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + expect(rs.rows.item(0).myresult).toBe('INF'); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + "SELECT LOWER(-ABS(?)) with ['9e999'] (Infinity) parameter argument (reference test)", function(done) { + var db = openDatabase('SELECT-LOWER-minus-ABS-Infinite-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT LOWER(-ABS(?)) AS myresult', ['9e999'], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + expect(rs.rows.item(0).myresult).toBe('-inf'); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT LOWER(?) with [Infinity] parameter argument [Android/iOS Plugin BROKEN: result with null value]', function(done) { + if (isWP8) pending('SKIP for WP8'); // SKIP for now + + var db = openDatabase('SELECT-LOWER-Infinite-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT LOWER(?) AS myresult', [Infinity], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + + // Android/iOS plugin issue + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe(''); + else if (!isWebSql && !isWindows) + expect(rs.rows.item(0).myresult).toBe(null); + else + expect(rs.rows.item(0).myresult).toBe('inf'); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT UPPER(?) with [-Infinity] parameter argument [Android/iOS Plugin BROKEN: result with null value]', function(done) { + if (isWP8) pending('SKIP for WP8'); // SKIP for now + + var db = openDatabase('SELECT-UPPER-minus-Infinite-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT UPPER(?) AS myresult', [-Infinity], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + + // Android/iOS plugin issue + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe(''); + else if (!isWebSql && !isWindows) + expect(rs.rows.item(0).myresult).toBe(null); + else + expect(rs.rows.item(0).myresult).toBe('-INF'); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); - // Android/iOS plugin BROKEN: - // - CRASH on iOS as reported in litehelpers/Cordova-sqlite-storage#405 - // - Android version returns result with missing row - it(suiteName + "SELECT ABS(?) with '9e999' (Infinity) parameter argument" + - ((!isWebSql && isAndroid) ? ' [Android PLUGIN BROKEN: result with missing row]' : ''), function(done) { - if (isWP8) pending('SKIP for WP8'); // (no callback received) - if (!isWebSql && !isAndroid && !isWindows && !isWP8) pending('SKIP for iOS plugin due to CRASH'); + it(suiteName + 'SELECT TYPEOF(?) with [Infinity] parameter argument [Android/iOS Plugin BROKEN: reports null type]', function(done) { + if (isWP8) pending('SKIP for WP8'); // SKIP for now - var db = openDatabase('Infinite-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + var db = openDatabase('SELECT-TYPEOF-Infinite-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); db.transaction(function(tx) { expect(tx).toBeDefined(); - tx.executeSql('SELECT ABS(?) AS myresult', ['9e999'], function(tx, rs) { + tx.executeSql('SELECT TYPEOF(?) AS myresult', [Infinity], function(ignored, rs) { expect(rs).toBeDefined(); expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); - if (!isWebSql && !isWindows && isAndroid) - expect(rs.rows.length).toBe(0); + // Android/iOS plugin issue + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else if (!isWebSql && !isWindows) + expect(rs.rows.item(0).myresult).toBe('null'); else - expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBe('real'); - if (isWebSql || isWindows) + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT TYPEOF(?) with -Infinity parameter argument [Android/iOS Plugin BROKEN: reports null type]', function(done) { + if (isWP8) pending('SKIP for WP8'); // SKIP for now + + var db = openDatabase('SELECT-TYPEOF-minus-Infinite-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT TYPEOF(?) AS myresult', [-Infinity], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + + // Android/iOS plugin issue + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else if (!isWebSql && !isWindows) + expect(rs.rows.item(0).myresult).toBe('null'); + else + expect(rs.rows.item(0).myresult).toBe('real'); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT (?) with Infinity parameter argument [Android/iOS Plugin BROKEN: result with null value]', function(done) { + if (isWP8) pending('SKIP for WP8'); // SKIP for now + + var db = openDatabase('SELECT-Infinite-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT (?) AS myresult', [Infinity], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + + // Android/iOS plugin issue + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe(''); + else if (!isWebSql && !isWindows) + expect(rs.rows.item(0).myresult).toBe(null); + else expect(rs.rows.item(0).myresult).toBe(Infinity); // Close (plugin only) & finish: @@ -134,8 +1243,266 @@ var mytests = function() { }); }, MYTIMEOUT); + it(suiteName + 'SELECT (?) with -Infinity parameter argument [Android/iOS Plugin BROKEN: result with null value]', function(done) { + if (isWP8) pending('SKIP for WP8'); // SKIP for now + + var db = openDatabase('SELECT-minus-Infinite-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT (?) AS myresult', [-Infinity], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + + // Android/iOS plugin issue + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe(''); + else if (!isWebSql && !isWindows) + expect(rs.rows.item(0).myresult).toBe(null); + else + expect(rs.rows.item(0).myresult).toBe(-Infinity); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + // General ref: http://sqlite.1065341.n5.nabble.com/NaN-in-0-0-out-td19086.html + + it(suiteName + "Infinity/NaN reference test: SELECT ABS(?)-ABS(?) with '9e999' (Infinity) parameter argument values", function(done) { + var db = openDatabase('SELECT-ABS-minus-ABS-with-Infinite-parameter-values-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT ABS(?)-ABS(?) AS myresult', ['9e999', '9e999'], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + + expect(rs.rows.item(0).myresult).toBe(null); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'Infinity/NaN test: SELECT (?-?) with Infinity parameter argument values [Infinity/NaN ISSUE with androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-minus-with-Infinite-parameter-values-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT (?-?) AS myresult', [Infinity, Infinity], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + + // Android/iOS plugin issue + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe(0); + else + expect(rs.rows.item(0).myresult).toBe(null); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'Infinity/NaN test: SELECT (?+?) with [Infinity, -Infinity] parameter argument values [Infinity/NaN ISSUE with androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-sum-with-Infinite-and-minus-Infinity-parameter-values-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT (?+?) AS myresult', [Infinity, -Infinity], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + + // Android/iOS plugin issue + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe(0); + else + expect(rs.rows.item(0).myresult).toBe(null); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + "NaN reference test: SELECT (1/0)", function(done) { + var db = openDatabase('SELECT-1-div-0-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT (1/0) AS myresult', [], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + expect(rs.rows.item(0).myresult).toBe(null); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT UPPER(?) with NaN parameter argument value [Infinity/NaN ISSUE with androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-UPPER-with-NaN-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT UPPER(?) AS myresult', [NaN], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + + // Android/iOS plugin issue + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe(''); + else + expect(rs.rows.item(0).myresult).toBe(null); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT TYPEOF(?) with NaN parameter argument value [Infinity/NaN ISSUE with androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-TYPEOF-with-NaN-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT TYPEOF(?) AS myresult', [NaN], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + + // Android/iOS plugin issue + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe('text'); + else + expect(rs.rows.item(0).myresult).toBe('null'); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'SELECT (?) with NaN parameter argument value [Infinity/NaN ISSUE with androidDatabaseImplementation: 2]', function(done) { + var db = openDatabase('SELECT-NaN-parameter-results-test.db', '1.0', 'Test', DEFAULT_SIZE); + + db.transaction(function(tx) { + expect(tx).toBeDefined(); + + tx.executeSql('SELECT (?) AS myresult', [NaN], function(ignored, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBe(1); + expect(rs.rows.item(0).myresult).toBeDefined(); + + // Android/iOS plugin issue + if (!isWebSql && isAndroid && isImpl2) + expect(rs.rows.item(0).myresult).toBe(''); + else + expect(rs.rows.item(0).myresult).toBe(null); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + }); + it(suiteName + 'String test with array parameter value including undefined/Infinity/NaN values', function(done) { + var db = openDatabase("String-test-with-array-parameter-value.db", "1.0", "Demo", DEFAULT_SIZE); + + db.transaction(function(tx) { + + tx.executeSql('SELECT UPPER(?) AS upper_result', [['a',undefined,'b',Infinity,'c',-Infinity,'d',NaN,'e']], function(ignored, rs) { + expect(rs.rows.item(0).upper_result).toBe('A,,B,INFINITY,C,-INFINITY,D,NAN,E'); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }); + }, MYTIMEOUT); + describe(suiteName + 'Inline BLOB value SELECT result tests', function() { it(suiteName + "SELECT LOWER(X'40414243')", function(done) { diff --git a/spec/www/spec/db-tx-value-bindings-test.js b/spec/www/spec/db-tx-value-bindings-test.js index 83ff6cc60..a8159bfc7 100755 --- a/spec/www/spec/db-tx-value-bindings-test.js +++ b/spec/www/spec/db-tx-value-bindings-test.js @@ -77,7 +77,110 @@ var mytests = function() { describe(suiteName + 'transaction column value insertion test(s)', function() { - it(suiteName + "all columns should be included in result set (including 'null' columns)", function(done) { + it(suiteName + 'INSERT with null parameter argument value and check stored data', function(done) { + var db = openDatabase('INSERT-null-arg-value-and-check.db', '1.0', 'Demo', DEFAULT_SIZE); + + db.transaction(function(tx) { + tx.executeSql('DROP TABLE IF EXISTS test_table'); + tx.executeSql('CREATE TABLE IF NOT EXISTS test_table (data1, data2)', [], function(ignored1, ignored2) { + + tx.executeSql('INSERT INTO test_table VALUES (?,?)', [null, 'test-string'], function(ignored, rs1) { + + expect(rs1).toBeDefined(); + expect(rs1.rowsAffected).toBe(1); + + tx.executeSql('SELECT * FROM test_table', [], function(ignored, rs2) { + var row = rs2.rows.item(0); + + expect(row.data1).toBeNull(); + expect(row.data2).toBe('test-string'); + + tx.executeSql('SELECT TYPEOF(data1) AS t1, TYPEOF(data2) AS t2 FROM test_table', null, function(ignored, rs3) { + expect(rs3).toBeDefined(); + expect(rs3.rows).toBeDefined(); + expect(rs3.rows.length).toBe(1); + expect(rs3.rows.item(0).t1).toBe('null'); + expect(rs3.rows.item(0).t2).toBe('text'); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }); + }); + }); + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'INSERT with undefined parameter argument value (inserted as null) and check stored data [BROKEN for Windows: Unsupported argument type ERROR]', function(done) { + if (isWP8) pending('SKIP for WP8'); // SKIP for now + + var db = openDatabase('INSERT-undefined-arg-value-and-check.db', '1.0', 'Demo', DEFAULT_SIZE); + + db.transaction(function(tx) { + tx.executeSql('DROP TABLE IF EXISTS test_table'); + tx.executeSql('CREATE TABLE IF NOT EXISTS test_table (data1, data2)', [], function(ignored1, ignored2) { + + tx.executeSql('INSERT INTO test_table VALUES (?,?)', [undefined, 'test-string'], function(ignored, rs1) { + + if (isWindows) expect('Windows plugin version FIXED please update this test').toBe('--'); + + expect(rs1).toBeDefined(); + expect(rs1.rowsAffected).toBe(1); + + tx.executeSql('SELECT * FROM test_table', [], function(ignored, rs2) { + var row = rs2.rows.item(0); + + if (isWebSql && isAndroid) + expect(row.data1).toBe('undefined'); + else + expect(row.data1).toBeNull(); + expect(row.data2).toBe('test-string'); + + tx.executeSql('SELECT TYPEOF(data1) AS t1, TYPEOF(data2) AS t2 FROM test_table', null, function(ignored, rs3) { + expect(rs3).toBeDefined(); + expect(rs3.rows).toBeDefined(); + expect(rs3.rows.length).toBe(1); + if (isWebSql && isAndroid) + expect(rs3.rows.item(0).t1).toBe('text'); + else + expect(rs3.rows.item(0).t1).toBe('null'); + expect(rs3.rows.item(0).t2).toBe('text'); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }); + }); + }); + }, function(error) { + // ERROR in case of Windows: + if (isWindows) { + expect(error).toBeDefined(); + expect(error.code).toBeDefined(); + expect(error.message).toBeDefined(); + expect(error.code).toBe(0); + expect(error.message).toMatch(/a statement with no error handler failed: Unsupported argument type: undefined/); + return done(); + } + + // OTHERWISE + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + "all columns should be included in result set including id integer primary key & 'null' columns", function(done) { var db = openDatabase('all-result-columns-including-null-columns.db', '1.0', 'Demo', DEFAULT_SIZE); @@ -113,6 +216,157 @@ var mytests = function() { }); }); + it(suiteName + 'INSERT Infinity with no/NUMERIC/REAL/INTEGER/TEXT type affinity and check stored data [Android/iOS Plugin BROKEN: stored with null value]', function(done) { + if (isWP8) pending('SKIP for WP8'); // SKIP for now + + var db = openDatabase('INSERT-Infinity-and-check.db', '1.0', 'Demo', DEFAULT_SIZE); + + db.transaction(function(tx) { + tx.executeSql('DROP TABLE IF EXISTS test_table'); + tx.executeSql('CREATE TABLE test_table (data, data_num NUMERIC, data_real REAL, data_int INTEGER, data_text TEXT)', [], function(ignored1, ignored2) { + + tx.executeSql('INSERT INTO test_table VALUES (?,?,?,?,?)', [Infinity, Infinity, Infinity, Infinity, Infinity], function(ignored, res) { + + expect(res).toBeDefined(); + expect(res.rowsAffected).toBe(1); + + tx.executeSql('SELECT * FROM test_table', [], function(tx, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBeDefined(); + + var row = rs.rows.item(0); + expect(row).toBeDefined(); + + if (!isWebSql && !isWindows) { + // Android/iOS plugin issue + expect(row.data).toBe(null); + expect(row.data_num).toBe(null); + expect(row.data_real).toBe(null); + expect(row.data_int).toBe(null); + expect(row.data_text).toBe(null); + } else { + expect(row.data).toBe(Infinity); + expect(row.data_num).toBe(Infinity); + expect(row.data_real).toBe(Infinity); + expect(row.data_int).toBe(Infinity); + expect(row.data_text).toBe('Inf'); + } + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }); + + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'INSERT -Infinity with no/NUMERIC/REAL/INTEGER/TEXT type affinity and check stored data [Android/iOS Plugin BROKEN: stored with null value]', function(done) { + if (isWP8) pending('SKIP for WP8'); // SKIP for now + + var db = openDatabase('INSERT-minus-Infinity-and-check.db', '1.0', 'Demo', DEFAULT_SIZE); + + db.transaction(function(tx) { + tx.executeSql('DROP TABLE IF EXISTS test_table'); + tx.executeSql('CREATE TABLE test_table (data, data_num NUMERIC, data_real REAL, data_int INTEGER, data_text TEXT)', [], function(ignored1, ignored2) { + + tx.executeSql('INSERT INTO test_table VALUES (?,?,?,?,?)', [-Infinity, -Infinity, -Infinity, -Infinity, -Infinity], function(ignored, res) { + + expect(res).toBeDefined(); + expect(res.rowsAffected).toBe(1); + + tx.executeSql('SELECT * FROM test_table', [], function(tx, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBeDefined(); + + var row = rs.rows.item(0); + expect(row).toBeDefined(); + + if (!isWebSql && !isWindows) { + // Android/iOS plugin issue + expect(row.data).toBe(null); + expect(row.data_num).toBe(null); + expect(row.data_real).toBe(null); + expect(row.data_int).toBe(null); + expect(row.data_text).toBe(null); + } else { + expect(row.data).toBe(-Infinity); + expect(row.data_num).toBe(-Infinity); + expect(row.data_real).toBe(-Infinity); + expect(row.data_int).toBe(-Infinity); + expect(row.data_text).toBe('-Inf'); + } + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }); + + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + + it(suiteName + 'INSERT NaN with no/NUMERIC/REAL/INTEGER/TEXT type affinity and check stored data', function(done) { + + var db = openDatabase('INSERT-minus-Infinity-and-check.db', '1.0', 'Demo', DEFAULT_SIZE); + + db.transaction(function(tx) { + tx.executeSql('DROP TABLE IF EXISTS test_table'); + tx.executeSql('CREATE TABLE test_table (data, data_num NUMERIC, data_real REAL, data_int INTEGER, data_text TEXT)', [], function(ignored1, ignored2) { + + tx.executeSql('INSERT INTO test_table VALUES (?,?,?,?,?)', [NaN, NaN, NaN, NaN, NaN], function(ignored, res) { + + expect(res).toBeDefined(); + expect(res.rowsAffected).toBe(1); + + tx.executeSql('SELECT * FROM test_table', [], function(tx, rs) { + expect(rs).toBeDefined(); + expect(rs.rows).toBeDefined(); + expect(rs.rows.length).toBeDefined(); + + var row = rs.rows.item(0); + expect(row).toBeDefined(); + expect(row.data).toBe(null); + expect(row.data_num).toBe(null); + expect(row.data_real).toBe(null); + expect(row.data_int).toBe(null); + expect(row.data_text).toBe(null); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + + }); + + }); + + }, function(error) { + // NOT EXPECTED: + expect(false).toBe(true); + expect(error.message).toBe('---'); + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }, MYTIMEOUT); + // NOTE: emojis and other 4-octet UTF-8 characters apparently not stored // properly by Android-sqlite-connector/Windows ref: litehelpers/Cordova-sqlite-storage#564 it(suiteName + 'INSERT TEXT string with emoji [\\u1F603 SMILING FACE (MOUTH OPEN)], SELECT the data, and check' + @@ -194,6 +448,20 @@ var mytests = function() { // Close (plugin only) & finish: (isWebSql) ? done() : db.close(done, done); + + tx.executeSql('SELECT TYPEOF(data_text1) AS t1, TYPEOF(data_text2) AS t2, data_int AS t3, data_real AS t4', null, function(ignored, rs3) { + expect(rs3).toBeDefined(); + expect(rs3.rows).toBeDefined(); + expect(rs3.rows.length).toBe(1); + expect(rs3.rows.item(0).t1).toBe('text'); + expect(rs3.rows.item(0).t2).toBe('text'); + expect(rs3.rows.item(0).t2).toBe('integer'); + expect(rs3.rows.item(0).t2).toBe('real'); + + // Close (plugin only) & finish: + (isWebSql) ? done() : db.close(done, done); + }); + }); }); }); @@ -466,6 +734,22 @@ var mytests = function() { expect(error.code).toBeDefined(); expect(error.message).toBeDefined(); + // PLUGIN BROKEN: reports INCORRECT error code: 0 (SQLite.UNKNOWN_ERR) + // WebKit Web SQL reports correct error code: 5 (SQLite.SYNTAX_ERR) in this case. + // ref: https://www.w3.org/TR/webdatabase/#dom-sqlexception-code-syntax + if (isWebSql) + expect(error.code).toBe(5); + else + expect(error.code).toBe(0); + + // WebKit Web SQL vs plugin error message + // FUTURE TBD plugin error message subject to change + if (isWebSql) + expect(error.message).toMatch(/number of '\?'s in statement string does not match argument count/); + else if (isWindows) + expect(error.message).toMatch(/Error 25 when binding argument to SQL query/); + else + expect(error.message).toMatch(/index.*out of range/); // Close (plugin only) & finish: (isWebSql) ? done() : db.close(done, done);