This series implements a new per-row TTL feature for CQL. The per-row TTL feature was requested in issue #13000. It is a feature that does not exist in Cassandra, and was inspired by DynamoDB's TTL feature - and under the hood uses the same implementation that we used in Alternator to implement this DynamoDB feature. The new per-row TTL feature is completely separate from CQL's existing per-write (and per-cell) TTL, and both will be available to users. In the per-row TTL feature, one column in the table is designated as the "TTL" column, and its value for a row is the expiration time for that row. The TTL column can be designated at table creation time, e.g.: ```cql CREATE TABLE tab ( id int PRIMARY KEY, t text, expiration timestamp TTL ); ``` Or after the table already exists with: ```cql ALTER TABLE tab TTL expiration ``` Expiration can also be disabled, with: ```cql ALTER TABLE tab TTL NULL ``` The new per-row TTL feature has two features that users have been asking for: 1. A user can change the value of just the TTL column - without rewriting the entire row - to change the expiration time of the entire row. 2. When an expired row is finally deleted, a CDC event about this deletion appears in the CDC log (if CDC is enabled), including - if a preimage is enabled - the content of the deleted row. To achieve the second goal (CDC events), a row is not guaranteed to disappear at exactly its expiration time (as CQL's original TTL feature guarantees). Rather, the row is deleted some time later, depending on `alternator_ttl_period_in_seconds`; Until the actual deletion, the row is still readable (and even writable). But we are guaranteed that when the row is finally deleted, the CDC event will come too. The implementation uses the same background thread used by Alternator to periodically scan for expired items and delete them. The expiration thread keeps the same metrics as it did for Alternator: * `scylla_expiration_scan_passes` * `scylla_expiration_scan_table` * `scylla_expiration_items_deleted` * `scylla_expiration_secondary_ranges_scanned` The series begins with a few small preparation patches, followed by the main part of the feature (which isn't big, since we are just enabling the pre-existing Alternator expiration machinary for CQL) and finally 30 tests (single-node and multi-node tests) and documentation. This series is a new feature, so traditionally would not be backported. However, I wouldn't be surprised if we will be requested to backport it so that customers will not need to wait for a new major release. Fixes #13000 Closes scylladb/scylladb#28320 * github.com:scylladb/scylladb: test/cqlpy: verify that a column can't be both STATIC and PRIMARY KEY docs/cql: document the new CQL per-row TTL feature test/cluster: tests for the new CQL per-row TTL feature test/cqlpy: tests for the new CQL per-row TTL feature test: set low alternator_ttl_period_in_seconds in CQL tests cql ttl: fix ALTER TABLE to disable TTL if column is dropped cql ttl: add setting/unsetting of TTL column to ALTER TABLE cql ttl: add TTL column support to CREATE TABLE and DESC TABLE ttl: add CQL support to Alternator's TTL expiration service alternator ttl: move TTL_TAG_KEY to a header file alternator ttl: remove unnecessary check of feature flag cql: add "cql_row_ttl" cluster feature alternator: fix error message if UpdateTimeToLive is not supported
2574 lines
100 KiB
Plaintext
2574 lines
100 KiB
Plaintext
/*
|
|
* 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/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/raw/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/raw/describe_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/list_effective_service_level_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/selection/selectable-expr.hh"
|
|
#include "cql3/dialect.hh"
|
|
#include "cql3/keyspace_element_name.hh"
|
|
#include "cql3/constants.hh"
|
|
#include "cql3/operation_impl.hh"
|
|
#include "cql3/error_listener.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 <seastar/core/sstring.hh>
|
|
#include "CqlLexer.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <unordered_map>
|
|
#include <map>
|
|
}
|
|
|
|
@parser::traits {
|
|
|
|
using namespace cql3;
|
|
using namespace cql3::statements;
|
|
using namespace cql3::selection;
|
|
using namespace cql3::expr;
|
|
|
|
using cql3::cql3_type;
|
|
using operations_type = std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>, std::unique_ptr<cql3::operation::raw_update>>>;
|
|
|
|
// 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<T> 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 <typename T>
|
|
struct uninitialized {
|
|
std::optional<T> _val;
|
|
uninitialized() = default;
|
|
uninitialized(const uninitialized&) = default;
|
|
uninitialized(uninitialized&&) = default;
|
|
uninitialized(const T& val) : _val(val) {}
|
|
uninitialized(T&& val) : _val(std::move(val)) {}
|
|
uninitialized(std::convertible_to<T> auto&& x) : _val(std::forward<decltype(x)>(x)) {}
|
|
uninitialized& operator=(const uninitialized&) = default;
|
|
uninitialized& operator=(uninitialized&&) = default;
|
|
operator T&&() && { return check(), std::move(*_val); }
|
|
operator std::optional<T>&&() && { return check(), std::move(_val); }
|
|
void check() const { if (!_val) { throw std::runtime_error("not initialized"); } }
|
|
};
|
|
|
|
template <typename T>
|
|
struct unwrap_uninitialized {
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
struct unwrap_uninitialized<uninitialized<T>> {
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
using unwrap_uninitialized_t = typename unwrap_uninitialized<T>::type;
|
|
|
|
using uexpression = uninitialized<expression>;
|
|
|
|
}
|
|
|
|
@context {
|
|
using collector_type = cql3::error_collector<ComponentType, ExceptionBaseType::TokenType, ExceptionBaseType>;
|
|
using listener_type = cql3::error_listener<ComponentType, ExceptionBaseType>;
|
|
|
|
listener_type* listener;
|
|
|
|
dialect _dialect;
|
|
|
|
// Keeps the names of all bind variables. For bind variables without a name ('?'), the name is nullptr.
|
|
// Maps bind_index -> name.
|
|
std::vector<::shared_ptr<cql3::column_identifier>> _bind_variable_names;
|
|
|
|
// Maps name -> bind_index for all named bind variables.
|
|
std::unordered_map<cql3::column_identifier, size_t> _named_bind_variables_indexes;
|
|
std::vector<std::unique_ptr<TokenType>> _missing_tokens;
|
|
|
|
// Can't use static variable, since it needs to be defined out-of-line
|
|
static const std::unordered_set<sstring>& _reserved_type_names() {
|
|
static std::unordered_set<sstring> s = {
|
|
"byte",
|
|
"smallint",
|
|
"complex",
|
|
"enum",
|
|
"date",
|
|
"interval",
|
|
"macaddr",
|
|
"bitstring",
|
|
};
|
|
return s;
|
|
}
|
|
|
|
void set_dialect(dialect d) {
|
|
_dialect = d;
|
|
}
|
|
|
|
bind_variable new_bind_variables(shared_ptr<cql3::column_identifier> name)
|
|
{
|
|
if (_dialect.duplicate_bind_variable_names_refer_to_same_variable
|
|
&& name && _named_bind_variables_indexes.contains(*name)) {
|
|
return bind_variable{_named_bind_variables_indexes[*name]};
|
|
}
|
|
auto marker = bind_variable{_bind_variable_names.size()};
|
|
_bind_variable_names.push_back(name);
|
|
if (name) {
|
|
_named_bind_variables_indexes[*name] = marker.bind_index;
|
|
}
|
|
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();
|
|
}
|
|
|
|
error_sink_fn get_error_sink() {
|
|
return [this] (const std::string& msg) { add_recognition_error(msg); };
|
|
}
|
|
|
|
std::map<sstring, sstring> convert_property_map(const collection_constructor& map) {
|
|
return cql3::expr::convert_property_map(map, get_error_sink());
|
|
}
|
|
|
|
property_definitions::extended_map_type
|
|
convert_extended_property_map(const collection_constructor& map) {
|
|
return cql3::expr::convert_extended_property_map(map, get_error_sink());
|
|
}
|
|
|
|
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";
|
|
}
|
|
|
|
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<CqlLexer, CqlParser> 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<ComponentType, ExceptionBaseType::TokenType, ExceptionBaseType>;
|
|
using listener_type = cql3::error_listener<ComponentType, ExceptionBaseType>;
|
|
|
|
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<std::unique_ptr<raw::parsed_statement>> stmts]
|
|
: st=cqlStatement { $stmts.emplace_back(std::move(st)); }
|
|
(';' st=cqlStatement { $stmts.emplace_back(std::move(st)); })*
|
|
(';')* EOF
|
|
;
|
|
|
|
query returns [std::unique_ptr<raw::parsed_statement> stmnt]
|
|
: st=cqlStatement (';')* EOF { $stmnt = std::move(st); }
|
|
;
|
|
|
|
cqlStatement returns [std::unique_ptr<raw::parsed_statement> stmt]
|
|
@after{ if (stmt) { stmt->set_bound_variables(_bind_variable_names); } }
|
|
: 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); }
|
|
| st48=pruneMaterializedViewStatement { $stmt = std::move(st48); }
|
|
| st49=describeStatement { $stmt = std::move(st49); }
|
|
| st50=listEffectiveServiceLevelStatement { $stmt = std::move(st50); }
|
|
;
|
|
|
|
/*
|
|
* USE <KEYSPACE>;
|
|
*/
|
|
useStatement returns [std::unique_ptr<raw::use_statement> stmt]
|
|
: K_USE ks=keyspaceName { $stmt = std::make_unique<raw::use_statement>(ks); }
|
|
;
|
|
|
|
/**
|
|
* SELECT [JSON] <expression>
|
|
* FROM <CF>
|
|
* WHERE KEY = "key1" AND COL > 1 AND COL < 100
|
|
* LIMIT <NUMBER>
|
|
* [USING TIMEOUT <duration>];
|
|
*/
|
|
selectStatement returns [std::unique_ptr<raw::select_statement> expr]
|
|
@init {
|
|
bool is_distinct = false;
|
|
std::optional<expression> limit;
|
|
std::optional<expression> per_partition_limit;
|
|
raw::select_statement::parameters::orderings_type orderings;
|
|
bool allow_filtering = false;
|
|
raw::select_statement::parameters::statement_subtype statement_subtype = raw::select_statement::parameters::statement_subtype::REGULAR;
|
|
bool bypass_cache = false;
|
|
auto attrs = std::make_unique<cql3::attributes::raw>();
|
|
expression wclause = conjunction{};
|
|
bool is_ann_ordering = false;
|
|
}
|
|
: K_SELECT (
|
|
( (K_JSON K_DISTINCT)=> K_JSON { statement_subtype = raw::select_statement::parameters::statement_subtype::JSON; }
|
|
| (K_JSON selectClause K_FROM)=> K_JSON { statement_subtype = raw::select_statement::parameters::statement_subtype::JSON; }
|
|
)?
|
|
( (K_DISTINCT selectClause K_FROM)=> K_DISTINCT { is_distinct = true; } )?
|
|
sclause=selectClause
|
|
)
|
|
K_FROM (
|
|
cf=columnFamilyName
|
|
| K_MUTATION_FRAGMENTS '(' cf=columnFamilyName ')' { statement_subtype = raw::select_statement::parameters::statement_subtype::MUTATION_FRAGMENTS; }
|
|
)
|
|
( K_WHERE w=whereClause { wclause = std::move(w); } )?
|
|
( K_GROUP K_BY gbcolumns=listOfIdentifiers)?
|
|
( K_ORDER K_BY orderByClause[orderings, is_ann_ordering] ( ',' orderByClause[orderings, is_ann_ordering] )* )?
|
|
( K_PER K_PARTITION K_LIMIT rows=intValue { per_partition_limit = std::move(rows); } )?
|
|
( K_LIMIT rows=intValue { limit = std::move(rows); } )?
|
|
( K_ALLOW K_FILTERING { allow_filtering = true; } )?
|
|
( K_BYPASS K_CACHE { bypass_cache = true; })?
|
|
( usingTimeoutServiceLevelClause[attrs] )?
|
|
{
|
|
auto params = make_lw_shared<raw::select_statement::parameters>(std::move(orderings), is_distinct, allow_filtering, statement_subtype, bypass_cache);
|
|
$expr = std::make_unique<raw::select_statement>(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<shared_ptr<raw_selector>> expr]
|
|
: t1=selector { $expr.push_back(t1); } (',' tN=selector { $expr.push_back(tN); })*
|
|
| '*' { }
|
|
;
|
|
|
|
selector returns [shared_ptr<raw_selector> s]
|
|
@init{ shared_ptr<cql3::column_identifier> alias; }
|
|
: us=unaliasedSelector (K_AS c=ident { alias = c; })? { $s = ::make_shared<raw_selector>(std::move(us), alias); }
|
|
;
|
|
|
|
unaliasedSelector returns [uexpression tmp]
|
|
: ( c=cident { tmp = unresolved_identifier{std::move(c)}; }
|
|
| v=value { tmp = std::move(v); }
|
|
| 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{.style = cast::cast_style::sql, .arg = std::move(arg), .type = std::move(t)}; }
|
|
)
|
|
( '.' fi=cident { tmp = field_selection{std::move(tmp), std::move(fi)}; }
|
|
| '[' sub=term ']' { tmp = subscript{std::move(tmp), std::move(sub)}; }
|
|
)*
|
|
;
|
|
|
|
selectionFunctionArgs returns [std::vector<expression> a]
|
|
: '(' ')'
|
|
| '(' s1=unaliasedSelector { a.push_back(std::move(s1)); }
|
|
( ',' sn=unaliasedSelector { a.push_back(std::move(sn)); } )*
|
|
')'
|
|
;
|
|
|
|
countArgument
|
|
: '*'
|
|
/* COUNT(1) is also allowed, it is recognized via the general function(args) path */
|
|
;
|
|
|
|
whereClause returns [uexpression clause]
|
|
@init { std::vector<expression> terms; }
|
|
: e1=relation { terms.push_back(std::move(e1)); } (K_AND en=relation { terms.push_back(std::move(en)); })*
|
|
{ clause = conjunction{std::move(terms)}; }
|
|
;
|
|
|
|
orderByClause[raw::select_statement::parameters::orderings_type& orderings, bool& is_ann_ordering]
|
|
@init{
|
|
raw::select_statement::ordering ordering = raw::select_statement::ordering::ascending;
|
|
std::optional<expression> ann_ordering;
|
|
}
|
|
: c=cident (K_ANN K_OF t=term {ann_ordering=std::move(t);})? (K_ASC | K_DESC { ordering = raw::select_statement::ordering::descending; })?
|
|
{
|
|
if (!ann_ordering) {
|
|
if (is_ann_ordering) {
|
|
throw exceptions::invalid_request_exception(
|
|
"ANN ordering does not support any other ordering");
|
|
}
|
|
orderings.emplace_back(c, ordering);
|
|
} else {
|
|
if (ordering != raw::select_statement::ordering::ascending) {
|
|
throw exceptions::invalid_request_exception(
|
|
"Descending ANN ordering is not supported");
|
|
}
|
|
if (!orderings.empty()) {
|
|
if (is_ann_ordering) {
|
|
throw exceptions::invalid_request_exception(
|
|
"Cannot specify more than one ANN ordering");
|
|
} else {
|
|
throw exceptions::invalid_request_exception(
|
|
"ANN ordering does not support any other ordering");
|
|
}
|
|
}
|
|
is_ann_ordering = true;
|
|
orderings.emplace_back(c, ann_ordering.value());
|
|
}
|
|
}
|
|
;
|
|
|
|
jsonValue returns [uexpression value]
|
|
: s=STRING_LITERAL { $value = untyped_constant{untyped_constant::string, $s.text}; }
|
|
| m=marker { $value = std::move(m); }
|
|
;
|
|
|
|
/**
|
|
* INSERT INTO <CF> (<column>, <column>, <column>, ...)
|
|
* VALUES (<value>, <value>, <value>, ...)
|
|
* USING TIMESTAMP <long>;
|
|
*
|
|
*/
|
|
insertStatement returns [std::unique_ptr<raw::modification_statement> expr]
|
|
@init {
|
|
auto attrs = std::make_unique<cql3::attributes::raw>();
|
|
std::vector<::shared_ptr<cql3::column_identifier::raw>> column_names;
|
|
std::vector<expression> values;
|
|
bool if_not_exists = false;
|
|
bool default_unset = false;
|
|
std::optional<expression> 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(std::move(v1)); } ( ',' vn=term { values.push_back(std::move(vn)); } )* ')'
|
|
( K_IF K_NOT K_EXISTS { if_not_exists = true; } )?
|
|
( usingClause[attrs] )?
|
|
{
|
|
$expr = std::make_unique<raw::insert_statement>(std::move(cf),
|
|
std::move(attrs),
|
|
std::move(column_names),
|
|
std::move(values),
|
|
if_not_exists);
|
|
}
|
|
| K_JSON
|
|
json_token=jsonValue { json_value = std::move(json_token); }
|
|
( 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<raw::insert_json_statement>(std::move(cf),
|
|
std::move(attrs),
|
|
std::move(*json_value),
|
|
if_not_exists,
|
|
default_unset);
|
|
}
|
|
)
|
|
;
|
|
|
|
usingClause[std::unique_ptr<cql3::attributes::raw>& attrs]
|
|
: K_USING usingClauseObjective[attrs] ( K_AND usingClauseObjective[attrs] )*
|
|
;
|
|
|
|
usingClauseObjective[std::unique_ptr<cql3::attributes::raw>& attrs]
|
|
: K_TIMESTAMP ts=intValue { attrs->timestamp = std::move(ts); }
|
|
| K_TTL t=intValue { attrs->time_to_live = std::move(t); }
|
|
| K_TIMEOUT to=term { attrs->timeout = std::move(to); }
|
|
;
|
|
|
|
usingTimestampTimeoutClause[std::unique_ptr<cql3::attributes::raw>& attrs]
|
|
: K_USING usingTimestampTimeoutClauseObjective[attrs] ( K_AND usingTimestampTimeoutClauseObjective[attrs] )*
|
|
;
|
|
|
|
usingTimestampTimeoutClauseObjective[std::unique_ptr<cql3::attributes::raw>& attrs]
|
|
: K_TIMESTAMP ts=intValue { attrs->timestamp = std::move(ts); }
|
|
| K_TIMEOUT to=term { attrs->timeout = std::move(to); }
|
|
;
|
|
|
|
usingTimeoutClause[std::unique_ptr<cql3::attributes::raw>& attrs]
|
|
: K_USING K_TIMEOUT to=term { attrs->timeout = std::move(to); }
|
|
;
|
|
|
|
usingTimestampClause[std::unique_ptr<cql3::attributes::raw>& attrs]
|
|
: K_USING K_TIMESTAMP ts=intValue { attrs->timestamp = std::move(ts); }
|
|
;
|
|
|
|
usingTimeoutServiceLevelClause[std::unique_ptr<cql3::attributes::raw>& attrs]
|
|
: K_USING usingTimeoutServiceLevelClauseObjective[attrs] ( K_AND usingTimeoutServiceLevelClauseObjective[attrs] )*
|
|
;
|
|
|
|
usingTimeoutServiceLevelClauseObjective[std::unique_ptr<cql3::attributes::raw>& attrs]
|
|
: K_TIMEOUT to=term { attrs->timeout = std::move(to); }
|
|
| serviceLevel sl_name=serviceLevelOrRoleName { attrs->service_level = std::move(sl_name); }
|
|
;
|
|
|
|
usingTimeoutConcurrencyClause[std::unique_ptr<cql3::attributes::raw>& attrs]
|
|
: K_USING usingTimeoutConcurrencyClauseObjective[attrs] ( K_AND usingTimeoutConcurrencyClauseObjective[attrs] )*
|
|
;
|
|
|
|
usingTimeoutConcurrencyClauseObjective[std::unique_ptr<cql3::attributes::raw>& attrs]
|
|
: K_TIMEOUT to=term { attrs->timeout = std::move(to); }
|
|
| K_CONCURRENCY c=term { attrs->concurrency = std::move(c); }
|
|
;
|
|
|
|
/**
|
|
* UPDATE <CF>
|
|
* USING TIMESTAMP <long>
|
|
* SET name1 = value1, name2 = value2
|
|
* WHERE key = value;
|
|
*/
|
|
updateStatement returns [std::unique_ptr<raw::update_statement> expr]
|
|
@init {
|
|
bool if_exists = false;
|
|
auto attrs = std::make_unique<cql3::attributes::raw>();
|
|
std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>, std::unique_ptr<cql3::operation::raw_update>>> operations;
|
|
std::optional<expression> cond_opt;
|
|
}
|
|
: 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 { cond_opt = std::move(conditions); } ))?
|
|
{
|
|
return std::make_unique<raw::update_statement>(std::move(cf),
|
|
std::move(attrs),
|
|
std::move(operations),
|
|
std::move(wclause),
|
|
std::move(cond_opt),
|
|
if_exists);
|
|
}
|
|
;
|
|
|
|
updateConditions returns [uexpression cond]
|
|
@init {
|
|
std::vector<expression> conditions;
|
|
}
|
|
: c1=columnCondition { conditions.emplace_back(std::move(c1)); }
|
|
( K_AND cn=columnCondition { conditions.emplace_back(std::move(cn)); } )*
|
|
{
|
|
return conjunction{std::move(conditions)};
|
|
}
|
|
;
|
|
|
|
/**
|
|
* DELETE name1, name2
|
|
* FROM <CF>
|
|
* [USING (TIMESTAMP <long> | TIMEOUT <duration>) [AND ...]]
|
|
* WHERE KEY = keyname
|
|
[IF (EXISTS | name = value, ...)];
|
|
*/
|
|
deleteStatement returns [std::unique_ptr<raw::delete_statement> expr]
|
|
@init {
|
|
auto attrs = std::make_unique<cql3::attributes::raw>();
|
|
std::vector<std::unique_ptr<cql3::operation::raw_deletion>> column_deletions;
|
|
bool if_exists = false;
|
|
std::optional<expression> cond_opt;
|
|
}
|
|
: K_DELETE ( dels=deleteSelection { column_deletions = std::move(dels); } )?
|
|
K_FROM cf=columnFamilyName
|
|
( usingTimestampTimeoutClause[attrs] )?
|
|
K_WHERE wclause=whereClause
|
|
( K_IF ( K_EXISTS { if_exists = true; } | conditions=updateConditions { cond_opt = std::move(conditions); } ))?
|
|
{
|
|
return std::make_unique<raw::delete_statement>(cf,
|
|
std::move(attrs),
|
|
std::move(column_deletions),
|
|
std::move(wclause),
|
|
std::move(cond_opt),
|
|
if_exists);
|
|
}
|
|
;
|
|
|
|
deleteSelection returns [std::vector<std::unique_ptr<cql3::operation::raw_deletion>> operations]
|
|
: t1=deleteOp { $operations.emplace_back(std::move(t1)); }
|
|
(',' tN=deleteOp { $operations.emplace_back(std::move(tN)); })*
|
|
;
|
|
|
|
deleteOp returns [std::unique_ptr<cql3::operation::raw_deletion> op]
|
|
: c=cident { $op = std::make_unique<cql3::operation::column_deletion>(std::move(c)); }
|
|
| c=cident '[' t=term ']' { $op = std::make_unique<cql3::operation::element_deletion>(std::move(c), std::move(t)); }
|
|
| c=cident '.' field=ident { $op = std::make_unique<cql3::operation::field_deletion>(std::move(c), std::move(field)); }
|
|
;
|
|
|
|
pruneMaterializedViewStatement returns [std::unique_ptr<raw::select_statement> expr]
|
|
@init {
|
|
bool is_distinct = false;
|
|
std::optional<expression> limit;
|
|
std::optional<expression> per_partition_limit;
|
|
raw::select_statement::parameters::orderings_type orderings;
|
|
bool allow_filtering = false;
|
|
raw::select_statement::parameters::statement_subtype statement_subtype = raw::select_statement::parameters::statement_subtype::PRUNE_MATERIALIZED_VIEW;
|
|
bool bypass_cache = false;
|
|
auto attrs = std::make_unique<cql3::attributes::raw>();
|
|
expression wclause = conjunction{};
|
|
}
|
|
: K_PRUNE K_MATERIALIZED K_VIEW cf=columnFamilyName (K_WHERE w=whereClause { wclause = std::move(w); } )? ( usingTimeoutConcurrencyClause[attrs] )?
|
|
{
|
|
auto params = make_lw_shared<raw::select_statement::parameters>(std::move(orderings), is_distinct, allow_filtering, statement_subtype, bypass_cache);
|
|
return std::make_unique<raw::select_statement>(std::move(cf), std::move(params),
|
|
std::vector<shared_ptr<raw_selector>>(), std::move(wclause), std::move(limit), std::move(per_partition_limit),
|
|
std::vector<::shared_ptr<cql3::column_identifier::raw>>(), std::move(attrs));
|
|
}
|
|
;
|
|
|
|
/**
|
|
* BEGIN BATCH
|
|
* UPDATE <CF> SET name1 = value1 WHERE KEY = keyname1;
|
|
* UPDATE <CF> SET name2 = value2 WHERE KEY = keyname2;
|
|
* UPDATE <CF> SET name3 = value3 WHERE KEY = keyname3;
|
|
* ...
|
|
* APPLY BATCH
|
|
*
|
|
* OR
|
|
*
|
|
* BEGIN BATCH
|
|
* INSERT INTO <CF> (KEY, <name>) VALUES ('<key>', '<value>');
|
|
* INSERT INTO <CF> (KEY, <name>) VALUES ('<key>', '<value>');
|
|
* ...
|
|
* APPLY BATCH
|
|
*
|
|
* OR
|
|
*
|
|
* BEGIN BATCH
|
|
* DELETE name1, name2 FROM <CF> WHERE key = <key>
|
|
* DELETE name3, name4 FROM <CF> WHERE key = <key>
|
|
* ...
|
|
* APPLY BATCH
|
|
*/
|
|
batchStatement returns [std::unique_ptr<cql3::statements::raw::batch_statement> expr]
|
|
@init {
|
|
using btype = cql3::statements::raw::batch_statement::type;
|
|
btype type = btype::LOGGED;
|
|
std::vector<std::unique_ptr<cql3::statements::raw::modification_statement>> statements;
|
|
auto attrs = std::make_unique<cql3::attributes::raw>();
|
|
}
|
|
: K_BEGIN
|
|
( K_UNLOGGED { type = btype::UNLOGGED; } | K_COUNTER { type = btype::COUNTER; } )?
|
|
K_BATCH ( usingClause[attrs] )?
|
|
( s=batchStatementObjective ';'?
|
|
{
|
|
auto&& stmt = *$s.statement;
|
|
stmt->add_raw(sstring{$s.text});
|
|
statements.push_back(std::move(stmt));
|
|
} )*
|
|
K_APPLY K_BATCH
|
|
{
|
|
$expr = std::make_unique<cql3::statements::raw::batch_statement>(type, std::move(attrs), std::move(statements));
|
|
}
|
|
;
|
|
|
|
batchStatementObjective returns [::lw_shared_ptr<std::unique_ptr<cql3::statements::raw::modification_statement>> statement]
|
|
@init { using original_ret_type = std::unique_ptr<cql3::statements::raw::modification_statement>; }
|
|
: i=insertStatement { $statement = make_lw_shared<original_ret_type>(std::move(i)); }
|
|
| u=updateStatement { $statement = make_lw_shared<original_ret_type>(std::move(u)); }
|
|
| d=deleteStatement { $statement = make_lw_shared<original_ret_type>(std::move(d)); }
|
|
;
|
|
|
|
dropAggregateStatement returns [std::unique_ptr<cql3::statements::drop_aggregate_statement> expr]
|
|
@init {
|
|
bool if_exists = false;
|
|
std::vector<shared_ptr<cql3_type::raw>> 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<cql3::statements::drop_aggregate_statement>(std::move(fn), std::move(arg_types), args_present, if_exists); }
|
|
;
|
|
|
|
createAggregateStatement returns [std::unique_ptr<cql3::statements::create_aggregate_statement> expr]
|
|
@init {
|
|
bool or_replace = false;
|
|
bool if_not_exists = false;
|
|
|
|
std::vector<shared_ptr<cql3_type::raw>> arg_types;
|
|
std::optional<sstring> ffunc;
|
|
std::optional<expr::expression> ival;
|
|
std::optional<sstring> rfunc;
|
|
}
|
|
: 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_REDUCEFUNC reduce_name = allowedFunctionName { rfunc = reduce_name; }
|
|
)?
|
|
(
|
|
K_FINALFUNC final_func = allowedFunctionName { ffunc = final_func; }
|
|
)?
|
|
(
|
|
K_INITCOND init_val = term { ival = std::move(init_val); }
|
|
)?
|
|
{ $expr = std::make_unique<cql3::statements::create_aggregate_statement>(std::move(fn), std::move(arg_types), std::move(sfunc), std::move(stype), std::move(rfunc), std::move(ffunc), std::move(ival), or_replace, if_not_exists); }
|
|
;
|
|
|
|
createFunctionStatement returns [std::unique_ptr<cql3::statements::create_function_statement> expr]
|
|
@init {
|
|
bool or_replace = false;
|
|
bool if_not_exists = false;
|
|
|
|
std::vector<shared_ptr<cql3::column_identifier>> arg_names;
|
|
std::vector<shared_ptr<cql3_type::raw>> 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<cql3::statements::create_function_statement>(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<cql3::statements::drop_function_statement> expr]
|
|
@init {
|
|
bool if_exists = false;
|
|
std::vector<shared_ptr<cql3_type::raw>> 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<cql3::statements::drop_function_statement>(std::move(fn), std::move(arg_types), args_present, if_exists); }
|
|
;
|
|
|
|
/**
|
|
* CREATE KEYSPACE [IF NOT EXISTS] <KEYSPACE> WITH attr1 = value1 AND attr2 = value2;
|
|
*/
|
|
createKeyspaceStatement returns [std::unique_ptr<cql3::statements::create_keyspace_statement> expr]
|
|
@init {
|
|
auto attrs = make_shared<cql3::statements::ks_prop_defs>();
|
|
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<cql3::statements::create_keyspace_statement>(ks, attrs, if_not_exists); }
|
|
;
|
|
|
|
/**
|
|
* CREATE COLUMNFAMILY [IF NOT EXISTS] <CF> (
|
|
* <name1> <type>,
|
|
* <name2> <type>,
|
|
* <name3> <type>
|
|
* ) WITH <property> = <value> AND ...;
|
|
*/
|
|
createTableStatement returns [std::unique_ptr<cql3::statements::create_table_statement::raw_statement> 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<cql3::statements::create_table_statement::raw_statement>(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, is_ttl=false; }
|
|
: k=ident v=comparatorType (K_TTL {is_ttl = true;})? (K_STATIC {is_static = true;})? { $expr.add_definition(k, v, is_static, is_ttl); }
|
|
(K_PRIMARY K_KEY { $expr.add_key_aliases(std::vector<shared_ptr<cql3::column_identifier>>{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<shared_ptr<cql3::column_identifier>> l; }
|
|
: k=ident { $expr.add_key_aliases(std::vector<shared_ptr<cql3::column_identifier>>{k}); }
|
|
| '(' k1=ident { l.push_back(k1); } ( ',' kn=ident { l.push_back(kn); } )* ')' { $expr.add_key_aliases(l); }
|
|
;
|
|
|
|
cfamProperties[cql3::statements::cf_properties& expr]
|
|
: cfamProperty[expr] (K_AND cfamProperty[expr])*
|
|
;
|
|
|
|
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 (
|
|
* <name1> <type1>,
|
|
* <name2> <type2>,
|
|
* ....
|
|
* )
|
|
*/
|
|
createTypeStatement returns [std::unique_ptr<create_type_statement> 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<create_type_statement>(ut_name(std::move(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 <columnFamily> (<columnName>);
|
|
* CREATE CUSTOM INDEX [IF NOT EXISTS] [indexName] ON <columnFamily> (<columnName>) USING <indexClass>;
|
|
*/
|
|
createIndexStatement returns [std::unique_ptr<create_index_statement> expr]
|
|
@init {
|
|
auto idx_props = make_shared<index_specific_prop_defs>();
|
|
auto props = index_prop_defs();
|
|
bool if_not_exists = false;
|
|
auto name = ::make_shared<cql3::index_name>();
|
|
std::vector<::shared_ptr<index_target::raw>> targets;
|
|
}
|
|
: K_CREATE (K_CUSTOM { idx_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 { idx_props->custom_class = sstring{$cls.text}; })?
|
|
(K_WITH cfamProperties[props])?
|
|
{
|
|
props.extract_index_specific_properties_to(*idx_props);
|
|
view_prop_defs view_props = std::move(props).into_view_prop_defs();
|
|
|
|
$expr = std::make_unique<create_index_statement>(cf, name, targets, std::move(idx_props), std::move(view_props), if_not_exists);
|
|
}
|
|
;
|
|
|
|
indexIdent returns [::shared_ptr<index_target::raw> id]
|
|
@init {
|
|
std::vector<::shared_ptr<cql3::column_identifier::raw>> columns;
|
|
}
|
|
: c=cident { $id = index_target::raw::regular_values_of(c); }
|
|
| K_VALUES '(' c=cident ')' { $id = index_target::raw::collection_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 <viewName> AS
|
|
* SELECT <columns>
|
|
* FROM <CF>
|
|
* WHERE <pkColumns> IS NOT NULL
|
|
* PRIMARY KEY (<pkColumns>)
|
|
* WITH <property> = <value> AND ...;
|
|
*/
|
|
createViewStatement returns [std::unique_ptr<create_view_statement> expr]
|
|
@init {
|
|
bool if_not_exists = false;
|
|
std::vector<::shared_ptr<cql3::column_identifier::raw>> partition_keys;
|
|
std::vector<::shared_ptr<cql3::column_identifier::raw>> composite_keys;
|
|
expression wclause = conjunction{};
|
|
}
|
|
: 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 w=whereClause { wclause = std::move(w); } )?
|
|
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<create_view_statement>(
|
|
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 <KS> WITH <property> = <value>;
|
|
*/
|
|
alterKeyspaceStatement returns [std::unique_ptr<cql3::statements::alter_keyspace_statement> expr]
|
|
@init {
|
|
auto attrs = make_shared<cql3::statements::ks_prop_defs>();
|
|
}
|
|
: K_ALTER K_KEYSPACE ks=keyspaceName
|
|
K_WITH properties[*attrs] { $expr = std::make_unique<cql3::statements::alter_keyspace_statement>(ks, attrs); }
|
|
;
|
|
|
|
/**
|
|
* ALTER COLUMN FAMILY <CF> ALTER <column> TYPE <newtype>;
|
|
* ALTER COLUMN FAMILY <CF> ADD <column> <newtype>; | ALTER COLUMN FAMILY <CF> ADD (<column> <newtype>,<column1> <newtype1>..... <column n> <newtype n>)
|
|
* ALTER COLUMN FAMILY <CF> DROP <column> [USING TIMESTAMP <ts>]; | ALTER COLUMN FAMILY <CF> DROP ( <column>,<column1>.....<column n>) [USING TIMESTAMP <ts>]
|
|
* ALTER COLUMN FAMILY <CF> WITH <property> = <value>;
|
|
* ALTER COLUMN FAMILY <CF> RENAME <column> TO <column>;
|
|
*/
|
|
alterTableStatement returns [std::unique_ptr<alter_table_statement::raw_statement> expr]
|
|
@init {
|
|
alter_table_statement::type type;
|
|
auto props = cql3::statements::cf_prop_defs();
|
|
std::vector<alter_table_statement::column_change> column_changes;
|
|
std::vector<std::pair<shared_ptr<cql3::column_identifier::raw>, shared_ptr<cql3::column_identifier::raw>>> renames;
|
|
auto attrs = std::make_unique<cql3::attributes::raw>();
|
|
shared_ptr<cql3::column_identifier::raw> ttl_change;
|
|
}
|
|
: 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}); } )* ')'
|
|
)
|
|
( usingTimestampClause[attrs] )?
|
|
| 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); } )*
|
|
| K_TTL { type = alter_table_statement::type::ttl; }
|
|
( id=cident { ttl_change = id; } | K_NULL )
|
|
)
|
|
{
|
|
$expr = std::make_unique<alter_table_statement::raw_statement>(std::move(cf), type, std::move(column_changes), std::move(props), std::move(renames), std::move(attrs), std::move(ttl_change));
|
|
}
|
|
;
|
|
|
|
cfisStatic returns [bool isStaticColumn=false]
|
|
: (K_STATIC { $isStaticColumn=true; })?
|
|
;
|
|
|
|
/**
|
|
* ALTER TYPE <name> ALTER <field> TYPE <newtype>;
|
|
* ALTER TYPE <name> ADD <field> <newtype>;
|
|
* ALTER TYPE <name> RENAME <field> TO <newtype> AND ...;
|
|
*/
|
|
alterTypeStatement returns [std::unique_ptr<alter_type_statement> expr]
|
|
: K_ALTER K_TYPE name=userTypeName
|
|
( K_ALTER f=ident K_TYPE v=comparatorType { $expr = std::make_unique<alter_type_statement::add_or_alter>(std::move(name), false, f, v); }
|
|
| K_ADD f=ident v=comparatorType { $expr = std::make_unique<alter_type_statement::add_or_alter>(std::move(name), true, f, v); }
|
|
| K_RENAME
|
|
{ $expr = std::make_unique<alter_type_statement::renames>(std::move(name)); }
|
|
renames[{ static_cast<alter_type_statement::renames&>(*$expr) }]
|
|
)
|
|
;
|
|
|
|
/**
|
|
* ALTER MATERIALIZED VIEW <CF> WITH <property> = <value>;
|
|
*/
|
|
alterViewStatement returns [std::unique_ptr<alter_view_statement> expr]
|
|
@init {
|
|
auto props = cql3::statements::view_prop_defs();
|
|
}
|
|
: K_ALTER K_MATERIALIZED K_VIEW cf=columnFamilyName K_WITH properties[*props.properties()]
|
|
{
|
|
$expr = std::make_unique<alter_view_statement>(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] <KSP>;
|
|
*/
|
|
dropKeyspaceStatement returns [std::unique_ptr<drop_keyspace_statement> ksp]
|
|
@init { bool if_exists = false; }
|
|
: K_DROP K_KEYSPACE (K_IF K_EXISTS { if_exists = true; } )? ks=keyspaceName { $ksp = std::make_unique<drop_keyspace_statement>(ks, if_exists); }
|
|
;
|
|
|
|
/**
|
|
* DROP COLUMNFAMILY [IF EXISTS] <CF>;
|
|
*/
|
|
dropTableStatement returns [std::unique_ptr<drop_table_statement> stmt]
|
|
@init { bool if_exists = false; }
|
|
: K_DROP K_COLUMNFAMILY (K_IF K_EXISTS { if_exists = true; } )? cf=columnFamilyName { $stmt = std::make_unique<drop_table_statement>(cf, if_exists); }
|
|
;
|
|
|
|
/**
|
|
* DROP TYPE <name>;
|
|
*/
|
|
dropTypeStatement returns [std::unique_ptr<drop_type_statement> stmt]
|
|
@init { bool if_exists = false; }
|
|
: K_DROP K_TYPE (K_IF K_EXISTS { if_exists = true; } )? name=userTypeName { $stmt = std::make_unique<drop_type_statement>(std::move(name), if_exists); }
|
|
;
|
|
|
|
/**
|
|
* DROP MATERIALIZED VIEW [IF EXISTS] <view_name>
|
|
*/
|
|
dropViewStatement returns [std::unique_ptr<drop_view_statement> 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<drop_view_statement>(cf, if_exists); }
|
|
;
|
|
|
|
/**
|
|
* DROP INDEX [IF EXISTS] <INDEX_NAME>
|
|
*/
|
|
dropIndexStatement returns [std::unique_ptr<drop_index_statement> expr]
|
|
@init { bool if_exists = false; }
|
|
: K_DROP K_INDEX (K_IF K_EXISTS { if_exists = true; } )? index=indexName
|
|
{ $expr = std::make_unique<drop_index_statement>(index, if_exists); }
|
|
;
|
|
|
|
/**
|
|
* TRUNCATE [TABLE] <CF>
|
|
* [USING TIMEOUT <duration>];
|
|
*/
|
|
truncateStatement returns [std::unique_ptr<raw::truncate_statement> stmt]
|
|
@init {
|
|
auto attrs = std::make_unique<cql3::attributes::raw>();
|
|
}
|
|
: K_TRUNCATE (K_COLUMNFAMILY)? cf=columnFamilyName
|
|
( usingTimeoutClause[attrs] )?
|
|
{
|
|
$stmt = std::make_unique<raw::truncate_statement>(std::move(cf), std::move(attrs));
|
|
}
|
|
;
|
|
|
|
/**
|
|
* GRANT <permission> ON <resource> TO <grantee>
|
|
*/
|
|
grantStatement returns [std::unique_ptr<grant_statement> stmt]
|
|
: K_GRANT
|
|
permissionOrAll
|
|
K_ON
|
|
r=resource
|
|
K_TO
|
|
grantee=userOrRoleName
|
|
{ $stmt = std::make_unique<grant_statement>($permissionOrAll.perms, std::move(r), std::move(grantee)); }
|
|
;
|
|
|
|
/**
|
|
* REVOKE <permission> ON <resource> FROM <revokee>
|
|
*/
|
|
revokeStatement returns [std::unique_ptr<revoke_statement> stmt]
|
|
: K_REVOKE
|
|
permissionOrAll
|
|
K_ON
|
|
r=resource
|
|
K_FROM
|
|
revokee=userOrRoleName
|
|
{ $stmt = std::make_unique<revoke_statement>($permissionOrAll.perms, std::move(r), std::move(revokee)); }
|
|
;
|
|
|
|
/**
|
|
* GRANT <rolename> to <grantee>
|
|
*/
|
|
grantRoleStatement returns [std::unique_ptr<grant_role_statement> stmt]
|
|
: K_GRANT role=userOrRoleName K_TO grantee=userOrRoleName
|
|
{ $stmt = std::make_unique<grant_role_statement>(std::move(role), std::move(grantee)); }
|
|
;
|
|
|
|
/**
|
|
* REVOKE <rolename> FROM <revokee>
|
|
*/
|
|
revokeRoleStatement returns [std::unique_ptr<revoke_role_statement> stmt]
|
|
: K_REVOKE role=userOrRoleName K_FROM revokee=userOrRoleName
|
|
{ $stmt = std::make_unique<revoke_role_statement>(std::move(role), std::move(revokee)); }
|
|
;
|
|
|
|
listPermissionsStatement returns [std::unique_ptr<list_permissions_statement> stmt]
|
|
@init {
|
|
std::optional<auth::resource> r;
|
|
std::optional<sstring> role;
|
|
bool recursive = true;
|
|
}
|
|
: K_LIST
|
|
permissionOrAll
|
|
( K_ON rr=resource { r = std::move(rr); } )?
|
|
( K_OF rn=userOrRoleName { role = sstring(cql3::role_name(std::move(rn)).to_string()); } )?
|
|
( K_NORECURSIVE { recursive = false; } )?
|
|
{ $stmt = std::make_unique<list_permissions_statement>($permissionOrAll.perms, std::move(r), std::move(role), recursive); }
|
|
;
|
|
|
|
permission returns [auth::permission perm = auth::permission{}]
|
|
: p=(K_CREATE | K_ALTER | K_DROP | K_SELECT | K_MODIFY | K_AUTHORIZE | K_DESCRIBE | K_EXECUTE | K_VECTOR_SEARCH_INDEXING)
|
|
{ $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<auth::resource> res]
|
|
: d=dataResource { $res = std::move(d); }
|
|
| r=roleResource { $res = std::move(r); }
|
|
| f=functionResource { $res = std::move(f); }
|
|
;
|
|
|
|
dataResource returns [uninitialized<auth::resource> 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<auth::resource> res]
|
|
: K_ALL K_ROLES { $res = auth::resource(auth::resource_kind::role); }
|
|
| K_ROLE role = userOrRoleName { $res = auth::make_role_resource(cql3::role_name(std::move(role)).to_string()); }
|
|
;
|
|
|
|
functionResource returns [uninitialized<auth::resource> res]
|
|
@init {
|
|
std::vector<shared_ptr<cql3_type::raw>> args_types;
|
|
}
|
|
: K_ALL K_FUNCTIONS { $res = auth::make_functions_resource(); }
|
|
| K_ALL K_FUNCTIONS K_IN K_KEYSPACE ks = keyspaceName { $res = auth::make_functions_resource($ks.id); }
|
|
| K_FUNCTION fn=functionName
|
|
(
|
|
'('
|
|
(
|
|
v=comparatorType { args_types.push_back(v); }
|
|
( ',' v=comparatorType { args_types.push_back(v); } )*
|
|
)?
|
|
')'
|
|
)
|
|
{ $res = auth::make_functions_resource($fn.s.keyspace, $fn.s.name, args_types); }
|
|
;
|
|
|
|
/**
|
|
* CREATE USER [IF NOT EXISTS] <username> [WITH PASSWORD <password>] [SUPERUSER|NOSUPERUSER]
|
|
*/
|
|
createUserStatement returns [std::unique_ptr<create_role_statement> 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<create_role_statement>(cql3::role_name(u, cql3::preserve_role_case::yes), std::move(opts), ifNotExists); }
|
|
;
|
|
|
|
/**
|
|
* ALTER USER <username> [WITH PASSWORD <password>] [SUPERUSER|NOSUPERUSER]
|
|
*/
|
|
alterUserStatement returns [std::unique_ptr<alter_role_statement> 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<alter_role_statement>(cql3::role_name(u, cql3::preserve_role_case::yes), std::move(opts)); }
|
|
;
|
|
|
|
/**
|
|
* DROP USER [IF EXISTS] <username>
|
|
*/
|
|
dropUserStatement returns [std::unique_ptr<drop_role_statement> stmt]
|
|
@init { bool ifExists = false; }
|
|
: K_DROP K_USER (K_IF K_EXISTS { ifExists = true; })? u=username
|
|
{ $stmt = std::make_unique<drop_role_statement>(cql3::role_name(std::move(u), cql3::preserve_role_case::yes), ifExists); }
|
|
;
|
|
|
|
/**
|
|
* LIST USERS
|
|
*/
|
|
listUsersStatement returns [std::unique_ptr<list_users_statement> stmt]
|
|
: K_LIST K_USERS { $stmt = std::make_unique<list_users_statement>(); }
|
|
;
|
|
|
|
/**
|
|
* CREATE ROLE [IF NOT EXISTS] <role_name> [WITH <roleOption> [AND <roleOption>]*]
|
|
*/
|
|
createRoleStatement returns [std::unique_ptr<create_role_statement> 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<create_role_statement>(std::move(name), std::move(opts), if_not_exists); }
|
|
;
|
|
|
|
/**
|
|
* ALTER ROLE <rolename> [WITH <roleOption> [AND <roleOption>]*]
|
|
*/
|
|
alterRoleStatement returns [std::unique_ptr<alter_role_statement> stmt]
|
|
@init {
|
|
cql3::role_options opts;
|
|
}
|
|
: K_ALTER K_ROLE name=userOrRoleName
|
|
(K_WITH roleOptions[opts])?
|
|
{ $stmt = std::make_unique<alter_role_statement>(std::move(name), std::move(opts)); }
|
|
;
|
|
|
|
/**
|
|
* DROP ROLE [IF EXISTS] <rolename>
|
|
*/
|
|
dropRoleStatement returns [std::unique_ptr<drop_role_statement> stmt]
|
|
@init {
|
|
bool if_exists = false;
|
|
}
|
|
: K_DROP K_ROLE (K_IF K_EXISTS { if_exists = true; })? name=userOrRoleName
|
|
{ $stmt = std::make_unique<drop_role_statement>(std::move(name), if_exists); }
|
|
;
|
|
|
|
/**
|
|
* LIST ROLES [OF <rolename>] [NORECURSIVE]
|
|
*/
|
|
listRolesStatement returns [std::unique_ptr<list_roles_statement> stmt]
|
|
@init {
|
|
bool recursive = true;
|
|
std::optional<cql3::role_name> grantee;
|
|
}
|
|
: K_LIST K_ROLES
|
|
(K_OF g=userOrRoleName { grantee = std::move(g); })?
|
|
(K_NORECURSIVE { recursive = false; })?
|
|
{ $stmt = std::make_unique<list_roles_statement>(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_HASHED K_PASSWORD '=' v=STRING_LITERAL { opts.hashed_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] <service_level_name> [WITH <param> = <value>]
|
|
*/
|
|
createServiceLevelStatement returns [std::unique_ptr<create_service_level_statement> stmt]
|
|
@init {
|
|
auto attrs = make_shared<cql3::statements::sl_prop_defs>();
|
|
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<create_service_level_statement>(name, attrs, if_not_exists); }
|
|
;
|
|
|
|
/**
|
|
* ALTER SERVICE_LEVEL <service_level_name> WITH <param> = <value>
|
|
*/
|
|
alterServiceLevelStatement returns [std::unique_ptr<alter_service_level_statement> stmt]
|
|
@init {
|
|
auto attrs = make_shared<cql3::statements::sl_prop_defs>();
|
|
}
|
|
: K_ALTER serviceLevel name=serviceLevelOrRoleName K_WITH properties[*attrs]
|
|
{ $stmt = std::make_unique<alter_service_level_statement>(name, attrs); }
|
|
;
|
|
|
|
/**
|
|
* DROP SERVICE_LEVEL [IF EXISTS] <service_level_name>
|
|
*/
|
|
dropServiceLevelStatement returns [std::unique_ptr<drop_service_level_statement> stmt]
|
|
@init {
|
|
bool if_exists = false;
|
|
}
|
|
: K_DROP serviceLevel (K_IF K_EXISTS { if_exists = true; })? name=serviceLevelOrRoleName
|
|
{ $stmt = std::make_unique<drop_service_level_statement>(name, if_exists); }
|
|
;
|
|
|
|
/**
|
|
* ATTACH SERVICE_LEVEL <service_level_name> TO <role_name>
|
|
*/
|
|
attachServiceLevelStatement returns [std::unique_ptr<attach_service_level_statement> stmt]
|
|
@init {
|
|
}
|
|
: K_ATTACH serviceLevel service_level_name=serviceLevelOrRoleName K_TO role_name=serviceLevelOrRoleName
|
|
{ $stmt = std::make_unique<attach_service_level_statement>(service_level_name, role_name); }
|
|
;
|
|
|
|
/**
|
|
* DETACH SERVICE_LEVEL FROM <role_name>
|
|
*/
|
|
detachServiceLevelStatement returns [std::unique_ptr<detach_service_level_statement> stmt]
|
|
@init {
|
|
}
|
|
: K_DETACH serviceLevel K_FROM role_name=serviceLevelOrRoleName
|
|
{ $stmt = std::make_unique<detach_service_level_statement>(role_name); }
|
|
;
|
|
|
|
|
|
/**
|
|
* LIST SERVICE_LEVEL <service_level_name>
|
|
* LIST ALL SERVICE_LEVELS
|
|
*/
|
|
listServiceLevelStatement returns [std::unique_ptr<list_service_level_statement> stmt]
|
|
@init {
|
|
}
|
|
: K_LIST serviceLevel service_level_name=serviceLevelOrRoleName
|
|
{ $stmt = std::make_unique<list_service_level_statement>(service_level_name, false); } |
|
|
K_LIST K_ALL serviceLevels
|
|
{ $stmt = std::make_unique<list_service_level_statement>("", true); }
|
|
;
|
|
|
|
/**
|
|
* LIST ATTACHED SERVICE_LEVEL OF <role_name>
|
|
* LIST ALL ATTACHED SERVICE_LEVELS
|
|
*/
|
|
listServiceLevelAttachStatement returns [std::unique_ptr<list_service_level_attachments_statement> stmt]
|
|
@init {
|
|
bool allow_nonexisting_roles = false;
|
|
}
|
|
: K_LIST K_ATTACHED serviceLevel K_OF role_name=serviceLevelOrRoleName
|
|
{ $stmt = std::make_unique<list_service_level_attachments_statement>(role_name); } |
|
|
K_LIST K_ALL K_ATTACHED serviceLevels
|
|
{ $stmt = std::make_unique<list_service_level_attachments_statement>(); }
|
|
;
|
|
|
|
/**
|
|
* LIST EFFECTIVE SERVICE_LEVEL OF <role_name>
|
|
*/
|
|
listEffectiveServiceLevelStatement returns [std::unique_ptr<list_effective_service_level_statement stmt>]
|
|
@init {
|
|
}
|
|
: K_LIST K_EFFECTIVE serviceLevel K_OF role_name=serviceLevelOrRoleName
|
|
{ $stmt = std::make_unique<list_effective_service_level_statement>(role_name); }
|
|
;
|
|
|
|
/**
|
|
* (DESCRIBE | DESC) (
|
|
* CLUSTER
|
|
* [FULL] SCHEMA
|
|
* KEYSPACES
|
|
* [ONLY] KEYSPACE <name>?
|
|
* TABLES
|
|
* TABLE <name>
|
|
* TYPES
|
|
* TYPE <name>
|
|
* FUNCTIONS
|
|
* FUNCTION <name>
|
|
* AGGREGATES
|
|
* AGGREGATE <name>
|
|
* ) (WITH INTERNALS)?
|
|
*/
|
|
describeStatement returns [std::unique_ptr<cql3::statements::raw::describe_statement> stmt]
|
|
@init {
|
|
bool fullSchema = false;
|
|
bool pending = false;
|
|
bool config = false;
|
|
bool only = false;
|
|
std::optional<sstring> keyspace;
|
|
sstring generic_name = "";
|
|
bool with_hashed_passwords = false;
|
|
}
|
|
: ( K_DESCRIBE | K_DESC )
|
|
( (K_CLUSTER) => K_CLUSTER { $stmt = cql3::statements::raw::describe_statement::cluster(); }
|
|
| (K_FULL { fullSchema=true; })? K_SCHEMA { $stmt = cql3::statements::raw::describe_statement::schema(fullSchema); }
|
|
| (K_KEYSPACES) => K_KEYSPACES { $stmt = cql3::statements::raw::describe_statement::keyspaces(); }
|
|
| (K_ONLY { only=true; })? K_KEYSPACE ( ks=keyspaceName { keyspace = ks; })?
|
|
{ $stmt = cql3::statements::raw::describe_statement::keyspace(keyspace, only); }
|
|
| (K_TABLES) => K_TABLES { $stmt = cql3::statements::raw::describe_statement::tables(); }
|
|
| K_COLUMNFAMILY cf=columnFamilyName { $stmt = cql3::statements::raw::describe_statement::table(cf); }
|
|
| K_INDEX idx=columnFamilyName { $stmt = cql3::statements::raw::describe_statement::index(idx); }
|
|
| K_MATERIALIZED K_VIEW view=columnFamilyName { $stmt = cql3::statements::raw::describe_statement::view(view); }
|
|
| (K_TYPES) => K_TYPES { $stmt = cql3::statements::raw::describe_statement::types(); }
|
|
| K_TYPE tn=userTypeName { $stmt = cql3::statements::raw::describe_statement::type(std::move(tn)); }
|
|
| (K_FUNCTIONS) => K_FUNCTIONS { $stmt = cql3::statements::raw::describe_statement::functions(); }
|
|
| K_FUNCTION fn=functionName { $stmt = cql3::statements::raw::describe_statement::function(fn); }
|
|
| (K_AGGREGATES) => K_AGGREGATES { $stmt = cql3::statements::raw::describe_statement::aggregates(); }
|
|
| K_AGGREGATE ag=functionName { $stmt = cql3::statements::raw::describe_statement::aggregate(ag); }
|
|
| ( ( ksT=IDENT { keyspace = sstring{$ksT.text}; }
|
|
| ksT=QUOTED_NAME { keyspace = sstring{$ksT.text}; }
|
|
| ksK=unreserved_keyword { keyspace = ksK; } )
|
|
'.' )?
|
|
( tT=IDENT { generic_name = sstring{$tT.text}; }
|
|
| tT=QUOTED_NAME { generic_name = sstring{$tT.text}; }
|
|
| tK=unreserved_keyword { generic_name = tK; } )
|
|
{ $stmt = cql3::statements::raw::describe_statement::generic(keyspace, generic_name); }
|
|
)
|
|
( K_WITH K_INTERNALS (K_AND K_PASSWORDS { with_hashed_passwords = true; })?
|
|
{ $stmt->with_internals_details(with_hashed_passwords); } )?
|
|
;
|
|
|
|
/** 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<cql3::column_identifier::raw> id]
|
|
: t=IDENT { $id = ::make_shared<cql3::column_identifier::raw>(sstring{$t.text}, false); }
|
|
| t=QUOTED_NAME { $id = ::make_shared<cql3::column_identifier::raw>(sstring{$t.text}, true); }
|
|
| k=unreserved_keyword { $id = ::make_shared<cql3::column_identifier::raw>(k, false); }
|
|
;
|
|
|
|
// Identifiers that do not refer to columns or where the comparator is known to be text
|
|
ident returns [shared_ptr<cql3::column_identifier> id]
|
|
: t=IDENT { $id = ::make_shared<cql3::column_identifier>(sstring{$t.text}, false); }
|
|
| t=QUOTED_NAME { $id = ::make_shared<cql3::column_identifier>(sstring{$t.text}, true); }
|
|
| k=unreserved_keyword { $id = ::make_shared<cql3::column_identifier>(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<cql3::index_name> name]
|
|
@init { $name = ::make_shared<cql3::index_name>(); }
|
|
: (ksName[*name] '.')? idxName[*name]
|
|
;
|
|
|
|
columnFamilyName returns [cql3::cf_name name]
|
|
@init { $name = cql3::cf_name(); }
|
|
: (ksName[name] '.')? cfName[name]
|
|
;
|
|
|
|
userTypeName returns [uninitialized<cql3::ut_name> name]
|
|
: (ks=ident '.')? ut=non_type_ident { $name = cql3::ut_name(ks, ut); }
|
|
;
|
|
|
|
userOrRoleName returns [uninitialized<cql3::role_name> 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 = k;
|
|
std::transform($name.begin(), $name.end(), $name.begin(), ::tolower);}
|
|
// The literal `default` will not be parsed by any of the previous
|
|
// rules, so we need to cover it manually. Needed by CREATE SERVICE
|
|
// LEVEL and ATTACH SERVICE LEVEL.
|
|
| t=K_DEFAULT { $name = sstring("default"); }
|
|
| 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<expression> 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[uexpression t] returns [collection_constructor value]
|
|
@init{ std::vector<expression> 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 [uexpression value]
|
|
@init{ std::vector<expression> 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_or_vector, 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 [uexpression 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 [uexpression tt]
|
|
@init{ std::vector<expression> 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 [uexpression 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 = make_untyped_null(); }
|
|
| e=marker { $value = std::move(e); }
|
|
;
|
|
|
|
marker returns [uexpression value]
|
|
: ':' id=ident { $value = new_bind_variables(id); }
|
|
| QMARK { $value = new_bind_variables(shared_ptr<cql3::column_identifier>{}); }
|
|
;
|
|
|
|
intValue returns [uexpression value]
|
|
: t=INTEGER { $value = untyped_constant{untyped_constant::integer, $t.text}; }
|
|
| e=marker { $value = std::move(e); }
|
|
;
|
|
|
|
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<expression> a]
|
|
: '(' ')'
|
|
| '(' t1=term { a.push_back(std::move(t1)); }
|
|
( ',' tn=term { a.push_back(std::move(tn)); } )*
|
|
')'
|
|
;
|
|
|
|
term returns [uexpression 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{.style = cast::cast_style::c, .arg = std::move(t), .type = c}; }
|
|
;
|
|
|
|
columnOperation[operations_type& operations]
|
|
: key=cident columnOperationDifferentiator[operations, key]
|
|
;
|
|
|
|
columnOperationDifferentiator[operations_type& operations, ::shared_ptr<cql3::column_identifier::raw> key]
|
|
: '=' normalColumnOperation[operations, key]
|
|
| '[' k=term ']' collectionColumnOperation[operations, key, std::move(k), false]
|
|
| '.' field=ident udtColumnOperation[operations, key, field]
|
|
| '[' K_SCYLLA_TIMEUUID_LIST_INDEX '(' k=term ')' ']' collectionColumnOperation[operations, key, std::move(k), true]
|
|
;
|
|
|
|
normalColumnOperation[operations_type& operations, ::shared_ptr<cql3::column_identifier::raw> key]
|
|
: t=term ('+' c=cident )?
|
|
{
|
|
if (!c) {
|
|
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::set_value>(std::move(t)));
|
|
} else {
|
|
if (*key != *c) {
|
|
add_recognition_error("Only expressions of the form X = <value> + X are supported.");
|
|
}
|
|
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::prepend>(std::move(t)));
|
|
}
|
|
}
|
|
| c=cident sig=('+' | '-') t=term
|
|
{
|
|
if (*key != *c) {
|
|
add_recognition_error("Only expressions of the form X = X " + $sig.text + "<value> are supported.");
|
|
}
|
|
std::unique_ptr<cql3::operation::raw_update> op;
|
|
if ($sig.text == "+") {
|
|
op = std::make_unique<cql3::operation::addition>(std::move(t));
|
|
} else {
|
|
op = std::make_unique<cql3::operation::subtraction>(std::move(t));
|
|
}
|
|
operations.emplace_back(std::move(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] == '-' ? "-" : "+") + " <value> are supported.");
|
|
}
|
|
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::addition>(untyped_constant{untyped_constant::integer, $i.text}));
|
|
}
|
|
| K_SCYLLA_COUNTER_SHARD_LIST '(' t=term ')'
|
|
{
|
|
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::set_counter_value_from_tuple_list>(std::move(t)));
|
|
}
|
|
;
|
|
|
|
collectionColumnOperation[operations_type& operations,
|
|
shared_ptr<cql3::column_identifier::raw> key,
|
|
expression k,
|
|
bool by_uuid]
|
|
: '=' t=term
|
|
{
|
|
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::set_element>(std::move(k), std::move(t), by_uuid));
|
|
}
|
|
;
|
|
|
|
udtColumnOperation[operations_type& operations,
|
|
shared_ptr<cql3::column_identifier::raw> key,
|
|
shared_ptr<cql3::column_identifier> field]
|
|
: '=' t=term
|
|
{
|
|
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::set_field>(std::move(field), std::move(t)));
|
|
}
|
|
;
|
|
|
|
columnRefExpr returns [uexpression e]
|
|
: column=cident { e = unresolved_identifier{column}; }
|
|
;
|
|
|
|
subscriptExpr returns [uexpression e]
|
|
: col=columnRefExpr { e = std::move(col); }
|
|
( '[' sub=term ']' { e = subscript{std::move(e), std::move(sub)}; } )?
|
|
;
|
|
|
|
singleColumnInValuesOrMarkerExpr returns [uexpression e]
|
|
: values=singleColumnInValues { e = collection_constructor{collection_constructor::style_type::list_or_vector, std::move(values)}; }
|
|
| m=marker { e = std::move(m); }
|
|
;
|
|
|
|
columnCondition returns [uexpression e]
|
|
// Note: we'll reject duplicates later
|
|
: key=subscriptExpr
|
|
( op=relationType t=term {
|
|
e = binary_operator(
|
|
std::move(key),
|
|
op,
|
|
std::move(t));
|
|
}
|
|
| K_IN
|
|
values=singleColumnInValuesOrMarkerExpr {
|
|
e = binary_operator(
|
|
std::move(key),
|
|
oper_t::IN,
|
|
std::move(values));
|
|
}
|
|
| K_NOT K_IN
|
|
values=singleColumnInValuesOrMarkerExpr {
|
|
e = binary_operator(
|
|
std::move(key),
|
|
oper_t::NOT_IN,
|
|
std::move(values));
|
|
}
|
|
)
|
|
;
|
|
|
|
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_extended_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 = oper_t{}]
|
|
: '=' { $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 returns [uexpression e]
|
|
@init{ oper_t rt; }
|
|
: name=cident type=relationType t=term { $e = binary_operator(unresolved_identifier{std::move(name)}, type, std::move(t)); }
|
|
|
|
| K_TOKEN l=tupleOfIdentifiers type=relationType t=term
|
|
{
|
|
$e = binary_operator(
|
|
function_call{functions::function_name::native_function("token"), std::move(l.elements)},
|
|
type,
|
|
std::move(t));
|
|
}
|
|
| name=cident K_IS K_NOT K_NULL {
|
|
$e = binary_operator(unresolved_identifier{std::move(name)}, oper_t::IS_NOT, make_untyped_null()); }
|
|
| name=cident K_IN marker1=marker
|
|
{ $e = binary_operator(unresolved_identifier{std::move(name)}, oper_t::IN, std::move(marker1)); }
|
|
| name=cident K_IN in_values=singleColumnInValues
|
|
{ $e = binary_operator(unresolved_identifier{std::move(name)}, oper_t::IN,
|
|
collection_constructor {
|
|
.style = collection_constructor::style_type::list_or_vector,
|
|
.elements = std::move(in_values)
|
|
}); }
|
|
| name=cident K_NOT K_IN marker1=marker
|
|
{ $e = binary_operator(unresolved_identifier{std::move(name)}, oper_t::NOT_IN, std::move(marker1)); }
|
|
| name=cident K_NOT K_IN in_values=singleColumnInValues
|
|
{ $e = binary_operator(unresolved_identifier{std::move(name)}, oper_t::NOT_IN,
|
|
collection_constructor {
|
|
.style = collection_constructor::style_type::list_or_vector,
|
|
.elements = std::move(in_values)
|
|
}); }
|
|
| name=cident K_CONTAINS { rt = oper_t::CONTAINS; } (K_KEY { rt = oper_t::CONTAINS_KEY; })?
|
|
t=term { $e = binary_operator(unresolved_identifier{std::move(name)}, rt, std::move(t)); }
|
|
| name=cident '[' key=term ']' type=relationType t=term { $e = binary_operator(subscript{.val = unresolved_identifier{std::move(name)}, .sub = std::move(key)}, type, std::move(t)); }
|
|
| ids=tupleOfIdentifiers
|
|
( K_IN
|
|
( '(' ')'
|
|
{
|
|
$e = binary_operator(
|
|
ids,
|
|
oper_t::IN,
|
|
collection_constructor {
|
|
.style = collection_constructor::style_type::list_or_vector,
|
|
.elements = std::vector<expression>()
|
|
}
|
|
);
|
|
}
|
|
| tupleInMarker=marker /* (a, b, c) IN ? */
|
|
{
|
|
$e = binary_operator(
|
|
ids,
|
|
oper_t::IN,
|
|
std::move(tupleInMarker)
|
|
);
|
|
}
|
|
| literals=tupleOfTupleLiterals /* (a, b, c) IN ((1, 2, 3), (4, 5, 6), ...) */
|
|
{
|
|
$e = binary_operator(
|
|
ids,
|
|
oper_t::IN,
|
|
collection_constructor {
|
|
.style = collection_constructor::style_type::list_or_vector,
|
|
.elements = std::move(literals)
|
|
}
|
|
);
|
|
}
|
|
| markers=tupleOfMarkersForTuples /* (a, b, c) IN (?, ?, ...) */
|
|
{
|
|
$e = binary_operator(
|
|
ids,
|
|
oper_t::IN,
|
|
collection_constructor {
|
|
.style = collection_constructor::style_type::list_or_vector,
|
|
.elements = std::move(markers)
|
|
}
|
|
);
|
|
}
|
|
)
|
|
| type=relationType literal=tupleLiteral /* (a, b, c) > (1, 2, 3) or (a, b, c) > (?, ?, ?) */
|
|
{
|
|
$e = binary_operator(ids, type, std::move(literal));
|
|
}
|
|
| type=relationType K_SCYLLA_CLUSTERING_BOUND literal=tupleLiteral /* (a, b, c) > (1, 2, 3) or (a, b, c) > (?, ?, ?) */
|
|
{
|
|
$e = binary_operator(ids, type, std::move(literal), cql3::expr::comparison_order::clustering);
|
|
}
|
|
| type=relationType tupleMarker=marker /* (a, b, c) >= ? */
|
|
{
|
|
$e = binary_operator(ids, type, std::move(tupleMarker));
|
|
}
|
|
)
|
|
| '(' e1=relation ')' { $e = std::move(e1); }
|
|
;
|
|
|
|
tupleOfIdentifiers returns [tuple_constructor tup]
|
|
: '(' n1=cident { $tup.elements.push_back(unresolved_identifier{std::move(n1)}); } (',' ni=cident { $tup.elements.push_back(unresolved_identifier{std::move(ni)}); })* ')'
|
|
;
|
|
|
|
listOfIdentifiers returns [std::vector<::shared_ptr<cql3::column_identifier::raw>> ids]
|
|
: n1=cident { $ids.push_back(n1); } (',' ni=cident { $ids.push_back(ni); })*
|
|
;
|
|
|
|
singleColumnInValues returns [std::vector<expression> list]
|
|
: '(' ( t1 = term { $list.push_back(std::move(t1)); } (',' ti=term { $list.push_back(std::move(ti)); })* )? ')'
|
|
;
|
|
|
|
tupleOfTupleLiterals returns [std::vector<expression> literals]
|
|
: '(' t1=tupleLiteral { $literals.emplace_back(std::move(t1)); } (',' ti=tupleLiteral { $literals.emplace_back(std::move(ti)); })* ')'
|
|
;
|
|
|
|
tupleOfMarkersForTuples returns [std::vector<expression> markers]
|
|
: '(' m1=marker { $markers.emplace_back(std::move(m1)); } (',' mi=marker { $markers.emplace_back(std::move(mi)); })* ')'
|
|
;
|
|
|
|
// 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<cql3_type::raw> 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; }
|
|
| vt=vector_type { $t = vt; }
|
|
| id=userTypeName { $t = cql3::cql3_type::raw::user_type(std::move(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<cql3_type::raw> 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<cql3::cql3_type::raw> 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<cql3::cql3_type::raw> t]
|
|
@init{ std::vector<shared_ptr<cql3::cql3_type::raw>> 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)); }
|
|
;
|
|
|
|
vector_type returns [shared_ptr<cql3::cql3_type::raw> pt]
|
|
: K_VECTOR '<' t=comparator_type[false] ',' d=INTEGER '>'
|
|
{
|
|
if ($d.text[0] == '-')
|
|
throw exceptions::invalid_request_exception("Vectors must have a dimension greater than 0");
|
|
unsigned long parsed_dimension;
|
|
try {
|
|
parsed_dimension = std::stoul($d.text);
|
|
} catch (const std::exception& e) {
|
|
throw exceptions::invalid_request_exception(format("Invalid vector dimension: {}", $d.text));
|
|
}
|
|
static_assert(sizeof(unsigned long) >= sizeof(vector_dimension_t));
|
|
if (parsed_dimension == 0) {
|
|
throw exceptions::invalid_request_exception("Vectors must have a dimension greater than 0");
|
|
}
|
|
if (parsed_dimension > cql3::cql3_type::MAX_VECTOR_DIMENSION) {
|
|
throw exceptions::invalid_request_exception(
|
|
format("Vectors must have a dimension less than or equal to {}", cql3::cql3_type::MAX_VECTOR_DIMENSION));
|
|
}
|
|
$pt = cql3::cql3_type::raw::vector(t, static_cast<vector_dimension_t>(parsed_dimension));
|
|
}
|
|
;
|
|
|
|
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 exclude existing CQL3 types
|
|
// (which for some reason are not reserved otherwise)
|
|
non_type_ident returns [shared_ptr<cql3::column_identifier> id]
|
|
: t=IDENT { if (_reserved_type_names().contains($t.text)) { add_recognition_error("Invalid (reserved) user type name " + $t.text); } $id = ::make_shared<cql3::column_identifier>($t.text, false); }
|
|
| t=QUOTED_NAME { $id = ::make_shared<cql3::column_identifier>($t.text, true); }
|
|
| k=basic_unreserved_keyword { $id = ::make_shared<cql3::column_identifier>(k, false); }
|
|
| kk=K_KEY { $id = ::make_shared<cql3::column_identifier>($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; }
|
|
| u=type_unreserved_keyword { $str = u; }
|
|
;
|
|
|
|
basic_unreserved_keyword returns [sstring str]
|
|
: k=( K_KEYS
|
|
| K_AS
|
|
| K_CLUSTER
|
|
| K_CLUSTERING
|
|
| K_COMPACT
|
|
| K_STORAGE
|
|
| K_TABLES
|
|
| K_TYPE
|
|
| K_TYPES
|
|
| 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_PASSWORDS
|
|
| K_HASHED
|
|
| K_EXISTS
|
|
| K_CUSTOM
|
|
| K_TRIGGER
|
|
| K_DISTINCT
|
|
| K_CONTAINS
|
|
| K_INTERNALS
|
|
| K_STATIC
|
|
| K_FROZEN
|
|
| K_TUPLE
|
|
| K_VECTOR
|
|
| K_FUNCTION
|
|
| K_FUNCTIONS
|
|
| K_AGGREGATE
|
|
| K_AGGREGATES
|
|
| K_SFUNC
|
|
| K_STYPE
|
|
| K_REDUCEFUNC
|
|
| 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_SHARES
|
|
| K_GROUP
|
|
| K_TIMEOUT
|
|
| K_SERVICE
|
|
| K_LEVEL
|
|
| K_LEVELS
|
|
| K_PRUNE
|
|
| K_ONLY
|
|
| K_DESCRIBE
|
|
| K_DESC
|
|
| K_EXECUTE
|
|
| K_MUTATION_FRAGMENTS
|
|
| K_EFFECTIVE
|
|
) { $str = $k.text; }
|
|
;
|
|
|
|
type_unreserved_keyword returns [sstring str]
|
|
: k=( K_ASCII
|
|
| K_BIGINT
|
|
| K_BLOB
|
|
| K_BOOLEAN
|
|
| K_COUNTER
|
|
| K_DECIMAL
|
|
| K_DOUBLE
|
|
| K_DURATION
|
|
| K_FLOAT
|
|
| K_INET
|
|
| K_INT
|
|
| K_SMALLINT
|
|
| K_TEXT
|
|
| K_TIMESTAMP
|
|
| K_TINYINT
|
|
| K_UUID
|
|
| K_VARCHAR
|
|
| K_VARINT
|
|
| K_TIMEUUID
|
|
| K_DATE
|
|
| K_TIME
|
|
| K_EMPTY
|
|
) { $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_SCHEMA: S C H E M A;
|
|
K_KEYSPACE: ( K E Y S P A C E
|
|
| K_SCHEMA );
|
|
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_TABLES: ( C O L U M N F A M I L I E S
|
|
| T A B L E S );
|
|
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_TYPES: T Y P E S;
|
|
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_ANN: A N N;
|
|
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_INTERNALS: I N T E R N A L S;
|
|
K_ONLY: O N L Y;
|
|
|
|
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_PASSWORDS: P A S S W O R D S;
|
|
K_HASHED: H A S H E 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_CLUSTER: C L U S T E R;
|
|
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_VECTOR: V E C T O R;
|
|
|
|
K_TRIGGER: T R I G G E R;
|
|
K_STATIC: S T A T I C;
|
|
K_FROZEN: F R O Z E N;
|
|
|
|
K_FUNCTION: F U N C T I O N;
|
|
K_FUNCTIONS: F U N C T I O N S;
|
|
K_AGGREGATE: A G G R E G A T E;
|
|
K_AGGREGATES: A G G R E G A T E S;
|
|
K_SFUNC: S F U N C;
|
|
K_STYPE: S T Y P E;
|
|
K_REDUCEFUNC: R E D U C E F U N C;
|
|
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_EFFECTIVE: E F F E C T I V E;
|
|
K_SHARES: S H A R E 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;
|
|
K_PRUNE: P R U N E;
|
|
K_CONCURRENCY: C O N C U R R E N C Y;
|
|
|
|
K_EXECUTE: E X E C U T E;
|
|
|
|
K_MUTATION_FRAGMENTS: M U T A T I O N '_' F R A G M E N T S;
|
|
|
|
K_VECTOR_SEARCH_INDEXING: V E C T O R '_' S E A R C H '_' I N D E X I N G;
|
|
|
|
// 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 precedence 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; }
|
|
;
|