-
Notifications
You must be signed in to change notification settings - Fork 14
use an index name that is guaranteed to be no more than 255 chars #21
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
import java.util.LinkedHashMap; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
import java.util.UUID; | ||
|
||
import org.apache.ignite.cache.CacheAtomicityMode; | ||
import org.apache.ignite.cache.QueryEntity; | ||
|
@@ -180,7 +181,21 @@ private void appendIndex(QueryEntity queryEntity, AssociationKeyMetadata associa | |
fields.put( realColumnName, true ); | ||
} | ||
queryIndex.setFields( fields ); | ||
queryIndex.setName( queryEntity.getTableName() + '_' + org.hibernate.ogm.util.impl.StringHelper.join( fields.keySet(), "_" ) ); | ||
String indexName = queryEntity.getTableName() + '_' + org.hibernate.ogm.util.impl.StringHelper.join( fields.keySet(), "_" ); | ||
Class<?> tableClass = context.getTableEntityTypeMapping().get( associationKeyMetadata.getAssociatedEntityKeyMetadata().getEntityKeyMetadata().getTable() ); | ||
javax.persistence.Table tableAnnotation = tableClass.getAnnotation( javax.persistence.Table.class ); | ||
if( tableAnnotation != null && tableAnnotation.indexes().length > 0) { | ||
for(javax.persistence.Index index: tableAnnotation.indexes()){ | ||
if(!index.name().isEmpty()) { | ||
indexName = index.name(); | ||
break; | ||
} | ||
} | ||
} | ||
if ( indexName.getBytes().length > 255 ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How come aren't you using indexName.length()? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because Ignite's limit is of bytes not char length. String.length will give num of chars in the string but isn't necessarily the same as num of bytes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Imagine a table MyTable with 100 columns, and at some point you see the error: How do you know which column caused the issue? Wouldn't you prefer something like: We could also add in the message the name of the table and the column used to create the index as additional information. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You also didn't add the charset StandardCharsets.UTF_8: This means that if OGM runs on a machine with a different charset the validation might not be correct. |
||
throw log.indexNameTooLong(indexName, queryEntity.getTableName()); | ||
} | ||
queryIndex.setName( indexName ); | ||
|
||
Set<QueryIndex> indexes = new HashSet<>( queryEntity.getIndexes() ); | ||
indexes.add( queryIndex ); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* | ||
* Hibernate OGM, Domain model persistence for NoSQL datastores | ||
* | ||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later | ||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. | ||
*/ | ||
package org.hibernate.ogm.datastore.ignite.test.cfg; | ||
|
||
import org.hibernate.HibernateException; | ||
import org.hibernate.ogm.utils.OgmTestCase; | ||
import org.junit.Test; | ||
import javax.persistence.*; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
import static org.junit.Assert.*; | ||
|
||
/** | ||
* Entities with long names that results in an index with greater than 255 chars is invalid in Ignite. | ||
* This ensures we raise an error and provide useful information to the user | ||
*/ | ||
public class LongIndexNameTest extends OgmTestCase { | ||
|
||
@Test(expected = HibernateException.class) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @DavideD / @schernolyas - I need a bit of guidance on how to achieve this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are several examples in our test base about checking for exceptions, look for the following line in test classes:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this class can be a good example: https://github.com/hibernate/hibernate-ogm/blob/a97bb73a3619ff37d02f88d628306bf8e9ac097f/core/src/test/java/org/hibernate/ogm/backendtck/jpa/JPAAPIWrappingTest.java |
||
public void testLongEntityIndexName() throws Exception { | ||
fail("The length of the registered entity's cache name should've failed this already"); | ||
} | ||
|
||
@Override | ||
protected Class<?>[] getAnnotatedClasses() { | ||
return new Class<?>[] { | ||
LongEntityName.class, | ||
LongEntityContainer.class | ||
}; | ||
} | ||
|
||
@Entity | ||
public static class LongEntityContainer { | ||
@Id | ||
private String id; | ||
|
||
@OneToMany(targetEntity = LongEntityName.class) | ||
private Set<LongEntityName> longEntityNames = new HashSet<>(); | ||
|
||
@javax.persistence.JoinTable(name = "joinLongEntityName") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this annotation required? |
||
public Set<LongEntityName> getLongEntityNames() { | ||
return longEntityNames; | ||
} | ||
} | ||
|
||
@Entity(name = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec dapibus cursus vestibulum. Quisque eu justo non mi tincidunt sagittis. Donec tincidunt facilisis placerat. Sed placerat urna eget tristique faucibus. Curabitur maximus gravida enim, vitae sed") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be |
||
public static class LongEntityName { | ||
@Id | ||
private String id; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* Hibernate OGM, Domain model persistence for NoSQL datastores | ||
* | ||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later | ||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. | ||
*/ | ||
package org.hibernate.ogm.datastore.ignite.test.cfg; | ||
|
||
import org.apache.ignite.cache.QueryIndex; | ||
import org.hibernate.HibernateException; | ||
import org.hibernate.ogm.OgmSession; | ||
import org.hibernate.ogm.datastore.ignite.utils.IgniteTestHelper; | ||
import org.hibernate.ogm.utils.OgmTestCase; | ||
import org.junit.Test; | ||
|
||
import javax.persistence.*; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import static org.fest.assertions.Assertions.assertThat; | ||
import static org.junit.Assert.fail; | ||
|
||
/** | ||
* Entities with long names that results in an index with greater than 255 chars is invalid in Ignite. | ||
* This ensures we raise an error and provide useful information to the user | ||
*/ | ||
public class LongIndexNameWithIndexAnnotationTest extends OgmTestCase { | ||
|
||
@Test | ||
public void testLongEntityIndexName() throws Exception { | ||
try ( OgmSession session = openSession() ) { | ||
Set<QueryIndex> indexes = IgniteTestHelper.getIndexes( session.getSessionFactory(), EntityWithCustomIndex.class ); | ||
assertThat( indexes.size() ).isEqualTo( 1 ); | ||
assertThat( indexes.iterator().next().getName() ).isEqualToIgnoringCase( "SimpleIndexName" ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! You could make this test even better using: instead of
By the way, is Ignite case insensitive? What happens if we have two indexes on two different columns with the same name and dfferent case. For example: "IndexNAME" and "Indexname". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need some additional test cases:
This is just a question because I'm not familiar with it: Can we support the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
} | ||
|
||
@Override | ||
protected Class<?>[] getAnnotatedClasses() { | ||
return new Class<?>[] { | ||
EntityWithCustomIndex.class, | ||
EntityWithCustomContainer.class | ||
}; | ||
} | ||
|
||
@Entity | ||
public static class EntityWithCustomContainer { | ||
@Id | ||
private String id; | ||
|
||
@OneToMany(targetEntity = EntityWithCustomIndex.class) | ||
private Set<EntityWithCustomIndex> entityWithCustomIndices = new HashSet<>(); | ||
|
||
@javax.persistence.JoinTable(name = "joinLongEntityName") | ||
public Set<EntityWithCustomIndex> getEntityWithCustomIndices() { | ||
return entityWithCustomIndices; | ||
} | ||
} | ||
|
||
@Entity(name = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec dapibus cursus vestibulum. Quisque eu justo non mi tincidunt sagittis. Donec tincidunt facilisis placerat. Sed placerat urna eget tristique faucibus. Curabitur maximus gravida enim, vitae sed") | ||
@Table(indexes = {@Index(name = "SimpleIndexName", columnList = "id")}) | ||
public static class EntityWithCustomIndex { | ||
@Id | ||
private String id; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DavideD / @schernolyas how do you propose this should be handled?
Here I'm just taking the first non-empty
@Index
name and using it...I'm not convinced that's the way to go but@Index
cannot be applied to the classes directly.Also, should the "columnList" be used as part of the name, if so, how?
edit
What about
org.hibernate.search.annotations.Index
- it's allowed on classes?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's for full-text searches and only if one want to use Hibernate Search.
It's not suitable for this case, I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what's going on with this part of the code, why would you take the first empty index name? Isn't an index related to a field? What's the logic here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's possible to create indexes in two ways:
@Table( indexes = {@Index( columnList= "field1,field2", name="" )})
@Index( ... )
on a field of the class