cqlsh: Handle collections embedded into UDTs correctly.

patch by Mikhail Stepura; reviewed by Tyler Hobbs for CASSANDRA-7267
This commit is contained in:
Mikhail Stepura 2014-05-27 20:05:34 -07:00
parent ea02b69001
commit 3391b99a0b
5 changed files with 130 additions and 1 deletions

View File

@ -28,6 +28,7 @@
* Backport Thrift MultiSliceRequest (CASSANDRA-7027)
* Handle overlapping MultiSlices (CASSANDRA-7279)
* Fix DataOutputTest on Windows (CASSANDRA-7265)
* Embedded sets in user defined data-types are not updating (CASSANDRA-7267)
Merged from 2.0:
* Copy compaction options to make sure they are reloaded (CASSANDRA-7290)
* Add option to do more aggressive tombstone compactions (CASSANDRA-6563)

View File

@ -119,6 +119,7 @@ from cqlshlib.displaying import (RED, BLUE, ANSI_RESET, COLUMN_NAME_COLORS,
from cqlshlib.formatting import format_by_type
from cqlshlib.util import trim_if_present
from cqlshlib.tracing import print_trace_session
from cqlshlib.usertypes import deserialize_safe_collection, deserialize_safe_map
HISTORY_DIR = os.path.expanduser(os.path.join('~', '.cassandra'))
CONFIG_FILE = os.path.join(HISTORY_DIR, 'cqlshrc')
@ -521,6 +522,10 @@ class Shell(cmd.Cmd):
#Python driver returns BLOBs as string, but we expect them as buffer()
cassandra.cqltypes.BytesType.deserialize = staticmethod(cassandra.cqltypes.BytesType.validate)
cassandra.cqltypes.CassandraType.support_empty_values = True
# see CASSANDRA-7267
cassandra.cqltypes._SimpleParameterizedType.deserialize_safe = classmethod(deserialize_safe_collection)
# see CASSANDRA-7267
cassandra.cqltypes.MapType.deserialize_safe = classmethod(deserialize_safe_map)
self.empty_lines = 0
self.statement_error = False
self.single_statement = single_statement

View File

@ -854,4 +854,34 @@ class TestCqlshOutput(BaseTestCase):
(2 rows)
nnnnnnnn
"""),
), cqlver=cqlsh.DEFAULT_CQLVER)
def test_user_types_with_collections(self):
self.assertCqlverQueriesGiveColoredOutput((
("select info from songs;", r"""
info
MMMM
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
{founded: '1970-01-02 20:24:54-0800', members: {'Adrian Smith', 'Bruce Dickinson', 'Dave Murray', 'Janick Gers', 'Nicko McBrain', 'Steve Harris'}, description: 'Pure evil metal'}
BYYYYYYYBBGGGGGGGGGGGGGGGGGGGGGGGGGGBBYYYYYYYBBBYYYYYYYYYYYYYYBBYYYYYYYYYYYYYYYYYBBYYYYYYYYYYYYYBBYYYYYYYYYYYYYBBYYYYYYYYYYYYYYYBBYYYYYYYYYYYYYYBBBYYYYYYYYYYYBBYYYYYYYYYYYYYYYYYB
(1 rows)
nnnnnnnn
"""),
), cqlver=cqlsh.DEFAULT_CQLVER)
self.assertCqlverQueriesGiveColoredOutput((
("select tags from songs;", r"""
tags
MMMM
-------------------------------------------------
{tags: {'genre': 'metal', 'origin': 'england'}}
BYYYYBBBYYYYYYYBBYYYYYYYBBYYYYYYYYBBYYYYYYYYYBB
(1 rows)
nnnnnnnn
"""),
), cqlver=cqlsh.DEFAULT_CQLVER)

View File

@ -231,3 +231,43 @@ values ('vpupkin',
{city: 'Chigirinsk', address: null, zip: '676722'}},
{{country: '+7', number: null},
{country: null, number: '03'}});
CREATE TYPE band_info_type (
founded timestamp,
members set<text>,
description text
);
CREATE TYPE tags (
tags map<text, text>
);
CREATE TABLE songs (
title text PRIMARY KEY,
band text,
info band_info_type,
tags tags
);
insert into songs (title, band, info, tags)
values (
'The trooper',
'Iron Maiden',
{
founded:188694000,
members: {
'Bruce Dickinson',
'Dave Murray',
'Adrian Smith',
'Janick Gers',
'Steve Harris',
'Nicko McBrain'
},
description: 'Pure evil metal'
},
{
tags: {
'genre':'metal',
'origin':'england'
}
});

View File

@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from cassandra.marshal import int32_unpack
from cassandra.marshal import int32_unpack, uint16_unpack
from cassandra.cqltypes import CompositeType
import collections
from formatting import formatter_for, format_value_utype
@ -60,5 +60,58 @@ class UserType(CompositeType):
return Result(*result)
def deserialize_safe_collection(cls, byts):
"""
Temporary work around for CASSANDRA-7267
"""
subtype, = cls.subtypes
unpack = uint16_unpack
length = 2
numelements = unpack(byts[:length])
if numelements == 0 and len(byts) > 2 :
unpack = int32_unpack
length = 4
numelements = unpack(byts[:length])
p = length
result = []
for n in xrange(numelements):
itemlen = unpack(byts[p:p + length])
p += length
item = byts[p:p + itemlen]
p += itemlen
result.append(subtype.from_binary(item))
return cls.adapter(result)
try:
from collections import OrderedDict
except ImportError: # Python <2.7
from cassandra.util import OrderedDict
def deserialize_safe_map(cls, byts):
"""
Temporary work around for CASSANDRA-7267
"""
subkeytype, subvaltype = cls.subtypes
unpack = uint16_unpack
length = 2
numelements = unpack(byts[:length])
if numelements == 0 and len(byts) > 2:
unpack = int32_unpack
length = 4
numelements = unpack(byts[:length])
p = length
themap = OrderedDict()
for n in xrange(numelements):
key_len = unpack(byts[p:p + length])
p += length
keybytes = byts[p:p + key_len]
p += key_len
val_len = unpack(byts[p:p + length])
p += length
valbytes = byts[p:p + val_len]
p += val_len
key = subkeytype.from_binary(keybytes)
val = subvaltype.from_binary(valbytes)
themap[key] = val
return themap