Skip to content

Commit a99f336

Browse files
author
Aurynn Shaw
committed
Adding support for INSERT...RETURNING
Additional support for NoData queries. They should now run correctly and not crash the driver. TODO: Provide a null result set and a TX object that knows how many rows were modified (if any) for insert, etc. commands.
1 parent 7abae81 commit a99f336

File tree

3 files changed

+109
-64
lines changed

3 files changed

+109
-64
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ All code is available under the terms of the MIT license, unless otherwise noted
1111

1212
(c) 2010, Tim Caswell, Aurynn Shaw.
1313

14+
Bugs can be reported @ https://public.commandprompt.com/projects/postgres-js
15+
1416
## Example use
1517

1618
var sys = require("sys");

demo.js

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,57 @@ var sys = require("sys");
22
var pg = require("./lib/postgres-pure");
33
pg.DEBUG=0;
44

5-
var db = new pg.connect("pgsql://test:12345@localhost:5432/template1");
6-
db.query("SELECT 1::int as foobar;", function (rs, tx) {
7-
sys.puts(sys.inspect(rs));
8-
tx.query("SELECT 2::int as foobartwo", function (rs) {
9-
sys.puts(sys.inspect(rs));
10-
});
11-
// db.close();
12-
});
5+
var db = new pg.connect("pgsql://test:12345@localhost:5432/pdxpugtest");
6+
// db.query("explain analyze select * from pg_class ;", function (rs, tx) {
7+
// sys.puts(sys.inspect(rs));
8+
// // tx.query("SELECT 2::int as querytest2", function (rs) {
9+
// // sys.puts(sys.inspect(rs));
10+
// // });
11+
// });
1312

