-
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 all 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() + '_' + UUID.nameUUIDFromBytes( org.hibernate.ogm.util.impl.StringHelper.join( fields.keySet(), "_" ).getBytes() ); | ||
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() ); | ||
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. Would it be possible to collect all the indexes with an invalid name and then throw an exception at the end? |
||
} | ||
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,59 @@ | ||
/* | ||
* 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.Entity; | ||
import javax.persistence.Id; | ||
import javax.persistence.OneToMany; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import static junit.framework.TestCase.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 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" ); | ||
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. This test is not good enough, The failure might be caused by something else. 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
THere are multiple example of tests in hibernate ogm core using 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. By the way, sometimes the JUnit rule is not easy to use. he try catch block is still a valid option |
||
} | ||
|
||
@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,68 @@ | ||
/* | ||
* 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.ogm.OgmSession; | ||
import org.hibernate.ogm.datastore.ignite.utils.IgniteTestHelper; | ||
import org.hibernate.ogm.utils.OgmTestCase; | ||
import org.junit.Test; | ||
|
||
import javax.persistence.Entity; | ||
import javax.persistence.Id; | ||
import javax.persistence.Index; | ||
import javax.persistence.OneToMany; | ||
import javax.persistence.Table; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import static org.fest.assertions.Assertions.assertThat; | ||
|
||
/** | ||
* 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.
Is this sufficient without the use of the
@Index
? It makes it extremely unlikely for this to happen and it was already a rare case.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.
Why wouldn't you simply concatenating the fields? What's the benefit in adding the UUID as suffix?