diff --git a/lib/client.js b/lib/client.js index c09d95bd..ae3c3c78 100644 --- a/lib/client.js +++ b/lib/client.js @@ -213,6 +213,52 @@ Client.prototype.cancel = function(client, query) { } }; +// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c +Client.prototype.escapeIdentifier = function(str) { + + var escaped = '"'; + + for(var i = 0; i < str.length; i++) { + var c = str[i]; + if(c === '"') { + escaped += c + c; + } else { + escaped += c; + } + } + + escaped += '"'; + + return escaped; +} + +// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c +Client.prototype.escapeLiteral = function(str) { + + var hasBackslash = false; + var escaped = '\''; + + for(var i = 0; i < str.length; i++) { + var c = str[i]; + if(c === '\'') { + escaped += c + c; + } else if (c === '\\') { + escaped += c + c; + hasBackslash = true; + } else { + escaped += c; + } + } + + escaped += '\''; + + if(hasBackslash === true) { + escaped = ' E' + escaped; + } + + return escaped; +} + Client.prototype._pulseQueryQueue = function() { if(this.readyForQuery===true) { this.activeQuery = this.queryQueue.shift(); diff --git a/src/binding.cc b/src/binding.cc index 9e26b266..ea262d06 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -67,6 +67,8 @@ public: command_symbol = NODE_PSYMBOL("command"); NODE_SET_PROTOTYPE_METHOD(t, "connect", Connect); + NODE_SET_PROTOTYPE_METHOD(t, "escapeIdentifier", EscapeIdentifier); + NODE_SET_PROTOTYPE_METHOD(t, "escapeLiteral", EscapeLiteral); NODE_SET_PROTOTYPE_METHOD(t, "_sendQuery", SendQuery); NODE_SET_PROTOTYPE_METHOD(t, "_sendQueryWithParams", SendQueryWithParams); NODE_SET_PROTOTYPE_METHOD(t, "_sendPrepare", SendPrepare); @@ -130,6 +132,48 @@ public: return Undefined(); } + //v8 entry point into Connection#escapeIdentifier + static Handle + EscapeIdentifier(const Arguments& args) + { + HandleScope scope; + Connection *self = ObjectWrap::Unwrap(args.This()); + + char* inputStr = MallocCString(args[0]); + char* escapedStr = self->EscapeIdentifier(inputStr); + free(inputStr); + + if(escapedStr == NULL) { + THROW(self->GetLastError()); + } + + Local jsStr = String::New(escapedStr, strlen(escapedStr)); + PQfreemem(escapedStr); + + return scope.Close(jsStr); + } + + //v8 entry point into Connection#escapeLiteral + static Handle + EscapeLiteral(const Arguments& args) + { + HandleScope scope; + Connection *self = ObjectWrap::Unwrap(args.This()); + + char* inputStr = MallocCString(args[0]); + char* escapedStr = self->EscapeLiteral(inputStr); + free(inputStr); + + if(escapedStr == NULL) { + THROW(self->GetLastError()); + } + + Local jsStr = String::New(escapedStr, strlen(escapedStr)); + PQfreemem(escapedStr); + + return scope.Close(jsStr); + } + //v8 entry point into Connection#_sendQuery static Handle SendQuery(const Arguments& args) @@ -307,6 +351,18 @@ protected: return args.This(); } + char * EscapeIdentifier(const char *str) + { + TRACE("js::EscapeIdentifier") + return PQescapeIdentifier(connection_, str, strlen(str)); + } + + char * EscapeLiteral(const char *str) + { + TRACE("js::EscapeLiteral") + return PQescapeLiteral(connection_, str, strlen(str)); + } + int Send(const char *queryText) { TRACE("js::Send")