Repository: cassandra Updated Branches: refs/heads/cassandra-2.1 b25139f8a -> 72057c697 refs/heads/cassandra-2.2 2dbcb5dae -> b6b251770 refs/heads/cassandra-3.0 fae7bf9c2 -> f2afd04e7 refs/heads/trunk 0b81f72ed -> e6505a606
cqlsh COPY FROM fails for null values with non-prepared statements patch by Stefania Alborghetti and Robert Stupp; reviewed by Robert Stupp for CASSANDRA-11631 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/72057c69 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/72057c69 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/72057c69 Branch: refs/heads/cassandra-2.1 Commit: 72057c6971abf40e2d1a545c4b511be84a4eb69f Parents: b25139f Author: Stefania Alborghetti <[email protected]> Authored: Mon Apr 25 10:33:54 2016 +0800 Committer: Stefania Alborghetti <[email protected]> Committed: Wed Apr 27 09:05:48 2016 +0800 ---------------------------------------------------------------------- CHANGES.txt | 1 + pylib/cqlshlib/copyutil.py | 36 +++++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/72057c69/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index ff26fde..5885a9a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 2.1.15 + * cqlsh COPY FROM fails for null values with non-prepared statements (CASSANDRA-11631) * Make cython optional in pylib/setup.py (CASSANDRA-11630) * Change order of directory searching for cassandra.in.sh to favor local one (CASSANDRA-11628) * cqlsh COPY FROM fails with []{} chars in UDT/tuple fields/values (CASSANDRA-11633) http://git-wip-us.apache.org/repos/asf/cassandra/blob/72057c69/pylib/cqlshlib/copyutil.py ---------------------------------------------------------------------- diff --git a/pylib/cqlshlib/copyutil.py b/pylib/cqlshlib/copyutil.py index e12b72f..d68812c 100644 --- a/pylib/cqlshlib/copyutil.py +++ b/pylib/cqlshlib/copyutil.py @@ -1634,6 +1634,7 @@ class ImportConversion(object): self.thousands_sep = parent.thousands_sep self.boolean_styles = parent.boolean_styles self.time_format = parent.time_format + self.debug = parent.debug self.table_meta = table_meta self.primary_key_indexes = [self.columns.index(col.name) for col in self.table_meta.primary_key] @@ -1682,7 +1683,16 @@ class ImportConversion(object): return CqlRuleSet.dequote_value(v) def convert(t, v): - return converters.get(t.typename, convert_unknown)(unprotect(v), ct=t) + v = unprotect(v) + if v == self.nullval: + return self.get_null_val() + return converters.get(t.typename, convert_unknown)(v, ct=t) + + def convert_mandatory(t, v): + v = unprotect(v) + if v == self.nullval: + raise ParseError('Empty values are not allowed') + return converters.get(t.typename, convert_unknown)(v, ct=t) def convert_blob(v, **_): try: @@ -1788,13 +1798,13 @@ class ImportConversion(object): return Time(v) def convert_tuple(val, ct=cql_type): - return tuple(convert(t, v) for t, v in zip(ct.subtypes, split(val))) + return tuple(convert_mandatory(t, v) for t, v in zip(ct.subtypes, split(val))) def convert_list(val, ct=cql_type): - return list(convert(ct.subtypes[0], v) for v in split(val)) + return list(convert_mandatory(ct.subtypes[0], v) for v in split(val)) def convert_set(val, ct=cql_type): - return frozenset(convert(ct.subtypes[0], v) for v in split(val)) + return frozenset(convert_mandatory(ct.subtypes[0], v) for v in split(val)) def convert_map(val, ct=cql_type): """ @@ -1806,7 +1816,7 @@ class ImportConversion(object): class ImmutableDict(frozenset): iteritems = frozenset.__iter__ - return ImmutableDict(frozenset((convert(ct.subtypes[0], v[0]), convert(ct.subtypes[1], v[1])) + return ImmutableDict(frozenset((convert_mandatory(ct.subtypes[0], v[0]), convert(ct.subtypes[1], v[1])) for v in [split('{%s}' % vv, sep=':') for vv in split(val)])) def convert_user_type(val, ct=cql_type): @@ -1862,6 +1872,9 @@ class ImportConversion(object): return converters.get(cql_type.typename, convert_unknown) + def get_null_val(self): + return None if self.use_prepared_statements else "NULL" + def convert_row(self, row): """ Convert the row into a list of parsed values if using prepared statements, else simply apply the @@ -1877,10 +1890,15 @@ class ImportConversion(object): if row[i] == self.nullval: raise ParseError(self.get_null_primary_key_message(i)) - try: - return [conv(val) if val != self.nullval else None for conv, val in zip(converters, row)] - except Exception, e: - raise ParseError(str(e)) + def convert(c, v): + try: + return c(v) if v != self.nullval else self.get_null_val() + except Exception, e: + if self.debug: + traceback.print_exc() + raise ParseError("Failed to parse %s : %s" % (val, str(e))) + + return [convert(conv, val) for conv, val in zip(converters, row)] def get_null_primary_key_message(self, idx): message = "Cannot insert null value for primary key column '%s'." % (self.columns[idx],)
