From 9db3a3bd169d452630448d33de3562b9df13f61c Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Tue, 3 Jun 2025 17:45:22 +0000 Subject: [PATCH 1/5] fix: use correct table alias in subselects for hasManyThrough and similar relationships --- models/QuickBuilder.cfc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/models/QuickBuilder.cfc b/models/QuickBuilder.cfc index baebefa..f6606e7 100644 --- a/models/QuickBuilder.cfc +++ b/models/QuickBuilder.cfc @@ -168,6 +168,8 @@ component accessors="true" transientCache="false" { } else if ( isSimpleValue( subselectQuery ) && listLen( subselectQuery, "." ) > 1 ) { var column = subselectQuery; var q = javacast( "null", "" ); + // Get the current table alias from the builder + var parentTableAlias = this.tableAlias(); while ( listLen( column, "." ) > 1 ) { var relationshipName = listFirst( column, "." ); if ( isNull( q ) ) { @@ -201,7 +203,8 @@ component accessors="true" transientCache="false" { } column = listRest( column, "." ); } - subselectQuery = q.select( q.qualifyColumn( column ) ); + // Use the parent table alias when qualifying the column + subselectQuery = q.select( q.qualifyColumn( column, parentTableAlias ) ); } subselectQuery.limit( 1 ) From 859656d77f842006e5e0e42367a06f124db97825 Mon Sep 17 00:00:00 2001 From: elpete Date: Tue, 3 Jun 2025 17:46:51 +0000 Subject: [PATCH 2/5] Apply cfformat changes --- models/QuickBuilder.cfc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/QuickBuilder.cfc b/models/QuickBuilder.cfc index f6606e7..3d3324d 100644 --- a/models/QuickBuilder.cfc +++ b/models/QuickBuilder.cfc @@ -166,8 +166,8 @@ component accessors="true" transientCache="false" { subselectQuery = variables.qb.newQuery(); arguments.subselect( subselectQuery ); } else if ( isSimpleValue( subselectQuery ) && listLen( subselectQuery, "." ) > 1 ) { - var column = subselectQuery; - var q = javacast( "null", "" ); + var column = subselectQuery; + var q = javacast( "null", "" ); // Get the current table alias from the builder var parentTableAlias = this.tableAlias(); while ( listLen( column, "." ) > 1 ) { From 44b51bc3c1d5ac15c8ca5437f1ffe621b41561ae Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Tue, 3 Jun 2025 17:51:43 +0000 Subject: [PATCH 3/5] fix: revert forcing parent table alias in subselects (fixes test failures) --- models/QuickBuilder.cfc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/models/QuickBuilder.cfc b/models/QuickBuilder.cfc index 3d3324d..baebefa 100644 --- a/models/QuickBuilder.cfc +++ b/models/QuickBuilder.cfc @@ -166,10 +166,8 @@ component accessors="true" transientCache="false" { subselectQuery = variables.qb.newQuery(); arguments.subselect( subselectQuery ); } else if ( isSimpleValue( subselectQuery ) && listLen( subselectQuery, "." ) > 1 ) { - var column = subselectQuery; - var q = javacast( "null", "" ); - // Get the current table alias from the builder - var parentTableAlias = this.tableAlias(); + var column = subselectQuery; + var q = javacast( "null", "" ); while ( listLen( column, "." ) > 1 ) { var relationshipName = listFirst( column, "." ); if ( isNull( q ) ) { @@ -203,8 +201,7 @@ component accessors="true" transientCache="false" { } column = listRest( column, "." ); } - // Use the parent table alias when qualifying the column - subselectQuery = q.select( q.qualifyColumn( column, parentTableAlias ) ); + subselectQuery = q.select( q.qualifyColumn( column ) ); } subselectQuery.limit( 1 ) From 1014c7350648c211f9c2ef8bc83abfc31087e4bf Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Tue, 3 Jun 2025 18:07:21 +0000 Subject: [PATCH 4/5] Add new test case --- .../HasManyThroughSubselectAliasSpec.cfc | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/specs/integration/BaseEntity/HasManyThroughSubselectAliasSpec.cfc diff --git a/tests/specs/integration/BaseEntity/HasManyThroughSubselectAliasSpec.cfc b/tests/specs/integration/BaseEntity/HasManyThroughSubselectAliasSpec.cfc new file mode 100644 index 0000000..c9f947b --- /dev/null +++ b/tests/specs/integration/BaseEntity/HasManyThroughSubselectAliasSpec.cfc @@ -0,0 +1,27 @@ +component extends="tests.resources.ModuleIntegrationSpec" { + + function run() { + describe("HasManyThrough subselect alias bug regression", function() { + it("uses the correct alias for parent table in subselects (no raw table name)", function() { + // Setup tables and data as in the bug report + getInstance("A").initTable(); + getInstance("B").initTable(); + getInstance("C").initTable(); + getInstance("D").initTable(); + + queryExecute(""" + insert into rmme_d(dID, dValue) values (42, 'some value in table D'); + insert into rmme_a (aID) values (1); + insert into rmme_b (bID, aID) values (2, 1); + insert into rmme_c (cID, bID, dID) values (3, 2, 42); + """); + + // This should not throw: The multi-part identifier "rmme_C.dID" could not be bound. + var v = getInstance("A").asMemento(includes = ["Cs"]).get(); + expect(v).notToBeNull(); + expect(v[1]["Cs"]).notToBeNull(); + expect(v[1]["Cs"][1]["inlined_dValue"]).toBe("some value in table D"); + }); + }); + } +} From 580ec0b293b97664ec2ee4205ee585fa6b576973 Mon Sep 17 00:00:00 2001 From: elpete Date: Tue, 3 Jun 2025 18:08:57 +0000 Subject: [PATCH 5/5] Apply cfformat changes --- .../HasManyThroughSubselectAliasSpec.cfc | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/tests/specs/integration/BaseEntity/HasManyThroughSubselectAliasSpec.cfc b/tests/specs/integration/BaseEntity/HasManyThroughSubselectAliasSpec.cfc index c9f947b..bc96ae9 100644 --- a/tests/specs/integration/BaseEntity/HasManyThroughSubselectAliasSpec.cfc +++ b/tests/specs/integration/BaseEntity/HasManyThroughSubselectAliasSpec.cfc @@ -1,27 +1,28 @@ component extends="tests.resources.ModuleIntegrationSpec" { function run() { - describe("HasManyThrough subselect alias bug regression", function() { - it("uses the correct alias for parent table in subselects (no raw table name)", function() { + describe( "HasManyThrough subselect alias bug regression", function() { + it( "uses the correct alias for parent table in subselects (no raw table name)", function() { // Setup tables and data as in the bug report - getInstance("A").initTable(); - getInstance("B").initTable(); - getInstance("C").initTable(); - getInstance("D").initTable(); + getInstance( "A" ).initTable(); + getInstance( "B" ).initTable(); + getInstance( "C" ).initTable(); + getInstance( "D" ).initTable(); - queryExecute(""" + queryExecute( """ insert into rmme_d(dID, dValue) values (42, 'some value in table D'); insert into rmme_a (aID) values (1); insert into rmme_b (bID, aID) values (2, 1); insert into rmme_c (cID, bID, dID) values (3, 2, 42); - """); + """ ); // This should not throw: The multi-part identifier "rmme_C.dID" could not be bound. - var v = getInstance("A").asMemento(includes = ["Cs"]).get(); - expect(v).notToBeNull(); - expect(v[1]["Cs"]).notToBeNull(); - expect(v[1]["Cs"][1]["inlined_dValue"]).toBe("some value in table D"); - }); - }); + var v = getInstance( "A" ).asMemento( includes = [ "Cs" ] ).get(); + expect( v ).notToBeNull(); + expect( v[ 1 ][ "Cs" ] ).notToBeNull(); + expect( v[ 1 ][ "Cs" ][ 1 ][ "inlined_dValue" ] ).toBe( "some value in table D" ); + } ); + } ); } + }