/* * 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 = Cpp; } @parser::namespace{cql3_parser} @lexer::includes { #include "cql3/error_collector.hh" #include "cql3/error_listener.hh" } @parser::includes { #include "cql3/selection/writetime_or_ttl.hh" #include "cql3/statements/raw/parsed_statement.hh" #include "cql3/statements/raw/select_statement.hh" #include "cql3/statements/alter_keyspace_statement.hh" #include "cql3/statements/alter_table_statement.hh" #include "cql3/statements/create_keyspace_statement.hh" #include "cql3/statements/drop_keyspace_statement.hh" #include "cql3/statements/create_index_statement.hh" #include "cql3/statements/create_table_statement.hh" #include "cql3/statements/create_type_statement.hh" #include "cql3/statements/drop_type_statement.hh" #include "cql3/statements/alter_type_statement.hh" #include "cql3/statements/property_definitions.hh" #include "cql3/statements/drop_table_statement.hh" #include "cql3/statements/truncate_statement.hh" #include "cql3/statements/raw/update_statement.hh" #include "cql3/statements/raw/insert_statement.hh" #include "cql3/statements/raw/delete_statement.hh" #include "cql3/statements/index_prop_defs.hh" #include "cql3/statements/raw/use_statement.hh" #include "cql3/statements/raw/batch_statement.hh" #include "cql3/statements/create_user_statement.hh" #include "cql3/statements/alter_user_statement.hh" #include "cql3/statements/drop_user_statement.hh" #include "cql3/statements/list_users_statement.hh" #include "cql3/statements/grant_statement.hh" #include "cql3/statements/revoke_statement.hh" #include "cql3/statements/list_permissions_statement.hh" #include "cql3/statements/index_target.hh" #include "cql3/statements/ks_prop_defs.hh" #include "cql3/selection/raw_selector.hh" #include "cql3/keyspace_element_name.hh" #include "cql3/selection/selectable_with_field_selection.hh" #include "cql3/constants.hh" #include "cql3/operation_impl.hh" #include "cql3/error_listener.hh" #include "cql3/multi_column_relation.hh" #include "cql3/single_column_relation.hh" #include "cql3/token_relation.hh" #include "cql3/index_name.hh" #include "cql3/cql3_type.hh" #include "cql3/cf_name.hh" #include "cql3/maps.hh" #include "cql3/sets.hh" #include "cql3/lists.hh" #include "cql3/type_cast.hh" #include "cql3/tuples.hh" #include "cql3/user_types.hh" #include "cql3/ut_name.hh" #include "cql3/functions/function_name.hh" #include "cql3/functions/function_call.hh" #include "core/sstring.hh" #include "CqlLexer.hpp" #include #include } @parser::traits { using namespace cql3::statements; using namespace cql3::selection; using cql3::cql3_type; using conditions_type = std::vector,::shared_ptr>>; using operations_type = std::vector,::shared_ptr>>; // ANTLR forces us to define a default-initialized return value // for every rule (e.g. [returns ut_name name]), but not every type // can be naturally zero-initialized. // // The uninitialized wrapper can be zero-initialized, and is convertible // to T (after checking that it was assigned to) implicitly, eliminating the // problem. It is up to the user to ensure it is actually assigned to. template struct uninitialized { std::experimental::optional _val; uninitialized() = default; uninitialized(const uninitialized&) = default; uninitialized(uninitialized&&) = default; uninitialized(const T& val) : _val(val) {} uninitialized(T&& val) : _val(std::move(val)) {} uninitialized& operator=(const uninitialized&) = default; uninitialized& operator=(uninitialized&&) = default; operator const T&() const & { return check(), *_val; } operator T&&() && { return check(), std::move(*_val); } void check() const { if (!_val) { throw std::runtime_error("not intitialized"); } } }; } @context { using collector_type = cql3::error_collector; using listener_type = cql3::error_listener; listener_type* listener; std::vector<::shared_ptr> _bind_variables; std::vector> _missing_tokens; // Can't use static variable, since it needs to be defined out-of-line static const std::unordered_set& _reserved_type_names() { static std::unordered_set s = { "byte", "smallint", "complex", "enum", "date", "interval", "macaddr", "bitstring", }; return s; } shared_ptr new_bind_variables(shared_ptr name) { auto marker = make_shared(_bind_variables.size()); _bind_variables.push_back(name); return marker; } shared_ptr new_in_bind_variables(shared_ptr name) { auto marker = make_shared(_bind_variables.size()); _bind_variables.push_back(std::move(name)); return marker; } shared_ptr new_tuple_bind_variables(shared_ptr name) { auto marker = make_shared(_bind_variables.size()); _bind_variables.push_back(std::move(name)); return marker; } shared_ptr new_tuple_in_bind_variables(shared_ptr name) { auto marker = make_shared(_bind_variables.size()); _bind_variables.push_back(std::move(name)); return marker; } void set_error_listener(listener_type& listener) { this->listener = &listener; } void displayRecognitionError(ANTLR_UINT8** token_names, ExceptionBaseType* ex) { listener->syntax_error(*this, token_names, ex); } void add_recognition_error(const sstring& msg) { listener->syntax_error(*this, msg); } bool is_eof_token(CommonTokenType token) const { return token == CommonTokenType::TOKEN_EOF; } std::string token_text(const TokenType* token) { if (!token) { return ""; } return token->getText(); } std::map convert_property_map(shared_ptr map) { if (!map || map->entries.empty()) { return std::map{}; } std::map res; for (auto&& 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.first || !entry.second) { break; } auto left = dynamic_pointer_cast(entry.first); if (!left) { sstring msg = "Invalid property name: " + entry.first->to_string(); if (dynamic_pointer_cast(entry.first)) { msg += " (bind variables are not supported in DDL queries)"; } add_recognition_error(msg); break; } auto right = dynamic_pointer_cast(entry.second); if (!right) { sstring msg = "Invalid property value: " + entry.first->to_string() + " for property: " + entry.second->to_string(); if (dynamic_pointer_cast(entry.second)) { msg += " (bind variables are not supported in DDL queries)"; } add_recognition_error(msg); break; } res.emplace(left->get_raw_text(), right->get_raw_text()); } return res; } void add_raw_update(std::vector,::shared_ptr>>& operations, ::shared_ptr key, ::shared_ptr update) { for (auto&& p : operations) { if (*p.first == *key && !p.second->is_compatible_with(update)) { // \%s is escaped for antlr add_recognition_error(sprint("Multiple incompatible setting of column \%s", *key)); } } operations.emplace_back(std::move(key), std::move(update)); } TokenType* getMissingSymbol(IntStreamType* istream, ExceptionBaseType* e, ANTLR_UINT32 expectedTokenType, BitsetListType* follow) { auto token = BaseType::getMissingSymbol(istream, e, expectedTokenType, follow); _missing_tokens.emplace_back(token); return token; } } @lexer::namespace{cql3_parser} @lexer::traits { class CqlLexer; class CqlParser; typedef antlr3::Traits CqlLexerTraits; typedef CqlLexerTraits CqlParserTraits; } @lexer::header { #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-function" } @lexer::context { using collector_type = cql3::error_collector; using listener_type = cql3::error_listener; listener_type* listener; void set_error_listener(listener_type& listener) { this->listener = &listener; } void displayRecognitionError(ANTLR_UINT8** token_names, ExceptionBaseType* ex) { listener->syntax_error(*this, token_names, ex); } bool is_eof_token(CommonTokenType token) const { return token == CommonTokenType::TOKEN_EOF; } std::string token_text(const TokenType* token) const { if (!token) { return ""; } return std::to_string(int(*token)); } } /** STATEMENTS **/ query returns [shared_ptr stmnt] : st=cqlStatement (';')* EOF { $stmnt = st; } ; cqlStatement returns [shared_ptr stmt] @after{ if (stmt) { stmt->set_bound_variables(_bind_variables); } } : 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; } #if 0 | st13=dropIndexStatement { $stmt = st13; } #endif | st14=alterTableStatement { $stmt = st14; } | st15=alterKeyspaceStatement { $stmt = st15; } | st16=grantStatement { $stmt = st16; } | st17=revokeStatement { $stmt = st17; } | st18=listPermissionsStatement { $stmt = st18; } | st19=createUserStatement { $stmt = st19; } | st20=alterUserStatement { $stmt = st20; } | st21=dropUserStatement { $stmt = st21; } | st22=listUsersStatement { $stmt = st22; } #if 0 | st23=createTriggerStatement { $stmt = st23; } | st24=dropTriggerStatement { $stmt = st24; } #endif | st25=createTypeStatement { $stmt = st25; } | st26=alterTypeStatement { $stmt = st26; } | st27=dropTypeStatement { $stmt = st27; } #if 0 | st28=createFunctionStatement { $stmt = st28; } | st29=dropFunctionStatement { $stmt = st29; } | st30=createAggregateStatement { $stmt = st30; } | st31=dropAggregateStatement { $stmt = st31; } #endif ; /* * USE ; */ useStatement returns [::shared_ptr stmt] : K_USE ks=keyspaceName { $stmt = ::make_shared(ks); } ; /** * SELECT * FROM * WHERE KEY = "key1" AND COL > 1 AND COL < 100 * LIMIT ; */ selectStatement returns [shared_ptr expr] @init { bool is_distinct = false; ::shared_ptr limit; raw::select_statement::parameters::orderings_type orderings; bool allow_filtering = false; } : K_SELECT ( ( K_DISTINCT { is_distinct = true; } )? sclause=selectClause | sclause=selectCountClause ) K_FROM cf=columnFamilyName ( K_WHERE wclause=whereClause )? ( K_ORDER K_BY orderByClause[orderings] ( ',' orderByClause[orderings] )* )? ( K_LIMIT rows=intValue { limit = rows; } )? ( K_ALLOW K_FILTERING { allow_filtering = true; } )? { auto params = ::make_shared(std::move(orderings), is_distinct, allow_filtering); $expr = ::make_shared(std::move(cf), std::move(params), std::move(sclause), std::move(wclause), std::move(limit)); } ; selectClause returns [std::vector> expr] : t1=selector { $expr.push_back(t1); } (',' tN=selector { $expr.push_back(tN); })* | '*' { } ; selector returns [shared_ptr s] @init{ shared_ptr alias; } : us=unaliasedSelector (K_AS c=ident { alias = c; })? { $s = make_shared(us, alias); } ; unaliasedSelector returns [shared_ptr s] @init { shared_ptr tmp; } : ( c=cident { tmp = c; } | K_WRITETIME '(' c=cident ')' { tmp = make_shared(c, true); } | K_TTL '(' c=cident ')' { tmp = make_shared(c, false); } | f=functionName args=selectionFunctionArgs { tmp = ::make_shared(std::move(f), std::move(args)); } ) ( '.' fi=cident { tmp = make_shared(std::move(tmp), std::move(fi)); } )* { $s = tmp; } ; selectionFunctionArgs returns [std::vector> a] : '(' ')' | '(' s1=unaliasedSelector { a.push_back(std::move(s1)); } ( ',' sn=unaliasedSelector { a.push_back(std::move(sn)); } )* ')' ; selectCountClause returns [std::vector> expr] @init{ auto alias = make_shared("count", false); } : K_COUNT '(' countArgument ')' (K_AS c=ident { alias = c; })? { auto&& with_fn = ::make_shared( cql3::functions::function_name::native_function("countRows"), std::vector>()); $expr.push_back(make_shared(with_fn, alias)); } ; countArgument : '*' | i=INTEGER { if (i->getText() != "1") { add_recognition_error("Only COUNT(1) is supported, got COUNT(" + i->getText() + ")"); } } ; whereClause returns [std::vector clause] : relation[$clause] (K_AND relation[$clause])* ; orderByClause[raw::select_statement::parameters::orderings_type& orderings] @init{ bool reversed = false; } : c=cident (K_ASC | K_DESC { reversed = true; })? { orderings.emplace_back(c, reversed); } ; /** * INSERT INTO (, , , ...) * VALUES (, , , ...) * USING TIMESTAMP ; * */ insertStatement returns [::shared_ptr expr] @init { auto attrs = ::make_shared(); std::vector<::shared_ptr> column_names; std::vector<::shared_ptr> values; bool if_not_exists = false; } : K_INSERT K_INTO cf=columnFamilyName '(' c1=cident { column_names.push_back(c1); } ( ',' cn=cident { column_names.push_back(cn); } )* ')' K_VALUES '(' v1=term { values.push_back(v1); } ( ',' vn=term { values.push_back(vn); } )* ')' ( K_IF K_NOT K_EXISTS { if_not_exists = true; } )? ( usingClause[attrs] )? { $expr = ::make_shared(std::move(cf), std::move(attrs), std::move(column_names), std::move(values), if_not_exists); } ; usingClause[::shared_ptr attrs] : K_USING usingClauseObjective[attrs] ( K_AND usingClauseObjective[attrs] )* ; usingClauseObjective[::shared_ptr attrs] : K_TIMESTAMP ts=intValue { attrs->timestamp = ts; } | K_TTL t=intValue { attrs->time_to_live = t; } ; /** * UPDATE * USING TIMESTAMP * SET name1 = value1, name2 = value2 * WHERE key = value; */ updateStatement returns [::shared_ptr expr] @init { auto attrs = ::make_shared(); std::vector, ::shared_ptr>> operations; } : K_UPDATE cf=columnFamilyName ( usingClause[attrs] )? K_SET columnOperation[operations] (',' columnOperation[operations])* K_WHERE wclause=whereClause ( K_IF conditions=updateConditions )? { return ::make_shared(std::move(cf), std::move(attrs), std::move(operations), std::move(wclause), std::move(conditions)); } ; updateConditions returns [conditions_type conditions] : columnCondition[conditions] ( K_AND columnCondition[conditions] )* ; /** * DELETE name1, name2 * FROM * USING TIMESTAMP * WHERE KEY = keyname [IF (EXISTS | name = value, ...)]; */ deleteStatement returns [::shared_ptr expr] @init { auto attrs = ::make_shared(); std::vector<::shared_ptr> column_deletions; bool if_exists = false; } : K_DELETE ( dels=deleteSelection { column_deletions = std::move(dels); } )? K_FROM cf=columnFamilyName ( usingClauseDelete[attrs] )? K_WHERE wclause=whereClause ( K_IF ( K_EXISTS { if_exists = true; } | conditions=updateConditions ))? { return ::make_shared(cf, std::move(attrs), std::move(column_deletions), std::move(wclause), std::move(conditions), if_exists); } ; deleteSelection returns [std::vector<::shared_ptr> operations] : t1=deleteOp { $operations.emplace_back(std::move(t1)); } (',' tN=deleteOp { $operations.emplace_back(std::move(tN)); })* ; deleteOp returns [::shared_ptr op] : c=cident { $op = ::make_shared(std::move(c)); } | c=cident '[' t=term ']' { $op = ::make_shared(std::move(c), std::move(t)); } ; usingClauseDelete[::shared_ptr attrs] : K_USING K_TIMESTAMP ts=intValue { attrs->timestamp = ts; } ; /** * BEGIN BATCH * UPDATE SET name1 = value1 WHERE KEY = keyname1; * UPDATE SET name2 = value2 WHERE KEY = keyname2; * UPDATE SET name3 = value3 WHERE KEY = keyname3; * ... * APPLY BATCH * * OR * * BEGIN BATCH * INSERT INTO (KEY, ) VALUES ('', ''); * INSERT INTO (KEY, ) VALUES ('', ''); * ... * APPLY BATCH * * OR * * BEGIN BATCH * DELETE name1, name2 FROM WHERE key = * DELETE name3, name4 FROM WHERE key = * ... * APPLY BATCH */ batchStatement returns [shared_ptr expr] @init { using btype = cql3::statements::raw::batch_statement::type; btype type = btype::LOGGED; std::vector> statements; auto attrs = make_shared(); } : K_BEGIN ( K_UNLOGGED { type = btype::UNLOGGED; } | K_COUNTER { type = btype::COUNTER; } )? K_BATCH ( usingClause[attrs] )? ( s=batchStatementObjective ';'? { statements.push_back(std::move(s)); } )* K_APPLY K_BATCH { $expr = ::make_shared(type, std::move(attrs), std::move(statements)); } ; batchStatementObjective returns [shared_ptr statement] : i=insertStatement { $statement = i; } | u=updateStatement { $statement = u; } | d=deleteStatement { $statement = d; } ; #if 0 createAggregateStatement returns [CreateAggregateStatement expr] @init { boolean orReplace = false; boolean ifNotExists = false; List 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 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; boolean deterministic = true; List argsNames = new ArrayList<>(); List argsTypes = new ArrayList<>(); } : K_CREATE (K_OR K_REPLACE { orReplace = true; })? ((K_NON { deterministic = false; })? K_DETERMINISTIC)? K_FUNCTION (K_IF K_NOT K_EXISTS { ifNotExists = true; })? fn=functionName '(' ( k=ident v=comparatorType { argsNames.add(k); argsTypes.add(v); } ( ',' k=ident v=comparatorType { argsNames.add(k); argsTypes.add(v); } )* )? ')' K_RETURNS rt = comparatorType K_LANGUAGE language = IDENT K_AS body = STRING_LITERAL { $expr = new CreateFunctionStatement(fn, $language.text.toLowerCase(), $body.text, deterministic, argsNames, argsTypes, rt, orReplace, ifNotExists); } ; dropFunctionStatement returns [DropFunctionStatement expr] @init { boolean ifExists = false; List 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); } ; #endif /** * CREATE KEYSPACE [IF NOT EXISTS] WITH attr1 = value1 AND attr2 = value2; */ createKeyspaceStatement returns [shared_ptr expr] @init { auto attrs = make_shared(); bool if_not_exists = false; } : K_CREATE K_KEYSPACE (K_IF K_NOT K_EXISTS { if_not_exists = true; } )? ks=keyspaceName K_WITH properties[attrs] { $expr = make_shared(ks, attrs, if_not_exists); } ; /** * CREATE COLUMNFAMILY [IF NOT EXISTS] ( * , * , * * ) WITH = AND ...; */ createTableStatement returns [shared_ptr expr] @init { bool if_not_exists = false; } : K_CREATE K_COLUMNFAMILY (K_IF K_NOT K_EXISTS { if_not_exists = true; } )? cf=columnFamilyName { $expr = make_shared(cf, if_not_exists); } cfamDefinition[expr] ; cfamDefinition[shared_ptr expr] : '(' cfamColumns[expr] ( ',' cfamColumns[expr]? )* ')' ( K_WITH cfamProperty[expr] ( K_AND cfamProperty[expr] )*)? ; cfamColumns[shared_ptr expr] @init { bool is_static=false; } : k=ident v=comparatorType (K_STATIC {is_static = true;})? { $expr->add_definition(k, v, is_static); } (K_PRIMARY K_KEY { $expr->add_key_aliases(std::vector>{k}); })? | K_PRIMARY K_KEY '(' pkDef[expr] (',' c=ident { $expr->add_column_alias(c); } )* ')' ; pkDef[shared_ptr expr] @init { std::vector> l; } : k=ident { $expr->add_key_aliases(std::vector>{k}); } | '(' k1=ident { l.push_back(k1); } ( ',' kn=ident { l.push_back(kn); } )* ')' { $expr->add_key_aliases(l); } ; cfamProperty[shared_ptr expr] : property[expr->properties] | K_COMPACT K_STORAGE { $expr->set_compact_storage(); } | K_CLUSTERING K_ORDER K_BY '(' cfamOrdering[expr] (',' cfamOrdering[expr])* ')' ; cfamOrdering[shared_ptr expr] @init{ bool reversed=false; } : k=ident (K_ASC | K_DESC { reversed=true;} ) { $expr->set_ordering(k, reversed); } ; /** * CREATE TYPE foo ( * , * , * .... * ) */ createTypeStatement returns [::shared_ptr expr] @init { bool if_not_exists = false; } : K_CREATE K_TYPE (K_IF K_NOT K_EXISTS { if_not_exists = true; } )? tn=userTypeName { $expr = ::make_shared(tn, if_not_exists); } '(' typeColumns[expr] ( ',' typeColumns[expr]? )* ')' ; typeColumns[::shared_ptr expr] : k=ident v=comparatorType { $expr->add_definition(k, v); } ; /** * CREATE INDEX [IF NOT EXISTS] [indexName] ON (); * CREATE CUSTOM INDEX [IF NOT EXISTS] [indexName] ON () USING ; */ createIndexStatement returns [::shared_ptr expr] @init { auto props = make_shared(); bool if_not_exists = false; auto name = ::make_shared(); } : K_CREATE (K_CUSTOM { props->is_custom = true; })? K_INDEX (K_IF K_NOT K_EXISTS { if_not_exists = true; } )? (idxName[name])? K_ON cf=columnFamilyName '(' id=indexIdent ')' (K_USING cls=STRING_LITERAL { props->custom_class = sstring{$cls.text}; })? (K_WITH properties[props])? { $expr = ::make_shared(cf, name, id, props, if_not_exists); } ; indexIdent returns [::shared_ptr id] : c=cident { $id = index_target::raw::values_of(c); } | K_KEYS '(' c=cident ')' { $id = index_target::raw::keys_of(c); } | K_ENTRIES '(' c=cident ')' { $id = index_target::raw::keys_and_values_of(c); } | K_FULL '(' c=cident ')' { $id = index_target::raw::full_collection(c); } ; #if 0 /** * 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.toString(), $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.toString(), ifExists); } ; #endif /** * ALTER KEYSPACE WITH = ; */ alterKeyspaceStatement returns [shared_ptr expr] @init { auto attrs = make_shared(); } : K_ALTER K_KEYSPACE ks=keyspaceName K_WITH properties[attrs] { $expr = make_shared(ks, attrs); } ; /** * ALTER COLUMN FAMILY ALTER TYPE ; * ALTER COLUMN FAMILY ADD ; * ALTER COLUMN FAMILY DROP ; * ALTER COLUMN FAMILY WITH = ; * ALTER COLUMN FAMILY RENAME TO ; */ alterTableStatement returns [shared_ptr expr] @init { alter_table_statement::type type; auto props = make_shared();; std::vector, shared_ptr>> renames; bool is_static = false; } : K_ALTER K_COLUMNFAMILY cf=columnFamilyName ( K_ALTER id=cident K_TYPE v=comparatorType { type = alter_table_statement::type::alter; } | K_ADD id=cident v=comparatorType ({ is_static=true; } K_STATIC)? { type = alter_table_statement::type::add; } | K_DROP id=cident { type = alter_table_statement::type::drop; } | K_WITH properties[props] { type = alter_table_statement::type::opts; } | K_RENAME { type = alter_table_statement::type::rename; } id1=cident K_TO toId1=cident { renames.emplace_back(id1, toId1); } ( K_AND idn=cident K_TO toIdn=cident { renames.emplace_back(idn, toIdn); } )* ) { $expr = ::make_shared(std::move(cf), type, std::move(id), std::move(v), std::move(props), std::move(renames), is_static); } ; /** * ALTER TYPE ALTER TYPE ; * ALTER TYPE ADD ; * ALTER TYPE RENAME TO AND ...; */ alterTypeStatement returns [::shared_ptr expr] : K_ALTER K_TYPE name=userTypeName ( K_ALTER f=ident K_TYPE v=comparatorType { $expr = ::make_shared(name, false, f, v); } | K_ADD f=ident v=comparatorType { $expr = ::make_shared(name, true, f, v); } | K_RENAME { $expr = ::make_shared(name); } renames[{ static_pointer_cast($expr) }] ) ; renames[::shared_ptr expr] : fromId=ident K_TO toId=ident { $expr->add_rename(fromId, toId); } ( K_AND renames[$expr] )? ; /** * DROP KEYSPACE [IF EXISTS] ; */ dropKeyspaceStatement returns [::shared_ptr ksp] @init { bool if_exists = false; } : K_DROP K_KEYSPACE (K_IF K_EXISTS { if_exists = true; } )? ks=keyspaceName { $ksp = ::make_shared(ks, if_exists); } ; /** * DROP COLUMNFAMILY [IF EXISTS] ; */ dropTableStatement returns [::shared_ptr stmt] @init { bool if_exists = false; } : K_DROP K_COLUMNFAMILY (K_IF K_EXISTS { if_exists = true; } )? cf=columnFamilyName { $stmt = ::make_shared(cf, if_exists); } ; /** * DROP TYPE ; */ dropTypeStatement returns [::shared_ptr stmt] @init { bool if_exists = false; } : K_DROP K_TYPE (K_IF K_EXISTS { if_exists = true; } )? name=userTypeName { $stmt = ::make_shared(name, if_exists); } ; #if 0 /** * DROP INDEX [IF EXISTS] */ 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); } ; #endif /** * TRUNCATE ; */ truncateStatement returns [::shared_ptr stmt] : K_TRUNCATE (K_COLUMNFAMILY)? cf=columnFamilyName { $stmt = ::make_shared(cf); } ; /** * GRANT ON TO */ grantStatement returns [::shared_ptr stmt] : K_GRANT permissionOrAll K_ON resource K_TO username { $stmt = ::make_shared($permissionOrAll.perms, $resource.res, $username.text); } ; /** * REVOKE ON FROM */ revokeStatement returns [::shared_ptr stmt] : K_REVOKE permissionOrAll K_ON resource K_FROM username { $stmt = ::make_shared($permissionOrAll.perms, $resource.res, $username.text); } ; listPermissionsStatement returns [::shared_ptr stmt] @init { std::experimental::optional r; std::experimental::optional u; bool recursive = true; } : K_LIST permissionOrAll ( K_ON resource { r = $resource.res; } )? ( K_OF username { u = sstring($username.text); } )? ( K_NORECURSIVE { recursive = false; } )? { $stmt = ::make_shared($permissionOrAll.perms, std::move(r), std::move(u), recursive); } ; permission returns [auth::permission perm] : p=(K_CREATE | K_ALTER | K_DROP | K_SELECT | K_MODIFY | K_AUTHORIZE) { $perm = auth::permissions::from_string($p.text); } ; permissionOrAll returns [auth::permission_set perms] : K_ALL ( K_PERMISSIONS )? { $perms = auth::permissions::ALL_DATA; } | p=permission ( K_PERMISSION )? { $perms = auth::permission_set::from_mask(auth::permission_set::mask_for($p.perm)); } ; resource returns [auth::data_resource res] : r=dataResource { $res = $r.res; } ; dataResource returns [auth::data_resource res] : K_ALL K_KEYSPACES { $res = auth::data_resource(); } | K_KEYSPACE ks = keyspaceName { $res = auth::data_resource($ks.id); } | ( K_COLUMNFAMILY )? cf = columnFamilyName { $res = auth::data_resource($cf.name->get_keyspace(), $cf.name->get_column_family()); } ; /** * CREATE USER [IF NOT EXISTS] [WITH PASSWORD ] [SUPERUSER|NOSUPERUSER] */ createUserStatement returns [::shared_ptr stmt] @init { auto opts = ::make_shared(); bool superuser = false; bool ifNotExists = false; } : K_CREATE K_USER (K_IF K_NOT K_EXISTS { ifNotExists = true; })? username ( K_WITH userOptions[opts] )? ( K_SUPERUSER { superuser = true; } | K_NOSUPERUSER { superuser = false; } )? { $stmt = ::make_shared($username.text, std::move(opts), superuser, ifNotExists); } ; /** * ALTER USER [WITH PASSWORD ] [SUPERUSER|NOSUPERUSER] */ alterUserStatement returns [::shared_ptr stmt] @init { auto opts = ::make_shared(); std::experimental::optional superuser; } : K_ALTER K_USER username ( K_WITH userOptions[opts] )? ( K_SUPERUSER { superuser = true; } | K_NOSUPERUSER { superuser = false; } )? { $stmt = ::make_shared($username.text, std::move(opts), std::move(superuser)); } ; /** * DROP USER [IF EXISTS] */ dropUserStatement returns [::shared_ptr stmt] @init { bool ifExists = false; } : K_DROP K_USER (K_IF K_EXISTS { ifExists = true; })? username { $stmt = ::make_shared($username.text, ifExists); } ; /** * LIST USERS */ listUsersStatement returns [::shared_ptr stmt] : K_LIST K_USERS { $stmt = ::make_shared(); } ; userOptions[::shared_ptr opts] : userOption[opts] ; userOption[::shared_ptr opts] : k=K_PASSWORD v=STRING_LITERAL { opts->put($k.text, $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 [shared_ptr id] : t=IDENT { $id = make_shared(sstring{$t.text}, false); } | t=QUOTED_NAME { $id = make_shared(sstring{$t.text}, true); } | k=unreserved_keyword { $id = make_shared(k, false); } ; // Identifiers that do not refer to columns or where the comparator is known to be text ident returns [shared_ptr id] : t=IDENT { $id = make_shared(sstring{$t.text}, false); } | t=QUOTED_NAME { $id = make_shared(sstring{$t.text}, true); } | k=unreserved_keyword { $id = make_shared(k, false); } ; // Keyspace & Column family names keyspaceName returns [sstring id] @init { auto name = make_shared(); } : ksName[name] { $id = name->get_keyspace(); } ; indexName returns [::shared_ptr name] @init { $name = ::make_shared(); } : (ksName[name] '.')? idxName[name] ; columnFamilyName returns [::shared_ptr name] @init { $name = ::make_shared(); } : (ksName[name] '.')? cfName[name] ; userTypeName returns [uninitialized name] : (ks=ident '.')? ut=non_type_ident { $name = cql3::ut_name(ks, ut); } ; #if 0 userOrRoleName returns [RoleName name] @init { $name = new RoleName(); } : roleName[name] {return $name;} ; #endif ksName[::shared_ptr name] : t=IDENT { $name->set_keyspace($t.text, false);} | t=QUOTED_NAME { $name->set_keyspace($t.text, true);} | k=unreserved_keyword { $name->set_keyspace(k, false);} | QMARK {add_recognition_error("Bind variables cannot be used for keyspace names");} ; cfName[::shared_ptr name] : t=IDENT { $name->set_column_family($t.text, false); } | t=QUOTED_NAME { $name->set_column_family($t.text, true); } | k=unreserved_keyword { $name->set_column_family(k, false); } | QMARK {add_recognition_error("Bind variables cannot be used for table names");} ; idxName[::shared_ptr name] : t=IDENT { $name->set_index($t.text, false); } | t=QUOTED_NAME { $name->set_index($t.text, true);} | k=unreserved_keyword { $name->set_index(k, false); } | QMARK {add_recognition_error("Bind variables cannot be used for index names");} ; #if 0 roleName[RoleName name] : t=IDENT { $name.setName($t.text, false); } | 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");} ; #endif constant returns [shared_ptr constant] @init{std::string sign;} : t=STRING_LITERAL { $constant = cql3::constants::literal::string(sstring{$t.text}); } | t=INTEGER { $constant = cql3::constants::literal::integer(sstring{$t.text}); } | t=FLOAT { $constant = cql3::constants::literal::floating_point(sstring{$t.text}); } | t=BOOLEAN { $constant = cql3::constants::literal::bool_(sstring{$t.text}); } | t=UUID { $constant = cql3::constants::literal::uuid(sstring{$t.text}); } | t=HEXNUMBER { $constant = cql3::constants::literal::hex(sstring{$t.text}); } | { sign=""; } ('-' {sign = "-"; } )? t=(K_NAN | K_INFINITY) { $constant = cql3::constants::literal::floating_point(sstring{sign + $t.text}); } ; mapLiteral returns [shared_ptr map] @init{std::vector, ::shared_ptr>> m;} : '{' { } ( k1=term ':' v1=term { m.push_back(std::pair, shared_ptr>{k1, v1}); } ( ',' kn=term ':' vn=term { m.push_back(std::pair, shared_ptr>{kn, vn}); } )* )? '}' { $map = ::make_shared(m); } ; setOrMapLiteral[shared_ptr t] returns [shared_ptr value] @init{ std::vector, shared_ptr>> m; std::vector> s; } : ':' v=term { m.push_back({t, v}); } ( ',' kn=term ':' vn=term { m.push_back({kn, vn}); } )* { $value = ::make_shared(std::move(m)); } | { s.push_back(t); } ( ',' tn=term { s.push_back(tn); } )* { $value = make_shared(cql3::sets::literal(std::move(s))); } ; collectionLiteral returns [shared_ptr value] @init{ std::vector> l; } : '[' ( t1=term { l.push_back(t1); } ( ',' tn=term { l.push_back(tn); } )* )? ']' { $value = ::make_shared(std::move(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 = make_shared(cql3::sets::literal({})); } ; usertypeLiteral returns [shared_ptr ut] @init{ cql3::user_types::literal::elements_map_type m; } @after{ $ut = ::make_shared(std::move(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=ident ':' v1=term { m.emplace(std::move(*k1), std::move(v1)); } ( ',' kn=ident ':' vn=term { m.emplace(std::move(*kn), std::move(vn)); } )* '}' ; tupleLiteral returns [shared_ptr tt] @init{ std::vector> l; } @after{ $tt = ::make_shared(std::move(l)); } : '(' t1=term { l.push_back(t1); } ( ',' tn=term { l.push_back(tn); } )* ')' ; value returns [::shared_ptr value] : c=constant { $value = c; } | l=collectionLiteral { $value = l; } | u=usertypeLiteral { $value = u; } | t=tupleLiteral { $value = t; } | K_NULL { $value = cql3::constants::NULL_LITERAL; } | ':' id=ident { $value = new_bind_variables(id); } | QMARK { $value = new_bind_variables(shared_ptr{}); } ; intValue returns [::shared_ptr value] : | t=INTEGER { $value = cql3::constants::literal::integer(sstring{$t.text}); } | ':' id=ident { $value = new_bind_variables(id); } | QMARK { $value = new_bind_variables(shared_ptr{}); } ; functionName returns [cql3::functions::function_name s] : (ks=keyspaceName '.')? f=allowedFunctionName { $s.keyspace = std::move(ks); $s.name = std::move(f); } ; allowedFunctionName returns [sstring s] : f=IDENT { $s = $f.text; std::transform(s.begin(), s.end(), s.begin(), ::tolower); } | f=QUOTED_NAME { $s = $f.text; } | u=unreserved_function_keyword { $s = u; } | K_TOKEN { $s = "token"; } | K_COUNT { $s = "count"; } ; functionArgs returns [std::vector> a] : '(' ')' | '(' t1=term { a.push_back(std::move(t1)); } ( ',' tn=term { a.push_back(std::move(tn)); } )* ')' ; term returns [::shared_ptr term1] : v=value { $term1 = v; } | f=functionName args=functionArgs { $term1 = ::make_shared(std::move(f), std::move(args)); } | '(' c=comparatorType ')' t=term { $term1 = make_shared(c, t); } ; columnOperation[operations_type& operations] : key=cident columnOperationDifferentiator[operations, key] ; columnOperationDifferentiator[operations_type& operations, ::shared_ptr key] : '=' normalColumnOperation[operations, key] | '[' k=term ']' specializedColumnOperation[operations, key, k, false] | '[' K_SCYLLA_TIMEUUID_LIST_INDEX '(' k=term ')' ']' specializedColumnOperation[operations, key, k, true] ; normalColumnOperation[operations_type& operations, ::shared_ptr key] : t=term ('+' c=cident )? { if (!c) { add_raw_update(operations, key, ::make_shared(t)); } else { if (*key != *c) { add_recognition_error("Only expressions of the form X = + X are supported."); } add_raw_update(operations, key, ::make_shared(t)); } } | c=cident sig=('+' | '-') t=term { if (*key != *c) { add_recognition_error("Only expressions of the form X = X " + $sig.text + " are supported."); } shared_ptr op; if ($sig.text == "+") { op = make_shared(t); } else { op = make_shared(t); } add_raw_update(operations, key, std::move(op)); } | 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 != *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 add_recognition_error("Only expressions of the form X = X " + sstring($i.text[0] == '-' ? "-" : "+") + " are supported."); } add_raw_update(operations, key, make_shared(cql3::constants::literal::integer($i.text))); } ; specializedColumnOperation[std::vector, shared_ptr>>& operations, shared_ptr key, shared_ptr k, bool by_uuid] : '=' t=term { add_raw_update(operations, key, make_shared(k, t, by_uuid)); } ; columnCondition[conditions_type& conditions] // Note: we'll reject duplicates later : key=cident ( op=relationType t=term { conditions.emplace_back(key, cql3::column_condition::raw::simple_condition(t, *op)); } | K_IN ( values=singleColumnInValues { conditions.emplace_back(key, cql3::column_condition::raw::simple_in_condition(values)); } | marker=inMarker { conditions.emplace_back(key, cql3::column_condition::raw::simple_in_condition(marker)); } ) | '[' element=term ']' ( op=relationType t=term { conditions.emplace_back(key, cql3::column_condition::raw::collection_condition(t, element, *op)); } | K_IN ( values=singleColumnInValues { conditions.emplace_back(key, cql3::column_condition::raw::collection_in_condition(element, values)); } | marker=inMarker { conditions.emplace_back(key, cql3::column_condition::raw::collection_in_condition(element, marker)); } ) ) ) ; properties[::shared_ptr props] : property[props] (K_AND property[props])* ; property[::shared_ptr props] : k=ident '=' simple=propertyValue { try { $props->add_property(k->to_string(), simple); } catch (exceptions::syntax_exception e) { add_recognition_error(e.what()); } } | k=ident '=' map=mapLiteral { try { $props->add_property(k->to_string(), convert_property_map(map)); } catch (exceptions::syntax_exception e) { add_recognition_error(e.what()); } } ; propertyValue returns [sstring str] : c=constant { $str = c->get_raw_text(); } | u=unreserved_keyword { $str = u; } ; relationType returns [const cql3::operator_type* op = nullptr] : '=' { $op = &cql3::operator_type::EQ; } | '<' { $op = &cql3::operator_type::LT; } | '<=' { $op = &cql3::operator_type::LTE; } | '>' { $op = &cql3::operator_type::GT; } | '>=' { $op = &cql3::operator_type::GTE; } | '!=' { $op = &cql3::operator_type::NEQ; } ; relation[std::vector& clauses] @init{ const cql3::operator_type* rt = nullptr; } : name=cident type=relationType t=term { $clauses.emplace_back(::make_shared(std::move(name), *type, std::move(t))); } | K_TOKEN l=tupleOfIdentifiers type=relationType t=term { $clauses.emplace_back(::make_shared(std::move(l), *type, std::move(t))); } | name=cident K_IN marker=inMarker { $clauses.emplace_back(make_shared(std::move(name), cql3::operator_type::IN, std::move(marker))); } | name=cident K_IN in_values=singleColumnInValues { $clauses.emplace_back(cql3::single_column_relation::create_in_relation(std::move(name), std::move(in_values))); } | name=cident K_CONTAINS { rt = &cql3::operator_type::CONTAINS; } (K_KEY { rt = &cql3::operator_type::CONTAINS_KEY; })? t=term { $clauses.emplace_back(make_shared(std::move(name), *rt, std::move(t))); } | name=cident '[' key=term ']' type=relationType t=term { $clauses.emplace_back(make_shared(std::move(name), std::move(key), *type, std::move(t))); } | ids=tupleOfIdentifiers ( K_IN ( '(' ')' { $clauses.emplace_back(cql3::multi_column_relation::create_in_relation(ids, std::vector>())); } | tupleInMarker=inMarkerForTuple /* (a, b, c) IN ? */ { $clauses.emplace_back(cql3::multi_column_relation::create_single_marker_in_relation(ids, tupleInMarker)); } | literals=tupleOfTupleLiterals /* (a, b, c) IN ((1, 2, 3), (4, 5, 6), ...) */ { $clauses.emplace_back(cql3::multi_column_relation::create_in_relation(ids, literals)); } | markers=tupleOfMarkersForTuples /* (a, b, c) IN (?, ?, ...) */ { $clauses.emplace_back(cql3::multi_column_relation::create_in_relation(ids, markers)); } ) | type=relationType literal=tupleLiteral /* (a, b, c) > (1, 2, 3) or (a, b, c) > (?, ?, ?) */ { $clauses.emplace_back(cql3::multi_column_relation::create_non_in_relation(ids, *type, literal)); } | type=relationType tupleMarker=markerForTuple /* (a, b, c) >= ? */ { $clauses.emplace_back(cql3::multi_column_relation::create_non_in_relation(ids, *type, tupleMarker)); } ) | '(' relation[$clauses] ')' ; inMarker returns [shared_ptr marker] : QMARK { $marker = new_in_bind_variables(nullptr); } | ':' name=ident { $marker = new_in_bind_variables(name); } ; tupleOfIdentifiers returns [std::vector<::shared_ptr> ids] : '(' n1=cident { $ids.push_back(n1); } (',' ni=cident { $ids.push_back(ni); })* ')' ; singleColumnInValues returns [std::vector<::shared_ptr> terms] : '(' ( t1 = term { $terms.push_back(t1); } (',' ti=term { $terms.push_back(ti); })* )? ')' ; tupleOfTupleLiterals returns [std::vector<::shared_ptr> literals] : '(' t1=tupleLiteral { $literals.emplace_back(t1); } (',' ti=tupleLiteral { $literals.emplace_back(ti); })* ')' ; markerForTuple returns [shared_ptr marker] : QMARK { $marker = new_tuple_bind_variables(nullptr); } | ':' name=ident { $marker = new_tuple_bind_variables(name); } ; tupleOfMarkersForTuples returns [std::vector<::shared_ptr> markers] : '(' m1=markerForTuple { $markers.emplace_back(m1); } (',' mi=markerForTuple { $markers.emplace_back(mi); })* ')' ; inMarkerForTuple returns [shared_ptr marker] : QMARK { $marker = new_tuple_in_bind_variables(nullptr); } | ':' name=ident { $marker = new_tuple_in_bind_variables(name); } ; comparatorType returns [shared_ptr t] : n=native_type { $t = cql3_type::raw::from(n); } | c=collection_type { $t = c; } | tt=tuple_type { $t = tt; } | id=userTypeName { $t = cql3::cql3_type::raw::user_type(id); } | K_FROZEN '<' f=comparatorType '>' { try { $t = cql3::cql3_type::raw::frozen(f); } catch (exceptions::invalid_request_exception& e) { add_recognition_error(e.what()); } } #if 0 | 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()); } } #endif ; native_type returns [shared_ptr t] : K_ASCII { $t = cql3_type::ascii; } | K_BIGINT { $t = cql3_type::bigint; } | K_BLOB { $t = cql3_type::blob; } | K_BOOLEAN { $t = cql3_type::boolean; } | K_COUNTER { $t = cql3_type::counter; } | K_DECIMAL { $t = cql3_type::decimal; } | K_DOUBLE { $t = cql3_type::double_; } | K_FLOAT { $t = cql3_type::float_; } | K_INET { $t = cql3_type::inet; } | K_INT { $t = cql3_type::int_; } | K_TEXT { $t = cql3_type::text; } | K_TIMESTAMP { $t = cql3_type::timestamp; } | K_UUID { $t = cql3_type::uuid; } | K_VARCHAR { $t = cql3_type::varchar; } | K_VARINT { $t = cql3_type::varint; } | K_TIMEUUID { $t = cql3_type::timeuuid; } ; collection_type returns [shared_ptr 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 && t2) { $pt = cql3::cql3_type::raw::map(t1, t2); } } | K_LIST '<' t=comparatorType '>' { if (t) { $pt = cql3::cql3_type::raw::list(t); } } | K_SET '<' t=comparatorType '>' { if (t) { $pt = cql3::cql3_type::raw::set(t); } } ; tuple_type returns [shared_ptr t] @init{ std::vector> types; } : K_TUPLE '<' t1=comparatorType { types.push_back(t1); } (',' tn=comparatorType { types.push_back(tn); })* '>' { $t = cql3::cql3_type::raw::tuple(std::move(types)); } ; username : IDENT | 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 [shared_ptr id] : t=IDENT { if (_reserved_type_names().count($t.text)) { add_recognition_error("Invalid (reserved) user type name " + $t.text); } $id = ::make_shared($t.text, false); } | t=QUOTED_NAME { $id = ::make_shared($t.text, true); } | k=basic_unreserved_keyword { $id = ::make_shared(k, false); } | kk=K_KEY { $id = ::make_shared($kk.text, false); } ; unreserved_keyword returns [sstring str] : u=unreserved_function_keyword { $str = u; } | k=(K_TTL | K_COUNT | K_WRITETIME | K_KEY) { $str = $k.text; } ; unreserved_function_keyword returns [sstring str] : u=basic_unreserved_keyword { $str = u; } | t=native_type { $str = t->to_string(); } ; basic_unreserved_keyword returns [sstring 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_SUPERUSER | K_NOSUPERUSER | K_PASSWORD | K_EXISTS | K_CUSTOM | K_TRIGGER | K_DISTINCT | K_CONTAINS | K_STATIC | K_FUNCTION | K_AGGREGATE | K_SFUNC | K_STYPE | K_FINALFUNC | K_INITCOND | K_RETURNS | K_LANGUAGE | K_NON | K_DETERMINISTIC ) { $str = $k.text; } ; // Case-insensitive keywords 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_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_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_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_CONTAINS: C O N T A I N S; 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_NORECURSIVE: N O R E C U R S I V E; K_USER: U S E R; K_USERS: U S E R 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_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_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_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_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_LANGUAGE: L A N G U A G E; K_NON: N O N; K_OR: O R; K_REPLACE: R E P L A C E; K_DETERMINISTIC: D E T E R M I N I S T I C; K_SCYLLA_TIMEUUID_LIST_INDEX: S C Y L L A '_' T I M E U U I D '_' L I S T '_' I N D E X; // 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{ std::string txt; // temporary to build pg-style-string } @after{ // This is an ugly hack that allows returning empty string literals. // If setText() was called with an empty string antlr3 would decide // that setText() was never called and just return the unmodified // token value. To prevent that we call setText() with non-empty string // that is not valid utf8 which will be later changed to an empty // string once it leaves antlr3 code. if (txt.empty()) { txt.push_back(-1); } setText(txt); } : /* pg-style string literal */ ( '$' '$' ( (c=~('$') { txt.push_back(c); }) | ('$' (c=~('$') { txt.push_back('$'); txt.push_back(c); })) )* '$' '$' ) | /* conventional quoted string literal */ ( '\'' (c=~('\'') { txt.push_back(c);} | '\'' '\'' { txt.push_back('\''); })* '\'' ) ; QUOTED_NAME @init{ std::string b; } @after{ setText(b); } : '\"' (c=~('\"') { b.push_back(c); } | '\"' '\"' { b.push_back('\"'); })+ '\"' ; 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; } ;