You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by br...@apache.org on 2012/04/28 00:14:46 UTC
git commit: Add missing file
Updated Branches:
refs/heads/cassandra-1.1 b81f5723e -> c5ad288c9
Add missing file
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/c5ad288c
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/c5ad288c
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/c5ad288c
Branch: refs/heads/cassandra-1.1
Commit: c5ad288c9119e4eda9e60fbb6d998e6a5fbd716b
Parents: b81f572
Author: Brandon Williams <br...@apache.org>
Authored: Fri Apr 27 17:14:33 2012 -0500
Committer: Brandon Williams <br...@apache.org>
Committed: Fri Apr 27 17:14:33 2012 -0500
----------------------------------------------------------------------
pylib/cqlshlib/cql3handling.py | 210 +++++++++++++++++++++++++++++++++++
1 files changed, 210 insertions(+), 0 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/c5ad288c/pylib/cqlshlib/cql3handling.py
----------------------------------------------------------------------
diff --git a/pylib/cqlshlib/cql3handling.py b/pylib/cqlshlib/cql3handling.py
new file mode 100644
index 0000000..9d27f44
--- /dev/null
+++ b/pylib/cqlshlib/cql3handling.py
@@ -0,0 +1,210 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+from warnings import warn
+from .cqlhandling import cql_typename, cql_escape
+
+try:
+ import json
+except ImportError:
+ import simplejson as json
+
+class UnexpectedTableStructure(UserWarning):
+ def __init__(self, msg):
+ self.msg = msg
+
+ def __str__(self):
+ return 'Unexpected table structure; may not translate correctly to CQL. ' + self.msg
+
+keywords = set((
+ 'select', 'from', 'where', 'and', 'key', 'insert', 'update', 'with',
+ 'limit', 'using', 'consistency', 'one', 'quorum', 'all', 'any',
+ 'local_quorum', 'each_quorum', 'two', 'three', 'use', 'count', 'set',
+ 'begin', 'apply', 'batch', 'truncate', 'delete', 'in', 'create',
+ 'keyspace', 'schema', 'columnfamily', 'table', 'index', 'on', 'drop',
+ 'primary', 'into', 'values', 'timestamp', 'ttl', 'alter', 'add', 'type',
+ 'compact', 'storage', 'order', 'by', 'asc', 'desc'
+))
+
+columnfamily_options = (
+ 'comment',
+ 'bloom_filter_fp_chance',
+ 'caching',
+ 'read_repair_chance',
+ # 'local_read_repair_chance', -- not yet a valid cql option
+ 'gc_grace_seconds',
+ 'min_compaction_threshold',
+ 'max_compaction_threshold',
+ 'replicate_on_write',
+ 'compaction_strategy_class',
+)
+
+columnfamily_map_options = (
+ ('compaction_strategy_options',
+ ()),
+ ('compression_parameters',
+ ('sstable_compression', 'chunk_length_kb', 'crc_check_chance')),
+)
+
+def cql3_escape_value(value):
+ return cql_escape(value)
+
+def cql3_escape_name(name):
+ return '"%s"' % name.replace('"', '""')
+
+valid_cql3_word_re = re.compile(r'^[a-z][0-9a-z_]*$', re.I)
+
+def is_valid_cql3_name(s):
+ return valid_cql3_word_re.match(s) is not None and s not in keywords
+
+def maybe_cql3_escape_name(name):
+ if is_valid_cql3_name(name):
+ return name
+ return cql3_escape_name(name)
+
+class CqlColumnDef:
+ index_name = None
+
+ def __init__(self, name, cqltype):
+ self.name = name
+ self.cqltype = cqltype
+
+ @classmethod
+ def from_layout(cls, layout):
+ c = cls(layout[u'column'], cql_typename(layout[u'validator']))
+ c.index_name = layout[u'index_name']
+ return c
+
+ def __str__(self):
+ indexstr = ' (index %s)' % self.index_name if self.index_name is not None else ''
+ return '<CqlColumnDef %r %r%s>' % (self.name, self.cqltype, indexstr)
+ __repr__ = __str__
+
+class CqlTableDef:
+ json_attrs = ('column_aliases', 'compaction_strategy_options', 'compression_parameters')
+ composite_type_name = 'org.apache.cassandra.db.marshal.CompositeType'
+ colname_type_name = 'org.apache.cassandra.db.marshal.UTF8Type'
+ column_class = CqlColumnDef
+ compact_storage = False
+
+ key_components = ()
+ columns = ()
+
+ def __init__(self, name):
+ self.name = name
+
+ @classmethod
+ def from_layout(cls, layout, coldefs):
+ cf = cls(name=layout[u'columnfamily'])
+ for attr, val in layout.items():
+ setattr(cf, attr.encode('ascii'), val)
+ for attr in cls.json_attrs:
+ try:
+ setattr(cf, attr, json.loads(getattr(cf, attr)))
+ except AttributeError:
+ pass
+ cf.key_components = [cf.key_alias.decode('ascii')] + list(cf.column_aliases)
+ cf.key_validator = cql_typename(cf.key_validator)
+ cf.default_validator = cql_typename(cf.default_validator)
+ cf.coldefs = coldefs
+ cf.parse_composite()
+ cf.check_assumptions()
+ return cf
+
+ def check_assumptions(self):
+ """
+ be explicit about assumptions being made; warn if not met. if some of
+ these are accurate but not the others, it's not clear whether the
+ right results will come out.
+ """
+
+ # assumption is that all valid CQL tables match the rules in the following table.
+ # if they don't, give a warning and try anyway, but there should be no expectation
+ # of success.
+ #
+ # non-null non-empty comparator is entries in
+ # value_alias column_aliases composite schema_columns
+ # +----------------------------------------------------------
+ # composite, compact storage | yes yes either no
+ # composite, dynamic storage | no yes yes yes
+ # single-column primary key | no no no either
+
+ if self.value_alias is not None:
+ # composite cf with compact storage
+ if len(self.coldefs) > 0:
+ warn(UnexpectedTableStructure(
+ "expected compact storage CF (has value alias) to have no "
+ "column definitions in system.schema_columns, but found %r"
+ % (self.coldefs,)))
+ elif len(self.column_aliases) == 0:
+ warn(UnexpectedTableStructure(
+ "expected compact storage CF (has value alias) to have "
+ "column aliases, but found none"))
+ elif self.comparator.startswith(self.composite_type_name + '('):
+ # composite cf with dynamic storage
+ if len(self.column_aliases) == 0:
+ warn(UnexpectedTableStructure(
+ "expected composite key CF to have column aliases, "
+ "but found none"))
+ elif not self.comparator.endswith(self.colname_type_name + ')'):
+ warn(UnexpectedTableStructure(
+ "expected non-compact composite CF to have %s as "
+ "last component of composite comparator, but found %r"
+ % (self.colname_type_name, self.comparator)))
+ elif len(self.coldefs) == 0:
+ warn(UnexpectedTableStructure(
+ "expected non-compact composite CF to have entries in "
+ "system.schema_columns, but found none"))
+ else:
+ # non-composite cf
+ if len(self.column_aliases) > 0:
+ warn(UnexpectedTableStructure(
+ "expected non-composite CF to have no column aliases, "
+ "but found %r." % (self.column_aliases,)))
+ num_subtypes = self.comparator.count(',') + 1
+ if self.compact_storage:
+ num_subtypes += 1
+ if len(self.key_components) != num_subtypes:
+ warn(UnexpectedTableStructure(
+ "expected %r length to be %d, but it's %d. comparator=%r"
+ % (self.key_components, num_subtypes, len(self.key_components), self.comparator)))
+
+ def parse_composite(self):
+ subtypes = [self.key_validator]
+ if self.comparator.startswith(self.composite_type_name + '('):
+ subtypenames = self.comparator[len(self.composite_type_name) + 1:-1]
+ subtypes.extend(map(cql_typename, subtypenames.split(',')))
+ else:
+ subtypes.append(cql_typename(self.comparator))
+
+ value_cols = []
+ if len(self.column_aliases) > 0:
+ if len(self.coldefs) > 0:
+ # composite cf, dynamic storage
+ subtypes.pop(-1)
+ else:
+ # composite cf, compact storage
+ self.compact_storage = True
+ value_cols = [self.column_class(self.value_alias, self.default_validator)]
+
+ keycols = map(self.column_class, self.key_components, subtypes)
+ normal_cols = map(self.column_class.from_layout, self.coldefs)
+ self.columns = keycols + value_cols + normal_cols
+
+ def __str__(self):
+ return '<%s %s.%s>' % (self.__class__.__name__, self.keyspace, self.name)
+ __repr__ = __str__