14-
db.prepare("SELECT ?::int AS foobar", function (sth, tx) {
15-
sth.execute(1, function (rs) {
16-
sys.puts(sys.inspect(rs));
17-
});
18-
sth.execute(2, function (rs) {
19-
sys.puts(sys.inspect(rs));
13+
db.prepare("INSERT INTO pdxpug (id) VALUES (?) RETURNING id", function (sth) {
14+
sth.execute(1, function(rs) {
15+
if (rs === undefined) {
16+
console.log("No data.");
17+
}
18+
else {
19+
console.log(sys.inspect(rs));
20+
}
2021

2122
});
22-
tx.prepare("SELECT ?::int AS cheese", function (sth) {
23-
sth.execute(3, function (rs) {
24-
sys.puts(sys.inspect(rs));
25-
}) ;
26-
});
27-
// db.close();
2823
});
2924

30-
db.transaction(function (tx) {
31-
// tx.begin();
32-
tx.query("SELECT ?::int AS txtest1", 1, function (rs) {
33-
sys.puts(sys.inspect(rs));
34-
});
35-
tx.prepare("SELECT ?::int AS txtest2", function (sth) {
36-
sth.execute(2, function (rs) {
37-
sys.puts(sys.inspect(rs));
38-
});
39-
});
40-
// tx.commit();
41-
});
42-
db.close();
25+
// db.prepare().on("some_event");
26+
27+
// db.prepare("SELECT ?::int AS preparetest", function (sth, tx) {
28+
// sth.execute(1, function (rs) {
29+
// sys.puts(sys.inspect(rs));
30+
// });
31+
// sth.execute(2, function (rs) {
32+
// sys.puts(sys.inspect(rs));
33+
//
34+
// });
35+
// // tx.prepare("SELECT ?::int AS preparetest2", function (sth) {
36+
// // sth.execute(3, function (rs) {
37+
// // sys.puts(sys.inspect(rs));
38+
// // }) ;
39+
// // });
40+
// });
41+
42+
// db.transaction(function (tx) {
43+
// // tx.begin();
44+
// tx.query("SELECT ?::int AS txtest1", 1, function (rs) {
45+
// sys.puts(sys.inspect(rs));
46+
// });
47+
// tx.prepare("SELECT ?::int AS txtest2", function (sth) {
48+
// sth.execute(2, function (rs) {
49+
// sys.puts(sys.inspect(rs));
50+
// });
51+
// });
52+
// // tx.commit();
53+
// });
54+
db.close();
55+
56+
// db.prepare(query, function (sth, tx) {
57+
// sth.execute(args, callback, errback);
58+
// })

lib/postgres-pure.js

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -331,12 +331,22 @@ function message () {
331331
}
332332
return false;
333333
}
334+
this.on("Error", function (err) {
335+
if (errback !== null && errback !== undefined) {
336+
errback(err);
337+
}
338+
else {
339+
// We don't have an error handler? Odd..
340+
// Pass it up to our connection/transaction.
341+
conn.emit("Error", err);
342+
}
343+
});
334344
}
335345

336346
message.prototype = new process.EventEmitter;
337347
// message.prototype.constructor = message;
338348

339-
function Query(sql, callback) {
349+
function Query(sql, callback, errback) {
340350
message.call(this);
341351
this.sql = sql;
342352
var q = this;
@@ -358,18 +368,18 @@ function Query(sql, callback) {
358368
// args: []
359369
// }
360370
]);
361-
q.addListener("newRow", function (row) {
371+
q.on("newRow", function (row) {
362372
q.results.push(row);
363373
});
364-
q.addListener("Complete", function (data) {
374+
q.on("Complete", function (data) {
365375
if (exports.DEBUG > 2) {
366376
sys.debug("Callback: " + callback);
367377
}
368378

369379
callback(q.results);
370380
});
371381
q.toString = function () { return "Query: " + q.length};
372-
q.addListener("RowDescription", function (desc) {
382+
q.on("RowDescription", function (desc) {
373383
q.row_description = desc;
374384
if (exports.DEBUG > 2) {
375385
sys.debug("Caught RowDescription message.");
@@ -418,7 +428,7 @@ function Prepared(sql, conn /*, use_named */) {
418428

419429
self.setMessages(arr);
420430

421-
self.addListener("ParseComplete", function () {
431+
self.on("ParseComplete", function () {
422432
// Execute can now be run successfully.
423433
// Until this point, we can't assume that there's a matching query.
424434
// Anyway, we now run a DESCRIBE operation, and store the row
@@ -441,9 +451,6 @@ function Prepared(sql, conn /*, use_named */) {
441451
self.parameters = desc;
442452
});
443453

444-
self.on("NoData", function () {
445-
self.noData = true;
446-
})
447454
self.on("newRow", function (row) {
448455
currExec.emit("newRow", row);
449456
});
@@ -473,6 +480,12 @@ function Prepared(sql, conn /*, use_named */) {
473480
}
474481
});
475482

483+
self.on("NoData", function () {
484+
if (currExec !== null) {
485+
currExec.noData = true;
486+
}
487+
});
488+
476489
self.on("BindComplete", function () {
477490
if (currExec != null) {
478491
currExec.emit("BindComplete");
@@ -574,6 +587,7 @@ function Prepared(sql, conn /*, use_named */) {
574587
if (exports.DEBUG > 0) {
575588
sys.debug("Results length " + eP.results.length);
576589
}
590+
sys.debug("noData is: "+eP.noData);
577591
if (eP.results.length > 0 && eP.bound) {
578592
if (exports.DEBUG > 0) {
579593
sys.debug("Execute Complete: Calling with results");
@@ -595,6 +609,7 @@ function Prepared(sql, conn /*, use_named */) {
595609
eP.bound = true;
596610
});
597611
eP.on("NoData", function () {
612+
598613
eP.noData = true;
599614
});
600615
eP.on("newRow", function (row) {
@@ -605,6 +620,9 @@ function Prepared(sql, conn /*, use_named */) {
605620
}
606621
eB.push(eP);
607622
}
623+
self.on("Error", function (err) {
624+
625+
});
608626
}
609627
Prepared.prototype = new message();
610628
Prepared.prototype.constructor = Prepared;
@@ -754,34 +772,43 @@ function Connection(args) {
754772
}
755773

756774
// Set up tcp client
757-
connection.addListener("connect", function () {
775+
connection.on("connect", function () {
758776
sendMessage('StartupMessage', [{user: args.username, database: args.database}]);
759777
});
760-
connection.addListener("data", function (data) {
778+
connection.on("data", function (data) {
761779
if (exports.DEBUG > 2) {
762780
sys.debug("<-" + data.inspect());
763781
}
764782
queue.push(data);
765783
checkInput();
766784
});
767-
connection.addListener("end", function (data) {
785+
connection.on("end", function (data) {
768786
connection.end();
769787
});
770-
connection.addListener("disconnect", function (had_error) {
788+
connection.on("disconnect", function (had_error) {
771789
if (had_error) {
772790
sys.debug("CONNECTION DIED WITH ERROR");
773791
}
774792
});
775793

776794
// Set up callbacks to automatically do the login and other logic
777-
events.addListener('AuthenticationMD5Password', function (salt) {
795+
events.on('AuthenticationMD5Password', function (salt) {
778796
var result = "md5" + md5(md5(args.password + args.username) + salt.toString("binary"));
779797
sendMessage('PasswordMessage', [result]);
780798
});
781-
events.addListener('AuthenticationCleartextPassword', function () {
799+
events.on('AuthenticationCleartextPassword', function () {
782800
sendMessage('PasswordMessage', [args.password]);
783801
});
784-
events.addListener('ErrorResponse', function (e) {
802+
803+
/*
804+
Errors shuld be handled at the TX layer.
805+
This allows for a given TX set (which contains 1..n message sets) to
806+
catch and gracefully recover from an error state, and not attempt to
807+
continue to slam messages onto the wire when there isn't an ability to
808+
do so.
809+
*/
810+
811+
events.on('ErrorResponse', function (e) {
785812
conn.emit('error', e.S + ": " + e.M);
786813
if (e.S === 'FATAL') {
787814
connection.end();
@@ -863,21 +890,13 @@ function Connection(args) {
863890
readyState = false;
864891
sendMessage.apply(conn, [msg.type, msg.args]);
865892
}
866-
// else {
867-
// sys.debug("getting next query, nM");
868-
// events.emit("nextQuery");
869-
// }
870893
if (exports.DEBUG > 2){
871894
sys.debug("waiting for RFQ");
872895
}
873896
}
874-
// else {
875-
// // wait
876-
//
877-
// }
878897
});
879898

880-
events.addListener("nextQuery", function () {
899+
events.on("nextQuery", function () {
881900
if (exports.DEBUG > 0) {
882901
sys.debug("got nextQuery");
883902
}
@@ -936,7 +955,7 @@ function Connection(args) {
936955

937956

938957
// This should always be caught by the current query.
939-
events.addListener("RowDescription", function (data) {
958+
events.on("RowDescription", function (data) {
940959
row_description = data;
941960
results = [];
942961
});
@@ -945,7 +964,7 @@ function Connection(args) {
945964
// Data row is handled by the connection for the time
946965
// being, even though we should be looking at handling it in the
947966
// query object, where the RowDescription lives.
948-
events.addListener("DataRow", function (data) {
967+
events.on("DataRow", function (data) {
949968
var row, i, l, description, value;
950969
row = {};
951970
l = data.length;
@@ -982,7 +1001,7 @@ function Connection(args) {
9821001
});
9831002

9841003

985-
events.addListener('CommandComplete', function (data, results) {
1004+
events.on('CommandComplete', function (data, results) {
9861005
if (results != null && results.length > 0) {
9871006
// To allow for insert..returning
9881007
current_query.emit("Complete", results, data);
@@ -1116,7 +1135,7 @@ function Connection(args) {
11161135
11171136
Easy, and very nifty.
11181137
*/
1119-
conn.addListener('newListener', function (e, listener) {
1138+
conn.on('newListener', function (e, listener) {
11201139
if (e === 'String') {
11211140
// It's a string.
11221141
if (!(e in ['newListener'])) {
@@ -1162,7 +1181,7 @@ function Transaction (connection /*, params */) {
11621181
var wrap = function (func) {
11631182
return (function () {
11641183
if (exports.DEBUG > 3) {
1165-
sys.debug(func);
1184+
sys.debug("Wrapping function: " + func);
11661185
}
11671186
func.apply(func, arguments);
11681187
});
@@ -1226,7 +1245,7 @@ function Transaction (connection /*, params */) {
12261245
events.emit("queryAdded");
12271246
wrap(callback)(p, thisp);
12281247
if (exports.DEBUG == 4) {
1229-
sys.debug("Prepared messages: " + sys.inspect(messages));
1248+
sys.debug("Prepared messages: " + sys.inspect(messages, 4));
12301249
}
12311250
// conn.emit.call(conn, "queryAdded");
12321251
}
@@ -1270,7 +1289,7 @@ function Transaction (connection /*, params */) {
12701289
messages.push(msg);
12711290
this.emit("queryAdded");
12721291
if (exports.DEBUG > 0) {
1273-
sys.debug("Added message of " + msg + " to TX");
1292+
sys.debug("Added message of " + sys.inspect(msg) + " to TX");
12741293
}
12751294
}
12761295
else {
@@ -1291,6 +1310,14 @@ function Transaction (connection /*, params */) {
12911310
}
12921311
return null;
12931312
}
1313+
this.on("Error", function (e) {
1314+
/* Global transaction error response.
1315+
This should push a SYNC message into the buffer immediately,
1316+
as well as a ROLLBACK command.
1317+
This will free up the wire from whatever the last message set was,
1318+
and allow for a given piece of code to recover gracefully.
1319+
*/
1320+
});
12941321
}
12951322

12961323
Transaction.prototype = new process.EventEmitter();

0 commit comments

Comments
 (0)