juanchinovas/nativescript-sqlite-access

Hang on `SELECT * FROM table` on iOS, if table is empty

bgohsman opened this issue · 1 comments

  • Make sure to check the demo app(s) for sample usage
  • Make sure to check the existing issues in this repository
  • If the demo apps cannot help and there is no issue for your problem, tell us about it. Please, ensure your title is less than 63 characters long and starts with a capital
    letter.

Which platform(s) does your issue occur on?

  • iOS/Android/Both
  • iOS/Android versions
  • emulator or device. What type of device?

Please, provide the following version numbers that your issue occurs with:

  • CLI: 6.5.0
  • Cross-platform modules: 6.5.0
  • Runtime(s): 6.5.0
  • Plugin(s):
"dependencies": {
    "@nativescript/theme": "^2.2.1",
    "axios": "^0.19.1",
    "binary-parser": "^1.5.0",
    "ml-regression": "^5.0.0",
    "nativescript-app-environment": "^1.0.0",
    "nativescript-audio": "^5.0.5",
    "nativescript-bluetooth": "^3.0.0-beta.10",
    "nativescript-fancyalert": "^3.0.9",
    "nativescript-geolocation": "^5.1.0",
    "nativescript-iqkeyboardmanager": "^1.5.1",
    "nativescript-permissions": "^1.3.8",
    "nativescript-picker": "^2.1.2",
    "nativescript-socketio": "^3.3.1",
    "nativescript-sqlite-access": "^1.0.3",
    "nativescript-toasty": "^2.0.1",
    "nativescript-ui-gauge": "^6.0.0",
    "nativescript-ui-listview": "^8.0.1",
    "nativescript-vue": "^2.4.0",
    "tns-core-modules": "^6.5.0",
    "vuex": "^3.1.2"
  }
"devDependencies": {
    "@babel/core": "^7.7.5",
    "@babel/preset-env": "^7.7.6",
    "@types/binary-parser": "^1.3.1",
    "@types/node": "^12.12.16",
    "@typescript-eslint/eslint-plugin": "^2.10.0",
    "@typescript-eslint/parser": "^2.10.0",
    "babel-loader": "^8.0.6",
    "eslint": "^6.7.2",
    "eslint-config-prettier": "^6.7.0",
    "eslint-loader": "^3.0.2",
    "eslint-plugin-prettier": "^3.1.1",
    "eslint-plugin-react": "^7.17.0",
    "eslint-plugin-react-hooks": "^2.3.0",
    "eslint-plugin-vue": "^6.0.1",
    "nativescript-dev-webpack": "^1.4.0",
    "nativescript-vue-template-compiler": "^2.4.0",
    "nativescript-worker-loader": "~0.10.0",
    "node-sass": "^4.13.1",
    "prettier": "^1.19.1",
    "tns-platform-declarations": "^6.5.0",
    "typescript": "3.7.3",
    "vue": "^2.6.11",
    "vue-eslint-parser": "^7.0.0",
    "vue-loader": "^15.8.3"
  }

Please, tell us how to recreate the issue in as much detail as possible.

Describe the steps to reproduce it.

  • In the demo app, call the reload() method prior to inserting any records in the table
  • Build/run for iOS (emulator or device) and the app will appear to hang

Is there any code involved?

I tracked this issue to the do/while loop within __processCursor() in sqlite-access.ios.js on line#111.

function __processCursor(cursorRef, returnType, reduceFn) {
    var result = reduceFn && {} || [];
    do {
        if (reduceFn) {
            result = reduceFn(result, __getRowValues(cursorRef, returnType));
            continue;
        }
        result.push(__getRowValues(cursorRef, returnType));
    } while (sqlite3_step(cursorRef) !== 101);
    sqlite3_finalize(cursorRef);
    return result;
}

With no records in the table, __getRowValues() will still return an object where every column has null values. That object gets pushed into result[] and while checks the outcome of sqlite3_step(cursorRef) for a value of 101. However, the value is 21 (SQLITE_MISUSE). So the do/while infinitely pushes empty objects into result[] and __processCursor() never returns.

Potential Solution
SQLite has a lot of return types. Checking for all of them would be a bit of a nightmare. But perhaps checking for the most common failure points would be good here. 21 is a bit of an outlier as it only throws a log warning and doesn't halt execution, so things just keep running until you run out of system resources. It's such a soft/quiet warning that it took a while to even know it was happening. I couldn't even see the log warnings until I built/ran the app from directly within Xcode. The NativeScript debugger doesn't show them.

Interim Workaround
In the mean time, I wrapped the call to reload(), in my code, with an initial call to get the number of records in the table:

select('SELECT COUNT(ALL) from mytable', null)

If the count is zero, I don't proceed. If there are 1 or more records, then I know it is safe to select all.

This issue was fixed in the version v1.0.4 and v1.05.