class CustomFunction : protected DataConverter { public: explicit CustomFunction( v8::Isolate* isolate, Database* db, const char* name, v8::Local fn, bool safe_ints ) : name(name), db(db), isolate(isolate), fn(isolate, fn), safe_ints(safe_ints) {} virtual ~CustomFunction() {} static void xDestroy(void* self) { delete static_cast(self); } static void xFunc(sqlite3_context* invocation, int argc, sqlite3_value** argv) { FUNCTION_START(); v8::Local args_fast[4]; v8::Local* args = NULL; if (argc != 0) { args = argc <= 4 ? args_fast : ALLOC_ARRAY>(argc); Data::GetArgumentsJS(isolate, args, argv, argc, self->safe_ints); } v8::MaybeLocal maybeReturnValue = self->fn.Get(isolate)->Call(OnlyContext, v8::Undefined(isolate), argc, args); if (args != args_fast) delete[] args; if (maybeReturnValue.IsEmpty()) self->PropagateJSError(invocation); else Data::ResultValueFromJS(isolate, invocation, maybeReturnValue.ToLocalChecked(), self); } protected: void PropagateJSError(sqlite3_context* invocation) { assert(db->GetState()->was_js_error == false); db->GetState()->was_js_error = true; sqlite3_result_error(invocation, "", 0); } std::string GetDataErrorPrefix() { return std::string("User-defined function ") + name + "() returned"; } private: const std::string name; Database* const db; protected: v8::Isolate* const isolate; const v8::Global fn; const bool safe_ints; };