Skip to content

Commit

Permalink
Merge branch 'bind-params' of https://github.com/gurzgri/node-odbc in…
Browse files Browse the repository at this point in the history
…to node-v0.5.x-bind-params
  • Loading branch information
wankdanker committed Oct 26, 2011
2 parents aef5966 + 0a0947d commit 5acc150
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 5 deletions.
45 changes: 45 additions & 0 deletions examples/params.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* This example demonstrates odbc parameter binding.
*
*/

var odbc = require("../odbc.js"),
db = new odbc.Database();



//open a connection to the database
db.open("DSN=myDsnName;UID=myUserName;PWD=mySuperSecretPassword;DATABASE=myAwesomeDatabase;CHARSET=UTF8", function(err)
{

if (err) {
//Something went bad
console.log(err);

//Let's not go any further
return;
}

/*
* A quick example of passing some random parameters
*
*/

db.query("select ? as a, ? as b, ? as c, ? as d, ? as e", [null, 4711, true, -3.14, 'string'], function (error, result, info) {
console.log("some random parameters");
if (error) {console.log(error); return false;}
console.log(result);
});

/*
* Some non-ASCII-characters (note that db.open above is configured to use utf8 encoding)
*
*/

db.query("select ?", ['áäàéêèóöòüßÄÖÜ€'], function (error, result) {
console.log("some non-ASCII characters");
if (error) {console.log(error); return false;}
console.log(result);
});

});
4 changes: 3 additions & 1 deletion odbc.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ Database.prototype.processQueue = function () {
}
};

Database.prototype.query = function(sql, callback) {
Database.prototype.query = function(sql, params, callback) {
var self = this;

if (callback == null) callback = params; // no parameters supplied

if (!self.connected) {
return callback( { message : "Connection not open." }, [], false );
Expand Down
113 changes: 109 additions & 4 deletions src/Database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ int Database::EIO_AfterQuery(eio_req *req) {
tuple->Set(String::New((const char *)columns[i].name), Null());
}
else
{
{
switch (columns[i].type) {
case SQL_NUMERIC :
tuple->Set(String::New((const char *)columns[i].name), Number::New(atof(buf)));
Expand All @@ -391,6 +391,9 @@ int Database::EIO_AfterQuery(eio_req *req) {
case SQL_SMALLINT :
tuple->Set(String::New((const char *)columns[i].name), Number::New(atof(buf)));
break;
case SQL_BIGINT :
tuple->Set(String::New((const char *)columns[i].name), Number::New(atof(buf)));
break;
case SQL_FLOAT :
tuple->Set(String::New((const char *)columns[i].name), Number::New(atof(buf)));
break;
Expand Down Expand Up @@ -492,15 +495,52 @@ int Database::EIO_AfterQuery(eio_req *req) {

void Database::EIO_Query(eio_req *req) {
struct query_request *prep_req = (struct query_request *)(req->data);
Parameter prm;

if(prep_req->dbo->m_hStmt)
{
SQLFreeStmt(prep_req->dbo->m_hStmt, SQL_CLOSE);
SQLAllocStmt(prep_req->dbo->m_hDBC,&prep_req->dbo->m_hStmt );
}

// prepare statement, bind parameters and execute statement
//
SQLRETURN ret = SQLPrepare(prep_req->dbo->m_hStmt, (SQLCHAR *)prep_req->sql, strlen(prep_req->sql));
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
for (int i = 0; i < prep_req->paramCount; i++)
{
prm = prep_req->params[i];

ret = SQLBindParameter(prep_req->dbo->m_hStmt, i + 1, SQL_PARAM_INPUT, prm.c_type, prm.type, prm.size, 0, prm.buffer, prm.buffer_length, &prep_req->params[i].length);
if (ret == SQL_ERROR) {break;}
}

if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
ret = SQLExecute(prep_req->dbo->m_hStmt);
}
}

SQLRETURN ret = SQLExecDirect( prep_req->dbo->m_hStmt,(SQLCHAR *)prep_req->sql, strlen(prep_req->sql) );


// free parameters
//
if (prep_req->paramCount)
{
for (int i = 0; i < prep_req->paramCount; i++)
{
if (prm = prep_req->params[i], prm.buffer != NULL)
{
switch (prm.c_type)
{
case SQL_C_CHAR: free(prm.buffer); break;
case SQL_C_LONG: delete (int64_t *)prm.buffer; break;
case SQL_C_DOUBLE: delete (double *)prm.buffer; break;
case SQL_C_BIT: delete (bool *)prm.buffer; break;
}
}
}
free(prep_req->params);
}

req->result = ret; // this will be checked later in EIO_AfterQuery

}
Expand All @@ -511,6 +551,9 @@ Handle<Value> Database::Query(const Arguments& args) {
REQ_STR_ARG(0, sql);
REQ_FUN_ARG(1, cb);

int paramCount = 0;
Parameter* params;

Database* dbo = ObjectWrap::Unwrap<Database>(args.This());

struct query_request *prep_req = (struct query_request *)
Expand All @@ -521,6 +564,68 @@ Handle<Value> Database::Query(const Arguments& args) {
return ThrowException(Exception::Error(String::New("Could not allocate enough memory")));
}

// populate prep_req->params if parameters were supplied
//
if (args.Length() > 1 && args[1]->IsArray())
{
Local<Array> values = Local<Array>::Cast(args[1]);

prep_req->paramCount = paramCount = values->Length();
prep_req->params = params = new Parameter[paramCount];

for (int i = 0; i < paramCount; i++)
{
Local<Value> value = values->Get(i);

params[i].size = 0;
params[i].length = NULL;
params[i].buffer_length = 0;

if (value->IsString())
{
String::Utf8Value string(value);

params[i].c_type = SQL_C_CHAR;
params[i].type = SQL_VARCHAR;
params[i].length = SQL_NTS;
params[i].buffer = malloc(string.length() + 1);
params[i].buffer_length = string.length() + 1;

strcpy((char*)params[i].buffer, *string);
}
else if (value->IsNull())
{
params[i].c_type = SQL_C_DEFAULT;
params[i].type = SQL_NULL_DATA;
params[i].length = SQL_NULL_DATA;
}
else if (value->IsInt32())
{
int64_t *number = new int64_t(value->IntegerValue());
params[i].c_type = SQL_C_LONG;
params[i].type = SQL_INTEGER;
params[i].buffer = number;
}
else if (value->IsNumber())
{
double *number = new double(value->NumberValue());
params[i].c_type = SQL_C_DOUBLE;
params[i].type = SQL_DECIMAL;
params[i].buffer = number;
}
else if (value->IsBoolean())
{
bool *boolean = new bool(value->BooleanValue());
params[i].c_type = SQL_C_BIT;
params[i].type = SQL_BIT;
params[i].buffer = boolean;
}
}
}
else {
prep_req->paramCount = 0;
}

prep_req->sql = (char *) malloc(sql.length() +1);
prep_req->catalog = NULL;
prep_req->schema = NULL;
Expand Down
11 changes: 11 additions & 0 deletions src/Database.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ struct close_request {
Database *dbo;
};

typedef struct {
SQLSMALLINT c_type;
SQLSMALLINT type;
SQLLEN size;
void *buffer;
SQLLEN buffer_length;
SQLLEN length;
} Parameter;

struct query_request {
Persistent<Function> cb;
Database *dbo;
Expand All @@ -101,6 +110,8 @@ struct query_request {
char *table;
char *type;
char *column;
Parameter *params;
int paramCount;
};

#define REQ_ARGS(N) \
Expand Down

0 comments on commit 5acc150

Please sign in to comment.