Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 43 additions & 33 deletions src/node_sqlite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
#include "node.h"
#include "node_errors.h"
#include "node_mem-inl.h"
#include "path.h"
#include "sqlite3.h"
#include "util-inl.h"

#include <cinttypes>
#include <string_view>

namespace node {
namespace sqlite {
Expand Down Expand Up @@ -47,7 +49,7 @@ using v8::Value;
#define THROW_AND_RETURN_ON_BAD_STATE(env, condition, msg) \
do { \
if ((condition)) { \
node::THROW_ERR_INVALID_STATE((env), (msg)); \
THROW_ERR_INVALID_STATE((env), (msg)); \
return; \
} \
} while (0)
Expand Down Expand Up @@ -90,12 +92,11 @@ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, const char* message) {

DatabaseSync::DatabaseSync(Environment* env,
Local<Object> object,
Local<String> location,
const std::string_view location,
bool open)
: BaseObject(env, object) {
MakeWeak();
node::Utf8Value utf8_location(env->isolate(), location);
location_ = utf8_location.ToString();
location_ = std::string(location);
connection_ = nullptr;

if (open) {
Expand All @@ -117,7 +118,7 @@ void DatabaseSync::MemoryInfo(MemoryTracker* tracker) const {

bool DatabaseSync::Open() {
if (IsOpen()) {
node::THROW_ERR_INVALID_STATE(env(), "database is already open");
THROW_ERR_INVALID_STATE(env(), "database is already open");
return false;
}

Expand Down Expand Up @@ -160,17 +161,17 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
}

if (!args[0]->IsString()) {
node::THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
"The \"path\" argument must be a string.");
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
"The \"path\" argument must be a string.");
return;
}

bool open = true;

if (args.Length() > 1) {
if (!args[1]->IsObject()) {
node::THROW_ERR_INVALID_ARG_TYPE(
env->isolate(), "The \"options\" argument must be an object.");
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
"The \"options\" argument must be an object.");
return;
}

Expand All @@ -182,15 +183,18 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
}
if (!open_v->IsUndefined()) {
if (!open_v->IsBoolean()) {
node::THROW_ERR_INVALID_ARG_TYPE(
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(), "The \"options.open\" argument must be a boolean.");
return;
}
open = open_v.As<Boolean>()->Value();
}
}

new DatabaseSync(env, args.This(), args[0].As<String>(), open);
BufferValue location(env->isolate(), args[0]);
CHECK_NOT_NULL(*location);
ToNamespacedPath(env, &location);
new DatabaseSync(env, args.This(), location.ToStringView(), open);
}

void DatabaseSync::Open(const FunctionCallbackInfo<Value>& args) {
Expand All @@ -217,12 +221,12 @@ void DatabaseSync::Prepare(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");

if (!args[0]->IsString()) {
node::THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
"The \"sql\" argument must be a string.");
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
"The \"sql\" argument must be a string.");
return;
}

node::Utf8Value sql(env->isolate(), args[0].As<String>());
Utf8Value sql(env->isolate(), args[0].As<String>());
sqlite3_stmt* s = nullptr;
int r = sqlite3_prepare_v2(db->connection_, *sql, -1, &s, 0);
CHECK_ERROR_OR_THROW(env->isolate(), db->connection_, r, SQLITE_OK, void());
Expand All @@ -238,12 +242,12 @@ void DatabaseSync::Exec(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");

if (!args[0]->IsString()) {
node::THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
"The \"sql\" argument must be a string.");
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
"The \"sql\" argument must be a string.");
return;
}

