Skip to content

Commit 2ab490a

Browse files
committed
fix reviews
1 parent ffd7dd0 commit 2ab490a

File tree

3 files changed

+55
-18
lines changed

3 files changed

+55
-18
lines changed

doc/api/sqlite.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,19 +157,31 @@ changes:
157157
**Default:** `false`.
158158
* `limits` {Object} Configuration for various SQLite limits. These limits
159159
can be used to prevent excessive resource consumption when handling
160-
potentially malicious input. See [Run-Time Limits][] in the SQLite
161-
documentation for details. The following properties are supported:
160+
potentially malicious input. See [Run-Time Limits][] and [Limit Constants][]
161+
in the SQLite documentation for details. The following properties are
162+
supported:
162163
* `length` {number} Maximum length of a string or BLOB.
164+
**Default:** `1000000000`.
163165
* `sqlLength` {number} Maximum length of an SQL statement.
166+
**Default:** `1000000000`.
164167
* `column` {number} Maximum number of columns.
168+
**Default:** `2000`.
165169
* `exprDepth` {number} Maximum depth of expression tree.
170+
**Default:** `1000`.
166171
* `compoundSelect` {number} Maximum number of terms in compound SELECT.
172+
**Default:** `500`.
167173
* `vdbeOp` {number} Maximum number of VDBE instructions.
174+
**Default:** `250000000`.
168175
* `functionArg` {number} Maximum number of function arguments.
176+
**Default:** `1000`.
169177
* `attach` {number} Maximum number of attached databases.
178+
**Default:** `10`.
170179
* `likePatternLength` {number} Maximum length of LIKE pattern.
180+
**Default:** `50000`.
171181
* `variableNumber` {number} Maximum number of SQL variables.
182+
**Default:** `32766`.
172183
* `triggerDepth` {number} Maximum trigger recursion depth.
184+
**Default:** `1000`.
173185

174186
Constructs a new `DatabaseSync` instance.
175187

@@ -1490,11 +1502,12 @@ callback function to indicate what type of operation is being authorized.
14901502
[Changesets and Patchsets]: https://www.sqlite.org/sessionintro.html#changesets_and_patchsets
14911503
[Constants Passed To The Conflict Handler]: https://www.sqlite.org/session/c_changeset_conflict.html
14921504
[Constants Returned From The Conflict Handler]: https://www.sqlite.org/session/c_changeset_abort.html
1505+
[Limit Constants]: https://www.sqlite.org/c3ref/c_limit_attached.html
1506+
[Run-Time Limits]: https://www.sqlite.org/c3ref/limit.html
14931507
[SQL injection]: https://en.wikipedia.org/wiki/SQL_injection
14941508
[Type conversion between JavaScript and SQLite]: #type-conversion-between-javascript-and-sqlite
14951509
[`ATTACH DATABASE`]: https://www.sqlite.org/lang_attach.html
14961510
[`PRAGMA foreign_keys`]: https://www.sqlite.org/pragma.html#pragma_foreign_keys
1497-
[Run-Time Limits]: https://www.sqlite.org/c3ref/limit.html
14981511
[`SQLITE_DBCONFIG_DEFENSIVE`]: https://www.sqlite.org/c3ref/c_dbconfig_defensive.html#sqlitedbconfigdefensive
14991512
[`SQLITE_DETERMINISTIC`]: https://www.sqlite.org/c3ref/c_deterministic.html
15001513
[`SQLITE_DIRECTONLY`]: https://www.sqlite.org/c3ref/c_deterministic.html

src/node_sqlite.cc

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "threadpoolwork-inl.h"
1313
#include "util-inl.h"
1414

15+
#include <array>
1516
#include <cinttypes>
1617

