Merge branch 'cassandra-3.0' into cassandra-3.X

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

Branch: refs/heads/cassandra-3.X
Commit: 206a7bbac70d8ad5f27eff7b22ccfc8ab703a31b
Parents: 771a1a2 153583b
Author: Carl Yeksigian <c...@apache.org>
Authored: Fri Oct 14 10:28:58 2016 -0400
Committer: Carl Yeksigian <c...@apache.org>
Committed: Fri Oct 14 10:28:58 2016 -0400

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 src/antlr/Lexer.g                               |   2 +
 src/antlr/Parser.g                              |   2 +-
 .../apache/cassandra/cql3/ColumnIdentifier.java |   2 +-
 .../apache/cassandra/cql3/ReservedKeywords.java | 118 +++++++++++++++++++
 .../org/apache/cassandra/cql3/ViewTest.java     |  20 ++++
 .../db/ColumnFamilyStoreCQLHelperTest.java      |   4 +-
 7 files changed, 145 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/206a7bba/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index bc5dcd1,e82eedd..0045ba5
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,85 -1,5 +1,86 @@@
 -3.0.10
 +3.10
 + * cqlsh fails to format collections when using aliases (CASSANDRA-11534)
 + * Check for hash conflicts in prepared statements (CASSANDRA-12733)
 + * Exit query parsing upon first error (CASSANDRA-12598)
 + * Fix cassandra-stress to use single seed in UUID generation 
(CASSANDRA-12729)
 + * CQLSSTableWriter does not allow Update statement (CASSANDRA-12450)
 + * Config class uses boxed types but DD exposes primitive types 
(CASSANDRA-12199)
 + * Add pre- and post-shutdown hooks to Storage Service (CASSANDRA-12461)
 + * Add hint delivery metrics (CASSANDRA-12693)
 + * Remove IndexInfo cache from FileIndexInfoRetriever (CASSANDRA-12731)
 + * ColumnIndex does not reuse buffer (CASSANDRA-12502)
 + * cdc column addition still breaks schema migration tasks (CASSANDRA-12697)
 + * Upgrade metrics-reporter dependencies (CASSANDRA-12089)
 + * Tune compaction thread count via nodetool (CASSANDRA-12248)
 + * Add +=/-= shortcut syntax for update queries (CASSANDRA-12232)
 + * Include repair session IDs in repair start message (CASSANDRA-12532)
 + * Add a blocking task to Index, run before joining the ring (CASSANDRA-12039)
 + * Fix NPE when using CQLSSTableWriter (CASSANDRA-12667)
 + * Support optional backpressure strategies at the coordinator 
(CASSANDRA-9318)
 + * Make randompartitioner work with new vnode allocation (CASSANDRA-12647)
 + * Fix cassandra-stress graphing (CASSANDRA-12237)
 + * Allow filtering on partition key columns for queries without secondary 
indexes (CASSANDRA-11031)
 + * Fix Cassandra Stress reporting thread model and precision (CASSANDRA-12585)
 + * Add JMH benchmarks.jar (CASSANDRA-12586)
 + * Add row offset support to SASI (CASSANDRA-11990)
 + * Cleanup uses of AlterTableStatementColumn (CASSANDRA-12567)
 + * Add keep-alive to streaming (CASSANDRA-11841)
 + * Tracing payload is passed through newSession(..) (CASSANDRA-11706)
 + * avoid deleting non existing sstable files and improve related log messages 
(CASSANDRA-12261)
 + * json/yaml output format for nodetool compactionhistory (CASSANDRA-12486)
 + * Retry all internode messages once after a connection is
 +   closed and reopened (CASSANDRA-12192)
 + * Add support to rebuild from targeted replica (CASSANDRA-9875)
 + * Add sequence distribution type to cassandra stress (CASSANDRA-12490)
 + * "SELECT * FROM foo LIMIT ;" does not error out (CASSANDRA-12154)
 + * Define executeLocally() at the ReadQuery Level (CASSANDRA-12474)
 + * Extend read/write failure messages with a map of replica addresses
 +   to error codes in the v5 native protocol (CASSANDRA-12311)
 + * Fix rebuild of SASI indexes with existing index files (CASSANDRA-12374)
 + * Let DatabaseDescriptor not implicitly startup services (CASSANDRA-9054, 
12550)
 + * Fix clustering indexes in presence of static columns in SASI 
(CASSANDRA-12378)
 + * Fix queries on columns with reversed type on SASI indexes (CASSANDRA-12223)
 + * Added slow query log (CASSANDRA-12403)
 + * Count full coordinated request against timeout (CASSANDRA-12256)
 + * Allow TTL with null value on insert and update (CASSANDRA-12216)
 + * Make decommission operation resumable (CASSANDRA-12008)
 + * Add support to one-way targeted repair (CASSANDRA-9876)
 + * Remove clientutil jar (CASSANDRA-11635)
 + * Fix compaction throughput throttle (CASSANDRA-12366, CASSANDRA-12717)
 + * Delay releasing Memtable memory on flush until PostFlush has finished 
running (CASSANDRA-12358)
 + * Cassandra stress should dump all setting on startup (CASSANDRA-11914)
 + * Make it possible to compact a given token range (CASSANDRA-10643)
 + * Allow updating DynamicEndpointSnitch properties via JMX (CASSANDRA-12179)
 + * Collect metrics on queries by consistency level (CASSANDRA-7384)
 + * Add support for GROUP BY to SELECT statement (CASSANDRA-10707)
 + * Deprecate memtable_cleanup_threshold and update default for 
memtable_flush_writers (CASSANDRA-12228)
 + * Upgrade to OHC 0.4.4 (CASSANDRA-12133)
 + * Add version command to cassandra-stress (CASSANDRA-12258)
 + * Create compaction-stress tool (CASSANDRA-11844)
 + * Garbage-collecting compaction operation and schema option (CASSANDRA-7019)
 + * Add beta protocol flag for v5 native protocol (CASSANDRA-12142)
 + * Support filtering on non-PRIMARY KEY columns in the CREATE
 +   MATERIALIZED VIEW statement's WHERE clause (CASSANDRA-10368)
 + * Unify STDOUT and SYSTEMLOG logback format (CASSANDRA-12004)
 + * COPY FROM should raise error for non-existing input files (CASSANDRA-12174)
 + * Faster write path (CASSANDRA-12269)
 + * Option to leave omitted columns in INSERT JSON unset (CASSANDRA-11424)
 + * Support json/yaml output in nodetool tpstats (CASSANDRA-12035)
 + * Expose metrics for successful/failed authentication attempts 
(CASSANDRA-10635)
 + * Prepend snapshot name with "truncated" or "dropped" when a snapshot
 +   is taken before truncating or dropping a table (CASSANDRA-12178)
 + * Optimize RestrictionSet (CASSANDRA-12153)
 + * cqlsh does not automatically downgrade CQL version (CASSANDRA-12150)
 + * Omit (de)serialization of state variable in UDAs (CASSANDRA-9613)
 + * Create a system table to expose prepared statements (CASSANDRA-8831)
 + * Reuse DataOutputBuffer from ColumnIndex (CASSANDRA-11970)
 + * Remove DatabaseDescriptor dependency from SegmentedFile (CASSANDRA-11580)
 + * Add supplied username to authentication error messages (CASSANDRA-12076)
 + * Remove pre-startup check for open JMX port (CASSANDRA-12074)
 + * Remove compaction Severity from DynamicEndpointSnitch (CASSANDRA-11738)
 + * Restore resumable hints delivery (CASSANDRA-11960)
 +Merged from 3.0:
+  * Preserve quoted reserved keyword column names in MV creation 
(CASSANDRA-11803)
   * nodetool stopdaemon errors out (CASSANDRA-12646)
   * Split materialized view mutations on build to prevent OOM (CASSANDRA-12268)
   * mx4j does not work in 3.0.8 (CASSANDRA-12274)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/206a7bba/src/antlr/Lexer.g
----------------------------------------------------------------------
diff --cc src/antlr/Lexer.g
index 0d79520,0000000..cbbfd6d
mode 100644,000000..100644
--- a/src/antlr/Lexer.g
+++ b/src/antlr/Lexer.g
@@@ -1,326 -1,0 +1,328 @@@
 +/*
 + * 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.
 + */
 +
 +lexer grammar Lexer;
 +
 +@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 new CommonToken(Token.EOF);
 +        return tokens.remove(0);
 +    }
 +
 +    private final List<ErrorListener> listeners = new 
ArrayList<ErrorListener>();
 +
 +    public void addErrorListener(ErrorListener listener)
 +    {
 +        this.listeners.add(listener);
 +    }
 +
 +    public void removeErrorListener(ErrorListener listener)
 +    {
 +        this.listeners.remove(listener);
 +    }
 +
 +    public void displayRecognitionError(String[] tokenNames, 
RecognitionException e)
 +    {
 +        for (int i = 0, m = listeners.size(); i < m; i++)
 +            listeners.get(i).syntaxError(this, tokenNames, e);
 +    }
 +}
 +
 +// Case-insensitive keywords
++// When adding a new reserved keyword, add entry to 
o.a.c.cql3.ReservedKeywords as well
++// When adding a new unreserved keyword, add entry to unreserved keywords in 
Parser.g
 +K_SELECT:      S E L E C T;
 +K_FROM:        F R O M;
 +K_AS:          A S;
 +K_WHERE:       W H E R E;
 +K_AND:         A N D;
 +K_KEY:         K E Y;
 +K_KEYS:        K E Y S;
 +K_ENTRIES:     E N T R I E S;
 +K_FULL:        F U L L;
 +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_PER:         P E R;
 +K_PARTITION:   P A R T I T I O N;
 +K_USING:       U S I N G;
 +K_USE:         U S E;
 +K_DISTINCT:    D I S T I N C T;
 +K_COUNT:       C O U N T;
 +K_SET:         S E T;
 +K_BEGIN:       B E G I N;
 +K_UNLOGGED:    U N L O G G E D;
 +K_BATCH:       B A T C H;
 +K_APPLY:       A P P L Y;
 +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_KEYSPACES:   K E Y S P A C E S;
 +K_COLUMNFAMILY:( C O L U M N F A M I L Y
 +                 | T A B L E );
 +K_MATERIALIZED:M A T E R I A L I Z E D;
 +K_VIEW:        V I E W;
 +K_INDEX:       I N D E X;
 +K_CUSTOM:      C U S T O M;
 +K_ON:          O N;
 +K_TO:          T O;
 +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_CAST:        C A S T;
 +K_ALTER:       A L T E R;
 +K_RENAME:      R E N A M E;
 +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_BY:          B Y;
 +K_ASC:         A S C;
 +K_DESC:        D E S C;
 +K_ALLOW:       A L L O W;
 +K_FILTERING:   F I L T E R I N G;
 +K_IF:          I F;
 +K_IS:          I S;
 +K_CONTAINS:    C O N T A I N S;
 +K_GROUP:       G R O U P;
 +
 +K_GRANT:       G R A N T;
 +K_ALL:         A L L;
 +K_PERMISSION:  P E R M I S S I O N;
 +K_PERMISSIONS: P E R M I S S I O N S;
 +K_OF:          O F;
 +K_REVOKE:      R E V O K E;
 +K_MODIFY:      M O D I F Y;
 +K_AUTHORIZE:   A U T H O R I Z E;
 +K_DESCRIBE:    D E S C R I B E;
 +K_EXECUTE:     E X E C U T E;
 +K_NORECURSIVE: N O R E C U R S I V E;
 +K_MBEAN:       M B E A N;
 +K_MBEANS:      M B E A N S;
 +
 +K_USER:        U S E R;
 +K_USERS:       U S E R S;
 +K_ROLE:        R O L E;
 +K_ROLES:       R O L E S;
 +K_SUPERUSER:   S U P E R U S E R;
 +K_NOSUPERUSER: N O S U P E R U S E R;
 +K_PASSWORD:    P A S S W O R D;
 +K_LOGIN:       L O G I N;
 +K_NOLOGIN:     N O L O G I N;
 +K_OPTIONS:     O P T I O N S;
 +
 +K_CLUSTERING:  C L U S T E R I N G;
 +K_ASCII:       A S C I I;
 +K_BIGINT:      B I G I N T;
 +K_BLOB:        B L O B;
 +K_BOOLEAN:     B O O L E A N;
 +K_COUNTER:     C O U N T E R;
 +K_DECIMAL:     D E C I M A L;
 +K_DOUBLE:      D O U B L E;
 +K_FLOAT:       F L O A T;
 +K_INET:        I N E T;
 +K_INT:         I N T;
 +K_SMALLINT:    S M A L L I N T;
 +K_TINYINT:     T I N Y I N T;
 +K_TEXT:        T E X T;
 +K_UUID:        U U I D;
 +K_VARCHAR:     V A R C H A R;
 +K_VARINT:      V A R I N T;
 +K_TIMEUUID:    T I M E U U I D;
 +K_TOKEN:       T O K E N;
 +K_WRITETIME:   W R I T E T I M E;
 +K_DATE:        D A T E;
 +K_TIME:        T I M E;
 +
 +K_NULL:        N U L L;
 +K_NOT:         N O T;
 +K_EXISTS:      E X I S T S;
 +
 +K_MAP:         M A P;
 +K_LIST:        L I S T;
 +K_NAN:         N A N;
 +K_INFINITY:    I N F I N I T Y;
 +K_TUPLE:       T U P L E;
 +
 +K_TRIGGER:     T R I G G E R;
 +K_STATIC:      S T A T I C;
 +K_FROZEN:      F R O Z E N;
 +
 +K_FUNCTION:    F U N C T I O N;
 +K_FUNCTIONS:   F U N C T I O N S;
 +K_AGGREGATE:   A G G R E G A T E;
 +K_SFUNC:       S F U N C;
 +K_STYPE:       S T Y P E;
 +K_FINALFUNC:   F I N A L F U N C;
 +K_INITCOND:    I N I T C O N D;
 +K_RETURNS:     R E T U R N S;
 +K_CALLED:      C A L L E D;
 +K_INPUT:       I N P U T;
 +K_LANGUAGE:    L A N G U A G E;
 +K_OR:          O R;
 +K_REPLACE:     R E P L A C E;
 +
 +K_JSON:        J S O N;
 +K_DEFAULT:     D E F A U L T;
 +K_UNSET:       U N S E T;
 +K_LIKE:        L I K E;
 +
 +// 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 txt = new StringBuilder(); // temporary to build 
