Can't create temporary tables after migration from 5.6.15.Final to 6.2.17.Final

But what I don’t understand (well, one of the things) is why in the ORM 5, although the generated SQL does not have any pagination clauses, the results that I get when executing the code are what is expected, i.e. executing em.getResultList() does come with only 20 results, which corresponds to the page size and with the proper offset.

You can start debugging in org.hibernate.hql.internal.ast.QueryTranslatorImpl#list to see how the pagination is implemented. Potentially, the pagination happens in-memory, but according to the information that you have provided until now, this should not be the case.

If needsDistincting is true, you will see that pagination is applied in-memory. The other place where such in-memory skipping happens is in org.hibernate.loader.Loader#processResultSet, but you wrote that the advance method is never entered.

In the ORM 6 context, I am trying to understand these entities and how they might relate to the issue we have and, roughly, it’s this:

  • a Profile entity
  • a ProfileAttribute entity
  • a ProfileSingleAttribute entity

The Profile represents a table of profiles and the ProfileAttribute represents a table of profile attributes. ProfileSingleAttribute implements the same interface that ProfileAttribute and is supposed, as far as I understand, to represent a specific profile attribute.

In theory Profile could have a one-to-many relation with ProfileAttributes but it doesn’t. What it does have is a relation of one-to-one with a specific profile attribute that’s DisplayNameAttribute, like this:

@OneToOne(fetch = FetchType.LAZY, mappedBy = "profile")
 private ProfileAttribute.DisplayNameAttribute displayNameAttribute;

As you can see this DisplayNameAttribute a static class declared inside ProfileAttribute that extends ProfileSingleAttribute.

The profile_attributes table has both a profile_id and a profile_key and these columns form a composite primary key used by the entity ProfileAttribute and there’s a many-to-one relation with Profile, like this:

 @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PROFILE_ID", insertable = false, updatable = false)
    private Profile profile;

In its turn ProfileSingleAttribute declares only profile_id as an id and profile_key is just a normal column, like this:

 @Id
    @Column(name = "PROFILE_ID", updatable = false)
    private String profileId;

@Column(name = "PROFILE_KEY", updatable = false, insertable = false)
    private String key;

but in the top of the class we have this:

@DiscriminatorColumn(length = 254, name = "PROFILE_KEY", discriminatorType = DiscriminatorType.STRING)

I am not sure what this @DiscriminatorColumn does exactly but I noticed that the query statement that we run:

FROM Profile p LEFT JOIN FETCH p.displayNameAttribute dna WHERE p.customer.id = :customerId

gives rise to an SQL query that instead of having:

from PROFILES a1_0
         left join PROFILE_ATTRIBUTES c1_0 on a1_0.PROFILE_ID = c1_0.PROFILE_ID AND c1_0.PROFILE_KEY = 'displayname'

has:

from PROFILES a1_0
         left join PROFILE_ATTRIBUTES c1_0 on a1_0.PROFILE_ID = c1_0.PROFILE_KEY AND c1_0.PROFILE_KEY = 'displayname'

Notice that it’s comparing id to key and not id to id.

I am not sure exactly why it’s behaving like this but I am hoping that you can grasp something out of it faster than me.

I also noticed that removing the FETCH from the query statement no longer causes the temporary space exception but it’s a much slower process because instead of one query I got 1 + 2n queries and that mistake I mentioned above about comparing profile_id to profile_key still remains and no pagination is applied.

Do you have any idea or suggestion regarding all of this?

