@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.
- package/LICENSE +21 -0
- package/README.md +99 -0
- package/binding.gyp +42 -0
- package/deps/common.gypi +68 -0
- package/deps/copy.js +31 -0
- package/deps/defines.gypi +43 -0
- package/deps/download.sh +122 -0
- package/deps/patches/1208.patch +15 -0
- package/deps/sqlite3/sqlite3.c +265969 -0
- package/deps/sqlite3/sqlite3.h +13968 -0
- package/deps/sqlite3/sqlite3ext.h +730 -0
- package/deps/sqlite3.gyp +80 -0
- package/deps/test_extension.c +21 -0
- package/lib/database.js +93 -0
- package/lib/index.js +3 -0
- package/lib/methods/aggregate.js +43 -0
- package/lib/methods/backup.js +67 -0
- package/lib/methods/function.js +31 -0
- package/lib/methods/inspect.js +7 -0
- package/lib/methods/pragma.js +12 -0
- package/lib/methods/serialize.js +16 -0
- package/lib/methods/table.js +189 -0
- package/lib/methods/transaction.js +78 -0
- package/lib/methods/wrappers.js +73 -0
- package/lib/sqlite-error.js +20 -0
- package/lib/util.js +12 -0
- package/package.json +59 -0
- package/src/addon.cpp +48 -0
- package/src/better_sqlite3.cpp +79 -0
- package/src/objects/backup.cpp +120 -0
- package/src/objects/backup.hpp +36 -0
- package/src/objects/database.cpp +521 -0
- package/src/objects/database.hpp +116 -0
- package/src/objects/session.cpp +148 -0
- package/src/objects/session.hpp +33 -0
- package/src/objects/statement-iterator.cpp +113 -0
- package/src/objects/statement-iterator.hpp +50 -0
- package/src/objects/statement.cpp +383 -0
- package/src/objects/statement.hpp +58 -0
- package/src/util/bind-map.cpp +73 -0
- package/src/util/binder.cpp +193 -0
- package/src/util/constants.cpp +172 -0
- package/src/util/custom-aggregate.cpp +121 -0
- package/src/util/custom-function.cpp +59 -0
- package/src/util/custom-table.cpp +409 -0
- package/src/util/data-converter.cpp +17 -0
- package/src/util/data.cpp +194 -0
- package/src/util/helpers.cpp +109 -0
- package/src/util/macros.cpp +70 -0
- package/src/util/query-macros.cpp +71 -0
- package/src/util/row-builder.cpp +49 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { cppdb } = require('../util');
|
|
3
|
+
|
|
4
|
+
exports.prepare = function prepare(sql) {
|
|
5
|
+
return this[cppdb].prepare(sql, this, false);
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
exports.exec = function exec(sql) {
|
|
9
|
+
this[cppdb].exec(sql);
|
|
10
|
+
return this;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
exports.close = function close() {
|
|
14
|
+
this[cppdb].close();
|
|
15
|
+
return this;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
exports.loadExtension = function loadExtension(...args) {
|
|
19
|
+
this[cppdb].loadExtension(...args);
|
|
20
|
+
return this;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
exports.defaultSafeIntegers = function defaultSafeIntegers(...args) {
|
|
24
|
+
this[cppdb].defaultSafeIntegers(...args);
|
|
25
|
+
return this;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
exports.unsafeMode = function unsafeMode(...args) {
|
|
29
|
+
this[cppdb].unsafeMode(...args);
|
|
30
|
+
return this;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
exports.createSession = function createSession(dbName) {
|
|
34
|
+
return this[cppdb].createSession(this, dbName || 'main');
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
exports.applyChangeset = function applyChangeset(changeset) {
|
|
38
|
+
if (!Buffer.isBuffer(changeset)) {
|
|
39
|
+
throw new TypeError('Expected first argument to be a Buffer');
|
|
40
|
+
}
|
|
41
|
+
this[cppdb].applyChangeset(changeset);
|
|
42
|
+
return this;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
exports.invertChangeset = function invertChangeset(changeset) {
|
|
46
|
+
if (!Buffer.isBuffer(changeset)) {
|
|
47
|
+
throw new TypeError('Expected first argument to be a Buffer');
|
|
48
|
+
}
|
|
49
|
+
return this[cppdb].invertChangeset(changeset);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
exports.getters = {
|
|
53
|
+
name: {
|
|
54
|
+
get: function name() { return this[cppdb].name; },
|
|
55
|
+
enumerable: true,
|
|
56
|
+
},
|
|
57
|
+
open: {
|
|
58
|
+
get: function open() { return this[cppdb].open; },
|
|
59
|
+
enumerable: true,
|
|
60
|
+
},
|
|
61
|
+
inTransaction: {
|
|
62
|
+
get: function inTransaction() { return this[cppdb].inTransaction; },
|
|
63
|
+
enumerable: true,
|
|
64
|
+
},
|
|
65
|
+
readonly: {
|
|
66
|
+
get: function readonly() { return this[cppdb].readonly; },
|
|
67
|
+
enumerable: true,
|
|
68
|
+
},
|
|
69
|
+
memory: {
|
|
70
|
+
get: function memory() { return this[cppdb].memory; },
|
|
71
|
+
enumerable: true,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const descriptor = { value: 'SqliteError', writable: true, enumerable: false, configurable: true };
|
|
3
|
+
|
|
4
|
+
function SqliteError(message, code) {
|
|
5
|
+
if (new.target !== SqliteError) {
|
|
6
|
+
return new SqliteError(message, code);
|
|
7
|
+
}
|
|
8
|
+
if (typeof code !== 'string') {
|
|
9
|
+
throw new TypeError('Expected second argument to be a string');
|
|
10
|
+
}
|
|
11
|
+
Error.call(this, message);
|
|
12
|
+
descriptor.value = '' + message;
|
|
13
|
+
Object.defineProperty(this, 'message', descriptor);
|
|
14
|
+
Error.captureStackTrace(this, SqliteError);
|
|
15
|
+
this.code = code;
|
|
16
|
+
}
|
|
17
|
+
Object.setPrototypeOf(SqliteError, Error);
|
|
18
|
+
Object.setPrototypeOf(SqliteError.prototype, Error.prototype);
|
|
19
|
+
Object.defineProperty(SqliteError.prototype, 'name', descriptor);
|
|
20
|
+
module.exports = SqliteError;
|
package/lib/util.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
exports.getBooleanOption = (options, key) => {
|
|
4
|
+
let value = false;
|
|
5
|
+
if (key in options && typeof (value = options[key]) !== 'boolean') {
|
|
6
|
+
throw new TypeError(`Expected the "${key}" option to be a boolean`);
|
|
7
|
+
}
|
|
8
|
+
return value;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
exports.cppdb = Symbol();
|
|
12
|
+
exports.inspect = Symbol.for('nodejs.util.inspect.custom');
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@barakxyz/better-sqlite3",
|
|
3
|
+
"version": "12.6.2",
|
|
4
|
+
"description": "The fastest and simplest library for SQLite in Node.js. Fork with session extension enabled.",
|
|
5
|
+
"homepage": "https://github.com/BarakXYZ/better-sqlite3",
|
|
6
|
+
"author": "Joshua Wise <joshuathomaswise@gmail.com>",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git://github.com/BarakXYZ/better-sqlite3.git"
|
|
10
|
+
},
|
|
11
|
+
"main": "lib/index.js",
|
|
12
|
+
"files": [
|
|
13
|
+
"binding.gyp",
|
|
14
|
+
"src/**/*.[ch]pp",
|
|
15
|
+
"lib/**",
|
|
16
|
+
"deps/**"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": "20.x || 22.x || 23.x || 24.x || 25.x"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"bindings": "^1.5.0",
|
|
23
|
+
"prebuild-install": "^7.1.1"
|
|
24
|
+
},
|
|
25
|
+
"overrides": {
|
|
26
|
+
"prebuild": {
|
|
27
|
+
"node-abi": "^4.25.0"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"chai": "^4.3.8",
|
|
32
|
+
"cli-color": "^2.0.3",
|
|
33
|
+
"fs-extra": "^11.1.1",
|
|
34
|
+
"mocha": "^10.2.0",
|
|
35
|
+
"nodemark": "^0.3.0",
|
|
36
|
+
"prebuild": "^13.0.1",
|
|
37
|
+
"sqlite": "^5.0.1",
|
|
38
|
+
"sqlite3": "^5.1.6"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"install": "prebuild-install || node-gyp rebuild --release",
|
|
42
|
+
"build-release": "node-gyp rebuild --release",
|
|
43
|
+
"build-debug": "node-gyp rebuild --debug",
|
|
44
|
+
"test": "mocha --exit --slow=75 --timeout=5000",
|
|
45
|
+
"benchmark": "node benchmark",
|
|
46
|
+
"download": "bash ./deps/download.sh"
|
|
47
|
+
},
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"keywords": [
|
|
50
|
+
"sql",
|
|
51
|
+
"sqlite",
|
|
52
|
+
"sqlite3",
|
|
53
|
+
"transactions",
|
|
54
|
+
"user-defined functions",
|
|
55
|
+
"aggregate functions",
|
|
56
|
+
"window functions",
|
|
57
|
+
"database"
|
|
58
|
+
]
|
|
59
|
+
}
|
package/src/addon.cpp
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
struct Addon {
|
|
2
|
+
explicit Addon(v8::Isolate* isolate) :
|
|
3
|
+
privileged_info(NULL),
|
|
4
|
+
next_id(0),
|
|
5
|
+
cs(isolate) {}
|
|
6
|
+
|
|
7
|
+
static void Cleanup(void* ptr) {
|
|
8
|
+
Addon* addon = static_cast<Addon*>(ptr);
|
|
9
|
+
for (Database* db : addon->dbs) db->CloseHandles();
|
|
10
|
+
addon->dbs.clear();
|
|
11
|
+
delete addon;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
inline sqlite3_uint64 NextId() {
|
|
15
|
+
return next_id++;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static void ConfigureURI() {
|
|
19
|
+
static std::once_flag init_flag;
|
|
20
|
+
std::call_once(init_flag, [](){
|
|
21
|
+
const char* env = getenv("SQLITE_USE_URI");
|
|
22
|
+
if (env != NULL) {
|
|
23
|
+
if (strcmp(env, "1") == 0) {
|
|
24
|
+
int status = sqlite3_config(SQLITE_CONFIG_URI, 1);
|
|
25
|
+
assert(status == SQLITE_OK); ((void)status);
|
|
26
|
+
} else if (strcmp(env, "0") == 0) {
|
|
27
|
+
int status = sqlite3_config(SQLITE_CONFIG_URI, 0);
|
|
28
|
+
assert(status == SQLITE_OK); ((void)status);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static NODE_METHOD(JS_setErrorConstructor) {
|
|
35
|
+
REQUIRE_ARGUMENT_FUNCTION(first, v8::Local<v8::Function> SqliteError);
|
|
36
|
+
OnlyAddon->SqliteError.Reset(OnlyIsolate, SqliteError);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
v8::Global<v8::Function> Statement;
|
|
40
|
+
v8::Global<v8::Function> StatementIterator;
|
|
41
|
+
v8::Global<v8::Function> Backup;
|
|
42
|
+
v8::Global<v8::Function> Session;
|
|
43
|
+
v8::Global<v8::Function> SqliteError;
|
|
44
|
+
NODE_ARGUMENTS_POINTER privileged_info;
|
|
45
|
+
sqlite3_uint64 next_id;
|
|
46
|
+
CS cs;
|
|
47
|
+
std::set<Database*, Database::CompareDatabase> dbs;
|
|
48
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#include <climits>
|
|
2
|
+
#include <cstdio>
|
|
3
|
+
#include <cstring>
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <vector>
|
|
6
|
+
#include <set>
|
|
7
|
+
#include <unordered_map>
|
|
8
|
+
#include <algorithm>
|
|
9
|
+
#include <mutex>
|
|
10
|
+
#include <sqlite3.h>
|
|
11
|
+
#include <node.h>
|
|
12
|
+
#include <node_object_wrap.h>
|
|
13
|
+
#include <node_buffer.h>
|
|
14
|
+
|
|
15
|
+
struct Addon;
|
|
16
|
+
class Database;
|
|
17
|
+
class Statement;
|
|
18
|
+
class StatementIterator;
|
|
19
|
+
class Backup;
|
|
20
|
+
class Session;
|
|
21
|
+
|
|
22
|
+
#include "util/macros.cpp"
|
|
23
|
+
#include "util/helpers.cpp"
|
|
24
|
+
#include "util/constants.cpp"
|
|
25
|
+
#include "util/bind-map.cpp"
|
|
26
|
+
#include "util/data-converter.cpp"
|
|
27
|
+
#include "util/data.cpp"
|
|
28
|
+
#if defined(NODE_MODULE_VERSION) && NODE_MODULE_VERSION >= 127
|
|
29
|
+
#include "util/row-builder.cpp"
|
|
30
|
+
#endif
|
|
31
|
+
|
|
32
|
+
#include "objects/backup.hpp"
|
|
33
|
+
#include "objects/session.hpp"
|
|
34
|
+
#include "objects/statement.hpp"
|
|
35
|
+
#include "objects/database.hpp"
|
|
36
|
+
#include "addon.cpp"
|
|
37
|
+
#include "objects/statement-iterator.hpp"
|
|
38
|
+
|
|
39
|
+
#include "util/query-macros.cpp"
|
|
40
|
+
#include "util/custom-function.cpp"
|
|
41
|
+
#include "util/custom-aggregate.cpp"
|
|
42
|
+
#include "util/custom-table.cpp"
|
|
43
|
+
#include "util/binder.cpp"
|
|
44
|
+
|
|
45
|
+
#include "objects/backup.cpp"
|
|
46
|
+
#include "objects/session.cpp"
|
|
47
|
+
#include "objects/statement.cpp"
|
|
48
|
+
#include "objects/database.cpp"
|
|
49
|
+
#include "objects/statement-iterator.cpp"
|
|
50
|
+
|
|
51
|
+
NODE_MODULE_INIT(/* exports, context */) {
|
|
52
|
+
#if defined(NODE_MODULE_VERSION) && NODE_MODULE_VERSION >= 140
|
|
53
|
+
// Use Isolate::GetCurrent as stated in deprecation message within v8_context.h 13.9.72320122
|
|
54
|
+
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
55
|
+
#else
|
|
56
|
+
v8::Isolate* isolate = context->GetIsolate();
|
|
57
|
+
#endif
|
|
58
|
+
v8::HandleScope scope(isolate);
|
|
59
|
+
Addon::ConfigureURI();
|
|
60
|
+
|
|
61
|
+
// Initialize addon instance.
|
|
62
|
+
Addon* addon = new Addon(isolate);
|
|
63
|
+
v8::Local<v8::External> data = v8::External::New(isolate, addon);
|
|
64
|
+
node::AddEnvironmentCleanupHook(isolate, Addon::Cleanup, addon);
|
|
65
|
+
|
|
66
|
+
// Create and export native-backed classes and functions.
|
|
67
|
+
exports->Set(context, InternalizedFromLatin1(isolate, "Database"), Database::Init(isolate, data)).FromJust();
|
|
68
|
+
exports->Set(context, InternalizedFromLatin1(isolate, "Statement"), Statement::Init(isolate, data)).FromJust();
|
|
69
|
+
exports->Set(context, InternalizedFromLatin1(isolate, "StatementIterator"), StatementIterator::Init(isolate, data)).FromJust();
|
|
70
|
+
exports->Set(context, InternalizedFromLatin1(isolate, "Backup"), Backup::Init(isolate, data)).FromJust();
|
|
71
|
+
exports->Set(context, InternalizedFromLatin1(isolate, "Session"), Session::Init(isolate, data)).FromJust();
|
|
72
|
+
exports->Set(context, InternalizedFromLatin1(isolate, "setErrorConstructor"), v8::FunctionTemplate::New(isolate, Addon::JS_setErrorConstructor, data)->GetFunction(context).ToLocalChecked()).FromJust();
|
|
73
|
+
|
|
74
|
+
// Store addon instance data.
|
|
75
|
+
addon->Statement.Reset(isolate, exports->Get(context, InternalizedFromLatin1(isolate, "Statement")).ToLocalChecked().As<v8::Function>());
|
|
76
|
+
addon->StatementIterator.Reset(isolate, exports->Get(context, InternalizedFromLatin1(isolate, "StatementIterator")).ToLocalChecked().As<v8::Function>());
|
|
77
|
+
addon->Backup.Reset(isolate, exports->Get(context, InternalizedFromLatin1(isolate, "Backup")).ToLocalChecked().As<v8::Function>());
|
|
78
|
+
addon->Session.Reset(isolate, exports->Get(context, InternalizedFromLatin1(isolate, "Session")).ToLocalChecked().As<v8::Function>());
|
|
79
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Backup::Backup(
|
|
2
|
+
Database* db,
|
|
3
|
+
sqlite3* dest_handle,
|
|
4
|
+
sqlite3_backup* backup_handle,
|
|
5
|
+
sqlite3_uint64 id,
|
|
6
|
+
bool unlink
|
|
7
|
+
) :
|
|
8
|
+
node::ObjectWrap(),
|
|
9
|
+
db(db),
|
|
10
|
+
dest_handle(dest_handle),
|
|
11
|
+
backup_handle(backup_handle),
|
|
12
|
+
id(id),
|
|
13
|
+
alive(true),
|
|
14
|
+
unlink(unlink) {
|
|
15
|
+
assert(db != NULL);
|
|
16
|
+
assert(dest_handle != NULL);
|
|
17
|
+
assert(backup_handle != NULL);
|
|
18
|
+
db->AddBackup(this);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
Backup::~Backup() {
|
|
22
|
+
if (alive) db->RemoveBackup(this);
|
|
23
|
+
CloseHandles();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Whenever this is used, db->RemoveBackup must be invoked beforehand.
|
|
27
|
+
void Backup::CloseHandles() {
|
|
28
|
+
if (alive) {
|
|
29
|
+
alive = false;
|
|
30
|
+
std::string filename(sqlite3_db_filename(dest_handle, "main"));
|
|
31
|
+
sqlite3_backup_finish(backup_handle);
|
|
32
|
+
int status = sqlite3_close(dest_handle);
|
|
33
|
+
assert(status == SQLITE_OK); ((void)status);
|
|
34
|
+
if (unlink) remove(filename.c_str());
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
INIT(Backup::Init) {
|
|
39
|
+
v8::Local<v8::FunctionTemplate> t = NewConstructorTemplate(isolate, data, JS_new, "Backup");
|
|
40
|
+
SetPrototypeMethod(isolate, data, t, "transfer", JS_transfer);
|
|
41
|
+
SetPrototypeMethod(isolate, data, t, "close", JS_close);
|
|
42
|
+
return t->GetFunction(OnlyContext).ToLocalChecked();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
NODE_METHOD(Backup::JS_new) {
|
|
46
|
+
UseAddon;
|
|
47
|
+
if (!addon->privileged_info) return ThrowTypeError("Disabled constructor");
|
|
48
|
+
assert(info.IsConstructCall());
|
|
49
|
+
Database* db = Unwrap<Database>(addon->privileged_info->This());
|
|
50
|
+
REQUIRE_DATABASE_OPEN(db->GetState());
|
|
51
|
+
REQUIRE_DATABASE_NOT_BUSY(db->GetState());
|
|
52
|
+
|
|
53
|
+
v8::Local<v8::Object> database = (*addon->privileged_info)[0].As<v8::Object>();
|
|
54
|
+
v8::Local<v8::String> attachedName = (*addon->privileged_info)[1].As<v8::String>();
|
|
55
|
+
v8::Local<v8::String> destFile = (*addon->privileged_info)[2].As<v8::String>();
|
|
56
|
+
bool unlink = (*addon->privileged_info)[3].As<v8::Boolean>()->Value();
|
|
57
|
+
|
|
58
|
+
UseIsolate;
|
|
59
|
+
sqlite3* dest_handle;
|
|
60
|
+
v8::String::Utf8Value dest_file(isolate, destFile);
|
|
61
|
+
v8::String::Utf8Value attached_name(isolate, attachedName);
|
|
62
|
+
int mask = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
|
|
63
|
+
|
|
64
|
+
if (sqlite3_open_v2(*dest_file, &dest_handle, mask, NULL) != SQLITE_OK) {
|
|
65
|
+
Database::ThrowSqliteError(addon, dest_handle);
|
|
66
|
+
int status = sqlite3_close(dest_handle);
|
|
67
|
+
assert(status == SQLITE_OK); ((void)status);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
sqlite3_extended_result_codes(dest_handle, 1);
|
|
72
|
+
sqlite3_limit(dest_handle, SQLITE_LIMIT_LENGTH, INT_MAX);
|
|
73
|
+
sqlite3_backup* backup_handle = sqlite3_backup_init(dest_handle, "main", db->GetHandle(), *attached_name);
|
|
74
|
+
if (backup_handle == NULL) {
|
|
75
|
+
Database::ThrowSqliteError(addon, dest_handle);
|
|
76
|
+
int status = sqlite3_close(dest_handle);
|
|
77
|
+
assert(status == SQLITE_OK); ((void)status);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
Backup* backup = new Backup(db, dest_handle, backup_handle, addon->NextId(), unlink);
|
|
82
|
+
backup->Wrap(info.This());
|
|
83
|
+
SetFrozen(isolate, OnlyContext, info.This(), addon->cs.database, database);
|
|
84
|
+
|
|
85
|
+
info.GetReturnValue().Set(info.This());
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
NODE_METHOD(Backup::JS_transfer) {
|
|
89
|
+
Backup* backup = Unwrap<Backup>(info.This());
|
|
90
|
+
REQUIRE_ARGUMENT_INT32(first, int pages);
|
|
91
|
+
REQUIRE_DATABASE_OPEN(backup->db->GetState());
|
|
92
|
+
assert(backup->db->GetState()->busy == false);
|
|
93
|
+
assert(backup->alive == true);
|
|
94
|
+
|
|
95
|
+
sqlite3_backup* backup_handle = backup->backup_handle;
|
|
96
|
+
int status = sqlite3_backup_step(backup_handle, pages) & 0xff;
|
|
97
|
+
|
|
98
|
+
Addon* addon = backup->db->GetAddon();
|
|
99
|
+
if (status == SQLITE_OK || status == SQLITE_DONE || status == SQLITE_BUSY) {
|
|
100
|
+
int total_pages = sqlite3_backup_pagecount(backup_handle);
|
|
101
|
+
int remaining_pages = sqlite3_backup_remaining(backup_handle);
|
|
102
|
+
UseIsolate;
|
|
103
|
+
UseContext;
|
|
104
|
+
v8::Local<v8::Object> result = v8::Object::New(isolate);
|
|
105
|
+
result->Set(ctx, addon->cs.totalPages.Get(isolate), v8::Int32::New(isolate, total_pages)).FromJust();
|
|
106
|
+
result->Set(ctx, addon->cs.remainingPages.Get(isolate), v8::Int32::New(isolate, remaining_pages)).FromJust();
|
|
107
|
+
info.GetReturnValue().Set(result);
|
|
108
|
+
if (status == SQLITE_DONE) backup->unlink = false;
|
|
109
|
+
} else {
|
|
110
|
+
Database::ThrowSqliteError(addon, sqlite3_errstr(status), status);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
NODE_METHOD(Backup::JS_close) {
|
|
115
|
+
Backup* backup = Unwrap<Backup>(info.This());
|
|
116
|
+
assert(backup->db->GetState()->busy == false);
|
|
117
|
+
if (backup->alive) backup->db->RemoveBackup(backup);
|
|
118
|
+
backup->CloseHandles();
|
|
119
|
+
info.GetReturnValue().Set(info.This());
|
|
120
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class Backup : public node::ObjectWrap {
|
|
2
|
+
public:
|
|
3
|
+
|
|
4
|
+
~Backup();
|
|
5
|
+
|
|
6
|
+
// Whenever this is used, db->RemoveBackup must be invoked beforehand.
|
|
7
|
+
void CloseHandles();
|
|
8
|
+
|
|
9
|
+
// Used to support ordered containers.
|
|
10
|
+
static inline bool Compare(Backup const * const a, Backup const * const b) {
|
|
11
|
+
return a->id < b->id;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static INIT(Init);
|
|
15
|
+
|
|
16
|
+
private:
|
|
17
|
+
|
|
18
|
+
explicit Backup(
|
|
19
|
+
Database* db,
|
|
20
|
+
sqlite3* dest_handle,
|
|
21
|
+
sqlite3_backup* backup_handle,
|
|
22
|
+
sqlite3_uint64 id,
|
|
23
|
+
bool unlink
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
static NODE_METHOD(JS_new);
|
|
27
|
+
static NODE_METHOD(JS_transfer);
|
|
28
|
+
static NODE_METHOD(JS_close);
|
|
29
|
+
|
|
30
|
+
Database* const db;
|
|
31
|
+
sqlite3* const dest_handle;
|
|
32
|
+
sqlite3_backup* const backup_handle;
|
|
33
|
+
const sqlite3_uint64 id;
|
|
34
|
+
bool alive;
|
|
35
|
+
bool unlink;
|
|
36
|
+
};
|