@@ -974,6 +974,15 @@ bool DatabaseSync::Open() {
974974 env ()->isolate (), this , load_extension_ret, SQLITE_OK, false );
975975 }
976976
977+ {
978+ Local<Value> cb =
979+ object ()->GetInternalField (kVerboseCallback ).template As <Value>();
980+ if (cb->IsFunction ()) {
981+ sqlite3_trace_v2 (
982+ connection_, SQLITE_TRACE_STMT, DatabaseSync::TraceCallback, this );
983+ }
984+ }
985+
977986 return true ;
978987}
979988
@@ -1339,6 +1348,23 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
13391348 }
13401349 }
13411350 }
1351+
1352+ // Parse verbose option
1353+ Local<Value> verbose_v;
1354+ if (!options->Get (env->context (), env->verbose_string ())
1355+ .ToLocal (&verbose_v)) {
1356+ return ;
1357+ }
1358+ if (!verbose_v->IsUndefined () && !verbose_v->IsNull ()) {
1359+ if (!verbose_v->IsFunction ()) {
1360+ THROW_ERR_INVALID_ARG_TYPE (
1361+ env->isolate (),
1362+ " The \" options.verbose\" argument must be a function." );
1363+ return ;
1364+ }
1365+ args.This ()->SetInternalField (kVerboseCallback ,
1366+ verbose_v.As <Function>());
1367+ }
13421368 }
13431369
13441370 new DatabaseSync (
@@ -2390,6 +2416,55 @@ int DatabaseSync::AuthorizerCallback(void* user_data,
23902416 return int_result;
23912417}
23922418
2419+ int DatabaseSync::TraceCallback (unsigned int type,
2420+ void * user_data,
2421+ void * p,
2422+ void * x) {
2423+ if (type != SQLITE_TRACE_STMT) {
2424+ return 0 ;
2425+ }
2426+
2427+ DatabaseSync* db = static_cast <DatabaseSync*>(user_data);
2428+ Environment* env = db->env ();
2429+ Isolate* isolate = env->isolate ();
2430+ HandleScope handle_scope (isolate);
2431+ Local<Context> context = env->context ();
2432+
2433+ Local<Value> cb =
2434+ db->object ()->GetInternalField (kVerboseCallback ).template As <Value>();
2435+
2436+ if (!cb->IsFunction ()) {
2437+ return 0 ;
2438+ }
2439+
2440+ char * expanded = sqlite3_expanded_sql (static_cast <sqlite3_stmt*>(p));
2441+ Local<Value> sql_string;
2442+ if (expanded != nullptr ) {
2443+ bool ok = String::NewFromUtf8 (isolate, expanded).ToLocal (&sql_string);
2444+ sqlite3_free (expanded);
2445+ if (!ok) {
2446+ return 0 ;
2447+ }
2448+ } else {
2449+ // Fallback to source SQL if expanded is unavailable
2450+ const char * source = sqlite3_sql (static_cast <sqlite3_stmt*>(p));
2451+ if (source == nullptr || !String::NewFromUtf8 (isolate, source)
2452+ .ToLocal (&sql_string)) {
2453+ return 0 ;
2454+ }
2455+ }
2456+
2457+ Local<Function> callback = cb.As <Function>();
2458+ MaybeLocal<Value> retval =
2459+ callback->Call (context, Undefined (isolate), 1 , &sql_string);
2460+
2461+ if (retval.IsEmpty ()) {
2462+ db->SetIgnoreNextSQLiteError (true );
2463+ }
2464+
2465+ return 0 ;
2466+ }
2467+
23932468StatementSync::StatementSync (Environment* env,
23942469 Local<Object> object,
23952470 BaseObjectPtr<DatabaseSync> db,
0 commit comments