diff --git a/.eslintrc.js b/.eslintrc.js index 08043675f..2303c3d4b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,6 +1,7 @@ module.exports = { "extends": "eslint:recommended", "env": { + "es2017": true, "node": true }, "rules": { @@ -9,4 +10,4 @@ module.exports = { "semi": ["error", "always"], "no-cond-assign": ["error", "always"] } -} +}; diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 000000000..b007fcc27 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,14 @@ +# Contributing + +General guidelines for contributing to node-sqlite3 + +## Install Help + +If you've landed here due to a failed install of `node-sqlite3` then feel free to create a [new issue](https://github.com/tryghost/node-sqlite3/issues/new) to ask for help. The most likely problem is that we do not yet provide pre-built binaries for your particular platform and so the `node-sqlite3` install attempted a source compile but failed because you are missing the [dependencies for node-gyp](https://github.com/nodejs/node-gyp#installation). Provide as much detail on your problem as possible and we'll try to help. Include: + + - Logs of failed install (preferably from running `npm install sqlite3 --loglevel=info`) + - Version of `node-sqlite3` you tried to install + - Node version you are running + - Operating system and architecture you are running, e.g. `Windows 7 64 bit`. + +The release process is documented in the wiki: https://github.com/TryGhost/node-sqlite3/wiki/Release-process diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..52634368b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,50 @@ +name: 🐛 Bug report +description: Report a reproducible issue +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + ## Welcome 👋 + Thank you for taking the time to fill out a bug report 🙂 + + The more information you provide, the easier & quicker it is for us to diagnose the problem. + + Please search the existing issues and recent releases to make sure your problem hasn't already been solved. + - type: textarea + id: summary + attributes: + label: Issue Summary + description: Explain what's wrong + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Steps to Reproduce + description: Also tell us, what did you expect to happen? + placeholder: | + 1. This is the first step... + 2. This is the second step, etc. + validations: + required: true + - type: input + id: version + attributes: + label: Version + description: What version of `node-sqlite3` are you using? + validations: + required: true + - type: input + id: node + attributes: + label: Node.js Version + validations: + required: true + - type: input + id: os + attributes: + label: How did you install the library? + description: Provide details of your operating system and architecture + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..729470a7d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: 📖 API documentation + url: https://github.com/TryGhost/node-sqlite3/wiki/API + about: Documentation for the `node-sqlite3` API diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..00d389139 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,27 @@ +name: ✨ Feature request +description: Request a desired feature +labels: ["feature request"] +body: + - type: markdown + attributes: + value: | + ## Welcome 👋 + Thank you for taking the time to fill out a feature request + + The more information you provide, the easier it is for us to understand your use case. + - type: textarea + id: summary + attributes: + label: Summary + description: Explain your use case. How would this improve your life? + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Proposed implementation + description: Give an API proposal. How would the feature work? + placeholder: | + The Database class has a new function called... + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/install_problem.yml b/.github/ISSUE_TEMPLATE/install_problem.yml new file mode 100644 index 000000000..66d6e3279 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/install_problem.yml @@ -0,0 +1,48 @@ +name: ⚙️ Installation problem +description: Report an issue installing the library +labels: ["install problem"] +body: + - type: markdown + attributes: + value: | + ## Welcome 👋 + Thank you for taking the time to fill out a report with installing 🙂 + + The more information you provide, the easier & quicker it is for us to diagnose the problem. + + Please search the existing issues and recent releases to make sure your problem hasn't already been solved. + - type: textarea + id: summary + attributes: + label: Issue Summary + description: Explain what's wrong + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant logs or output + placeholder: | + Error when installing `sqlite3` due to... + validations: + required: true + - type: input + id: version + attributes: + label: Version + description: What version of `node-sqlite3` are you using? + validations: + required: true + - type: input + id: node + attributes: + label: Node.js Version + validations: + required: true + - type: input + id: os + attributes: + label: How did you install the library? + description: Provide details of your operating system and architecture + validations: + required: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..35a44a39a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,171 @@ +name: CI +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + - grist-main + - grist-main-dev + tags: + - '*' +env: + FORCE_COLOR: 1 +concurrency: + group: ${{ github.head_ref || github.run_id }} + cancel-in-progress: true +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - macos-latest + - ubuntu-20.04 + - windows-latest + host: + - x64 + target: + - x64 + node: + - 14 + - 16 + - 18 + include: + - os: windows-latest + node: 16 + host: x86 + target: x86 + # This is a self-hosted runner, github doesn't have this architecture yet. + - os: macos-m1 + node: 16 + host: arm64 + target: arm64 + name: ${{ matrix.os }} (node=${{ matrix.node }}, host=${{ matrix.host }}, target=${{ matrix.target }}) + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + architecture: ${{ matrix.host }} + + - name: Add yarn (self-hosted) + if: matrix.os == 'macos-m1' + run: npm install -g yarn + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1.1 + if: contains(matrix.os, 'windows') + with: + msbuild-architecture: ${{ matrix.target }} + + - name: Install dependencies + run: yarn install --ignore-scripts + + - name: Add env vars + shell: bash + run: | + echo "V=1" >> $GITHUB_ENV + + if [ "${{ matrix.target }}" = "x86" ]; then + echo "TARGET=ia32" >> $GITHUB_ENV + else + echo "TARGET=${{ matrix.target }}" >> $GITHUB_ENV + fi + + - name: Add Linux env vars + if: contains(matrix.os, 'ubuntu') + run: | + echo "CFLAGS=${CFLAGS:-} -include ../src/gcc-preinclude.h" >> $GITHUB_ENV + echo "CXXFLAGS=${CXXFLAGS:-} -include ../src/gcc-preinclude.h" >> $GITHUB_ENV + + - name: Configure build + run: yarn node-pre-gyp configure --target_arch=${{ env.TARGET }} + + - name: Build binaries + run: yarn node-pre-gyp build --target_arch=${{ env.TARGET }} + + - name: Print binary info + if: contains(matrix.os, 'ubuntu') + run: | + ldd lib/binding/*/node_sqlite3.node + echo "---" + nm lib/binding/*/node_sqlite3.node | grep "GLIBC_" | c++filt || true + echo "---" + file lib/binding/napi-v*/* + + - name: Run tests + run: yarn test + + - name: Package prebuilt binaries + run: yarn node-pre-gyp package --target_arch=${{ env.TARGET }} + + - name: Upload binaries to commit artifacts + uses: actions/upload-artifact@v3 + if: matrix.node == 16 + with: + name: prebuilt-binaries + path: build/stage/*/* + retention-days: 7 + + - name: Upload binaries to GitHub Release + run: yarn node-pre-gyp-github publish + if: matrix.node == 16 && startsWith(github.ref, 'refs/tags/') + env: + NODE_PRE_GYP_GITHUB_TOKEN: ${{ github.token }} + build-qemu: + runs-on: ubuntu-latest + if: github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/') + strategy: + fail-fast: false + matrix: + node: + - 16 + target: + - linux/arm64 + variant: + - bullseye + - alpine3.15 + include: + # musl x64 builds + - target: linux/amd64 + variant: alpine3.15 + node: 16 + name: ${{ matrix.variant }} (node=${{ matrix.node }}, target=${{ matrix.target }}) + steps: + - uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build binaries and test + run: | + docker buildx build \ + --file ./tools/BinaryBuilder.Dockerfile \ + --load \ + --tag sqlite-builder \ + --platform ${{ matrix.target }} \ + --no-cache \ + --build-arg VARIANT=${{ matrix.variant }} \ + --build-arg NODE_VERSION=${{ matrix.node }} \ + . + CONTAINER_ID=$(docker create -it sqlite-builder) + docker cp $CONTAINER_ID:/usr/src/build/build/ ./build + + - name: Upload binaries to commit artifacts + uses: actions/upload-artifact@v3 + if: matrix.node == 16 + with: + name: prebuilt-binaries + path: build/stage/*/* + retention-days: 7 + + - name: Upload binaries to GitHub Release + run: yarn install --ignore-scripts && yarn node-pre-gyp-github publish + if: matrix.node == 16 && startsWith(github.ref, 'refs/tags/') + env: + NODE_PRE_GYP_GITHUB_TOKEN: ${{ github.token }} diff --git a/.gitignore b/.gitignore index 7990d97d5..3a26475cb 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,9 @@ test/nw/app.nw .dtps local.env .mason -.eslintrc.js setup.sh /build-tmp-napi-v3 +/build-tmp-napi-v6 +*.tgz +package-lock.json +yarn.lock diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 05b181283..000000000 --- a/.npmignore +++ /dev/null @@ -1,20 +0,0 @@ -.gitignore -.npmignore -node_modules -lib/binding -build -test -benchmark -configure -Makefile -scripts -.travis.yml -examples -.dtps -local.env -.mason -.eslintrc.js -setup.sh -cloudformation/ci.template.js -appveyor.yml -.vscode \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3a506145b..000000000 --- a/.travis.yml +++ /dev/null @@ -1,178 +0,0 @@ -sudo: false - -language: generic - -dist: precise - -git: - depth: 10 - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.5 - packages: - - clang-3.5 - -matrix: - include: - # Linux - - os: linux - dist: trusty - compiler: clang - env: NODE_VERSION="13" - addons: - apt: - sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ] - packages: [ 'clang-3.5', 'libstdc++-4.9-dev'] - - os: linux - dist: trusty - compiler: clang - env: NODE_VERSION="12" - addons: - apt: - sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ] - packages: [ 'clang-3.5', 'libstdc++-4.9-dev'] - - os: linux - compiler: clang - env: NODE_VERSION="11" - addons: - apt: - sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ] - packages: [ 'clang-3.5', 'libstdc++-4.9-dev'] - - os: linux - compiler: clang - env: NODE_VERSION="10" - addons: - apt: - sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ] - packages: [ 'clang-3.5', 'libstdc++-4.9-dev'] - # OS X - - os: osx - compiler: clang - env: NODE_VERSION="13" # node abi 79 - - os: osx - compiler: clang - env: NODE_VERSION="12" # node abi 72 - - os: osx - compiler: clang - env: NODE_VERSION="11" # node abi 67 - - os: osx - compiler: clang - env: NODE_VERSION="10" # node abi 64 - # electron Linux - - os: linux - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="8.2.0" - dist: trusty - addons: - apt: - sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ] - packages: [ 'clang-3.5', 'libstdc++-4.9-dev'] - - os: linux - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="8.1.0" - dist: trusty - addons: - apt: - sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ] - packages: [ 'clang-3.5', 'libstdc++-4.9-dev'] - - os: linux - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="8.0.0" - dist: trusty - addons: - apt: - sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ] - packages: [ 'clang-3.5', 'libstdc++-4.9-dev'] - - os: linux - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="7.1.0" - dist: trusty - addons: - apt: - sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ] - packages: [ 'clang-3.5', 'libstdc++-4.9-dev'] - - os: linux - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="7.0.0" - dist: trusty - addons: - apt: - sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ] - packages: [ 'clang-3.5', 'libstdc++-4.9-dev'] - - os: linux - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="6.1.0" - dist: trusty - addons: - apt: - sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ] - packages: [ 'clang-3.5', 'libstdc++-4.9-dev'] - - os: linux - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="6.0.0" - dist: trusty # needed for libc6 / 'version `GLIBC_2.17` not found' error on precise - addons: - apt: - sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ] - packages: [ 'clang-3.5', 'libstdc++-4.9-dev'] - # electron MacOs - - os: osx - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="8.2.0" - - os: osx - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="8.1.0" - - os: osx - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="8.0.0" - - os: osx - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="7.1.0" - - os: osx - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="7.0.0" - - os: osx - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="6.1.0" - - os: osx - compiler: clang - env: NODE_VERSION="12" ELECTRON_VERSION="6.0.0" - -env: - global: - - JOBS: "8" - -before_install: -- export PUBLISHABLE=${PUBLISHABLE:-true} -- if [[ $(uname -s) == 'Linux' ]]; then - export CXX="clang++-3.5"; - export CC="clang-3.5"; - export PYTHONPATH=$(pwd)/py-local/lib/python2.7/site-packages; - else - export PYTHONPATH=$(pwd)/py-local/lib/python/site-packages; - fi; -- scripts/validate_tag.sh -- source ./scripts/install_node.sh ${NODE_VERSION} - -install: -# put node-pre-gyp on path -- export PATH=./node_modules/.bin/:$PATH - -before_script: -# get commit message -- export COMMIT_MESSAGE=$(git show -s --format=%B $TRAVIS_COMMIT | tr -d '\n') - -script: -- if [[ "${NODE_VERSION}" ]]; then - if [[ "${ELECTRON_VERSION}" ]]; then - ./scripts/build_against_electron.sh; - else - ./scripts/build_against_node.sh; - fi; - fi -- if [[ "${NODE_VERSION}" -eq "4" ]]; then ./node_modules/.bin/eslint lib; fi; -# disabled for now: need to port to sudo:false -#- if [[ "${NODE_WEBKIT}" ]]; then ./scripts/build_against_node_webkit.sh; fi; diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index e8e425d91..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,282 +0,0 @@ -# Changelog - -## 4.1.1 -- Electron v6.1 and v7 support [#1237](https://github.com/mapbox/node-sqlite3/pull/1237) -- Electron v7.1 support [#1254](https://github.com/mapbox/node-sqlite3/pull/1254) -- SQLite3 update to 3.30.1 [#1238](https://github.com/mapbox/node-sqlite3/pull/1238) -- Overwrite 'msbuild_toolset' only if 'toolset' is defined [#1242](https://github.com/mapbox/node-sqlite3/pull/1242) -- Upgrade CI to node-gyp 6.x for Windows Electron v5 & v6 builds [#1245](https://github.com/mapbox/node-sqlite3/pull/1245) -- Node v13 support [#1247](https://github.com/mapbox/node-sqlite3/pull/1247) -- Use minimum supported node version for Electron 7 [#1255](https://github.com/mapbox/node-sqlite3/pull/1255) - -## 4.1.0 - -- Electron v6 support [#1195](https://github.com/mapbox/node-sqlite3/pull/1195) -- Electron v4.1 and v4.2 support [#1180](https://github.com/mapbox/node-sqlite3/pull/1180) -- Custom file header with `--sqlite_magic` [#1144](https://github.com/mapbox/node-sqlite3/pull/1144) -- https everywhere [#1177](https://github.com/mapbox/node-sqlite3/pull/1177) - -## 4.0.9 -- Use trusty as the base for prebuilts [#1167](https://github.com/mapbox/node-sqlite3/pull/1167) - -## 4.0.8 -- Rerelease of 4.0.7 but removed excess .vscode files [0df90c7](https://github.com/mapbox/node-sqlite3/commit/0df90c7811331169ad5f8fbad396422e72757af3) - -## 4.0.7 - -- Node v12 support -- Electron v5 support -- Fix backup API tests -- HAVE_USLEEP=1 for all platforms -- docker suport - -## 4.0.6 -- Release of 4.0.5 (again due CI) - -## 4.0.5 -- **SECURITY:** Upgrade SQLite to 3.26.0 [#1088](https://github.com/mapbox/node-sqlite3/pull/1088) -- add constants for file open (shared databases) [#1078](https://github.com/mapbox/node-sqlite3/pull/1078) -- Allow specifying the python to use [#1089](https://github.com/mapbox/node-sqlite3/pull/1089) - -## 4.0.4 -- Add NodeJS 11 support [#1072](https://github.com/mapbox/node-sqlite3/pull/1072) -- Add electron osx 3.0.0 support [#1071](https://github.com/mapbox/node-sqlite3/pull/1071) - -## 4.0.3 - -- Increase electron/osx binary coverage [#1041](https://github.com/mapbox/node-sqlite3/pull/1041) (@kewde) - -## 4.0.2 - -- Fixed HTTP proxy support by using `request` over `needle` in node-pre-gyp - -## 4.0.1 - -- Node v10 support -- Upgrade to node-pre-gyp@0.10.1 -- Upgrade to nan@2.10.0 -- Upgrade to sqlite v3.24.0 -- Stopped bundling node-pre-gyp -- Upgrade to mocha@5 -- Now building electron binaries (@kewde) -- Add OPEN_FULLMUTEX constant - -## 4.0.0 - - - Drop support for Node v0.10 and v.12 - - Upgrade to node-pre-gyp@0.9.0 - - Upgrade to nan@2.9.2 - -## 3.1.13 - -- Attempt to fix regression of #866 - -## 3.1.12 - -- Fixed to ensure the binaries do not rely on `GLIBC_2.14` and only `GLIBC_2.2.5`. This regressed in v3.1.11. - -## 3.1.11 - -- Fixed building from source on alpine linux - -## 3.1.10 - -- Removed `npm ls` from `prepublish` hook per mapbox/node-pre-gyp#291 -- Upgraded node-pre-gyp to v0.6.37 -- Removed accidentally committed large file - -## 3.1.9 - -- Added support for node v8 and upgraded `nan`, `node-pre-gyp` deps. - -## 3.1.8 - -- Added support for node v7 (pre-compiled binaries available) - -## 3.1.7 - -- Upgrade sqlite to 3.15, enable FTS4, FTS5 (@wmertens) -- Upgrade to node-pre-gyp@0.6.31 and nan@2.4.0 - -## 3.1.6 - -- Starts bundling node-pre-gyp again to avoid #720 - -## 3.1.5 - -- [Added support for sqlite3_interrupt](https://github.com/mapbox/node-sqlite3/pull/518): this makes - it possible to interrupt a long-running query. -- [Fixes uv_ref race](https://github.com/mapbox/node-sqlite3/pull/705). - -## 3.1.4 - - - Added support for node v6 - -## 3.1.3 - - - Upgrade to node-pre-gyp@0.6.26 with better support for Electron - -## 3.1.2 - - - Only providing binaries for node v0.10x, v0.12.x, v4, and v5 - - Upgrade to nan@2.2.x - - Upgrade to node-pre-gyp@0.6.24 - - -## 3.1.1 - - - Support for node 5.x - - Upgraded SQLite to 3.9.1: https://www.sqlite.org/releaselog/3_9_1.html - - Enabled json1 extension by default - -## 3.1.0 - - - Support for node 3.x and 4.x - - Stopped producing binaries for node-webkit and 32 bit linux - -## 3.0.11 - - - Support for io.js 3.x (upgrade to Nan 2.x) @kkoopa - -## 3.0.10 - - - Upgraded SQLite to 3.8.11.1: https://www.sqlite.org/releaselog/3_8_11_1.html - - Fixed binary compatibility regression with old centos/rhel glibc GLIBC_2.14 (re-introduced alpine linux (musl) build regression) - - Now providing binaries against Visual Studio 2015 (pass --toolset=v140) and use binaries from https://github.com/mapbox/node-cpp11 - -## 3.0.9 - - - Fixed build regression against alpine linux (musl) - - Upgraded node-pre-gyp@0.6.8 - -## 3.0.8 - - - Fixed build regression against FreeBSD - - Upgraded node-pre-gyp@0.6.7 - -## 3.0.7 - - - Fixed build regression against ARM and i386 linux - - Upgraded node-pre-gyp@0.6.6 - - Added support for io.js 2.0.0 - -## 3.0.6 - - - Upgraded node-pre-gyp@0.6.5 - - Upgraded nan@1.8.4 - - Fixed binaries to work on older linux systems (circa GLIBC_2.2.5 like centos 6) @bnoordhuis - - Updated internal libsqlite3 from 3.8.7.1 -> 3.8.9 (https://www.sqlite.org/news.html) - -## 3.0.5 - - - IO.js and Node v0.12.x support. - - Node-webkit v0.11.x support regressed in this release, sorry (https://github.com/mapbox/node-sqlite3/issues/404). - -## 3.0.4 - - - Upgraded node-pre-gyp@0.6.1 - -## 3.0.3 - - - Upgraded to node-pre-gyp@0.6.0 which should fix crashes against node v0.11.14 - - Now providing binaries against Visual Studio 2014 (pass --toolset=v140) and use binaries from https://github.com/mapbox/node-cpp11 - -## 3.0.2 - - - Republish for possibly busted npm package. - -## 3.0.1 - - - Use ~ in node-pre-gyp semver for more flexible dep management. - -## 3.0.0 - -Released September 20nd, 2014 - - - Backwards-incompatible change: node versions 0.8.x are no longer supported. - - Updated to node-pre-gyp@0.5.27 - - Updated NAN to 1.3.0 - - Updated internal libsqlite3 to v3.8.6 - -## 2.2.7 - -Released August 6th, 2014 - - - Removed usage of `npm ls` with `prepublish` target (which breaks node v0.8.x) - -## 2.2.6 - -Released August 6th, 2014 - - - Fix bundled version of node-pre-gyp - -## 2.2.5 - -Released August 5th, 2014 - - - Fix leak in complete() callback of Database.each() (#307) - - Started using `engineStrict` and improved `engines` declaration to make clear only >= 0.11.13 is supported for the 0.11.x series. - -## 2.2.4 - -Released July 14th, 2014 - - - Now supporting node v0.11.x (specifically >=0.11.13) - - Fix db opening error with absolute path on windows - - Updated to node-pre-gyp@0.5.18 - - updated internal libsqlite3 from 3.8.4.3 -> 3.8.5 (https://www.sqlite.org/news.html) - -## 2.2.3 - - - Fixed regression in v2.2.2 for installing from binaries on windows. - -## 2.2.2 - - - Fixed packaging problem whereby a `config.gypi` was unintentially packaged and could cause breakages for OS X builds. - -## 2.2.1 - - - Now shipping with 64bit FreeBSD binaries against both node v0.10.x and node v0.8.x. - - Fixed solaris/smartos source compile by passing `-std=c99` when building internally bundled libsqlite3 (#201) - - Reduced size of npm package by ignoring tests and examples. - - Various fixes and improvements for building against node-webkit - - Upgraded to node-pre-gyp@0.5.x from node-pre-gyp@0.2.5 - - Improved ability to build from source against `sqlcipher` by passing custom library name: `--sqlite_libname=sqlcipher` - - No changes to C++ Core / Existing binaries are exactly the same - -## 2.2.0 - -Released Jan 13th, 2014 - - - updated internal libsqlite3 from 3.7.17 -> 3.8.2 (https://www.sqlite.org/news.html) which includes the next-generation query planner http://www.sqlite.org/queryplanner-ng.html - - improved binary deploy system using https://github.com/springmeyer/node-pre-gyp - - binary install now supports http proxies - - source compile now supports freebsd - - fixed support for node-webkit - -## 2.1.19 - -Released October 31st, 2013 - - - Started respecting `process.env.npm_config_tmp` as location to download binaries - - Removed uneeded `progress` dependency - -## 2.1.18 - -Released October 22nd, 2013 - - - `node-sqlite3` moved to mapbox github group - - Fixed reporting of node-gyp errors - - Fixed support for node v0.6.x - -## 2.1.17 - - Minor fixes to binary deployment - -## 2.1.16 - - Support for binary deployment - -## 2.1.15 - -Released August 7th, 2013 - - - Minor readme additions and code optimizations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 0a75e352b..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,57 +0,0 @@ -# Contributing - -General guidelines for contributing to node-sqlite3 - -## Install Help - -If you've landed here due to a failed install of `node-sqlite3` then feel free to create a [new issue](https://github.com/mapbox/node-sqlite3/issues/new) to ask for help. The most likely problem is that we do not yet provide pre-built binaries for your particular platform and so the `node-sqlite3` install attempted a source compile but failed because you are missing the [dependencies for node-gyp](https://github.com/TooTallNate/node-gyp#installation). But please provide as much detail on your problem as possible and we'll try to help. Please include: - - terminal logs of failed install (preferably from running `npm install sqlite3 --loglevel=info`) - - `node-sqlite3` version you tried to install - - node version you are running - - operating system and architecture you are running, e.g. `Windows 7 64 bit`. - -## Developing / Pre-release - -Create a milestone for the next release on github. If all anticipated changes are back compatible then a `patch` release is in order. If minor API changes are needed then a `minor` release is in order. And a `major` bump is warranted if major API changes are needed. - -Assign tickets and pull requests you are working to the milestone you created. - -## Releasing - -To release a new version: - -**1)** Ensure tests are passing - -Before considering a release all the tests need to be passing on appveyor and travis. - -**2)** Bump commit - -Bump the version in `package.json` like https://github.com/mapbox/node-sqlite3/commit/77d51d5785b047ff40f6a8225051488a0d96f7fd - -What if you already committed the `package.json` bump and you have no changes to commit but want to publish binaries? In this case you can do: - -```sh -git commit --allow-empty -m "[publish binary]" -``` - -**3)** Ensure binaries built - -Check the travis and appveyor pages to ensure they are all green as an indication that the `[publish binary]` command worked. - -If you need to republish binaries you can do this with the command below, however this should not be a common thing for you to do! - -```sh -git commit --allow-empty -m "[republish binary]" -``` - -Note: NEVER republish binaries for an existing released version. - -**7)** Officially release - -An official release requires: - - - Updating the CHANGELOG.md - - Create and push github tag like `git tag v3.1.1 -m "v3.1.1" && git push --tags` - - Ensure you have a clean checkout (no extra files in your check that are not known by git). You need to be careful, for instance, to avoid a large accidental file being packaged by npm. You can get a view of what npm will publish by running `make testpack` - - Fully rebuild and ensure install from binary works: `make clean && npm install --fallback-to-build=false` - - Then publish the module to npm repositories by running `npm publish` diff --git a/Dockerfile b/Dockerfile deleted file mode 100755 index c14d98946..000000000 --- a/Dockerfile +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/echo docker build . -f -# -*- coding: utf-8 -*- -#{ -# ISC License -# Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") -# Copyright (c) 1995-2003 by Internet Software Consortium -# Permission to use, copy, modify, and /or distribute this software -# for any purpose with or without fee is hereby granted, -# provided that the above copyright notice -# and this permission notice appear in all copies. -# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS. -# IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, -# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, -# ARISING OUT OF OR IN CONNECTION WITH THE USE -# OR PERFORMANCE OF THIS SOFTWARE. -#} - -FROM ubuntu:latest -MAINTAINER Philippe Coval (p.coval@samsung.com) - -ENV DEBIAN_FRONTEND noninteractive -ENV LC_ALL en_US.UTF-8 -ENV LANG ${LC_ALL} - -RUN echo "#log: Configuring locales" \ - && set -x \ - && apt-get update -y \ - && apt-get install -y locales \ - && echo "${LC_ALL} UTF-8" | tee /etc/locale.gen \ - && locale-gen ${LC_ALL} \ - && dpkg-reconfigure locales \ - && sync - -ENV project node-sqlite3 - -RUN echo "#log: ${project}: Setup system" \ - && set -x \ - && apt-get update -y \ - && apt-get install -y \ - curl \ - sudo \ - build-essential \ - python \ - && apt-get clean \ - && NVM_VERSION="v0.33.8" \ - && NODE_VERSION="--lts=carbon" \ - && curl -o- https://raw.githubusercontent.com/creationix/nvm/${NVM_VERSION}/install.sh | bash \ - && which nvm || . ~/.bashrc \ - && nvm install ${NODE_VERSION} \ - && nvm use ${NODE_VERSION} \ - && sync - -ADD . /usr/local/${project}/${project} -WORKDIR /usr/local/${project}/${project} -RUN echo "#log: ${project}: Preparing sources" \ - && set -x \ - && which npm || . ~/.bashrc \ - && npm install || cat npm-debug.log \ - && npm install \ - && npm install --unsafe-perm --build-from-source \ - && sync - -WORKDIR /usr/local/${project}/${project} -RUN echo "#log: ${project}: Building sources" \ - && set -x \ - && which npm || . ~/.bashrc \ - && npm run pack \ - && npm pack \ - && find build/stage/ -type f \ - && sync - diff --git a/Makefile b/Makefile deleted file mode 100644 index 48118eb8b..000000000 --- a/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -#https://www.gnu.org/prep/standards/html_node/Standard-Targets.html#Standard-Targets - -all: build - -./node_modules: - npm install --build-from-source - -build: ./node_modules - ./node_modules/.bin/node-pre-gyp build --loglevel=silent - -debug: - ./node_modules/.bin/node-pre-gyp rebuild --debug - -verbose: - ./node_modules/.bin/node-pre-gyp rebuild --loglevel=verbose - -clean: - @rm -rf ./build - rm -rf lib/binding/ - rm -f test/support/big.db-journal - rm -rf ./node_modules/ - -grind: - valgrind --leak-check=full node node_modules/.bin/_mocha - -testpack: - rm -f ./*tgz - npm pack - tar -ztvf *tgz - rm -f ./*tgz - -rebuild: - @make clean - @make - -test: - npm test - -check: test - -.PHONY: test clean build diff --git a/README.md b/README.md index 1e563446b..14553ac83 100644 --- a/README.md +++ b/README.md @@ -1,148 +1,158 @@ -# Quick instructions for Grist devs - -1. Run `make` to install dependencies and build. Delete the `package-lock.json` which this creates. -2. Possibly rename `build-tmp-napi-v3` or something to `build`. Don't know why it isn't just `build` and if this is system-specific. -3. Run `npm run rebuild-tests` which puts files in `test/cpp`, particularly `marshal.node`. -4. Run `npm test`. A failure in the test `respects ELECTRON_VERSION` is OK. -5. Maybe run `npm pack`? Not sure if needed. -6. Run `npm publish`. - ----- ----- +# ⚙️ node-sqlite3 Asynchronous, non-blocking [SQLite3](https://sqlite.org/) bindings for [Node.js](http://nodejs.org/). -[![NPM](https://nodei.co/npm/sqlite3.png?downloads=true&downloadRank=true)](https://nodei.co/npm/sqlite3/) - -[![Build Status](https://travis-ci.org/mapbox/node-sqlite3.svg?branch=master)](https://travis-ci.org/mapbox/node-sqlite3) -[![Build status](https://ci.appveyor.com/api/projects/status/gvm7ul0hpmdawqom)](https://ci.appveyor.com/project/Mapbox/node-sqlite3) -[![Coverage Status](https://coveralls.io/repos/mapbox/node-sqlite3/badge.svg?branch=master&service=github)](https://coveralls.io/github/mapbox/node-sqlite3?branch=master) -[![Dependencies](https://david-dm.org/mapbox/node-sqlite3.svg)](https://david-dm.org/mapbox/node-sqlite3) +[![Latest release](https://img.shields.io/github/release/TryGhost/node-sqlite3.svg)](https://www.npmjs.com/package/sqlite3) +![Build Status](https://github.com/TryGhost/node-sqlite3/workflows/CI/badge.svg?branch=master) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fnode-sqlite3.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fnode-sqlite3?ref=badge_shield) [![N-API v3 Badge](https://img.shields.io/badge/N--API-v3-green.svg)](https://nodejs.org/dist/latest/docs/api/n-api.html#n_api_n_api) +[![N-API v6 Badge](https://img.shields.io/badge/N--API-v6-green.svg)](https://nodejs.org/dist/latest/docs/api/n-api.html#n_api_n_api) -## Supported platforms +# Features -The `sqlite3` module works with Node.js v10.x, v11.x, v12.x and v13.x. + - Straightforward query and parameter binding interface + - Full Buffer/Blob support + - Extensive [debugging support](https://github.com/tryghost/node-sqlite3/wiki/Debugging) + - [Query serialization](https://github.com/tryghost/node-sqlite3/wiki/Control-Flow) API + - [Extension support](https://github.com/TryGhost/node-sqlite3/wiki/API#databaseloadextensionpath-callback), including bundled support for the [json1 extension](https://www.sqlite.org/json1.html) + - Big test suite + - Written in modern C++ and tested for memory leaks + - Bundles SQLite v3.40.0, or you can build using a local SQLite -Binaries for most Node versions and platforms are provided by default via [node-pre-gyp](https://github.com/mapbox/node-pre-gyp). +# Installing -The `sqlite3` module also works with [node-webkit](https://github.com/rogerwang/node-webkit) if node-webkit contains a supported version of Node.js engine. [(See below.)](#building-for-node-webkit) +You can use [`npm`](https://github.com/npm/cli) or [`yarn`](https://github.com/yarnpkg/yarn) to install `sqlite3`: -SQLite's [SQLCipher extension](https://github.com/sqlcipher/sqlcipher) is also supported. [(See below.)](#building-for-sqlcipher) +* (recommended) Latest published package: +```bash +npm install sqlite3 +# or +yarn add sqlite3 +``` +* GitHub's `master` branch: `npm install https://github.com/tryghost/node-sqlite3/tarball/master` -# Usage +### Prebuilt binaries -**Note:** the module must be [installed](#installing) before use. +`sqlite3` v5+ was rewritten to use [Node-API](https://nodejs.org/api/n-api.html) so prebuilt binaries do not need to be built for specific Node versions. `sqlite3` currently builds for both Node-API v3 and v6. Check the [Node-API version matrix](https://nodejs.org/api/n-api.html#node-api-version-matrix) to ensure your Node version supports one of these. The prebuilt binaries should be supported on Node v10+. -``` js -var sqlite3 = require('sqlite3').verbose(); -var db = new sqlite3.Database(':memory:'); +The module uses [node-pre-gyp](https://github.com/mapbox/node-pre-gyp) to download the prebuilt binary for your platform, if it exists. These binaries are hosted on GitHub Releases for `sqlite3` versions above 5.0.2, and they are hosted on S3 otherwise. The following targets are currently provided: -db.serialize(function() { - db.run("CREATE TABLE lorem (info TEXT)"); +Format: `napi-v{napi_build_version}-{platform}-{libc}-{arch}` - var stmt = db.prepare("INSERT INTO lorem VALUES (?)"); - for (var i = 0; i < 10; i++) { - stmt.run("Ipsum " + i); - } - stmt.finalize(); +* `napi-v3-darwin-unknown-arm64` +* `napi-v3-darwin-unknown-x64` +* `napi-v3-linux-glibc-arm64` +* `napi-v3-linux-glibc-x64` +* `napi-v3-linux-musl-arm64` +* `napi-v3-linux-musl-x64` +* `napi-v3-win32-unknown-ia32` +* `napi-v3-win32-unknown-x64` +* `napi-v6-darwin-unknown-arm64` +* `napi-v6-darwin-unknown-x64` +* `napi-v6-linux-glibc-arm64` +* `napi-v6-linux-glibc-x64` +* `napi-v6-linux-musl-arm64` +* `napi-v6-linux-musl-x64` +* `napi-v6-win32-unknown-ia32` +* `napi-v6-win32-unknown-x64` - db.each("SELECT rowid AS id, info FROM lorem", function(err, row) { - console.log(row.id + ": " + row.info); - }); -}); +Unfortunately, [node-pre-gyp](https://github.com/mapbox/node-pre-gyp) cannot differentiate between `armv6` and `armv7`, and instead uses `arm` as the `{arch}`. Until that is fixed, you will still need to install `sqlite3` from [source](#source-install). -db.close(); -``` +Support for other platforms and architectures may be added in the future if CI supports building on them. -# Features +If your environment isn't supported, it'll use `node-gyp` to build SQLite but you will need to install a C++ compiler and linker. - - Straightforward query and parameter binding interface - - Full Buffer/Blob support - - Extensive [debugging support](https://github.com/mapbox/node-sqlite3/wiki/Debugging) - - [Query serialization](https://github.com/mapbox/node-sqlite3/wiki/Control-Flow) API - - [Extension support](https://github.com/mapbox/node-sqlite3/wiki/Extensions), including bundled support for the [json1 extension](https://www.sqlite.org/json1.html). - - Big test suite - - Written in modern C++ and tested for memory leaks - - Bundles Sqlite3 3.26.0 as a fallback if the installing system doesn't include SQLite +### Other ways to install + +It is also possible to make your own build of `sqlite3` from its source instead of its npm package ([See below.](#source-install)). + +The `sqlite3` module also works with [node-webkit](https://github.com/rogerwang/node-webkit) if node-webkit contains a supported version of Node.js engine. [(See below.)](#building-for-node-webkit) + +SQLite's [SQLCipher extension](https://github.com/sqlcipher/sqlcipher) is also supported. [(See below.)](#building-for-sqlcipher) # API -See the [API documentation](https://github.com/mapbox/node-sqlite3/wiki) in the wiki. +See the [API documentation](https://github.com/TryGhost/node-sqlite3/wiki/API) in the wiki. -# Installing +# Usage -You can use [`npm`](https://github.com/isaacs/npm) to download and install: +**Note:** the module must be [installed](#installing) before use. -* The latest `sqlite3` package: `npm install sqlite3` +``` js +const sqlite3 = require('sqlite3').verbose(); +const db = new sqlite3.Database(':memory:'); -* GitHub's `master` branch: `npm install https://github.com/mapbox/node-sqlite3/tarball/master` +db.serialize(() => { + db.run("CREATE TABLE lorem (info TEXT)"); -The module uses [node-pre-gyp](https://github.com/mapbox/node-pre-gyp) to download a pre-compiled binary for your platform, if it exists. Otherwise, it uses `node-gyp` to build the extension. + const stmt = db.prepare("INSERT INTO lorem VALUES (?)"); + for (let i = 0; i < 10; i++) { + stmt.run("Ipsum " + i); + } + stmt.finalize(); -It is also possible to make your own build of `sqlite3` from its source instead of its npm package ([see below](#building-from-the-source)). + db.each("SELECT rowid AS id, info FROM lorem", (err, row) => { + console.log(row.id + ": " + row.info); + }); +}); -It is possible to use the installed package in [node-webkit](https://github.com/rogerwang/node-webkit) instead of the vanilla Node.js. See [Building for node-webkit](#building-for-node-webkit) for details. +db.close(); +``` ## Source install To skip searching for pre-compiled binaries, and force a build from source, use - npm install --build-from-source +```bash +npm install --build-from-source +``` The sqlite3 module depends only on libsqlite3. However, by default, an internal/bundled copy of sqlite will be built and statically linked, so an externally installed sqlite3 is not required. If you wish to install against an external sqlite then you need to pass the `--sqlite` argument to `npm` wrapper: - npm install --build-from-source --sqlite=/usr/local +```bash +npm install --build-from-source --sqlite=/usr/local +``` If building against an external sqlite3 make sure to have the development headers available. Mac OS X ships with these by default. If you don't have them installed, install the `-dev` package with your package manager, e.g. `apt-get install libsqlite3-dev` for Debian/Ubuntu. Make sure that you have at least `libsqlite3` >= 3.6. Note, if building against homebrew-installed sqlite on OS X you can do: - npm install --build-from-source --sqlite=/usr/local/opt/sqlite/ - -By default the node-gyp install will use `python` as part of the installation. A -different python executable can be specified on the command line. - - npm install --build-from-source --python=/usr/bin/python2 - -This uses the npm_config_python config, so values in .npmrc will be honoured: - - python=/usr/bin/python2 +```bash +npm install --build-from-source --sqlite=/usr/local/opt/sqlite/ +``` ## Custom file header (magic) -The default sqlite file header is "SQLite format 3". -You can specify a different magic, though this will make standard tools and libraries unable to work with your files. - - - npm install --build-from-source --sqlite_magic="MyCustomMagic15" +The default sqlite file header is "SQLite format 3". You can specify a different magic, though this will make standard tools and libraries unable to work with your files. +```bash +npm install --build-from-source --sqlite_magic="MyCustomMagic15" +``` Note that the magic *must* be exactly 15 characters long (16 bytes including null terminator). - + ## Building for node-webkit Because of ABI differences, `sqlite3` must be built in a custom to be used with [node-webkit](https://github.com/rogerwang/node-webkit). -To build node-sqlite3 for node-webkit: +To build `sqlite3` for node-webkit: 1. Install [`nw-gyp`](https://github.com/rogerwang/nw-gyp) globally: `npm install nw-gyp -g` *(unless already installed)* 2. Build the module with the custom flags of `--runtime`, `--target_arch`, and `--target`: -```sh +```bash NODE_WEBKIT_VERSION="0.8.6" # see latest version at https://github.com/rogerwang/node-webkit#downloads npm install sqlite3 --build-from-source --runtime=node-webkit --target_arch=ia32 --target=$(NODE_WEBKIT_VERSION) ``` This command internally calls out to [`node-pre-gyp`](https://github.com/mapbox/node-pre-gyp) which itself calls out to [`nw-gyp`](https://github.com/rogerwang/nw-gyp) when the `--runtime=node-webkit` option is passed. -You can also run this command from within a `node-sqlite3` checkout: +You can also run this command from within a `sqlite3` checkout: -```sh +```bash npm install --build-from-source --runtime=node-webkit --target_arch=ia32 --target=$(NODE_WEBKIT_VERSION) ``` @@ -155,60 +165,64 @@ Remember the following: Visit the “[Using Node modules](https://github.com/rogerwang/node-webkit/wiki/Using-Node-modules)” article in the node-webkit's wiki for more details. -## Building for sqlcipher +## Building for SQLCipher -For instructions for building sqlcipher see -[Building SQLCipher for node.js](https://coolaj86.com/articles/building-sqlcipher-for-node-js-on-raspberry-pi-2/) +For instructions on building SQLCipher, see [Building SQLCipher for Node.js](https://coolaj86.com/articles/building-sqlcipher-for-node-js-on-raspberry-pi-2/). Alternatively, you can install it with your local package manager. -To run node-sqlite3 against sqlcipher you need to compile from source by passing build options like: +To run against SQLCipher, you need to compile `sqlite3` from source by passing build options like: - npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=/usr/ +```bash +npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=/usr/ - node -e 'require("sqlite3")' +node -e 'require("sqlite3")' +``` -If your sqlcipher is installed in a custom location (if you compiled and installed it yourself), -you'll also need to to set some environment variables: +If your SQLCipher is installed in a custom location (if you compiled and installed it yourself), you'll need to set some environment variables: ### On OS X with Homebrew Set the location where `brew` installed it: - export LDFLAGS="-L`brew --prefix`/opt/sqlcipher/lib" - export CPPFLAGS="-I`brew --prefix`/opt/sqlcipher/include" - npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=`brew --prefix` +```bash +export LDFLAGS="-L`brew --prefix`/opt/sqlcipher/lib" +export CPPFLAGS="-I`brew --prefix`/opt/sqlcipher/include/sqlcipher" +npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=`brew --prefix` - node -e 'require("sqlite3")' +node -e 'require("sqlite3")' +``` ### On most Linuxes (including Raspberry Pi) Set the location where `make` installed it: - export LDFLAGS="-L/usr/local/lib" - export CPPFLAGS="-I/usr/local/include -I/usr/local/include/sqlcipher" - export CXXFLAGS="$CPPFLAGS" - npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=/usr/local --verbose +```bash +export LDFLAGS="-L/usr/local/lib" +export CPPFLAGS="-I/usr/local/include -I/usr/local/include/sqlcipher" +export CXXFLAGS="$CPPFLAGS" +npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=/usr/local --verbose - node -e 'require("sqlite3")' +node -e 'require("sqlite3")' +``` ### Custom builds and Electron -Running sqlite3 through [electron-rebuild](https://github.com/electron/electron-rebuild) does not preserve the sqlcipher extension, so some additional flags are needed to make this build Electron compatible. Your `npm install sqlite3 --build-from-source` command needs these additional flags (be sure to replace the target version with the current Electron version you are working with): +Running `sqlite3` through [electron-rebuild](https://github.com/electron/electron-rebuild) does not preserve the SQLCipher extension, so some additional flags are needed to make this build Electron compatible. Your `npm install sqlite3 --build-from-source` command needs these additional flags (be sure to replace the target version with the current Electron version you are working with): - --runtime=electron --target=1.7.6 --dist-url=https://electronjs.org/headers +```bash +--runtime=electron --target=18.2.1 --dist-url=https://electronjs.org/headers +``` In the case of MacOS with Homebrew, the command should look like the following: - npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=`brew --prefix` --runtime=electron --target=1.7.6 --dist-url=https://electronjs.org/headers - -# Testing (updated for marshalling) - -[mocha](https://github.com/visionmedia/mocha) is required to run unit tests. +```bash +npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=`brew --prefix` --runtime=electron --target=18.2.1 --dist-url=https://electronjs.org/headers +``` -In sqlite3's directory (where its `package.json` resides) run the following: +# Testing - npm install mocha - npm run rebuild-tests #rebuilds marshal hooks - npm test +```bash +npm test +``` # Contributors @@ -226,6 +240,7 @@ In sqlite3's directory (where its `package.json` resides) run the following: * [Audrius Kažukauskas](https://github.com/audriusk) * [Johannes Schauer](https://github.com/pyneo) * [Mithgol](https://github.com/Mithgol) +* [Kewde](https://github.com/kewde) # Acknowledgments @@ -233,10 +248,14 @@ Thanks to [Orlando Vazquez](https://github.com/orlandov), [Eric Fredricksen](https://github.com/grumdrig) and [Ryan Dahl](https://github.com/ry) for their SQLite bindings for node, and to mraleph on Freenode's #v8 for answering questions. -Development of this module is sponsored by [MapBox](https://mapbox.org/). +This module was originally created by [Mapbox](https://mapbox.com/) & is now maintained by [Ghost](https://ghost.org). + +# Changelog + +We use [GitHub releases](https://github.com/TryGhost/node-sqlite3/releases) for notes on the latest versions. See [CHANGELOG.md](https://github.com/TryGhost/node-sqlite3/blob/b05f4594cf8b0de64743561fcd2cfe6f4571754d/CHANGELOG.md) in git history for details on older versions. # License -`node-sqlite3` is [BSD licensed](https://github.com/mapbox/node-sqlite3/raw/master/LICENSE). +`node-sqlite3` is [BSD licensed](https://github.com/tryghost/node-sqlite3/raw/master/LICENSE). [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fnode-sqlite3.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fnode-sqlite3?ref=badge_large) diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 26d7eefb8..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,99 +0,0 @@ -environment: - matrix: - - nodejs_version: 10 - platform: x64 - - nodejs_version: 10 - platform: x86 - - nodejs_version: 11 - platform: x64 - - nodejs_version: 11 - platform: x86 - - nodejs_version: 12 - platform: x64 - - nodejs_version: 12 - platform: x86 - - nodejs_version: 13 - platform: x64 - - nodejs_version: 13 - platform: x86 - # electron - - nodejs_version: 12 - platform: x64 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 8.2.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x86 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 8.2.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x64 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 8.1.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x86 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 8.1.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x64 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 8.0.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x86 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 8.0.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x64 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 7.1.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x86 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 7.1.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x64 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 7.0.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x86 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 7.0.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x64 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 6.1.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x86 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 6.1.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x64 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 6.0.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - - nodejs_version: 12 - platform: x86 - NODE_RUNTIME: electron - NODE_RUNTIME_VERSION: 6.0.0 - TOOLSET_ARGS: --dist-url=https://electronjs.org/headers - -os: Visual Studio 2015 - - -install: - - scripts\build-appveyor.bat - -build: OFF -test: OFF -deploy: OFF diff --git a/binding.gyp b/binding.gyp index de22468ba..48ae690fb 100644 --- a/binding.gyp +++ b/binding.gyp @@ -54,25 +54,14 @@ }, { "target_name": "action_after_build", - "cflags!": [ "-fno-exceptions" ], - "cflags_cc!": [ "-fno-exceptions" ], - "xcode_settings": { "GCC_ENABLE_CPP_EXCEPTIONS": "YES", - "CLANG_CXX_LIBRARY": "libc++", - "MACOSX_DEPLOYMENT_TARGET": "10.7", - }, - "msvs_settings": { - "VCCLCompilerTool": { "ExceptionHandling": 1 }, - }, "type": "none", - "dependencies": [ - " + +import events = require("events"); + +export const OPEN_READONLY: number; +export const OPEN_READWRITE: number; +export const OPEN_CREATE: number; +export const OPEN_FULLMUTEX: number; +export const OPEN_SHAREDCACHE: number; +export const OPEN_PRIVATECACHE: number; +export const OPEN_URI: number; + +export const VERSION: string; +export const SOURCE_ID: string; +export const VERSION_NUMBER: number; + +export const OK: number; +export const ERROR: number; +export const INTERNAL: number; +export const PERM: number; +export const ABORT: number; +export const BUSY: number; +export const LOCKED: number; +export const NOMEM: number; +export const READONLY: number; +export const INTERRUPT: number +export const IOERR: number; +export const CORRUPT: number +export const NOTFOUND: number; +export const FULL: number; +export const CANTOPEN: number; +export const PROTOCOL: number; +export const EMPTY: number; +export const SCHEMA: number; +export const TOOBIG: number +export const CONSTRAINT: number +export const MISMATCH: number; +export const MISUSE: number; +export const NOLFS: number; +export const AUTH: number +export const FORMAT: number; +export const RANGE: number +export const NOTADB: number; + +export const LIMIT_LENGTH: number; +export const LIMIT_SQL_LENGTH: number; +export const LIMIT_COLUMN: number; +export const LIMIT_EXPR_DEPTH: number; +export const LIMIT_COMPOUND_SELECT: number; +export const LIMIT_VDBE_OP: number; +export const LIMIT_FUNCTION_ARG: number; +export const LIMIT_ATTACHED: number; +export const LIMIT_LIKE_PATTERN_LENGTH: number; +export const LIMIT_VARIABLE_NUMBER: number; +export const LIMIT_TRIGGER_DEPTH: number; +export const LIMIT_WORKER_THREADS: number; + +export const cached: { + Database(filename: string, callback?: (this: Database, err: Error | null) => void): Database; + Database(filename: string, mode?: number, callback?: (this: Database, err: Error | null) => void): Database; +}; + +export interface RunResult extends Statement { + lastID: number; + changes: number; +} + +export class Statement extends events.EventEmitter { + bind(callback?: (err: Error | null) => void): this; + bind(...params: any[]): this; + + reset(callback?: (err: null) => void): this; + + finalize(callback?: (err: Error) => void): Database; + + run(callback?: (err: Error | null) => void): this; + run(params: any, callback?: (this: RunResult, err: Error | null) => void): this; + run(...params: any[]): this; + + get(callback?: (err: Error | null, row?: any) => void): this; + get(params: any, callback?: (this: RunResult, err: Error | null, row?: any) => void): this; + get(...params: any[]): this; + + all(callback?: (err: Error | null, rows: any[]) => void): this; + all(params: any, callback?: (this: RunResult, err: Error | null, rows: any[]) => void): this; + all(...params: any[]): this; + + each(callback?: (err: Error | null, row: any) => void, complete?: (err: Error | null, count: number) => void): this; + each(params: any, callback?: (this: RunResult, err: Error | null, row: any) => void, complete?: (err: Error | null, count: number) => void): this; + each(...params: any[]): this; +} + +export class Database extends events.EventEmitter { + constructor(filename: string, callback?: (err: Error | null) => void); + constructor(filename: string, mode?: number, callback?: (err: Error | null) => void); + + close(callback?: (err: Error | null) => void): void; + + run(sql: string, callback?: (this: RunResult, err: Error | null) => void): this; + run(sql: string, params: any, callback?: (this: RunResult, err: Error | null) => void): this; + run(sql: string, ...params: any[]): this; + + get(sql: string, callback?: (this: Statement, err: Error | null, row: any) => void): this; + get(sql: string, params: any, callback?: (this: Statement, err: Error | null, row: any) => void): this; + get(sql: string, ...params: any[]): this; + + all(sql: string, callback?: (this: Statement, err: Error | null, rows: any[]) => void): this; + all(sql: string, params: any, callback?: (this: Statement, err: Error | null, rows: any[]) => void): this; + all(sql: string, ...params: any[]): this; + + each(sql: string, callback?: (this: Statement, err: Error | null, row: any) => void, complete?: (err: Error | null, count: number) => void): this; + each(sql: string, params: any, callback?: (this: Statement, err: Error | null, row: any) => void, complete?: (err: Error | null, count: number) => void): this; + each(sql: string, ...params: any[]): this; + + exec(sql: string, callback?: (this: Statement, err: Error | null) => void): this; + + prepare(sql: string, callback?: (this: Statement, err: Error | null) => void): Statement; + prepare(sql: string, params: any, callback?: (this: Statement, err: Error | null) => void): Statement; + prepare(sql: string, ...params: any[]): Statement; + + serialize(callback?: () => void): void; + parallelize(callback?: () => void): void; + + on(event: "trace", listener: (sql: string) => void): this; + on(event: "profile", listener: (sql: string, time: number) => void): this; + on(event: "change", listener: (type: string, database: string, table: string, rowid: number) => void): this; + on(event: "error", listener: (err: Error) => void): this; + on(event: "open" | "close", listener: () => void): this; + on(event: string, listener: (...args: any[]) => void): this; + + configure(option: "busyTimeout", value: number): void; + configure(option: "limit", id: number, value: number): void; + + loadExtension(filename: string, callback?: (err: Error | null) => void): this; + + wait(callback?: (param: null) => void): this; + + interrupt(): void; +} + +export function verbose(): sqlite3; + +export interface sqlite3 { + OPEN_READONLY: number; + OPEN_READWRITE: number; + OPEN_CREATE: number; + OPEN_FULLMUTEX: number; + OPEN_SHAREDCACHE: number; + OPEN_PRIVATECACHE: number; + OPEN_URI: number; + + VERSION: string; + SOURCE_ID: string; + VERSION_NUMBER: number; + + OK: number; + ERROR: number; + INTERNAL: number; + PERM: number; + ABORT: number; + BUSY: number; + LOCKED: number; + NOMEM: number; + READONLY: number; + INTERRUPT: number + IOERR: number; + CORRUPT: number + NOTFOUND: number; + FULL: number; + CANTOPEN: number; + PROTOCOL: number; + EMPTY: number; + SCHEMA: number; + TOOBIG: number + CONSTRAINT: number + MISMATCH: number; + MISUSE: number; + NOLFS: number; + AUTH: number + FORMAT: number; + RANGE: number + NOTADB: number; + + LIMIT_LENGTH: number; + LIMIT_SQL_LENGTH: number; + LIMIT_COLUMN: number; + LIMIT_EXPR_DEPTH: number; + LIMIT_COMPOUND_SELECT: number; + LIMIT_VDBE_OP: number; + LIMIT_FUNCTION_ARG: number; + LIMIT_ATTACHED: number; + LIMIT_LIKE_PATTERN_LENGTH: number; + LIMIT_VARIABLE_NUMBER: number; + LIMIT_TRIGGER_DEPTH: number; + LIMIT_WORKER_THREADS: number; + + cached: typeof cached; + RunResult: RunResult; + Statement: typeof Statement; + Database: typeof Database; + verbose(): this; +} \ No newline at end of file diff --git a/lib/sqlite3.js b/lib/sqlite3.js index 198d0cbcd..e73f0a9b8 100644 --- a/lib/sqlite3.js +++ b/lib/sqlite3.js @@ -1,27 +1,28 @@ -var path = require('path'); -var sqlite3 = require('./sqlite3-binding.js'); -var EventEmitter = require('events').EventEmitter; +const path = require('path'); +const sqlite3 = require('./sqlite3-binding.js'); +const EventEmitter = require('events').EventEmitter; module.exports = exports = sqlite3; function normalizeMethod (fn) { return function (sql) { - var errBack; - var args = Array.prototype.slice.call(arguments, 1); + let errBack; + const args = Array.prototype.slice.call(arguments, 1); + if (typeof args[args.length - 1] === 'function') { - var callback = args[args.length - 1]; + const callback = args[args.length - 1]; errBack = function(err) { if (err) { callback(err); } }; } - var statement = new Statement(this, sql, errBack); + const statement = new Statement(this, sql, errBack); return fn.call(this, statement, args); }; } function inherits(target, source) { - for (var k in source.prototype) + for (const k in source.prototype) target.prototype[k] = source.prototype[k]; } @@ -32,9 +33,8 @@ sqlite3.cached = { return new Database(file, a, b); } - var db; + let db; file = path.resolve(file); - function cb() { callback.call(db, null); } if (!sqlite3.cached.objects[file]) { db = sqlite3.cached.objects[file] = new Database(file, a, b); @@ -42,8 +42,9 @@ sqlite3.cached = { else { // Make sure the callback is called. db = sqlite3.cached.objects[file]; - var callback = (typeof a === 'number') ? b : a; + const callback = (typeof a === 'number') ? b : a; if (typeof callback === 'function') { + function cb() { callback.call(db, null); } if (db.open) process.nextTick(cb); else db.once('open', cb); } @@ -55,9 +56,9 @@ sqlite3.cached = { }; -var Database = sqlite3.Database; -var Statement = sqlite3.Statement; -var Backup = sqlite3.Backup; +const Database = sqlite3.Database; +const Statement = sqlite3.Statement; +const Backup = sqlite3.Backup; inherits(Database, EventEmitter); inherits(Statement, EventEmitter); @@ -108,7 +109,7 @@ Database.prototype.map = normalizeMethod(function(statement, params) { // Database#backup(filename, [callback]) // Database#backup(filename, destName, sourceName, filenameIsDest, [callback]) Database.prototype.backup = function() { - var backup; + let backup; if (arguments.length <= 2) { // By default, we write the main database out to the main database of the named file. // This is the most likely use of the backup api. @@ -123,22 +124,23 @@ Database.prototype.backup = function() { }; Statement.prototype.map = function() { - var params = Array.prototype.slice.call(arguments); - var callback = params.pop(); + const params = Array.prototype.slice.call(arguments); + const callback = params.pop(); params.push(function(err, rows) { if (err) return callback(err); - var result = {}; + const result = {}; if (rows.length) { - var keys = Object.keys(rows[0]), key = keys[0]; + const keys = Object.keys(rows[0]); + const key = keys[0]; if (keys.length > 2) { // Value is an object - for (var i = 0; i < rows.length; i++) { + for (let i = 0; i < rows.length; i++) { result[rows[i][key]] = rows[i]; } } else { - var value = keys[1]; + const value = keys[1]; // Value is a plain value - for (i = 0; i < rows.length; i++) { + for (let i = 0; i < rows.length; i++) { result[rows[i][key]] = rows[i][value]; } } @@ -148,12 +150,12 @@ Statement.prototype.map = function() { return this.all.apply(this, params); }; -var isVerbose = false; +let isVerbose = false; -var supportedEvents = [ 'trace', 'profile', 'insert', 'update', 'delete' ]; +const supportedEvents = [ 'trace', 'profile', 'change' ]; Database.prototype.addListener = Database.prototype.on = function(type) { - var val = EventEmitter.prototype.addListener.apply(this, arguments); + const val = EventEmitter.prototype.addListener.apply(this, arguments); if (supportedEvents.indexOf(type) >= 0) { this.configure(type, true); } @@ -161,7 +163,7 @@ Database.prototype.addListener = Database.prototype.on = function(type) { }; Database.prototype.removeListener = function(type) { - var val = EventEmitter.prototype.removeListener.apply(this, arguments); + const val = EventEmitter.prototype.removeListener.apply(this, arguments); if (supportedEvents.indexOf(type) >= 0 && !this._events[type]) { this.configure(type, false); } @@ -169,7 +171,7 @@ Database.prototype.removeListener = function(type) { }; Database.prototype.removeAllListeners = function(type) { - var val = EventEmitter.prototype.removeAllListeners.apply(this, arguments); + const val = EventEmitter.prototype.removeAllListeners.apply(this, arguments); if (supportedEvents.indexOf(type) >= 0) { this.configure(type, false); } @@ -179,7 +181,7 @@ Database.prototype.removeAllListeners = function(type) { // Save the stack trace over EIO callbacks. sqlite3.verbose = function() { if (!isVerbose) { - var trace = require('./trace'); + const trace = require('./trace'); [ 'prepare', 'get', @@ -207,5 +209,5 @@ sqlite3.verbose = function() { isVerbose = true; } - return this; + return sqlite3; }; diff --git a/lib/trace.js b/lib/trace.js index 987f38a77..1d84cb011 100644 --- a/lib/trace.js +++ b/lib/trace.js @@ -1,31 +1,28 @@ // Inspired by https://github.com/tlrobinson/long-stack-traces -var util = require('util'); +const util = require('util'); function extendTrace(object, property, pos) { - var old = object[property]; + const old = object[property]; object[property] = function() { - var error = new Error(); - var name = object.constructor.name + '#' + property + '(' + + const error = new Error(); + const name = object.constructor.name + '#' + property + '(' + Array.prototype.slice.call(arguments).map(function(el) { return util.inspect(el, false, 0); }).join(', ') + ')'; if (typeof pos === 'undefined') pos = -1; if (pos < 0) pos += arguments.length; - var cb = arguments[pos]; + const cb = arguments[pos]; if (typeof arguments[pos] === 'function') { arguments[pos] = function replacement() { - try { - return cb.apply(this, arguments); - } catch (err) { - if (err && err.stack && !err.__augmented) { - err.stack = filter(err).join('\n'); - err.stack += '\n--> in ' + name; - err.stack += '\n' + filter(error).slice(1).join('\n'); - err.__augmented = true; - } - throw err; + const err = arguments[0]; + if (err && err.stack && !err.__augmented) { + err.stack = filter(err).join('\n'); + err.stack += '\n--> in ' + name; + err.stack += '\n' + filter(error).slice(1).join('\n'); + err.__augmented = true; } + return cb.apply(this, arguments); }; } return old.apply(this, arguments); diff --git a/package.json b/package.json index 3e4cb2cd5..031646e2b 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,21 @@ { "name": "@gristlabs/sqlite3", "description": "Asynchronous, non-blocking SQLite3 bindings", - "version": "4.1.1-grist.6", - "homepage": "https://github.com/mapbox/node-sqlite3", + "version": "5.1.4-grist.7", + "homepage": "https://github.com/gristlabs/node-sqlite3", "author": { - "name": "MapBox", + "name": "Mapbox", "url": "https://mapbox.com/" }, "binary": { "module_name": "node_sqlite3", - "module_path": "./lib/binding/napi-v{napi_build_version}-{platform}-{arch}", - "host": "https://mapbox-node-binary.s3.amazonaws.com", - "remote_path": "./{name}/v{version}/{toolset}/", - "package_name": "napi-v{napi_build_version}-{platform}-{arch}.tar.gz", + "module_path": "./lib/binding/napi-v{napi_build_version}-{platform}-{libc}-{arch}", + "host": "https://github.com/gristlabs/node-sqlite3/releases/download/", + "remote_path": "v{version}", + "package_name": "napi-v{napi_build_version}-{platform}-{libc}-{arch}.tar.gz", "napi_versions": [ - 3 + 3, + 6 ] }, "contributors": [ @@ -35,25 +36,44 @@ "Mithgol", "Ben Noordhuis " ], + "files": [ + "binding.gyp", + "deps/", + "lib/*.js", + "lib/*.d.ts", + "src/" + ], "repository": { "type": "git", - "url": "git://github.com/mapbox/node-sqlite3.git" + "url": "https://github.com/gristlabs/node-sqlite3.git" }, "dependencies": { - "node-addon-api": "2.0.0", - "node-pre-gyp": "^0.11.0" + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^4.2.0", + "tar": "^6.1.11" }, "devDependencies": { - "@mapbox/cloudfriend": "^1.9.0", - "aws-sdk": "2.x", - "bindings": "^1.3.0", - "eslint": "3.5.0", - "mocha": "^5.2.0" + "eslint": "6.8.0", + "mocha": "7.2.0", + "node-pre-gyp-github": "1.4.4" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + }, + "optionalDependencies": { + "node-gyp": "8.x" }, "scripts": { - "install": "node-pre-gyp install --build-from-source", + "build": "node-pre-gyp build", + "build:debug": "node-pre-gyp build --debug", + "install": "node-pre-gyp install --fallback-to-build", "pretest": "node test/support/createdb.js", - "test": "./scripts/prepare_for_test.sh; mocha -R spec --timeout 480000", + "test": "mocha -R spec --timeout 480000", "rebuild-tests": "node-gyp rebuild --directory test/cpp", "pack": "node-pre-gyp package" }, @@ -64,5 +84,11 @@ "sqlite3", "database" ], - "main": "./lib/sqlite3" + "main": "./lib/sqlite3", + "types": "./lib/sqlite3.d.ts", + "renovate": { + "extends": [ + "@tryghost:base" + ] + } } diff --git a/scripts/build-appveyor.bat b/scripts/build-appveyor.bat deleted file mode 100644 index d3befa449..000000000 --- a/scripts/build-appveyor.bat +++ /dev/null @@ -1,168 +0,0 @@ -@ECHO OFF -SETLOCAL -SET EL=0 - -ECHO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -IF /I "%msvs_toolset%"=="" ECHO msvs_toolset unset, defaulting to 14 && SET msvs_toolset=14 -IF /I "%msvs_version%"=="" ECHO msvs_version unset, defaulting to 2015 && SET msvs_version=2015 - -SET PATH=%CD%;%PATH% -IF "%msvs_toolset%"=="12" SET msvs_version=2013 -IF NOT "%NODE_RUNTIME%"=="" SET "TOOLSET_ARGS=%TOOLSET_ARGS% --runtime=%NODE_RUNTIME%" -IF NOT "%NODE_RUNTIME_VERSION%"=="" SET "TOOLSET_ARGS=%TOOLSET_ARGS% --target=%NODE_RUNTIME_VERSION%" - -ECHO APPVEYOR^: %APPVEYOR% -ECHO nodejs_version^: %nodejs_version% -ECHO platform^: %platform% -ECHO msvs_toolset^: %msvs_toolset% -ECHO msvs_version^: %msvs_version% -ECHO TOOLSET_ARGS^: %TOOLSET_ARGS% - -ECHO activating VS command prompt -:: NOTE this call makes the x64 -> X64 -IF /I "%platform%"=="x64" ECHO x64 && CALL "C:\Program Files (x86)\Microsoft Visual Studio %msvs_toolset%.0\VC\vcvarsall.bat" amd64 -IF /I "%platform%"=="x86" ECHO x86 && CALL "C:\Program Files (x86)\Microsoft Visual Studio %msvs_toolset%.0\VC\vcvarsall.bat" x86 -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO using compiler^: && CALL cl -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO using MSBuild^: && CALL msbuild /version && ECHO. -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO downloading/installing node -powershell Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) $env:PLATFORM -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -powershell Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO available node.exe^: -call where node -ECHO available npm^: -call where npm - -ECHO node^: && call node -v -call node -e "console.log(' - arch:',process.arch,'\n - argv:',process.argv,'\n - execPath:',process.execPath)" -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO npm^: && CALL npm -v -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO ===== where npm puts stuff START ============ -ECHO npm root && CALL npm root -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -ECHO npm root -g && CALL npm root -g -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO npm bin && CALL npm bin -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -ECHO npm bin -g && CALL npm bin -g -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -SET NPM_BIN_DIR= -FOR /F "tokens=*" %%i in ('CALL npm bin -g') DO SET NPM_BIN_DIR=%%i -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -IF /I "%NPM_BIN_DIR%"=="%CD%" ECHO ERROR npm bin -g equals local directory && SET ERRORLEVEL=1 && GOTO ERROR -ECHO ===== where npm puts stuff END ============ - -IF "%nodejs_version:~0,1%"=="4" CALL npm install node-gyp@3.x -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -IF "%nodejs_version:~0,1%"=="5" CALL npm install node-gyp@3.x -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -::Need to force update node-gyp to v6+ for electron v6 and v5 -ECHO ===== conditional node-gyp upgrade START ============ -:: Find the folder to install the node-gyp in -SET npm_in_nodejs_dir="%ProgramFiles%\nodejs\node_modules\npm" -ECHO npm_in_nodejs_dir^: %npm_in_nodejs_dir% -IF /I "%platform%"=="x86" SET npm_in_nodejs_dir="%ProgramFiles(x86)%\nodejs\node_modules\npm" -ECHO npm_in_nodejs_dir^: %npm_in_nodejs_dir% -:: Set boolean whether the update has to happen -SET "needs_patch=" -IF DEFINED NODE_RUNTIME_VERSION ( - ECHO NODE_RUNTIME_VERSION_REDUCED^: %NODE_RUNTIME_VERSION:~0,1% - IF "%NODE_RUNTIME_VERSION:~0,1%"=="1" SET "needs_patch=y" - IF "%NODE_RUNTIME_VERSION:~0,1%"=="2" SET "needs_patch=y" - IF "%NODE_RUNTIME_VERSION:~0,1%"=="3" SET "needs_patch=y" - IF "%NODE_RUNTIME_VERSION:~0,1%"=="4" SET "needs_patch=y" - IF "%NODE_RUNTIME_VERSION:~0,1%"=="5" SET "needs_patch=y" - IF "%NODE_RUNTIME_VERSION:~0,1%"=="6" SET "needs_patch=y" -) -:: Check if electron and install -ECHO NODE_RUNTIME^: %NODE_RUNTIME% -IF DEFINED needs_patch CALL npm install --prefix %npm_in_nodejs_dir% node-gyp@6.x -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -ECHO ===== conditional node-gyp upgrade END ============ - -CALL npm install --build-from-source --msvs_version=%msvs_version% %TOOLSET_ARGS% --loglevel=http -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -FOR /F "tokens=*" %%i in ('"CALL node_modules\.bin\node-pre-gyp reveal module %TOOLSET_ARGS% --silent"') DO SET MODULE=%%i -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -FOR /F "tokens=*" %%i in ('node -e "console.log(process.execPath)"') DO SET NODE_EXE=%%i -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -dumpbin /DEPENDENTS "%NODE_EXE%" -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -dumpbin /DEPENDENTS "%MODULE%" -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - - -IF "%NODE_RUNTIME%"=="electron" GOTO CHECK_ELECTRON_TEST_ERRORLEVEL - -::skipping check for errorlevel npm test result when using io.js -::@springmeyer: how to proceed? -IF NOT "%nodejs_version%"=="1.8.1" IF NOT "%nodejs_version%"=="2.0.0" GOTO CHECK_NPM_TEST_ERRORLEVEL - -ECHO calling npm test -CALL npm test -ECHO ========================================== -ECHO ========================================== -ECHO ========================================== - -GOTO NPM_TEST_FINISHED - - -:CHECK_ELECTRON_TEST_ERRORLEVEL -ECHO installing electron -CALL npm install -g "electron@%NODE_RUNTIME_VERSION%" -ECHO installing electron-mocha -IF "%nodejs_version%" LEQ 6 CALL npm install -g "electron-mocha@7" -IF "%nodejs_version%" GTR 6 CALL npm install -g "electron-mocha" -ECHO preparing tests -CALL electron "test/support/createdb-electron.js" -DEL "test\support\createdb-electron.js" -ECHO calling electron-mocha -CALL electron-mocha -R spec --timeout 480000 -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -GOTO NPM_TEST_FINISHED - - -:CHECK_NPM_TEST_ERRORLEVEL -ECHO calling npm test -CALL npm test -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -:NPM_TEST_FINISHED -ECHO packaging for node-gyp -CALL node_modules\.bin\node-pre-gyp package %TOOLSET_ARGS% -::make commit message env var shorter -SET CM=%APPVEYOR_REPO_COMMIT_MESSAGE% -IF NOT "%CM%" == "%CM:[publish binary]=%" (ECHO publishing && CALL node_modules\.bin\node-pre-gyp --msvs_version=%msvs_version% publish %TOOLSET_ARGS%) ELSE (ECHO not publishing) -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -GOTO DONE - - - -:ERROR -ECHO ~~~~~~~~~~~~~~~~~~~~~~ ERROR %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -ECHO ERRORLEVEL^: %ERRORLEVEL% -SET EL=%ERRORLEVEL% - -:DONE -ECHO ~~~~~~~~~~~~~~~~~~~~~~ DONE %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -EXIT /b %EL% diff --git a/scripts/build-local.bat b/scripts/build-local.bat deleted file mode 100644 index 615aa4a96..000000000 --- a/scripts/build-local.bat +++ /dev/null @@ -1,65 +0,0 @@ -@ECHO OFF -SETLOCAL -SET EL=0 - -ECHO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -SET PATH=C:\Python27;%PATH% - -SET APPVEYOR_REPO_COMMIT_MESSAGE=local build - -IF EXIST lib\binding ECHO deleting lib/binding && RD /Q /S lib\binding -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -IF EXIST node_modules ECHO deleting node_modules && RD /Q /S node_modules -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -GOTO VS2015 - -ECHO ============================ -ECHO VS2013 -ECHO ============================ -SET nodejs_version=4.4.2 -SET platform=x86 -SET msvs_toolset=12 -SET TOOLSET_ARGS= - -CALL scripts\build-appveyor.bat -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -GOTO DONE - -:VS2015 - -IF EXIST lib\binding ECHO deleting lib/binding && RD /Q /S lib\binding -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -IF EXIST node_modules ECHO deleting node_modules && RD /Q /S node_modules -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO ============================ -ECHO VS2015 -ECHO ============================ -SET nodejs_version=0.10.40 -ECHO SET nodejs_version^: %nodejs_version% -SET platform=x64 -ECHO SET platform^: %platform% -SET msvs_toolset=14 -ECHO SET msvs_toolset^: %msvs_toolset% -::SET TOOLSET_ARGS=--dist-url=https://s3.amazonaws.com/mapbox/node-cpp11 --toolset=v140 - -CALL scripts\build-appveyor.bat -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - - - - -GOTO DONE - -:ERROR -ECHO ~~~~~~~~~~~~~~~~~~~~~~ ERROR %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -ECHO ERRORLEVEL^: %ERRORLEVEL% -SET EL=%ERRORLEVEL% - -:DONE -ECHO ~~~~~~~~~~~~~~~~~~~~~~ DONE %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -EXIT /b %EL% diff --git a/scripts/build_against_electron.sh b/scripts/build_against_electron.sh deleted file mode 100755 index 205b3ebc3..000000000 --- a/scripts/build_against_electron.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash - -source ~/.nvm/nvm.sh - -set -e -u - -export DISPLAY=":99.0" -GYP_ARGS="--runtime=electron --target=${ELECTRON_VERSION} --dist-url=https://electronjs.org/headers" -NPM_BIN_DIR="$(npm bin -g 2>/dev/null)" - -function publish() { - if [[ ${PUBLISHABLE:-false} == true ]] && [[ ${COMMIT_MESSAGE} =~ "[publish binary]" ]]; then - node-pre-gyp package $GYP_ARGS - node-pre-gyp publish $GYP_ARGS - node-pre-gyp info $GYP_ARGS - fi -} - -function electron_pretest() { - npm install -g electron@${ELECTRON_VERSION} - if [ "$NODE_VERSION" -le 6 ]; then - npm install -g electron-mocha@7 - else - npm install -g electron-mocha - fi - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then - (sudo Xvfb :99 -ac -screen 0 1024x768x8; echo ok )& - else - sh -e /etc/init.d/xvfb start - fi - - sleep 3 -} - -function electron_test() { - "$NPM_BIN_DIR"/electron test/support/createdb-electron.js - "$NPM_BIN_DIR"/electron-mocha -R spec --timeout 480000 -} - -# test installing from source -npm install --build-from-source --clang=1 $GYP_ARGS - -electron_pretest -electron_test - -publish -make clean - -# now test building against shared sqlite -export NODE_SQLITE3_JSON1=no -if [[ $(uname -s) == 'Darwin' ]]; then - brew update - brew install sqlite - npm install --build-from-source --sqlite=$(brew --prefix) --clang=1 $GYP_ARGS -else - npm install --build-from-source --sqlite=/usr --clang=1 $GYP_ARGS -fi -electron_test -export NODE_SQLITE3_JSON1=yes diff --git a/scripts/build_against_node.sh b/scripts/build_against_node.sh deleted file mode 100755 index fcd2457d5..000000000 --- a/scripts/build_against_node.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env bash - -source ~/.nvm/nvm.sh - -set -e -u - -function publish() { - if [[ ${PUBLISHABLE:-false} == true ]] && [[ ${COMMIT_MESSAGE} =~ "[publish binary]" ]]; then - node-pre-gyp package testpackage - node-pre-gyp publish - node-pre-gyp info - make clean - fi -} - -echo "building binaries for publishing" -CFLAGS="${CFLAGS:-} -include $(pwd)/src/gcc-preinclude.h" CXXFLAGS="${CXXFLAGS:-} -include $(pwd)/src/gcc-preinclude.h" V=1 npm install --build-from-source --clang=1 -nm lib/binding/*/node_sqlite3.node | grep "GLIBCXX_" | c++filt || true -nm lib/binding/*/node_sqlite3.node | grep "GLIBC_" | c++filt || true -npm test - -publish - -# now test building against shared sqlite -echo "building from source to test against external libsqlite3" -export NODE_SQLITE3_JSON1=no -if [[ $(uname -s) == 'Darwin' ]]; then - brew update - brew install sqlite - npm install --build-from-source --sqlite=$(brew --prefix) --clang=1 -else - npm install --build-from-source --sqlite=/usr --clang=1 -fi -npm test -export NODE_SQLITE3_JSON1=yes - -platform=$(uname -s | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/") - -: ' -if [[ $(uname -s) == 'Linux' ]]; then - # node v0.8 and above provide pre-built 32 bit and 64 bit binaries - # so here we use the 32 bit ones to also test 32 bit builds - NVER=`node -v` - # enable 32 bit node - export PATH=$(pwd)/node-${NVER}-${platform}-x86/bin:$PATH - if [[ ${NODE_VERSION:0:4} == 'iojs' ]]; then - wget https://iojs.org/download/release/${NVER}/iojs-${NVER}-${platform}-x86.tar.gz - tar xf iojs-${NVER}-${platform}-x86.tar.gz - # enable 32 bit iojs - export PATH=$(pwd)/iojs-${NVER}-${platform}-x86/bin:$(pwd)/iojs-${NVER}-${platform}-ia32/bin:$PATH - else - wget https://nodejs.org/dist/${NVER}/node-${NVER}-${platform}-x86.tar.gz - tar xf node-${NVER}-${platform}-x86.tar.gz - # enable 32 bit node - export PATH=$(pwd)/node-${NVER}-${platform}-x86/bin:$(pwd)/node-${NVER}-${platform}-ia32/bin:$PATH - fi - which node - ls -l $(which node) - #node -e "console.log(process.arch,process.execPath)" - # install 32 bit compiler toolchain and X11 - # test source compile in 32 bit mode with internal libsqlite3 - CC=gcc-4.6 CXX=g++-4.6 npm install --build-from-source --clang=1 - node-pre-gyp package testpackage - npm test - publish - make clean - # broken for some unknown reason against io.js - if [[ ${NODE_VERSION:0:4} != 'iojs' ]]; then - # test source compile in 32 bit mode against external libsqlite3 - export NODE_SQLITE3_JSON1=no - CC=gcc-4.6 CXX=g++-4.6 npm install --build-from-source --sqlite=/usr --clang=1 - npm test - fi -fi - -' diff --git a/scripts/build_against_node_webkit.sh b/scripts/build_against_node_webkit.sh deleted file mode 100755 index 584fc7d82..000000000 --- a/scripts/build_against_node_webkit.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env bash - - -if [[ ! -d ../.nvm ]]; then - git clone https://github.com/creationix/nvm.git ../.nvm -fi -source ../.nvm/nvm.sh -nvm install 0.10 - -set -u -e - -npm install nw-gyp -g - -OLD_PATH="$PATH" - -GYP_ARGS="--runtime=node-webkit --target=${NODE_WEBKIT} --target_arch=${TARGET_ARCH}" -if [[ $(uname -s) == 'Darwin' ]]; then - if [[ '${TARGET_ARCH}' == 'x64' ]]; then - # do not build on Mac OS X x64 until node-webkit 0.10.1 is released - false - fi -fi - -if [[ $(uname -s) == 'Darwin' ]]; then - export NW_DOWNLOAD=node-webkit-v${NODE_WEBKIT}-osx-${TARGET_ARCH} - wget https://dl.node-webkit.org/v${NODE_WEBKIT}/${NW_DOWNLOAD}.zip - unzip -q ${NW_DOWNLOAD}.zip - export PATH=$(pwd)/node-webkit.app/Contents/MacOS/:${PATH} - # v0.10.0-rc1 unzips with extra folder - export PATH=$(pwd)/${NW_DOWNLOAD}/node-webkit.app/Contents/MacOS/:${PATH} - npm install --build-from-source ${GYP_ARGS} -else - sudo apt-get install build-essential - # Linux - export NW_DOWNLOAD=node-webkit-v${NODE_WEBKIT}-linux-${TARGET_ARCH} - # for testing node-webkit, launch a virtual display - export DISPLAY=:99.0 - # NOTE: travis already has xvfb installed - # https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-GUI-%28e.g.-a-Web-browser%29 - sh -e /etc/init.d/xvfb start +extension RANDR - wget https://dl.node-webkit.org/v${NODE_WEBKIT}/${NW_DOWNLOAD}.tar.gz - tar xf ${NW_DOWNLOAD}.tar.gz - export PATH=$(pwd)/${NW_DOWNLOAD}:${PATH} - if [[ "${TARGET_ARCH}" == 'ia32' ]]; then - # for nw >= 0.11.0 on ia32 we need gcc/g++ 4.8 - IFS='.' read -a NODE_WEBKIT_VERSION <<< "${NODE_WEBKIT}" - if test ${NODE_WEBKIT_VERSION[0]} -ge 0 -a ${NODE_WEBKIT_VERSION[1]} -ge 11; then - # travis-ci runs ubuntu 12.04, so we need this ppa for gcc/g++ 4.8 - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - export CC=gcc-4.8 - export CXX=g++-4.8 - export CXXFLAGS="-fpermissive" - COMPILER_PACKAGES="gcc-4.8-multilib g++-4.8-multilib" - else - export CC=gcc-4.6 - export CXX=g++-4.6 - export CXXFLAGS="-fpermissive" - COMPILER_PACKAGES="gcc-multilib g++-multilib" - fi - # need to update to avoid 404 for linux-libc-dev_3.2.0-64.97_amd64.deb - sudo apt-get update - # prepare packages for 32-bit builds on Linux - sudo apt-get -y install $COMPILER_PACKAGES libx11-6:i386 libnotify4:i386 libxtst6:i386 libcap2:i386 libglib2.0-0:i386 libgtk2.0-0:i386 libatk1.0-0:i386 libgdk-pixbuf2.0-0:i386 libcairo2:i386 libfreetype6:i386 libfontconfig1:i386 libxcomposite1:i386 libasound2:i386 libxdamage1:i386 libxext6:i386 libxfixes3:i386 libnss3:i386 libnspr4:i386 libgconf-2-4:i386 libexpat1:i386 libdbus-1-3:i386 libudev0:i386 - # also use ldd to find out if some necessary apt-get is missing - ldd $(pwd)/${NW_DOWNLOAD}/nw - npm install --build-from-source ${GYP_ARGS} - else - npm install --build-from-source ${GYP_ARGS} - fi -fi - -# test the package -node-pre-gyp package testpackage ${GYP_ARGS} - -PUBLISH_BINARY=false -if test "${COMMIT_MESSAGE#*'[publish binary]'}" != "$COMMIT_MESSAGE"; then - node-pre-gyp publish ${GYP_ARGS} - node-pre-gyp info ${GYP_ARGS} - node-pre-gyp clean ${GYP_ARGS} - make clean - # now install from binary - INSTALL_RESULT=$(npm install ${GYP_ARGS} --fallback-to-build=false > /dev/null)$? || true - # if install returned non zero (errored) then we first unpublish and then call false so travis will bail at this line - if [[ $INSTALL_RESULT != 0 ]]; then echo "returned $INSTALL_RESULT";node-pre-gyp unpublish ${GYP_ARGS};false; fi - # If success then we arrive here so lets clean up - node-pre-gyp clean ${GYP_ARGS} -fi - -# restore PATH -export PATH="$OLD_PATH" -rm -rf ${NW_DOWNLOAD} diff --git a/scripts/build_for_node_webkit.cmd b/scripts/build_for_node_webkit.cmd deleted file mode 100644 index ef809be15..000000000 --- a/scripts/build_for_node_webkit.cmd +++ /dev/null @@ -1,15 +0,0 @@ -echo Platform: %1 -echo The list of environment variables: -set -if not "%1" == "x86" goto end -if "%nw_version%" == "" goto end -call npm install nw-gyp -call cinst wget 7zip.commandline -call wget https://dl.node-webkit.org/v%nw_version%/node-webkit-v%nw_version%-win-ia32.zip -call 7z e -onw node-webkit-v%nw_version%-win-ia32.zip -dir nw -set PATH=nw;%PATH% -call node-pre-gyp rebuild --runtime=node-webkit --target=%nw_version% --target_arch=ia32 -call node-pre-gyp package testpackage --runtime=node-webkit --target=%nw_version% --target_arch=ia32 -if not "%CM%" == "%CM:[publish binary]=%" call node-pre-gyp publish --msvs_version=2013 --runtime=node-webkit --target=%nw_version% --target_arch=ia32 -:end \ No newline at end of file diff --git a/scripts/install_node.sh b/scripts/install_node.sh deleted file mode 100755 index d1ae0670e..000000000 --- a/scripts/install_node.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -if [[ ${1:-false} == 'false' ]]; then - echo "Error: pass node version as first argument" - exit 1 -fi - -NODE_VERSION=$1 - -# if an existing nvm is already installed we need to unload it -nvm unload || true - -# here we set up the node version on the fly based on the matrix value. -# This is done manually so that the build works the same on OS X -rm -rf ./__nvm/ && git clone --depth 1 https://github.com/creationix/nvm.git ./__nvm -source ./__nvm/nvm.sh -nvm install ${NODE_VERSION} -nvm use --delete-prefix ${NODE_VERSION} -node --version -npm --version -which node diff --git a/scripts/prepare_for_test.sh b/scripts/prepare_for_test.sh deleted file mode 100755 index b306e2364..000000000 --- a/scripts/prepare_for_test.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# Marshalling tests need to use built node_sqlite3.node, but bindings helper -# doesn't look in the right place. There's probably a smart way to fix this, -# but since this only affects tests of our fork, this script just makes a -# link in the place where marshalling tests expect. - -set -e - -expected=$(echo "console.log('node-v' + process.versions.modules + '-' + process.platform + '-' + process.arch)" | node) -if [ ! -e lib/binding/$expected/node_sqlite3.node ]; then - cd lib/binding - target=$(find . -iname "node_sqlite3.node" | head -n1) - mkdir -p $expected - ln -s ../$target $expected/node_sqlite3.node - echo Added lib/binding/$expected/node_sqlite3.node -fi diff --git a/scripts/validate_tag.sh b/scripts/validate_tag.sh deleted file mode 100755 index 67d039b70..000000000 --- a/scripts/validate_tag.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -set -u - -# let's catch the case where we tag but -# forget to increment the package.json version - -# check if we are on a tag -if [ `git describe --tags --always HEAD` ]; then - echo 'looks like we are on a tag' - if [[ $TRAVIS_BRANCH == `git describe --tags --always HEAD` ]]; then - echo 'git reports the same tag as travis' - # now check to make sure package.json `version` matches - MODULE_VERSION=$(node -e "console.log(require('./package.json').version)") - if [[ $MODULE_VERSION != $TRAVIS_BRANCH ]] && [[ v$MODULE_VERSION != $TRAVIS_BRANCH ]]; then - echo "package.json version ($MODULE_VERSION) does not match tag ($TRAVIS_BRANCH)" - exit 1 - else - echo "Validation success: package.json ($MODULE_VERSION) matches tag ($TRAVIS_BRANCH)" - fi - else - echo "warning: travis thinks the tag ($TRAVIS_BRANCH) differs from git (`git describe --tags --always HEAD`)" - fi -fi diff --git a/sqlite3.js b/sqlite3.js deleted file mode 100644 index c4b587d07..000000000 --- a/sqlite3.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./lib/sqlite3'); diff --git a/src/async.h b/src/async.h index 9c4d8926a..b1a8f9dd6 100644 --- a/src/async.h +++ b/src/async.h @@ -6,11 +6,6 @@ #include "threading.h" -#if defined(NODE_SQLITE3_BOOST_THREADING) -#include -#endif - - // Generic uv_async handler. template class Async { typedef void (*Callback)(Parent* parent, Item* item); diff --git a/src/backup.cc b/src/backup.cc index 470d8f5f4..9f3893b96 100644 --- a/src/backup.cc +++ b/src/backup.cc @@ -7,15 +7,15 @@ using namespace node_sqlite3; -Napi::FunctionReference Backup::constructor; - - Napi::Object Backup::Init(Napi::Env env, Napi::Object exports) { Napi::HandleScope scope(env); + // declare napi_default_method here as it is only available in Node v14.12.0+ + napi_property_attributes napi_default_method = static_cast(napi_writable | napi_configurable); + Napi::Function t = DefineClass(env, "Backup", { - InstanceMethod("step", &Backup::Step), - InstanceMethod("finish", &Backup::Finish), + InstanceMethod("step", &Backup::Step, napi_default_method), + InstanceMethod("finish", &Backup::Finish, napi_default_method), InstanceAccessor("idle", &Backup::IdleGetter, nullptr), InstanceAccessor("completed", &Backup::CompletedGetter, nullptr), InstanceAccessor("failed", &Backup::FailedGetter, nullptr), @@ -24,9 +24,6 @@ Napi::Object Backup::Init(Napi::Env env, Napi::Object exports) { InstanceAccessor("retryErrors", &Backup::RetryErrorGetter, &Backup::RetryErrorSetter), }); - constructor = Napi::Persistent(t); - constructor.SuppressDestruct(); - exports.Set("Backup", t); return exports; } @@ -37,11 +34,10 @@ void Backup::Process() { } while (inited && !locked && !queue.empty()) { - Call* call = queue.front(); + std::unique_ptr call(queue.front()); queue.pop(); call->callback(call->baton); - delete call; } } @@ -92,21 +88,17 @@ void Backup::CleanQueue() { // Clear out the queue so that this object can get GC'ed. while (!queue.empty()) { - Call* call = queue.front(); + std::unique_ptr call(queue.front()); queue.pop(); - Napi::Function cb = call->baton->callback.Value(); + std::unique_ptr baton(call->baton); + Napi::Function cb = baton->callback.Value(); if (inited && !cb.IsEmpty() && cb.IsFunction()) { TRY_CATCH_CALL(Value(), cb, 1, argv); called = true; } - - // We don't call the actual callback, so we have to make sure that - // the baton gets destroyed. - delete call->baton; - delete call; } // When we couldn't call a callback function, emit an error on the @@ -119,13 +111,12 @@ void Backup::CleanQueue() { else while (!queue.empty()) { // Just delete all items in the queue; we already fired an event when // initializing the backup failed. - Call* call = queue.front(); + std::unique_ptr call(queue.front()); queue.pop(); // We don't call the actual callback, so we have to make sure that // the baton gets destroyed. delete call->baton; - delete call; } } @@ -226,13 +217,14 @@ void Backup::Work_Initialize(napi_env e, void* data) { } void Backup::Work_AfterInitialize(napi_env e, napi_status status, void* data) { - BACKUP_INIT(InitializeBaton); + std::unique_ptr baton(static_cast(data)); + Backup* backup = baton->backup; Napi::Env env = backup->Env(); Napi::HandleScope scope(env); if (backup->status != SQLITE_OK) { - Error(baton); + Error(baton.get()); backup->FinishAll(); } else { @@ -288,7 +280,8 @@ void Backup::Work_Step(napi_env e, void* data) { } void Backup::Work_AfterStep(napi_env e, napi_status status, void* data) { - BACKUP_INIT(StepBaton); + std::unique_ptr baton(static_cast(data)); + Backup* backup = baton->backup; Napi::Env env = backup->Env(); Napi::HandleScope scope(env); @@ -300,7 +293,7 @@ void Backup::Work_AfterStep(napi_env e, napi_status status, void* data) { } if (backup->status != SQLITE_OK && backup->status != SQLITE_DONE) { - Error(baton); + Error(baton.get()); } else { // Fire callbacks. @@ -335,7 +328,8 @@ void Backup::Work_Finish(napi_env e, void* data) { } void Backup::Work_AfterFinish(napi_env e, napi_status status, void* data) { - BACKUP_INIT(Baton); + std::unique_ptr baton(static_cast(data)); + Backup* backup = baton->backup; Napi::Env env = backup->Env(); Napi::HandleScope scope(env); diff --git a/src/backup.h b/src/backup.h index 95edc1ab6..c15b77bfe 100644 --- a/src/backup.h +++ b/src/backup.h @@ -93,12 +93,10 @@ namespace node_sqlite3 { */ class Backup : public Napi::ObjectWrap { public: - static Napi::FunctionReference constructor; - static Napi::Object Init(Napi::Env env, Napi::Object exports); struct Baton { - napi_async_work request; + napi_async_work request = NULL; Backup* backup; Napi::FunctionReference callback; @@ -107,6 +105,7 @@ class Backup : public Napi::ObjectWrap { callback.Reset(cb_, 1); } virtual ~Baton() { + if (request) napi_delete_async_work(backup->Env(), request); backup->Unref(); callback.Reset(); } diff --git a/src/database.cc b/src/database.cc index 5abc427e9..45af8e93c 100644 --- a/src/database.cc +++ b/src/database.cc @@ -1,4 +1,5 @@ #include +#include #include "macros.h" #include "database.h" @@ -6,25 +7,35 @@ using namespace node_sqlite3; +#if NAPI_VERSION < 6 Napi::FunctionReference Database::constructor; +#endif Napi::Object Database::Init(Napi::Env env, Napi::Object exports) { Napi::HandleScope scope(env); + // declare napi_default_method here as it is only available in Node v14.12.0+ + napi_property_attributes napi_default_method = static_cast(napi_writable | napi_configurable); Napi::Function t = DefineClass(env, "Database", { - InstanceMethod("close", &Database::Close), - InstanceMethod("exec", &Database::Exec), - InstanceMethod("wait", &Database::Wait), - InstanceMethod("loadExtension", &Database::LoadExtension), - InstanceMethod("serialize", &Database::Serialize), - InstanceMethod("parallelize", &Database::Parallelize), - InstanceMethod("configure", &Database::Configure), - InstanceMethod("interrupt", &Database::Interrupt), + InstanceMethod("close", &Database::Close, napi_default_method), + InstanceMethod("exec", &Database::Exec, napi_default_method), + InstanceMethod("wait", &Database::Wait, napi_default_method), + InstanceMethod("loadExtension", &Database::LoadExtension, napi_default_method), + InstanceMethod("serialize", &Database::Serialize, napi_default_method), + InstanceMethod("parallelize", &Database::Parallelize, napi_default_method), + InstanceMethod("configure", &Database::Configure, napi_default_method), + InstanceMethod("interrupt", &Database::Interrupt, napi_default_method), InstanceAccessor("open", &Database::OpenGetter, nullptr) }); +#if NAPI_VERSION < 6 constructor = Napi::Persistent(t); constructor.SuppressDestruct(); +#else + Napi::FunctionReference* constructor = new Napi::FunctionReference(); + *constructor = Napi::Persistent(t); + env.SetInstanceData(constructor); +#endif exports.Set("Database", t); return exports; @@ -41,17 +52,14 @@ void Database::Process() { // Call all callbacks with the error object. while (!queue.empty()) { - Call* call = queue.front(); - Napi::Function cb = call->baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + std::unique_ptr call(queue.front()); + queue.pop(); + std::unique_ptr baton(call->baton); + Napi::Function cb = baton->callback.Value(); + if (IS_FUNCTION(cb)) { TRY_CATCH_CALL(this->Value(), cb, 1, argv); called = true; } - queue.pop(); - // We don't call the actual callback, so we have to make sure that - // the baton gets destroyed. - delete call->baton; - delete call; } // When we couldn't call a callback function, emit an error on the @@ -64,16 +72,16 @@ void Database::Process() { } while (open && (!locked || pending == 0) && !queue.empty()) { - Call* call = queue.front(); + Call *c = queue.front(); - if (call->exclusive && pending > 0) { + if (c->exclusive && pending > 0) { break; } queue.pop(); + std::unique_ptr call(c); locked = call->exclusive; call->callback(call->baton); - delete call; if (locked) break; } @@ -86,7 +94,10 @@ void Database::Schedule(Work_Callback callback, Baton* baton, bool exclusive) { if (!open && locked) { EXCEPTION(Napi::String::New(env, "Database is closed"), SQLITE_MISUSE, exception); Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + // We don't call the actual callback, so we have to make sure that + // the baton gets destroyed. + delete baton; + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { exception }; TRY_CATCH_CALL(Value(), cb, 1, argv); } @@ -173,7 +184,7 @@ void Database::Work_Open(napi_env e, void* data) { } void Database::Work_AfterOpen(napi_env e, napi_status status, void* data) { - OpenBaton* baton = static_cast(data); + std::unique_ptr baton(static_cast(data)); Database* db = baton->db; @@ -192,7 +203,7 @@ void Database::Work_AfterOpen(napi_env e, napi_status status, void* data) { Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { TRY_CATCH_CALL(db->Value(), cb, 1, argv); } else if (!db->open) { @@ -205,9 +216,6 @@ void Database::Work_AfterOpen(napi_env e, napi_status status, void* data) { EMIT_EVENT(db->Value(), 1, info); db->Process(); } - - napi_delete_async_work(e, baton->request); - delete baton; } Napi::Value Database::OpenGetter(const Napi::CallbackInfo& info) { @@ -233,6 +241,7 @@ void Database::Work_BeginClose(Baton* baton) { assert(baton->db->_handle); assert(baton->db->pending == 0); + baton->db->pending++; baton->db->RemoveCallbacks(); baton->db->closing = true; @@ -261,13 +270,14 @@ void Database::Work_Close(napi_env e, void* data) { } void Database::Work_AfterClose(napi_env e, napi_status status, void* data) { - Baton* baton = static_cast(data); + std::unique_ptr baton(static_cast(data)); Database* db = baton->db; Napi::Env env = db->Env(); Napi::HandleScope scope(env); + db->pending--; db->closing = false; Napi::Value argv[1]; @@ -285,7 +295,7 @@ void Database::Work_AfterClose(napi_env e, napi_status status, void* data) { Napi::Function cb = baton->callback.Value(); // Fire callbacks. - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { TRY_CATCH_CALL(db->Value(), cb, 1, argv); } else if (db->open) { @@ -298,9 +308,6 @@ void Database::Work_AfterClose(napi_env e, napi_status status, void* data) { EMIT_EVENT(db->Value(), 1, info); db->Process(); } - - napi_delete_async_work(e, baton->request); - delete baton; } Napi::Value Database::Serialize(const Napi::CallbackInfo& info) { @@ -312,7 +319,7 @@ Napi::Value Database::Serialize(const Napi::CallbackInfo& info) { db->serialize = true; if (!callback.IsEmpty() && callback.IsFunction()) { - TRY_CATCH_CALL(info.This(), callback, 0, NULL); + TRY_CATCH_CALL(info.This(), callback, 0, NULL, info.This()); db->serialize = before; } @@ -330,7 +337,7 @@ Napi::Value Database::Parallelize(const Napi::CallbackInfo& info) { db->serialize = false; if (!callback.IsEmpty() && callback.IsFunction()) { - TRY_CATCH_CALL(info.This(), callback, 0, NULL); + TRY_CATCH_CALL(info.This(), callback, 0, NULL, info.This()); db->serialize = before; } @@ -381,6 +388,11 @@ Napi::Value Database::Configure(const Napi::CallbackInfo& info) { Baton* baton = new LimitBaton(db, handle, id, value); db->Schedule(SetLimit, baton); } + else if (info[0].StrictEquals(Napi::String::New(env, "change"))) { + Napi::Function handle; + Baton* baton = new Baton(db, handle); + db->Schedule(RegisterUpdateCallback, baton); + } else { Napi::TypeError::New(env, (StringConcat( #if V8_MAJOR_VERSION > 6 @@ -415,14 +427,14 @@ Napi::Value Database::Interrupt(const Napi::CallbackInfo& info) { return info.This(); } -void Database::SetBusyTimeout(Baton* baton) { +void Database::SetBusyTimeout(Baton* b) { + std::unique_ptr baton(b); + assert(baton->db->open); assert(baton->db->_handle); // Abuse the status field for passing the timeout. sqlite3_busy_timeout(baton->db->_handle, baton->status); - - delete baton; } void Database::SetLimit(Baton* b) { @@ -434,7 +446,8 @@ void Database::SetLimit(Baton* b) { sqlite3_limit(baton->db->_handle, baton->id, baton->value); } -void Database::RegisterTraceCallback(Baton* baton) { +void Database::RegisterTraceCallback(Baton* b) { + std::unique_ptr baton(b); assert(baton->db->open); assert(baton->db->_handle); Database* db = baton->db; @@ -450,8 +463,6 @@ void Database::RegisterTraceCallback(Baton* baton) { db->debug_trace->finish(); db->debug_trace = NULL; } - - delete baton; } void Database::TraceCallback(void* db, const char* sql) { @@ -460,7 +471,8 @@ void Database::TraceCallback(void* db, const char* sql) { static_cast(db)->debug_trace->send(new std::string(sql)); } -void Database::TraceCallback(Database* db, std::string* sql) { +void Database::TraceCallback(Database* db, std::string* s) { + std::unique_ptr sql(s); // Note: This function is called in the main V8 thread. Napi::Env env = db->Env(); Napi::HandleScope scope(env); @@ -470,10 +482,10 @@ void Database::TraceCallback(Database* db, std::string* sql) { Napi::String::New(env, sql->c_str()) }; EMIT_EVENT(db->Value(), 2, argv); - delete sql; } -void Database::RegisterProfileCallback(Baton* baton) { +void Database::RegisterProfileCallback(Baton* b) { + std::unique_ptr baton(b); assert(baton->db->open); assert(baton->db->_handle); Database* db = baton->db; @@ -489,8 +501,6 @@ void Database::RegisterProfileCallback(Baton* baton) { db->debug_profile->finish(); db->debug_profile = NULL; } - - delete baton; } void Database::ProfileCallback(void* db, const char* sql, sqlite3_uint64 nsecs) { @@ -502,7 +512,8 @@ void Database::ProfileCallback(void* db, const char* sql, sqlite3_uint64 nsecs) static_cast(db)->debug_profile->send(info); } -void Database::ProfileCallback(Database *db, ProfileInfo* info) { +void Database::ProfileCallback(Database *db, ProfileInfo* i) { + std::unique_ptr info(i); Napi::Env env = db->Env(); Napi::HandleScope scope(env); @@ -512,10 +523,10 @@ void Database::ProfileCallback(Database *db, ProfileInfo* info) { Napi::Number::New(env, (double)info->nsecs / 1000000.0) }; EMIT_EVENT(db->Value(), 3, argv); - delete info; } -void Database::RegisterUpdateCallback(Baton* baton) { +void Database::RegisterUpdateCallback(Baton* b) { + std::unique_ptr baton(b); assert(baton->db->open); assert(baton->db->_handle); Database* db = baton->db; @@ -531,8 +542,6 @@ void Database::RegisterUpdateCallback(Baton* baton) { db->update_event->finish(); db->update_event = NULL; } - - delete baton; } void Database::UpdateCallback(void* db, int type, const char* database, @@ -547,18 +556,19 @@ void Database::UpdateCallback(void* db, int type, const char* database, static_cast(db)->update_event->send(info); } -void Database::UpdateCallback(Database *db, UpdateInfo* info) { +void Database::UpdateCallback(Database *db, UpdateInfo* i) { + std::unique_ptr info(i); Napi::Env env = db->Env(); Napi::HandleScope scope(env); Napi::Value argv[] = { + Napi::String::New(env, "change"), Napi::String::New(env, sqlite_authorizer_string(info->type)), Napi::String::New(env, info->database.c_str()), Napi::String::New(env, info->table.c_str()), Napi::Number::New(env, info->rowid), }; - EMIT_EVENT(db->Value(), 4, argv); - delete info; + EMIT_EVENT(db->Value(), 5, argv); } Napi::Value Database::Exec(const Napi::CallbackInfo& info) { @@ -579,6 +589,7 @@ void Database::Work_BeginExec(Baton* baton) { assert(baton->db->open); assert(baton->db->_handle); assert(baton->db->pending == 0); + baton->db->pending++; Napi::Env env = baton->db->Env(); int status = napi_create_async_work( env, NULL, Napi::String::New(env, "sqlite3.Database.Exec"), @@ -608,9 +619,10 @@ void Database::Work_Exec(napi_env e, void* data) { } void Database::Work_AfterExec(napi_env e, napi_status status, void* data) { - ExecBaton* baton = static_cast(data); + std::unique_ptr baton(static_cast(data)); Database* db = baton->db; + db->pending--; Napi::Env env = db->Env(); Napi::HandleScope scope(env); @@ -620,7 +632,7 @@ void Database::Work_AfterExec(napi_env e, napi_status status, void* data) { if (baton->status != SQLITE_OK) { EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { exception }; TRY_CATCH_CALL(db->Value(), cb, 1, argv); } @@ -629,15 +641,12 @@ void Database::Work_AfterExec(napi_env e, napi_status status, void* data) { EMIT_EVENT(db->Value(), 2, info); } } - else if (!cb.IsUndefined() && cb.IsFunction()) { + else if (IS_FUNCTION(cb)) { Napi::Value argv[] = { env.Null() }; TRY_CATCH_CALL(db->Value(), cb, 1, argv); } db->Process(); - - napi_delete_async_work(e, baton->request); - delete baton; } Napi::Value Database::Wait(const Napi::CallbackInfo& info) { @@ -652,7 +661,9 @@ Napi::Value Database::Wait(const Napi::CallbackInfo& info) { return info.This(); } -void Database::Work_Wait(Baton* baton) { +void Database::Work_Wait(Baton* b) { + std::unique_ptr baton(b); + Napi::Env env = baton->db->Env(); Napi::HandleScope scope(env); @@ -662,14 +673,12 @@ void Database::Work_Wait(Baton* baton) { assert(baton->db->pending == 0); Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { env.Null() }; TRY_CATCH_CALL(baton->db->Value(), cb, 1, argv); } baton->db->Process(); - - delete baton; } Napi::Value Database::LoadExtension(const Napi::CallbackInfo& info) { @@ -690,6 +699,7 @@ void Database::Work_BeginLoadExtension(Baton* baton) { assert(baton->db->open); assert(baton->db->_handle); assert(baton->db->pending == 0); + baton->db->pending++; Napi::Env env = baton->db->Env(); int status = napi_create_async_work( env, NULL, Napi::String::New(env, "sqlite3.Database.LoadExtension"), @@ -722,9 +732,10 @@ void Database::Work_LoadExtension(napi_env e, void* data) { } void Database::Work_AfterLoadExtension(napi_env e, napi_status status, void* data) { - LoadExtensionBaton* baton = static_cast(data); + std::unique_ptr baton(static_cast(data)); Database* db = baton->db; + db->pending--; Napi::Env env = db->Env(); Napi::HandleScope scope(env); @@ -734,7 +745,7 @@ void Database::Work_AfterLoadExtension(napi_env e, napi_status status, void* dat if (baton->status != SQLITE_OK) { EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { exception }; TRY_CATCH_CALL(db->Value(), cb, 1, argv); } @@ -743,15 +754,12 @@ void Database::Work_AfterLoadExtension(napi_env e, napi_status status, void* dat EMIT_EVENT(db->Value(), 2, info); } } - else if (!cb.IsUndefined() && cb.IsFunction()) { + else if (IS_FUNCTION(cb)) { Napi::Value argv[] = { env.Null() }; TRY_CATCH_CALL(db->Value(), cb, 1, argv); } db->Process(); - - napi_delete_async_work(e, baton->request); - delete baton; } void Database::RemoveCallbacks() { @@ -763,4 +771,8 @@ void Database::RemoveCallbacks() { debug_profile->finish(); debug_profile = NULL; } + if (update_event) { + update_event->finish(); + update_event = NULL; + } } diff --git a/src/database.h b/src/database.h index 45063b57b..420b5dd1c 100644 --- a/src/database.h +++ b/src/database.h @@ -21,7 +21,9 @@ class Database; class Database : public Napi::ObjectWrap { public: +#if NAPI_VERSION < 6 static Napi::FunctionReference constructor; +#endif static Napi::Object Init(Napi::Env env, Napi::Object exports); static inline bool HasInstance(Napi::Value val) { @@ -29,11 +31,17 @@ class Database : public Napi::ObjectWrap { Napi::HandleScope scope(env); if (!val.IsObject()) return false; Napi::Object obj = val.As(); +#if NAPI_VERSION < 6 return obj.InstanceOf(constructor.Value()); +#else + Napi::FunctionReference* constructor = + env.GetInstanceData(); + return obj.InstanceOf(constructor->Value()); +#endif } struct Baton { - napi_async_work request; + napi_async_work request = NULL; Database* db; Napi::FunctionReference callback; int status; @@ -47,6 +55,7 @@ class Database : public Napi::ObjectWrap { } } virtual ~Baton() { + if (request) napi_delete_async_work(db->Env(), request); db->Unref(); callback.Reset(); } diff --git a/src/gcc-preinclude.h b/src/gcc-preinclude.h index 9ea8c5765..f7e5ed59f 100644 --- a/src/gcc-preinclude.h +++ b/src/gcc-preinclude.h @@ -1,6 +1,28 @@ - // http://web.archive.org/web/20140401031018/http://rjpower9000.wordpress.com:80/2012/04/09/fun-with-shared-libraries-version-glibc_2-14-not-found/ -#if defined(__linux__) && defined(__x86_64__) +#if defined(__linux__) + +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE + +#if defined(__USE_GNU) + +#if defined(__x86_64__) __asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); +__asm__(".symver exp,exp@GLIBC_2.2.5"); +__asm__(".symver log,log@GLIBC_2.2.5"); +__asm__(".symver pow,pow@GLIBC_2.2.5"); +__asm__(".symver fcntl64,fcntl@GLIBC_2.2.5"); +#endif + +#if defined(__aarch64__) || defined(_M_ARM64) +__asm__(".symver memcpy,memcpy@GLIBC_2.17"); +__asm__(".symver exp,exp@GLIBC_2.17"); +__asm__(".symver log,log@GLIBC_2.17"); +__asm__(".symver pow,pow@GLIBC_2.17"); +__asm__(".symver fcntl64,fcntl@GLIBC_2.17"); +#endif + +#endif #endif diff --git a/src/macros.h b/src/macros.h index cd089fe56..cda290da8 100644 --- a/src/macros.h +++ b/src/macros.h @@ -23,6 +23,9 @@ inline bool OtherIsInt(Napi::Number source) { } } +#define IS_FUNCTION(cb) \ + !cb.IsUndefined() && cb.IsFunction() + #define REQUIRE_ARGUMENTS(n) \ if (info.Length() < (n)) { \ Napi::TypeError::New(env, "Expected " #n "arguments").ThrowAsJavaScriptException(); \ @@ -119,13 +122,14 @@ inline bool OtherIsInt(Napi::Number source) { // The Mac OS compiler complains when argv is NULL unless we // first assign it to a locally defined variable. -#define TRY_CATCH_CALL(context, callback, argc, argv) \ +#define TRY_CATCH_CALL(context, callback, argc, argv, ...) \ Napi::Value* passed_argv = argv;\ std::vector args;\ if ((argc != 0) && (passed_argv != NULL)) {\ args.assign(passed_argv, passed_argv + argc);\ }\ - (callback).MakeCallback(Napi::Value(context), args); + Napi::Value res = (callback).Call(Napi::Value(context), args); \ + if (res.IsEmpty()) return __VA_ARGS__; #define WORK_DEFINITION(name) \ Napi::Value name(const Napi::CallbackInfo& info); \ @@ -153,15 +157,21 @@ inline bool OtherIsInt(Napi::Number source) { type* baton = static_cast(data); \ Statement* stmt = baton->stmt; +#define STATEMENT_MUTEX(name) \ + if (!stmt->db->_handle) { \ + stmt->status = SQLITE_MISUSE; \ + stmt->message = "Database handle is closed"; \ + return; \ + } \ + sqlite3_mutex* name = sqlite3_db_mutex(stmt->db->_handle); + #define STATEMENT_END() \ assert(stmt->locked); \ assert(stmt->db->pending); \ stmt->locked = false; \ stmt->db->pending--; \ stmt->Process(); \ - stmt->db->Process(); \ - napi_delete_async_work(e, baton->request); \ - delete baton; + stmt->db->Process(); #define BACKUP_BEGIN(type) \ assert(baton); \ @@ -189,9 +199,7 @@ inline bool OtherIsInt(Napi::Number source) { backup->locked = false; \ backup->db->pending--; \ backup->Process(); \ - backup->db->Process(); \ - napi_delete_async_work(e, baton->request); \ - delete baton; + backup->db->Process(); #define DELETE_FIELD(field) \ if (field != NULL) { \ diff --git a/src/node_sqlite3.cc b/src/node_sqlite3.cc index 6f47a68a8..4cc16f1a1 100644 --- a/src/node_sqlite3.cc +++ b/src/node_sqlite3.cc @@ -125,4 +125,68 @@ const char* sqlite_authorizer_string(int type) { } } -NODE_API_MODULE(node_sqlite3, RegisterModule) + +/*************************************/ +/* Some hooks for Grist testing. */ +/*************************************/ + +Napi::Value Serialize(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + if (info.Length() > 0) { + Marshaller m; + m.marshalValue(info[0]); + const std::vector &buffer = m.getBuffer(); + Napi::Env env = info.Env(); + return Napi::Buffer::Copy(env, &buffer[0], buffer.size()); + } + return env.Null(); +} + +Napi::Value Parse(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + if (info.Length() > 0) { + if (!info[0].IsBuffer()) { + Napi::Error::New(env, "Argument must be a buffer").ThrowAsJavaScriptException(); + return env.Null(); + } else { + Napi::Buffer buffer = info[0].As>(); + Napi::Value result = Unmarshaller::parse(info, buffer.Data(), buffer.Length()); + if (!result.IsEmpty()) { + return result; + } + } + } + return env.Null(); +} + +Napi::Value TestOppositeEndianness(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + if (info.Length() > 0) { + marshalTestOppositeEndianness(info[0].As().Value()); + } + return env.Null(); +} + +Napi::Object RegisterTestHooks(Napi::Env env, Napi::Object exports) { + exports.Set(Napi::String::New(env, "serialize"), + Napi::Function::New(env, Serialize)); + exports.Set(Napi::String::New(env, "parse"), + Napi::Function::New(env, Parse)); + exports.Set(Napi::String::New(env, "testOppositeEndianness"), + Napi::Function::New(env, TestOppositeEndianness)); + return exports; +} + +Napi::Object RegisterModuleAndTestHooks(Napi::Env env, Napi::Object exports) { + RegisterModule(env, exports); + return RegisterTestHooks(env, exports); +} + + +/*************************************/ +/* End of hooks for Grist testing. */ +/*************************************/ + + + +NODE_API_MODULE(node_sqlite3, RegisterModuleAndTestHooks) diff --git a/src/statement.cc b/src/statement.cc index b387e2ee7..c882308b6 100644 --- a/src/statement.cc +++ b/src/statement.cc @@ -8,34 +8,32 @@ using namespace node_sqlite3; -Napi::FunctionReference Statement::constructor; - Napi::Object Statement::Init(Napi::Env env, Napi::Object exports) { Napi::HandleScope scope(env); + // declare napi_default_method here as it is only available in Node v14.12.0+ + napi_property_attributes napi_default_method = static_cast(napi_writable | napi_configurable); + Napi::Function t = DefineClass(env, "Statement", { - InstanceMethod("bind", &Statement::Bind), - InstanceMethod("get", &Statement::Get), - InstanceMethod("run", &Statement::Run), - InstanceMethod("all", &Statement::All), - InstanceMethod("allMarshal", &Statement::AllMarshal), - InstanceMethod("each", &Statement::Each), - InstanceMethod("reset", &Statement::Reset), - InstanceMethod("finalize", &Statement::Finalize_), + InstanceMethod("bind", &Statement::Bind, napi_default_method), + InstanceMethod("get", &Statement::Get, napi_default_method), + InstanceMethod("run", &Statement::Run, napi_default_method), + InstanceMethod("all", &Statement::All, napi_default_method), + InstanceMethod("allMarshal", &Statement::AllMarshal, napi_default_method), + InstanceMethod("each", &Statement::Each, napi_default_method), + InstanceMethod("reset", &Statement::Reset, napi_default_method), + InstanceMethod("finalize", &Statement::Finalize_, napi_default_method), }); - constructor = Napi::Persistent(t); - constructor.SuppressDestruct(); - exports.Set("Statement", t); return exports; } // A Napi InstanceOf for Javascript Objects "Date" and "RegExp" -bool OtherInstanceOf(Napi::Object source, char* object_type) { - if (object_type == "Date") { +bool OtherInstanceOf(Napi::Object source, const char* object_type) { + if (strncmp(object_type, "Date", 4) == 0) { return source.InstanceOf(source.Env().Global().Get("Date").As()); - } else if (object_type == "RegExp") { + } else if (strncmp(object_type, "RegExp", 6) == 0) { return source.InstanceOf(source.Env().Global().Get("RegExp").As()); } @@ -48,11 +46,10 @@ void Statement::Process() { } while (prepared && !locked && !queue.empty()) { - Call* call = queue.front(); + std::unique_ptr call(queue.front()); queue.pop(); call->callback(call->baton); - delete call; } } @@ -81,7 +78,7 @@ template void Statement::Error(T* baton) { Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { exception }; TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); } @@ -139,7 +136,7 @@ void Statement::Work_Prepare(napi_env e, void* data) { // In case preparing fails, we use a mutex to make sure we get the associated // error message. - sqlite3_mutex* mtx = sqlite3_db_mutex(baton->db->_handle); + STATEMENT_MUTEX(mtx); sqlite3_mutex_enter(mtx); stmt->status = sqlite3_prepare_v2( @@ -159,13 +156,14 @@ void Statement::Work_Prepare(napi_env e, void* data) { } void Statement::Work_AfterPrepare(napi_env e, napi_status status, void* data) { - STATEMENT_INIT(PrepareBaton); + std::unique_ptr baton(static_cast(data)); + Statement* stmt = baton->stmt; Napi::Env env = stmt->Env(); Napi::HandleScope scope(env); if (stmt->status != SQLITE_OK) { - Error(baton); + Error(baton.get()); stmt->Finalize_(); } else { @@ -211,7 +209,13 @@ template Values::Field* return new Values::Float(pos, source.ToNumber().DoubleValue()); } else if (source.IsObject()) { - std::string val = source.ToString().Utf8Value(); + Napi::String napiVal = source.ToString(); + // Check whether toString returned a value that is not undefined. + if(napiVal.Type() == 0) { + return NULL; + } + + std::string val = napiVal.Utf8Value(); return new Values::Text(pos, val.length(), val.c_str()); } else { @@ -353,25 +357,26 @@ void Statement::Work_BeginBind(Baton* baton) { void Statement::Work_Bind(napi_env e, void* data) { STATEMENT_INIT(Baton); - sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle); + STATEMENT_MUTEX(mtx); sqlite3_mutex_enter(mtx); stmt->Bind(baton->parameters); sqlite3_mutex_leave(mtx); } void Statement::Work_AfterBind(napi_env e, napi_status status, void* data) { - STATEMENT_INIT(Baton); + std::unique_ptr baton(static_cast(data)); + Statement* stmt = baton->stmt; Napi::Env env = stmt->Env(); Napi::HandleScope scope(env); if (stmt->status != SQLITE_OK) { - Error(baton); + Error(baton.get()); } else { // Fire callbacks. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { env.Null() }; TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); } @@ -405,7 +410,7 @@ void Statement::Work_Get(napi_env e, void* data) { STATEMENT_INIT(RowBaton); if (stmt->status != SQLITE_DONE || baton->parameters.size()) { - sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle); + STATEMENT_MUTEX(mtx); sqlite3_mutex_enter(mtx); if (stmt->Bind(baton->parameters)) { @@ -426,18 +431,19 @@ void Statement::Work_Get(napi_env e, void* data) { } void Statement::Work_AfterGet(napi_env e, napi_status status, void* data) { - STATEMENT_INIT(RowBaton); + std::unique_ptr baton(static_cast(data)); + Statement* stmt = baton->stmt; Napi::Env env = stmt->Env(); Napi::HandleScope scope(env); if (stmt->status != SQLITE_ROW && stmt->status != SQLITE_DONE) { - Error(baton); + Error(baton.get()); } else { // Fire callbacks. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { if (stmt->status == SQLITE_ROW) { // Create the result array from the data we acquired. Napi::Value argv[] = { env.Null(), RowToJS(env, &baton->row) }; @@ -475,7 +481,7 @@ void Statement::Work_BeginRun(Baton* baton) { void Statement::Work_Run(napi_env e, void* data) { STATEMENT_INIT(RunBaton); - sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle); + STATEMENT_MUTEX(mtx); sqlite3_mutex_enter(mtx); // Make sure that we also reset when there are no parameters. @@ -499,18 +505,19 @@ void Statement::Work_Run(napi_env e, void* data) { } void Statement::Work_AfterRun(napi_env e, napi_status status, void* data) { - STATEMENT_INIT(RunBaton); + std::unique_ptr baton(static_cast(data)); + Statement* stmt = baton->stmt; Napi::Env env = stmt->Env(); Napi::HandleScope scope(env); if (stmt->status != SQLITE_ROW && stmt->status != SQLITE_DONE) { - Error(baton); + Error(baton.get()); } else { // Fire callbacks. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { (stmt->Value()).Set(Napi::String::New(env, "lastID"), Napi::Number::New(env, baton->inserted_id)); (stmt->Value()).Set( Napi::String::New(env, "changes"), Napi::Number::New(env, baton->changes)); @@ -544,7 +551,7 @@ void Statement::Work_BeginAll(Baton* baton) { void Statement::Work_All(napi_env e, void* data) { STATEMENT_INIT(RowsBaton); - sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle); + STATEMENT_MUTEX(mtx); sqlite3_mutex_enter(mtx); // Make sure that we also reset when there are no parameters. @@ -568,26 +575,27 @@ void Statement::Work_All(napi_env e, void* data) { } void Statement::Work_AfterAll(napi_env e, napi_status status, void* data) { - STATEMENT_INIT(RowsBaton); + std::unique_ptr baton(static_cast(data)); + Statement* stmt = baton->stmt; Napi::Env env = stmt->Env(); Napi::HandleScope scope(env); if (stmt->status != SQLITE_DONE) { - Error(baton); + Error(baton.get()); } else { // Fire callbacks. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { if (baton->rows.size()) { // Create the result array from the data we acquired. Napi::Array result(Napi::Array::New(env, baton->rows.size())); Rows::const_iterator it = baton->rows.begin(); Rows::const_iterator end = baton->rows.end(); for (int i = 0; it < end; ++it, i++) { - (result).Set(i, RowToJS(env,*it)); - delete *it; + std::unique_ptr row(*it); + (result).Set(i, RowToJS(env,row.get())); } Napi::Value argv[] = { env.Null(), result }; @@ -760,7 +768,7 @@ void Statement::Work_Each(napi_env e, void* data) { Async* async = baton->async; - sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle); + STATEMENT_MUTEX(mtx); int retrieved = 0; @@ -823,17 +831,17 @@ void Statement::AsyncEach(uv_async_t* handle) { } Napi::Function cb = async->item_cb.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[2]; argv[0] = env.Null(); Rows::const_iterator it = rows.begin(); Rows::const_iterator end = rows.end(); for (int i = 0; it < end; ++it, i++) { - argv[1] = RowToJS(env,*it); + std::unique_ptr row(*it); + argv[1] = RowToJS(env,row.get()); async->retrieved++; TRY_CATCH_CALL(async->stmt->Value(), cb, 2, argv); - delete *it; } } } @@ -853,13 +861,14 @@ void Statement::AsyncEach(uv_async_t* handle) { } void Statement::Work_AfterEach(napi_env e, napi_status status, void* data) { - STATEMENT_INIT(EachBaton); + std::unique_ptr baton(static_cast(data)); + Statement* stmt = baton->stmt; Napi::Env env = stmt->Env(); Napi::HandleScope scope(env); if (stmt->status != SQLITE_DONE) { - Error(baton); + Error(baton.get()); } STATEMENT_END(); @@ -889,14 +898,15 @@ void Statement::Work_Reset(napi_env e, void* data) { } void Statement::Work_AfterReset(napi_env e, napi_status status, void* data) { - STATEMENT_INIT(Baton); + std::unique_ptr baton(static_cast(data)); + Statement* stmt = baton->stmt; Napi::Env env = stmt->Env(); Napi::HandleScope scope(env); // Fire callbacks. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { env.Null() }; TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); } @@ -943,11 +953,15 @@ Napi::Value Statement::RowToJS(Napi::Env env, Row* row) { } void Statement::GetRow(Row* row, sqlite3_stmt* stmt) { - int rows = sqlite3_column_count(stmt); + int cols = sqlite3_column_count(stmt); - for (int i = 0; i < rows; i++) { + for (int i = 0; i < cols; i++) { int type = sqlite3_column_type(stmt, i); const char* name = sqlite3_column_name(stmt, i); + if (name == NULL) { + assert(false); + } + switch (type) { case SQLITE_INTEGER: { row->push_back(new Values::Integer(name, sqlite3_column_int64(stmt, i))); @@ -985,7 +999,8 @@ Napi::Value Statement::Finalize_(const Napi::CallbackInfo& info) { return stmt->db->Value(); } -void Statement::Finalize_(Baton* baton) { +void Statement::Finalize_(Baton* b) { + std::unique_ptr baton(b); Napi::Env env = baton->stmt->Env(); Napi::HandleScope scope(env); @@ -993,11 +1008,9 @@ void Statement::Finalize_(Baton* baton) { // Fire callback in case there was one. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { TRY_CATCH_CALL(baton->stmt->Value(), cb, 0, NULL); } - - delete baton; } void Statement::Finalize_() { @@ -1024,21 +1037,17 @@ void Statement::CleanQueue() { // Clear out the queue so that this object can get GC'ed. while (!queue.empty()) { - Call* call = queue.front(); + std::unique_ptr call(queue.front()); queue.pop(); - Napi::Function cb = call->baton->callback.Value(); + std::unique_ptr baton(call->baton); + Napi::Function cb = baton->callback.Value(); if (prepared && !cb.IsEmpty() && cb.IsFunction()) { TRY_CATCH_CALL(Value(), cb, 1, argv); called = true; } - - // We don't call the actual callback, so we have to make sure that - // the baton gets destroyed. - delete call->baton; - delete call; } // When we couldn't call a callback function, emit an error on the @@ -1051,12 +1060,10 @@ void Statement::CleanQueue() { else while (!queue.empty()) { // Just delete all items in the queue; we already fired an event when // preparing the statement failed. - Call* call = queue.front(); + std::unique_ptr call(queue.front()); queue.pop(); - // We don't call the actual callback, so we have to make sure that // the baton gets destroyed. delete call->baton; - delete call; } } diff --git a/src/statement.h b/src/statement.h index 9ea62cfd9..e9335e1d6 100644 --- a/src/statement.h +++ b/src/statement.h @@ -73,13 +73,11 @@ typedef Row Parameters; class Statement : public Napi::ObjectWrap { public: - static Napi::FunctionReference constructor; - static Napi::Object Init(Napi::Env env, Napi::Object exports); static Napi::Value New(const Napi::CallbackInfo& info); struct Baton { - napi_async_work request; + napi_async_work request = NULL; Statement* stmt; Napi::FunctionReference callback; Parameters parameters; @@ -89,10 +87,11 @@ class Statement : public Napi::ObjectWrap { callback.Reset(cb_, 1); } virtual ~Baton() { - for (unsigned int i = 0; i < parameters.size(); i++) { + for (size_t i = 0; i < parameters.size(); i++) { Values::Field* field = parameters[i]; DELETE_FIELD(field); } + if (request) napi_delete_async_work(stmt->Env(), request); stmt->Unref(); callback.Reset(); } diff --git a/src/threading.h b/src/threading.h index fe738a4c0..7c7139bd3 100644 --- a/src/threading.h +++ b/src/threading.h @@ -1,48 +1,10 @@ #ifndef NODE_SQLITE3_SRC_THREADING_H #define NODE_SQLITE3_SRC_THREADING_H - -#ifdef _WIN32 - -#include - - #define NODE_SQLITE3_MUTEX_t HANDLE mutex; - - #define NODE_SQLITE3_MUTEX_INIT mutex = CreateMutex(NULL, FALSE, NULL); - - #define NODE_SQLITE3_MUTEX_LOCK(m) WaitForSingleObject(*m, INFINITE); - - #define NODE_SQLITE3_MUTEX_UNLOCK(m) ReleaseMutex(*m); - - #define NODE_SQLITE3_MUTEX_DESTROY CloseHandle(mutex); - -#elif defined(NODE_SQLITE3_BOOST_THREADING) - -#include - - #define NODE_SQLITE3_MUTEX_t boost::mutex mutex; - - #define NODE_SQLITE3_MUTEX_INIT - - #define NODE_SQLITE3_MUTEX_LOCK(m) (*m).lock(); - - #define NODE_SQLITE3_MUTEX_UNLOCK(m) (*m).unlock(); - - #define NODE_SQLITE3_MUTEX_DESTROY mutex.unlock(); - -#else - - #define NODE_SQLITE3_MUTEX_t pthread_mutex_t mutex; - - #define NODE_SQLITE3_MUTEX_INIT pthread_mutex_init(&mutex,NULL); - - #define NODE_SQLITE3_MUTEX_LOCK(m) pthread_mutex_lock(m); - - #define NODE_SQLITE3_MUTEX_UNLOCK(m) pthread_mutex_unlock(m); - - #define NODE_SQLITE3_MUTEX_DESTROY pthread_mutex_destroy(&mutex); - -#endif - +#define NODE_SQLITE3_MUTEX_t uv_mutex_t mutex; +#define NODE_SQLITE3_MUTEX_INIT uv_mutex_init(&mutex); +#define NODE_SQLITE3_MUTEX_LOCK(m) uv_mutex_lock(m); +#define NODE_SQLITE3_MUTEX_UNLOCK(m) uv_mutex_unlock(m); +#define NODE_SQLITE3_MUTEX_DESTROY uv_mutex_destroy(&mutex); #endif // NODE_SQLITE3_SRC_THREADING_H diff --git a/test/.eslintrc.js b/test/.eslintrc.js new file mode 100644 index 000000000..41371e2b6 --- /dev/null +++ b/test/.eslintrc.js @@ -0,0 +1,5 @@ +module.exports = { + env: { + mocha: true, + }, +}; diff --git a/test/async_calls.test.js b/test/async_calls.test.js new file mode 100644 index 000000000..9ce29a730 --- /dev/null +++ b/test/async_calls.test.js @@ -0,0 +1,42 @@ +"use strict" + +var sqlite3 = require('..'); +const assert = require("assert"); +const { createHook, executionAsyncId } = require("async_hooks"); + + +describe('async_hooks', function() { + let db; + let dbId; + let asyncHook; + + beforeEach(function() { + db = new sqlite3.Database(':memory:'); + + asyncHook = createHook({ + init(asyncId, type) { + if (dbId == null && type.startsWith("sqlite3.")) { + dbId = asyncId; + } + } + }).enable(); + }); + + it('should support performance measuring with async hooks', function(done) { + db.run("DROP TABLE user", () => { + const cbId = executionAsyncId(); + assert.strictEqual(cbId, dbId); + done(); + }); + }); + + afterEach(function() { + if (asyncHook != null) { + asyncHook.disable(); + } + dbId = null; + if (db != null) { + db.close(); + } + }); +}); \ No newline at end of file diff --git a/test/cpp/binding.gyp b/test/cpp/binding.gyp deleted file mode 100644 index d85a62f2f..000000000 --- a/test/cpp/binding.gyp +++ /dev/null @@ -1,19 +0,0 @@ -{ - "target_defaults": - { - "cflags" : ["-Wall", "-Wextra", "-Wno-unused-parameter"], - "defines": [ "V8_DEPRECATION_WARNINGS=1" ], - "conditions" : [ - ["OS=='linux'", {"libraries+": ["../../../build/<(PRODUCT_DIR)/node_sqlite3.node"] } ] - ], - "include_dirs": [ - " -#include -#include -#include -#include "../../src/marshal.h" - - -Napi::Value Serialize(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - if (info.Length() > 0) { - Marshaller m; - m.marshalValue(info[0]); - const std::vector &buffer = m.getBuffer(); - Napi::Env env = info.Env(); - return Napi::Buffer::Copy(env, &buffer[0], buffer.size()); - } - return env.Null(); -} - -Napi::Value Parse(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - if (info.Length() > 0) { - if (!info[0].IsBuffer()) { - Napi::Error::New(env, "Argument must be a buffer").ThrowAsJavaScriptException(); - return env.Null(); - } else { - Napi::Buffer buffer = info[0].As>(); - Napi::Value result = Unmarshaller::parse(info, buffer.Data(), buffer.Length()); - if (!result.IsEmpty()) { - return result; - } - } - } - return env.Null(); -} - -Napi::Value TestOppositeEndianness(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - if (info.Length() > 0) { - marshalTestOppositeEndianness(info[0].As().Value()); - } - return env.Null(); -} - -Napi::Object Init(Napi::Env env, Napi::Object exports) { - exports.Set(Napi::String::New(env, "serialize"), - Napi::Function::New(env, Serialize)); - exports.Set(Napi::String::New(env, "parse"), - Napi::Function::New(env, Parse)); - exports.Set(Napi::String::New(env, "testOppositeEndianness"), - Napi::Function::New(env, TestOppositeEndianness)); - return exports; -} - -NODE_API_MODULE(marshal, Init) diff --git a/test/electron.test.js b/test/electron.test.js index 24b7abf26..e2027456f 100644 --- a/test/electron.test.js +++ b/test/electron.test.js @@ -1,6 +1,8 @@ var assert = require('assert'); -describe('electron', function() { +// I can't find definitive documentation, but the napi-based binaries seem to run +// fine with Electron these days, no need for a special song and dance. +describe.skip('electron', function() { it('respects ELECTRON_VERSION', function() { process.env.ELECTRON_VERSION = '1.2.3'; let name = require.resolve('..'); diff --git a/test/issue-108.test.js b/test/issue-108.test.js index 637d2c0f4..99343782c 100644 --- a/test/issue-108.test.js +++ b/test/issue-108.test.js @@ -17,7 +17,7 @@ describe('buffer', function() { throw err; }); - var buff = new Buffer(2); + var buff = Buffer.alloc(2); stmt.run(buff); stmt.finalize(); }); diff --git a/test/marshal-test.js b/test/marshal-test.js index 5b9ee2fb3..62c8bd358 100644 --- a/test/marshal-test.js +++ b/test/marshal-test.js @@ -3,12 +3,7 @@ const path = require('path'); const assert = require('assert'); const util = require('util'); -const bindings = require('bindings'); - -const testRoot = path.resolve(__dirname, 'cpp'); -const mainRoot = path.resolve(__dirname, '..'); -bindings({ module_root: mainRoot, bindings: 'node_sqlite3' }); -const marshal = bindings({ module_root: testRoot, bindings: 'marshal' }); +const marshal = require('..'); // Marshaling test hooks are now in library. describe('marshal', function() { function stringToArray(str) { diff --git a/test/other_objects.test.js b/test/other_objects.test.js index 155951791..718598768 100644 --- a/test/other_objects.test.js +++ b/test/other_objects.test.js @@ -86,4 +86,13 @@ describe('data types', function() { }); }); }); + + it('should ignore faulty toString', function(done) { + const faulty = { toString: 23 }; + db.run("INSERT INTO txt_table VALUES(?)", faulty, function (err) { + assert.notEqual(err, undefined); + done(); + }); + }); + }); diff --git a/test/patching.test.js b/test/patching.test.js new file mode 100644 index 000000000..3f9f68d59 --- /dev/null +++ b/test/patching.test.js @@ -0,0 +1,184 @@ +var sqlite3 = require('..'); +var assert = require('assert'); + +describe('patching', function() { + describe("Database", function() { + var db; + var originalFunctions = {}; + + before(function() { + originalFunctions.close = sqlite3.Database.prototype.close; + originalFunctions.exec = sqlite3.Database.prototype.exec; + originalFunctions.wait = sqlite3.Database.prototype.wait; + originalFunctions.loadExtension = sqlite3.Database.prototype.loadExtension; + originalFunctions.serialize = sqlite3.Database.prototype.serialize; + originalFunctions.parallelize = sqlite3.Database.prototype.parallelize; + originalFunctions.configure = sqlite3.Database.prototype.configure; + originalFunctions.interrupt = sqlite3.Database.prototype.interrupt; + }); + + it('allow patching native functions', function() { + var myFun = function myFunction() { + return "Success"; + } + + assert.doesNotThrow(() => { + sqlite3.Database.prototype.close = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Database.prototype.exec = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Database.prototype.wait = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Database.prototype.loadExtension = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Database.prototype.serialize = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Database.prototype.parallelize = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Database.prototype.configure = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Database.prototype.interrupt = myFun; + }); + + db = new sqlite3.Database(':memory:'); + assert.strictEqual(db.close(), "Success"); + assert.strictEqual(db.exec(), "Success"); + assert.strictEqual(db.wait(), "Success"); + assert.strictEqual(db.loadExtension(), "Success"); + assert.strictEqual(db.serialize(), "Success"); + assert.strictEqual(db.parallelize(), "Success"); + assert.strictEqual(db.configure(), "Success"); + assert.strictEqual(db.interrupt(), "Success"); + }); + + after(function() { + if(db != null) { + sqlite3.Database.prototype.close = originalFunctions.close; + sqlite3.Database.prototype.exec = originalFunctions.exec; + sqlite3.Database.prototype.wait = originalFunctions.wait; + sqlite3.Database.prototype.loadExtension = originalFunctions.loadExtension; + sqlite3.Database.prototype.serialize = originalFunctions.serialize; + sqlite3.Database.prototype.parallelize = originalFunctions.parallelize; + sqlite3.Database.prototype.configure = originalFunctions.configure; + sqlite3.Database.prototype.interrupt = originalFunctions.interrupt; + db.close(); + } + }); + }); + + describe('Statement', function() { + var db; + var statement; + var originalFunctions = {}; + + before(function() { + originalFunctions.bind = sqlite3.Statement.prototype.bind; + originalFunctions.get = sqlite3.Statement.prototype.get; + originalFunctions.run = sqlite3.Statement.prototype.run; + originalFunctions.all = sqlite3.Statement.prototype.all; + originalFunctions.each = sqlite3.Statement.prototype.each; + originalFunctions.reset = sqlite3.Statement.prototype.reset; + originalFunctions.finalize = sqlite3.Statement.prototype.finalize; + }); + + it('allow patching native functions', function() { + var myFun = function myFunction() { + return "Success"; + } + + assert.doesNotThrow(() => { + sqlite3.Statement.prototype.bind = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Statement.prototype.get = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Statement.prototype.run = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Statement.prototype.all = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Statement.prototype.each = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Statement.prototype.reset = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Statement.prototype.finalize = myFun; + }); + + db = new sqlite3.Database(':memory:'); + statement = db.prepare(""); + assert.strictEqual(statement.bind(), "Success"); + assert.strictEqual(statement.get(), "Success"); + assert.strictEqual(statement.run(), "Success"); + assert.strictEqual(statement.all(), "Success"); + assert.strictEqual(statement.each(), "Success"); + assert.strictEqual(statement.reset(), "Success"); + assert.strictEqual(statement.finalize(), "Success"); + }); + + after(function() { + if(statement != null) { + sqlite3.Statement.prototype.bind = originalFunctions.bind; + sqlite3.Statement.prototype.get = originalFunctions.get; + sqlite3.Statement.prototype.run = originalFunctions.run; + sqlite3.Statement.prototype.all = originalFunctions.all; + sqlite3.Statement.prototype.each = originalFunctions.each; + sqlite3.Statement.prototype.reset = originalFunctions.reset; + sqlite3.Statement.prototype.finalize = originalFunctions.finalize; + } + if(db != null) { + db.close(); + } + }); + }); + + describe('Backup', function() { + var db; + var backup; + var originalFunctions = {}; + + before(function() { + originalFunctions.step = sqlite3.Backup.prototype.step; + originalFunctions.finish = sqlite3.Backup.prototype.finish; + }); + + it('allow patching native functions', function() { + var myFun = function myFunction() { + return "Success"; + } + + assert.doesNotThrow(() => { + sqlite3.Backup.prototype.step = myFun; + }); + assert.doesNotThrow(() => { + sqlite3.Backup.prototype.finish = myFun; + }); + + db = new sqlite3.Database(':memory:'); + backup = db.backup("somefile", myFun); + assert.strictEqual(backup.step(), "Success"); + assert.strictEqual(backup.finish(), "Success"); + }); + + after(function() { + if(backup != null) { + sqlite3.Backup.prototype.step = originalFunctions.step; + sqlite3.Backup.prototype.finish = originalFunctions.finish; + backup.finish(); + } + if(db != null) { + db.close(); + } + }); + }); +}); diff --git a/test/prepare.test.js b/test/prepare.test.js index c32db72a4..c237b6222 100644 --- a/test/prepare.test.js +++ b/test/prepare.test.js @@ -270,7 +270,7 @@ describe('prepare', function() { before(function(done) { db = new sqlite3.Database('test/support/prepare.db', sqlite3.OPEN_READONLY, done); }); it('should retrieve particular rows', function(done) { - db.prepare("SELECT txt, num, flt, blb FROM foo WHERE num > 5000") + db.prepare("SELECT txt, num, flt, blb FROM foo WHERE num > 5000") .all(function(err, rows) { if (err) throw err; assert.ok(rows.length === 0); diff --git a/test/profile.test.js b/test/profile.test.js index 6545f09c9..d8eb8b5d6 100644 --- a/test/profile.test.js +++ b/test/profile.test.js @@ -14,7 +14,6 @@ describe('profiling', function() { if (sql.match(/^SELECT/)) { assert.ok(!select); assert.equal(sql, "SELECT * FROM foo"); - console.log('profile select'); select = true; } else if (sql.match(/^CREATE/)) { diff --git a/test/support/createdb.js b/test/support/createdb.js index 0c35871da..3c7308ed8 100755 --- a/test/support/createdb.js +++ b/test/support/createdb.js @@ -16,7 +16,7 @@ function createdb(callback) { str += chars[Math.floor(Math.random() * chars.length)]; } return str; - }; + } if (existsSync(db_path)) { @@ -38,7 +38,7 @@ function createdb(callback) { }); }); } -}; +} if (require.main === module) { createdb(); diff --git a/test/support/helper.js b/test/support/helper.js index 10dc20c70..99671b8ff 100644 --- a/test/support/helper.js +++ b/test/support/helper.js @@ -15,8 +15,8 @@ exports.deleteFile = function(name) { exports.ensureExists = function(name,cb) { if (!pathExists(name)) { fs.mkdirSync(name); - }; -} + } +}; assert.fileDoesNotExist = function(name) { try { diff --git a/test/unicode.test.js b/test/unicode.test.js index b76ca4289..9a78c53d6 100644 --- a/test/unicode.test.js +++ b/test/unicode.test.js @@ -48,7 +48,7 @@ describe('unicode', function() { } else if (first < 0xe0) { return String.fromCharCode((first & 0x1f) << 0x6 | random_choice(trailing_values) & 0x3f); } else if (first == 0xe0) { - return String.fromCharCode(((first & 0xf) << 0xc) | ((random_choice(subranges[0]) & 0x3f) << 6) | random_choice(trailing_values) & 0x3f); + return String.fromCharCode(((first & 0xf) << 0xc) | ((random_choice(subranges[0]) & 0x3f) << 6) | random_choice(trailing_values) & 0x3f); } else if (first == 0xed) { return String.fromCharCode(((first & 0xf) << 0xc) | ((random_choice(subranges[1]) & 0x3f) << 6) | random_choice(trailing_values) & 0x3f); } else if (first < 0xf0) { @@ -58,7 +58,7 @@ describe('unicode', function() { function randomString() { var str = '', - i; + i; for (i = Math.random() * 300; i > 0; i--) { str += random_utf8(); @@ -68,7 +68,7 @@ describe('unicode', function() { } - // Generate random data. + // Generate random data. var data = []; var length = Math.floor(Math.random() * 1000) + 200; for (var i = 0; i < length; i++) { diff --git a/test/update_hook.test.js b/test/update_hook.test.js new file mode 100644 index 000000000..6507d2c83 --- /dev/null +++ b/test/update_hook.test.js @@ -0,0 +1,75 @@ +var sqlite3 = require('..'); +var assert = require('assert'); + +describe('update_hook', function() { + var db; + + beforeEach(function(done) { + db = new sqlite3.Database(':memory:', function(err) { + if (err) return done(err); + + db.run("CREATE TABLE update_hooks_test (id int PRIMARY KEY, value text)", done); + }); + }); + + it('emits insert event on inserting data to table', function(done) { + db.addListener('change', function(eventType, database, table, rowId) { + assert.equal(eventType, 'insert'); + assert.equal(database, 'main'); + assert.equal(table, 'update_hooks_test'); + assert.equal(rowId, 1); + + return done(); + }); + + db.run("INSERT INTO update_hooks_test VALUES (1, 'value')", function(err) { + if (err) return done(err); + }); + }); + + it('emits update event on row modification in table', function(done) { + db.run("INSERT INTO update_hooks_test VALUES (2, 'value'), (3, 'value4')", function(err) { + if (err) return done(err); + + db.addListener('change', function(eventType, database, table, rowId) { + assert.equal(eventType, 'update'); + assert.equal(database, 'main'); + assert.equal(table, 'update_hooks_test'); + assert.equal(rowId, 1); + + db.all("SELECT * FROM update_hooks_test WHERE rowid = ?", rowId, function(err, rows) { + assert.deepEqual(rows, [{ id: 2, value: 'new_val' }]); + + return done(err); + }); + }); + + db.run("UPDATE update_hooks_test SET value = 'new_val' WHERE id = 2", function(err) { + if (err) return done(err); + }); + }); + }); + + it('emits delete event on row was deleted from table', function(done) { + db.run("INSERT INTO update_hooks_test VALUES (2, 'value')", function(err) { + if (err) return done(err); + + db.addListener('change', function(eventType, database, table, rowId) { + assert.equal(eventType, 'delete'); + assert.equal(database, 'main'); + assert.equal(table, 'update_hooks_test'); + assert.equal(rowId, 1); + + return done(); + }); + + db.run("DELETE FROM update_hooks_test WHERE id = 2", function(err) { + if (err) return done(err); + }); + }); + }); + + afterEach(function(done) { + db.close(done); + }); +}); diff --git a/test/upsert.test.js b/test/upsert.test.js index f3e7e8c17..f2aa8fa8b 100644 --- a/test/upsert.test.js +++ b/test/upsert.test.js @@ -20,7 +20,7 @@ describe('query properties', function() { if (err) throw err; assert.equal(row.count, 3); // equals 3 }); - }) + }); }); db.wait(done); }); diff --git a/test/verbose.test.js b/test/verbose.test.js new file mode 100644 index 000000000..b680280c4 --- /dev/null +++ b/test/verbose.test.js @@ -0,0 +1,60 @@ +var sqlite3 = require('..'); +var assert = require('assert'); + +var invalid_sql = 'update non_existent_table set id=1'; + +var originalMethods = { + Database: {}, + Statement: {}, +}; + +function backupOriginalMethods() { + for (var obj in originalMethods) { + for (var attr in sqlite3[obj].prototype) { + originalMethods[obj][attr] = sqlite3[obj].prototype[attr]; + } + } +} + +function resetVerbose() { + for (var obj in originalMethods) { + for (var attr in originalMethods[obj]) { + sqlite3[obj].prototype[attr] = originalMethods[obj][attr]; + } + } +} + +describe('verbose', function() { + it('Shoud add trace info to error when verbose is called', function(done) { + var db = new sqlite3.Database(':memory:'); + backupOriginalMethods(); + sqlite3.verbose(); + + db.run(invalid_sql, function(err) { + assert(err instanceof Error); + + assert( + err.stack.indexOf(`Database#run('${invalid_sql}'`) > -1, + `Stack shoud contain trace info, stack = ${err.stack}` + ); + + done(); + resetVerbose(); + }); + }); + + it('Shoud not add trace info to error when verbose is not called', function(done) { + var db = new sqlite3.Database(':memory:'); + + db.run(invalid_sql, function(err) { + assert(err instanceof Error); + + assert( + err.stack.indexOf(invalid_sql) === -1, + `Stack shoud not contain trace info, stack = ${err.stack}` + ); + + done(); + }); + }); +}); diff --git a/tools/BinaryBuilder.Dockerfile b/tools/BinaryBuilder.Dockerfile new file mode 100644 index 000000000..ec0b9e59e --- /dev/null +++ b/tools/BinaryBuilder.Dockerfile @@ -0,0 +1,30 @@ +ARG NODE_VERSION=16 +ARG VARIANT=bullseye + +FROM node:$NODE_VERSION-$VARIANT + +ARG VARIANT + +RUN if [[ "$VARIANT" =~ alpine* ]] ; then apk add build-base python3 --update-cache ; fi + +WORKDIR /usr/src/build + +COPY . . +RUN npm install --ignore-scripts + +# Workaround for https://github.com/mapbox/node-pre-gyp/issues/644 +RUN cd node_modules/\@mapbox/node-pre-gyp \ + && npm install fs-extra@10.0.1 \ + && sed -i -e s/\'fs/\'fs-extra/ -e s/fs\.renameSync/fs.moveSync/ ./lib/util/napi.js + +ENV CFLAGS="${CFLAGS:-} -include ../src/gcc-preinclude.h" +ENV CXXFLAGS="${CXXFLAGS:-} -include ../src/gcc-preinclude.h" +RUN npx node-pre-gyp configure +RUN npx node-pre-gyp build + +RUN if [[ ! "$VARIANT" =~ alpine* ]] ; then ldd lib/binding/*/node_sqlite3.node; nm lib/binding/*/node_sqlite3.node | grep "GLIBC_" | c++filt || true ; fi + +RUN npm run test +RUN npx node-pre-gyp package + +CMD ["sh"] diff --git a/benchmark/insert-transaction.sql b/tools/benchmark/insert-transaction.sql similarity index 100% rename from benchmark/insert-transaction.sql rename to tools/benchmark/insert-transaction.sql diff --git a/benchmark/insert.js b/tools/benchmark/insert.js similarity index 96% rename from benchmark/insert.js rename to tools/benchmark/insert.js index c6810cfbe..f2ebf7b90 100644 --- a/benchmark/insert.js +++ b/tools/benchmark/insert.js @@ -1,4 +1,4 @@ -var sqlite3 = require('../lib/sqlite3'); +var sqlite3 = require('../../lib/sqlite3'); var fs = require('fs'); var iterations = 10000; @@ -8,7 +8,7 @@ exports.compare = { var db = new sqlite3.Database(''); var file = fs.readFileSync('benchmark/insert-transaction.sql', 'utf8'); db.exec(file); - db.close(finished) + db.close(finished); }, 'insert with transaction and two statements': function(finished) { diff --git a/tools/benchmark/select-data.sql b/tools/benchmark/select-data.sql new file mode 100644 index 000000000..64015274c --- /dev/null +++ b/tools/benchmark/select-data.sql @@ -0,0 +1,114 @@ +CREATE TEMP TABLE Bits (Bit INTEGER PRIMARY KEY); +INSERT INTO Bits VALUES (0); +INSERT INTO Bits VALUES (1); + +CREATE TEMP TABLE Nums AS SELECT + b9.Bit * 512 + b8.Bit * 256 + b7.Bit * 128 + b6.Bit * 64 + b5.Bit * 32 + + b4.Bit * 16 + b3.Bit * 8 + b2.Bit * 4 + b1.Bit * 2 + b0.Bit + AS Num +FROM Bits b9, Bits b8, Bits b7, Bits b6, Bits b5, + Bits b4, Bits b3, Bits b2, Bits b1, Bits b0; + +CREATE TABLE foo (id INT, txt TEXT); +BEGIN; +INSERT INTO foo SELECT 0 + Num, 'Row ' || ( 0 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 1000 + Num, 'Row ' || ( 1000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 2000 + Num, 'Row ' || ( 2000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 3000 + Num, 'Row ' || ( 3000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 4000 + Num, 'Row ' || ( 4000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 5000 + Num, 'Row ' || ( 5000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 6000 + Num, 'Row ' || ( 6000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 7000 + Num, 'Row ' || ( 7000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 8000 + Num, 'Row ' || ( 8000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 9000 + Num, 'Row ' || ( 9000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 10000 + Num, 'Row ' || (10000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 11000 + Num, 'Row ' || (11000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 12000 + Num, 'Row ' || (12000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 13000 + Num, 'Row ' || (13000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 14000 + Num, 'Row ' || (14000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 15000 + Num, 'Row ' || (15000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 16000 + Num, 'Row ' || (16000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 17000 + Num, 'Row ' || (17000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 18000 + Num, 'Row ' || (18000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 19000 + Num, 'Row ' || (19000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 20000 + Num, 'Row ' || (20000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 21000 + Num, 'Row ' || (21000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 22000 + Num, 'Row ' || (22000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 23000 + Num, 'Row ' || (23000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 24000 + Num, 'Row ' || (24000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 25000 + Num, 'Row ' || (25000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 26000 + Num, 'Row ' || (26000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 27000 + Num, 'Row ' || (27000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 28000 + Num, 'Row ' || (28000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 29000 + Num, 'Row ' || (29000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 30000 + Num, 'Row ' || (30000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 31000 + Num, 'Row ' || (31000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 32000 + Num, 'Row ' || (32000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 33000 + Num, 'Row ' || (33000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 34000 + Num, 'Row ' || (34000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 35000 + Num, 'Row ' || (35000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 36000 + Num, 'Row ' || (36000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 37000 + Num, 'Row ' || (37000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 38000 + Num, 'Row ' || (38000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 39000 + Num, 'Row ' || (39000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 40000 + Num, 'Row ' || (40000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 41000 + Num, 'Row ' || (41000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 42000 + Num, 'Row ' || (42000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 43000 + Num, 'Row ' || (43000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 44000 + Num, 'Row ' || (44000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 45000 + Num, 'Row ' || (45000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 46000 + Num, 'Row ' || (46000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 47000 + Num, 'Row ' || (47000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 48000 + Num, 'Row ' || (48000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 49000 + Num, 'Row ' || (49000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 50000 + Num, 'Row ' || (50000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 51000 + Num, 'Row ' || (51000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 52000 + Num, 'Row ' || (52000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 53000 + Num, 'Row ' || (53000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 54000 + Num, 'Row ' || (54000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 55000 + Num, 'Row ' || (55000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 56000 + Num, 'Row ' || (56000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 57000 + Num, 'Row ' || (57000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 58000 + Num, 'Row ' || (58000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 59000 + Num, 'Row ' || (59000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 60000 + Num, 'Row ' || (60000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 61000 + Num, 'Row ' || (61000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 62000 + Num, 'Row ' || (62000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 63000 + Num, 'Row ' || (63000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 64000 + Num, 'Row ' || (64000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 65000 + Num, 'Row ' || (65000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 66000 + Num, 'Row ' || (66000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 67000 + Num, 'Row ' || (67000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 68000 + Num, 'Row ' || (68000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 69000 + Num, 'Row ' || (69000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 70000 + Num, 'Row ' || (70000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 71000 + Num, 'Row ' || (71000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 72000 + Num, 'Row ' || (72000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 73000 + Num, 'Row ' || (73000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 74000 + Num, 'Row ' || (74000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 75000 + Num, 'Row ' || (75000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 76000 + Num, 'Row ' || (76000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 77000 + Num, 'Row ' || (77000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 78000 + Num, 'Row ' || (78000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 79000 + Num, 'Row ' || (79000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 80000 + Num, 'Row ' || (80000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 81000 + Num, 'Row ' || (81000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 82000 + Num, 'Row ' || (82000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 83000 + Num, 'Row ' || (83000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 84000 + Num, 'Row ' || (84000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 85000 + Num, 'Row ' || (85000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 86000 + Num, 'Row ' || (86000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 87000 + Num, 'Row ' || (87000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 88000 + Num, 'Row ' || (88000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 89000 + Num, 'Row ' || (89000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 90000 + Num, 'Row ' || (90000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 91000 + Num, 'Row ' || (91000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 92000 + Num, 'Row ' || (92000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 93000 + Num, 'Row ' || (93000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 94000 + Num, 'Row ' || (94000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 95000 + Num, 'Row ' || (95000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 96000 + Num, 'Row ' || (96000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 97000 + Num, 'Row ' || (97000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 98000 + Num, 'Row ' || (98000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +INSERT INTO foo SELECT 99000 + Num, 'Row ' || (99000 + Num) FROM Nums WHERE Num BETWEEN 1 AND 1000; +COMMIT; diff --git a/tools/benchmark/select.js b/tools/benchmark/select.js new file mode 100644 index 000000000..be4b0e71d --- /dev/null +++ b/tools/benchmark/select.js @@ -0,0 +1,28 @@ +const sqlite3 = require('../../'); +const { readFileSync } = require('fs'); +const db = new sqlite3.Database(':memory:'); + +db.serialize(() => { + db.exec(readFileSync(`${__dirname}/select-data.sql`, 'utf8'), (err) => { + if (err) throw err; + console.time('db.each'); + }); + + { + const results = []; + db.each('SELECT * FROM foo', (err, row) => { + if (err) throw err; + results.push(row); + }, () => { + console.timeEnd('db.each'); + console.time('db.all'); + }); + } + + db.all('SELECT * FROM foo', (err, rows) => { + console.timeEnd('db.all'); + if (err) throw err; + }); + + db.close(); +}); diff --git a/tools/docker/architecture/linux-arm/Dockerfile b/tools/docker/architecture/linux-arm/Dockerfile deleted file mode 100755 index ed587a774..000000000 --- a/tools/docker/architecture/linux-arm/Dockerfile +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/echo docker build . -f -# -*- coding: utf-8 -*- -# SPDX-License-Identifier: ISC -# Copyright 2019-present Samsung Electronics Co., Ltd. and other contributors -#{ -# ISC License -# Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") -# Copyright (c) 1995-2003 by Internet Software Consortium -# Permission to use, copy, modify, and /or distribute this software -# for any purpose with or without fee is hereby granted, -# provided that the above copyright notice -# and this permission notice appear in all copies. -# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS. -# IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, -# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, -# ARISING OUT OF OR IN CONNECTION WITH THE USE -# OR PERFORMANCE OF THIS SOFTWARE. -#} - -FROM resin/rpi-raspbian:stretch -MAINTAINER Philippe Coval (p.coval@samsung.com) - -RUN [ "cross-build-start" ] - -ENV DEBIAN_FRONTEND noninteractive -ENV LC_ALL en_US.UTF-8 -ENV LANG ${LC_ALL} - -RUN echo "#log: Configuring locales" \ - && set -x \ - && apt-get update -y \ - && apt-get install -y locales \ - && echo "${LC_ALL} UTF-8" | tee /etc/locale.gen \ - && locale-gen ${LC_ALL} \ - && dpkg-reconfigure locales \ - && sync - -ENV project node-sqlite3 - -RUN echo "#log: ${project}: Setup system" \ - && set -x \ - && apt-get update -y \ - && apt-get install -y \ - curl \ - sudo \ - build-essential \ - python \ - && apt-get clean \ - && NVM_VERSION="v0.33.8" \ - && NODE_VERSION="--lts=carbon" \ - && curl -o- https://raw.githubusercontent.com/creationix/nvm/${NVM_VERSION}/install.sh | bash \ - && which nvm || . ~/.bashrc \ - && nvm install ${NODE_VERSION} \ - && nvm use ${NODE_VERSION} \ - && sync - -ADD . /usr/local/opt/${project}/src/${project} -WORKDIR /usr/local/opt/${project}/src/${project} -RUN echo "#log: ${project}: Preparing sources" \ - && set -x \ - && which npm || . ~/.bashrc \ - && npm install || cat npm-debug.log \ - && npm install \ - && npm install --unsafe-perm --build-from-source \ - && sync - -WORKDIR /usr/local/opt/${project}/src/${project} -RUN echo "#log: ${project}: Building sources" \ - && set -x \ - && which npm || . ~/.bashrc \ - && npm run pack \ - && npm pack \ - && find ${PWD}/build/stage/ -type f \ - && sync - -RUN [ "cross-build-end" ] diff --git a/tools/docker/architecture/linux-arm/run.sh b/tools/docker/architecture/linux-arm/run.sh deleted file mode 100755 index 4f5c88566..000000000 --- a/tools/docker/architecture/linux-arm/run.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh -# -*- coding: utf-8 -*- -# SPDX-License-Identifier: ISC -# Copyright 2019-present Samsung Electronics Co., Ltd. and other contributors -#{ -# ISC License -# Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") -# Copyright (c) 1995-2003 by Internet Software Consortium -# Permission to use, copy, modify, and /or distribute this software -# for any purpose with or without fee is hereby granted, -# provided that the above copyright notice -# and this permission notice appear in all copies. -# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS. -# IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, -# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, -# ARISING OUT OF OR IN CONNECTION WITH THE USE -# OR PERFORMANCE OF THIS SOFTWARE. -#} - -set -e -set -x - -this_dir=$(dirname -- "$0") -this_dir=$(realpath "${this_dir}") -this_name=$(basename -- "$0") -top_dir="${this_dir}/../../.." - -module_name="sqlite3" -project="node-${module_name}" -arch="arm" -architecture=$(basename "${this_dir}") -name="${project}-${architecture}" -dir="/usr/local/opt/${project}/" -dist_dir="${dir}/src/${project}/build" -tag=$(git describe --tags || echo v0.0.0) -version=$(echo "${tag}" | cut -dv -f2 | cut -d'-' -f1) - -mkdir -p "${this_dir}/local" "${this_dir}/tmp" -cp -a "/usr/bin/qemu-${arch}-static" "${this_dir}/local" -time docker build -t "${name}" -f "${this_dir}/Dockerfile" . -container=$(docker create "${name}") -mkdir -p "${this_dir}/tmp/${dist_dir}" -rm -rf "${this_dir}/tmp/${dist_dir}" -docker cp "${container}:${dist_dir}" "${this_dir}/tmp/${dist_dir}" -file=$(ls "${this_dir}/tmp/${dist_dir}/stage/${module_name}/"*/*".tar.gz" | head -n1 \ - || echo "/tmp/${USER}/failure.tmp") - -sha256sum "${file}" diff --git a/tools/docker/architecture/linux-arm64/Dockerfile b/tools/docker/architecture/linux-arm64/Dockerfile deleted file mode 100755 index 5a19c7311..000000000 --- a/tools/docker/architecture/linux-arm64/Dockerfile +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/echo docker build . -f -# -*- coding: utf-8 -*- -# SPDX-License-Identifier: ISC -# Copyright 2019-present Samsung Electronics Co., Ltd. and other contributors -#{ -# ISC License -# Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") -# Copyright (c) 1995-2003 by Internet Software Consortium -# Permission to use, copy, modify, and /or distribute this software -# for any purpose with or without fee is hereby granted, -# provided that the above copyright notice -# and this permission notice appear in all copies. -# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS. -# IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, -# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, -# ARISING OUT OF OR IN CONNECTION WITH THE USE -# OR PERFORMANCE OF THIS SOFTWARE. -#} - -FROM arm64v8/node:carbon -ADD tools/docker/architecture/linux-arm64/local/qemu-aarch64-static /usr/bin/qemu-aarch64-static - -MAINTAINER Philippe Coval (p.coval@samsung.com) - -ENV DEBIAN_FRONTEND noninteractive -ENV LC_ALL en_US.UTF-8 -ENV LANG ${LC_ALL} - -RUN echo "#log: Configuring locales" \ - && set -x \ - && apt-get update -y \ - && apt-get install -y locales \ - && echo "${LC_ALL} UTF-8" | tee /etc/locale.gen \ - && locale-gen ${LC_ALL} \ - && dpkg-reconfigure locales \ - && sync - -ENV project node-sqlite3 - -RUN echo "#log: ${project}: Setup system" \ - && set -x \ - && apt-get update -y \ - && apt-get install -y \ - curl \ - sudo \ - build-essential \ - python \ - && apt-get clean \ - && NVM_VERSION="v0.33.8" \ - && NODE_VERSION="--lts=carbon" \ - && curl -o- https://raw.githubusercontent.com/creationix/nvm/${NVM_VERSION}/install.sh | bash \ - && which nvm || . ~/.bashrc \ - && nvm install ${NODE_VERSION} \ - && nvm use ${NODE_VERSION} \ - && sync - -ADD . /usr/local/opt/${project}/src/${project} -WORKDIR /usr/local/opt/${project}/src/${project} -RUN echo "#log: ${project}: Preparing sources" \ - && set -x \ - && which npm || . ~/.bashrc \ - && npm install || cat npm-debug.log \ - && npm install \ - && npm install --unsafe-perm --build-from-source \ - && sync - -WORKDIR /usr/local/opt/${project}/src/${project} -RUN echo "#log: ${project}: Building sources" \ - && set -x \ - && which npm || . ~/.bashrc \ - && npm run pack \ - && npm pack \ - && find ${PWD}/build/stage/ -type f \ - && sync - diff --git a/tools/docker/architecture/linux-arm64/run.sh b/tools/docker/architecture/linux-arm64/run.sh deleted file mode 100755 index 6bdda58fd..000000000 --- a/tools/docker/architecture/linux-arm64/run.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh -# -*- coding: utf-8 -*- -# SPDX-License-Identifier: ISC -# Copyright 2019-present Samsung Electronics Co., Ltd. and other contributors -#{ -# ISC License -# Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") -# Copyright (c) 1995-2003 by Internet Software Consortium -# Permission to use, copy, modify, and /or distribute this software -# for any purpose with or without fee is hereby granted, -# provided that the above copyright notice -# and this permission notice appear in all copies. -# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS. -# IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, -# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, -# ARISING OUT OF OR IN CONNECTION WITH THE USE -# OR PERFORMANCE OF THIS SOFTWARE. -#} - -set -e -set -x - -this_dir=$(dirname -- "$0") -this_dir=$(realpath "${this_dir}") -this_name=$(basename -- "$0") -top_dir="${this_dir}/../../.." - -module_name="sqlite3" -project="node-${module_name}" -arch="aarch64" # AKA: arm64, arm64v8 -architecture=$(basename "${this_dir}") -name="${project}-${architecture}" -dir="/usr/local/opt/${project}/" -dist_dir="${dir}/src/${project}/build" -tag=$(git describe --tags || echo v0.0.0) -version=$(echo "${tag}" | cut -dv -f2 | cut -d'-' -f1) - -mkdir -p "${this_dir}/local" "${this_dir}/tmp" -cp -a "/usr/bin/qemu-${arch}-static" "${this_dir}/local" -time docker build -t "${name}" -f "${this_dir}/Dockerfile" . -container=$(docker create "${name}") -mkdir -p "${this_dir}/tmp/${dist_dir}" -rm -rf "${this_dir}/tmp/${dist_dir}" -docker cp "${container}:${dist_dir}" "${this_dir}/tmp/${dist_dir}" -file=$(ls "${this_dir}/tmp/${dist_dir}/stage/${module_name}/"*/*".tar.gz" | head -n1 \ - || echo "/tmp/${USER}/failure.tmp") - -sha256sum "${file}"