| [81bc7da] | 1 | #ifndef NODE_SQLITE3_SRC_MACROS_H
|
|---|
| 2 | #define NODE_SQLITE3_SRC_MACROS_H
|
|---|
| 3 |
|
|---|
| 4 | const char* sqlite_code_string(int code);
|
|---|
| 5 | const char* sqlite_authorizer_string(int type);
|
|---|
| 6 | #include <vector>
|
|---|
| 7 |
|
|---|
| 8 | // TODO: better way to work around StringConcat?
|
|---|
| 9 | #include <napi.h>
|
|---|
| 10 | inline Napi::String StringConcat(Napi::Value str1, Napi::Value str2) {
|
|---|
| 11 | return Napi::String::New(str1.Env(), str1.As<Napi::String>().Utf8Value() +
|
|---|
| 12 | str2.As<Napi::String>().Utf8Value() );
|
|---|
| 13 | }
|
|---|
| 14 |
|
|---|
| 15 | // A Napi substitute IsInt32()
|
|---|
| 16 | inline bool OtherIsInt(Napi::Number source) {
|
|---|
| 17 | double orig_val = source.DoubleValue();
|
|---|
| 18 | double int_val = static_cast<double>(source.Int32Value());
|
|---|
| 19 | if (orig_val == int_val) {
|
|---|
| 20 | return true;
|
|---|
| 21 | } else {
|
|---|
| 22 | return false;
|
|---|
| 23 | }
|
|---|
| 24 | }
|
|---|
| 25 |
|
|---|
| 26 | #define IS_FUNCTION(cb) \
|
|---|
| 27 | !cb.IsUndefined() && cb.IsFunction()
|
|---|
| 28 |
|
|---|
| 29 | #define REQUIRE_ARGUMENTS(n) \
|
|---|
| 30 | if (info.Length() < (n)) { \
|
|---|
| 31 | Napi::TypeError::New(env, "Expected " #n "arguments").ThrowAsJavaScriptException(); \
|
|---|
| 32 | return env.Null(); \
|
|---|
| 33 | }
|
|---|
| 34 |
|
|---|
| 35 |
|
|---|
| 36 | #define REQUIRE_ARGUMENT_EXTERNAL(i, var) \
|
|---|
| 37 | if (info.Length() <= (i) || !info[i].IsExternal()) { \
|
|---|
| 38 | Napi::TypeError::New(env, "Argument " #i " invalid").ThrowAsJavaScriptException(); \
|
|---|
| 39 | return env.Null(); \
|
|---|
| 40 | } \
|
|---|
| 41 | Napi::External var = info[i].As<Napi::External>();
|
|---|
| 42 |
|
|---|
| 43 |
|
|---|
| 44 | #define REQUIRE_ARGUMENT_FUNCTION(i, var) \
|
|---|
| 45 | if (info.Length() <= (i) || !info[i].IsFunction()) { \
|
|---|
| 46 | Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \
|
|---|
| 47 | return env.Null(); \
|
|---|
| 48 | } \
|
|---|
| 49 | Napi::Function var = info[i].As<Napi::Function>();
|
|---|
| 50 |
|
|---|
| 51 |
|
|---|
| 52 | #define REQUIRE_ARGUMENT_STRING(i, var) \
|
|---|
| 53 | if (info.Length() <= (i) || !info[i].IsString()) { \
|
|---|
| 54 | Napi::TypeError::New(env, "Argument " #i " must be a string").ThrowAsJavaScriptException(); \
|
|---|
| 55 | return env.Null(); \
|
|---|
| 56 | } \
|
|---|
| 57 | std::string var = info[i].As<Napi::String>();
|
|---|
| 58 |
|
|---|
| 59 | #define REQUIRE_ARGUMENT_INTEGER(i, var) \
|
|---|
| 60 | if (info.Length() <= (i) || !info[i].IsNumber()) { \
|
|---|
| 61 | Napi::TypeError::New(env, "Argument " #i " must be an integer").ThrowAsJavaScriptException(); \
|
|---|
| 62 | return env.Null(); \
|
|---|
| 63 | } \
|
|---|
| 64 | int var(info[i].As<Napi::Number>().Int32Value());
|
|---|
| 65 |
|
|---|
| 66 | #define OPTIONAL_ARGUMENT_FUNCTION(i, var) \
|
|---|
| 67 | Napi::Function var; \
|
|---|
| 68 | if (info.Length() > i && !info[i].IsUndefined()) { \
|
|---|
| 69 | if (!info[i].IsFunction()) { \
|
|---|
| 70 | Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \
|
|---|
| 71 | return env.Null(); \
|
|---|
| 72 | } \
|
|---|
| 73 | var = info[i].As<Napi::Function>(); \
|
|---|
| 74 | }
|
|---|
| 75 |
|
|---|
| 76 |
|
|---|
| 77 | #define OPTIONAL_ARGUMENT_INTEGER(i, var, default) \
|
|---|
| 78 | int var; \
|
|---|
| 79 | if (info.Length() <= (i)) { \
|
|---|
| 80 | var = (default); \
|
|---|
| 81 | } \
|
|---|
| 82 | else if (info[i].IsNumber()) { \
|
|---|
| 83 | if (OtherIsInt(info[i].As<Number>())) { \
|
|---|
| 84 | var = info[i].As<Napi::Number>().Int32Value(); \
|
|---|
| 85 | } \
|
|---|
| 86 | } \
|
|---|
| 87 | else { \
|
|---|
| 88 | Napi::TypeError::New(env, "Argument " #i " must be an integer").ThrowAsJavaScriptException(); \
|
|---|
| 89 | return env.Null(); \
|
|---|
| 90 | }
|
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 | #define DEFINE_CONSTANT_INTEGER(target, constant, name) \
|
|---|
| 94 | Napi::PropertyDescriptor::Value(#name, Napi::Number::New(env, constant), \
|
|---|
| 95 | static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)),
|
|---|
| 96 |
|
|---|
| 97 | #define DEFINE_CONSTANT_STRING(target, constant, name) \
|
|---|
| 98 | Napi::PropertyDescriptor::Value(#name, Napi::String::New(env, constant), \
|
|---|
| 99 | static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)),
|
|---|
| 100 |
|
|---|
| 101 | #define EXCEPTION(msg, errno, name) \
|
|---|
| 102 | Napi::Value name = Napi::Error::New(env, \
|
|---|
| 103 | StringConcat( \
|
|---|
| 104 | StringConcat( \
|
|---|
| 105 | Napi::String::New(env, sqlite_code_string(errno)), \
|
|---|
| 106 | Napi::String::New(env, ": ") \
|
|---|
| 107 | ), \
|
|---|
| 108 | (msg) \
|
|---|
| 109 | ).Utf8Value() \
|
|---|
| 110 | ).Value(); \
|
|---|
| 111 | Napi::Object name ##_obj = name.As<Napi::Object>(); \
|
|---|
| 112 | (name ##_obj).Set( Napi::String::New(env, "errno"), Napi::Number::New(env, errno)); \
|
|---|
| 113 | (name ##_obj).Set( Napi::String::New(env, "code"), \
|
|---|
| 114 | Napi::String::New(env, sqlite_code_string(errno)));
|
|---|
| 115 |
|
|---|
| 116 |
|
|---|
| 117 | #define EMIT_EVENT(obj, argc, argv) \
|
|---|
| 118 | TRY_CATCH_CALL((obj), \
|
|---|
| 119 | (obj).Get("emit").As<Napi::Function>(),\
|
|---|
| 120 | argc, argv \
|
|---|
| 121 | );
|
|---|
| 122 |
|
|---|
| 123 | // The Mac OS compiler complains when argv is NULL unless we
|
|---|
| 124 | // first assign it to a locally defined variable.
|
|---|
| 125 | #define TRY_CATCH_CALL(context, callback, argc, argv, ...) \
|
|---|
| 126 | Napi::Value* passed_argv = argv;\
|
|---|
| 127 | std::vector<napi_value> args;\
|
|---|
| 128 | if ((argc != 0) && (passed_argv != NULL)) {\
|
|---|
| 129 | args.assign(passed_argv, passed_argv + argc);\
|
|---|
| 130 | }\
|
|---|
| 131 | Napi::Value res = (callback).Call(Napi::Value(context), args); \
|
|---|
| 132 | if (res.IsEmpty()) return __VA_ARGS__;
|
|---|
| 133 |
|
|---|
| 134 | #define WORK_DEFINITION(name) \
|
|---|
| 135 | Napi::Value name(const Napi::CallbackInfo& info); \
|
|---|
| 136 | static void Work_Begin##name(Baton* baton); \
|
|---|
| 137 | static void Work_##name(napi_env env, void* data); \
|
|---|
| 138 | static void Work_After##name(napi_env env, napi_status status, void* data);
|
|---|
| 139 |
|
|---|
| 140 | #ifdef DEBUG
|
|---|
| 141 | #define ASSERT_STATUS() assert(status == 0);
|
|---|
| 142 | #else
|
|---|
| 143 | #define ASSERT_STATUS() (void)status;
|
|---|
| 144 | #endif
|
|---|
| 145 |
|
|---|
| 146 | #define CREATE_WORK(name, workerFn, afterFn) \
|
|---|
| 147 | int status = napi_create_async_work(env, NULL, Napi::String::New(env, name),\
|
|---|
| 148 | workerFn, afterFn, baton, &baton->request); \
|
|---|
| 149 | \
|
|---|
| 150 | ASSERT_STATUS(); \
|
|---|
| 151 | napi_queue_async_work(env, baton->request);
|
|---|
| 152 |
|
|---|
| 153 | #define STATEMENT_BEGIN(type) \
|
|---|
| 154 | assert(baton); \
|
|---|
| 155 | assert(baton->stmt); \
|
|---|
| 156 | assert(!baton->stmt->locked); \
|
|---|
| 157 | assert(!baton->stmt->finalized); \
|
|---|
| 158 | assert(baton->stmt->prepared); \
|
|---|
| 159 | baton->stmt->locked = true; \
|
|---|
| 160 | baton->stmt->db->pending++; \
|
|---|
| 161 | auto env = baton->stmt->Env(); \
|
|---|
| 162 | CREATE_WORK("sqlite3.Statement."#type, Work_##type, Work_After##type);
|
|---|
| 163 |
|
|---|
| 164 | #define STATEMENT_INIT(type) \
|
|---|
| 165 | type* baton = static_cast<type*>(data); \
|
|---|
| 166 | Statement* stmt = baton->stmt;
|
|---|
| 167 |
|
|---|
| 168 | #define STATEMENT_MUTEX(name) \
|
|---|
| 169 | if (!stmt->db->_handle) { \
|
|---|
| 170 | stmt->status = SQLITE_MISUSE; \
|
|---|
| 171 | stmt->message = "Database handle is closed"; \
|
|---|
| 172 | return; \
|
|---|
| 173 | } \
|
|---|
| 174 | sqlite3_mutex* name = sqlite3_db_mutex(stmt->db->_handle);
|
|---|
| 175 |
|
|---|
| 176 | #define STATEMENT_END() \
|
|---|
| 177 | assert(stmt->locked); \
|
|---|
| 178 | assert(stmt->db->pending); \
|
|---|
| 179 | stmt->locked = false; \
|
|---|
| 180 | stmt->db->pending--; \
|
|---|
| 181 | stmt->Process(); \
|
|---|
| 182 | stmt->db->Process();
|
|---|
| 183 |
|
|---|
| 184 | #define BACKUP_BEGIN(type) \
|
|---|
| 185 | assert(baton); \
|
|---|
| 186 | assert(baton->backup); \
|
|---|
| 187 | assert(!baton->backup->locked); \
|
|---|
| 188 | assert(!baton->backup->finished); \
|
|---|
| 189 | assert(baton->backup->inited); \
|
|---|
| 190 | baton->backup->locked = true; \
|
|---|
| 191 | baton->backup->db->pending++; \
|
|---|
| 192 | auto env = baton->backup->Env(); \
|
|---|
| 193 | CREATE_WORK("sqlite3.Backup."#type, Work_##type, Work_After##type);
|
|---|
| 194 |
|
|---|
| 195 | #define BACKUP_INIT(type) \
|
|---|
| 196 | type* baton = static_cast<type*>(data); \
|
|---|
| 197 | Backup* backup = baton->backup;
|
|---|
| 198 |
|
|---|
| 199 | #define BACKUP_END() \
|
|---|
| 200 | assert(backup->locked); \
|
|---|
| 201 | assert(backup->db->pending); \
|
|---|
| 202 | backup->locked = false; \
|
|---|
| 203 | backup->db->pending--; \
|
|---|
| 204 | backup->Process(); \
|
|---|
| 205 | backup->db->Process();
|
|---|
| 206 |
|
|---|
| 207 | #endif |
|---|