Skip to content

Commit

Permalink
Added support for setting SQLite limits
Browse files Browse the repository at this point in the history
  • Loading branch information
paulfitz committed Jul 31, 2022
1 parent 61194ec commit 1bcbf70
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 0 deletions.
25 changes: 25 additions & 0 deletions src/database.cc
Expand Up @@ -371,6 +371,22 @@ Napi::Value Database::Configure(const Napi::CallbackInfo& info) {
baton->status = info[1].As<Napi::Number>().Int32Value();
db->Schedule(SetBusyTimeout, baton);
}
else if (info[0].StrictEquals( Napi::String::New(env, "limit"))) {
REQUIRE_ARGUMENTS(3);
if (!info[1].IsNumber()) {
Napi::TypeError::New(env, "limit id must be an integer").ThrowAsJavaScriptException();
return env.Null();
}
if (!info[2].IsNumber()) {
Napi::TypeError::New(env, "limit value must be an integer").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Function handle;
int id = info[1].As<Napi::Number>().Int32Value();
int value = info[2].As<Napi::Number>().Int32Value();
Baton* baton = new LimitBaton(db, handle, id, value);
db->Schedule(SetLimit, baton);
}
else {
Napi::TypeError::New(env, (StringConcat(
#if V8_MAJOR_VERSION > 6
Expand Down Expand Up @@ -415,6 +431,15 @@ void Database::SetBusyTimeout(Baton* b) {
sqlite3_busy_timeout(baton->db->_handle, baton->status);
}

void Database::SetLimit(Baton* b) {
std::unique_ptr<LimitBaton> baton(static_cast<LimitBaton*>(b));

assert(baton->db->open);
assert(baton->db->_handle);

sqlite3_limit(baton->db->_handle, baton->id, baton->value);
}

void Database::RegisterTraceCallback(Baton* b) {
std::unique_ptr<Baton> baton(b);
assert(baton->db->open);
Expand Down
8 changes: 8 additions & 0 deletions src/database.h
Expand Up @@ -80,6 +80,13 @@ class Database : public Napi::ObjectWrap<Database> {
Baton(db_, cb_), filename(filename_) {}
};

struct LimitBaton : Baton {
int id;
int value;
LimitBaton(Database* db_, Napi::Function cb_, int id_, int value_) :
Baton(db_, cb_), id(id_), value(value_) {}
};

typedef void (*Work_Callback)(Baton* baton);

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

static void SetBusyTimeout(Baton* baton);
static void SetLimit(Baton* baton);

static void RegisterTraceCallback(Baton* baton);
static void TraceCallback(void* db, const char* sql);
Expand Down
13 changes: 13 additions & 0 deletions src/node_sqlite3.cc
Expand Up @@ -61,6 +61,19 @@ Napi::Object RegisterModule(Napi::Env env, Napi::Object exports) {
DEFINE_CONSTANT_INTEGER(exports, SQLITE_FORMAT, FORMAT)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_RANGE, RANGE)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_NOTADB, NOTADB)

DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_LENGTH, LIMIT_LENGTH)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_SQL_LENGTH, LIMIT_SQL_LENGTH)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_COLUMN, LIMIT_COLUMN)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_EXPR_DEPTH, LIMIT_EXPR_DEPTH)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_COMPOUND_SELECT, LIMIT_COMPOUND_SELECT)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_VDBE_OP, LIMIT_VDBE_OP)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_FUNCTION_ARG, LIMIT_FUNCTION_ARG)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_ATTACHED, LIMIT_ATTACHED)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_LIKE_PATTERN_LENGTH, LIMIT_LIKE_PATTERN_LENGTH)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_VARIABLE_NUMBER, LIMIT_VARIABLE_NUMBER)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_TRIGGER_DEPTH, LIMIT_TRIGGER_DEPTH)
DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_WORKER_THREADS, LIMIT_WORKER_THREADS)
});

return exports;
Expand Down
28 changes: 28 additions & 0 deletions test/limit.test.js
@@ -0,0 +1,28 @@
var sqlite3 = require('..');

describe('limit', function() {
var db;

before(function(done) {
db = new sqlite3.Database(':memory:', done);
});

it('should support applying limits via configure', function(done) {
db.configure('limit', sqlite3.LIMIT_ATTACHED, 0);
db.exec("ATTACH 'test/support/prepare.db' AS zing", function(err) {
if (!err) {
throw new Error('ATTACH should not succeed');
}
if (err.errno === sqlite3.ERROR &&
err.message === 'SQLITE_ERROR: too many attached databases - max 0') {
db.configure('limit', sqlite3.LIMIT_ATTACHED, 1);
db.exec("ATTACH 'test/support/prepare.db' AS zing", function(err) {
if (err) throw err;
db.close(done);
});
} else {
throw err;
}
});
});
});

0 comments on commit 1bcbf70

Please sign in to comment.