You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by jb...@apache.org on 2011/07/19 18:14:45 UTC

svn commit: r1148425 - in /cassandra/branches/cassandra-0.8: ./ src/java/org/apache/cassandra/cql/ test/system/

Author: jbellis
Date: Tue Jul 19 16:14:44 2011
New Revision: 1148425

URL: http://svn.apache.org/viewvc?rev=1148425&view=rev
Log:
CQL: include only one row per unique keyfor IN queries
patch by Jim Ancona; reviewed by pyaskevich for CASSANDRA-2717

Modified:
    cassandra/branches/cassandra-0.8/CHANGES.txt
    cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Cql.g
    cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java
    cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/SelectStatement.java
    cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Term.java
    cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/WhereClause.java
    cassandra/branches/cassandra-0.8/test/system/test_cql.py

Modified: cassandra/branches/cassandra-0.8/CHANGES.txt
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/CHANGES.txt?rev=1148425&r1=1148424&r2=1148425&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/CHANGES.txt (original)
+++ cassandra/branches/cassandra-0.8/CHANGES.txt Tue Jul 19 16:14:44 2011
@@ -32,6 +32,8 @@
  * fix updating KS with durable_writes=false (CASSANDRA-2907)
  * add simplified facade to SSTableWriter for bulk loading use
    (CASSANDRA-2911)
+ * CQL: include only one row per unique key for IN queries
+   (CASSANDRA-2717)
 
 
 0.8.1

Modified: cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Cql.g
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Cql.g?rev=1148425&r1=1148424&r2=1148425&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Cql.g (original)
+++ cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Cql.g Tue Jul 19 16:14:44 2011
@@ -188,7 +188,7 @@ whereClause returns [WhereClause clause]
       | key_alias=term { inClause.setKeyAlias(key_alias.getText()); }
            K_IN '(' f1=term { inClause.andKeyEquals(f1); }
                   (',' fN=term { inClause.andKeyEquals(fN); } )* ')'
