vþ�@†¾Üð¹¾‚cÜ'²ÇÛ¯êE¢=Jn4	ä€ö{‘fqÉy¯sÑWÛa©'�ÄvPo´ÎÞ&©¹ÅZnFÏ‘“«Q­¥
7’™	Üb,g«EÝÊM …´bØð¾î<o¢PjVZ{„dé°J\Ë±U7W&zhž–HwÖË‡˜HïÈºLÚV>ÔlŸþµfQ>Îçþ‹ÐÃTþÜìâÄr¤Ó3<S‰Z Å[_QŽE%5ÌŠ? »GtýÁÎ~·Ì„ó°K]1<Ü#7Àï5Ó ¹ðÈÂW“ù¶€løšÖ®ÈùWÏXä)ú0Ý“Á½Á}qðwò+ÕŽ6z±—�¥`ã½Zdü«×••]&˜,‰‡­›³ÇÀk2ZÈY“™[¾oª6  c#«ýÒ�¸,§5GkI+¥VêË#[S›TúAm¢g²úN2UIß£.ÅJäô¨h�Œ¥éýÏˆýwqìpEëÝM‘BK<£'ÝšäGçWdìçÀ”IYWGÞªõ9Êt1?pü Àâ/ìöºÏ¬'àºwñ’`)f+·Uz' J@—èV®·÷·ùV­�h6û¯¶ËžyNPÕ—zq: `?ÿ]þç¸ÎC `²°ù^¥lºSBÿÿq>I½
}Ä–W¬Î“„ìUÄžê9HíÙ*/î¨9…‹í4úÊÌT
&É©¨AM„�’ReÔ×YÍñ8$‡OGâºuUÑÖw”ŽÑ3-ï¸HˆìOj3ÝEÐÂÿ•¼ùQß…±¢h¶¡¡2™¥ÁqVj</„X›í¦Óƒ…6¸¸'ÊÎ—ln˜œF\’÷ò¿á“v›/ƒƒ¤Ú>±ì‰ç˜ƒËm}Þ ¨Ýõ5Iïð†öÙi"y›ü¸+ø !âk¹ç{U_®òŠáØ0®þû�J½bÑ¤ì{Õ÷M^þyÁU�àJº2[­»¾sY’OuP×wÛ´´Ñ=å˜ã9šÅX‘¨ZÂŽ^¤™‹-�ÁÀ©ÖrÊnî¸ä^¥Ì^øwôºhóŒc¹š²&è�ƒ$™éU—‰Bl]ŸË}w:…_&Láõ«àÆ&ó_Ó½zÉÑˆÓ›¹6WßžbÚ¡ñ¨ÓÔì9YÝÁƒ²w¶B¼ Æ~mËîsûèºò¦IÜo4îô!Ì¤{Ö¦ëµÚ·ƒæª§q’f2û'°µ¬¹à’=\o=tb+ëÜ¼8C[lÆ"~›7ZÓÔì9YÝÁƒ²w¶B¼ Æ~mËîsûèºò¦IÜo4ð©S'˜ßÏˆ´/3®»Ò¯Çá¼àNÏÂ˜~DJ²Ïø¢©èÒiõMåWÃ[Âç“a’´7-4r¦¹	AÙ`8$‡OGâºuUÑÖw”ŽØ,C ;AzSzY	^œ¦¾K@ ýLæ
†Š¹çÛÃ×©"Ç.s<L³»)Õcöç“a’´7-4r¦¹	AÙ`8$‡OGâºuUÑÖw”ŽÕ¢ÿIGI}ÌŸÂ×4ÕÝ•Á²+ÇÄûò�OUt}°î®e>“FÿÎnB]Esè~8…ç“a’´7-4r¦¹	AÙ`8$‡OGâºuUÑÖw”ŽXH‰wÓ\€ŒçtQ¿ë¬zã ²Bá3Á9ÿèÎ]éÄÌ�i)…À�èþƒèÖ¦NL4(+Cm €á@Ð3¢[R5ç†éž}‘Ïì]"Q”.3$R¾ùJ‰{üþzÍÞêŠ2]HweQvR~ë±Øk‡¾\ƒ²�³~÷³ !åéCÆPÐÅF8iøôÊ™òÄ¸á¢"LèRýÏ³ÁbF¼¹ Ä4�–ç�ïç)šäÛæä#00{Fy?—ÅMJŒY¬<>ð%”µÎ=&ƒ›»¡æøÀž}�'!7„owðÑC±Q¾üçÄÝ{øækõŽVì‹JUO0»Ï‡ûEÂ	Ö\ßíÐ(š–³JË.ñ8éÒöaÌ®KõÖdÞ¤Óª%–Ð8ÏÓ¢{î£ÈüR˜ŸÀ�Y~$÷�ºvE@:uüR¶`ðŽb`ßPÑmCQxâ3c_kŽ’¸¸,ÑÃ*{xu%“ÈˆZË)ÚF¢6}
dL…D¤R1�ZëÜ›Zõç¯mhxq,yú=?#}ÕŒ¡I¶Ó@¥ôëM´ïuˆ#ÃÆÄ€ú³¨,·J«ÒÃùœÎ/ß-ã]~Z”ó}�àú»Q©ÕÃy9g¿]9ÒŠfka`(c)bBåÞy®ŸÂk�1¥OåXLð{*ön¬ˆPÅeb‘½9Ä=QïÉvCv/ì·CjqVu›èh6_ã÷†3Ðæ‚ò©/Ëšó=aµ&•ƒAýe9•ä³0u',ÂÍ`ÏYëwºÏné63Í½Ù~kÖ§ç«¶Þ+W©7”|[®à÷ŽÃœCÌ¨q½gíÁ²µø'L�4'ðÞ”óÏ ™œ:ët
ƒ$‡Ür‹6C¯Æ«‡K_YYu`¶­Â¿vpÝÜ/jÒ‚£‰ùà>§¤RrddYOÆ:fŸ}‚6AkÎ"2|Ó¡yÛä�±\©5[á^ÛD¿«ŒKf‡§±‚rØÍpæa¼ËÔ¬�‰s¦8wégtÍØˆë»¾ÅhÈ8¡izsûDC&
ÿ:….¯o«q$¨cØRSü«4™ùê  ÿ€—§ë×›1¦L€ä±tìO¨ÞÑ ¨¸Äg<ï–5‰æU”[Ã@#j&ÌZyÛÎðéjÙNpyáÿÉ%žô¤Iõé[zÄiÒUnLOÝº¡/œÐ²Ãëé™ÎOC‰ÝÛV� »ªóÇì°ê®qaÑµÎ“1÷7
Ü. u†²ònqD¤ô82´,‘&8•Üóbæ¤9<û�ë.ò„Ö7)r»í€o+Ö n^ßA— (§–ƒ¦×L|‘BIU’±:"isAG9õŸ÷ƒDÓŠÁèúž.åcÐ¸ªYÕÈ$çåÒ;™¦çi›ðÁ“µ½ÝL½$øüm~†wÜýSàâmBQ	ÚHJò¼nboÖ¦íøu[…ïF‡ƒwC¿}¸6E·£sòÒWüµ×´ˆ&á•I·éèXÈßÉƒ¢ô´¨Âùƒý¢æô­9‚?ƒîæ0N_ïUS�ˆŠ¬ç=8¤ÍA„¾)ÂV+ÈAîð;…ˆ¥“¸—å¤Ö{«;¨U$Ã^õM-[EC6¼†äkàBùlK¿MF¼ÌŠ¾�µ9Êå³Ñž �tï¥ª/+$üëU›Ä³M°L\ÂŽûÓa!›Ÿj=Y8˜ÁoÇÞä:>µµM	“'¥�ÒÇØšôaÈâÿ¿U©ôí;žjÄÙt¦•Ë([CÓ®1Ýâ1ÝÿÞ9n‘Q~’¹¥/ßîùË,ˆ� µÔU�ÆP9Ç‹0 oÜµÓá®'¦jGY„�¤1òÎ+è.DÉÈvT\õ�hØÑÈl$
9ao›P€VÀø"�˜BÈ<¢IkkÅnxãŒ‹7Ç3	ðVêJ�v¯ìè®DÀÀŽêŸ9Qñ¼]ŠÊÔgÊñ\¸'ºˆ‡xî9GÁ*¦õíµd@é~MÝ¸·Í3ŸfÚ \�gn‹ˆ8R�;\qÕÚÔ°s›µéT8Aî¨ŸHiW·á#�Ø–¢b·vAõFHÎe
§$N@¬M]ý#\ñlÿmrÎÏ³!³µµO'P:èž	Œ=5ìjXK%§œ<:þB.\¯‡I¬_³D(áÎ,êßÓ€6_–¦­n=ya|²Õî1«Ë¿×—øJŽÚ»Õó	\/Wg>3Û~J¯ma�As9ÞFßØcÊ8¬ªüÎ|Ÿ¶wFÏRŽ/å'ìÎqÚjFˆ;ë»²ãñ<ßV´Ë9lÐøíø5çÓ¶j–²âR¯áÁ�†gmð;Ó ¶`èã]ûES£®î[8-|k!Åš??ªwl~<nàÁSJeÐþ�ÅºŽc'¸Õ	s4,cÆÇ4¿
Û�$Â)¦ÇÏ>Þz¾[Wk%Ÿj²žnÞËÒSŒG Ýã�¶ÐåÖŠ[dùsÔ_é*x§úLÐÉZ?Ü�t=×pÇõnnu±Ëèê†Ô›¾ÇàÅÙØSîÊê”Š·m�ê-c¶mùµ"dNÊ¦£i¹¬Æy¬ž›Ž�ŠŸPT€%2c•òrCÅMê‡=Eçµp:õ Ý¯‚ò©/Ëšó=aµ&•ƒAýe9•ä³0u',ÂÍ`ÏYëwºÏné63Í¼Š–Õ€|ñÞXÈÖ|•f€3 2`o^Zv´!3Ž>V!ä@¿Éš©½]º¦:8ÐuÖ7)r»í€o+Ö n^ßA— (§–ƒ¦×L|‘BIU’±:"isAG9õŸ–#¬³ÍNûK1§ŠZ¥�ä¥ŽÉW×�S2ù™î¿«ˆQá1ùSÄ8¡­Øá©RéVåÅ¹¶±óû®"§ÄÜÅ Ó’“Dó6,¥ üî8%™–<0ãªù÷ÛJ¾F  Âão²ñRúë®\@‰jÿ`oÇ)²aš]ÚgŸÙ÷µØÈ´ErÅÂñH¬f[{7‡ÉZu˜´º¹âeåÏûMŽ=¢¿�Ÿµ¸å¶)•xªñšù‘�:#GòNÔj÷w�Íði²€ÕÞSk­’§V­Ü{‡ç—@Ù¾˜,I2æ2"S`Ãµ—™c&‚Å€Eqð�Å›å|?<¦aM®ióYXóoëDÁ7ÖÂ�3ú=Bº�öcí¬o4j¼ƒn&ý*U“$ƒ³3Å�Q™b\‚=NÛ�¯’êö/ß$Ó¬œ¹*m³víå$î²slWTBØÌ ð�Àïß’¨¸kÄ¡€í¡Râ,€‰®?Qã’p”•à*3µ @~�-w'*í#x˜i©çõÙ'pÙÈ¶8$è®Ã.@sWÖ1¨¹«š�.”þ]’«lG–�|Éw„IïŠÇ9…‘x·yàvÆv±Íi»Ü+Ë÷ÿÇþsoLÒ45LüCçé$*z�sõþ®’˜èîIDƒÈ[ÒT:áYÑý:Ö¡ê1?OB«¼neà³û‘ß?±óHÖÑÔ(ë¸Tº¶ KÌUÓ þ+éŸboäºTcç]*ƒ…7¶�hkšýTP¨±H®.�Å†èþ»5´ú²PÂîôûm	Ó-Åt+Û–Þ †|‡é§'†Xë¢/±2…•Âù]å^ªÆ4¯•�í¾½Ï£ó-Ç=!‡‹å‘€K#�r¿y4¸#<H­ñ vf¨vgÕ6ÄÆ&Y®¦G‹�ItÏñ¡…gýòŒ PŒØSõ¨ªÖpf4vlf€L OµkîÅl_¡kamêÛÑt³€Ü	—!g{‘µo/KÛ€“C‡£ÚLÓ„=GÙž¥DËÉtð�Ù0:û“\á'×àÿxè>±kÛi§õ‚,ŒiBFI ¹â‰q8öÜPºo/—–¡bD’WŸ+’ng()) {
        Napi::TypeError::New(env, "String expected").ThrowAsJavaScriptException();
        return;
    }
    auto filename = info[0].As<Napi::String>().Utf8Value();

    unsigned int pos = 1;

    int mode;
    if (info.Length() >= pos && info[pos].IsNumber() && OtherIsInt(info[pos].As<Napi::Number>())) {
        mode = info[pos++].As<Napi::Number>().Int32Value();
    }
    else {
        mode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
    }

    Napi::Function callback;
    if (info.Length() >= pos && info[pos].IsFunction()) {
        callback = info[pos++].As<Napi::Function>();
    }

    info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("filename", info[0].As<Napi::String>(), napi_default));
    info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("mode", Napi::Number::New(env, mode), napi_default));

    // Start opening the database.
    auto* baton = new OpenBaton(this, callback, filename.c_str(), mode);
    Work_BeginOpen(baton);
}

