cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From slebre...@apache.org
Subject [2/5] git commit: CQL 3.0 beta
Date Wed, 25 Jan 2012 12:35:05 GMT
CQL 3.0 beta

patch by slebresne; reviewed by jbellis and urandom for CASSANDRA-3761


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/655ccc3a
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/655ccc3a
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/655ccc3a

Branch: refs/heads/trunk
Commit: 655ccc3abfc0f3fbe974d3f52cd38bf0d6afe2a9
Parents: 86637d4
Author: Sylvain Lebresne <sylvain@datastax.com>
Authored: Mon Jan 16 18:50:53 2012 +0100
Committer: Sylvain Lebresne <sylvain@datastax.com>
Committed: Wed Jan 25 13:34:18 2012 +0100

----------------------------------------------------------------------
 CHANGES.txt                                        |    1 +
 build.xml                                          |   15 +-
 interface/cassandra.thrift                         |    6 +-
 src/avro/internode.genavro                         |    2 +
 .../org/apache/cassandra/config/CFMetaData.java    |   91 ++-
 .../org/apache/cassandra/cql/QueryProcessor.java   |    3 +-
 src/java/org/apache/cassandra/cql3/Attributes.java |   32 +
 .../org/apache/cassandra/cql3/CFDefinition.java    |  303 +++++
 src/java/org/apache/cassandra/cql3/CFName.java     |   58 +
 src/java/org/apache/cassandra/cql3/CFPropDefs.java |  260 ++++
 .../org/apache/cassandra/cql3/CQLStatement.java    |   70 +
 .../apache/cassandra/cql3/ColumnIdentifier.java    |   79 ++
 .../apache/cassandra/cql3/ColumnNameBuilder.java   |   73 ++
 src/java/org/apache/cassandra/cql3/Cql.g           |  633 ++++++++++
 src/java/org/apache/cassandra/cql3/Operation.java  |   54 +
 .../org/apache/cassandra/cql3/QueryProcessor.java  |  205 +++
 src/java/org/apache/cassandra/cql3/Relation.java   |  117 ++
 src/java/org/apache/cassandra/cql3/Term.java       |  205 +++
 .../cql3/statements/AlterTableStatement.java       |  180 +++
 .../cassandra/cql3/statements/BatchStatement.java  |  166 +++
 .../cassandra/cql3/statements/CFStatement.java     |   56 +
 .../statements/CreateColumnFamilyStatement.java    |  294 +++++
 .../cql3/statements/CreateIndexStatement.java      |  108 ++
 .../cql3/statements/CreateKeyspaceStatement.java   |  114 ++
 .../cassandra/cql3/statements/DeleteStatement.java |  164 +++
 .../cql3/statements/DropColumnFamilyStatement.java |   39 +
 .../cql3/statements/DropIndexStatement.java        |   74 ++
 .../cql3/statements/DropKeyspaceStatement.java     |   52 +
 .../cql3/statements/ModificationStatement.java     |  129 ++
 .../cassandra/cql3/statements/Preprocessable.java  |   27 +
 .../cql3/statements/SchemaAlteringStatement.java   |  184 +++
 .../cassandra/cql3/statements/SelectStatement.java |  972 +++++++++++++++
 .../cql3/statements/TruncateStatement.java         |   68 +
 .../cassandra/cql3/statements/UpdateStatement.java |  359 ++++++
 .../cassandra/cql3/statements/UseStatement.java    |   48 +
 .../org/apache/cassandra/db/CounterMutation.java   |    9 +
 src/java/org/apache/cassandra/db/IMutation.java    |    1 +
 src/java/org/apache/cassandra/db/RowMutation.java  |   19 +
 src/java/org/apache/cassandra/db/SystemTable.java  |    2 +-
 .../db/marshal/AbstractCompositeType.java          |   17 +
 .../apache/cassandra/db/marshal/CompositeType.java |  128 ++-
 .../org/apache/cassandra/service/ClientState.java  |   57 +-
 .../apache/cassandra/service/StorageService.java   |    1 +
 .../apache/cassandra/thrift/CassandraServer.java   |   42 +-
 .../apache/cassandra/thrift/ThriftValidation.java  |    8 +-
 .../apache/cassandra/utils/SemanticVersion.java    |  231 ++++
 .../cassandra/utils/SemanticVersionTest.java       |  105 ++
 47 files changed, 5829 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 66ab562..03d2e69 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -55,6 +55,7 @@
  * Add SnapshotCommand to trigger snapshot on remote node (CASSANDRA-3721)
  * Make CFMetaData conversions to/from thrift/native schema inverses
    (CASSANDRA_3559)
+ * Add initial code for CQL 3.0-beta (CASSANDRA-3781)
 
 
 1.0.8

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/build.xml
----------------------------------------------------------------------
diff --git a/build.xml b/build.xml
index d382e34..2a46f37 100644
--- a/build.xml
+++ b/build.xml
@@ -202,6 +202,9 @@
       <uptodate property="cqlcurrent" 
                 srcfile="${build.src.java}/org/apache/cassandra/cql/Cql.g" 
                 targetfile="${build.src.gen-java}/org/apache/cassandra/cql/Cql.tokens"/>
+      <uptodate property="cqlcurrent"
+                srcfile="${build.src.java}/org/apache/cassandra/cql3/Cql.g"
+                targetfile="${build.src.gen-java}/org/apache/cassandra/cql3/Cql.tokens"/>
     </target>
  
     <target name="gen-cql-grammar" depends="check-gen-cql-grammar" unless="cqlcurrent">
@@ -213,9 +216,17 @@
          <arg value="${build.src.java}/org/apache/cassandra/cql/Cql.g" />
          <arg value="-fo" />
          <arg value="${build.src.gen-java}/org/apache/cassandra/cql/" />
-      </java> 
+      </java>
+      <java classname="org.antlr.Tool"
+            classpath="${build.lib}/antlr-3.2.jar"
+            fork="true"
+            failonerror="true">
+         <arg value="${build.src.java}/org/apache/cassandra/cql3/Cql.g" />
+         <arg value="-fo" />
+         <arg value="${build.src.gen-java}/org/apache/cassandra/cql3/" />
+      </java>
     </target>
-	
+
 	<target name="generate-cql-html" depends="maven-ant-tasks-init" description="Generate HTML from textile source">
 	  <artifact:dependencies pathId="wikitext.classpath">
 	    <dependency groupId="com.datastax.wikitext" artifactId="wikitext-core-ant" version="1.3"/>	    	  

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/interface/cassandra.thrift
----------------------------------------------------------------------
diff --git a/interface/cassandra.thrift b/interface/cassandra.thrift
index e28b236..08b776e 100644
--- a/interface/cassandra.thrift
+++ b/interface/cassandra.thrift
@@ -46,7 +46,7 @@ namespace rb CassandraThrift
 #           for every edit that doesn't result in a change to major/minor.
 #
 # See the Semantic Versioning Specification (SemVer) http://semver.org.
-const string VERSION = "19.25.0"
+const string VERSION = "19.26.0"
 
 
 #
@@ -415,6 +415,8 @@ struct CfDef {
     32: optional map<string,string> compression_options,
     33: optional double bloom_filter_fp_chance,
     34: optional string caching="keys_only",
+    35: optional list<binary> column_aliases,
+    36: optional binary value_alias,
 }
 
 /* describes a keyspace. */
@@ -714,6 +716,6 @@ service Cassandra {
             2:UnavailableException ue,
             3:TimedOutException te,
             4:SchemaDisagreementException sde)
-           
 
+  void set_cql_version(1: required string version) throws (1:InvalidRequestException ire)
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/avro/internode.genavro
----------------------------------------------------------------------
diff --git a/src/avro/internode.genavro b/src/avro/internode.genavro
index c36a83f..36c2cba 100644
--- a/src/avro/internode.genavro
+++ b/src/avro/internode.genavro
@@ -67,6 +67,8 @@ protocol InterNode {
         union { null, map<string> } compression_options = null;
         union { null, double } bloom_filter_fp_chance = null;
         union { null, string } caching = null;
+        union { null, array<bytes> } column_aliases = null;
+        union { null, bytes } value_alias = null;
     }
 
     @aliases(["org.apache.cassandra.config.avro.KsDef"])

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/config/CFMetaData.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/CFMetaData.java b/src/java/org/apache/cassandra/config/CFMetaData.java
index 9bd731a..a82639d 100644
--- a/src/java/org/apache/cassandra/config/CFMetaData.java
+++ b/src/java/org/apache/cassandra/config/CFMetaData.java
@@ -32,6 +32,7 @@ import org.apache.commons.lang.builder.EqualsBuilder;
 import org.apache.commons.lang.builder.HashCodeBuilder;
 import org.apache.commons.lang.builder.ToStringBuilder;
 
+import org.apache.cassandra.cql3.CFDefinition;
 import org.apache.cassandra.db.*;
 import org.apache.cassandra.db.filter.QueryPath;
 import org.apache.cassandra.db.compaction.AbstractCompactionStrategy;
@@ -173,6 +174,8 @@ public final class CFMetaData
     // thrift compatibility
     private double mergeShardsChance;                 // default 0.1, chance [0.0, 1.0] of merging old shards during replication
     private ByteBuffer keyAlias;                      // default NULL
+    private List<ByteBuffer> columnAliases = new ArrayList<ByteBuffer>();
+    private ByteBuffer valueAlias;                    // default NULL
     private Double bloomFilterFpChance;               // default NULL
     private Caching caching;                          // default KEYS_ONLY (possible: all, key_only, row_only, none)
 
@@ -182,17 +185,24 @@ public final class CFMetaData
 
     private CompressionParameters compressionParameters;
 
