pi-para 0.7.8 → 0.7.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/node_modules/better-sqlite3/LICENSE +21 -0
  3. package/node_modules/better-sqlite3/README.md +99 -0
  4. package/node_modules/better-sqlite3/binding.gyp +60 -0
  5. package/node_modules/better-sqlite3/deps/common.gypi +68 -0
  6. package/node_modules/better-sqlite3/deps/copy.js +31 -0
  7. package/node_modules/better-sqlite3/deps/defines.gypi +42 -0
  8. package/node_modules/better-sqlite3/deps/download.sh +123 -0
  9. package/node_modules/better-sqlite3/deps/patches/1208.patch +15 -0
  10. package/node_modules/better-sqlite3/deps/sqlite3/sqlite3.c +269668 -0
  11. package/node_modules/better-sqlite3/deps/sqlite3/sqlite3.h +14349 -0
  12. package/node_modules/better-sqlite3/deps/sqlite3/sqlite3ext.h +739 -0
  13. package/node_modules/better-sqlite3/deps/sqlite3.gyp +80 -0
  14. package/node_modules/better-sqlite3/deps/test_extension.c +21 -0
  15. package/node_modules/better-sqlite3/lib/binding.js +62 -0
  16. package/node_modules/better-sqlite3/lib/darwin-arm64.js +3 -0
  17. package/node_modules/better-sqlite3/lib/darwin-x64.js +3 -0
  18. package/node_modules/better-sqlite3/lib/database.js +109 -0
  19. package/node_modules/better-sqlite3/lib/index.js +3 -0
  20. package/node_modules/better-sqlite3/lib/linux-arm64.js +3 -0
  21. package/node_modules/better-sqlite3/lib/linux-x64.js +3 -0
  22. package/node_modules/better-sqlite3/lib/linuxmusl-arm64.js +4 -0
  23. package/node_modules/better-sqlite3/lib/linuxmusl-x64.js +4 -0
  24. package/node_modules/better-sqlite3/lib/methods/aggregate.js +43 -0
  25. package/node_modules/better-sqlite3/lib/methods/backup.js +67 -0
  26. package/node_modules/better-sqlite3/lib/methods/explain.js +9 -0
  27. package/node_modules/better-sqlite3/lib/methods/function.js +31 -0
  28. package/node_modules/better-sqlite3/lib/methods/inspect.js +7 -0
  29. package/node_modules/better-sqlite3/lib/methods/pragma.js +12 -0
  30. package/node_modules/better-sqlite3/lib/methods/serialize.js +16 -0
  31. package/node_modules/better-sqlite3/lib/methods/table.js +195 -0
  32. package/node_modules/better-sqlite3/lib/methods/transaction.js +78 -0
  33. package/node_modules/better-sqlite3/lib/methods/wrappers.js +54 -0
  34. package/node_modules/better-sqlite3/lib/sqlite-error.js +25 -0
  35. package/node_modules/better-sqlite3/lib/util.js +12 -0
  36. package/node_modules/better-sqlite3/lib/win32-arm64.js +3 -0
  37. package/node_modules/better-sqlite3/lib/win32-x64.js +3 -0
  38. package/node_modules/better-sqlite3/package.json +67 -0
  39. package/node_modules/better-sqlite3/prebuilds/darwin-arm64.node +0 -0
  40. package/node_modules/better-sqlite3/prebuilds/darwin-x64.node +0 -0
  41. package/node_modules/better-sqlite3/prebuilds/linux-arm64.node +0 -0
  42. package/node_modules/better-sqlite3/prebuilds/linux-x64.node +0 -0
  43. package/node_modules/better-sqlite3/prebuilds/linuxmusl-arm64.node +0 -0
  44. package/node_modules/better-sqlite3/prebuilds/linuxmusl-x64.node +0 -0
  45. package/node_modules/better-sqlite3/prebuilds/win32-arm64.node +0 -0
  46. package/node_modules/better-sqlite3/prebuilds/win32-x64.node +0 -0
  47. package/node_modules/better-sqlite3/src/addon.cpp +59 -0
  48. package/node_modules/better-sqlite3/src/better_sqlite3.cpp +73 -0
  49. package/node_modules/better-sqlite3/src/objects/backup.cpp +121 -0
  50. package/node_modules/better-sqlite3/src/objects/backup.hpp +32 -0
  51. package/node_modules/better-sqlite3/src/objects/database.cpp +432 -0
  52. package/node_modules/better-sqlite3/src/objects/database.hpp +100 -0
  53. package/node_modules/better-sqlite3/src/objects/statement-iterator.cpp +119 -0
  54. package/node_modules/better-sqlite3/src/objects/statement-iterator.hpp +71 -0
  55. package/node_modules/better-sqlite3/src/objects/statement.cpp +380 -0
  56. package/node_modules/better-sqlite3/src/objects/statement.hpp +65 -0
  57. package/node_modules/better-sqlite3/src/util/bind-map.cpp +73 -0
  58. package/node_modules/better-sqlite3/src/util/binder.cpp +210 -0
  59. package/node_modules/better-sqlite3/src/util/constants.cpp +172 -0
  60. package/node_modules/better-sqlite3/src/util/custom-aggregate.cpp +121 -0
  61. package/node_modules/better-sqlite3/src/util/custom-function.cpp +59 -0
  62. package/node_modules/better-sqlite3/src/util/custom-table.cpp +406 -0
  63. package/node_modules/better-sqlite3/src/util/data-converter.cpp +17 -0
  64. package/node_modules/better-sqlite3/src/util/data.cpp +134 -0
  65. package/node_modules/better-sqlite3/src/util/helpers.cpp +190 -0
  66. package/node_modules/better-sqlite3/src/util/macros.cpp +74 -0
  67. package/node_modules/better-sqlite3/src/util/query-macros.cpp +71 -0
  68. package/node_modules/better-sqlite3/src/util/row-builder.cpp +53 -0
  69. package/node_modules/better-sqlite3/src/util/row-builder.hpp +22 -0
  70. package/node_modules/node-addon-api/LICENSE.md +9 -0
  71. package/node_modules/node-addon-api/README.md +95 -0
  72. package/node_modules/node-addon-api/common.gypi +21 -0
  73. package/node_modules/node-addon-api/except.gypi +25 -0
  74. package/node_modules/node-addon-api/index.js +14 -0
  75. package/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
  76. package/node_modules/node-addon-api/napi-inl.h +7165 -0
  77. package/node_modules/node-addon-api/napi.h +3364 -0
  78. package/node_modules/node-addon-api/node_addon_api.gyp +42 -0
  79. package/node_modules/node-addon-api/node_api.gyp +9 -0
  80. package/node_modules/node-addon-api/noexcept.gypi +26 -0
  81. package/node_modules/node-addon-api/nothing.c +0 -0
  82. package/node_modules/node-addon-api/package-support.json +21 -0
  83. package/node_modules/node-addon-api/package.json +480 -0
  84. package/node_modules/node-addon-api/tools/README.md +73 -0
  85. package/node_modules/node-addon-api/tools/check-napi.js +99 -0
  86. package/node_modules/node-addon-api/tools/clang-format.js +71 -0
  87. package/node_modules/node-addon-api/tools/conversion.js +301 -0
  88. package/package.json +5 -2