void Database::Work_BeginOpen(Baton* baton) {
    auto env = baton->db->Env();
    CREATE_WORK("sqlite3.Database.Open", Work_Open, Work_AfterOpen);
}

void Database::Work_Open(napi_env e, void* data) {
    auto* baton = static_cast<OpenBaton*>(data);
    auto* db = baton->db;

    baton->status = sqlite3_open_v2(
        baton->filename.c_str(),
        &db->_handle,
        baton->mode,
        NULL
    );

    if (baton->status != SQLITE_OK) {
        baton->message = std::string(sqlite3_errmsg(db->_handle));
        sqlite3_close(db->_handle);
        db->_handle = NULL;
    }
    else {
        // Set default database handle values.
        sqlite3_busy_timeout(db->_handle, 1000);
    }
}

void Database::Work_AfterOpen(napi_env e, napi_status status, void* data) {
    std::unique_ptr<OpenBaton> baton(static_cast<OpenBaton*>(data));

    auto* db = baton->db;

    auto env = db->Env();
    Napi::HandleScope scope(env);

    Napi::Value argv[1];
    if (baton->status != SQLITE_OK) {
        EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception);
        argv[0] = exception;
    }
    else {
        db->open = true;
        argv[0] = env.Null();
    }

    Napi::Function cb = baton->callback.Value();

    if (IS_FUNCTION(cb)) {
        TRY_CATCH_CALL(db->Value(), cb, 1, argv);
    }
    else if (!db->open) {
        Napi::Value info[] = { Napi::String::New(env, "error"), argv[0] };
        EMIT_EVENT(db->Value(), 2, info);
    }

    if (db->open) {
        Napi::Value info[] = { Napi::String::New(env, "open") };
        EMIT_EVENT(db->Value(), 1, info);
        db->Process();
    }
}