I suppose the comparison of id to key happens in ORM 6? That would be a bug, but I don’t have the full entity model to understand if you might have a wrong mapping, so please try to create a reproducer with our test case template (hibernate-test-case-templates/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java at main · hibernate/hibernate-test-case-templates · GitHub) and if you are able to reproduce the issue, create a bug ticket in our issue tracker(https://hibernate.atlassian.net) and attach that reproducer.

I’d need at least the code for the involved entity classes.

I copied the relevant entities to my fork of the test repository you pointed to and I cannot reproduce the behavior in any of the versions I tried, 6.1.7.Final, 6.2.22.Final or 6.4.2.Final. In my application the SQL output for:

"FROM Profile$Active p LEFT JOIN FETCH p.commonDisplayNameAttribute dna WHERE p.customer.id = :customerId order by LOWER(COALESCE(dna.value, p.name)) asc"

is:

select *
from (select a1_0.PROFILEID                c0,
             a1_0.LASTMODIFIEDATTRIBUTESTS c1,
             c1_0.PROFILEID                c2,
             c1_0.AUTOMATICALLYSET         c3,
             c1_0.PROFILEKEY               c4,
             c1_0.PROFILEVALUE             c5,
             a1_0.CREATETS                 c6,
             a1_0.CUSTOMERID                     c7,
             a1_0.DELETETS                 c8,
             a1_0.DISABLETS                c9,
             a1_0.LASTMODIFIEDUSER         c10,
             a1_0.LASTMODIFIEDCOMMENT      c11,
             a1_0.LASTMODIFIEDTS           c12,
             a1_0.PROFILENAME              c13,
             row_number()                  over(order by lower(coalesce(c1_0.PROFILEVALUE,a1_0.PROFILENAME))) rn
      from PROFILES a1_0
               left join PROFILES_ATTRIBUTES c1_0 on a1_0.PROFILEID = c1_0.PROFILEKEY
      where a1_0.CUSTOMERID = ?
        and CASE
                WHEN a1_0.DELETETS IS NOT NULL AND a1_0.DELETETS != '1970-01-01 01:00:00' THEN 'DELETED'
                WHEN a1_0.DISABLETS IS NOT NULL AND a1_0.DISABLETS != '1970-01-01 01:00:00' THEN 'DISABLED'
                ELSE 'ACTIVE' end = 'ACTIVE') r_0_
where r_0_.rn <= ? + ?
  and r_0_.rn > ?
order by r_0_.rn

and in the test repository:

select
    a1_0.PROFILEID,
    a1_0.LASTMODIFIEDATTRIBUTESTS,
    c1_0.PROFILEID,
    c1_0.AUTOMATICALLYSET,
    c1_0.PROFILEKEY,
    c1_0.PROFILEVALUE,
    a1_0.CREATETS,
    a1_0.CUSTOMERID,
    a1_0.DELETETS,
    a1_0.DISABLETS,
    a1_0.LASTMODIFIEDUSER,
    a1_0.LASTMODIFIEDCOMMENT,
    a1_0.LASTMODIFIEDTS,
    a1_0.PROFILENAME
from
    PROFILES a1_0
        left join
    PROFILE_ATTRIBUTES c1_0
    on a1_0.PROFILEID=c1_0.PROFILEID
where
        a1_0.CUSTOMERID=?
  and CASE
          WHEN a1_0.DELETETS IS NOT NULL
              AND a1_0.DELETETS != '1970-01-01 01:00:00' THEN 'DELETED'
          WHEN a1_0.DISABLETS IS NOT NULL
              AND a1_0.DISABLETS != '1970-01-01 01:00:00' THEN 'DISABLED'
          ELSE 'ACTIVE'
          end='ACTIVE'
order by
    lower(coalesce(c1_0.PROFILEVALUE,a1_0.PROFILENAME))
offset
    ? rows
    fetch
    first ? rows only

It’s quite different, and the code is the same. Not only the in the application is matching wrong columns, PROFILEID with PROFILEKEY, but neither of the queries has the other join for the displayName attribute as it was in ORM 5:

left join PROFILE_ATTRIBUTES c1_0 on a1_0.PROFILEID = c1_0.PROFILEID AND c1_0.PROFILEKEY = 'common.displayname'

I cannot understand what the hell is going on. The code is the same, the entities are the same. I checked the entityManager to see if any crazy configuration was there but just standard stuff.

Feel free to take a look at the repository if you think it might help:

Are you 100% certain that you are using 6.2.17.Final in your application? Note that the queries might be different because of the database version that your using for the test.

Yes, I was using 6.2.17 but yesterday I bumped it to 6.2.22 to be sure that I was using the same version as the test and it’s the same.

Hello @arqaos, I’ve also tried running your tests here:

the test is passing and I can confirm the behavior looks coorect to me: the column used in the join condition is PROFILEID on both sides and the discriminator formula is filtering 'ACTIVE' profiles only, which looks correct. I also see the left join with the PROFILE_ATTRIBUTES join table. Here’s the full generated query:

    select
        a1_0.PROFILEID,
        a1_0.LASTMODIFIEDATTRIBUTESTS,
        c1_0.PROFILEID,
        c1_0.AUTOMATICALLYSET,
        c1_0.PROFILEKEY,
        c1_0.PROFILEVALUE,
        a1_0.CREATETS,
        a1_0.CUSTOMER_ID,
        a1_0.DELETETS,
        a1_0.DISABLETS,
        a1_0.LASTMODIFIEDUSER,
        a1_0.LASTMODIFIEDCOMMENT,
        a1_0.LASTMODIFIEDTS,
        a1_0.PROFILENAME 
    from
        PROFILES a1_0 
    left join
        PROFILE_ATTRIBUTES c1_0 
            on a1_0.PROFILEID=c1_0.PROFILEID 
    where
        a1_0.CUSTOMER_ID=? 
        and CASE 
            WHEN a1_0.DELETETS IS NOT NULL 
            AND a1_0.DELETETS != '1970-01-01 01:00:00' THEN 'DELETED' 
            WHEN a1_0.DISABLETS IS NOT NULL 
            AND a1_0.DISABLETS != '1970-01-01 01:00:00' THEN 'DISABLED' 
            ELSE 'ACTIVE' 
        end='ACTIVE' 
    order by
        lower(coalesce(c1_0.PROFILEVALUE,a1_0.PROFILENAME)) 
    offset
        ? rows 
    fetch
        first ? rows only

I’m not sure why the generated query in your application is different, maybe it has something to do with Spring (or another component manipulating the query)?

Anyways, I would suggest adding data in your test case and some assertions as to what you expect the results of the query to be and see if you can trigger an error. If you can, it will be much easier for us to understand what might be going wrong.

Thank you for your reply. I am going to pause this effort for the moment, I have no viable pathway to follow at this point. I will try to get back at it later. Thank you for trying to help.

When Hibernate ORM boots up it will print out the version. Trying looking for that in the logs. My gut feeling tells me you are using an old version.

I don’t see how but I checked and it appears to be correct: