jsql-neo 6.4.0-beta.10 → 6.4.0-beta.12

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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  > **One engine to rule them all** — a Rust-powered embedded database that speaks your language:
4
4
  > MySQL, PostgreSQL, MongoDB, Redis, SQL, TypeScript, **and the browser**.
5
5
 
6
- > **v6.4.0-beta.10** — official release build · [github.com/vexify-org/JSQL-neo](https://github.com/vexify-org/JSQL-neo) · [jsql.vexify.top](https://jsql.vexify.top)
6
+ > **v6.4.0-beta.12** — official release build · [github.com/vexify-org/JSQL-neo](https://github.com/vexify-org/JSQL-neo) · [jsql.vexify.top](https://jsql.vexify.top)
7
7
 
8
8
  ![Engines](https://img.shields.io/badge/engines-Native%20%7C%20WASM%20%7C%20Pure%20JS-7ee787)
9
9
  ![MySQL](https://img.shields.io/badge/protocol-MySQL%20compatible-1f6feb)
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * JSQL-NEO v6.4.0-beta.10 — Rust-Powered Embedded Database (WASM + HTTP)
2
+ * JSQL-NEO v6.4.0-beta.12 — Rust-Powered Embedded Database (WASM + HTTP)
3
3
  *
4
4
  * @example
5
5
  * const jsql = require('jsql-neo');
package/lib/sql.js CHANGED
@@ -392,6 +392,7 @@ class Parser {
392
392
  this.pos = 0;
393
393
  this.paramCount = 0; // 顺序占位符 ? 的序号(从 0 开始)
394
394
  this.subquerySeq = 0; // FROM 子查询无别名时自动生成 __subN
395
+ this.depth = 0; // 子查询递归深度
395
396
  }
396
397
 
397
398
  peek(offset = 0) { return this.tokens[this.pos + offset]; }
@@ -1220,6 +1221,8 @@ class Parser {
1220
1221
  }
1221
1222
 
1222
1223
  parseSelect() {
1224
+ this.depth++;
1225
+ if (this.depth > 200) throw new Error('Subquery nesting too deep (max 200)');
1223
1226
  this.expectKeyword('SELECT');
1224
1227
  let distinct = false;
1225
1228
  if (this.isKeyword('DISTINCT')) { this.next(); distinct = true; }
@@ -1390,9 +1393,18 @@ class Parser {
1390
1393
  if (this.isKeyword('LIMIT')) {
1391
1394
  this.next();
1392
1395
  limit = this.parseValue();
1396
+ if (typeof limit === 'bigint') limit = Number(limit <= BigInt(Number.MAX_SAFE_INTEGER) ? limit : BigInt(Number.MAX_SAFE_INTEGER));
1393
1397
  if (typeof limit === 'number' && limit < 0) throw new Error(`LIMIT must be a non-negative integer, got ${limit}`);
1394
- if (this.isKeyword('OFFSET')) { this.next(); offset = this.parseValue(); if (typeof offset === 'number' && offset < 0) throw new Error(`OFFSET must be a non-negative integer, got ${offset}`); }
1395
- else if (this.peek().type === 'op' && this.peek().value === ',') { this.next(); offset = limit; limit = this.parseValue(); if (typeof limit === 'number' && limit < 0) throw new Error(`LIMIT must be a non-negative integer, got ${limit}`); }
1398
+ if (this.isKeyword('OFFSET')) { this.next(); offset = this.parseValue(); if (typeof offset === 'bigint') offset = Number(offset <= BigInt(Number.MAX_SAFE_INTEGER) ? offset : BigInt(Number.MAX_SAFE_INTEGER)); if (typeof offset === 'number' && offset < 0) throw new Error(`OFFSET must be a non-negative integer, got ${offset}`); }
1399
+ else if (this.peek().type === 'op' && this.peek().value === ',') { this.next(); offset = limit; limit = this.parseValue(); if (typeof limit === 'bigint') limit = Number(limit <= BigInt(Number.MAX_SAFE_INTEGER) ? limit : BigInt(Number.MAX_SAFE_INTEGER)); if (typeof limit === 'number' && limit < 0) throw new Error(`LIMIT must be a non-negative integer, got ${limit}`); }
1400
+ }
1401
+ // OFFSET without LIMIT (MySQL compatible)
1402
+ if (limit === null && this.isKeyword('OFFSET')) {
1403
+ this.next();
1404
+ offset = this.parseValue();
1405
+ if (typeof offset === 'bigint') offset = Number(offset <= BigInt(Number.MAX_SAFE_INTEGER) ? offset : BigInt(Number.MAX_SAFE_INTEGER));
1406
+ if (typeof offset === 'number' && offset < 0) throw new Error(`OFFSET must be a non-negative integer, got ${offset}`);
1407
+ limit = Number.MAX_SAFE_INTEGER;
1396
1408
  }
1397
1409
  // 集合运算:UNION [ALL|DISTINCT] / INTERSECT [ALL|DISTINCT] / EXCEPT [ALL|DISTINCT]
1398
1410
  let union = null, intersect = null, except = null;
@@ -1421,13 +1433,15 @@ class Parser {
1421
1433
  if (this.isWord('FIRST') || this.isWord('NEXT')) this.next();
1422
1434
  else throw new Error(`Expected FIRST or NEXT after FETCH, got '${this.peek().value}'`);
1423
1435
  const nTok = this.next();
1424
- const n = nTok.type === 'number' ? nTok.value : Number(nTok.value);
1436
+ let n = nTok.type === 'number' ? nTok.value : Number(nTok.value);
1437
+ if (typeof n === 'bigint') n = Number(n <= BigInt(Number.MAX_SAFE_INTEGER) ? n : BigInt(Number.MAX_SAFE_INTEGER));
1425
1438
  if (!Number.isFinite(n)) throw new Error(`Expected row count after FETCH FIRST, got '${nTok.value}'`);
1426
1439
  limit = n;
1427
1440
  if (this.isWord('ROW') || this.isWord('ROWS')) this.next();
1428
1441
  if (this.isWord('ONLY')) this.next();
1429
1442
  }
1430
1443
  this.optionalTailSemicolon();
1444
+ this.depth--;
1431
1445
 
1432
1446
  return { type: 'select', columns, aggregate, distinct, from, where, groupBy, having, orderBy, limit, offset, union, intersect, except, rollup };
1433
1447
  }
@@ -1534,6 +1548,7 @@ class Parser {
1534
1548
  }
1535
1549
  let where = null;
1536
1550
  if (this.isKeyword('WHERE')) { this.next(); where = this.parseExpr(); }
1551
+ else console.warn(`⚠️ UPDATE without WHERE clause — this will modify ALL rows in '${table}'`);
1537
1552
  const returning = this.parseOptionalReturning();
1538
1553
  this.optionalTailSemicolon();
1539
1554
  return { type: 'update', table, assignments, where, returning };
@@ -1562,6 +1577,7 @@ class Parser {
1562
1577
  if (this.isKeyword('LIMIT')) {
1563
1578
  this.next();
1564
1579
  limit = this.parseValue();
1580
+ if (typeof limit === 'bigint') limit = Number(limit <= BigInt(Number.MAX_SAFE_INTEGER) ? limit : BigInt(Number.MAX_SAFE_INTEGER));
1565
1581
  if (typeof limit === 'number' && limit < 0) throw new Error(`LIMIT must be a non-negative integer, got ${limit}`);
1566
1582
  }
1567
1583
  const returning = this.parseOptionalReturning();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsql-neo",
3
- "version": "6.4.0-beta.10",
3
+ "version": "6.4.0-beta.12",
4
4
  "description": "JSQL-NEO — Rust-powered embedded database with WASM, REST API, B-Tree indexes, WAL, crash recovery",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",