Skip to content

Commit da8026d

Browse files
committed
prepared statements moved forward a good deal
1 parent 9d2c1e3 commit da8026d

File tree

4 files changed

+205
-42
lines changed

4 files changed

+205
-42
lines changed

lib/client.js

+20-9
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ p.pulseQueryQueue = function() {
7777

7878
p.query = function(config) {
7979
//can take in strings or config objects
80-
var query = new Query(config.text ? config : { text: config });
80+
var query = new Query((config.text || config.name) ? config : { text: config });
8181
this.queryQueue.push(query);
8282
this.pulseQueryQueue();
8383
return query;
@@ -102,6 +102,7 @@ var Query = function(config) {
102102
this.rowDescription = null;
103103
EventEmitter.call(this);
104104
};
105+
105106
sys.inherits(Query, EventEmitter);
106107
var p = Query.prototype;
107108

@@ -132,16 +133,13 @@ p.submit = function(connection) {
132133
});
133134
};
134135

136+
p.hasBeenParsed = function(connection) {
137+
return this.name && connection.parsedStatements[this.name];
138+
};
139+
135140
p.prepare = function(connection) {
136141
var self = this;
137142

138-
connection.parse({
139-
text: self.text,
140-
name: self.name,
141-
types: self.types
142-
});
143-
connection.flush();
144-
145143
var onParseComplete = function() {
146144
connection.bind({
147145
portal: self.name,
@@ -151,7 +149,20 @@ p.prepare = function(connection) {
151149
connection.flush();
152150
};
153151

154-
connection.once('parseComplete', onParseComplete);
152+
153+
if(this.hasBeenParsed(connection)) {
154+
onParseComplete();
155+
} else {
156+
connection.parsedStatements[this.name] = true;
157+
connection.parse({
158+
text: self.text,
159+
name: self.name,
160+
types: self.types
161+
});
162+
connection.flush();
163+
connection.once('parseComplete', onParseComplete);
164+
}
165+
155166

156167
var onBindComplete = function() {
157168
connection.describe({

lib/connection.js

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var Connection = function(config) {
1515
this.buffer = null;
1616
this.offset = null;
1717
this.encoding = 'utf8';
18+
this.parsedStatements = {};
1819
};
1920

2021
sys.inherits(Connection, EventEmitter);

test/integration/client/prepared-statement-tests.js

+136-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
var helper = require(__dirname +'/test-helper');
22

3-
test("simple prepared statement", function(){
3+
test("simple, unnamed prepared statement", function(){
44
var client = helper.client();
55

66
var query = client.query({
@@ -16,3 +16,138 @@ test("simple prepared statement", function(){
1616
client.end();
1717
});
1818
});
19+
20+
test("named prepared statement", function() {
21+
22+
var client = helper.client();
23+
var queryName = "user by age and like name";
24+
var query = client.query({
25+
text: 'select name from person where age <= $1 and name LIKE $2',
26+
values: [20, 'Bri%'],
27+
name: queryName
28+
});
29+
30+
var parseCount = 0;
31+
client.connection.on('parseComplete', function() {
32+
parseCount++;
33+
});
34+
35+
assert.raises(query, 'row', function(row) {
36+
assert.equal(row.fields[0], 'Brian');
37+
});
38+
39+
assert.raises(query, 'end', function() {
40+
test("query was parsed", function() {
41+
assert.equal(parseCount, 1);
42+
});
43+
44+
test("with same name & text", function() {
45+
var cachedQuery = client.query({
46+
text: 'select name from person where age <= $1 and name LIKE $2',
47+
name: queryName,
48+
values: [10, 'A%']
49+
});
50+
51+
assert.raises(cachedQuery, 'row', function(row) {
52+
assert.equal(row.fields[0], 'Aaron');
53+
});
54+
55+
assert.raises(cachedQuery, 'end', function() {
56+
test("query was only parsed one time", function() {
57+
assert.equal(parseCount, 1, "Should not have reparsed query");
58+
});
59+
});
60+
});
61+
62+
test("with same name, but the query text not even there batman!", function() {
63+
var q = client.query({
64+
name: queryName,
65+
values: [30, '%n%']
66+
});
67+
68+
test("gets first row", function() {
69+
70+
assert.raises(q, 'row', function(row) {
71+
assert.equal(row.fields[0], "Aaron");
72+
73+
test("gets second row", function() {
74+
75+
assert.raises(q, 'row', function(row) {
76+
assert.equal(row.fields[0], "Brian");
77+
});
78+
});
79+
80+
});
81+
});
82+
83+
test("only parsed query once total", function() {
84+
assert.equal(parseCount, 1);
85+
q.on('end', function() {
86+
client.end();
87+
});
88+
});
89+
90+
});
91+
});
92+
93+
});
94+
95+
test("prepared statements on different clients", function() {
96+
var statementName = "differ";
97+
var statement1 = "select count(*) from person";
98+
var statement2 = "select count(*) from person where age < $1";
99+
100+
var client1Finished = false;
101+
var client2Finished = false;
102+
103+
var client1 = helper.client();
104+
105+
var client2 = helper.client();
106+
107+
test("client 1 execution", function() {
108+
109+
var query = client1.query({
110+
name: statementName,
111+
text: statement1
112+
});
113+
test('gets right data back', function() {
114+
assert.raises(query, 'row', function(row) {
115+
assert.equal(row.fields[0], 26);
116+
});
117+
});
118+
119+
assert.raises(query, 'end', function() {
120+
if(client2Finished) {
121+
client1.end();
122+
client2.end();
123+
} else {
124+
client1Finished = true;
125+
}
126+
});
127+
128+
});
129+
130+
test('client 2 execution', function() {
131+
var query = client2.query({
132+
name: statementName,
133+
text: statement2,
134+
values: [11]
135+
});
136+
137+
test('gets right data', function() {
138+
assert.raises(query, 'row', function(row) {
139+
assert.equal(row.fields[0], 1);
140+
});
141+
});
142+
143+
assert.raises(query, 'end', function() {
144+
if(client1Finished) {
145+
client1.end();
146+
client2.end();
147+
} else {
148+
client2Finished = true;
149+
}
150+
});
151+
});
152+
153+
});

test/unit/client/prepared-statement-tests.js

+48-32
Original file line numberDiff line numberDiff line change
@@ -3,68 +3,84 @@ var helper = require(__dirname + '/test-helper');
33
var client = helper.client();
44
var con = client.connection;
55
var parseArg = null;
6-
con.parse = function(query) {
7-
parseArg = query;
6+
con.parse = function(arg) {
7+
parseArg = arg;
8+
process.nextTick(function() {
9+
con.emit('parseComplete');
10+
});
811
};
912

1013
var bindArg = null;
1114
con.bind = function(arg) {
1215
bindArg = arg;
13-
this.emit('bindComplete');
16+
process.nextTick(function(){
17+
con.emit('bindComplete');
18+
});
1419
};
1520

1621
var executeArg = null;
1722
con.execute = function(arg) {
1823
executeArg = arg;
19-
this.emit('rowData',{ fields: [] });
20-
this.emit('commandComplete');
24+
process.nextTick(function() {
25+
con.emit('rowData',{ fields: [] });
26+
con.emit('commandComplete');
27+
});
2128
};
2229

2330
var describeArg = null;
2431
con.describe = function(arg) {
2532
describeArg = arg;
26-
this.emit('rowDescription', { fields: [] });
33+
process.nextTick(function() {
34+
con.emit('rowDescription', { fields: [] });
35+
});
2736
};
2837

29-
var syncCalled = true;
38+
var syncCalled = false;
39+
con.flush = function() {
40+
};
3041
con.sync = function() {
31-
syncCalled = false;
32-
this.emit('readyForQuery')
42+
syncCalled = true;
43+
process.nextTick(function() {
44+
con.emit('readyForQuery');
45+
});
3346
};
3447

3548
test('bound command', function() {
3649
test('simple, unnamed bound command', function() {
37-
return false;
50+
assert.ok(client.connection.emit('readyForQuery'));
51+
3852
var query = client.query({
3953
text: 'select * where name = $1',
40-
parameters: ['hi']
54+
values: ['hi']
4155
});
4256

43-
test('parse argument', function() {
44-
assert.equal(parseArg.name, null);
45-
assert.equal(parseArg.text, 'select * where name = $1');
46-
assert.equal(parseArg.types, null);
47-
});
57+
assert.raises(query,'end', function() {
58+
test('parse argument', function() {
59+
assert.equal(parseArg.name, null);
60+
assert.equal(parseArg.text, 'select * where name = $1');
61+
assert.equal(parseArg.types, null);
62+
});
4863

49-
test('bind argument', function() {
50-
assert.equal(bindArg.statement, null);
51-
assert.equal(bindArg.portal, null);
52-
assert.length(bindArg.values, 1);
53-
assert.equal(bindArg.values[0], 'hi')
54-
});
64+
test('bind argument', function() {
65+
assert.equal(bindArg.statement, null);
66+
assert.equal(bindArg.portal, null);
67+
assert.length(bindArg.values, 1);
68+
assert.equal(bindArg.values[0], 'hi')
69+
});
5570

56-
test('describe argument', function() {
57-
assert.equal(describeArg, null);
58-
});
71+
test('describe argument', function() {
72+
assert.equal(describeArg.type, 'P');
73+
assert.equal(describeArg.name, "");
74+
});
5975

60-
test('execute argument', function() {
61-
assert.equal(executeArg.portal, null);
62-
assert.equal(executeArg.rows, null);
63-
});
76+
test('execute argument', function() {
77+
assert.equal(executeArg.portal, null);
78+
assert.equal(executeArg.rows, null);
79+
});
6480

65-
test('sync called', function() {
66-
assert.ok(syncCalled);
81+
test('sync called', function() {
82+
assert.ok(syncCalled);
83+
});
6784
});
68-
6985
});
7086
});

0 commit comments

Comments
 (0)