From 7f438a5e6e0c8b7eaee6c8068c8ee6fe7d350732 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Aug 2026 11:31:32 +0000 Subject: [PATCH 1/6] Initial plan From b42f314ff573003c40f40463e1ae08709e3dfec4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Aug 2026 11:35:32 +0000 Subject: [PATCH 2/6] Fix grouped ORDER BY by source column Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/424select.js | 19 ++++++++++++++++++- test/test2515.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 test/test2515.js diff --git a/src/424select.js b/src/424select.js index b7d7e4b999..cfb9b749d5 100755 --- a/src/424select.js +++ b/src/424select.js @@ -734,7 +734,24 @@ yy.Select.prototype.compileSelectGroup2 = function (query) { // Use Object.keys to get column names and access by index s += "var keys=Object.keys(r);r['" + key + "']=r[keys[" + v.columnIndex + ']];'; } else if (v instanceof yy.Column && query.groupColumns[v.columnid]) { - s += "r['" + key + "']=r['" + v.columnid + "'];"; + var groupColumn = groupColMap[(v.tableid || '') + '\t' + v.columnid]; + if (groupColumn) { + s += + "r['" + + key + + "']=('" + + v.columnid + + "' in r)?r['" + + v.columnid + + "']:g['" + + groupColumn.nick + + "'];"; + } else { + s += "r['" + key + "']=r['" + v.columnid + "'];"; + } + } else if (v instanceof yy.Column && groupColMap[(v.tableid || '') + '\t' + v.columnid]) { + s += + "r['" + key + "']=g['" + groupColMap[(v.tableid || '') + '\t' + v.columnid].nick + "'];"; } else { s += "r['" + key + "']=" + v.toJS('g', '') + ';'; } diff --git a/test/test2515.js b/test/test2515.js new file mode 100644 index 0000000000..44fb4057dc --- /dev/null +++ b/test/test2515.js @@ -0,0 +1,44 @@ +if (typeof exports === 'object') { + var assert = require('assert'); + var alasql = require('..'); +} + +describe('Test 2515 - ORDER BY original grouped column with selected alias', function () { + it('A) Orders ascending by original grouped column name', function () { + var data = [ + {num: 100, letter: 'one'}, + {num: 50, letter: 'two'}, + {num: 10, letter: 'two'}, + ]; + + var res = alasql( + 'SELECT num AS position, letter AS note FROM ? GROUP BY num, letter ORDER BY num', + [data] + ); + + assert.deepStrictEqual(res, [ + {position: 10, note: 'two'}, + {position: 50, note: 'two'}, + {position: 100, note: 'one'}, + ]); + }); + + it('B) Orders descending by original grouped column name', function () { + var data = [ + {num: 100, letter: 'one'}, + {num: 50, letter: 'two'}, + {num: 10, letter: 'two'}, + ]; + + var res = alasql( + 'SELECT num AS position, letter AS note FROM ? GROUP BY num, letter ORDER BY num DESC', + [data] + ); + + assert.deepStrictEqual(res, [ + {position: 100, note: 'one'}, + {position: 50, note: 'two'}, + {position: 10, note: 'two'}, + ]); + }); +}); From fdb4b4038749acce8545f843f2378dc38ee632a1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Aug 2026 08:56:10 +0000 Subject: [PATCH 3/6] Simplify grouped ORDER BY alias resolution Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/424select.js | 41 ++++++++++++++++++++++------------------- test/test2515.js | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/424select.js b/src/424select.js index cfb9b749d5..11cfdc857f 100755 --- a/src/424select.js +++ b/src/424select.js @@ -687,12 +687,27 @@ yy.Select.prototype.compileSelectGroup2 = function (query) { // Create a lookup map for GROUP BY columns to optimize performance var groupColMap = {}; + var groupProjectedColumnMap = {}; + var projectedSelectColumnMap = {}; if (self.group) { self.group.forEach(function (gp) { var key = (gp.tableid || '') + '\t' + gp.columnid; groupColMap[key] = gp; }); + self.columns.forEach(function (col) { + if (col instanceof yy.Column) { + var key = (col.tableid || '') + '\t' + col.columnid; + if (groupColMap[key] && (!groupProjectedColumnMap[key] || !col.as)) { + groupProjectedColumnMap[key] = col.as || col.columnid; + } + } + }); } + self.columns.forEach(function (col) { + if (!(col instanceof yy.Column && col.columnid === '*')) { + projectedSelectColumnMap[col.as || col.nick] = true; + } + }); self.columns.forEach(function (col) { // console.log(col); @@ -728,30 +743,18 @@ yy.Select.prototype.compileSelectGroup2 = function (query) { this.orderColumns.forEach(function (v, idx) { // console.log(411,v); var key = '$$$' + idx; + var groupKey = (v.tableid || '') + '\t' + v.columnid; // console.log(427,v,query.groupColumns,query.xgroupColumns); // Handle positional column reference (for SELECT * with ORDER BY numeric) if (v._useColumnIndex !== undefined) { // Use Object.keys to get column names and access by index s += "var keys=Object.keys(r);r['" + key + "']=r[keys[" + v.columnIndex + ']];'; - } else if (v instanceof yy.Column && query.groupColumns[v.columnid]) { - var groupColumn = groupColMap[(v.tableid || '') + '\t' + v.columnid]; - if (groupColumn) { - s += - "r['" + - key + - "']=('" + - v.columnid + - "' in r)?r['" + - v.columnid + - "']:g['" + - groupColumn.nick + - "'];"; - } else { - s += "r['" + key + "']=r['" + v.columnid + "'];"; - } - } else if (v instanceof yy.Column && groupColMap[(v.tableid || '') + '\t' + v.columnid]) { - s += - "r['" + key + "']=g['" + groupColMap[(v.tableid || '') + '\t' + v.columnid].nick + "'];"; + } else if (v instanceof yy.Column && groupProjectedColumnMap[groupKey]) { + s += "r['" + key + "']=r['" + groupProjectedColumnMap[groupKey] + "'];"; + } else if (v instanceof yy.Column && projectedSelectColumnMap[v.columnid]) { + s += "r['" + key + "']=r['" + v.columnid + "'];"; + } else if (v instanceof yy.Column && groupColMap[groupKey]) { + s += "r['" + key + "']=g['" + groupColMap[groupKey].nick + "'];"; } else { s += "r['" + key + "']=" + v.toJS('g', '') + ';'; } diff --git a/test/test2515.js b/test/test2515.js index 44fb4057dc..ff605263d2 100644 --- a/test/test2515.js +++ b/test/test2515.js @@ -23,7 +23,26 @@ describe('Test 2515 - ORDER BY original grouped column with selected alias', fun ]); }); - it('B) Orders descending by original grouped column name', function () { + it('B) Orders ascending by original grouped column name with explicit ASC', function () { + var data = [ + {num: 100, letter: 'one'}, + {num: 50, letter: 'two'}, + {num: 10, letter: 'two'}, + ]; + + var res = alasql( + 'SELECT num AS position, letter AS note FROM ? GROUP BY num, letter ORDER BY num ASC', + [data] + ); + + assert.deepStrictEqual(res, [ + {position: 10, note: 'two'}, + {position: 50, note: 'two'}, + {position: 100, note: 'one'}, + ]); + }); + + it('C) Orders descending by original grouped column name', function () { var data = [ {num: 100, letter: 'one'}, {num: 50, letter: 'two'}, @@ -41,4 +60,16 @@ describe('Test 2515 - ORDER BY original grouped column with selected alias', fun {position: 10, note: 'two'}, ]); }); + + it('D) Orders by grouped source column that is not projected', function () { + var data = [ + {num: 100, letter: 'one'}, + {num: 50, letter: 'two'}, + {num: 10, letter: 'three'}, + ]; + + var res = alasql('SELECT letter AS note FROM ? GROUP BY num, letter ORDER BY num', [data]); + + assert.deepStrictEqual(res, [{note: 'three'}, {note: 'two'}, {note: 'one'}]); + }); }); From d03f42b7f8c730a192ec26518543f91caa5693da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Aug 2026 08:57:24 +0000 Subject: [PATCH 4/6] Clarify grouped ORDER BY lookup maps Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/424select.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/424select.js b/src/424select.js index 11cfdc857f..b1b6c9ff2b 100755 --- a/src/424select.js +++ b/src/424select.js @@ -697,15 +697,20 @@ yy.Select.prototype.compileSelectGroup2 = function (query) { self.columns.forEach(function (col) { if (col instanceof yy.Column) { var key = (col.tableid || '') + '\t' + col.columnid; - if (groupColMap[key] && (!groupProjectedColumnMap[key] || !col.as)) { - groupProjectedColumnMap[key] = col.as || col.columnid; + if (groupColMap[key]) { + if (!col.as) { + groupProjectedColumnMap[key] = col.columnid; + } else if (!groupProjectedColumnMap[key]) { + groupProjectedColumnMap[key] = col.as; + } } } }); } self.columns.forEach(function (col) { if (!(col instanceof yy.Column && col.columnid === '*')) { - projectedSelectColumnMap[col.as || col.nick] = true; + projectedSelectColumnMap[col.as || (col instanceof yy.Column ? col.columnid : col.nick)] = + true; } }); From bcb87d0c8e579b975240ae34c5cb75a67c53388c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Aug 2026 08:58:33 +0000 Subject: [PATCH 5/6] Guard grouped ORDER BY projection keys Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/424select.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/424select.js b/src/424select.js index b1b6c9ff2b..3bb39f11d6 100755 --- a/src/424select.js +++ b/src/424select.js @@ -709,8 +709,10 @@ yy.Select.prototype.compileSelectGroup2 = function (query) { } self.columns.forEach(function (col) { if (!(col instanceof yy.Column && col.columnid === '*')) { - projectedSelectColumnMap[col.as || (col instanceof yy.Column ? col.columnid : col.nick)] = - true; + var projectedSelectKey = col.as || (col instanceof yy.Column ? col.columnid : col.nick); + if (projectedSelectKey) { + projectedSelectColumnMap[projectedSelectKey] = true; + } } }); From 174ba2d3a4e408394b24afe0f566791309a118f0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Aug 2026 09:41:16 +0000 Subject: [PATCH 6/6] Optimize grouped ORDER BY lookup setup Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/424select.js | 57 ++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/src/424select.js b/src/424select.js index 3bb39f11d6..dca58a7036 100755 --- a/src/424select.js +++ b/src/424select.js @@ -684,6 +684,18 @@ yy.Select.prototype.compileSelectGroup1 = function (query) { yy.Select.prototype.compileSelectGroup2 = function (query) { var self = this; var s = query.selectgfns; + var hasOrderColumns = + this.orderColumns && + this.orderColumns.length > 0 && + !this.union && + !this.unionall && + !this.except && + !this.intersect; + var needsOrderColumnMaps = + hasOrderColumns && + this.orderColumns.some(function (col) { + return col instanceof yy.Column; + }); // Create a lookup map for GROUP BY columns to optimize performance var groupColMap = {}; @@ -694,27 +706,31 @@ yy.Select.prototype.compileSelectGroup2 = function (query) { var key = (gp.tableid || '') + '\t' + gp.columnid; groupColMap[key] = gp; }); - self.columns.forEach(function (col) { - if (col instanceof yy.Column) { - var key = (col.tableid || '') + '\t' + col.columnid; - if (groupColMap[key]) { - if (!col.as) { - groupProjectedColumnMap[key] = col.columnid; - } else if (!groupProjectedColumnMap[key]) { - groupProjectedColumnMap[key] = col.as; + if (needsOrderColumnMaps) { + self.columns.forEach(function (col) { + if (col instanceof yy.Column) { + var key = (col.tableid || '') + '\t' + col.columnid; + if (groupColMap[key]) { + if (!col.as) { + groupProjectedColumnMap[key] = col.columnid; + } else if (!groupProjectedColumnMap[key]) { + groupProjectedColumnMap[key] = col.as; + } } } + }); + } + } + if (needsOrderColumnMaps) { + self.columns.forEach(function (col) { + if (!(col instanceof yy.Column && col.columnid === '*')) { + var projectedSelectKey = col.as || (col instanceof yy.Column ? col.columnid : col.nick); + if (projectedSelectKey) { + projectedSelectColumnMap[projectedSelectKey] = true; + } } }); } - self.columns.forEach(function (col) { - if (!(col instanceof yy.Column && col.columnid === '*')) { - var projectedSelectKey = col.as || (col instanceof yy.Column ? col.columnid : col.nick); - if (projectedSelectKey) { - projectedSelectColumnMap[projectedSelectKey] = true; - } - } - }); self.columns.forEach(function (col) { // console.log(col); @@ -739,14 +755,7 @@ yy.Select.prototype.compileSelectGroup2 = function (query) { }); // Only add order keys if there's no union operation (otherwise they'll be added later) - if ( - this.orderColumns && - this.orderColumns.length > 0 && - !this.union && - !this.unionall && - !this.except && - !this.intersect - ) { + if (hasOrderColumns) { this.orderColumns.forEach(function (v, idx) { // console.log(411,v); var key = '$$$' + idx;