Author: jbellis
Date: Sat May  7 02:23:47 2011
New Revision: 1100432

URL: http://svn.apache.org/viewvc?rev=1100432&view=rev
Log:
simplify python cursor design and make fetchall actually work
patch by jbellis

Removed:
    cassandra/branches/cassandra-0.8/drivers/py/cql/results.py
Modified:
    cassandra/branches/cassandra-0.8/drivers/py/cql/cursor.py
    cassandra/branches/cassandra-0.8/drivers/py/cql/decoders.py
    cassandra/branches/cassandra-0.8/test/system/test_cql.py

Modified: cassandra/branches/cassandra-0.8/drivers/py/cql/cursor.py
URL: 
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/drivers/py/cql/cursor.py?rev=1100432&r1=1100431&r2=1100432&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/drivers/py/cql/cursor.py (original)
+++ cassandra/branches/cassandra-0.8/drivers/py/cql/cursor.py Sat May  7 
02:23:47 2011
@@ -21,7 +21,6 @@ import zlib
 import cql
 from cql.marshal import prepare
 from cql.decoders import SchemaDecoder
-from cql.results import ResultSet
 from cql.cassandra.ttypes import (
     Compression, 
     CqlResultType, 
@@ -31,6 +30,8 @@ from cql.cassandra.ttypes import (
     TApplicationException,
     SchemaDisagreementException)
 
+_COUNT_DESCRIPTION = (None, None, None, None, None, None, None)
+
 class Cursor:
 
     _keyspace_re = re.compile("USE (\w+);?", re.I | re.M)
@@ -41,7 +42,6 @@ class Cursor:
         self.open_socket = True
         self.parent_connection = parent_connection
 
-        self.result = None      # Populate on execute()
         self.description = None # A list of 7-tuples: 
                                 #  (column_name, type_code, none, none,
                                 #   none, none, nulls_ok=True)
@@ -145,20 +145,18 @@ class Cursor:
             self.decoder.schema = self.__get_schema()
 
         if response.type == CqlResultType.ROWS:
-            self.result = ResultSet(response.rows,
-                                    self._query_ks,
-                                    self._query_cf,
-                                    self.decoder)
+            self.result = response.rows
             self.rs_idx = 0
             self.rowcount = len(self.result)
-            self.description = self.result.description
+            if self.result:
+                self.description = 
self.decoder.decode_description(self._query_ks, self._query_cf, self.result[0])
 
         if response.type == CqlResultType.INT:
             self.result = [(response.num,)]
             self.rs_idx = 0
             self.rowcount = 1
             # TODO: name could be the COUNT expression
-            self.description = (None, None, None, None, None, None, None)
+            self.description = _COUNT_DESCRIPTION
 
         # 'Return values are not defined.'
         return True
@@ -178,27 +176,28 @@ class Cursor:
 
     def fetchone(self):
         self.__checksock()
-        ret = self.result[self.rs_idx]
+        row = self.result[self.rs_idx]
         self.rs_idx += 1
-        self.description = getattr(self.result, 'description', 
self.description)
-        return ret
+        if self.description != _COUNT_DESCRIPTION:
+            self.description = self.decoder.decode_description(self._query_ks, 
self._query_cf, row)
+            return self.decoder.decode_row(self._query_ks, self._query_cf, row)
+        else:
+            return row
 
     def fetchmany(self, size=None):
         self.__checksock()
         if size is None:
             size = self.arraysize
-        end = self.rs_idx + size
-        ret = self.result[self.rs_idx:end]
-        self.rs_idx = end
-        self.description = getattr(self.result, 'description', 
self.description)
-        return ret
+        # we avoid leveraging fetchone here to avoid calling 
decode_description unnecessarily
+        L = []
+        while len(L) < size and self.rs_idx < len(self.result):
+            row = self.result[self.rs_idx]
+            self.rs_idx += 1
+            L.append(self.decoder.decode_row(self._query_ks, self._query_cf, 
row))
+        return L
 
     def fetchall(self):
-        self.__checksock()
-        ret = self.result[self.rs_idx:]
-        self.rs_idx = len(self.result)
-        self.description = self.result.description
-        return ret
+        return self.fetchmany(len(self.result) - self.rs_idx)
 
     ###
     # Iterator extension

Modified: cassandra/branches/cassandra-0.8/drivers/py/cql/decoders.py
URL: 
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/drivers/py/cql/decoders.py?rev=1100432&r1=1100431&r2=1100432&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/drivers/py/cql/decoders.py (original)
+++ cassandra/branches/cassandra-0.8/drivers/py/cql/decoders.py Sat May  7 
02:23:47 2011
@@ -50,20 +50,27 @@ class SchemaDecoder(object):
             return cfam["key_validation_class"]
         return None
 
-    def decode_row(self, keyspace, column_family, row):
+    def decode_description(self, keyspace, column_family, row):
         key_type = self.__keytype_for(keyspace, column_family)
-        key = unmarshallers.get(key_type, unmarshal_noop)(row.key)
         description = [(cql.ROW_KEY, key_type, None, None, None, None, None, 
False)]
+        comparator = self.__comparator_for(keyspace, column_family)
+        unmarshal = unmarshallers.get(comparator, unmarshal_noop)
+        for column in row.columns:
+            description.append((unmarshal(column.name), comparator, None, 
None, None, None, True))
 
+        return description
+
+    def decode_row(self, keyspace, column_family, row):
+        key_type = self.__keytype_for(keyspace, column_family)
+        key = unmarshallers.get(key_type, unmarshal_noop)(row.key)
         comparator = self.__comparator_for(keyspace, column_family)
         unmarshal = unmarshallers.get(comparator, unmarshal_noop)
         values = [key]
         for column in row.columns:
-            description.append((unmarshal(column.name), comparator, None, 
None, None, None, True))
             validator = self.__validator_for(keyspace, column_family, 
column.name)
             if column.value is None:
                 values.append(None)
             else:
                 values.append(unmarshallers.get(validator, 
unmarshal_noop)(column.value))
 
-        return description, values
+        return values

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=1100432&r1=1100431&r2=1100432&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/test/system/test_cql.py (original)
+++ cassandra/branches/cassandra-0.8/test/system/test_cql.py Sat May  7 
02:23:47 2011
@@ -125,7 +125,7 @@ def init(keyspace="Keyspace1"):
 
 class TestCql(ThriftTester):
     def test_select_simple(self):
-        "retrieve a column"
+        "single-row named column queries"
         cursor = init()
         cursor.execute("SELECT 'ca1' FROM StandardString1 WHERE KEY='ka'")
         r = cursor.fetchone()
@@ -137,10 +137,8 @@ class TestCql(ThriftTester):
         assert d[1][0] == 'ca1'
         assert r[1] == 'va1'
 
-    def test_select_columns(self):
-        "retrieve multiple columns"
-        cursor = init()
-        # we deliberately request columns in non-comparator order
+        # retrieve multiple columns
+        # (we deliberately request columns in non-comparator order)
         cursor.execute("""
             SELECT ca1, col, cd1 FROM StandardString1 WHERE KEY = 'kd'
         """)
@@ -157,12 +155,8 @@ class TestCql(ThriftTester):
         cursor.execute("""
             SELECT 4 FROM StandardLongA WHERE KEY > 'ad' AND KEY < 'ag';
         """)
-        keys = ['ad', 'ae', 'af']
-        assert cursor.rowcount == 4
-        for i in range(3):
-            r = cursor.fetchone()
-            assert len(r) == 2
-            assert r[0] == keys[i]
+        rows = [row[0] for row in cursor.fetchall()]
+        assert ['ad', 'ae', 'af', 'ag'] == rows, rows
 
     def test_select_row_range_with_limit(self):
         "retrieve a limited range of rows with columns"
@@ -183,9 +177,18 @@ class TestCql(ThriftTester):
             assert r[0] == "k%d" % (i+1)
 
     def test_select_columns_slice(self):
-        "range of columns (slice) by row"
+        "column slice tests"
         cursor = init()
 
+        # all columns
+        cursor.execute("SELECT * FROM StandardString1 WHERE KEY = 'ka';")
+        r = cursor.fetchone()
+        assert len(r) == 3
+        cursor.execute("SELECT ''..'' FROM StandardString1 WHERE KEY = 'ka';")
+        r = cursor.fetchone()
+        assert len(r) == 3
+
+        # column subsets
         cursor.execute("SELECT 1..3 FROM StandardLongA WHERE KEY = 'aa';")
         assert cursor.rowcount == 1
         r = cursor.fetchone()
@@ -193,7 +196,7 @@ class TestCql(ThriftTester):
         assert r[1] == "1"
         assert r[2] == "2"
         assert r[3] == "3"
-
+        
         cursor.execute("SELECT 10..30 FROM StandardIntegerA WHERE KEY='k1'")
         assert cursor.rowcount == 1
         r = cursor.fetchone()
@@ -202,19 +205,7 @@ class TestCql(ThriftTester):
         assert r[2] == "b"
         assert r[3] == "c"
 
-    def test_select_columns_slice_all(self):
-        "slice all columns in a row"
-        cursor = init()
-        cursor.execute("SELECT * FROM StandardString1 WHERE KEY = 'ka';")
-        r = cursor.fetchone()
-        assert len(r) == 3
-        cursor.execute("SELECT ''..'' FROM StandardString1 WHERE KEY = 'ka';")
-        r = cursor.fetchone()
-        assert len(r) == 3
-
-    def test_select_columns_slice_with_limit(self):
-        "range of columns (slice) by row with limit"
-        cursor = init()
+        # range of columns (slice) by row with FIRST
         cursor.execute("""
             SELECT FIRST 1 1..3 FROM StandardLongA WHERE KEY = 'aa';
         """)
@@ -224,6 +215,17 @@ class TestCql(ThriftTester):
         assert r[0] == "aa"
         assert r[1] == "1"
 
+        # range of columns (slice) by row reversed
+        cursor.execute("""
+            SELECT FIRST 2 REVERSED 3..1 FROM StandardLongA WHERE KEY = 'aa';
+        """)
+        assert cursor.rowcount == 1, "%d != 1" % cursor.rowcount
+        r = cursor.fetchone()
+        assert len(r) == 3
+        assert r[0] == 'aa'
+        assert r[1] == "3"
+        assert r[2] == "2"
+
     def test_select_range_with_single_column_results(self):
         "range should not fail when keys were not set"
         cursor = init()
@@ -253,19 +255,6 @@ class TestCql(ThriftTester):
         assert r[0] == "user3"
         assert r[1] == None
 
-    def test_select_columns_slice_reversed(self):
-        "range of columns (slice) by row reversed"
-        cursor= init()
-        cursor.execute("""
-            SELECT FIRST 2 REVERSED 3..1 FROM StandardLongA WHERE KEY = 'aa';
-        """)
-        assert cursor.rowcount == 1, "%d != 1" % cursor.rowcount
-        r = cursor.fetchone()
-        assert len(r) == 3
-        assert r[0] == 'aa'
-        assert r[1] == "3"
-        assert r[2] == "2"
-
     def test_error_on_multiple_key_by(self):
         "ensure multiple key-bys in where clause excepts"
         cursor = init()


Reply via email to