pg-style-string
 +    }
 +    @after{ setText(txt.toString()); }
 +    :
 +      /* pg-style string literal */
 +      (
 +        '\$' '\$'
 +        ( /* collect all input until '$$' is reached again */
 +          {  (input.size() - input.index() > 1)
 +               && !"$$".equals(input.substring(input.index(), input.index() + 
1)) }?
 +             => c=. { txt.appendCodePoint(c); }
 +        )*
 +        '\$' '\$'
 +      )
 +      |
 +      /* conventional quoted string literal */
 +      (
 +        '\'' (c=~('\'') { txt.appendCodePoint(c);} | '\'' '\'' { 
txt.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')
 +    ;
 +
 +fragment EXPONENT
 +    : E ('+' | '-')? DIGIT+
 +    ;
 +
 +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 EXPONENT
 +    | INTEGER '.' DIGIT* EXPONENT?
 +    ;
 +
 +/*
 + * This has to be before IDENT so it takes precendence over it.
 + */
 +BOOLEAN
 +    : T R U E | F A L S E
 +    ;
 +
 +IDENT
 +    : LETTER (LETTER | DIGIT | '_')*
 +    ;
 +
 +HEXNUMBER
 +    : '0' X HEX*
 +    ;
 +
 +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/206a7bba/src/antlr/Parser.g
----------------------------------------------------------------------
diff --cc src/antlr/Parser.g
index b3a9f5c,0000000..7d3c93b
mode 100644,000000..100644
--- a/src/antlr/Parser.g
+++ b/src/antlr/Parser.g
@@@ -1,1670 -1,0 +1,1670 @@@
 +/*
 + * 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.
 + */
 +
 +parser grammar Parser;
 +
 +options {
 +    language = Java;
 +}
 +
 +@members {
 +    private final List<ErrorListener> listeners = new 
ArrayList<ErrorListener>();
 +    protected final List<ColumnIdentifier> bindVariables = new 
ArrayList<ColumnIdentifier>();
 +
 +    public static final Set<String> reservedTypeNames = new HashSet<String>()
 +    {{
 +        add("byte");
 +        add("complex");
 +        add("enum");
 +        add("date");
 +        add("interval");
 +        add("macaddr");
 +        add("bitstring");
 +    }};
 +
 +    public AbstractMarker.Raw newBindVariables(ColumnIdentifier name)
 +    {
 +        AbstractMarker.Raw marker = new 
AbstractMarker.Raw(bindVariables.size());
 +        bindVariables.add(name);
 +        return marker;
 +    }
 +
 +    public AbstractMarker.INRaw newINBindVariables(ColumnIdentifier name)
 +    {
 +        AbstractMarker.INRaw marker = new 
AbstractMarker.INRaw(bindVariables.size());
 +        bindVariables.add(name);
 +        return marker;
 +    }
 +
 +    public Tuples.Raw newTupleBindVariables(ColumnIdentifier name)
 +    {
 +        Tuples.Raw marker = new Tuples.Raw(bindVariables.size());
 +        bindVariables.add(name);
 +        return marker;
 +    }
 +
 +    public Tuples.INRaw newTupleINBindVariables(ColumnIdentifier name)
 +    {
 +        Tuples.INRaw marker = new Tuples.INRaw(bindVariables.size());
 +        bindVariables.add(name);
 +        return marker;
 +    }
 +
 +    public Json.Marker newJsonBindVariables(ColumnIdentifier name)
 +    {
 +        Json.Marker marker = new Json.Marker(bindVariables.size());
 +        bindVariables.add(name);
 +        return marker;
 +    }
 +
 +    public void addErrorListener(ErrorListener listener)
 +    {
 +        this.listeners.add(listener);
 +    }
 +
 +    public void removeErrorListener(ErrorListener listener)
 +    {
 +        this.listeners.remove(listener);
 +    }
 +
 +    public void displayRecognitionError(String[] tokenNames, 
RecognitionException e)
 +    {
 +        for (int i = 0, m = listeners.size(); i < m; i++)
 +            listeners.get(i).syntaxError(this, tokenNames, e);
 +    }
 +
 +    protected void addRecognitionError(String msg)
 +    {
 +        for (int i = 0, m = listeners.size(); i < m; i++)
 +            listeners.get(i).syntaxError(this, msg);
 +    }
 +
 +    public Map<String, String> convertPropertyMap(Maps.Literal map)
 +    {
 +        if (map == null || map.entries == null || map.entries.isEmpty())
 +            return Collections.<String, String>emptyMap();
 +
 +        Map<String, String> res = new HashMap<>(map.entries.size());
 +
 +        for (Pair<Term.Raw, Term.Raw> entry : map.entries)
 +        {
 +            // Because the parser tries to be smart and recover on error (to
 +            // allow displaying more than one error I suppose), we have null
 +            // entries in there. Just skip those, a proper error will be 
thrown in the end.
 +            if (entry.left == null || entry.right == null)
 +                break;
 +
 +            if (!(entry.left instanceof Constants.Literal))
 +            {
 +                String msg = "Invalid property name: " + entry.left;
 +                if (entry.left instanceof AbstractMarker.Raw)
 +                    msg += " (bind variables are not supported in DDL 
queries)";
 +                addRecognitionError(msg);
 +                break;
 +            }
 +            if (!(entry.right instanceof Constants.Literal))
 +            {
 +                String msg = "Invalid property value: " + entry.right + " for 
property: " + entry.left;
 +                if (entry.right instanceof AbstractMarker.Raw)
 +                    msg += " (bind variables are not supported in DDL 
queries)";
 +                addRecognitionError(msg);
 +                break;
 +            }
 +
 +            res.put(((Constants.Literal)entry.left).getRawText(), 
((Constants.Literal)entry.right).getRawText());
 +        }
 +
 +        return res;
 +    }
 +
 +    public void addRawUpdate(List<Pair<ColumnDefinition.Raw, 
Operation.RawUpdate>> operations, ColumnDefinition.Raw key, Operation.RawUpdate 
update)
 +    {
 +        for (Pair<ColumnDefinition.Raw, Operation.RawUpdate> p : operations)
 +        {
 +            if (p.left.equals(key) && !p.right.isCompatibleWith(update))
 +                addRecognitionError("Multiple incompatible setting of column 
" + key);
 +        }
 +        operations.add(Pair.create(key, update));
 +    }
 +
 +    public Set<Permission> filterPermissions(Set<Permission> permissions, 
IResource resource)
 +    {
 +        if (resource == null)
 +            return Collections.emptySet();
 +        Set<Permission> filtered = new HashSet<>(permissions);
 +        filtered.retainAll(resource.applicablePermissions());
 +        if (filtered.isEmpty())
 +            addRecognitionError("Resource type " + 
resource.getClass().getSimpleName() +
 +                                    " does not support any of the requested 
permissions");
 +
 +        return filtered;
 +    }
 +
 +    public String canonicalizeObjectName(String s, boolean enforcePattern)
 +    {
 +        // these two conditions are here because technically they are valid
 +        // ObjectNames, but we want to restrict their use without adding 
unnecessary
 +        // work to JMXResource construction as that also happens on hotter 
code paths
 +        if ("".equals(s))
 +            addRecognitionError("Empty JMX object name supplied");
 +
 +        if ("*:*".equals(s))
 +            addRecognitionError("Please use ALL MBEANS instead of wildcard 
pattern");
 +
 +        try
 +        {
 +            javax.management.ObjectName objectName = 
javax.management.ObjectName.getInstance(s);
 +            if (enforcePattern && !objectName.isPattern())
 +                addRecognitionError("Plural form used, but non-pattern JMX 
object name specified (" + s + ")");
 +            return objectName.getCanonicalName();
 +        }
 +        catch (javax.management.MalformedObjectNameException e)
 +        {
 +          addRecognitionError(s + " is not a valid JMX object name");
 +          return s;
 +        }
 +    }
 +
 +    
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 +    // Recovery methods are overridden to avoid wasting work on recovering 
from errors when the result will be
 +    // ignored anyway.
 +    
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 +
 +    @Override
 +    protected Object recoverFromMismatchedToken(IntStream input, int ttype, 
BitSet follow) throws RecognitionException
 +    {
 +        throw new MismatchedTokenException(ttype, input);
 +    }
 +
 +    @Override
 +    public void recover(IntStream input, RecognitionException re)
 +    {
 +        // Do nothing.
 +    }
 +}
 +
 +/** STATEMENTS **/
 +
 +cqlStatement returns [ParsedStatement stmt]
 +    @after{ if (stmt != null) stmt.setBoundVariables(bindVariables); }
 +    : 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= createTableStatement            { $stmt = st9; }
 +    | st10=createIndexStatement            { $stmt = st10; }
 +    | st11=dropKeyspaceStatement           { $stmt = st11; }
 +    | st12=dropTableStatement              { $stmt = st12; }
 +    | st13=dropIndexStatement              { $stmt = st13; }
 +    | st14=alterTableStatement             { $stmt = st14; }
 +    | st15=alterKeyspaceStatement          { $stmt = st15; }
 +    | st16=grantPermissionsStatement       { $stmt = st16; }
 +    | st17=revokePermissionsStatement      { $stmt = st17; }
 +    | st18=listPermissionsStatement        { $stmt = st18; }
 +    | st19=createUserStatement             { $stmt = st19; }
 +    | st20=alterUserStatement              { $stmt = st20; }
 +    | st21=dropUserStatement               { $stmt = st21; }
 +    | st22=listUsersStatement              { $stmt = st22; }
 +    | st23=createTriggerStatement          { $stmt = st23; }
 +    | st24=dropTriggerStatement            { $stmt = st24; }
 +    | st25=createTypeStatement             { $stmt = st25; }
 +    | st26=alterTypeStatement              { $stmt = st26; }
 +    | st27=dropTypeStatement               { $stmt = st27; }
 +    | st28=createFunctionStatement         { $stmt = st28; }
 +    | st29=dropFunctionStatement           { $stmt = st29; }
 +    | st30=createAggregateStatement        { $stmt = st30; }
 +    | st31=dropAggregateStatement          { $stmt = st31; }
 +    | st32=createRoleStatement             { $stmt = st32; }
 +    | st33=alterRoleStatement              { $stmt = st33; }
 +    | st34=dropRoleStatement               { $stmt = st34; }
 +    | st35=listRolesStatement              { $stmt = st35; }
 +    | st36=grantRoleStatement              { $stmt = st36; }
 +    | st37=revokeRoleStatement             { $stmt = st37; }
 +    | st38=createMaterializedViewStatement { $stmt = st38; }
 +    | st39=dropMaterializedViewStatement   { $stmt = st39; }
 +    | st40=alterMaterializedViewStatement  { $stmt = st40; }
 +    ;
 +
 +/*
 + * USE <KEYSPACE>;
 + */
 +useStatement returns [UseStatement stmt]
 +    : K_USE ks=keyspaceName { $stmt = new UseStatement(ks); }
 +    ;
 +
 +/**
 + * SELECT <expression>
 + * FROM <CF>
 + * WHERE KEY = "key1" AND COL > 1 AND COL < 100
 + * LIMIT <NUMBER>;
 + */
 +selectStatement returns [SelectStatement.RawStatement expr]
 +    @init {
 +        boolean isDistinct = false;
 +        Term.Raw limit = null;
 +        Term.Raw perPartitionLimit = null;
 +        Map<ColumnDefinition.Raw, Boolean> orderings = new LinkedHashMap<>();
 +        List<ColumnDefinition.Raw> groups = new ArrayList<>();
 +        boolean allowFiltering = false;
 +        boolean isJson = false;
 +    }
 +    : K_SELECT
 +      ( K_JSON { isJson = true; } )?
 +      ( ( K_DISTINCT { isDistinct = true; } )? sclause=selectClause )
 +      K_FROM cf=columnFamilyName
 +      ( K_WHERE wclause=whereClause )?
 +      ( K_GROUP K_BY groupByClause[groups] ( ',' groupByClause[groups] )* )?
 +      ( K_ORDER K_BY orderByClause[orderings] ( ',' orderByClause[orderings] 
)* )?
 +      ( K_PER K_PARTITION K_LIMIT rows=intValue { perPartitionLimit = rows; } 
)?
 +      ( K_LIMIT rows=intValue { limit = rows; } )?
 +      ( K_ALLOW K_FILTERING  { allowFiltering = true; } )?
 +      {
 +          SelectStatement.Parameters params = new 
SelectStatement.Parameters(orderings,
 +                                                                             
groups,
 +                                                                             
isDistinct,
 +                                                                             
allowFiltering,
 +                                                                             
isJson);
 +          WhereClause where = wclause == null ? WhereClause.empty() : 
wclause.build();
 +          $expr = new SelectStatement.RawStatement(cf, params, sclause, 
where, limit, perPartitionLimit);
 +      }
 +    ;
 +
 +selectClause returns [List<RawSelector> expr]
 +    : t1=selector { $expr = new ArrayList<RawSelector>(); $expr.add(t1); } 
(',' tN=selector { $expr.add(tN); })*
 +    | '\*' { $expr = Collections.<RawSelector>emptyList();}
 +    ;
 +
 +selector returns [RawSelector s]
 +    @init{ ColumnIdentifier alias = null; }
 +    : us=unaliasedSelector (K_AS c=noncol_ident { alias = c; })? { $s = new 
RawSelector(us, alias); }
 +    ;
 +
 +/*
 + * A single selection. The core of it is selecting a column, but we also 
allow any term and function, as well as
 + * sub-element selection for UDT.
 + */
 +unaliasedSelector returns [Selectable.Raw s]
 +    @init { Selectable.Raw tmp = null; }
 +    :  ( c=cident                                  { tmp = c; }
 +       | v=value                                   { tmp = new 
Selectable.WithTerm.Raw(v); }
 +       | '(' ct=comparatorType ')' v=value         { tmp = new 
Selectable.WithTerm.Raw(new TypeCast(ct, v)); }
 +       | K_COUNT '(' '\*' ')'                      { tmp = 
Selectable.WithFunction.Raw.newCountRowsFunction(); }
 +       | K_WRITETIME '(' c=cident ')'              { tmp = new 
Selectable.WritetimeOrTTL.Raw(c, true); }
 +       | K_TTL       '(' c=cident ')'              { tmp = new 
Selectable.WritetimeOrTTL.Raw(c, false); }
 +       | K_CAST      '(' sn=unaliasedSelector K_AS t=native_type ')' {tmp = 
new Selectable.WithCast.Raw(sn, t);}
 +       | f=functionName args=selectionFunctionArgs { tmp = new 
Selectable.WithFunction.Raw(f, args); }
 +       ) ( '.' fi=fident { tmp = new Selectable.WithFieldSelection.Raw(tmp, 
fi); } )* { $s = tmp; }
 +    ;
 +
 +selectionFunctionArgs returns [List<Selectable.Raw> a]
 +    : '(' ')' { $a = Collections.emptyList(); }
 +    | '(' s1=unaliasedSelector { List<Selectable.Raw> args = new 
ArrayList<Selectable.Raw>(); args.add(s1); }
 +          ( ',' sn=unaliasedSelector { args.add(sn); } )*
 +      ')' { $a = args; }
 +    ;
 +
 +whereClause returns [WhereClause.Builder clause]
 +    @init{ $clause = new WhereClause.Builder(); }
 +    : relationOrExpression[$clause] (K_AND relationOrExpression[$clause])*
 +    ;
 +
 +relationOrExpression [WhereClause.Builder clause]
 +    : relation[$clause]
 +    | customIndexExpression[$clause]
 +    ;
 +
 +customIndexExpression [WhereClause.Builder clause]
 +    @init{IndexName name = new IndexName();}
 +    : 'expr(' idxName[name] ',' t=term ')' { clause.add(new 
CustomIndexExpression(name, t));}
 +    ;
 +
 +orderByClause[Map<ColumnDefinition.Raw, Boolean> orderings]
 +    @init{
 +        boolean reversed = false;
 +    }
 +    : c=cident (K_ASC | K_DESC { reversed = true; })? { orderings.put(c, 
reversed); }
 +    ;
 +
 +groupByClause[List<ColumnDefinition.Raw> groups]
 +    : c=cident { groups.add(c); }
 +    ;
 +
 +/**
 + * INSERT INTO <CF> (<column>, <column>, <column>, ...)
 + * VALUES (<value>, <value>, <value>, ...)
 + * USING TIMESTAMP <long>;
 + *
 + */
 +insertStatement returns [ModificationStatement.Parsed expr]
 +    : K_INSERT K_INTO cf=columnFamilyName
 +        ( st1=normalInsertStatement[cf] { $expr = st1; }
 +        | K_JSON st2=jsonInsertStatement[cf] { $expr = st2; })
 +    ;
 +
 +normalInsertStatement [CFName cf] returns [UpdateStatement.ParsedInsert expr]
 +    @init {
 +        Attributes.Raw attrs = new Attributes.Raw();
 +        List<ColumnDefinition.Raw> columnNames  = new ArrayList<>();
 +        List<Term.Raw> values = new ArrayList<>();
 +        boolean ifNotExists = false;
 +    }
 +    : '(' c1=cident { columnNames.add(c1); }  ( ',' cn=cident { 
columnNames.add(cn); } )* ')'
 +      K_VALUES
 +      '(' v1=term { values.add(v1); } ( ',' vn=term { values.add(vn); } )* ')'
 +      ( K_IF K_NOT K_EXISTS { ifNotExists = true; } )?
 +      ( usingClause[attrs] )?
 +      {
 +          $expr = new UpdateStatement.ParsedInsert(cf, attrs, columnNames, 
values, ifNotExists);
 +      }
 +    ;
 +
 +jsonInsertStatement [CFName cf] returns [UpdateStatement.ParsedInsertJson 
expr]
 +    @init {
 +        Attributes.Raw attrs = new Attributes.Raw();
 +        boolean ifNotExists = false;
 +        boolean defaultUnset = false;
 +    }
 +    : val=jsonValue
 +      ( K_DEFAULT ( K_NULL | ( { defaultUnset = true; } K_UNSET) ) )?
 +      ( K_IF K_NOT K_EXISTS { ifNotExists = true; } )?
 +      ( usingClause[attrs] )?
 +      {
 +          $expr = new UpdateStatement.ParsedInsertJson(cf, attrs, val, 
defaultUnset, ifNotExists);
 +      }
 +    ;
 +
 +jsonValue returns [Json.Raw value]
 +    : s=STRING_LITERAL { $value = new Json.Literal($s.text); }
 +    | ':' id=noncol_ident     { $value = newJsonBindVariables(id); }
 +    | QMARK            { $value = newJsonBindVariables(null); }
 +    ;
 +
 +usingClause[Attributes.Raw attrs]
 +    : K_USING usingClauseObjective[attrs] ( K_AND usingClauseObjective[attrs] 
)*
 +    ;
 +
 +usingClauseObjective[Attributes.Raw attrs]
 +    : K_TIMESTAMP ts=intValue { attrs.timestamp = ts; }
 +    | K_TTL t=intValue { attrs.timeToLive = t; }
 +    ;
 +
 +/**
 + * UPDATE <CF>
 + * USING TIMESTAMP <long>
 + * SET name1 = value1, name2 = value2
 + * WHERE key = value;
 + * [IF (EXISTS | name = value, ...)];
 + */
 +updateStatement returns [UpdateStatement.ParsedUpdate expr]
 +    @init {
 +        Attributes.Raw attrs = new Attributes.Raw();
 +        List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> operations = 
new ArrayList<>();
 +        boolean ifExists = false;
 +    }
 +    : K_UPDATE cf=columnFamilyName
 +      ( usingClause[attrs] )?
 +      K_SET columnOperation[operations] (',' columnOperation[operations])*
 +      K_WHERE wclause=whereClause
 +      ( K_IF ( K_EXISTS { ifExists = true; } | conditions=updateConditions ))?
 +      {
 +          $expr = new UpdateStatement.ParsedUpdate(cf,
 +                                                   attrs,
 +                                                   operations,
 +                                                   wclause.build(),
 +                                                   conditions == null ? 
Collections.<Pair<ColumnDefinition.Raw, ColumnCondition.Raw>>emptyList() : 
conditions,
 +                                                   ifExists);
 +     }
 +    ;
 +
 +updateConditions returns [List<Pair<ColumnDefinition.Raw, 
ColumnCondition.Raw>> conditions]
 +    @init { conditions = new ArrayList<Pair<ColumnDefinition.Raw, 
ColumnCondition.Raw>>(); }
 +    : columnCondition[conditions] ( K_AND columnCondition[conditions] )*
 +    ;
 +
 +
 +/**
 + * DELETE name1, name2
 + * FROM <CF>
 + * USING TIMESTAMP <long>
 + * WHERE KEY = keyname
 +   [IF (EXISTS | name = value, ...)];
 + */
 +deleteStatement returns [DeleteStatement.Parsed expr]
 +    @init {
 +        Attributes.Raw attrs = new Attributes.Raw();
 +        List<Operation.RawDeletion> columnDeletions = Collections.emptyList();
 +        boolean ifExists = false;
 +    }
 +    : K_DELETE ( dels=deleteSelection { columnDeletions = dels; } )?
 +      K_FROM cf=columnFamilyName
 +      ( usingClauseDelete[attrs] )?
 +      K_WHERE wclause=whereClause
 +      ( K_IF ( K_EXISTS { ifExists = true; } | conditions=updateConditions ))?
 +      {
 +          $expr = new DeleteStatement.Parsed(cf,
 +                                             attrs,
 +                                             columnDeletions,
 +                                             wclause.build(),
 +                                             conditions == null ? 
Collections.<Pair<ColumnDefinition.Raw, ColumnCondition.Raw>>emptyList() : 
conditions,
 +                                             ifExists);
 +      }
 +    ;
 +
 +deleteSelection returns [List<Operation.RawDeletion> operations]
 +    : { $operations = new ArrayList<Operation.RawDeletion>(); }
 +          t1=deleteOp { $operations.add(t1); }
 +          (',' tN=deleteOp { $operations.add(tN); })*
 +    ;
 +
 +deleteOp returns [Operation.RawDeletion op]
 +    : c=cident                { $op = new Operation.ColumnDeletion(c); }
 +    | c=cident '[' t=term ']' { $op = new Operation.ElementDeletion(c, t); }
 +    | c=cident '.' field=fident { $op = new Operation.FieldDeletion(c, 
field); }
 +    ;
 +
 +usingClauseDelete[Attributes.Raw attrs]
 +    : K_USING K_TIMESTAMP ts=intValue { attrs.timestamp = ts; }
 +    ;
 +
 +/**
 + * BEGIN BATCH
 + *   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
 + *   INSERT INTO <CF> (KEY, <name>) VALUES ('<key>', '<value>');
 + *   INSERT INTO <CF> (KEY, <name>) VALUES ('<key>', '<value>');
 + *   ...
 + * APPLY BATCH
 + *
 + * OR
 + *
 + * BEGIN BATCH
 + *   DELETE name1, name2 FROM <CF> WHERE key = <key>
 + *   DELETE name3, name4 FROM <CF> WHERE key = <key>
 + *   ...
 + * APPLY BATCH
 + */
 +batchStatement returns [BatchStatement.Parsed expr]
 +    @init {
 +        BatchStatement.Type type = BatchStatement.Type.LOGGED;
 +        List<ModificationStatement.Parsed> statements = new 
ArrayList<ModificationStatement.Parsed>();
 +        Attributes.Raw attrs = new Attributes.Raw();
 +    }
 +    : K_BEGIN
 +      ( K_UNLOGGED { type = BatchStatement.Type.UNLOGGED; } | K_COUNTER { 
type = BatchStatement.Type.COUNTER; } )?
 +      K_BATCH ( usingClause[attrs] )?
 +          ( s=batchStatementObjective ';'? { statements.add(s); } )*
 +      K_APPLY K_BATCH
 +      {
 +          $expr = new BatchStatement.Parsed(type, attrs, statements);
 +      }
 +    ;
 +
 +batchStatementObjective returns [ModificationStatement.Parsed statement]
 +    : i=insertStatement  { $statement = i; }
 +    | u=updateStatement  { $statement = u; }
 +    | d=deleteStatement  { $statement = d; }
 +    ;
 +
 +createAggregateStatement returns [CreateAggregateStatement expr]
 +    @init {
 +        boolean orReplace = false;
 +        boolean ifNotExists = false;
 +
 +        List<CQL3Type.Raw> argsTypes = new ArrayList<>();
 +    }
 +    : K_CREATE (K_OR K_REPLACE { orReplace = true; })?
 +      K_AGGREGATE
 +      (K_IF K_NOT K_EXISTS { ifNotExists = true; })?
 +      fn=functionName
 +      '('
 +        (
 +          v=comparatorType { argsTypes.add(v); }
 +          ( ',' v=comparatorType { argsTypes.add(v); } )*
 +        )?
 +      ')'
 +      K_SFUNC sfunc = allowedFunctionName
 +      K_STYPE stype = comparatorType
 +      (
 +        K_FINALFUNC ffunc = allowedFunctionName
 +      )?
 +      (
 +        K_INITCOND ival = term
 +      )?
 +      { $expr = new CreateAggregateStatement(fn, argsTypes, sfunc, stype, 
ffunc, ival, orReplace, ifNotExists); }
 +    ;
 +
 +dropAggregateStatement returns [DropAggregateStatement expr]
 +    @init {
 +        boolean ifExists = false;
 +        List<CQL3Type.Raw> argsTypes = new ArrayList<>();
 +        boolean argsPresent = false;
 +    }
 +    : K_DROP K_AGGREGATE
 +      (K_IF K_EXISTS { ifExists = true; } )?
 +      fn=functionName
 +      (
 +        '('
 +          (
 +            v=comparatorType { argsTypes.add(v); }
 +            ( ',' v=comparatorType { argsTypes.add(v); } )*
 +          )?
 +        ')'
 +        { argsPresent = true; }
 +      )?
 +      { $expr = new DropAggregateStatement(fn, argsTypes, argsPresent, 
ifExists); }
 +    ;
 +
 +createFunctionStatement returns [CreateFunctionStatement expr]
 +    @init {
 +        boolean orReplace = false;
 +        boolean ifNotExists = false;
 +
 +        List<ColumnIdentifier> argsNames = new ArrayList<>();
 +        List<CQL3Type.Raw> argsTypes = new ArrayList<>();
 +        boolean calledOnNullInput = false;
 +    }
 +    : K_CREATE (K_OR K_REPLACE { orReplace = true; })?
 +      K_FUNCTION
 +      (K_IF K_NOT K_EXISTS { ifNotExists = true; })?
 +      fn=functionName
 +      '('
 +        (
 +          k=noncol_ident v=comparatorType { argsNames.add(k); 
argsTypes.add(v); }
 +          ( ',' k=noncol_ident v=comparatorType { argsNames.add(k); 
argsTypes.add(v); } )*
 +        )?
 +      ')'
 +      ( (K_RETURNS K_NULL) | (K_CALLED { calledOnNullInput=true; })) K_ON 
K_NULL K_INPUT
 +      K_RETURNS rt = comparatorType
 +      K_LANGUAGE language = IDENT
 +      K_AS body = STRING_LITERAL
 +      { $expr = new CreateFunctionStatement(fn, $language.text.toLowerCase(), 
$body.text,
 +                                            argsNames, argsTypes, rt, 
calledOnNullInput, orReplace, ifNotExists); }
 +    ;
 +
 +dropFunctionStatement returns [DropFunctionStatement expr]
 +    @init {
 +        boolean ifExists = false;
 +        List<CQL3Type.Raw> argsTypes = new ArrayList<>();
 +        boolean argsPresent = false;
 +    }
 +    : K_DROP K_FUNCTION
 +      (K_IF K_EXISTS { ifExists = true; } )?
 +      fn=functionName
 +      (
 +        '('
 +          (
 +            v=comparatorType { argsTypes.add(v); }
 +            ( ',' v=comparatorType { argsTypes.add(v); } )*
 +          )?
 +        ')'
 +        { argsPresent = true; }
 +      )?
 +      { $expr = new DropFunctionStatement(fn, argsTypes, argsPresent, 
ifExists); }
 +    ;
 +
 +/**
 + * CREATE KEYSPACE [IF NOT EXISTS] <KEYSPACE> WITH attr1 = value1 AND attr2 = 
value2;
 + */
 +createKeyspaceStatement returns [CreateKeyspaceStatement expr]
 +    @init {
 +        KeyspaceAttributes attrs = new KeyspaceAttributes();
 +        boolean ifNotExists = false;
 +    }
 +    : K_CREATE K_KEYSPACE (K_IF K_NOT K_EXISTS { ifNotExists = true; } )? 
ks=keyspaceName
 +      K_WITH properties[attrs] { $expr = new CreateKeyspaceStatement(ks, 
attrs, ifNotExists); }
 +    ;
 +
 +/**
 + * CREATE COLUMNFAMILY [IF NOT EXISTS] <CF> (
 + *     <name1> <type>,
 + *     <name2> <type>,
 + *     <name3> <type>
 + * ) WITH <property> = <value> AND ...;
 + */
 +createTableStatement returns [CreateTableStatement.RawStatement expr]
 +    @init { boolean ifNotExists = false; }
 +    : K_CREATE K_COLUMNFAMILY (K_IF K_NOT K_EXISTS { ifNotExists = true; } )?
 +      cf=columnFamilyName { $expr = new CreateTableStatement.RawStatement(cf, 
ifNotExists); }
 +      cfamDefinition[expr]
 +    ;
 +
 +cfamDefinition[CreateTableStatement.RawStatement expr]
 +    : '(' cfamColumns[expr] ( ',' cfamColumns[expr]? )* ')'
 +      ( K_WITH cfamProperty[expr.properties] ( K_AND 
cfamProperty[expr.properties] )*)?
 +    ;
 +
 +cfamColumns[CreateTableStatement.RawStatement expr]
 +    : k=ident v=comparatorType { boolean isStatic=false; } (K_STATIC 
{isStatic = true;})? { $expr.addDefinition(k, v, isStatic); }
 +        (K_PRIMARY K_KEY { $expr.addKeyAliases(Collections.singletonList(k)); 
})?
 +    | K_PRIMARY K_KEY '(' pkDef[expr] (',' c=ident { $expr.addColumnAlias(c); 
} )* ')'
 +    ;
 +
 +pkDef[CreateTableStatement.RawStatement expr]
 +    : k=ident { $expr.addKeyAliases(Collections.singletonList(k)); }
 +    | '(' { List<ColumnIdentifier> l = new ArrayList<ColumnIdentifier>(); } 
k1=ident { l.add(k1); } ( ',' kn=ident { l.add(kn); } )* ')' { 
$expr.addKeyAliases(l); }
 +    ;
 +
 +cfamProperty[CFProperties props]
 +    : property[props.properties]
 +    | K_COMPACT K_STORAGE { $props.setCompactStorage(); }
 +    | K_CLUSTERING K_ORDER K_BY '(' cfamOrdering[props] (',' 
cfamOrdering[props])* ')'
 +    ;
 +
 +cfamOrdering[CFProperties props]
 +    @init{ boolean reversed=false; }
 +    : k=ident (K_ASC | K_DESC { reversed=true;} ) { $props.setOrdering(k, 
reversed); }
 +    ;
 +
 +
 +/**
 + * CREATE TYPE foo (
 + *    <name1> <type1>,
 + *    <name2> <type2>,
 + *    ....
 + * )
 + */
 +createTypeStatement returns [CreateTypeStatement expr]
 +    @init { boolean ifNotExists = false; }
 +    : K_CREATE K_TYPE (K_IF K_NOT K_EXISTS { ifNotExists = true; } )?
 +         tn=userTypeName { $expr = new CreateTypeStatement(tn, ifNotExists); }
 +         '(' typeColumns[expr] ( ',' typeColumns[expr]? )* ')'
 +    ;
 +
 +typeColumns[CreateTypeStatement expr]
 +    : k=fident v=comparatorType { $expr.addDefinition(k, v); }
 +    ;
 +
 +
 +/**
 + * CREATE INDEX [IF NOT EXISTS] [indexName] ON <columnFamily> (<columnName>);
 + * CREATE CUSTOM INDEX [IF NOT EXISTS] [indexName] ON <columnFamily> 
(<columnName>) USING <indexClass>;
 + */
 +createIndexStatement returns [CreateIndexStatement expr]
 +    @init {
 +        IndexPropDefs props = new IndexPropDefs();
 +        boolean ifNotExists = false;
 +        IndexName name = new IndexName();
 +        List<IndexTarget.Raw> targets = new ArrayList<>();
 +    }
 +    : K_CREATE (K_CUSTOM { props.isCustom = true; })? K_INDEX (K_IF K_NOT 
K_EXISTS { ifNotExists = true; } )?
 +        (idxName[name])? K_ON cf=columnFamilyName '(' (indexIdent[targets] 
(',' indexIdent[targets])*)? ')'
 +        (K_USING cls=STRING_LITERAL { props.customClass = $cls.text; })?
 +        (K_WITH properties[props])?
 +      { $expr = new CreateIndexStatement(cf, name, targets, props, 
ifNotExists); }
 +    ;
 +
 +indexIdent [List<IndexTarget.Raw> targets]
 +    : c=cident                   { 
$targets.add(IndexTarget.Raw.simpleIndexOn(c)); }
 +    | K_VALUES '(' c=cident ')'  { $targets.add(IndexTarget.Raw.valuesOf(c)); 
}
 +    | K_KEYS '(' c=cident ')'    { $targets.add(IndexTarget.Raw.keysOf(c)); }
 +    | K_ENTRIES '(' c=cident ')' { 
$targets.add(IndexTarget.Raw.keysAndValuesOf(c)); }
 +    | K_FULL '(' c=cident ')'    { 
$targets.add(IndexTarget.Raw.fullCollection(c)); }
 +    ;
 +
 +/**
 + * CREATE MATERIALIZED VIEW <viewName> AS
 + *  SELECT <columns>
 + *  FROM <CF>
 + *  WHERE <pkColumns> IS NOT NULL
 + *  PRIMARY KEY (<pkColumns>)
 + *  WITH <property> = <value> AND ...;
 + */
 +createMaterializedViewStatement returns [CreateViewStatement expr]
 +    @init {
 +        boolean ifNotExists = false;
 +        List<ColumnDefinition.Raw> partitionKeys = new ArrayList<>();
 +        List<ColumnDefinition.Raw> compositeKeys = new ArrayList<>();
 +    }
 +    : K_CREATE K_MATERIALIZED K_VIEW (K_IF K_NOT K_EXISTS { ifNotExists = 
true; })? cf=columnFamilyName K_AS
 +        K_SELECT sclause=selectClause K_FROM basecf=columnFamilyName
 +        (K_WHERE wclause=whereClause)?
 +        K_PRIMARY K_KEY (
 +        '(' '(' k1=cident { partitionKeys.add(k1); } ( ',' kn=cident { 
partitionKeys.add(kn); } )* ')' ( ',' c1=cident { compositeKeys.add(c1); } )* 
')'
 +    |   '(' k1=cident { partitionKeys.add(k1); } ( ',' cn=cident { 
compositeKeys.add(cn); } )* ')'
 +        )
 +        {
 +             WhereClause where = wclause == null ? WhereClause.empty() : 
wclause.build();
 +             $expr = new CreateViewStatement(cf, basecf, sclause, where, 
partitionKeys, compositeKeys, ifNotExists);
 +        }
 +        ( K_WITH cfamProperty[expr.properties] ( K_AND 
cfamProperty[expr.properties] )*)?
 +    ;
 +
 +/**
 + * CREATE TRIGGER triggerName ON columnFamily USING 'triggerClass';
 + */
 +createTriggerStatement returns [CreateTriggerStatement expr]
 +    @init {
 +        boolean ifNotExists = false;
 +    }
 +    : K_CREATE K_TRIGGER (K_IF K_NOT K_EXISTS { ifNotExists = true; } )? 
(name=cident)
 +        K_ON cf=columnFamilyName K_USING cls=STRING_LITERAL
 +      { $expr = new CreateTriggerStatement(cf, name.rawText(), $cls.text, 
ifNotExists); }
 +    ;
 +
 +/**
 + * DROP TRIGGER [IF EXISTS] triggerName ON columnFamily;
 + */
 +dropTriggerStatement returns [DropTriggerStatement expr]
 +     @init { boolean ifExists = false; }
 +    : K_DROP K_TRIGGER (K_IF K_EXISTS { ifExists = true; } )? (name=cident) 
K_ON cf=columnFamilyName
 +      { $expr = new DropTriggerStatement(cf, name.rawText(), ifExists); }
 +    ;
 +
 +/**
 + * ALTER KEYSPACE <KS> WITH <property> = <value>;
 + */
 +alterKeyspaceStatement returns [AlterKeyspaceStatement expr]
 +    @init { KeyspaceAttributes attrs = new KeyspaceAttributes(); }
 +    : K_ALTER K_KEYSPACE ks=keyspaceName
 +        K_WITH properties[attrs] { $expr = new AlterKeyspaceStatement(ks, 
attrs); }
 +    ;
 +
 +/**
 + * ALTER COLUMN FAMILY <CF> ALTER <column> TYPE <newtype>;
 + * ALTER COLUMN FAMILY <CF> ADD <column> <newtype>; | ALTER COLUMN FAMILY 
<CF> ADD (<column> <newtype>,<column1> <newtype1>..... <column n> <newtype n>)
 + * ALTER COLUMN FAMILY <CF> DROP <column>; | ALTER COLUMN FAMILY <CF> DROP ( 
<column>,<column1>.....<column n>)
 + * ALTER COLUMN FAMILY <CF> WITH <property> = <value>;
 + * ALTER COLUMN FAMILY <CF> RENAME <column> TO <column>;
 + */
 +alterTableStatement returns [AlterTableStatement expr]
 +    @init {
 +        AlterTableStatement.Type type = null;
 +        TableAttributes attrs = new TableAttributes();
 +        Map<ColumnDefinition.Raw, ColumnDefinition.Raw> renames = new 
HashMap<ColumnDefinition.Raw, ColumnDefinition.Raw>();
 +        List<AlterTableStatementColumn> colNameList = new 
ArrayList<AlterTableStatementColumn>();
 +        Long deleteTimestamp = null;
 +    }
 +    : K_ALTER K_COLUMNFAMILY cf=columnFamilyName
 +          ( K_ALTER id=cident  K_TYPE v=comparatorType  { type = 
AlterTableStatement.Type.ALTER; } { colNameList.add(new 
AlterTableStatementColumn(id,v)); }
 +          | K_ADD  (        (id=cident   v=comparatorType   b1=cfisStatic { 
colNameList.add(new AlterTableStatementColumn(id,v,b1)); })
 +                     | ('('  id1=cident  v1=comparatorType  b1=cfisStatic { 
colNameList.add(new AlterTableStatementColumn(id1,v1,b1)); }
 +                       ( ',' idn=cident  vn=comparatorType  bn=cfisStatic { 
colNameList.add(new AlterTableStatementColumn(idn,vn,bn)); } )* ')' ) ) { type 
= AlterTableStatement.Type.ADD; }
 +          | K_DROP ( (         id=cident  { colNameList.add(new 
AlterTableStatementColumn(id)); }
 +                      | ('('  id1=cident { colNameList.add(new 
AlterTableStatementColumn(id1)); }
 +                        ( ',' idn=cident { colNameList.add(new 
AlterTableStatementColumn(idn)); } )* ')') )
 +                     ( K_USING K_TIMESTAMP t=INTEGER { deleteTimestamp = 
Long.parseLong(Constants.Literal.integer($t.text).getText()); })? ) { type = 
AlterTableStatement.Type.DROP; }
 +          | K_WITH  properties[attrs]                 { type = 
AlterTableStatement.Type.OPTS; }
 +          | K_RENAME                                  { type = 
AlterTableStatement.Type.RENAME; }
 +               id1=cident K_TO toId1=cident { renames.put(id1, toId1); }
 +               ( K_AND idn=cident K_TO toIdn=cident { renames.put(idn, 
toIdn); } )*
 +          )
 +    {
 +        $expr = new AlterTableStatement(cf, type, colNameList, attrs, 
renames, deleteTimestamp);
 +    }
 +    ;
 +
 +cfisStatic returns [boolean isStaticColumn]
 +    @init{
 +        boolean isStatic = false;
 +    }
 +    : (K_STATIC { isStatic=true; })? { $isStaticColumn = isStatic;
 +    }
 +    ;
 +
 +alterMaterializedViewStatement returns [AlterViewStatement expr]
 +    @init {
 +        TableAttributes attrs = new TableAttributes();
 +    }
 +    : K_ALTER K_MATERIALIZED K_VIEW name=columnFamilyName
 +          K_WITH properties[attrs]
 +    {
 +        $expr = new AlterViewStatement(name, attrs);
 +    }
 +    ;
 +
 +
 +/**
 + * ALTER TYPE <name> ALTER <field> TYPE <newtype>;
 + * ALTER TYPE <name> ADD <field> <newtype>;
 + * ALTER TYPE <name> RENAME <field> TO <newtype> AND ...;
 + */
 +alterTypeStatement returns [AlterTypeStatement expr]
 +    : K_ALTER K_TYPE name=userTypeName
 +          ( K_ALTER f=fident K_TYPE v=comparatorType { $expr = 
AlterTypeStatement.alter(name, f, v); }
 +          | K_ADD   f=fident v=comparatorType        { $expr = 
AlterTypeStatement.addition(name, f, v); }
 +          | K_RENAME
 +               { Map<FieldIdentifier, FieldIdentifier> renames = new 
HashMap<>(); }
 +                 id1=fident K_TO toId1=fident { renames.put(id1, toId1); }
 +                 ( K_AND idn=fident K_TO toIdn=fident { renames.put(idn, 
toIdn); } )*
 +               { $expr = AlterTypeStatement.renames(name, renames); }
 +          )
 +    ;
 +
 +
 +/**
 + * DROP KEYSPACE [IF EXISTS] <KSP>;
 + */
 +dropKeyspaceStatement returns [DropKeyspaceStatement ksp]
 +    @init { boolean ifExists = false; }
 +    : K_DROP K_KEYSPACE (K_IF K_EXISTS { ifExists = true; } )? 
ks=keyspaceName { $ksp = new DropKeyspaceStatement(ks, ifExists); }
 +    ;
 +
 +/**
 + * DROP COLUMNFAMILY [IF EXISTS] <CF>;
 + */
 +dropTableStatement returns [DropTableStatement stmt]
 +    @init { boolean ifExists = false; }
 +    : K_DROP K_COLUMNFAMILY (K_IF K_EXISTS { ifExists = true; } )? 
cf=columnFamilyName { $stmt = new DropTableStatement(cf, ifExists); }
 +    ;
 +
 +/**
 + * DROP TYPE <name>;
 + */
 +dropTypeStatement returns [DropTypeStatement stmt]
 +    @init { boolean ifExists = false; }
 +    : K_DROP K_TYPE (K_IF K_EXISTS { ifExists = true; } )? name=userTypeName 
{ $stmt = new DropTypeStatement(name, ifExists); }
 +    ;
 +
 +/**
 + * DROP INDEX [IF EXISTS] <INDEX_NAME>
 + */
 +dropIndexStatement returns [DropIndexStatement expr]
 +    @init { boolean ifExists = false; }
 +    : K_DROP K_INDEX (K_IF K_EXISTS { ifExists = true; } )? index=indexName
 +      { $expr = new DropIndexStatement(index, ifExists); }
 +    ;
 +
 +/**
 + * DROP MATERIALIZED VIEW [IF EXISTS] <view_name>
 + */
 +dropMaterializedViewStatement returns [DropViewStatement expr]
 +    @init { boolean ifExists = false; }
 +    : K_DROP K_MATERIALIZED K_VIEW (K_IF K_EXISTS { ifExists = true; } )? 
cf=columnFamilyName
 +      { $expr = new DropViewStatement(cf, ifExists); }
 +    ;
 +
 +/**
 +  * TRUNCATE <CF>;
 +  */
 +truncateStatement returns [TruncateStatement stmt]
 +    : K_TRUNCATE (K_COLUMNFAMILY)? cf=columnFamilyName { $stmt = new 
TruncateStatement(cf); }
 +    ;
 +
 +/**
 + * GRANT <permission> ON <resource> TO <rolename>
 + */
 +grantPermissionsStatement returns [GrantPermissionsStatement stmt]
 +    : K_GRANT
 +          permissionOrAll
 +      K_ON
 +          resource
 +      K_TO
 +          grantee=userOrRoleName
 +      { $stmt = new 
GrantPermissionsStatement(filterPermissions($permissionOrAll.perms, 
$resource.res), $resource.res, grantee); }
 +    ;
 +
 +/**
 + * REVOKE <permission> ON <resource> FROM <rolename>
 + */
 +revokePermissionsStatement returns [RevokePermissionsStatement stmt]
 +    : K_REVOKE
 +          permissionOrAll
 +      K_ON
 +          resource
 +      K_FROM
 +          revokee=userOrRoleName
 +      { $stmt = new 
RevokePermissionsStatement(filterPermissions($permissionOrAll.perms, 
$resource.res), $resource.res, revokee); }
 +    ;
 +
 +/**
 + * GRANT ROLE <rolename> TO <grantee>
 + */
 +grantRoleStatement returns [GrantRoleStatement stmt]
 +    : K_GRANT
 +          role=userOrRoleName
 +      K_TO
 +          grantee=userOrRoleName
 +      { $stmt = new GrantRoleStatement(role, grantee); }
 +    ;
 +
 +/**
 + * REVOKE ROLE <rolename> FROM <revokee>
 + */
 +revokeRoleStatement returns [RevokeRoleStatement stmt]
 +    : K_REVOKE
 +          role=userOrRoleName
 +      K_FROM
 +          revokee=userOrRoleName
 +      { $stmt = new RevokeRoleStatement(role, revokee); }
 +    ;
 +
 +listPermissionsStatement returns [ListPermissionsStatement stmt]
 +    @init {
 +        IResource resource = null;
 +        boolean recursive = true;
 +        RoleName grantee = new RoleName();
 +    }
 +    : K_LIST
 +          permissionOrAll
 +      ( K_ON resource { resource = $resource.res; } )?
 +      ( K_OF roleName[grantee] )?
 +      ( K_NORECURSIVE { recursive = false; } )?
 +      { $stmt = new ListPermissionsStatement($permissionOrAll.perms, 
resource, grantee, recursive); }
 +    ;
 +
 +permission returns [Permission perm]
 +    : p=(K_CREATE | K_ALTER | K_DROP | K_SELECT | K_MODIFY | K_AUTHORIZE | 
K_DESCRIBE | K_EXECUTE)
 +    { $perm = Permission.valueOf($p.text.toUpperCase()); }
 +    ;
 +
 +permissionOrAll returns [Set<Permission> perms]
 +    : K_ALL ( K_PERMISSIONS )?       { $perms = Permission.ALL; }
 +    | p=permission ( K_PERMISSION )? { $perms = EnumSet.of($p.perm); }
 +    ;
 +
 +resource returns [IResource res]
 +    : d=dataResource { $res = $d.res; }
 +    | r=roleResource { $res = $r.res; }
 +    | f=functionResource { $res = $f.res; }
 +    | j=jmxResource { $res = $j.res; }
 +    ;
 +
 +dataResource returns [DataResource res]
 +    : K_ALL K_KEYSPACES { $res = DataResource.root(); }
 +    | K_KEYSPACE ks = keyspaceName { $res = DataResource.keyspace($ks.id); }
 +    | ( K_COLUMNFAMILY )? cf = columnFamilyName
 +      { $res = DataResource.table($cf.name.getKeyspace(), 
$cf.name.getColumnFamily()); }
 +    ;
 +
 +jmxResource returns [JMXResource res]
 +    : K_ALL K_MBEANS { $res = JMXResource.root(); }
 +    // when a bean name (or pattern) is supplied, validate that it's a legal 
ObjectName
 +    // also, just to be picky, if the "MBEANS" form is used, only allow a 
pattern style names
 +    | K_MBEAN mbean { $res = 
JMXResource.mbean(canonicalizeObjectName($mbean.text, false)); }
 +    | K_MBEANS mbean { $res = 
JMXResource.mbean(canonicalizeObjectName($mbean.text, true)); }
 +    ;
 +
 +roleResource returns [RoleResource res]
 +    : K_ALL K_ROLES { $res = RoleResource.root(); }
 +    | K_ROLE role = userOrRoleName { $res = 
RoleResource.role($role.name.getName()); }
 +    ;
 +
 +functionResource returns [FunctionResource res]
 +    @init {
 +        List<CQL3Type.Raw> argsTypes = new ArrayList<>();
 +    }
 +    : K_ALL K_FUNCTIONS { $res = FunctionResource.root(); }
 +    | K_ALL K_FUNCTIONS K_IN K_KEYSPACE ks = keyspaceName { $res = 
FunctionResource.keyspace($ks.id); }
 +    // Arg types are mandatory for DCL statements on Functions
 +    | K_FUNCTION fn=functionName
 +      (
 +        '('
 +          (
 +            v=comparatorType { argsTypes.add(v); }
 +            ( ',' v=comparatorType { argsTypes.add(v); } )*
 +          )?
 +        ')'
 +      )
 +      { $res = FunctionResource.functionFromCql($fn.s.keyspace, $fn.s.name, 
argsTypes); }
 +    ;
 +
 +/**
 + * CREATE USER [IF NOT EXISTS] <username> [WITH PASSWORD <password>] 
[SUPERUSER|NOSUPERUSER]
 + */
 +createUserStatement returns [CreateRoleStatement stmt]
 +    @init {
 +        RoleOptions opts = new RoleOptions();
 +        opts.setOption(IRoleManager.Option.LOGIN, true);
 +        boolean superuser = false;
 +        boolean ifNotExists = false;
 +        RoleName name = new RoleName();
 +    }
 +    : K_CREATE K_USER (K_IF K_NOT K_EXISTS { ifNotExists = true; })? 
u=username { name.setName($u.text, true); }
 +      ( K_WITH userPassword[opts] )?
 +      ( K_SUPERUSER { superuser = true; } | K_NOSUPERUSER { superuser = 
false; } )?
 +      { opts.setOption(IRoleManager.Option.SUPERUSER, superuser);
 +        $stmt = new CreateRoleStatement(name, opts, ifNotExists); }
 +    ;
 +
 +/**
 + * ALTER USER <username> [WITH PASSWORD <password>] [SUPERUSER|NOSUPERUSER]
 + */
 +alterUserStatement returns [AlterRoleStatement stmt]
 +    @init {
 +        RoleOptions opts = new RoleOptions();
 +        RoleName name = new RoleName();
 +    }
 +    : K_ALTER K_USER u=username { name.setName($u.text, true); }
 +      ( K_WITH userPassword[opts] )?
 +      ( K_SUPERUSER { opts.setOption(IRoleManager.Option.SUPERUSER, true); }
 +        | K_NOSUPERUSER { opts.setOption(IRoleManager.Option.SUPERUSER, 
false); } ) ?
 +      {  $stmt = new AlterRoleStatement(name, opts); }
 +    ;
 +
 +/**
 + * DROP USER [IF EXISTS] <username>
 + */
 +dropUserStatement returns [DropRoleStatement stmt]
 +    @init {
 +        boolean ifExists = false;
 +        RoleName name = new RoleName();
 +    }
 +    : K_DROP K_USER (K_IF K_EXISTS { ifExists = true; })? u=username { 
name.setName($u.text, true); $stmt = new DropRoleStatement(name, ifExists); }
 +    ;
 +
 +/**
 + * LIST USERS
 + */
 +listUsersStatement returns [ListRolesStatement stmt]
 +    : K_LIST K_USERS { $stmt = new ListUsersStatement(); }
 +    ;
 +
 +/**
 + * CREATE ROLE [IF NOT EXISTS] <rolename> [ [WITH] option [ [AND] option ]* ]
 + *
 + * where option can be:
 + *  PASSWORD = '<password>'
 + *  SUPERUSER = (true|false)
 + *  LOGIN = (true|false)
 + *  OPTIONS = { 'k1':'v1', 'k2':'v2'}
 + */
 +createRoleStatement returns [CreateRoleStatement stmt]
 +    @init {
 +        RoleOptions opts = new RoleOptions();
 +        boolean ifNotExists = false;
 +    }
 +    : K_CREATE K_ROLE (K_IF K_NOT K_EXISTS { ifNotExists = true; })? 
name=userOrRoleName
 +      ( K_WITH roleOptions[opts] )?
 +      {
 +        // set defaults if they weren't explictly supplied
 +        if (!opts.getLogin().isPresent())
 +        {
 +            opts.setOption(IRoleManager.Option.LOGIN, false);
 +        }
 +        if (!opts.getSuperuser().isPresent())
 +        {
 +            opts.setOption(IRoleManager.Option.SUPERUSER, false);
 +        }
 +        $stmt = new CreateRoleStatement(name, opts, ifNotExists);
 +      }
 +    ;
 +
 +/**
 + * ALTER ROLE <rolename> [ [WITH] option [ [AND] option ]* ]
 + *
 + * where option can be:
 + *  PASSWORD = '<password>'
 + *  SUPERUSER = (true|false)
 + *  LOGIN = (true|false)
 + *  OPTIONS = { 'k1':'v1', 'k2':'v2'}
 + */
 +alterRoleStatement returns [AlterRoleStatement stmt]
 +    @init {
 +        RoleOptions opts = new RoleOptions();
 +    }
 +    : K_ALTER K_ROLE name=userOrRoleName
 +      ( K_WITH roleOptions[opts] )?
 +      {  $stmt = new AlterRoleStatement(name, opts); }
 +    ;
 +
 +/**
 + * DROP ROLE [IF EXISTS] <rolename>
 + */
 +dropRoleStatement returns [DropRoleStatement stmt]
 +    @init {
 +        boolean ifExists = false;
 +    }
 +    : K_DROP K_ROLE (K_IF K_EXISTS { ifExists = true; })? name=userOrRoleName
 +      { $stmt = new DropRoleStatement(name, ifExists); }
 +    ;
 +
 +/**
 + * LIST ROLES [OF <rolename>] [NORECURSIVE]
 + */
 +listRolesStatement returns [ListRolesStatement stmt]
 +    @init {
 +        boolean recursive = true;
 +        RoleName grantee = new RoleName();
 +    }
 +    : K_LIST K_ROLES
 +      ( K_OF roleName[grantee])?
 +      ( K_NORECURSIVE { recursive = false; } )?
 +      { $stmt = new ListRolesStatement(grantee, recursive); }
 +    ;
 +
 +roleOptions[RoleOptions opts]
 +    : roleOption[opts] (K_AND roleOption[opts])*
 +    ;
 +
 +roleOption[RoleOptions opts]
 +    :  K_PASSWORD '=' v=STRING_LITERAL { 
opts.setOption(IRoleManager.Option.PASSWORD, $v.text); }
 +    |  K_OPTIONS '=' m=mapLiteral { 
opts.setOption(IRoleManager.Option.OPTIONS, convertPropertyMap(m)); }
 +    |  K_SUPERUSER '=' b=BOOLEAN { 
opts.setOption(IRoleManager.Option.SUPERUSER, Boolean.valueOf($b.text)); }
 +    |  K_LOGIN '=' b=BOOLEAN { opts.setOption(IRoleManager.Option.LOGIN, 
Boolean.valueOf($b.text)); }
 +    ;
 +
 +// for backwards compatibility in CREATE/ALTER USER, this has no '='
 +userPassword[RoleOptions opts]
 +    :  K_PASSWORD v=STRING_LITERAL { 
opts.setOption(IRoleManager.Option.PASSWORD, $v.text); }
 +    ;
 +
 +/** DEFINITIONS **/
 +
 +// Column Identifiers.  These need to be treated differently from other
 +// identifiers because the underlying comparator is not necessarily text. See
 +// CASSANDRA-8178 for details.
 +cident returns [ColumnDefinition.Raw id]
 +    : t=IDENT              { $id = ColumnDefinition.Raw.forUnquoted($t.text); 
}
 +    | t=QUOTED_NAME        { $id = ColumnDefinition.Raw.forQuoted($t.text); }
 +    | k=unreserved_keyword { $id = ColumnDefinition.Raw.forUnquoted(k); }
 +    ;
 +
 +// Column identifiers where the comparator is known to be text
 +ident returns [ColumnIdentifier id]
 +    : t=IDENT              { $id = ColumnIdentifier.getInterned($t.text, 
false); }
 +    | t=QUOTED_NAME        { $id = ColumnIdentifier.getInterned($t.text, 
true); }
 +    | k=unreserved_keyword { $id = ColumnIdentifier.getInterned(k, false); }
 +    ;
 +
 +fident returns [FieldIdentifier id]
 +    : t=IDENT              { $id = FieldIdentifier.forUnquoted($t.text); }
 +    | t=QUOTED_NAME        { $id = FieldIdentifier.forQuoted($t.text); }
 +    | k=unreserved_keyword { $id = FieldIdentifier.forUnquoted(k); }
 +    ;
 +
 +// Identifiers that do not refer to columns
 +noncol_ident returns [ColumnIdentifier id]
 +    : t=IDENT              { $id = new ColumnIdentifier($t.text, false); }
 +    | t=QUOTED_NAME        { $id = new ColumnIdentifier($t.text, true); }
 +    | k=unreserved_keyword { $id = new ColumnIdentifier(k, false); }
 +    ;
 +
 +// Keyspace & Column family names
 +keyspaceName returns [String id]
 +    @init { CFName name = new CFName(); }
 +    : ksName[name] { $id = name.getKeyspace(); }
 +    ;
 +
 +indexName returns [IndexName name]
 +    @init { $name = new IndexName(); }
 +    : (ksName[name] '.')? idxName[name]
 +    ;
 +
 +columnFamilyName returns [CFName name]
 +    @init { $name = new CFName(); }
 +    : (ksName[name] '.')? cfName[name]
 +    ;
 +
 +userTypeName returns [UTName name]
 +    : (ks=noncol_ident '.')? ut=non_type_ident { $name = new UTName(ks, ut); }
 +    ;
 +
 +userOrRoleName returns [RoleName name]
 +    @init { RoleName role = new RoleName(); }
 +    : roleName[role] {$name = role;}
 +    ;
 +
 +ksName[KeyspaceElementName name]
 +    : t=IDENT              { $name.setKeyspace($t.text, false);}
 +    | t=QUOTED_NAME        { $name.setKeyspace($t.text, true);}
 +    | k=unreserved_keyword { $name.setKeyspace(k, false);}
 +    | QMARK {addRecognitionError("Bind variables cannot be used for keyspace 
names");}
 +    ;
 +
 +cfName[CFName name]
 +    : t=IDENT              { $name.setColumnFamily($t.text, false); }
 +    | t=QUOTED_NAME        { $name.setColumnFamily($t.text, true); }
 +    | k=unreserved_keyword { $name.setColumnFamily(k, false); }
 +    | QMARK {addRecognitionError("Bind variables cannot be used for table 
names");}
 +    ;
 +
 +idxName[IndexName name]
 +    : t=IDENT              { $name.setIndex($t.text, false); }
 +    | t=QUOTED_NAME        { $name.setIndex($t.text, true);}
 +    | k=unreserved_keyword { $name.setIndex(k, false); }
 +    | QMARK {addRecognitionError("Bind variables cannot be used for index 
names");}
 +    ;
 +
 +roleName[RoleName name]
 +    : t=IDENT              { $name.setName($t.text, false); }
 +    | s=STRING_LITERAL     { $name.setName($s.text, true); }
 +    | t=QUOTED_NAME        { $name.setName($t.text, true); }
 +    | k=unreserved_keyword { $name.setName(k, false); }
 +    | QMARK {addRecognitionError("Bind variables cannot be used for role 
names");}
 +    ;
 +
 +constant returns [Constants.Literal constant]
 +    : t=STRING_LITERAL { $constant = Constants.Literal.string($t.text); }
 +    | t=INTEGER        { $constant = Constants.Literal.integer($t.text); }
 +    | t=FLOAT          { $constant = 
Constants.Literal.floatingPoint($t.text); }
 +    | t=BOOLEAN        { $constant = Constants.Literal.bool($t.text); }
 +    | t=UUID           { $constant = Constants.Literal.uuid($t.text); }
 +    | t=HEXNUMBER      { $constant = Constants.Literal.hex($t.text); }
 +    | { String sign=""; } ('-' {sign = "-"; } )? t=(K_NAN | K_INFINITY) { 
$constant = Constants.Literal.floatingPoint(sign + $t.text); }
 +    ;
 +
 +mapLiteral returns [Maps.Literal map]
 +    : '{' { List<Pair<Term.Raw, Term.Raw>> m = new ArrayList<Pair<Term.Raw, 
Term.Raw>>(); }
 +          ( k1=term ':' v1=term { m.add(Pair.create(k1, v1)); } ( ',' kn=term 
':' vn=term { m.add(Pair.create(kn, vn)); } )* )?
 +      '}' { $map = new Maps.Literal(m); }
 +    ;
 +
 +setOrMapLiteral[Term.Raw t] returns [Term.Raw value]
 +    : ':' v=term { List<Pair<Term.Raw, Term.Raw>> m = new 
ArrayList<Pair<Term.Raw, Term.Raw>>(); m.add(Pair.create(t, v)); }
 +          ( ',' kn=term ':' vn=term { m.add(Pair.create(kn, vn)); } )*
 +      { $value = new Maps.Literal(m); }
 +    | { List<Term.Raw> s = new ArrayList<Term.Raw>(); s.add(t); }
 +          ( ',' tn=term { s.add(tn); } )*
 +      { $value = new Sets.Literal(s); }
 +    ;
 +
 +collectionLiteral returns [Term.Raw value]
 +    : '[' { List<Term.Raw> l = new ArrayList<Term.Raw>(); }
 +          ( t1=term { l.add(t1); } ( ',' tn=term { l.add(tn); } )* )?
 +      ']' { $value = new Lists.Literal(l); }
 +    | '{' t=term v=setOrMapLiteral[t] { $value = v; } '}'
 +    // Note that we have an ambiguity between maps and set for "{}". So we 
force it to a set literal,
 +    // and deal with it later based on the type of the column 
(SetLiteral.java).
 +    | '{' '}' { $value = new Sets.Literal(Collections.<Term.Raw>emptyList()); 
}
 +    ;
 +
 +usertypeLiteral returns [UserTypes.Literal ut]
 +    @init{ Map<FieldIdentifier, Term.Raw> m = new HashMap<>(); }
 +    @after{ $ut = new UserTypes.Literal(m); }
 +    // We don't allow empty literals because that conflicts with sets/maps 
and is currently useless since we don't allow empty user types
 +    : '{' k1=fident ':' v1=term { m.put(k1, v1); } ( ',' kn=fident ':' 
vn=term { m.put(kn, vn); } )* '}'
 +    ;
 +
 +tupleLiteral returns [Tuples.Literal tt]
 +    @init{ List<Term.Raw> l = new ArrayList<Term.Raw>(); }
 +    @after{ $tt = new Tuples.Literal(l); }
 +    : '(' t1=term { l.add(t1); } ( ',' tn=term { l.add(tn); } )* ')'
 +    ;
 +
 +value returns [Term.Raw value]
 +    : c=constant           { $value = c; }
 +    | l=collectionLiteral  { $value = l; }
 +    | u=usertypeLiteral    { $value = u; }
 +    | t=tupleLiteral       { $value = t; }
 +    | K_NULL               { $value = Constants.NULL_LITERAL; }
 +    | ':' id=noncol_ident  { $value = newBindVariables(id); }
 +    | QMARK                { $value = newBindVariables(null); }
 +    ;
 +
 +intValue returns [Term.Raw value]
 +    : t=INTEGER     { $value = Constants.Literal.integer($t.text); }
 +    | ':' id=noncol_ident  { $value = newBindVariables(id); }
 +    | QMARK         { $value = newBindVariables(null); }
 +    ;
 +
 +functionName returns [FunctionName s]
 +    : (ks=keyspaceName '.')? f=allowedFunctionName   { $s = new 
FunctionName(ks, f); }
 +    ;
 +
 +allowedFunctionName returns [String s]
 +    : f=IDENT                       { $s = $f.text.toLowerCase(); }
 +    | f=QUOTED_NAME                 { $s = $f.text; }
 +    | u=unreserved_function_keyword { $s = u; }
 +    | K_TOKEN                       { $s = "token"; }
 +    | K_COUNT                       { $s = "count"; }
 +    ;
 +
 +function returns [Term.Raw t]
 +    : f=functionName '(' ')'                   { $t = new FunctionCall.Raw(f, 
Collections.<Term.Raw>emptyList()); }
 +    | f=functionName '(' args=functionArgs ')' { $t = new FunctionCall.Raw(f, 
args); }
 +    ;
 +
 +functionArgs returns [List<Term.Raw> args]
 +    @init{ $args = new ArrayList<Term.Raw>(); }
 +    : t1=term {args.add(t1); } ( ',' tn=term { args.add(tn); } )*
 +    ;
 +
 +term returns [Term.Raw term]
 +    : v=value                          { $term = v; }
 +    | f=function                       { $term = f; }
 +    | '(' c=comparatorType ')' t=term  { $term = new TypeCast(c, t); }
 +    ;
 +
 +columnOperation[List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> 
operations]
 +    : key=cident columnOperationDifferentiator[operations, key]
 +    ;
 +
 +columnOperationDifferentiator[List<Pair<ColumnDefinition.Raw, 
Operation.RawUpdate>> operations, ColumnDefinition.Raw key]
 +    : '=' normalColumnOperation[operations, key]
 +    | shorthandColumnOperation[operations, key]
 +    | '[' k=term ']' collectionColumnOperation[operations, key, k]
 +    | '.' field=fident udtColumnOperation[operations, key, field]
 +    ;
 +
 +normalColumnOperation[List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> 
operations, ColumnDefinition.Raw key]
 +    : t=term ('+' c=cident )?
 +      {
 +          if (c == null)
 +          {
 +              addRawUpdate(operations, key, new Operation.SetValue(t));
 +          }
 +          else
 +          {
 +              if (!key.equals(c))
 +                  addRecognitionError("Only expressions of the form X = 
<value> + X are supported.");
 +              addRawUpdate(operations, key, new Operation.Prepend(t));
 +          }
 +      }
 +    | c=cident sig=('+' | '-') t=term
 +      {
 +          if (!key.equals(c))
 +              addRecognitionError("Only expressions of the form X = X " + 
$sig.text + "<value> are supported.");
 +          addRawUpdate(operations, key, $sig.text.equals("+") ? new 
Operation.Addition(t) : new Operation.Substraction(t));
 +      }
 +    | c=cident i=INTEGER
 +      {
 +          // Note that this production *is* necessary because X = X - 3 will 
in fact be lexed as [ X, '=', X, INTEGER].
 +          if (!key.equals(c))
 +              // We don't yet allow a '+' in front of an integer, but we 
could in the future really, so let's be future-proof in our error message
 +              addRecognitionError("Only expressions of the form X = X " + 
($i.text.charAt(0) == '-' ? '-' : '+') + " <value> are supported.");
 +          addRawUpdate(operations, key, new 
Operation.Addition(Constants.Literal.integer($i.text)));
 +      }
 +    ;
 +
 +shorthandColumnOperation[List<Pair<ColumnDefinition.Raw, 
Operation.RawUpdate>> operations, ColumnDefinition.Raw key]
 +    : sig=('+=' | '-=') t=term
 +      {
 +          addRawUpdate(operations, key, $sig.text.equals("+=") ? new 
Operation.Addition(t) : new Operation.Substraction(t));
 +      }
 +    ;
 +
 +collectionColumnOperation[List<Pair<ColumnDefinition.Raw, 
Operation.RawUpdate>> operations, ColumnDefinition.Raw key, Term.Raw k]
 +    : '=' t=term
 +      {
 +          addRawUpdate(operations, key, new Operation.SetElement(k, t));
 +      }
 +    ;
 +
 +udtColumnOperation[List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> 
operations, ColumnDefinition.Raw key, FieldIdentifier field]
 +    : '=' t=term
 +      {
 +          addRawUpdate(operations, key, new Operation.SetField(field, t));
 +      }
 +    ;
 +
 +columnCondition[List<Pair<ColumnDefinition.Raw, ColumnCondition.Raw>> 
conditions]
 +    // Note: we'll reject duplicates later
 +    : key=cident
 +        ( op=relationType t=term { conditions.add(Pair.create(key, 
ColumnCondition.Raw.simpleCondition(t, op))); }
 +        | K_IN
 +            ( values=singleColumnInValues { conditions.add(Pair.create(key, 
ColumnCondition.Raw.simpleInCondition(values))); }
 +            | marker=inMarker { conditions.add(Pair.create(key, 
ColumnCondition.Raw.simpleInCondition(marker))); }
 +            )
 +        | '[' element=term ']'
 +            ( op=relationType t=term { conditions.add(Pair.create(key, 
ColumnCondition.Raw.collectionCondition(t, element, op))); }
 +            | K_IN
 +                ( values=singleColumnInValues { 
conditions.add(Pair.create(key, 
ColumnCondition.Raw.collectionInCondition(element, values))); }
 +                | marker=inMarker { conditions.add(Pair.create(key, 
ColumnCondition.Raw.collectionInCondition(element, marker))); }
 +                )
 +            )
 +        | '.' field=fident
 +            ( op=relationType t=term { conditions.add(Pair.create(key, 
ColumnCondition.Raw.udtFieldCondition(t, field, op))); }
 +            | K_IN
 +                ( values=singleColumnInValues { 
conditions.add(Pair.create(key, ColumnCondition.Raw.udtFieldInCondition(field, 
values))); }
 +                | marker=inMarker { conditions.add(Pair.create(key, 
ColumnCondition.Raw.udtFieldInCondition(field, marker))); }
 +                )
 +            )
 +        )
 +    ;
 +
 +properties[PropertyDefinitions props]
 +    : property[props] (K_AND property[props])*
 +    ;
 +
 +property[PropertyDefinitions props]
 +    : k=noncol_ident '=' simple=propertyValue { try { 
$props.addProperty(k.toString(), simple); } catch (SyntaxException e) { 
addRecognitionError(e.getMessage()); } }
 +    | k=noncol_ident '=' map=mapLiteral { try { 
$props.addProperty(k.toString(), convertPropertyMap(map)); } catch 
(SyntaxException e) { addRecognitionError(e.getMessage()); } }
 +    ;
 +
 +propertyValue returns [String str]
 +    : c=constant           { $str = c.getRawText(); }
 +    | u=unreserved_keyword { $str = u; }
 +    ;
 +
 +relationType returns [Operator op]
 +    : '='  { $op = Operator.EQ; }
 +    | '<'  { $op = Operator.LT; }
 +    | '<=' { $op = Operator.LTE; }
 +    | '>'  { $op = Operator.GT; }
 +    | '>=' { $op = Operator.GTE; }
 +    | '!=' { $op = Operator.NEQ; }
 +    ;
 +
 +relation[WhereClause.Builder clauses]
 +    : name=cident type=relationType t=term { $clauses.add(new 
SingleColumnRelation(name, type, t)); }
 +    | name=cident K_LIKE t=term { $clauses.add(new SingleColumnRelation(name, 
Operator.LIKE, t)); }
 +    | name=cident K_IS K_NOT K_NULL { $clauses.add(new 
SingleColumnRelation(name, Operator.IS_NOT, Constants.NULL_LITERAL)); }
 +    | K_TOKEN l=tupleOfIdentifiers type=relationType t=term
 +        { $clauses.add(new TokenRelation(l, type, t)); }
 +    | name=cident K_IN marker=inMarker
 +        { $clauses.add(new SingleColumnRelation(name, Operator.IN, marker)); }
 +    | name=cident K_IN inValues=singleColumnInValues
 +        { $clauses.add(SingleColumnRelation.createInRelation($name.id, 
inValues)); }
 +    | name=cident K_CONTAINS { Operator rt = Operator.CONTAINS; } (K_KEY { rt 
= Operator.CONTAINS_KEY; })?
 +        t=term { $clauses.add(new SingleColumnRelation(name, rt, t)); }
 +    | name=cident '[' key=term ']' type=relationType t=term { 
$clauses.add(new SingleColumnRelation(name, key, type, t)); }
 +    | ids=tupleOfIdentifiers
 +      ( K_IN
 +          ( '(' ')'
 +              { $clauses.add(MultiColumnRelation.createInRelation(ids, new 
ArrayList<Tuples.Literal>())); }
 +          | tupleInMarker=inMarkerForTuple /* (a, b, c) IN ? */
 +              { 
$clauses.add(MultiColumnRelation.createSingleMarkerInRelation(ids, 
tupleInMarker)); }
 +          | literals=tupleOfTupleLiterals /* (a, b, c) IN ((1, 2, 3), (4, 5, 
6), ...) */
 +              {
 +                  $clauses.add(MultiColumnRelation.createInRelation(ids, 
literals));
 +              }
 +          | markers=tupleOfMarkersForTuples /* (a, b, c) IN (?, ?, ...) */
 +              { $clauses.add(MultiColumnRelation.createInRelation(ids, 
markers)); }
 +          )
 +      | type=relationType literal=tupleLiteral /* (a, b, c) > (1, 2, 3) or 
(a, b, c) > (?, ?, ?) */
 +          {
 +              $clauses.add(MultiColumnRelation.createNonInRelation(ids, type, 
literal));
 +          }
 +      | type=relationType tupleMarker=markerForTuple /* (a, b, c) >= ? */
 +          { $clauses.add(MultiColumnRelation.createNonInRelation(ids, type, 
tupleMarker)); }
 +      )
 +    | '(' relation[$clauses] ')'
 +    ;
 +
 +inMarker returns [AbstractMarker.INRaw marker]
 +    : QMARK { $marker = newINBindVariables(null); }
 +    | ':' name=noncol_ident { $marker = newINBindVariables(name); }
 +    ;
 +
 +tupleOfIdentifiers returns [List<ColumnDefinition.Raw> ids]
 +    @init { $ids = new ArrayList<ColumnDefinition.Raw>(); }
 +    : '(' n1=cident { $ids.add(n1); } (',' ni=cident { $ids.add(ni); })* ')'
 +    ;
 +
 +singleColumnInValues returns [List<Term.Raw> terms]
 +    @init { $terms = new ArrayList<Term.Raw>(); }
 +    : '(' ( t1 = term { $terms.add(t1); } (',' ti=term { $terms.add(ti); })* 
)? ')'
 +    ;
 +
 +tupleOfTupleLiterals returns [List<Tuples.Literal> literals]
 +    @init { $literals = new ArrayList<>(); }
 +    : '(' t1=tupleLiteral { $literals.add(t1); } (',' ti=tupleLiteral { 
$literals.add(ti); })* ')'
 +    ;
 +
 +markerForTuple returns [Tuples.Raw marker]
 +    : QMARK { $marker = newTupleBindVariables(null); }
 +    | ':' name=noncol_ident { $marker = newTupleBindVariables(name); }
 +    ;
 +
 +tupleOfMarkersForTuples returns [List<Tuples.Raw> markers]
 +    @init { $markers = new ArrayList<Tuples.Raw>(); }
 +    : '(' m1=markerForTuple { $markers.add(m1); } (',' mi=markerForTuple { 
$markers.add(mi); })* ')'
 +    ;
 +
 +inMarkerForTuple returns [Tuples.INRaw marker]
 +    : QMARK { $marker = newTupleINBindVariables(null); }
 +    | ':' name=noncol_ident { $marker = newTupleINBindVariables(name); }
 +    ;
 +
 +comparatorType returns [CQL3Type.Raw t]
 +    : n=native_type     { $t = CQL3Type.Raw.from(n); }
 +    | c=collection_type { $t = c; }
 +    | tt=tuple_type     { $t = tt; }
 +    | id=userTypeName   { $t = CQL3Type.Raw.userType(id); }
 +    | K_FROZEN '<' f=comparatorType '>'
 +      {
 +        try {
 +            $t = CQL3Type.Raw.frozen(f);
 +        } catch (InvalidRequestException e) {
 +            addRecognitionError(e.getMessage());
 +        }
 +      }
 +    | s=STRING_LITERAL
 +      {
 +        try {
 +            $t = CQL3Type.Raw.from(new CQL3Type.Custom($s.text));
 +        } catch (SyntaxException e) {
 +            addRecognitionError("Cannot parse type " + $s.text + ": " + 
e.getMessage());
 +        } catch (ConfigurationException e) {
 +            addRecognitionError("Error setting type " + $s.text + ": " + 
e.getMessage());
 +        }
 +      }
 +    ;
 +
 +native_type returns [CQL3Type t]
 +    : K_ASCII     { $t = CQL3Type.Native.ASCII; }
 +    | K_BIGINT    { $t = CQL3Type.Native.BIGINT; }
 +    | K_BLOB      { $t = CQL3Type.Native.BLOB; }
 +    | K_BOOLEAN   { $t = CQL3Type.Native.BOOLEAN; }
 +    | K_COUNTER   { $t = CQL3Type.Native.COUNTER; }
 +    | K_DECIMAL   { $t = CQL3Type.Native.DECIMAL; }
 +    | K_DOUBLE    { $t = CQL3Type.Native.DOUBLE; }
 +    | K_FLOAT     { $t = CQL3Type.Native.FLOAT; }
 +    | K_INET      { $t = CQL3Type.Native.INET;}
 +    | K_INT       { $t = CQL3Type.Native.INT; }
 +    | K_SMALLINT  { $t = CQL3Type.Native.SMALLINT; }
 +    | K_TEXT      { $t = CQL3Type.Native.TEXT; }
 +    | K_TIMESTAMP { $t = CQL3Type.Native.TIMESTAMP; }
 +    | K_TINYINT   { $t = CQL3Type.Native.TINYINT; }
 +    | K_UUID      { $t = CQL3Type.Native.UUID; }
 +    | K_VARCHAR   { $t = CQL3Type.Native.VARCHAR; }
 +    | K_VARINT    { $t = CQL3Type.Native.VARINT; }
 +    | K_TIMEUUID  { $t = CQL3Type.Native.TIMEUUID; }
 +    | K_DATE      { $t = CQL3Type.Native.DATE; }
 +    | K_TIME      { $t = CQL3Type.Native.TIME; }
 +    ;
 +
 +collection_type returns [CQL3Type.Raw pt]
 +    : K_MAP  '<' t1=comparatorType ',' t2=comparatorType '>'
 +        {
 +            // if we can't parse either t1 or t2, antlr will "recover" and we 
may have t1 or t2 null.
 +            if (t1 != null && t2 != null)
 +                $pt = CQL3Type.Raw.map(t1, t2);
 +        }
 +    | K_LIST '<' t=comparatorType '>'
 +        { if (t != null) $pt = CQL3Type.Raw.list(t); }
 +    | K_SET  '<' t=comparatorType '>'
 +        { if (t != null) $pt = CQL3Type.Raw.set(t); }
 +    ;
 +
 +tuple_type returns [CQL3Type.Raw t]
 +    : K_TUPLE '<' { List<CQL3Type.Raw> types = new ArrayList<>(); }
 +         t1=comparatorType { types.add(t1); } (',' tn=comparatorType { 
types.add(tn); })*
 +      '>' { $t = CQL3Type.Raw.tuple(types); }
 +    ;
 +
 +username
 +    : IDENT
 +    | STRING_LITERAL
 +    | QUOTED_NAME { addRecognitionError("Quoted strings are are not supported 
for user names and USER is deprecated, please use ROLE");}
 +    ;
 +
 +mbean
 +    : STRING_LITERAL
 +    ;
 +
 +// Basically the same as cident, but we need to exlude existing CQL3 types
 +// (which for some reason are not reserved otherwise)
 +non_type_ident returns [ColumnIdentifier id]
 +    : t=IDENT                    { if (reservedTypeNames.contains($t.text)) 
addRecognitionError("Invalid (reserved) user type name " + $t.text); $id = new 
ColumnIdentifier($t.text, false); }
 +    | t=QUOTED_NAME              { $id = new ColumnIdentifier($t.text, true); 
}
 +    | k=basic_unreserved_keyword { $id = new ColumnIdentifier(k, false); }
 +    | kk=K_KEY                   { $id = new ColumnIdentifier($kk.text, 
false); }
 +    ;
 +
 +unreserved_keyword returns [String str]
 +    : u=unreserved_function_keyword     { $str = u; }
 +    | k=(K_TTL | K_COUNT | K_WRITETIME | K_KEY | K_CAST | K_JSON | 
K_DISTINCT) { $str = $k.text; }
 +    ;
 +
 +unreserved_function_keyword returns [String str]
 +    : u=basic_unreserved_keyword { $str = u; }
 +    | t=native_type              { $str = t.toString(); }
 +    ;
 +
 +basic_unreserved_keyword returns [String str]
 +    : k=( K_KEYS
 +        | K_AS
 +        | K_CLUSTERING
 +        | K_COMPACT
 +        | K_STORAGE
 +        | K_TYPE
 +        | K_VALUES
 +        | K_MAP
 +        | K_LIST
 +        | K_FILTERING
 +        | K_PERMISSION
 +        | K_PERMISSIONS
 +        | K_KEYSPACES
 +        | K_ALL
 +        | K_USER
 +        | K_USERS
 +        | K_ROLE
 +        | K_ROLES
 +        | K_SUPERUSER
 +        | K_NOSUPERUSER
 +        | K_LOGIN
 +        | K_NOLOGIN
 +        | K_OPTIONS
 +        | K_PASSWORD
 +        | K_EXISTS
 +        | K_CUSTOM
 +        | K_TRIGGER
 +        | K_CONTAINS
 +        | K_STATIC
 +        | K_FROZEN
 +        | K_TUPLE
 +        | K_FUNCTION
 +        | K_FUNCTIONS
 +        | K_AGGREGATE
 +        | K_SFUNC
 +        | K_STYPE
 +        | K_FINALFUNC
 +        | K_INITCOND
 +        | K_RETURNS
 +        | K_LANGUAGE
 +        | K_CALLED
 +        | K_INPUT
 +        | K_LIKE
 +        | K_PER
 +        | K_PARTITION
 +        | K_GROUP
 +        ) { $str = $k.text; }
-     ;
++    ;

Reply via email to