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