@photostructure/sqlite 0.0.1

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 (53) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/LICENSE +21 -0
  3. package/README.md +522 -0
  4. package/SECURITY.md +114 -0
  5. package/binding.gyp +94 -0
  6. package/dist/index.cjs +134 -0
  7. package/dist/index.cjs.map +1 -0
  8. package/dist/index.d.cts +408 -0
  9. package/dist/index.d.mts +408 -0
  10. package/dist/index.d.ts +408 -0
  11. package/dist/index.mjs +103 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/package.json +144 -0
  14. package/prebuilds/darwin-arm64/@photostructure+sqlite.glibc.node +0 -0
  15. package/prebuilds/linux-arm64/@photostructure+sqlite.glibc.node +0 -0
  16. package/prebuilds/linux-arm64/@photostructure+sqlite.musl.node +0 -0
  17. package/prebuilds/linux-x64/@photostructure+sqlite.glibc.node +0 -0
  18. package/prebuilds/linux-x64/@photostructure+sqlite.musl.node +0 -0
  19. package/prebuilds/win32-x64/@photostructure+sqlite.glibc.node +0 -0
  20. package/scripts/post-build.mjs +21 -0
  21. package/scripts/prebuild-linux-glibc.sh +108 -0
  22. package/src/aggregate_function.cpp +417 -0
  23. package/src/aggregate_function.h +116 -0
  24. package/src/binding.cpp +160 -0
  25. package/src/dirname.ts +13 -0
  26. package/src/index.ts +465 -0
  27. package/src/shims/base_object-inl.h +8 -0
  28. package/src/shims/base_object.h +50 -0
  29. package/src/shims/debug_utils-inl.h +23 -0
  30. package/src/shims/env-inl.h +19 -0
  31. package/src/shims/memory_tracker-inl.h +17 -0
  32. package/src/shims/napi_extensions.h +73 -0
  33. package/src/shims/node.h +16 -0
  34. package/src/shims/node_errors.h +66 -0
  35. package/src/shims/node_mem-inl.h +8 -0
  36. package/src/shims/node_mem.h +31 -0
  37. package/src/shims/node_url.h +23 -0
  38. package/src/shims/promise_resolver.h +31 -0
  39. package/src/shims/util-inl.h +18 -0
  40. package/src/shims/util.h +101 -0
  41. package/src/sqlite_impl.cpp +2440 -0
  42. package/src/sqlite_impl.h +314 -0
  43. package/src/stack_path.ts +64 -0
  44. package/src/types/node-gyp-build.d.ts +4 -0
  45. package/src/upstream/node_sqlite.cc +2706 -0
  46. package/src/upstream/node_sqlite.h +234 -0
  47. package/src/upstream/sqlite.gyp +38 -0
  48. package/src/upstream/sqlite.js +19 -0
  49. package/src/upstream/sqlite3.c +262809 -0
  50. package/src/upstream/sqlite3.h +13773 -0
  51. package/src/upstream/sqlite3ext.h +723 -0
  52. package/src/user_function.cpp +225 -0
  53. package/src/user_function.h +40 -0