Napi::Value Database::Open(const Napi::CallbackInfo& info) {
    auto env = this->Env();
    auto* db = this;
    return Napi::Boolean::New(env, db->open);
}

Napi::Value Database::Close(const Napi::CallbackInfo& info) {
    auto env = info.Env();
    auto* db = this;
    OPTIONAL_ARGUMENT_FUNCTION(0, callback);

   auto* baton = new Baton(db, callback);
    db->Schedule(Work_BeginClose, baton, true);

    return info.This();
}

void Database::Work_BeginClose(Baton* baton) {
    assert(baton->db->locked);
    assert(baton->db->open);
    assert(baton->db->_handle);
    assert(baton->db->pending == 0);

    baton->db->pending++;
    baton->db->RemoveCallbacks();
    baton->db->closing = true;

    auto env = baton->db->Env();
    CREATE_WORK("sqlite3.Database.Close", Work_Close, Work_AfterClose);
}

void Database::Work_Close(napi_env e, void* data) {
    auto* baton = static_cast<Baton*>(data);
    auto* db = baton->db;

    baton->status = sqlite3_close(db->_handle);

    if (baton->status != SQLITE_OK) {
        baton->message = std::string(sqlite3_errmsg(db->_handle));
    }
    else {
        db->_handle = NULL;
    }
}

