From 1e648c5df4fc12bd7bc2fe82704bbe725f0b2e36 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Sun, 19 Oct 2014 22:53:08 -0400 Subject: [PATCH 01/11] Do not consider a statement as prepared if it errors Fixes #600 --- lib/native/index.js | 2 +- lib/query.js | 6 +-- test/integration/gh-issues/600-tests.js | 58 +++++++++++++++++++++++++ test/test-helper.js | 4 +- 4 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 test/integration/gh-issues/600-tests.js diff --git a/lib/native/index.js b/lib/native/index.js index 1e1d4460..dd16ea8b 100644 --- a/lib/native/index.js +++ b/lib/native/index.js @@ -119,7 +119,6 @@ Connection.prototype._pulseQueryQueue = function(initialConnection) { this._sendQueryPrepared(query.name, query.values||[], query.singleRowMode); } else { this._namedQuery = true; - this._namedQueries[query.name] = true; this._sendPrepare(query.name, query.text, (query.values||[]).length, query.singleRowMode); } } else if(query.values) { @@ -200,6 +199,7 @@ var clientBuilder = function(config) { var q = this._activeQuery; //a named query finished being prepared if(this._namedQuery) { + this._namedQueries[q.name] = true; this._namedQuery = false; this._sendQueryPrepared(q.name, q.values||[]); } else { diff --git a/lib/query.js b/lib/query.js index 0c6bbc70..841e9a4f 100644 --- a/lib/query.js +++ b/lib/query.js @@ -67,6 +67,9 @@ Query.prototype.handleDataRow = function(msg) { }; Query.prototype.handleCommandComplete = function(msg, con) { + if(this.name) { + con.parsedStatements[this.name] = true; + } this._result.addCommandComplete(msg); //need to sync after each command complete of a prepared statement if(this.isPreparedStatement) { @@ -137,9 +140,6 @@ Query.prototype.prepare = function(connection) { name: self.name, types: self.types }, true); - if(this.name) { - connection.parsedStatements[this.name] = true; - } } //TODO is there some better way to prepare values for the database? diff --git a/test/integration/gh-issues/600-tests.js b/test/integration/gh-issues/600-tests.js new file mode 100644 index 00000000..faf8fd8e --- /dev/null +++ b/test/integration/gh-issues/600-tests.js @@ -0,0 +1,58 @@ +var async = require('async'); +var helper = require('../test-helper'); + +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 +] + +async.series(steps, assert.success(function() { + db.end() +})) diff --git a/test/test-helper.js b/test/test-helper.js index acd092b4..cb7e6067 100644 --- a/test/test-helper.js +++ b/test/test-helper.js @@ -101,7 +101,7 @@ assert.success = function(callback) { if(err) { console.log(err); } - assert.isNull(err); + assert(!err); callback(arg); }); } else if (callback.length === 2) { @@ -109,7 +109,7 @@ assert.success = function(callback) { if(err) { console.log(err); } - assert.isNull(err); + assert(!err); callback(arg1, arg2); }); } else { From 1ccc5eb40b8d17160761b31045c306921a49812a Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Mon, 20 Oct 2014 00:21:16 -0400 Subject: [PATCH 02/11] Add regression test for #199 --- test/integration/gh-issues/199-tests.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test/integration/gh-issues/199-tests.js diff --git a/test/integration/gh-issues/199-tests.js b/test/integration/gh-issues/199-tests.js new file mode 100644 index 00000000..b60477fd --- /dev/null +++ b/test/integration/gh-issues/199-tests.js @@ -0,0 +1,21 @@ +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(); +}); From eeae8e6f57cedff7b7cd7a200f8265a73dd55e29 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Mon, 20 Oct 2014 10:18:47 -0400 Subject: [PATCH 03/11] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 31ad20e5..2f366919 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pg", - "version": "3.6.0", + "version": "3.6.1", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords": [ "postgres", From 36be8539dea2761c95374785d1ab6d5357dd173c Mon Sep 17 00:00:00 2001 From: rpedela Date: Tue, 21 Oct 2014 11:23:12 -0600 Subject: [PATCH 04/11] Add pg-format to the list of helper modules. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f87d810d..66210619 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,7 @@ node-postgres is by design _low level_ with the bare minimum of abstraction. Th - [brianc/node-sql](https://github.com/brianc/node-sql) - SQL generation for node.js - [hiddentao/suqel](https://hiddentao.github.io/squel/) - SQL query string builder for Javascript - [CSNW/sql-bricks](https://github.com/CSNW/sql-bricks) - Transparent, Schemaless SQL Generation +- [datalanche/node-pg-format](https://github.com/datalanche/node-pg-format) - Safely and easily create dynamic SQL queries with this Node implementation of [PostgreSQL format()](http://www.postgresql.org/docs/9.3/static/functions-string.html#FUNCTIONS-STRING-FORMAT). ### Windows From 9e2a3e599bede76ae5351f807310385521516afe Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Tue, 21 Oct 2014 13:50:49 -0400 Subject: [PATCH 05/11] Fix issue with parsed statement cache timing - closes #665 --- lib/client.js | 9 +++++++++ lib/query.js | 3 --- test/integration/gh-issues/600-tests.js | 25 ++++++++++++++++++++++--- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/lib/client.js b/lib/client.js index dfce3937..a512e266 100644 --- a/lib/client.js +++ b/lib/client.js @@ -117,6 +117,15 @@ Client.prototype.connect = function(callback) { 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 + con.on('parseComplete', function(msg) { + if(self.activeQuery.name) { + con.parsedStatements[self.activeQuery.name] = true; + } + }); + con.on('copyInResponse', function(msg) { self.activeQuery.handleCopyInResponse(self.connection); }); diff --git a/lib/query.js b/lib/query.js index 841e9a4f..1eb47b40 100644 --- a/lib/query.js +++ b/lib/query.js @@ -67,9 +67,6 @@ Query.prototype.handleDataRow = function(msg) { }; Query.prototype.handleCommandComplete = function(msg, con) { - if(this.name) { - con.parsedStatements[this.name] = true; - } this._result.addCommandComplete(msg); //need to sync after each command complete of a prepared statement if(this.isPreparedStatement) { diff --git a/test/integration/gh-issues/600-tests.js b/test/integration/gh-issues/600-tests.js index faf8fd8e..0476d42d 100644 --- a/test/integration/gh-issues/600-tests.js +++ b/test/integration/gh-issues/600-tests.js @@ -53,6 +53,25 @@ var steps = [ insertDataBar ] -async.series(steps, assert.success(function() { - db.end() -})) +test('test if query fails', function() { + async.series(steps, assert.success(function() { + db.end() + })) +}) + +test('test if prepare works but bind fails', function() { + 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(); + })); + })); +}); + From 7a0e9f69db900a79845cb432940e7154efeeaf2e Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Tue, 21 Oct 2014 14:14:20 -0400 Subject: [PATCH 06/11] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2f366919..4dbd4b7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pg", - "version": "3.6.1", + "version": "3.6.2", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords": [ "postgres", From d00d1eb4a9ed2c74361d464e97efc42bd06f81fa Mon Sep 17 00:00:00 2001 From: Thomas Hunter II Date: Sun, 26 Oct 2014 23:10:44 -0700 Subject: [PATCH 07/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 66210619..1c82ed5e 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ __I love contributions.__ You are welcome contribute via pull requests. If you need help getting the tests running locally feel free to email me or gchat me. I will __happily__ accept your pull request if it: -- _)has tests__ +- __has tests__ - looks reasonable - does not break backwards compatibility - satisfies jshint From f088442570a7259fa315fe36548419af1d8922e2 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Mon, 10 Nov 2014 23:29:15 -0500 Subject: [PATCH 08/11] Fix for empty buffer segfault in native bindings --- src/binding.cc | 16 ++++++++------ test/integration/gh-issues/675-tests.js | 28 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 test/integration/gh-issues/675-tests.js diff --git a/src/binding.cc b/src/binding.cc index c1c93ed4..c2757c66 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -876,13 +876,17 @@ private: } else if(val->IsNull()) { paramValues[i] = NULL; } else if(val->IsObject() && Buffer::HasInstance(val)) { - char *cHexString = MallocCHexString(val->ToObject()); - if(!cHexString) { - LOG("ArgToCStringArray: OUT OF MEMORY OR SOMETHING BAD!"); - ReleaseCStringArray(paramValues, i-1); - return 0; + if(Buffer::Length(val) > 0) { + char *cHexString = MallocCHexString(val->ToObject()); + if(!cHexString) { + LOG("ArgToCStringArray: OUT OF MEMORY OR SOMETHING BAD!"); + ReleaseCStringArray(paramValues, i-1); + return 0; + } + paramValues[i] = cHexString; + } else { + paramValues[i] = MallocCString(NanNew("")); } - paramValues[i] = cHexString; } else { //a paramter was not a string LOG("Parameter not a string or buffer"); diff --git a/test/integration/gh-issues/675-tests.js b/test/integration/gh-issues/675-tests.js new file mode 100644 index 00000000..128afc65 --- /dev/null +++ b/test/integration/gh-issues/675-tests.js @@ -0,0 +1,28 @@ +var helper = require('../test-helper'); +var assert = require('assert'); + +helper.pg.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 = new Buffer('foo'); + client.query(c, [body], function(err) { + if (err) throw err; + + body = new Buffer([]); + client.query(c, [body], function(err, res) { + done(); + + if (err) throw err; + assert.equal(res.rows[0].body, '') + helper.pg.end(); + }); + }); + }); +}); From c21dcfbf1270c4d93044c52f100ba433cb44bd6b Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Tue, 11 Nov 2014 09:42:46 -0500 Subject: [PATCH 09/11] Fix travis environment --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 98ec2cce..6b32c30d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,3 +3,5 @@ node_js: - "0.10" before_script: - node script/create-test-tables.js pg://postgres@127.0.0.1:5432/postgres +env: + - PGUSER=postgres PGDATABASE=postgres From af8f4990c6eae59495fc3487bd5ebaa2bcd959e6 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Tue, 11 Nov 2014 09:50:38 -0500 Subject: [PATCH 10/11] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4dbd4b7d..eff34bf9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pg", - "version": "3.6.2", + "version": "3.6.3", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords": [ "postgres", From 17f22bb56ce598cd2014a5d2d92d6c4f361a5ad3 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Fri, 14 Nov 2014 18:01:21 -0700 Subject: [PATCH 11/11] add pg-transact to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1c82ed5e..64d50f97 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ node-postgres is by design _low level_ with the bare minimum of abstraction. Th - [hiddentao/suqel](https://hiddentao.github.io/squel/) - SQL query string builder for Javascript - [CSNW/sql-bricks](https://github.com/CSNW/sql-bricks) - Transparent, Schemaless SQL Generation - [datalanche/node-pg-format](https://github.com/datalanche/node-pg-format) - Safely and easily create dynamic SQL queries with this Node implementation of [PostgreSQL format()](http://www.postgresql.org/docs/9.3/static/functions-string.html#FUNCTIONS-STRING-FORMAT). +- [iceddev/pg-transact](https://github.com/iceddev/pg-transact) - A nicer API on node-postgres transactions ### Windows