Issue #640: Weird issue with variable naming

Type: Bug ReoprtPriority: NormalStatus: FixedReplies: 4
#1

hi,

We've hit again against troubles with the variable naming when trying to get the query string with CriteriaQuery.toString(). I've tried three hours to replicate it without success, all I can say is that we do a LEFT JOIN on an embedded property as well as ordering is involved in selection and order by. Removing the addition of order stuff solves the issue of double naming though doesn't help us without ordering. The issue is that the name of the root variable is $1 as well as the name of our left join variable becomes $1. We're also adding a custom function expression in where clause though however as said, cannot replicate it in a demo, however here's my code I was trying to replicate it which is similiar to what we do. We'd really need this fixed urgently, we cannot work with order by right now :((

package com.test;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.CascadeType;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.OneToMany;
import javax.persistence.Persistence;
import javax.persistence.Tuple;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Root;

public final class F329
{

public static void main(String[] args)
{
  EntityManagerFactory emf = Persistence.createEntityManagerFactory("objectdb:$objectdb/db/test_F329.tmp;drop");
  EntityManager em = emf.createEntityManager();

  em.getTransaction().begin();
  for (int i = 0; i < 1000; ++i)
  {
   MyEntity entity = null;
   if (i % 2 == 0)
   {
    entity = new MyEntity(new MyMapEntity("Name-" + Integer.toString(i)));
   }
   else
   {
    entity = new MyEntity();
   }
   em.persist(entity);
  }
  em.getTransaction().commit();

  final CriteriaBuilder cb = em.getCriteriaBuilder();
  final CriteriaQuery<Tuple> cq = cb.createQuery(Tuple.class);
  final Root<?> from = cq.from(MyEntity.class);
  final Join<?, ?> join2 = from.join("embedded", JoinType.LEFT);
  final Join<?, ?> join = from.join("map", JoinType.LEFT);
  cq.multiselect(from, join2.get("name"));

  cq.where(cb.equal(join2.get("name"), cb.literal("TEST")));
  cq.orderBy(cb.asc(join2.get("name")));

  System.out.println(cq.toString());
  System.out.println(em.createQuery(cq).getResultList());

  em.close();
  emf.close();
}

@Entity
public static final class MyEntity
{
  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
  public Map<String, MyMapEntity> map = new HashMap<String, MyMapEntity>();
  public MyEmbedded embedded = new MyEmbedded();

  public MyEntity()
  {
  }

  public MyEntity(MyMapEntity... mapEntities)
  {
   for (MyMapEntity me : mapEntities)
   {
    map.put(me.name123, me);
   }
  }
}

@Embeddable
public static final class MyEmbedded
{
  public String name = "TEST";

  public String getName()
  {
   return name;
  }

  public void setName(String name)
  {
   this.name = name;
  }
}

@Entity
public static final class MyMapEntity
{
  public String name123;

  public MyMapEntity()
  {
  }

  public MyMapEntity(String name123)
  {
   this.name123 = name123;
  }
}
}
#2

oh and we re-use a join setup in our filter for the order by clause as well not sure if that makes the difference though I am doing that in the demo code as well without success of replication..

#3

Please post the query string with double use of $1.

What is the purpose of the test case that you posted? Is it the same query? similar query?

Can you post the code that build the problematic query?

ObjectDB Support
#4

Hi,

I finally found a way to replicate it and I found out why / when it happens. Take this code:

package com.test;

import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Tuple;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Root;

public final class F329
{

public static void main(String[] args)
{
  EntityManagerFactory emf = Persistence.createEntityManagerFactory("objectdb:$objectdb/db/test_F329.tmp;drop");
  EntityManager em = emf.createEntityManager();

  final CriteriaBuilder cb = em.getCriteriaBuilder();
  final CriteriaQuery<Tuple> cq = cb.createTupleQuery();
  final Root<?> from = cq.from(MyEntity.class);

  final Join<?, ?> join = from.join("embedded", JoinType.LEFT);

  // COMMENT THIS OUT AND IT WORKS OK
  from.get("name").toString();

  System.out.println(cq.toString());

  em.close();
  emf.close();
}

@Entity
public static final class MyEntity
{
  public MyEmbedded embedded = new MyEmbedded();
  public String name = null;

  public MyEntity()
  {
   name = "TEST";
  }
}

@Embeddable
public static final class MyEmbedded
{
  public String name = "TEST";

  public String getName()
  {
   return name;
  }

  public void setName(String name)
  {
   this.name = name;
  }
}
}

When using the toString() function of the path it turns out the variable naming goes wrong ($1 is twice). Comment this line from.get("name").toString(); out and everything works as expected ($1 and $2 are used). Now this is critical for us because we need to full path string for query replacing stuff later on as well as this happens during debugging because when you check the value of a path (which calls toString()), your whole query goes wrong after debugging!!

thanks for a fast fix,

Alex

#5

Yes, toString invocation should not affect. Build 2.3.6_08 fixes it.

ObjectDB Support

Reply