src: improve error handling in node_sqlite · nodejs/node@d6cf091

@@ -126,13 +126,15 @@ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, int errcode) {

126126

const char* errstr = sqlite3_errstr(errcode);

127127128128

Environment* env = Environment::GetCurrent(isolate);

129-

auto error = CreateSQLiteError(isolate, errstr).ToLocalChecked();

130-

error

131-

->Set(isolate->GetCurrentContext(),

132-

env->errcode_string(),

133-

Integer::New(isolate, errcode))

134-

.ToChecked();

135-

isolate->ThrowException(error);

129+

Local<Object> error;

130+

if (CreateSQLiteError(isolate, errstr).ToLocal(&error) &&

131+

error

132+

->Set(isolate->GetCurrentContext(),

133+

env->errcode_string(),

134+

Integer::New(isolate, errcode))

135+

.IsJust()) {

136+

isolate->ThrowException(error);

137+

}

136138

}

137139138140

UserDefinedFunction::UserDefinedFunction(Environment* env,

@@ -734,12 +736,14 @@ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {

734736

}

735737

}

736738737-

Local<String> db_key =

738-

String::NewFromUtf8(env->isolate(), "db", NewStringType::kNormal)

739-

.ToLocalChecked();

739+

Local<String> db_key = FIXED_ONE_BYTE_STRING(env->isolate(), "db");

740+740741