1718
namespace node {
@@ -144,7 +145,7 @@ struct LimitInfo {
144145
int sqlite_limit_id;
145146
};
146147

147-
static constexpr LimitInfo kLimitMapping[] = {
148+
static constexpr std::array<LimitInfo, 11> kLimitMapping = {{
148149
{"length", SQLITE_LIMIT_LENGTH},
149150
{"sqlLength", SQLITE_LIMIT_SQL_LENGTH},
150151
{"column", SQLITE_LIMIT_COLUMN},
@@ -156,13 +157,11 @@ static constexpr LimitInfo kLimitMapping[] = {
156157
{"likePatternLength", SQLITE_LIMIT_LIKE_PATTERN_LENGTH},
157158
{"variableNumber", SQLITE_LIMIT_VARIABLE_NUMBER},
158159
{"triggerDepth", SQLITE_LIMIT_TRIGGER_DEPTH},
159-
};
160-
161-
static constexpr size_t kLimitMappingCount = arraysize(kLimitMapping);
160+
}};
162161

163162
// Helper function to find limit ID from JS property name
164163
static int GetLimitIdFromName(const std::string& name) {
165-
for (size_t i = 0; i < kLimitMappingCount; ++i) {
164+
for (size_t i = 0; i < kLimitMapping.size(); ++i) {
166165
if (name == kLimitMapping[i].js_name) {
167166
return kLimitMapping[i].sqlite_limit_id;
168167
}
@@ -835,7 +834,7 @@ void DatabaseSyncLimits::LimitsEnumerator(
835834
Isolate* isolate = info.GetIsolate();
836835
LocalVector<Value> names(isolate);
837836

838-
for (size_t i = 0; i < kLimitMappingCount; ++i) {
837+
for (size_t i = 0; i < kLimitMapping.size(); ++i) {
839838
Local<String> name;
840839
if (String::NewFromUtf8(isolate, kLimitMapping[i].js_name).ToLocal(&name)) {
841840
names.push_back(name);
@@ -1301,7 +1300,7 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
13011300
Local<Object> limits_obj = limits_v.As<Object>();
13021301

13031302
// Iterate through known limit names and extract values
1304-
for (size_t i = 0; i < kLimitMappingCount; ++i) {
1303+
for (size_t i = 0; i < kLimitMapping.size(); ++i) {
13051304
Local<String> key;
13061305
if (!String::NewFromUtf8(env->isolate(), kLimitMapping[i].js_name)
13071306
.ToLocal(&key)) {

test/parallel/test-sqlite-limits.js

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,23 @@ const { DatabaseSync } = require('node:sqlite');
55
const { suite, test } = require('node:test');
66

77
suite('DatabaseSync limits', () => {
8+
test('default limits match expected SQLite defaults', (t) => {
9+
const db = new DatabaseSync(':memory:');
10+
t.assert.deepStrictEqual({ ...db.limits }, {
11+
length: 1000000000,
12+
sqlLength: 1000000000,
13+
column: 2000,
14+
exprDepth: 1000,
15+
compoundSelect: 500,
16+
vdbeOp: 250000000,
17+
functionArg: 1000,
18+
attach: 10,
19+
likePatternLength: 50000,
20+
variableNumber: 32766,
21+
triggerDepth: 1000,
22+
});
23+
});
24+
825
test('constructor accepts limits option', (t) => {
926
const db = new DatabaseSync(':memory:', {
1027
limits: {
@@ -33,7 +50,6 @@ suite('DatabaseSync limits', () => {
3350
t.assert.strictEqual(db.limits.likePatternLength, 1000);
3451
t.assert.strictEqual(db.limits.variableNumber, 100);
3552
t.assert.strictEqual(db.limits.triggerDepth, 5);
36-
db.close();
3753
});
3854

3955
test('getter returns current limit value', (t) => {
@@ -42,7 +58,6 @@ suite('DatabaseSync limits', () => {
4258
t.assert.ok(db.limits.length > 0);
4359
t.assert.strictEqual(typeof db.limits.sqlLength, 'number');
4460
t.assert.ok(db.limits.sqlLength > 0);
45-
db.close();
4661
});
4762

4863
test('setter modifies limit value', (t) => {
@@ -56,8 +71,6 @@ suite('DatabaseSync limits', () => {
5671

5772
db.limits.column = 50;
5873
t.assert.strictEqual(db.limits.column, 50);
59-
60-
db.close();
6174
});
6275

6376
test('throws on invalid argument type', (t) => {
@@ -68,7 +81,6 @@ suite('DatabaseSync limits', () => {
6881
name: 'TypeError',
6982
message: /Limit value must be an integer/,
7083
});
71-
db.close();
7284
});
7385

7486
test('throws on negative value', (t) => {
@@ -79,7 +91,6 @@ suite('DatabaseSync limits', () => {
7991
name: 'RangeError',
8092
message: /Limit value must be non-negative/,
8193
});
82-
db.close();
8394
});
8495

8596
test('throws on getter access after close', (t) => {
@@ -118,7 +129,6 @@ suite('DatabaseSync limits', () => {
118129
t.assert.ok(keys.includes('likePatternLength'));
119130
t.assert.ok(keys.includes('variableNumber'));
120131
t.assert.ok(keys.includes('triggerDepth'));
121-
db.close();
122132
});
123133

124134
test('throws on invalid limits option type', (t) => {
@@ -156,6 +166,21 @@ suite('DatabaseSync limits', () => {
156166
});
157167
t.assert.strictEqual(db.limits.length, 100000);
158168
t.assert.strictEqual(typeof db.limits.sqlLength, 'number');
159-
db.close();
169+
});
170+
171+
test('throws when exceeding column limit', (t) => {
172+
const db = new DatabaseSync(':memory:', {
173+
limits: {
174+
column: 10,
175+
}
176+
});
177+
178+
db.exec('CREATE TABLE t1 (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10)');
179+
180+
t.assert.throws(() => {
181+
db.exec('CREATE TABLE t2 (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11)');
182+
}, {
183+
message: /too many columns/,
184+
});
160185
});
161186
});

0 commit comments

Comments
 (0)