2 new revisions:

Revision: d9a82df6eb8e
Author:   paul cannon <[email protected]>
Date:     Mon Mar 26 10:25:06 2012
Log:      Expose column name storage types...
http://code.google.com/a/apache-extras.org/p/cassandra-dbapi2/source/detail?r=d9a82df6eb8e

Revision: 96b873606e46
Author:   paul cannon <[email protected]>
Date:     Mon Mar 26 11:13:36 2012
Log:      add test for exposed colname types
http://code.google.com/a/apache-extras.org/p/cassandra-dbapi2/source/detail?r=96b873606e46

==============================================================================
Revision: d9a82df6eb8e
Author:   paul cannon <[email protected]>
Date:     Mon Mar 26 10:25:06 2012
Log:      Expose column name storage types

Since some clients need to know how a column name was deserialized,
and/or what the raw bytes were. This makes a change to the SchemaDecoder
interface, but unless clients are replacing SchemaDecoder wholesale,
it should be backwards-compatible.

As of now, the "storage type" so exposed will pretty much always be the
CF's comparator, except for columns corresponding to a row key, but
there isn't really any other way for a CQL client to inspect a
CF's comparator, and sometimes identifying the CF to be queried would
require parsing CQL.

http://code.google.com/a/apache-extras.org/p/cassandra-dbapi2/source/detail?r=d9a82df6eb8e

Modified:
 /cql/cursor.py
 /cql/decoders.py

=======================================
--- /cql/cursor.py      Tue Feb 28 15:33:03 2012
+++ /cql/cursor.py      Mon Mar 26 10:25:06 2012
@@ -22,8 +22,8 @@
 from cql.marshal import prepare_inline, prepare_query, PreparedQuery
 from cql.decoders import SchemaDecoder
 from cql.cassandra.ttypes import (
-    Compression,
-    CqlResultType,
+    Compression,
+    CqlResultType,
     InvalidRequestException,
     UnavailableException,
     TimedOutException,
@@ -43,15 +43,21 @@
     _ddl_re = re.compile("\s*(CREATE|ALTER|DROP)\s+",
                          re.IGNORECASE | re.MULTILINE)
     supports_prepared_queries = False
+    supports_name_info = True

     def __init__(self, parent_connection):
         self.open_socket = True
         self._connection = parent_connection

-        self.description = None # A list of 7-tuples:
-                                #  (column_name, type_code, none, none,
-                                #   none, none, nulls_ok=True)
-                                # Populate on execute()
+        # A list of 7-tuples corresponding to the column metadata for the
+        # current row (populated on execute() and on fetchone()):
+        #  (column_name, type_code, None, None, None, None, nulls_ok=True)
+        self.description = None
+
+        # A list of 2-tuples (name_bytes, type_code), corresponding to the
+        # raw bytes of the column names for each column in the current row,
+        # in order, and the types under which they can be deserialized
+        self.name_info = None

         self.arraysize = 1
         self.rowcount = -1      # Populate on execute()
@@ -101,6 +107,7 @@
         self.rs_idx = 0
         self.rowcount = 0
         self.description = None
+        self.name_info = None

     def execute(self, cql_query, params={}, decoder=None):
         self.pre_execution_setup()
@@ -142,18 +149,20 @@
             self.rs_idx = 0
             self.rowcount = len(self.result)
             if self.result:
- self.description = self.decoder.decode_description(self.result[0]) + self.description, self.name_info = self.decoder.decode_metadata(self.result[0])
         elif response.type == CqlResultType.INT:
             self.result = [(response.num,)]
             self.rs_idx = 0
             self.rowcount = 1
             # TODO: name could be the COUNT expression
             self.description = _COUNT_DESCRIPTION
+            self.name_info = None
         elif response.type == CqlResultType.VOID:
             self.result = []
             self.rs_idx = 0
             self.rowcount = 0
             self.description = _VOID_DESCRIPTION
+            self.name_info = ()
         else:
             raise Exception('unknown result type %s' % response.type)

@@ -180,17 +189,17 @@

         row = self.result[self.rs_idx]
         self.rs_idx += 1
-        if self.description == _COUNT_DESCRIPTION:
+        if self.description is _COUNT_DESCRIPTION:
             return row
         else:
-            self.description = self.decoder.decode_description(row)
+ self.description, self.name_info = self.decoder.decode_metadata(row)
             return self.decoder.decode_row(row)

     def fetchmany(self, size=None):
         self.__checksock()
         if size is None:
             size = self.arraysize
- # we avoid leveraging fetchone here to avoid calling decode_description unnecessarily + # we avoid leveraging fetchone here to avoid calling decode_metadata unnecessarily
         L = []
         while len(L) < size and self.rs_idx < len(self.result):
             row = self.result[self.rs_idx]
@@ -204,7 +213,7 @@
     ###
     # extra, for cqlsh
     ###
-
+
     def _reset(self):
         self.rs_idx = 0

=======================================
--- /cql/decoders.py    Tue Feb 14 15:22:20 2012
+++ /cql/decoders.py    Mon Mar 26 10:25:06 2012
@@ -34,8 +34,12 @@
% (valuebytes, namebytes, expectedtype, err))

     def decode_description(self, row):
+        return self.decode_metadata(row)[0]
+
+    def decode_metadata(self, row):
         schema = self.schema
         description = []
+        name_info = []
         for column in row.columns:
             namebytes = column.name
comparator = schema.name_types.get(namebytes, schema.default_name_type)
@@ -46,8 +50,9 @@
             except Exception, e:
                 name = self.name_decode_error(e, namebytes, validator)
description.append((name, validator, None, None, None, None, True))
-
-        return description
+            name_info.append((namebytes, comparator))
+
+        return description, name_info

     def decode_row(self, row):
         schema = self.schema

==============================================================================
Revision: 96b873606e46
Author:   paul cannon <[email protected]>
Date:     Mon Mar 26 11:13:36 2012
Log:      add test for exposed colname types

http://code.google.com/a/apache-extras.org/p/cassandra-dbapi2/source/detail?r=96b873606e46

Modified:
 /test/test_cql.py

=======================================
--- /test/test_cql.py   Fri Feb 10 14:12:57 2012
+++ /test/test_cql.py   Mon Mar 26 11:13:36 2012
@@ -675,6 +675,19 @@
                           cursor.execute,
                           "DROP INDEX undefIndex")

+    def test_name_info(self):
+        cursor = self.cursor
+        timeuuid = uuid.uuid1()
+        cursor.execute("""
+            UPDATE StandardTimeUUID SET '%s' = 19 WHERE KEY = 'uuidtest'
+        """ % str(timeuuid))
+        cursor.execute("""
+            SELECT KEY, '%s' FROM StandardTimeUUID WHERE KEY = 'uuidtest'
+        """ % str(timeuuid))
+        self.assertEqual(len(cursor.name_info), 2)
+        self.assertEqual(cursor.name_info[0], ('KEY', 'AsciiType'))
+        self.assertEqual(cursor.name_info[1], (timeuuid.bytes, 'UUIDType'))
+
     def test_time_uuid(self):
         "store and retrieve time-based (type 1) uuids"
         cursor = self.cursor

Reply via email to