void Database::Work_AfterClose(napi_env e, napi_status status, void* data) {
    std::unique_ptr<Baton> baton(static_cast<Baton*>(data));

    auto* db = baton->db;

    auto env = db->Env();
    Napi::HandleScope scope(env);

    db->pending--;
    db->closing = false;

    Napi::Value argv[1];
    if (baton->status != SQLITE_OK) {
        EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception);
        argv[0] = exception;
    }
    else {
        db->open = false;
        // Leave db->locked to indicate that this db object has reached
        // the end of its life.
        argv[0] = env.Null();
    }

    Napi::Function cb = baton->callback.Value();

    // Fire callbacks.
    if (IS_FUNCTION(cb)) {
        TRY_CATCH_CALL(db->Value(), cb, 1, argv);
    }
    else if (db->open) {
        Napi::Value info[] = { Napi::String::New(env, "error"), argv[0] };
        EMIT_EVENT(db->Value(), 2, info);
    }

    if (!db->open) {
        Napi::Value info[] = { Napi::String::New(env, "close") };
        EMIT_EVENT(db->Value(), 1, info);
        db->Process();
    }
}

Napi::Value Database::Serialize(const Napi::CallbackInfo& info) {
    auto env = this->Env();
    auto* db = this;
    OPTIONAL_ARGUMENT_FUNCTION(0, callback);

    bool before = db->serialize;
    db->serialize = true;

    if (!callback.IsEmpty() && callback.IsFunction()) {
        TRY_CATCH_CALL(info.This(), callback, 0, NULL, info.This());
        db->serialize = before;
    }

    db->Process();

    return info.This();
}

