You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ma...@apache.org on 2013/05/06 21:04:50 UTC

git commit: add support for bind variables to non-prepared statements.

Updated Branches:
  refs/heads/trunk 3c06ff0a8 -> df723af8a


add support for bind variables to non-prepared statements.

patch by marcuse, reviewed by pcmanus for CASSANDRA-5349


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/df723af8
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/df723af8
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/df723af8

Branch: refs/heads/trunk
Commit: df723af8a6c04536abd2b4a48cd101f3b2e96746
Parents: 3c06ff0
Author: Marcus Eriksson <ma...@spotify.com>
Authored: Mon May 6 21:03:26 2013 +0200
Committer: Marcus Eriksson <ma...@spotify.com>
Committed: Mon May 6 21:03:26 2013 +0200

----------------------------------------------------------------------
 doc/native_protocol_v2.spec                        |   16 +++++-
 .../org/apache/cassandra/cql3/QueryProcessor.java  |   12 +++-
 .../apache/cassandra/transport/SimpleClient.java   |    7 ++
 .../cassandra/transport/messages/QueryMessage.java |   44 +++++++++++++--
 4 files changed, 68 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/df723af8/doc/native_protocol_v2.spec
----------------------------------------------------------------------
diff --git a/doc/native_protocol_v2.spec b/doc/native_protocol_v2.spec
index ad14929..a765700 100644
--- a/doc/native_protocol_v2.spec
+++ b/doc/native_protocol_v2.spec
@@ -263,8 +263,13 @@ Table of Contents
 
 4.1.4. QUERY
 
-  Performs a CQL query. The body of the message consists of a CQL query as a [long
-  string] followed by the [consistency] for the operation.
+  Performs a CQL query. The body of the message must be:
+    <query><consistency>[<n><value_1>...<value_n>]
+  where:
+    - <query> the query, [long string].
+    - <consistency> is the [consistency] level for the operation.
+    - optional: <n> [short], the number of following values.
+    - optional: <value_1>...<value_n> are [bytes] to use for bound variables in the query.
 
   Note that the consistency is ignored by some queries (USE, CREATE, ALTER,
   TRUNCATE, ...).
@@ -638,3 +643,10 @@ Table of Contents
               executed if the provide prepared statement ID is not known by
               this host. The rest of the ERROR message body will be [short
               bytes] representing the unknown ID.
+
+8. Changes from v1
+  * Protocol is versioned to allow old client connects to a newer server, if a newer
+    client connects to an older server, it needs to check if it gets a
+    ProtocolException on connection and try connecting with a lower version.
+  * A query can now have bind variables even though the statement is not
+    prepared. (see Section 4.1.4)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/df723af8/src/java/org/apache/cassandra/cql3/QueryProcessor.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/QueryProcessor.java b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
index 61b0b50..f7aebff 100644
--- a/src/java/org/apache/cassandra/cql3/QueryProcessor.java
+++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
@@ -134,11 +134,17 @@ public class QueryProcessor
     public static ResultMessage process(String queryString, ConsistencyLevel cl, QueryState queryState)
     throws RequestExecutionException, RequestValidationException
     {
+        return process(queryString, Collections.<ByteBuffer>emptyList(), cl, queryState);
+    }
+
+    public static ResultMessage process(String queryString, List<ByteBuffer> variables, ConsistencyLevel cl, QueryState queryState)
+    throws RequestExecutionException, RequestValidationException
+    {
         logger.trace("CQL QUERY: {}", queryString);
         CQLStatement prepared = getStatement(queryString, queryState.getClientState()).statement;
-        if (prepared.getBoundsTerms() > 0)
-            throw new InvalidRequestException("Cannot execute query with bind variables");
-        return processStatement(prepared, cl, queryState, Collections.<ByteBuffer>emptyList());
+        if (prepared.getBoundsTerms() != variables.size())
+            throw new InvalidRequestException("Invalid amount of bind variables");
+        return processStatement(prepared, cl, queryState, variables);
     }
 
     public static UntypedResultSet process(String query, ConsistencyLevel cl) throws RequestExecutionException