node::Utf8Value sql(env->isolate(), args[0].As<String>());
Utf8Value sql(env->isolate(), args[0].As<String>());
int r = sqlite3_exec(db->connection_, *sql, nullptr, nullptr, nullptr);
CHECK_ERROR_OR_THROW(env->isolate(), db->connection_, r, SQLITE_OK, void());
}
Expand Down Expand Up @@ -311,7 +315,7 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
if (insertion.second == false) {
auto existing_full_name = (*insertion.first).second;
if (full_name != existing_full_name) {
node::THROW_ERR_INVALID_STATE(
THROW_ERR_INVALID_STATE(
env(),
"Cannot create bare named parameter '%s' because of "
"conflicting names '%s' and '%s'.",
Expand All @@ -331,7 +335,7 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
return false;
}

node::Utf8Value utf8_key(env()->isolate(), key);
Utf8Value utf8_key(env()->isolate(), key);
int r = sqlite3_bind_parameter_index(statement_, *utf8_key);
if (r == 0) {
if (allow_bare_named_params_) {
Expand All @@ -343,7 +347,7 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
}

if (r == 0) {
node::THROW_ERR_INVALID_STATE(
THROW_ERR_INVALID_STATE(
env(), "Unknown named parameter '%s'", *utf8_key);
return false;
}
Expand Down Expand Up @@ -387,7 +391,7 @@ bool StatementSync::BindValue(const Local<Value>& value, const int index) {
double val = value.As<Number>()->Value();
r = sqlite3_bind_double(statement_, index, val);
} else if (value->IsString()) {
node::Utf8Value val(env()->isolate(), value.As<String>());
Utf8Value val(env()->isolate(), value.As<String>());
r = sqlite3_bind_text(
statement_, index, *val, val.length(), SQLITE_TRANSIENT);
} else if (value->IsNull()) {
Expand All @@ -400,13 +404,12 @@ bool StatementSync::BindValue(const Local<Value>& value, const int index) {
bool lossless;
int64_t as_int = value.As<BigInt>()->Int64Value(&lossless);
if (!lossless) {
node::THROW_ERR_INVALID_ARG_VALUE(env(),
"BigInt value is too large to bind.");
THROW_ERR_INVALID_ARG_VALUE(env(), "BigInt value is too large to bind.");
return false;
}
r = sqlite3_bind_int64(statement_, index, as_int);
} else {
node::THROW_ERR_INVALID_ARG_TYPE(
THROW_ERR_INVALID_ARG_TYPE(
env()->isolate(),
"Provided value cannot be bound to SQLite parameter %d.",
index);
Expand All @@ -432,7 +435,7 @@ MaybeLocal<Value> StatementSync::ColumnToValue(const int column) {
"represented as a JavaScript number: %" PRId64,
column,
value);
return MaybeLocal<Value>();
return {};
}
}
case SQLITE_FLOAT:
Expand All @@ -441,7 +444,11 @@ MaybeLocal<Value> StatementSync::ColumnToValue(const int column) {
case SQLITE_TEXT: {
const char* value = reinterpret_cast<const char*>(
sqlite3_column_text(statement_, column));
return String::NewFromUtf8(env()->isolate(), value).As<Value>();
Local<Value> val;
if (!String::NewFromUtf8(env()->isolate(), value).ToLocal(&val)) {
return {};
}
return val;
}
case SQLITE_NULL:
return Null(env()->isolate());
Expand All @@ -463,12 +470,15 @@ MaybeLocal<Value> StatementSync::ColumnToValue(const int column) {
MaybeLocal<Name> StatementSync::ColumnNameToName(const int column) {
const char* col_name = sqlite3_column_name(statement_, column);
if (col_name == nullptr) {
node::THROW_ERR_INVALID_STATE(
env(), "Cannot get name of column %d", column);
return MaybeLocal<Name>();
THROW_ERR_INVALID_STATE(env(), "Cannot get name of column %d", column);
return {};
}

return String::NewFromUtf8(env()->isolate(), col_name).As<Name>();
Local<String> key;
if (!String::NewFromUtf8(env()->isolate(), col_name).ToLocal(&key)) {
return {};
}
return key;
}

void StatementSync::MemoryInfo(MemoryTracker* tracker) const {}
Expand Down Expand Up @@ -657,7 +667,7 @@ void StatementSync::SetAllowBareNamedParameters(
env, stmt->IsFinalized(), "statement has been finalized");

if (!args[0]->IsBoolean()) {
node::THROW_ERR_INVALID_ARG_TYPE(
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(),
"The \"allowBareNamedParameters\" argument must be a boolean.");
return;
Expand All @@ -674,7 +684,7 @@ void StatementSync::SetReadBigInts(const FunctionCallbackInfo<Value>& args) {
env, stmt->IsFinalized(), "statement has been finalized");

if (!args[0]->IsBoolean()) {
node::THROW_ERR_INVALID_ARG_TYPE(
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(), "The \"readBigInts\" argument must be a boolean.");
return;
}
Expand All @@ -683,7 +693,7 @@ void StatementSync::SetReadBigInts(const FunctionCallbackInfo<Value>& args) {
}

void IllegalConstructor(const FunctionCallbackInfo<Value>& args) {
node::THROW_ERR_ILLEGAL_CONSTRUCTOR(Environment::GetCurrent(args));
THROW_ERR_ILLEGAL_CONSTRUCTOR(Environment::GetCurrent(args));
}

Local<FunctionTemplate> StatementSync::GetConstructorTemplate(
Expand Down
3 changes: 2 additions & 1 deletion src/node_sqlite.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "util.h"

#include <map>
#include <string_view>
#include <unordered_set>

namespace node {
Expand All @@ -20,7 +21,7 @@ class DatabaseSync : public BaseObject {
public:
DatabaseSync(Environment* env,
v8::Local<v8::Object> object,
v8::Local<v8::String> location,
std::string_view location,
bool open);
void MemoryInfo(MemoryTracker* tracker) const override;
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
Expand Down