Napi::Value Database::Parallelize(const Napi::CallbackInfo& info) {
    auto env = this->Env();
    auto* db = this;
    OPTIONAL_ARGUMENT_FUNCTION(0, callback);

    auto before = db->serialize;
    db->serialize = false;

    if (!callback.IsEmpty() && callback.IsFunction()) {
        TRY_CATCH_CALL(info.This(), callback, 0, NULL, info.This());
        db->serialize = before;
    }

    db->Process();

    return info.This();
}

Napi::Value Database::Configure(const Napi::CallbackInfo& info) {
    auto env = this->Env();
    auto* db = this;

    REQUIRE_ARGUMENTS(2);

    Napi::Function handle;
    if (info[0].StrictEquals( Napi::String::New(env, "trace"))) {    
       auto* baton = new Baton(db, handle);
        db->Schedule(RegisterTraceCallback, baton);
    }
    else if (info[0].StrictEquals( Napi::String::New(env, "profile"))) {
       auto* baton = new Baton(db, handle);
        db->Schedule(RegisterProfileCallback, baton);
    }
    else if (info[0].StrictEquals( Napi::String::New(env, "busyTimeout"))) {
        if (!info[1].IsNumber()) {
            Napi::TypeError::New(env, "Value must be an integer").ThrowAsJavaScriptException();
            return env.Null();
        }
       auto* baton = new Baton(db, handle);
        baton->status = info[1].As<Napi::Number>().Int32Value();
        db->Schedule(SetBusyTimeout, baton);
    }
    else if (info[0].StrictEquals( Napi::String::New(env, "limit"))) {
        REQUIRE_ARGUMENTS(3);
        if (!info[1].IsNumber()) {
            Napi::TypeError::New(env, "limit id must be an integer").ThrowAsJavaScriptException();
            return env.Null();
        }
        if (!info[2].IsNumber()) {
            Napi::TypeError::New(env, "limit value must be an integer").ThrowAsJavaScriptException();
            return env.Null();
        }
        int id = info[1].As<Napi::Number>().Int32Value();
        int value = info[2].As<Napi::Number>().Int32Value();
        Baton* baton = new LimitBaton(db, handle, id, value);
        db->Schedule(SetLimit, baton);
    }
    else if (info[0].StrictEquals(Napi::String::New(env, "change"))) {
       auto* baton = new Baton(db, handle);
        db->Schedule(RegisterUpdateCallback, baton);
    }
    else {
        Napi::TypeError::New(env, (StringConcat(
#if V8_MAJOR_VERSION > 6
            info.GetIsolate(),
#endif
            info[0].As<Napi::String>(),
            Napi::String::New(env, " is not a valid configuration option")
        )).Utf8Value().c_str()).ThrowAsJavaScriptException();
        return env.Null();
    }

    db->Process();

    return info.This();
}

