alasql 4.15.0 → 4.16.1

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/bin/alasql-cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  //
4
4
  // Command line interface for Alasql
5
- // Version: 0.2.3
5
+ // Version: 4.16.1
6
6
  // Date: 28.07.2015
7
7
  // (c) 2014-2022, Andrey Gershun & Mathias Wulff
8
8
  //
@@ -1,7 +1,7 @@
1
- //! AlaSQL v4.14.0 build: develop-3b8d5542 | © 2014-2025 Andrey Gershun & Mathias Wulff | License: MIT
1
+ //! AlaSQL v4.16.1 build: develop-ff717ec7 | © 2014-2025 Andrey Gershun & Mathias Wulff | License: MIT
2
2
  /*
3
3
  @module alasql
4
- @version 4.14.0
4
+ @version 4.16.1
5
5
 
6
6
  AlaSQL - JavaScript SQL database
7
7
  © 2014-2025 Andrey Gershun & Mathias Wulff
package/dist/alasql.fs.js CHANGED
@@ -1,7 +1,7 @@
1
- //! AlaSQL v4.14.0 build: develop-3b8d5542 | © 2014-2025 Andrey Gershun & Mathias Wulff | License: MIT
1
+ //! AlaSQL v4.16.1 build: develop-ff717ec7 | © 2014-2025 Andrey Gershun & Mathias Wulff | License: MIT
2
2
  /*
3
3
  @module alasql
4
- @version 4.14.0
4
+ @version 4.16.1
5
5
 
6
6
  AlaSQL - JavaScript SQL database
7
7
  © 2014-2025 Andrey Gershun & Mathias Wulff
@@ -141,8 +141,8 @@ SOFTWARE.
141
141
  Current version of alasql
142
142
  @constant {string}
143
143
  */
144
- alasql.version = '4.14.0';
145
- alasql.build = 'develop-3b8d5542';
144
+ alasql.version = '4.16.1';
145
+ alasql.build = 'develop-ff717ec7';
146
146
 
147
147
  /**
148
148
  Debug flag
@@ -4522,11 +4522,11 @@ var cloneDeep = (utils.cloneDeep = function cloneDeep(obj) {
4522
4522
  return +obj;
4523
4523
  }
4524
4524
 
4525
- var temp = new obj.constructor(); // changed
4525
+ var temp = new (Object.prototype.hasOwnProperty.call(obj, 'constructor') ? Object : obj.constructor)(); // changed
4526
4526
 
4527
4527
  for (var key in obj) {
4528
4528
  if (obj.hasOwnProperty(key)) {
4529
- temp[key] = cloneDeep(obj[key]);
4529
+ /* A "__proto__" key from parsed data is copied as data, never as the prototype */ if (key === '__proto__') { Object.defineProperty(temp, key, {value: cloneDeep(obj[key]), writable: true, enumerable: true, configurable: true}); } else { temp[key] = cloneDeep(obj[key]); }
4530
4530
  }
4531
4531
  }
4532
4532
  return temp;
