spring-data-relational icon indicating copy to clipboard operation
spring-data-relational copied to clipboard

Bug encountered with duplicate column names in result set, but only in specific alias order

Open edwardmp opened this issue 1 year ago • 2 comments
trafficstars

Hey folks,

Noticed a weird bug today.

Suppose I have the following entity structure:

CREATE TABLE "group" (
    uuid UUID PRIMARY KEY,
    name TEXT NOT NULL
);

CREATE TABLE "user" (
    uuid UUID PRIMARY KEY,
    name TEXT NOT NULL,
    group_uuid UUID,
    FOREIGN KEY (group_uuid) REFERENCES "group" (uuid)
);

E.g. a root entity group and embedded entity user.

Before I had a query like this, which worked fine using Spring data JDBC 2.4.16 despite the duplicate column name in both entities. There was something logged though ResultSet contains name multiple times, but in my case everything worked fine. I remember this from the past, because back then I could not find a proper fix that would remove the warning, however it seemed harmless at the time.

I recently upgraded to Spring Data JDBC 3.2.0 and this behavior has now changed. There is nothing logged, and the value of the name columns is swapped between the entities, e.g. the group entity will have the name of the user, and the user will have the name of the group.

Anyhow, I guess it's logical that due to the single select * Spring Data JDBC couldn't figure it out, not sure why the warning message no longer is logged though. I found #1073 which might explain this change, and based on this I modified my query to:

@Query(
    """
        select u.*, g.*
        from group g
        inner join user u on u.group_uuid = g.uuid
    """,
)
fun findAll(
): List<Group>

Then, everything works as expected.

However I also noticed that if I swap the order of select aliases, the issue appears again:

@Query(
    """
        select g.*, u.*
        from group g
        inner join user u on u.group_uuid = g.uuid
    """,
)
fun findAll(
): List<Group>

So I have 2 questions/remarks:

  1. Why is there nothing logged anymore like before if Spring Data JDBC can't figure out the column mapping due to duplicate names like before? This would have saved me quite some debugging time.
  2. Why does Spring Data JDBC still swap the values across entities with the correct query syntax if the order is different? I can't think of any valid reason why the order should matter here.

@schauder perhaps you have an idea here since you worked on the related commit.

Edit: I had to downgrade to Spring Boot 3.1.5 (and thus Spring Data JDBC 3.1.5) for other reasons, and now I notice that the issue is inverted again.

E.g. this works:

@Query(
    """
        select g.*, u.*
        from group g
        inner join user u on u.group_uuid = g.uuid
    """,
)
fun findAll(
): List<Group>

But swapping g.* and u.* makes it fail here. So exactly inverted of what happens with 3.2.0.. very puzzling

edwardmp avatar Nov 29 '23 16:11 edwardmp

Hi @edwardmp,

thanks for raising this issue, I'll consider the missing warning a bug. As for why it is depending on the order of columns, I can't give an exact explanation, but it doesn't surprise me. I'd guess something is iterating columns an properties and in the process copies data from the two columns in the same variable => the last one wins.

This might even be related to #1684 which we fixed with 8a94345a7a272db2.

In order to get properly hunting, could you please provide the domain model you are using, i.e. the classes Group and I assume User?

schauder avatar May 13 '24 12:05 schauder

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

spring-projects-issues avatar May 20 '24 12:05 spring-projects-issues

Hey @schauder

Here's the domain model:

import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import java.util.UUID

@Table("group")
data class Group(
    @Id
    val uuid: UUID,
    val name: String
)
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import org.springframework.data.relational.core.mapping.Column
import java.util.UUID

@Table("user")
data class User(
    @Id
    val uuid: UUID,
    val name: String,
    @Column("group_uuid")
    val groupUuid: UUID?
)

edwardmp avatar May 25 '24 16:05 edwardmp