From b579da84231cd18f0ed2dd706b6fce620a0a5d51 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 27 Jan 2025 16:32:42 +0100 Subject: [PATCH] fix: groupby path expression with overlapping identifier (#992) Currently, the HANA service is unable to `GROUP BY foobar.foobar`, raising an error like `invalid column name: foobar.foobar`, if the query includes an aggregation and `sql syntax error: incorrect syntax near "FROM"`, if it does not. The problem is caused by the overlapping column names and the HANA service not correctly injecting the column groupby requires into the parent select - if the parent includes a column with the same `column_name` as the 'grouped-by' column. This fix enables the required injection, by skipping the overlapping names check for columns that contain a select. --------- Co-authored-by: Bob den Os <108393871+BobdenOs@users.noreply.github.com> Co-authored-by: Johannes Vogel <31311694+johannes-vogel@users.noreply.github.com> --- hana/lib/HANAService.js | 2 +- test/compliance/SELECT.test.js | 12 ++++++++++++ .../compliance/resources/db/complex/associations.cds | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/hana/lib/HANAService.js b/hana/lib/HANAService.js index e28aff781..4024e122a 100644 --- a/hana/lib/HANAService.js +++ b/hana/lib/HANAService.js @@ -549,7 +549,7 @@ class HANAService extends SQLService { // if (col.ref?.length === 1) { col.ref.unshift(parent.as) } if (col.ref?.length > 1) { const colName = this.column_name(col) - if (!parent.SELECT.columns.some(c => this.column_name(c) === colName)) { + if (!parent.SELECT.columns.some(c => !c.elements && this.column_name(c) === colName)) { const isSource = from => { if (from.as === col.ref[0]) return true return from.args?.some(a => { diff --git a/test/compliance/SELECT.test.js b/test/compliance/SELECT.test.js index 786193446..a25b5029d 100644 --- a/test/compliance/SELECT.test.js +++ b/test/compliance/SELECT.test.js @@ -635,6 +635,18 @@ describe('SELECT', () => { const res = await cds.run(cqn) assert.strictEqual(res.length, 3, 'Ensure that all rows are coming back') }) + + test('navigation with duplicate identifier in path', async () => { + const { Books } = cds.entities('complex.associations') + const res = await cds.ql`SELECT name { name } FROM ${Books} GROUP BY name.name` + assert.strictEqual(res.length, 1, 'Ensure that all rows are coming back') + }) + + test('navigation with duplicate identifier in path and aggregation', async () => { + const { Books } = cds.entities('complex.associations') + const res = await cds.ql`SELECT name { name }, count(1) as total FROM ${Books} GROUP BY name.name` + assert.strictEqual(res.length, 1, 'Ensure that all rows are coming back') + }) }) describe('having', () => { diff --git a/test/compliance/resources/db/complex/associations.cds b/test/compliance/resources/db/complex/associations.cds index 6f5216285..5fc0edb8c 100644 --- a/test/compliance/resources/db/complex/associations.cds +++ b/test/compliance/resources/db/complex/associations.cds @@ -4,6 +4,7 @@ entity Books { key ID : Integer; title : String(111); author : Association to Authors; + name : Association to Authors on $self.author.ID = name.ID; } entity Authors {