diff --git a/community/common/src/main/java/org/neo4j/kernel/api/exceptions/Status.java b/community/common/src/main/java/org/neo4j/kernel/api/exceptions/Status.java
index 746ad2ec53dc3..ea657e9e9d5ef 100644
--- a/community/common/src/main/java/org/neo4j/kernel/api/exceptions/Status.java
+++ b/community/common/src/main/java/org/neo4j/kernel/api/exceptions/Status.java
@@ -298,6 +298,8 @@ public Code code()
enum Schema implements Status
{
// client errors
+ RepeatedPropertyInCompositeSchema( ClientError,
+ "Unable to create composite index or constraint because a property was specified in several positions." ),
ConstraintAlreadyExists( ClientError,
"Unable to perform operation because it would clash with a pre-existing constraint." ),
ConstraintNotFound( ClientError,
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaWriteOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaWriteOperations.java
index 82e28467d0438..3c08f470c5367 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaWriteOperations.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaWriteOperations.java
@@ -24,6 +24,7 @@
import org.neo4j.kernel.api.exceptions.schema.CreateConstraintFailureException;
import org.neo4j.kernel.api.exceptions.schema.DropConstraintFailureException;
import org.neo4j.kernel.api.exceptions.schema.DropIndexFailureException;
+import org.neo4j.kernel.api.exceptions.schema.RepeatedPropertyInCompositeSchemaException;
import org.neo4j.kernel.api.schema_new.LabelSchemaDescriptor;
import org.neo4j.kernel.api.schema_new.RelationTypeSchemaDescriptor;
import org.neo4j.kernel.api.schema_new.constaints.ConstraintDescriptor;
@@ -40,7 +41,7 @@ public interface SchemaWriteOperations
* @param schemaDescriptor
*/
NewIndexDescriptor indexCreate( LabelSchemaDescriptor schemaDescriptor )
- throws AlreadyIndexedException, AlreadyConstrainedException;
+ throws AlreadyIndexedException, AlreadyConstrainedException, RepeatedPropertyInCompositeSchemaException;
/** Drops a {@link NewIndexDescriptor} from the database */
void indexDrop( NewIndexDescriptor descriptor ) throws DropIndexFailureException;
@@ -52,14 +53,17 @@ NewIndexDescriptor indexCreate( LabelSchemaDescriptor schemaDescriptor )
void uniqueIndexDrop( NewIndexDescriptor descriptor ) throws DropIndexFailureException;
UniquenessConstraintDescriptor uniquePropertyConstraintCreate( LabelSchemaDescriptor descriptor )
- throws CreateConstraintFailureException, AlreadyConstrainedException, AlreadyIndexedException;
+ throws CreateConstraintFailureException, AlreadyConstrainedException, AlreadyIndexedException,
+ RepeatedPropertyInCompositeSchemaException;
NodeExistenceConstraintDescriptor nodePropertyExistenceConstraintCreate( LabelSchemaDescriptor descriptor )
- throws CreateConstraintFailureException, AlreadyConstrainedException;
+ throws CreateConstraintFailureException, AlreadyConstrainedException,
+ RepeatedPropertyInCompositeSchemaException;
RelExistenceConstraintDescriptor relationshipPropertyExistenceConstraintCreate(
- RelationTypeSchemaDescriptor relationshipPropertyDescriptor ) throws
- CreateConstraintFailureException, AlreadyConstrainedException;
+ RelationTypeSchemaDescriptor relationshipPropertyDescriptor )
+ throws CreateConstraintFailureException, AlreadyConstrainedException,
+ RepeatedPropertyInCompositeSchemaException;
void constraintDrop( ConstraintDescriptor constraint ) throws DropConstraintFailureException;
}
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/RepeatedPropertyInCompositeSchemaException.java b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/RepeatedPropertyInCompositeSchemaException.java
new file mode 100644
index 0000000000000..89a17e3b4bb5b
--- /dev/null
+++ b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/RepeatedPropertyInCompositeSchemaException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2002-2017 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.kernel.api.exceptions.schema;
+
+import org.neo4j.kernel.api.TokenNameLookup;
+import org.neo4j.kernel.api.exceptions.Status;
+import org.neo4j.kernel.api.schema_new.SchemaDescriptor;
+import org.neo4j.kernel.api.schema_new.SchemaUtil;
+
+public class RepeatedPropertyInCompositeSchemaException extends SchemaKernelException
+{
+ private final SchemaDescriptor schema;
+ private final OperationContext context;
+
+ public RepeatedPropertyInCompositeSchemaException( SchemaDescriptor schema, OperationContext context )
+ {
+ super( Status.Schema.RepeatedPropertyInCompositeSchema, format(
+ schema, context, SchemaUtil.idTokenNameLookup ) );
+ this.schema = schema;
+ this.context = context;
+ }
+
+ @Override
+ public String getUserMessage( TokenNameLookup tokenNameLookup )
+ {
+ return format( schema, context, tokenNameLookup );
+ }
+
+ private static String format(
+ SchemaDescriptor schema, OperationContext context, TokenNameLookup tokenNameLookup )
+ {
+ String schemaName;
+ switch ( context )
+ {
+ case INDEX_CREATION:
+ schemaName = "Index";
+ break;
+
+ case CONSTRAINT_CREATION:
+ schemaName = "Constraint";
+ break;
+
+ default:
+ schemaName = "Schema object";
+ break;
+ }
+ return String.format( "%s on %s includes a property more than once.",
+ schemaName, schema.userDescription( tokenNameLookup ) );
+
+ }
+}
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/ConstraintEnforcingEntityOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/ConstraintEnforcingEntityOperations.java
index d382e66c66c65..6c70f69295163 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/ConstraintEnforcingEntityOperations.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/ConstraintEnforcingEntityOperations.java
@@ -44,6 +44,7 @@
import org.neo4j.kernel.api.exceptions.schema.DropConstraintFailureException;
import org.neo4j.kernel.api.exceptions.schema.DropIndexFailureException;
import org.neo4j.kernel.api.exceptions.schema.IndexBrokenKernelException;
+import org.neo4j.kernel.api.exceptions.schema.RepeatedPropertyInCompositeSchemaException;
import org.neo4j.kernel.api.exceptions.schema.UnableToValidateConstraintException;
import org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException;
import org.neo4j.kernel.api.properties.DefinedProperty;
@@ -539,7 +540,7 @@ public Cursor nodeGetRelationships( KernelStatement statement,
@Override
public NewIndexDescriptor indexCreate( KernelStatement state, LabelSchemaDescriptor descriptor )
- throws AlreadyIndexedException, AlreadyConstrainedException
+ throws AlreadyIndexedException, AlreadyConstrainedException, RepeatedPropertyInCompositeSchemaException
{
return schemaWriteOperations.indexCreate( state, descriptor );
}
@@ -558,7 +559,8 @@ public void uniqueIndexDrop( KernelStatement state, NewIndexDescriptor descripto
@Override
public UniquenessConstraintDescriptor uniquePropertyConstraintCreate( KernelStatement state, LabelSchemaDescriptor descriptor )
- throws AlreadyConstrainedException, CreateConstraintFailureException, AlreadyIndexedException
+ throws AlreadyConstrainedException, CreateConstraintFailureException, AlreadyIndexedException,
+ RepeatedPropertyInCompositeSchemaException
{
return schemaWriteOperations.uniquePropertyConstraintCreate( state, descriptor );
}
@@ -567,7 +569,7 @@ public UniquenessConstraintDescriptor uniquePropertyConstraintCreate( KernelStat
public NodeExistenceConstraintDescriptor nodePropertyExistenceConstraintCreate(
KernelStatement state,
LabelSchemaDescriptor descriptor
- ) throws AlreadyConstrainedException, CreateConstraintFailureException
+ ) throws AlreadyConstrainedException, CreateConstraintFailureException, RepeatedPropertyInCompositeSchemaException
{
Iterator> nodes = new NodeLoadingIterator( nodesGetForLabel( state, descriptor.getLabelId() ),
( id ) -> nodeCursorById( state, id ) );
@@ -580,7 +582,7 @@ public NodeExistenceConstraintDescriptor nodePropertyExistenceConstraintCreate(
public RelExistenceConstraintDescriptor relationshipPropertyExistenceConstraintCreate(
KernelStatement state,
RelationTypeSchemaDescriptor descriptor
- ) throws AlreadyConstrainedException, CreateConstraintFailureException
+ ) throws AlreadyConstrainedException, CreateConstraintFailureException, RepeatedPropertyInCompositeSchemaException
{
try ( Cursor cursor = relationshipCursorGetAll( state ) )
{
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperations.java
index ee7bcf3187cba..eef367e33c091 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperations.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperations.java
@@ -19,7 +19,8 @@
*/
package org.neo4j.kernel.impl.api;
-import org.neo4j.kernel.api.schema.NodePropertyDescriptor;
+import java.util.Arrays;
+
import org.neo4j.kernel.api.Statement;
import org.neo4j.kernel.api.StatementTokenNameLookup;
import org.neo4j.kernel.api.constraints.UniquenessConstraint;
@@ -32,11 +33,14 @@
import org.neo4j.kernel.api.exceptions.schema.IndexBelongsToConstraintException;
import org.neo4j.kernel.api.exceptions.schema.NoSuchConstraintException;
import org.neo4j.kernel.api.exceptions.schema.NoSuchIndexException;
+import org.neo4j.kernel.api.exceptions.schema.RepeatedPropertyInCompositeSchemaException;
import org.neo4j.kernel.api.exceptions.schema.SchemaKernelException.OperationContext;
import org.neo4j.kernel.api.exceptions.schema.TooManyLabelsException;
+import org.neo4j.kernel.api.schema.NodePropertyDescriptor;
import org.neo4j.kernel.api.schema_new.LabelSchemaDescriptor;
import org.neo4j.kernel.api.schema_new.RelationTypeSchemaDescriptor;
import org.neo4j.kernel.api.schema_new.SchemaBoundary;
+import org.neo4j.kernel.api.schema_new.SchemaDescriptor;
import org.neo4j.kernel.api.schema_new.constaints.ConstraintBoundary;
import org.neo4j.kernel.api.schema_new.constaints.ConstraintDescriptor;
import org.neo4j.kernel.api.schema_new.constaints.ConstraintDescriptorFactory;
@@ -111,9 +115,10 @@ public void relationshipTypeCreateForName( KernelStatement state, String relatio
@Override
public NewIndexDescriptor indexCreate( KernelStatement state, LabelSchemaDescriptor descriptor )
- throws AlreadyIndexedException, AlreadyConstrainedException
+ throws AlreadyIndexedException, AlreadyConstrainedException, RepeatedPropertyInCompositeSchemaException
{
- checkIndexExistence( state, OperationContext.INDEX_CREATION, SchemaBoundary.map( descriptor ) );
+ assertValidDescriptor( descriptor, OperationContext.INDEX_CREATION );
+ assertIndexDoesNotExist( state, OperationContext.INDEX_CREATION, SchemaBoundary.map( descriptor ) );
return schemaWriteDelegate.indexCreate( state, descriptor );
}
@@ -151,21 +156,25 @@ public void uniqueIndexDrop( KernelStatement state, NewIndexDescriptor index ) t
@Override
public UniquenessConstraintDescriptor uniquePropertyConstraintCreate(
KernelStatement state, LabelSchemaDescriptor descriptor )
- throws AlreadyConstrainedException, CreateConstraintFailureException, AlreadyIndexedException
+ throws AlreadyConstrainedException, CreateConstraintFailureException, AlreadyIndexedException,
+ RepeatedPropertyInCompositeSchemaException
{
+ assertValidDescriptor( descriptor, OperationContext.CONSTRAINT_CREATION );
ConstraintDescriptor constraint = ConstraintDescriptorFactory.uniqueForSchema( descriptor );
assertConstraintDoesNotExist( state, constraint );
// It is not allowed to create uniqueness constraints on indexed label/property pairs
- checkIndexExistence( state, OperationContext.CONSTRAINT_CREATION, SchemaBoundary.map( descriptor ) );
+ assertIndexDoesNotExist( state, OperationContext.CONSTRAINT_CREATION, SchemaBoundary.map( descriptor ) );
return schemaWriteDelegate.uniquePropertyConstraintCreate( state, descriptor );
}
@Override
public NodeExistenceConstraintDescriptor nodePropertyExistenceConstraintCreate( KernelStatement state,
- LabelSchemaDescriptor descriptor) throws AlreadyConstrainedException, CreateConstraintFailureException
+ LabelSchemaDescriptor descriptor) throws AlreadyConstrainedException, CreateConstraintFailureException,
+ RepeatedPropertyInCompositeSchemaException
{
+ assertValidDescriptor( descriptor, OperationContext.CONSTRAINT_CREATION );
ConstraintDescriptor constraint = ConstraintDescriptorFactory.existsForSchema( descriptor );
assertConstraintDoesNotExist( state, constraint );
return schemaWriteDelegate.nodePropertyExistenceConstraintCreate( state, descriptor );
@@ -173,8 +182,11 @@ public NodeExistenceConstraintDescriptor nodePropertyExistenceConstraintCreate(
@Override
public RelExistenceConstraintDescriptor relationshipPropertyExistenceConstraintCreate( KernelStatement state,
- RelationTypeSchemaDescriptor descriptor ) throws AlreadyConstrainedException, CreateConstraintFailureException
+ RelationTypeSchemaDescriptor descriptor )
+ throws AlreadyConstrainedException, CreateConstraintFailureException,
+ RepeatedPropertyInCompositeSchemaException
{
+ assertValidDescriptor( descriptor, OperationContext.CONSTRAINT_CREATION );
ConstraintDescriptor constraint = ConstraintDescriptorFactory.existsForSchema( descriptor );
assertConstraintDoesNotExist( state, constraint );
return schemaWriteDelegate.relationshipPropertyExistenceConstraintCreate( state, descriptor );
@@ -194,7 +206,7 @@ public void constraintDrop( KernelStatement state, ConstraintDescriptor descript
schemaWriteDelegate.constraintDrop( state, descriptor );
}
- private void checkIndexExistence( KernelStatement state, OperationContext context,
+ private void assertIndexDoesNotExist( KernelStatement state, OperationContext context,
NodePropertyDescriptor descriptor )
throws AlreadyIndexedException, AlreadyConstrainedException
{
@@ -238,4 +250,14 @@ private void assertConstraintExists( KernelStatement state, ConstraintDescriptor
throw new NoSuchConstraintException( ConstraintBoundary.map( constraint ) );
}
}
+
+ private void assertValidDescriptor( SchemaDescriptor descriptor, OperationContext context )
+ throws RepeatedPropertyInCompositeSchemaException
+ {
+ int numUnique = Arrays.stream( descriptor.getPropertyIds() ).distinct().toArray().length;
+ if ( numUnique != descriptor.getPropertyIds().length )
+ {
+ throw new RepeatedPropertyInCompositeSchemaException( descriptor, context );
+ }
+ }
}
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/LockingStatementOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/LockingStatementOperations.java
index 0fa1a9d3f3dfb..e11a1ad7e5c61 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/LockingStatementOperations.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/LockingStatementOperations.java
@@ -36,6 +36,7 @@
import org.neo4j.kernel.api.exceptions.schema.CreateConstraintFailureException;
import org.neo4j.kernel.api.exceptions.schema.DropConstraintFailureException;
import org.neo4j.kernel.api.exceptions.schema.DropIndexFailureException;
+import org.neo4j.kernel.api.exceptions.schema.RepeatedPropertyInCompositeSchemaException;
import org.neo4j.kernel.api.exceptions.schema.SchemaRuleNotFoundException;
import org.neo4j.kernel.api.index.InternalIndexState;
import org.neo4j.kernel.api.properties.DefinedProperty;
@@ -127,7 +128,7 @@ public boolean nodeRemoveLabel( KernelStatement state, long nodeId, int labelId
@Override
public NewIndexDescriptor indexCreate( KernelStatement state, LabelSchemaDescriptor descriptor )
- throws AlreadyIndexedException, AlreadyConstrainedException
+ throws AlreadyIndexedException, AlreadyConstrainedException, RepeatedPropertyInCompositeSchemaException
{
acquireExclusiveSchemaLock( state );
state.assertOpen();
@@ -345,7 +346,8 @@ private void lockRelationshipNodes( KernelStatement state, long startNodeId, lon
@Override
public UniquenessConstraintDescriptor uniquePropertyConstraintCreate( KernelStatement state,LabelSchemaDescriptor descriptor )
- throws CreateConstraintFailureException, AlreadyConstrainedException, AlreadyIndexedException
+ throws CreateConstraintFailureException, AlreadyConstrainedException, AlreadyIndexedException,
+ RepeatedPropertyInCompositeSchemaException
{
acquireExclusiveSchemaLock( state );
state.assertOpen();
@@ -354,7 +356,8 @@ public UniquenessConstraintDescriptor uniquePropertyConstraintCreate( KernelStat
@Override
public NodeExistenceConstraintDescriptor nodePropertyExistenceConstraintCreate( KernelStatement state,
- LabelSchemaDescriptor descriptor ) throws AlreadyConstrainedException, CreateConstraintFailureException
+ LabelSchemaDescriptor descriptor ) throws AlreadyConstrainedException, CreateConstraintFailureException,
+ RepeatedPropertyInCompositeSchemaException
{
acquireExclusiveSchemaLock( state );
state.assertOpen();
@@ -363,7 +366,9 @@ public NodeExistenceConstraintDescriptor nodePropertyExistenceConstraintCreate(
@Override
public RelExistenceConstraintDescriptor relationshipPropertyExistenceConstraintCreate( KernelStatement state,
- RelationTypeSchemaDescriptor descriptor ) throws AlreadyConstrainedException, CreateConstraintFailureException
+ RelationTypeSchemaDescriptor descriptor )
+ throws AlreadyConstrainedException, CreateConstraintFailureException,
+ RepeatedPropertyInCompositeSchemaException
{
acquireExclusiveSchemaLock( state );
state.assertOpen();
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/OperationsFacade.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/OperationsFacade.java
index 02a80a998267e..774135709ed60 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/OperationsFacade.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/OperationsFacade.java
@@ -63,6 +63,7 @@
import org.neo4j.kernel.api.exceptions.schema.DuplicateSchemaRuleException;
import org.neo4j.kernel.api.exceptions.schema.IllegalTokenNameException;
import org.neo4j.kernel.api.exceptions.schema.IndexBrokenKernelException;
+import org.neo4j.kernel.api.exceptions.schema.RepeatedPropertyInCompositeSchemaException;
import org.neo4j.kernel.api.exceptions.schema.SchemaRuleNotFoundException;
import org.neo4j.kernel.api.exceptions.schema.TooManyLabelsException;
import org.neo4j.kernel.api.index.InternalIndexState;
@@ -989,7 +990,7 @@ public Property graphRemoveProperty( int propertyKeyId )
//
@Override
public NewIndexDescriptor indexCreate( LabelSchemaDescriptor descriptor )
- throws AlreadyIndexedException, AlreadyConstrainedException
+ throws AlreadyIndexedException, AlreadyConstrainedException, RepeatedPropertyInCompositeSchemaException
{
statement.assertOpen();
return schemaWrite().indexCreate( statement, descriptor );
@@ -1004,7 +1005,8 @@ public void indexDrop( NewIndexDescriptor descriptor ) throws DropIndexFailureEx
@Override
public UniquenessConstraintDescriptor uniquePropertyConstraintCreate( LabelSchemaDescriptor descriptor )
- throws CreateConstraintFailureException, AlreadyConstrainedException, AlreadyIndexedException
+ throws CreateConstraintFailureException, AlreadyConstrainedException, AlreadyIndexedException,
+ RepeatedPropertyInCompositeSchemaException
{
statement.assertOpen();
return schemaWrite().uniquePropertyConstraintCreate( statement, descriptor );
@@ -1012,7 +1014,8 @@ public UniquenessConstraintDescriptor uniquePropertyConstraintCreate( LabelSchem
@Override
public NodeExistenceConstraintDescriptor nodePropertyExistenceConstraintCreate( LabelSchemaDescriptor descriptor )
- throws CreateConstraintFailureException, AlreadyConstrainedException
+ throws CreateConstraintFailureException, AlreadyConstrainedException,
+ RepeatedPropertyInCompositeSchemaException
{
statement.assertOpen();
return schemaWrite().nodePropertyExistenceConstraintCreate( statement, descriptor );
@@ -1021,7 +1024,8 @@ public NodeExistenceConstraintDescriptor nodePropertyExistenceConstraintCreate(
@Override
public RelExistenceConstraintDescriptor relationshipPropertyExistenceConstraintCreate(
RelationTypeSchemaDescriptor descriptor )
- throws CreateConstraintFailureException, AlreadyConstrainedException
+ throws CreateConstraintFailureException, AlreadyConstrainedException,
+ RepeatedPropertyInCompositeSchemaException
{
statement.assertOpen();
return schemaWrite().relationshipPropertyExistenceConstraintCreate( statement, descriptor );
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaWriteOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaWriteOperations.java
index 0fc1c47a47ba0..e5e3e3eb4875f 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaWriteOperations.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaWriteOperations.java
@@ -24,6 +24,7 @@
import org.neo4j.kernel.api.exceptions.schema.CreateConstraintFailureException;
import org.neo4j.kernel.api.exceptions.schema.DropConstraintFailureException;
import org.neo4j.kernel.api.exceptions.schema.DropIndexFailureException;
+import org.neo4j.kernel.api.exceptions.schema.RepeatedPropertyInCompositeSchemaException;
import org.neo4j.kernel.api.schema_new.LabelSchemaDescriptor;
import org.neo4j.kernel.api.schema_new.RelationTypeSchemaDescriptor;
import org.neo4j.kernel.api.schema_new.constaints.ConstraintDescriptor;
@@ -40,7 +41,7 @@ public interface SchemaWriteOperations
* {@code labelId}.
*/
NewIndexDescriptor indexCreate( KernelStatement state, LabelSchemaDescriptor descriptor )
- throws AlreadyIndexedException, AlreadyConstrainedException;
+ throws AlreadyIndexedException, AlreadyConstrainedException, RepeatedPropertyInCompositeSchemaException;
/** Drops a {@link NewIndexDescriptor} from the database */
void indexDrop( KernelStatement state, NewIndexDescriptor descriptor ) throws DropIndexFailureException;
@@ -52,13 +53,17 @@ NewIndexDescriptor indexCreate( KernelStatement state, LabelSchemaDescriptor des
void uniqueIndexDrop( KernelStatement state, NewIndexDescriptor descriptor ) throws DropIndexFailureException;
UniquenessConstraintDescriptor uniquePropertyConstraintCreate( KernelStatement state, LabelSchemaDescriptor descriptor )
- throws AlreadyConstrainedException, CreateConstraintFailureException, AlreadyIndexedException;
+ throws AlreadyConstrainedException, CreateConstraintFailureException, AlreadyIndexedException,
+ RepeatedPropertyInCompositeSchemaException;
NodeExistenceConstraintDescriptor nodePropertyExistenceConstraintCreate( KernelStatement state,
- LabelSchemaDescriptor descriptor ) throws AlreadyConstrainedException, CreateConstraintFailureException;
+ LabelSchemaDescriptor descriptor ) throws AlreadyConstrainedException, CreateConstraintFailureException,
+ RepeatedPropertyInCompositeSchemaException;
RelExistenceConstraintDescriptor relationshipPropertyExistenceConstraintCreate( KernelStatement state,
- RelationTypeSchemaDescriptor descriptor ) throws AlreadyConstrainedException, CreateConstraintFailureException;
+ RelationTypeSchemaDescriptor descriptor )
+ throws AlreadyConstrainedException, CreateConstraintFailureException,
+ RepeatedPropertyInCompositeSchemaException;
void constraintDrop( KernelStatement state, ConstraintDescriptor constraint ) throws DropConstraintFailureException;
}
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java
index 7fc7f448190e4..72741d70de3b5 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java
@@ -59,11 +59,11 @@
import org.neo4j.kernel.api.exceptions.schema.DropConstraintFailureException;
import org.neo4j.kernel.api.exceptions.schema.DropIndexFailureException;
import org.neo4j.kernel.api.exceptions.schema.IllegalTokenNameException;
+import org.neo4j.kernel.api.exceptions.schema.RepeatedPropertyInCompositeSchemaException;
import org.neo4j.kernel.api.exceptions.schema.SchemaRuleNotFoundException;
import org.neo4j.kernel.api.exceptions.schema.TooManyLabelsException;
import org.neo4j.kernel.api.index.InternalIndexState;
import org.neo4j.kernel.api.schema.NodeMultiPropertyDescriptor;
-import org.neo4j.kernel.api.schema.NodePropertyDescriptor;
import org.neo4j.kernel.api.schema.RelationshipPropertyDescriptor;
import org.neo4j.kernel.api.schema_new.LabelSchemaDescriptor;
import org.neo4j.kernel.api.schema_new.SchemaDescriptorFactory;
@@ -429,7 +429,7 @@ public IndexDefinition createIndexDefinition( Label label, String... propertyKey
statement.schemaWriteOperations().indexCreate( descriptor );
return indexDefinition;
}
- catch ( AlreadyIndexedException | AlreadyConstrainedException e )
+ catch ( AlreadyIndexedException | AlreadyConstrainedException | RepeatedPropertyInCompositeSchemaException e )
{
throw new ConstraintViolationException(
e.getUserMessage( new StatementTokenNameLookup( statement.readOperations() ) ), e );
@@ -490,7 +490,8 @@ public ConstraintDefinition createPropertyUniquenessConstraint( IndexDefinition
SchemaDescriptorFactory.forLabel( labelId, propertyKeyIds ) );
return new UniquenessConstraintDefinition( this, indexDefinition );
}
- catch ( AlreadyConstrainedException | CreateConstraintFailureException | AlreadyIndexedException e )
+ catch ( AlreadyConstrainedException | CreateConstraintFailureException | AlreadyIndexedException |
+ RepeatedPropertyInCompositeSchemaException e )
{
throw new ConstraintViolationException(
e.getUserMessage( new StatementTokenNameLookup( statement.readOperations() ) ), e );
@@ -524,7 +525,8 @@ public ConstraintDefinition createPropertyExistenceConstraint( Label label, Stri
SchemaDescriptorFactory.forLabel( labelId, propertyKeyIds ) );
return new NodePropertyExistenceConstraintDefinition( this, label, propertyKeys );
}
- catch ( AlreadyConstrainedException | CreateConstraintFailureException e )
+ catch ( AlreadyConstrainedException | CreateConstraintFailureException |
+ RepeatedPropertyInCompositeSchemaException e )
{
throw new ConstraintViolationException(
e.getUserMessage( new StatementTokenNameLookup( statement.readOperations() ) ), e );
@@ -558,7 +560,8 @@ public ConstraintDefinition createPropertyExistenceConstraint( RelationshipType
SchemaDescriptorFactory.forRelType( typeId, propertyKeyId ) );
return new RelationshipPropertyExistenceConstraintDefinition( this, type, propertyKey );
}
- catch ( AlreadyConstrainedException | CreateConstraintFailureException e )
+ catch ( AlreadyConstrainedException | CreateConstraintFailureException |
+ RepeatedPropertyInCompositeSchemaException e )
{
throw new ConstraintViolationException(
e.getUserMessage( new StatementTokenNameLookup( statement.readOperations() ) ), e );
diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperationsTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperationsTest.java
index 36592278fb019..97f09f173609e 100644
--- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperationsTest.java
+++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperationsTest.java
@@ -19,6 +19,7 @@
*/
package org.neo4j.kernel.impl.api;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -27,7 +28,7 @@
import java.util.Iterator;
-import org.neo4j.kernel.api.schema.NodePropertyDescriptor;
+import org.neo4j.kernel.api.exceptions.schema.RepeatedPropertyInCompositeSchemaException;
import org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException;
import org.neo4j.kernel.api.exceptions.schema.AlreadyIndexedException;
import org.neo4j.kernel.api.exceptions.schema.DropIndexFailureException;
@@ -63,21 +64,30 @@ public class DataIntegrityValidatingStatementOperationsTest
LabelSchemaDescriptor descriptor = SchemaDescriptorFactory.forLabel( 0, 7 );
NewIndexDescriptor index = NewIndexDescriptorFactory.forLabel( 0, 7 );
NewIndexDescriptor uniqueIndex = NewIndexDescriptorFactory.uniqueForLabel( 0, 7 );
+ private SchemaReadOperations innerRead;
+ private SchemaWriteOperations innerWrite;
+ private KeyWriteOperations innerKeyWrite;
+ private DataIntegrityValidatingStatementOperations ops;
+
+ @Before
+ public void setup()
+ {
+ innerKeyWrite = mock( KeyWriteOperations.class );
+ innerRead = mock( SchemaReadOperations.class );
+ innerWrite = mock( SchemaWriteOperations.class );
+ ops = new DataIntegrityValidatingStatementOperations( innerKeyWrite, innerRead, innerWrite );
+ }
@Test
public void shouldDisallowReAddingIndex() throws Exception
{
// GIVEN
- SchemaReadOperations innerRead = mock( SchemaReadOperations.class );
- SchemaWriteOperations innerWrite = mock( SchemaWriteOperations.class );
- DataIntegrityValidatingStatementOperations ctx =
- new DataIntegrityValidatingStatementOperations( null, innerRead, innerWrite );
when( innerRead.indexGetForLabelAndPropertyKey( state, SchemaBoundary.map( descriptor ) ) ).thenReturn( index );
// WHEN
try
{
- ctx.indexCreate( state, descriptor );
+ ops.indexCreate( state, descriptor );
fail( "Should have thrown exception." );
}
catch ( AlreadyIndexedException e )
@@ -93,16 +103,12 @@ public void shouldDisallowReAddingIndex() throws Exception
public void shouldDisallowAddingIndexWhenConstraintIndexExists() throws Exception
{
// GIVEN
- SchemaReadOperations innerRead = mock( SchemaReadOperations.class );
- SchemaWriteOperations innerWrite = mock( SchemaWriteOperations.class );
- DataIntegrityValidatingStatementOperations ctx =
- new DataIntegrityValidatingStatementOperations( null, innerRead, innerWrite );
when( innerRead.indexGetForLabelAndPropertyKey( state, SchemaBoundary.map( descriptor ) ) ).thenReturn( uniqueIndex );
// WHEN
try
{
- ctx.indexCreate( state, descriptor );
+ ops.indexCreate( state, descriptor );
fail( "Should have thrown exception." );
}
catch ( AlreadyConstrainedException e )
@@ -118,16 +124,12 @@ public void shouldDisallowAddingIndexWhenConstraintIndexExists() throws Exceptio
public void shouldDisallowDroppingIndexThatDoesNotExist() throws Exception
{
// GIVEN
- SchemaReadOperations innerRead = mock( SchemaReadOperations.class );
- SchemaWriteOperations innerWrite = mock( SchemaWriteOperations.class );
- DataIntegrityValidatingStatementOperations ctx =
- new DataIntegrityValidatingStatementOperations( null, innerRead, innerWrite );
when( innerRead.indexGetForLabelAndPropertyKey( state, SchemaBoundary.map( descriptor ) ) ).thenReturn( null );
// WHEN
try
{
- ctx.indexDrop( state, index );
+ ops.indexDrop( state, index );
fail( "Should have thrown exception." );
}
catch ( DropIndexFailureException e )
@@ -143,16 +145,12 @@ public void shouldDisallowDroppingIndexThatDoesNotExist() throws Exception
public void shouldDisallowDroppingIndexWhenConstraintIndexExists() throws Exception
{
// GIVEN
- SchemaReadOperations innerRead = mock( SchemaReadOperations.class );
- SchemaWriteOperations innerWrite = mock( SchemaWriteOperations.class );
- DataIntegrityValidatingStatementOperations ctx =
- new DataIntegrityValidatingStatementOperations( null, innerRead, innerWrite );
when( innerRead.indexGetForLabelAndPropertyKey( state, SchemaBoundary.map( descriptor ) ) ).thenReturn( uniqueIndex );
// WHEN
try
{
- ctx.indexDrop( state, index );
+ ops.indexDrop( state, index );
fail( "Should have thrown exception." );
}
catch ( DropIndexFailureException e )
@@ -168,16 +166,12 @@ public void shouldDisallowDroppingIndexWhenConstraintIndexExists() throws Except
public void shouldDisallowDroppingConstraintIndexThatDoesNotExists() throws Exception
{
// GIVEN
- SchemaReadOperations innerRead = mock( SchemaReadOperations.class );
- SchemaWriteOperations innerWrite = mock( SchemaWriteOperations.class );
- DataIntegrityValidatingStatementOperations ctx =
- new DataIntegrityValidatingStatementOperations( null, innerRead, innerWrite );
when( innerRead.indexGetForLabelAndPropertyKey( state, SchemaBoundary.map( descriptor ) ) ).thenReturn( uniqueIndex );
// WHEN
try
{
- ctx.indexDrop( state, index );
+ ops.indexDrop( state, index );
fail( "Should have thrown exception." );
}
catch ( DropIndexFailureException e )
@@ -193,16 +187,12 @@ public void shouldDisallowDroppingConstraintIndexThatDoesNotExists() throws Exce
public void shouldDisallowDroppingConstraintIndexThatIsReallyJustRegularIndex() throws Exception
{
// GIVEN
- SchemaReadOperations innerRead = mock( SchemaReadOperations.class );
- SchemaWriteOperations innerWrite = mock( SchemaWriteOperations.class );
- DataIntegrityValidatingStatementOperations ctx =
- new DataIntegrityValidatingStatementOperations( null, innerRead, innerWrite );
when( innerRead.indexGetForLabelAndPropertyKey( state, SchemaBoundary.map( descriptor ) ) ).thenReturn( uniqueIndex );
// WHEN
try
{
- ctx.indexDrop( state, index );
+ ops.indexDrop( state, index );
fail( "Should have thrown exception." );
}
catch ( DropIndexFailureException e )
@@ -217,13 +207,9 @@ public void shouldDisallowDroppingConstraintIndexThatIsReallyJustRegularIndex()
@Test
public void shouldDisallowNullOrEmptyPropertyKey() throws Exception
{
- KeyWriteOperations inner = mock( KeyWriteOperations.class );
- DataIntegrityValidatingStatementOperations ctx =
- new DataIntegrityValidatingStatementOperations( inner, null, null );
-
try
{
- ctx.propertyKeyGetOrCreateForName( state, null );
+ ops.propertyKeyGetOrCreateForName( state, null );
fail( "Should not be able to create null property key" );
}
catch ( IllegalTokenNameException e )
@@ -232,7 +218,7 @@ public void shouldDisallowNullOrEmptyPropertyKey() throws Exception
try
{
- ctx.propertyKeyGetOrCreateForName( state, "" );
+ ops.propertyKeyGetOrCreateForName( state, "" );
fail( "Should not be able to create empty property key" );
}
catch ( IllegalTokenNameException e )
@@ -243,13 +229,9 @@ public void shouldDisallowNullOrEmptyPropertyKey() throws Exception
@Test
public void shouldDisallowNullOrEmptyLabelName() throws Exception
{
- KeyWriteOperations inner = mock( KeyWriteOperations.class );
- DataIntegrityValidatingStatementOperations ctx =
- new DataIntegrityValidatingStatementOperations( inner, null, null );
-
try
{
- ctx.labelGetOrCreateForName( state, null );
+ ops.labelGetOrCreateForName( state, null );
fail( "Should not be able to create null label" );
}
catch ( IllegalTokenNameException e )
@@ -258,7 +240,7 @@ public void shouldDisallowNullOrEmptyLabelName() throws Exception
try
{
- ctx.labelGetOrCreateForName( state, "" );
+ ops.labelGetOrCreateForName( state, "" );
fail( "Should not be able to create empty label" );
}
catch ( IllegalTokenNameException e )
@@ -269,23 +251,37 @@ public void shouldDisallowNullOrEmptyLabelName() throws Exception
@Test( expected = SchemaKernelException.class )
public void shouldFailInvalidLabelNames() throws Exception
{
- // Given
- DataIntegrityValidatingStatementOperations ctx =
- new DataIntegrityValidatingStatementOperations( null, null, null );
-
- // When
- ctx.labelGetOrCreateForName( state, "" );
+ ops.labelGetOrCreateForName( state, "" );
}
@Test( expected = SchemaKernelException.class )
public void shouldFailOnNullLabel() throws Exception
{
- // Given
- DataIntegrityValidatingStatementOperations ctx =
- new DataIntegrityValidatingStatementOperations( null, null, null );
+ ops.labelGetOrCreateForName( state, null );
+ }
- // When
- ctx.labelGetOrCreateForName( state, null );
+ @Test( expected = RepeatedPropertyInCompositeSchemaException.class )
+ public void shouldFailIndexCreateOnRepeatedPropertyId() throws Exception
+ {
+ ops.indexCreate( state, SchemaDescriptorFactory.forLabel( 0, 1, 1 ) );
+ }
+
+ @Test( expected = RepeatedPropertyInCompositeSchemaException.class )
+ public void shouldFailNodeExistenceCreateOnRepeatedPropertyId() throws Exception
+ {
+ ops.nodePropertyExistenceConstraintCreate( state, SchemaDescriptorFactory.forLabel( 0, 1, 1 ) );
+ }
+
+ @Test( expected = RepeatedPropertyInCompositeSchemaException.class )
+ public void shouldFailRelExistenceCreateOnRepeatedPropertyId() throws Exception
+ {
+ ops.relationshipPropertyExistenceConstraintCreate( state, SchemaDescriptorFactory.forRelType( 0, 1, 1 ) );
+ }
+
+ @Test( expected = RepeatedPropertyInCompositeSchemaException.class )
+ public void shouldFailUniquenessCreateOnRepeatedPropertyId() throws Exception
+ {
+ ops.uniquePropertyConstraintCreate( state, SchemaDescriptorFactory.forLabel( 0, 1, 1 ) );
}
@SafeVarargs