diff --git a/binding.gyp b/binding.gyp index 9f7bea93e..bdcbb29a3 100644 --- a/binding.gyp +++ b/binding.gyp @@ -17,6 +17,7 @@ "src/workers/get.cc", "src/workers/all.cc", "src/workers/each.cc", + "src/binder/binder.cc", "src/sqlite3_plus.cc" ] } diff --git a/src/binder/advance-anon-index.cc b/src/binder/advance-anon-index.cc new file mode 100644 index 000000000..299cbdfb8 --- /dev/null +++ b/src/binder/advance-anon-index.cc @@ -0,0 +1,6 @@ +// Increments anon_index until it is out of range, or a nameless parameter +// index is reached. It is incremented at least once. + +void Binder::AdvanceAnonIndex() { + while (sqlite3_bind_parameter_name(++anon_index) != NULL) {} +} diff --git a/src/binder/bind-buffer.cc b/src/binder/bind-buffer.cc new file mode 100644 index 000000000..6afdb489e --- /dev/null +++ b/src/binder/bind-buffer.cc @@ -0,0 +1,8 @@ +void Binder::BindBuffer(v8::Local value, int index = 0) { + if (!index) {index = anon_index;} + AdvanceAnonIndex(); + + int status = sqlite3_bind_text(handle, index, node::Buffer::Data(value), node::Buffer::Length(value), SQLITE_TRANSIENT); + + SetBindingError(status); +} diff --git a/src/binder/bind-null.cc b/src/binder/bind-null.cc new file mode 100644 index 000000000..9e4c112f2 --- /dev/null +++ b/src/binder/bind-null.cc @@ -0,0 +1,6 @@ +void Binder::BindNull(int index = 0) { + if (!index) {index = anon_index;} + AdvanceAnonIndex(); + int status = sqlite3_bind_null(handle, index); + SetBindingError(status); +} diff --git a/src/binder/bind-number.cc b/src/binder/bind-number.cc new file mode 100644 index 000000000..ae0c6dd94 --- /dev/null +++ b/src/binder/bind-number.cc @@ -0,0 +1,6 @@ +void Binder::BindNumber(v8::Local value, int index = 0) { + if (!index) {index = anon_index;} + AdvanceAnonIndex(); + int status = sqlite3_bind_double(handle, index, value->Value()); + SetBindingError(status); +} diff --git a/src/binder/bind-string.cc b/src/binder/bind-string.cc new file mode 100644 index 000000000..fd588af3f --- /dev/null +++ b/src/binder/bind-string.cc @@ -0,0 +1,9 @@ +void Binder::BindString(v8::Local value, int index = 0) { + if (!index) {index = anon_index;} + AdvanceAnonIndex(); + + Nan::Utf8String utf8(value); + int status = sqlite3_bind_text(handle, index, *utf8, utf8.length(), SQLITE_TRANSIENT); + + SetBindingError(status); +} diff --git a/src/binder/bind-value.cc b/src/binder/bind-value.cc new file mode 100644 index 000000000..96b38b989 --- /dev/null +++ b/src/binder/bind-value.cc @@ -0,0 +1,13 @@ +void Binder::BindValue(v8::Local value, int index = 0) { + if (value->IsNumber()) { + BindNumber(v8::Local::Cast(value), index); + } else if (value->IsString()) { + BindString(v8::Local::Cast(value), index); + } else if (value->IsNull() || value->IsUndefined()) { + BindNull(index); + } else if (node::Buffer::HasInstance(value)) { + BindBuffer(v8::Local::Cast(value), index); + } else { + error = "SQLite3 can only bind numbers, strings, Buffers, and null."; + } +} diff --git a/src/binder/binder.cc b/src/binder/binder.cc new file mode 100644 index 000000000..89a6cbb6f --- /dev/null +++ b/src/binder/binder.cc @@ -0,0 +1,19 @@ +#include +#include +#include "binder.h" + +#include "advance-anon-index.cc" +#include "set-binding-error.cc" +#include "bind-number.cc" +#include "bind-string.cc" +#include "bind-buffer.cc" +#include "bind-null.cc" +#include "bind-value.cc" + +Binder::Binder(sqlite3_stmt* handle) + : handle(handle) + , param_count(sqlite3_bind_parameter_count(handle)) + , bound_args(0) + , anon_index(1) + , error(NULL) {} + diff --git a/src/binder/binder.h b/src/binder/binder.h new file mode 100644 index 000000000..f142344ce --- /dev/null +++ b/src/binder/binder.h @@ -0,0 +1,27 @@ +#ifndef NODE_SQLITE3_PLUS_WORKER_STATEMENT_WORKER_H +#define NODE_SQLITE3_PLUS_WORKER_STATEMENT_WORKER_H + +#include + +class Binder { + public: + Binder(sqlite3_stmt*); + + private: + void AdvanceAnonIndex(); + void SetBindingError(int); + void BindNumber(v8::Local, int); + void BindString(v8::Local, int); + void BindBuffer(v8::Local, int); + void BindNull(int); + void BindValue(v8::Local, int); + + sqlite3_stmt* const handle; + int const param_count; + + int bound_args; + int anon_index; + const char* error; +}; + +#endif \ No newline at end of file diff --git a/src/binder/set-binding-error.cc b/src/binder/set-binding-error.cc new file mode 100644 index 000000000..c1b9755e0 --- /dev/null +++ b/src/binder/set-binding-error.cc @@ -0,0 +1,17 @@ +void Binder::SetBindingError(int status) { + if (status != SQLITE_OK) { + switch (status) { + case SQLITE_RANGE: + error = "Too many parameters were provided."; + break; + case SQLITE_TOOBIG: + error = "The bound string or Buffer is too big."; + break; + case SQLITE_NOMEM: + error = "Out of memory."; + break; + default: + error = "An unexpected error occured while trying to bind parameters."; + } + } +}