@@ -0,0 +1,225 @@
1
+ #include "user_function.h"
2
+
3
+ #include <climits>
4
+ #include <cmath>
5
+ #include <stdexcept>
6
+
7
+ #include "sqlite_impl.h"
8
+
9
+ namespace photostructure {
10
+ namespace sqlite {
11
+
12
+ UserDefinedFunction::UserDefinedFunction(Napi::Env env, Napi::Function fn,
13
+ DatabaseSync *db, bool use_bigint_args)
14
+ : env_(env), fn_(Napi::Reference<Napi::Function>::New(fn, 1)), db_(db),
15
+ use_bigint_args_(use_bigint_args) {
16
+ // No need for SuppressDestruct when using reference count
17
+ }
18
+
19
+ UserDefinedFunction::~UserDefinedFunction() {
20
+ // Clean up the persistent function reference
21
+ if (!fn_.IsEmpty()) {
22
+ fn_.Reset();
23
+ }
24
+ }
25
+
26
+ void UserDefinedFunction::xFunc(sqlite3_context *ctx, int argc,
27
+ sqlite3_value **argv) {
28
+ void *user_data = sqlite3_user_data(ctx);
29
+ if (!user_data) {
30
+ sqlite3_result_error(ctx, "Invalid user data in function callback", -1);
31
+ return;
32
+ }
33
+
34
+ UserDefinedFunction *self = static_cast<UserDefinedFunction *>(user_data);
35
+
36
+ try {
37
+ Napi::HandleScope scope(self->env_);
38
+
39
+ // Check if function reference is still valid
40
+ if (self->fn_.IsEmpty()) {
41
+ sqlite3_result_error(ctx, "Function reference is no longer valid", -1);
42
+ return;
43
+ }
44
+
45
+ Napi::Value fn_value;
46
+ try {
47
+ fn_value = self->fn_.Value();
48
+ } catch (const Napi::Error &e) {
49
+ sqlite3_result_error(ctx, "Failed to retrieve function reference", -1);
50
+ return;
51
+ }
52
+
53
+ // Additional check for function validity
54
+ if (!fn_value.IsFunction()) {
55
+ sqlite3_result_error(ctx, "Invalid function reference - not a function",
56
+ -1);
57
+ return;
58
+ }
59
+
60
+ Napi::Function fn = fn_value.As<Napi::Function>();
61
+
62
+ // Convert SQLite arguments to JavaScript values
63
+ std::vector<napi_value> js_args;
64
+ js_args.reserve(argc);
65
+
66
+ for (int i = 0; i < argc; i++) {
67
+ Napi::Value js_val = self->SqliteValueToJS(argv[i]);
68
+ js_args.push_back(js_val);
69
+ }
70
+
71
+ // Call the JavaScript function
72
+ Napi::Value result = fn.Call(js_args);
73
+
74
+ // Check if there's a pending exception after the call
75
+ if (self->env_.IsExceptionPending()) {
76
+ Napi::Error error = self->env_.GetAndClearPendingException();
77
+ std::string error_msg = error.Message();
78
+ try {
79
+ sqlite3_result_error(ctx, error_msg.c_str(),
80
+ SafeCastToInt(error_msg.length()));
81
+ } catch (const std::overflow_error &) {
82
+ sqlite3_result_error(ctx, "Error message too long", -1);
83
+ }
84
+ return;
85
+ }
86
+
87
+ // Convert result back to SQLite
88
+ self->JSValueToSqliteResult(ctx, result);
89
+
90
+ } catch (const Napi::Error &e) {
91
+ // Handle JavaScript exceptions
92
+ std::string error_msg = e.Message();
93
+ try {
94
+ sqlite3_result_error(ctx, error_msg.c_str(),
95
+ SafeCastToInt(error_msg.length()));
96
+ } catch (const std::overflow_error &) {
97
+ sqlite3_result_error(ctx, "Error message too long", -1);
98
+ }
99
+ } catch (const std::exception &e) {
100
+ sqlite3_result_error(ctx, e.what(), -1);
101
+ } catch (...) {
102
+ sqlite3_result_error(ctx, "Unknown error in user-defined function", -1);
103
+ }
104
+ }
105
+
106
+ void UserDefinedFunction::xDestroy(void *self) {
107
+ if (self) {
108
+ delete static_cast<UserDefinedFunction *>(self);
109
+ }
110
+ }
111
+
112
+ Napi::Value UserDefinedFunction::SqliteValueToJS(sqlite3_value *value) {
113
+ switch (sqlite3_value_type(value)) {
114
+ case SQLITE_INTEGER: {
115
+ sqlite3_int64 int_val = sqlite3_value_int64(value);
116
+
117
+ if (use_bigint_args_) {
118
+ return Napi::BigInt::New(env_, static_cast<int64_t>(int_val));
119
+ } else if (int_val >= INT32_MIN && int_val <= INT32_MAX) {
120
+ return Napi::Number::New(env_, static_cast<int32_t>(int_val));
121
+ } else {
122
+ // Large integers that don't fit in int32 but aren't using BigInt
123
+ // Check if the value can be safely represented as a JavaScript number
124
+ if (int_val < -0x1FFFFFFFFFFFFF || int_val > 0x1FFFFFFFFFFFFF) {
125
+ // Value is outside safe integer range for JavaScript numbers
126
+ std::string error_msg =
127
+ "Value is too large to be represented as a JavaScript number: " +
128
+ std::to_string(int_val);
129
+ throw std::runtime_error(error_msg);
130
+ }
131
+ return Napi::Number::New(env_, static_cast<double>(int_val));
132
+ }
133
+ }
134
+
135
+ case SQLITE_FLOAT: {
136
+ double double_val = sqlite3_value_double(value);
137
+ return Napi::Number::New(env_, double_val);
138
+ }
139
+
140
+ case SQLITE_TEXT: {
141
+ const unsigned char *text = sqlite3_value_text(value);
142
+ return Napi::String::New(env_, reinterpret_cast<const char *>(text));
143
+ }
144
+
145
+ case SQLITE_BLOB: {
146
+ const void *blob_data = sqlite3_value_blob(value);
147
+ int blob_size = sqlite3_value_bytes(value);
148
+ return Napi::Buffer<uint8_t>::Copy(
149
+ env_, static_cast<const uint8_t *>(blob_data), blob_size);
150
+ }
151
+
152
+ case SQLITE_NULL:
153
+ default:
154
+ return env_.Null();
155
+ }
156
+ }
157
+
158
+ void UserDefinedFunction::JSValueToSqliteResult(sqlite3_context *ctx,
159
+ Napi::Value value) {
160
+ if (value.IsNull() || value.IsUndefined()) {
161
+ sqlite3_result_null(ctx);
162
+ } else if (value.IsBoolean()) {
163
+ // Check boolean BEFORE number, since boolean values can also be numbers
164
+ bool bool_val = value.As<Napi::Boolean>().Value();
165
+ sqlite3_result_int(ctx, bool_val ? 1 : 0);
166
+ } else if (value.IsBigInt()) {
167
+ // Check BigInt BEFORE number to handle large integers properly
168
+ bool lossless;
169
+ int64_t bigint_val = value.As<Napi::BigInt>().Int64Value(&lossless);
170
+ if (lossless) {
171
+ sqlite3_result_int64(ctx, static_cast<sqlite3_int64>(bigint_val));
172
+ } else {
173
+ // BigInt too large, convert to text representation
174
+ std::string bigint_str = value.As<Napi::BigInt>().ToString().Utf8Value();
175
+ try {
176
+ sqlite3_result_text(ctx, bigint_str.c_str(),
177
+ SafeCastToInt(bigint_str.length()),
178
+ SQLITE_TRANSIENT);
179
+ } catch (const std::overflow_error &) {
180
+ sqlite3_result_error(ctx, "BigInt string representation too long", -1);
181
+ }
182
+ }
183
+ } else if (value.IsNumber()) {
184
+ double num_val = value.As<Napi::Number>().DoubleValue();
185
+
186
+ // Check if it's an integer value
187
+ // Note: We cast INT64_MIN/MAX to double to avoid implicit conversion
188
+ // warnings
189
+ if (std::floor(num_val) == num_val &&
190
+ num_val >= static_cast<double>(INT64_MIN) &&
191
+ num_val <= static_cast<double>(INT64_MAX)) {
192
+ sqlite3_result_int64(ctx, static_cast<sqlite3_int64>(num_val));
193
+ } else {
194
+ sqlite3_result_double(ctx, num_val);
195
+ }
196
+ } else if (value.IsString()) {
197
+ std::string str_val = value.As<Napi::String>().Utf8Value();
198
+ try {
199
+ sqlite3_result_text(ctx, str_val.c_str(), SafeCastToInt(str_val.length()),
200
+ SQLITE_TRANSIENT);
201
+ } catch (const std::overflow_error &) {
202
+ sqlite3_result_error(ctx, "String value too long", -1);
203
+ }
204
+ } else if (value.IsBuffer()) {
205
+ Napi::Buffer<uint8_t> buffer = value.As<Napi::Buffer<uint8_t>>();
206
+ try {
207
+ sqlite3_result_blob(ctx, buffer.Data(), SafeCastToInt(buffer.Length()),
208
+ SQLITE_TRANSIENT);
209
+ } catch (const std::overflow_error &) {
210
+ sqlite3_result_error(ctx, "Buffer too large", -1);
211
+ }
212
+ } else {
213
+ // For any other type, convert to string
214
+ std::string str_val = value.ToString().Utf8Value();
215
+ try {
216
+ sqlite3_result_text(ctx, str_val.c_str(), SafeCastToInt(str_val.length()),
217
+ SQLITE_TRANSIENT);
218
+ } catch (const std::overflow_error &) {
219
+ sqlite3_result_error(ctx, "Converted string value too long", -1);
220
+ }
221
+ }
222
+ }
223
+
224
+ } // namespace sqlite
225
+ } // namespace photostructure
@@ -0,0 +1,40 @@
1
+ #ifndef SRC_USER_FUNCTION_H_
2
+ #define SRC_USER_FUNCTION_H_
3
+
4
+ #include <napi.h>
5
+ #include <sqlite3.h>
6
+
7
+ #include <string>
8
+
9
+ namespace photostructure {
10
+ namespace sqlite {
11
+
12
+ // Forward declaration
13
+ class DatabaseSync;
14
+
15
+ // User-defined function wrapper for SQLite callbacks
16
+ class UserDefinedFunction {
17
+ public:
18
+ UserDefinedFunction(Napi::Env env, Napi::Function fn, DatabaseSync *db,
19
+ bool use_bigint_args);
20
+ ~UserDefinedFunction();
21
+
22
+ // SQLite callback functions
23
+ static void xFunc(sqlite3_context *ctx, int argc, sqlite3_value **argv);
24
+ static void xDestroy(void *self);
25
+
26
+ private:
27
+ Napi::Env env_;
28
+ Napi::FunctionReference fn_;
29
+ DatabaseSync *db_;
30
+ bool use_bigint_args_;
31
+
32
+ // Helper methods
33
+ Napi::Value SqliteValueToJS(sqlite3_value *value);
34
+ void JSValueToSqliteResult(sqlite3_context *ctx, Napi::Value value);
35
+ };
36
+
37
+ } // namespace sqlite
38
+ } // namespace photostructure
39
+
40
+ #endif // SRC_USER_FUNCTION_H_