@barakxyz/better-sqlite3 12.6.2

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +99 -0
  3. package/binding.gyp +42 -0
  4. package/deps/common.gypi +68 -0
  5. package/deps/copy.js +31 -0
  6. package/deps/defines.gypi +43 -0
  7. package/deps/download.sh +122 -0
  8. package/deps/patches/1208.patch +15 -0
  9. package/deps/sqlite3/sqlite3.c +265969 -0
  10. package/deps/sqlite3/sqlite3.h +13968 -0
  11. package/deps/sqlite3/sqlite3ext.h +730 -0
  12. package/deps/sqlite3.gyp +80 -0
  13. package/deps/test_extension.c +21 -0
  14. package/lib/database.js +93 -0
  15. package/lib/index.js +3 -0
  16. package/lib/methods/aggregate.js +43 -0
  17. package/lib/methods/backup.js +67 -0
  18. package/lib/methods/function.js +31 -0
  19. package/lib/methods/inspect.js +7 -0
  20. package/lib/methods/pragma.js +12 -0
  21. package/lib/methods/serialize.js +16 -0
  22. package/lib/methods/table.js +189 -0
  23. package/lib/methods/transaction.js +78 -0
  24. package/lib/methods/wrappers.js +73 -0
  25. package/lib/sqlite-error.js +20 -0
  26. package/lib/util.js +12 -0
  27. package/package.json +59 -0
  28. package/src/addon.cpp +48 -0
  29. package/src/better_sqlite3.cpp +79 -0
  30. package/src/objects/backup.cpp +120 -0
  31. package/src/objects/backup.hpp +36 -0
  32. package/src/objects/database.cpp +521 -0
  33. package/src/objects/database.hpp +116 -0
  34. package/src/objects/session.cpp +148 -0
  35. package/src/objects/session.hpp +33 -0
  36. package/src/objects/statement-iterator.cpp +113 -0
  37. package/src/objects/statement-iterator.hpp +50 -0
  38. package/src/objects/statement.cpp +383 -0
  39. package/src/objects/statement.hpp +58 -0
  40. package/src/util/bind-map.cpp +73 -0
  41. package/src/util/binder.cpp +193 -0
  42. package/src/util/constants.cpp +172 -0
  43. package/src/util/custom-aggregate.cpp +121 -0
  44. package/src/util/custom-function.cpp +59 -0
  45. package/src/util/custom-table.cpp +409 -0
  46. package/src/util/data-converter.cpp +17 -0
  47. package/src/util/data.cpp +194 -0
  48. package/src/util/helpers.cpp +109 -0
  49. package/src/util/macros.cpp +70 -0
  50. package/src/util/query-macros.cpp +71 -0
  51. package/src/util/row-builder.cpp +49 -0
