use of org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException in project neo4j by neo4j.
the class UniquenessConstraintValidationIT method shouldEnforceOnSetProperty.
@Test
void shouldEnforceOnSetProperty() throws Exception {
// given
constrainedNode("Label1", "key1", "value1");
KernelTransaction transaction = newTransaction(AnonymousContext.writeToken());
// when
long node = createLabeledNode(transaction, "Label1");
try {
int propertyKeyId = transaction.tokenWrite().propertyKeyGetOrCreateForName("key1");
transaction.dataWrite().nodeSetProperty(node, propertyKeyId, Values.of("value1"));
fail("should have thrown exception");
}// then
catch (UniquePropertyValueValidationException e) {
assertThat(e.getUserMessage(transaction.tokenRead())).contains("`key1` = 'value1'");
}
commit();
}
use of org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException in project neo4j by neo4j.
the class ConstraintIndexCreatorTest method shouldDropIndexIfPopulationFails.
@Test
void shouldDropIndexIfPopulationFails() throws Exception {
// given
IndexingService indexingService = mock(IndexingService.class);
IndexProxy indexProxy = mock(IndexProxy.class);
when(indexingService.getIndexProxy(index)).thenReturn(indexProxy);
when(indexProxy.getDescriptor()).thenReturn(index);
when(schemaRead.indexGetForName(constraint.getName())).thenReturn(IndexDescriptor.NO_INDEX, index);
IndexEntryConflictException cause = new IndexEntryConflictException(2, 1, Values.of("a"));
doThrow(new IndexPopulationFailedKernelException("some index", cause)).when(indexProxy).awaitStoreScanCompleted(anyLong(), any());
when(schemaRead.index(any(SchemaDescriptor.class))).thenReturn(// first claim it doesn't exist, because it doesn't... so
Iterators.emptyResourceIterator()).thenReturn(// then after it failed claim it does exist
Iterators.iterator(index));
ConstraintIndexCreator creator = new ConstraintIndexCreator(() -> kernel, indexingService, logProvider);
// when
KernelTransactionImplementation transaction = createTransaction();
UniquePropertyValueValidationException exception = assertThrows(UniquePropertyValueValidationException.class, () -> creator.createUniquenessConstraintIndex(transaction, constraint, prototype));
assertEquals("Existing data does not satisfy Constraint( name='constraint', type='UNIQUENESS', schema=(:Label {prop}) ): " + "Both node 2 and node 1 share the property value ( String(\"a\") )", exception.getMessage());
assertEquals(2, kernel.transactions.size());
KernelTransactionImplementation tx1 = kernel.transactions.get(0);
verify(tx1).indexUniqueCreate(prototype);
verify(schemaRead, times(2)).indexGetForName(constraint.getName());
verifyNoMoreInteractions(schemaRead);
KernelTransactionImplementation kti2 = kernel.transactions.get(1);
verify(kti2).addIndexDoDropToTxState(index);
}
use of org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException in project neo4j by neo4j.
the class StateHandlingStatementOperations method uniquePropertyConstraintCreate.
@Override
public UniquenessConstraintDescriptor uniquePropertyConstraintCreate(KernelStatement state, LabelSchemaDescriptor descriptor) throws CreateConstraintFailureException {
UniquenessConstraintDescriptor constraint = ConstraintDescriptorFactory.uniqueForSchema(descriptor);
try {
if (state.hasTxStateWithChanges() && // ..., DROP, *CREATE*
state.txState().indexDoUnRemove(constraint.ownedIndexDescriptor())) {
// creation is undoing a drop
if (// CREATE, ..., DROP, *CREATE*
!state.txState().constraintDoUnRemove(constraint)) {
// ... the drop we are undoing did itself undo a prior create...
state.txState().constraintDoAdd(constraint, state.txState().indexCreatedForConstraint(constraint));
}
} else // *CREATE*
{
// create from scratch
Iterator<ConstraintDescriptor> it = storeLayer.constraintsGetForSchema(descriptor);
while (it.hasNext()) {
if (it.next().equals(constraint)) {
return constraint;
}
}
long indexId = constraintIndexCreator.createUniquenessConstraintIndex(state, this, descriptor);
state.txState().constraintDoAdd(constraint, indexId);
}
return constraint;
} catch (UniquePropertyValueValidationException | DropIndexFailureException | TransactionFailureException e) {
throw new CreateConstraintFailureException(constraint, e);
}
}
use of org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException in project neo4j by neo4j.
the class ConstraintIndexCreator method createUniquenessConstraintIndex.
/**
* You MUST hold a schema write lock before you call this method.
* However the schema write lock is temporarily released while populating the index backing the constraint.
* It goes a little like this:
* <ol>
* <li>Prerequisite: Getting here means that there's an open schema transaction which has acquired the
* SCHEMA WRITE lock.</li>
* <li>Index schema rule which is backing the constraint is created in a nested mini-transaction
* which doesn't acquire any locking, merely adds tx state and commits so that the index rule is applied
* to the store, which triggers the index population</li>
* <li>Release the SCHEMA WRITE lock</li>
* <li>Await index population to complete</li>
* <li>Acquire the SCHEMA WRITE lock (effectively blocking concurrent transactions changing
* data related to this constraint, and it so happens, most other transactions as well) and verify
* the uniqueness of the built index</li>
* <li>Leave this method, knowing that the uniqueness constraint rule will be added to tx state
* and this tx committed, which will create the uniqueness constraint</li>
* </ol>
*/
public long createUniquenessConstraintIndex(KernelStatement state, SchemaReadOperations schema, LabelSchemaDescriptor descriptor) throws TransactionFailureException, CreateConstraintFailureException, DropIndexFailureException, UniquePropertyValueValidationException {
UniquenessConstraintDescriptor constraint = ConstraintDescriptorFactory.uniqueForSchema(descriptor);
NewIndexDescriptor index = createConstraintIndex(descriptor);
boolean success = false;
boolean reacquiredSchemaLock = false;
Client locks = state.locks().pessimistic();
try {
long indexId = schema.indexGetCommittedId(state, index);
// Release the SCHEMA WRITE lock during index population.
// At this point the integrity of the constraint to be created was checked
// while holding the lock and the index rule backing the soon-to-be-created constraint
// has been created. Now it's just the population left, which can take a long time
releaseSchemaLock(locks);
awaitConstrainIndexPopulation(constraint, indexId);
// Index population was successful, but at this point we don't know if the uniqueness constraint holds.
// Acquire SCHEMA WRITE lock and verify the constraints here in this user transaction
// and if everything checks out then it will be held until after the constraint has been
// created and activated.
acquireSchemaLock(state, locks);
reacquiredSchemaLock = true;
indexingService.getIndexProxy(indexId).verifyDeferredConstraints(propertyAccessor);
success = true;
return indexId;
} catch (SchemaRuleNotFoundException | IndexNotFoundKernelException e) {
throw new IllegalStateException(String.format("Index (%s) that we just created does not exist.", descriptor));
} catch (IndexEntryConflictException e) {
throw new UniquePropertyValueValidationException(constraint, VERIFICATION, e);
} catch (InterruptedException | IOException e) {
throw new CreateConstraintFailureException(constraint, e);
} finally {
if (!success) {
if (!reacquiredSchemaLock) {
acquireSchemaLock(state, locks);
}
dropUniquenessConstraintIndex(index);
}
}
}
use of org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException in project neo4j by neo4j.
the class UniquenessConstraintValidationIT method shouldEnforceUniquenessConstraintOnAddLabelForNumberPropertyOnNodeNotFromTransaction.
@Test
void shouldEnforceUniquenessConstraintOnAddLabelForNumberPropertyOnNodeNotFromTransaction() throws Exception {
// given
constrainedNode("Label1", "key1", 1);
// when
KernelTransaction transaction = newTransaction(AnonymousContext.writeToken());
long node = createNode(transaction, "key1", 1);
commit();
transaction = newTransaction(AnonymousContext.writeToken());
try {
int label = transaction.tokenWrite().labelGetOrCreateForName("Label1");
transaction.dataWrite().nodeAddLabel(node, label);
fail("should have thrown exception");
}// then
catch (UniquePropertyValueValidationException e) {
assertThat(e.getUserMessage(transaction.tokenRead())).contains("`key1` = 1");
}
commit();
}
Aggregations