/* * SPDX-License-Identifier: Apache-2.0 */ 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/alter_view_statement.hh" #include "cql3/statements/alter_service_level_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_view_statement.hh" #include "cql3/statements/create_type_statement.hh" #include "cql3/statements/create_function_statement.hh" #include "cql3/statements/create_aggregate_statement.hh" #include "cql3/statements/create_service_level_statement.hh" #include "cql3/statements/sl_prop_defs.hh" #include "cql3/statements/attach_service_level_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_index_statement.hh" #include "cql3/statements/drop_table_statement.hh" #include "cql3/statements/drop_view_statement.hh" #include "cql3/statements/drop_function_statement.hh" #include "cql3/statements/drop_aggregate_statement.hh" #include "cql3/statements/drop_service_level_statement.hh" #include "cql3/statements/detach_service_level_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/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/alter_role_statement.hh" #include "cql3/statements/list_roles_statement.hh" #include "cql3/statements/list_service_level_statement.hh" #include "cql3/statements/list_service_level_attachments_statement.hh" #include "cql3/statements/grant_role_statement.hh" #include "cql3/statements/revoke_role_statement.hh" #include "cql3/statements/drop_role_statement.hh" #include "cql3/statements/create_role_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/role_name.hh" #include "cql3/role_options.hh" #include "cql3/user_types.hh" #include "cql3/ut_name.hh" #include "cql3/functions/function_name.hh" #include "cql3/expr/expression.hh" #include #include "CqlLexer.hpp" #include #include #include } @parser::traits { using namespace cql3; using namespace cql3::statements; using namespace cql3::selection; using namespace cql3::expr; using cql3::cql3_type; using conditions_type = std::vector,lw_shared_ptr>>; using operations_type = std::vector, std::unique_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::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); } operator std::optional&&() && { 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; } bind_variable new_bind_variables(shared_ptr name) { auto marker = bind_variable{bind_variable::shape_type::scalar, _bind_variables.size()}; _bind_variables.push_back(name); return marker; } bind_variable new_in_bind_variables(shared_ptr name) { auto marker = bind_variable{bind_variable::shape_type::scalar_in, _bind_variables.size()}; _bind_variables.push_back(std::move(name)); return marker; } bind_variable new_tuple_bind_variables(shared_ptr name) { auto marker = bind_variable{bind_variable::shape_type::tuple, _bind_variables.size()}; _bind_variables.push_back(std::move(name)); return marker; } bind_variable new_tuple_in_bind_variables(shared_ptr name) { auto marker = bind_variable{bind_variable::shape_type::tuple_in, _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(const collection_constructor& map) { if (map.elements.empty()) { return std::map{}; } std::map res; for (auto&& entry : map.elements) { auto entry_tuple = expr::as_if(&entry); // Because the parser tries to be smart and recover on error (to // allow displaying more than one error I suppose), we have default-constructed // entries in map.elements. Just skip those, a proper error will be thrown in the end. if (!entry_tuple || entry_tuple->elements.size() != 2) { break; } auto left = expr::as_if(&entry_tuple->elements[0]); if (!left) { sstring msg = fmt::format("Invalid property name: {}", entry_tuple->elements[0]); if (expr::is(entry_tuple->elements[0])) { msg += " (bind variables are not supported in DDL queries)"; } add_recognition_error(msg); break; } auto right = expr::as_if(&entry_tuple->elements[1]); if (!right) { sstring msg = fmt::format("Invalid property value: {} for property: {}", entry_tuple->elements[0], entry_tuple->elements[1]); if (expr::is(entry_tuple->elements[1])) { msg += " (bind variables are not supported in DDL queries)"; } add_recognition_error(msg); break; } if (!res.emplace(left->raw_text, right->raw_text).second) { sstring msg = fmt::format("Multiple definition for property {}", left->raw_text); add_recognition_error(msg); break; } } return res; } sstring to_lower(std::string_view s) { sstring lower_s(s.size(), '\0'); std::transform(s.cbegin(), s.cend(), lower_s.begin(), &::tolower); return lower_s; } bool convert_boolean_literal(std::string_view s) { return to_lower(s) == "true"; } void add_raw_update(std::vector, std::unique_ptr>>& operations, ::shared_ptr key, std::unique_ptr update) { for (auto&& p : operations) { if (*p.first == *key && !p.second->is_compatible_with(update)) { add_recognition_error(format("Multiple incompatible setting of column {}", *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 **/ queries returns [std::vector> stmts] : st=cqlStatement { $stmts.emplace_back(std::move(st)); } (';' st=cqlStatement { $stmts.emplace_back(std::move(st)); })* (';')* EOF ; query returns [std::unique_ptr stmnt] : st=cqlStatement (';')* EOF { $stmnt = std::move(st); } ; cqlStatement returns [std::unique_ptr stmt] @after{ if (stmt) { stmt->set_bound_variables(_bind_variables); } } : st1= selectStatement { $stmt = std::move(st1); } | st2= insertStatement { $stmt = std::move(st2); } | st3= updateStatement { $stmt = std::move(st3); } | st4= batchStatement { $stmt = std::move(st4); } | st5= deleteStatement { $stmt = std::move(st5); } | st6= useStatement { $stmt = std::move(st6); } | st7= truncateStatement { $stmt = std::move(st7); } | st8= createKeyspaceStatement { $stmt = std::move(st8); } | st9= createTableStatement { $stmt = std::move(st9); } | st10=createIndexStatement { $stmt = std::move(st10); } | st11=dropKeyspaceStatement { $stmt = std::move(st11); } | st12=dropTableStatement { $stmt = std::move(st12); } | st13=dropIndexStatement { $stmt = std::move(st13); } | st14=alterTableStatement { $stmt = std::move(st14); } | st15=alterKeyspaceStatement { $stmt = std::move(st15); } | st16=grantStatement { $stmt = std::move(st16); } | st17=revokeStatement { $stmt = std::move(st17); } | st18=listPermissionsStatement { $stmt = std::move(st18); } | st19=createUserStatement { $stmt = std::move(st19); } | st20=alterUserStatement { $stmt = std::move(st20); } | st21=dropUserStatement { $stmt = std::move(st21); } | st22=listUsersStatement { $stmt = std::move(st22); } #if 0 | st23=createTriggerStatement { $stmt = st23; } | st24=dropTriggerStatement { $stmt = st24; } #endif | st25=createTypeStatement { $stmt = std::move(st25); } | st26=alterTypeStatement { $stmt = std::move(st26); } | st27=dropTypeStatement { $stmt = std::move(st27); } | st28=createFunctionStatement { $stmt = std::move(st28); } | st29=dropFunctionStatement { $stmt = std::move(st29); } | st30=createAggregateStatement { $stmt = std::move(st30); } | st31=dropAggregateStatement { $stmt = std::move(st31); } | st32=createViewStatement { $stmt = std::move(st32); } | st33=alterViewStatement { $stmt = std::move(st33); } | st34=dropViewStatement { $stmt = std::move(st34); } | st35=listRolesStatement { $stmt = std::move(st35); } | st36=grantRoleStatement { $stmt = std::move(st36); } | st37=revokeRoleStatement { $stmt = std::move(st37); } | st38=dropRoleStatement { $stmt = std::move(st38); } | st39=createRoleStatement { $stmt = std::move(st39); } | st40=alterRoleStatement { $stmt = std::move(st40); } | st41=createServiceLevelStatement { $stmt = std::move(st41); } | st42=alterServiceLevelStatement { $stmt = std::move(st42); } | st43=dropServiceLevelStatement { $stmt = std::move(st43); } | st44=attachServiceLevelStatement { $stmt = std::move(st44); } | st45=detachServiceLevelStatement { $stmt = std::move(st45); } | st46=listServiceLevelStatement { $stmt = std::move(st46); } | st47=listServiceLevelAttachStatement { $stmt = std::move(st47); } ; /* * USE ; */ useStatement returns [std::unique_ptr stmt] : K_USE ks=keyspaceName { $stmt = std::make_unique(ks); } ; /** * SELECT [JSON] * FROM * WHERE KEY = "key1" AND COL > 1 AND COL < 100 * LIMIT ; */ selectStatement returns [std::unique_ptr expr] @init { bool is_distinct = false; std::optional limit; std::optional per_partition_limit; raw::select_statement::parameters::orderings_type orderings; bool allow_filtering = false; bool is_json = false; bool bypass_cache = false; auto attrs = std::make_unique(); } : K_SELECT ( ( K_JSON { is_json = true; } )? ( K_DISTINCT { is_distinct = true; } )? sclause=selectClause ) K_FROM cf=columnFamilyName ( K_WHERE wclause=whereClause )? ( K_GROUP K_BY gbcolumns=listOfIdentifiers)? ( K_ORDER K_BY orderByClause[orderings] ( ',' orderByClause[orderings] )* )? ( K_PER K_PARTITION K_LIMIT rows=intValue { per_partition_limit = rows; } )? ( K_LIMIT rows=intValue { limit = rows; } )? ( K_ALLOW K_FILTERING { allow_filtering = true; } )? ( K_BYPASS K_CACHE { bypass_cache = true; })? ( usingClause[attrs] )? { auto params = make_lw_shared(std::move(orderings), is_distinct, allow_filtering, is_json, bypass_cache); $expr = std::make_unique(std::move(cf), std::move(params), std::move(sclause), std::move(wclause), std::move(limit), std::move(per_partition_limit), std::move(gbcolumns), std::move(attrs)); } ; 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 [expression s] @init { expression tmp; } : ( c=cident { tmp = unresolved_identifier{std::move(c)}; } | K_COUNT '(' countArgument ')' { tmp = make_count_rows_function_expression(); } | K_WRITETIME '(' c=cident ')' { tmp = column_mutation_attribute{column_mutation_attribute::attribute_kind::writetime, unresolved_identifier{std::move(c)}}; } | K_TTL '(' c=cident ')' { tmp = column_mutation_attribute{column_mutation_attribute::attribute_kind::ttl, unresolved_identifier{std::move(c)}}; } | f=functionName args=selectionFunctionArgs { tmp = function_call{std::move(f), std::move(args)}; } | K_CAST '(' arg=unaliasedSelector K_AS t=native_type ')' { tmp = cast{std::move(arg), std::move(t)}; } ) ( '.' fi=cident { tmp = field_selection{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)); } )* ')' ; 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{ raw::select_statement::ordering ordering = raw::select_statement::ordering::ascending; } : c=cident (K_ASC | K_DESC { ordering = raw::select_statement::ordering::descending; })? { orderings.emplace_back(c, ordering); } ; jsonValue returns [expression value] : | s=STRING_LITERAL { $value = untyped_constant{untyped_constant::string, $s.text}; } | ':' id=ident { $value = new_bind_variables(id); } | QMARK { $value = new_bind_variables(shared_ptr{}); } ; /** * INSERT INTO (, , , ...) * VALUES (, , , ...) * USING TIMESTAMP ; * */ insertStatement returns [std::unique_ptr expr] @init { auto attrs = std::make_unique(); std::vector<::shared_ptr> column_names; std::vector values; bool if_not_exists = false; bool default_unset = false; std::optional json_value; } : 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 = std::make_unique(std::move(cf), std::move(attrs), std::move(column_names), std::move(values), if_not_exists); } | K_JSON json_token=jsonValue { json_value = $json_token.value; } ( K_DEFAULT K_UNSET { default_unset = true; } | K_DEFAULT K_NULL )? ( K_IF K_NOT K_EXISTS { if_not_exists = true; } )? ( usingClause[attrs] )? { $expr = std::make_unique(std::move(cf), std::move(attrs), std::move(*json_value), if_not_exists, default_unset); } ) ; usingClause[std::unique_ptr& attrs] : K_USING usingClauseObjective[attrs] ( K_AND usingClauseObjective[attrs] )* ; usingClauseObjective[std::unique_ptr& attrs] : K_TIMESTAMP ts=intValue { attrs->timestamp = ts; } | K_TTL t=intValue { attrs->time_to_live = t; } | K_TIMEOUT to=term { attrs->timeout = to; } ; /** * UPDATE * USING TIMESTAMP * SET name1 = value1, name2 = value2 * WHERE key = value; */ updateStatement returns [std::unique_ptr expr] @init { bool if_exists = false; auto attrs = std::make_unique(); std::vector, std::unique_ptr>> operations; } : K_UPDATE cf=columnFamilyName ( usingClause[attrs] )? K_SET columnOperation[operations] (',' columnOperation[operations])* K_WHERE wclause=whereClause ( K_IF (K_EXISTS{ if_exists = true; } | conditions=updateConditions) )? { return std::make_unique(std::move(cf), std::move(attrs), std::move(operations), std::move(wclause), std::move(conditions), if_exists); } ; 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 [std::unique_ptr expr] @init { auto attrs = std::make_unique(); std::vector> column_deletions; bool if_exists = false; } : K_DELETE ( dels=deleteSelection { column_deletions = std::move(dels); } )? K_FROM cf=columnFamilyName ( usingClause[attrs] )? K_WHERE wclause=whereClause ( K_IF ( K_EXISTS { if_exists = true; } | conditions=updateConditions ))? { return std::make_unique(cf, std::move(attrs), std::move(column_deletions), std::move(wclause), std::move(conditions), if_exists); } ; deleteSelection returns [std::vector> operations] : t1=deleteOp { $operations.emplace_back(std::move(t1)); } (',' tN=deleteOp { $operations.emplace_back(std::move(tN)); })* ; deleteOp returns [std::unique_ptr op] : c=cident { $op = std::make_unique(std::move(c)); } | c=cident '[' t=term ']' { $op = std::make_unique(std::move(c), std::move(t)); } | c=cident '.' field=ident { $op = std::make_unique(std::move(c), std::move(field)); } ; /** * 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 [std::unique_ptr expr] @init { using btype = cql3::statements::raw::batch_statement::type; btype type = btype::LOGGED; std::vector> statements; auto attrs = std::make_unique(); } : 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 = std::make_unique(type, std::move(attrs), std::move(statements)); } ; batchStatementObjective returns [std::unique_ptr statement] : i=insertStatement { $statement = std::move(i); } | u=updateStatement { $statement = std::move(u); } | d=deleteStatement { $statement = std::move(d); } ; dropAggregateStatement returns [std::unique_ptr expr] @init { bool if_exists = false; std::vector> arg_types; bool args_present = false; } : K_DROP K_AGGREGATE (K_IF K_EXISTS { if_exists = true; } )? fn=functionName ( '(' ( v=comparatorType { arg_types.push_back(v); } ( ',' v=comparatorType { arg_types.push_back(v); } )* )? ')' { args_present = true; } )? { $expr = std::make_unique(std::move(fn), std::move(arg_types), args_present, if_exists); } ; createAggregateStatement returns [std::unique_ptr expr] @init { bool or_replace = false; bool if_not_exists = false; std::vector> arg_types; std::optional ffunc; std::optional ival; } : K_CREATE (K_OR K_REPLACE { or_replace = true; })? K_AGGREGATE (K_IF K_NOT K_EXISTS { if_not_exists = true; })? fn=functionName '(' ( v=comparatorType { arg_types.push_back(v); } ( ',' v=comparatorType { arg_types.push_back(v); } )* )? ')' K_SFUNC sfunc = allowedFunctionName K_STYPE stype = comparatorType ( K_FINALFUNC final_func = allowedFunctionName { ffunc = final_func; } )? ( K_INITCOND init_val = term { ival = init_val; } )? { $expr = std::make_unique(std::move(fn), std::move(arg_types), std::move(sfunc), std::move(stype), std::move(ffunc), std::move(ival), or_replace, if_not_exists); } ; createFunctionStatement returns [std::unique_ptr expr] @init { bool or_replace = false; bool if_not_exists = false; std::vector> arg_names; std::vector> arg_types; bool called_on_null_input = false; } : K_CREATE // "OR REPLACE" and "IF NOT EXISTS" cannot be used together ((K_OR K_REPLACE { or_replace = true; } K_FUNCTION) | (K_FUNCTION K_IF K_NOT K_EXISTS { if_not_exists = true; }) | K_FUNCTION) fn=functionName '(' ( k=ident v=comparatorType { arg_names.push_back(k); arg_types.push_back(v); } ( ',' k=ident v=comparatorType { arg_names.push_back(k); arg_types.push_back(v); } )* )? ')' ( (K_RETURNS K_NULL) | (K_CALLED { called_on_null_input = true; })) K_ON K_NULL K_INPUT K_RETURNS rt = comparatorType K_LANGUAGE language = IDENT K_AS body = STRING_LITERAL { $expr = std::make_unique(std::move(fn), to_lower($language.text), $body.text, std::move(arg_names), std::move(arg_types), std::move(rt), called_on_null_input, or_replace, if_not_exists); } ; dropFunctionStatement returns [std::unique_ptr expr] @init { bool if_exists = false; std::vector> arg_types; bool args_present = false; } : K_DROP K_FUNCTION (K_IF K_EXISTS { if_exists = true; } )? fn=functionName ( '(' ( v=comparatorType { arg_types.push_back(v); } ( ',' v=comparatorType { arg_types.push_back(v); } )* )? ')' { args_present = true; } )? { $expr = std::make_unique(std::move(fn), std::move(arg_types), args_present, if_exists); } ; /** * CREATE KEYSPACE [IF NOT EXISTS] WITH attr1 = value1 AND attr2 = value2; */ createKeyspaceStatement returns [std::unique_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 = std::make_unique(ks, attrs, if_not_exists); } ; /** * CREATE COLUMNFAMILY [IF NOT EXISTS] ( * , * , * * ) WITH = AND ...; */ createTableStatement returns [std::unique_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 = std::make_unique(cf, if_not_exists); } cfamDefinition[*expr] ; cfamDefinition[cql3::statements::create_table_statement::raw_statement& expr] : '(' cfamColumns[expr] ( ',' cfamColumns[expr]? )* ')' ( K_WITH cfamProperty[$expr.properties()] ( K_AND cfamProperty[$expr.properties()] )*)? ; cfamColumns[cql3::statements::create_table_statement::raw_statement& 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[cql3::statements::create_table_statement::raw_statement& 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[cql3::statements::cf_properties& expr] : property[*$expr.properties()] | K_COMPACT K_STORAGE { $expr.set_compact_storage(); } | K_CLUSTERING K_ORDER K_BY '(' cfamOrdering[expr] (',' cfamOrdering[expr])* ')' ; cfamOrdering[cql3::statements::cf_properties& expr] @init{ bool reversed=false; } : k=ident (K_ASC | K_DESC { reversed=true;} ) { $expr.set_ordering(k, reversed); } ; /** * CREATE TYPE foo ( * , * , * .... * ) */ createTypeStatement returns [std::unique_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 = std::make_unique(tn, if_not_exists); } '(' typeColumns[*expr] ( ',' typeColumns[*expr]? )* ')' ; typeColumns[create_type_statement& 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 [std::unique_ptr expr] @init { auto props = make_shared(); bool if_not_exists = false; auto name = ::make_shared(); std::vector<::shared_ptr> targets; } : 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 '(' (target1=indexIdent { targets.emplace_back(target1); } (',' target2=indexIdent { targets.emplace_back(target2); } )*)? ')' (K_USING cls=STRING_LITERAL { props->custom_class = sstring{$cls.text}; })? (K_WITH properties[*props])? { $expr = std::make_unique(cf, name, targets, props, if_not_exists); } ; indexIdent returns [::shared_ptr id] @init { std::vector<::shared_ptr> columns; } : 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); } | '(' c1=cident { columns.push_back(c1); } ( ',' cn=cident { columns.push_back(cn); } )* ')' { $id = index_target::raw::columns(std::move(columns)); } ; /** * CREATE MATERIALIZED VIEW AS * SELECT * FROM * WHERE IS NOT NULL * PRIMARY KEY () * WITH = AND ...; */ createViewStatement returns [std::unique_ptr expr] @init { bool if_not_exists = false; std::vector<::shared_ptr> partition_keys; std::vector<::shared_ptr> composite_keys; } : K_CREATE K_MATERIALIZED K_VIEW (K_IF K_NOT K_EXISTS { if_not_exists = true; })? cf=columnFamilyName K_AS K_SELECT sclause=selectClause K_FROM basecf=columnFamilyName (K_WHERE wclause=whereClause)? K_PRIMARY K_KEY ( '(' '(' k1=cident { partition_keys.push_back(k1); } ( ',' kn=cident { partition_keys.push_back(kn); } )* ')' ( ',' c1=cident { composite_keys.push_back(c1); } )* ')' | '(' k1=cident { partition_keys.push_back(k1); } ( ',' cn=cident { composite_keys.push_back(cn); } )* ')' ) { $expr = std::make_unique( std::move(cf), std::move(basecf), std::move(sclause), std::move(wclause), std::move(partition_keys), std::move(composite_keys), if_not_exists); } ( K_WITH cfamProperty[{ $expr->properties() }] ( K_AND cfamProperty[{ $expr->properties() }] )*)? ; #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 [std::unique_ptr expr] @init { auto attrs = make_shared(); } : K_ALTER K_KEYSPACE ks=keyspaceName K_WITH properties[*attrs] { $expr = std::make_unique(ks, attrs); } ; /** * ALTER COLUMN FAMILY ALTER TYPE ; * ALTER COLUMN FAMILY ADD ; | ALTER COLUMN FAMILY ADD ( , ..... ) * ALTER COLUMN FAMILY DROP ; | ALTER COLUMN FAMILY DROP ( ,.....) * ALTER COLUMN FAMILY WITH = ; * ALTER COLUMN FAMILY RENAME TO ; */ alterTableStatement returns [std::unique_ptr expr] @init { alter_table_statement::type type; auto props = cql3::statements::cf_prop_defs(); std::vector column_changes; std::vector, shared_ptr>> renames; } : K_ALTER K_COLUMNFAMILY cf=columnFamilyName ( K_ALTER id=cident K_TYPE v=comparatorType { type = alter_table_statement::type::alter; column_changes.emplace_back(alter_table_statement::column_change{id, v}); } | K_ADD { type = alter_table_statement::type::add; } ( id=cident v=comparatorType s=cfisStatic { column_changes.emplace_back(alter_table_statement::column_change{id, v, s}); } | '(' id1=cident v1=comparatorType s1=cfisStatic { column_changes.emplace_back(alter_table_statement::column_change{id1, v1, s1}); } (',' idn=cident vn=comparatorType sn=cfisStatic { column_changes.emplace_back(alter_table_statement::column_change{idn, vn, sn}); } )* ')' ) | K_DROP { type = alter_table_statement::type::drop; } ( id=cident { column_changes.emplace_back(alter_table_statement::column_change{id}); } | '(' id1=cident { column_changes.emplace_back(alter_table_statement::column_change{id1}); } (',' idn=cident { column_changes.emplace_back(alter_table_statement::column_change{idn}); } )* ')' ) | 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 = std::make_unique(std::move(cf), type, std::move(column_changes), std::move(props), std::move(renames)); } ; cfisStatic returns [bool isStaticColumn] @init{ bool isStatic = false; } : (K_STATIC { isStatic=true; })? { $isStaticColumn = isStatic; } ; /** * ALTER TYPE ALTER TYPE ; * ALTER TYPE ADD ; * ALTER TYPE RENAME TO AND ...; */ alterTypeStatement returns [std::unique_ptr expr] : K_ALTER K_TYPE name=userTypeName ( K_ALTER f=ident K_TYPE v=comparatorType { $expr = std::make_unique(name, false, f, v); } | K_ADD f=ident v=comparatorType { $expr = std::make_unique(name, true, f, v); } | K_RENAME { $expr = std::make_unique(name); } renames[{ static_cast(*$expr) }] ) ; /** * ALTER MATERIALIZED VIEW WITH = ; */ alterViewStatement returns [std::unique_ptr expr] @init { auto props = cql3::statements::cf_prop_defs(); } : K_ALTER K_MATERIALIZED K_VIEW cf=columnFamilyName K_WITH properties[props] { $expr = std::make_unique(std::move(cf), std::move(props)); } ; renames[alter_type_statement::renames& expr] : fromId=ident K_TO toId=ident { $expr.add_rename(fromId, toId); } ( K_AND renames[$expr] )? ; /** * DROP KEYSPACE [IF EXISTS] ; */ dropKeyspaceStatement returns [std::unique_ptr ksp] @init { bool if_exists = false; } : K_DROP K_KEYSPACE (K_IF K_EXISTS { if_exists = true; } )? ks=keyspaceName { $ksp = std::make_unique(ks, if_exists); } ; /** * DROP COLUMNFAMILY [IF EXISTS] ; */ dropTableStatement returns [std::unique_ptr stmt] @init { bool if_exists = false; } : K_DROP K_COLUMNFAMILY (K_IF K_EXISTS { if_exists = true; } )? cf=columnFamilyName { $stmt = std::make_unique(cf, if_exists); } ; /** * DROP TYPE ; */ dropTypeStatement returns [std::unique_ptr stmt] @init { bool if_exists = false; } : K_DROP K_TYPE (K_IF K_EXISTS { if_exists = true; } )? name=userTypeName { $stmt = std::make_unique(name, if_exists); } ; /** * DROP MATERIALIZED VIEW [IF EXISTS] */ dropViewStatement returns [std::unique_ptr stmt] @init { bool if_exists = false; } : K_DROP K_MATERIALIZED K_VIEW (K_IF K_EXISTS { if_exists = true; } )? cf=columnFamilyName { $stmt = std::make_unique(cf, if_exists); } ; /** * DROP INDEX [IF EXISTS] */ dropIndexStatement returns [std::unique_ptr expr] @init { bool if_exists = false; } : K_DROP K_INDEX (K_IF K_EXISTS { if_exists = true; } )? index=indexName { $expr = std::make_unique(index, if_exists); } ; /** * TRUNCATE ; */ truncateStatement returns [std::unique_ptr stmt] : K_TRUNCATE (K_COLUMNFAMILY)? cf=columnFamilyName { $stmt = std::make_unique(cf); } ; /** * GRANT ON TO */ grantStatement returns [std::unique_ptr stmt] : K_GRANT permissionOrAll K_ON resource K_TO grantee=userOrRoleName { $stmt = std::make_unique($permissionOrAll.perms, $resource.res, std::move(grantee)); } ; /** * REVOKE ON FROM */ revokeStatement returns [std::unique_ptr stmt] : K_REVOKE permissionOrAll K_ON resource K_FROM revokee=userOrRoleName { $stmt = std::make_unique($permissionOrAll.perms, $resource.res, std::move(revokee)); } ; /** * GRANT to */ grantRoleStatement returns [std::unique_ptr stmt] : K_GRANT role=userOrRoleName K_TO grantee=userOrRoleName { $stmt = std::make_unique(std::move(role), std::move(grantee)); } ; /** * REVOKE FROM */ revokeRoleStatement returns [std::unique_ptr stmt] : K_REVOKE role=userOrRoleName K_FROM revokee=userOrRoleName { $stmt = std::make_unique(std::move(role), std::move(revokee)); } ; listPermissionsStatement returns [std::unique_ptr stmt] @init { std::optional r; std::optional role; bool recursive = true; } : K_LIST permissionOrAll ( K_ON resource { r = $resource.res; } )? ( K_OF rn=userOrRoleName { role = sstring(static_cast(rn).to_string()); } )? ( K_NORECURSIVE { recursive = false; } )? { $stmt = std::make_unique($permissionOrAll.perms, std::move(r), std::move(role), recursive); } ; permission returns [auth::permission perm] : p=(K_CREATE | K_ALTER | K_DROP | K_SELECT | K_MODIFY | K_AUTHORIZE | K_DESCRIBE) { $perm = auth::permissions::from_string($p.text); } ; permissionOrAll returns [auth::permission_set perms] : K_ALL ( K_PERMISSIONS )? { $perms = auth::permissions::ALL; } | p=permission ( K_PERMISSION )? { $perms = auth::permission_set::from_mask(auth::permission_set::mask_for($p.perm)); } ; resource returns [uninitialized res] : d=dataResource { $res = std::move(d); } | r=roleResource { $res = std::move(r); } ; dataResource returns [uninitialized res] : K_ALL K_KEYSPACES { $res = auth::resource(auth::resource_kind::data); } | K_KEYSPACE ks = keyspaceName { $res = auth::make_data_resource($ks.id); } | ( K_COLUMNFAMILY )? cf = columnFamilyName { $res = auth::make_data_resource($cf.name.has_keyspace() ? $cf.name.get_keyspace() : "", $cf.name.get_column_family()); } ; roleResource returns [uninitialized res] : K_ALL K_ROLES { $res = auth::resource(auth::resource_kind::role); } | K_ROLE role = userOrRoleName { $res = auth::make_role_resource(static_cast(role).to_string()); } ; /** * CREATE USER [IF NOT EXISTS] [WITH PASSWORD ] [SUPERUSER|NOSUPERUSER] */ createUserStatement returns [std::unique_ptr stmt] @init { cql3::role_options opts; opts.is_superuser = false; opts.can_login = true; bool ifNotExists = false; } : K_CREATE K_USER (K_IF K_NOT K_EXISTS { ifNotExists = true; })? u=username ( K_WITH K_PASSWORD v=STRING_LITERAL { opts.password = $v.text; })? ( K_SUPERUSER { opts.is_superuser = true; } | K_NOSUPERUSER { opts.is_superuser = false; } )? { $stmt = std::make_unique(cql3::role_name(u, cql3::preserve_role_case::yes), std::move(opts), ifNotExists); } ; /** * ALTER USER [WITH PASSWORD ] [SUPERUSER|NOSUPERUSER] */ alterUserStatement returns [std::unique_ptr stmt] @init { cql3::role_options opts; } : K_ALTER K_USER u=username ( K_WITH K_PASSWORD v=STRING_LITERAL { opts.password = $v.text; })? ( K_SUPERUSER { opts.is_superuser = true; } | K_NOSUPERUSER { opts.is_superuser = false; } )? { $stmt = std::make_unique(cql3::role_name(u, cql3::preserve_role_case::yes), std::move(opts)); } ; /** * DROP USER [IF EXISTS] */ dropUserStatement returns [std::unique_ptr stmt] @init { bool ifExists = false; } : K_DROP K_USER (K_IF K_EXISTS { ifExists = true; })? u=username { $stmt = std::make_unique(cql3::role_name(u, cql3::preserve_role_case::yes), ifExists); } ; /** * LIST USERS */ listUsersStatement returns [std::unique_ptr stmt] : K_LIST K_USERS { $stmt = std::make_unique(); } ; /** * CREATE ROLE [IF NOT EXISTS] [WITH [AND ]*] */ createRoleStatement returns [std::unique_ptr stmt] @init { cql3::role_options opts; opts.is_superuser = false; opts.can_login = false; bool if_not_exists = false; } : K_CREATE K_ROLE (K_IF K_NOT K_EXISTS { if_not_exists = true; })? name=userOrRoleName (K_WITH roleOptions[opts])? { $stmt = std::make_unique(name, std::move(opts), if_not_exists); } ; /** * ALTER ROLE [WITH [AND ]*] */ alterRoleStatement returns [std::unique_ptr stmt] @init { cql3::role_options opts; } : K_ALTER K_ROLE name=userOrRoleName (K_WITH roleOptions[opts])? { $stmt = std::make_unique(name, std::move(opts)); } ; /** * DROP ROLE [IF EXISTS] */ dropRoleStatement returns [std::unique_ptr stmt] @init { bool if_exists = false; } : K_DROP K_ROLE (K_IF K_EXISTS { if_exists = true; })? name=userOrRoleName { $stmt = std::make_unique(name, if_exists); } ; /** * LIST ROLES [OF ] [NORECURSIVE] */ listRolesStatement returns [std::unique_ptr stmt] @init { bool recursive = true; std::optional grantee; } : K_LIST K_ROLES (K_OF g=userOrRoleName { grantee = std::move(g); })? (K_NORECURSIVE { recursive = false; })? { $stmt = std::make_unique(grantee, recursive); } ; roleOptions[cql3::role_options& opts] : roleOption[opts] (K_AND roleOption[opts])* ; roleOption[cql3::role_options& opts] : K_PASSWORD '=' v=STRING_LITERAL { opts.password = $v.text; } | K_OPTIONS '=' m=mapLiteral { opts.options = convert_property_map(m); } | K_SUPERUSER '=' b=BOOLEAN { opts.is_superuser = convert_boolean_literal($b.text); } | K_LOGIN '=' b=BOOLEAN { opts.can_login = convert_boolean_literal($b.text); } ; // Introduce a more natural syntax (SERVICE LEVEL), but still allow // the original one (SERVICE_LEVEL) serviceLevel : K_SERVICE_LEVEL | ( K_SERVICE K_LEVEL ) ; serviceLevels : K_SERVICE_LEVELS | ( K_SERVICE K_LEVELS ) ; /** * CREATE SERVICE_LEVEL [IF NOT EXISTS] [WITH = ] */ createServiceLevelStatement returns [std::unique_ptr stmt] @init { auto attrs = make_shared(); bool if_not_exists = false; } : K_CREATE serviceLevel (K_IF K_NOT K_EXISTS { if_not_exists = true; })? name=serviceLevelOrRoleName (K_WITH properties[*attrs])? { $stmt = std::make_unique(name, attrs, if_not_exists); } ; /** * ALTER SERVICE_LEVEL WITH = */ alterServiceLevelStatement returns [std::unique_ptr stmt] @init { auto attrs = make_shared(); } : K_ALTER serviceLevel name=serviceLevelOrRoleName K_WITH properties[*attrs] { $stmt = std::make_unique(name, attrs); } ; /** * DROP SERVICE_LEVEL [IF EXISTS] */ dropServiceLevelStatement returns [std::unique_ptr stmt] @init { bool if_exists = false; } : K_DROP serviceLevel (K_IF K_EXISTS { if_exists = true; })? name=serviceLevelOrRoleName { $stmt = std::make_unique(name, if_exists); } ; /** * ATTACH SERVICE_LEVEL TO */ attachServiceLevelStatement returns [std::unique_ptr stmt] @init { } : K_ATTACH serviceLevel service_level_name=serviceLevelOrRoleName K_TO role_name=serviceLevelOrRoleName { $stmt = std::make_unique(service_level_name, role_name); } ; /** * DETACH SERVICE_LEVEL FROM */ detachServiceLevelStatement returns [std::unique_ptr stmt] @init { } : K_DETACH serviceLevel K_FROM role_name=serviceLevelOrRoleName { $stmt = std::make_unique(role_name); } ; /** * LIST SERVICE_LEVEL * LIST ALL SERVICE_LEVELS */ listServiceLevelStatement returns [std::unique_ptr stmt] @init { } : K_LIST serviceLevel service_level_name=serviceLevelOrRoleName { $stmt = std::make_unique(service_level_name, false); } | K_LIST K_ALL serviceLevels { $stmt = std::make_unique("", true); } ; /** * LIST ATTACHED SERVICE_LEVEL OF * LIST ALL ATTACHED SERVICE_LEVELS */ listServiceLevelAttachStatement returns [std::unique_ptr stmt] @init { bool allow_nonexisting_roles = false; } : K_LIST K_ATTACHED serviceLevel K_OF role_name=serviceLevelOrRoleName { $stmt = std::make_unique(role_name); } | K_LIST K_ALL K_ATTACHED serviceLevels { $stmt = std::make_unique(); } ; /** 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 = cql3::cf_name(); } : ksName[name] { $id = name.get_keyspace(); } ; indexName returns [::shared_ptr name] @init { $name = ::make_shared(); } : (ksName[*name] '.')? idxName[*name] ; columnFamilyName returns [cql3::cf_name name] @init { $name = cql3::cf_name(); } : (ksName[name] '.')? cfName[name] ; userTypeName returns [uninitialized name] : (ks=ident '.')? ut=non_type_ident { $name = cql3::ut_name(ks, ut); } ; userOrRoleName returns [uninitialized name] : t=IDENT { $name = cql3::role_name($t.text, cql3::preserve_role_case::no); } | t=STRING_LITERAL { $name = cql3::role_name($t.text, cql3::preserve_role_case::yes); } | t=QUOTED_NAME { $name = cql3::role_name($t.text, cql3::preserve_role_case::yes); } | k=unreserved_keyword { $name = cql3::role_name(k, cql3::preserve_role_case::no); } | QMARK {add_recognition_error("Bind variables cannot be used for role names");} ; serviceLevelOrRoleName returns [sstring name] : t=IDENT { $name = sstring($t.text); std::transform($name.begin(), $name.end(), $name.begin(), ::tolower); } | t=STRING_LITERAL { $name = sstring($t.text); } | t=QUOTED_NAME { $name = sstring($t.text); } | k=unreserved_keyword { $name = sstring($t.text); std::transform($name.begin(), $name.end(), $name.begin(), ::tolower);} | QMARK {add_recognition_error("Bind variables cannot be used for service levels or role names");} ; ksName[cql3::keyspace_element_name& 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[cql3::cf_name& 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[cql3::index_name& 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");} ; constant returns [untyped_constant constant] @init{std::string sign;} : t=STRING_LITERAL { // This is a workaround for antlr3 not distinguishing between // calling in lexer setText() with an empty string and not calling // setText() at all. auto text = $t.text; if (text.size() == 1 && text[0] == '\xFF') { text = {}; } $constant = untyped_constant{untyped_constant::string, std::move(text)}; } | t=INTEGER { $constant = untyped_constant{untyped_constant::integer, $t.text}; } | t=FLOAT { $constant = untyped_constant{untyped_constant::floating_point, $t.text}; } | t=BOOLEAN { $constant = untyped_constant{untyped_constant::boolean, $t.text}; } | t=DURATION { $constant = untyped_constant{untyped_constant::duration, $t.text}; } | t=UUID { $constant = untyped_constant{untyped_constant::uuid, $t.text}; } | t=HEXNUMBER { $constant = untyped_constant{untyped_constant::hex, $t.text}; } | { sign=""; } ('-' {sign = "-"; } )? t=(K_NAN | K_INFINITY) { $constant = untyped_constant{untyped_constant::floating_point, sign + $t.text}; } ; mapLiteral returns [collection_constructor map] @init{std::vector m;} : '{' { } ( k1=term ':' v1=term { m.push_back(tuple_constructor{{std::move(k1), std::move(v1)}}); } ( ',' kn=term ':' vn=term { m.push_back(tuple_constructor{{std::move(kn), std::move(vn)}}); } )* )? '}' { $map = collection_constructor{collection_constructor::style_type::map, std::move(m)}; } ; setOrMapLiteral[expression t] returns [collection_constructor value] @init{ std::vector e; } : ':' v=term { e.push_back(tuple_constructor{{std::move(t), std::move(v)}}); } ( ',' kn=term ':' vn=term { e.push_back(tuple_constructor{{std::move(kn), std::move(vn)}}); } )* { $value = collection_constructor{collection_constructor::style_type::map, std::move(e)}; } | { e.push_back(std::move(t)); } ( ',' tn=term { e.push_back(std::move(tn)); } )* { $value = collection_constructor{collection_constructor::style_type::set, std::move(e)}; } ; collectionLiteral returns [expression value] @init{ std::vector l; } : '[' ( t1=term { l.push_back(std::move(t1)); } ( ',' tn=term { l.push_back(std::move(tn)); } )* )? ']' { $value = collection_constructor{collection_constructor::style_type::list, std::move(l)}; } | '{' t=term v=setOrMapLiteral[t] { $value = std::move(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 = collection_constructor{collection_constructor::style_type::set, {}}; } ; usertypeLiteral returns [expression ut] @init{ usertype_constructor::elements_map_type m; } @after{ $ut = usertype_constructor{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 [expression tt] @init{ std::vector l; } @after{ $tt = tuple_constructor{std::move(l)}; } : '(' t1=term { l.push_back(std::move(t1)); } ( ',' tn=term { l.push_back(std::move(tn)); } )* ')' ; value returns [expression value] : c=constant { $value = std::move(c); } | l=collectionLiteral { $value = std::move(l); } | u=usertypeLiteral { $value = std::move(u); } | t=tupleLiteral { $value = std::move(t); } | K_NULL { $value = null(); } | ':' id=ident { $value = new_bind_variables(id); } | QMARK { $value = new_bind_variables(shared_ptr{}); } ; intValue returns [expression value] : | t=INTEGER { $value = untyped_constant{untyped_constant::integer, $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 [expression term1] : v=value { $term1 = std::move(v); } | f=functionName args=functionArgs { $term1 = function_call{std::move(f), std::move(args)}; } | '(' c=comparatorType ')' t=term { $term1 = cast{std::move(t), c}; } ; columnOperation[operations_type& operations] : key=cident columnOperationDifferentiator[operations, key] ; columnOperationDifferentiator[operations_type& operations, ::shared_ptr key] : '=' normalColumnOperation[operations, key] | '[' k=term ']' collectionColumnOperation[operations, key, k, false] | '.' field=ident udtColumnOperation[operations, key, field] | '[' K_SCYLLA_TIMEUUID_LIST_INDEX '(' k=term ')' ']' collectionColumnOperation[operations, key, k, true] ; normalColumnOperation[operations_type& operations, ::shared_ptr key] : t=term ('+' c=cident )? { if (!c) { add_raw_update(operations, key, std::make_unique(t)); } else { if (*key != *c) { add_recognition_error("Only expressions of the form X = + X are supported."); } add_raw_update(operations, key, std::make_unique(t)); } } | c=cident sig=('+' | '-') t=term { if (*key != *c) { add_recognition_error("Only expressions of the form X = X " + $sig.text + " are supported."); } std::unique_ptr op; if ($sig.text == "+") { op = std::make_unique(t); } else { op = std::make_unique(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, std::make_unique(untyped_constant{untyped_constant::integer, $i.text})); } | K_SCYLLA_COUNTER_SHARD_LIST '(' t=term ')' { add_raw_update(operations, key, std::make_unique(t)); } ; collectionColumnOperation[operations_type& operations, shared_ptr key, expression k, bool by_uuid] : '=' t=term { add_raw_update(operations, key, std::make_unique(std::move(k), std::move(t), by_uuid)); } ; udtColumnOperation[operations_type& operations, shared_ptr key, shared_ptr field] : '=' t=term { add_raw_update(operations, std::move(key), std::make_unique(std::move(field), std::move(t))); } ; 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::in_condition({}, {}, values)); } | marker=inMarker { conditions.emplace_back(key, cql3::column_condition::raw::in_condition({}, marker, {})); } ) | '[' element=term ']' ( op=relationType t=term { conditions.emplace_back(key, cql3::column_condition::raw::simple_condition(t, element, op)); } | K_IN ( values=singleColumnInValues { conditions.emplace_back(key, cql3::column_condition::raw::in_condition(element, {}, values)); } | marker=inMarker { conditions.emplace_back(key, cql3::column_condition::raw::in_condition(element, marker, {})); } ) ) ) ; properties[cql3::statements::property_definitions& props] : property[props] (K_AND property[props])* ; property[cql3::statements::property_definitions& 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.raw_text; } // FIXME: unreserved keywords below are indistinguishable from their string representation, // which might be problematic in the future. A possible solution is to use a more complicated // type for storing property values instead of just plain strings. For the specific case // of "null" it would be enough to use an optional, but for the general case it should be // a variant-like class which distinguishes plain string values from special keywords | u=unreserved_keyword { $str = u; } | K_NULL { $str = "null"; } ; relationType returns [oper_t op] : '=' { $op = oper_t::EQ; } | '<' { $op = oper_t::LT; } | '<=' { $op = oper_t::LTE; } | '>' { $op = oper_t::GT; } | '>=' { $op = oper_t::GTE; } | '!=' { $op = oper_t::NEQ; } | K_LIKE { $op = oper_t::LIKE; } ; relation[std::vector& clauses] @init{ oper_t rt; } : 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_IS K_NOT K_NULL { $clauses.emplace_back(make_shared(std::move(name), oper_t::IS_NOT, null())); } | name=cident K_IN marker=inMarker { $clauses.emplace_back(::make_shared(std::move(name), oper_t::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 = oper_t::CONTAINS; } (K_KEY { rt = oper_t::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, std::move(literal))); } | type=relationType K_SCYLLA_CLUSTERING_BOUND literal=tupleLiteral /* (a, b, c) > (1, 2, 3) or (a, b, c) > (?, ?, ?) */ { $clauses.emplace_back(cql3::multi_column_relation::create_scylla_clustering_bound_non_in_relation(ids, type, std::move(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 [expression 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); })* ')' ; listOfIdentifiers returns [std::vector<::shared_ptr> ids] : n1=cident { $ids.push_back(n1); } (',' ni=cident { $ids.push_back(ni); })* ; singleColumnInValues returns [std::vector terms] : '(' ( t1 = term { $terms.push_back(std::move(t1)); } (',' ti=term { $terms.push_back(std::move(ti)); })* )? ')' ; tupleOfTupleLiterals returns [std::vector literals] : '(' t1=tupleLiteral { $literals.emplace_back(std::move(t1)); } (',' ti=tupleLiteral { $literals.emplace_back(std::move(ti)); })* ')' ; markerForTuple returns [expression marker] : QMARK { $marker = new_tuple_bind_variables(nullptr); } | ':' name=ident { $marker = new_tuple_bind_variables(name); } ; tupleOfMarkersForTuples returns [std::vector markers] : '(' m1=markerForTuple { $markers.emplace_back(std::move(m1)); } (',' mi=markerForTuple { $markers.emplace_back(std::move(mi)); })* ')' ; inMarkerForTuple returns [expression marker] : QMARK { $marker = new_tuple_in_bind_variables(nullptr); } | ':' name=ident { $marker = new_tuple_in_bind_variables(name); } ; // The comparator_type rule is used for users' queries (internal=false) // and for internal calls from db::cql_type_parser::parse() (internal=true). // The latter is used for reading schemas stored in the system tables, and // may support additional column types that cannot be created through CQL, // but only internally through code. Today the only such type is "empty": // Scylla code internally creates columns with type "empty" or collections // "empty" to represent unselected columns in materialized views. // If a user (internal=false) tries to use "empty" as a type, it is treated - // as do all unknown types - as an attempt to use a user-defined type, and // we report this name is reserved (as for _reserved_type_names()). comparator_type [bool internal] returns [shared_ptr t] : n=native_or_internal_type[internal] { $t = cql3_type::raw::from(n); } | c=collection_type[internal] { $t = c; } | tt=tuple_type[internal] { $t = tt; } | id=userTypeName { $t = cql3::cql3_type::raw::user_type(id); } | K_FROZEN '<' f=comparator_type[internal] '>' { 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_or_internal_type [bool internal] returns [data_type t] : n=native_type { $t = n; } // The "internal" types, only supported when internal==true: | K_EMPTY { if (internal) { $t = empty_type; } else { add_recognition_error("Invalid (reserved) user type name empty"); } } ; comparatorType returns [shared_ptr t] : tt=comparator_type[false] { $t = tt; } ; native_type returns [data_type t] : K_ASCII { $t = ascii_type; } | K_BIGINT { $t = long_type; } | K_BLOB { $t = bytes_type; } | K_BOOLEAN { $t = boolean_type; } | K_COUNTER { $t = counter_type; } | K_DECIMAL { $t = decimal_type; } | K_DOUBLE { $t = double_type; } | K_DURATION { $t = duration_type; } | K_FLOAT { $t = float_type; } | K_INET { $t = inet_addr_type; } | K_INT { $t = int32_type; } | K_SMALLINT { $t = short_type; } | K_TEXT { $t = utf8_type; } | K_TIMESTAMP { $t = timestamp_type; } | K_TINYINT { $t = byte_type; } | K_UUID { $t = uuid_type; } | K_VARCHAR { $t = utf8_type; } | K_VARINT { $t = varint_type; } | K_TIMEUUID { $t = timeuuid_type; } | K_DATE { $t = simple_date_type; } | K_TIME { $t = time_type; } ; collection_type [bool internal] returns [shared_ptr pt] : K_MAP '<' t1=comparator_type[internal] ',' t2=comparator_type[internal] '>' { // 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=comparator_type[internal] '>' { if (t) { $pt = cql3::cql3_type::raw::list(t); } } | K_SET '<' t=comparator_type[internal] '>' { if (t) { $pt = cql3::cql3_type::raw::set(t); } } ; tuple_type [bool internal] returns [shared_ptr t] @init{ std::vector> types; } : K_TUPLE '<' t1=comparator_type[internal] { types.push_back(t1); } (',' tn=comparator_type[internal] { types.push_back(tn); })* '>' { $t = cql3::cql3_type::raw::tuple(std::move(types)); } ; username returns [sstring str] : t=IDENT { $str = $t.text; } | t=STRING_LITERAL { $str = $t.text; } | s=unreserved_keyword { $str = s; } | QUOTED_NAME { add_recognition_error("Quoted strings are not supported for user names"); } ; // 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().contains($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_or_internal_type[true] { $str = t->as_cql3_type().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_ROLE | K_ROLES | K_SUPERUSER | K_NOSUPERUSER | K_LOGIN | K_NOLOGIN | K_OPTIONS | K_PASSWORD | K_EXISTS | K_CUSTOM | K_TRIGGER | K_DISTINCT | K_CONTAINS | K_STATIC | K_FROZEN | K_TUPLE | K_FUNCTION | K_AGGREGATE | K_SFUNC | K_STYPE | K_FINALFUNC | K_INITCOND | K_RETURNS | K_LANGUAGE | K_CALLED | K_INPUT | K_JSON | K_CACHE | K_BYPASS | K_LIKE | K_PER | K_PARTITION | K_SERVICE_LEVEL | K_ATTACH | K_DETACH | K_SERVICE_LEVELS | K_ATTACHED | K_FOR | K_GROUP | K_TIMEOUT | K_SERVICE | K_LEVEL | K_LEVELS ) { $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_CAST: C A S T; 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_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_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_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_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_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_DURATION: D U R A T I O N; 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_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_EMPTY: E M P T Y; K_BYPASS: B Y P A S S; K_CACHE: C A C H E; K_PER: P E R; K_PARTITION: P A R T I T I O N; K_SERVICE_LEVEL: S E R V I C E '_' L E V E L; K_ATTACH: A T T A C H; K_DETACH: D E T A C H; K_SERVICE_LEVELS: S E R V I C E '_' L E V E L S; K_ATTACHED: A T T A C H E D; K_FOR: F O R; K_SERVICE: S E R V I C E; K_LEVEL: L E V E L; K_LEVELS: L E V E L S; 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; K_SCYLLA_COUNTER_SHARD_LIST: S C Y L L A '_' C O U N T E R '_' S H A R D '_' L I S T; K_SCYLLA_CLUSTERING_BOUND: S C Y L L A '_' C L U S T E R I N G '_' B O U N D; K_GROUP: G R O U P; K_LIKE: L I K E; K_TIMEOUT: T I M E O U T; // 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+ ; fragment DURATION_UNIT : Y | M O | W | D | H | M | S | M S | U S | '\u00B5' S | N S ; 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 ; DURATION : '-'? DIGIT+ DURATION_UNIT (DIGIT+ DURATION_UNIT)* | '-'? 'P' (DIGIT+ 'Y')? (DIGIT+ 'M')? (DIGIT+ 'D')? ('T' (DIGIT+ 'H')? (DIGIT+ 'M')? (DIGIT+ 'S')?)? // ISO 8601 "format with designators" | '-'? 'P' DIGIT+ 'W' | '-'? 'P' DIGIT DIGIT DIGIT DIGIT '-' DIGIT DIGIT '-' DIGIT DIGIT 'T' DIGIT DIGIT ':' DIGIT DIGIT ':' DIGIT DIGIT // ISO 8601 "alternative format" ; 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; } ;