Skip to content

Commit

Permalink
Add statement#bindObject to bind placeholders using an object.
Browse files Browse the repository at this point in the history
  • Loading branch information
orlandov committed Jul 13, 2010
1 parent 8df79ce commit 9fae3ab
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 124 deletions.
11 changes: 6 additions & 5 deletions README.md
Expand Up @@ -60,7 +60,7 @@ from the API have been made to improve performance.


db.open("lilponies.db", function () { db.open("lilponies.db", function () {
var colour = 'pink'; var colour = 'pink';
var sql = 'SELECT name FROM ponies WHERE hair_colour = ? and gemstones = ?'; var sql = 'SELECT name FROM ponies WHERE hair_colour = $hair_colour and gemstones = ?';


var ponies = []; var ponies = [];


Expand All @@ -74,13 +74,14 @@ from the API have been made to improve performance.
db.prepare(sql, function (error, statement) { db.prepare(sql, function (error, statement) {
if (error) throw error; if (error) throw error;


// fill in the placeholders // Fill in the placeholders
// Could also have used: // Could also have used:
// statement.bind($index, $value, function () { ... }); // statement.bind(position, value, function () { ... });
statement.bindArray('pink', 4], function () { // statement.bindObject({ $hair_colour: 'pink' }, function () {});
statement.bindArray(['pink', 4], function () {


// call step once per row result // call step once per row result
statement.step(function (row) { statement.step(function (error, row) {
if (!row) { if (!row) {
// end of rows // end of rows
} }
Expand Down
213 changes: 99 additions & 114 deletions src/statement.cc
Expand Up @@ -33,7 +33,9 @@ void Statement::Init(v8::Handle<Object> target) {
constructor_template->SetClassName(String::NewSymbol("Statement")); constructor_template->SetClassName(String::NewSymbol("Statement"));


NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind); NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind);
NODE_SET_PROTOTYPE_METHOD(t, "bindObject", BindObject);
NODE_SET_PROTOTYPE_METHOD(t, "bindArray", BindArray); NODE_SET_PROTOTYPE_METHOD(t, "bindArray", BindArray);

NODE_SET_PROTOTYPE_METHOD(t, "finalize", Finalize); NODE_SET_PROTOTYPE_METHOD(t, "finalize", Finalize);
NODE_SET_PROTOTYPE_METHOD(t, "reset", Reset); NODE_SET_PROTOTYPE_METHOD(t, "reset", Reset);
NODE_SET_PROTOTYPE_METHOD(t, "clearBindings", ClearBindings); NODE_SET_PROTOTYPE_METHOD(t, "clearBindings", ClearBindings);
Expand Down Expand Up @@ -86,42 +88,6 @@ int Statement::EIO_AfterBindArray(eio_req *req) {
return 0; return 0;
} }


int Statement::EIO_AfterBind(eio_req *req) {
ev_unref(EV_DEFAULT_UC);

HandleScope scope;
struct bind_request *bind_req = (struct bind_request *)(req->data);

Local<Value> argv[1];
bool err = false;
if (req->result) {
err = true;
argv[0] = Exception::Error(String::New("Error binding parameter"));
}

TryCatch try_catch;

bind_req->cb->Call(Context::GetCurrent()->Global(), err ? 1 : 0, argv);

if (try_catch.HasCaught()) {
FatalException(try_catch);
}

bind_req->cb.Dispose();

struct bind_pair *pair = bind_req->pairs;

for (size_t i = 0; i < bind_req->len; i++, pair++) {
free(pair->key);
free(pair->value);
}

free(bind_req->pairs);
free(bind_req);

return 0;
}

int Statement::EIO_BindArray(eio_req *req) { int Statement::EIO_BindArray(eio_req *req) {
struct bind_request *bind_req = (struct bind_request *)(req->data); struct bind_request *bind_req = (struct bind_request *)(req->data);
Statement *sto = bind_req->sto; Statement *sto = bind_req->sto;
Expand Down Expand Up @@ -181,75 +147,82 @@ int Statement::EIO_BindArray(eio_req *req) {
return 0; return 0;
} }


int Statement::EIO_Bind(eio_req *req) { Handle<Value> Statement::BindObject(const Arguments& args) {
struct bind_request *bind_req = (struct bind_request *)(req->data); HandleScope scope;
Statement *sto = bind_req->sto; Statement* sto = ObjectWrap::Unwrap<Statement>(args.This());


int index(0); REQ_ARGS(2);
switch(bind_req->pairs->key_type) { REQ_FUN_ARG(1, cb);
case KEY_INT:
index = *(int*)(bind_req->pairs->key);
break;


case KEY_STRING: if (! args[0]->IsObject())
index = sqlite3_bind_parameter_index(sto->stmt_, return ThrowException(Exception::TypeError(
(char*)(bind_req->pairs->key)); String::New("First argument must be an Array.")));
break; Local<Object> obj = args[0]->ToObject();
Local<Array> properties = obj->GetPropertyNames();


default: { struct bind_request *bind_req = (struct bind_request *)
// this SHOULD be unreachable calloc(1, sizeof(struct bind_request));
}
}


if (!index) { int len = bind_req->len = properties->Length();
req->result = SQLITE_MISMATCH; bind_req->pairs = (struct bind_pair *)
return 0; calloc(len, sizeof(struct bind_pair));
}


int rc = 0; struct bind_pair *pairs = bind_req->pairs;
switch(bind_req->pairs->value_type) {
case VALUE_INT:
rc = sqlite3_bind_int(sto->stmt_, index, *(int*)(bind_req->pairs->value));
break;
case VALUE_DOUBLE:
rc = sqlite3_bind_double(sto->stmt_, index, *(double*)(bind_req->pairs->value));
break;
case VALUE_STRING:
rc = sqlite3_bind_text(sto->stmt_, index, (char*)(bind_req->pairs->value),
bind_req->pairs->value_size, SQLITE_TRANSIENT);
break;
case VALUE_NULL:
rc = sqlite3_bind_null(sto->stmt_, index);
break;

default: {
// should be unreachable
}
}


if (rc) { for (uint32_t i = 0; i < properties->Length(); i++, pairs++) {
req->result = rc; Local<Value> name = properties->Get(Integer::New(i));
return 0; Local<Value> val = obj->Get(name->ToString());

String::Utf8Value keyValue(name);
printf("prop %d is %s\n", i, *keyValue);

// setting key type
pairs->key_type = KEY_STRING;
char *key = (char *) calloc(1, keyValue.length() + 1);
strcpy(key, *keyValue);
pairs->key = key;

// setup value
if (val->IsInt32()) {
pairs->value_type = VALUE_INT;
int *value = (int *) malloc(sizeof(int));
*value = val->Int32Value();
pairs->value = value;
}
else if (val->IsNumber()) {
pairs->value_type = VALUE_DOUBLE;
double *value = (double *) malloc(sizeof(double));
*value = val->NumberValue();
pairs->value = value;
}
else if (val->IsString()) {
pairs->value_type = VALUE_STRING;
String::Utf8Value text(val);
char *value = (char *) calloc(text.length()+1, sizeof(char*));
strcpy(value, *text);
pairs->value = value;
pairs->value_size = text.length()+1;
}
else if (val->IsNull() || val->IsUndefined()) {
pairs->value_type = VALUE_NULL;
pairs->value = NULL;
}
else {
free(pairs->key);
return ThrowException(Exception::TypeError(
String::New("Unable to bind value of this type")));
}
} }


return 0; bind_req->cb = Persistent<Function>::New(cb);
} bind_req->sto = sto;


eio_custom(EIO_BindArray, EIO_PRI_DEFAULT, EIO_AfterBindArray, bind_req);


// db.prepare "SELECT $x, ?" -> statement ev_ref(EV_DEFAULT_UC);
//
// Bind multiple placeholders by array
// statement.bind([ value0, value1 ], callback);
//
// Bind multiple placeholdders by name
// statement.bind({ $x: value }, callback);
//
// Bind single placeholder by name:
// statement.bind('$x', value, callback);
//
// Bind placeholder by index:
// statement.bind(1, value, callback);


return Undefined();
};


Handle<Value> Statement::BindArray(const Arguments& args) { Handle<Value> Statement::BindArray(const Arguments& args) {
HandleScope scope; HandleScope scope;
Expand All @@ -275,12 +248,11 @@ Handle<Value> Statement::BindArray(const Arguments& args) {
for (int i = 0; i < len; i++, pairs++) { for (int i = 0; i < len; i++, pairs++) {
Local<Value> val = array->Get(i); Local<Value> val = array->Get(i);



// setting key type // setting key type
pairs->key_type = KEY_INT; pairs->key_type = KEY_INT;
int *index = (int *) malloc(sizeof(int)); int *index = (int *) malloc(sizeof(int));
*index = i+1; *index = i+1;
pairs->value_size = sizeof(int); // pairs->value_size = sizeof(int);


// don't forget to `free` this // don't forget to `free` this
pairs->key = index; pairs->key = index;
Expand Down Expand Up @@ -327,6 +299,20 @@ Handle<Value> Statement::BindArray(const Arguments& args) {
return Undefined(); return Undefined();
} }


// db.prepare "SELECT $x, ?" -> statement
//
// Bind multiple placeholders by array
// statement.bind([ value0, value1 ], callback);
//
// Bind multiple placeholdders by name
// statement.bind({ $x: value }, callback);
//
// Bind single placeholder by name:
// statement.bind('$x', value, callback);
//
// Bind placeholder by index:
// statement.bind(1, value, callback);

Handle<Value> Statement::Bind(const Arguments& args) { Handle<Value> Statement::Bind(const Arguments& args) {
HandleScope scope; HandleScope scope;
Statement* sto = ObjectWrap::Unwrap<Statement>(args.This()); Statement* sto = ObjectWrap::Unwrap<Statement>(args.This());
Expand All @@ -344,65 +330,64 @@ Handle<Value> Statement::Bind(const Arguments& args) {
struct bind_request *bind_req = (struct bind_request *) struct bind_request *bind_req = (struct bind_request *)
calloc(1, sizeof(struct bind_request)); calloc(1, sizeof(struct bind_request));


bind_req->pairs = (struct bind_pair *) bind_req->len = 1;
struct bind_pair *pair = bind_req->pairs = (struct bind_pair *)
calloc(1, sizeof(struct bind_pair)); calloc(1, sizeof(struct bind_pair));


// setup key // setup key
if (args[0]->IsString()) { if (args[0]->IsString()) {
String::Utf8Value keyValue(args[0]); String::Utf8Value keyValue(args[0]);
bind_req->pairs->key_type = KEY_STRING; pair->key_type = KEY_STRING;


char *key = (char *) calloc(1, keyValue.length() + 1); char *key = (char *) calloc(1, keyValue.length() + 1);
bind_req->pairs->value_size = keyValue.length() + 1;
strcpy(key, *keyValue); strcpy(key, *keyValue);


bind_req->pairs->key = key; pair->key = key;
} }
else if (args[0]->IsInt32()) { else if (args[0]->IsInt32()) {
bind_req->pairs->key_type = KEY_INT; pair->key_type = KEY_INT;
int *index = (int *) malloc(sizeof(int)); int *index = (int *) malloc(sizeof(int));
*index = args[0]->Int32Value(); *index = args[0]->Int32Value();
bind_req->pairs->value_size = sizeof(int);


// don't forget to `free` this // don't forget to `free` this
bind_req->pairs->key = index; pair->key = index;
} }


// setup value // setup value
if (args[1]->IsInt32()) { if (args[1]->IsInt32()) {
bind_req->pairs->value_type = VALUE_INT; pair->value_type = VALUE_INT;
int *value = (int *) malloc(sizeof(int)); int *value = (int *) malloc(sizeof(int));
*value = args[1]->Int32Value(); *value = args[1]->Int32Value();
bind_req->pairs->value = value; pair->value = value;
} }
else if (args[1]->IsNumber()) { else if (args[1]->IsNumber()) {
bind_req->pairs->value_type = VALUE_DOUBLE; pair->value_type = VALUE_DOUBLE;
double *value = (double *) malloc(sizeof(double)); double *value = (double *) malloc(sizeof(double));
*value = args[1]->NumberValue(); *value = args[1]->NumberValue();
bind_req->pairs->value = value; pair->value = value;
} }
else if (args[1]->IsString()) { else if (args[1]->IsString()) {
bind_req->pairs->value_type = VALUE_STRING; pair->value_type = VALUE_STRING;
String::Utf8Value text(args[1]); String::Utf8Value text(args[1]);
char *value = (char *) calloc(text.length()+1, sizeof(char*)); char *value = (char *) calloc(text.length()+1, sizeof(char*));
strcpy(value, *text); strcpy(value, *text);
bind_req->pairs->value = value; pair->value = value;
bind_req->pairs->value_size = text.length()+1; pair->value_size = text.length()+1;
} }
else if (args[1]->IsNull() || args[1]->IsUndefined()) { else if (args[1]->IsNull() || args[1]->IsUndefined()) {
bind_req->pairs->value_type = VALUE_NULL; pair->value_type = VALUE_NULL;
bind_req->pairs->value = NULL; pair->value = NULL;
} }
else { else {
free(bind_req->pairs->key); free(pair->key);
return ThrowException(Exception::TypeError( return ThrowException(Exception::TypeError(
String::New("Unable to bind value of this type"))); String::New("Unable to bind value of this type")));
} }


bind_req->cb = Persistent<Function>::New(cb); bind_req->cb = Persistent<Function>::New(cb);
bind_req->sto = sto; bind_req->sto = sto;


eio_custom(EIO_Bind, EIO_PRI_DEFAULT, EIO_AfterBind, bind_req); eio_custom(EIO_BindArray, EIO_PRI_DEFAULT, EIO_AfterBindArray, bind_req);


ev_ref(EV_DEFAULT_UC); ev_ref(EV_DEFAULT_UC);


Expand Down
8 changes: 3 additions & 5 deletions src/statement.h
Expand Up @@ -50,13 +50,11 @@ class Statement : public EventEmitter {
if (column_data_) FreeColumnData(); if (column_data_) FreeColumnData();
} }


static int EIO_AfterBind(eio_req *req);
static int EIO_Bind(eio_req *req);
static Handle<Value> Bind(const Arguments& args); static Handle<Value> Bind(const Arguments& args);

static Handle<Value> BindObject(const Arguments& args);
static int EIO_AfterBindArray(eio_req *req);
static int EIO_BindArray(eio_req *req);
static Handle<Value> BindArray(const Arguments& args); static Handle<Value> BindArray(const Arguments& args);
static int EIO_BindArray(eio_req *req);
static int EIO_AfterBindArray(eio_req *req);


static int EIO_AfterFinalize(eio_req *req); static int EIO_AfterFinalize(eio_req *req);
static int EIO_Finalize(eio_req *req); static int EIO_Finalize(eio_req *req);
Expand Down

0 comments on commit 9fae3ab

Please sign in to comment.