@@ -0,0 +1,119 @@
1
+ const napi_type_tag StatementIterator::TYPE_TAG = RandomTypeTag();
2
+
3
+ StatementIterator::StatementIterator(const Napi::CallbackInfo& info) :
4
+ Napi::ObjectWrap<StatementIterator>(info),
5
+ stmt(NULL),
6
+ handle(NULL),
7
+ db_state(NULL),
8
+ bound(false),
9
+ safe_ints(false),
10
+ mode(Data::FLAT),
11
+ alive(false),
12
+ logged(false) {
13
+ TYPE_TAG_CONSTRUCTOR(info);
14
+ JS_new(info);
15
+ }
16
+
17
+ // The ~Statement destructor currently covers any state this object creates.
18
+ // Additionally, we actually DON'T want to revert stmt->locked or db_state
19
+ // ->iterators in this destructor, to ensure deterministic database access.
20
+ StatementIterator::~StatementIterator() {}
21
+
22
+ Napi::Value StatementIterator::Next(Napi::Env env) {
23
+ assert(alive == true);
24
+ db_state->busy = true;
25
+ if (!logged) {
26
+ logged = true;
27
+ if (stmt->db->Log(env, handle)) {
28
+ db_state->busy = false;
29
+ return Throw(env);
30
+ }
31
+ }
32
+ int status = sqlite3_step(handle);
33
+ db_state->busy = false;
34
+
35
+ if (status == SQLITE_ROW) {
36
+ Napi::Value row = Data::GetRowJS(env, stmt, handle, safe_ints, mode);
37
+ return NewRecord(env, row, db_state->addon, false);
38
+ } else {
39
+ if (status == SQLITE_DONE) return Return(env);
40
+ return Throw(env);
41
+ }
42
+ }
43
+
44
+ Napi::Value StatementIterator::Return(Napi::Env env) {
45
+ Cleanup();
46
+ STATEMENT_RETURN_LOGIC(DoneRecord(env, db_state->addon));
47
+ }
48
+
49
+ Napi::Value StatementIterator::Throw(Napi::Env env) {
50
+ Cleanup();
51
+ Database* db = stmt->db;
52
+ STATEMENT_THROW_LOGIC();
53
+ }
54
+
55
+ void StatementIterator::Cleanup() {
56
+ assert(alive == true);
57
+ alive = false;
58
+ stmt->locked = false;
59
+ db_state->iterators -= 1;
60
+ sqlite3_reset(handle);
61
+ }
62
+
63
+ INIT(StatementIterator::Init) {
64
+ return DefineClass(env, "StatementIterator", {
65
+ PrototypeMethod<StatementIterator, &StatementIterator::JS_next>("next", addon),
66
+ PrototypeMethod<StatementIterator, &StatementIterator::JS_return>("return", addon),
67
+ PrototypeSymbolMethod<StatementIterator, &StatementIterator::JS_symbolIterator>(Napi::Symbol::WellKnown(env, "iterator"), addon),
68
+ }, addon);
69
+ }
70
+
71
+ NODE_METHOD(StatementIterator::JS_new) {
72
+ UseAddon;
73
+ if (!addon->privileged_info) return ThrowTypeError(info.Env(), "Disabled constructor");
74
+ assert(info.IsConstructCall());
75
+
76
+ {
77
+ const Napi::CallbackInfo& info = *addon->privileged_info;
78
+ STATEMENT_START_LOGIC(REQUIRE_STATEMENT_RETURNS_DATA, DOES_ADD_ITERATOR);
79
+ this->stmt = stmt;
80
+ this->handle = stmt->handle;
81
+ this->db_state = stmt->db->GetState();
82
+ this->bound = bound;
83
+ this->safe_ints = stmt->safe_ints;
84
+ this->mode = stmt->mode;
85
+ this->alive = true;
86
+ this->logged = !db_state->has_logger;
87
+ assert(stmt != NULL);
88
+ assert(handle != NULL);
89
+ assert(stmt->bound == bound);
90
+ assert(stmt->alive == true);
91
+ assert(stmt->locked == false);
92
+ assert(db_state->iterators < USHRT_MAX);
93
+ stmt->locked = true;
94
+ db_state->iterators += 1;
95
+ }
96
+
97
+ UseIsolate;
98
+ SetFrozen(env, info.This().As<Napi::Object>(), addon->cs.statement, addon->privileged_info->This());
99
+
100
+ return info.This();
101
+ }
102
+
103
+ NODE_METHOD(StatementIterator::JS_next) {
104
+ UNWRAP_OR_RETURN(StatementIterator, iter, info.This());
105
+ REQUIRE_DATABASE_NOT_BUSY(iter->db_state);
106
+ if (iter->alive) return iter->Next(info.Env());
107
+ return DoneRecord(info.Env(), iter->db_state->addon);
108
+ }
109
+
110
+ NODE_METHOD(StatementIterator::JS_return) {
111
+ UNWRAP_OR_RETURN(StatementIterator, iter, info.This());
112
+ REQUIRE_DATABASE_NOT_BUSY(iter->db_state);
113
+ if (iter->alive) return iter->Return(info.Env());
114
+ return DoneRecord(info.Env(), iter->db_state->addon);
115
+ }
116
+
117
+ NODE_METHOD(StatementIterator::JS_symbolIterator) {
118
+ return info.This();
119
+ }
@@ -0,0 +1,71 @@
1
+ class StatementIterator : public Napi::ObjectWrap<StatementIterator> {
2
+ public:
3
+
4
+ // The ~Statement destructor currently covers any state this object creates.
5
+ // Additionally, we actually DON'T want to revert stmt->locked or db_state
6
+ // ->iterators in this destructor, to ensure deterministic database access.
7
+ explicit StatementIterator(const Napi::CallbackInfo& info);
8
+ ~StatementIterator();
9
+
10
+ // Identifies objects that are backed by this class (see IsInstanceOf).
11
+ static const napi_type_tag TYPE_TAG;
12
+
13
+ static INIT(Init);
14
+
15
+ private:
16
+
17
+ Napi::Value Next(Napi::Env env);
18
+ Napi::Value Return(Napi::Env env);
19
+ Napi::Value Throw(Napi::Env env);
20
+ void Cleanup();
21
+
22
+ static inline Napi::Object NewRecord(
23
+ Napi::Env env,
24
+ Napi::Value value,
25
+ Addon* addon,
26
+ bool done
27
+ ) {
28
+ assert(!addon->RecordFactory.IsEmpty());
29
+
30
+ // Fast path, using a factory function from JS land.
31
+ if (!done) {
32
+ napi_value arg = value;
33
+ return SafeCall(env, addon->RecordFactory.Value(), env.Undefined(), 1, &arg)
34
+ .As<Napi::Object>();
35
+ }
36
+
37
+ // Slow path, only used after the iterator is done.
38
+ napi_property_descriptor properties[2] = {};
39
+ properties[0].name = addon->cs.value.Value();
40
+ properties[0].value = value;
41
+ properties[0].attributes = DEFAULT_ATTRIBUTES;
42
+ properties[1].name = addon->cs.done.Value();
43
+ properties[1].value = Napi::Boolean::New(env, done);
44
+ properties[1].attributes = DEFAULT_ATTRIBUTES;
45
+
46
+ napi_value record;
47
+ napi_status status = napi_create_object(env, &record);
48
+ assert(status == napi_ok || status == napi_cannot_run_js);
49
+ status = napi_define_properties(env, record, 2, properties);
50
+ assert(status == napi_ok || status == napi_cannot_run_js); ((void)status);
51
+ return Napi::Object(env, record);
52
+ }
53
+
54
+ static inline Napi::Object DoneRecord(Napi::Env env, Addon* addon) {
55
+ return NewRecord(env, env.Undefined(), addon, true);
56
+ }
57
+
58
+ NODE_METHOD(JS_new);
59
+ static NODE_METHOD(JS_next);
60
+ static NODE_METHOD(JS_return);
61
+ static NODE_METHOD(JS_symbolIterator);
62
+
63
+ Statement* stmt;
64
+ sqlite3_stmt* handle;
65
+ Database::State* db_state;
66
+ bool bound;
67
+ bool safe_ints;
68
+ char mode;
69
+ bool alive;
70
+ bool logged;
71
+ };
@@ -0,0 +1,380 @@
1
+ const napi_type_tag Statement::TYPE_TAG = RandomTypeTag();
2
+
3
+ Statement::Statement(const Napi::CallbackInfo& info) :
4
+ Napi::ObjectWrap<Statement>(info),
5
+ db(NULL),
6
+ handle(NULL),
7
+ extras(NULL),
8
+ alive(false),
9
+ locked(false),
10
+ bound(false),
11
+ has_bind_map(false),
12
+ safe_ints(false),
13
+ mode(Data::FLAT),
14
+ returns_data(false) {
15
+ TYPE_TAG_CONSTRUCTOR(info);
16
+ JS_new(info);
17
+ }
18
+
19
+ Statement::~Statement() {
20
+ if (alive) db->RemoveStatement(this);
21
+ CloseHandles();
22
+ delete extras;
23
+ }
24
+
25
+ // Whenever this is used, db->RemoveStatement must be invoked beforehand.
26
+ void Statement::CloseHandles() {
27
+ if (alive) {
28
+ alive = false;
29
+ sqlite3_finalize(handle);
30
+ }
31
+ }
32
+
33
+ // Returns the Statement's bind map (creates it upon first execution).
34
+ BindMap& Statement::GetBindMap(Napi::Env env) {
35
+ if (has_bind_map) return extras->bind_map;
36
+ BindMap& bind_map = extras->bind_map;
37
+ int param_count = sqlite3_bind_parameter_count(handle);
38
+ for (int i = 1; i <= param_count; ++i) {
39
+ const char* name = sqlite3_bind_parameter_name(handle, i);
40
+ if (name != NULL) bind_map.Add(env, name + 1, i);
41
+ }
42
+ has_bind_map = true;
43
+ return bind_map;
44
+ }
45
+
46
+ // Returns the Statement's row builder.
47
+ RowBuilder& Statement::GetRowBuilder() {
48
+ return extras->row_builder;
49
+ }
50
+
51
+ Statement::Extras::Extras(
52
+ Napi::Env env,
53
+ Napi::Function row_factory,
54
+ Napi::Function array_factory,
55
+ sqlite3_uint64 id
56
+ ) :
57
+ bind_map(0),
58
+ row_builder(env, row_factory, array_factory),
59
+ id(id) {}
60
+
61
+ INIT(Statement::Init) {
62
+ return DefineClass(env, "Statement", {
63
+ PrototypeMethod<Statement, &Statement::JS_run>("run", addon),
64
+ PrototypeMethod<Statement, &Statement::JS_get>("get", addon),
65
+ PrototypeMethod<Statement, &Statement::JS_all>("all", addon),
66
+ PrototypeMethod<Statement, &Statement::JS_iterate>("iterate", addon),
67
+ PrototypeMethod<Statement, &Statement::JS_bind>("bind", addon),
68
+ PrototypeMethod<Statement, &Statement::JS_pluck>("pluck", addon),
69
+ PrototypeMethod<Statement, &Statement::JS_expand>("expand", addon),
70
+ PrototypeMethod<Statement, &Statement::JS_raw>("raw", addon),
71
+ PrototypeMethod<Statement, &Statement::JS_safeIntegers>("safeIntegers", addon),
72
+ PrototypeMethod<Statement, &Statement::JS_columns>("columns", addon),
73
+ PrototypeMethod<Statement, &Statement::JS_toString>("toString", addon),
74
+ }, addon);
75
+ }
76
+
77
+ NODE_METHOD(Statement::JS_new) {
78
+ UseAddon;
79
+ if (!addon->privileged_info) {
80
+ return ThrowTypeError(info.Env(), "Statements can only be constructed by the db.prepare() method");
81
+ }
82
+ assert(info.IsConstructCall());
83
+ const Napi::CallbackInfo& pinfo = *addon->privileged_info;
84
+ UNWRAP_OR_RETURN(Database, db, pinfo.This());
85
+ REQUIRE_DATABASE_OPEN(db->GetState());
86
+ REQUIRE_DATABASE_NOT_BUSY(db->GetState());
87
+
88
+ Napi::String source = pinfo[0].As<Napi::String>();
89
+ Napi::Object database = pinfo[1].As<Napi::Object>();
90
+ bool pragmaMode = pinfo[2].As<Napi::Boolean>().Value();
91
+ bool explainMode = pinfo[3].As<Napi::Boolean>().Value();
92
+ int flags = SQLITE_PREPARE_PERSISTENT;
93
+
94
+ if (pragmaMode) {
95
+ REQUIRE_DATABASE_NO_ITERATORS_UNLESS_UNSAFE(db->GetState());
96
+ flags = 0;
97
+ }
98
+ if (explainMode) {
99
+ flags = 0;
100
+ }
101
+
102
+ UseIsolate;
103
+ std::string utf8 = source.Utf8Value();
104
+ sqlite3_stmt* handle;
105
+ const char* tail;
106
+
107
+ if (sqlite3_prepare_v3(db->GetHandle(), utf8.c_str(), utf8.length() + 1, flags, &handle, &tail) != SQLITE_OK) {
108
+ db->ThrowDatabaseError(env);
109
+ return env.Undefined();
110
+ }
111
+ if (handle == NULL) {
112
+ return ThrowRangeError(env, "The supplied SQL string contains no statements");
113
+ }
114
+ // https://github.com/WiseLibs/better-sqlite3/issues/975#issuecomment-1520934678
115
+ for (char c; (c = *tail); ) {
116
+ if (IS_SKIPPED(c)) {
117
+ ++tail;
118
+ continue;
119
+ }
120
+ if (c == '/' && tail[1] == '*') {
121
+ tail += 2;
122
+ for (char c; (c = *tail); ++tail) {
123
+ if (c == '*' && tail[1] == '/') {
124
+ tail += 2;
125
+ break;
126
+ }
127
+ }
128
+ } else if (c == '-' && tail[1] == '-') {
129
+ tail += 2;
130
+ for (char c; (c = *tail); ++tail) {
131
+ if (c == '\n') {
132
+ ++tail;
133
+ break;
134
+ }
135
+ }
136
+ } else {
137
+ sqlite3_finalize(handle);
138
+ return ThrowRangeError(env, "The supplied SQL string contains more than one statement");
139
+ }
140
+ }
141
+
142
+ bool returns_data = sqlite3_column_count(handle) >= 1 || pragmaMode;
143
+ this->db = db;
144
+ this->handle = handle;
145
+ this->extras = new Extras(env, addon->RowFactory.Value(), addon->ArrayFactory.Value(), addon->NextId());
146
+ this->bound = explainMode;
147
+ this->safe_ints = db->GetState()->safe_ints;
148
+ this->returns_data = returns_data;
149
+ this->alive = true;
150
+ assert(db->GetState()->open);
151
+ assert(!db->GetState()->busy);
152
+ db->AddStatement(this);
153
+
154
+ Napi::Object _this = info.This().As<Napi::Object>();
155
+ SetFrozen(env, _this, addon->cs.reader, Napi::Boolean::New(env, returns_data));
156
+ SetFrozen(env, _this, addon->cs.readonly, Napi::Boolean::New(env, sqlite3_stmt_readonly(handle) != 0));
157
+ SetFrozen(env, _this, addon->cs.source, source);
158
+ SetFrozen(env, _this, addon->cs.database, database);
159
+ SetInstanceGetter<Statement, &Statement::JS_busy>(_this, "busy", addon);
160
+
161
+ return info.This();
162
+ }
163
+
164
+ NODE_METHOD(Statement::JS_run) {
165
+ STATEMENT_START(ALLOW_ANY_STATEMENT, DOES_MUTATE);
166
+ sqlite3* db_handle = db->GetHandle();
167
+ int total_changes_before = sqlite3_total_changes(db_handle);
168
+
169
+ sqlite3_step(handle);
170
+ if (sqlite3_reset(handle) == SQLITE_OK) {
171
+ int changes = sqlite3_total_changes(db_handle) == total_changes_before ? 0 : sqlite3_changes(db_handle);
172
+ sqlite3_int64 id = sqlite3_last_insert_rowid(db_handle);
173
+ Addon* addon = db->GetAddon();
174
+
175
+ napi_property_descriptor properties[2] = {};
176
+ properties[0].name = addon->cs.changes.Value();
177
+ properties[0].value = Napi::Number::New(env, changes);
178
+ properties[0].attributes = DEFAULT_ATTRIBUTES;
179
+ properties[1].name = addon->cs.lastInsertRowid.Value();
180
+ if (stmt->safe_ints) {
181
+ properties[1].value = Napi::BigInt::New(env, (int64_t)id);
182
+ } else {
183
+ properties[1].value = Napi::Number::New(env, (double)id);
184
+ }
185
+ properties[1].attributes = DEFAULT_ATTRIBUTES;
186
+
187
+ napi_value result;
188
+ napi_status status = napi_create_object(env, &result);
189
+ assert(status == napi_ok || status == napi_cannot_run_js);
190
+ status = napi_define_properties(env, result, 2, properties);
191
+ assert(status == napi_ok || status == napi_cannot_run_js); ((void)status);
192
+ STATEMENT_RETURN(Napi::Object(env, result));
193
+ }
194
+ STATEMENT_THROW();
195
+ }
196
+
197
+ NODE_METHOD(Statement::JS_get) {
198
+ STATEMENT_START(REQUIRE_STATEMENT_RETURNS_DATA, DOES_NOT_MUTATE);
199
+ int status = sqlite3_step(handle);
200
+ if (status == SQLITE_ROW) {
201
+ Napi::Value result = Data::GetRowJS(env, stmt, handle, stmt->safe_ints, stmt->mode);
202
+ sqlite3_reset(handle);
203
+ STATEMENT_RETURN(result);
204
+ } else if (status == SQLITE_DONE) {
205
+ sqlite3_reset(handle);
206
+ STATEMENT_RETURN(env.Undefined());
207
+ }
208
+ sqlite3_reset(handle);
209
+ STATEMENT_THROW();
210
+ }
211
+
212
+ NODE_METHOD(Statement::JS_all) {
213
+ STATEMENT_START(REQUIRE_STATEMENT_RETURNS_DATA, DOES_NOT_MUTATE);
214
+ const bool safe_ints = stmt->safe_ints;
215
+ const char mode = stmt->mode;
216
+
217
+ std::vector<napi_value> rows;
218
+ rows.reserve(8);
219
+
220
+ while (sqlite3_step(handle) == SQLITE_ROW) {
221
+ rows.emplace_back(Data::GetRowJS(env, stmt, handle, safe_ints, mode));
222
+ }
223
+
224
+ if (sqlite3_reset(handle) == SQLITE_OK) {
225
+ if (rows.size() > 0xffffffff) {
226
+ ThrowRangeError(env, "Array overflow (too many rows returned)");
227
+ db->GetState()->was_js_error = true;
228
+ } else {
229
+ Addon* addon = db->GetAddon();
230
+ assert(!addon->ArrayFactory.IsEmpty());
231
+ assert(!addon->ArrayAppender.IsEmpty());
232
+ static const size_t batch_size = 1024;
233
+ size_t first_batch_size = std::min(rows.size(), batch_size);
234
+ Napi::Value result = SafeCall(env, addon->ArrayFactory.Value(), env.Undefined(), first_batch_size, rows.data());
235
+ if (!env.IsExceptionPending()) {
236
+ napi_value args[batch_size + 1];
237
+ args[0] = result;
238
+ for (size_t offset = first_batch_size; offset < rows.size(); offset += batch_size) {
239
+ size_t count = std::min(rows.size() - offset, batch_size);
240
+ std::copy_n(rows.data() + offset, count, args + 1);
241
+ SafeCall(env, addon->ArrayAppender.Value(), env.Undefined(), count + 1, args);
242
+ if (env.IsExceptionPending()) break;
243
+ }
244
+ }
245
+ if (env.IsExceptionPending()) {
246
+ db->GetState()->was_js_error = true;
247
+ } else {
248
+ STATEMENT_RETURN(result);
249
+ }
250
+ }
251
+ }
252
+ STATEMENT_THROW();
253
+ }
254
+
255
+ NODE_METHOD(Statement::JS_iterate) {
256
+ UseAddon;
257
+ UseIsolate;
258
+ Napi::Function c = addon->StatementIterator.Value();
259
+ addon->privileged_info = &info;
260
+ Napi::Object iterator = SafeConstruct(env, c);
261
+ addon->privileged_info = NULL;
262
+ if (env.IsExceptionPending()) return env.Undefined();
263
+ return iterator;
264
+ }
265
+
266
+ NODE_METHOD(Statement::JS_bind) {
267
+ UNWRAP_OR_RETURN(Statement, stmt, info.This());
268
+ if (stmt->bound) return ThrowTypeError(info.Env(), "The bind() method can only be invoked once per statement object");
269
+ REQUIRE_DATABASE_OPEN(stmt->db->GetState());
270
+ REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
271
+ REQUIRE_STATEMENT_NOT_LOCKED(stmt);
272
+ STATEMENT_BIND(stmt->handle);
273
+ stmt->bound = true;
274
+ return info.This();
275
+ }
276
+
277
+ NODE_METHOD(Statement::JS_pluck) {
278
+ UNWRAP_OR_RETURN(Statement, stmt, info.This());
279
+ if (!stmt->returns_data) return ThrowTypeError(info.Env(), "The pluck() method is only for statements that return data");
280
+ REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
281
+ REQUIRE_STATEMENT_NOT_LOCKED(stmt);
282
+ bool use = true;
283
+ if (info.Length() != 0) { REQUIRE_ARGUMENT_BOOLEAN(first, use); }
284
+ stmt->mode = use ? Data::PLUCK : stmt->mode == Data::PLUCK ? Data::FLAT : stmt->mode;
285
+ return info.This();
286
+ }
287
+
288
+ NODE_METHOD(Statement::JS_expand) {
289
+ UNWRAP_OR_RETURN(Statement, stmt, info.This());
290
+ if (!stmt->returns_data) return ThrowTypeError(info.Env(), "The expand() method is only for statements that return data");
291
+ REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
292
+ REQUIRE_STATEMENT_NOT_LOCKED(stmt);
293
+ bool use = true;
294
+ if (info.Length() != 0) { REQUIRE_ARGUMENT_BOOLEAN(first, use); }
295
+ stmt->mode = use ? Data::EXPAND : stmt->mode == Data::EXPAND ? Data::FLAT : stmt->mode;
296
+ return info.This();
297
+ }
298
+
299
+ NODE_METHOD(Statement::JS_raw) {
300
+ UNWRAP_OR_RETURN(Statement, stmt, info.This());
301
+ if (!stmt->returns_data) return ThrowTypeError(info.Env(), "The raw() method is only for statements that return data");
302
+ REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
303
+ REQUIRE_STATEMENT_NOT_LOCKED(stmt);
304
+ bool use = true;
305
+ if (info.Length() != 0) { REQUIRE_ARGUMENT_BOOLEAN(first, use); }
306
+ stmt->mode = use ? Data::RAW : stmt->mode == Data::RAW ? Data::FLAT : stmt->mode;
307
+ return info.This();
308
+ }
309
+
310
+ NODE_METHOD(Statement::JS_safeIntegers) {
311
+ UNWRAP_OR_RETURN(Statement, stmt, info.This());
312
+ REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
313
+ REQUIRE_STATEMENT_NOT_LOCKED(stmt);
314
+ if (info.Length() == 0) stmt->safe_ints = true;
315
+ else { REQUIRE_ARGUMENT_BOOLEAN(first, stmt->safe_ints); }
316
+ return info.This();
317
+ }
318
+
319
+ NODE_METHOD(Statement::JS_columns) {
320
+ UNWRAP_OR_RETURN(Statement, stmt, info.This());
321
+ if (!stmt->returns_data) return ThrowTypeError(info.Env(), "The columns() method is only for statements that return data");
322
+ REQUIRE_DATABASE_OPEN(stmt->db->GetState());
323
+ REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
324
+ Addon* addon = stmt->db->GetAddon();
325
+ UseIsolate;
326
+
327
+ int column_count = sqlite3_column_count(stmt->handle);
328
+ Napi::Array columns = Napi::Array::New(env, column_count);
329
+
330
+ Napi::String name = addon->cs.name.Value();
331
+ Napi::String columnName = addon->cs.column.Value();
332
+ Napi::String tableName = addon->cs.table.Value();
333
+ Napi::String databaseName = addon->cs.database.Value();
334
+ Napi::String typeName = addon->cs.type.Value();
335
+
336
+ for (int i = 0; i < column_count; ++i) {
337
+ Napi::Object column = Napi::Object::New(env);
338
+
339
+ column.Set(name,
340
+ InternalizedFromUtf8OrNull(env, sqlite3_column_name(stmt->handle, i), -1)
341
+ );
342
+ column.Set(columnName,
343
+ InternalizedFromUtf8OrNull(env, sqlite3_column_origin_name(stmt->handle, i), -1)
344
+ );
345
+ column.Set(tableName,
346
+ InternalizedFromUtf8OrNull(env, sqlite3_column_table_name(stmt->handle, i), -1)
347
+ );
348
+ column.Set(databaseName,
349
+ InternalizedFromUtf8OrNull(env, sqlite3_column_database_name(stmt->handle, i), -1)
350
+ );
351
+ column.Set(typeName,
352
+ InternalizedFromUtf8OrNull(env, sqlite3_column_decltype(stmt->handle, i), -1)
353
+ );
354
+
355
+ columns.Set(i, column);
356
+ }
357
+
358
+ return columns;
359
+ }
360
+
361
+ NODE_METHOD(Statement::JS_toString) {
362
+ UNWRAP_OR_RETURN(Statement, stmt, info.This());
363
+ Addon* addon = stmt->db->GetAddon();
364
+
365
+ char* expanded = stmt->alive && stmt->bound ? sqlite3_expanded_sql(stmt->handle) : NULL;
366
+ if (expanded != NULL) {
367
+ Napi::Value ret = StringFromUtf8(info.Env(), expanded, -1);
368
+ sqlite3_free(expanded);
369
+ return ret;
370
+ }
371
+
372
+ return info.This().As<Napi::Object>()
373
+ .Get(addon->cs.source.Value())
374
+ .As<Napi::String>();
375
+ }
376
+
377
+ NODE_GETTER(Statement::JS_busy) {
378
+ UNWRAP_OR_RETURN(Statement, stmt, info.This());
379
+ return Napi::Boolean::New(info.Env(), stmt->alive && stmt->locked);
380
+ }
@@ -0,0 +1,65 @@
1
+ class Statement : public Napi::ObjectWrap<Statement> { friend class StatementIterator;
2
+ public:
3
+
4
+ explicit Statement(const Napi::CallbackInfo& info);
5
+ ~Statement();
6
+
7
+ // Whenever this is used, db->RemoveStatement must be invoked beforehand.
8
+ void CloseHandles();
9
+
10
+ // Used to support ordered containers.
11
+ static inline bool Compare(Statement const * const a, Statement const * const b) {
12
+ return a->extras->id < b->extras->id;
13
+ }
14
+
15
+ // Returns the Statement's bind map (creates it upon first execution).
16
+ BindMap& GetBindMap(Napi::Env env);
17
+
18
+ // Returns the Statement's row builder.
19
+ RowBuilder& GetRowBuilder();
20
+
21
+ // Identifies objects that are backed by this class (see IsInstanceOf).
22
+ static const napi_type_tag TYPE_TAG;
23
+
24
+ static INIT(Init);
25
+
26
+ private:
27
+
28
+ // A class for holding values that are less often used.
29
+ class Extras { friend class Statement; friend class StatementIterator;
30
+ explicit Extras(
31
+ Napi::Env env,
32
+ Napi::Function row_factory,
33
+ Napi::Function array_Factory,
34
+ sqlite3_uint64 id
35
+ );
36
+ BindMap bind_map;
37
+ RowBuilder row_builder;
38
+ const sqlite3_uint64 id;
39
+ };
40
+
41
+ NODE_METHOD(JS_new);
42
+ static NODE_METHOD(JS_run);
43
+ static NODE_METHOD(JS_get);
44
+ static NODE_METHOD(JS_all);
45
+ static NODE_METHOD(JS_iterate);
46
+ static NODE_METHOD(JS_bind);
47
+ static NODE_METHOD(JS_pluck);
48
+ static NODE_METHOD(JS_expand);
49
+ static NODE_METHOD(JS_raw);
50
+ static NODE_METHOD(JS_safeIntegers);
51
+ static NODE_METHOD(JS_columns);
52
+ static NODE_METHOD(JS_toString);
53
+ static NODE_GETTER(JS_busy);
54
+
55
+ Database* db;
56
+ sqlite3_stmt* handle;
57
+ Extras* extras;
58
+ bool alive;
59
+ bool locked;
60
+ bool bound;
61
+ bool has_bind_map;
62
+ bool safe_ints;
63
+ char mode;
64
+ bool returns_data;
65
+ };
@@ -0,0 +1,73 @@
1
+ class BindMap {
2
+ public:
3
+
4
+ // This nested class represents a single mapping between a parameter name
5
+ // and its associated parameter index in a prepared statement.
6
+ class Pair { friend class BindMap;
7
+ public:
8
+
9
+ inline int GetIndex() {
10
+ return index;
11
+ }
12
+
13
+ inline Napi::String GetName(Napi::Env env) {
14
+ return name.Value();
15
+ }
16
+
17
+ private:
18
+
19
+ explicit Pair(Napi::Env env, const char* name, int index)
20
+ : name(Napi::Persistent(InternalizedFromUtf8(env, name, -1))), index(index) {}
21
+
22
+ explicit Pair(Napi::Env env, Pair* pair)
23
+ : name(Napi::Persistent(pair->name.Value())), index(pair->index) {}
24
+
25
+ const Napi::Reference<Napi::String> name;
26
+ const int index;
27
+ };
28
+
29
+ explicit BindMap(char _) {
30
+ assert(_ == 0);
31
+ pairs = NULL;
32
+ capacity = 0;
33
+ length = 0;
34
+ }
35
+
36
+ ~BindMap() {
37
+ while (length) pairs[--length].~Pair();
38
+ FREE_ARRAY<Pair>(pairs);
39
+ }
40
+
41
+ inline Pair* GetPairs() {
42
+ return pairs;
43
+ }
44
+
45
+ inline int GetSize() {
46
+ return length;
47
+ }
48
+
49
+ // Adds a pair to the bind map, expanding the capacity if necessary.
50
+ void Add(Napi::Env env, const char* name, int index) {
51
+ assert(name != NULL);
52
+ if (capacity == length) Grow(env);
53
+ new (pairs + length++) Pair(env, name, index);
54
+ }
55
+
56
+ private:
57
+
58
+ void Grow(Napi::Env env) {
59
+ assert(capacity == length);
60
+ capacity = (capacity << 1) | 2;
61
+ Pair* new_pairs = ALLOC_ARRAY<Pair>(capacity);
62
+ for (int i = 0; i < length; ++i) {
63
+ new (new_pairs + i) Pair(env, pairs + i);
64
+ pairs[i].~Pair();
65
+ }
66
+ FREE_ARRAY<Pair>(pairs);
67
+ pairs = new_pairs;
68
+ }
69
+
70
+ Pair* pairs;
71
+ int capacity;
72
+ int length;
73
+ };