@@ -993,6 +993,15 @@ bool DatabaseSync::Open() {
993993 env ()->isolate (), this , load_extension_ret, SQLITE_OK, false );
994994 }
995995
996+ {
997+ Local<Value> cb =
998+ object ()->GetInternalField (kVerboseCallback ).template As <Value>();
999+ if (cb->IsFunction ()) {
1000+ sqlite3_trace_v2 (
1001+ connection_, SQLITE_TRACE_STMT, DatabaseSync::TraceCallback, this );
1002+ }
1003+ }
1004+
9961005 return true ;
9971006}
9981007
@@ -1358,6 +1367,23 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
13581367 }
13591368 }
13601369 }
1370+
1371+ // Parse verbose option
1372+ Local<Value> verbose_v;
1373+ if (!options->Get (env->context (), env->verbose_string ())
1374+ .ToLocal (&verbose_v)) {
1375+ return ;
1376+ }
1377+ if (!verbose_v->IsUndefined () && !verbose_v->IsNull ()) {
1378+ if (!verbose_v->IsFunction ()) {
1379+ THROW_ERR_INVALID_ARG_TYPE (
1380+ env->isolate (),
1381+ " The \" options.verbose\" argument must be a function." );
1382+ return ;
1383+ }
1384+ args.This ()->SetInternalField (kVerboseCallback ,
1385+ verbose_v.As <Function>());
1386+ }
13611387 }
13621388
13631389 new DatabaseSync (
@@ -2540,6 +2566,55 @@ int DatabaseSync::AuthorizerCallback(void* user_data,
25402566 return int_result;
25412567}
25422568
2569+ int DatabaseSync::TraceCallback (unsigned int type,
2570+ void * user_data,
2571+ void * p,
2572+ void * x) {
2573+ if (type != SQLITE_TRACE_STMT) {
2574+ return 0 ;
2575+ }
2576+
2577+ DatabaseSync* db = static_cast <DatabaseSync*>(user_data);
2578+ Environment* env = db->env ();
2579+ Isolate* isolate = env->isolate ();
2580+ HandleScope handle_scope (isolate);
2581+ Local<Context> context = env->context ();
2582+
2583+ Local<Value> cb =
2584+ db->object ()->GetInternalField (kVerboseCallback ).template As <Value>();
2585+
2586+ if (!cb->IsFunction ()) {
2587+ return 0 ;
2588+ }
2589+
2590+ char * expanded = sqlite3_expanded_sql (static_cast <sqlite3_stmt*>(p));
2591+ Local<Value> sql_string;
2592+ if (expanded != nullptr ) {
2593+ bool ok = String::NewFromUtf8 (isolate, expanded).ToLocal (&sql_string);
2594+ sqlite3_free (expanded);
2595+ if (!ok) {
2596+ return 0 ;
2597+ }
2598+ } else {
2599+ // Fallback to source SQL if expanded is unavailable
2600+ const char * source = sqlite3_sql (static_cast <sqlite3_stmt*>(p));
2601+ if (source == nullptr || !String::NewFromUtf8 (isolate, source)
2602+ .ToLocal (&sql_string)) {
2603+ return 0 ;
2604+ }
2605+ }
2606+
2607+ Local<Function> callback = cb.As <Function>();
2608+ MaybeLocal<Value> retval =
2609+ callback->Call (context, Undefined (isolate), 1 , &sql_string);
2610+
2611+ if (retval.IsEmpty ()) {
2612+ db->SetIgnoreNextSQLiteError (true );
2613+ }
2614+
2615+ return 0 ;
2616+ }
2617+
25432618StatementSync::StatementSync (Environment* env,
25442619 Local<Object> object,
25452620 BaseObjectPtr<DatabaseSync> db,
0 commit comments