Napi::Value Database::Interrupt(const Napi::CallbackInfo& info) {
    auto env = this->Env();
    auto* db = this;

    if (!db->open) {
        Napi::Error::New(env, "Database is not open").ThrowAsJavaScriptException();
        return env.Null();
    }

    if (db->closing) {
        Napi::Error::New(env, "Database is closing").ThrowAsJavaScriptException();
        return env.Null();
    }

    sqlite3_interrupt(db->_handle);
    return info.This();
}

void Database::SetBusyTimeout(Baton* b) {
    auto baton = std::unique_ptr<Baton>(b);

    assert(baton->db->open);
    assert(baton->db->_handle);

    // Abuse the status field for passing the timeout.
    sqlite3_busy_timeout(baton->db->_handle, baton->status);
}

void Database::SetLimit(Baton* b) {
    std::unique_ptr<LimitBaton> baton(static_cast<LimitBaton*>(b));

    assert(baton->db->open);
    assert(baton->db->_handle);

    sqlite3_limit(baton->db->_handle, baton->id, baton->value);
}

void Database::RegisterTraceCallback(Baton* b) {
    auto baton = std::unique_ptr<Baton>(b);
    assert(baton->db->open);
    assert(baton->db->_handle);
    auto* db = baton->db;

    if (db->debug_trace == NULL) {
        // Add it.
        db->debug_trace = new AsyncTrace(db, TraceCallback);
        sqlite3_trace(db->_handle, TraceCallback, db);
    }
    else {
        // Remove it.
        sqlite3_trace(db->_handle, NULL, NULL);
        db->debug_trace->finish();
        db->debug_trace = NULL;
    }
}

void Database::TraceCallback(void* db, const char* sql) {
    // Note: This function is called in the thread pool.
    // Note: Some queries, such as "EXPLAIN" queries, are not sent through this.
    static_cast<Database*>(db)->debug_trace->send(new std::string(sql));
}

void Database::TraceCallback(Database* db, std::string* s) {
    std::unique_ptr<std::string> sql(s);
    // Note: This function is called in the main V8 thread.
    auto env = db->Env();
    Napi::HandleScope scope(env);

    Napi::Value argv[] = {
        Napi::String::New(env, "trace"),
        Napi::String::New(env, sql->c_str())
    };
    EMIT_EVENT(db->Value(), 2, argv);
}

void Database::RegisterProfileCallback(Baton* b) {
    auto baton = std::unique_ptr<Baton>(b);
    assert(baton->db->open);
    assert(baton->db->_handle);
    auto* db = baton->db;

    if (db->debug_profile == NULL) {
        // Add it.
        db->debug_profile = new AsyncProfile(db, ProfileCallback);
        sqlite3_profile(db->_handle, ProfileCallback, db);
    }
    else {
        // Remove it.
        sqlite3_profile(db->_handle, NULL, NULL);
        db->debug_profile->finish();
        db->debug_profile = NULL;
    }
}