http://git-wip-us.apache.org/repos/asf/cassandra/blob/df723af8/src/java/org/apache/cassandra/transport/SimpleClient.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/transport/SimpleClient.java b/src/java/org/apache/cassandra/transport/SimpleClient.java
index 4caac61..993a490 100644
--- a/src/java/org/apache/cassandra/transport/SimpleClient.java
+++ b/src/java/org/apache/cassandra/transport/SimpleClient.java
@@ -154,6 +154,13 @@ public class SimpleClient
         return (ResultMessage)msg;
     }
 
+    public ResultMessage execute(String query, List<ByteBuffer> values, ConsistencyLevel consistencyLevel)
+    {
+        Message.Response msg = execute(new QueryMessage(query, values, consistencyLevel));
+        assert msg instanceof ResultMessage;
+        return (ResultMessage)msg;
+    }
+
     public ResultMessage.Prepared prepare(String query)
     {
         Message.Response msg = execute(new PrepareMessage(query));

http://git-wip-us.apache.org/repos/asf/cassandra/blob/df723af8/src/java/org/apache/cassandra/transport/messages/QueryMessage.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/transport/messages/QueryMessage.java b/src/java/org/apache/cassandra/transport/messages/QueryMessage.java
index 69c6529..9aa7e49 100644
--- a/src/java/org/apache/cassandra/transport/messages/QueryMessage.java
+++ b/src/java/org/apache/cassandra/transport/messages/QueryMessage.java
@@ -17,8 +17,11 @@
  */
 package org.apache.cassandra.transport.messages;
 
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.UUID;
-
 import com.google.common.collect.ImmutableMap;
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.jboss.netty.buffer.ChannelBuffers;
@@ -42,24 +45,53 @@ public class QueryMessage extends Message.Request
         {
             String query = CBUtil.readLongString(body);
             ConsistencyLevel consistency = CBUtil.readConsistencyLevel(body);
-            return new QueryMessage(query, consistency);
+            List<ByteBuffer> values = new ArrayList<ByteBuffer>();
+            if (body.readable())
+            {
+                int paramCount = body.readUnsignedShort();
+                for (int i = 0; i < paramCount; i++)
+                     values.add(CBUtil.readValue(body));
+            }
+            return new QueryMessage(query, values, consistency);
         }
 
         public ChannelBuffer encode(QueryMessage msg)
         {
-
-            return ChannelBuffers.wrappedBuffer(CBUtil.longStringToCB(msg.query), CBUtil.consistencyLevelToCB(msg.consistency));
+            // We have:
+            //   - query
+            //   - options
+            //     * optional:
+            //   - Number of values
+            //   - The values
+            int vs = msg.values.size();
+            CBUtil.BufferBuilder builder = new CBUtil.BufferBuilder(3, 0, vs);
+            builder.add(CBUtil.longStringToCB(msg.query));
+            builder.add(CBUtil.consistencyLevelToCB(msg.consistency));
+            if (vs > 0 && msg.getVersion() > 1)
+            {
+                builder.add(CBUtil.shortToCB(vs));
+                for (ByteBuffer value : msg.values)
+                    builder.addValue(value);
+            }
+            return builder.build();
         }
     };
 
     public final String query;
     public final ConsistencyLevel consistency;
+    public final List<ByteBuffer> values;
 
     public QueryMessage(String query, ConsistencyLevel consistency)
     {
-        super(Message.Type.QUERY);
+        this(query, Collections.<ByteBuffer>emptyList(), consistency);
+    }
+
+    public QueryMessage(String query, List<ByteBuffer> values, ConsistencyLevel consistency)
+    {
+        super(Type.QUERY);
         this.query = query;
         this.consistency = consistency;
+        this.values = values;
     }
 
     public ChannelBuffer encode()
@@ -84,7 +116,7 @@ public class QueryMessage extends Message.Request
                 Tracing.instance().begin("Execute CQL3 query", ImmutableMap.of("query", query));
             }
 
-            Message.Response response = QueryProcessor.process(query, consistency, state);
+            Message.Response response = QueryProcessor.process(query, values, consistency, state);
 
             if (tracingId != null)
                 response.setTracingId(tracingId);