coldbox-modules / quick

A ColdBox ORM Engine
https://quick.ortusbooks.com
MIT License
23 stars 19 forks source link

subQuery `.from()` references wrong table (regression from v4 to v6) #231

Open MordantWastrel opened 1 year ago

MordantWastrel commented 1 year ago

We had an entity with the following scope in Quick 4:

                    q.whereHas( "child", ( q ) => q.whereIn( "familyID", ( q ) => {
                        q.from( "family_parents" )
                            .where( "clientID", "=", application.clientID )
                            .where( "userID", "=", parentUserID )
                            .select( "familyID" );
                    } ) )

which emitted this (focus is on the whereIn() portion with where [clientID] = @P4

WHERE
    [registrations].[clientID] = @P0 AND
    [registrations].[registered] = @P1 AND
    [registrations].[seasonID] = @P2 AND
    [registrations].[childID] != @P3 AND
    EXISTS (
        SELECT 1 FROM [children]
        WHERE
            ([children].[childID] = [registrations].[childID]) AND
            [children].[familyID] IN (
                SELECT [familyID]
                FROM [family_parents]
                WHERE
                    [clientID] = @P4 AND
                    [userID] = @P5
            )
    )

In Quick 6/7, it does this:

FROM [registrations]
WHERE
    [registrations].[clientID] = @P0 AND
    [registrations].[registered] = @P1 AND
    [registrations].[seasonID] = @P2 AND
    [registrations].[childID] != @P3 AND
    EXISTS (
        SELECT 1 FROM [children]
        WHERE
            ([children].[childID] = [registrations].[childID]) AND
            [children].[familyID] IN (
                -- should be select fp.familyID from family_parents where fp.clientID = x and fp.userID = y
                SELECT [children].[familyID]
                FROM [family_parents]
                WHERE
                    [children].[clientID] = @P4 AND
                    [userID] = @P5
            )
    )

This appears to occur only when both the parent object and the subQuery .from() table contain the same column: the builder references the parent table's column even with an explicit .from()

A workaround is to avoid .whereIn() in favor of additional .whereHas() but this is a prickly one as it's tough to track down unless you're explicitly testing for valid results in these queries.

MordantWastrel commented 1 year ago

@elpete This bug has blown up a number of pieces of our apps where we relying on Quick/QB intermingling, and causing records to be returned that should not be returned. It seems like a pretty big deal because it's not a 'crashes and throws an error' bug but a 'quietly does something other than what you asked it to' bug.