Skip to content

Commit 96bea73

Browse files
committed
Use cached short names in place of long prepared statement names
This allows for prepared statement names of any length. In particular it lets one safely use the SQL query itself as the name.
1 parent 8eaa1f0 commit 96bea73

File tree

3 files changed

+43
-9
lines changed

3 files changed

+43
-9
lines changed

lib/connection.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ var Connection = function(config) {
1919
this.parsedStatements = {};
2020
this.writer = new Writer();
2121
this.ssl = config.ssl || false;
22+
this.longNameI = 0;
23+
this.longNameMap = {};
2224
this._ending = false;
2325
this._mode = TEXT_MODE;
2426
this._emitMessage = false;
@@ -189,6 +191,15 @@ Connection.prototype.query = function(text) {
189191
this.stream.write(this.writer.addCString(text).flush(0x51));
190192
};
191193

194+
Connection.prototype.getShortName = function(longName) {
195+
var shortName = this.longNameMap[longName];
196+
if (!shortName) {
197+
shortName = '__node_pg_short_name_' + (++this.longNameI) + '__';
198+
this.longNameMap[longName] = shortName;
199+
}
200+
return shortName;
201+
};
202+
192203
//send parse message
193204
//"more" === true to buffer the message until flush() is called
194205
Connection.prototype.parse = function(query, more) {
@@ -198,12 +209,16 @@ Connection.prototype.parse = function(query, more) {
198209
// types: ['int8', 'bool'] }
199210

200211
//normalize missing query names to allow for null
201-
query.name = query.name || '';
212+
var query_name = query.name || '';
213+
//shorten long (>63 character) names
214+
if (query_name.length > 63) {
215+
query_name = this.getShortName(query_name);
216+
}
202217
//normalize null type array
203218
query.types = query.types || [];
204219
var len = query.types.length;
205220
var buffer = this.writer
206-
.addCString(query.name) //name of query
221+
.addCString(query_name) //name of query
207222
.addCString(query.text) //actual query text
208223
.addInt16(len);
209224
for(var i = 0; i < len; i++) {
@@ -220,7 +235,11 @@ Connection.prototype.bind = function(config, more) {
220235
//normalize config
221236
config = config || {};
222237
config.portal = config.portal || '';
223-
config.statement = config.statement || '';
238+
var config_statement = config.statement || '';
239+
//shorten long (>63 character) names
240+
if (config_statement.length > 63) {
241+
config_statement = this.getShortName(config_statement);
242+
}
224243
config.binary = config.binary || false;
225244
var values = config.values || [];
226245
var len = values.length;
@@ -229,7 +248,7 @@ Connection.prototype.bind = function(config, more) {
229248
useBinary |= values[j] instanceof Buffer;
230249
var buffer = this.writer
231250
.addCString(config.portal)
232-
.addCString(config.statement);
251+
.addCString(config_statement);
233252
if (!useBinary)
234253
buffer.addInt16(0);
235254
else {

lib/native/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ var Client = module.exports = function(config) {
3636

3737
//a hash to hold named queries
3838
this.namedQueries = {};
39+
this.longNameI = 0;
40+
this.longNameMap = {};
3941
};
4042

4143
util.inherits(Client, EventEmitter);
@@ -191,3 +193,12 @@ Client.prototype.setTypeParser = function(oid, format, parseFn) {
191193
Client.prototype.getTypeParser = function(oid, format) {
192194
return this._types.getTypeParser(oid, format);
193195
};
196+
197+
Client.prototype.getShortName = function(longName) {
198+
var shortName = this.longNameMap[longName];
199+
if (!shortName) {
200+
shortName = '__node_pg_native_short_name_' + (++this.longNameI) + '__';
201+
this.longNameMap[longName] = shortName;
202+
}
203+
return shortName;
204+
};

lib/native/query.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,17 +86,21 @@ NativeQuery.prototype.submit = function(client) {
8686
//named query
8787
if(this.name) {
8888
var values = (this.values||[]).map(utils.prepareValue);
89+
var this_name = this.name;
90+
if(this_name.length > 63) {
91+
this_name = client.getShortName(this_name);
92+
}
8993

9094
//check if the client has already executed this named query
9195
//if so...just execute it again - skip the planning phase
92-
if(client.namedQueries[this.name]) {
93-
return this.native.execute(this.name, values, after);
96+
if(client.namedQueries[this_name]) {
97+
return this.native.execute(this_name, values, after);
9498
}
9599
//plan the named query the first time, then execute it
96-
return this.native.prepare(this.name, this.text, values.length, function(err) {
100+
return this.native.prepare(this_name, this.text, values.length, function(err) {
97101
if(err) return after(err);
98-
client.namedQueries[self.name] = true;
99-
return self.native.execute(self.name, values, after);
102+
client.namedQueries[this_name] = true;
103+
return self.native.execute(this_name, values, after);
100104
});
101105
}
102106
else if(this.values) {

0 commit comments

Comments
 (0)