From 46f6d9037c4839d867b77407ec3e7dd04ac2e1d1 Mon Sep 17 00:00:00 2001 From: Roman Shtylman Date: Sun, 30 Oct 2011 16:20:21 -0400 Subject: [PATCH 01/11] fix for writing null terminated buffers node 0.5.10+ changed how null terminated buffers are written. The null terminator is no longer written explicitly. fixes #63 --- lib/writer.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/writer.js b/lib/writer.js index fe539ef0..27b4bc8e 100644 --- a/lib/writer.js +++ b/lib/writer.js @@ -15,7 +15,7 @@ p._ensure = function(size) { var remaining = this.buffer.length - this.offset; if(remaining < size) { var oldBuffer = this.buffer; - this.buffer = Buffer(oldBuffer.length + size); + this.buffer = new Buffer(oldBuffer.length + size); oldBuffer.copy(this.buffer); } } @@ -40,20 +40,20 @@ p.addCString = function(string) { //just write a 0 for empty or null strings if(!string) { this._ensure(1); - this.buffer[this.offset++] = 0; - return this; + } else { + var len = Buffer.byteLength(string); + this._ensure(len + 1); //+1 for null terminator + this.buffer.write(string, this.offset, len); + this.offset += len; } - var len = Buffer.byteLength(string) + 1; - this._ensure(len); - this.buffer.write(string, this.offset); - this.offset += len; - this.buffer[this.offset] = 0; //add null terminator + + this.buffer[this.offset++] = 0; // null terminator return this; } p.addChar = function(char) { this._ensure(1); - this.buffer.write(char, this.offset); + this.buffer.write(char, this.offset, 1); this.offset++; return this; } From 106490f0a8b297dc42c8435ad790f9407b85fc8c Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Sun, 30 Oct 2011 21:53:59 -0500 Subject: [PATCH 02/11] version & contributor bump --- README.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cc27d747..2c7bd15a 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ Many thanks to the following: * [homme](https://github.com/homme) * [bdunavant](https://github.com/bdunavant) * [tokumine](https://github.com/tokumine) +* [shtylman](https://github.com/shtylman) ## Documentation diff --git a/package.json b/package.json index 076ddcf3..b36f1775 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { "name": "pg", - "version": "0.6.3", + "version": "0.6.4", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords" : ["postgres", "pg", "libpq", "postgre", "database", "rdbms"], "homepage": "http://github.com/brianc/node-postgres", From 2cddf2a112828b0f8b4dabe47a8b9b015297072a Mon Sep 17 00:00:00 2001 From: brianc Date: Tue, 1 Nov 2011 23:02:59 -0500 Subject: [PATCH 03/11] fix for changes to Buffer.prototype.write signature change between node version. closes gh#66 --- lib/writer.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/writer.js b/lib/writer.js index 27b4bc8e..49aed26d 100644 --- a/lib/writer.js +++ b/lib/writer.js @@ -3,7 +3,7 @@ //same buffer to avoid memcpy and limit memory allocations var Writer = function(size) { this.size = size || 1024; - this.buffer = new Buffer(this.size + 5); + this.buffer = Buffer(this.size + 5); this.offset = 5; this.headerPosition = 0; }; @@ -36,6 +36,18 @@ p.addInt16 = function(num) { return this; } +//for versions of node requiring 'length' as 3rd argument to buffer.write +var writeString = function(buffer, string, offset, len) { + buffer.write(string, offset, len); +} + +//overwrite function for older versions of node +if(Buffer.prototype.write.length === 3) { + writeString = function(buffer, string, offset, len) { + buffer.write(string, offset); + } +} + p.addCString = function(string) { //just write a 0 for empty or null strings if(!string) { @@ -43,7 +55,7 @@ p.addCString = function(string) { } else { var len = Buffer.byteLength(string); this._ensure(len + 1); //+1 for null terminator - this.buffer.write(string, this.offset, len); + writeString(this.buffer, string, this.offset, len); this.offset += len; } @@ -53,7 +65,7 @@ p.addCString = function(string) { p.addChar = function(char) { this._ensure(1); - this.buffer.write(char, this.offset, 1); + writeString(this.buffer, char, this.offset, 1); this.offset++; return this; } From 6b97ed2abc3783d9dd6575a4c2e20d282c56905e Mon Sep 17 00:00:00 2001 From: brianc Date: Tue, 1 Nov 2011 23:03:23 -0500 Subject: [PATCH 04/11] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b36f1775..4fd73b1c 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { "name": "pg", - "version": "0.6.4", + "version": "0.6.5", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords" : ["postgres", "pg", "libpq", "postgre", "database", "rdbms"], "homepage": "http://github.com/brianc/node-postgres", From f3c8b972fe3a2fbffc0731d943afce2dcb729f8d Mon Sep 17 00:00:00 2001 From: Christophe Macabiau Date: Wed, 2 Nov 2011 16:07:14 +0100 Subject: [PATCH 05/11] query cancellation --- lib/client.js | 26 ++++++++++++++++++++++++++ lib/connection.js | 17 +++++++++++++++++ lib/index.js | 10 ++++++++++ 3 files changed, 53 insertions(+) diff --git a/lib/client.js b/lib/client.js index 64b1b59c..891e1812 100644 --- a/lib/client.js +++ b/lib/client.js @@ -21,6 +21,8 @@ var Client = function(config) { this.queryQueue = []; this.password = config.password || defaults.password; this.encoding = 'utf8'; + this.processID = null; + this.secretKey = null; var self = this; }; @@ -59,6 +61,11 @@ p.connect = function(callback) { con.password(md5password); }); + con.once('backendKeyData', function(msg) { + self.processID = msg.processID; + self.secretKey = msg.secretKey; + }); + //hook up query handling events to connection //after the connection initially becomes ready for queries con.once('readyForQuery', function() { @@ -130,6 +137,25 @@ p.connect = function(callback) { }; +p.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); +}; + p._pulseQueryQueue = function() { if(this.readyForQuery===true) { this.activeQuery = this.queryQueue.shift(); diff --git a/lib/connection.js b/lib/connection.js index 71b84400..c70dd0d8 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -73,6 +73,23 @@ p.startup = function(config) { this.stream.write(buffer); }; +p.cancel = function(processID, secretKey) { + var bodyBuffer = this.writer + .addInt16(1234) + .addInt16(5678) + .addInt32(processID) + .addInt32(secretKey) + .addCString('').flush(); + + var length = bodyBuffer.length + 4; + + var buffer = new Writer() + .addInt32(length) + .add(bodyBuffer) + .join(); + this.stream.write(buffer); +}; + p.password = function(password) { //0x70 = 'p' this._send(0x70, this.writer.addCString(password)); diff --git a/lib/index.js b/lib/index.js index a454bcbd..d96d44c1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -81,6 +81,16 @@ PG.prototype.connect = function(config, callback) { return pool.acquire(cb); } +// cancel the query runned by the given client +PG.prototype.cancel = function(config, client, query) { + var c = config; + //allow for no config to be passed + if(typeof c === 'function') + c = defaults; + var cancellingClient = new this.Client(c); + cancellingClient.cancel(client, query); +} + module.exports = new PG(Client); //lazy require native module...the native module may not have installed From c98ebb55e211f922ca0334b7d0af719b423053b1 Mon Sep 17 00:00:00 2001 From: Christophe Macabiau Date: Wed, 2 Nov 2011 16:35:09 +0100 Subject: [PATCH 06/11] query cancellation test --- test/integration/client/cancel-query-tests.js | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 test/integration/client/cancel-query-tests.js diff --git a/test/integration/client/cancel-query-tests.js b/test/integration/client/cancel-query-tests.js new file mode 100644 index 00000000..84240ad1 --- /dev/null +++ b/test/integration/client/cancel-query-tests.js @@ -0,0 +1,47 @@ +var helper = require(__dirname+"/test-helper"); +var pg = require(__dirname + '/../../../lib'); + +//before running this test make sure you run the script create-test-tables +test("cancellation of a query", function() { + + var client = helper.client(); + + var qry = client.query("select name from person order by name"); + + client.on('drain', client.end.bind(client)); + + var rows1 = 0, rows2 = 0, rows3 = 0, rows4 = 0; + + var query1 = client.query(qry); + query1.on('row', function(row) { + rows1++; + }); + var query2 = client.query(qry); + query2.on('row', function(row) { + rows2++; + }); + var query3 = client.query(qry); + query3.on('row', function(row) { + rows3++; + }); + var query4 = client.query(qry); + query4.on('row', function(row) { + rows4++; + }); + + pg.cancel(helper.connectionString, client, query1); + pg.cancel(helper.connectionString, client, query2); + pg.cancel(helper.connectionString, client, query4); + + setTimeout(function() { + assert.equal(rows1, 0); + assert.equal(rows2, 0); + assert.equal(rows4, 0); + }, 2000); + + assert.emits(query3, 'end', function() { + test("returned right number of rows", function() { + assert.equal(rows3, 26); + }); + }); +}); From 947b53a0cc0f254f4642a2b7b5aa81d02033d49a Mon Sep 17 00:00:00 2001 From: Christophe Macabiau Date: Wed, 2 Nov 2011 19:16:13 +0100 Subject: [PATCH 07/11] use the correct pg bindings --- test/integration/client/cancel-query-tests.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/integration/client/cancel-query-tests.js b/test/integration/client/cancel-query-tests.js index 84240ad1..36d5710b 100644 --- a/test/integration/client/cancel-query-tests.js +++ b/test/integration/client/cancel-query-tests.js @@ -1,5 +1,4 @@ var helper = require(__dirname+"/test-helper"); -var pg = require(__dirname + '/../../../lib'); //before running this test make sure you run the script create-test-tables test("cancellation of a query", function() { @@ -29,9 +28,9 @@ test("cancellation of a query", function() { rows4++; }); - pg.cancel(helper.connectionString, client, query1); - pg.cancel(helper.connectionString, client, query2); - pg.cancel(helper.connectionString, client, query4); + helper.pg.cancel(helper.connectionString, client, query1); + helper.pg.cancel(helper.connectionString, client, query2); + helper.pg.cancel(helper.connectionString, client, query4); setTimeout(function() { assert.equal(rows1, 0); From fe6d5aeb68e921fc3095127c9d9f2b9b1118712a Mon Sep 17 00:00:00 2001 From: Christophe Macabiau Date: Wed, 2 Nov 2011 19:30:44 +0100 Subject: [PATCH 08/11] query cancellation (libpq native binding) --- lib/native/index.js | 13 +++++++++++-- src/binding.cc | 26 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/native/index.js b/lib/native/index.js index 02d99df9..ae73f841 100644 --- a/lib/native/index.js +++ b/lib/native/index.js @@ -56,6 +56,15 @@ p.query = function(config, values, callback) { return q; } +var nativeCancel = p.cancel; + +p.cancel = function(client, query) { + if (client._activeQuery == query) + this.connect(nativeCancel.bind(client)); + else if (client._queryQueue.indexOf(query) != -1) + client._queryQueue.splice(client._queryQueue.indexOf(query), 1); +}; + p._pulseQueryQueue = function(initialConnection) { if(!this._connected) { return; @@ -94,8 +103,8 @@ p.pauseDrain = function() { }; p.resumeDrain = function() { - if(this._drainPaused > 1) { - this.emit('drain') + if(this._drainPaused > 1) { + this.emit('drain') }; this._drainPaused = 0; }; diff --git a/src/binding.cc b/src/binding.cc index 5a8815d9..8518c561 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -69,6 +69,7 @@ public: NODE_SET_PROTOTYPE_METHOD(t, "_sendQueryWithParams", SendQueryWithParams); NODE_SET_PROTOTYPE_METHOD(t, "_sendPrepare", SendPrepare); NODE_SET_PROTOTYPE_METHOD(t, "_sendQueryPrepared", SendQueryPrepared); + NODE_SET_PROTOTYPE_METHOD(t, "cancel", Cancel); NODE_SET_PROTOTYPE_METHOD(t, "end", End); target->Set(String::NewSymbol("Connection"), t->GetFunction()); @@ -104,6 +105,22 @@ public: return Undefined(); } + //v8 entry point into Connection#cancel + static Handle + Cancel(const Arguments& args) + { + HandleScope scope; + Connection *self = ObjectWrap::Unwrap(args.This()); + + bool success = self->Cancel(); + if(!success) { + self -> EmitLastError(); + self -> DestroyConnection(); + } + + return Undefined(); + } + //v8 entry point into Connection#_sendQuery static Handle SendQuery(const Arguments& args) @@ -267,6 +284,15 @@ protected: return PQsendQueryPrepared(connection_, name, nParams, paramValues, NULL, NULL, 0); } + int Cancel() + { + PGcancel* pgCancel = PQgetCancel(connection_); + char errbuf[256]; + int result = PQcancel(pgCancel, errbuf, 256); + PQfreeCancel(pgCancel); + return result; + } + //flushes socket void Flush() { From 4a7d894c8d1ad4f7e17aad665d435dbb4402c227 Mon Sep 17 00:00:00 2001 From: Chad Stansbury Date: Mon, 7 Nov 2011 16:05:26 -0600 Subject: [PATCH 09/11] Removed (apparently obsolete) require('util') statement from create-test-tables so that the script could run w/o error. --- script/create-test-tables.js | 1 - 1 file changed, 1 deletion(-) diff --git a/script/create-test-tables.js b/script/create-test-tables.js index 98307d39..d8cbc4c6 100644 --- a/script/create-test-tables.js +++ b/script/create-test-tables.js @@ -1,4 +1,3 @@ -var sys = require('utils'); var args = require(__dirname + '/../test/cli'); var pg = require(__dirname + '/../lib'); From 736bac354d714cb8f20c5b31b0a14fff5e8e1065 Mon Sep 17 00:00:00 2001 From: brianc Date: Fri, 11 Nov 2011 00:14:41 -0600 Subject: [PATCH 10/11] update contributors --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2c7bd15a..7c77ecab 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ Many thanks to the following: * [bdunavant](https://github.com/bdunavant) * [tokumine](https://github.com/tokumine) * [shtylman](https://github.com/shtylman) +* [cricri](https://github.com/cricri) ## Documentation From 91afa89d377252b930c8728de71860874b60adad Mon Sep 17 00:00:00 2001 From: brianc Date: Fri, 11 Nov 2011 00:18:37 -0600 Subject: [PATCH 11/11] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4fd73b1c..aa8846f6 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { "name": "pg", - "version": "0.6.5", + "version": "0.6.6", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords" : ["postgres", "pg", "libpq", "postgre", "database", "rdbms"], "homepage": "http://github.com/brianc/node-postgres",