+    // Processed infos used by CQL. This can be fully reconstructed from the CFMedata,
+    // so it's not saved on disk. It is however costlyish to recreate for each query
+    // so we cache it here (and update on each relevant CFMetadata change)
+    private CFDefinition cqlCfDef;
+
     public CFMetaData comment(String prop) { comment = enforceCommentNotNull(prop); return this;}
     public CFMetaData readRepairChance(double prop) {readRepairChance = prop; return this;}
     public CFMetaData replicateOnWrite(boolean prop) {replicateOnWrite = prop; return this;}
     public CFMetaData gcGraceSeconds(int prop) {gcGraceSeconds = prop; return this;}
-    public CFMetaData defaultValidator(AbstractType<?> prop) {defaultValidator = prop; return this;}
-    public CFMetaData keyValidator(AbstractType<?> prop) {keyValidator = prop; return this;}
+    public CFMetaData defaultValidator(AbstractType<?> prop) {defaultValidator = prop; updateCfDef(); return this;}
+    public CFMetaData keyValidator(AbstractType<?> prop) {keyValidator = prop; updateCfDef(); return this;}
     public CFMetaData minCompactionThreshold(int prop) {minCompactionThreshold = prop; return this;}
     public CFMetaData maxCompactionThreshold(int prop) {maxCompactionThreshold = prop; return this;}
     public CFMetaData mergeShardsChance(double prop) {mergeShardsChance = prop; return this;}
-    public CFMetaData keyAlias(ByteBuffer prop) {keyAlias = prop; return this;}
-    public CFMetaData columnMetadata(Map<ByteBuffer,ColumnDefinition> prop) {column_metadata = prop; return this;}
+    public CFMetaData keyAlias(ByteBuffer prop) {keyAlias = prop; updateCfDef(); return this;}
+    public CFMetaData columnAliases(List<ByteBuffer> prop) {columnAliases = prop; updateCfDef(); return this;}
+    public CFMetaData valueAlias(ByteBuffer prop) {valueAlias = prop; updateCfDef(); return this;}
+    public CFMetaData columnMetadata(Map<ByteBuffer,ColumnDefinition> prop) {column_metadata = prop; updateCfDef(); return this;}
     public CFMetaData compactionStrategyClass(Class<? extends AbstractCompactionStrategy> prop) {compactionStrategyClass = prop; return this;}
     public CFMetaData compactionStrategyOptions(Map<String, String> prop) {compactionStrategyOptions = prop; return this;}
     public CFMetaData compressionParameters(CompressionParameters prop) {compressionParameters = prop; return this;}
@@ -246,6 +256,7 @@ public final class CFMetaData
         keyValidator = BytesType.instance;
         comment = "";
         keyAlias = null; // This qualifies as a 'strange default'.
+        valueAlias = null;
         column_metadata = new HashMap<ByteBuffer,ColumnDefinition>();
 
         try
@@ -259,6 +270,7 @@ public final class CFMetaData
         compactionStrategyOptions = new HashMap<String, String>();
 
         compressionParameters = new CompressionParameters(null);
+        updateCfDef(); // init cqlCfDef
     }
 
     private static CFMetaData newSystemMetadata(String cfName, int cfId, String comment, AbstractType<?> comparator, AbstractType<?> subcc)
@@ -369,6 +381,8 @@ public final class CFMetaData
         if (cf.max_compaction_threshold != null) { newCFMD.maxCompactionThreshold(cf.max_compaction_threshold); }
         if (cf.merge_shards_chance != null) { newCFMD.mergeShardsChance(cf.merge_shards_chance); }
         if (cf.key_alias != null) { newCFMD.keyAlias(cf.key_alias); }
+        if (cf.column_aliases != null) { newCFMD.columnAliases(fixAvroRetardation(cf.column_aliases)); }
+        if (cf.value_alias != null) { newCFMD.valueAlias(cf.value_alias); }
         if (cf.compaction_strategy != null)
         {
             try
@@ -418,6 +432,18 @@ public final class CFMetaData
                       .bloomFilterFpChance(cf.bloom_filter_fp_chance)
                       .caching(caching);
     }
+
+    /*
+     * Avro handles array with it's own class, GenericArray, that extends
+     * AbstractList but redefine equals() in a way that violate List.equals()
+     * specification (basically only a GenericArray can ever be equal to a
+     * GenericArray).
+     * (Concretely, keeping the list returned by avro breaks DefsTest.saveAndRestore())
+     */
+    private static <T> List<T> fixAvroRetardation(List<T> array)
+    {
+        return new ArrayList<T>(array);
+    }
     
     public String getComment()
     {
@@ -469,6 +495,21 @@ public final class CFMetaData
         return keyAlias == null ? DEFAULT_KEY_NAME : keyAlias;
     }
 
+    public ByteBuffer getKeyAlias()
+    {
+        return keyAlias;
+    }
+
+    public List<ByteBuffer> getColumnAliases()
+    {
+        return columnAliases;
+    }
+
+    public ByteBuffer getValueAlias()
+    {
+        return valueAlias;
+    }
+
     public CompressionParameters compressionParameters()
     {
         return compressionParameters;
@@ -524,6 +565,8 @@ public final class CFMetaData
             .append(column_metadata, rhs.column_metadata)
             .append(mergeShardsChance, rhs.mergeShardsChance)
             .append(keyAlias, rhs.keyAlias)
+            .append(columnAliases, rhs.columnAliases)
+            .append(valueAlias, rhs.valueAlias)
             .append(compactionStrategyClass, rhs.compactionStrategyClass)
             .append(compactionStrategyOptions, rhs.compactionStrategyOptions)
             .append(compressionParameters, rhs.compressionParameters)
@@ -552,6 +595,8 @@ public final class CFMetaData
             .append(column_metadata)
             .append(mergeShardsChance)
             .append(keyAlias)
+            .append(columnAliases)
+            .append(valueAlias)
             .append(compactionStrategyClass)
             .append(compactionStrategyOptions)
             .append(compressionParameters)
@@ -613,6 +658,8 @@ public final class CFMetaData
         if (cf_def.isSetMax_compaction_threshold()) { newCFMD.maxCompactionThreshold(cf_def.max_compaction_threshold); }
         if (cf_def.isSetMerge_shards_chance()) { newCFMD.mergeShardsChance(cf_def.merge_shards_chance); }
         if (cf_def.isSetKey_alias()) { newCFMD.keyAlias(cf_def.key_alias); }
+        if (cf_def.isSetColumn_aliases() && cf_def.column_aliases != null) { newCFMD.columnAliases(cf_def.column_aliases); }
+        if (cf_def.isSetValue_alias()) { newCFMD.valueAlias(cf_def.value_alias); }
         if (cf_def.isSetKey_validation_class()) { newCFMD.keyValidator(TypeParser.parse(cf_def.key_validation_class)); }
         if (cf_def.isSetCompaction_strategy())
             newCFMD.compactionStrategyClass = createCompactionStrategy(cf_def.compaction_strategy);
@@ -698,6 +745,8 @@ public final class CFMetaData
         maxCompactionThreshold = cf_def.max_compaction_threshold;
         mergeShardsChance = cf_def.merge_shards_chance;
         keyAlias = cf_def.key_alias;
+        columnAliases = cf_def.column_aliases;
+        valueAlias = cf_def.value_alias;
         if (cf_def.isSetBloom_filter_fp_chance())
             bloomFilterFpChance = cf_def.bloom_filter_fp_chance;
         caching = Caching.fromString(cf_def.caching);
@@ -1073,14 +1122,29 @@ public final class CFMetaData
         if (!cfDef.isSetColumn_metadata())
             return;
 
-        AbstractType comparator = TypeParser.parse(cfDef.column_type.equals("Super")
-                                           ? cfDef.subcomparator_type
-                                           : cfDef.comparator_type);
+        AbstractType comparator = getColumnDefinitionComparator(cfDef);
 
         for (ColumnDef columnDef : cfDef.column_metadata)
             ColumnDefinition.addToSchema(mutation, cfDef.name, comparator, columnDef, timestamp);
     }
 
