simple bound queries

This commit is contained in:
brianc 2010-10-23 16:21:11 -05:00
parent 5650b02993
commit 057df36e2a
7 changed files with 137 additions and 27 deletions

View File

@ -147,6 +147,18 @@ p.bind = function(config) {
this.send('B', buffer.join());
};
p.execute = function(name, rows) {
this.send('E',new BufferList().addCString(name||'').addInt32(rows||0).join());
};
p.flush = function() {
this.send('H',Buffer(0));
}
p.sync = function() {
this.send('S', Buffer(0));
};
p.pulseQueryQueue = function(ready) {
if(!this.readyForQuery) {
return;
@ -255,11 +267,13 @@ var messageNames = {
Z: 'readyForQuery',
T: 'rowDescription',
D: 'dataRow',
E: 'error'
E: 'error',
1: 'parseComplete',
2: 'bindComplete'
};
p.parseMessage = function() {
var remaining = this.buffer.length - this.offset - 1;
var remaining = this.buffer.length - (this.offset);
if(remaining < 5) {
//cannot read id + length without at least 5 bytes
//just abort the read now
@ -276,7 +290,7 @@ p.parseMessage = function() {
length: this.parseInt32()
};
if(remaining < message.length) {
if(remaining <= message.length) {
this.lastBuffer = this.buffer;
//rewind the last 5 bytes we read
this.lastOffset = this.offset-5;
@ -365,6 +379,7 @@ p.parseD = function(msg) {
return msg;
};
//parses error
p.parseE = function(msg) {
var fields = {};
var fieldType = this.readString(1);
@ -387,6 +402,16 @@ p.parseE = function(msg) {
return msg;
};
//parses parseComplete
p.parse1 = function(msg) {
return msg;
};
//parses bindComplete
p.parse2 = function(msg) {
return msg;
};
p.readChar = function() {
return Buffer([this.buffer[this.offset++]]).toString(this.encoding);
};

View File

@ -0,0 +1,34 @@
var helper = require(__dirname + '/test-helper');
http://developer.postgresql.org/pgdocs/postgres/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
helper.connect(function(con) {
con.parse({
text: 'select * from ids'
});
con.flush();
con.once('parseComplete', function() {
con.bind();
con.flush();
});
con.once('bindComplete', function() {
con.execute();
con.flush();
});
con.on('dataRow', function(msg) {
sys.debug("got row from pepared query");
});
con.on('commandComplete', function() {
con.sync();
});
con.on('readyForQuery', function() {
con.end();
});
});

View File

@ -1,27 +1,24 @@
var helper = require(__dirname+"/test-helper");
var assert = require('assert');
var client = helper.client();
var rows = [];
//testing the low level 1-1 mapping api of client to postgres messages
//it's cumbersome to use the api this way
client.query('create temporary table bang(id integer)');
client.once('commandComplete', function() {
client.query('insert into bang(id) values(1)');
client.once('commandComplete', function() {
client.query('select * from bang');
client.on('dataRow', function(row) {
rows.push(row.fields);
});
client.on('readyForQuery',function() {
client.end();
});
helper.connect(function(con) {
con.query('select * from ids');
con.on('dataRow', function(msg) {
rows.push(msg.fields);
});
con.once('readyForQuery', function() {
con.end();
});
});
process.on('exit', function() {
assert.equal(rows.length, 1);
assert.equal(rows.length, 2);
assert.equal(rows[0].length, 1);
assert.equal(rows[0], 1);
assert.equal(rows[0] [0], 1);
assert.equal(rows[1] [0], 2);
});

View File

@ -2,15 +2,23 @@ Client = require(__dirname+'/../../lib/client');
sys = require('sys');
//creates a configured, connecting client
var client = function() {
var client = new Client({
var connect = function(onReady) {
var con = new Client({
database: 'postgres',
user: 'brian'
});
client.connect();
return client;
con.connect();
con.once('readyForQuery', function() {
con.query('create temporary 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() {
onReady(con);
});
});
});
};
module.exports = {
client: client
connect: connect
};

View File

@ -9,7 +9,8 @@ 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 addRow = function(bufferList, name, offset) {
return bufferList.addCString(name) //field name
@ -294,6 +295,20 @@ test('Client', function() {
});
});
});
test('parses parse complete command', function() {
testForMessage(parseCompleteBuffer, {
id: '1',
name: 'parseComplete'
});
});
test('parses bind complete command', function() {
testForMessage(bindCompleteBuffer, {
id: '2',
name: 'bindComplete'
});
});
});
//since the data message on a stream can randomly divide the incomming

View File

@ -40,9 +40,9 @@ test('prepared queries', function() {
//server raises parse complete message
test('sends bind message', function() {
test('binding to unnamed prepared statement with no values', function() {
client.bind();
assert.length(client.stream.packets, 1);
var packet = client.stream.packets.pop();
@ -57,8 +57,35 @@ test('prepared queries', function() {
});
test('recieves rows', function() {
return false;
test('sends execute message', function() {
test('executing an unnamed portal with no row limit', function() {
client.execute();
assert.length(client.stream.packets, 1);
var packet = client.stream.packets.pop();
var expectedBuffer = new BufferList()
.addCString('')
.addInt32(0)
.join(true,'E');
assert.equalBuffers(packet, expectedBuffer);
});
});
test('sends flush command', function() {
client.flush();
assert.length(client.stream.packets, 1);
var packet = client.stream.packets.pop();
var expected = new BufferList().join(true, 'H');
assert.equalBuffers(packet, expected);
});
test('sends sync command', function() {
client.sync();
assert.length(client.stream.packets, 1);
var packet = client.stream.packets.pop();
var expected = new BufferList().join(true,'S');
assert.equalBuffers(packet, expected);
});
});

View File

@ -81,4 +81,8 @@ buffers.parseComplete = function() {
return new BufferList().join(true, '1');
};
buffers.bindComplete = function() {
return new BufferList().join(true, '2');
};
module.exports = buffers;