public boolean transitionToCanceled()
    {
        cleanupQueryQuietly();
        queryStateTimer.endQuery();

        // NOTE: The failure cause must be set before triggering the state change, so
        // listeners can observe the exception. This is safe because the failure cause
        // can only be observed if the transition to FAILED is successful.
        failureCause.compareAndSet(null, toFailure(new PrestoException(USER_CANCELED, "Query was canceled")));

        boolean canceled = queryState.setIf(QueryState.FAILED, currentState -> !currentState.isDone());
        if (canceled) {
            // if the transaction is already gone, do nothing
            session.getTransactionId().flatMap(transactionManager::getOptionalTransactionInfo).ifPresent(transaction -> {
                if (transaction.isAutoCommitContext()) {
                    transactionManager.asyncAbort(transaction.getTransactionId());
                }
                else {
                    transactionManager.fail(transaction.getTransactionId());
                }
            });
        }

        return canceled;
    }
@Test
    public void testCanceled()
    {
        QueryStateMachine stateMachine = createQueryStateMachine();
        assertTrue(stateMachine.transitionToCanceled());
        assertFinalState(stateMachine, FAILED, new PrestoException(USER_CANCELED, "canceled"));
    }