@@ -4598,7 +4598,7 @@ var extend = (utils.extend = function extend(a, b) {
4598
4598
  a = a || {};
4599
4599
  for (var key in b) {
4600
4600
  if (b.hasOwnProperty(key)) {
4601
- a[key] = b[key];
4601
+ /* A "__proto__" key from parsed data is copied as data, never as the prototype */ if (key === '__proto__') { Object.defineProperty(a, key, {value: b[key], writable: true, enumerable: true, configurable: true}); } else { a[key] = b[key]; }
4602
4602
  }
4603
4603
  }
4604
4604
  return a;
@@ -8527,6 +8527,12 @@ yy.ExistsValue = class ExistsValue {
8527
8527
  alasql.precompile = function (statement, databaseid, params) {
8528
8528
  if (!statement) return;
8529
8529
  statement.params = params;
8530
+ // For CREATE VIEW statements, move queries to the select object
8531
+ // so they can be compiled later when the view is first used
8532
+ if (statement.view && statement.select && statement.queries) {
8533
+ statement.select.queries = statement.queries;
8534
+ return;
8535
+ }
8530
8536
  if (statement.queries) {
8531
8537
  statement.queriesfn = statement.queries.map(function (q) {
8532
8538
  var nq = q.compile(databaseid || statement.database.databaseid);
@@ -8615,7 +8621,12 @@ yy.Select.prototype.compileFrom = function (query) {
8615
8621
  };
8616
8622
  } else if (alasql.databases[source.databaseid].tables[source.tableid].view) {
8617
8623
  source.datafn = (query, params, cb, idx, alasql) => {
8618
- let res = alasql.databases[source.databaseid].tables[source.tableid].select(params);
8624
+ let table = alasql.databases[source.databaseid].tables[source.tableid];
8625
+ // Lazily compile the view's select on first use
8626
+ if (!table.select && table.viewSelect) {
8627
+ table.select = table.viewSelect.compile(table.viewDatabaseid);
8628
+ }
8629
+ let res = table.select(params);
8619
8630
  if (cb) res = cb(res, idx, query);
8620
8631
  return res;
8621
8632
  };
@@ -9331,7 +9342,7 @@ yy.Select.prototype.compileGroup = function (query) {
9331
9342
  aft2 = '';
9332
9343
 
9333
9344
  if (typeof query.groupStar !== 'undefined') {
9334
- aft2 += "for(var f in p['" + query.groupStar + "']) {g[f]=p['" + query.groupStar + "'][f];};";
9345
+ aft2 += "for(var f in p['" + query.groupStar + "']) {if(/^__proto__$/.test(f))Object.defineProperty(g,f,{writable:true,enumerable:true,configurable:true});g[f]=p['" + query.groupStar + "'][f];};";
9335
9346
  }
9336
9347
 
9337
9348
  s += query.selectGroup
@@ -9793,7 +9804,7 @@ function compileSelectStar(query, aliases, joinstar) {
9793
9804
  'var w=p["' + escapeq(alias) + '"];for(var k in w){r["' + escapeq(alias) + '_"+k]=w[k]};';
9794
9805
  } else {
9795
9806
  // Default overwrite mode
9796
- sp += 'var w=p["' + escapeq(alias) + '"];for(var k in w){r[k]=w[k]};';
9807
+ sp += 'var w=p["' + escapeq(alias) + '"];for(var k in w){if(/^__proto__$/.test(k))Object.defineProperty(r,k,{writable:true,enumerable:true,configurable:true});r[k]=w[k]};';
9797
9808
  }
9798
9809
 
9799
9810
  query.dirtyColumns = true;
@@ -10232,10 +10243,10 @@ yy.Select.prototype.compileSelectGroup1 = function (query) {
10232
10243
  self.columns.forEach(function (col) {
10233
10244
 
10234
10245
  if (col instanceof yy.Column && col.columnid === '*') {
10235
- // s += 'for(var k in g){r[k]=g[k]};';
10246
+ // s += 'for(var k in g){if(/^__proto__$/.test(k))Object.defineProperty(r,k,{writable:true,enumerable:true,configurable:true});r[k]=g[k]};';
10236
10247
  // s += 'for(var k in this.query.groupColumns){r[k]=g[this.query.groupColumns[k]]};';
10237
10248
 
10238
- s += 'for(var k in g) {r[k]=g[k]};';
10249
+ s += 'for(var k in g) {if(/^__proto__$/.test(k))Object.defineProperty(r,k,{writable:true,enumerable:true,configurable:true});r[k]=g[k]};';
10239
10250
  return '';
10240
10251
 
10241
10252
  } else {
@@ -11537,7 +11548,7 @@ yy.Over = class Over {
11537
11548
  const allValues = this.right.map(value => value.value);
11538
11549
  const allValuesStr = allValues.join(',');
11539
11550
  alasql.sets[allValuesStr] = alasql.sets[allValuesStr] || new Set(allValues);
11540
- s = `alasql.sets["${allValuesStr}"].has(alasql.utils.getValueOf(${leftJS()}))`;
11551
+ s = `alasql.sets[${JSON.stringify(allValuesStr)}].has(alasql.utils.getValueOf(${leftJS()}))`;
11541
11552
  }
11542
11553
  } else {
11543
11554
  s = `(${rightJS()}.indexOf(${leftJS()}) > -1)`;
@@ -11571,7 +11582,7 @@ yy.Over = class Over {
11571
11582
  const allValues = this.right.map(value => value.value);
11572
11583
  const allValuesStr = allValues.join(',');
11573
11584
  alasql.sets[allValuesStr] = alasql.sets[allValuesStr] || new Set(allValues);
11574
- s = `!alasql.sets["${allValuesStr}"].has(alasql.utils.getValueOf(${leftJS()}))`;
11585
+ s = `!alasql.sets[${JSON.stringify(allValuesStr)}].has(alasql.utils.getValueOf(${leftJS()}))`;
11575
11586
  }
11576
11587
  } else {
11577
11588
  s = `(${rightJS()}.indexOf(${leftJS()}) === -1)`;
@@ -11976,17 +11987,23 @@ yy.Over = class Over {
11976
11987
  }
11977
11988
 
11978
11989
  findAggregator(query) {
11979
- const colas = escapeq(this.toString()) + ':' + query.selectGroup.length;
11980
-
11981
- if (!this.nick) {
11982
- this.nick = colas;
11990
+ // Check if an identical aggregate already exists in selectGroup
11991
+ let existingAggr = query.selectGroup.find(agg => agg.toString() === this.toString());
11983
11992
 
11984
- if (!query.removeKeys.includes(colas)) {
11985
- query.removeKeys.push(colas);
11993
+ if (existingAggr) {
11994
+ // Reuse the existing aggregate's nick to share the same accumulator
11995
+ this.aggrNick = existingAggr.nick;
11996
+ } else {
11997
+ // New aggregate - assign nick and add to selectGroup
11998
+ if (!this.nick) {
11999
+ this.nick = escapeq(this.toString()) + ':' + query.selectGroup.length;
12000
+ if (!query.removeKeys.includes(this.nick)) {
12001
+ query.removeKeys.push(this.nick);
12002
+ }
11986
12003
  }
12004
+ this.aggrNick = this.nick;
12005
+ query.selectGroup.push(this);
11987
12006
  }
11988
-
11989
- query.selectGroup.push(this);
11990
12007
  }
11991
12008
 
11992
12009
  toType() {
@@ -12006,7 +12023,8 @@ yy.Over = class Over {
12006
12023
  }
12007
12024
 
12008
12025
  toJS() {
12009
- var colas = this.nick;
12026
+ // Use aggrNick for duplicate aggregates to share the same accumulator, otherwise use the unique nick
12027
+ var colas = this.aggrNick || this.nick;
12010
12028
  if (colas === undefined) {
12011
12029
  colas = escapeq(this.toString());
12012
12030
  }
@@ -12506,8 +12524,20 @@ stdfn.CONCAT_WS = function () {
12506
12524
  // Aggregator for joining strings
12507
12525
  alasql.aggr.group_concat = alasql.aggr.GROUP_CONCAT = function (v, s, stage) {
12508
12526
  if (stage === 1) {
12527
+ // Initialize: skip null values
12528
+ if (v === null || v === undefined) {
12529
+ return null;
12530
+ }
12509
12531
  return '' + v;
12510
12532
  } else if (stage === 2) {
12533
+ // Accumulate: skip null values
12534
+ if (v === null || v === undefined) {
12535
+ return s;
12536
+ }
12537
+ // If accumulator is null/undefined, start with current value
12538
+ if (s === null || s === undefined) {
12539
+ return '' + v;
12540
+ }
12511
12541
  s += ',' + v;
12512
12542
  return s;
12513
12543
  }
@@ -13400,7 +13430,9 @@ yy.CreateTable.prototype.execute = function (databaseid, params, cb) {
13400
13430
  //Used in 420from queryfn when table.view = true!
13401
13431
  if (this.view && this.select) {
13402
13432
  table.view = true;
13403
- table.select = this.select.compile(this.table.databaseid || databaseid);
13433
+ // Store the uncompiled select statement and databaseid for lazy compilation
13434
+ table.viewSelect = this.select;
13435
+ table.viewDatabaseid = this.table.databaseid || databaseid;
13404
13436
  }
13405
13437
 
13406
13438
  if (db.engineid) {
@@ -13521,7 +13553,7 @@ yy.CreateTable.prototype.execute = function (databaseid, params, cb) {
13521
13553
 
13522
13554
  table.update(
13523
13555
  function (t) {
13524
- for (var f in r) t[f] = r[f];
13556
+ for (var f in r) {if(/^__proto__$/.test(f))Object.defineProperty(t,f,{writable:true,enumerable:true,configurable:true});t[f] = r[f];}
13525
13557
  },
13526
13558
  table.data.indexOf(toreplace),
13527
13559
  params
@@ -15188,6 +15220,14 @@ yy.Insert.prototype.compile = function (databaseid) {
15188
15220
  throw "Table '" + tableid + "' could not be found";
15189
15221
  }
15190
15222
 
15223
+ // Helper function to create error message for value/column count mismatch
15224
+ var createValueCountMismatchError = function (valueCount, columnCount, columnType) {
15225
+ return (
15226
+ `The number of values (${valueCount}) does not match the number of ${columnType} (${columnCount}). ` +
15227
+ 'If using a subquery, use INSERT INTO ... SELECT instead of INSERT INTO ... VALUES (SELECT ...)'
15228
+ );
15229
+ };
15230
+
15191
15231
  // Check, if this dirty flag is required
15192
15232
  var s = '';
15193
15233
  var sw = '';
@@ -15221,6 +15261,12 @@ yy.Insert.prototype.compile = function (databaseid) {
15221
15261
 
15222
15262
  // s += '';
15223
15263
  if (self.columns) {
15264
+ // Validate that we have the right number of values for the columns
15265
+ if (values.length !== self.columns.length) {
15266
+ throw new Error(
15267
+ createValueCountMismatchError(values.length, self.columns.length, 'columns')
15268
+ );
15269
+ }
15224
15270
  self.columns.forEach(function (col, idx) {
15225
15271
 
15226
15272
  // ss.push(col.columnid +':'+ self.values[idx].value.toString());
@@ -15253,6 +15299,12 @@ yy.Insert.prototype.compile = function (databaseid) {
15253
15299
  // var table = db.tables[tableid];
15254
15300
 
15255
15301
  if (Array.isArray(values) && table.columns && table.columns.length > 0) {
15302
+ // Validate that we have the right number of values for the table columns
15303
+ if (values.length !== table.columns.length) {
15304
+ throw new Error(
15305
+ createValueCountMismatchError(values.length, table.columns.length, 'table columns')
15306
+ );
15307
+ }
15256
15308
  table.columns.forEach(function (col, idx) {
15257
15309
  var q = "'" + col.columnid + "':";
15258
15310
  // var val = values[idx].toJS();
@@ -15272,7 +15324,7 @@ yy.Insert.prototype.compile = function (databaseid) {
15272
15324
  });
15273
15325
  } else {
15274
15326
 
15275
- // sw = 'var w='+JSONtoJS(values)+';for(var k in w){r[k]=w[k]};';
15327
+ // sw = 'var w='+JSONtoJS(values)+';for(var k in w){if(/^__proto__$/.test(k))Object.defineProperty(r,k,{writable:true,enumerable:true,configurable:true});r[k]=w[k]};';
15276
15328
  sw = JSONtoJS(values);
15277
15329
  }
15278
15330
  }
@@ -15351,7 +15403,7 @@ yy.Insert.prototype.compile = function (databaseid) {
15351
15403
  self.output.columns.forEach(function (col) {
15352
15404
  if (col.columnid === '*') {
15353
15405
  // For *, expand all properties
15354
- s += 'for(var key in r){ outputRow[key] = r[key]; }';
15406
+ s += 'for(var key in r){ if(/^__proto__$/.test(key))Object.defineProperty(outputRow,key,{writable:true,enumerable:true,configurable:true});outputRow[key] = r[key]; }';
15355
15407
  } else {
15356
15408
  var colname = col.as || col.columnid;
15357
15409
  // Direct property access for simple columns
@@ -15430,7 +15482,7 @@ yy.Insert.prototype.compile = function (databaseid) {
15430
15482
  if (col.columnid === '*') {
15431
15483
  // For *, expand all properties
15432
15484
  for (var key in r) {
15433
- outputRow[key] = r[key];
15485
+ if(/^__proto__$/.test(key))Object.defineProperty(outputRow,key,{writable:true,enumerable:true,configurable:true});outputRow[key] = r[key];
15434
15486
  }
15435
15487
  } else {
15436
15488
  var colname = col.as || col.columnid;
@@ -15781,7 +15833,7 @@ yy.Delete.prototype.compile = function (databaseid) {
15781
15833
  if (col.columnid === '*') {
15782
15834
  // For *, expand all properties
15783
15835
  for (var key in r) {
15784
- outputRow[key] = r[key];
15836
+ if(/^__proto__$/.test(key))Object.defineProperty(outputRow,key,{writable:true,enumerable:true,configurable:true});outputRow[key] = r[key];
15785
15837
  }
15786
15838
  } else {
15787
15839
  var colname = col.as || col.columnid;
@@ -15852,7 +15904,7 @@ yy.Delete.prototype.compile = function (databaseid) {
15852
15904
  if (col.columnid === '*') {
15853
15905
  // For *, expand all properties
15854
15906
  for (var key in r) {
15855
- outputRow[key] = r[key];
15907
+ if(/^__proto__$/.test(key))Object.defineProperty(outputRow,key,{writable:true,enumerable:true,configurable:true});outputRow[key] = r[key];
15856
15908
  }
15857
15909
  } else {
15858
15910
  var colname = col.as || col.columnid;
@@ -16022,7 +16074,7 @@ yy.Update.prototype.compile = function (databaseid) {
16022
16074
  if (col.columnid === '*') {
16023
16075
  // For *, use INSERTED values
16024
16076
  for (var key in inserted) {
16025
- outputRow[key] = inserted[key];
16077
+ if(/^__proto__$/.test(key))Object.defineProperty(outputRow,key,{writable:true,enumerable:true,configurable:true});outputRow[key] = inserted[key];
16026
16078
  }
16027
16079
  } else {
16028
16080
  var colname = col.as || col.columnid;
@@ -19587,6 +19639,35 @@ IDB.updateTable = function (databaseid, tableid, assignfn, wherefn, params, cb)
19587
19639
  };
19588
19640
  };
19589
19641
  };
19642
+
19643
+ /**
19644
+ * Commit transaction for IndexedDB
19645
+ * Note: IndexedDB operations are auto-committed per operation
19646
+ * This method provides API compatibility
19647
+ */
19648
+ IDB.commit = function (databaseid, cb) {
19649
+ // IndexedDB auto-commits each operation's transaction
19650
+ // No additional action needed
19651
+ return cb ? cb(1) : 1;
19652
+ };
19653
+
19654
+ /**
19655
+ * Begin transaction - alias to commit for IndexedDB
19656
+ * Similar to LOCALSTORAGE pattern
19657
+ */
19658
+ IDB.begin = IDB.commit;
19659
+
19660
+ /**
19661
+ * Rollback transaction for IndexedDB
19662
+ * Note: IndexedDB operations are auto-committed per operation
19663
+ * Manual rollback not supported - operations cannot be undone
19664
+ */
19665
+ IDB.rollback = function (databaseid, cb) {
19666
+ // IndexedDB auto-commits each operation
19667
+ // Cannot rollback already-committed operations
19668
+ // This provides API compatibility only
19669
+ return cb ? cb(1) : 1;
19670
+ };
19590
19671
  //
19591
19672
  // 91localstorage.js
19592
19673
  // localStorage and DOM-Storage engine
package/dist/alasql.js CHANGED
@@ -1,7 +1,7 @@
1
- //! AlaSQL v4.14.0 build: develop-3b8d5542 | © 2014-2025 Andrey Gershun & Mathias Wulff | License: MIT
1
+ //! AlaSQL v4.16.1 build: develop-ff717ec7 | © 2014-2025 Andrey Gershun & Mathias Wulff | License: MIT
2
2
  /*
3
3
  @module alasql
4
- @version 4.14.0
4
+ @version 4.16.1
5
5
 
6
6
  AlaSQL - JavaScript SQL database
7
7
  © 2014-2025 Andrey Gershun & Mathias Wulff
@@ -141,8 +141,8 @@ SOFTWARE.
141
141
  Current version of alasql
142
142
  @constant {string}
143
143
  */
144
- alasql.version = '4.14.0';
145
- alasql.build = 'develop-3b8d5542';
144
+ alasql.version = '4.16.1';
145
+ alasql.build = 'develop-ff717ec7';
146
146
 
147
147
  /**
148
148
  Debug flag
@@ -4522,11 +4522,11 @@ var cloneDeep = (utils.cloneDeep = function cloneDeep(obj) {
4522
4522
  return +obj;
4523
4523
  }
4524
4524
 
4525
- var temp = new obj.constructor(); // changed
4525
+ var temp = new (Object.prototype.hasOwnProperty.call(obj, 'constructor') ? Object : obj.constructor)(); // changed
4526
4526
 
4527
4527
  for (var key in obj) {
4528
4528
  if (obj.hasOwnProperty(key)) {
4529
- temp[key] = cloneDeep(obj[key]);
4529
+ /* A "__proto__" key from parsed data is copied as data, never as the prototype */ if (key === '__proto__') { Object.defineProperty(temp, key, {value: cloneDeep(obj[key]), writable: true, enumerable: true, configurable: true}); } else { temp[key] = cloneDeep(obj[key]); }
4530
4530
  }
4531
4531
  }
4532
4532
  return temp;
@@ -4598,7 +4598,7 @@ var extend = (utils.extend = function extend(a, b) {
4598
4598
  a = a || {};
4599
4599
  for (var key in b) {
4600
4600
  if (b.hasOwnProperty(key)) {
4601
- a[key] = b[key];
4601
+ /* A "__proto__" key from parsed data is copied as data, never as the prototype */ if (key === '__proto__') { Object.defineProperty(a, key, {value: b[key], writable: true, enumerable: true, configurable: true}); } else { a[key] = b[key]; }
4602
4602
  }
4603
4603
  }
4604
4604
  return a;
@@ -8527,6 +8527,12 @@ yy.ExistsValue = class ExistsValue {
8527
8527
  alasql.precompile = function (statement, databaseid, params) {
8528
8528
  if (!statement) return;
8529
8529
  statement.params = params;
8530
+ // For CREATE VIEW statements, move queries to the select object
8531
+ // so they can be compiled later when the view is first used
8532
+ if (statement.view && statement.select && statement.queries) {
8533
+ statement.select.queries = statement.queries;
8534
+ return;
8535
+ }
8530
8536
  if (statement.queries) {
8531
8537
  statement.queriesfn = statement.queries.map(function (q) {
8532
8538
  var nq = q.compile(databaseid || statement.database.databaseid);
@@ -8615,7 +8621,12 @@ yy.Select.prototype.compileFrom = function (query) {
8615
8621
  };
8616
8622
  } else if (alasql.databases[source.databaseid].tables[source.tableid].view) {
8617
8623
  source.datafn = (query, params, cb, idx, alasql) => {
8618
- let res = alasql.databases[source.databaseid].tables[source.tableid].select(params);
8624
+ let table = alasql.databases[source.databaseid].tables[source.tableid];
8625
+ // Lazily compile the view's select on first use
8626
+ if (!table.select && table.viewSelect) {
8627
+ table.select = table.viewSelect.compile(table.viewDatabaseid);
8628
+ }
8629
+ let res = table.select(params);
8619
8630
  if (cb) res = cb(res, idx, query);
8620
8631
  return res;
8621
8632
  };
@@ -9331,7 +9342,7 @@ yy.Select.prototype.compileGroup = function (query) {
9331
9342
  aft2 = '';
9332
9343
 
9333
9344
  if (typeof query.groupStar !== 'undefined') {
9334
- aft2 += "for(var f in p['" + query.groupStar + "']) {g[f]=p['" + query.groupStar + "'][f];};";
9345
+ aft2 += "for(var f in p['" + query.groupStar + "']) {if(/^__proto__$/.test(f))Object.defineProperty(g,f,{writable:true,enumerable:true,configurable:true});g[f]=p['" + query.groupStar + "'][f];};";
9335
9346
  }
9336
9347
 
9337
9348
  s += query.selectGroup
@@ -9793,7 +9804,7 @@ function compileSelectStar(query, aliases, joinstar) {
9793
9804
  'var w=p["' + escapeq(alias) + '"];for(var k in w){r["' + escapeq(alias) + '_"+k]=w[k]};';
9794
9805
  } else {
9795
9806
  // Default overwrite mode
9796
- sp += 'var w=p["' + escapeq(alias) + '"];for(var k in w){r[k]=w[k]};';
9807
+ sp += 'var w=p["' + escapeq(alias) + '"];for(var k in w){if(/^__proto__$/.test(k))Object.defineProperty(r,k,{writable:true,enumerable:true,configurable:true});r[k]=w[k]};';
9797
9808
  }
9798
9809
 
9799
9810
  query.dirtyColumns = true;
@@ -10232,10 +10243,10 @@ yy.Select.prototype.compileSelectGroup1 = function (query) {
10232
10243
  self.columns.forEach(function (col) {
10233
10244
 
10234
10245
  if (col instanceof yy.Column && col.columnid === '*') {
10235
- // s += 'for(var k in g){r[k]=g[k]};';
10246
+ // s += 'for(var k in g){if(/^__proto__$/.test(k))Object.defineProperty(r,k,{writable:true,enumerable:true,configurable:true});r[k]=g[k]};';
10236
10247
  // s += 'for(var k in this.query.groupColumns){r[k]=g[this.query.groupColumns[k]]};';
10237
10248
 
10238
- s += 'for(var k in g) {r[k]=g[k]};';
10249
+ s += 'for(var k in g) {if(/^__proto__$/.test(k))Object.defineProperty(r,k,{writable:true,enumerable:true,configurable:true});r[k]=g[k]};';
10239
10250
  return '';
10240
10251
 
10241
10252
  } else {
@@ -11537,7 +11548,7 @@ yy.Over = class Over {
11537
11548
  const allValues = this.right.map(value => value.value);
11538
11549
  const allValuesStr = allValues.join(',');
11539
11550
  alasql.sets[allValuesStr] = alasql.sets[allValuesStr] || new Set(allValues);
11540
- s = `alasql.sets["${allValuesStr}"].has(alasql.utils.getValueOf(${leftJS()}))`;
11551
+ s = `alasql.sets[${JSON.stringify(allValuesStr)}].has(alasql.utils.getValueOf(${leftJS()}))`;
11541
11552
  }
11542
11553
  } else {
11543
11554
  s = `(${rightJS()}.indexOf(${leftJS()}) > -1)`;
@@ -11571,7 +11582,7 @@ yy.Over = class Over {
11571
11582
  const allValues = this.right.map(value => value.value);
11572
11583
  const allValuesStr = allValues.join(',');
11573
11584
  alasql.sets[allValuesStr] = alasql.sets[allValuesStr] || new Set(allValues);
11574
- s = `!alasql.sets["${allValuesStr}"].has(alasql.utils.getValueOf(${leftJS()}))`;
11585
+ s = `!alasql.sets[${JSON.stringify(allValuesStr)}].has(alasql.utils.getValueOf(${leftJS()}))`;
11575
11586
  }
11576
11587
  } else {
11577
11588
  s = `(${rightJS()}.indexOf(${leftJS()}) === -1)`;
@@ -11976,17 +11987,23 @@ yy.Over = class Over {
11976
11987
  }
11977
11988
 
11978
11989
  findAggregator(query) {
11979
- const colas = escapeq(this.toString()) + ':' + query.selectGroup.length;
11980
-
11981
- if (!this.nick) {
11982
- this.nick = colas;
11990
+ // Check if an identical aggregate already exists in selectGroup
11991
+ let existingAggr = query.selectGroup.find(agg => agg.toString() === this.toString());
11983
11992
 
11984
- if (!query.removeKeys.includes(colas)) {
11985
- query.removeKeys.push(colas);
11993
+ if (existingAggr) {
11994
+ // Reuse the existing aggregate's nick to share the same accumulator
11995
+ this.aggrNick = existingAggr.nick;
11996
+ } else {
11997
+ // New aggregate - assign nick and add to selectGroup
11998
+ if (!this.nick) {
11999
+ this.nick = escapeq(this.toString()) + ':' + query.selectGroup.length;
12000
+ if (!query.removeKeys.includes(this.nick)) {
12001
+ query.removeKeys.push(this.nick);
12002
+ }
11986
12003
  }
12004
+ this.aggrNick = this.nick;
12005
+ query.selectGroup.push(this);
11987
12006
  }
11988
-
11989
- query.selectGroup.push(this);
11990
12007
  }
11991
12008
 
11992
12009
  toType() {
@@ -12006,7 +12023,8 @@ yy.Over = class Over {
12006
12023
  }
12007
12024
 
12008
12025
  toJS() {
12009
- var colas = this.nick;
12026
+ // Use aggrNick for duplicate aggregates to share the same accumulator, otherwise use the unique nick
12027
+ var colas = this.aggrNick || this.nick;
12010
12028
  if (colas === undefined) {
12011
12029
  colas = escapeq(this.toString());
12012
12030
  }
@@ -12506,8 +12524,20 @@ stdfn.CONCAT_WS = function () {
12506
12524
  // Aggregator for joining strings
12507
12525
  alasql.aggr.group_concat = alasql.aggr.GROUP_CONCAT = function (v, s, stage) {
12508
12526
  if (stage === 1) {
12527
+ // Initialize: skip null values
12528
+ if (v === null || v === undefined) {
12529
+ return null;
12530
+ }
12509
12531
  return '' + v;
12510
12532
  } else if (stage === 2) {
12533
+ // Accumulate: skip null values
12534
+ if (v === null || v === undefined) {
12535
+ return s;
12536
+ }
12537
+ // If accumulator is null/undefined, start with current value
12538
+ if (s === null || s === undefined) {
12539
+ return '' + v;
12540
+ }
12511
12541
  s += ',' + v;
12512
12542
  return s;
12513
12543
  }
@@ -13400,7 +13430,9 @@ yy.CreateTable.prototype.execute = function (databaseid, params, cb) {
13400
13430
  //Used in 420from queryfn when table.view = true!
13401
13431
  if (this.view && this.select) {
13402
13432
  table.view = true;
13403
- table.select = this.select.compile(this.table.databaseid || databaseid);
13433
+ // Store the uncompiled select statement and databaseid for lazy compilation
13434
+ table.viewSelect = this.select;
13435
+ table.viewDatabaseid = this.table.databaseid || databaseid;
13404
13436
  }
13405
13437
 
13406
13438
  if (db.engineid) {
@@ -13521,7 +13553,7 @@ yy.CreateTable.prototype.execute = function (databaseid, params, cb) {
13521
13553
 
13522
13554
  table.update(
13523
13555
  function (t) {
13524
- for (var f in r) t[f] = r[f];
13556
+ for (var f in r) {if(/^__proto__$/.test(f))Object.defineProperty(t,f,{writable:true,enumerable:true,configurable:true});t[f] = r[f];}
13525
13557
  },
13526
13558
  table.data.indexOf(toreplace),
13527
13559
  params
@@ -15188,6 +15220,14 @@ yy.Insert.prototype.compile = function (databaseid) {
15188
15220
  throw "Table '" + tableid + "' could not be found";
15189
15221
  }
15190
15222
 
15223
+ // Helper function to create error message for value/column count mismatch
15224
+ var createValueCountMismatchError = function (valueCount, columnCount, columnType) {
15225
+ return (
15226
+ `The number of values (${valueCount}) does not match the number of ${columnType} (${columnCount}). ` +
15227
+ 'If using a subquery, use INSERT INTO ... SELECT instead of INSERT INTO ... VALUES (SELECT ...)'
15228
+ );
15229
+ };
15230
+
15191
15231
  // Check, if this dirty flag is required
15192
15232
  var s = '';
15193
15233
  var sw = '';
@@ -15221,6 +15261,12 @@ yy.Insert.prototype.compile = function (databaseid) {
15221
15261
 
15222
15262
  // s += '';
15223
15263
  if (self.columns) {
15264
+ // Validate that we have the right number of values for the columns
15265
+ if (values.length !== self.columns.length) {
15266
+ throw new Error(
15267
+ createValueCountMismatchError(values.length, self.columns.length, 'columns')
15268
+ );
15269
+ }
15224
15270
  self.columns.forEach(function (col, idx) {
15225
15271
 
15226
15272
  // ss.push(col.columnid +':'+ self.values[idx].value.toString());
@@ -15253,6 +15299,12 @@ yy.Insert.prototype.compile = function (databaseid) {
15253
15299
  // var table = db.tables[tableid];
15254
15300
 
15255
15301
  if (Array.isArray(values) && table.columns && table.columns.length > 0) {
15302
+ // Validate that we have the right number of values for the table columns
15303
+ if (values.length !== table.columns.length) {
15304
+ throw new Error(
15305
+ createValueCountMismatchError(values.length, table.columns.length, 'table columns')
15306
+ );
15307
+ }
15256
15308
  table.columns.forEach(function (col, idx) {
15257
15309
  var q = "'" + col.columnid + "':";
15258
15310
  // var val = values[idx].toJS();
@@ -15272,7 +15324,7 @@ yy.Insert.prototype.compile = function (databaseid) {
15272
15324
  });
15273
15325
  } else {
15274
15326
 
15275
- // sw = 'var w='+JSONtoJS(values)+';for(var k in w){r[k]=w[k]};';
15327
+ // sw = 'var w='+JSONtoJS(values)+';for(var k in w){if(/^__proto__$/.test(k))Object.defineProperty(r,k,{writable:true,enumerable:true,configurable:true});r[k]=w[k]};';
15276
15328
  sw = JSONtoJS(values);
15277
15329
  }
15278
15330
  }
@@ -15351,7 +15403,7 @@ yy.Insert.prototype.compile = function (databaseid) {
15351
15403
  self.output.columns.forEach(function (col) {
15352
15404
  if (col.columnid === '*') {
15353
15405
  // For *, expand all properties
15354
- s += 'for(var key in r){ outputRow[key] = r[key]; }';
15406
+ s += 'for(var key in r){ if(/^__proto__$/.test(key))Object.defineProperty(outputRow,key,{writable:true,enumerable:true,configurable:true});outputRow[key] = r[key]; }';
15355
15407
  } else {
15356
15408
  var colname = col.as || col.columnid;
15357
15409
  // Direct property access for simple columns
@@ -15430,7 +15482,7 @@ yy.Insert.prototype.compile = function (databaseid) {
15430
15482
  if (col.columnid === '*') {
15431
15483
  // For *, expand all properties
15432
15484
  for (var key in r) {
15433
- outputRow[key] = r[key];
15485
+ if(/^__proto__$/.test(key))Object.defineProperty(outputRow,key,{writable:true,enumerable:true,configurable:true});outputRow[key] = r[key];
15434
15486
  }
15435
15487
  } else {
15436
15488
  var colname = col.as || col.columnid;
@@ -15781,7 +15833,7 @@ yy.Delete.prototype.compile = function (databaseid) {
15781
15833
  if (col.columnid === '*') {
15782
15834
  // For *, expand all properties
15783
15835
  for (var key in r) {
15784
- outputRow[key] = r[key];
15836
+ if(/^__proto__$/.test(key))Object.defineProperty(outputRow,key,{writable:true,enumerable:true,configurable:true});outputRow[key] = r[key];
15785
15837
  }
15786
15838
  } else {
15787
15839
  var colname = col.as || col.columnid;
@@ -15852,7 +15904,7 @@ yy.Delete.prototype.compile = function (databaseid) {
15852
15904
  if (col.columnid === '*') {
15853
15905
  // For *, expand all properties
15854
15906
  for (var key in r) {
15855
- outputRow[key] = r[key];
15907
+ if(/^__proto__$/.test(key))Object.defineProperty(outputRow,key,{writable:true,enumerable:true,configurable:true});outputRow[key] = r[key];
15856
15908
  }
15857
15909
  } else {
15858
15910
  var colname = col.as || col.columnid;
@@ -16022,7 +16074,7 @@ yy.Update.prototype.compile = function (databaseid) {
16022
16074
  if (col.columnid === '*') {
16023
16075
  // For *, use INSERTED values
16024
16076
  for (var key in inserted) {
16025
- outputRow[key] = inserted[key];
16077
+ if(/^__proto__$/.test(key))Object.defineProperty(outputRow,key,{writable:true,enumerable:true,configurable:true});outputRow[key] = inserted[key];
16026
16078
  }
16027
16079
  } else {
16028
16080
  var colname = col.as || col.columnid;
@@ -19587,6 +19639,35 @@ IDB.updateTable = function (databaseid, tableid, assignfn, wherefn, params, cb)
19587
19639
  };
19588
19640
  };
19589
19641
  };
19642
+
19643
+ /**
19644
+ * Commit transaction for IndexedDB
19645
+ * Note: IndexedDB operations are auto-committed per operation
19646
+ * This method provides API compatibility
19647
+ */
19648
+ IDB.commit = function (databaseid, cb) {
19649
+ // IndexedDB auto-commits each operation's transaction
19650
+ // No additional action needed
19651
+ return cb ? cb(1) : 1;
19652
+ };
19653
+
19654
+ /**
19655
+ * Begin transaction - alias to commit for IndexedDB
19656
+ * Similar to LOCALSTORAGE pattern
19657
+ */
19658
+ IDB.begin = IDB.commit;
19659
+
19660
+ /**
19661
+ * Rollback transaction for IndexedDB
19662
+ * Note: IndexedDB operations are auto-committed per operation
19663
+ * Manual rollback not supported - operations cannot be undone
19664
+ */
19665
+ IDB.rollback = function (databaseid, cb) {
19666
+ // IndexedDB auto-commits each operation
19667
+ // Cannot rollback already-committed operations
19668
+ // This provides API compatibility only
19669
+ return cb ? cb(1) : 1;
19670
+ };
19590
19671
  //
19591
19672
  // 91localstorage.js
19592
19673
  // localStorage and DOM-Storage engine