-        { $clause = inClause; }
+        { inClause.setMultiKey(true); $clause = inClause; }
     ;
 
 /**

Modified: cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java?rev=1148425&r1=1148424&r2=1148425&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java (original)
+++ cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java Tue Jul 19 16:14:44 2011
@@ -334,6 +334,10 @@ public class QueryProcessor
         if (select.isKeyRange() && (select.getKeyFinish() != null) && (select.getColumnRelations().size() > 0))
             throw new InvalidRequestException("You cannot combine key range and by-column clauses in a SELECT");
         
+        // Can't use more than one KEY =
+        if (!select.isMultiKey() && select.getKeys().size() > 1)
+            throw new InvalidRequestException("You cannot use more than one KEY = in a SELECT");
+
         AbstractType<?> comparator = select.getComparator(keyspace);
         
         if (select.getColumnRelations().size() > 0)

Modified: cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/SelectStatement.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/SelectStatement.java?rev=1148425&r1=1148424&r2=1148425&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/SelectStatement.java (original)
+++ cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/SelectStatement.java Tue Jul 19 16:14:44 2011
@@ -22,6 +22,7 @@ package org.apache.cassandra.cql;
 
 import java.nio.ByteBuffer;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.DatabaseDescriptor;
@@ -58,7 +59,7 @@ public class SelectStatement
         return clause.isKeyRange();
     }
     
-    public List<Term> getKeys()
+    public Set<Term> getKeys()
     {
         return clause.getKeys();
     }
@@ -148,6 +149,11 @@ public class SelectStatement
         return clause.getKeyAlias();
     }
 
+    public boolean isMultiKey()
+    {
+        return clause.isMultiKey();
+    }
+
     public void extractKeyAliasFromColumns(CFMetaData cfm)
     {
         clause.extractKeysFromColumns(cfm);
@@ -162,4 +168,5 @@ public class SelectStatement
     {
         return DatabaseDescriptor.getValueValidator(keyspace, columnFamily, column);
     }
+
 }

Modified: cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Term.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Term.java?rev=1148425&r1=1148424&r2=1148425&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Term.java (original)
+++ cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Term.java Tue Jul 19 16:14:44 2011
@@ -130,6 +130,38 @@ public class Term
     {
         return String.format("Term(%s, type=%s)", getText(), type);
     }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((text == null) ? 0 : text.hashCode());
+        result = prime * result + ((type == null) ? 0 : type.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Term other = (Term) obj;
+        if (text == null)
+        {
+            if (other.text != null)
+                return false;
+        } else if (!text.equals(other.text))
+            return false;
+        if (type != other.type)
+            return false;
+        return true;
+    }
+
     
 }
 

Modified: cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/WhereClause.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/WhereClause.java?rev=1148425&r1=1148424&r2=1148425&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/WhereClause.java (original)
+++ cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/WhereClause.java Tue Jul 19 16:14:44 2011
@@ -22,15 +22,14 @@ package org.apache.cassandra.cql;
 
 
 import org.apache.cassandra.config.CFMetaData;
-import org.apache.cassandra.db.marshal.AbstractType;
-import org.apache.cassandra.thrift.InvalidRequestException;
-import org.apache.cassandra.thrift.ThriftValidation;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * WhereClauses encapsulate all of the predicates of a SELECT query.
@@ -39,10 +38,10 @@ import java.util.List;
 public class WhereClause
 {
     // added to either by the parser, e.g. from an IN clause, or by extractKeysFromColumns
-    private List<Term> keys = new ArrayList<Term>();
+    private Set<Term> keys = new LinkedHashSet<Term>();
     private Term startKey, finishKey;
     private List<Relation> columns = new ArrayList<Relation>();
-    private boolean includeStartKey = false, includeFinishKey = false;
+    private boolean includeStartKey = false, includeFinishKey = false, multiKey = false;
     // set by extractKeysFromColumns
     private String keyAlias = null;
 
@@ -117,7 +116,7 @@ public class WhereClause
         return finishKey;
     }
     
-    public List<Term> getKeys()
+    public Set<Term> getKeys()
     {
         return keys;
     }
@@ -137,6 +136,15 @@ public class WhereClause
         keyAlias = alias.toUpperCase();
     }
 
+    public boolean isMultiKey() {
+        return multiKey;
+    }
+
+    public void setMultiKey(boolean multiKey)
+    {
+        this.multiKey = multiKey;
+    }
+
     public String getKeyAlias()
     {
         // TODO fix special casing here, key alias should always be set post-extract

Modified: cassandra/branches/cassandra-0.8/test/system/test_cql.py
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/test/system/test_cql.py?rev=1148425&r1=1148424&r2=1148425&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/test/system/test_cql.py (original)
+++ cassandra/branches/cassandra-0.8/test/system/test_cql.py Tue Jul 19 16:14:44 2011
@@ -881,6 +881,19 @@ class TestCql(ThriftTester):
             assert r[2] == "p4ssw0rd", \
                    "unrecognized value '%s'" % r[1]
 
+        # select with same KEY AND'ed (see CASSANDRA-2717)
+        cursor.execute("SELECT * FROM StandardString1 WHERE KEY = 'mUser1' AND KEY = 'mUser1'")
+        assert cursor.rowcount == 1, "expected 1 result, got %d" % cursor.rowcount
+
+        # select with different KEYs AND'ed
+        assert_raises(cql.ProgrammingError,
+                      cursor.execute,
+                      "SELECT * FROM StandardString1 WHERE KEY = 'mUser1' AND KEY = 'mUser2'")
+
+        # select with same KEY repeated in IN
+        cursor.execute("SELECT * FROM StandardString1 WHERE KEY IN ('mUser1', 'mUser1')")
+        assert cursor.rowcount == 1, "expected 1 result, got %d" % cursor.rowcount
+
     def test_insert_with_timestamp_and_ttl(self):
         "insert statement should support setting timestamp"
         cursor = init()