From 60dc7851b3d95ae82e9ab6140bfbe2bb1ed52166 Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 29 Aug 2017 17:09:55 -0700 Subject: [PATCH 1/7] support statement_timeout --- .gitignore | 1 + lib/client.js | 3 + lib/connection-parameters.js | 1 + lib/defaults.js | 5 +- .../client/statement_timeout-tests.js | 69 +++++++++++++++++++ .../connection-parameters/creation-tests.js | 4 +- 6 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 test/integration/client/statement_timeout-tests.js diff --git a/.gitignore b/.gitignore index 88b672dd3..439db5fd6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ build/ node_modules/ package-lock.json *.swp +/.idea diff --git a/lib/client.js b/lib/client.js index 72edd699b..a904168f6 100644 --- a/lib/client.js +++ b/lib/client.js @@ -272,6 +272,9 @@ Client.prototype.getStartupConf = function () { if (params.replication) { data.replication = '' + params.replication } + if (params.statement_timeout) { + data.statement_timeout = String(parseInt(params.statement_timeout, 10)) + } return data } diff --git a/lib/connection-parameters.js b/lib/connection-parameters.js index 2ba409c24..f31f28dd3 100644 --- a/lib/connection-parameters.js +++ b/lib/connection-parameters.js @@ -64,6 +64,7 @@ var ConnectionParameters = function (config) { 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) } // Convert arg to a string, surround in single quotes, and escape single quotes and backslashes diff --git a/lib/defaults.js b/lib/defaults.js index 62f2ad158..7fb11d885 100644 --- a/lib/defaults.js +++ b/lib/defaults.js @@ -60,7 +60,10 @@ module.exports = { application_name: undefined, fallback_application_name: undefined, - parseInputDatesAsUTC: false + parseInputDatesAsUTC: false, + + // max milliseconds any query using this connection will execute for before timing out in error. false=unlimited + statement_timeout: false } var pgTypes = require('pg-types') diff --git a/test/integration/client/statement_timeout-tests.js b/test/integration/client/statement_timeout-tests.js new file mode 100644 index 000000000..5bf1e943d --- /dev/null +++ b/test/integration/client/statement_timeout-tests.js @@ -0,0 +1,69 @@ +'use strict' +var helper = require('./test-helper') +var Client = helper.Client + +var suite = new helper.Suite() + +var conInfo = helper.config + +function getConInfo (override) { + var newConInfo = {} + Object.keys(conInfo).forEach(function (k) { + newConInfo[k] = conInfo[k] + }) + Object.keys(override || {}).forEach(function (k) { + newConInfo[k] = override[k] + }) + return newConInfo +} + +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() + }) + }) +} diff --git a/test/unit/connection-parameters/creation-tests.js b/test/unit/connection-parameters/creation-tests.js index a3fa25135..8563a404e 100644 --- a/test/unit/connection-parameters/creation-tests.js +++ b/test/unit/connection-parameters/creation-tests.js @@ -22,6 +22,7 @@ var compare = function (actual, expected, type) { 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 + ' binary') } test('ConnectionParameters initializing from defaults', function () { @@ -60,7 +61,8 @@ test('ConnectionParameters initializing from config', function () { host: 'yo', ssl: { asdf: 'blah' - } + }, + statement_timeout: 15000 } var subject = new ConnectionParameters(config) compare(subject, config, 'config') From 41f9f7ca2d2f8249de27d0eb9cc35e723e2760f3 Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 29 Aug 2017 17:16:21 -0700 Subject: [PATCH 2/7] fixed test failure message --- test/unit/connection-parameters/creation-tests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/connection-parameters/creation-tests.js b/test/unit/connection-parameters/creation-tests.js index 8563a404e..fc9f6521f 100644 --- a/test/unit/connection-parameters/creation-tests.js +++ b/test/unit/connection-parameters/creation-tests.js @@ -22,7 +22,7 @@ var compare = function (actual, expected, type) { 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 + ' binary') + assert.equal(actual.statement_timout, expected.statement_timout, type + ' statement_timeout') } test('ConnectionParameters initializing from defaults', function () { From 640495b754b53cacb3adf32ba65a8e503cc7a136 Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 29 Aug 2017 18:19:51 -0700 Subject: [PATCH 3/7] remove .idea from gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 439db5fd6..8e3056a0e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,4 @@ build/ *.log node_modules/ package-lock.json -*.swp -/.idea +*.swp \ No newline at end of file From d5e2f334c047daa5e57ae9213e69ab9cf4530972 Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 29 Aug 2017 18:23:21 -0700 Subject: [PATCH 4/7] fixes --- package.json | 3 ++- test/integration/client/appname-tests.js | 9 +-------- test/integration/client/statement_timeout-tests.js | 9 +-------- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index fe251ab10..680a54d44 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,10 @@ "main": "./lib", "dependencies": { "buffer-writer": "1.0.1", - "packet-reader": "0.3.1", "js-string-escape": "1.0.1", + "packet-reader": "0.3.1", "pg-connection-string": "0.1.3", + "pg-native": "^2.2.0", "pg-pool": "~2.0.3", "pg-types": "~1.12.1", "pgpass": "1.x", diff --git a/test/integration/client/appname-tests.js b/test/integration/client/appname-tests.js index 4db5297c9..e5883908d 100644 --- a/test/integration/client/appname-tests.js +++ b/test/integration/client/appname-tests.js @@ -7,14 +7,7 @@ var suite = new helper.Suite() var conInfo = helper.config function getConInfo (override) { - var newConInfo = {} - Object.keys(conInfo).forEach(function (k) { - newConInfo[k] = conInfo[k] - }) - Object.keys(override || {}).forEach(function (k) { - newConInfo[k] = override[k] - }) - return newConInfo + return Object.assign({}, conInfo, override ) } function getAppName (conf, cb) { diff --git a/test/integration/client/statement_timeout-tests.js b/test/integration/client/statement_timeout-tests.js index 5bf1e943d..5574285c6 100644 --- a/test/integration/client/statement_timeout-tests.js +++ b/test/integration/client/statement_timeout-tests.js @@ -7,14 +7,7 @@ var suite = new helper.Suite() var conInfo = helper.config function getConInfo (override) { - var newConInfo = {} - Object.keys(conInfo).forEach(function (k) { - newConInfo[k] = conInfo[k] - }) - Object.keys(override || {}).forEach(function (k) { - newConInfo[k] = override[k] - }) - return newConInfo + return Object.assign({}, conInfo, override ) } function getStatementTimeout (conf, cb) { From 2dcb7d67f8798c5f66ead85d30dc0e7cb37994e9 Mon Sep 17 00:00:00 2001 From: Josh Date: Wed, 30 Aug 2017 08:07:57 -0700 Subject: [PATCH 5/7] remove pg-native from dependencies `npm run test` seems to be adding this --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 680a54d44..eddce4902 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "js-string-escape": "1.0.1", "packet-reader": "0.3.1", "pg-connection-string": "0.1.3", - "pg-native": "^2.2.0", "pg-pool": "~2.0.3", "pg-types": "~1.12.1", "pgpass": "1.x", From fc8f81c4d089fe2009177b5fe503254c0d7a3309 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 31 Aug 2017 08:57:02 -0700 Subject: [PATCH 6/7] new test for actual statement timeout --- .../integration/client/statement_timeout-tests.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/integration/client/statement_timeout-tests.js b/test/integration/client/statement_timeout-tests.js index 5574285c6..393e82a19 100644 --- a/test/integration/client/statement_timeout-tests.js +++ b/test/integration/client/statement_timeout-tests.js @@ -59,4 +59,19 @@ if (!helper.args.native) { // statement_timeout is not supported with the native 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() + }) + })) + }) + } From c5aec2845ad1a1567e86b223bf00bbee1f26037c Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 31 Aug 2017 09:01:15 -0700 Subject: [PATCH 7/7] restore newline at end of file --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8e3056a0e..88b672dd3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ build/ *.log node_modules/ package-lock.json -*.swp \ No newline at end of file +*.swp