From ce8d932a467559fdcc75bafeda2bc4a183c480c0 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 28 Apr 2014 09:07:21 +0200 Subject: [PATCH] DATAREDIS-226 - Syntax exceptions using lettuce should be reported immediately. If running in transaction mode we now do a rudimentary check if the provided number of arguments matches the ones defined for the RedisCommand to execute. If the command passes this first check and causes an error on redis server one has to check results for Command.getOutput().hasError(). Original Pull Request: #66. --- .../connection/lettuce/LettuceConnection.java | 28 +++++++++++++++++-- .../data/redis/core/RedisCommand.java | 2 +- ...ConnectionTransactionIntegrationTests.java | 5 ---- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index 046b5cff2..9fb72fe7a 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -49,6 +49,7 @@ import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.connection.Subscription; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.convert.TransactionResultConverter; +import org.springframework.data.redis.core.RedisCommand; import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -294,18 +295,22 @@ public class LettuceConnection implements RedisConnection { try { String name = command.trim().toUpperCase(); CommandType cmd = CommandType.valueOf(name); - CommandArgs cmdArg = new CommandArgs(CODEC); + validateCommandIfRunningInTransactionMode(cmd, args); + + CommandArgs cmdArg = new CommandArgs(CODEC); if (!ObjectUtils.isEmpty(args)) { cmdArg.addKeys(args); } CommandOutput expectedOutput = commandOutputTypeHint != null ? commandOutputTypeHint : typeHints.getTypeHint(cmd); if (isPipelined()) { + pipeline(new LettuceResult(getAsyncConnection().dispatch(cmd, expectedOutput, cmdArg))); return null; } else if (isQueueing()) { - transaction(new LettuceResult(getAsyncConnection().dispatch(cmd, expectedOutput, cmdArg))); + + transaction(new LettuceTxResult(getAsyncConnection().dispatch(cmd, expectedOutput, cmdArg))); return null; } else { return await(getAsyncConnection().dispatch(cmd, expectedOutput, cmdArg)); @@ -3168,6 +3173,25 @@ public class LettuceConnection implements RedisConnection { return args; } + private void validateCommandIfRunningInTransactionMode(CommandType cmd, byte[]... args) { + + if (this.isQueueing()) { + validateCommand(cmd, args); + } + } + + private void validateCommand(CommandType cmd, byte[]... args) { + + RedisCommand redisCommand = RedisCommand.failsafeCommandLookup(cmd.name()); + if (!RedisCommand.UNKNOWN.equals(redisCommand) && redisCommand.requiresArguments()) { + try { + redisCommand.validateArgumentCount(args != null ? args.length : 0); + } catch (IllegalArgumentException e) { + throw new InvalidDataAccessApiUsageException(String.format("Validation failed for %s command.", cmd), e); + } + } + } + /** * {@link TypeHints} provide {@link CommandOutput} information for a given {@link CommandType}. * diff --git a/src/main/java/org/springframework/data/redis/core/RedisCommand.java b/src/main/java/org/springframework/data/redis/core/RedisCommand.java index be629b33e..4115bc8c5 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisCommand.java +++ b/src/main/java/org/springframework/data/redis/core/RedisCommand.java @@ -32,7 +32,7 @@ import org.springframework.util.StringUtils; * @see Redis command list: * https://github.com/antirez/redis/blob/93e7a130fc9594e41ccfc996b5eca7626ae5356a/src/redis.c#L119 */ -enum RedisCommand { +public enum RedisCommand { // -- A APPEND("rw", 2, 2), // AUTH("rw", 1, 1), // diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java index 56b460f69..e269d6006 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java @@ -19,7 +19,6 @@ import static org.junit.Assert.*; import java.util.Arrays; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.data.redis.connection.AbstractConnectionTransactionIntegrationTests; @@ -40,10 +39,6 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @ContextConfiguration("LettuceConnectionIntegrationTests-context.xml") public class LettuceConnectionTransactionIntegrationTests extends AbstractConnectionTransactionIntegrationTests { - @Test - @Ignore("DATAREDIS-226 Exceptions on native execute are swallowed in tx") - public void exceptionExecuteNative() throws Exception {} - @Test(expected = UnsupportedOperationException.class) @IfProfileValue(name = "redisVersion", value = "2.6") public void testSRandMemberCountNegative() {