+    public static AbstractType<?> getColumnDefinitionComparator(CfDef cfDef) throws ConfigurationException
+    {
+        AbstractType<?> cfComparator = TypeParser.parse(cfDef.column_type.equals("Super")
+                                     ? cfDef.subcomparator_type
+                                     : cfDef.comparator_type);
+
+        if (cfComparator instanceof CompositeType)
+        {
+            List<AbstractType<?>> types = ((CompositeType)cfComparator).types;
+            return types.get(types.size() - 1);
+        }
+        else
+        {
+            return cfComparator;
+        }
+    }
+
     /**
      * Deserialize CF metadata from low-level representation
      *
@@ -1130,6 +1194,17 @@ public final class CFMetaData
         return cfDef;
     }
 
+    private void updateCfDef()
+    {
+        cqlCfDef = new CFDefinition(this);
+    }
+
+    public CFDefinition getCfDef()
+    {
+        assert cqlCfDef != null;
+        return cqlCfDef;
+    }
+
     @Override
     public String toString()
     {
@@ -1150,6 +1225,8 @@ public final class CFMetaData
             .append("maxCompactionThreshold", maxCompactionThreshold)
             .append("mergeShardsChance", mergeShardsChance)
             .append("keyAlias", keyAlias)
+            .append("columnAliases", columnAliases)
+            .append("valueAlias", keyAlias)
             .append("column_metadata", column_metadata)
             .append("compactionStrategyClass", compactionStrategyClass)
             .append("compactionStrategyOptions", compactionStrategyOptions)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/cql/QueryProcessor.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql/QueryProcessor.java b/src/java/org/apache/cassandra/cql/QueryProcessor.java
index 917fb92..c539979 100644
--- a/src/java/org/apache/cassandra/cql/QueryProcessor.java
+++ b/src/java/org/apache/cassandra/cql/QueryProcessor.java
@@ -53,6 +53,7 @@ import org.apache.cassandra.thrift.Column;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.Pair;
+import org.apache.cassandra.utils.SemanticVersion;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.Maps;
@@ -65,7 +66,7 @@ import static org.apache.cassandra.thrift.ThriftValidation.validateColumnFamily;
 
 public class QueryProcessor
 {
-    public static final String CQL_VERSION = "2.0.0";
+    public static final SemanticVersion CQL_VERSION = new SemanticVersion("2.0.0");
 
     private static final Logger logger = LoggerFactory.getLogger(QueryProcessor.class);
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/cql3/Attributes.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Attributes.java b/src/java/org/apache/cassandra/cql3/Attributes.java
new file mode 100644
index 0000000..41f78fb
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/Attributes.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+package org.apache.cassandra.cql3;
+
+import org.apache.cassandra.thrift.ConsistencyLevel;
+
+/**
+ * Utility class for the Parser to gather attributes for modification
+ * statements.
+ */
+public class Attributes
+{
+    public ConsistencyLevel cLevel;
+    public Long timestamp;
+    public int timeToLive;
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/cql3/CFDefinition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/CFDefinition.java b/src/java/org/apache/cassandra/cql3/CFDefinition.java
new file mode 100644
index 0000000..b3725db
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/CFDefinition.java
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+package org.apache.cassandra.cql3;
+
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import com.google.common.collect.AbstractIterator;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CompositeType;
+import org.apache.cassandra.db.marshal.UTF8Type;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+/**
+ * Holds metadata on a CF preprocessed for use by CQL queries.
+ */
+public class CFDefinition implements Iterable<CFDefinition.Name>
+{
+    public static final AbstractType<?> definitionType = UTF8Type.instance;
+
+    private static final String DEFAULT_KEY_ALIAS = "key";
+    private static final String DEFAULT_COLUMN_ALIAS = "column";
+    private static final String DEFAULT_VALUE_ALIAS = "value";
+
+    public final CFMetaData cfm;
+    public final Name key;
+    // LinkedHashMap because the order does matter (it is the order in the composite type)
+    public final LinkedHashMap<ColumnIdentifier, Name> columns = new LinkedHashMap<ColumnIdentifier, Name>();
+    public final Name value;
+    // Keep metadata lexicographically ordered so that wildcard expansion have a deterministic order
+    public final Map<ColumnIdentifier, Name> metadata = new TreeMap<ColumnIdentifier, Name>();
+
+    public final boolean isComposite;
+    public final boolean isCompact;
+
+    public CFDefinition(CFMetaData cfm)
+    {
+        this.cfm = cfm;
+        this.key = new Name(getKeyId(cfm), Name.Kind.KEY_ALIAS, cfm.getKeyValidator());
+        if (cfm.comparator instanceof CompositeType)
+        {
+            this.isComposite = true;
+            CompositeType composite = (CompositeType)cfm.comparator;
+            if (!cfm.getColumn_metadata().isEmpty())
+            {
+                // "sparse" composite
+                this.isCompact = false;
+                this.value = null;
+                assert cfm.getValueAlias() == null;
+                for (int i = 0; i < composite.types.size() - 1; i++)
+                {
+                    ColumnIdentifier id = getColumnId(cfm, i);
+                    this.columns.put(id, new Name(id, Name.Kind.COLUMN_ALIAS, i, composite.types.get(i)));
+                }
+
+                for (Map.Entry<ByteBuffer, ColumnDefinition> def : cfm.getColumn_metadata().entrySet())
+                {
+                    ColumnIdentifier id = new ColumnIdentifier(def.getKey());
+                    this.metadata.put(id, new Name(id, Name.Kind.COLUMN_METADATA, def.getValue().getValidator()));
+                }
+            }
+            else
+            {
+                // "dense" composite
+                this.isCompact = true;
+                for (int i = 0; i < composite.types.size(); i++)
+                {
+                    ColumnIdentifier id = getColumnId(cfm, i);
+                    this.columns.put(id, new Name(id, Name.Kind.COLUMN_ALIAS, i, composite.types.get(i)));
+                }
+                this.value = new Name(getValueId(cfm), Name.Kind.VALUE_ALIAS, cfm.getDefaultValidator());
+            }
+        }
+        else
+        {
+            this.isComposite = false;
+            if (!cfm.getColumn_metadata().isEmpty())
+            {
+                // static CF
+                this.isCompact = false;
+                this.value = null;
+                assert cfm.getValueAlias() == null;
+                assert cfm.getColumnAliases() == null || cfm.getColumnAliases().isEmpty();
+                for (Map.Entry<ByteBuffer, ColumnDefinition> def : cfm.getColumn_metadata().entrySet())
+                {
+                    ColumnIdentifier id = new ColumnIdentifier(def.getKey());
+                    this.metadata.put(id, new Name(id, Name.Kind.COLUMN_METADATA, def.getValue().getValidator()));
+                }
+            }
+            else
+            {
+                // dynamic CF
+                this.isCompact = true;
+                ColumnIdentifier id = getColumnId(cfm, 0);
+                Name name = new Name(id, Name.Kind.COLUMN_ALIAS, 0, cfm.comparator);
+                this.columns.put(id, name);
+                this.value = new Name(getValueId(cfm), Name.Kind.VALUE_ALIAS, cfm.getDefaultValidator());
+            }
+        }
+        assert value == null || metadata.isEmpty();
+    }
+
+    private static ColumnIdentifier getKeyId(CFMetaData cfm)
+    {
+        return cfm.getKeyAlias() == null
+             ? new ColumnIdentifier(DEFAULT_KEY_ALIAS, false)
+             : new ColumnIdentifier(cfm.getKeyAlias());
+    }
+
+    private static ColumnIdentifier getColumnId(CFMetaData cfm, int i)
+    {
+        List<ByteBuffer> definedNames = cfm.getColumnAliases();
+        return definedNames == null || i >= definedNames.size()
+             ? new ColumnIdentifier(DEFAULT_COLUMN_ALIAS + (i + 1), false)
+             : new ColumnIdentifier(cfm.getColumnAliases().get(i));
+    }
+
+    private static ColumnIdentifier getValueId(CFMetaData cfm)
+    {
+        return cfm.getValueAlias() == null
+             ? new ColumnIdentifier(DEFAULT_VALUE_ALIAS, false)
+             : new ColumnIdentifier(cfm.getValueAlias());
+    }
+
+    public Name get(ColumnIdentifier name)
+    {
+        if (name.equals(key.name))
+            return key;
+        if (value != null && name.equals(value.name))
+            return value;
+        CFDefinition.Name def = columns.get(name);
+        if (def != null)
+            return def;
+        return metadata.get(name);
+    }
+
+    public Iterator<Name> iterator()
+    {
+        return new AbstractIterator<Name>()
+        {
+            private boolean keyDone;
+            private final Iterator<Name> columnIter = columns.values().iterator();
+            private boolean valueDone;
+            private final Iterator<Name> metadataIter = metadata.values().iterator();
+
+            protected Name computeNext()
+            {
+                if (!keyDone)
+                {
+                    keyDone = true;
+                    return key;
+                }
+
+                if (columnIter.hasNext())
+                    return columnIter.next();
+
+                if (value != null && !valueDone)
+                {
+                    valueDone = true;
+                    return value;
+                }
+
+                if (metadataIter.hasNext())
+                    return metadataIter.next();
+
+                return endOfData();
+            }
+        };
+    }
+
+    public ColumnNameBuilder getColumnNameBuilder()
+    {
+        return isComposite
+             ? new CompositeType.Builder((CompositeType)cfm.comparator)
+             : new NonCompositeBuilder(cfm.comparator);
+    }
+
+    public static class Name
+    {
+        public static enum Kind
+        {
+            KEY_ALIAS, COLUMN_ALIAS, VALUE_ALIAS, COLUMN_METADATA
+        }
+
+        private Name(ColumnIdentifier name, Kind kind, AbstractType<?> type)
+        {
+            this(name, kind, -1, type);
+        }
+
+        private Name(ColumnIdentifier name, Kind kind, int position, AbstractType<?> type)
+        {
+            this.kind = kind;
+            this.name = name;
+            this.compositePosition = position;
+            this.type = type;
+        }
+
+        public final Kind kind;
+        public final ColumnIdentifier name;
+        public final int compositePosition; // only make sense for COLUMN_ALIAS if CFDefinition.isComposite()
+        public final AbstractType<?> type;
+
+        @Override
+        public String toString()
+        {
+            // It is not fully conventional, but it is convenient for error messages to the user
+            return name.toString();
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append(key.name);
+        for (Name name : columns.values())
+            sb.append(", ").append(name.name);
+        sb.append(" => ");
+        if (value != null)
+            sb.append(value.name);
+        if (!metadata.isEmpty())
+        {
+            sb.append("{");
+            for (Name name : metadata.values())
+                sb.append(" ").append(name.name);
+            sb.append(" }");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    private static class NonCompositeBuilder implements ColumnNameBuilder
+    {
+        private final AbstractType<?> type;
+        private ByteBuffer columnName;
+
+        private NonCompositeBuilder(AbstractType<?> type)
+        {
+            this.type = type;
+        }
+
+        public NonCompositeBuilder add(ByteBuffer bb)
+        {
+            if (columnName != null)
+                throw new IllegalStateException("Column name is already constructed");
+
+            columnName = bb;
+            return this;
+        }
+
+        public NonCompositeBuilder add(Term t, Relation.Type op, List<ByteBuffer> variables) throws InvalidRequestException
+        {
+            if (columnName != null)
+                throw new IllegalStateException("Column name is already constructed");
+
+            // We don't support the relation type yet, i.e., there is no distinction between x > 3 and x >= 3.
+            columnName = t.getByteBuffer(type, variables);
+            return this;
+        }
+
+        public int componentCount()
+        {
+            return columnName == null ? 0 : 1;
+        }
+
+        public ByteBuffer build()
+        {
+            return columnName == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : columnName;
+        }
+
+        public ByteBuffer buildAsEndOfRange()
+        {
+            throw new IllegalStateException();
+        }
+
+        public NonCompositeBuilder copy()
+        {
+            NonCompositeBuilder newBuilder = new NonCompositeBuilder(type);
+            newBuilder.columnName = columnName;
+            return newBuilder;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/cql3/CFName.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/CFName.java b/src/java/org/apache/cassandra/cql3/CFName.java
new file mode 100644
index 0000000..cd6e6d3
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/CFName.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+package org.apache.cassandra.cql3;
+
+import java.util.Locale;
+
+public class CFName
+{
+    private String ksName;
+    private String cfName;
+
+    public void setKeyspace(String ks, boolean keepCase)
+    {
+        ksName = keepCase ? ks : ks.toLowerCase(Locale.US);
+    }
+
+    public void setColumnFamily(String cf, boolean keepCase)
+    {
+        cfName = keepCase ? cf : cf.toLowerCase(Locale.US);
+    }
+
+    public boolean hasKeyspace()
+    {
+        return ksName != null;
+    }
+
+    public String getKeyspace()
+    {
+        return ksName;
+    }
+
+    public String getColumnFamily()
+    {
+        return cfName;
+    }
+
+    @Override
+    public String toString()
+    {
+        return (hasKeyspace() ? (ksName + ".") : "") + cfName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/cql3/CFPropDefs.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/CFPropDefs.java b/src/java/org/apache/cassandra/cql3/CFPropDefs.java
new file mode 100644
index 0000000..e878e63
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/CFPropDefs.java
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+package org.apache.cassandra.cql3;
+
+import com.google.common.collect.Sets;
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.ConfigurationException;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.TypeParser;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class CFPropDefs
+{
+    private static Logger logger = LoggerFactory.getLogger(CFPropDefs.class);
+
+    public static final String KW_COMMENT = "comment";
+    public static final String KW_READREPAIRCHANCE = "read_repair_chance";
+    public static final String KW_GCGRACESECONDS = "gc_grace_seconds";
+    public static final String KW_MINCOMPACTIONTHRESHOLD = "min_compaction_threshold";
+    public static final String KW_MAXCOMPACTIONTHRESHOLD = "max_compaction_threshold";
+    public static final String KW_REPLICATEONWRITE = "replicate_on_write";
+
+    public static final String KW_COMPACTION_STRATEGY_CLASS = "compaction_strategy_class";
+
+    // Maps CQL short names to the respective Cassandra comparator/validator class names
+    public static final Map<String, String> comparators = new HashMap<String, String>();
+    public static final Set<String> keywords = new HashSet<String>();
+    public static final Set<String> obsoleteKeywords = new HashSet<String>();
+    public static final Set<String> allowedKeywords = new HashSet<String>();
+
+    public static final String COMPACTION_OPTIONS_PREFIX = "compaction_strategy_options";
+    public static final String COMPRESSION_PARAMETERS_PREFIX = "compression_parameters";
+
+    static
+    {
+        comparators.put("ascii", "AsciiType");
+        comparators.put("bigint", "LongType");
+        comparators.put("blob", "BytesType");
+        comparators.put("boolean", "BooleanType");
+        comparators.put("counter", "CounterColumnType");
+        comparators.put("decimal", "DecimalType");
+        comparators.put("double", "DoubleType");
+        comparators.put("float", "FloatType");
+        comparators.put("int", "Int32Type");
+        comparators.put("text", "UTF8Type");
+        comparators.put("timestamp", "DateType");
+        comparators.put("uuid", "UUIDType");
+        comparators.put("varchar", "UTF8Type");
+        comparators.put("varint", "IntegerType");
+
+        keywords.add(KW_COMMENT);
+        keywords.add(KW_READREPAIRCHANCE);
+        keywords.add(KW_GCGRACESECONDS);
+        keywords.add(KW_MINCOMPACTIONTHRESHOLD);
+        keywords.add(KW_MAXCOMPACTIONTHRESHOLD);
+        keywords.add(KW_REPLICATEONWRITE);
+        keywords.add(KW_COMPACTION_STRATEGY_CLASS);
+
+        obsoleteKeywords.add("row_cache_size");
+        obsoleteKeywords.add("key_cache_size");
+        obsoleteKeywords.add("row_cache_save_period_in_seconds");
+        obsoleteKeywords.add("key_cache_save_period_in_seconds");
+        obsoleteKeywords.add("memtable_throughput_in_mb");
+        obsoleteKeywords.add("memtable_operations_in_millions");
+        obsoleteKeywords.add("memtable_flush_after_mins");
+        obsoleteKeywords.add("row_cache_provider");
+        obsoleteKeywords.add("comparator");
+        obsoleteKeywords.add("default_validation");
+
+        allowedKeywords.addAll(keywords);
+        allowedKeywords.addAll(obsoleteKeywords);
+    }
+
+    public final Map<String, String> properties = new HashMap<String, String>();
+    public final Map<String, String> compactionStrategyOptions = new HashMap<String, String>();
+    public final Map<String, String> compressionParameters = new HashMap<String, String>();
+
+    public static AbstractType<?> parseType(String type) throws InvalidRequestException
+    {
+        try
+        {
+            String className = comparators.get(type);
+            if (className == null)
+                className = type;
+            return TypeParser.parse(className);
+        }
+        catch (ConfigurationException e)
+        {
+            InvalidRequestException ex = new InvalidRequestException(e.toString());
+            ex.initCause(e);
+            throw ex;
+        }
+    }
+
+    /* If not comparator/validator is not specified, default to text (BytesType is the wrong default for CQL
+     * since it uses hex terms).  If the value specified is not found in the comparators map, assume the user
+     * knows what they are doing (a custom comparator/validator for example), and pass it on as-is.
+     */
+
+    public void validate() throws InvalidRequestException
+    {
+        // Catch the case where someone passed a kwarg that is not recognized.
+        for (String bogus : Sets.difference(properties.keySet(), allowedKeywords))
+            throw new InvalidRequestException(bogus + " is not a valid keyword argument for CREATE COLUMNFAMILY");
+        for (String obsolete : Sets.intersection(properties.keySet(), obsoleteKeywords))
+            logger.warn("Ignoring obsolete property {}", obsolete);
+
+        // Validate min/max compaction thresholds
+        Integer minCompaction = getInt(KW_MINCOMPACTIONTHRESHOLD, null);
+        Integer maxCompaction = getInt(KW_MAXCOMPACTIONTHRESHOLD, null);
+
+        if ((minCompaction != null) && (maxCompaction != null))     // Both min and max are set
+        {
+            if ((minCompaction > maxCompaction) && (maxCompaction != 0))
+                throw new InvalidRequestException(String.format("%s cannot be larger than %s",
+                        KW_MINCOMPACTIONTHRESHOLD,
+                        KW_MAXCOMPACTIONTHRESHOLD));
+        }
+        else if (minCompaction != null)     // Only the min threshold is set
+        {
+            if (minCompaction > CFMetaData.DEFAULT_MAX_COMPACTION_THRESHOLD)
+                throw new InvalidRequestException(String.format("%s cannot be larger than %s, (default %s)",
+                        KW_MINCOMPACTIONTHRESHOLD,
+                        KW_MAXCOMPACTIONTHRESHOLD,
+                        CFMetaData.DEFAULT_MAX_COMPACTION_THRESHOLD));
+        }
+        else if (maxCompaction != null)     // Only the max threshold is set
+        {
+            if ((maxCompaction < CFMetaData.DEFAULT_MIN_COMPACTION_THRESHOLD) && (maxCompaction != 0))
+                throw new InvalidRequestException(String.format("%s cannot be smaller than %s, (default %s)",
+                        KW_MAXCOMPACTIONTHRESHOLD,
+                        KW_MINCOMPACTIONTHRESHOLD,
+                        CFMetaData.DEFAULT_MIN_COMPACTION_THRESHOLD));
+        }
+    }
+
+    /** Map a keyword to the corresponding value */
+    public void addProperty(String name, String value)
+    {
+        String[] composite = name.split(":");
+        if (composite.length > 1)
+        {
+            if (composite[0].equals(COMPACTION_OPTIONS_PREFIX))
+            {
+                compactionStrategyOptions.put(composite[1], value);
+                return;
+            }
+            else if (composite[0].equals(COMPRESSION_PARAMETERS_PREFIX))
+            {
+                compressionParameters.put(composite[1], value);
+                return;
+            }
+        }
+        properties.put(name, value);
+    }
+
+    public void addAll(Map<String, String> propertyMap)
+    {
+        for (Map.Entry<String, String> entry : propertyMap.entrySet())
+            addProperty(entry.getKey(), entry.getValue());
+    }
+
+    public Boolean hasProperty(String name)
+    {
+        return properties.containsKey(name);
+    }
+
+    public String get(String name)
+    {
+        return properties.get(name);
+    }
+
+    public String getString(String key, String defaultValue)
+    {
+        String value = properties.get(key);
+        return value != null ? value : defaultValue;
+    }
+
+    // Return a property value, typed as a Boolean
+    public Boolean getBoolean(String key, Boolean defaultValue) throws InvalidRequestException
+    {
+        String value = properties.get(key);
+        return (value == null) ? defaultValue : value.toLowerCase().matches("(1|true|yes)");
+    }
+
+    // Return a property value, typed as a Double
+    public Double getDouble(String key, Double defaultValue) throws InvalidRequestException
+    {
+        Double result;
+        String value = properties.get(key);
+
+        if (value == null)
+            result = defaultValue;
+        else
+        {
+            try
+            {
+                result = Double.parseDouble(value);
+            }
+            catch (NumberFormatException e)
+            {
+                throw new InvalidRequestException(String.format("%s not valid for \"%s\"", value, key));
+            }
+        }
+        return result;
+    }
+
+    // Return a property value, typed as an Integer
+    public Integer getInt(String key, Integer defaultValue) throws InvalidRequestException
+    {
+        Integer result;
+        String value = properties.get(key);
+
+        if (value == null)
+            result = defaultValue;
+        else
+        {
+            try
+            {
+                result = Integer.parseInt(value);
+            }
+            catch (NumberFormatException e)
+            {
+                throw new InvalidRequestException(String.format("%s not valid for \"%s\"", value, key));
+            }
+        }
+        return result;
+    }
+
+    public String toString()
+    {
+        return String.format("CFPropDefs(%s, compaction: %s, compression: %s)",
+                             properties.toString(),
+                             compactionStrategyOptions.toString(),
+                             compressionParameters.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/cql3/CQLStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/CQLStatement.java b/src/java/org/apache/cassandra/cql3/CQLStatement.java
new file mode 100644
index 0000000..90277c0
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/CQLStatement.java
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+package org.apache.cassandra.cql3;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.thrift.SchemaDisagreementException;
+import org.apache.cassandra.thrift.TimedOutException;
+import org.apache.cassandra.thrift.UnavailableException;
+
+public abstract class CQLStatement
+{
+    private int boundTerms;
+
+    public int getBoundsTerms()
+    {
+        return boundTerms;
+    }
+
+    // Used by the parser and preparable statement
+    public void setBoundTerms(int boundTerms)
+    {
+        this.boundTerms = boundTerms;
+    }
+
+    /**
+     * Perform any access verification necessary for the statement.
+     *
+     * @param state the current client state
+     */
+    public abstract void checkAccess(ClientState state) throws InvalidRequestException;
+
+    /**
+     * Perform additional validation required by the statment.
+     * To be overriden by subclasses if needed.
+     *
+     * @param state the current client state
+     */
+    public void validate(ClientState state) throws InvalidRequestException, SchemaDisagreementException
+    {}
+
+    /**
+     * Execute the statement and return the resulting result or null if there is no result.
+     *
+     * @param state the current client state
+     * @param variables the values for bounded variables. The implementation
+     * can assume that each bound term have a corresponding value.
+     */
+    public abstract CqlResult execute(ClientState state, List<ByteBuffer> variables) throws InvalidRequestException, UnavailableException, TimedOutException, SchemaDisagreementException;
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
new file mode 100644
index 0000000..60f3ecb
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+package org.apache.cassandra.cql3;
+
+import java.util.Locale;
+import java.nio.charset.CharacterCodingException;
+import java.nio.ByteBuffer;
+
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+/**
+ * Represents an identifer for a CQL column definition.
+ */
+public class ColumnIdentifier implements Comparable<ColumnIdentifier>
+{
+    public final ByteBuffer key;
+    private final String text;
+
+    public ColumnIdentifier(String rawText, boolean keepCase)
+    {
+        this.text = keepCase ? rawText : rawText.toLowerCase(Locale.US);
+        this.key = ByteBufferUtil.bytes(this.text);
+    }
+
+    public ColumnIdentifier(ByteBuffer key)
+    {
+        try
+        {
+            this.key = key;
+            this.text = ByteBufferUtil.string(key);
+        }
+        catch (CharacterCodingException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public final int hashCode()
+    {
+        return key.hashCode();
+    }
+
+    @Override
+    public final boolean equals(Object o)
+    {
+        if(!(o instanceof ColumnIdentifier))
+            return false;
+        ColumnIdentifier that = (ColumnIdentifier)o;
+        return key.equals(that.key);
+    }
+
+    @Override
+    public String toString()
+    {
+        return text;
+    }
+
+    public int compareTo(ColumnIdentifier other)
+    {
+        return key.compareTo(other.key);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/cql3/ColumnNameBuilder.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/ColumnNameBuilder.java b/src/java/org/apache/cassandra/cql3/ColumnNameBuilder.java
new file mode 100644
index 0000000..d9ca902
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/ColumnNameBuilder.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+package org.apache.cassandra.cql3;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.thrift.InvalidRequestException;
+
+/**
+ * Build a potentially composite column name.
+ */
+public interface ColumnNameBuilder
+{
+    /**
+     * Add a new ByteBuffer as the next component for this name.
+     * @param bb the ByteBuffer to add
+     * @throws IllegalStateException if the builder if full, i.e. if enough component has been added.
+     * @return this builder
+     */
+    public ColumnNameBuilder add(ByteBuffer bb);
+
+    /**
+     * Add a new Term as the next component for this name.
+     * @param t the Term to add
+     * @param op the relationship this component should respect.
+     * @param variables the variables corresponding to prepared markers
+     * @throws IllegalStateException if the builder if full, i.e. if enough component has been added.
+     * @return this builder
+     */
+    public ColumnNameBuilder add(Term t, Relation.Type op, List<ByteBuffer> variables) throws InvalidRequestException;
+
+    /**
+     * Returns the number of component already added to this builder.
+     * @return the number of component in this Builder
+     */
+    public int componentCount();
+
+    /**
+     * Build the column name.
+     * @return the built column name
+     */
+    public ByteBuffer build();
+
+    /**
+     * Build the column name so that the result sorts at the end of the range
+     * represented by this (uncomplete) column name.
+     * @throws IllegalStateException if the builder is empty or full.
+     */
+    public ByteBuffer buildAsEndOfRange();
+
+    /**
+     * Clone this builder.
+     * @return the cloned builder.
+     */
+    public ColumnNameBuilder copy();
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/cql3/Cql.g
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Cql.g b/src/java/org/apache/cassandra/cql3/Cql.g
new file mode 100644
index 0000000..13b2956
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@ -0,0 +1,633 @@
+/*
+ * 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.
+ */
+
+grammar Cql;
+
+options {
+    language = Java;
+}
+
+@header {
+    package org.apache.cassandra.cql3;
+
+    import java.util.Map;
+    import java.util.HashMap;
+    import java.util.Collections;
+    import java.util.List;
+    import java.util.ArrayList;
+
+    import org.apache.cassandra.cql3.statements.*;
+    import org.apache.cassandra.utils.Pair;
+    import org.apache.cassandra.thrift.ConsistencyLevel;
+    import org.apache.cassandra.thrift.InvalidRequestException;
+}
+
+@members {
+    private List<String> recognitionErrors = new ArrayList<String>();
+    private int currentBindMarkerIdx = -1;
+
+    public void displayRecognitionError(String[] tokenNames, RecognitionException e)
+    {
+        String hdr = getErrorHeader(e);
+        String msg = getErrorMessage(e, tokenNames);
+        recognitionErrors.add(hdr + " " + msg);
+    }
+
+    public List<String> getRecognitionErrors()
+    {
+        return recognitionErrors;
+    }
+
+    public void throwLastRecognitionError() throws InvalidRequestException
+    {
+        if (recognitionErrors.size() > 0)
+            throw new InvalidRequestException(recognitionErrors.get((recognitionErrors.size()-1)));
+    }
+
+    // used by UPDATE of the counter columns to validate if '-' was supplied by user
+    public void validateMinusSupplied(Object op, final Term value, IntStream stream) throws MissingTokenException
+    {
+        if (op == null && (value.isBindMarker() || Long.parseLong(value.getText()) > 0))
+            throw new MissingTokenException(102, stream, value);
+    }
+
+}
+
+@lexer::header {
+    package org.apache.cassandra.cql3;
+
+    import org.apache.cassandra.thrift.InvalidRequestException;
+}
+
+@lexer::members {
+    List<Token> tokens = new ArrayList<Token>();
+
+    public void emit(Token token)
+    {
+        state.token = token;
+        tokens.add(token);
+    }
+
+    public Token nextToken()
+    {
+        super.nextToken();
+        if (tokens.size() == 0)
+            return Token.EOF_TOKEN;
+        return tokens.remove(0);
+    }
+
+    private List<String> recognitionErrors = new ArrayList<String>();
+
+    public void displayRecognitionError(String[] tokenNames, RecognitionException e)
+    {
+        String hdr = getErrorHeader(e);
+        String msg = getErrorMessage(e, tokenNames);
+        recognitionErrors.add(hdr + " " + msg);
+    }
+
+    public List<String> getRecognitionErrors()
+    {
+        return recognitionErrors;
+    }
+
+    public void throwLastRecognitionError() throws InvalidRequestException
+    {
+        if (recognitionErrors.size() > 0)
+            throw new InvalidRequestException(recognitionErrors.get((recognitionErrors.size()-1)));
+    }
+}
+
+/** STATEMENTS **/
+
+query returns [CQLStatement stmnt]
+    : st=cqlStatement (';')* EOF { $stmnt = st; }
+    ;
+
+cqlStatement returns [CQLStatement stmt]
+    @after{ if (stmt != null) stmt.setBoundTerms(currentBindMarkerIdx + 1); }
+    : st1= selectStatement             { $stmt = st1; }
+    | st2= insertStatement             { $stmt = st2; }
+    | st3= updateStatement             { $stmt = st3; }
+    | st4= batchStatement              { $stmt = st4; }
+    | st5= deleteStatement             { $stmt = st5; }
+    | st6= useStatement                { $stmt = st6; }
+    | st7= truncateStatement           { $stmt = st7; }
+    | st8= createKeyspaceStatement     { $stmt = st8; }
+    | st9= createColumnFamilyStatement { $stmt = st9; }
+    | st10=createIndexStatement        { $stmt = st10; }
+    | st11=dropKeyspaceStatement       { $stmt = st11; }
+    | st12=dropColumnFamilyStatement   { $stmt = st12; }
+    | st13=dropIndexStatement          { $stmt = st13; }
+    | st14=alterTableStatement         { $stmt = st14; }
+    ;
+
+/*
+ * USE <KEYSPACE>;
+ */
+useStatement returns [UseStatement stmt]
+    : K_USE ks=keyspaceName { $stmt = new UseStatement(ks); }
+    ;
+
+/**
+ * SELECT <expression>
+ * FROM <CF>
+ * USING CONSISTENCY <LEVEL>
+ * WHERE KEY = "key1" AND COL > 1 AND COL < 100
+ * LIMIT <NUMBER>;
+ */
+selectStatement returns [SelectStatement.RawStatement expr]
+    @init {
+        boolean isCount = false;
+        ConsistencyLevel cLevel = ConsistencyLevel.ONE;
+        int limit = 10000;
+        boolean reversed = false;
+    }
+    : K_SELECT ( sclause=selectClause | (K_COUNT '(' sclause=selectClause ')' { isCount = true; }) )
+      K_FROM cf=columnFamilyName
+      ( K_USING K_CONSISTENCY K_LEVEL { cLevel = ConsistencyLevel.valueOf($K_LEVEL.text.toUpperCase()); } )?
+      ( K_WHERE wclause=whereClause )?
+      ( K_ORDER (K_ASC | K_DESC { reversed = true; }) )?
+      ( K_LIMIT rows=INTEGER { limit = Integer.parseInt($rows.text); } )?
+      {
+          SelectStatement.Parameters params = new SelectStatement.Parameters(cLevel,
+                                                                             limit,
+                                                                             reversed,
+                                                                             isCount);
+          $expr = new SelectStatement.RawStatement(cf, params, sclause, wclause);
+      }
+    ;
+
+selectClause returns [List<ColumnIdentifier> expr]
+    : ids=cidentList { $expr = ids; }
+    | '\*'           { $expr = Collections.<ColumnIdentifier>emptyList();}
+    ;
+
+whereClause returns [List<Relation> clause]
+    @init{ $clause = new ArrayList<Relation>(); }
+    : first=relation { $clause.add(first); } (K_AND next=relation { $clause.add(next); })*
+    ;
+
+/**
+ * INSERT INTO <CF> (<column>, <column>, <column>, ...)
+ * VALUES (<value>, <value>, <value>, ...)
+ * USING CONSISTENCY <level> AND TIMESTAMP <long>;
+ *
+ * Consistency level is set to ONE by default
+ */
+insertStatement returns [UpdateStatement expr]
+    @init {
+        Attributes attrs = new Attributes();
+        List<ColumnIdentifier> columnNames  = new ArrayList<ColumnIdentifier>();
+        List<Term> columnValues = new ArrayList<Term>();
+    }
+    : K_INSERT K_INTO cf=columnFamilyName
+          '(' c1=cident { columnNames.add(c1); }  ( ',' cn=cident { columnNames.add(cn); } )+ ')'
+        K_VALUES
+          '(' v1=term { columnValues.add(v1); } ( ',' vn=term { columnValues.add(vn); } )+ ')'
+        ( usingClause[attrs] )?
+      {
+          $expr = new UpdateStatement(cf, columnNames, columnValues, attrs);
+      }
+    ;
+
+usingClause[Attributes attrs]
+    : K_USING usingClauseObjective[attrs] ( K_AND? usingClauseObjective[attrs] )*
+    ;
+
+usingClauseDelete[Attributes attrs]
+    : K_USING usingClauseDeleteObjective[attrs] ( K_AND? usingClauseDeleteObjective[attrs] )*
+    ;
+
+usingClauseDeleteObjective[Attributes attrs]
+    : K_CONSISTENCY K_LEVEL  { attrs.cLevel = ConsistencyLevel.valueOf($K_LEVEL.text.toUpperCase()); }
+    | K_TIMESTAMP ts=INTEGER { attrs.timestamp = Long.valueOf($ts.text); }
+    ;
+
+usingClauseObjective[Attributes attrs]
+    : usingClauseDeleteObjective[attrs]
+    | K_TTL t=INTEGER { attrs.timeToLive = Integer.valueOf($t.text); }
+    ;
+
+/**
+ * UPDATE <CF>
+ * USING CONSISTENCY <level> AND TIMESTAMP <long>
+ * SET name1 = value1, name2 = value2
+ * WHERE key = value;
+ */
+updateStatement returns [UpdateStatement expr]
+    @init {
+        Attributes attrs = new Attributes();
+        Map<ColumnIdentifier, Operation> columns = new HashMap<ColumnIdentifier, Operation>();
+    }
+    : K_UPDATE cf=columnFamilyName
+      ( usingClause[attrs] )?
+      K_SET termPairWithOperation[columns] (',' termPairWithOperation[columns])*
+      K_WHERE wclause=whereClause
+      {
+          return new UpdateStatement(cf, columns, wclause, attrs);
+      }
+    ;
+
+/**
+ * DELETE name1, name2
+ * FROM <CF>
+ * USING CONSISTENCY <level> AND TIMESTAMP <long>
+ * WHERE KEY = keyname;
+ */
+deleteStatement returns [DeleteStatement expr]
+    @init {
+        Attributes attrs = new Attributes();
+        List<ColumnIdentifier> columnsList = Collections.emptyList();
+    }
+    : K_DELETE ( ids=cidentList { columnsList = ids; } )?
+      K_FROM cf=columnFamilyName
+      ( usingClauseDelete[attrs] )?
+      K_WHERE wclause=whereClause
+      {
+          return new DeleteStatement(cf, columnsList, wclause, attrs);
+      }
+    ;
+
+
+/**
+ * BEGIN BATCH [USING CONSISTENCY <LVL>]
+ *   UPDATE <CF> SET name1 = value1 WHERE KEY = keyname1;
+ *   UPDATE <CF> SET name2 = value2 WHERE KEY = keyname2;
+ *   UPDATE <CF> SET name3 = value3 WHERE KEY = keyname3;
+ *   ...
+ * APPLY BATCH
+ *
+ * OR
+ *
+ * BEGIN BATCH [USING CONSISTENCY <LVL>]
+ *   INSERT INTO <CF> (KEY, <name>) VALUES ('<key>', '<value>');
+ *   INSERT INTO <CF> (KEY, <name>) VALUES ('<key>', '<value>');
+ *   ...
+ * APPLY BATCH
+ *
+ * OR
+ *
+ * BEGIN BATCH [USING CONSISTENCY <LVL>]
+ *   DELETE name1, name2 FROM <CF> WHERE key = <key>
+ *   DELETE name3, name4 FROM <CF> WHERE key = <key>
+ *   ...
+ * APPLY BATCH
+ */
+batchStatement returns [BatchStatement expr]
+    @init {
+        Attributes attrs = new Attributes();
+        List<ModificationStatement> statements = new ArrayList<ModificationStatement>();
+    }
+    : K_BEGIN K_BATCH ( usingClause[attrs] )?
+          s1=batchStatementObjective ';'? { statements.add(s1); } ( sN=batchStatementObjective ';'? { statements.add(sN); } )*
+      K_APPLY K_BATCH
+      {
+          return new BatchStatement(statements, attrs);
+      }
+    ;
+
+batchStatementObjective returns [ModificationStatement statement]
+    : i=insertStatement  { $statement = i; }
+    | u=updateStatement  { $statement = u; }
+    | d=deleteStatement  { $statement = d; }
+    ;
+
+/**
+ * CREATE KEYSPACE <KEYSPACE> WITH attr1 = value1 AND attr2 = value2;
+ */
+createKeyspaceStatement returns [CreateKeyspaceStatement expr]
+    : K_CREATE K_KEYSPACE ks=keyspaceName
+      K_WITH props=properties { $expr = new CreateKeyspaceStatement(ks, props); }
+    ;
+
+/**
+ * CREATE COLUMNFAMILY <CF> (
+ *     <name1> <type>,
+ *     <name2> <type>,
+ *     <name3> <type>
+ * ) WITH <property> = <value> AND ...;
+ */
+createColumnFamilyStatement returns [CreateColumnFamilyStatement.RawStatement expr]
+    : K_CREATE K_COLUMNFAMILY cf=columnFamilyName { $expr = new CreateColumnFamilyStatement.RawStatement(cf); }
+      cfamDefinition[expr]
+    ;
+
+cfamDefinition[CreateColumnFamilyStatement.RawStatement expr]
+    : '(' cfamColumns[expr] ( ',' cfamColumns[expr]? )* ')'
+      ( K_WITH cfamProperty[expr] ( K_AND cfamProperty[expr] )*)?
+    ;
+
+cfamColumns[CreateColumnFamilyStatement.RawStatement expr]
+    : k=cident v=comparatorType { $expr.addDefinition(k, v); } (K_PRIMARY K_KEY { $expr.setKeyAlias(k); })?
+    | K_PRIMARY K_KEY '(' k=cident { $expr.setKeyAlias(k); } (',' c=cident { $expr.addColumnAlias(c); } )* ')'
+    ;
+
+cfamProperty[CreateColumnFamilyStatement.RawStatement expr]
+    : k=property '=' v=propertyValue { $expr.addProperty(k, v); }
+    | K_COMPACT K_STORAGE { $expr.setCompactStorage(); }
+    ;
+
+/**
+ * CREATE INDEX [indexName] ON columnFamily (columnName);
+ */
+createIndexStatement returns [CreateIndexStatement expr]
+    : K_CREATE K_INDEX (idxName=IDENT)? K_ON cf=columnFamilyName '(' id=cident ')'
+      { $expr = new CreateIndexStatement(cf, $idxName.text, id); }
+    ;
+
+/**
+ * ALTER COLUMN FAMILY <CF> ALTER <column> TYPE <newtype>;
+ * ALTER COLUMN FAMILY <CF> ADD <column> <newtype>;
+ * ALTER COLUMN FAMILY <CF> DROP <column>;
+ * ALTER COLUMN FAMILY <CF> WITH <property> = <value>;
+ */
+alterTableStatement returns [AlterTableStatement expr]
+    @init {
+        AlterTableStatement.Type type = null;
+        String validator = null;
+        ColumnIdentifier columnName = null;
+        Map<String, String> propertyMap = null;
+    }
+    : K_ALTER K_COLUMNFAMILY cf=columnFamilyName
+          ( K_ALTER id=cident K_TYPE v=comparatorType { type = AlterTableStatement.Type.ALTER; }
+          | K_ADD   id=cident v=comparatorType        { type = AlterTableStatement.Type.ADD; }
+          | K_DROP  id=cident                         { type = AlterTableStatement.Type.DROP; }
+          | K_WITH  props=properties                  { type = AlterTableStatement.Type.OPTS; }
+          )
+    {
+        $expr = new AlterTableStatement(cf, type, id, v, props);
+    }
+    ;
+
+/**
+ * DROP KEYSPACE <KSP>;
+ */
+dropKeyspaceStatement returns [DropKeyspaceStatement ksp]
+    : K_DROP K_KEYSPACE ks=keyspaceName { $ksp = new DropKeyspaceStatement(ks); }
+    ;
+
+/**
+ * DROP COLUMNFAMILY <CF>;
+ */
+dropColumnFamilyStatement returns [DropColumnFamilyStatement stmt]
+    : K_DROP K_COLUMNFAMILY cf=columnFamilyName { $stmt = new DropColumnFamilyStatement(cf); }
+    ;
+
+/**
+ * DROP INDEX <INDEX_NAME>
+ */
+dropIndexStatement returns [DropIndexStatement expr]
+    :
+      K_DROP K_INDEX index=IDENT
+      { $expr = new DropIndexStatement($index.text); }
+    ;
+
+/**
+  * TRUNCATE <CF>;
+  */
+truncateStatement returns [TruncateStatement stmt]
+    : K_TRUNCATE cf=columnFamilyName { $stmt = new TruncateStatement(cf); }
+    ;
+
+
+/** DEFINITIONS **/
+
+// Column Identifiers
+cident returns [ColumnIdentifier id]
+    : t=( IDENT | UUID | INTEGER ) { $id = new ColumnIdentifier($t.text, false); }
+    | t=QUOTED_NAME                { $id = new ColumnIdentifier($t.text, true); }
+    ;
+
+// Keyspace & Column family names
+keyspaceName returns [String id]
+    @init { CFName name = new CFName(); }
+    : cfOrKsName[name, true] { $id = name.getKeyspace(); }
+    ;
+
+columnFamilyName returns [CFName name]
+    @init { $name = new CFName(); }
+    : (cfOrKsName[name, true] '.')? cfOrKsName[name, false]
+    ;
+
+cfOrKsName[CFName name, boolean isKs]
+    : t=IDENT        { if (isKs) $name.setKeyspace($t.text, false); else $name.setColumnFamily($t.text, false); }
+    | t=QUOTED_NAME  { if (isKs) $name.setKeyspace($t.text, true); else $name.setColumnFamily($t.text, true); }
+    ;
+
+cidentList returns [List<ColumnIdentifier> items]
+    @init{ $items = new ArrayList<ColumnIdentifier>(); }
+    :  t1=cident { $items.add(t1); } (',' tN=cident { $items.add(tN); })*
+    ;
+
+// Values (includes prepared statement markers)
+term returns [Term term]
+    : t=(STRING_LITERAL | UUID | IDENT | INTEGER | FLOAT ) { $term = new Term($t.text, $t.type); }
+    | t=QMARK                                              { $term = new Term($t.text, $t.type, ++currentBindMarkerIdx); }
+    ;
+
+intTerm returns [Term integer]
+    : t=INTEGER { $integer = new Term($t.text, $t.type); }
+    | t=QMARK   { $integer = new Term($t.text, $t.type, ++currentBindMarkerIdx); }
+    ;
+
+termPairWithOperation[Map<ColumnIdentifier, Operation> columns]
+    : key=cident '='
+        ( value=term { columns.put(key, new Operation(value)); }
+        | c=cident ( '+'     v=intTerm { columns.put(key, new Operation(c, Operation.Type.PLUS, v)); }
+                   | op='-'? v=intTerm
+                     {
+                       validateMinusSupplied(op, v, input);
+                       if (op == null)
+                           v = new Term(-(Long.valueOf(v.getText())), v.getType());
+                       columns.put(key, new Operation(c, Operation.Type.MINUS, v));
+                     }
+                    )
+        )
+    ;
+
+property returns [String str]
+    : p=(COMPIDENT | IDENT) { $str = $p.text; }
+    ;
+
+propertyValue returns [String str]
+    : v=(STRING_LITERAL | IDENT | INTEGER | FLOAT) { $str = $v.text; }
+    ;
+
+properties returns [Map<String, String> props]
+    @init{ $props = new HashMap<String, String>(); }
+    : k1=property '=' v1=propertyValue { $props.put(k1, v1); } (K_AND kn=property '=' vn=propertyValue { $props.put(kn, vn); } )*
+    ;
+
+relation returns [Relation rel]
+    : name=cident type=('=' | '<' | '<=' | '>=' | '>') t=term { $rel = new Relation($name.id, $type.text, $t.term); }
+    | name=cident K_IN { $rel = Relation.createInRelation($name.id); }
+      '(' f1=term { $rel.addInValue(f1); } (',' fN=term { $rel.addInValue(fN); } )* ')'
+    ;
+
+comparatorType returns [String str]
+    : c=(IDENT | STRING_LITERAL) { $str = $c.text; }
+    ;
+
+
+// Case-insensitive keywords
+K_SELECT:      S E L E C T;
+K_FROM:        F R O M;
+K_WHERE:       W H E R E;
+K_AND:         A N D;
+K_KEY:         K E Y;
+K_INSERT:      I N S E R T;
+K_UPDATE:      U P D A T E;
+K_WITH:        W I T H;
+K_LIMIT:       L I M I T;
+K_USING:       U S I N G;
+K_CONSISTENCY: C O N S I S T E N C Y;
+K_LEVEL:       ( O N E
+               | Q U O R U M
+               | A L L
+               | A N Y
+               | L O C A L '_' Q U O R U M
+               | E A C H '_' Q U O R U M
+               )
+               ;
+K_USE:         U S E;
+K_COUNT:       C O U N T;
+K_SET:         S E T;
+K_BEGIN:       B E G I N;
+K_APPLY:       A P P L Y;
+K_BATCH:       B A T C H;
+K_TRUNCATE:    T R U N C A T E;
+K_DELETE:      D E L E T E;
+K_IN:          I N;
+K_CREATE:      C R E A T E;
+K_KEYSPACE:    ( K E Y S P A C E
+                 | S C H E M A );
+K_COLUMNFAMILY:( C O L U M N F A M I L Y
+                 | T A B L E );
+K_INDEX:       I N D E X;
+K_ON:          O N;
+K_DROP:        D R O P;
+K_PRIMARY:     P R I M A R Y;
+K_INTO:        I N T O;
+K_VALUES:      V A L U E S;
+K_TIMESTAMP:   T I M E S T A M P;
+K_TTL:         T T L;
+K_ALTER:       A L T E R;
+K_ADD:         A D D;
+K_TYPE:        T Y P E;
+K_COMPACT:     C O M P A C T;
+K_STORAGE:     S T O R A G E;
+K_ORDER:       O R D E R;
+K_ASC:         A S C;
+K_DESC:        D E S C;
+
+// Case-insensitive alpha characters
+fragment A: ('a'|'A');
+fragment B: ('b'|'B');
+fragment C: ('c'|'C');
+fragment D: ('d'|'D');
+fragment E: ('e'|'E');
+fragment F: ('f'|'F');
+fragment G: ('g'|'G');
+fragment H: ('h'|'H');
+fragment I: ('i'|'I');
+fragment J: ('j'|'J');
+fragment K: ('k'|'K');
+fragment L: ('l'|'L');
+fragment M: ('m'|'M');
+fragment N: ('n'|'N');
+fragment O: ('o'|'O');
+fragment P: ('p'|'P');
+fragment Q: ('q'|'Q');
+fragment R: ('r'|'R');
+fragment S: ('s'|'S');
+fragment T: ('t'|'T');
+fragment U: ('u'|'U');
+fragment V: ('v'|'V');
+fragment W: ('w'|'W');
+fragment X: ('x'|'X');
+fragment Y: ('y'|'Y');
+fragment Z: ('z'|'Z');
+
+STRING_LITERAL
+    @init{ StringBuilder b = new StringBuilder(); }
+    @after{ setText(b.toString()); }
+    : '\'' (c=~('\'') { b.appendCodePoint(c);} | '\'' '\'' { b.appendCodePoint('\''); })* '\''
+    ;
+
+QUOTED_NAME
+    @init{ StringBuilder b = new StringBuilder(); }
+    @after{ setText(b.toString()); }
+    : '\"' (c=~('\"') { b.appendCodePoint(c); } | '\"' '\"' { b.appendCodePoint('\"'); })* '\"'
+    ;
+
+fragment DIGIT
+    : '0'..'9'
+    ;
+
+fragment LETTER
+    : ('A'..'Z' | 'a'..'z')
+    ;
+
+fragment HEX
+    : ('A'..'F' | 'a'..'f' | '0'..'9')
+    ;
+
+INTEGER
+    : '-'? DIGIT+
+    ;
+
+QMARK
+    : '?'
+    ;
+
+/*
+ * Normally a lexer only emits one token at a time, but ours is tricked out
+ * to support multiple (see @lexer::members near the top of the grammar).
+ */
+FLOAT
+    : INTEGER '.' INTEGER
+    ;
+
+IDENT
+    : LETTER (LETTER | DIGIT | '_')*
+    ;
+
+COMPIDENT
+    : IDENT ( ':' (IDENT | INTEGER))+
+    ;
+
+UUID
+    : HEX HEX HEX HEX HEX HEX HEX HEX '-'
+      HEX HEX HEX HEX '-'
+      HEX HEX HEX HEX '-'
+      HEX HEX HEX HEX '-'
+      HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX
+    ;
+
+WS
+    : (' ' | '\t' | '\n' | '\r')+ { $channel = HIDDEN; }
+    ;
+
+COMMENT
+    : ('--' | '//') .* ('\n'|'\r') { $channel = HIDDEN; }
+    ;
+
+MULTILINE_COMMENT
+    : '/*' .* '*/' { $channel = HIDDEN; }
+    ;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/cql3/Operation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Operation.java b/src/java/org/apache/cassandra/cql3/Operation.java
new file mode 100644
index 0000000..63097b9
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/Operation.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+package org.apache.cassandra.cql3;
+
+public class Operation
+{
+    public static enum Type { PLUS, MINUS }
+
+    public final Type type;
+    public final ColumnIdentifier ident;
+    public final Term value;
+
+    // unary operation
+    public Operation(Term a)
+    {
+        this(null, null, a);
+    }
+
+    // binary operation
+    public Operation(ColumnIdentifier a, Type type, Term b)
+    {
+        this.ident = a;
+        this.type = type;
+        this.value = b;
+    }
+
+    public boolean isUnary()
+    {
+        return type == null && ident == null;
+    }
+
+    public String toString()
+    {
+        return (isUnary())
+                ? String.format("UnaryOperation(%s)", value)
+                : String.format("BinaryOperation(%s, %s, %s)", ident, type, value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/655ccc3a/src/java/org/apache/cassandra/cql3/QueryProcessor.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/QueryProcessor.java b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
new file mode 100644
index 0000000..7c82616
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+package org.apache.cassandra.cql3;
+
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Maps;
+import org.antlr.runtime.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.cassandra.cql3.statements.*;
+import org.apache.cassandra.config.*;
+import org.apache.cassandra.db.*;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.thrift.*;
+import org.apache.cassandra.thrift.Column;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.Pair;
+import org.apache.cassandra.utils.SemanticVersion;
+
+public class QueryProcessor
+{
+    public static final SemanticVersion CQL_VERSION = new SemanticVersion("3.0.0-beta1");
+
+    private static final Logger logger = LoggerFactory.getLogger(QueryProcessor.class);
+
+    public static void validateKey(ByteBuffer key) throws InvalidRequestException
+    {
+        if (key == null || key.remaining() == 0)
+        {
+            throw new InvalidRequestException("Key may not be empty");
+        }
+
+        // check that key can be handled by FBUtilities.writeShortByteArray
+        if (key.remaining() > FBUtilities.MAX_UNSIGNED_SHORT)
+        {
+            throw new InvalidRequestException("Key length of " + key.remaining() +
+                                              " is longer than maximum of " + FBUtilities.MAX_UNSIGNED_SHORT);
+        }
+    }
+
+    public static void validateColumnNames(Iterable<ByteBuffer> columns)
+    throws InvalidRequestException
+    {
+        for (ByteBuffer name : columns)
+        {
+            if (name.remaining() > IColumn.MAX_NAME_LENGTH)
+                throw new InvalidRequestException(String.format("column name is too long (%s > %s)",
+                                                                name.remaining(),
+                                                                IColumn.MAX_NAME_LENGTH));
+            if (name.remaining() == 0)
+                throw new InvalidRequestException("zero-length column name");
+        }
+    }
+
+    public static void validateColumnName(ByteBuffer column)
+    throws InvalidRequestException
+    {
+        validateColumnNames(Collections.singletonList(column));
+    }
+
+    public static void validateSlicePredicate(CFMetaData metadata, SlicePredicate predicate)
+    throws InvalidRequestException
+    {
+        if (predicate.slice_range != null)
+            validateSliceRange(metadata, predicate.slice_range);
+        else
+            validateColumnNames(predicate.column_names);
+    }
+
+    public static void validateSliceRange(CFMetaData metadata, SliceRange range)
+    throws InvalidRequestException
+    {
+        validateSliceRange(metadata, range.start, range.finish, range.reversed);
+    }
+
+    public static void validateSliceRange(CFMetaData metadata, ByteBuffer start, ByteBuffer finish, boolean reversed)
+    throws InvalidRequestException
+    {
+        AbstractType<?> comparator = metadata.getComparatorFor(null);
+        Comparator<ByteBuffer> orderedComparator = reversed ? comparator.reverseComparator: comparator;
+        if (start.remaining() > 0 && finish.remaining() > 0 && orderedComparator.compare(start, finish) > 0)
+            throw new InvalidRequestException("Range finish must come after start in traversal order");
+    }
+
+    private static CqlResult processStatement(CQLStatement statement, ClientState clientState, List<ByteBuffer> variables)
+    throws  UnavailableException, InvalidRequestException, TimedOutException, SchemaDisagreementException
+    {
+        statement.checkAccess(clientState);
+        statement.validate(clientState);
+        CqlResult result = statement.execute(clientState, variables);
+        if (result == null)
+        {
+            result = new CqlResult();
+            result.type = CqlResultType.VOID;
+        }
+        return result;
+    }
+
+    public static CqlResult process(String queryString, ClientState clientState)
+    throws RecognitionException, UnavailableException, InvalidRequestException, TimedOutException, SchemaDisagreementException
+    {
+        logger.trace("CQL QUERY: {}", queryString);
+        return processStatement(getStatement(queryString, clientState), clientState, Collections.<ByteBuffer>emptyList());
+    }
+
+    public static CqlPreparedResult prepare(String queryString, ClientState clientState)
+    throws RecognitionException, InvalidRequestException
+    {
+        logger.trace("CQL QUERY: {}", queryString);
+
+        CQLStatement statement = getStatement(queryString, clientState);
+        int statementId = makeStatementId(queryString);
+        logger.trace("Discovered "+ statement.getBoundsTerms() + " bound variables.");
+
+        clientState.getCQL3Prepared().put(statementId, statement);
+        logger.trace(String.format("Stored prepared statement #%d with %d bind markers",
+                                   statementId,
+                                   statement.getBoundsTerms()));
+
+        return new CqlPreparedResult(statementId, statement.getBoundsTerms());
+    }
+
+    public static CqlResult processPrepared(CQLStatement statement, ClientState clientState, List<ByteBuffer> variables)
+    throws UnavailableException, InvalidRequestException, TimedOutException, SchemaDisagreementException
+    {
+        // Check to see if there are any bound variables to verify
+        if (!(variables.isEmpty() && (statement.getBoundsTerms() == 0)))
+        {
+            if (variables.size() != statement.getBoundsTerms())
+                throw new InvalidRequestException(String.format("there were %d markers(?) in CQL but %d bound variables",
+                                                                statement.getBoundsTerms(),
+                                                                variables.size()));
+
+            // at this point there is a match in count between markers and variables that is non-zero
+
+            if (logger.isTraceEnabled())
+                for (int i = 0; i < variables.size(); i++)
+                    logger.trace("[{}] '{}'", i+1, variables.get(i));
+        }
+
+        return processStatement(statement, clientState, variables);
+    }
+
+    private static final int makeStatementId(String cql)
+    {
+        // use the hash of the string till something better is provided
+        return cql.hashCode();
+    }
+
+    private static CQLStatement getStatement(String queryStr, ClientState clientState) throws InvalidRequestException, RecognitionException
+    {
+        CQLStatement statement = parseStatement(queryStr);
+
+        // Set keyspace for statement that require login
+        if (statement instanceof CFStatement)
+            ((CFStatement)statement).prepareKeyspace(clientState);
+
+        if (statement instanceof Preprocessable)
+            statement = ((Preprocessable)statement).preprocess();
+
+        return statement;
+    }
+
+    private static CQLStatement parseStatement(String queryStr) throws InvalidRequestException, RecognitionException
+    {
+        // Lexer and parser
+        CharStream stream = new ANTLRStringStream(queryStr);
+        CqlLexer lexer = new CqlLexer(stream);
+        TokenStream tokenStream = new CommonTokenStream(lexer);
+        CqlParser parser = new CqlParser(tokenStream);
+
+        // Parse the query string to a statement instance
+        CQLStatement statement = parser.query();
+
+        // The lexer and parser queue up any errors they may have encountered
+        // along the way, if necessary, we turn them into exceptions here.
+        lexer.throwLastRecognitionError();
+        parser.throwLastRecognitionError();
+
+        return statement;
+    }
+
+}


Mime
View raw message