@@ -0,0 +1,148 @@
1
+ Session::Session(
2
+ Database* db,
3
+ sqlite3_session* session_handle,
4
+ sqlite3_uint64 id
5
+ ) :
6
+ node::ObjectWrap(),
7
+ db(db),
8
+ session_handle(session_handle),
9
+ id(id),
10
+ alive(true) {
11
+ assert(db != NULL);
12
+ assert(session_handle != NULL);
13
+ db->AddSession(this);
14
+ }
15
+
16
+ Session::~Session() {
17
+ if (alive) db->RemoveSession(this);
18
+ CloseHandles();
19
+ }
20
+
21
+ // Whenever this is used, db->RemoveSession must be invoked beforehand.
22
+ void Session::CloseHandles() {
23
+ if (alive) {
24
+ alive = false;
25
+ sqlite3session_delete(session_handle);
26
+ }
27
+ }
28
+
29
+ INIT(Session::Init) {
30
+ v8::Local<v8::FunctionTemplate> t = NewConstructorTemplate(isolate, data, JS_new, "Session");
31
+ SetPrototypeMethod(isolate, data, t, "attach", JS_attach);
32
+ SetPrototypeMethod(isolate, data, t, "changeset", JS_changeset);
33
+ SetPrototypeMethod(isolate, data, t, "close", JS_close);
34
+ return t->GetFunction(OnlyContext).ToLocalChecked();
35
+ }
36
+
37
+ NODE_METHOD(Session::JS_new) {
38
+ UseAddon;
39
+ if (!addon->privileged_info) return ThrowTypeError("Disabled constructor");
40
+ assert(info.IsConstructCall());
41
+ Database* db = Unwrap<Database>(addon->privileged_info->This());
42
+ REQUIRE_DATABASE_OPEN(db->GetState());
43
+ REQUIRE_DATABASE_NOT_BUSY(db->GetState());
44
+
45
+ v8::Local<v8::Object> database = (*addon->privileged_info)[0].As<v8::Object>();
46
+ v8::Local<v8::String> dbName = (*addon->privileged_info)[1].As<v8::String>();
47
+
48
+ UseIsolate;
49
+ v8::String::Utf8Value db_name(isolate, dbName);
50
+
51
+ sqlite3_session* session_handle;
52
+ int status = sqlite3session_create(db->GetHandle(), *db_name, &session_handle);
53
+
54
+ if (status != SQLITE_OK) {
55
+ Database::ThrowSqliteError(addon, db->GetHandle());
56
+ return;
57
+ }
58
+
59
+ Session* session = new Session(db, session_handle, addon->NextId());
60
+ session->Wrap(info.This());
61
+ SetFrozen(isolate, OnlyContext, info.This(), addon->cs.database, database);
62
+
63
+ info.GetReturnValue().Set(info.This());
64
+ }
65
+
66
+ NODE_METHOD(Session::JS_attach) {
67
+ Session* session = Unwrap<Session>(info.This());
68
+ if (!session->alive) return ThrowTypeError("The session has been closed");
69
+ REQUIRE_DATABASE_OPEN(session->db->GetState());
70
+
71
+ UseIsolate;
72
+ const char* table_name = NULL;
73
+
74
+ // If a string argument is provided, attach only that table
75
+ // If null/undefined or no argument, attach all tables (NULL)
76
+ if (info.Length() > 0 && !info[0]->IsNullOrUndefined()) {
77
+ if (!info[0]->IsString()) {
78
+ return ThrowTypeError("Expected first argument to be a string or null");
79
+ }
80
+ v8::String::Utf8Value utf8(isolate, info[0].As<v8::String>());
81
+ table_name = *utf8;
82
+ int status = sqlite3session_attach(session->session_handle, table_name);
83
+ if (status != SQLITE_OK) {
84
+ session->db->ThrowDatabaseError();
85
+ }
86
+ } else {
87
+ // NULL means attach all tables
88
+ int status = sqlite3session_attach(session->session_handle, NULL);
89
+ if (status != SQLITE_OK) {
90
+ session->db->ThrowDatabaseError();
91
+ }
92
+ }
93
+ }
94
+
95
+ // Custom destructor for sqlite3_free
96
+ static void FreeSqliteMemory(char* data, void* hint) {
97
+ sqlite3_free(data);
98
+ }
99
+
100
+ NODE_METHOD(Session::JS_changeset) {
101
+ Session* session = Unwrap<Session>(info.This());
102
+ if (!session->alive) return ThrowTypeError("The session has been closed");
103
+ REQUIRE_DATABASE_OPEN(session->db->GetState());
104
+
105
+ int size = 0;
106
+ void* buffer = NULL;
107
+ int status = sqlite3session_changeset(session->session_handle, &size, &buffer);
108
+
109
+ if (status != SQLITE_OK) {
110
+ session->db->ThrowDatabaseError();
111
+ return;
112
+ }
113
+
114
+ UseIsolate;
115
+
116
+ // If no changes, return undefined
117
+ if (buffer == NULL || size == 0) {
118
+ if (buffer) sqlite3_free(buffer);
119
+ info.GetReturnValue().Set(v8::Undefined(isolate));
120
+ return;
121
+ }
122
+
123
+ // Create a Node.js Buffer from the changeset data
124
+ // sqlite3_free will be called when the buffer is garbage collected
125
+ auto result = SAFE_NEW_BUFFER(
126
+ isolate,
127
+ reinterpret_cast<char*>(buffer),
128
+ size,
129
+ FreeSqliteMemory,
130
+ NULL
131
+ );
132
+
133
+ if (result.IsEmpty()) {
134
+ sqlite3_free(buffer);
135
+ return ThrowError("Failed to create buffer for changeset");
136
+ }
137
+
138
+ info.GetReturnValue().Set(result.ToLocalChecked());
139
+ }
140
+
141
+ NODE_METHOD(Session::JS_close) {
142
+ Session* session = Unwrap<Session>(info.This());
143
+ if (session->alive) {
144
+ session->db->RemoveSession(session);
145
+ session->CloseHandles();
146
+ }
147
+ info.GetReturnValue().Set(info.This());
148
+ }
@@ -0,0 +1,33 @@
1
+ class Session : public node::ObjectWrap {
2
+ public:
3
+
4
+ ~Session();
5
+
6
+ // Whenever this is used, db->RemoveSession must be invoked beforehand.
7
+ void CloseHandles();
8
+
9
+ // Used to support ordered containers.
10
+ static inline bool Compare(Session const * const a, Session const * const b) {
11
+ return a->id < b->id;
12
+ }
13
+
14
+ static INIT(Init);
15
+
16
+ private:
17
+
18
+ explicit Session(
19
+ Database* db,
20
+ sqlite3_session* session_handle,
21
+ sqlite3_uint64 id
22
+ );
23
+
24
+ static NODE_METHOD(JS_new);
25
+ static NODE_METHOD(JS_attach);
26
+ static NODE_METHOD(JS_changeset);
27
+ static NODE_METHOD(JS_close);
28
+
29
+ Database* const db;
30
+ sqlite3_session* session_handle;
31
+ const sqlite3_uint64 id;
32
+ bool alive;
33
+ };
@@ -0,0 +1,113 @@
1
+ StatementIterator::StatementIterator(Statement* stmt, bool bound) :
2
+ node::ObjectWrap(),
3
+ stmt(stmt),
4
+ handle(stmt->handle),
5
+ db_state(stmt->db->GetState()),
6
+ bound(bound),
7
+ safe_ints(stmt->safe_ints),
8
+ mode(stmt->mode),
9
+ alive(true),
10
+ logged(!db_state->has_logger) {
11
+ assert(stmt != NULL);
12
+ assert(handle != NULL);
13
+ assert(stmt->bound == bound);
14
+ assert(stmt->alive == true);
15
+ assert(stmt->locked == false);
16
+ assert(db_state->iterators < USHRT_MAX);
17
+ stmt->locked = true;
18
+ db_state->iterators += 1;
19
+ }
20
+
21
+ // The ~Statement destructor currently covers any state this object creates.
22
+ // Additionally, we actually DON'T want to revert stmt->locked or db_state
23
+ // ->iterators in this destructor, to ensure deterministic database access.
24
+ StatementIterator::~StatementIterator() {}
25
+
26
+ void StatementIterator::Next(NODE_ARGUMENTS info) {
27
+ assert(alive == true);
28
+ db_state->busy = true;
29
+ if (!logged) {
30
+ logged = true;
31
+ if (stmt->db->Log(OnlyIsolate, handle)) {
32
+ db_state->busy = false;
33
+ Throw();
34
+ return;
35
+ }
36
+ }
37
+ int status = sqlite3_step(handle);
38
+ db_state->busy = false;
39
+ if (status == SQLITE_ROW) {
40
+ UseIsolate;
41
+ UseContext;
42
+ info.GetReturnValue().Set(
43
+ NewRecord(isolate, ctx, Data::GetRowJS(isolate, ctx, handle, safe_ints, mode), db_state->addon, false)
44
+ );
45
+ } else {
46
+ if (status == SQLITE_DONE) Return(info);
47
+ else Throw();
48
+ }
49
+ }
50
+
51
+ void StatementIterator::Return(NODE_ARGUMENTS info) {
52
+ Cleanup();
53
+ STATEMENT_RETURN_LOGIC(DoneRecord(OnlyIsolate, db_state->addon));
54
+ }
55
+
56
+ void StatementIterator::Throw() {
57
+ Cleanup();
58
+ Database* db = stmt->db;
59
+ STATEMENT_THROW_LOGIC();
60
+ }
61
+
62
+ void StatementIterator::Cleanup() {
63
+ assert(alive == true);
64
+ alive = false;
65
+ stmt->locked = false;
66
+ db_state->iterators -= 1;
67
+ sqlite3_reset(handle);
68
+ }
69
+
70
+ INIT(StatementIterator::Init) {
71
+ v8::Local<v8::FunctionTemplate> t = NewConstructorTemplate(isolate, data, JS_new, "StatementIterator");
72
+ SetPrototypeMethod(isolate, data, t, "next", JS_next);
73
+ SetPrototypeMethod(isolate, data, t, "return", JS_return);
74
+ SetPrototypeSymbolMethod(isolate, data, t, v8::Symbol::GetIterator(isolate), JS_symbolIterator);
75
+ return t->GetFunction(OnlyContext).ToLocalChecked();
76
+ }
77
+
78
+ NODE_METHOD(StatementIterator::JS_new) {
79
+ UseAddon;
80
+ if (!addon->privileged_info) return ThrowTypeError("Disabled constructor");
81
+ assert(info.IsConstructCall());
82
+
83
+ StatementIterator* iter;
84
+ {
85
+ NODE_ARGUMENTS info = *addon->privileged_info;
86
+ STATEMENT_START_LOGIC(REQUIRE_STATEMENT_RETURNS_DATA, DOES_ADD_ITERATOR);
87
+ iter = new StatementIterator(stmt, bound);
88
+ }
89
+ UseIsolate;
90
+ UseContext;
91
+ iter->Wrap(info.This());
92
+ SetFrozen(isolate, ctx, info.This(), addon->cs.statement, addon->privileged_info->This());
93
+
94
+ info.GetReturnValue().Set(info.This());
95
+ }
96
+
97
+ NODE_METHOD(StatementIterator::JS_next) {
98
+ StatementIterator* iter = Unwrap<StatementIterator>(info.This());
99
+ REQUIRE_DATABASE_NOT_BUSY(iter->db_state);
100
+ if (iter->alive) iter->Next(info);
101
+ else info.GetReturnValue().Set(DoneRecord(OnlyIsolate, iter->db_state->addon));
102
+ }
103
+
104
+ NODE_METHOD(StatementIterator::JS_return) {
105
+ StatementIterator* iter = Unwrap<StatementIterator>(info.This());
106
+ REQUIRE_DATABASE_NOT_BUSY(iter->db_state);
107
+ if (iter->alive) iter->Return(info);
108
+ else info.GetReturnValue().Set(DoneRecord(OnlyIsolate, iter->db_state->addon));
109
+ }
110
+
111
+ NODE_METHOD(StatementIterator::JS_symbolIterator) {
112
+ info.GetReturnValue().Set(info.This());
113
+ }
@@ -0,0 +1,50 @@
1
+ class StatementIterator : public node::ObjectWrap {
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
+ ~StatementIterator();
8
+
9
+ static INIT(Init);
10
+
11
+ private:
12
+
13
+ explicit StatementIterator(Statement* stmt, bool bound);
14
+
15
+ void Next(NODE_ARGUMENTS info);
16
+ void Return(NODE_ARGUMENTS info);
17
+ void Throw();
18
+ void Cleanup();
19
+
20
+ static inline v8::Local<v8::Object> NewRecord(
21
+ v8::Isolate* isolate,
22
+ v8::Local<v8::Context> ctx,
23
+ v8::Local<v8::Value> value,
24
+ Addon* addon,
25
+ bool done
26
+ ) {
27
+ v8::Local<v8::Object> record = v8::Object::New(isolate);
28
+ record->Set(ctx, addon->cs.value.Get(isolate), value).FromJust();
29
+ record->Set(ctx, addon->cs.done.Get(isolate), v8::Boolean::New(isolate, done)).FromJust();
30
+ return record;
31
+ }
32
+
33
+ static inline v8::Local<v8::Object> DoneRecord(v8::Isolate* isolate, Addon* addon) {
34
+ return NewRecord(isolate, OnlyContext, v8::Undefined(isolate), addon, true);
35
+ }
36
+
37
+ static NODE_METHOD(JS_new);
38
+ static NODE_METHOD(JS_next);
39
+ static NODE_METHOD(JS_return);
40
+ static NODE_METHOD(JS_symbolIterator);
41
+
42
+ Statement* const stmt;
43
+ sqlite3_stmt* const handle;
44
+ Database::State* const db_state;
45
+ const bool bound;
46
+ const bool safe_ints;
47
+ const char mode;
48
+ bool alive;
49
+ bool logged;
50
+ };