void Database::ProfileCallback(void* db, const char* sql, sqlite3_uint64 nsecs) {
    // Note: This function is called in the thread pool.
    // Note: Some queries, such as "EXPLAIN" queries, are not sent through this.
    auto* info = new ProfileInfo();
    info->sql = std::string(sql);
    info->nsecs = nsecs;
    static_cast<Database*>(db)->debug_profile->send(info);
}

void Database::ProfileCallback(Database *db, ProfileInfo* i) {
    auto info = std::unique_ptr<ProfileInfo>(i);
    auto env = db->Env();
    Napi::HandleScope scope(env);

    Napi::Value argv[] = {
        Napi::String::New(env, "profile"),
        Napi::String::New(env, info->sql.c_str()),
        Napi::Number::New(env, (double)info->nsecs / 1000000.0)
    };
    EMIT_EVENT(db->Value(), 3, argv);
}

void Database::RegisterUpdateCallback(Baton* b) {
    auto baton = std::unique_ptr<Baton>(b);
    assert(baton->db->open);
    assert(baton->db->_handle);
    auto* db = baton->db;

    if (db->update_event == NULL) {
        // Add it.
        db->update_event = new AsyncUpdate(db, UpdateCallback);
        sqlite3_update_hook(db->_handle, UpdateCallback, db);
    }
    else {
        // Remove it.
        sqlite3_update_hook(db->_handle, NULL, NULL);
        db->update_event->finish();
        db->update_event = NULL;
    }
}

void Database::UpdateCallback(void* db, int type, const char* database,
        const char* table, sqlite3_int64 rowid) {
    // Note: This function is called in the thread pool.
    // Note: Some queries, such as "EXPLAIN" queries, are not sent through this.
    auto* info = new UpdateInfo();
    info->type = type;
    info->database = std::string(database);
    info->table = std::string(table);
    info->rowid = rowid;
    static_cast<Database*>(db)->update_event->send(info);
}

void Database::UpdateCallback(Database *db, UpdateInfo* i) {
    auto info = std::unique_ptr<UpdateInfo>(i);
    auto env = db->Env();
    Napi::HandleScope scope(env);

    Napi::Value argv[] = {
        Napi::String::New(env, "change"),
        Napi::String::New(env, sqlite_authorizer_string(info->type)),
        Napi::String::New(env, info->database.c_str()),
        Napi::String::New(env, info->table.c_str()),
        Napi::Number::New(env, info->rowid),
    };
    EMIT_EVENT(db->Value(), 5, argv);
}

Napi::Value Database::Exec(const Napi::CallbackInfo& info) {
    auto env = this->Env();
    auto* db = this;

    REQUIRE_ARGUMENT_STRING(0, sql);
    OPTIONAL_ARGUMENT_FUNCTION(1, callback);

    Baton* baton = new ExecBaton(db, callback, sql.c_str());
    db->Schedule(Work_BeginExec, baton, true);

    return info.This();
}

void Database::Work_BeginExec(Baton* baton) {
    assert(baton->db->locked);
    assert(baton->db->open);
    assert(baton->db->_handle);
    assert(baton->db->pending == 0);
    baton->db->pending++;

    auto env = baton->db->Env();
    CREATE_WORK("sqlite3.Database.Exec", Work_Exec, Work_AfterExec);
}

void Database::Work_Exec(napi_env e, void* data) {
    auto* baton = static_cast<ExecBaton*>(data);

    char* message = NULL;
    baton->status = sqlite3_exec(
        baton->db->_handle,
        baton->sql.c_str(),
        NULL,
        NULL,
        &message
    );

    if (baton->status != SQLITE_OK && message != NULL) {
        baton->message = std::string(message);
        sqlite3_free(message);
    }
}

void Database::Work_AfterExec(napi_env e, napi_status status, void* data) {
    std::unique_ptr<ExecBaton> baton(static_cast<ExecBaton*>(data));

    auto* db = baton->db;
    db->pending--;

    auto env = db->Env();
    Napi::HandleScope scope(env);

    Napi::Function cb = baton->callback.Value();

    if (baton->status != SQLITE_OK) {
        EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception);

        if (IS_FUNCTION(cb)) {
            Napi::Value argv[] = { exception };
            TRY_CATCH_CALL(db->Value(), cb, 1, argv);
        }
        else {
            Napi::Value info[] = { Napi::String::New(env, "error"), exception };
            EMIT_EVENT(db->Value(), 2, info);
        }
    }
    else if (IS_FUNCTION(cb)) {
        Napi::Value argv[] = { env.Null() };
        TRY_CATCH_CALL(db->Value(), cb, 1, argv);
    }

    db->Process();
}

