@@ -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 (
@@ -2391,6 +2417,55 @@ int DatabaseSync::AuthorizerCallback(void* user_data,
23912417 return int_result;
23922418}
23932419
2420+ int DatabaseSync::TraceCallback (unsigned int type,
2421+ void * user_data,
2422+ void * p,
2423+ void * x) {
2424+ if (type != SQLITE_TRACE_STMT) {
2425+ return 0 ;
2426+ }
2427+
2428+ DatabaseSync* db = static_cast <DatabaseSync*>(user_data);
2429+ Environment* env = db->env ();
2430+ Isolate* isolate = env->isolate ();
2431+ HandleScope handle_scope (isolate);
2432+ Local<Context> context = env->context ();
2433+
2434+ Local<Value> cb =
2435+ db->object ()->GetInternalField (kVerboseCallback ).template As <Value>();
2436+
2437+ if (!cb->IsFunction ()) {
2438+ return 0 ;
2439+ }
2440+
2441+ char * expanded = sqlite3_expanded_sql (static_cast <sqlite3_stmt*>(p));
2442+ Local<Value> sql_string;
2443+ if (expanded != nullptr ) {
2444+ bool ok = String::NewFromUtf8 (isolate, expanded).ToLocal (&sql_string);
2445+ sqlite3_free (expanded);
2446+ if (!ok) {
2447+ return 0 ;
2448+ }
2449+ } else {
2450+ // Fallback to source SQL if expanded is unavailable
2451+ const char * source = sqlite3_sql (static_cast <sqlite3_stmt*>(p));
2452+ if (source == nullptr || !String::NewFromUtf8 (isolate, source)
2453+ .ToLocal (&sql_string)) {
2454+ return 0 ;
2455+ }
2456+ }
2457+
2458+ Local<Function> callback = cb.As <Function>();
2459+ MaybeLocal<Value> retval =
2460+ callback->Call (context, Undefined (isolate), 1 , &sql_string);
2461+
2462+ if (retval.IsEmpty ()) {
2463+ db->SetIgnoreNextSQLiteError (true );
2464+ }
2465+
2466+ return 0 ;
2467+ }
2468+
23942469StatementSync::StatementSync (Environment* env,
23952470 Local<Object> object,
23962471 BaseObjectPtr<DatabaseSync> db,
0 commit comments