if (options->HasOwnProperty(env->context(), db_key).FromJust()) {

741-

Local<Value> db_value =

742-

options->Get(env->context(), db_key).ToLocalChecked();

742+

Local<Value> db_value;

743+

if (!options->Get(env->context(), db_key).ToLocal(&db_value)) {

744+

// An error will have been scheduled.

745+

return;

746+

}

743747

if (db_value->IsString()) {

744748

String::Utf8Value str(env->isolate(), db_value);

745749

db_name = std::string(*str);

@@ -808,8 +812,12 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {

808812

}

809813810814

Local<Object> options = args[1].As<Object>();

811-

Local<Value> conflictValue =

812-

options->Get(env->context(), env->onconflict_string()).ToLocalChecked();

815+

Local<Value> conflictValue;

816+

if (!options->Get(env->context(), env->onconflict_string())

817+

.ToLocal(&conflictValue)) {

818+

// An error will have been scheduled.

819+

return;

820+

}

813821814822

if (!conflictValue->IsUndefined()) {

815823

if (!conflictValue->IsFunction()) {

@@ -837,8 +845,12 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {

837845838846

if (options->HasOwnProperty(env->context(), env->filter_string())

839847

.FromJust()) {

840-

Local<Value> filterValue =

841-

options->Get(env->context(), env->filter_string()).ToLocalChecked();

848+

Local<Value> filterValue;

849+

if (!options->Get(env->context(), env->filter_string())

850+

.ToLocal(&filterValue)) {

851+

// An error will have been scheduled.

852+

return;

853+

}

842854843855

if (!filterValue->IsFunction()) {

844856

THROW_ERR_INVALID_ARG_TYPE(

@@ -850,6 +862,10 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {

850862

Local<Function> filterFunc = filterValue.As<Function>();

851863852864

filterCallback = [env, filterFunc](std::string item) -> bool {

865+

// TODO(@jasnell): The use of ToLocalChecked here means that if

866+

// the filter function throws an error the process will crash.

867+

// The filterCallback should be updated to avoid the check and

868+

// propagate the error correctly.

853869

Local<Value> argv[] = {String::NewFromUtf8(env->isolate(),

854870

item.c_str(),

855871

NewStringType::kNormal)

@@ -1214,11 +1230,18 @@ void StatementSync::IterateReturnCallback(

1214123012151231

auto self = args.This();

12161232

// iterator has fetch all result or break, prevent next func to return result

1217-

self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))

1218-

.ToChecked();

1233+

if (self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))

1234+

.IsNothing()) {

1235+

// An error will have been scheduled.

1236+

return;

1237+

}

121912381220-

auto external_stmt = Local<External>::Cast(

1221-

self->Get(context, env->statement_string()).ToLocalChecked());

1239+

Local<Value> val;

1240+

if (!self->Get(context, env->statement_string()).ToLocal(&val)) {

1241+

// An error will have been scheduled.

1242+

return;

1243+

}

1244+

auto external_stmt = Local<External>::Cast(val);

12221245

auto stmt = static_cast<StatementSync*>(external_stmt->Value());

12231246

if (!stmt->IsFinalized()) {

12241247

sqlite3_reset(stmt->statement_);

@@ -1242,28 +1265,38 @@ void StatementSync::IterateNextCallback(

1242126512431266

auto self = args.This();

124412671268+

Local<Value> val;

1269+

if (!self->Get(context, env->isfinished_string()).ToLocal(&val)) {

1270+

// An error will have been scheduled.

1271+

return;

1272+

}

1273+12451274

// skip iteration if is_finished

1246-

auto is_finished = Local<Boolean>::Cast(

1247-

self->Get(context, env->isfinished_string()).ToLocalChecked());

1275+

auto is_finished = Local<Boolean>::Cast(val);

12481276

if (is_finished->Value()) {

1249-

LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});

1250-

LocalVector<Value> values(isolate,

1251-

{Boolean::New(isolate, true), Null(isolate)});

1252-1253-

DCHECK_EQ(keys.size(), values.size());

1277+

Local<Name> keys[] = {env->done_string(), env->value_string()};

1278+

Local<Value> values[] = {Boolean::New(isolate, true), Null(isolate)};

1279+

static_assert(arraysize(keys) == arraysize(values));

12541280

Local<Object> result = Object::New(

1255-

isolate, Null(isolate), keys.data(), values.data(), keys.size());

1281+

isolate, Null(isolate), &keys[0], &values[0], arraysize(keys));

12561282

args.GetReturnValue().Set(result);

12571283

return;

12581284

}

125912851260-

auto external_stmt = Local<External>::Cast(

1261-

self->Get(context, env->statement_string()).ToLocalChecked());

1286+

if (!self->Get(context, env->statement_string()).ToLocal(&val)) {

1287+

// An error will have been scheduled.

1288+

return;

1289+

}

1290+1291+

auto external_stmt = Local<External>::Cast(val);

12621292

auto stmt = static_cast<StatementSync*>(external_stmt->Value());

1263-

auto num_cols =

1264-

Local<Integer>::Cast(

1265-

self->Get(context, env->num_cols_string()).ToLocalChecked())

1266-

->Value();

1293+1294+

if (!self->Get(context, env->num_cols_string()).ToLocal(&val)) {

1295+

// An error will have been scheduled.

1296+

return;

1297+

}

1298+1299+

auto num_cols = Local<Integer>::Cast(val)->Value();

1267130012681301

THROW_AND_RETURN_ON_BAD_STATE(

12691302

env, stmt->IsFinalized(), "statement has been finalized");

@@ -1275,8 +1308,12 @@ void StatementSync::IterateNextCallback(

1275130812761309

// cleanup when no more rows to fetch

12771310

sqlite3_reset(stmt->statement_);

1278-

self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))

1279-

.ToChecked();

1311+

if (self->Set(

1312+

context, env->isfinished_string(), Boolean::New(isolate, true))

1313+

.IsNothing()) {

1314+

// An error would have been scheduled

1315+

return;

1316+

}

1280131712811318

LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});

12821319

LocalVector<Value> values(isolate,

@@ -1329,15 +1366,19 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {

13291366

return;

13301367

}

133113681332-

Local<Function> next_func =

1333-

Function::New(context, StatementSync::IterateNextCallback)

1334-

.ToLocalChecked();

1335-

Local<Function> return_func =

1336-

Function::New(context, StatementSync::IterateReturnCallback)

1337-

.ToLocalChecked();

1369+

Local<Function> next_func;

1370+

Local<Function> return_func;

1371+

if (!Function::New(context, StatementSync::IterateNextCallback)

1372+

.ToLocal(&next_func) ||

1373+

!Function::New(context, StatementSync::IterateReturnCallback)

1374+

.ToLocal(&return_func)) {

1375+

// An error will have been scheduled.

1376+

return;

1377+

}

133813781339-

LocalVector<Name> keys(isolate, {env->next_string(), env->return_string()});

1340-

LocalVector<Value> values(isolate, {next_func, return_func});

1379+

Local<Name> keys[] = {env->next_string(), env->return_string()};

1380+

Local<Value> values[] = {next_func, return_func};

1381+

static_assert(arraysize(keys) == arraysize(values));

1341138213421383

Local<Object> global = context->Global();

13431384

Local<Value> js_iterator;

@@ -1349,32 +1390,41 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {

13491390

.ToLocal(&js_iterator_prototype))

13501391

return;

135113921352-

DCHECK_EQ(keys.size(), values.size());

13531393

Local<Object> iterable_iterator = Object::New(

1354-

isolate, js_iterator_prototype, keys.data(), values.data(), keys.size());

1394+

isolate, js_iterator_prototype, &keys[0], &values[0], arraysize(keys));

1355139513561396

auto num_cols_pd = v8::PropertyDescriptor(

13571397

v8::Integer::New(isolate, sqlite3_column_count(stmt->statement_)), false);

13581398

num_cols_pd.set_enumerable(false);

13591399

num_cols_pd.set_configurable(false);

1360-

iterable_iterator

1361-

->DefineProperty(context, env->num_cols_string(), num_cols_pd)

1362-

.ToChecked();

1400+

if (iterable_iterator

1401+

->DefineProperty(context, env->num_cols_string(), num_cols_pd)

1402+

.IsNothing()) {

1403+

// An error will have been scheduled.

1404+

return;

1405+

}

1363140613641407

auto stmt_pd =

13651408

v8::PropertyDescriptor(v8::External::New(isolate, stmt), false);

13661409

stmt_pd.set_enumerable(false);

13671410

stmt_pd.set_configurable(false);

1368-

iterable_iterator->DefineProperty(context, env->statement_string(), stmt_pd)

1369-

.ToChecked();

1411+

if (iterable_iterator

1412+

->DefineProperty(context, env->statement_string(), stmt_pd)

1413+

.IsNothing()) {

1414+

// An error will have been scheduled.

1415+

return;

1416+

}

1370141713711418

auto is_finished_pd =

13721419

v8::PropertyDescriptor(v8::Boolean::New(isolate, false), true);

13731420

stmt_pd.set_enumerable(false);

13741421

stmt_pd.set_configurable(false);

1375-

iterable_iterator

1376-

->DefineProperty(context, env->isfinished_string(), is_finished_pd)

1377-

.ToChecked();

1422+

if (iterable_iterator

1423+

->DefineProperty(context, env->isfinished_string(), is_finished_pd)

1424+

.IsNothing()) {

1425+

// An error will have been scheduled.

1426+

return;

1427+

}

1378142813791429

args.GetReturnValue().Set(iterable_iterator);

13801430

}