Napi::Value Database::Wait(const Napi::CallbackInfo& info) {
    auto env = info.Env();
    auto* db = this;

    OPTIONAL_ARGUMENT_FUNCTION(0, callback);

   auto* baton = new Baton(db, callback);
    db->Schedule(Work_Wait, baton, true);

    return info.This();
}

void Database::Work_Wait(Baton* b) {
    auto baton = std::unique_ptr<Baton>(b);

    auto env = baton->db->Env();
    Napi::HandleScope scope(env);

    assert(baton->db->locked);
    assert(baton->db->open);
    assert(baton->db->_handle);
    assert(baton->db->pending == 0);

    Napi::Function cb = baton->callback.Value();
    if (IS_FUNCTION(cb)) {
        Napi::Value argv[] = { env.Null() };
        TRY_CATCH_CALL(baton->db->Value(), cb, 1, argv);
    }

    baton->db->Process();
}

Napi::Value Database::LoadExtension(const Napi::CallbackInfo& info) {
    auto env = this->Env();
    auto* db = this;

    REQUIRE_ARGUMENT_STRING(0, filename);
    OPTIONAL_ARGUMENT_FUNCTION(1, callback);

    Baton* baton = new LoadExtensionBaton(db, callback, filename.c_str());
    db->Schedule(Work_BeginLoadExtension, baton, true);

    return info.This();
}

void Database::Work_BeginLoadExtension(Baton* baton) {
    assert(baton->db->locked);
    assert(baton->db->open);
    assert(baton->db->_handle);
    assert(baton->db->pending == 0);
    baton->db->pending++;

    auto env = baton->db->Env();
    CREATE_WORK("sqlite3.Database.LoadExtension", Work_LoadExtension, Work_AfterLoadExtension);
}

void Database::Work_LoadExtension(napi_env e, void* data) {
    auto* baton = static_cast<LoadExtensionBaton*>(data);

    sqlite3_enable_load_extension(baton->db->_handle, 1);

    char* message = NULL;
    baton->status = sqlite3_load_extension(
        baton->db->_handle,
        baton->filename.c_str(),
        0,
        &message
    );

    sqlite3_enable_load_extension(baton->db->_handle, 0);

    if (baton->status != SQLITE_OK && message != NULL) {
        baton->message = std::string(message);
        sqlite3_free(message);
    }
}

void Database::Work_AfterLoadExtension(napi_env e, napi_status status, void* data) {
    std::unique_ptr<LoadExtensionBaton> baton(static_cast<LoadExtensionBaton*>(data));

    auto* db = baton->db;
    db->pending--;

    auto env = db->Env();
    Napi::HandleScope scope(env);

    Napi::Function cb = baton->callback.Value();

    if (baton->status != SQLITE_OK) {
        EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception);

        if (IS_FUNCTION(cb)) {
            Napi::Value argv[] = { exception };
            TRY_CATCH_CALL(db->Value(), cb, 1, argv);
        }
        else {
            Napi::Value info[] = { Napi::String::New(env, "error"), exception };
            EMIT_EVENT(db->Value(), 2, info);
        }
    }
    else if (IS_FUNCTION(cb)) {
        Napi::Value argv[] = { env.Null() };
        TRY_CATCH_CALL(db->Value(), cb, 1, argv);
    }

    db->Process();
}

void Database::RemoveCallbacks() {
    if (debug_trace) {
        debug_trace->finish();
        debug_trace = NULL;
    }
    if (debug_profile) {
        debug_profile->finish();
        debug_profile = NULL;
    }
    if (update_event) {
        update_event->finish();
        update_event = NULL;
    }
}
