Skip to content

Commit d9d3d0a

Browse files
committed
support sqlite3_limit(id, value) via db.configure('limit', id, value)
This extends `db.configure` to support the `sqlite3_limit` method. Calling `db.configure('limit', sqlite3.LIMIT_XXX, value)` is equivalent to calling `sqlite3_limit(db, SQLITE_LIMIT_XXX, value)`. For example, to prohibit attaching extra databases on a given database connection, you'd call `db.configure('limit', sqlite3.LIMIT_ATTACHED, 0)`.
1 parent 918052b commit d9d3d0a

File tree

4 files changed

+74
-0
lines changed

4 files changed

+74
-0
lines changed

src/database.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,22 @@ Napi::Value Database::Configure(const Napi::CallbackInfo& info) {
369369
baton->status = info[1].As<Napi::Number>().Int32Value();
370370
db->Schedule(SetBusyTimeout, baton);
371371
}
372+
else if (info[0].StrictEquals( Napi::String::New(env, "limit"))) {
373+
REQUIRE_ARGUMENTS(3);
374+
if (!info[1].IsNumber()) {
375+
Napi::TypeError::New(env, "limit id must be an integer").ThrowAsJavaScriptException();
376+
return env.Null();
377+
}
378+
if (!info[2].IsNumber()) {
379+
Napi::TypeError::New(env, "limit value must be an integer").ThrowAsJavaScriptException();
380+
return env.Null();
381+
}
382+
Napi::Function handle;
383+
int id = info[1].As<Napi::Number>().Int32Value();
384+
int value = info[2].As<Napi::Number>().Int32Value();
385+
Baton* baton = new LimitBaton(db, handle, id, value);
386+
db->Schedule(SetLimit, baton);
387+
}
372388
else {
373389
Napi::TypeError::New(env, (StringConcat(
374390
#if V8_MAJOR_VERSION > 6
@@ -413,6 +429,15 @@ void Database::SetBusyTimeout(Baton* b) {
413429
sqlite3_busy_timeout(baton->db->_handle, baton->status);
414430
}
415431

432+
void Database::SetLimit(Baton* b) {
433+
std::unique_ptr<LimitBaton> baton(static_cast<LimitBaton*>(b));
434+
435+
assert(baton->db->open);
436+
assert(baton->db->_handle);
437+
438+
sqlite3_limit(baton->db->_handle, baton->id, baton->value);
439+
}
440+
416441
void Database::RegisterTraceCallback(Baton* b) {
417442
std::unique_ptr<Baton> baton(b);
418443
assert(baton->db->open);

src/database.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ class Database : public Napi::ObjectWrap<Database> {
8080
Baton(db_, cb_), filename(filename_) {}
8181
};
8282

83+
struct LimitBaton : Baton {
84+
int id;
85+
int value;
86+
LimitBaton(Database* db_, Napi::Function cb_, int id_, int value_) :
87+
Baton(db_, cb_), id(id_), value(value_) {}
88+
};
89+
8390
typedef void (*Work_Callback)(Baton* baton);
8491

8592
struct Call {
@@ -169,6 +176,7 @@ class Database : public Napi::ObjectWrap<Database> {
169176
Napi::Value Interrupt(const Napi::CallbackInfo& info);
170177

171178
static void SetBusyTimeout(Baton* baton);
179+
static void SetLimit(Baton* baton);
172180

173181
static void RegisterTraceCallback(Baton* baton);
174182
static void TraceCallback(void* db, const char* sql);

src/node_sqlite3.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@ Napi::Object RegisterModule(Napi::Env env, Napi::Object exports) {
6161
DEFINE_CONSTANT_INTEGER(exports, SQLITE_FORMAT, FORMAT)
6262
DEFINE_CONSTANT_INTEGER(exports, SQLITE_RANGE, RANGE)
6363
DEFINE_CONSTANT_INTEGER(exports, SQLITE_NOTADB, NOTADB)
64+
65+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_LENGTH, LIMIT_LENGTH)
66+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_SQL_LENGTH, LIMIT_SQL_LENGTH)
67+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_COLUMN, LIMIT_COLUMN)
68+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_EXPR_DEPTH, LIMIT_EXPR_DEPTH)
69+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_COMPOUND_SELECT, LIMIT_COMPOUND_SELECT)
70+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_VDBE_OP, LIMIT_VDBE_OP)
71+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_FUNCTION_ARG, LIMIT_FUNCTION_ARG)
72+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_ATTACHED, LIMIT_ATTACHED)
73+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_LIKE_PATTERN_LENGTH, LIMIT_LIKE_PATTERN_LENGTH)
74+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_VARIABLE_NUMBER, LIMIT_VARIABLE_NUMBER)
75+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_TRIGGER_DEPTH, LIMIT_TRIGGER_DEPTH)
76+
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_WORKER_THREADS, LIMIT_WORKER_THREADS)
6477
});
6578

6679
return exports;

test/limit.test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
var sqlite3 = require('..');
2+
3+
describe('limit', function() {
4+
var db;
5+
6+
before(function(done) {
7+
db = new sqlite3.Database(':memory:', done);
8+
});
9+
10+
it('should support applying limits via configure', function(done) {
11+
db.configure('limit', sqlite3.LIMIT_ATTACHED, 0);
12+
db.exec("ATTACH 'test/support/prepare.db' AS zing", function(err) {
13+
if (!err) {
14+
throw new Error('ATTACH should not succeed');
15+
}
16+
if (err.errno === sqlite3.ERROR &&
17+
err.message === 'SQLITE_ERROR: too many attached databases - max 0') {
18+
db.configure('limit', sqlite3.LIMIT_ATTACHED, 1);
19+
db.exec("ATTACH 'test/support/prepare.db' AS zing", function(err) {
20+
if (err) throw err;
21+
db.close(done);
22+
});
23+
} else {
24+
throw err;
25+
}
26+
});
27+
});
28+
});

0 commit comments

Comments
 (0)