pax_global_header00006660000000000000000000000064135652631700014522gustar00rootroot0000000000000052 comment=30f67bb246cabfc6a9d4cd026e6abedbcd0e2239 node-postgres-7.14.0/000077500000000000000000000000001356526317000144045ustar00rootroot00000000000000node-postgres-7.14.0/.eslintrc000066400000000000000000000003641356526317000162330ustar00rootroot00000000000000{ "plugins": [ "node" ], "extends": [ "standard", "eslint:recommended", "plugin:node/recommended" ], "parserOptions": { "ecmaVersion": 2017 }, "env": { "node": true, "es6": true }, "rules": { } } node-postgres-7.14.0/.gitignore000066400000000000000000000001041356526317000163670ustar00rootroot00000000000000*~ build/ .lock-wscript *.log node_modules/ package-lock.json *.swp node-postgres-7.14.0/.travis.yml000066400000000000000000000021021356526317000165100ustar00rootroot00000000000000language: node_js sudo: true dist: trusty before_script: - node script/create-test-tables.js pg://postgres@127.0.0.1:5432/postgres before_install: - if [ $TRAVIS_OS_NAME == "linux" ]; then if [[ $(node -v) =~ v[1-9][0-9] ]]; then source ./ci_scripts/build.sh; fi fi env: - CC=clang CXX=clang++ npm_config_clang=1 PGUSER=postgres PGDATABASE=postgres matrix: include: - node_js: "lts/boron" addons: postgresql: "9.6" - node_js: "lts/argon" addons: postgresql: "9.6" - node_js: "10" addons: postgresql: "9.6" - node_js: "12" addons: postgresql: "9.6" - node_js: "lts/carbon" addons: postgresql: "9.1" dist: precise - node_js: "lts/carbon" addons: postgresql: "9.2" - node_js: "lts/carbon" addons: postgresql: "9.3" - node_js: "lts/carbon" addons: postgresql: "9.4" - node_js: "lts/carbon" addons: postgresql: "9.5" - node_js: "lts/carbon" addons: postgresql: "9.6" node-postgres-7.14.0/CHANGELOG.md000066400000000000000000000363471356526317000162320ustar00rootroot00000000000000All major and minor releases are briefly explained below. For richer information consult the commit log on github with referenced pull requests. We do not include break-fix version release in this file. ### 7.14.0 - Reverts 7.13.0 as it contained [an accidental breaking change](https://github.com/brianc/node-postgres/pull/2010) for self-signed SSL cert verification. 7.14.0 is identical to 7.12.1. ### 7.13.0 - Add support for [all tls.connect()](https://github.com/brianc/node-postgres/pull/1996) options. ### 7.12.0 - Add support for [async password lookup](https://github.com/brianc/node-postgres/pull/1926). ### 7.11.0 - Add support for [connection_timeout](https://github.com/brianc/node-postgres/pull/1847/files#diff-5391bde944956870128be1136e7bc176R63) and [keepalives_idle](https://github.com/brianc/node-postgres/pull/1847). ### 7.10.0 - Add support for [per-query types](https://github.com/brianc/node-postgres/pull/1825). ### 7.9.0 - Add support for [sasl/scram authentication](https://github.com/brianc/node-postgres/pull/1835). ### 7.8.0 - Add support for passing [secureOptions](https://github.com/brianc/node-postgres/pull/1804) SSL config. - Upgrade [pg-types](https://github.com/brianc/node-postgres/pull/1806) to 2.0. ### 7.7.0 - Add support for configurable [query timeout](https://github.com/brianc/node-postgres/pull/1760) on a client level. ### 7.6.0 - Add support for ["bring your own promise"](https://github.com/brianc/node-postgres/pull/1518) ### 7.5.0 - Better [error message](https://github.com/brianc/node-postgres/commit/11a4793452d618c53e019416cc886ad38deb1aa7) when passing `null` or `undefined` to `client.query`. - Better [error handling](https://github.com/brianc/node-postgres/pull/1503) on queued queries. ### 7.4.0 - Add support for [Uint8Array](https://github.com/brianc/node-postgres/pull/1448) values. ### 7.3.0 - Add support for [statement timeout](https://github.com/brianc/node-postgres/pull/1436). ### 7.2.0 - Pinned pg-pool and pg-types to a tighter semver range. This is likely not a noticeable change for you unless you were specifically installing older versions of those libraries for some reason, but making it a minor bump here just in case it could cause any confusion. ### 7.1.0 #### Enhancements - [You can now supply both a connection string and additional config options to clients.](https://github.com/brianc/node-postgres/pull/1363) ### 7.0.0 #### Breaking Changes - Drop support for node < `4.x`. - Remove `pg.connect` `pg.end` and `pg.cancel` singleton methods. - `Client#connect(callback)` now returns `undefined`. It used to return an event emitter. - Upgrade [pg-pool](https://github.com/brianc/node-pg-pool) to `2.x`. - Upgrade [pg-native](https://github.com/brianc/node-pg-native) to `2.x`. - Standardize error message fields between JS and native driver. The only breaking changes were in the native driver as its field names were brought into alignment with the existing JS driver field names. - Result from multi-statement text queries such as `SELECT 1; SELECT 2;` are now returned as an array of results instead of a single result with 1 array containing rows from both queries. [Please see here for a migration guide](https://node-postgres.com/guides/upgrading) #### Enhancements - Overhauled documentation: [https://node-postgres.com](https://node-postgres.com). - Add `Client#connect() => Promise` and `Client#end() => Promise` calls. Promises are now returned from all async methods on clients _if and only if_ no callback was supplied to the method. - Add `connectionTimeoutMillis` to pg-pool. ### v6.2.0 - Add support for [parsing `replicationStart` messages](https://github.com/brianc/node-postgres/pull/1271/files). ### v6.1.0 - Add optional callback parameter to the pure JavaScript `client.end` method. The native client already supported this. ### v6.0.0 #### Breaking Changes - Remove `pg.pools`. There is still a reference kept to the pools created & tracked by `pg.connect` but it has been renamed, is considered private, and should not be used. Accessing this API directly was uncommon and was _supposed_ to be private but was incorrectly documented on the wiki. Therefore, it is a breaking change of an (unintentionally) public interface to remove it by renaming it & making it private. Eventually `pg.connect` itself will be deprecated in favor of instantiating pools directly via `new pg.Pool()` so this property should become completely moot at some point. In the mean time...check out the new features... #### New features - Replace internal pooling code with [pg-pool](https://github.com/brianc/node-pg-pool). This is the first step in eventually deprecating and removing the singleton `pg.connect`. The pg-pool constructor is exported from node-postgres at `require('pg').Pool`. It provides a backwards compatible interface with `pg.connect` as well as a promise based interface & additional niceties. You can now create an instance of a pool and don't have to rely on the `pg` singleton for anything: ``` var pg = require('pg') var pool = new pg.Pool() // your friendly neighborhood pool interface, without the singleton pool.connect(function(err, client, done) { // ... }) ``` Promise support & other goodness lives now in [pg-pool](https://github.com/brianc/node-pg-pool). **Please** read the readme at [pg-pool](https://github.com/brianc/node-pg-pool) for the full api. - Included support for tcp keep alive. Enable it as follows: ```js var client = new Client({ keepAlive: true }); ``` This should help with backends incorrectly considering idle clients to be dead and prematurely disconnecting them. ### v5.1.0 - Make the query object returned from `client.query` implement the promise interface. This is the first step towards promisifying more of the node-postgres api. Example: ```js var client = new Client(); client.connect(); client.query("SELECT $1::text as name", ["brianc"]).then(function(res) { console.log("hello from", res.rows[0]); client.end(); }); ``` ### v5.0.0 #### Breaking Changes - `require('pg').native` now returns null if the native bindings cannot be found; previously, this threw an exception. #### New Features - better error message when passing `undefined` as a query parameter - support for `defaults.connectionString` - support for `returnToHead` being passed to [generic pool](https://github.com/coopernurse/node-pool) ### v4.5.0 - Add option to parse JS date objects in query parameters as [UTC](https://github.com/brianc/node-postgres/pull/943) ### v4.4.0 - Warn to `stderr` if a named query exceeds 63 characters which is the max length supported by postgres. ### v4.3.0 - Unpin `pg-types` semver. Allow it to float against `pg-types@1.x`. ### v4.2.0 - Support for additional error fields in postgres >= 9.3 if available. ### v4.1.0 - Allow type parser overrides on a [per-client basis](https://github.com/brianc/node-postgres/pull/679) ### v4.0.0 - Make [native bindings](https://github.com/brianc/node-pg-native.git) an optional install with `npm install pg-native` - No longer surround query result callback with `try/catch` block. - Remove built in COPY IN / COPY OUT support - better implementations provided by [pg-copy-streams](https://github.com/brianc/node-pg-copy-streams.git) and [pg-native](https://github.com/brianc/node-pg-native.git) ### v3.6.0 - Include support for (parsing JSONB)[https://github.com/brianc/node-pg-types/pull/13] (supported in postgres 9.4) ### v3.5.0 - Include support for parsing boolean arrays ### v3.4.0 - Include port as connection parameter to [unix sockets](https://github.com/brianc/node-postgres/pull/604) - Better support for odd [date parsing](https://github.com/brianc/node-pg-types/pull/8) ### v3.2.0 - Add support for parsing [date arrays](https://github.com/brianc/node-pg-types/pull/3) - Expose array parsers on [pg.types](https://github.com/brianc/node-pg-types/pull/2) - Allow [pool](https://github.com/brianc/node-postgres/pull/591) to be configured ### v3.1.0 - Add [count of the number of times a client has been checked out from the pool](https://github.com/brianc/node-postgres/pull/556) - Emit `end` from `pg` object [when a pool is drained](https://github.com/brianc/node-postgres/pull/571) ### v3.0.0 #### Breaking changes - [Parse the DATE PostgreSQL type as local time](https://github.com/brianc/node-postgres/pull/514) After [some discussion](https://github.com/brianc/node-postgres/issues/510) it was decided node-postgres was non-compliant in how it was handling DATE results. They were being converted to UTC, but the PostgreSQL documentation specifies they should be returned in the client timezone. This is a breaking change, and if you use the `date` type you might want to examine your code and make sure nothing is impacted. - [Fix possible numeric precision loss on numeric & int8 arrays](https://github.com/brianc/node-postgres/pull/501) pg@v2.0 included changes to not convert large integers into their JavaScript number representation because of possibility for numeric precision loss. The same types in arrays were not taken into account. This fix applies the same type of type-coercion rules to arrays of those types, so there will be no more possible numeric loss on an array of very large int8s for example. This is a breaking change because now a return type from a query of `int8[]` will contain _string_ representations of the integers. Use your favorite JavaScript bignum module to represent them without precision loss, or punch over the type converter to return the old style arrays again. - [Fix to input array of dates being improperly converted to utc](https://github.com/benesch/node-postgres/commit/c41eedc3e01e5527a3d5c242fa1896f02ef0b261#diff-7172adb1fec2457a2700ed29008a8e0aR108) Single `date` parameters were properly sent to the PostgreSQL server properly in local time, but an input array of dates was being changed into utc dates. This is a violation of what PostgreSQL expects. Small breaking change, but none-the-less something you should check out if you are inserting an array of dates. - [Query no longer emits `end` event if it ends due to an error](https://github.com/brianc/node-postgres/commit/357b64d70431ec5ca721eb45a63b082c18e6ffa3) This is a small change to bring the semantics of query more in line with other EventEmitters. The tests all passed after this change, but I suppose it could still be a breaking change in certain use cases. If you are doing clever things with the `end` and `error` events of a query object you might want to check to make sure its still behaving normally, though it is most likely not an issue. #### New features - [Supercharge `prepareValue`](https://github.com/brianc/node-postgres/pull/555) The long & short of it is now any object you supply in the list of query values will be inspected for a `.toPostgres` method. If the method is present it will be called and its result used as the raw text value sent to PostgreSQL for that value. This allows the same type of custom type coercion on query parameters as was previously afforded to query result values. - [Domain aware connection pool](https://github.com/brianc/node-postgres/pull/531) If domains are active node-postgres will honor them and do everything it can to ensure all callbacks are properly fired in the active domain. If you have tried to use domains with node-postgres (or many other modules which pool long lived event emitters) you may have run into an issue where the active domain changes before and after a callback. This has been a longstanding footgun within node-postgres and I am happy to get it fixed. - [Disconnected clients now removed from pool](https://github.com/brianc/node-postgres/pull/543) Avoids a scenario where your pool could fill up with disconnected & unusable clients. - [Break type parsing code into separate module](https://github.com/brianc/node-postgres/pull/541) To provide better documentation and a clearer explanation of how to override the query result parsing system we broke the type converters [into their own module](https://github.com/brianc/node-pg-types). There is still work around removing the 'global-ness' of the type converters so each query or connection can return types differently, but this is a good first step and allow a lot more obvious way to return int8 results as JavaScript numbers, for example ### v2.11.0 - Add support for [application_name](https://github.com/brianc/node-postgres/pull/497) ### v2.10.0 - Add support for [the password file](http://www.postgresql.org/docs/9.3/static/libpq-pgpass.html) ### v2.9.0 - Add better support for [unix domain socket](https://github.com/brianc/node-postgres/pull/487) connections ### v2.8.0 - Add support for parsing JSON[] and UUID[] result types ### v2.7.0 - Use single row mode in native bindings when available [@rpedela] - reduces memory consumption when handling row values in 'row' event - Automatically bind buffer type parameters as binary [@eugeneware] ### v2.6.0 - Respect PGSSLMODE environment variable ### v2.5.0 - Ability to opt-in to int8 parsing via `pg.defaults.parseInt8 = true` ### v2.4.0 - Use eval in the result set parser to increase performance ### v2.3.0 - Remove built-in support for binary Int64 parsing. _Due to the low usage & required compiled dependency this will be pushed into a 3rd party add-on_ ### v2.2.0 - [Add support for excapeLiteral and escapeIdentifier in both JavaScript and the native bindings](https://github.com/brianc/node-postgres/pull/396) ### v2.1.0 - Add support for SSL connections in JavaScript driver - this means you can connect to heroku postgres from your local machine without the native bindings! - [Add field metadata to result object](https://github.com/brianc/node-postgres/blob/master/test/integration/client/row-description-on-results-tests.js) - [Add ability for rows to be returned as arrays instead of objects](https://github.com/brianc/node-postgres/blob/master/test/integration/client/results-as-array-tests.js) ### v2.0.0 - Properly handle various PostgreSQL to JavaScript type conversions to avoid data loss: ``` PostgreSQL | pg@v2.0 JavaScript | pg@v1.0 JavaScript --------------------------------|---------------- float4 | number (float) | string float8 | number (float) | string int8 | string | number (int) numeric | string | number (float) decimal | string | number (float) ``` For more information see https://github.com/brianc/node-postgres/pull/353 If you are unhappy with these changes you can always [override the built in type parsing fairly easily](https://github.com/brianc/node-pg-parse-float). ### v1.3.0 - Make client_encoding configurable and optional ### v1.2.0 - return field metadata on result object: access via result.fields[i].name/dataTypeID ### v1.1.0 - built in support for `JSON` data type for PostgreSQL Server @ v9.2.0 or greater ### v1.0.0 - remove deprecated functionality - Callback function passed to `pg.connect` now **requires** 3 arguments - Client#pauseDrain() / Client#resumeDrain removed - numeric, decimal, and float data types no longer parsed into float before being returned. Will be returned from query results as `String` ### v0.15.0 - client now emits `end` when disconnected from back-end server - if client is disconnected in the middle of a query, query receives an error ### v0.14.0 - add deprecation warnings in prep for v1.0 - fix read/write failures in native module under node v0.9.x node-postgres-7.14.0/LICENSE000066400000000000000000000020651356526317000154140ustar00rootroot00000000000000MIT License Copyright (c) 2010 - 2019 Brian Carlson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. node-postgres-7.14.0/Makefile000066400000000000000000000034111356526317000160430ustar00rootroot00000000000000SHELL := /bin/sh connectionString=postgres:// params := $(connectionString) node-command := xargs -n 1 -I file node file $(params) .PHONY : test test-connection test-integration bench test-native \ lint publish test-missing-native update-npm all: npm install help: @echo "make test-all [connectionString=postgres://]" test: test-unit test-all: lint test-missing-native test-unit test-integration test-native update-npm: @npm i npm --global bench: @find benchmark -name "*-bench.js" | $(node-command) test-unit: @find test/unit -name "*-tests.js" | $(node-command) test-connection: @echo "***Testing connection***" @node script/create-test-tables.js $(params) test-missing-native: @echo "***Testing optional native install***" @rm -rf node_modules/pg-native @rm -rf node_modules/libpq @node test/native/missing-native.js @rm -rf node_modules/pg-native @rm -rf node_modules/libpq node_modules/pg-native/index.js: @npm i --no-save pg-native test-native: node_modules/pg-native/index.js test-connection @echo "***Testing native bindings***" @find test/native -name "*-tests.js" | $(node-command) @find test/integration -name "*-tests.js" | $(node-command) native test-integration: test-connection @echo "***Testing Pure Javascript***" @find test/integration -name "*-tests.js" | $(node-command) test-binary: test-connection @echo "***Testing Pure Javascript (binary)***" @find test/integration -name "*-tests.js" | $(node-command) binary test-pool: @find test/integration/connection-pool -name "*.js" | $(node-command) binary lint: @echo "***Starting lint***" node -e "process.exit(Number(process.versions.node.split('.')[0]) < 8 ? 0 : 1)" \ && echo "***Skipping lint (node version too old)***" \ || node_modules/.bin/eslint lib node-postgres-7.14.0/README.md000066400000000000000000000100621356526317000156620ustar00rootroot00000000000000# node-postgres [![Build Status](https://secure.travis-ci.org/brianc/node-postgres.svg?branch=master)](http://travis-ci.org/brianc/node-postgres) [![Dependency Status](https://david-dm.org/brianc/node-postgres.svg)](https://david-dm.org/brianc/node-postgres) NPM version NPM downloads Non-blocking PostgreSQL client for Node.js. Pure JavaScript and optional native libpq bindings. ## Install ```sh $ npm install pg ``` --- ## :star: [Documentation](https://node-postgres.com) :star: ### Features * Pure JavaScript client and native libpq bindings share _the same API_ * Connection pooling * Extensible JS ↔ PostgreSQL data-type coercion * Supported PostgreSQL features * Parameterized queries * Named statements with query plan caching * Async notifications with `LISTEN/NOTIFY` * Bulk import & export with `COPY TO/COPY FROM` ### Extras node-postgres is by design pretty light on abstractions. These are some handy modules we've been using over the years to complete the picture. The entire list can be found on our [wiki](https://github.com/brianc/node-postgres/wiki/Extras). ## Support node-postgres is free software. If you encounter a bug with the library please open an issue on the [GitHub repo](https://github.com/brianc/node-postgres). If you have questions unanswered by the documentation please open an issue pointing out how the documentation was unclear & I will do my best to make it better! When you open an issue please provide: - version of Node - version of Postgres - smallest possible snippet of code to reproduce the problem You can also follow me [@briancarlson](https://twitter.com/briancarlson) if that's your thing. I try to always announce noteworthy changes & developments with node-postgres on Twitter. ### Professional Support I offer professional support for node-postgres. I provide implementation, training, and many years of expertise on how to build applications with Node, Express, PostgreSQL, and React/Redux. Please contact me at [brian.m.carlson@gmail.com](mailto:brian.m.carlson@gmail.com) to discuss how I can help your company be more successful! ### Sponsorship :star: If you are benefiting from node-postgres and would like to help keep the project financially sustainable please visit Brian Carlson's [Patreon page](https://www.patreon.com/node_postgres). ## Contributing __:heart: contributions!__ I will __happily__ accept your pull request if it: - __has tests__ - looks reasonable - does not break backwards compatibility ## Troubleshooting and FAQ The causes and solutions to common errors can be found among the [Frequently Asked Questions (FAQ)](https://github.com/brianc/node-postgres/wiki/FAQ) ## License Copyright (c) 2010-2019 Brian Carlson (brian.m.carlson@gmail.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. node-postgres-7.14.0/SPONSORS.md000066400000000000000000000015461356526317000162220ustar00rootroot00000000000000node-postgres is made possible by the helpful contributors from the community well as the following generous supporters on [Patreon](https://www.patreon.com/node_postgres). # Leaders - [MadKudu](https://www.madkudu.com) - [@madkudu](https://twitter.com/madkudu) - [Third Iron](https://thirdiron.com/) - [Timescale](https://timescale.com) - [Nafundi](https://nafundi.com) # Supporters - John Fawcett - Lalit Kapoor [@lalitkapoor](https://twitter.com/lalitkapoor) - Paul Frazee [@pfrazee](https://twitter.com/pfrazee) - Rein Petersen - Arnaud Benhamdine [@abenhamdine](https://twitter.com/abenhamdine) - Matthew Welke - Matthew Weber - Andrea De Simon - Todd Kennedy - Alexander Robson - Benjie Gillam - David Hanson - Franklin Davenport - [Eventbot](https://geteventbot.com/) - Chuck T - Paul Cothenet - Pelle Wessman - Raul Murray - Simple Analytics - Trevor Linton node-postgres-7.14.0/ci_scripts/000077500000000000000000000000001356526317000165465ustar00rootroot00000000000000node-postgres-7.14.0/ci_scripts/build.sh000066400000000000000000000002511356526317000201770ustar00rootroot00000000000000#!/bin/sh BUILD_DIR="$(pwd)" source ./ci_scripts/install_openssl.sh 1.1.1b sudo updatedb source ./ci_scripts/install_libpq.sh sudo updatedb sudo ldconfig cd $BUILD_DIR node-postgres-7.14.0/ci_scripts/install_libpq.sh000066400000000000000000000021251356526317000217370ustar00rootroot00000000000000#!/bin/bash set -e OPENSSL_DIR="$(pwd)/openssl-1.1.1b" POSTGRES_VERSION="11.3" POSTGRES_DIR="$(pwd)/postgres-${POSTGRES_VERSION}" TMP_DIR="/tmp/postgres" JOBS="-j$(nproc || echo 1)" if [ -d "${TMP_DIR}" ]; then rm -rf "${TMP_DIR}" fi mkdir -p "${TMP_DIR}" curl https://ftp.postgresql.org/pub/source/v${POSTGRES_VERSION}/postgresql-${POSTGRES_VERSION}.tar.gz | \ tar -C "${TMP_DIR}" -xzf - cd "${TMP_DIR}/postgresql-${POSTGRES_VERSION}" if [ -d "${POSTGRES_DIR}" ]; then rm -rf "${POSTGRES_DIR}" fi mkdir -p $POSTGRES_DIR ./configure --prefix=$POSTGRES_DIR --with-openssl --with-includes=${OPENSSL_DIR}/include --with-libraries=${OPENSSL_DIR}/lib --without-readline cd src/interfaces/libpq; make; make install; cd - cd src/bin/pg_config; make install; cd - cd src/backend; make generated-headers; cd - cd src/include; make install; cd - export PATH="${POSTGRES_DIR}/bin:${PATH}" export CFLAGS="-I${POSTGRES_DIR}/include" export LDFLAGS="-L${POSTGRES_DIR}/lib" export LD_LIBRARY_PATH="${POSTGRES_DIR}/lib:$LD_LIBRARY_PATH" export PKG_CONFIG_PATH="${POSTGRES_DIR}/lib/pkgconfig:$PKG_CONFIG_PATH" node-postgres-7.14.0/ci_scripts/install_openssl.sh000066400000000000000000000015741356526317000223220ustar00rootroot00000000000000#!/bin/sh if [ ${#} -lt 1 ]; then echo "OpenSSL version required." 1>&2 exit 1 fi OPENSSL_VERSION="${1}" OPENSSL_DIR="$(pwd)/openssl-${OPENSSL_VERSION}" TMP_DIR="/tmp/openssl" JOBS="-j$(nproc)" if [ -d "${TMP_DIR}" ]; then rm -rf "${TMP_DIR}" fi mkdir -p "${TMP_DIR}" curl -s https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz | \ tar -C "${TMP_DIR}" -xzf - pushd "${TMP_DIR}/openssl-${OPENSSL_VERSION}" if [ -d "${OPENSSL_DIR}" ]; then rm -rf "${OPENSSL_DIR}" fi ./Configure \ --prefix=${OPENSSL_DIR} \ enable-crypto-mdebug enable-crypto-mdebug-backtrace \ linux-x86_64 make -s $JOBS make install_sw popd export PATH="${OPENSSL_DIR}/bin:${PATH}" export CFLAGS="-I${OPENSSL_DIR}/include" export LDFLAGS="-L${OPENSSL_DIR}/lib" export LD_LIBRARY_PATH="${OPENSSL_DIR}/lib:$LD_LIBRARY_PATH" export PKG_CONFIG_PATH="${OPENSSL_DIR}/lib/pkgconfig:$PKG_CONFIG_PATH" node-postgres-7.14.0/lib/000077500000000000000000000000001356526317000151525ustar00rootroot00000000000000node-postgres-7.14.0/lib/client.js000066400000000000000000000353171356526317000167770ustar00rootroot00000000000000'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ var EventEmitter = require('events').EventEmitter var util = require('util') var utils = require('./utils') var sasl = require('./sasl') var pgPass = require('pgpass') var TypeOverrides = require('./type-overrides') var ConnectionParameters = require('./connection-parameters') var Query = require('./query') var defaults = require('./defaults') var Connection = require('./connection') var Client = function (config) { EventEmitter.call(this) this.connectionParameters = new ConnectionParameters(config) this.user = this.connectionParameters.user this.database = this.connectionParameters.database this.port = this.connectionParameters.port this.host = this.connectionParameters.host this.password = this.connectionParameters.password this.replication = this.connectionParameters.replication var c = config || {} this._Promise = c.Promise || global.Promise this._types = new TypeOverrides(c.types) this._ending = false this._connecting = false this._connected = false this._connectionError = false this._queryable = true this.connection = c.connection || new Connection({ stream: c.stream, ssl: this.connectionParameters.ssl, keepAlive: c.keepAlive || false, keepAliveInitialDelayMillis: c.keepAliveInitialDelayMillis || 0, encoding: this.connectionParameters.client_encoding || 'utf8' }) this.queryQueue = [] this.binary = c.binary || defaults.binary this.processID = null this.secretKey = null this.ssl = this.connectionParameters.ssl || false this._connectionTimeoutMillis = c.connectionTimeoutMillis || 0 } util.inherits(Client, EventEmitter) Client.prototype._errorAllQueries = function (err) { const enqueueError = (query) => { process.nextTick(() => { query.handleError(err, this.connection) }) } if (this.activeQuery) { enqueueError(this.activeQuery) this.activeQuery = null } this.queryQueue.forEach(enqueueError) this.queryQueue.length = 0 } Client.prototype._connect = function (callback) { var self = this var con = this.connection if (this._connecting || this._connected) { const err = new Error('Client has already been connected. You cannot reuse a client.') process.nextTick(() => { callback(err) }) return } this._connecting = true var connectionTimeoutHandle if (this._connectionTimeoutMillis > 0) { connectionTimeoutHandle = setTimeout(() => { con._ending = true con.stream.destroy(new Error('timeout expired')) }, this._connectionTimeoutMillis) } if (this.host && this.host.indexOf('/') === 0) { con.connect(this.host + '/.s.PGSQL.' + this.port) } else { con.connect(this.port, this.host) } // once connection is established send startup message con.on('connect', function () { if (self.ssl) { con.requestSsl() } else { con.startup(self.getStartupConf()) } }) con.on('sslconnect', function () { con.startup(self.getStartupConf()) }) function checkPgPass (cb) { return function (msg) { if (typeof self.password === 'function') { self._Promise.resolve() .then(() => self.password()) .then(pass => { if (pass !== undefined) { if (typeof pass !== 'string') { con.emit('error', new TypeError('Password must be a string')) return } self.connectionParameters.password = self.password = pass } else { self.connectionParameters.password = self.password = null } cb(msg) }).catch(err => { con.emit('error', err) }) } else if (self.password !== null) { cb(msg) } else { pgPass(self.connectionParameters, function (pass) { if (undefined !== pass) { self.connectionParameters.password = self.password = pass } cb(msg) }) } } } // password request handling con.on('authenticationCleartextPassword', checkPgPass(function () { con.password(self.password) })) // password request handling con.on('authenticationMD5Password', checkPgPass(function (msg) { con.password(utils.postgresMd5PasswordHash(self.user, self.password, msg.salt)) })) // password request handling (SASL) var saslSession con.on('authenticationSASL', checkPgPass(function (msg) { saslSession = sasl.startSession(msg.mechanisms) con.sendSASLInitialResponseMessage(saslSession.mechanism, saslSession.response) })) // password request handling (SASL) con.on('authenticationSASLContinue', function (msg) { sasl.continueSession(saslSession, self.password, msg.data) con.sendSCRAMClientFinalMessage(saslSession.response) }) // password request handling (SASL) con.on('authenticationSASLFinal', function (msg) { sasl.finalizeSession(saslSession, msg.data) saslSession = null }) con.once('backendKeyData', function (msg) { self.processID = msg.processID self.secretKey = msg.secretKey }) const connectingErrorHandler = (err) => { if (this._connectionError) { return } this._connectionError = true clearTimeout(connectionTimeoutHandle) if (callback) { return callback(err) } this.emit('error', err) } const connectedErrorHandler = (err) => { this._queryable = false this._errorAllQueries(err) this.emit('error', err) } const connectedErrorMessageHandler = (msg) => { const activeQuery = this.activeQuery if (!activeQuery) { connectedErrorHandler(msg) return } this.activeQuery = null activeQuery.handleError(msg, con) } con.on('error', connectingErrorHandler) con.on('errorMessage', connectingErrorHandler) // hook up query handling events to connection // after the connection initially becomes ready for queries con.once('readyForQuery', function () { self._connecting = false self._connected = true self._attachListeners(con) con.removeListener('error', connectingErrorHandler) con.removeListener('errorMessage', connectingErrorHandler) con.on('error', connectedErrorHandler) con.on('errorMessage', connectedErrorMessageHandler) clearTimeout(connectionTimeoutHandle) // process possible callback argument to Client#connect if (callback) { callback(null, self) // remove callback for proper error handling // after the connect event callback = null } self.emit('connect') }) con.on('readyForQuery', function () { var activeQuery = self.activeQuery self.activeQuery = null self.readyForQuery = true if (activeQuery) { activeQuery.handleReadyForQuery(con) } self._pulseQueryQueue() }) con.once('end', () => { const error = this._ending ? new Error('Connection terminated') : new Error('Connection terminated unexpectedly') this._errorAllQueries(error) if (!this._ending) { // if the connection is ended without us calling .end() // on this client then we have an unexpected disconnection // treat this as an error unless we've already emitted an error // during connection. if (this._connecting && !this._connectionError) { if (callback) { callback(error) } else { connectedErrorHandler(error) } } else if (!this._connectionError) { connectedErrorHandler(error) } } process.nextTick(() => { this.emit('end') }) }) con.on('notice', function (msg) { self.emit('notice', msg) }) } Client.prototype.connect = function (callback) { if (callback) { this._connect(callback) return } return new this._Promise((resolve, reject) => { this._connect((error) => { if (error) { reject(error) } else { resolve() } }) }) } Client.prototype._attachListeners = function (con) { const self = this // delegate rowDescription to active query con.on('rowDescription', function (msg) { self.activeQuery.handleRowDescription(msg) }) // delegate dataRow to active query con.on('dataRow', function (msg) { self.activeQuery.handleDataRow(msg) }) // delegate portalSuspended to active query // eslint-disable-next-line no-unused-vars con.on('portalSuspended', function (msg) { self.activeQuery.handlePortalSuspended(con) }) // delegate emptyQuery to active query // eslint-disable-next-line no-unused-vars con.on('emptyQuery', function (msg) { self.activeQuery.handleEmptyQuery(con) }) // delegate commandComplete to active query con.on('commandComplete', function (msg) { self.activeQuery.handleCommandComplete(msg, con) }) // if a prepared statement has a name and properly parses // we track that its already been executed so we don't parse // it again on the same client // eslint-disable-next-line no-unused-vars con.on('parseComplete', function (msg) { if (self.activeQuery.name) { con.parsedStatements[self.activeQuery.name] = self.activeQuery.text } }) // eslint-disable-next-line no-unused-vars con.on('copyInResponse', function (msg) { self.activeQuery.handleCopyInResponse(self.connection) }) con.on('copyData', function (msg) { self.activeQuery.handleCopyData(msg, self.connection) }) con.on('notification', function (msg) { self.emit('notification', msg) }) } Client.prototype.getStartupConf = function () { var params = this.connectionParameters var data = { user: params.user, database: params.database } var appName = params.application_name || params.fallback_application_name if (appName) { data.application_name = appName } if (params.replication) { data.replication = '' + params.replication } if (params.statement_timeout) { data.statement_timeout = String(parseInt(params.statement_timeout, 10)) } return data } Client.prototype.cancel = function (client, query) { if (client.activeQuery === query) { var con = this.connection if (this.host && this.host.indexOf('/') === 0) { con.connect(this.host + '/.s.PGSQL.' + this.port) } else { con.connect(this.port, this.host) } // once connection is established send cancel message con.on('connect', function () { con.cancel(client.processID, client.secretKey) }) } else if (client.queryQueue.indexOf(query) !== -1) { client.queryQueue.splice(client.queryQueue.indexOf(query), 1) } } Client.prototype.setTypeParser = function (oid, format, parseFn) { return this._types.setTypeParser(oid, format, parseFn) } Client.prototype.getTypeParser = function (oid, format) { return this._types.getTypeParser(oid, format) } // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c Client.prototype.escapeIdentifier = function (str) { return '"' + str.replace(/"/g, '""') + '"' } // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c Client.prototype.escapeLiteral = function (str) { var hasBackslash = false var escaped = '\'' for (var i = 0; i < str.length; i++) { var c = str[i] if (c === '\'') { escaped += c + c } else if (c === '\\') { escaped += c + c hasBackslash = true } else { escaped += c } } escaped += '\'' if (hasBackslash === true) { escaped = ' E' + escaped } return escaped } Client.prototype._pulseQueryQueue = function () { if (this.readyForQuery === true) { this.activeQuery = this.queryQueue.shift() if (this.activeQuery) { this.readyForQuery = false this.hasExecuted = true const queryError = this.activeQuery.submit(this.connection) if (queryError) { process.nextTick(() => { this.activeQuery.handleError(queryError, this.connection) this.readyForQuery = true this._pulseQueryQueue() }) } } else if (this.hasExecuted) { this.activeQuery = null this.emit('drain') } } } Client.prototype.query = function (config, values, callback) { // can take in strings, config object or query object var query var result var readTimeout var readTimeoutTimer var queryCallback if (config === null || config === undefined) { throw new TypeError('Client was passed a null or undefined query') } else if (typeof config.submit === 'function') { readTimeout = config.query_timeout || this.connectionParameters.query_timeout result = query = config if (typeof values === 'function') { query.callback = query.callback || values } } else { readTimeout = this.connectionParameters.query_timeout query = new Query(config, values, callback) if (!query.callback) { result = new this._Promise((resolve, reject) => { query.callback = (err, res) => err ? reject(err) : resolve(res) }) } } if (readTimeout) { queryCallback = query.callback readTimeoutTimer = setTimeout(() => { var error = new Error('Query read timeout') process.nextTick(() => { query.handleError(error, this.connection) }) queryCallback(error) // we already returned an error, // just do nothing if query completes query.callback = () => {} // Remove from queue var index = this.queryQueue.indexOf(query) if (index > -1) { this.queryQueue.splice(index, 1) } this._pulseQueryQueue() }, readTimeout) query.callback = (err, res) => { clearTimeout(readTimeoutTimer) queryCallback(err, res) } } if (this.binary && !query.binary) { query.binary = true } if (query._result && !query._result._types) { query._result._types = this._types } if (!this._queryable) { process.nextTick(() => { query.handleError(new Error('Client has encountered a connection error and is not queryable'), this.connection) }) return result } if (this._ending) { process.nextTick(() => { query.handleError(new Error('Client was closed and is not queryable'), this.connection) }) return result } this.queryQueue.push(query) this._pulseQueryQueue() return result } Client.prototype.end = function (cb) { this._ending = true if (this.activeQuery) { // if we have an active query we need to force a disconnect // on the socket - otherwise a hung query could block end forever this.connection.stream.destroy() } else { this.connection.end() } if (cb) { this.connection.once('end', cb) } else { return new this._Promise((resolve) => { this.connection.once('end', resolve) }) } } // expose a Query constructor Client.Query = Query module.exports = Client node-postgres-7.14.0/lib/connection-parameters.js000066400000000000000000000103331356526317000220100ustar00rootroot00000000000000'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ var dns = require('dns') var defaults = require('./defaults') var parse = require('pg-connection-string').parse // parses a connection string var val = function (key, config, envVar) { if (envVar === undefined) { envVar = process.env['PG' + key.toUpperCase()] } else if (envVar === false) { // do nothing ... use false } else { envVar = process.env[envVar] } return config[key] || envVar || defaults[key] } var useSsl = function () { switch (process.env.PGSSLMODE) { case 'disable': return false case 'prefer': case 'require': case 'verify-ca': case 'verify-full': return true } return defaults.ssl } var ConnectionParameters = function (config) { // if a string is passed, it is a raw connection string so we parse it into a config config = typeof config === 'string' ? parse(config) : config || {} // if the config has a connectionString defined, parse IT into the config we use // this will override other default values with what is stored in connectionString if (config.connectionString) { config = Object.assign({}, config, parse(config.connectionString)) } this.user = val('user', config) this.database = val('database', config) this.port = parseInt(val('port', config), 10) this.host = val('host', config) this.password = val('password', config) this.binary = val('binary', config) this.ssl = typeof config.ssl === 'undefined' ? useSsl() : config.ssl this.client_encoding = val('client_encoding', config) this.replication = val('replication', config) // a domain socket begins with '/' this.isDomainSocket = (!(this.host || '').indexOf('/')) this.application_name = val('application_name', config, 'PGAPPNAME') this.fallback_application_name = val('fallback_application_name', config, false) this.statement_timeout = val('statement_timeout', config, false) this.query_timeout = val('query_timeout', config, false) if (config.connectionTimeoutMillis === undefined) { this.connect_timeout = process.env.PGCONNECT_TIMEOUT || 0 } else { this.connect_timeout = Math.floor(config.connectionTimeoutMillis / 1000) } if (config.keepAlive === false) { this.keepalives = 0 } else if (config.keepAlive === true) { this.keepalives = 1 } if (typeof config.keepAliveInitialDelayMillis === 'number') { this.keepalives_idle = Math.floor(config.keepAliveInitialDelayMillis / 1000) } } // Convert arg to a string, surround in single quotes, and escape single quotes and backslashes var quoteParamValue = function (value) { return "'" + ('' + value).replace(/\\/g, '\\\\').replace(/'/g, "\\'") + "'" } var add = function (params, config, paramName) { var value = config[paramName] if (value !== undefined && value !== null) { params.push(paramName + '=' + quoteParamValue(value)) } } ConnectionParameters.prototype.getLibpqConnectionString = function (cb) { var params = [] add(params, this, 'user') add(params, this, 'password') add(params, this, 'port') add(params, this, 'application_name') add(params, this, 'fallback_application_name') add(params, this, 'connect_timeout') var ssl = typeof this.ssl === 'object' ? this.ssl : this.ssl ? { sslmode: this.ssl } : {} add(params, ssl, 'sslmode') add(params, ssl, 'sslca') add(params, ssl, 'sslkey') add(params, ssl, 'sslcert') add(params, ssl, 'sslrootcert') if (this.database) { params.push('dbname=' + quoteParamValue(this.database)) } if (this.replication) { params.push('replication=' + quoteParamValue(this.replication)) } if (this.host) { params.push('host=' + quoteParamValue(this.host)) } if (this.isDomainSocket) { return cb(null, params.join(' ')) } if (this.client_encoding) { params.push('client_encoding=' + quoteParamValue(this.client_encoding)) } dns.lookup(this.host, function (err, address) { if (err) return cb(err, null) params.push('hostaddr=' + quoteParamValue(address)) return cb(null, params.join(' ')) }) } module.exports = ConnectionParameters node-postgres-7.14.0/lib/connection.js000066400000000000000000000443331356526317000176560ustar00rootroot00000000000000'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ var net = require('net') var EventEmitter = require('events').EventEmitter var util = require('util') var Writer = require('buffer-writer') var Reader = require('packet-reader') var TEXT_MODE = 0 var BINARY_MODE = 1 var Connection = function (config) { EventEmitter.call(this) config = config || {} this.stream = config.stream || new net.Socket() this._keepAlive = config.keepAlive this._keepAliveInitialDelayMillis = config.keepAliveInitialDelayMillis this.lastBuffer = false this.lastOffset = 0 this.buffer = null this.offset = null this.encoding = config.encoding || 'utf8' this.parsedStatements = {} this.writer = new Writer() this.ssl = config.ssl || false this._ending = false this._mode = TEXT_MODE this._emitMessage = false this._reader = new Reader({ headerSize: 1, lengthPadding: -4 }) var self = this this.on('newListener', function (eventName) { if (eventName === 'message') { self._emitMessage = true } }) } util.inherits(Connection, EventEmitter) Connection.prototype.connect = function (port, host) { var self = this if (this.stream.readyState === 'closed') { this.stream.connect(port, host) } else if (this.stream.readyState === 'open') { this.emit('connect') } this.stream.on('connect', function () { if (self._keepAlive) { self.stream.setKeepAlive(true, self._keepAliveInitialDelayMillis) } self.emit('connect') }) const reportStreamError = function (error) { // errors about disconnections should be ignored during disconnect if (self._ending && (error.code === 'ECONNRESET' || error.code === 'EPIPE')) { return } self.emit('error', error) } this.stream.on('error', reportStreamError) this.stream.on('close', function () { self.emit('end') }) if (!this.ssl) { return this.attachListeners(this.stream) } this.stream.once('data', function (buffer) { var responseCode = buffer.toString('utf8') switch (responseCode) { case 'N': // Server does not support SSL connections return self.emit('error', new Error('The server does not support SSL connections')) case 'S': // Server supports SSL connections, continue with a secure connection break default: // Any other response byte, including 'E' (ErrorResponse) indicating a server error return self.emit('error', new Error('There was an error establishing an SSL connection')) } var tls = require('tls') const options = { socket: self.stream, checkServerIdentity: self.ssl.checkServerIdentity || tls.checkServerIdentity, rejectUnauthorized: self.ssl.rejectUnauthorized, ca: self.ssl.ca, pfx: self.ssl.pfx, key: self.ssl.key, passphrase: self.ssl.passphrase, cert: self.ssl.cert, secureOptions: self.ssl.secureOptions, NPNProtocols: self.ssl.NPNProtocols } if (net.isIP(host) === 0) { options.servername = host } self.stream = tls.connect(options) self.attachListeners(self.stream) self.stream.on('error', reportStreamError) self.emit('sslconnect') }) } Connection.prototype.attachListeners = function (stream) { var self = this stream.on('data', function (buff) { self._reader.addChunk(buff) var packet = self._reader.read() while (packet) { var msg = self.parseMessage(packet) var eventName = msg.name === 'error' ? 'errorMessage' : msg.name if (self._emitMessage) { self.emit('message', msg) } self.emit(eventName, msg) packet = self._reader.read() } }) stream.on('end', function () { self.emit('end') }) } Connection.prototype.requestSsl = function () { var bodyBuffer = this.writer .addInt16(0x04D2) .addInt16(0x162F).flush() var length = bodyBuffer.length + 4 var buffer = new Writer() .addInt32(length) .add(bodyBuffer) .join() this.stream.write(buffer) } Connection.prototype.startup = function (config) { var writer = this.writer .addInt16(3) .addInt16(0) Object.keys(config).forEach(function (key) { var val = config[key] writer.addCString(key).addCString(val) }) writer.addCString('client_encoding').addCString("'utf-8'") var bodyBuffer = writer.addCString('').flush() // this message is sent without a code var length = bodyBuffer.length + 4 var buffer = new Writer() .addInt32(length) .add(bodyBuffer) .join() this.stream.write(buffer) } Connection.prototype.cancel = function (processID, secretKey) { var bodyBuffer = this.writer .addInt16(1234) .addInt16(5678) .addInt32(processID) .addInt32(secretKey) .flush() var length = bodyBuffer.length + 4 var buffer = new Writer() .addInt32(length) .add(bodyBuffer) .join() this.stream.write(buffer) } Connection.prototype.password = function (password) { // 0x70 = 'p' this._send(0x70, this.writer.addCString(password)) } Connection.prototype.sendSASLInitialResponseMessage = function (mechanism, initialResponse) { // 0x70 = 'p' this.writer .addCString(mechanism) .addInt32(Buffer.byteLength(initialResponse)) .addString(initialResponse) this._send(0x70) } Connection.prototype.sendSCRAMClientFinalMessage = function (additionalData) { // 0x70 = 'p' this.writer .addString(additionalData) this._send(0x70) } Connection.prototype._send = function (code, more) { if (!this.stream.writable) { return false } if (more === true) { this.writer.addHeader(code) } else { return this.stream.write(this.writer.flush(code)) } } Connection.prototype.query = function (text) { // 0x51 = Q this.stream.write(this.writer.addCString(text).flush(0x51)) } // send parse message // "more" === true to buffer the message until flush() is called Connection.prototype.parse = function (query, more) { // expect something like this: // { name: 'queryName', // text: 'select * from blah', // types: ['int8', 'bool'] } // normalize missing query names to allow for null query.name = query.name || '' if (query.name.length > 63) { /* eslint-disable no-console */ console.error('Warning! Postgres only supports 63 characters for query names.') console.error('You supplied %s (%s)', query.name, query.name.length) console.error('This can cause conflicts and silent errors executing queries') /* eslint-enable no-console */ } // normalize null type array query.types = query.types || [] var len = query.types.length var buffer = this.writer .addCString(query.name) // name of query .addCString(query.text) // actual query text .addInt16(len) for (var i = 0; i < len; i++) { buffer.addInt32(query.types[i]) } var code = 0x50 this._send(code, more) } // send bind message // "more" === true to buffer the message until flush() is called Connection.prototype.bind = function (config, more) { // normalize config config = config || {} config.portal = config.portal || '' config.statement = config.statement || '' config.binary = config.binary || false var values = config.values || [] var len = values.length var useBinary = false for (var j = 0; j < len; j++) { useBinary |= values[j] instanceof Buffer } var buffer = this.writer .addCString(config.portal) .addCString(config.statement) if (!useBinary) { buffer.addInt16(0) } else { buffer.addInt16(len) for (j = 0; j < len; j++) { buffer.addInt16(values[j] instanceof Buffer) } } buffer.addInt16(len) for (var i = 0; i < len; i++) { var val = values[i] if (val === null || typeof val === 'undefined') { buffer.addInt32(-1) } else if (val instanceof Buffer) { buffer.addInt32(val.length) buffer.add(val) } else { buffer.addInt32(Buffer.byteLength(val)) buffer.addString(val) } } if (config.binary) { buffer.addInt16(1) // format codes to use binary buffer.addInt16(1) } else { buffer.addInt16(0) // format codes to use text } // 0x42 = 'B' this._send(0x42, more) } // send execute message // "more" === true to buffer the message until flush() is called Connection.prototype.execute = function (config, more) { config = config || {} config.portal = config.portal || '' config.rows = config.rows || '' this.writer .addCString(config.portal) .addInt32(config.rows) // 0x45 = 'E' this._send(0x45, more) } var emptyBuffer = Buffer.alloc(0) Connection.prototype.flush = function () { // 0x48 = 'H' this.writer.add(emptyBuffer) this._send(0x48) } Connection.prototype.sync = function () { // clear out any pending data in the writer this.writer.flush(0) this.writer.add(emptyBuffer) this._ending = true this._send(0x53) } const END_BUFFER = Buffer.from([0x58, 0x00, 0x00, 0x00, 0x04]) Connection.prototype.end = function () { // 0x58 = 'X' this.writer.add(emptyBuffer) this._ending = true return this.stream.write(END_BUFFER, () => { this.stream.end() }) } Connection.prototype.close = function (msg, more) { this.writer.addCString(msg.type + (msg.name || '')) this._send(0x43, more) } Connection.prototype.describe = function (msg, more) { this.writer.addCString(msg.type + (msg.name || '')) this._send(0x44, more) } Connection.prototype.sendCopyFromChunk = function (chunk) { this.stream.write(this.writer.add(chunk).flush(0x64)) } Connection.prototype.endCopyFrom = function () { this.stream.write(this.writer.add(emptyBuffer).flush(0x63)) } Connection.prototype.sendCopyFail = function (msg) { // this.stream.write(this.writer.add(emptyBuffer).flush(0x66)); this.writer.addCString(msg) this._send(0x66) } var Message = function (name, length) { this.name = name this.length = length } Connection.prototype.parseMessage = function (buffer) { this.offset = 0 var length = buffer.length + 4 switch (this._reader.header) { case 0x52: // R return this.parseR(buffer, length) case 0x53: // S return this.parseS(buffer, length) case 0x4b: // K return this.parseK(buffer, length) case 0x43: // C return this.parseC(buffer, length) case 0x5a: // Z return this.parseZ(buffer, length) case 0x54: // T return this.parseT(buffer, length) case 0x44: // D return this.parseD(buffer, length) case 0x45: // E return this.parseE(buffer, length) case 0x4e: // N return this.parseN(buffer, length) case 0x31: // 1 return new Message('parseComplete', length) case 0x32: // 2 return new Message('bindComplete', length) case 0x33: // 3 return new Message('closeComplete', length) case 0x41: // A return this.parseA(buffer, length) case 0x6e: // n return new Message('noData', length) case 0x49: // I return new Message('emptyQuery', length) case 0x73: // s return new Message('portalSuspended', length) case 0x47: // G return this.parseG(buffer, length) case 0x48: // H return this.parseH(buffer, length) case 0x57: // W return new Message('replicationStart', length) case 0x63: // c return new Message('copyDone', length) case 0x64: // d return this.parsed(buffer, length) } } Connection.prototype.parseR = function (buffer, length) { var code = this.parseInt32(buffer) var msg = new Message('authenticationOk', length) switch (code) { case 0: // AuthenticationOk return msg case 3: // AuthenticationCleartextPassword if (msg.length === 8) { msg.name = 'authenticationCleartextPassword' return msg } break case 5: // AuthenticationMD5Password if (msg.length === 12) { msg.name = 'authenticationMD5Password' msg.salt = Buffer.alloc(4) buffer.copy(msg.salt, 0, this.offset, this.offset + 4) this.offset += 4 return msg } break case 10: // AuthenticationSASL msg.name = 'authenticationSASL' msg.mechanisms = [] do { var mechanism = this.parseCString(buffer) if (mechanism) { msg.mechanisms.push(mechanism) } } while (mechanism) return msg case 11: // AuthenticationSASLContinue msg.name = 'authenticationSASLContinue' msg.data = this.readString(buffer, length - 4) return msg case 12: // AuthenticationSASLFinal msg.name = 'authenticationSASLFinal' msg.data = this.readString(buffer, length - 4) return msg } throw new Error('Unknown authenticationOk message type' + util.inspect(msg)) } Connection.prototype.parseS = function (buffer, length) { var msg = new Message('parameterStatus', length) msg.parameterName = this.parseCString(buffer) msg.parameterValue = this.parseCString(buffer) return msg } Connection.prototype.parseK = function (buffer, length) { var msg = new Message('backendKeyData', length) msg.processID = this.parseInt32(buffer) msg.secretKey = this.parseInt32(buffer) return msg } Connection.prototype.parseC = function (buffer, length) { var msg = new Message('commandComplete', length) msg.text = this.parseCString(buffer) return msg } Connection.prototype.parseZ = function (buffer, length) { var msg = new Message('readyForQuery', length) msg.name = 'readyForQuery' msg.status = this.readString(buffer, 1) return msg } var ROW_DESCRIPTION = 'rowDescription' Connection.prototype.parseT = function (buffer, length) { var msg = new Message(ROW_DESCRIPTION, length) msg.fieldCount = this.parseInt16(buffer) var fields = [] for (var i = 0; i < msg.fieldCount; i++) { fields.push(this.parseField(buffer)) } msg.fields = fields return msg } var Field = function () { this.name = null this.tableID = null this.columnID = null this.dataTypeID = null this.dataTypeSize = null this.dataTypeModifier = null this.format = null } var FORMAT_TEXT = 'text' var FORMAT_BINARY = 'binary' Connection.prototype.parseField = function (buffer) { var field = new Field() field.name = this.parseCString(buffer) field.tableID = this.parseInt32(buffer) field.columnID = this.parseInt16(buffer) field.dataTypeID = this.parseInt32(buffer) field.dataTypeSize = this.parseInt16(buffer) field.dataTypeModifier = this.parseInt32(buffer) if (this.parseInt16(buffer) === TEXT_MODE) { this._mode = TEXT_MODE field.format = FORMAT_TEXT } else { this._mode = BINARY_MODE field.format = FORMAT_BINARY } return field } var DATA_ROW = 'dataRow' var DataRowMessage = function (length, fieldCount) { this.name = DATA_ROW this.length = length this.fieldCount = fieldCount this.fields = [] } // extremely hot-path code Connection.prototype.parseD = function (buffer, length) { var fieldCount = this.parseInt16(buffer) var msg = new DataRowMessage(length, fieldCount) for (var i = 0; i < fieldCount; i++) { msg.fields.push(this._readValue(buffer)) } return msg } // extremely hot-path code Connection.prototype._readValue = function (buffer) { var length = this.parseInt32(buffer) if (length === -1) return null if (this._mode === TEXT_MODE) { return this.readString(buffer, length) } return this.readBytes(buffer, length) } // parses error Connection.prototype.parseE = function (buffer, length) { var fields = {} var msg, item var input = new Message('error', length) var fieldType = this.readString(buffer, 1) while (fieldType !== '\0') { fields[fieldType] = this.parseCString(buffer) fieldType = this.readString(buffer, 1) } if (input.name === 'error') { // the msg is an Error instance msg = new Error(fields.M) for (item in input) { // copy input properties to the error if (Object.prototype.hasOwnProperty.call(input, item)) { msg[item] = input[item] } } } else { // the msg is an object literal msg = input msg.message = fields.M } msg.severity = fields.S msg.code = fields.C msg.detail = fields.D msg.hint = fields.H msg.position = fields.P msg.internalPosition = fields.p msg.internalQuery = fields.q msg.where = fields.W msg.schema = fields.s msg.table = fields.t msg.column = fields.c msg.dataType = fields.d msg.constraint = fields.n msg.file = fields.F msg.line = fields.L msg.routine = fields.R return msg } // same thing, different name Connection.prototype.parseN = function (buffer, length) { var msg = this.parseE(buffer, length) msg.name = 'notice' return msg } Connection.prototype.parseA = function (buffer, length) { var msg = new Message('notification', length) msg.processId = this.parseInt32(buffer) msg.channel = this.parseCString(buffer) msg.payload = this.parseCString(buffer) return msg } Connection.prototype.parseG = function (buffer, length) { var msg = new Message('copyInResponse', length) return this.parseGH(buffer, msg) } Connection.prototype.parseH = function (buffer, length) { var msg = new Message('copyOutResponse', length) return this.parseGH(buffer, msg) } Connection.prototype.parseGH = function (buffer, msg) { var isBinary = buffer[this.offset] !== 0 this.offset++ msg.binary = isBinary var columnCount = this.parseInt16(buffer) msg.columnTypes = [] for (var i = 0; i < columnCount; i++) { msg.columnTypes.push(this.parseInt16(buffer)) } return msg } Connection.prototype.parsed = function (buffer, length) { var msg = new Message('copyData', length) msg.chunk = this.readBytes(buffer, msg.length - 4) return msg } Connection.prototype.parseInt32 = function (buffer) { var value = buffer.readInt32BE(this.offset) this.offset += 4 return value } Connection.prototype.parseInt16 = function (buffer) { var value = buffer.readInt16BE(this.offset) this.offset += 2 return value } Connection.prototype.readString = function (buffer, length) { return buffer.toString(this.encoding, this.offset, (this.offset += length)) } Connection.prototype.readBytes = function (buffer, length) { return buffer.slice(this.offset, (this.offset += length)) } Connection.prototype.parseCString = function (buffer) { var start = this.offset var end = buffer.indexOf(0, start) this.offset = end + 1 return buffer.toString(this.encoding, start, end) } // end parsing methods module.exports = Connection node-postgres-7.14.0/lib/defaults.js000066400000000000000000000044271356526317000173260ustar00rootroot00000000000000'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ module.exports = { // database host. defaults to localhost host: 'localhost', // database user's name user: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, // name of database to connect database: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, // database user's password password: null, // a Postgres connection string to be used instead of setting individual connection items // NOTE: Setting this value will cause it to override any other value (such as database or user) defined // in the defaults object. connectionString: undefined, // database port port: 5432, // number of rows to return at a time from a prepared statement's // portal. 0 will return all rows at once rows: 0, // binary result mode binary: false, // Connection pool options - see https://github.com/brianc/node-pg-pool // number of connections to use in connection pool // 0 will disable connection pooling max: 10, // max milliseconds a client can go unused before it is removed // from the pool and destroyed idleTimeoutMillis: 30000, client_encoding: '', ssl: false, application_name: undefined, fallback_application_name: undefined, parseInputDatesAsUTC: false, // max milliseconds any query using this connection will execute for before timing out in error. // false=unlimited statement_timeout: false, // max milliseconds to wait for query to complete (client side) query_timeout: false, connect_timeout: 0, keepalives: 1, keepalives_idle: 0 } var pgTypes = require('pg-types') // save default parsers var parseBigInteger = pgTypes.getTypeParser(20, 'text') var parseBigIntegerArray = pgTypes.getTypeParser(1016, 'text') // parse int8 so you can get your count values as actual numbers module.exports.__defineSetter__('parseInt8', function (val) { pgTypes.setTypeParser(20, 'text', val ? pgTypes.getTypeParser(23, 'text') : parseBigInteger) pgTypes.setTypeParser(1016, 'text', val ? pgTypes.getTypeParser(1007, 'text') : parseBigIntegerArray) }) node-postgres-7.14.0/lib/index.js000066400000000000000000000030261356526317000166200ustar00rootroot00000000000000'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ var util = require('util') var Client = require('./client') var defaults = require('./defaults') var Connection = require('./connection') var Pool = require('pg-pool') const poolFactory = (Client) => { var BoundPool = function (options) { var config = Object.assign({ Client: Client }, options) return new Pool(config) } util.inherits(BoundPool, Pool) return BoundPool } var PG = function (clientConstructor) { this.defaults = defaults this.Client = clientConstructor this.Query = this.Client.Query this.Pool = poolFactory(this.Client) this._pools = [] this.Connection = Connection this.types = require('pg-types') } if (typeof process.env.NODE_PG_FORCE_NATIVE !== 'undefined') { module.exports = new PG(require('./native')) } else { module.exports = new PG(Client) // lazy require native module...the native module may not have installed module.exports.__defineGetter__('native', function () { delete module.exports.native var native = null try { native = new PG(require('./native')) } catch (err) { if (err.code !== 'MODULE_NOT_FOUND') { throw err } /* eslint-disable no-console */ console.error(err.message) /* eslint-enable no-console */ } module.exports.native = native return native }) } node-postgres-7.14.0/lib/native/000077500000000000000000000000001356526317000164405ustar00rootroot00000000000000node-postgres-7.14.0/lib/native/client.js000066400000000000000000000166701356526317000202660ustar00rootroot00000000000000'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ // eslint-disable-next-line var Native = require('pg-native') var TypeOverrides = require('../type-overrides') var semver = require('semver') var pkg = require('../../package.json') var assert = require('assert') var EventEmitter = require('events').EventEmitter var util = require('util') var ConnectionParameters = require('../connection-parameters') var msg = 'Version >= ' + pkg.minNativeVersion + ' of pg-native required.' assert(semver.gte(Native.version, pkg.minNativeVersion), msg) var NativeQuery = require('./query') var Client = module.exports = function (config) { EventEmitter.call(this) config = config || {} this._Promise = config.Promise || global.Promise this._types = new TypeOverrides(config.types) this.native = new Native({ types: this._types }) this._queryQueue = [] this._ending = false this._connecting = false this._connected = false this._queryable = true // keep these on the object for legacy reasons // for the time being. TODO: deprecate all this jazz var cp = this.connectionParameters = new ConnectionParameters(config) this.user = cp.user this.password = cp.password this.database = cp.database this.host = cp.host this.port = cp.port // a hash to hold named queries this.namedQueries = {} } Client.Query = NativeQuery util.inherits(Client, EventEmitter) Client.prototype._errorAllQueries = function (err) { const enqueueError = (query) => { process.nextTick(() => { query.native = this.native query.handleError(err) }) } if (this._hasActiveQuery()) { enqueueError(this._activeQuery) this._activeQuery = null } this._queryQueue.forEach(enqueueError) this._queryQueue.length = 0 } // connect to the backend // pass an optional callback to be called once connected // or with an error if there was a connection error Client.prototype._connect = function (cb) { var self = this if (this._connecting) { process.nextTick(() => cb(new Error('Client has already been connected. You cannot reuse a client.'))) return } this._connecting = true this.connectionParameters.getLibpqConnectionString(function (err, conString) { if (err) return cb(err) self.native.connect(conString, function (err) { if (err) return cb(err) // set internal states to connected self._connected = true // handle connection errors from the native layer self.native.on('error', function (err) { self._queryable = false self._errorAllQueries(err) self.emit('error', err) }) self.native.on('notification', function (msg) { self.emit('notification', { channel: msg.relname, payload: msg.extra }) }) // signal we are connected now self.emit('connect') self._pulseQueryQueue(true) cb() }) }) } Client.prototype.connect = function (callback) { if (callback) { this._connect(callback) return } return new this._Promise((resolve, reject) => { this._connect((error) => { if (error) { reject(error) } else { resolve() } }) }) } // send a query to the server // this method is highly overloaded to take // 1) string query, optional array of parameters, optional function callback // 2) object query with { // string query // optional array values, // optional function callback instead of as a separate parameter // optional string name to name & cache the query plan // optional string rowMode = 'array' for an array of results // } Client.prototype.query = function (config, values, callback) { var query var result var readTimeout var readTimeoutTimer var queryCallback if (config === null || config === undefined) { throw new TypeError('Client was passed a null or undefined query') } else if (typeof config.submit === 'function') { readTimeout = config.query_timeout || this.connectionParameters.query_timeout result = query = config // accept query(new Query(...), (err, res) => { }) style if (typeof values === 'function') { config.callback = values } } else { readTimeout = this.connectionParameters.query_timeout query = new NativeQuery(config, values, callback) if (!query.callback) { let resolveOut, rejectOut result = new this._Promise((resolve, reject) => { resolveOut = resolve rejectOut = reject }) query.callback = (err, res) => err ? rejectOut(err) : resolveOut(res) } } if (readTimeout) { queryCallback = query.callback readTimeoutTimer = setTimeout(() => { var error = new Error('Query read timeout') process.nextTick(() => { query.handleError(error, this.connection) }) queryCallback(error) // we already returned an error, // just do nothing if query completes query.callback = () => {} // Remove from queue var index = this._queryQueue.indexOf(query) if (index > -1) { this._queryQueue.splice(index, 1) } this._pulseQueryQueue() }, readTimeout) query.callback = (err, res) => { clearTimeout(readTimeoutTimer) queryCallback(err, res) } } if (!this._queryable) { query.native = this.native process.nextTick(() => { query.handleError(new Error('Client has encountered a connection error and is not queryable')) }) return result } if (this._ending) { query.native = this.native process.nextTick(() => { query.handleError(new Error('Client was closed and is not queryable')) }) return result } this._queryQueue.push(query) this._pulseQueryQueue() return result } // disconnect from the backend server Client.prototype.end = function (cb) { var self = this this._ending = true if (!this._connected) { this.once('connect', this.end.bind(this, cb)) } var result if (!cb) { result = new this._Promise(function (resolve, reject) { cb = (err) => err ? reject(err) : resolve() }) } this.native.end(function () { self._errorAllQueries(new Error('Connection terminated')) process.nextTick(() => { self.emit('end') if (cb) cb() }) }) return result } Client.prototype._hasActiveQuery = function () { return this._activeQuery && this._activeQuery.state !== 'error' && this._activeQuery.state !== 'end' } Client.prototype._pulseQueryQueue = function (initialConnection) { if (!this._connected) { return } if (this._hasActiveQuery()) { return } var query = this._queryQueue.shift() if (!query) { if (!initialConnection) { this.emit('drain') } return } this._activeQuery = query query.submit(this) var self = this query.once('_done', function () { self._pulseQueryQueue() }) } // attempt to cancel an in-progress query Client.prototype.cancel = function (query) { if (this._activeQuery === query) { this.native.cancel(function () {}) } else if (this._queryQueue.indexOf(query) !== -1) { this._queryQueue.splice(this._queryQueue.indexOf(query), 1) } } Client.prototype.setTypeParser = function (oid, format, parseFn) { return this._types.setTypeParser(oid, format, parseFn) } Client.prototype.getTypeParser = function (oid, format) { return this._types.getTypeParser(oid, format) } node-postgres-7.14.0/lib/native/index.js000066400000000000000000000000621356526317000201030ustar00rootroot00000000000000'use strict' module.exports = require('./client') node-postgres-7.14.0/lib/native/query.js000066400000000000000000000115111356526317000201420ustar00rootroot00000000000000'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ var EventEmitter = require('events').EventEmitter var util = require('util') var utils = require('../utils') var NativeQuery = module.exports = function (config, values, callback) { EventEmitter.call(this) config = utils.normalizeQueryConfig(config, values, callback) this.text = config.text this.values = config.values this.name = config.name this.callback = config.callback this.state = 'new' this._arrayMode = config.rowMode === 'array' // if the 'row' event is listened for // then emit them as they come in // without setting singleRowMode to true // this has almost no meaning because libpq // reads all rows into memory befor returning any this._emitRowEvents = false this.on('newListener', function (event) { if (event === 'row') this._emitRowEvents = true }.bind(this)) } util.inherits(NativeQuery, EventEmitter) var errorFieldMap = { /* eslint-disable quote-props */ 'sqlState': 'code', 'statementPosition': 'position', 'messagePrimary': 'message', 'context': 'where', 'schemaName': 'schema', 'tableName': 'table', 'columnName': 'column', 'dataTypeName': 'dataType', 'constraintName': 'constraint', 'sourceFile': 'file', 'sourceLine': 'line', 'sourceFunction': 'routine' } NativeQuery.prototype.handleError = function (err) { // copy pq error fields into the error object var fields = this.native.pq.resultErrorFields() if (fields) { for (var key in fields) { var normalizedFieldName = errorFieldMap[key] || key err[normalizedFieldName] = fields[key] } } if (this.callback) { this.callback(err) } else { this.emit('error', err) } this.state = 'error' } NativeQuery.prototype.then = function (onSuccess, onFailure) { return this._getPromise().then(onSuccess, onFailure) } NativeQuery.prototype.catch = function (callback) { return this._getPromise().catch(callback) } NativeQuery.prototype._getPromise = function () { if (this._promise) return this._promise this._promise = new Promise(function (resolve, reject) { this._once('end', resolve) this._once('error', reject) }.bind(this)) return this._promise } NativeQuery.prototype.submit = function (client) { this.state = 'running' var self = this this.native = client.native client.native.arrayMode = this._arrayMode var after = function (err, rows, results) { client.native.arrayMode = false setImmediate(function () { self.emit('_done') }) // handle possible query error if (err) { return self.handleError(err) } // emit row events for each row in the result if (self._emitRowEvents) { if (results.length > 1) { rows.forEach((rowOfRows, i) => { rowOfRows.forEach(row => { self.emit('row', row, results[i]) }) }) } else { rows.forEach(function (row) { self.emit('row', row, results) }) } } // handle successful result self.state = 'end' self.emit('end', results) if (self.callback) { self.callback(null, results) } } if (process.domain) { after = process.domain.bind(after) } // named query if (this.name) { if (this.name.length > 63) { /* eslint-disable no-console */ console.error('Warning! Postgres only supports 63 characters for query names.') console.error('You supplied %s (%s)', this.name, this.name.length) console.error('This can cause conflicts and silent errors executing queries') /* eslint-enable no-console */ } var values = (this.values || []).map(utils.prepareValue) // check if the client has already executed this named query // if so...just execute it again - skip the planning phase if (client.namedQueries[this.name]) { if (this.text && client.namedQueries[this.name] !== this.text) { const err = new Error(`Prepared statements must be unique - '${this.name}' was used for a different statement`) return after(err) } return client.native.execute(this.name, values, after) } // plan the named query the first time, then execute it return client.native.prepare(this.name, this.text, values.length, function (err) { if (err) return after(err) client.namedQueries[self.name] = self.text return self.native.execute(self.name, values, after) }) } else if (this.values) { if (!Array.isArray(this.values)) { const err = new Error('Query values must be an array') return after(err) } var vals = this.values.map(utils.prepareValue) client.native.query(this.text, vals, after) } else { client.native.query(this.text, after) } } node-postgres-7.14.0/lib/query.js000066400000000000000000000144301356526317000166570ustar00rootroot00000000000000'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ var EventEmitter = require('events').EventEmitter var util = require('util') var Result = require('./result') var utils = require('./utils') var Query = function (config, values, callback) { // use of "new" optional if (!(this instanceof Query)) { return new Query(config, values, callback) } config = utils.normalizeQueryConfig(config, values, callback) this.text = config.text this.values = config.values this.rows = config.rows this.types = config.types this.name = config.name this.binary = config.binary // use unique portal name each time this.portal = config.portal || '' this.callback = config.callback this._rowMode = config.rowMode if (process.domain && config.callback) { this.callback = process.domain.bind(config.callback) } this._result = new Result(this._rowMode, this.types) // potential for multiple results this._results = this._result this.isPreparedStatement = false this._canceledDueToError = false this._promise = null EventEmitter.call(this) } util.inherits(Query, EventEmitter) Query.prototype.requiresPreparation = function () { // named queries must always be prepared if (this.name) { return true } // always prepare if there are max number of rows expected per // portal execution if (this.rows) { return true } // don't prepare empty text queries if (!this.text) { return false } // prepare if there are values if (!this.values) { return false } return this.values.length > 0 } Query.prototype._checkForMultirow = function () { // if we already have a result with a command property // then we've already executed one query in a multi-statement simple query // turn our results into an array of results if (this._result.command) { if (!Array.isArray(this._results)) { this._results = [this._result] } this._result = new Result(this._rowMode, this.types) this._results.push(this._result) } } // associates row metadata from the supplied // message with this query object // metadata used when parsing row results Query.prototype.handleRowDescription = function (msg) { this._checkForMultirow() this._result.addFields(msg.fields) this._accumulateRows = this.callback || !this.listeners('row').length } Query.prototype.handleDataRow = function (msg) { var row if (this._canceledDueToError) { return } try { row = this._result.parseRow(msg.fields) } catch (err) { this._canceledDueToError = err return } this.emit('row', row, this._result) if (this._accumulateRows) { this._result.addRow(row) } } Query.prototype.handleCommandComplete = function (msg, con) { this._checkForMultirow() this._result.addCommandComplete(msg) // need to sync after each command complete of a prepared statement if (this.isPreparedStatement) { con.sync() } } // if a named prepared statement is created with empty query text // the backend will send an emptyQuery message but *not* a command complete message // execution on the connection will hang until the backend receives a sync message Query.prototype.handleEmptyQuery = function (con) { if (this.isPreparedStatement) { con.sync() } } Query.prototype.handleReadyForQuery = function (con) { if (this._canceledDueToError) { return this.handleError(this._canceledDueToError, con) } if (this.callback) { this.callback(null, this._results) } this.emit('end', this._results) } Query.prototype.handleError = function (err, connection) { // need to sync after error during a prepared statement if (this.isPreparedStatement) { connection.sync() } if (this._canceledDueToError) { err = this._canceledDueToError this._canceledDueToError = false } // if callback supplied do not emit error event as uncaught error // events will bubble up to node process if (this.callback) { return this.callback(err) } this.emit('error', err) } Query.prototype.submit = function (connection) { if (typeof this.text !== 'string' && typeof this.name !== 'string') { return new Error('A query must have either text or a name. Supplying neither is unsupported.') } const previous = connection.parsedStatements[this.name] if (this.text && previous && this.text !== previous) { return new Error(`Prepared statements must be unique - '${this.name}' was used for a different statement`) } if (this.values && !Array.isArray(this.values)) { return new Error('Query values must be an array') } if (this.requiresPreparation()) { this.prepare(connection) } else { connection.query(this.text) } return null } Query.prototype.hasBeenParsed = function (connection) { return this.name && connection.parsedStatements[this.name] } Query.prototype.handlePortalSuspended = function (connection) { this._getRows(connection, this.rows) } Query.prototype._getRows = function (connection, rows) { connection.execute({ portal: this.portal, rows: rows }, true) connection.flush() } Query.prototype.prepare = function (connection) { var self = this // prepared statements need sync to be called after each command // complete or when an error is encountered this.isPreparedStatement = true // TODO refactor this poor encapsulation if (!this.hasBeenParsed(connection)) { connection.parse({ text: self.text, name: self.name, types: self.types }, true) } if (self.values) { try { self.values = self.values.map(utils.prepareValue) } catch (err) { this.handleError(err, connection) return } } // http://developer.postgresql.org/pgdocs/postgres/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY connection.bind({ portal: self.portal, statement: self.name, values: self.values, binary: self.binary }, true) connection.describe({ type: 'P', name: self.portal || '' }, true) this._getRows(connection, this.rows) } Query.prototype.handleCopyInResponse = function (connection) { connection.sendCopyFail('No source stream defined') } // eslint-disable-next-line no-unused-vars Query.prototype.handleCopyData = function (msg, connection) { // noop } module.exports = Query node-postgres-7.14.0/lib/result.js000066400000000000000000000050541356526317000170320ustar00rootroot00000000000000'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ var types = require('pg-types') // result object returned from query // in the 'end' event and also // passed as second argument to provided callback var Result = function (rowMode, types) { this.command = null this.rowCount = null this.oid = null this.rows = [] this.fields = [] this._parsers = [] this._types = types this.RowCtor = null this.rowAsArray = rowMode === 'array' if (this.rowAsArray) { this.parseRow = this._parseRowAsArray } } var matchRegexp = /^([A-Za-z]+)(?: (\d+))?(?: (\d+))?/ // adds a command complete message Result.prototype.addCommandComplete = function (msg) { var match if (msg.text) { // pure javascript match = matchRegexp.exec(msg.text) } else { // native bindings match = matchRegexp.exec(msg.command) } if (match) { this.command = match[1] if (match[3]) { // COMMMAND OID ROWS this.oid = parseInt(match[2], 10) this.rowCount = parseInt(match[3], 10) } else if (match[2]) { // COMMAND ROWS this.rowCount = parseInt(match[2], 10) } } } Result.prototype._parseRowAsArray = function (rowData) { var row = [] for (var i = 0, len = rowData.length; i < len; i++) { var rawValue = rowData[i] if (rawValue !== null) { row.push(this._parsers[i](rawValue)) } else { row.push(null) } } return row } Result.prototype.parseRow = function (rowData) { var row = {} for (var i = 0, len = rowData.length; i < len; i++) { var rawValue = rowData[i] var field = this.fields[i].name if (rawValue !== null) { row[field] = this._parsers[i](rawValue) } else { row[field] = null } } return row } Result.prototype.addRow = function (row) { this.rows.push(row) } Result.prototype.addFields = function (fieldDescriptions) { // clears field definitions // multiple query statements in 1 action can result in multiple sets // of rowDescriptions...eg: 'select NOW(); select 1::int;' // you need to reset the fields if (this.fields.length) { this.fields = [] this._parsers = [] } for (var i = 0; i < fieldDescriptions.length; i++) { var desc = fieldDescriptions[i] this.fields.push(desc) var parser = (this._types || types).getTypeParser(desc.dataTypeID, desc.format || 'text') this._parsers.push(parser) } } module.exports = Result node-postgres-7.14.0/lib/sasl.js000066400000000000000000000075031356526317000164570ustar00rootroot00000000000000'use strict' const crypto = require('crypto') function startSession (mechanisms) { if (mechanisms.indexOf('SCRAM-SHA-256') === -1) { throw new Error('SASL: Only mechanism SCRAM-SHA-256 is currently supported') } const clientNonce = crypto.randomBytes(18).toString('base64') return { mechanism: 'SCRAM-SHA-256', clientNonce, response: 'n,,n=*,r=' + clientNonce, message: 'SASLInitialResponse' } } function continueSession (session, password, serverData) { if (session.message !== 'SASLInitialResponse') { throw new Error('SASL: Last message was not SASLInitialResponse') } const sv = extractVariablesFromFirstServerMessage(serverData) if (!sv.nonce.startsWith(session.clientNonce)) { throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce does not start with client nonce') } var saltBytes = Buffer.from(sv.salt, 'base64') var saltedPassword = Hi(password, saltBytes, sv.iteration) var clientKey = createHMAC(saltedPassword, 'Client Key') var storedKey = crypto.createHash('sha256').update(clientKey).digest() var clientFirstMessageBare = 'n=*,r=' + session.clientNonce var serverFirstMessage = 'r=' + sv.nonce + ',s=' + sv.salt + ',i=' + sv.iteration var clientFinalMessageWithoutProof = 'c=biws,r=' + sv.nonce var authMessage = clientFirstMessageBare + ',' + serverFirstMessage + ',' + clientFinalMessageWithoutProof var clientSignature = createHMAC(storedKey, authMessage) var clientProofBytes = xorBuffers(clientKey, clientSignature) var clientProof = clientProofBytes.toString('base64') var serverKey = createHMAC(saltedPassword, 'Server Key') var serverSignatureBytes = createHMAC(serverKey, authMessage) session.message = 'SASLResponse' session.serverSignature = serverSignatureBytes.toString('base64') session.response = clientFinalMessageWithoutProof + ',p=' + clientProof } function finalizeSession (session, serverData) { if (session.message !== 'SASLResponse') { throw new Error('SASL: Last message was not SASLResponse') } var serverSignature String(serverData).split(',').forEach(function (part) { switch (part[0]) { case 'v': serverSignature = part.substr(2) break } }) if (serverSignature !== session.serverSignature) { throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature does not match') } } function extractVariablesFromFirstServerMessage (data) { var nonce, salt, iteration String(data).split(',').forEach(function (part) { switch (part[0]) { case 'r': nonce = part.substr(2) break case 's': salt = part.substr(2) break case 'i': iteration = parseInt(part.substr(2), 10) break } }) if (!nonce) { throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing') } if (!salt) { throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: salt missing') } if (!iteration) { throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: iteration missing') } return { nonce, salt, iteration } } function xorBuffers (a, b) { if (!Buffer.isBuffer(a)) a = Buffer.from(a) if (!Buffer.isBuffer(b)) b = Buffer.from(b) var res = [] if (a.length > b.length) { for (var i = 0; i < b.length; i++) { res.push(a[i] ^ b[i]) } } else { for (var j = 0; j < a.length; j++) { res.push(a[j] ^ b[j]) } } return Buffer.from(res) } function createHMAC (key, msg) { return crypto.createHmac('sha256', key).update(msg).digest() } function Hi (password, saltBytes, iterations) { var ui1 = createHMAC(password, Buffer.concat([saltBytes, Buffer.from([0, 0, 0, 1])])) var ui = ui1 for (var i = 0; i < iterations - 1; i++) { ui1 = createHMAC(password, ui1) ui = xorBuffers(ui, ui1) } return ui } module.exports = { startSession, continueSession, finalizeSession } node-postgres-7.14.0/lib/type-overrides.js000066400000000000000000000017271356526317000205000ustar00rootroot00000000000000'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ var types = require('pg-types') function TypeOverrides (userTypes) { this._types = userTypes || types this.text = {} this.binary = {} } TypeOverrides.prototype.getOverrides = function (format) { switch (format) { case 'text': return this.text case 'binary': return this.binary default: return {} } } TypeOverrides.prototype.setTypeParser = function (oid, format, parseFn) { if (typeof format === 'function') { parseFn = format format = 'text' } this.getOverrides(format)[oid] = parseFn } TypeOverrides.prototype.getTypeParser = function (oid, format) { format = format || 'text' return this.getOverrides(format)[oid] || this._types.getTypeParser(oid, format) } module.exports = TypeOverrides node-postgres-7.14.0/lib/utils.js000066400000000000000000000115261356526317000166550ustar00rootroot00000000000000'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ const crypto = require('crypto') const defaults = require('./defaults') function escapeElement (elementRepresentation) { var escaped = elementRepresentation .replace(/\\/g, '\\\\') .replace(/"/g, '\\"') return '"' + escaped + '"' } // convert a JS array to a postgres array literal // uses comma separator so won't work for types like box that use // a different array separator. function arrayString (val) { var result = '{' for (var i = 0; i < val.length; i++) { if (i > 0) { result = result + ',' } if (val[i] === null || typeof val[i] === 'undefined') { result = result + 'NULL' } else if (Array.isArray(val[i])) { result = result + arrayString(val[i]) } else if (val[i] instanceof Buffer) { result += '\\\\x' + val[i].toString('hex') } else { result += escapeElement(prepareValue(val[i])) } } result = result + '}' return result } // converts values from javascript types // to their 'raw' counterparts for use as a postgres parameter // note: you can override this function to provide your own conversion mechanism // for complex types, etc... var prepareValue = function (val, seen) { if (val instanceof Buffer) { return val } if (ArrayBuffer.isView(val)) { var buf = Buffer.from(val.buffer, val.byteOffset, val.byteLength) if (buf.length === val.byteLength) { return buf } return buf.slice(val.byteOffset, val.byteOffset + val.byteLength) // Node.js v4 does not support those Buffer.from params } if (val instanceof Date) { if (defaults.parseInputDatesAsUTC) { return dateToStringUTC(val) } else { return dateToString(val) } } if (Array.isArray(val)) { return arrayString(val) } if (val === null || typeof val === 'undefined') { return null } if (typeof val === 'object') { return prepareObject(val, seen) } return val.toString() } function prepareObject (val, seen) { if (val && typeof val.toPostgres === 'function') { seen = seen || [] if (seen.indexOf(val) !== -1) { throw new Error('circular reference detected while preparing "' + val + '" for query') } seen.push(val) return prepareValue(val.toPostgres(prepareValue), seen) } return JSON.stringify(val) } function pad (number, digits) { number = '' + number while (number.length < digits) { number = '0' + number } return number } function dateToString (date) { var offset = -date.getTimezoneOffset() var year = date.getFullYear() var isBCYear = year < 1 if (isBCYear) year = Math.abs(year) + 1 // negative years are 1 off their BC representation var ret = pad(year, 4) + '-' + pad(date.getMonth() + 1, 2) + '-' + pad(date.getDate(), 2) + 'T' + pad(date.getHours(), 2) + ':' + pad(date.getMinutes(), 2) + ':' + pad(date.getSeconds(), 2) + '.' + pad(date.getMilliseconds(), 3) if (offset < 0) { ret += '-' offset *= -1 } else { ret += '+' } ret += pad(Math.floor(offset / 60), 2) + ':' + pad(offset % 60, 2) if (isBCYear) ret += ' BC' return ret } function dateToStringUTC (date) { var year = date.getUTCFullYear() var isBCYear = year < 1 if (isBCYear) year = Math.abs(year) + 1 // negative years are 1 off their BC representation var ret = pad(year, 4) + '-' + pad(date.getUTCMonth() + 1, 2) + '-' + pad(date.getUTCDate(), 2) + 'T' + pad(date.getUTCHours(), 2) + ':' + pad(date.getUTCMinutes(), 2) + ':' + pad(date.getUTCSeconds(), 2) + '.' + pad(date.getUTCMilliseconds(), 3) ret += '+00:00' if (isBCYear) ret += ' BC' return ret } function normalizeQueryConfig (config, values, callback) { // can take in strings or config objects config = (typeof (config) === 'string') ? { text: config } : config if (values) { if (typeof values === 'function') { config.callback = values } else { config.values = values } } if (callback) { config.callback = callback } return config } const md5 = function (string) { return crypto.createHash('md5').update(string, 'utf-8').digest('hex') } // See AuthenticationMD5Password at https://www.postgresql.org/docs/current/static/protocol-flow.html const postgresMd5PasswordHash = function (user, password, salt) { var inner = md5(password + user) var outer = md5(Buffer.concat([Buffer.from(inner), salt])) return 'md5' + outer } module.exports = { prepareValue: function prepareValueWrapper (value) { // this ensures that extra arguments do not get passed into prepareValue // by accident, eg: from calling values.map(utils.prepareValue) return prepareValue(value) }, normalizeQueryConfig, postgresMd5PasswordHash, md5 } node-postgres-7.14.0/package.json000066400000000000000000000023071356526317000166740ustar00rootroot00000000000000{ "name": "pg", "version": "7.14.0", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords": [ "database", "libpq", "pg", "postgre", "postgres", "postgresql", "rdbms" ], "homepage": "http://github.com/brianc/node-postgres", "repository": { "type": "git", "url": "git://github.com/brianc/node-postgres.git" }, "author": "Brian Carlson ", "main": "./lib", "dependencies": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", "pg-connection-string": "0.1.3", "pg-pool": "^2.0.7", "pg-types": "^2.1.0", "pgpass": "1.x", "semver": "4.3.2" }, "devDependencies": { "async": "0.9.0", "bluebird": "3.5.2", "co": "4.6.0", "eslint": "^6.0.1", "eslint-config-standard": "^13.0.1", "eslint-plugin-import": "^2.18.1", "eslint-plugin-node": "^9.1.0", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.0", "pg-copy-streams": "0.3.0" }, "minNativeVersion": "2.0.0", "scripts": { "test": "make test-all" }, "files": [ "lib", "SPONSORS.md" ], "license": "MIT", "engines": { "node": ">= 4.5.0" } } node-postgres-7.14.0/script/000077500000000000000000000000001356526317000157105ustar00rootroot00000000000000node-postgres-7.14.0/script/create-test-tables.js000066400000000000000000000027111356526317000217370ustar00rootroot00000000000000'use strict' var args = require(__dirname + '/../test/cli') var pg = require(__dirname + '/../lib') var people = [ {name: 'Aaron', age: 10}, {name: 'Brian', age: 20}, {name: 'Chris', age: 30}, {name: 'David', age: 40}, {name: 'Elvis', age: 50}, {name: 'Frank', age: 60}, {name: 'Grace', age: 70}, {name: 'Haley', age: 80}, {name: 'Irma', age: 90}, {name: 'Jenny', age: 100}, {name: 'Kevin', age: 110}, {name: 'Larry', age: 120}, {name: 'Michelle', age: 130}, {name: 'Nancy', age: 140}, {name: 'Olivia', age: 150}, {name: 'Peter', age: 160}, {name: 'Quinn', age: 170}, {name: 'Ronda', age: 180}, {name: 'Shelley', age: 190}, {name: 'Tobias', age: 200}, {name: 'Uma', age: 210}, {name: 'Veena', age: 220}, {name: 'Wanda', age: 230}, {name: 'Xavier', age: 240}, {name: 'Yoyo', age: 250}, {name: 'Zanzabar', age: 260} ] var con = new pg.Client({ host: args.host, port: args.port, user: args.user, password: args.password, database: args.database }) con.connect() var query = con.query('drop table if exists person') con.query('create table person(id serial, name varchar(10), age integer)', (err, res) => { console.log('Created table person') console.log('Filling it with people') }) people.map(function (person) { return con.query(new pg.Query("insert into person(name, age) values('" + person.name + "', '" + person.age + "')")) }).pop().on('end', function () { console.log('Inserted 26 people') con.end() }) node-postgres-7.14.0/script/dump-db-types.js000066400000000000000000000007721356526317000207460ustar00rootroot00000000000000'use strict' var pg = require(__dirname + '/../lib') var args = require(__dirname + '/../test/cli') var queries = [ 'select CURRENT_TIMESTAMP', "select interval '1 day' + interval '1 hour'", "select TIMESTAMP 'today'"] queries.forEach(function (query) { var client = new pg.Client({ user: args.user, database: args.database, password: args.password }) client.connect() client .query(query) .on('row', function (row) { console.log(row) client.end() }) }) node-postgres-7.14.0/script/list-db-types.js000066400000000000000000000004471356526317000207530ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/../test/integration/test-helper') var pg = helper.pg pg.connect(helper.config, assert.success(function (client) { var query = client.query('select oid, typname from pg_type where typtype = \'b\' order by oid') query.on('row', console.log) })) node-postgres-7.14.0/test/000077500000000000000000000000001356526317000153635ustar00rootroot00000000000000node-postgres-7.14.0/test/buffer-list.js000066400000000000000000000032411356526317000201430ustar00rootroot00000000000000'use strict' global.BufferList = function () { this.buffers = [] } var p = BufferList.prototype p.add = function (buffer, front) { this.buffers[front ? 'unshift' : 'push'](buffer) return this } p.addInt16 = function (val, front) { return this.add(Buffer.from([(val >>> 8), (val >>> 0)]), front) } p.getByteLength = function (initial) { return this.buffers.reduce(function (previous, current) { return previous + current.length }, initial || 0) } p.addInt32 = function (val, first) { return this.add(Buffer.from([ (val >>> 24 & 0xFF), (val >>> 16 & 0xFF), (val >>> 8 & 0xFF), (val >>> 0 & 0xFF) ]), first) } p.addCString = function (val, front) { var len = Buffer.byteLength(val) var buffer = Buffer.alloc(len + 1) buffer.write(val) buffer[len] = 0 return this.add(buffer, front) } p.addString = function (val, front) { var len = Buffer.byteLength(val) var buffer = Buffer.alloc(len) buffer.write(val) return this.add(buffer, front) } p.addChar = function (char, first) { return this.add(Buffer.from(char, 'utf8'), first) } p.join = function (appendLength, char) { var length = this.getByteLength() if (appendLength) { this.addInt32(length + 4, true) return this.join(false, char) } if (char) { this.addChar(char, true) length++ } var result = Buffer.alloc(length) var index = 0 this.buffers.forEach(function (buffer) { buffer.copy(result, index, 0) index += buffer.length }) return result } BufferList.concat = function () { var total = new BufferList() for (var i = 0; i < arguments.length; i++) { total.add(arguments[i]) } return total.join() } module.exports = BufferList node-postgres-7.14.0/test/cli.js000066400000000000000000000010211356526317000164620ustar00rootroot00000000000000'use strict' var ConnectionParameters = require(__dirname + '/../lib/connection-parameters') var config = new ConnectionParameters(process.argv[2]) for (var i = 0; i < process.argv.length; i++) { switch (process.argv[i].toLowerCase()) { case 'native': config.native = true break case 'binary': config.binary = true break case 'down': config.down = true break default: break } } if (process.env['PG_TEST_NATIVE']) { config.native = true } module.exports = config node-postgres-7.14.0/test/integration/000077500000000000000000000000001356526317000177065ustar00rootroot00000000000000node-postgres-7.14.0/test/integration/client/000077500000000000000000000000001356526317000211645ustar00rootroot00000000000000node-postgres-7.14.0/test/integration/client/api-tests.js000066400000000000000000000147651356526317000234500ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/../test-helper') var pg = helper.pg var suite = new helper.Suite() suite.test('pool callback behavior', done => { // test weird callback behavior with node-pool const pool = new pg.Pool() pool.connect(function (err) { assert(!err) arguments[1].emit('drain') arguments[2]() pool.end(done) }) }) suite.test('query timeout', (cb) => { const pool = new pg.Pool({query_timeout: 1000}) pool.connect().then((client) => { client.query('SELECT pg_sleep(2)', assert.calls(function (err, result) { assert(err) assert(err.message === 'Query read timeout') client.release() pool.end(cb) })) }) }) suite.test('query recover from timeout', (cb) => { const pool = new pg.Pool({query_timeout: 1000}) pool.connect().then((client) => { client.query('SELECT pg_sleep(20)', assert.calls(function (err, result) { assert(err) assert(err.message === 'Query read timeout') client.release(err) pool.connect().then((client) => { client.query('SELECT 1', assert.calls(function (err, result) { assert(!err) client.release(err) pool.end(cb) })) }) })) }) }) suite.test('query no timeout', (cb) => { const pool = new pg.Pool({query_timeout: 10000}) pool.connect().then((client) => { client.query('SELECT pg_sleep(1)', assert.calls(function (err, result) { assert(!err) client.release() pool.end(cb) })) }) }) suite.test('callback API', done => { const client = new helper.Client() client.query('CREATE TEMP TABLE peep(name text)') client.query('INSERT INTO peep(name) VALUES ($1)', ['brianc']) const config = { text: 'INSERT INTO peep(name) VALUES ($1)', values: ['brian'] } client.query(config) client.query('INSERT INTO peep(name) VALUES ($1)', ['aaron']) client.query('SELECT * FROM peep ORDER BY name COLLATE "C"', (err, res) => { assert(!err) assert.equal(res.rowCount, 3) assert.deepEqual(res.rows, [ { name: 'aaron' }, { name: 'brian' }, { name: 'brianc' } ]) done() }) client.connect(err => { assert(!err) client.once('drain', () => client.end()) }) }) suite.test('executing nested queries', function (done) { const pool = new pg.Pool() pool.connect( assert.calls(function (err, client, release) { assert(!err) client.query( 'select now as now from NOW()', assert.calls(function (err, result) { assert.equal(new Date().getYear(), result.rows[0].now.getYear()) client.query( 'select now as now_again FROM NOW()', assert.calls(function () { client.query( 'select * FROM NOW()', assert.calls(function () { assert.ok('all queries hit') release() pool.end(done) }) ) }) ) }) ) }) ) }) suite.test('raises error if cannot connect', function () { var connectionString = 'pg://sfalsdkf:asdf@localhost/ieieie' const pool = new pg.Pool({ connectionString: connectionString }) pool.connect( assert.calls(function (err, client, done) { assert.ok(err, 'should have raised an error') done() }) ) }) suite.test('query errors are handled and do not bubble if callback is provided', function (done) { const pool = new pg.Pool() pool.connect( assert.calls(function (err, client, release) { assert(!err) client.query( 'SELECT OISDJF FROM LEIWLISEJLSE', assert.calls(function (err, result) { assert.ok(err) release() pool.end(done) }) ) }) ) } ) suite.test('callback is fired once and only once', function (done) { const pool = new pg.Pool() pool.connect( assert.calls(function (err, client, release) { assert(!err) client.query('CREATE TEMP TABLE boom(name varchar(10))') var callCount = 0 client.query( [ "INSERT INTO boom(name) VALUES('hai')", "INSERT INTO boom(name) VALUES('boom')", "INSERT INTO boom(name) VALUES('zoom')" ].join(';'), function (err, callback) { assert.equal( callCount++, 0, 'Call count should be 0. More means this callback fired more than once.' ) release() pool.end(done) } ) }) ) }) suite.test('can provide callback and config object', function (done) { const pool = new pg.Pool() pool.connect( assert.calls(function (err, client, release) { assert(!err) client.query( { name: 'boom', text: 'select NOW()' }, assert.calls(function (err, result) { assert(!err) assert.equal(result.rows[0].now.getYear(), new Date().getYear()) release() pool.end(done) }) ) }) ) }) suite.test('can provide callback and config and parameters', function (done) { const pool = new pg.Pool() pool.connect( assert.calls(function (err, client, release) { assert(!err) var config = { text: 'select $1::text as val' } client.query( config, ['hi'], assert.calls(function (err, result) { assert(!err) assert.equal(result.rows.length, 1) assert.equal(result.rows[0].val, 'hi') release() pool.end(done) }) ) }) ) }) suite.test('null and undefined are both inserted as NULL', function (done) { const pool = new pg.Pool() pool.connect( assert.calls(function (err, client, release) { assert(!err) client.query( 'CREATE TEMP TABLE my_nulls(a varchar(1), b varchar(1), c integer, d integer, e date, f date)' ) client.query( 'INSERT INTO my_nulls(a,b,c,d,e,f) VALUES ($1,$2,$3,$4,$5,$6)', [null, undefined, null, undefined, null, undefined] ) client.query( 'SELECT * FROM my_nulls', assert.calls(function (err, result) { assert(!err) assert.equal(result.rows.length, 1) assert.isNull(result.rows[0].a) assert.isNull(result.rows[0].b) assert.isNull(result.rows[0].c) assert.isNull(result.rows[0].d) assert.isNull(result.rows[0].e) assert.isNull(result.rows[0].f) pool.end(done) release() }) ) }) ) }) node-postgres-7.14.0/test/integration/client/appname-tests.js000066400000000000000000000045471356526317000243150ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var Client = helper.Client var suite = new helper.Suite() var conInfo = helper.config function getConInfo (override) { return Object.assign({}, conInfo, override ) } function getAppName (conf, cb) { var client = new Client(conf) client.connect(assert.success(function () { client.query('SHOW application_name', assert.success(function (res) { var appName = res.rows[0].application_name cb(appName) client.end() })) })) } suite.test('No default appliation_name ', function (done) { var conf = getConInfo() getAppName({ }, function (res) { assert.strictEqual(res, '') done() }) }) suite.test('fallback_application_name is used', function (done) { var fbAppName = 'this is my app' var conf = getConInfo({ 'fallback_application_name': fbAppName }) getAppName(conf, function (res) { assert.strictEqual(res, fbAppName) done() }) }) suite.test('application_name is used', function (done) { var appName = 'some wired !@#$% application_name' var conf = getConInfo({ 'application_name': appName }) getAppName(conf, function (res) { assert.strictEqual(res, appName) done() }) }) suite.test('application_name has precedence over fallback_application_name', function (done) { var appName = 'some wired !@#$% application_name' var fbAppName = 'some other strange $$test$$ appname' var conf = getConInfo({ 'application_name': appName, 'fallback_application_name': fbAppName }) getAppName(conf, function (res) { assert.strictEqual(res, appName) done() }) }) suite.test('application_name from connection string', function (done) { var appName = 'my app' var conParams = require(__dirname + '/../../../lib/connection-parameters') var conf if (process.argv[2]) { conf = new conParams(process.argv[2] + '?application_name=' + appName) } else { conf = 'postgres://?application_name=' + appName } getAppName(conf, function (res) { assert.strictEqual(res, appName) done() }) }) // TODO: make the test work for native client too if (!helper.args.native) { suite.test('application_name is read from the env', function (done) { var appName = process.env.PGAPPNAME = 'testest' getAppName({ }, function (res) { delete process.env.PGAPPNAME assert.strictEqual(res, appName) done() }) }) } node-postgres-7.14.0/test/integration/client/array-tests.js000066400000000000000000000130651356526317000240050ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') var pg = helper.pg var suite = new helper.Suite() const pool = new pg.Pool() pool.connect(assert.calls(function (err, client, release) { assert(!err) suite.test('nulls', function (done) { client.query('SELECT $1::text[] as array', [[null]], assert.success(function (result) { var array = result.rows[0].array assert.lengthIs(array, 1) assert.isNull(array[0]) done() })) }) suite.test('elements containing JSON-escaped characters', function (done) { var param = '\\"\\"' for (var i = 1; i <= 0x1f; i++) { param += String.fromCharCode(i) } client.query('SELECT $1::text[] as array', [[param]], assert.success(function (result) { var array = result.rows[0].array assert.lengthIs(array, 1) assert.equal(array[0], param) done() })) }) suite.test('cleanup', () => release()) pool.connect(assert.calls(function (err, client, release) { assert(!err) client.query('CREATE TEMP TABLE why(names text[], numbors integer[])') client.query(new pg.Query('INSERT INTO why(names, numbors) VALUES(\'{"aaron", "brian","a b c" }\', \'{1, 2, 3}\')')).on('error', console.log) suite.test('numbers', function (done) { // client.connection.on('message', console.log) client.query('SELECT numbors FROM why', assert.success(function (result) { assert.lengthIs(result.rows[0].numbors, 3) assert.equal(result.rows[0].numbors[0], 1) assert.equal(result.rows[0].numbors[1], 2) assert.equal(result.rows[0].numbors[2], 3) done() })) }) suite.test('parses string arrays', function (done) { client.query('SELECT names FROM why', assert.success(function (result) { var names = result.rows[0].names assert.lengthIs(names, 3) assert.equal(names[0], 'aaron') assert.equal(names[1], 'brian') assert.equal(names[2], 'a b c') done() })) }) suite.test('empty array', function (done) { client.query("SELECT '{}'::text[] as names", assert.success(function (result) { var names = result.rows[0].names assert.lengthIs(names, 0) done() })) }) suite.test('element containing comma', function (done) { client.query("SELECT '{\"joe,bob\",jim}'::text[] as names", assert.success(function (result) { var names = result.rows[0].names assert.lengthIs(names, 2) assert.equal(names[0], 'joe,bob') assert.equal(names[1], 'jim') done() })) }) suite.test('bracket in quotes', function (done) { client.query("SELECT '{\"{\",\"}\"}'::text[] as names", assert.success(function (result) { var names = result.rows[0].names assert.lengthIs(names, 2) assert.equal(names[0], '{') assert.equal(names[1], '}') done() })) }) suite.test('null value', function (done) { client.query("SELECT '{joe,null,bob,\"NULL\"}'::text[] as names", assert.success(function (result) { var names = result.rows[0].names assert.lengthIs(names, 4) assert.equal(names[0], 'joe') assert.equal(names[1], null) assert.equal(names[2], 'bob') assert.equal(names[3], 'NULL') done() })) }) suite.test('element containing quote char', function (done) { client.query("SELECT ARRAY['joe''', 'jim', 'bob\"'] AS names", assert.success(function (result) { var names = result.rows[0].names assert.lengthIs(names, 3) assert.equal(names[0], 'joe\'') assert.equal(names[1], 'jim') assert.equal(names[2], 'bob"') done() })) }) suite.test('nested array', function (done) { client.query("SELECT '{{1,joe},{2,bob}}'::text[] as names", assert.success(function (result) { var names = result.rows[0].names assert.lengthIs(names, 2) assert.lengthIs(names[0], 2) assert.equal(names[0][0], '1') assert.equal(names[0][1], 'joe') assert.lengthIs(names[1], 2) assert.equal(names[1][0], '2') assert.equal(names[1][1], 'bob') done() })) }) suite.test('integer array', function (done) { client.query("SELECT '{1,2,3}'::integer[] as names", assert.success(function (result) { var names = result.rows[0].names assert.lengthIs(names, 3) assert.equal(names[0], 1) assert.equal(names[1], 2) assert.equal(names[2], 3) done() })) }) suite.test('integer nested array', function (done) { client.query("SELECT '{{1,100},{2,100},{3,100}}'::integer[] as names", assert.success(function (result) { var names = result.rows[0].names assert.lengthIs(names, 3) assert.equal(names[0][0], 1) assert.equal(names[0][1], 100) assert.equal(names[1][0], 2) assert.equal(names[1][1], 100) assert.equal(names[2][0], 3) assert.equal(names[2][1], 100) done() })) }) suite.test('JS array parameter', function (done) { client.query('SELECT $1::integer[] as names', [[[1, 100], [2, 100], [3, 100]]], assert.success(function (result) { var names = result.rows[0].names assert.lengthIs(names, 3) assert.equal(names[0][0], 1) assert.equal(names[0][1], 100) assert.equal(names[1][0], 2) assert.equal(names[1][1], 100) assert.equal(names[2][0], 3) assert.equal(names[2][1], 100) release() pool.end(() => { done() }) })) }) })) })) node-postgres-7.14.0/test/integration/client/big-simple-query-tests.js000066400000000000000000000250151356526317000260600ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var Query = helper.pg.Query const suite = new helper.Suite() /* Test to trigger a bug. I really dont know what's wrong but it seams that its triggered by multable big queryies with supplied values. The test bellow can trigger the bug. */ // Big query with a where clouse from supplied value var big_query_rows_1 = [] var big_query_rows_2 = [] var big_query_rows_3 = [] // Works suite.test('big simple query 1', function (done) { var client = helper.client() client.query(new Query("select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as bla from person where name = '' or 1 = 1")) .on('row', function (row) { big_query_rows_1.push(row) }) .on('error', function (error) { console.log('big simple query 1 error'); console.log(error) }) client.on('drain', () => { client.end() done() }) }) // Works suite.test('big simple query 2', function (done) { var client = helper.client() client.query(new Query("select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as bla from person where name = $1 or 1 = 1", [''])) .on('row', function (row) { big_query_rows_2.push(row) }) .on('error', function (error) { console.log('big simple query 2 error'); console.log(error) }) client.on('drain', () => { client.end() done() }) }) // Fails most of the time with 'invalid byte sequence for encoding "UTF8": 0xb9' or 'insufficient data left in message' // If test 1 and 2 are commented out it works suite.test('big simple query 3', function (done) { var client = helper.client() client.query(new Query("select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as bla from person where name = $1 or 1 = 1", [''])) .on('row', function (row) { big_query_rows_3.push(row) }) .on('error', function (error) { console.log('big simple query 3 error'); console.log(error) }) client.on('drain', () => { client.end() done() }) }) process.on('exit', function () { assert.equal(big_query_rows_1.length, 26, 'big simple query 1 should return 26 rows') assert.equal(big_query_rows_2.length, 26, 'big simple query 2 should return 26 rows') assert.equal(big_query_rows_3.length, 26, 'big simple query 3 should return 26 rows') }) var runBigQuery = function (client) { var rows = [] var q = client.query("select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as bla from person where name = $1 or 1 = 1", [''], function (err, result) { if (err != null) { console.log(err) throw Err } assert.lengthIs(result.rows, 26) }) } suite.test('many times', function (done) { var client = helper.client() for (var i = 0; i < 20; i++) { runBigQuery(client) } client.on('drain', function () { client.end() setTimeout(function () { done() // let client disconnect fully }, 100) }) }) node-postgres-7.14.0/test/integration/client/configuration-tests.js000066400000000000000000000024731356526317000255370ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var pg = helper.pg var suite = new helper.Suite() // clear process.env var realEnv = {} for (var key in process.env) { realEnv[key] = process.env[key] if (!key.indexOf('PG')) delete process.env[key] } suite.test('default values are used in new clients', function () { assert.same(pg.defaults, { user: process.env.USER, database: process.env.USER, password: null, port: 5432, rows: 0, max: 10, binary: false, idleTimeoutMillis: 30000, client_encoding: '', ssl: false, application_name: undefined, fallback_application_name: undefined, parseInputDatesAsUTC: false }) var client = new pg.Client() assert.same(client, { user: process.env.USER, database: process.env.USER, password: null, port: 5432 }) }) suite.test('modified values are passed to created clients', function () { pg.defaults.user = 'boom' pg.defaults.password = 'zap' pg.defaults.database = 'pow' pg.defaults.port = 1234 pg.defaults.host = 'blam' var client = new Client() assert.same(client, { user: 'boom', password: 'zap', database: 'pow', port: 1234, host: 'blam' }) }) suite.test('cleanup', () => { // restore process.env for (var key in realEnv) { process.env[key] = realEnv[key] } }) node-postgres-7.14.0/test/integration/client/connection-timeout-tests.js000066400000000000000000000046351356526317000265150ustar00rootroot00000000000000'use strict' const net = require('net') const buffers = require('../../test-buffers') const helper = require('./test-helper') const suite = new helper.Suite() const options = { host: 'localhost', port: 54321, connectionTimeoutMillis: 2000, user: 'not', database: 'existing' } const serverWithConnectionTimeout = (timeout, callback) => { const sockets = new Set() const server = net.createServer(socket => { sockets.add(socket) socket.once('end', () => sockets.delete(socket)) socket.on('data', data => { // deny request for SSL if (data.length === 8) { socket.write(Buffer.from('N', 'utf8')) // consider all authentication requests as good } else if (!data[0]) { socket.write(buffers.authenticationOk()) // send ReadyForQuery `timeout` ms after authentication setTimeout(() => socket.write(buffers.readyForQuery()), timeout).unref() // respond with our canned response } else { socket.write(buffers.readyForQuery()) } }) }) let closing = false const closeServer = done => { if (closing) return closing = true server.close(done) for (const socket of sockets) { socket.destroy() } } server.listen(options.port, options.host, () => callback(closeServer)) } suite.test('successful connection', done => { serverWithConnectionTimeout(0, closeServer => { const timeoutId = setTimeout(() => { throw new Error('Client should have connected successfully but it did not.') }, 3000) const client = new helper.Client(options) client.connect() .then(() => client.end()) .then(() => closeServer(done)) .catch(err => closeServer(() => done(err))) .then(() => clearTimeout(timeoutId)) }) }) suite.test('expired connection timeout', done => { serverWithConnectionTimeout(options.connectionTimeoutMillis * 2, closeServer => { const timeoutId = setTimeout(() => { throw new Error('Client should have emitted an error but it did not.') }, 3000) const client = new helper.Client(options) client.connect() .then(() => client.end()) .then(() => closeServer(() => done(new Error('Connection timeout should have expired but it did not.')))) .catch(err => { assert(err instanceof Error) assert(/timeout expired\s*/.test(err.message)) closeServer(done) }) .then(() => clearTimeout(timeoutId)) }) }) node-postgres-7.14.0/test/integration/client/custom-types-tests.js000066400000000000000000000017121356526317000253370ustar00rootroot00000000000000'use strict' const helper = require('./test-helper') const Client = helper.pg.Client const suite = new helper.Suite() const customTypes = { getTypeParser: () => () => 'okay!' } suite.test('custom type parser in client config', (done) => { const client = new Client({ types: customTypes }) client.connect() .then(() => { client.query('SELECT NOW() as val', assert.success(function (res) { assert.equal(res.rows[0].val, 'okay!') client.end().then(done) })) }) }) // Custom type-parsers per query are not supported in native if (!helper.args.native) { suite.test('custom type parser in query', (done) => { const client = new Client() client.connect() .then(() => { client.query({ text: 'SELECT NOW() as val', types: customTypes }, assert.success(function (res) { assert.equal(res.rows[0].val, 'okay!') client.end().then(done) })) }) }) } node-postgres-7.14.0/test/integration/client/empty-query-tests.js000066400000000000000000000007461356526317000251720ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') const suite = new helper.Suite() suite.test('empty query message handling', function (done) { const client = helper.client() assert.emits(client, 'drain', function () { client.end(done) }) client.query({text: ''}) }) suite.test('callback supported', function (done) { const client = helper.client() client.query('', function (err, result) { assert(!err) assert.empty(result.rows) client.end(done) }) }) node-postgres-7.14.0/test/integration/client/error-handling-tests.js000066400000000000000000000132011356526317000255720ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var util = require('util') var pg = helper.pg const Client = pg.Client var createErorrClient = function () { var client = helper.client() client.once('error', function (err) { assert.fail('Client shoud not throw error during query execution') }) client.on('drain', client.end.bind(client)) return client } const suite = new helper.Suite('error handling') suite.test('sending non-array argument as values causes an error callback', (done) => { const client = new Client() client.connect(() => { client.query('select $1::text as name', 'foo', (err) => { assert(err instanceof Error) client.query('SELECT $1::text as name', ['foo'], (err, res) => { assert.equal(res.rows[0].name, 'foo') client.end(done) }) }) }) }) suite.test('re-using connections results in error callback', (done) => { const client = new Client() client.connect(() => { client.connect(err => { assert(err instanceof Error) client.end(done) }) }) }) suite.test('re-using connections results in promise rejection', (done) => { const client = new Client() client.connect().then(() => { client.connect().catch(err => { assert(err instanceof Error) client.end().then(done) }) }) }) suite.test('using a client after closing it results in error', (done) => { const client = new Client() client.connect(() => { client.end(assert.calls(() => { client.query('SELECT 1', assert.calls((err) => { assert.equal(err.message, 'Client was closed and is not queryable') done() })) })) }) }) suite.test('query receives error on client shutdown', function (done) { var client = new Client() client.connect(assert.success(function () { const config = { text: 'select pg_sleep(5)', name: 'foobar' } let queryError client.query(new pg.Query(config), assert.calls(function (err, res) { assert(err instanceof Error) queryError = err })) setTimeout(() => client.end(), 50) client.once('end', () => { assert(queryError instanceof Error) done() }) })) }) var ensureFuture = function (testClient, done) { var goodQuery = testClient.query(new pg.Query('select age from boom')) assert.emits(goodQuery, 'row', function (row) { assert.equal(row.age, 28) done() }) } suite.test('when query is parsing', (done) => { var client = createErorrClient() var q = client.query({ text: 'CREATE TEMP TABLE boom(age integer); INSERT INTO boom (age) VALUES (28);' }) // this query wont parse since there isn't a table named bang var query = client.query(new pg.Query({ text: 'select * from bang where name = $1', values: ['0'] })) assert.emits(query, 'error', function (err) { ensureFuture(client, done) }) }) suite.test('when a query is binding', function (done) { var client = createErorrClient() var q = client.query({ text: 'CREATE TEMP TABLE boom(age integer); INSERT INTO boom (age) VALUES (28);' }) var query = client.query(new pg.Query({ text: 'select * from boom where age = $1', values: ['asldkfjasdf'] })) assert.emits(query, 'error', function (err) { assert.equal(err.severity, 'ERROR') ensureFuture(client, done) }) }) suite.test('non-query error with callback', function (done) { var client = new Client({ user: 'asldkfjsadlfkj' }) client.connect(assert.calls(function (error, client) { assert(error instanceof Error) done() })) }) suite.test('non-error calls supplied callback', function (done) { var client = new Client({ user: helper.args.user, password: helper.args.password, host: helper.args.host, port: helper.args.port, database: helper.args.database }) client.connect(assert.calls(function (err) { assert.ifError(err) client.end(done) })) }) suite.test('when connecting to an invalid host with callback', function (done) { var client = new Client({ user: 'very invalid username' }) client.on('error', () => { assert.fail('unexpected error event when connecting') }) client.connect(function (error, client) { assert(error instanceof Error) done() }) }) suite.test('when connecting to invalid host with promise', function (done) { var client = new Client({ user: 'very invalid username' }) client.on('error', () => { assert.fail('unexpected error event when connecting') }) client.connect().catch((e) => done()) }) suite.test('non-query error', function (done) { var client = new Client({ user: 'asldkfjsadlfkj' }) client.connect() .catch(e => { assert(e instanceof Error) done() }) }) suite.test('within a simple query', (done) => { var client = createErorrClient() var query = client.query(new pg.Query("select eeeee from yodas_dsflsd where pixistix = 'zoiks!!!'")) assert.emits(query, 'error', function (error) { assert.equal(error.severity, 'ERROR') done() }) }) suite.test('connected, idle client error', (done) => { const client = new Client() client.connect((err) => { if (err) { throw new Error('Should not receive error callback after connection') } setImmediate(() => { (client.connection || client.native).emit('error', new Error('expected')) }) }) client.on('error', (err) => { assert.equal(err.message, 'expected') client.end(done) }) }) suite.test('cannot pass non-string values to query as text', (done) => { const client = new Client() client.connect() client.query({ text: { } }, (err) => { assert(err) client.query({ }, (err) => { client.on('drain', () => { client.end(done) }) }) }) }) node-postgres-7.14.0/test/integration/client/field-name-escape-tests.js000066400000000000000000000003661356526317000261260ustar00rootroot00000000000000var pg = require('./test-helper').pg var sql = 'SELECT 1 AS "\\\'/*", 2 AS "\\\'*/\n + process.exit(-1)] = null;\n//"' var client = new pg.Client() client.connect() client.query(sql, function (err, res) { if (err) throw err client.end() }) node-postgres-7.14.0/test/integration/client/huge-numeric-tests.js000066400000000000000000000012321356526317000252500ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') const pool = new helper.pg.Pool() pool.connect(assert.success(function (client, done) { var types = require('pg-types') // 1231 = numericOID types.setTypeParser(1700, function () { return 'yes' }) types.setTypeParser(1700, 'binary', function () { return 'yes' }) var bignum = '294733346389144765940638005275322203805' client.query('CREATE TEMP TABLE bignumz(id numeric)') client.query('INSERT INTO bignumz(id) VALUES ($1)', [bignum]) client.query('SELECT * FROM bignumz', assert.success(function (result) { assert.equal(result.rows[0].id, 'yes') done() pool.end() })) })) node-postgres-7.14.0/test/integration/client/json-type-parsing-tests.js000066400000000000000000000020571356526317000262570ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var assert = require('assert') const pool = new helper.pg.Pool() pool.connect(assert.success(function (client, done) { helper.versionGTE(client, 90200, assert.success(function (jsonSupported) { if (!jsonSupported) { console.log('skip json test on older versions of postgres') done() return pool.end() } client.query('CREATE TEMP TABLE stuff(id SERIAL PRIMARY KEY, data JSON)') var value = { name: 'Brian', age: 250, alive: true, now: new Date() } client.query('INSERT INTO stuff (data) VALUES ($1)', [value]) client.query('SELECT * FROM stuff', assert.success(function (result) { assert.equal(result.rows.length, 1) assert.equal(typeof result.rows[0].data, 'object') var row = result.rows[0].data assert.strictEqual(row.name, value.name) assert.strictEqual(row.age, value.age) assert.strictEqual(row.alive, value.alive) assert.equal(JSON.stringify(row.now), JSON.stringify(value.now)) done() pool.end() })) })) })) node-postgres-7.14.0/test/integration/client/multiple-results-tests.js000066400000000000000000000036501356526317000262200ustar00rootroot00000000000000'use strict' const assert = require('assert') const co = require('co') const helper = require('./test-helper') const suite = new helper.Suite('multiple result sets') suite.test('two select results work', co.wrap(function * () { const client = new helper.Client() yield client.connect() const results = yield client.query(`SELECT 'foo'::text as name; SELECT 'bar'::text as baz`) assert(Array.isArray(results)) assert.equal(results[0].fields[0].name, 'name') assert.deepEqual(results[0].rows, [{ name: 'foo' }]) assert.equal(results[1].fields[0].name, 'baz') assert.deepEqual(results[1].rows, [{ baz: 'bar' }]) return client.end() })) suite.test('multiple selects work', co.wrap(function * () { const client = new helper.Client() yield client.connect() const text = ` SELECT * FROM generate_series(2, 4) as foo; SELECT * FROM generate_series(8, 10) as bar; SELECT * FROM generate_series(20, 22) as baz; ` const results = yield client.query(text) assert(Array.isArray(results)) assert.equal(results[0].fields[0].name, 'foo') assert.deepEqual(results[0].rows, [{ foo: 2 }, { foo: 3 }, { foo: 4 }]) assert.equal(results[1].fields[0].name, 'bar') assert.deepEqual(results[1].rows, [{ bar: 8 }, { bar: 9 }, { bar: 10 }]) assert.equal(results[2].fields[0].name, 'baz') assert.deepEqual(results[2].rows, [{ baz: 20 }, { baz: 21 }, { baz: 22 }]) assert.equal(results.length, 3) return client.end() })) suite.test('mixed queries and statements', co.wrap(function * () { const client = new helper.Client() yield client.connect() const text = ` CREATE TEMP TABLE weather(type text); INSERT INTO weather(type) VALUES ('rain'); SELECT * FROM weather; ` const results = yield client.query(text) assert(Array.isArray(results)) assert.equal(results[0].command, 'CREATE') assert.equal(results[1].command, 'INSERT') assert.equal(results[2].command, 'SELECT') return client.end() })) node-postgres-7.14.0/test/integration/client/network-partition-tests.js000066400000000000000000000045201356526317000263630ustar00rootroot00000000000000'use strict' var buffers = require('../../test-buffers') var helper = require('./test-helper') var suite = new helper.Suite() var net = require('net') var Server = function (response) { this.server = undefined this.socket = undefined this.response = response } Server.prototype.start = function (cb) { // this is our fake postgres server // it responds with our specified response immediatley after receiving every buffer // this is sufficient into convincing the client its connectet to a valid backend // if we respond with a readyForQuery message this.server = net.createServer(function (socket) { this.socket = socket if (this.response) { this.socket.on('data', function (data) { // deny request for SSL if (data.length == 8) { this.socket.write(Buffer.from('N', 'utf8')) // consider all authentication requests as good } else if (!data[0]) { this.socket.write(buffers.authenticationOk()) // respond with our canned response } else { this.socket.write(this.response) } }.bind(this)) } }.bind(this)) var port = 54321 var options = { host: 'localhost', port: port } this.server.listen(options.port, options.host, function () { cb(options) }) } Server.prototype.drop = function () { this.socket.destroy() } Server.prototype.close = function (cb) { this.server.close(cb) } var testServer = function (server, cb) { // wait for our server to start server.start(function (options) { // connect a client to it var client = new helper.Client(options) client.connect() .catch((err) => { assert(err instanceof Error) clearTimeout(timeoutId) server.close(cb) }) server.server.on('connection', () => { // after 50 milliseconds, drop the client setTimeout(function () { server.drop() }, 50) }) // blow up if we don't receive an error var timeoutId = setTimeout(function () { throw new Error('Client should have emitted an error but it did not.') }, 5000) }) } suite.test('readyForQuery server', (done) => { const respondingServer = new Server(buffers.readyForQuery()) testServer(respondingServer, done) }) suite.test('silent server', (done) => { const silentServer = new Server() testServer(silentServer, done) }) node-postgres-7.14.0/test/integration/client/no-data-tests.js000066400000000000000000000014321356526317000242050ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') const suite = new helper.Suite() suite.test('noData message handling', function () { var client = helper.client() var q = client.query({ name: 'boom', text: 'create temp table boom(id serial, size integer)' }) client.query({ name: 'insert', text: 'insert into boom(size) values($1)', values: [100] }, function (err, result) { if (err) { console.log(err) throw err } }) client.query({ name: 'insert', values: [101] }) var query = client.query({ name: 'fetch', text: 'select size from boom where size < $1', values: [101] }, (err, res) => { var row = res.rows[0] assert.strictEqual(row.size, 100) }) client.on('drain', client.end.bind(client)) }) node-postgres-7.14.0/test/integration/client/no-row-result-tests.js000066400000000000000000000014421356526317000254200ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var pg = helper.pg const suite = new helper.Suite() const pool = new pg.Pool() suite.test('can access results when no rows are returned', function (done) { var checkResult = function (result) { assert(result.fields, 'should have fields definition') assert.equal(result.fields.length, 1) assert.equal(result.fields[0].name, 'val') assert.equal(result.fields[0].dataTypeID, 25) } pool.connect( assert.success(function (client, release) { const q = new pg.Query('select $1::text as val limit 0', ['hi']) var query = client.query(q, assert.success(function (result) { checkResult(result) release() pool.end(done) }) ) assert.emits(query, 'end', checkResult) }) ) }) node-postgres-7.14.0/test/integration/client/notice-tests.js000066400000000000000000000033001356526317000241370ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') const suite = new helper.Suite() suite.test('emits notify message', function (done) { var client = helper.client() client.query('LISTEN boom', assert.calls(function () { var otherClient = helper.client() var bothEmitted = -1 otherClient.query('LISTEN boom', assert.calls(function () { assert.emits(client, 'notification', function (msg) { // make sure PQfreemem doesn't invalidate string pointers setTimeout(function () { assert.equal(msg.channel, 'boom') assert.ok(msg.payload == 'omg!' /* 9.x */ || msg.payload == '' /* 8.x */, 'expected blank payload or correct payload but got ' + msg.message) client.end(++bothEmitted ? done : undefined) }, 100) }) assert.emits(otherClient, 'notification', function (msg) { assert.equal(msg.channel, 'boom') otherClient.end(++bothEmitted ? done : undefined) }) client.query("NOTIFY boom, 'omg!'", function (err, q) { if (err) { // notify not supported with payload on 8.x client.query('NOTIFY boom') } }) })) })) }) // this test fails on travis due to their config suite.test('emits notice message', false, function (done) { if (helper.args.native) { console.error('need to get notice message working on native') return done() } // TODO this doesn't work on all versions of postgres var client = helper.client() const text = ` DO language plpgsql $$ BEGIN RAISE NOTICE 'hello, world!'; END $$; ` client.query(text, () => { client.end() }) assert.emits(client, 'notice', function (notice) { assert.ok(notice != null) done() }) }) node-postgres-7.14.0/test/integration/client/parse-int-8-tests.js000066400000000000000000000022011356526317000247240ustar00rootroot00000000000000'use strict' var helper = require('../test-helper') var pg = helper.pg const suite = new helper.Suite() const pool = new pg.Pool(helper.config) suite.test('ability to turn on and off parser', function () { if (helper.args.binary) return false pool.connect(assert.success(function (client, done) { pg.defaults.parseInt8 = true client.query('CREATE TEMP TABLE asdf(id SERIAL PRIMARY KEY)') client.query('SELECT COUNT(*) as "count", \'{1,2,3}\'::bigint[] as array FROM asdf', assert.success(function (res) { assert.strictEqual(0, res.rows[0].count) assert.strictEqual(1, res.rows[0].array[0]) assert.strictEqual(2, res.rows[0].array[1]) assert.strictEqual(3, res.rows[0].array[2]) pg.defaults.parseInt8 = false client.query('SELECT COUNT(*) as "count", \'{1,2,3}\'::bigint[] as array FROM asdf', assert.success(function (res) { done() assert.strictEqual('0', res.rows[0].count) assert.strictEqual('1', res.rows[0].array[0]) assert.strictEqual('2', res.rows[0].array[1]) assert.strictEqual('3', res.rows[0].array[2]) pool.end() })) })) })) }) node-postgres-7.14.0/test/integration/client/prepared-statement-tests.js000066400000000000000000000076551356526317000265030ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var Query = helper.pg.Query var suite = new helper.Suite() ;(function () { var client = helper.client() client.on('drain', client.end.bind(client)) var queryName = 'user by age and like name' var parseCount = 0 suite.test('first named prepared statement', function (done) { var query = client.query(new Query({ text: 'select name from person where age <= $1 and name LIKE $2', values: [20, 'Bri%'], name: queryName })) assert.emits(query, 'row', function (row) { assert.equal(row.name, 'Brian') }) query.on('end', () => done()) }) suite.test('second named prepared statement with same name & text', function (done) { var cachedQuery = client.query(new Query({ text: 'select name from person where age <= $1 and name LIKE $2', name: queryName, values: [10, 'A%'] })) assert.emits(cachedQuery, 'row', function (row) { assert.equal(row.name, 'Aaron') }) cachedQuery.on('end', () => done()) }) suite.test('with same name, but without query text', function (done) { var q = client.query(new Query({ name: queryName, values: [30, '%n%'] })) assert.emits(q, 'row', function (row) { assert.equal(row.name, 'Aaron') // test second row is emitted as well assert.emits(q, 'row', function (row) { assert.equal(row.name, 'Brian') }) }) q.on('end', () => done()) }) suite.test('with same name, but with different text', function (done) { client.query(new Query({ text: 'select name from person where age >= $1 and name LIKE $2', name: queryName, values: [30, '%n%'] }), assert.calls(err => { assert.equal(err.message, `Prepared statements must be unique - '${queryName}' was used for a different statement`) done() })) }) })() ;(function () { var statementName = 'differ' var statement1 = 'select count(*)::int4 as count from person' var statement2 = 'select count(*)::int4 as count from person where age < $1' var client1 = helper.client() var client2 = helper.client() suite.test('client 1 execution', function (done) { var query = client1.query({ name: statementName, text: statement1 }, (err, res) => { assert(!err) assert.equal(res.rows[0].count, 26) done() }) }) suite.test('client 2 execution', function (done) { var query = client2.query(new Query({ name: statementName, text: statement2, values: [11] })) assert.emits(query, 'row', function (row) { assert.equal(row.count, 1) }) assert.emits(query, 'end', function () { done() }) }) suite.test('clean up clients', () => { return client1.end().then(() => client2.end()) }) })() ;(function () { var client = helper.client() client.query('CREATE TEMP TABLE zoom(name varchar(100));') client.query("INSERT INTO zoom (name) VALUES ('zed')") client.query("INSERT INTO zoom (name) VALUES ('postgres')") client.query("INSERT INTO zoom (name) VALUES ('node postgres')") var checkForResults = function (q) { assert.emits(q, 'row', function (row) { assert.equal(row.name, 'node postgres') assert.emits(q, 'row', function (row) { assert.equal(row.name, 'postgres') assert.emits(q, 'row', function (row) { assert.equal(row.name, 'zed') }) }) }) } suite.test('with small row count', function (done) { var query = client.query(new Query({ name: 'get names', text: 'SELECT name FROM zoom ORDER BY name COLLATE "C"', rows: 1 }, done)) checkForResults(query) }) suite.test('with large row count', function (done) { var query = client.query(new Query({ name: 'get names', text: 'SELECT name FROM zoom ORDER BY name COLLATE "C"', rows: 1000 }, done)) checkForResults(query) }) suite.test('cleanup', () => client.end()) })() node-postgres-7.14.0/test/integration/client/promise-api-tests.js000066400000000000000000000022331356526317000251070ustar00rootroot00000000000000'use strict' const helper = require('./test-helper') const pg = helper.pg const suite = new helper.Suite() suite.test('valid connection completes promise', () => { const client = new pg.Client() return client.connect() .then(() => { return client.end() .then(() => { }) }) }) suite.test('valid connection completes promise', () => { const client = new pg.Client() return client.connect() .then(() => { return client.end() .then(() => { }) }) }) suite.test('invalid connection rejects promise', (done) => { const client = new pg.Client({ host: 'alksdjflaskdfj' }) return client.connect() .catch(e => { assert(e instanceof Error) done() }) }) suite.test('connected client does not reject promise after connection', (done) => { const client = new pg.Client() return client.connect() .then(() => { setTimeout(() => { client.on('error', (e) => { assert(e instanceof Error) client.end() done() }) // manually kill the connection client.emit('error', new Error('something bad happened...but not really')) }, 50) }) }) node-postgres-7.14.0/test/integration/client/query-as-promise-tests.js000066400000000000000000000027441356526317000261130ustar00rootroot00000000000000'use strict' var bluebird = require('bluebird') var helper = require(__dirname + '/../test-helper') var pg = helper.pg process.on('unhandledRejection', function (e) { console.error(e, e.stack) process.exit(1) }) const suite = new helper.Suite() suite.test('promise API', (cb) => { const pool = new pg.Pool() pool.connect().then((client) => { client.query('SELECT $1::text as name', ['foo']) .then(function (result) { assert.equal(result.rows[0].name, 'foo') return client }) .then(function (client) { client.query('ALKJSDF') .catch(function (e) { assert(e instanceof Error) client.query('SELECT 1 as num') .then(function (result) { assert.equal(result.rows[0].num, 1) client.release() pool.end(cb) }) }) }) }) }) suite.test('promise API with configurable promise type', (cb) => { const client = new pg.Client({ Promise: bluebird }) const connectPromise = client.connect() assert(connectPromise instanceof bluebird, 'Client connect() returns configured promise') connectPromise .then(() => { const queryPromise = client.query('SELECT 1') assert(queryPromise instanceof bluebird, 'Client query() returns configured promise') return queryPromise.then(() => { client.end(cb) }) }) .catch((error) => { process.nextTick(() => { throw error }) }) }); node-postgres-7.14.0/test/integration/client/query-column-names-tests.js000066400000000000000000000007541356526317000264310ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/../test-helper') var pg = helper.pg new helper.Suite().test('support for complex column names', function () { const pool = new pg.Pool() pool.connect(assert.success(function (client, done) { client.query("CREATE TEMP TABLE t ( \"complex''column\" TEXT )") client.query('SELECT * FROM t', assert.success(function (res) { done() assert.strictEqual(res.fields[0].name, "complex''column") pool.end() })) })) }) node-postgres-7.14.0/test/integration/client/query-error-handling-prepared-statement-tests.js000066400000000000000000000054741356526317000325540ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var Query = helper.pg.Query var util = require('util') var suite = new helper.Suite() suite.test('client end during query execution of prepared statement', function (done) { var client = new Client() client.connect(assert.success(function () { var sleepQuery = 'select pg_sleep($1)' var queryConfig = { name: 'sleep query', text: sleepQuery, values: [5] } var queryInstance = new Query(queryConfig, assert.calls(function (err, result) { assert.equal(err.message, 'Connection terminated') done() })) var query1 = client.query(queryInstance) query1.on('error', function (err) { assert.fail('Prepared statement should not emit error') }) query1.on('row', function (row) { assert.fail('Prepared statement should not emit row') }) query1.on('end', function (err) { assert.fail('Prepared statement when executed should not return before being killed') }) client.end() })) }) function killIdleQuery (targetQuery, cb) { var client2 = new Client(helper.args) var pidColName = 'procpid' var queryColName = 'current_query' client2.connect(assert.success(function () { helper.versionGTE(client2, 90200, assert.success(function (isGreater) { if (isGreater) { pidColName = 'pid' queryColName = 'query' } var killIdleQuery = 'SELECT ' + pidColName + ', (SELECT pg_terminate_backend(' + pidColName + ')) AS killed FROM pg_stat_activity WHERE ' + queryColName + ' = $1' client2.query(killIdleQuery, [targetQuery], assert.calls(function (err, res) { assert.ifError(err) assert.equal(res.rows.length, 1) client2.end(cb) assert.emits(client2, 'end') })) })) })) } suite.test('query killed during query execution of prepared statement', function (done) { if (helper.args.native) { return done() } var client = new Client(helper.args) client.connect(assert.success(function () { var sleepQuery = 'select pg_sleep($1)' const queryConfig = { name: 'sleep query', text: sleepQuery, values: [5] } // client should emit an error because it is unexpectedly disconnected assert.emits(client, 'error') var query1 = client.query(new Query(queryConfig), assert.calls(function (err, result) { assert.equal(err.message, 'terminating connection due to administrator command') })) query1.on('error', function (err) { assert.fail('Prepared statement should not emit error') }) query1.on('row', function (row) { assert.fail('Prepared statement should not emit row') }) query1.on('end', function (err) { assert.fail('Prepared statement when executed should not return before being killed') }) killIdleQuery(sleepQuery, done) })) }) node-postgres-7.14.0/test/integration/client/query-error-handling-tests.js000066400000000000000000000060371356526317000267460ustar00rootroot00000000000000"use strict"; var helper = require('./test-helper'); var util = require('util'); var Query = helper.pg.Query; test('error during query execution', function() { var client = new Client(helper.args); client.connect(assert.success(function() { var queryText = 'select pg_sleep(10)' var sleepQuery = new Query(queryText); var pidColName = 'procpid' var queryColName = 'current_query'; helper.versionGTE(client, 90200, assert.success(function(isGreater) { if(isGreater) { pidColName = 'pid'; queryColName = 'query'; } var query1 = client.query(sleepQuery, assert.calls(function(err, result) { assert(err); client.end(); })); //ensure query1 does not emit an 'end' event //because it was killed and received an error //https://github.com/brianc/node-postgres/issues/547 query1.on('end', function() { assert.fail('Query with an error should not emit "end" event') }) setTimeout(function() { var client2 = new Client(helper.args); client2.connect(assert.success(function() { var killIdleQuery = `SELECT ${pidColName}, (SELECT pg_cancel_backend(${pidColName})) AS killed FROM pg_stat_activity WHERE ${queryColName} LIKE $1`; client2.query(killIdleQuery, [queryText], assert.calls(function(err, res) { assert.ifError(err); assert(res.rows.length > 0); client2.end(); assert.emits(client2, 'end'); })); })); }, 300) })); })); }); if (helper.config.native) { return } test('9.3 column error fields', function() { var client = new Client(helper.args); client.connect(assert.success(function() { helper.versionGTE(client, 90300, assert.success(function(isGreater) { if(!isGreater) { return client.end(); } client.query('CREATE TEMP TABLE column_err_test(a int NOT NULL)'); client.query('INSERT INTO column_err_test(a) VALUES (NULL)', function (err) { assert.equal(err.severity, 'ERROR'); assert.equal(err.code, '23502'); assert.equal(err.table, 'column_err_test'); assert.equal(err.column, 'a'); return client.end(); }); })); })); }); test('9.3 constraint error fields', function() { var client = new Client(helper.args); client.connect(assert.success(function() { helper.versionGTE(client, 90300, assert.success(function(isGreater) { if(!isGreater) { console.log('skip 9.3 error field on older versions of postgres'); return client.end(); } client.query('CREATE TEMP TABLE constraint_err_test(a int PRIMARY KEY)'); client.query('INSERT INTO constraint_err_test(a) VALUES (1)'); client.query('INSERT INTO constraint_err_test(a) VALUES (1)', function (err) { assert.equal(err.severity, 'ERROR'); assert.equal(err.code, '23505'); assert.equal(err.table, 'constraint_err_test'); assert.equal(err.constraint, 'constraint_err_test_pkey'); return client.end(); }); })); })); }); node-postgres-7.14.0/test/integration/client/quick-disconnect-tests.js000066400000000000000000000002351356526317000261250ustar00rootroot00000000000000'use strict' // test for issue #320 // var helper = require('./test-helper') var client = new helper.pg.Client(helper.config) client.connect() client.end() node-postgres-7.14.0/test/integration/client/result-metadata-tests.js000066400000000000000000000021271356526317000257600ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var pg = helper.pg const pool = new pg.Pool() new helper.Suite().test('should return insert metadata', function () { pool.connect(assert.calls(function (err, client, done) { assert(!err) helper.versionGTE(client, 90000, assert.success(function (hasRowCount) { client.query('CREATE TEMP TABLE zugzug(name varchar(10))', assert.calls(function (err, result) { assert(!err) assert.equal(result.oid, null) assert.equal(result.command, 'CREATE') var q = client.query("INSERT INTO zugzug(name) VALUES('more work?')", assert.calls(function (err, result) { assert(!err) assert.equal(result.command, 'INSERT') assert.equal(result.rowCount, 1) client.query('SELECT * FROM zugzug', assert.calls(function (err, result) { assert(!err) if (hasRowCount) assert.equal(result.rowCount, 1) assert.equal(result.command, 'SELECT') done() process.nextTick(pool.end.bind(pool)) })) })) })) })) })) }) node-postgres-7.14.0/test/integration/client/results-as-array-tests.js000066400000000000000000000015441356526317000261040ustar00rootroot00000000000000'use strict' var util = require('util') var helper = require('./test-helper') var Client = helper.Client var conInfo = helper.config test('returns results as array', function () { var client = new Client(conInfo) var checkRow = function (row) { assert(util.isArray(row), 'row should be an array') assert.equal(row.length, 4) assert.equal(row[0].getFullYear(), new Date().getFullYear()) assert.strictEqual(row[1], 1) assert.strictEqual(row[2], 'hai') assert.strictEqual(row[3], null) } client.connect(assert.success(function () { var config = { text: 'SELECT NOW(), 1::int, $1::text, null', values: ['hai'], rowMode: 'array' } var query = client.query(config, assert.success(function (result) { assert.equal(result.rows.length, 1) checkRow(result.rows[0]) client.end() })) })) }) node-postgres-7.14.0/test/integration/client/row-description-on-results-tests.js000066400000000000000000000021441356526317000301240ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var Client = helper.Client var conInfo = helper.config var checkResult = function (result) { assert(result.fields) assert.equal(result.fields.length, 3) var fields = result.fields assert.equal(fields[0].name, 'now') assert.equal(fields[1].name, 'num') assert.equal(fields[2].name, 'texty') assert.equal(fields[0].dataTypeID, 1184) assert.equal(fields[1].dataTypeID, 23) assert.equal(fields[2].dataTypeID, 25) } test('row descriptions on result object', function () { var client = new Client(conInfo) client.connect(assert.success(function () { client.query('SELECT NOW() as now, 1::int as num, $1::text as texty', ['hello'], assert.success(function (result) { checkResult(result) client.end() })) })) }) test('row description on no rows', function () { var client = new Client(conInfo) client.connect(assert.success(function () { client.query('SELECT NOW() as now, 1::int as num, $1::text as texty LIMIT 0', ['hello'], assert.success(function (result) { checkResult(result) client.end() })) })) }) node-postgres-7.14.0/test/integration/client/sasl-scram-tests.js000066400000000000000000000020371356526317000247310ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/../test-helper') var pg = helper.pg var suite = new helper.Suite() /* SQL to create test role: set password_encryption = 'scram-sha-256'; create role npgtest login password 'test'; pg_hba: host all npgtest ::1/128 scram-sha-256 host all npgtest 0.0.0.0/0 scram-sha-256 */ /* suite.test('can connect using sasl/scram', function () { var connectionString = 'pg://npgtest:test@localhost/postgres' const pool = new pg.Pool({ connectionString: connectionString }) pool.connect( assert.calls(function (err, client, done) { assert.ifError(err, 'should have connected') done() }) ) }) suite.test('sasl/scram fails when password is wrong', function () { var connectionString = 'pg://npgtest:bad@localhost/postgres' const pool = new pg.Pool({ connectionString: connectionString }) pool.connect( assert.calls(function (err, client, done) { assert.ok(err, 'should have a connection error') done() }) ) }) */ node-postgres-7.14.0/test/integration/client/simple-query-tests.js000066400000000000000000000056721356526317000253300ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var Query = helper.pg.Query // before running this test make sure you run the script create-test-tables test('simple query interface', function () { var client = helper.client() var query = client.query(new Query('select name from person order by name collate "C"')) client.on('drain', client.end.bind(client)) var rows = [] query.on('row', function (row, result) { assert.ok(result) rows.push(row['name']) }) query.once('row', function (row) { test('Can iterate through columns', function () { var columnCount = 0 for (var column in row) { columnCount++ } if ('length' in row) { assert.lengthIs(row, columnCount, 'Iterating through the columns gives a different length from calling .length.') } }) }) assert.emits(query, 'end', function () { test('returned right number of rows', function () { assert.lengthIs(rows, 26) }) test('row ordering', function () { assert.equal(rows[0], 'Aaron') assert.equal(rows[25], 'Zanzabar') }) }) }) test('prepared statements do not mutate params', function () { var client = helper.client() var params = [1] var query = client.query(new Query('select name from person where $1 = 1 order by name collate "C"', params)) assert.deepEqual(params, [1]) client.on('drain', client.end.bind(client)) const rows = [] query.on('row', function (row, result) { assert.ok(result) rows.push(row) }) query.on('end', function (result) { assert.lengthIs(rows, 26, 'result returned wrong number of rows') assert.lengthIs(rows, result.rowCount) assert.equal(rows[0].name, 'Aaron') assert.equal(rows[25].name, 'Zanzabar') }) }) test('multiple simple queries', function () { var client = helper.client() client.query({ text: "create temp table bang(id serial, name varchar(5));insert into bang(name) VALUES('boom');"}) client.query("insert into bang(name) VALUES ('yes');") var query = client.query(new Query('select name from bang')) assert.emits(query, 'row', function (row) { assert.equal(row['name'], 'boom') assert.emits(query, 'row', function (row) { assert.equal(row['name'], 'yes') }) }) client.on('drain', client.end.bind(client)) }) test('multiple select statements', function () { var client = helper.client() client.query('create temp table boom(age integer); insert into boom(age) values(1); insert into boom(age) values(2); insert into boom(age) values(3)') client.query({text: "create temp table bang(name varchar(5)); insert into bang(name) values('zoom');"}) var result = client.query(new Query({text: 'select age from boom where age < 2; select name from bang'})) assert.emits(result, 'row', function (row) { assert.strictEqual(row['age'], 1) assert.emits(result, 'row', function (row) { assert.strictEqual(row['name'], 'zoom') }) }) client.on('drain', client.end.bind(client)) }) node-postgres-7.14.0/test/integration/client/ssl-tests.js000066400000000000000000000006071356526317000234660ustar00rootroot00000000000000'use strict' var pg = require(__dirname + '/../../../lib') var config = require(__dirname + '/test-helper').config test('can connect with ssl', function () { return false config.ssl = { rejectUnauthorized: false } pg.connect(config, assert.success(function (client) { return false client.query('SELECT NOW()', assert.success(function () { pg.end() })) })) }) node-postgres-7.14.0/test/integration/client/statement_timeout-tests.js000066400000000000000000000037641356526317000264460ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var Client = helper.Client var suite = new helper.Suite() var conInfo = helper.config function getConInfo (override) { return Object.assign({}, conInfo, override ) } function getStatementTimeout (conf, cb) { var client = new Client(conf) client.connect(assert.success(function () { client.query('SHOW statement_timeout', assert.success(function (res) { var statementTimeout = res.rows[0].statement_timeout cb(statementTimeout) client.end() })) })) } if (!helper.args.native) { // statement_timeout is not supported with the native client suite.test('No default statement_timeout ', function (done) { getConInfo() getStatementTimeout({}, function (res) { assert.strictEqual(res, '0') // 0 = no timeout done() }) }) suite.test('statement_timeout integer is used', function (done) { var conf = getConInfo({ 'statement_timeout': 3000 }) getStatementTimeout(conf, function (res) { assert.strictEqual(res, '3s') done() }) }) suite.test('statement_timeout float is used', function (done) { var conf = getConInfo({ 'statement_timeout': 3000.7 }) getStatementTimeout(conf, function (res) { assert.strictEqual(res, '3s') done() }) }) suite.test('statement_timeout string is used', function (done) { var conf = getConInfo({ 'statement_timeout': '3000' }) getStatementTimeout(conf, function (res) { assert.strictEqual(res, '3s') done() }) }) suite.test('statement_timeout actually cancels long running queries', function (done) { var conf = getConInfo({ 'statement_timeout': '10' // 10ms to keep tests running fast }) var client = new Client(conf) client.connect(assert.success(function () { client.query('SELECT pg_sleep( 1 )', function ( error ) { client.end() assert.strictEqual( error.code, '57014' ) // query_cancelled done() }) })) }) } node-postgres-7.14.0/test/integration/client/test-helper.js000066400000000000000000000001171356526317000237550ustar00rootroot00000000000000'use strict' var helper = require('./../test-helper') module.exports = helper node-postgres-7.14.0/test/integration/client/timezone-tests.js000066400000000000000000000016151356526317000245170ustar00rootroot00000000000000'use strict' var helper = require('./../test-helper') var exec = require('child_process').exec var oldTz = process.env.TZ process.env.TZ = 'Europe/Berlin' var date = new Date() const pool = new helper.pg.Pool() const suite = new helper.Suite() pool.connect(function (err, client, done) { assert(!err) suite.test('timestamp without time zone', function (cb) { client.query('SELECT CAST($1 AS TIMESTAMP WITHOUT TIME ZONE) AS "val"', [date], function (err, result) { assert(!err) assert.equal(result.rows[0].val.getTime(), date.getTime()) cb() }) }) suite.test('timestamp with time zone', function (cb) { client.query('SELECT CAST($1 AS TIMESTAMP WITH TIME ZONE) AS "val"', [date], function (err, result) { assert(!err) assert.equal(result.rows[0].val.getTime(), date.getTime()) done() pool.end(cb) process.env.TZ = oldTz }) }) }) node-postgres-7.14.0/test/integration/client/transaction-tests.js000066400000000000000000000035531356526317000252150ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') const suite = new helper.Suite() const pg = helper.pg const client = new pg.Client() client.connect(assert.success(function () { client.query('begin') var getZed = { text: 'SELECT * FROM person WHERE name = $1', values: ['Zed'] } suite.test('name should not exist in the database', function (done) { client.query(getZed, assert.calls(function (err, result) { assert(!err) assert.empty(result.rows) done() })) }) suite.test('can insert name', (done) => { client.query('INSERT INTO person(name, age) VALUES($1, $2)', ['Zed', 270], assert.calls(function (err, result) { assert(!err) done() })) }) suite.test('name should exist in the database', function (done) { client.query(getZed, assert.calls(function (err, result) { assert(!err) assert.equal(result.rows[0].name, 'Zed') done() })) }) suite.test('rollback', (done) => { client.query('rollback', done) }) suite.test('name should not exist in the database', function (done) { client.query(getZed, assert.calls(function (err, result) { assert(!err) assert.empty(result.rows) client.end(done) })) }) })) suite.test('gh#36', function (cb) { const pool = new pg.Pool() pool.connect(assert.success(function (client, done) { client.query('BEGIN') client.query({ name: 'X', text: 'SELECT $1::INTEGER', values: [0] }, assert.calls(function (err, result) { if (err) throw err assert.equal(result.rows.length, 1) })) client.query({ name: 'X', text: 'SELECT $1::INTEGER', values: [0] }, assert.calls(function (err, result) { if (err) throw err assert.equal(result.rows.length, 1) })) client.query('COMMIT', function () { done() pool.end(cb) }) })) }) node-postgres-7.14.0/test/integration/client/type-coercion-tests.js000066400000000000000000000130241356526317000254420ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') var pg = helper.pg var sink const suite = new helper.Suite() var testForTypeCoercion = function (type) { const pool = new pg.Pool() suite.test(`test type coercion ${type.name}`, (cb) => { pool.connect(function (err, client, done) { assert(!err) client.query('create temp table test_type(col ' + type.name + ')', assert.calls(function (err, result) { assert(!err) type.values.forEach(function (val) { var insertQuery = client.query('insert into test_type(col) VALUES($1)', [val], assert.calls(function (err, result) { assert(!err) })) var query = client.query(new pg.Query({ name: 'get type ' + type.name, text: 'select col from test_type' })) query.on('error', function (err) { console.log(err) throw err }) assert.emits(query, 'row', function (row) { var expected = val + ' (' + typeof val + ')' var returned = row.col + ' (' + typeof row.col + ')' assert.strictEqual(row.col, val, 'expected ' + type.name + ' of ' + expected + ' but got ' + returned) }, 'row should have been called for ' + type.name + ' of ' + val) client.query('delete from test_type') }) client.query('drop table test_type', function () { done() pool.end(cb) }) })) }) }) } var types = [{ name: 'integer', values: [-2147483648, -1, 0, 1, 2147483647, null] }, { name: 'smallint', values: [-32768, -1, 0, 1, 32767, null] }, { name: 'bigint', values: [ '-9223372036854775808', '-9007199254740992', '0', '9007199254740992', '72057594037928030', '9223372036854775807', null ] }, { name: 'varchar(5)', values: ['yo', '', 'zomg!', null] }, { name: 'oid', values: [0, 204410, null] }, { name: 'bool', values: [true, false, null] }, { name: 'numeric', values: [ '-12.34', '0', '12.34', '-3141592653589793238462643383279502.1618033988749894848204586834365638', '3141592653589793238462643383279502.1618033988749894848204586834365638', null ] }, { name: 'real', values: [-101.3, -1.2, 0, 1.2, 101.1, null] }, { name: 'double precision', values: [-101.3, -1.2, 0, 1.2, 101.1, null] }, { name: 'timestamptz', values: [null] }, { name: 'timestamp', values: [null] }, { name: 'timetz', values: ['13:11:12.1234-05:30', null] }, { name: 'time', values: ['13:12:12.321', null] }] // ignore some tests in binary mode if (helper.config.binary) { types = types.filter(function (type) { return !(type.name in { 'real': 1, 'timetz': 1, 'time': 1, 'numeric': 1, 'bigint': 1 }) }) } var valueCount = 0 types.forEach(function (type) { testForTypeCoercion(type) }) suite.test('timestampz round trip', function (cb) { var now = new Date() var client = helper.client() client.query('create temp table date_tests(name varchar(10), tstz timestamptz(3))') client.query({ text: 'insert into date_tests(name, tstz)VALUES($1, $2)', name: 'add date', values: ['now', now] }) var result = client.query(new pg.Query({ name: 'get date', text: 'select * from date_tests where name = $1', values: ['now'] })) assert.emits(result, 'row', function (row) { var date = row.tstz assert.equal(date.getYear(), now.getYear()) assert.equal(date.getMonth(), now.getMonth()) assert.equal(date.getDate(), now.getDate()) assert.equal(date.getHours(), now.getHours()) assert.equal(date.getMinutes(), now.getMinutes()) assert.equal(date.getSeconds(), now.getSeconds()) assert.equal(date.getMilliseconds(), now.getMilliseconds()) }) client.on('drain', () => { client.end(cb) }) }) suite.test('selecting nulls', cb => { const pool = new pg.Pool() pool.connect(assert.calls(function (err, client, done) { assert.ifError(err) client.query('select null as res;', assert.calls(function (err, res) { assert(!err) assert.strictEqual(res.rows[0].res, null) })) client.query('select 7 <> $1 as res;', [null], function (err, res) { assert(!err) assert.strictEqual(res.rows[0].res, null) done() pool.end(cb) }) })) }) suite.test('date range extremes', function (done) { var client = helper.client() // Set the server timeszone to the same as used for the test, // otherwise (if server's timezone is ahead of GMT) in // textParsers.js::parseDate() the timezone offest is added to the date; // in the case of "275760-09-13 00:00:00 GMT" the timevalue overflows. client.query('SET TIMEZONE TO GMT', assert.success(function (res) { // PostgreSQL supports date range of 4713 BCE to 294276 CE // http://www.postgresql.org/docs/9.2/static/datatype-datetime.html // ECMAScript supports date range of Apr 20 271821 BCE to Sep 13 275760 CE // http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.1 client.query('SELECT $1::TIMESTAMPTZ as when', ['275760-09-13 00:00:00 GMT'], assert.success(function (res) { assert.equal(res.rows[0].when.getFullYear(), 275760) })) client.query('SELECT $1::TIMESTAMPTZ as when', ['4713-12-31 12:31:59 BC GMT'], assert.success(function (res) { assert.equal(res.rows[0].when.getFullYear(), -4712) })) client.query('SELECT $1::TIMESTAMPTZ as when', ['275760-09-13 00:00:00 -15:00'], assert.success(function (res) { assert(isNaN(res.rows[0].when.getTime())) })) client.on('drain', () => { client.end(done) }) })) }) node-postgres-7.14.0/test/integration/client/type-parser-override-tests.js000066400000000000000000000022151356526317000267520ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') function testTypeParser (client, expectedResult, done) { var boolValue = true client.query('CREATE TEMP TABLE parserOverrideTest(id bool)') client.query('INSERT INTO parserOverrideTest(id) VALUES ($1)', [boolValue]) client.query('SELECT * FROM parserOverrideTest', assert.success(function (result) { assert.equal(result.rows[0].id, expectedResult) done() })) } const pool = new helper.pg.Pool(helper.config) pool.connect(assert.success(function (client1, done1) { pool.connect(assert.success(function (client2, done2) { var boolTypeOID = 16 client1.setTypeParser(boolTypeOID, function () { return 'first client' }) client2.setTypeParser(boolTypeOID, function () { return 'second client' }) client1.setTypeParser(boolTypeOID, 'binary', function () { return 'first client binary' }) client2.setTypeParser(boolTypeOID, 'binary', function () { return 'second client binary' }) testTypeParser(client1, 'first client', () => { done1() testTypeParser(client2, 'second client', () => done2(), pool.end()) }) })) })) node-postgres-7.14.0/test/integration/connection-pool/000077500000000000000000000000001356526317000230145ustar00rootroot00000000000000node-postgres-7.14.0/test/integration/connection-pool/connection-pool-size-tests.js000066400000000000000000000002261356526317000305700ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') helper.testPoolSize(1) helper.testPoolSize(2) helper.testPoolSize(40) helper.testPoolSize(200) node-postgres-7.14.0/test/integration/connection-pool/error-tests.js000066400000000000000000000061431356526317000256470ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') const pg = helper.pg const suite = new helper.Suite() suite.test('connecting to invalid port', (cb) => { const pool = new pg.Pool({ port: 13801 }) pool.connect().catch(e => cb()) }) suite.test('errors emitted on checked-out clients', (cb) => { // make pool hold 2 clients const pool = new pg.Pool({ max: 2 }) // get first client pool.connect(assert.success(function (client, done) { client.query('SELECT NOW()', function () { pool.connect(assert.success(function (client2, done2) { var pidColName = 'procpid' helper.versionGTE(client2, 90200, assert.success(function (isGreater) { var killIdleQuery = 'SELECT pid, (SELECT pg_terminate_backend(pid)) AS killed FROM pg_stat_activity WHERE state = $1' var params = ['idle'] if (!isGreater) { killIdleQuery = 'SELECT procpid, (SELECT pg_terminate_backend(procpid)) AS killed FROM pg_stat_activity WHERE current_query LIKE $1' params = ['%IDLE%'] } client.once('error', (err) => { client.on('error', (err) => {}) done(err) cb() }) // kill the connection from client client2.query(killIdleQuery, params, assert.success(function (res) { // check to make sure client connection actually was killed // return client2 to the pool done2() pool.end() })) })) })) }) })) }) suite.test('connection-level errors cause queued queries to fail', (cb) => { const pool = new pg.Pool() pool.connect(assert.success((client, done) => { client.query('SELECT pg_terminate_backend(pg_backend_pid())', assert.calls((err) => { if (helper.args.native) { assert.ok(err) } else { assert.equal(err.code, '57P01') } })) client.once('error', assert.calls((err) => { client.on('error', (err) => {}) })) client.query('SELECT 1', assert.calls((err) => { if (helper.args.native) { assert.equal(err.message, 'terminating connection due to administrator command') } else { assert.equal(err.message, 'Connection terminated unexpectedly') } done(err) pool.end() cb() })) })) }) suite.test('connection-level errors cause future queries to fail', (cb) => { const pool = new pg.Pool() pool.connect(assert.success((client, done) => { client.query('SELECT pg_terminate_backend(pg_backend_pid())', assert.calls((err) => { if (helper.args.native) { assert.ok(err) } else { assert.equal(err.code, '57P01') } })) client.once('error', assert.calls((err) => { client.on('error', (err) => {}) client.query('SELECT 1', assert.calls((err) => { if (helper.args.native) { assert.equal(err.message, 'terminating connection due to administrator command') } else { assert.equal(err.message, 'Client has encountered a connection error and is not queryable') } done(err) pool.end() cb() })) })) })) }) node-postgres-7.14.0/test/integration/connection-pool/idle-timeout-tests.js000066400000000000000000000005421356526317000271140ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') new helper.Suite().test('idle timeout', function () { const config = Object.assign({}, helper.config, { idleTimeoutMillis: 50 }) const pool = new helper.pg.Pool(config) pool.connect(assert.calls(function (err, client, done) { assert(!err) client.query('SELECT NOW()') done() })) }) node-postgres-7.14.0/test/integration/connection-pool/native-instance-tests.js000066400000000000000000000004531356526317000276040ustar00rootroot00000000000000'use strict' var helper = require('./../test-helper') var pg = helper.pg var native = helper.args.native var pool = new pg.Pool() pool.connect(assert.calls(function (err, client, done) { if (native) { assert(client.native) } else { assert(!client.native) } done() pool.end() })) node-postgres-7.14.0/test/integration/connection-pool/test-helper.js000066400000000000000000000015071356526317000256110ustar00rootroot00000000000000'use strict' var helper = require('./../test-helper') const suite = new helper.Suite() helper.testPoolSize = function (max) { suite.test(`test ${max} queries executed on a pool rapidly`, (cb) => { const pool = new helper.pg.Pool({ max: 10 }) var sink = new helper.Sink(max, function () { pool.end(cb) }) for (var i = 0; i < max; i++) { pool.connect(function (err, client, done) { assert(!err) client.query('SELECT * FROM NOW()') client.query('select generate_series(0, 25)', function (err, result) { assert.equal(result.rows.length, 26) }) var query = client.query('SELECT * FROM NOW()', (err) => { assert(!err) sink.add() done() }) }) } }) } module.exports = Object.assign({}, helper, { suite: suite }) node-postgres-7.14.0/test/integration/connection-pool/yield-support-tests.js000066400000000000000000000007751356526317000273430ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var co = require('co') const pool = new helper.pg.Pool() new helper.Suite().test('using coroutines works with promises', co.wrap(function * () { var client = yield pool.connect() var res = yield client.query('SELECT $1::text as name', ['foo']) assert.equal(res.rows[0].name, 'foo') var threw = false try { yield client.query('SELECT LKDSJDSLKFJ') } catch (e) { threw = true } assert(threw) client.release() yield pool.end() })) node-postgres-7.14.0/test/integration/connection/000077500000000000000000000000001356526317000220455ustar00rootroot00000000000000node-postgres-7.14.0/test/integration/connection/bound-command-tests.js000066400000000000000000000025001356526317000262630ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') // http://developer.postgresql.org/pgdocs/postgres/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY test('flushing once', function () { helper.connect(function (con) { con.parse({ text: 'select * from ids' }) con.bind() con.execute() con.flush() assert.emits(con, 'parseComplete') assert.emits(con, 'bindComplete') assert.emits(con, 'dataRow') assert.emits(con, 'commandComplete', function () { con.sync() }) assert.emits(con, 'readyForQuery', function () { con.end() }) }) }) test('sending many flushes', function () { helper.connect(function (con) { assert.emits(con, 'parseComplete', function () { con.bind() con.flush() }) assert.emits(con, 'bindComplete', function () { con.execute() con.flush() }) assert.emits(con, 'dataRow', function (msg) { assert.equal(msg.fields[0], 1) assert.emits(con, 'dataRow', function (msg) { assert.equal(msg.fields[0], 2) assert.emits(con, 'commandComplete', function () { con.sync() }) assert.emits(con, 'readyForQuery', function () { con.end() }) }) }) con.parse({ text: 'select * from ids order by id' }) con.flush() }) }) node-postgres-7.14.0/test/integration/connection/copy-tests.js000066400000000000000000000022551356526317000245210ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') var assert = require('assert') test('COPY FROM events check', function () { helper.connect(function (con) { var stdinStream = con.query('COPY person FROM STDIN') con.on('copyInResponse', function () { con.endCopyFrom() }) assert.emits(con, 'copyInResponse', function () { con.endCopyFrom() }, 'backend should emit copyInResponse after COPY FROM query' ) assert.emits(con, 'commandComplete', function () { con.end() }, 'backend should emit commandComplete after COPY FROM stream ends' ) }) }) test('COPY TO events check', function () { helper.connect(function (con) { var stdoutStream = con.query('COPY person TO STDOUT') assert.emits(con, 'copyOutResponse', function () { }, 'backend should emit copyOutResponse after COPY TO query' ) assert.emits(con, 'copyData', function () { }, 'backend should emit copyData on every data row' ) assert.emits(con, 'copyDone', function () { con.end() }, 'backend should emit copyDone after all data rows' ) }) }) node-postgres-7.14.0/test/integration/connection/dynamic-password.js000066400000000000000000000065401356526317000256740ustar00rootroot00000000000000'use strict' const assert = require('assert') const helper = require('./../test-helper') const suite = new helper.Suite() const pg = require('../../../lib/index') const Client = pg.Client; const password = process.env.PGPASSWORD || null const sleep = millis => new Promise(resolve => setTimeout(resolve, millis)) suite.testAsync('Get password from a sync function', () => { let wasCalled = false function getPassword() { wasCalled = true return password } const client = new Client({ password: getPassword, }) return client.connect() .then(() => { assert.ok(wasCalled, 'Our password function should have been called') return client.end() }) }) suite.testAsync('Throw error from a sync function', () => { let wasCalled = false const myError = new Error('Oops!') function getPassword() { wasCalled = true throw myError } const client = new Client({ password: getPassword, }) let wasThrown = false return client.connect() .catch(err => { assert.equal(err, myError, 'Our sync error should have been thrown') wasThrown = true }) .then(() => { assert.ok(wasCalled, 'Our password function should have been called') assert.ok(wasThrown, 'Our error should have been thrown') return client.end() }) }) suite.testAsync('Get password from a function asynchronously', () => { let wasCalled = false function getPassword() { wasCalled = true return sleep(100).then(() => password) } const client = new Client({ password: getPassword, }) return client.connect() .then(() => { assert.ok(wasCalled, 'Our password function should have been called') return client.end() }) }) suite.testAsync('Throw error from an async function', () => { let wasCalled = false const myError = new Error('Oops!') function getPassword() { wasCalled = true return sleep(100).then(() => { throw myError }) } const client = new Client({ password: getPassword, }) let wasThrown = false return client.connect() .catch(err => { assert.equal(err, myError, 'Our async error should have been thrown') wasThrown = true }) .then(() => { assert.ok(wasCalled, 'Our password function should have been called') assert.ok(wasThrown, 'Our error should have been thrown') return client.end() }) }) suite.testAsync('Password function must return a string', () => { let wasCalled = false function getPassword() { wasCalled = true // Return a password that is not a string return 12345 } const client = new Client({ password: getPassword, }) let wasThrown = false return client.connect() .catch(err => { assert.ok(err instanceof TypeError, 'A TypeError should have been thrown') assert.equal(err.message, 'Password must be a string') wasThrown = true }) .then(() => { assert.ok(wasCalled, 'Our password function should have been called') assert.ok(wasThrown, 'Our error should have been thrown') return client.end() }) }) node-postgres-7.14.0/test/integration/connection/notification-tests.js000066400000000000000000000010241356526317000262260ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') // http://www.postgresql.org/docs/8.3/static/libpq-notify.html test('recieves notification from same connection with no payload', function () { helper.connect(function (con) { con.query('LISTEN boom') assert.emits(con, 'readyForQuery', function () { con.query('NOTIFY boom') assert.emits(con, 'notification', function (msg) { assert.equal(msg.payload, '') assert.equal(msg.channel, 'boom') con.end() }) }) }) }) node-postgres-7.14.0/test/integration/connection/query-tests.js000066400000000000000000000013101356526317000247030ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') var assert = require('assert') var rows = [] // testing the low level 1-1 mapping api of client to postgres messages // it's cumbersome to use the api this way test('simple query', function () { helper.connect(function (con) { con.query('select * from ids') assert.emits(con, 'dataRow') con.on('dataRow', function (msg) { rows.push(msg.fields) }) assert.emits(con, 'readyForQuery', function () { con.end() }) }) }) process.on('exit', function () { assert.equal(rows.length, 2) assert.equal(rows[0].length, 1) assert.strictEqual(String(rows[0][0]), '1') assert.strictEqual(String(rows[1][0]), '2') }) node-postgres-7.14.0/test/integration/connection/test-helper.js000066400000000000000000000024371356526317000246450ustar00rootroot00000000000000'use strict' var net = require('net') var helper = require(__dirname + '/../test-helper') var Connection = require(__dirname + '/../../../lib/connection') var utils = require(__dirname + '/../../../lib/utils') var connect = function (callback) { var username = helper.args.user var database = helper.args.database var con = new Connection({stream: new net.Stream()}) con.on('error', function (error) { console.log(error) throw new Error('Connection error') }) con.connect(helper.args.port || '5432', helper.args.host || 'localhost') con.once('connect', function () { con.startup({ user: username, database: database }) con.once('authenticationCleartextPassword', function () { con.password(helper.args.password) }) con.once('authenticationMD5Password', function (msg) { con.password(utils.postgresMd5PasswordHash(helper.args.user, helper.args.password, msg.salt)); }) con.once('readyForQuery', function () { con.query('create temp table ids(id integer)') con.once('readyForQuery', function () { con.query('insert into ids(id) values(1); insert into ids(id) values(2);') con.once('readyForQuery', function () { callback(con) }) }) }) }) } module.exports = { connect: connect } node-postgres-7.14.0/test/integration/domain-tests.js000066400000000000000000000027771356526317000226700ustar00rootroot00000000000000'use strict' var async = require('async') var helper = require('./test-helper') var Query = helper.pg.Query var suite = new helper.Suite() const Pool = helper.pg.Pool suite.test('no domain', function (cb) { assert(!process.domain) const pool = new Pool() pool.connect(assert.success(function (client, done) { assert(!process.domain) done() pool.end(cb) })) }) suite.test('with domain', function (cb) { assert(!process.domain) const pool = new Pool() var domain = require('domain').create() domain.run(function () { var startingDomain = process.domain assert(startingDomain) pool.connect(assert.success(function (client, done) { assert(process.domain, 'no domain exists in connect callback') assert.equal(startingDomain, process.domain, 'domain was lost when checking out a client') var query = client.query('SELECT NOW()', assert.success(function () { assert(process.domain, 'no domain exists in query callback') assert.equal(startingDomain, process.domain, 'domain was lost when checking out a client') done(true) process.domain.exit() pool.end(cb) })) })) }) }) suite.test('error on domain', function (cb) { var domain = require('domain').create() const pool = new Pool() domain.on('error', function () { pool.end(cb) }) domain.run(function () { pool.connect(assert.success(function (client, done) { client.query(new Query('SELECT SLDKJFLSKDJF')) client.on('drain', done) })) }) }) node-postgres-7.14.0/test/integration/gh-issues/000077500000000000000000000000001356526317000216155ustar00rootroot00000000000000node-postgres-7.14.0/test/integration/gh-issues/130-tests.js000066400000000000000000000015441356526317000236220ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/../test-helper') var exec = require('child_process').exec helper.pg.defaults.poolIdleTimeout = 1000 const pool = new helper.pg.Pool() pool.connect(function (err, client, done) { assert.ifError(err) client.once('error', function (err) { client.on('error', (err) => {}) done(err) }) client.query('SELECT pg_backend_pid()', function (err, result) { assert.ifError(err) var pid = result.rows[0].pg_backend_pid var psql = 'psql' if (helper.args.host) psql = psql + ' -h ' + helper.args.host if (helper.args.port) psql = psql + ' -p ' + helper.args.port if (helper.args.user) psql = psql + ' -U ' + helper.args.user exec(psql + ' -c "select pg_terminate_backend(' + pid + ')" template1', assert.calls(function (error, stdout, stderr) { assert.ifError(error) })) }) }) node-postgres-7.14.0/test/integration/gh-issues/131-tests.js000066400000000000000000000016041356526317000236200ustar00rootroot00000000000000'use strict' var helper = require('../test-helper') var pg = helper.pg var suite = new helper.Suite() suite.test('parsing array decimal results', function (done) { const pool = new pg.Pool() pool.connect(assert.calls(function (err, client, release) { assert(!err) client.query('CREATE TEMP TABLE why(names text[], numbors integer[], decimals double precision[])') client.query(new pg.Query('INSERT INTO why(names, numbors, decimals) VALUES(\'{"aaron", "brian","a b c" }\', \'{1, 2, 3}\', \'{.1, 0.05, 3.654}\')')).on('error', console.log) client.query('SELECT decimals FROM why', assert.success(function (result) { assert.lengthIs(result.rows[0].decimals, 3) assert.equal(result.rows[0].decimals[0], 0.1) assert.equal(result.rows[0].decimals[1], 0.05) assert.equal(result.rows[0].decimals[2], 3.654) release() pool.end(done) })) })) }) node-postgres-7.14.0/test/integration/gh-issues/1382-tests.js000066400000000000000000000015531356526317000237140ustar00rootroot00000000000000"use strict" var helper = require('./../test-helper') const suite = new helper.Suite() suite.test('calling end during active query should return a promise', (done) => { const client = new helper.pg.Client() let callCount = 0 // ensure both the query rejects and the end promise resolves const after = () => { if (++callCount > 1) { done() } } client.connect().then(() => { client.query('SELECT NOW()').catch(after) client.end().then(after) }) }) suite.test('calling end during an active query should call end callback', (done) => { const client = new helper.pg.Client() let callCount = 0 // ensure both the query rejects and the end callback fires const after = () => { if (++callCount > 1) { done() } } client.connect().then(() => { client.query('SELECT NOW()').catch(after) client.end(after) }) }) node-postgres-7.14.0/test/integration/gh-issues/1854-tests.js000066400000000000000000000016671356526317000237260ustar00rootroot00000000000000"use strict" var helper = require('./../test-helper') const suite = new helper.Suite() suite.test('Parameter serialization errors should not cause query to hang', (done) => { if (helper.config.native) { // pg-native cannot handle non-string parameters so skip this entirely return done() } const client = new helper.pg.Client() const expectedErr = new Error('Serialization error') client.connect() .then(() => { const obj = { toPostgres: function () { throw expectedErr } } return client.query('SELECT $1::text', [obj]) .then(() => { throw new Error('Expected a serialization error to be thrown but no error was thrown') }) }) .catch((err) => { client.end(() => {}) if (err !== expectedErr) { done(new Error('Expected a serialization error to be thrown but instead caught: ' + err)) return } done() }) }) node-postgres-7.14.0/test/integration/gh-issues/199-tests.js000066400000000000000000000011241356526317000236330ustar00rootroot00000000000000'use strict' var helper = require('../test-helper') var client = helper.client() client.query('CREATE TEMP TABLE arrtest (n integer, s varchar)') client.query("INSERT INTO arrtest VALUES (4, 'foo'), (5, 'bar'), (6, 'baz');") var qText = "SELECT \ ARRAY[1, 2, 3] AS b,\ ARRAY['xx', 'yy', 'zz'] AS c,\ ARRAY(SELECT n FROM arrtest) AS d,\ ARRAY(SELECT s FROM arrtest) AS e;" client.query(qText, function (err, result) { if (err) throw err var row = result.rows[0] for (var key in row) { assert.equal(typeof row[key], 'object') assert.equal(row[key].length, 3) } client.end() }) node-postgres-7.14.0/test/integration/gh-issues/507-tests.js000066400000000000000000000011251356526317000236250ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/../test-helper') var pg = helper.pg new helper.Suite().test('parsing array results', function (cb) { const pool = new pg.Pool() pool.connect(assert.success(function (client, done) { client.query('CREATE TEMP TABLE test_table(bar integer, "baz\'s" integer)') client.query('INSERT INTO test_table(bar, "baz\'s") VALUES(1, 1), (2, 2)') client.query('SELECT * FROM test_table', function (err, res) { assert.equal(res.rows[0]["baz's"], 1) assert.equal(res.rows[1]["baz's"], 2) done() pool.end(cb) }) })) }) node-postgres-7.14.0/test/integration/gh-issues/600-tests.js000066400000000000000000000034011356526317000236160ustar00rootroot00000000000000'use strict' var async = require('async') var helper = require('../test-helper') const suite = new helper.Suite() var db = helper.client() function createTableFoo (callback) { db.query('create temp table foo(column1 int, column2 int)', callback) } function createTableBar (callback) { db.query('create temp table bar(column1 text, column2 text)', callback) } function insertDataFoo (callback) { db.query({ name: 'insertFoo', text: 'insert into foo values($1,$2)', values: ['one', 'two'] }, callback) } function insertDataBar (callback) { db.query({ name: 'insertBar', text: 'insert into bar values($1,$2)', values: ['one', 'two'] }, callback) } function startTransaction (callback) { db.query('BEGIN', callback) } function endTransaction (callback) { db.query('COMMIT', callback) } function doTransaction (callback) { // The transaction runs startTransaction, then all queries, then endTransaction, // no matter if there has been an error in a query in the middle. startTransaction(function () { insertDataFoo(function () { insertDataBar(function () { endTransaction(callback) }) }) }) } var steps = [ createTableFoo, createTableBar, doTransaction, insertDataBar ] suite.test('test if query fails', function (done) { async.series(steps, assert.success(function () { db.end() done() })) }) suite.test('test if prepare works but bind fails', function (done) { var client = helper.client() var q = { text: 'SELECT $1::int as name', values: ['brian'], name: 'test' } client.query(q, assert.calls(function (err, res) { q.values = [1] client.query(q, assert.calls(function (err, res) { assert.ifError(err) client.end() done() })) })) }) node-postgres-7.14.0/test/integration/gh-issues/675-tests.js000066400000000000000000000012331356526317000236330ustar00rootroot00000000000000'use strict' var helper = require('../test-helper') var assert = require('assert') const pool = new helper.pg.Pool() pool.connect(function (err, client, done) { if (err) throw err var c = 'CREATE TEMP TABLE posts (body TEXT)' client.query(c, function (err) { if (err) throw err c = 'INSERT INTO posts (body) VALUES ($1) RETURNING *' var body = Buffer.from('foo') client.query(c, [body], function (err) { if (err) throw err body = Buffer.from([]) client.query(c, [body], function (err, res) { done() if (err) throw err assert.equal(res.rows[0].body, '') pool.end() }) }) }) }) node-postgres-7.14.0/test/integration/gh-issues/699-tests.js000066400000000000000000000013721356526317000236450ustar00rootroot00000000000000"use strict"; var helper = require('../test-helper'); var assert = require('assert'); var copyFrom = require('pg-copy-streams').from; if(helper.args.native) return; const pool = new helper.pg.Pool() pool.connect(function (err, client, done) { if (err) throw err; var c = 'CREATE TEMP TABLE employee (id integer, fname varchar(400), lname varchar(400))'; client.query(c, function (err) { if (err) throw err; var stream = client.query(copyFrom("COPY employee FROM STDIN")); stream.on('end', function () { done(); setTimeout(() => { pool.end() }, 50) }); for (var i = 1; i <= 5; i++) { var line = ['1\ttest', i, '\tuser', i, '\n']; stream.write(line.join('')); } stream.end(); }); }); node-postgres-7.14.0/test/integration/gh-issues/787-tests.js000066400000000000000000000006051356526317000236410ustar00rootroot00000000000000'use strict' var helper = require('../test-helper') const pool = new helper.pg.Pool() pool.connect(function (err, client) { var q = { name: 'This is a super long query name just so I can test that an error message is properly spit out to console.error without throwing an exception or anything', text: 'SELECT NOW()' } client.query(q, function () { client.end() }) }) node-postgres-7.14.0/test/integration/gh-issues/882-tests.js000066400000000000000000000004441356526317000236360ustar00rootroot00000000000000'use strict' // client should not hang on an empty query var helper = require('../test-helper') var client = helper.client() client.query({ name: 'foo1', text: null}) client.query({ name: 'foo2', text: ' ' }) client.query({ name: 'foo3', text: '' }, function (err, res) { client.end() }) node-postgres-7.14.0/test/integration/gh-issues/981-tests.js000066400000000000000000000016051356526317000236360ustar00rootroot00000000000000"use strict"; var helper = require('./../test-helper'); //native bindings are only installed for native tests if (!helper.args.native) { return; } var assert = require('assert') var pg = require('../../../lib') var native = require('../../../lib').native var JsClient = require('../../../lib/client') var NativeClient = require('../../../lib/native') assert(pg.Client === JsClient); assert(native.Client === NativeClient); const jsPool = new pg.Pool() const nativePool = new native.Pool() const suite = new helper.Suite() suite.test('js pool returns js client', cb => { jsPool.connect(function (err, client, done) { assert(client instanceof JsClient); done() jsPool.end(cb) }) }) suite.test('native pool returns native client', cb => { nativePool.connect(function (err, client, done) { assert(client instanceof NativeClient); done() nativePool.end(cb) }); }) node-postgres-7.14.0/test/integration/test-helper.js000066400000000000000000000012461356526317000225030ustar00rootroot00000000000000'use strict' var helper = require('./../test-helper') if (helper.args.native) { Client = require('./../../lib/native') helper.Client = Client helper.pg = helper.pg.native } // creates a client from cli parameters helper.client = function (cb) { var client = new Client() client.connect(cb) return client } helper.versionGTE = function (client, testVersion, callback) { client.query('SHOW server_version_num', assert.calls(function (err, result) { if (err) return callback(err) var version = parseInt(result.rows[0].server_version_num, 10) return callback(null, version >= testVersion) })) } // export parent helper stuffs module.exports = helper node-postgres-7.14.0/test/native/000077500000000000000000000000001356526317000166515ustar00rootroot00000000000000node-postgres-7.14.0/test/native/callback-api-tests.js000066400000000000000000000020441356526317000226520ustar00rootroot00000000000000'use strict' var domain = require('domain') var helper = require('./../test-helper') var Client = require('./../../lib/native') const suite = new helper.Suite() suite.test('fires callback with results', function (done) { var client = new Client(helper.config) client.connect() client.query('SELECT 1 as num', assert.calls(function (err, result) { assert(!err) assert.equal(result.rows[0].num, 1) assert.strictEqual(result.rowCount, 1) client.query('SELECT * FROM person WHERE name = $1', ['Brian'], assert.calls(function (err, result) { assert(!err) assert.equal(result.rows[0].name, 'Brian') client.end(done) })) })) }) suite.test('preserves domain', function (done) { var dom = domain.create() dom.run(function () { var client = new Client(helper.config) assert.ok(dom === require('domain').active, 'domain is active') client.connect() client.query('select 1', function () { assert.ok(dom === require('domain').active, 'domain is still active') client.end(done) }) }) }) node-postgres-7.14.0/test/native/evented-api-tests.js000066400000000000000000000052451356526317000225560ustar00rootroot00000000000000'use strict' var helper = require('../test-helper') var Client = require('../../lib/native') var Query = Client.Query var setupClient = function () { var client = new Client(helper.config) client.connect() client.query('CREATE TEMP TABLE boom(name varchar(10), age integer)') client.query("INSERT INTO boom(name, age) VALUES('Aaron', 26)") client.query("INSERT INTO boom(name, age) VALUES('Brian', 28)") return client } test('multiple results', function () { test('queued queries', function () { var client = setupClient() var q = client.query(new Query('SELECT name FROM BOOM')) assert.emits(q, 'row', function (row) { assert.equal(row.name, 'Aaron') assert.emits(q, 'row', function (row) { assert.equal(row.name, 'Brian') }) }) assert.emits(q, 'end', function () { test('query with config', function () { var q2 = client.query(new Query({text: 'SELECT 1 as num'})) assert.emits(q2, 'row', function (row) { assert.strictEqual(row.num, 1) assert.emits(q2, 'end', function () { client.end() }) }) }) }) }) }) test('parameterized queries', function () { test('with a single string param', function () { var client = setupClient() var q = client.query(new Query('SELECT * FROM boom WHERE name = $1', ['Aaron'])) assert.emits(q, 'row', function (row) { assert.equal(row.name, 'Aaron') }) assert.emits(q, 'end', function () { client.end() }) }) test('with object config for query', function () { var client = setupClient() var q = client.query(new Query({ text: 'SELECT name FROM boom WHERE name = $1', values: ['Brian'] })) assert.emits(q, 'row', function (row) { assert.equal(row.name, 'Brian') }) assert.emits(q, 'end', function () { client.end() }) }) test('multiple parameters', function () { var client = setupClient() var q = client.query(new Query('SELECT name FROM boom WHERE name = $1 or name = $2 ORDER BY name COLLATE "C"', ['Aaron', 'Brian'])) assert.emits(q, 'row', function (row) { assert.equal(row.name, 'Aaron') assert.emits(q, 'row', function (row) { assert.equal(row.name, 'Brian') assert.emits(q, 'end', function () { client.end() }) }) }) }) test('integer parameters', function () { var client = setupClient() var q = client.query(new Query('SELECT * FROM boom WHERE age > $1', [27])) assert.emits(q, 'row', function (row) { assert.equal(row.name, 'Brian') assert.equal(row.age, 28) }) assert.emits(q, 'end', function () { client.end() }) }) }) node-postgres-7.14.0/test/native/missing-native.js000066400000000000000000000003111356526317000221370ustar00rootroot00000000000000'use strict' // this test assumes it has been run from the Makefile // and that node_modules/pg-native has been deleted var assert = require('assert') assert.equal(require('../../lib').native, null) node-postgres-7.14.0/test/native/native-vs-js-error-tests.js000066400000000000000000000010451356526317000240240ustar00rootroot00000000000000'use strict' var assert = require('assert') var Client = require('../../lib/client') var NativeClient = require('../../lib/native') var client = new Client() var nativeClient = new NativeClient() client.connect() nativeClient.connect((err) => { client.query('SELECT alsdkfj', (err) => { client.end() nativeClient.query('SELECT lkdasjfasd', (nativeErr) => { for (var key in nativeErr) { assert.equal(err[key], nativeErr[key], `Expected err.${key} to equal nativeErr.${key}`) } nativeClient.end() }) }) }) node-postgres-7.14.0/test/native/stress-tests.js000066400000000000000000000023101356526317000216660ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/../test-helper') var Client = require(__dirname + '/../../lib/native') var Query = Client.Query test('many rows', function () { var client = new Client(helper.config) client.connect() var q = client.query(new Query('SELECT * FROM person')) var rows = [] q.on('row', function (row) { rows.push(row) }) assert.emits(q, 'end', function () { client.end() assert.lengthIs(rows, 26) }) }) test('many queries', function () { var client = new Client(helper.config) client.connect() var count = 0 var expected = 100 for (var i = 0; i < expected; i++) { var q = client.query(new Query('SELECT * FROM person')) assert.emits(q, 'end', function () { count++ }) } assert.emits(client, 'drain', function () { client.end() assert.equal(count, expected) }) }) test('many clients', function () { var clients = [] for (var i = 0; i < 10; i++) { clients.push(new Client(helper.config)) } clients.forEach(function (client) { client.connect() for (var i = 0; i < 20; i++) { client.query('SELECT * FROM person') } assert.emits(client, 'drain', function () { client.end() }) }) }) node-postgres-7.14.0/test/suite.js000066400000000000000000000040041356526317000170500ustar00rootroot00000000000000'use strict' const async = require('async') class Test { constructor (name, cb) { this.name = name this.action = cb this.timeout = 5000 } run (cb) { try { this._run(cb) } catch (e) { cb(e) } } _run (cb) { if (!this.action) { console.log(`${this.name} skipped`) return cb() } if (!this.action.length) { const result = this.action.call(this) if (!(result || 0).then) { return cb() } result .then(() => cb()) .catch(err => cb(err || new Error('Unhandled promise rejection'))) } else { this.action.call(this, cb) } } } class Suite { constructor (name) { console.log('') this._queue = async.queue(this.run.bind(this), 1) this._queue.drain = () => { } } run (test, cb) { process.stdout.write(' ' + test.name + ' ') if (!test.action) { process.stdout.write('? - SKIPPED\n') return cb() } const tid = setTimeout(() => { const err = Error(`test: ${test.name} did not complete withint ${test.timeout}ms`) console.log('\n' + err.stack) process.exit(-1) }, test.timeout) test.run((err) => { clearTimeout(tid) if (err) { process.stdout.write(`FAILED!\n\n${err.stack}\n`) process.exit(-1) } else { process.stdout.write('✔\n') cb() } }) } test (name, cb) { const test = new Test(name, cb) this._queue.push(test) } /** * Run an async test that can return a Promise. If the Promise resolves * successfully then the test will pass. If the Promise rejects with an * error then the test will be considered failed. */ testAsync (name, action) { const test = new Test(name, cb => { Promise.resolve() .then(action) .then(() => cb(null), cb) }) this._queue.push(test) } } process.on('unhandledRejection', (e) => { setImmediate(() => { console.error('Unhandled promise rejection') throw e }) }) module.exports = Suite node-postgres-7.14.0/test/test-buffers.js000066400000000000000000000063431356526317000203400ustar00rootroot00000000000000'use strict' require(__dirname + '/test-helper') // http://developer.postgresql.org/pgdocs/postgres/protocol-message-formats.html var buffers = {} buffers.readyForQuery = function () { return new BufferList() .add(Buffer.from('I')) .join(true, 'Z') } buffers.authenticationOk = function () { return new BufferList() .addInt32(0) .join(true, 'R') } buffers.authenticationCleartextPassword = function () { return new BufferList() .addInt32(3) .join(true, 'R') } buffers.authenticationMD5Password = function () { return new BufferList() .addInt32(5) .add(Buffer.from([1, 2, 3, 4])) .join(true, 'R') } buffers.authenticationSASL = function () { return new BufferList() .addInt32(10) .addCString('SCRAM-SHA-256') .addCString('') .join(true, 'R') } buffers.authenticationSASLContinue = function () { return new BufferList() .addInt32(11) .addString('data') .join(true, 'R') } buffers.authenticationSASLFinal = function () { return new BufferList() .addInt32(12) .addString('data') .join(true, 'R') } buffers.parameterStatus = function (name, value) { return new BufferList() .addCString(name) .addCString(value) .join(true, 'S') } buffers.backendKeyData = function (processID, secretKey) { return new BufferList() .addInt32(processID) .addInt32(secretKey) .join(true, 'K') } buffers.commandComplete = function (string) { return new BufferList() .addCString(string) .join(true, 'C') } buffers.rowDescription = function (fields) { fields = fields || [] var buf = new BufferList() buf.addInt16(fields.length) fields.forEach(function (field) { buf.addCString(field.name) .addInt32(field.tableID || 0) .addInt16(field.attributeNumber || 0) .addInt32(field.dataTypeID || 0) .addInt16(field.dataTypeSize || 0) .addInt32(field.typeModifier || 0) .addInt16(field.formatCode || 0) }) return buf.join(true, 'T') } buffers.dataRow = function (columns) { columns = columns || [] var buf = new BufferList() buf.addInt16(columns.length) columns.forEach(function (col) { if (col == null) { buf.addInt32(-1) } else { var strBuf = Buffer.from(col, 'utf8') buf.addInt32(strBuf.length) buf.add(strBuf) } }) return buf.join(true, 'D') } buffers.error = function (fields) { return errorOrNotice(fields).join(true, 'E') } buffers.notice = function (fields) { return errorOrNotice(fields).join(true, 'N') } var errorOrNotice = function (fields) { fields = fields || [] var buf = new BufferList() fields.forEach(function (field) { buf.addChar(field.type) buf.addCString(field.value) }) return buf.add(Buffer.from([0]))// terminator } buffers.parseComplete = function () { return new BufferList().join(true, '1') } buffers.bindComplete = function () { return new BufferList().join(true, '2') } buffers.notification = function (id, channel, payload) { return new BufferList() .addInt32(id) .addCString(channel) .addCString(payload) .join(true, 'A') } buffers.emptyQuery = function () { return new BufferList().join(true, 'I') } buffers.portalSuspended = function () { return new BufferList().join(true, 's') } module.exports = buffers node-postgres-7.14.0/test/test-helper.js000066400000000000000000000153431356526317000201630ustar00rootroot00000000000000'use strict' // make assert a global... global.assert = require('assert') var EventEmitter = require('events').EventEmitter var sys = require('util') var BufferList = require('./buffer-list') const Suite = require('./suite') const args = require('./cli') var Connection = require('./../lib/connection') global.Client = require('./../lib').Client process.on('uncaughtException', function (d) { if ('stack' in d && 'message' in d) { console.log('Message: ' + d.message) console.log(d.stack) } else { console.log(d) } process.exit(-1) }) assert.same = function (actual, expected) { for (var key in expected) { assert.equal(actual[key], expected[key]) } } assert.emits = function (item, eventName, callback, message) { var called = false var id = setTimeout(function () { test("Should have called '" + eventName + "' event", function () { assert.ok(called, message || "Expected '" + eventName + "' to be called.") }) }, 5000) item.once(eventName, function () { if (eventName === 'error') { // belt and braces test to ensure all error events return an error assert.ok(arguments[0] instanceof Error, 'Expected error events to throw instances of Error but found: ' + sys.inspect(arguments[0])) } called = true clearTimeout(id) assert.ok(true) if (callback) { callback.apply(item, arguments) } }) } assert.UTCDate = function (actual, year, month, day, hours, min, sec, milisecond) { var actualYear = actual.getUTCFullYear() assert.equal(actualYear, year, 'expected year ' + year + ' but got ' + actualYear) var actualMonth = actual.getUTCMonth() assert.equal(actualMonth, month, 'expected month ' + month + ' but got ' + actualMonth) var actualDate = actual.getUTCDate() assert.equal(actualDate, day, 'expected day ' + day + ' but got ' + actualDate) var actualHours = actual.getUTCHours() assert.equal(actualHours, hours, 'expected hours ' + hours + ' but got ' + actualHours) var actualMin = actual.getUTCMinutes() assert.equal(actualMin, min, 'expected min ' + min + ' but got ' + actualMin) var actualSec = actual.getUTCSeconds() assert.equal(actualSec, sec, 'expected sec ' + sec + ' but got ' + actualSec) var actualMili = actual.getUTCMilliseconds() assert.equal(actualMili, milisecond, 'expected milisecond ' + milisecond + ' but got ' + actualMili) } assert.equalBuffers = function (actual, expected) { if (actual.length != expected.length) { spit(actual, expected) assert.equal(actual.length, expected.length) } for (var i = 0; i < actual.length; i++) { if (actual[i] != expected[i]) { spit(actual, expected) } assert.equal(actual[i], expected[i]) } } assert.empty = function (actual) { assert.lengthIs(actual, 0) } assert.success = function (callback) { if (callback.length === 1 || callback.length === 0) { return assert.calls(function (err, arg) { if (err) { console.log(err) } assert(!err) callback(arg) }) } else if (callback.length === 2) { return assert.calls(function (err, arg1, arg2) { if (err) { console.log(err) } assert(!err) callback(arg1, arg2) }) } else { throw new Error('need to preserve arrity of wrapped function') } } assert.throws = function (offender) { try { offender() } catch (e) { assert.ok(e instanceof Error, 'Expected ' + offender + ' to throw instances of Error') return } assert.ok(false, 'Expected ' + offender + ' to throw exception') } assert.lengthIs = function (actual, expectedLength) { assert.equal(actual.length, expectedLength) } var expect = function (callback, timeout) { var executed = false timeout = timeout || parseInt(process.env.TEST_TIMEOUT) || 5000 var id = setTimeout(function () { assert.ok(executed, 'Expected execution of function to be fired within ' + timeout + ' milliseconds ' + ' (hint: export TEST_TIMEOUT=' + ' to change timeout globally)' + callback.toString()) }, timeout) if (callback.length < 3) { return function (err, queryResult) { clearTimeout(id) if (err) { assert.ok(err instanceof Error, 'Expected errors to be instances of Error: ' + sys.inspect(err)) } callback.apply(this, arguments) } } else if (callback.length == 3) { return function (err, arg1, arg2) { clearTimeout(id) if (err) { assert.ok(err instanceof Error, 'Expected errors to be instances of Error: ' + sys.inspect(err)) } callback.apply(this, arguments) } } else { throw new Error('Unsupported arrity ' + callback.length) } } assert.calls = expect assert.isNull = function (item, message) { message = message || 'expected ' + item + ' to be null' assert.ok(item === null, message) } const getMode = () => { if (args.native) return 'native' if (args.binary) return 'binary' return '' } global.test = function (name, action) { test.testCount ++ test[name] = action var result = test[name]() if (result === false) { process.stdout.write('?') } else { process.stdout.write('.') } } // print out the filename process.stdout.write(require('path').basename(process.argv[1])) if (args.binary) process.stdout.write(' (binary)') if (args.native) process.stdout.write(' (native)') process.on('exit', function () { console.log('') }) process.on('uncaughtException', function (err) { console.error('\n %s', err.stack || err.toString()) // causes xargs to abort right away process.exit(255) }) var count = 0 var Sink = function (expected, timeout, callback) { var defaultTimeout = 5000 if (typeof timeout === 'function') { callback = timeout timeout = defaultTimeout } timeout = timeout || defaultTimeout var internalCount = 0 var kill = function () { assert.ok(false, 'Did not reach expected ' + expected + ' with an idle timeout of ' + timeout) } var killTimeout = setTimeout(kill, timeout) return { add: function (count) { count = count || 1 internalCount += count clearTimeout(killTimeout) if (internalCount < expected) { killTimeout = setTimeout(kill, timeout) } else { assert.equal(internalCount, expected) callback() } } } } var getTimezoneOffset = Date.prototype.getTimezoneOffset var setTimezoneOffset = function (minutesOffset) { Date.prototype.getTimezoneOffset = function () { return minutesOffset } } var resetTimezoneOffset = function () { Date.prototype.getTimezoneOffset = getTimezoneOffset } module.exports = { Sink: Sink, Suite: Suite, pg: require('./../lib/'), args: args, config: args, sys: sys, Client: Client, setTimezoneOffset: setTimezoneOffset, resetTimezoneOffset: resetTimezoneOffset } node-postgres-7.14.0/test/unit/000077500000000000000000000000001356526317000163425ustar00rootroot00000000000000node-postgres-7.14.0/test/unit/client/000077500000000000000000000000001356526317000176205ustar00rootroot00000000000000node-postgres-7.14.0/test/unit/client/cleartext-password-tests.js000066400000000000000000000012011356526317000251430ustar00rootroot00000000000000'use strict' const createClient = require('./test-helper').createClient /* * TODO: Add _some_ comments to explain what it is we're testing, and how the * code-being-tested works behind the scenes. */ test('cleartext password authentication', function () { var client = createClient() client.password = '!' client.connection.stream.packets = [] client.connection.emit('authenticationCleartextPassword') test('responds with password', function () { var packets = client.connection.stream.packets assert.lengthIs(packets, 1) var packet = packets[0] assert.equalBuffers(packet, [0x70, 0, 0, 0, 6, 33, 0]) }) }) node-postgres-7.14.0/test/unit/client/configuration-tests.js000066400000000000000000000120741356526317000241710ustar00rootroot00000000000000'use strict' require(__dirname + '/test-helper') var pguser = process.env['PGUSER'] || process.env.USER var pgdatabase = process.env['PGDATABASE'] || process.env.USER var pgport = process.env['PGPORT'] || 5432 test('client settings', function () { test('defaults', function () { var client = new Client() assert.equal(client.user, pguser) assert.equal(client.database, pgdatabase) assert.equal(client.port, pgport) assert.equal(client.ssl, false) }) test('custom', function () { var user = 'brian' var database = 'pgjstest' var password = 'boom' var client = new Client({ user: user, database: database, port: 321, password: password, ssl: true }) assert.equal(client.user, user) assert.equal(client.database, database) assert.equal(client.port, 321) assert.equal(client.password, password) assert.equal(client.ssl, true) }) test('custom ssl default on', function () { var old = process.env.PGSSLMODE process.env.PGSSLMODE = 'prefer' var client = new Client() process.env.PGSSLMODE = old assert.equal(client.ssl, true) }) test('custom ssl force off', function () { var old = process.env.PGSSLMODE process.env.PGSSLMODE = 'prefer' var client = new Client({ ssl: false }) process.env.PGSSLMODE = old assert.equal(client.ssl, false) }) }) test('initializing from a config string', function () { test('uses connectionString property', function () { var client = new Client({ connectionString: 'postgres://brian:pass@host1:333/databasename' }) assert.equal(client.user, 'brian') assert.equal(client.password, 'pass') assert.equal(client.host, 'host1') assert.equal(client.port, 333) assert.equal(client.database, 'databasename') }) test('uses the correct values from the config string', function () { var client = new Client('postgres://brian:pass@host1:333/databasename') assert.equal(client.user, 'brian') assert.equal(client.password, 'pass') assert.equal(client.host, 'host1') assert.equal(client.port, 333) assert.equal(client.database, 'databasename') }) test('uses the correct values from the config string with space in password', function () { var client = new Client('postgres://brian:pass word@host1:333/databasename') assert.equal(client.user, 'brian') assert.equal(client.password, 'pass word') assert.equal(client.host, 'host1') assert.equal(client.port, 333) assert.equal(client.database, 'databasename') }) test('when not including all values the defaults are used', function () { var client = new Client('postgres://host1') assert.equal(client.user, process.env['PGUSER'] || process.env.USER) assert.equal(client.password, process.env['PGPASSWORD'] || null) assert.equal(client.host, 'host1') assert.equal(client.port, process.env['PGPORT'] || 5432) assert.equal(client.database, process.env['PGDATABASE'] || process.env.USER) }) test('when not including all values the environment variables are used', function () { var envUserDefined = process.env['PGUSER'] !== undefined var envPasswordDefined = process.env['PGPASSWORD'] !== undefined var envDBDefined = process.env['PGDATABASE'] !== undefined var envHostDefined = process.env['PGHOST'] !== undefined var envPortDefined = process.env['PGPORT'] !== undefined var savedEnvUser = process.env['PGUSER'] var savedEnvPassword = process.env['PGPASSWORD'] var savedEnvDB = process.env['PGDATABASE'] var savedEnvHost = process.env['PGHOST'] var savedEnvPort = process.env['PGPORT'] process.env['PGUSER'] = 'utUser1' process.env['PGPASSWORD'] = 'utPass1' process.env['PGDATABASE'] = 'utDB1' process.env['PGHOST'] = 'utHost1' process.env['PGPORT'] = 5464 var client = new Client('postgres://host1') assert.equal(client.user, process.env['PGUSER']) assert.equal(client.password, process.env['PGPASSWORD']) assert.equal(client.host, 'host1') assert.equal(client.port, process.env['PGPORT']) assert.equal(client.database, process.env['PGDATABASE']) if (envUserDefined) { process.env['PGUSER'] = savedEnvUser } else { delete process.env['PGUSER'] } if (envPasswordDefined) { process.env['PGPASSWORD'] = savedEnvPassword } else { delete process.env['PGPASSWORD'] } if (envDBDefined) { process.env['PGDATABASE'] = savedEnvDB } else { delete process.env['PGDATABASE'] } if (envHostDefined) { process.env['PGHOST'] = savedEnvHost } else { delete process.env['PGHOST'] } if (envPortDefined) { process.env['PGPORT'] = savedEnvPort } else { delete process.env['PGPORT'] } }) }) test('calls connect correctly on connection', function () { var client = new Client('/tmp') var usedPort = '' var usedHost = '' client.connection.connect = function (port, host) { usedPort = port usedHost = host } client.connect() assert.equal(usedPort, '/tmp/.s.PGSQL.' + pgport) assert.strictEqual(usedHost, undefined) }) node-postgres-7.14.0/test/unit/client/early-disconnect-tests.js000066400000000000000000000006651356526317000245700ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var net = require('net') var pg = require('../../../lib/index.js') /* console.log() messages show up in `make test` output. TODO: fix it. */ var server = net.createServer(function (c) { c.destroy() server.close() }) server.listen(7777, function () { var client = new pg.Client('postgres://localhost:7777') client.connect(assert.calls(function (err) { assert(err) })) }) node-postgres-7.14.0/test/unit/client/escape-tests.js000066400000000000000000000046411356526317000225630ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') function createClient (callback) { var client = new Client(helper.config) client.connect(function (err) { return callback(client) }) } var testLit = function (testName, input, expected) { test(testName, function () { var client = new Client(helper.config) var actual = client.escapeLiteral(input) assert.equal(expected, actual) }) } var testIdent = function (testName, input, expected) { test(testName, function () { var client = new Client(helper.config) var actual = client.escapeIdentifier(input) assert.equal(expected, actual) }) } testLit('escapeLiteral: no special characters', 'hello world', "'hello world'") testLit('escapeLiteral: contains double quotes only', 'hello " world', "'hello \" world'") testLit('escapeLiteral: contains single quotes only', 'hello \' world', "'hello \'\' world'") testLit('escapeLiteral: contains backslashes only', 'hello \\ world', " E'hello \\\\ world'") testLit('escapeLiteral: contains single quotes and double quotes', 'hello \' " world', "'hello '' \" world'") testLit('escapeLiteral: contains double quotes and backslashes', 'hello \\ " world', " E'hello \\\\ \" world'") testLit('escapeLiteral: contains single quotes and backslashes', 'hello \\ \' world', " E'hello \\\\ '' world'") testLit('escapeLiteral: contains single quotes, double quotes, and backslashes', 'hello \\ \' " world', " E'hello \\\\ '' \" world'") testIdent('escapeIdentifier: no special characters', 'hello world', '"hello world"') testIdent('escapeIdentifier: contains double quotes only', 'hello " world', '"hello "" world"') testIdent('escapeIdentifier: contains single quotes only', 'hello \' world', '"hello \' world"') testIdent('escapeIdentifier: contains backslashes only', 'hello \\ world', '"hello \\ world"') testIdent('escapeIdentifier: contains single quotes and double quotes', 'hello \' " world', '"hello \' "" world"') testIdent('escapeIdentifier: contains double quotes and backslashes', 'hello \\ " world', '"hello \\ "" world"') testIdent('escapeIdentifier: contains single quotes and backslashes', 'hello \\ \' world', '"hello \\ \' world"') testIdent('escapeIdentifier: contains single quotes, double quotes, and backslashes', 'hello \\ \' " world', '"hello \\ \' "" world"') node-postgres-7.14.0/test/unit/client/md5-password-tests.js000066400000000000000000000015271356526317000236500ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var utils = require('../../../lib/utils') test('md5 authentication', function () { var client = helper.createClient() client.password = '!' var salt = Buffer.from([1, 2, 3, 4]) client.connection.emit('authenticationMD5Password', {salt: salt}) test('responds', function () { assert.lengthIs(client.connection.stream.packets, 1) test('should have correct encrypted data', function () { var password = utils.postgresMd5PasswordHash(client.user, client.password, salt) // how do we want to test this? assert.equalBuffers(client.connection.stream.packets[0], new BufferList() .addCString(password).join(true, 'p')) }) }) }) test('md5 of utf-8 strings', function () { assert.equal(utils.md5('😊'), '5deda34cd95f304948d2bc1b4a62c11e') }) node-postgres-7.14.0/test/unit/client/notification-tests.js000066400000000000000000000004301356526317000240010ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') test('passes connection notification', function () { var client = helper.client() assert.emits(client, 'notice', function (msg) { assert.equal(msg, 'HAY!!') }) client.connection.emit('notice', 'HAY!!') }) node-postgres-7.14.0/test/unit/client/prepared-statement-tests.js000066400000000000000000000071071356526317000251270ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var Query = require('../../../lib/query') var client = helper.client() var con = client.connection var parseArg = null con.parse = function (arg) { parseArg = arg process.nextTick(function () { con.emit('parseComplete') }) } var bindArg = null con.bind = function (arg) { bindArg = arg process.nextTick(function () { con.emit('bindComplete') }) } var executeArg = null con.execute = function (arg) { executeArg = arg process.nextTick(function () { con.emit('rowData', { fields: [] }) con.emit('commandComplete', { text: '' }) }) } var describeArg = null con.describe = function (arg) { describeArg = arg process.nextTick(function () { con.emit('rowDescription', { fields: [] }) }) } var syncCalled = false con.flush = function () { } con.sync = function () { syncCalled = true process.nextTick(function () { con.emit('readyForQuery') }) } test('bound command', function () { test('simple, unnamed bound command', function () { assert.ok(client.connection.emit('readyForQuery')) var query = client.query(new Query({ text: 'select * from X where name = $1', values: ['hi'] })) assert.emits(query, 'end', function () { test('parse argument', function () { assert.equal(parseArg.name, null) assert.equal(parseArg.text, 'select * from X where name = $1') assert.equal(parseArg.types, null) }) test('bind argument', function () { assert.equal(bindArg.statement, null) assert.equal(bindArg.portal, '') assert.lengthIs(bindArg.values, 1) assert.equal(bindArg.values[0], 'hi') }) test('describe argument', function () { assert.equal(describeArg.type, 'P') assert.equal(describeArg.name, '') }) test('execute argument', function () { assert.equal(executeArg.portal, '') assert.equal(executeArg.rows, null) }) test('sync called', function () { assert.ok(syncCalled) }) }) }) }) var portalClient = helper.client() var portalCon = portalClient.connection var portalParseArg = null portalCon.parse = function (arg) { portalParseArg = arg process.nextTick(function () { portalCon.emit('parseComplete') }) } var portalBindArg = null portalCon.bind = function (arg) { portalBindArg = arg process.nextTick(function () { portalCon.emit('bindComplete') }) } var portalExecuteArg = null portalCon.execute = function (arg) { portalExecuteArg = arg process.nextTick(function () { portalCon.emit('rowData', { fields: [] }) portalCon.emit('commandComplete', { text: '' }) }) } var portalDescribeArg = null portalCon.describe = function (arg) { portalDescribeArg = arg process.nextTick(function () { portalCon.emit('rowDescription', { fields: [] }) }) } portalCon.flush = function () { } portalCon.sync = function () { process.nextTick(function () { portalCon.emit('readyForQuery') }) } test('prepared statement with explicit portal', function () { assert.ok(portalClient.connection.emit('readyForQuery')) var query = portalClient.query(new Query({ text: 'select * from X where name = $1', portal: 'myportal', values: ['hi'] })) assert.emits(query, 'end', function () { test('bind argument', function () { assert.equal(portalBindArg.portal, 'myportal') }) test('describe argument', function () { assert.equal(portalDescribeArg.name, 'myportal') }) test('execute argument', function () { assert.equal(portalExecuteArg.portal, 'myportal') }) }) }) node-postgres-7.14.0/test/unit/client/query-queue-tests.js000066400000000000000000000023471356526317000236130ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') var Connection = require(__dirname + '/../../../lib/connection') test('drain', function () { var con = new Connection({stream: 'NO'}) var client = new Client({connection: con}) con.connect = function () { con.emit('connect') } con.query = function () { } client.connect() var raisedDrain = false client.on('drain', function () { raisedDrain = true }) client.query('hello') client.query('sup') client.query('boom') test('with pending queries', function () { test('does not emit drain', function () { assert.equal(raisedDrain, false) }) }) test('after some queries executed', function () { con.emit('readyForQuery') test('does not emit drain', function () { assert.equal(raisedDrain, false) }) }) test('when all queries are sent', function () { con.emit('readyForQuery') con.emit('readyForQuery') test('does not emit drain', function () { assert.equal(raisedDrain, false) }) }) test('after last query finishes', function () { con.emit('readyForQuery') test('emits drain', function () { process.nextTick(function () { assert.ok(raisedDrain) }) }) }) }) node-postgres-7.14.0/test/unit/client/result-metadata-tests.js000066400000000000000000000022571356526317000244200ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') var testForTag = function (tagText, callback) { test('includes command tag data for tag ' + tagText, function () { var client = helper.client() client.connection.emit('readyForQuery') var query = client.query('whatever', assert.calls((err, result) => { assert.ok(result != null, 'should pass something to this event') callback(result) })) assert.lengthIs(client.connection.queries, 1) client.connection.emit('commandComplete', { text: tagText }) client.connection.emit('readyForQuery') }) } var check = function (oid, rowCount, command) { return function (result) { if (oid != null) { assert.equal(result.oid, oid) } assert.equal(result.rowCount, rowCount) assert.equal(result.command, command) } } testForTag('INSERT 0 3', check(0, 3, 'INSERT')) testForTag('INSERT 841 1', check(841, 1, 'INSERT')) testForTag('DELETE 10', check(null, 10, 'DELETE')) testForTag('UPDATE 11', check(null, 11, 'UPDATE')) testForTag('SELECT 20', check(null, 20, 'SELECT')) testForTag('COPY', check(null, null, 'COPY')) testForTag('COPY 12345', check(null, 12345, 'COPY')) node-postgres-7.14.0/test/unit/client/sasl-scram-tests.js000066400000000000000000000073641356526317000233750ustar00rootroot00000000000000'use strict' require('./test-helper'); var sasl = require('../../../lib/sasl') test('sasl/scram', function () { test('startSession', function () { test('fails when mechanisms does not include SCRAM-SHA-256', function () { assert.throws(function () { sasl.startSession([]) }, { message: 'SASL: Only mechanism SCRAM-SHA-256 is currently supported', }) }) test('returns expected session data', function () { const session = sasl.startSession(['SCRAM-SHA-256']) assert.equal(session.mechanism, 'SCRAM-SHA-256') assert.equal(String(session.clientNonce).length, 24) assert.equal(session.message, 'SASLInitialResponse') assert(session.response.match(/^n,,n=\*,r=.{24}/)) }) test('creates random nonces', function () { const session1 = sasl.startSession(['SCRAM-SHA-256']) const session2 = sasl.startSession(['SCRAM-SHA-256']) assert(session1.clientNonce != session2.clientNonce) }) }) test('continueSession', function () { test('fails when last session message was not SASLInitialResponse', function () { assert.throws(function () { sasl.continueSession({}) }, { message: 'SASL: Last message was not SASLInitialResponse', }) }) test('fails when nonce is missing in server message', function () { assert.throws(function () { sasl.continueSession({ message: 'SASLInitialResponse', }, "s=1,i=1") }, { message: 'SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing', }) }) test('fails when salt is missing in server message', function () { assert.throws(function () { sasl.continueSession({ message: 'SASLInitialResponse', }, "r=1,i=1") }, { message: 'SASL: SCRAM-SERVER-FIRST-MESSAGE: salt missing', }) }) test('fails when iteration is missing in server message', function () { assert.throws(function () { sasl.continueSession({ message: 'SASLInitialResponse', }, "r=1,s=1") }, { message: 'SASL: SCRAM-SERVER-FIRST-MESSAGE: iteration missing', }) }) test('fails when server nonce does not start with client nonce', function () { assert.throws(function () { sasl.continueSession({ message: 'SASLInitialResponse', clientNonce: '2', }, 'r=1,s=1,i=1') }, { message: 'SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce does not start with client nonce', }) }) test('sets expected session data', function () { const session = { message: 'SASLInitialResponse', clientNonce: 'a', }; sasl.continueSession(session, 'password', 'r=ab,s=x,i=1') assert.equal(session.message, 'SASLResponse') assert.equal(session.serverSignature, 'TtywIrpWDJ0tCSXM2mjkyiaa8iGZsZG7HllQxr8fYAo=') assert.equal(session.response, 'c=biws,r=ab,p=KAEPBUTjjofB0IM5UWcZApK1dSzFE0o5vnbWjBbvFHA=') }) }) test('continueSession', function () { test('fails when last session message was not SASLResponse', function () { assert.throws(function () { sasl.finalizeSession({}) }, { message: 'SASL: Last message was not SASLResponse', }) }) test('fails when server signature does not match', function () { assert.throws(function () { sasl.finalizeSession({ message: 'SASLResponse', serverSignature: '3', }, "v=4") }, { message: 'SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature does not match', }) }) test('does not fail when eveything is ok', function () { sasl.finalizeSession({ message: 'SASLResponse', serverSignature: '5', }, "v=5") }) }) }) node-postgres-7.14.0/test/unit/client/set-keepalives.js000066400000000000000000000012741356526317000231030ustar00rootroot00000000000000'use strict' const net = require('net') const pg = require('../../../lib/index.js') const helper = require('./test-helper') const suite = new helper.Suite() suite.test('setting keep alive', done => { const server = net.createServer(c => { c.destroy() server.close() }) server.listen(7777, () => { const stream = new net.Socket() stream.setKeepAlive = (enable, initialDelay) => { assert(enable === true) assert(initialDelay === 10000) done() } const client = new pg.Client({ host: 'localhost', port: 7777, keepAlive: true, keepAliveInitialDelayMillis: 10000, stream }) client.connect().catch(() => {}) }) }) node-postgres-7.14.0/test/unit/client/simple-query-tests.js000066400000000000000000000106571356526317000237630ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') var Query = require('../../../lib/query') test('executing query', function () { test('queing query', function () { test('when connection is ready', function () { var client = helper.client() assert.empty(client.connection.queries) client.connection.emit('readyForQuery') client.query('yes') assert.lengthIs(client.connection.queries, 1) assert.equal(client.connection.queries, 'yes') }) test('when connection is not ready', function () { var client = helper.client() test('query is not sent', function () { client.query('boom') assert.empty(client.connection.queries) }) test('sends query to connection once ready', function () { assert.ok(client.connection.emit('readyForQuery')) assert.lengthIs(client.connection.queries, 1) assert.equal(client.connection.queries[0], 'boom') }) }) test('multiple in the queue', function () { var client = helper.client() var connection = client.connection var queries = connection.queries client.query('one') client.query('two') client.query('three') assert.empty(queries) test('after one ready for query', function () { connection.emit('readyForQuery') assert.lengthIs(queries, 1) assert.equal(queries[0], 'one') }) test('after two ready for query', function () { connection.emit('readyForQuery') assert.lengthIs(queries, 2) }) test('after a bunch more', function () { connection.emit('readyForQuery') connection.emit('readyForQuery') connection.emit('readyForQuery') assert.lengthIs(queries, 3) assert.equal(queries[0], 'one') assert.equal(queries[1], 'two') assert.equal(queries[2], 'three') }) }) }) test('query event binding and flow', function () { var client = helper.client() var con = client.connection var query = client.query(new Query('whatever')) test('has no queries sent before ready', function () { assert.empty(con.queries) }) test('sends query on readyForQuery event', function () { con.emit('readyForQuery') assert.lengthIs(con.queries, 1) assert.equal(con.queries[0], 'whatever') }) test('handles rowDescription message', function () { var handled = con.emit('rowDescription', { fields: [{ name: 'boom' }] }) assert.ok(handled, 'should have handlded rowDescription') }) test('handles dataRow messages', function () { assert.emits(query, 'row', function (row) { assert.equal(row['boom'], 'hi') }) var handled = con.emit('dataRow', { fields: ['hi'] }) assert.ok(handled, 'should have handled first data row message') assert.emits(query, 'row', function (row) { assert.equal(row['boom'], 'bye') }) var handledAgain = con.emit('dataRow', { fields: ['bye'] }) assert.ok(handledAgain, 'should have handled seciond data row message') }) // multiple command complete messages will be sent // when multiple queries are in a simple command test('handles command complete messages', function () { con.emit('commandComplete', { text: 'INSERT 31 1' }) }) test('removes itself after another readyForQuery message', function () { return false assert.emits(query, 'end', function (msg) { // TODO do we want to check the complete messages? }) con.emit('readyForQuery'); // this would never actually happen ['dataRow', 'rowDescription', 'commandComplete'].forEach(function (msg) { assert.equal(con.emit(msg), false, "Should no longer be picking up '" + msg + "' messages") }) }) }) test('handles errors', function () { var client = helper.client() test('throws an error when config is null', function () { try { client.query(null, undefined) } catch (error) { assert.equal(error.message, 'Client was passed a null or undefined query', 'Should have thrown an Error for null queries') } }) test('throws an error when config is undefined', function () { try { client.query() } catch (error) { assert.equal(error.message, 'Client was passed a null or undefined query', 'Should have thrown an Error for null queries') } }) }) }) node-postgres-7.14.0/test/unit/client/stream-and-query-error-interaction-tests.js000066400000000000000000000016321356526317000301620ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') var Connection = require(__dirname + '/../../../lib/connection') var Client = require(__dirname + '/../../../lib/client') test('emits end when not in query', function () { var stream = new (require('events').EventEmitter)() stream.write = function () { // NOOP } var client = new Client({connection: new Connection({stream: stream})}) client.connect(assert.calls(function () { client.query('SELECT NOW()', assert.calls(function (err, result) { assert(err) })) })) assert.emits(client, 'error') assert.emits(client, 'end') client.connection.emit('connect') process.nextTick(function () { client.connection.emit('readyForQuery') assert.equal(client.queryQueue.length, 0) assert(client.activeQuery, 'client should have issued query') process.nextTick(function () { stream.emit('close') }) }) }) node-postgres-7.14.0/test/unit/client/test-helper.js000066400000000000000000000010461356526317000224130ustar00rootroot00000000000000'use strict' var helper = require('../test-helper') var Connection = require('../../../lib/connection') var makeClient = function () { var connection = new Connection({stream: 'no'}) connection.startup = function () {} connection.connect = function () {} connection.query = function (text) { this.queries.push(text) } connection.queries = [] var client = new Client({connection: connection}) client.connect() client.connection.emit('connect') return client } module.exports = Object.assign({ client: makeClient }, helper) node-postgres-7.14.0/test/unit/client/throw-in-type-parser-tests.js000066400000000000000000000030611356526317000253360ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var Query = require('../../../lib/query') var types = require('pg-types') const suite = new helper.Suite() var typeParserError = new Error('TEST: Throw in type parsers') types.setTypeParser('special oid that will throw', function () { throw typeParserError }) const emitFakeEvents = con => { setImmediate(() => { con.emit('readyForQuery') con.emit('rowDescription', { fields: [ { name: 'boom', dataTypeID: 'special oid that will throw' } ] }) con.emit('dataRow', { fields: ['hi'] }) con.emit('dataRow', { fields: ['hi'] }) con.emit('commandComplete', { text: 'INSERT 31 1' }) con.emit('readyForQuery') }) } suite.test('emits error', function (done) { var handled var client = helper.client() var con = client.connection var query = client.query(new Query('whatever')) emitFakeEvents(con) assert.emits(query, 'error', function (err) { assert.equal(err, typeParserError) done() }) }) suite.test('calls callback with error', function (done) { var handled var callbackCalled = 0 var client = helper.client() var con = client.connection emitFakeEvents(con) var query = client.query('whatever', function (err) { assert.equal(err, typeParserError) done() }) }) suite.test('rejects promise with error', function (done) { var client = helper.client() var con = client.connection emitFakeEvents(con) client.query('whatever').catch(err => { assert.equal(err, typeParserError) done() }) }) node-postgres-7.14.0/test/unit/connection-parameters/000077500000000000000000000000001356526317000226425ustar00rootroot00000000000000node-postgres-7.14.0/test/unit/connection-parameters/creation-tests.js000066400000000000000000000240001356526317000261400ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/../test-helper') var assert = require('assert') var ConnectionParameters = require(__dirname + '/../../../lib/connection-parameters') var defaults = require(__dirname + '/../../../lib').defaults // clear process.env for (var key in process.env) { delete process.env[key] } test('ConnectionParameters construction', function () { assert.ok(new ConnectionParameters(), 'with null config') assert.ok(new ConnectionParameters({user: 'asdf'}), 'with config object') assert.ok(new ConnectionParameters('postgres://localhost/postgres'), 'with connection string') }) var compare = function (actual, expected, type) { assert.equal(actual.user, expected.user, type + ' user') assert.equal(actual.database, expected.database, type + ' database') assert.equal(actual.port, expected.port, type + ' port') assert.equal(actual.host, expected.host, type + ' host') assert.equal(actual.password, expected.password, type + ' password') assert.equal(actual.binary, expected.binary, type + ' binary') assert.equal(actual.statement_timout, expected.statement_timout, type + ' statement_timeout') } test('ConnectionParameters initializing from defaults', function () { var subject = new ConnectionParameters() compare(subject, defaults, 'defaults') assert.ok(subject.isDomainSocket === false) }) test('ConnectionParameters initializing from defaults with connectionString set', function () { var config = { user: 'brians-are-the-best', database: 'scoobysnacks', port: 7777, password: 'mypassword', host: 'foo.bar.net', binary: defaults.binary } var original_value = defaults.connectionString // Just changing this here doesn't actually work because it's no longer in scope when viewed inside of // of ConnectionParameters() so we have to pass in the defaults explicitly to test it defaults.connectionString = 'postgres://brians-are-the-best:mypassword@foo.bar.net:7777/scoobysnacks' var subject = new ConnectionParameters(defaults) defaults.connectionString = original_value compare(subject, config, 'defaults-connectionString') }) test('ConnectionParameters initializing from config', function () { var config = { user: 'brian', database: 'home', port: 7777, password: 'pizza', binary: true, encoding: 'utf8', host: 'yo', ssl: { asdf: 'blah' }, statement_timeout: 15000 } var subject = new ConnectionParameters(config) compare(subject, config, 'config') assert.ok(subject.isDomainSocket === false) }) test('ConnectionParameters initializing from config and config.connectionString', function() { var subject1 = new ConnectionParameters({ connectionString: 'postgres://test@host/db' }) var subject2 = new ConnectionParameters({ connectionString: 'postgres://test@host/db?ssl=1' }) var subject3 = new ConnectionParameters({ connectionString: 'postgres://test@host/db', ssl: true }) var subject4 = new ConnectionParameters({ connectionString: 'postgres://test@host/db?ssl=1', ssl: false }) assert.equal(subject1.ssl, false) assert.equal(subject2.ssl, true) assert.equal(subject3.ssl, true) assert.equal(subject4.ssl, true) }); test('escape spaces if present', function () { var subject = new ConnectionParameters('postgres://localhost/post gres') assert.equal(subject.database, 'post gres') }) test('do not double escape spaces', function () { var subject = new ConnectionParameters('postgres://localhost/post%20gres') assert.equal(subject.database, 'post gres') }) test('initializing with unix domain socket', function () { var subject = new ConnectionParameters('/var/run/') assert.ok(subject.isDomainSocket) assert.equal(subject.host, '/var/run/') assert.equal(subject.database, defaults.user) }) test('initializing with unix domain socket and a specific database, the simple way', function () { var subject = new ConnectionParameters('/var/run/ mydb') assert.ok(subject.isDomainSocket) assert.equal(subject.host, '/var/run/') assert.equal(subject.database, 'mydb') }) test('initializing with unix domain socket, the health way', function () { var subject = new ConnectionParameters('socket:/some path/?db=my[db]&encoding=utf8') assert.ok(subject.isDomainSocket) assert.equal(subject.host, '/some path/') assert.equal(subject.database, 'my[db]', 'must to be escaped and unescaped trough "my%5Bdb%5D"') assert.equal(subject.client_encoding, 'utf8') }) test('initializing with unix domain socket, the escaped health way', function () { var subject = new ConnectionParameters('socket:/some%20path/?db=my%2Bdb&encoding=utf8') assert.ok(subject.isDomainSocket) assert.equal(subject.host, '/some path/') assert.equal(subject.database, 'my+db') assert.equal(subject.client_encoding, 'utf8') }) test('libpq connection string building', function () { var checkForPart = function (array, part) { assert.ok(array.indexOf(part) > -1, array.join(' ') + ' did not contain ' + part) } test('builds simple string', function () { var config = { user: 'brian', password: 'xyz', port: 888, host: 'localhost', database: 'bam' } var subject = new ConnectionParameters(config) subject.getLibpqConnectionString(assert.calls(function (err, constring) { assert(!err) var parts = constring.split(' ') checkForPart(parts, "user='brian'") checkForPart(parts, "password='xyz'") checkForPart(parts, "port='888'") checkForPart(parts, "hostaddr='127.0.0.1'") checkForPart(parts, "dbname='bam'") })) }) test('builds dns string', function () { var config = { user: 'brian', password: 'asdf', port: 5432, host: 'localhost' } var subject = new ConnectionParameters(config) subject.getLibpqConnectionString(assert.calls(function (err, constring) { assert(!err) var parts = constring.split(' ') checkForPart(parts, "user='brian'") checkForPart(parts, "hostaddr='127.0.0.1'") })) }) test('error when dns fails', function () { var config = { user: 'brian', password: 'asf', port: 5432, host: 'asdlfkjasldfkksfd#!$!!!!..com' } var subject = new ConnectionParameters(config) subject.getLibpqConnectionString(assert.calls(function (err, constring) { assert.ok(err) assert.isNull(constring) })) }) test('connecting to unix domain socket', function () { var config = { user: 'brian', password: 'asf', port: 5432, host: '/tmp/' } var subject = new ConnectionParameters(config) subject.getLibpqConnectionString(assert.calls(function (err, constring) { assert(!err) var parts = constring.split(' ') checkForPart(parts, "user='brian'") checkForPart(parts, "host='/tmp/'") })) }) test('config contains quotes and backslashes', function () { var config = { user: 'not\\brian', password: 'bad\'chars', port: 5432, host: '/tmp/' } var subject = new ConnectionParameters(config) subject.getLibpqConnectionString(assert.calls(function (err, constring) { assert(!err) var parts = constring.split(' ') checkForPart(parts, "user='not\\\\brian'") checkForPart(parts, "password='bad\\'chars'") })) }) test('encoding can be specified by config', function () { var config = { client_encoding: 'utf-8' } var subject = new ConnectionParameters(config) subject.getLibpqConnectionString(assert.calls(function (err, constring) { assert(!err) var parts = constring.split(' ') checkForPart(parts, "client_encoding='utf-8'") })) }) test('password contains < and/or > characters', function () { return false var sourceConfig = { user: 'brian', password: 'helloe', port: 5432, host: 'localhost', database: 'postgres' } var connectionString = 'postgres://' + sourceConfig.user + ':' + sourceConfig.password + '@' + sourceConfig.host + ':' + sourceConfig.port + '/' + sourceConfig.database var subject = new ConnectionParameters(connectionString) assert.equal(subject.password, sourceConfig.password) }) test('username or password contains weird characters', function () { var defaults = require('../../../lib/defaults') defaults.ssl = true var strang = 'pg://my f%irst name:is&%awesome!@localhost:9000' var subject = new ConnectionParameters(strang) assert.equal(subject.user, 'my f%irst name') assert.equal(subject.password, 'is&%awesome!') assert.equal(subject.host, 'localhost') assert.equal(subject.ssl, true) }) test('url is properly encoded', function () { var encoded = 'pg://bi%25na%25%25ry%20:s%40f%23@localhost/%20u%2520rl' var subject = new ConnectionParameters(encoded) assert.equal(subject.user, 'bi%na%%ry ') assert.equal(subject.password, 's@f#') assert.equal(subject.host, 'localhost') assert.equal(subject.database, ' u%20rl') }) test('ssl is set on client', function () { var Client = require('../../../lib/client') var defaults = require('../../../lib/defaults') defaults.ssl = true var c = new Client('postgres://user@password:host/database') assert(c.ssl, 'Client should have ssl enabled via defaults') }) test('ssl is set on client', function () { var sourceConfig = { user: 'brian', password: 'helloe', port: 5432, host: 'localhost', database: 'postgres', ssl: { sslmode: 'verify-ca', sslca: '/path/ca.pem', sslkey: '/path/cert.key', sslcert: '/path/cert.crt', sslrootcert: '/path/root.crt' } } var Client = require('../../../lib/client') var defaults = require('../../../lib/defaults') defaults.ssl = true var c = new ConnectionParameters(sourceConfig) c.getLibpqConnectionString(assert.calls(function (err, pgCString) { assert(!err) assert.equal( pgCString.indexOf('sslrootcert=\'/path/root.crt\'') !== -1, true, 'libpqConnectionString should contain sslrootcert' ) })) }) }) node-postgres-7.14.0/test/unit/connection-parameters/environment-variable-tests.js000066400000000000000000000067351356526317000305020ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/../test-helper') var assert = require('assert') var ConnectionParameters = require(__dirname + '/../../../lib/connection-parameters') var defaults = require(__dirname + '/../../../lib').defaults // clear process.env var realEnv = {} for (var key in process.env) { realEnv[key] = process.env[key] delete process.env[key] } test('ConnectionParameters initialized from environment variables', function (t) { process.env['PGHOST'] = 'local' process.env['PGUSER'] = 'bmc2' process.env['PGPORT'] = 7890 process.env['PGDATABASE'] = 'allyerbase' process.env['PGPASSWORD'] = 'open' var subject = new ConnectionParameters() assert.equal(subject.host, 'local', 'env host') assert.equal(subject.user, 'bmc2', 'env user') assert.equal(subject.port, 7890, 'env port') assert.equal(subject.database, 'allyerbase', 'env database') assert.equal(subject.password, 'open', 'env password') }) test('ConnectionParameters initialized from mix', function (t) { delete process.env['PGPASSWORD'] delete process.env['PGDATABASE'] var subject = new ConnectionParameters({ user: 'testing', database: 'zugzug' }) assert.equal(subject.host, 'local', 'env host') assert.equal(subject.user, 'testing', 'config user') assert.equal(subject.port, 7890, 'env port') assert.equal(subject.database, 'zugzug', 'config database') assert.equal(subject.password, defaults.password, 'defaults password') }) // clear process.env for (var key in process.env) { delete process.env[key] } test('connection string parsing', function (t) { var string = 'postgres://brian:pw@boom:381/lala' var subject = new ConnectionParameters(string) assert.equal(subject.host, 'boom', 'string host') assert.equal(subject.user, 'brian', 'string user') assert.equal(subject.password, 'pw', 'string password') assert.equal(subject.port, 381, 'string port') assert.equal(subject.database, 'lala', 'string database') }) test('connection string parsing - ssl', function (t) { var string = 'postgres://brian:pw@boom:381/lala?ssl=true' var subject = new ConnectionParameters(string) assert.equal(subject.ssl, true, 'ssl') string = 'postgres://brian:pw@boom:381/lala?ssl=1' subject = new ConnectionParameters(string) assert.equal(subject.ssl, true, 'ssl') string = 'postgres://brian:pw@boom:381/lala?other&ssl=true' subject = new ConnectionParameters(string) assert.equal(subject.ssl, true, 'ssl') string = 'postgres://brian:pw@boom:381/lala?ssl=0' subject = new ConnectionParameters(string) assert.equal(!!subject.ssl, false, 'ssl') string = 'postgres://brian:pw@boom:381/lala' subject = new ConnectionParameters(string) assert.equal(!!subject.ssl, false, 'ssl') }) // clear process.env for (var key in process.env) { delete process.env[key] } test('ssl is false by default', function () { var subject = new ConnectionParameters() assert.equal(subject.ssl, false) }) var testVal = function (mode, expected) { // clear process.env for (var key in process.env) { delete process.env[key] } process.env.PGSSLMODE = mode test('ssl is ' + expected + ' when $PGSSLMODE=' + mode, function () { var subject = new ConnectionParameters() assert.equal(subject.ssl, expected) }) } testVal('', false) testVal('disable', false) testVal('allow', false) testVal('prefer', true) testVal('require', true) testVal('verify-ca', true) testVal('verify-full', true) // restore process.env for (var key in realEnv) { process.env[key] = realEnv[key] } node-postgres-7.14.0/test/unit/connection/000077500000000000000000000000001356526317000205015ustar00rootroot00000000000000node-postgres-7.14.0/test/unit/connection/error-tests.js000066400000000000000000000047251356526317000233400ustar00rootroot00000000000000'use strict' var helper = require(__dirname + '/test-helper') var Connection = require(__dirname + '/../../../lib/connection') var net = require('net') const suite = new helper.Suite() suite.test('connection emits stream errors', function (done) { var con = new Connection({stream: new MemoryStream()}) assert.emits(con, 'error', function (err) { assert.equal(err.message, 'OMG!') done() }) con.connect() con.stream.emit('error', new Error('OMG!')) }) suite.test('connection emits ECONNRESET errors during normal operation', function (done) { var con = new Connection({stream: new MemoryStream()}) con.connect() assert.emits(con, 'error', function (err) { assert.equal(err.code, 'ECONNRESET') done() }) var e = new Error('Connection Reset') e.code = 'ECONNRESET' con.stream.emit('error', e) }) suite.test('connection does not emit ECONNRESET errors during disconnect', function (done) { var con = new Connection({stream: new MemoryStream()}) con.connect() var e = new Error('Connection Reset') e.code = 'ECONNRESET' con.end() con.stream.emit('error', e) done() }) var SSLNegotiationPacketTests = [ { testName: 'connection does not emit ECONNRESET errors during disconnect also when using SSL', errorMessage: null, response: 'S', responseType: 'sslconnect' }, { testName: 'connection emits an error when SSL is not supported', errorMessage: 'The server does not support SSL connections', response: 'N', responseType: 'error' }, { testName: 'connection emits an error when postmaster responds to SSL negotiation packet', errorMessage: 'There was an error establishing an SSL connection', response: 'E', responseType: 'error' } ] for (var i = 0; i < SSLNegotiationPacketTests.length; i++) { var tc = SSLNegotiationPacketTests[i] suite.test(tc.testName, function (done) { // our fake postgres server var socket var server = net.createServer(function (c) { socket = c c.once('data', function (data) { c.write(Buffer.from(tc.response)) }) }) server.listen(7778, function () { var con = new Connection({ssl: true}) con.connect(7778, 'localhost') assert.emits(con, tc.responseType, function (err) { if (tc.errorMessage !== null || err) { assert.equal(err.message, tc.errorMessage) } con.end() socket.destroy() server.close() done() }) con.requestSsl() }) }) } node-postgres-7.14.0/test/unit/connection/inbound-parser-tests.js000066400000000000000000000320231356526317000251270ustar00rootroot00000000000000'use strict' require(__dirname + '/test-helper') var Connection = require(__dirname + '/../../../lib/connection') var buffers = require(__dirname + '/../../test-buffers') var PARSE = function (buffer) { return new Parser(buffer).parse() } var authOkBuffer = buffers.authenticationOk() var paramStatusBuffer = buffers.parameterStatus('client_encoding', 'UTF8') var readyForQueryBuffer = buffers.readyForQuery() var backendKeyDataBuffer = buffers.backendKeyData(1, 2) var commandCompleteBuffer = buffers.commandComplete('SELECT 3') var parseCompleteBuffer = buffers.parseComplete() var bindCompleteBuffer = buffers.bindComplete() var portalSuspendedBuffer = buffers.portalSuspended() var addRow = function (bufferList, name, offset) { return bufferList.addCString(name) // field name .addInt32(offset++) // table id .addInt16(offset++) // attribute of column number .addInt32(offset++) // objectId of field's data type .addInt16(offset++) // datatype size .addInt32(offset++) // type modifier .addInt16(0) // format code, 0 => text } var row1 = { name: 'id', tableID: 1, attributeNumber: 2, dataTypeID: 3, dataTypeSize: 4, typeModifier: 5, formatCode: 0 } var oneRowDescBuff = new buffers.rowDescription([row1]) row1.name = 'bang' var twoRowBuf = new buffers.rowDescription([row1, { name: 'whoah', tableID: 10, attributeNumber: 11, dataTypeID: 12, dataTypeSize: 13, typeModifier: 14, formatCode: 0 }]) var emptyRowFieldBuf = new BufferList() .addInt16(0) .join(true, 'D') var emptyRowFieldBuf = buffers.dataRow() var oneFieldBuf = new BufferList() .addInt16(1) // number of fields .addInt32(5) // length of bytes of fields .addCString('test') .join(true, 'D') var oneFieldBuf = buffers.dataRow(['test']) var expectedAuthenticationOkayMessage = { name: 'authenticationOk', length: 8 } var expectedParameterStatusMessage = { name: 'parameterStatus', parameterName: 'client_encoding', parameterValue: 'UTF8', length: 25 } var expectedBackendKeyDataMessage = { name: 'backendKeyData', processID: 1, secretKey: 2 } var expectedReadyForQueryMessage = { name: 'readyForQuery', length: 5, status: 'I' } var expectedCommandCompleteMessage = { length: 13, text: 'SELECT 3' } var emptyRowDescriptionBuffer = new BufferList() .addInt16(0) // number of fields .join(true, 'T') var expectedEmptyRowDescriptionMessage = { name: 'rowDescription', length: 6, fieldCount: 0 } var expectedOneRowMessage = { name: 'rowDescription', length: 27, fieldCount: 1 } var expectedTwoRowMessage = { name: 'rowDescription', length: 53, fieldCount: 2 } var testForMessage = function (buffer, expectedMessage) { var lastMessage = {} test('recieves and parses ' + expectedMessage.name, function () { var stream = new MemoryStream() var client = new Connection({ stream: stream }) client.connect() client.on('message', function (msg) { lastMessage = msg }) client.on(expectedMessage.name, function () { client.removeAllListeners(expectedMessage.name) }) stream.emit('data', buffer) assert.same(lastMessage, expectedMessage) }) return lastMessage } var plainPasswordBuffer = buffers.authenticationCleartextPassword() var md5PasswordBuffer = buffers.authenticationMD5Password() var SASLBuffer = buffers.authenticationSASL() var SASLContinueBuffer = buffers.authenticationSASLContinue() var SASLFinalBuffer = buffers.authenticationSASLFinal() var expectedPlainPasswordMessage = { name: 'authenticationCleartextPassword' } var expectedMD5PasswordMessage = { name: 'authenticationMD5Password' } var expectedSASLMessage = { name: 'authenticationSASL', } var expectedSASLContinueMessage = { name: 'authenticationSASLContinue', data: 'data', } var expectedSASLFinalMessage = { name: 'authenticationSASLFinal', data: 'data', } var notificationResponseBuffer = buffers.notification(4, 'hi', 'boom') var expectedNotificationResponseMessage = { name: 'notification', processId: 4, channel: 'hi', payload: 'boom' } test('Connection', function () { testForMessage(authOkBuffer, expectedAuthenticationOkayMessage) testForMessage(plainPasswordBuffer, expectedPlainPasswordMessage) var msgMD5 = testForMessage(md5PasswordBuffer, expectedMD5PasswordMessage) test('md5 has right salt', function () { assert.equalBuffers(msgMD5.salt, Buffer.from([1, 2, 3, 4])) }) var msgSASL = testForMessage(SASLBuffer, expectedSASLMessage) test('SASL has the right mechanisms', function () { assert.deepStrictEqual(msgSASL.mechanisms, ['SCRAM-SHA-256']) }) testForMessage(SASLContinueBuffer, expectedSASLContinueMessage) testForMessage(SASLFinalBuffer, expectedSASLFinalMessage) testForMessage(paramStatusBuffer, expectedParameterStatusMessage) testForMessage(backendKeyDataBuffer, expectedBackendKeyDataMessage) testForMessage(readyForQueryBuffer, expectedReadyForQueryMessage) testForMessage(commandCompleteBuffer, expectedCommandCompleteMessage) testForMessage(notificationResponseBuffer, expectedNotificationResponseMessage) test('empty row message', function () { var message = testForMessage(emptyRowDescriptionBuffer, expectedEmptyRowDescriptionMessage) test('has no fields', function () { assert.equal(message.fields.length, 0) }) }) test('no data message', function () { testForMessage(Buffer.from([0x6e, 0, 0, 0, 4]), { name: 'noData' }) }) test('one row message', function () { var message = testForMessage(oneRowDescBuff, expectedOneRowMessage) test('has one field', function () { assert.equal(message.fields.length, 1) }) test('has correct field info', function () { assert.same(message.fields[0], { name: 'id', tableID: 1, columnID: 2, dataTypeID: 3, dataTypeSize: 4, dataTypeModifier: 5, format: 'text' }) }) }) test('two row message', function () { var message = testForMessage(twoRowBuf, expectedTwoRowMessage) test('has two fields', function () { assert.equal(message.fields.length, 2) }) test('has correct first field', function () { assert.same(message.fields[0], { name: 'bang', tableID: 1, columnID: 2, dataTypeID: 3, dataTypeSize: 4, dataTypeModifier: 5, format: 'text' }) }) test('has correct second field', function () { assert.same(message.fields[1], { name: 'whoah', tableID: 10, columnID: 11, dataTypeID: 12, dataTypeSize: 13, dataTypeModifier: 14, format: 'text' }) }) }) test('parsing rows', function () { test('parsing empty row', function () { var message = testForMessage(emptyRowFieldBuf, { name: 'dataRow', fieldCount: 0 }) test('has 0 fields', function () { assert.equal(message.fields.length, 0) }) }) test('parsing data row with fields', function () { var message = testForMessage(oneFieldBuf, { name: 'dataRow', fieldCount: 1 }) test('has 1 field', function () { assert.equal(message.fields.length, 1) }) test('field is correct', function () { assert.equal(message.fields[0], 'test') }) }) }) test('notice message', function () { // this uses the same logic as error message var buff = buffers.notice([{type: 'C', value: 'code'}]) testForMessage(buff, { name: 'notice', code: 'code' }) }) test('error messages', function () { test('with no fields', function () { var msg = testForMessage(buffers.error(), { name: 'error' }) }) test('with all the fields', function () { var buffer = buffers.error([{ type: 'S', value: 'ERROR' }, { type: 'C', value: 'code' }, { type: 'M', value: 'message' }, { type: 'D', value: 'details' }, { type: 'H', value: 'hint' }, { type: 'P', value: '100' }, { type: 'p', value: '101' }, { type: 'q', value: 'query' }, { type: 'W', value: 'where' }, { type: 'F', value: 'file' }, { type: 'L', value: 'line' }, { type: 'R', value: 'routine' }, { type: 'Z', // ignored value: 'alsdkf' }]) testForMessage(buffer, { name: 'error', severity: 'ERROR', code: 'code', message: 'message', detail: 'details', hint: 'hint', position: '100', internalPosition: '101', internalQuery: 'query', where: 'where', file: 'file', line: 'line', routine: 'routine' }) }) }) test('parses parse complete command', function () { testForMessage(parseCompleteBuffer, { name: 'parseComplete' }) }) test('parses bind complete command', function () { testForMessage(bindCompleteBuffer, { name: 'bindComplete' }) }) test('parses portal suspended message', function () { testForMessage(portalSuspendedBuffer, { name: 'portalSuspended' }) }) test('parses replication start message', function () { testForMessage(Buffer.from([0x57, 0x00, 0x00, 0x00, 0x04]), { name: 'replicationStart', length: 4 }) }) }) // since the data message on a stream can randomly divide the incomming // tcp packets anywhere, we need to make sure we can parse every single // split on a tcp message test('split buffer, single message parsing', function () { var fullBuffer = buffers.dataRow([null, 'bang', 'zug zug', null, '!']) var stream = new MemoryStream() stream.readyState = 'open' var client = new Connection({ stream: stream }) client.connect() var message = null client.on('message', function (msg) { message = msg }) test('parses when full buffer comes in', function () { stream.emit('data', fullBuffer) assert.lengthIs(message.fields, 5) assert.equal(message.fields[0], null) assert.equal(message.fields[1], 'bang') assert.equal(message.fields[2], 'zug zug') assert.equal(message.fields[3], null) assert.equal(message.fields[4], '!') }) var testMessageRecievedAfterSpiltAt = function (split) { var firstBuffer = Buffer.alloc(fullBuffer.length - split) var secondBuffer = Buffer.alloc(fullBuffer.length - firstBuffer.length) fullBuffer.copy(firstBuffer, 0, 0) fullBuffer.copy(secondBuffer, 0, firstBuffer.length) stream.emit('data', firstBuffer) stream.emit('data', secondBuffer) assert.lengthIs(message.fields, 5) assert.equal(message.fields[0], null) assert.equal(message.fields[1], 'bang') assert.equal(message.fields[2], 'zug zug') assert.equal(message.fields[3], null) assert.equal(message.fields[4], '!') } test('parses when split in the middle', function () { testMessageRecievedAfterSpiltAt(6) }) test('parses when split at end', function () { testMessageRecievedAfterSpiltAt(2) }) test('parses when split at beginning', function () { testMessageRecievedAfterSpiltAt(fullBuffer.length - 2) testMessageRecievedAfterSpiltAt(fullBuffer.length - 1) testMessageRecievedAfterSpiltAt(fullBuffer.length - 5) }) }) test('split buffer, multiple message parsing', function () { var dataRowBuffer = buffers.dataRow(['!']) var readyForQueryBuffer = buffers.readyForQuery() var fullBuffer = Buffer.alloc(dataRowBuffer.length + readyForQueryBuffer.length) dataRowBuffer.copy(fullBuffer, 0, 0) readyForQueryBuffer.copy(fullBuffer, dataRowBuffer.length, 0) var messages = [] var stream = new MemoryStream() var client = new Connection({ stream: stream }) client.connect() client.on('message', function (msg) { messages.push(msg) }) var verifyMessages = function () { assert.lengthIs(messages, 2) assert.same(messages[0], { name: 'dataRow', fieldCount: 1 }) assert.equal(messages[0].fields[0], '!') assert.same(messages[1], { name: 'readyForQuery' }) messages = [] } // sanity check test('recieves both messages when packet is not split', function () { stream.emit('data', fullBuffer) verifyMessages() }) var splitAndVerifyTwoMessages = function (split) { var firstBuffer = Buffer.alloc(fullBuffer.length - split) var secondBuffer = Buffer.alloc(fullBuffer.length - firstBuffer.length) fullBuffer.copy(firstBuffer, 0, 0) fullBuffer.copy(secondBuffer, 0, firstBuffer.length) stream.emit('data', firstBuffer) stream.emit('data', secondBuffer) } test('recieves both messages when packet is split', function () { test('in the middle', function () { splitAndVerifyTwoMessages(11) }) test('at the front', function () { splitAndVerifyTwoMessages(fullBuffer.length - 1) splitAndVerifyTwoMessages(fullBuffer.length - 4) splitAndVerifyTwoMessages(fullBuffer.length - 6) }) test('at the end', function () { splitAndVerifyTwoMessages(8) splitAndVerifyTwoMessages(1) }) }) }) node-postgres-7.14.0/test/unit/connection/outbound-sending-tests.js000066400000000000000000000131011356526317000254570ustar00rootroot00000000000000'use strict' require(__dirname + '/test-helper') var Connection = require(__dirname + '/../../../lib/connection') var stream = new MemoryStream() var con = new Connection({ stream: stream }) assert.received = function (stream, buffer) { assert.lengthIs(stream.packets, 1) var packet = stream.packets.pop() assert.equalBuffers(packet, buffer) } test('sends startup message', function () { con.startup({ user: 'brian', database: 'bang' }) assert.received(stream, new BufferList() .addInt16(3) .addInt16(0) .addCString('user') .addCString('brian') .addCString('database') .addCString('bang') .addCString('client_encoding') .addCString("'utf-8'") .addCString('').join(true)) }) test('sends password message', function () { con.password('!') assert.received(stream, new BufferList().addCString('!').join(true, 'p')) }) test('sends SASLInitialResponseMessage message', function () { con.sendSASLInitialResponseMessage('mech', 'data') assert.received(stream, new BufferList().addCString('mech').addInt32(4).addString('data').join(true, 'p')) }) test('sends SCRAMClientFinalMessage message', function () { con.sendSCRAMClientFinalMessage('data') assert.received(stream, new BufferList().addString('data').join(true, 'p')) }) test('sends query message', function () { var txt = 'select * from boom' con.query(txt) assert.received(stream, new BufferList().addCString(txt).join(true, 'Q')) }) test('sends parse message', function () { con.parse({text: '!'}) var expected = new BufferList() .addCString('') .addCString('!') .addInt16(0).join(true, 'P') assert.received(stream, expected) }) test('sends parse message with named query', function () { con.parse({ name: 'boom', text: 'select * from boom', types: [] }) var expected = new BufferList() .addCString('boom') .addCString('select * from boom') .addInt16(0).join(true, 'P') assert.received(stream, expected) test('with multiple parameters', function () { con.parse({ name: 'force', text: 'select * from bang where name = $1', types: [1, 2, 3, 4] }) var expected = new BufferList() .addCString('force') .addCString('select * from bang where name = $1') .addInt16(4) .addInt32(1) .addInt32(2) .addInt32(3) .addInt32(4).join(true, 'P') assert.received(stream, expected) }) }) test('bind messages', function () { test('with no values', function () { con.bind() var expectedBuffer = new BufferList() .addCString('') .addCString('') .addInt16(0) .addInt16(0) .addInt16(0) .join(true, 'B') assert.received(stream, expectedBuffer) }) test('with named statement, portal, and values', function () { con.bind({ portal: 'bang', statement: 'woo', values: ['1', 'hi', null, 'zing'] }) var expectedBuffer = new BufferList() .addCString('bang') // portal name .addCString('woo') // statement name .addInt16(0) .addInt16(4) .addInt32(1) .add(Buffer.from('1')) .addInt32(2) .add(Buffer.from('hi')) .addInt32(-1) .addInt32(4) .add(Buffer.from('zing')) .addInt16(0) .join(true, 'B') assert.received(stream, expectedBuffer) }) }) test('with named statement, portal, and buffer value', function () { con.bind({ portal: 'bang', statement: 'woo', values: ['1', 'hi', null, Buffer.from('zing', 'utf8')] }) var expectedBuffer = new BufferList() .addCString('bang') // portal name .addCString('woo') // statement name .addInt16(4)// value count .addInt16(0)// string .addInt16(0)// string .addInt16(0)// string .addInt16(1)// binary .addInt16(4) .addInt32(1) .add(Buffer.from('1')) .addInt32(2) .add(Buffer.from('hi')) .addInt32(-1) .addInt32(4) .add(Buffer.from('zing', 'UTF-8')) .addInt16(0) .join(true, 'B') assert.received(stream, expectedBuffer) }) test('sends execute message', function () { test('for unamed portal with no row limit', function () { con.execute() var expectedBuffer = new BufferList() .addCString('') .addInt32(0) .join(true, 'E') assert.received(stream, expectedBuffer) }) test('for named portal with row limit', function () { con.execute({ portal: 'my favorite portal', rows: 100 }) var expectedBuffer = new BufferList() .addCString('my favorite portal') .addInt32(100) .join(true, 'E') assert.received(stream, expectedBuffer) }) }) test('sends flush command', function () { con.flush() var expected = new BufferList().join(true, 'H') assert.received(stream, expected) }) test('sends sync command', function () { con.sync() var expected = new BufferList().join(true, 'S') assert.received(stream, expected) }) test('sends end command', function () { con.end() var expected = Buffer.from([0x58, 0, 0, 0, 4]) assert.received(stream, expected) assert.equal(stream.closed, true) }) test('sends describe command', function () { test('describe statement', function () { con.describe({type: 'S', name: 'bang'}) var expected = new BufferList().addChar('S').addCString('bang').join(true, 'D') assert.received(stream, expected) }) test('describe unnamed portal', function () { con.describe({type: 'P'}) var expected = new BufferList().addChar('P').addCString('').join(true, 'D') assert.received(stream, expected) }) }) node-postgres-7.14.0/test/unit/connection/startup-tests.js000066400000000000000000000037061356526317000237070ustar00rootroot00000000000000'use strict' require(__dirname + '/test-helper') var Connection = require(__dirname + '/../../../lib/connection') test('connection can take existing stream', function () { var stream = new MemoryStream() var con = new Connection({stream: stream}) assert.equal(con.stream, stream) }) test('using closed stream', function () { var makeStream = function () { var stream = new MemoryStream() stream.readyState = 'closed' stream.connect = function (port, host) { this.connectCalled = true this.port = port this.host = host } return stream } var stream = makeStream() var con = new Connection({stream: stream}) con.connect(1234, 'bang') test('makes stream connect', function () { assert.equal(stream.connectCalled, true) }) test('uses configured port', function () { assert.equal(stream.port, 1234) }) test('uses configured host', function () { assert.equal(stream.host, 'bang') }) test('after stream connects client emits connected event', function () { var hit = false con.once('connect', function () { hit = true }) assert.ok(stream.emit('connect')) assert.ok(hit) }) test('after stream emits connected event init TCP-keepalive', function () { var stream = makeStream() var con = new Connection({ stream: stream, keepAlive: true }) con.connect(123, 'test') var res = false stream.setKeepAlive = function (bit) { res = bit } assert.ok(stream.emit('connect')) setTimeout(function () { assert.equal(res, true) }) }) }) test('using opened stream', function () { var stream = new MemoryStream() stream.readyState = 'open' stream.connect = function () { assert.ok(false, 'Should not call open') } var con = new Connection({stream: stream}) test('does not call open', function () { var hit = false con.once('connect', function () { hit = true }) con.connect() assert.ok(hit) }) }) node-postgres-7.14.0/test/unit/connection/test-helper.js000066400000000000000000000001051356526317000232670ustar00rootroot00000000000000'use strict' module.exports = require(__dirname + '/../test-helper') node-postgres-7.14.0/test/unit/test-helper.js000066400000000000000000000014571356526317000211430ustar00rootroot00000000000000'use strict' var EventEmitter = require('events').EventEmitter var helper = require('../test-helper') var Connection = require('../../lib/connection') global.MemoryStream = function () { EventEmitter.call(this) this.packets = [] } helper.sys.inherits(MemoryStream, EventEmitter) var p = MemoryStream.prototype p.write = function (packet, cb) { this.packets.push(packet) if(cb){ cb(); } } p.end = function() { p.closed = true; } p.setKeepAlive = function () {} p.closed = false; p.writable = true const createClient = function () { var stream = new MemoryStream() stream.readyState = 'open' var client = new Client({ connection: new Connection({stream: stream}) }) client.connect() return client } module.exports = Object.assign({}, helper, { createClient: createClient }) node-postgres-7.14.0/test/unit/utils-tests.js000066400000000000000000000155351356526317000212110ustar00rootroot00000000000000'use strict' var helper = require('./test-helper') var utils = require('./../../lib/utils') var defaults = require('./../../lib').defaults test('ensure types is exported on root object', function () { var pg = require('../../lib') assert(pg.types) assert(pg.types.getTypeParser) assert(pg.types.setTypeParser) }) // this tests the monkey patching // to ensure comptability with older // versions of node test('EventEmitter.once', function (t) { // an event emitter var stream = new MemoryStream() var callCount = 0 stream.once('single', function () { callCount++ }) stream.emit('single') stream.emit('single') assert.equal(callCount, 1) }) test('normalizing query configs', function () { var config var callback = function () { } config = utils.normalizeQueryConfig({ text: 'TEXT' }) assert.same(config, { text: 'TEXT' }) config = utils.normalizeQueryConfig({ text: 'TEXT' }, [10]) assert.deepEqual(config, { text: 'TEXT', values: [10] }) config = utils.normalizeQueryConfig({ text: 'TEXT', values: [10] }) assert.deepEqual(config, { text: 'TEXT', values: [10] }) config = utils.normalizeQueryConfig('TEXT', [10], callback) assert.deepEqual(config, { text: 'TEXT', values: [10], callback: callback }) config = utils.normalizeQueryConfig({ text: 'TEXT', values: [10] }, callback) assert.deepEqual(config, { text: 'TEXT', values: [10], callback: callback }) }) test('prepareValues: buffer prepared properly', function () { var buf = Buffer.from('quack') var out = utils.prepareValue(buf) assert.strictEqual(buf, out) }) test('prepareValues: Uint8Array prepared properly', function () { var buf = new Uint8Array([1, 2, 3]).subarray(1, 2) var out = utils.prepareValue(buf) assert.ok(Buffer.isBuffer(out)) assert.equal(out.length, 1) assert.deepEqual(out[0], 2) }) test('prepareValues: date prepared properly', function () { helper.setTimezoneOffset(-330) var date = new Date(2014, 1, 1, 11, 11, 1, 7) var out = utils.prepareValue(date) assert.strictEqual(out, '2014-02-01T11:11:01.007+05:30') helper.resetTimezoneOffset() }) test('prepareValues: date prepared properly as UTC', function () { defaults.parseInputDatesAsUTC = true // make a date in the local timezone that represents a specific UTC point in time var date = new Date(Date.UTC(2014, 1, 1, 11, 11, 1, 7)) var out = utils.prepareValue(date) assert.strictEqual(out, '2014-02-01T11:11:01.007+00:00') defaults.parseInputDatesAsUTC = false }) test('prepareValues: BC date prepared properly', function () { helper.setTimezoneOffset(-330) var date = new Date(-3245, 1, 1, 11, 11, 1, 7) var out = utils.prepareValue(date) assert.strictEqual(out, '3246-02-01T11:11:01.007+05:30 BC') helper.resetTimezoneOffset() }) test('prepareValues: 1 BC date prepared properly', function () { helper.setTimezoneOffset(-330) // can't use the multi-argument constructor as year 0 would be interpreted as 1900 var date = new Date('0000-02-01T11:11:01.007') var out = utils.prepareValue(date) assert.strictEqual(out, '0001-02-01T11:11:01.007+05:30 BC') helper.resetTimezoneOffset() }) test('prepareValues: undefined prepared properly', function () { var out = utils.prepareValue(void 0) assert.strictEqual(out, null) }) test('prepareValue: null prepared properly', function () { var out = utils.prepareValue(null) assert.strictEqual(out, null) }) test('prepareValue: true prepared properly', function () { var out = utils.prepareValue(true) assert.strictEqual(out, 'true') }) test('prepareValue: false prepared properly', function () { var out = utils.prepareValue(false) assert.strictEqual(out, 'false') }) test('prepareValue: number prepared properly', function () { var out = utils.prepareValue(3.042) assert.strictEqual(out, '3.042') }) test('prepareValue: string prepared properly', function () { var out = utils.prepareValue('big bad wolf') assert.strictEqual(out, 'big bad wolf') }) test('prepareValue: simple array prepared properly', function () { var out = utils.prepareValue([1, null, 3, undefined, [5, 6, 'squ,awk']]) assert.strictEqual(out, '{"1",NULL,"3",NULL,{"5","6","squ,awk"}}') }) test('prepareValue: complex array prepared properly', function () { var out = utils.prepareValue([{ x: 42 }, { y: 84 }]) assert.strictEqual(out, '{"{\\"x\\":42}","{\\"y\\":84}"}') }) test('prepareValue: date array prepared properly', function () { helper.setTimezoneOffset(-330) var date = new Date(2014, 1, 1, 11, 11, 1, 7) var out = utils.prepareValue([date]) assert.strictEqual(out, '{"2014-02-01T11:11:01.007+05:30"}') helper.resetTimezoneOffset() }) test('prepareValue: arbitrary objects prepared properly', function () { var out = utils.prepareValue({ x: 42 }) assert.strictEqual(out, '{"x":42}') }) test('prepareValue: objects with simple toPostgres prepared properly', function () { var customType = { toPostgres: function () { return 'zomgcustom!' } } var out = utils.prepareValue(customType) assert.strictEqual(out, 'zomgcustom!') }) test('prepareValue: buffer array prepared properly', function () { var buffer1 = Buffer.from('dead', 'hex') var buffer2 = Buffer.from('beef', 'hex') var out = utils.prepareValue([buffer1, buffer2]) assert.strictEqual(out, '{\\\\xdead,\\\\xbeef}') }) test('prepareValue: objects with complex toPostgres prepared properly', function () { var buf = Buffer.from('zomgcustom!') var customType = { toPostgres: function () { return [1, 2] } } var out = utils.prepareValue(customType) assert.strictEqual(out, '{"1","2"}') }) test('prepareValue: objects with toPostgres receive prepareValue', function () { var customRange = { lower: { toPostgres: function () { return 5 } }, upper: { toPostgres: function () { return 10 } }, toPostgres: function (prepare) { return '[' + prepare(this.lower) + ',' + prepare(this.upper) + ']' } } var out = utils.prepareValue(customRange) assert.strictEqual(out, '[5,10]') }) test('prepareValue: objects with circular toPostgres rejected', function () { var buf = Buffer.from('zomgcustom!') var customType = { toPostgres: function () { return { toPostgres: function () { return customType } } } } // can't use `assert.throws` since we need to distinguish circular reference // errors from call stack exceeded errors try { utils.prepareValue(customType) } catch (e) { assert.ok(e.message.match(/circular/), 'Expected circular reference error but got ' + e) return } throw new Error('Expected prepareValue to throw exception') }) test('prepareValue: can safely be used to map an array of values including those with toPostgres functions', function () { var customType = { toPostgres: function () { return 'zomgcustom!' } } var values = [1, 'test', customType] var out = values.map(utils.prepareValue) assert.deepEqual(out, [1, 'test', 'zomgcustom!']) })