mirror of
https://github.com/scylladb/scylladb.git
synced 2026-04-24 10:30:38 +00:00
Merge branch 'tgrabiec/cql3' of github.com:cloudius-systems/seastar-dev into db
Enable parsing of INSERT and UPDATE CQL3 statements, from Tomasz.
This commit is contained in:
@@ -103,6 +103,7 @@ urchin_tests = [
|
||||
'tests/urchin/mutation_test',
|
||||
'tests/urchin/types_test',
|
||||
'tests/perf/perf_mutation',
|
||||
'tests/urchin/cql_query_test',
|
||||
]
|
||||
|
||||
tests = [
|
||||
@@ -248,6 +249,11 @@ urchin_core = (['database.cc',
|
||||
'cql3/operator.cc',
|
||||
'cql3/relation.cc',
|
||||
'cql3/column_identifier.cc',
|
||||
'cql3/constants.cc',
|
||||
'cql3/query_processor.cc',
|
||||
'cql3/query_options.cc',
|
||||
'cql3/single_column_relation.cc',
|
||||
'cql3/column_condition.cc',
|
||||
'db/db.cc',
|
||||
'io/io.cc',
|
||||
'utils/utils.cc',
|
||||
|
||||
286
cql3/Cql.g
286
cql3/Cql.g
@@ -23,13 +23,21 @@ options {
|
||||
language = Cpp;
|
||||
}
|
||||
|
||||
@parser::namespace{cql3}
|
||||
@parser::namespace{cql3_parser}
|
||||
|
||||
@lexer::includes {
|
||||
#include "cql3/error_listener.hh"
|
||||
}
|
||||
|
||||
@parser::includes {
|
||||
#include "cql3/statements/select_statement.hh"
|
||||
#include "cql3/statements/update_statement.hh"
|
||||
#include "cql3/statements/use_statement.hh"
|
||||
#include "cql3/selection/raw_selector.hh"
|
||||
#include "cql3/constants.hh"
|
||||
#include "cql3/operation_impl.hh"
|
||||
#include "cql3/error_listener.hh"
|
||||
#include "cql3/single_column_relation.hh"
|
||||
#include "cql3/cql3_type.hh"
|
||||
#include "cql3/cf_name.hh"
|
||||
#include "core/sstring.hh"
|
||||
@@ -39,9 +47,12 @@ options {
|
||||
}
|
||||
|
||||
@parser::traits {
|
||||
using namespace cql3;
|
||||
using namespace cql3::statements;
|
||||
using namespace cql3::selection;
|
||||
using cql3::cql3_type;
|
||||
using cql3::native_cql3_type;
|
||||
using conditions_type = std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,::shared_ptr<cql3::column_condition::raw>>>;
|
||||
using operations_type = std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,::shared_ptr<cql3::operation::raw_update>>>;
|
||||
}
|
||||
|
||||
@header {
|
||||
@@ -74,11 +85,13 @@ using namespace cql3::selection;
|
||||
#endif
|
||||
}
|
||||
|
||||
@members {
|
||||
#if 0
|
||||
private final List<ErrorListener> listeners = new ArrayList<ErrorListener>();
|
||||
private final List<ColumnIdentifier> bindVariables = new ArrayList<ColumnIdentifier>();
|
||||
@context {
|
||||
using listener_type = cql3::error_listener<RecognizerType>;
|
||||
listener_type* listener;
|
||||
|
||||
std::vector<::shared_ptr<cql3::column_identifier>> _bind_variables;
|
||||
|
||||
#if 0
|
||||
public static final Set<String> reservedTypeNames = new HashSet<String>()
|
||||
{{
|
||||
add("byte");
|
||||
@@ -118,29 +131,25 @@ using namespace cql3::selection;
|
||||
bindVariables.add(name);
|
||||
return marker;
|
||||
}
|
||||
#endif
|
||||
|
||||
public void addErrorListener(ErrorListener listener)
|
||||
{
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeErrorListener(ErrorListener listener)
|
||||
{
|
||||
this.listeners.remove(listener);
|
||||
void set_error_listener(listener_type& listener) {
|
||||
this->listener = &listener;
|
||||
}
|
||||
|
||||
#if 0
|
||||
public void displayRecognitionError(String[] tokenNames, RecognitionException e)
|
||||
{
|
||||
for (int i = 0, m = listeners.size(); i < m; i++)
|
||||
listeners.get(i).syntaxError(this, tokenNames, e);
|
||||
}
|
||||
#endif
|
||||
|
||||
private void addRecognitionError(String msg)
|
||||
{
|
||||
for (int i = 0, m = listeners.size(); i < m; i++)
|
||||
listeners.get(i).syntaxError(this, msg);
|
||||
void add_recognition_error(const sstring& msg) {
|
||||
listener->syntax_error(*this, msg);
|
||||
}
|
||||
|
||||
#if 0
|
||||
public Map<String, String> convertPropertyMap(Maps.Literal map)
|
||||
{
|
||||
if (map == null || map.entries == null || map.entries.isEmpty())
|
||||
@@ -179,19 +188,21 @@ using namespace cql3::selection;
|
||||
return res;
|
||||
}
|
||||
|
||||
public void addRawUpdate(List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations, ColumnIdentifier.Raw key, Operation.RawUpdate update)
|
||||
{
|
||||
for (Pair<ColumnIdentifier.Raw, Operation.RawUpdate> p : operations)
|
||||
{
|
||||
if (p.left.equals(key) && !p.right.isCompatibleWith(update))
|
||||
addRecognitionError("Multiple incompatible setting of column " + key);
|
||||
}
|
||||
operations.add(Pair.create(key, update));
|
||||
}
|
||||
#endif
|
||||
void add_raw_update(std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,::shared_ptr<cql3::operation::raw_update>>>& operations,
|
||||
::shared_ptr<cql3::column_identifier::raw> key, ::shared_ptr<cql3::operation::raw_update> update)
|
||||
{
|
||||
for (auto&& p : operations) {
|
||||
if (*p.first == *key && !p.second->is_compatible_with(update)) {
|
||||
// \%s is escaped for antlr
|
||||
add_recognition_error(sprint("Multiple incompatible setting of column \%s", *key));
|
||||
}
|
||||
}
|
||||
operations.emplace_back(std::move(key), std::move(update));
|
||||
}
|
||||
}
|
||||
|
||||
@lexer::namespace{cql3}
|
||||
@lexer::namespace{cql3_parser}
|
||||
|
||||
@lexer::traits {
|
||||
class CqlLexer;
|
||||
@@ -210,7 +221,7 @@ using namespace cql3::selection;
|
||||
#endif
|
||||
}
|
||||
|
||||
@lexer::members {
|
||||
@lexer::context {
|
||||
#if 0
|
||||
List<Token> tokens = new ArrayList<Token>();
|
||||
|
||||
@@ -227,19 +238,17 @@ using namespace cql3::selection;
|
||||
return new CommonToken(Token.EOF);
|
||||
return tokens.remove(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
private final List<ErrorListener> listeners = new ArrayList<ErrorListener>();
|
||||
using listener_type = cql3::error_listener<RecognizerType>;
|
||||
|
||||
public void addErrorListener(ErrorListener listener)
|
||||
{
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeErrorListener(ErrorListener listener)
|
||||
{
|
||||
this.listeners.remove(listener);
|
||||
listener_type* listener;
|
||||
|
||||
void set_error_listener(listener_type& listener) {
|
||||
this->listener = &listener;
|
||||
}
|
||||
|
||||
#if 0
|
||||
public void displayRecognitionError(String[] tokenNames, RecognitionException e)
|
||||
{
|
||||
for (int i = 0, m = listeners.size(); i < m; i++)
|
||||
@@ -255,13 +264,11 @@ query returns [shared_ptr<parsed_statement> stmnt]
|
||||
;
|
||||
|
||||
cqlStatement returns [shared_ptr<parsed_statement> stmt]
|
||||
#if 0
|
||||
@after{ if (stmt != null) stmt.setBoundVariables(bindVariables); }
|
||||
#endif
|
||||
@after{ if (stmt) { stmt->set_bound_variables(_bind_variables); } }
|
||||
: st1= selectStatement { $stmt = st1; }
|
||||
#if 0
|
||||
| st2= insertStatement { $stmt = st2; }
|
||||
| st3= updateStatement { $stmt = st3; }
|
||||
#if 0
|
||||
| st4= batchStatement { $stmt = st4; }
|
||||
| st5= deleteStatement { $stmt = st5; }
|
||||
#endif
|
||||
@@ -346,7 +353,7 @@ selectClause returns [std::vector<shared_ptr<raw_selector>> expr]
|
||||
;
|
||||
|
||||
selector returns [shared_ptr<raw_selector> s]
|
||||
@init{ shared_ptr<column_identifier> alias; }
|
||||
@init{ shared_ptr<cql3::column_identifier> alias; }
|
||||
: us=unaliasedSelector (K_AS c=ident { alias = c; })? { $s = make_shared<raw_selector>(us, alias); }
|
||||
;
|
||||
|
||||
@@ -381,18 +388,20 @@ countArgument
|
||||
: '\*'
|
||||
| i=INTEGER { if (!i.getText().equals("1")) addRecognitionError("Only COUNT(1) is supported, got COUNT(" + i.getText() + ")");}
|
||||
;
|
||||
#endif
|
||||
|
||||
whereClause returns [List<Relation> clause]
|
||||
@init{ $clause = new ArrayList<Relation>(); }
|
||||
whereClause returns [std::vector<cql3::relation_ptr> clause]
|
||||
: relation[$clause] (K_AND relation[$clause])*
|
||||
;
|
||||
|
||||
#if 0
|
||||
orderByClause[Map<ColumnIdentifier.Raw, Boolean> orderings]
|
||||
@init{
|
||||
boolean reversed = false;
|
||||
}
|
||||
: c=cident (K_ASC | K_DESC { reversed = true; })? { orderings.put(c, reversed); }
|
||||
;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* INSERT INTO <CF> (<column>, <column>, <column>, ...)
|
||||
@@ -400,36 +409,36 @@ orderByClause[Map<ColumnIdentifier.Raw, Boolean> orderings]
|
||||
* USING TIMESTAMP <long>;
|
||||
*
|
||||
*/
|
||||
insertStatement returns [UpdateStatement.ParsedInsert expr]
|
||||
insertStatement returns [::shared_ptr<update_statement::parsed_insert> expr]
|
||||
@init {
|
||||
Attributes.Raw attrs = new Attributes.Raw();
|
||||
List<ColumnIdentifier.Raw> columnNames = new ArrayList<ColumnIdentifier.Raw>();
|
||||
List<Term.Raw> values = new ArrayList<Term.Raw>();
|
||||
boolean ifNotExists = false;
|
||||
auto attrs = ::make_shared<cql3::attributes::raw>();
|
||||
std::vector<::shared_ptr<cql3::column_identifier::raw>> column_names;
|
||||
std::vector<::shared_ptr<cql3::term::raw>> values;
|
||||
bool if_not_exists = false;
|
||||
}
|
||||
: K_INSERT K_INTO cf=columnFamilyName
|
||||
'(' c1=cident { columnNames.add(c1); } ( ',' cn=cident { columnNames.add(cn); } )* ')'
|
||||
'(' c1=cident { column_names.push_back(c1); } ( ',' cn=cident { column_names.push_back(cn); } )* ')'
|
||||
K_VALUES
|
||||
'(' v1=term { values.add(v1); } ( ',' vn=term { values.add(vn); } )* ')'
|
||||
'(' v1=term { values.push_back(v1); } ( ',' vn=term { values.push_back(vn); } )* ')'
|
||||
|
||||
( K_IF K_NOT K_EXISTS { ifNotExists = true; } )?
|
||||
( K_IF K_NOT K_EXISTS { if_not_exists = true; } )?
|
||||
( usingClause[attrs] )?
|
||||
{
|
||||
$expr = new UpdateStatement.ParsedInsert(cf,
|
||||
attrs,
|
||||
columnNames,
|
||||
values,
|
||||
ifNotExists);
|
||||
$expr = ::make_shared<update_statement::parsed_insert>(std::move(cf),
|
||||
std::move(attrs),
|
||||
std::move(column_names),
|
||||
std::move(values),
|
||||
if_not_exists);
|
||||
}
|
||||
;
|
||||
|
||||
usingClause[Attributes.Raw attrs]
|
||||
usingClause[::shared_ptr<cql3::attributes::raw> attrs]
|
||||
: K_USING usingClauseObjective[attrs] ( K_AND usingClauseObjective[attrs] )*
|
||||
;
|
||||
|
||||
usingClauseObjective[Attributes.Raw attrs]
|
||||
: K_TIMESTAMP ts=intValue { attrs.timestamp = ts; }
|
||||
| K_TTL t=intValue { attrs.timeToLive = t; }
|
||||
usingClauseObjective[::shared_ptr<cql3::attributes::raw> attrs]
|
||||
: K_TIMESTAMP ts=intValue { attrs->timestamp = ts; }
|
||||
| K_TTL t=intValue { attrs->time_to_live = t; }
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -438,10 +447,10 @@ usingClauseObjective[Attributes.Raw attrs]
|
||||
* SET name1 = value1, name2 = value2
|
||||
* WHERE key = value;
|
||||
*/
|
||||
updateStatement returns [UpdateStatement.ParsedUpdate expr]
|
||||
updateStatement returns [::shared_ptr<update_statement::parsed_update> expr]
|
||||
@init {
|
||||
Attributes.Raw attrs = new Attributes.Raw();
|
||||
List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations = new ArrayList<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>>();
|
||||
auto attrs = ::make_shared<cql3::attributes::raw>();
|
||||
std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>, ::shared_ptr<cql3::operation::raw_update>>> operations;
|
||||
}
|
||||
: K_UPDATE cf=columnFamilyName
|
||||
( usingClause[attrs] )?
|
||||
@@ -449,19 +458,19 @@ updateStatement returns [UpdateStatement.ParsedUpdate expr]
|
||||
K_WHERE wclause=whereClause
|
||||
( K_IF conditions=updateConditions )?
|
||||
{
|
||||
return new UpdateStatement.ParsedUpdate(cf,
|
||||
attrs,
|
||||
operations,
|
||||
wclause,
|
||||
conditions == null ? Collections.<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>>emptyList() : conditions);
|
||||
return ::make_shared<update_statement::parsed_update>(std::move(cf),
|
||||
std::move(attrs),
|
||||
std::move(operations),
|
||||
std::move(wclause),
|
||||
std::move(conditions));
|
||||
}
|
||||
;
|
||||
|
||||
updateConditions returns [List<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>> conditions]
|
||||
@init { conditions = new ArrayList<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>>(); }
|
||||
updateConditions returns [conditions_type conditions]
|
||||
: columnCondition[conditions] ( K_AND columnCondition[conditions] )*
|
||||
;
|
||||
|
||||
#if 0
|
||||
|
||||
/**
|
||||
* DELETE name1, name2
|
||||
@@ -981,22 +990,22 @@ userOption[UserOptions opts]
|
||||
// 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<column_identifier::raw> id]
|
||||
: t=IDENT { $id = make_shared<column_identifier::raw>(sstring{$t.text}, false); }
|
||||
| t=QUOTED_NAME { $id = make_shared<column_identifier::raw>(sstring{$t.text}, true); }
|
||||
| k=unreserved_keyword { $id = make_shared<column_identifier::raw>(k, false); }
|
||||
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<column_identifier> id]
|
||||
: t=IDENT { $id = make_shared<column_identifier>(sstring{$t.text}, false); }
|
||||
| t=QUOTED_NAME { $id = make_shared<column_identifier>(sstring{$t.text}, true); }
|
||||
| k=unreserved_keyword { $id = make_shared<column_identifier>(k, false); }
|
||||
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 = make_shared<cf_name>(); }
|
||||
@init { auto name = make_shared<cql3::cf_name>(); }
|
||||
: cfOrKsName[name, true] { $id = name->get_keyspace(); }
|
||||
;
|
||||
|
||||
@@ -1013,8 +1022,8 @@ idxOrKsName[IndexName name, boolean isKs]
|
||||
;
|
||||
#endif
|
||||
|
||||
columnFamilyName returns [shared_ptr<cf_name> name]
|
||||
@init { $name = make_shared<cf_name>(); }
|
||||
columnFamilyName returns [shared_ptr<cql3::cf_name> name]
|
||||
@init { $name = make_shared<cql3::cf_name>(); }
|
||||
: (cfOrKsName[name, true] '.')? cfOrKsName[name, false]
|
||||
;
|
||||
|
||||
@@ -1024,7 +1033,7 @@ userTypeName returns [UTName name]
|
||||
;
|
||||
#endif
|
||||
|
||||
cfOrKsName[shared_ptr<cf_name> name, bool isKs]
|
||||
cfOrKsName[shared_ptr<cql3::cf_name> name, bool isKs]
|
||||
: t=IDENT { if (isKs) $name->set_keyspace($t.text, false); else $name->set_column_family($t.text, false); }
|
||||
| t=QUOTED_NAME { if (isKs) $name->set_keyspace($t.text, true); else $name->set_column_family($t.text, true); }
|
||||
| k=unreserved_keyword { if (isKs) $name->set_keyspace(k, false); else $name->set_column_family(k, false); }
|
||||
@@ -1033,15 +1042,15 @@ cfOrKsName[shared_ptr<cf_name> name, bool isKs]
|
||||
#endif
|
||||
;
|
||||
|
||||
constant returns [shared_ptr<constants::literal> constant]
|
||||
constant returns [shared_ptr<cql3::constants::literal> constant]
|
||||
@init{std::string sign;}
|
||||
: t=STRING_LITERAL { $constant = constants::literal::string(sstring{$t.text}); }
|
||||
| t=INTEGER { $constant = constants::literal::integer(sstring{$t.text}); }
|
||||
| t=FLOAT { $constant = constants::literal::floating_point(sstring{$t.text}); }
|
||||
| t=BOOLEAN { $constant = constants::literal::bool_(sstring{$t.text}); }
|
||||
| t=UUID { $constant = constants::literal::uuid(sstring{$t.text}); }
|
||||
| t=HEXNUMBER { $constant = constants::literal::hex(sstring{$t.text}); }
|
||||
| { sign=""; } ('-' {sign = "-"; } )? t=(K_NAN | K_INFINITY) { $constant = constants::literal::floating_point(sstring{sign + $t.text}); }
|
||||
: t=STRING_LITERAL { $constant = cql3::constants::literal::string(sstring{$t.text}); }
|
||||
| t=INTEGER { $constant = cql3::constants::literal::integer(sstring{$t.text}); }
|
||||
| t=FLOAT { $constant = cql3::constants::literal::floating_point(sstring{$t.text}); }
|
||||
| t=BOOLEAN { $constant = cql3::constants::literal::bool_(sstring{$t.text}); }
|
||||
| t=UUID { $constant = cql3::constants::literal::uuid(sstring{$t.text}); }
|
||||
| t=HEXNUMBER { $constant = cql3::constants::literal::hex(sstring{$t.text}); }
|
||||
| { sign=""; } ('-' {sign = "-"; } )? t=(K_NAN | K_INFINITY) { $constant = cql3::constants::literal::floating_point(sstring{sign + $t.text}); }
|
||||
;
|
||||
|
||||
#if 0
|
||||
@@ -1082,21 +1091,25 @@ tupleLiteral returns [Tuples.Literal tt]
|
||||
@after{ $tt = new Tuples.Literal(l); }
|
||||
: '(' t1=term { l.add(t1); } ( ',' tn=term { l.add(tn); } )* ')'
|
||||
;
|
||||
#endif
|
||||
|
||||
value returns [Term.Raw value]
|
||||
value returns [::shared_ptr<cql3::term::raw> value]
|
||||
: c=constant { $value = c; }
|
||||
#if 0
|
||||
| l=collectionLiteral { $value = l; }
|
||||
| u=usertypeLiteral { $value = u; }
|
||||
| t=tupleLiteral { $value = t; }
|
||||
| K_NULL { $value = Constants.NULL_LITERAL; }
|
||||
#endif
|
||||
| K_NULL { $value = cql3::constants::NULL_LITERAL; }
|
||||
#if 0
|
||||
| ':' id=ident { $value = newBindVariables(id); }
|
||||
| QMARK { $value = newBindVariables(null); }
|
||||
;
|
||||
#endif
|
||||
;
|
||||
|
||||
intValue returns [::shared_ptr<term::raw> value]
|
||||
intValue returns [::shared_ptr<cql3::term::raw> value]
|
||||
:
|
||||
| t=INTEGER { $value = constants::literal::integer(sstring{$t.text}); }
|
||||
| t=INTEGER { $value = cql3::constants::literal::integer(sstring{$t.text}); }
|
||||
#if 0
|
||||
| ':' id=ident { $value = newBindVariables(id); }
|
||||
| QMARK { $value = newBindVariables(null); }
|
||||
@@ -1122,36 +1135,43 @@ functionArgs returns [List<Term.Raw> a]
|
||||
( ',' tn=term { args.add(tn); } )*
|
||||
')' { $a = args; }
|
||||
;
|
||||
#endif
|
||||
|
||||
term returns [Term.Raw term]
|
||||
term returns [::shared_ptr<cql3::term::raw> term]
|
||||
: v=value { $term = v; }
|
||||
#if 0
|
||||
| f=functionName args=functionArgs { $term = new FunctionCall.Raw(f, args); }
|
||||
| '(' c=comparatorType ')' t=term { $term = new TypeCast(c, t); }
|
||||
#endif
|
||||
;
|
||||
|
||||
columnOperation[List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations]
|
||||
columnOperation[operations_type& operations]
|
||||
: key=cident columnOperationDifferentiator[operations, key]
|
||||
;
|
||||
|
||||
columnOperationDifferentiator[List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations, ColumnIdentifier.Raw key]
|
||||
columnOperationDifferentiator[operations_type& operations, ::shared_ptr<cql3::column_identifier::raw> key]
|
||||
: '=' normalColumnOperation[operations, key]
|
||||
#if 0
|
||||
| '[' k=term ']' specializedColumnOperation[operations, key, k]
|
||||
#endif
|
||||
;
|
||||
|
||||
normalColumnOperation[List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations, ColumnIdentifier.Raw key]
|
||||
normalColumnOperation[operations_type& operations, ::shared_ptr<cql3::column_identifier::raw> key]
|
||||
: t=term ('+' c=cident )?
|
||||
{
|
||||
if (c == null)
|
||||
{
|
||||
addRawUpdate(operations, key, new Operation.SetValue(t));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!key.equals(c))
|
||||
addRecognitionError("Only expressions of the form X = <value> + X are supported.");
|
||||
addRawUpdate(operations, key, new Operation.Prepend(t));
|
||||
if (!c) {
|
||||
add_raw_update(operations, key, ::make_shared<cql3::operation::set_value>(t));
|
||||
} else {
|
||||
throw std::runtime_error("not implemented");
|
||||
#if 0
|
||||
if (!key.equals(c)) {
|
||||
add_recognition_error("Only expressions of the form X = <value> + X are supported.");
|
||||
}
|
||||
add_raw_update(operations, key, ::make_shared<cql3::operation::prepend>(t));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
| c=cident sig=('+' | '-') t=term
|
||||
{
|
||||
if (!key.equals(c))
|
||||
@@ -1166,33 +1186,42 @@ normalColumnOperation[List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> oper
|
||||
addRecognitionError("Only expressions of the form X = X " + ($i.text.charAt(0) == '-' ? '-' : '+') + " <value> are supported.");
|
||||
addRawUpdate(operations, key, new Operation.Addition(Constants.Literal.integer($i.text)));
|
||||
}
|
||||
#endif
|
||||
;
|
||||
|
||||
#if 0
|
||||
specializedColumnOperation[List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations, ColumnIdentifier.Raw key, Term.Raw k]
|
||||
: '=' t=term
|
||||
{
|
||||
addRawUpdate(operations, key, new Operation.SetElement(k, t));
|
||||
}
|
||||
;
|
||||
#endif
|
||||
|
||||
columnCondition[List<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>> conditions]
|
||||
columnCondition[conditions_type& conditions]
|
||||
// Note: we'll reject duplicates later
|
||||
: key=cident
|
||||
( op=relationType t=term { conditions.add(Pair.create(key, ColumnCondition.Raw.simpleCondition(t, op))); }
|
||||
( op=relationType t=term { conditions.emplace_back(key, cql3::column_condition::raw::simple_condition(t, *op)); }
|
||||
| K_IN
|
||||
( values=singleColumnInValues { conditions.add(Pair.create(key, ColumnCondition.Raw.simpleInCondition(values))); }
|
||||
( values=singleColumnInValues { conditions.emplace_back(key, cql3::column_condition::raw::simple_in_condition(values)); }
|
||||
#if 0
|
||||
| marker=inMarker { conditions.add(Pair.create(key, ColumnCondition.Raw.simpleInCondition(marker))); }
|
||||
#endif
|
||||
)
|
||||
#if 0
|
||||
| '[' element=term ']'
|
||||
( op=relationType t=term { conditions.add(Pair.create(key, ColumnCondition.Raw.collectionCondition(t, element, op))); }
|
||||
( op=relationType t=term { conditions.add(Pair.create(key, ColumnCondition.Raw.collectionCondition(t, element, *op))); }
|
||||
| K_IN
|
||||
( values=singleColumnInValues { conditions.add(Pair.create(key, ColumnCondition.Raw.collectionInCondition(element, values))); }
|
||||
| marker=inMarker { conditions.add(Pair.create(key, ColumnCondition.Raw.collectionInCondition(element, marker))); }
|
||||
)
|
||||
)
|
||||
#endif
|
||||
)
|
||||
;
|
||||
|
||||
#if 0
|
||||
|
||||
properties[PropertyDefinitions props]
|
||||
: property[props] (K_AND property[props])*
|
||||
;
|
||||
@@ -1206,18 +1235,20 @@ propertyValue returns [String str]
|
||||
: c=constant { $str = c.getRawText(); }
|
||||
| u=unreserved_keyword { $str = u; }
|
||||
;
|
||||
#endif
|
||||
|
||||
relationType returns [Operator op]
|
||||
: '=' { $op = Operator.EQ; }
|
||||
| '<' { $op = Operator.LT; }
|
||||
| '<=' { $op = Operator.LTE; }
|
||||
| '>' { $op = Operator.GT; }
|
||||
| '>=' { $op = Operator.GTE; }
|
||||
| '!=' { $op = Operator.NEQ; }
|
||||
relationType returns [const cql3::operator_type* op = nullptr]
|
||||
: '=' { $op = &cql3::operator_type::EQ; }
|
||||
| '<' { $op = &cql3::operator_type::LT; }
|
||||
| '<=' { $op = &cql3::operator_type::LTE; }
|
||||
| '>' { $op = &cql3::operator_type::GT; }
|
||||
| '>=' { $op = &cql3::operator_type::GTE; }
|
||||
| '!=' { $op = &cql3::operator_type::NEQ; }
|
||||
;
|
||||
|
||||
relation[List<Relation> clauses]
|
||||
: name=cident type=relationType t=term { $clauses.add(new SingleColumnRelation(name, type, t)); }
|
||||
relation[std::vector<cql3::relation_ptr>& clauses]
|
||||
: name=cident type=relationType t=term { $clauses.emplace_back(::make_shared<cql3::single_column_relation>(std::move(name), *type, std::move(t))); }
|
||||
#if 0
|
||||
| K_TOKEN l=tupleOfIdentifiers type=relationType t=term
|
||||
{ $clauses.add(new TokenRelation(l, type, t)); }
|
||||
| name=cident K_IN marker=inMarker
|
||||
@@ -1247,9 +1278,11 @@ relation[List<Relation> clauses]
|
||||
| type=relationType tupleMarker=markerForTuple /* (a, b, c) >= ? */
|
||||
{ $clauses.add(MultiColumnRelation.createNonInRelation(ids, type, tupleMarker)); }
|
||||
)
|
||||
#endif
|
||||
| '(' relation[$clauses] ')'
|
||||
;
|
||||
|
||||
#if 0
|
||||
inMarker returns [AbstractMarker.INRaw marker]
|
||||
: QMARK { $marker = newINBindVariables(null); }
|
||||
| ':' name=ident { $marker = newINBindVariables(name); }
|
||||
@@ -1259,12 +1292,13 @@ tupleOfIdentifiers returns [List<ColumnIdentifier.Raw> ids]
|
||||
@init { $ids = new ArrayList<ColumnIdentifier.Raw>(); }
|
||||
: '(' n1=cident { $ids.add(n1); } (',' ni=cident { $ids.add(ni); })* ')'
|
||||
;
|
||||
#endif
|
||||
|
||||
singleColumnInValues returns [List<Term.Raw> terms]
|
||||
@init { $terms = new ArrayList<Term.Raw>(); }
|
||||
: '(' ( t1 = term { $terms.add(t1); } (',' ti=term { $terms.add(ti); })* )? ')'
|
||||
singleColumnInValues returns [std::vector<::shared_ptr<cql3::term::raw>> terms]
|
||||
: '(' ( t1 = term { $terms.push_back(t1); } (',' ti=term { $terms.push_back(ti); })* )? ')'
|
||||
;
|
||||
|
||||
#if 0
|
||||
tupleOfTupleLiterals returns [List<Tuples.Literal> literals]
|
||||
@init { $literals = new ArrayList<>(); }
|
||||
: '(' t1=tupleLiteral { $literals.add(t1); } (',' ti=tupleLiteral { $literals.add(ti); })* ')'
|
||||
|
||||
@@ -97,6 +97,7 @@ public:
|
||||
return ::make_shared<column_specification>(receiver->ks_name, receiver->cf_name, in_name, db::marshal::list_type::get_instance(receiver->type, false));
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ::shared_ptr<term> prepare(const sstring& keyspace, ::shared_ptr<column_specification> receiver) override;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -38,24 +38,24 @@ namespace cql3 {
|
||||
*/
|
||||
class attributes final {
|
||||
private:
|
||||
const std::experimental::optional<::shared_ptr<term>> _timestamp;
|
||||
const std::experimental::optional<::shared_ptr<term>> _time_to_live;
|
||||
const ::shared_ptr<term> _timestamp;
|
||||
const ::shared_ptr<term> _time_to_live;
|
||||
|
||||
public:
|
||||
static std::unique_ptr<attributes> none() {
|
||||
return std::unique_ptr<attributes>{new attributes{std::move(std::experimental::optional<::shared_ptr<term>>{}), std::move(std::experimental::optional<::shared_ptr<term>>{})}};
|
||||
return std::unique_ptr<attributes>{new attributes{{}, {}}};
|
||||
}
|
||||
|
||||
private:
|
||||
attributes(std::experimental::optional<::shared_ptr<term>>&& timestamp, std::experimental::optional<::shared_ptr<term>>&& time_to_live)
|
||||
attributes(::shared_ptr<term>&& timestamp, ::shared_ptr<term>&& time_to_live)
|
||||
: _timestamp{std::move(timestamp)}
|
||||
, _time_to_live{std::move(time_to_live)}
|
||||
{ }
|
||||
|
||||
public:
|
||||
bool uses_function(const sstring& ks_name, const sstring& function_name) const {
|
||||
return (_timestamp && _timestamp.value()->uses_function(ks_name, function_name))
|
||||
|| (_time_to_live && _time_to_live.value()->uses_function(ks_name, function_name));
|
||||
return (_timestamp && _timestamp->uses_function(ks_name, function_name))
|
||||
|| (_time_to_live && _time_to_live->uses_function(ks_name, function_name));
|
||||
}
|
||||
|
||||
bool is_timestamp_set() const {
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
return now;
|
||||
}
|
||||
|
||||
bytes_opt tval = _timestamp.value()->bind_and_get(options);
|
||||
bytes_opt tval = _timestamp->bind_and_get(options);
|
||||
if (!tval) {
|
||||
throw exceptions::invalid_request_exception("Invalid null value of timestamp");
|
||||
}
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
if (!_time_to_live)
|
||||
return 0;
|
||||
|
||||
bytes_opt tval = _time_to_live.value()->bind_and_get(options);
|
||||
bytes_opt tval = _time_to_live->bind_and_get(options);
|
||||
if (!tval) {
|
||||
throw exceptions::invalid_request_exception("Invalid null value of TTL");
|
||||
}
|
||||
@@ -114,10 +114,10 @@ public:
|
||||
|
||||
void collect_marker_specification(::shared_ptr<variable_specifications> bound_names) {
|
||||
if (_timestamp) {
|
||||
_timestamp.value()->collect_marker_specification(bound_names);
|
||||
_timestamp->collect_marker_specification(bound_names);
|
||||
}
|
||||
if (_time_to_live) {
|
||||
_time_to_live.value()->collect_marker_specification(bound_names);
|
||||
_time_to_live->collect_marker_specification(bound_names);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
if (!keep_case) {
|
||||
std::transform(ks.begin(), ks.end(), ks.begin(), ::tolower);
|
||||
}
|
||||
_ks_name = std::experimental::make_optional(ks);
|
||||
_ks_name = std::experimental::make_optional(std::move(ks));
|
||||
}
|
||||
|
||||
void set_column_family(sstring cf, bool keep_case) {
|
||||
|
||||
120
cql3/column_condition.cc
Normal file
120
cql3/column_condition.cc
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
#include "cql3/column_condition.hh"
|
||||
#include "unimplemented.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
bool
|
||||
column_condition::uses_function(const sstring& ks_name, const sstring& function_name) {
|
||||
if (bool(_collection_element) && _collection_element->uses_function(ks_name, function_name)) {
|
||||
return true;
|
||||
}
|
||||
if (bool(_value) && _value->uses_function(ks_name, function_name)) {
|
||||
return true;
|
||||
}
|
||||
if (!_in_values.empty()) {
|
||||
for (auto&& value : _in_values) {
|
||||
if (bool(value) && value->uses_function(ks_name, function_name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void column_condition::collect_marker_specificaton(::shared_ptr<variable_specifications> bound_names) {
|
||||
if (_collection_element) {
|
||||
_collection_element->collect_marker_specification(bound_names);
|
||||
}
|
||||
if (!_in_values.empty()) {
|
||||
for (auto&& value : _in_values) {
|
||||
value->collect_marker_specification(bound_names);
|
||||
}
|
||||
}
|
||||
_value->collect_marker_specification(bound_names);
|
||||
}
|
||||
|
||||
::shared_ptr<column_condition>
|
||||
column_condition::raw::prepare(const sstring& keyspace, column_definition& receiver) {
|
||||
if (receiver.type->is_counter()) {
|
||||
throw exceptions::invalid_request_exception("Conditions on counters are not supported");
|
||||
}
|
||||
|
||||
if (!_collection_element) {
|
||||
if (_op == operator_type::IN) {
|
||||
if (_in_values.empty()) { // ?
|
||||
return column_condition::in_condition(receiver, _in_marker->prepare(keyspace, receiver.column_specification));
|
||||
}
|
||||
|
||||
std::vector<::shared_ptr<term>> terms;
|
||||
for (auto&& value : _in_values) {
|
||||
terms.push_back(value->prepare(keyspace, receiver.column_specification));
|
||||
}
|
||||
return column_condition::in_condition(receiver, std::move(terms));
|
||||
} else {
|
||||
return column_condition::condition(receiver, _value->prepare(keyspace, receiver.column_specification), _op);
|
||||
}
|
||||
}
|
||||
|
||||
if (!receiver.type->is_collection()) {
|
||||
throw exceptions::invalid_request_exception(sprint("Invalid element access syntax for non-collection column %s", receiver.name_as_text()));
|
||||
}
|
||||
|
||||
unimplemented::collections();
|
||||
#if 0
|
||||
ColumnSpecification elementSpec, valueSpec;
|
||||
switch ((((CollectionType)receiver.type).kind))
|
||||
{
|
||||
case LIST:
|
||||
elementSpec = Lists.indexSpecOf(receiver);
|
||||
valueSpec = Lists.valueSpecOf(receiver);
|
||||
break;
|
||||
case MAP:
|
||||
elementSpec = Maps.keySpecOf(receiver);
|
||||
valueSpec = Maps.valueSpecOf(receiver);
|
||||
break;
|
||||
case SET:
|
||||
throw new InvalidRequestException(String.format("Invalid element access syntax for set column %s", receiver.name));
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
if (operator == Operator.IN)
|
||||
{
|
||||
if (inValues == null)
|
||||
return ColumnCondition.inCondition(receiver, collectionElement.prepare(keyspace, elementSpec), inMarker.prepare(keyspace, valueSpec));
|
||||
List<Term> terms = new ArrayList<>(inValues.size());
|
||||
for (Term.Raw value : inValues)
|
||||
terms.add(value.prepare(keyspace, valueSpec));
|
||||
return ColumnCondition.inCondition(receiver, collectionElement.prepare(keyspace, elementSpec), terms);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ColumnCondition.condition(receiver, collectionElement.prepare(keyspace, elementSpec), value.prepare(keyspace, valueSpec), operator);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,6 +25,10 @@
|
||||
#ifndef CQL3_COLUMN_CONDITION_HH
|
||||
#define CQL3_COLUMN_CONDITION_HH
|
||||
|
||||
#include "cql3/term.hh"
|
||||
#include "cql3/abstract_marker.hh"
|
||||
#include "cql3/operator.hh"
|
||||
|
||||
#if 0
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
@@ -53,74 +57,59 @@ namespace cql3 {
|
||||
class column_condition final {
|
||||
public:
|
||||
column_definition& column;
|
||||
|
||||
#if 0
|
||||
// For collection, when testing the equality of a specific element, null otherwise.
|
||||
private final Term collectionElement;
|
||||
|
||||
private final Term value; // a single value or a marker for a list of IN values
|
||||
private final List<Term> inValues;
|
||||
|
||||
public final Operator operator;
|
||||
|
||||
private ColumnCondition(ColumnDefinition column, Term collectionElement, Term value, List<Term> inValues, Operator op)
|
||||
private:
|
||||
// For collection, when testing the equality of a specific element, nullptr otherwise.
|
||||
::shared_ptr<term> _collection_element;
|
||||
::shared_ptr<term> _value;
|
||||
std::vector<::shared_ptr<term>> _in_values;
|
||||
const operator_type& _op;
|
||||
public:
|
||||
column_condition(column_definition& column, ::shared_ptr<term> collection_element,
|
||||
::shared_ptr<term> value, std::vector<::shared_ptr<term>> in_values, const operator_type& op)
|
||||
: column(column)
|
||||
, _collection_element(std::move(collection_element))
|
||||
, _value(std::move(value))
|
||||
, _in_values(std::move(in_values))
|
||||
, _op(op)
|
||||
{
|
||||
this.column = column;
|
||||
this.collectionElement = collectionElement;
|
||||
this.value = value;
|
||||
this.inValues = inValues;
|
||||
this.operator = op;
|
||||
|
||||
if (operator != Operator.IN)
|
||||
assert this.inValues == null;
|
||||
if (op != operator_type::IN) {
|
||||
assert(_in_values.empty());
|
||||
}
|
||||
}
|
||||
|
||||
public static ColumnCondition condition(ColumnDefinition column, Term value, Operator op)
|
||||
{
|
||||
return new ColumnCondition(column, null, value, null, op);
|
||||
static ::shared_ptr<column_condition> condition(column_definition& def, ::shared_ptr<term> value, const operator_type& op) {
|
||||
return ::make_shared<column_condition>(def, ::shared_ptr<term>{}, std::move(value), std::vector<::shared_ptr<term>>{}, op);
|
||||
}
|
||||
|
||||
public static ColumnCondition condition(ColumnDefinition column, Term collectionElement, Term value, Operator op)
|
||||
{
|
||||
return new ColumnCondition(column, collectionElement, value, null, op);
|
||||
static ::shared_ptr<column_condition> condition(column_definition& def, ::shared_ptr<term> collection_element,
|
||||
::shared_ptr<term> value, const operator_type& op) {
|
||||
return ::make_shared<column_condition>(def, std::move(collection_element), std::move(value),
|
||||
std::vector<::shared_ptr<term>>{}, op);
|
||||
}
|
||||
|
||||
public static ColumnCondition inCondition(ColumnDefinition column, List<Term> inValues)
|
||||
{
|
||||
return new ColumnCondition(column, null, null, inValues, Operator.IN);
|
||||
static ::shared_ptr<column_condition> in_condition(column_definition& def, std::vector<::shared_ptr<term>> in_values) {
|
||||
return ::make_shared<column_condition>(def, ::shared_ptr<term>{}, ::shared_ptr<term>{},
|
||||
std::move(in_values), operator_type::IN);
|
||||
}
|
||||
|
||||
public static ColumnCondition inCondition(ColumnDefinition column, Term collectionElement, List<Term> inValues)
|
||||
{
|
||||
return new ColumnCondition(column, collectionElement, null, inValues, Operator.IN);
|
||||
static ::shared_ptr<column_condition> in_condition(column_definition& def, ::shared_ptr<term> collection_element,
|
||||
std::vector<::shared_ptr<term>> in_values) {
|
||||
return ::make_shared<column_condition>(def, std::move(collection_element), ::shared_ptr<term>{},
|
||||
std::move(in_values), operator_type::IN);
|
||||
}
|
||||
|
||||
public static ColumnCondition inCondition(ColumnDefinition column, Term inMarker)
|
||||
{
|
||||
return new ColumnCondition(column, null, inMarker, null, Operator.IN);
|
||||
static ::shared_ptr<column_condition> in_condition(column_definition& def, ::shared_ptr<term> in_marker) {
|
||||
return ::make_shared<column_condition>(def, ::shared_ptr<term>{}, std::move(in_marker),
|
||||
std::vector<::shared_ptr<term>>{}, operator_type::IN);
|
||||
}
|
||||
|
||||
public static ColumnCondition inCondition(ColumnDefinition column, Term collectionElement, Term inMarker)
|
||||
{
|
||||
return new ColumnCondition(column, collectionElement, inMarker, null, Operator.IN);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool uses_function(const sstring& ks_name, const sstring& function_name) const {
|
||||
throw std::runtime_error("not implemented");
|
||||
#if 0
|
||||
if (collectionElement != null && collectionElement.usesFunction(ksName, functionName))
|
||||
return true;
|
||||
if (value != null && value.usesFunction(ksName, functionName))
|
||||
return true;
|
||||
if (inValues != null)
|
||||
for (Term value : inValues)
|
||||
if (value != null && value.usesFunction(ksName, functionName))
|
||||
return true;
|
||||
return false;
|
||||
#endif
|
||||
static ::shared_ptr<column_condition> in_condition(column_definition& def, ::shared_ptr<term> collection_element,
|
||||
::shared_ptr<term> in_marker) {
|
||||
return ::make_shared<column_condition>(def, std::move(collection_element), std::move(in_marker),
|
||||
std::vector<::shared_ptr<term>>{}, operator_type::IN);
|
||||
}
|
||||
|
||||
bool uses_function(const sstring& ks_name, const sstring& function_name);
|
||||
public:
|
||||
/**
|
||||
* Collects the column specification for the bind variables of this operation.
|
||||
@@ -128,23 +117,7 @@ public:
|
||||
* @param boundNames the list of column specification where to collect the
|
||||
* bind variables of this term in.
|
||||
*/
|
||||
void collect_marker_specificaton(::shared_ptr<variable_specifications> bound_names) {
|
||||
throw std::runtime_error("not found");
|
||||
#if 0
|
||||
if (collectionElement != null)
|
||||
collectionElement.collectMarkerSpecification(boundNames);
|
||||
|
||||
if ((operator == Operator.IN) && inValues != null)
|
||||
{
|
||||
for (Term value : inValues)
|
||||
value.collectMarkerSpecification(boundNames);
|
||||
}
|
||||
else
|
||||
{
|
||||
value.collectMarkerSpecification(boundNames);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void collect_marker_specificaton(::shared_ptr<variable_specifications> bound_names);
|
||||
|
||||
#if 0
|
||||
public ColumnCondition.Bound bind(QueryOptions options) throws InvalidRequestException
|
||||
@@ -725,120 +698,67 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
class raw {
|
||||
#if 0
|
||||
private final Term.Raw value;
|
||||
private final List<Term.Raw> inValues;
|
||||
private final AbstractMarker.INRaw inMarker;
|
||||
class raw final {
|
||||
private:
|
||||
::shared_ptr<term::raw> _value;
|
||||
std::vector<::shared_ptr<term::raw>> _in_values;
|
||||
::shared_ptr<abstract_marker::in_raw> _in_marker;
|
||||
|
||||
// Can be null, only used with the syntax "IF m[e] = ..." (in which case it's 'e')
|
||||
private final Term.Raw collectionElement;
|
||||
|
||||
private final Operator operator;
|
||||
|
||||
private Raw(Term.Raw value, List<Term.Raw> inValues, AbstractMarker.INRaw inMarker, Term.Raw collectionElement, Operator op)
|
||||
{
|
||||
this.value = value;
|
||||
this.inValues = inValues;
|
||||
this.inMarker = inMarker;
|
||||
this.collectionElement = collectionElement;
|
||||
this.operator = op;
|
||||
}
|
||||
// Can be nullptr, only used with the syntax "IF m[e] = ..." (in which case it's 'e')
|
||||
::shared_ptr<term::raw> _collection_element;
|
||||
const operator_type& _op;
|
||||
public:
|
||||
raw(::shared_ptr<term::raw> value,
|
||||
std::vector<::shared_ptr<term::raw>> in_values,
|
||||
::shared_ptr<abstract_marker::in_raw> in_marker,
|
||||
::shared_ptr<term::raw> collection_element,
|
||||
const operator_type& op)
|
||||
: _value(std::move(value))
|
||||
, _in_values(std::move(in_values))
|
||||
, _in_marker(std::move(in_marker))
|
||||
, _collection_element(std::move(collection_element))
|
||||
, _op(op)
|
||||
{ }
|
||||
|
||||
/** A condition on a column. For example: "IF col = 'foo'" */
|
||||
public static Raw simpleCondition(Term.Raw value, Operator op)
|
||||
{
|
||||
return new Raw(value, null, null, null, op);
|
||||
static ::shared_ptr<raw> simple_condition(::shared_ptr<term::raw> value, const operator_type& op) {
|
||||
return ::make_shared<raw>(std::move(value), std::vector<::shared_ptr<term::raw>>{},
|
||||
::shared_ptr<abstract_marker::in_raw>{}, ::shared_ptr<term::raw>{}, op);
|
||||
}
|
||||
|
||||
/** An IN condition on a column. For example: "IF col IN ('foo', 'bar', ...)" */
|
||||
public static Raw simpleInCondition(List<Term.Raw> inValues)
|
||||
{
|
||||
return new Raw(null, inValues, null, null, Operator.IN);
|
||||
static ::shared_ptr<raw> simple_in_condition(std::vector<::shared_ptr<term::raw>> in_values) {
|
||||
return ::make_shared<raw>(::shared_ptr<term::raw>{}, std::move(in_values),
|
||||
::shared_ptr<abstract_marker::in_raw>{}, ::shared_ptr<term::raw>{}, operator_type::IN);
|
||||
}
|
||||
|
||||
/** An IN condition on a column with a single marker. For example: "IF col IN ?" */
|
||||
public static Raw simpleInCondition(AbstractMarker.INRaw inMarker)
|
||||
{
|
||||
return new Raw(null, null, inMarker, null, Operator.IN);
|
||||
static ::shared_ptr<raw> simple_in_condition(::shared_ptr<abstract_marker::in_raw> in_marker) {
|
||||
return ::make_shared<raw>(::shared_ptr<term::raw>{}, std::vector<::shared_ptr<term::raw>>{},
|
||||
std::move(in_marker), ::shared_ptr<term::raw>{}, operator_type::IN);
|
||||
}
|
||||
|
||||
/** A condition on a collection element. For example: "IF col['key'] = 'foo'" */
|
||||
public static Raw collectionCondition(Term.Raw value, Term.Raw collectionElement, Operator op)
|
||||
{
|
||||
return new Raw(value, null, null, collectionElement, op);
|
||||
static ::shared_ptr<raw> collection_condition(::shared_ptr<term::raw> value, ::shared_ptr<term::raw> collection_element,
|
||||
const operator_type& op) {
|
||||
return ::make_shared<raw>(std::move(value), std::vector<::shared_ptr<term::raw>>{}, ::shared_ptr<abstract_marker::in_raw>{}, std::move(collection_element), operator_type::IN);
|
||||
}
|
||||
|
||||
/** An IN condition on a collection element. For example: "IF col['key'] IN ('foo', 'bar', ...)" */
|
||||
public static Raw collectionInCondition(Term.Raw collectionElement, List<Term.Raw> inValues)
|
||||
{
|
||||
return new Raw(null, inValues, null, collectionElement, Operator.IN);
|
||||
static ::shared_ptr<raw> collection_in_condition(::shared_ptr<term::raw> collection_element,
|
||||
std::vector<::shared_ptr<term::raw>> in_values) {
|
||||
return ::make_shared<raw>(::shared_ptr<term::raw>{}, std::move(in_values), ::shared_ptr<abstract_marker::in_raw>{},
|
||||
std::move(collection_element), operator_type::IN);
|
||||
}
|
||||
|
||||
/** An IN condition on a collection element with a single marker. For example: "IF col['key'] IN ?" */
|
||||
public static Raw collectionInCondition(Term.Raw collectionElement, AbstractMarker.INRaw inMarker)
|
||||
{
|
||||
return new Raw(null, null, inMarker, collectionElement, Operator.IN);
|
||||
static ::shared_ptr<raw> collectionInCondition(::shared_ptr<term::raw> collection_element,
|
||||
::shared_ptr<abstract_marker::in_raw> in_marker) {
|
||||
return ::make_shared<raw>(::shared_ptr<term::raw>{}, std::vector<::shared_ptr<term::raw>>{}, std::move(in_marker),
|
||||
std::move(collection_element), operator_type::IN);
|
||||
}
|
||||
#endif
|
||||
public:
|
||||
::shared_ptr<column_condition> prepare(const sstring& keyspace, column_definition& receiver) {
|
||||
throw std::runtime_error("not implemented");
|
||||
#if 0
|
||||
if (receiver.type instanceof CounterColumnType)
|
||||
throw new InvalidRequestException("Conditions on counters are not supported");
|
||||
|
||||
if (collectionElement == null)
|
||||
{
|
||||
if (operator == Operator.IN)
|
||||
{
|
||||
if (inValues == null)
|
||||
return ColumnCondition.inCondition(receiver, inMarker.prepare(keyspace, receiver));
|
||||
List<Term> terms = new ArrayList<>(inValues.size());
|
||||
for (Term.Raw value : inValues)
|
||||
terms.add(value.prepare(keyspace, receiver));
|
||||
return ColumnCondition.inCondition(receiver, terms);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ColumnCondition.condition(receiver, value.prepare(keyspace, receiver), operator);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(receiver.type.isCollection()))
|
||||
throw new InvalidRequestException(String.format("Invalid element access syntax for non-collection column %s", receiver.name));
|
||||
|
||||
ColumnSpecification elementSpec, valueSpec;
|
||||
switch ((((CollectionType)receiver.type).kind))
|
||||
{
|
||||
case LIST:
|
||||
elementSpec = Lists.indexSpecOf(receiver);
|
||||
valueSpec = Lists.valueSpecOf(receiver);
|
||||
break;
|
||||
case MAP:
|
||||
elementSpec = Maps.keySpecOf(receiver);
|
||||
valueSpec = Maps.valueSpecOf(receiver);
|
||||
break;
|
||||
case SET:
|
||||
throw new InvalidRequestException(String.format("Invalid element access syntax for set column %s", receiver.name));
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
if (operator == Operator.IN)
|
||||
{
|
||||
if (inValues == null)
|
||||
return ColumnCondition.inCondition(receiver, collectionElement.prepare(keyspace, elementSpec), inMarker.prepare(keyspace, valueSpec));
|
||||
List<Term> terms = new ArrayList<>(inValues.size());
|
||||
for (Term.Raw value : inValues)
|
||||
terms.add(value.prepare(keyspace, valueSpec));
|
||||
return ColumnCondition.inCondition(receiver, collectionElement.prepare(keyspace, elementSpec), terms);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ColumnCondition.condition(receiver, collectionElement.prepare(keyspace, elementSpec), value.prepare(keyspace, valueSpec), operator);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
::shared_ptr<column_condition> prepare(const sstring& keyspace, column_definition& receiver);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -162,16 +162,9 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@Override
|
||||
public final boolean equals(Object o)
|
||||
{
|
||||
if(!(o instanceof ColumnIdentifier.Raw))
|
||||
return false;
|
||||
ColumnIdentifier.Raw that = (ColumnIdentifier.Raw)o;
|
||||
return text.equals(that.text);
|
||||
bool operator==(const raw& other) const {
|
||||
return _text == other._text;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual sstring to_string() const {
|
||||
return _text;
|
||||
|
||||
139
cql3/constants.cc
Normal file
139
cql3/constants.cc
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
#include "cql3/constants.hh"
|
||||
#include "cql3/cql3_type.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
const ::shared_ptr<term::raw> constants::NULL_LITERAL = ::make_shared<constants::null_literal>();
|
||||
const ::shared_ptr<terminal> constants::null_literal::NULL_VALUE = ::make_shared<constants::null_literal::null_value>();
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream&out, constants::type t)
|
||||
{
|
||||
switch (t) {
|
||||
case constants::type::STRING: return out << "STRING";
|
||||
case constants::type::INTEGER: return out << "INTEGER";
|
||||
case constants::type::UUID: return out << "UUID";
|
||||
case constants::type::FLOAT: return out << "FLOAT";
|
||||
case constants::type::BOOLEAN: return out << "BOOLEAN";
|
||||
case constants::type::HEX: return out << "HEX";
|
||||
};
|
||||
assert(0);
|
||||
}
|
||||
|
||||
bytes
|
||||
constants::literal::parsed_value(::shared_ptr<abstract_type> validator)
|
||||
{
|
||||
try {
|
||||
if (_type == type::HEX && validator == bytes_type) {
|
||||
auto v = static_cast<sstring_view>(_text);
|
||||
v.remove_prefix(2);
|
||||
return validator->from_string(v);
|
||||
}
|
||||
if (validator->is_counter()) {
|
||||
return long_type->from_string(_text);
|
||||
}
|
||||
return validator->from_string(_text);
|
||||
} catch (const exceptions::marshal_exception& e) {
|
||||
throw exceptions::invalid_request_exception(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
assignment_testable::test_result
|
||||
constants::literal::test_assignment(const sstring& keyspace, ::shared_ptr<column_specification> receiver)
|
||||
{
|
||||
auto receiver_type = receiver->type->as_cql3_type();
|
||||
if (receiver_type->is_collection()) {
|
||||
return test_result::NOT_ASSIGNABLE;
|
||||
}
|
||||
if (!receiver_type->is_native()) {
|
||||
return test_result::WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
auto kind = static_cast<native_cql3_type*>(receiver_type.get())->get_kind();
|
||||
switch (_type) {
|
||||
case type::STRING:
|
||||
if (native_cql3_type::kind_enum_set::frozen<
|
||||
native_cql3_type::kind::ASCII,
|
||||
native_cql3_type::kind::TEXT,
|
||||
native_cql3_type::kind::INET,
|
||||
native_cql3_type::kind::VARCHAR,
|
||||
native_cql3_type::kind::TIMESTAMP>::contains(kind)) {
|
||||
return assignment_testable::test_result::WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
case type::INTEGER:
|
||||
if (native_cql3_type::kind_enum_set::frozen<
|
||||
native_cql3_type::kind::BIGINT,
|
||||
native_cql3_type::kind::COUNTER,
|
||||
native_cql3_type::kind::DECIMAL,
|
||||
native_cql3_type::kind::DOUBLE,
|
||||
native_cql3_type::kind::FLOAT,
|
||||
native_cql3_type::kind::INT,
|
||||
native_cql3_type::kind::TIMESTAMP,
|
||||
native_cql3_type::kind::VARINT>::contains(kind)) {
|
||||
return assignment_testable::test_result::WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
case type::UUID:
|
||||
if (native_cql3_type::kind_enum_set::frozen<
|
||||
native_cql3_type::kind::UUID,
|
||||
native_cql3_type::kind::TIMEUUID>::contains(kind)) {
|
||||
return assignment_testable::test_result::WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
case type::FLOAT:
|
||||
if (native_cql3_type::kind_enum_set::frozen<
|
||||
native_cql3_type::kind::DECIMAL,
|
||||
native_cql3_type::kind::DOUBLE,
|
||||
native_cql3_type::kind::FLOAT>::contains(kind)) {
|
||||
return assignment_testable::test_result::WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
case type::BOOLEAN:
|
||||
if (kind == native_cql3_type::kind_enum_set::prepare<native_cql3_type::kind::BOOLEAN>()) {
|
||||
return assignment_testable::test_result::WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
case type::HEX:
|
||||
if (kind == native_cql3_type::kind_enum_set::prepare<native_cql3_type::kind::BLOB>()) {
|
||||
return assignment_testable::test_result::WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return assignment_testable::test_result::NOT_ASSIGNABLE;
|
||||
}
|
||||
|
||||
::shared_ptr<term>
|
||||
constants::literal::prepare(const sstring& keyspace, ::shared_ptr<column_specification> receiver)
|
||||
{
|
||||
if (!is_assignable(test_assignment(keyspace, receiver))) {
|
||||
throw exceptions::invalid_request_exception(sprint("Invalid %s constant (%s) for \"%s\" of type %s",
|
||||
_type, _text, *receiver->name, receiver->type->as_cql3_type()->to_string()));
|
||||
}
|
||||
return ::make_shared<value>(std::experimental::make_optional(parsed_value(receiver->type)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "cql3/abstract_marker.hh"
|
||||
#include "cql3/update_parameters.hh"
|
||||
#include "cql3/operation.hh"
|
||||
#include "cql3/term.hh"
|
||||
#include "core/shared_ptr.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
@@ -66,47 +68,48 @@ public:
|
||||
STRING, INTEGER, UUID, FLOAT, BOOLEAN, HEX
|
||||
};
|
||||
|
||||
#if 0
|
||||
public static final Term.Raw NULL_LITERAL = new Term.Raw()
|
||||
{
|
||||
private final Term.Terminal NULL_VALUE = new Value(null)
|
||||
{
|
||||
@Override
|
||||
public Terminal bind(QueryOptions options)
|
||||
{
|
||||
// We return null because that makes life easier for collections
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* A constant value, i.e. a ByteBuffer.
|
||||
*/
|
||||
class value : public terminal {
|
||||
public:
|
||||
bytes_opt _bytes;
|
||||
value(bytes_opt bytes_) : _bytes(std::move(bytes_)) {}
|
||||
virtual bytes_opt get(const query_options& options) override { return _bytes; }
|
||||
virtual bytes_opt bind_and_get(const query_options& options) override { return _bytes; }
|
||||
virtual sstring to_string() const override { return to_hex(*_bytes); }
|
||||
};
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
class null_literal final : public term::raw {
|
||||
private:
|
||||
class null_value final : public value {
|
||||
public:
|
||||
null_value() : value({}) {}
|
||||
virtual ::shared_ptr<terminal> bind(const query_options& options) override { return {}; }
|
||||
virtual sstring to_string() const override { return "null"; }
|
||||
};
|
||||
|
||||
public Term prepare(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
|
||||
{
|
||||
if (!testAssignment(keyspace, receiver).isAssignable())
|
||||
throw new InvalidRequestException("Invalid null value for counter increment/decrement");
|
||||
|
||||
static const ::shared_ptr<terminal> NULL_VALUE;
|
||||
public:
|
||||
virtual ::shared_ptr<term> prepare(const sstring& keyspace, ::shared_ptr<column_specification> receiver) override {
|
||||
if (!is_assignable(test_assignment(keyspace, receiver))) {
|
||||
throw exceptions::invalid_request_exception("Invalid null value for counter increment/decrement");
|
||||
}
|
||||
return NULL_VALUE;
|
||||
}
|
||||
|
||||
public AssignmentTestable.TestResult testAssignment(String keyspace, ColumnSpecification receiver)
|
||||
{
|
||||
return receiver.type instanceof CounterColumnType
|
||||
? AssignmentTestable.TestResult.NOT_ASSIGNABLE
|
||||
: AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
|
||||
virtual assignment_testable::test_result test_assignment(const sstring& keyspace,
|
||||
::shared_ptr<column_specification> receiver) override {
|
||||
return receiver->type->is_counter()
|
||||
? assignment_testable::test_result::NOT_ASSIGNABLE
|
||||
: assignment_testable::test_result::WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
virtual sstring to_string() override {
|
||||
return "null";
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
static const ::shared_ptr<term::raw> NULL_LITERAL;
|
||||
|
||||
class literal : public term::raw {
|
||||
private:
|
||||
@@ -142,153 +145,21 @@ public:
|
||||
return ::make_shared<literal>(type::HEX, text);
|
||||
}
|
||||
|
||||
virtual ::shared_ptr<term> prepare(const sstring& keyspace, ::shared_ptr<column_specification> receiver) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
#if 0
|
||||
if (!testAssignment(keyspace, receiver).isAssignable())
|
||||
throw new InvalidRequestException(String.format("Invalid %s constant (%s) for \"%s\" of type %s", type, text, receiver.name, receiver.type.asCQL3Type()));
|
||||
|
||||
return new Value(parsedValue(receiver.type));
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
private ByteBuffer parsedValue(AbstractType<?> validator) throws InvalidRequestException
|
||||
{
|
||||
if (validator instanceof ReversedType<?>)
|
||||
validator = ((ReversedType<?>) validator).baseType;
|
||||
try
|
||||
{
|
||||
// BytesType doesn't want it's input prefixed by '0x'.
|
||||
if (type == Type.HEX && validator instanceof BytesType)
|
||||
return validator.fromString(text.substring(2));
|
||||
if (validator instanceof CounterColumnType)
|
||||
return LongType.instance.fromString(text);
|
||||
return validator.fromString(text);
|
||||
}
|
||||
catch (MarshalException e)
|
||||
{
|
||||
throw new InvalidRequestException(e.getMessage());
|
||||
}
|
||||
virtual ::shared_ptr<term> prepare(const sstring& keyspace, ::shared_ptr<column_specification> receiver);
|
||||
private:
|
||||
bytes parsed_value(::shared_ptr<abstract_type> validator);
|
||||
public:
|
||||
const sstring& get_raw_text() {
|
||||
return _text;
|
||||
}
|
||||
|
||||
public String getRawText()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual assignment_testable::test_result test_assignment(const sstring& keyspace, ::shared_ptr<column_specification> receiver) override {
|
||||
throw new std::runtime_error("not implemented");
|
||||
#if 0
|
||||
CQL3Type receiverType = receiver.type.asCQL3Type();
|
||||
if (receiverType.isCollection())
|
||||
return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
|
||||
|
||||
if (!(receiverType instanceof CQL3Type.Native))
|
||||
// Skip type validation for custom types. May or may not be a good idea
|
||||
return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
|
||||
|
||||
CQL3Type.Native nt = (CQL3Type.Native)receiverType;
|
||||
switch (type)
|
||||
{
|
||||
case STRING:
|
||||
switch (nt)
|
||||
{
|
||||
case ASCII:
|
||||
case TEXT:
|
||||
case INET:
|
||||
case VARCHAR:
|
||||
case TIMESTAMP:
|
||||
return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
case INTEGER:
|
||||
switch (nt)
|
||||
{
|
||||
case BIGINT:
|
||||
case COUNTER:
|
||||
case DECIMAL:
|
||||
case DOUBLE:
|
||||
case FLOAT:
|
||||
case INT:
|
||||
case TIMESTAMP:
|
||||
case VARINT:
|
||||
return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
case UUID:
|
||||
switch (nt)
|
||||
{
|
||||
case UUID:
|
||||
case TIMEUUID:
|
||||
return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
case FLOAT:
|
||||
switch (nt)
|
||||
{
|
||||
case DECIMAL:
|
||||
case DOUBLE:
|
||||
case FLOAT:
|
||||
return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
case BOOLEAN:
|
||||
switch (nt)
|
||||
{
|
||||
case BOOLEAN:
|
||||
return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
case HEX:
|
||||
switch (nt)
|
||||
{
|
||||
case BLOB:
|
||||
return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
|
||||
#endif
|
||||
}
|
||||
virtual assignment_testable::test_result test_assignment(const sstring& keyspace, ::shared_ptr<column_specification> receiver);
|
||||
|
||||
virtual sstring to_string() override {
|
||||
return _type == type::STRING ? sstring(sprint("'%s'", _text)) : _text;
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* A constant value, i.e. a ByteBuffer.
|
||||
*/
|
||||
public static class Value extends Term.Terminal
|
||||
{
|
||||
public final ByteBuffer bytes;
|
||||
|
||||
public Value(ByteBuffer bytes)
|
||||
{
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public ByteBuffer get(QueryOptions options)
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer bindAndGet(QueryOptions options)
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return ByteBufferUtil.bytesToHex(bytes);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
class marker : public abstract_marker {
|
||||
public:
|
||||
marker(int32_t bind_index, ::shared_ptr<column_specification> receiver)
|
||||
@@ -409,6 +280,8 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream&out, constants::type t);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::ascii = make("ascii", ascii_type);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::bigint = make("bigint", long_type);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::blob = make("blob", bytes_type);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::boolean = make("boolean", boolean_type);
|
||||
//thread_local shared_ptr<cql3_type> native_cql3_type::double = make("double", double_type);
|
||||
//thread_local shared_ptr<cql3_type> native_cql3_type::float = make("float", float_type);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::int_ = make("int", int32_type);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::text = make("text", utf8_type);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::timestamp = make("timestamp", timestamp_type);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::uuid = make("uuid", uuid_type);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::varchar = make("varchar", utf8_type);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::timeuuid = make("timeuuid", timeuuid_type);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::ascii = make("ascii", ascii_type, native_cql3_type::kind::ASCII);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::bigint = make("bigint", long_type, native_cql3_type::kind::BIGINT);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::blob = make("blob", bytes_type, native_cql3_type::kind::BLOB);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::boolean = make("boolean", boolean_type, native_cql3_type::kind::BOOLEAN);
|
||||
//thread_local shared_ptr<cql3_type> native_cql3_type::double = make("double", double_type, native_cql3_type::kind::DOUBLE);
|
||||
//thread_local shared_ptr<cql3_type> native_cql3_type::float = make("float", float_type, native_cql3_type::kind::FLOAT);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::int_ = make("int", int32_type, native_cql3_type::kind::INT);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::text = make("text", utf8_type, native_cql3_type::kind::TEXT);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::timestamp = make("timestamp", timestamp_type, native_cql3_type::kind::TIMESTAMP);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::uuid = make("uuid", uuid_type, native_cql3_type::kind::UUID);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::varchar = make("varchar", utf8_type, native_cql3_type::kind::TEXT);
|
||||
thread_local shared_ptr<cql3_type> native_cql3_type::timeuuid = make("timeuuid", timeuuid_type, native_cql3_type::kind::TIMEUUID);
|
||||
|
||||
const std::vector<shared_ptr<cql3_type>>&
|
||||
native_cql3_type::values() {
|
||||
|
||||
@@ -24,9 +24,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "database.hh"
|
||||
#include "types.hh"
|
||||
#include "exceptions/exceptions.hh"
|
||||
#include <iosfwd>
|
||||
#include "enum_set.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
@@ -37,13 +38,38 @@ public:
|
||||
cql3_type(sstring name, data_type type) : _name(std::move(name)), _type(std::move(type)) {}
|
||||
virtual ~cql3_type() {}
|
||||
virtual bool is_collection() const = 0;
|
||||
virtual bool is_native() const { return false; }
|
||||
data_type get_type() const { return _type; }
|
||||
sstring to_string() const { return _name; }
|
||||
};
|
||||
|
||||
class native_cql3_type : public cql3_type {
|
||||
static shared_ptr<cql3_type> make(sstring name, data_type type) {
|
||||
return make_shared<native_cql3_type>(std::move(name), std::move(type));
|
||||
public:
|
||||
enum class kind : int8_t {
|
||||
ASCII, BIGINT, BLOB, BOOLEAN, COUNTER, DECIMAL, DOUBLE, FLOAT, INT, INET, TEXT, TIMESTAMP, UUID, VARCHAR, VARINT, TIMEUUID
|
||||
};
|
||||
using kind_enum = super_enum<kind,
|
||||
kind::ASCII,
|
||||
kind::BIGINT,
|
||||
kind::BLOB,
|
||||
kind::BOOLEAN,
|
||||
kind::COUNTER,
|
||||
kind::DECIMAL,
|
||||
kind::DOUBLE,
|
||||
kind::FLOAT,
|
||||
kind::INET,
|
||||
kind::INT,
|
||||
kind::TEXT,
|
||||
kind::TIMESTAMP,
|
||||
kind::UUID,
|
||||
kind::VARCHAR,
|
||||
kind::VARINT,
|
||||
kind::TIMEUUID>;
|
||||
using kind_enum_set = enum_set<kind_enum>;
|
||||
private:
|
||||
kind_enum_set::prepared _kind;
|
||||
static shared_ptr<cql3_type> make(sstring name, data_type type, kind kind_) {
|
||||
return make_shared<native_cql3_type>(std::move(name), std::move(type), kind_);
|
||||
}
|
||||
public:
|
||||
static thread_local shared_ptr<cql3_type> ascii;
|
||||
@@ -67,10 +93,16 @@ public:
|
||||
#endif
|
||||
static const std::vector<shared_ptr<cql3_type>>& values();
|
||||
public:
|
||||
using cql3_type::cql3_type;
|
||||
native_cql3_type(sstring name, data_type type, kind kind_)
|
||||
: cql3_type(std::move(name), std::move(type)), _kind(kind_enum_set::prepare(kind_))
|
||||
{ }
|
||||
virtual bool is_collection() const override {
|
||||
return false;
|
||||
}
|
||||
virtual bool is_native() const override {
|
||||
return true;
|
||||
}
|
||||
kind_enum_set::prepared get_kind() const { return _kind; }
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
virtual ~cql_statement()
|
||||
{ }
|
||||
|
||||
virtual int get_bound_terms() = 0;
|
||||
virtual uint32_t get_bound_terms() = 0;
|
||||
|
||||
/**
|
||||
* Perform any access verification necessary for the statement.
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
* @param state the current query state
|
||||
* @param options options for this query (consistency, variables, pageSize, ...)
|
||||
*/
|
||||
virtual future<std::experimental::optional<transport::messages::result_message>>
|
||||
virtual future<::shared_ptr<transport::messages::result_message>>
|
||||
execute(service::storage_proxy& proxy, service::query_state& state, const query_options& options) = 0;
|
||||
|
||||
/**
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
*
|
||||
* @param state the current query state
|
||||
*/
|
||||
virtual future<std::experimental::optional<transport::messages::result_message>>
|
||||
virtual future<::shared_ptr<transport::messages::result_message>>
|
||||
execute_internal(database& db, service::query_state& state, const query_options& options) = 0;
|
||||
|
||||
virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const = 0;
|
||||
|
||||
@@ -15,41 +15,46 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.cassandra.cql3;
|
||||
|
||||
import java.util.LinkedList;
|
||||
/*
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
import org.antlr.runtime.BaseRecognizer;
|
||||
import org.antlr.runtime.Parser;
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
import org.antlr.runtime.Token;
|
||||
import org.antlr.runtime.TokenStream;
|
||||
import org.apache.cassandra.exceptions.SyntaxException;
|
||||
#pragma once
|
||||
|
||||
#include "cql3/error_listener.hh"
|
||||
#include "exceptions/exceptions.hh"
|
||||
#include "types.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
/**
|
||||
* <code>ErrorListener</code> that collect and enhance the errors send by the CQL lexer and parser.
|
||||
*/
|
||||
public final class ErrorCollector implements ErrorListener
|
||||
{
|
||||
template<typename Recognizer>
|
||||
class error_collector : public error_listener<Recognizer> {
|
||||
/**
|
||||
* The offset of the first token of the snippet.
|
||||
*/
|
||||
private static final int FIRST_TOKEN_OFFSET = 10;
|
||||
static const int32_t FIRST_TOKEN_OFFSET = 10;
|
||||
|
||||
/**
|
||||
* The offset of the last token of the snippet.
|
||||
*/
|
||||
private static final int LAST_TOKEN_OFFSET = 2;
|
||||
static const int32_t LAST_TOKEN_OFFSET = 2;
|
||||
|
||||
/**
|
||||
* The CQL query.
|
||||
*/
|
||||
private final String query;
|
||||
const sstring_view _query;
|
||||
|
||||
/**
|
||||
* The error messages.
|
||||
*/
|
||||
private final LinkedList<String> errorMsgs = new LinkedList<>();
|
||||
std::vector<sstring> _error_msgs;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new <code>ErrorCollector</code> instance to collect the syntax errors associated to the specified CQL
|
||||
@@ -57,17 +62,12 @@ public final class ErrorCollector implements ErrorListener
|
||||
*
|
||||
* @param query the CQL query that will be parsed
|
||||
*/
|
||||
public ErrorCollector(String query)
|
||||
{
|
||||
this.query = query;
|
||||
}
|
||||
error_collector(const sstring_view& query) : _query(query) {}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void syntaxError(BaseRecognizer recognizer, String[] tokenNames, RecognitionException e)
|
||||
{
|
||||
virtual void syntax_error(Recognizer& recognizer, const std::vector<sstring>& token_names) override {
|
||||
// FIXME: stub
|
||||
syntax_error(recognizer, "Parsing failed, detailed description construction not implemented yet");
|
||||
#if 0
|
||||
String hdr = recognizer.getErrorHeader(e);
|
||||
String msg = recognizer.getErrorMessage(e, tokenNames);
|
||||
|
||||
@@ -79,15 +79,11 @@ public final class ErrorCollector implements ErrorListener
|
||||
appendQuerySnippet((Parser) recognizer, builder);
|
||||
|
||||
errorMsgs.add(builder.toString());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void syntaxError(BaseRecognizer recognizer, String errorMsg)
|
||||
{
|
||||
errorMsgs.add(errorMsg);
|
||||
virtual void syntax_error(Recognizer& recognizer, const sstring& msg) override {
|
||||
_error_msgs.emplace_back(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,12 +91,14 @@ public final class ErrorCollector implements ErrorListener
|
||||
*
|
||||
* @throws SyntaxException the syntax error.
|
||||
*/
|
||||
public void throwFirstSyntaxError() throws SyntaxException
|
||||
{
|
||||
if (!errorMsgs.isEmpty())
|
||||
throw new SyntaxException(errorMsgs.getFirst());
|
||||
void throw_first_syntax_error() {
|
||||
if (!_error_msgs.empty()) {
|
||||
throw exceptions::syntax_exception(_error_msgs[0]);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/**
|
||||
* Appends a query snippet to the message to help the user to understand the problem.
|
||||
*
|
||||
@@ -287,4 +285,7 @@ public final class ErrorCollector implements ErrorListener
|
||||
{
|
||||
return Math.max(0, index - FIRST_TOKEN_OFFSET);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
@@ -15,16 +15,26 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.cassandra.cql3;
|
||||
|
||||
import org.antlr.runtime.BaseRecognizer;
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
/*
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "core/sstring.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
/**
|
||||
* Listener used to collect the syntax errors emitted by the Lexer and Parser.
|
||||
*/
|
||||
public interface ErrorListener
|
||||
{
|
||||
template<typename RecognizerType>
|
||||
class error_listener {
|
||||
public:
|
||||
/**
|
||||
* Invoked when a syntax error occurs.
|
||||
*
|
||||
@@ -32,7 +42,7 @@ public interface ErrorListener
|
||||
* @param tokenNames the token names
|
||||
* @param e the exception
|
||||
*/
|
||||
void syntaxError(BaseRecognizer recognizer, String[] tokenNames, RecognitionException e);
|
||||
virtual void syntax_error(RecognizerType& recognizer, const std::vector<sstring>& token_names) = 0;
|
||||
|
||||
/**
|
||||
* Invoked when a syntax error with a specified message occurs.
|
||||
@@ -40,5 +50,7 @@ public interface ErrorListener
|
||||
* @param recognizer the parser or lexer that emitted the error
|
||||
* @param errorMsg the error message
|
||||
*/
|
||||
void syntaxError(BaseRecognizer recognizer, String errorMsg);
|
||||
virtual void syntax_error(RecognizerType& recognizer, const sstring& error_msg) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
const operator_type& reverse() const { return _reverse; }
|
||||
sstring to_string() const { return _text; }
|
||||
bool operator==(const operator_type& other) const { return this == &other; }
|
||||
|
||||
bool operator!=(const operator_type& other) const { return this != &other; }
|
||||
#if 0
|
||||
|
||||
/**
|
||||
|
||||
34
cql3/query_options.cc
Normal file
34
cql3/query_options.cc
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
#include "query_options.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
const query_options::specific_options query_options::specific_options::DEFAULT{-1, {}, {}, api::missing_timestamp};
|
||||
|
||||
default_query_options query_options::DEFAULT{db::consistency_level::ONE,
|
||||
{}, false, query_options::specific_options::DEFAULT, 3};
|
||||
|
||||
}
|
||||
@@ -28,21 +28,34 @@
|
||||
#include "database.hh"
|
||||
#include "db/consistency_level.hh"
|
||||
#include "service/query_state.hh"
|
||||
#include "service/pager/paging_state.hh"
|
||||
#include "cql3/column_specification.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
class default_query_options;
|
||||
|
||||
/**
|
||||
* Options for a query.
|
||||
*/
|
||||
class query_options {
|
||||
public:
|
||||
#if 0
|
||||
public static final QueryOptions DEFAULT = new DefaultQueryOptions(ConsistencyLevel.ONE,
|
||||
Collections.<ByteBuffer>emptyList(),
|
||||
false,
|
||||
SpecificOptions.DEFAULT,
|
||||
3);
|
||||
// Options that are likely to not be present in most queries
|
||||
struct specific_options final {
|
||||
static const specific_options DEFAULT;
|
||||
|
||||
const int page_size;
|
||||
const ::shared_ptr<service::pager::paging_state> state;
|
||||
const std::experimental::optional<db::consistency_level> serial_consistency;
|
||||
const api::timestamp_type timestamp;
|
||||
};
|
||||
|
||||
// It can't be const because of prepare()
|
||||
static default_query_options DEFAULT;
|
||||
|
||||
virtual ~query_options() {}
|
||||
|
||||
#if 0
|
||||
public static final CBCodec<QueryOptions> codec = new Codec();
|
||||
|
||||
public static QueryOptions fromProtocolV1(ConsistencyLevel consistency, List<ByteBuffer> values)
|
||||
@@ -76,39 +89,26 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual db::consistency_level get_consistency() const = 0;
|
||||
|
||||
#if 0
|
||||
public abstract List<ByteBuffer> getValues();
|
||||
public abstract boolean skipMetadata();
|
||||
virtual const std::vector<bytes_opt>& get_values() const = 0;
|
||||
virtual bool skip_metadata() const = 0;
|
||||
|
||||
/** The pageSize for this query. Will be <= 0 if not relevant for the query. */
|
||||
public int getPageSize()
|
||||
{
|
||||
return getSpecificOptions().pageSize;
|
||||
}
|
||||
int32_t get_page_size() const { return get_specific_options().page_size; }
|
||||
|
||||
/** The paging state for this query, or null if not relevant. */
|
||||
public PagingState getPagingState()
|
||||
{
|
||||
return getSpecificOptions().state;
|
||||
::shared_ptr<service::pager::paging_state> get_paging_state() const {
|
||||
return get_specific_options().state;
|
||||
}
|
||||
|
||||
/** Serial consistency for conditional updates. */
|
||||
public ConsistencyLevel getSerialConsistency()
|
||||
{
|
||||
return getSpecificOptions().serialConsistency;
|
||||
std::experimental::optional<db::consistency_level> get_serial_consistency() const {
|
||||
return get_specific_options().serial_consistency;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
api::timestamp_type get_timestamp(const service::query_state& state) const {
|
||||
throw std::runtime_error("NOT IMPLEMENTED");
|
||||
#if 0
|
||||
api::timestamp_type get_timestamp(service::query_state& state) const {
|
||||
auto tstamp = get_specific_options().timestamp;
|
||||
return tstamp != api::missing_timestamp ? tstamp : state.get_timestamp();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,60 +117,14 @@ public:
|
||||
*/
|
||||
virtual int get_protocol_version() const = 0;
|
||||
|
||||
#if 0
|
||||
// Mainly for the sake of BatchQueryOptions
|
||||
abstract SpecificOptions getSpecificOptions();
|
||||
virtual const specific_options& get_specific_options() const = 0;
|
||||
|
||||
public QueryOptions prepare(List<ColumnSpecification> specs)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
static class DefaultQueryOptions extends QueryOptions
|
||||
{
|
||||
private final ConsistencyLevel consistency;
|
||||
private final List<ByteBuffer> values;
|
||||
private final boolean skipMetadata;
|
||||
|
||||
private final SpecificOptions options;
|
||||
|
||||
private final transient int protocolVersion;
|
||||
|
||||
DefaultQueryOptions(ConsistencyLevel consistency, List<ByteBuffer> values, boolean skipMetadata, SpecificOptions options, int protocolVersion)
|
||||
{
|
||||
this.consistency = consistency;
|
||||
this.values = values;
|
||||
this.skipMetadata = skipMetadata;
|
||||
this.options = options;
|
||||
this.protocolVersion = protocolVersion;
|
||||
}
|
||||
|
||||
public ConsistencyLevel getConsistency()
|
||||
{
|
||||
return consistency;
|
||||
}
|
||||
|
||||
public List<ByteBuffer> getValues()
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
public boolean skipMetadata()
|
||||
{
|
||||
return skipMetadata;
|
||||
}
|
||||
|
||||
public int getProtocolVersion()
|
||||
{
|
||||
return protocolVersion;
|
||||
}
|
||||
|
||||
SpecificOptions getSpecificOptions()
|
||||
{
|
||||
return options;
|
||||
}
|
||||
query_options& prepare(const std::vector<::shared_ptr<column_specification>>& specs) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static abstract class QueryOptionsWrapper extends QueryOptions
|
||||
{
|
||||
protected final QueryOptions wrapped;
|
||||
@@ -247,25 +201,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Options that are likely to not be present in most queries
|
||||
static class SpecificOptions
|
||||
{
|
||||
private static final SpecificOptions DEFAULT = new SpecificOptions(-1, null, null, Long.MIN_VALUE);
|
||||
|
||||
private final int pageSize;
|
||||
private final PagingState state;
|
||||
private final ConsistencyLevel serialConsistency;
|
||||
private final long timestamp;
|
||||
|
||||
private SpecificOptions(int pageSize, PagingState state, ConsistencyLevel serialConsistency, long timestamp)
|
||||
{
|
||||
this.pageSize = pageSize;
|
||||
this.state = state;
|
||||
this.serialConsistency = serialConsistency == null ? ConsistencyLevel.SERIAL : serialConsistency;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Codec implements CBCodec<QueryOptions>
|
||||
{
|
||||
private static enum Flag
|
||||
@@ -418,6 +353,39 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
class default_query_options : public query_options {
|
||||
private:
|
||||
const db::consistency_level _consistency;
|
||||
const std::vector<bytes_opt> _values;
|
||||
const bool _skip_metadata;
|
||||
const specific_options _options;
|
||||
const int32_t _protocol_version; // transient
|
||||
public:
|
||||
default_query_options(db::consistency_level consistency, std::vector<bytes_opt> values, bool skip_metadata, specific_options options,
|
||||
int protocol_version)
|
||||
: _consistency(consistency)
|
||||
, _values(std::move(values))
|
||||
, _skip_metadata(skip_metadata)
|
||||
, _options(std::move(options))
|
||||
, _protocol_version(protocol_version)
|
||||
{ }
|
||||
virtual db::consistency_level get_consistency() const override {
|
||||
return _consistency;
|
||||
}
|
||||
virtual const std::vector<bytes_opt>& get_values() const override {
|
||||
return _values;
|
||||
}
|
||||
virtual bool skip_metadata() const override {
|
||||
return _skip_metadata;
|
||||
}
|
||||
virtual int32_t get_protocol_version() const override {
|
||||
return _protocol_version;
|
||||
}
|
||||
virtual const specific_options& get_specific_options() const override {
|
||||
return _options;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
125
cql3/query_processor.cc
Normal file
125
cql3/query_processor.cc
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
#include "cql3/query_processor.hh"
|
||||
#include "cql3/CqlParser.hpp"
|
||||
#include "cql3/error_collector.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
using namespace statements;
|
||||
using namespace transport::messages;
|
||||
|
||||
thread_local logging::logger log("query_processor");
|
||||
|
||||
future<::shared_ptr<result_message>>
|
||||
query_processor::process(const sstring_view& query_string, service::query_state& query_state, query_options& options)
|
||||
{
|
||||
std::unique_ptr<parsed_statement::prepared> p = get_statement(query_string, query_state.get_client_state());
|
||||
options.prepare(p->bound_names);
|
||||
auto cql_statement = p->statement;
|
||||
if (cql_statement->get_bound_terms() != options.get_values().size()) {
|
||||
throw exceptions::invalid_request_exception("Invalid amount of bind variables");
|
||||
}
|
||||
|
||||
unimplemented::metrics();
|
||||
#if 0
|
||||
if (!queryState.getClientState().isInternal)
|
||||
metrics.regularStatementsExecuted.inc();
|
||||
#endif
|
||||
return process_statement(std::move(cql_statement), query_state, options);
|
||||
}
|
||||
|
||||
future<::shared_ptr<result_message>>
|
||||
query_processor::process_statement(::shared_ptr<cql_statement> statement, service::query_state& query_state,
|
||||
const query_options& options)
|
||||
{
|
||||
#if 0
|
||||
logger.trace("Process {} @CL.{}", statement, options.getConsistency());
|
||||
#endif
|
||||
auto& client_state = query_state.get_client_state();
|
||||
statement->check_access(client_state);
|
||||
statement->validate(client_state);
|
||||
|
||||
return statement->execute(_proxy, query_state, options)
|
||||
.then([] (auto msg) {
|
||||
if (msg) {
|
||||
return make_ready_future<::shared_ptr<result_message>>(std::move(msg));
|
||||
}
|
||||
return make_ready_future<::shared_ptr<result_message>>(
|
||||
::make_shared<result_message::void_message>());
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_ptr<parsed_statement::prepared>
|
||||
query_processor::get_statement(const sstring_view& query, service::client_state& client_state)
|
||||
{
|
||||
#if 0
|
||||
Tracing.trace("Parsing {}", queryStr);
|
||||
#endif
|
||||
::shared_ptr<parsed_statement> statement = parse_statement(query);
|
||||
|
||||
// Set keyspace for statement that require login
|
||||
auto cf_stmt = dynamic_pointer_cast<cf_statement>(statement);
|
||||
if (cf_stmt) {
|
||||
cf_stmt->prepare_keyspace(client_state);
|
||||
}
|
||||
#if 0
|
||||
Tracing.trace("Preparing statement");
|
||||
#endif
|
||||
return statement->prepare(_db);
|
||||
}
|
||||
|
||||
::shared_ptr<parsed_statement>
|
||||
query_processor::parse_statement(const sstring_view& query)
|
||||
{
|
||||
try {
|
||||
error_collector<cql3_parser::CqlLexer::RecognizerType> lexer_error_collector(query);
|
||||
error_collector<cql3_parser::CqlParser::RecognizerType> parser_error_collector(query);
|
||||
cql3_parser::CqlLexer::InputStreamType input{reinterpret_cast<const ANTLR_UINT8*>(query.begin()), ANTLR_ENC_UTF8, static_cast<ANTLR_UINT32>(query.size()), nullptr};
|
||||
cql3_parser::CqlLexer lexer{&input};
|
||||
lexer.set_error_listener(lexer_error_collector);
|
||||
cql3_parser::CqlParser::TokenStreamType tstream(ANTLR_SIZE_HINT, lexer.get_tokSource());
|
||||
cql3_parser::CqlParser parser{&tstream};
|
||||
parser.set_error_listener(parser_error_collector);
|
||||
|
||||
auto statement = parser.query();
|
||||
|
||||
lexer_error_collector.throw_first_syntax_error();
|
||||
parser_error_collector.throw_first_syntax_error();
|
||||
|
||||
if (!statement) {
|
||||
// TODO: We should plug into get_rec()->displayRecognitionError and call error_collector from there
|
||||
throw exceptions::syntax_exception("Parsing failed");
|
||||
};
|
||||
return std::move(statement);
|
||||
} catch (const exceptions::recognition_exception& e) {
|
||||
throw exceptions::syntax_exception(sprint("Invalid or malformed CQL query string: %s", e.what()));
|
||||
} catch (const std::exception& e) {
|
||||
log.error("The statement: {} could not be parsed: {}", query, e.what());
|
||||
throw exceptions::syntax_exception(sprint("Failed parsing statement: [%s] reason: %s", query, e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,56 +15,32 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.cassandra.cql3;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
/*
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
|
||||
import com.googlecode.concurrentlinkedhashmap.EntryWeigher;
|
||||
import com.googlecode.concurrentlinkedhashmap.EvictionListener;
|
||||
#include <experimental/string_view>
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
#include "core/shared_ptr.hh"
|
||||
#include "exceptions/exceptions.hh"
|
||||
#include "cql3/query_options.hh"
|
||||
#include "cql3/statements/cf_statement.hh"
|
||||
#include "service/query_state.hh"
|
||||
#include "log.hh"
|
||||
|
||||
import org.apache.cassandra.concurrent.ScheduledExecutors;
|
||||
import org.apache.cassandra.cql3.functions.*;
|
||||
namespace cql3 {
|
||||
|
||||
import org.apache.cassandra.cql3.statements.*;
|
||||
import org.apache.cassandra.db.*;
|
||||
import org.apache.cassandra.db.composites.CType;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
import org.apache.cassandra.db.composites.Composite;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.exceptions.RequestExecutionException;
|
||||
import org.apache.cassandra.exceptions.RequestValidationException;
|
||||
import org.apache.cassandra.exceptions.SyntaxException;
|
||||
import org.apache.cassandra.metrics.CQLMetrics;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.IMigrationListener;
|
||||
import org.apache.cassandra.service.MigrationManager;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.service.pager.QueryPager;
|
||||
import org.apache.cassandra.service.pager.QueryPagers;
|
||||
import org.apache.cassandra.thrift.ThriftClientState;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.MD5Digest;
|
||||
import org.apache.cassandra.utils.SemanticVersion;
|
||||
import org.github.jamm.MemoryMeter;
|
||||
class query_processor {
|
||||
private:
|
||||
service::storage_proxy& _proxy;
|
||||
database& _db;
|
||||
public:
|
||||
query_processor(service::storage_proxy& proxy, database& db) : _proxy(proxy), _db(db) {}
|
||||
|
||||
public class QueryProcessor implements QueryHandler
|
||||
{
|
||||
#if 0
|
||||
public static final SemanticVersion CQL_VERSION = new SemanticVersion("3.2.0");
|
||||
|
||||
public static final QueryProcessor instance = new QueryProcessor();
|
||||
@@ -227,40 +203,23 @@ public class QueryProcessor implements QueryHandler
|
||||
serializedSize,
|
||||
Cell.MAX_NAME_LENGTH));
|
||||
}
|
||||
#endif
|
||||
public:
|
||||
future<::shared_ptr<transport::messages::result_message>> process_statement(::shared_ptr<cql_statement> statement,
|
||||
service::query_state& query_state, const query_options& options);
|
||||
|
||||
public ResultMessage processStatement(CQLStatement statement, QueryState queryState, QueryOptions options)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
logger.trace("Process {} @CL.{}", statement, options.getConsistency());
|
||||
ClientState clientState = queryState.getClientState();
|
||||
statement.checkAccess(clientState);
|
||||
statement.validate(clientState);
|
||||
|
||||
ResultMessage result = statement.execute(queryState, options);
|
||||
return result == null ? new ResultMessage.Void() : result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
public static ResultMessage process(String queryString, ConsistencyLevel cl, QueryState queryState)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
return instance.process(queryString, queryState, QueryOptions.forInternalCalls(cl, Collections.<ByteBuffer>emptyList()));
|
||||
}
|
||||
#endif
|
||||
|
||||
public ResultMessage process(String queryString, QueryState queryState, QueryOptions options)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
ParsedStatement.Prepared p = getStatement(queryString, queryState.getClientState());
|
||||
options.prepare(p.boundNames);
|
||||
CQLStatement prepared = p.statement;
|
||||
if (prepared.getBoundTerms() != options.getValues().size())
|
||||
throw new InvalidRequestException("Invalid amount of bind variables");
|
||||
|
||||
if (!queryState.getClientState().isInternal)
|
||||
metrics.regularStatementsExecuted.inc();
|
||||
|
||||
return processStatement(prepared, queryState, options);
|
||||
}
|
||||
future<::shared_ptr<transport::messages::result_message>> process(const std::experimental::string_view& query_string,
|
||||
service::query_state& query_state, query_options& options);
|
||||
|
||||
#if 0
|
||||
public static ParsedStatement.Prepared parseStatement(String queryStr, QueryState queryState) throws RequestValidationException
|
||||
{
|
||||
return getStatement(queryStr, queryState.getClientState());
|
||||
@@ -503,58 +462,14 @@ public class QueryProcessor implements QueryHandler
|
||||
batch.validate(clientState);
|
||||
return batch.execute(queryState, options);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static ParsedStatement.Prepared getStatement(String queryStr, ClientState clientState)
|
||||
throws RequestValidationException
|
||||
{
|
||||
Tracing.trace("Parsing {}", queryStr);
|
||||
ParsedStatement statement = parseStatement(queryStr);
|
||||
|
||||
// Set keyspace for statement that require login
|
||||
if (statement instanceof CFStatement)
|
||||
((CFStatement)statement).prepareKeyspace(clientState);
|
||||
|
||||
Tracing.trace("Preparing statement");
|
||||
return statement.prepare();
|
||||
}
|
||||
|
||||
public static ParsedStatement parseStatement(String queryStr) throws SyntaxException
|
||||
{
|
||||
try
|
||||
{
|
||||
// Lexer and parser
|
||||
ErrorCollector errorCollector = new ErrorCollector(queryStr);
|
||||
CharStream stream = new ANTLRStringStream(queryStr);
|
||||
CqlLexer lexer = new CqlLexer(stream);
|
||||
lexer.addErrorListener(errorCollector);
|
||||
|
||||
TokenStream tokenStream = new CommonTokenStream(lexer);
|
||||
CqlParser parser = new CqlParser(tokenStream);
|
||||
parser.addErrorListener(errorCollector);
|
||||
|
||||
// Parse the query string to a statement instance
|
||||
ParsedStatement statement = parser.query();
|
||||
|
||||
// The errorCollector has queue up any errors that the lexer and parser may have encountered
|
||||
// along the way, if necessary, we turn the last error into exceptions here.
|
||||
errorCollector.throwFirstSyntaxError();
|
||||
|
||||
return statement;
|
||||
}
|
||||
catch (RuntimeException re)
|
||||
{
|
||||
logger.error(String.format("The statement: [%s] could not be parsed.", queryStr), re);
|
||||
throw new SyntaxException(String.format("Failed parsing statement: [%s] reason: %s %s",
|
||||
queryStr,
|
||||
re.getClass().getSimpleName(),
|
||||
re.getMessage()));
|
||||
}
|
||||
catch (RecognitionException e)
|
||||
{
|
||||
throw new SyntaxException("Invalid or malformed CQL query string: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
public:
|
||||
std::unique_ptr<statements::parsed_statement::prepared> get_statement(const std::experimental::string_view& query,
|
||||
service::client_state& client_state);
|
||||
static ::shared_ptr<statements::parsed_statement> parse_statement(const std::experimental::string_view& query);
|
||||
|
||||
#if 0
|
||||
private static long measure(Object key)
|
||||
{
|
||||
return meter.measureDeep(key);
|
||||
@@ -659,4 +574,7 @@ public class QueryProcessor implements QueryHandler
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
@@ -38,7 +38,7 @@ protected:
|
||||
const operator_type& _relation_type;
|
||||
public:
|
||||
relation(const operator_type& relation_type)
|
||||
: _relation_type(_relation_type) {
|
||||
: _relation_type(relation_type) {
|
||||
}
|
||||
virtual ~relation() {}
|
||||
|
||||
@@ -106,8 +106,7 @@ public:
|
||||
* @return <code>true</code> if the operator of this relation is a <code>Slice</code>, <code>false</code> otherwise.
|
||||
*/
|
||||
virtual bool is_slice() final {
|
||||
return _relation_type == operator_type::
|
||||
GT
|
||||
return _relation_type == operator_type::GT
|
||||
|| _relation_type == operator_type::GTE
|
||||
|| _relation_type == operator_type::LTE
|
||||
|| _relation_type ==
|
||||
|
||||
149
cql3/single_column_relation.cc
Normal file
149
cql3/single_column_relation.cc
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
#include "cql3/single_column_relation.hh"
|
||||
#include "cql3/restrictions/single_column_restriction.hh"
|
||||
#include "unimplemented.hh"
|
||||
|
||||
using namespace cql3::restrictions;
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
::shared_ptr<term>
|
||||
single_column_relation::to_term(std::vector<::shared_ptr<column_specification>> receivers,
|
||||
::shared_ptr<term::raw> raw,
|
||||
const sstring& keyspace,
|
||||
::shared_ptr<variable_specifications> bound_names)
|
||||
{
|
||||
// TODO: optimize vector away, accept single column_specification
|
||||
assert(receivers.size() == 1);
|
||||
auto term = raw->prepare(keyspace, receivers[0]);
|
||||
term->collect_marker_specification(bound_names);
|
||||
return term;
|
||||
}
|
||||
|
||||
::shared_ptr<restrictions::restriction>
|
||||
single_column_relation::new_EQ_restriction(schema_ptr schema, ::shared_ptr<variable_specifications> bound_names)
|
||||
{
|
||||
column_definition& column_def = to_column_definition(schema, _entity);
|
||||
if (!_map_key) {
|
||||
auto term = to_term(to_receivers(schema, column_def), _value, schema->ks_name, bound_names);
|
||||
return ::make_shared<single_column_restriction::EQ>(column_def, std::move(term));
|
||||
}
|
||||
unimplemented::collections();
|
||||
#if 0
|
||||
List<? extends ColumnSpecification> receivers = toReceivers(schema, columnDef);
|
||||
Term entryKey = toTerm(Collections.singletonList(receivers.get(0)), map_key, schema.ksName, bound_names);
|
||||
Term entryValue = toTerm(Collections.singletonList(receivers.get(1)), value, schema.ksName, bound_names);
|
||||
return new SingleColumnRestriction.Contains(columnDef, entryKey, entryValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<::shared_ptr<column_specification>>
|
||||
single_column_relation::to_receivers(schema_ptr schema, column_definition& column_def)
|
||||
{
|
||||
auto receiver = column_def.column_specification;
|
||||
|
||||
if (column_def.is_compact_value()) {
|
||||
throw exceptions::invalid_request_exception(sprint(
|
||||
"Predicates on the non-primary-key column (%s) of a COMPACT table are not yet supported", column_def.name_as_text()));
|
||||
}
|
||||
|
||||
if (is_IN()) {
|
||||
// For partition keys we only support IN for the last name so far
|
||||
if (column_def.is_partition_key() && !schema->is_last_partition_key(column_def)) {
|
||||
throw exceptions::invalid_request_exception(sprint(
|
||||
"Partition KEY part %s cannot be restricted by IN relation (only the last part of the partition key can)",
|
||||
column_def.name_as_text()));
|
||||
}
|
||||
|
||||
// We only allow IN on the row key and the clustering key so far, never on non-PK columns, and this even if
|
||||
// there's an index
|
||||
// Note: for backward compatibility reason, we conside a IN of 1 value the same as a EQ, so we let that
|
||||
// slide.
|
||||
if (!column_def.is_primary_key() && !can_have_only_one_value()) {
|
||||
throw exceptions::invalid_request_exception(sprint(
|
||||
"IN predicates on non-primary-key columns (%s) is not yet supported", column_def.name_as_text()));
|
||||
}
|
||||
} else if (is_slice()) {
|
||||
// Non EQ relation is not supported without token(), even if we have a 2ndary index (since even those
|
||||
// are ordered by partitioner).
|
||||
// Note: In theory we could allow it for 2ndary index queries with ALLOW FILTERING, but that would
|
||||
// probably require some special casing
|
||||
// Note bis: This is also why we don't bother handling the 'tuple' notation of #4851 for keys. If we
|
||||
// lift the limitation for 2ndary
|
||||
// index with filtering, we'll need to handle it though.
|
||||
if (column_def.is_partition_key()) {
|
||||
throw exceptions::invalid_request_exception(
|
||||
"Only EQ and IN relation are supported on the partition key (unless you use the token() function)");
|
||||
}
|
||||
}
|
||||
|
||||
if (is_contains_key()) {
|
||||
unimplemented::collections();
|
||||
#if 0
|
||||
if (!(receiver.type instanceof MapType)) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot use CONTAINS KEY on non-map column %s", receiver.name_as_text()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_map_key) {
|
||||
unimplemented::collections();
|
||||
#if 0
|
||||
checkFalse(receiver.type instanceof ListType, "Indexes on list entries (%s[index] = value) are not currently supported.", receiver.name);
|
||||
checkTrue(receiver.type instanceof MapType, "Column %s cannot be used as a map", receiver.name);
|
||||
checkTrue(receiver.type.isMultiCell(), "Map-entry equality predicates on frozen map column %s are not supported", receiver.name);
|
||||
checkTrue(isEQ(), "Only EQ relations are supported on map entries");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (receiver->type->is_collection()) {
|
||||
unimplemented::collections();
|
||||
#if 0
|
||||
// We don't support relations against entire collections (unless they're frozen), like "numbers = {1, 2, 3}"
|
||||
checkFalse(receiver.type.isMultiCell() && !isLegalRelationForNonFrozenCollection(),
|
||||
"Collection column '%s' (%s) cannot be restricted by a '%s' relation",
|
||||
receiver.name,
|
||||
receiver.type.asCQL3Type(),
|
||||
get_operator());
|
||||
|
||||
if (isContainsKey() || isContains())
|
||||
{
|
||||
receiver = makeCollectionReceiver(receiver, isContainsKey());
|
||||
}
|
||||
else if (receiver.type.isMultiCell() && map_key != null && isEQ())
|
||||
{
|
||||
List<ColumnSpecification> receivers = new ArrayList<>(2);
|
||||
receivers.add(makeCollectionReceiver(receiver, true));
|
||||
receivers.add(makeCollectionReceiver(receiver, false));
|
||||
return receivers;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return {std::move(receiver)};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
* @param value the value being compared.
|
||||
*/
|
||||
single_column_relation(::shared_ptr<column_identifier::raw> entity, const operator_type& type, ::shared_ptr<term::raw> value)
|
||||
: single_column_relation(std::move(entity), {}, std::move(type), std::move(value))
|
||||
: single_column_relation(std::move(entity), {}, type, std::move(value))
|
||||
{ }
|
||||
|
||||
#if 0
|
||||
@@ -95,22 +95,12 @@ public:
|
||||
::shared_ptr<term::raw> get_map_key() {
|
||||
return _map_key;
|
||||
}
|
||||
protected:
|
||||
::shared_ptr<term> to_term(std::vector<::shared_ptr<column_specification>> receivers,
|
||||
::shared_ptr<term::raw> raw, const sstring& keyspace,
|
||||
::shared_ptr<variable_specifications> bound_names);
|
||||
|
||||
#if 0
|
||||
@Override
|
||||
protected Term toTerm(List<? extends ColumnSpecification> receivers,
|
||||
Raw raw,
|
||||
String keyspace,
|
||||
::shared_ptr<variable_specifications> boundNames)
|
||||
throws InvalidRequestException
|
||||
{
|
||||
assert receivers.size() == 1;
|
||||
|
||||
Term term = raw.prepare(keyspace, receivers.get(0));
|
||||
term.collectMarkerSpecification(boundNames);
|
||||
return term;
|
||||
}
|
||||
|
||||
public SingleColumnRelation withNonStrictOperator()
|
||||
{
|
||||
switch (relationType)
|
||||
@@ -137,21 +127,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual ::shared_ptr<restrictions::restriction> new_EQ_restriction(schema_ptr schema,
|
||||
::shared_ptr<variable_specifications> bound_names) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
#if 0
|
||||
ColumnDefinition columnDef = toColumnDefinition(schema, entity);
|
||||
if (map_key == null)
|
||||
{
|
||||
Term term = toTerm(toReceivers(schema, columnDef), value, schema.ksName, bound_names);
|
||||
return new SingleColumnRestriction.EQ(columnDef, term);
|
||||
}
|
||||
List<? extends ColumnSpecification> receivers = toReceivers(schema, columnDef);
|
||||
Term entryKey = toTerm(Collections.singletonList(receivers.get(0)), map_key, schema.ksName, bound_names);
|
||||
Term entryValue = toTerm(Collections.singletonList(receivers.get(1)), value, schema.ksName, bound_names);
|
||||
return new SingleColumnRestriction.Contains(columnDef, entryKey, entryValue);
|
||||
#endif
|
||||
}
|
||||
::shared_ptr<variable_specifications> bound_names);
|
||||
|
||||
virtual ::shared_ptr<restrictions::restriction> new_IN_restriction(schema_ptr schema,
|
||||
::shared_ptr<variable_specifications> bound_names) override {
|
||||
@@ -192,84 +168,18 @@ protected:
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
private:
|
||||
/**
|
||||
* Returns the receivers for this relation.
|
||||
*
|
||||
* @param schema the Column Family meta data
|
||||
* @param columnDef the column definition
|
||||
* @param column_def the column definition
|
||||
* @return the receivers for the specified relation.
|
||||
* @throws InvalidRequestException if the relation is invalid
|
||||
* @throws exceptions::invalid_request_exception if the relation is invalid
|
||||
*/
|
||||
private List<? extends ColumnSpecification> toReceivers(schema_ptr schema, ColumnDefinition columnDef) throws InvalidRequestException
|
||||
{
|
||||
ColumnSpecification receiver = columnDef;
|
||||
|
||||
checkFalse(columnDef.isCompactValue(),
|
||||
"Predicates on the non-primary-key column (%s) of a COMPACT table are not yet supported",
|
||||
columnDef.name);
|
||||
|
||||
if (isIN())
|
||||
{
|
||||
// For partition keys we only support IN for the last name so far
|
||||
checkFalse(columnDef.isPartitionKey() && !isLastPartitionKey(schema, columnDef),
|
||||
"Partition KEY part %s cannot be restricted by IN relation (only the last part of the partition key can)",
|
||||
columnDef.name);
|
||||
|
||||
// We only allow IN on the row key and the clustering key so far, never on non-PK columns, and this even if
|
||||
// there's an index
|
||||
// Note: for backward compatibility reason, we conside a IN of 1 value the same as a EQ, so we let that
|
||||
// slide.
|
||||
checkFalse(!columnDef.isPrimaryKeyColumn() && !canHaveOnlyOneValue(),
|
||||
"IN predicates on non-primary-key columns (%s) is not yet supported", columnDef.name);
|
||||
}
|
||||
else if (isSlice())
|
||||
{
|
||||
// Non EQ relation is not supported without token(), even if we have a 2ndary index (since even those
|
||||
// are ordered by partitioner).
|
||||
// Note: In theory we could allow it for 2ndary index queries with ALLOW FILTERING, but that would
|
||||
// probably require some special casing
|
||||
// Note bis: This is also why we don't bother handling the 'tuple' notation of #4851 for keys. If we
|
||||
// lift the limitation for 2ndary
|
||||
// index with filtering, we'll need to handle it though.
|
||||
checkFalse(columnDef.isPartitionKey(), "Only EQ and IN relation are supported on the partition key (unless you use the token() function)");
|
||||
}
|
||||
|
||||
checkFalse(isContainsKey() && !(receiver.type instanceof MapType), "Cannot use CONTAINS KEY on non-map column %s", receiver.name);
|
||||
|
||||
if (map_key != null)
|
||||
{
|
||||
checkFalse(receiver.type instanceof ListType, "Indexes on list entries (%s[index] = value) are not currently supported.", receiver.name);
|
||||
checkTrue(receiver.type instanceof MapType, "Column %s cannot be used as a map", receiver.name);
|
||||
checkTrue(receiver.type.isMultiCell(), "Map-entry equality predicates on frozen map column %s are not supported", receiver.name);
|
||||
checkTrue(isEQ(), "Only EQ relations are supported on map entries");
|
||||
}
|
||||
|
||||
if (receiver.type.isCollection())
|
||||
{
|
||||
// We don't support relations against entire collections (unless they're frozen), like "numbers = {1, 2, 3}"
|
||||
checkFalse(receiver.type.isMultiCell() && !isLegalRelationForNonFrozenCollection(),
|
||||
"Collection column '%s' (%s) cannot be restricted by a '%s' relation",
|
||||
receiver.name,
|
||||
receiver.type.asCQL3Type(),
|
||||
get_operator());
|
||||
|
||||
if (isContainsKey() || isContains())
|
||||
{
|
||||
receiver = makeCollectionReceiver(receiver, isContainsKey());
|
||||
}
|
||||
else if (receiver.type.isMultiCell() && map_key != null && isEQ())
|
||||
{
|
||||
List<ColumnSpecification> receivers = new ArrayList<>(2);
|
||||
receivers.add(makeCollectionReceiver(receiver, true));
|
||||
receivers.add(makeCollectionReceiver(receiver, false));
|
||||
return receivers;
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.singletonList(receiver);
|
||||
}
|
||||
std::vector<::shared_ptr<column_specification>> to_receivers(schema_ptr schema, column_definition& column_def);
|
||||
|
||||
#if 0
|
||||
private ColumnSpecification makeCollectionReceiver(ColumnSpecification receiver, bool forKey)
|
||||
{
|
||||
return ((CollectionType<?>) receiver.type).makeCollectionReceiver(receiver, forKey);
|
||||
@@ -284,25 +194,12 @@ protected:
|
||||
{
|
||||
return map_key != null && isEQ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified column is the last column of the partition key.
|
||||
*
|
||||
* @param schema the column family meta data
|
||||
* @param columnDef the column to check
|
||||
* @return <code>true</code> if the specified column is the last column of the partition key, <code>false</code>
|
||||
* otherwise.
|
||||
*/
|
||||
private static bool isLastPartitionKey(schema_ptr schema, ColumnDefinition columnDef)
|
||||
{
|
||||
return columnDef.position() == schema.partitionKeyColumns().size() - 1;
|
||||
}
|
||||
|
||||
private bool canHaveOnlyOneValue()
|
||||
{
|
||||
return isEQ() || (isIN() && in_values != null && in_values.size() == 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool can_have_only_one_value() {
|
||||
return is_EQ() || (is_IN() && _in_values.size() == 1);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -39,9 +39,9 @@ namespace statements {
|
||||
*/
|
||||
class cf_statement : public parsed_statement {
|
||||
protected:
|
||||
std::experimental::optional<cf_name> _cf_name;
|
||||
::shared_ptr<cf_name> _cf_name;
|
||||
|
||||
cf_statement(std::experimental::optional<cf_name>&& cf_name)
|
||||
cf_statement(::shared_ptr<cf_name>&& cf_name)
|
||||
: _cf_name(std::move(cf_name))
|
||||
{ }
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ import org.apache.cassandra.utils.Pair;
|
||||
*/
|
||||
class delete_statement : public modification_statement {
|
||||
public:
|
||||
delete_statement(statement_type type, int32_t bound_terms, schema_ptr s, std::unique_ptr<attributes> attrs)
|
||||
delete_statement(statement_type type, uint32_t bound_terms, schema_ptr s, std::unique_ptr<attributes> attrs)
|
||||
: modification_statement{type, bound_terms, std::move(s), std::move(attrs)}
|
||||
{ }
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ modification_statement::read_required_rows(
|
||||
const column_definition*
|
||||
modification_statement::get_first_empty_key() {
|
||||
for (auto& def : s->clustering_key) {
|
||||
if (!_processed_keys[&def]) {
|
||||
if (_processed_keys.find(&def) == _processed_keys.end()) {
|
||||
return &def;
|
||||
}
|
||||
}
|
||||
@@ -154,8 +154,8 @@ modification_statement::create_clustering_prefix_internal(const query_options& o
|
||||
const column_definition* first_empty_key = nullptr;
|
||||
|
||||
for (auto& def : s->clustering_key) {
|
||||
auto r = _processed_keys[&def];
|
||||
if (!r) {
|
||||
auto i = _processed_keys.find(&def);
|
||||
if (i == _processed_keys.end()) {
|
||||
first_empty_key = &def;
|
||||
// Tomek: Origin had "&& s->comparator->is_composite()" in the condition below.
|
||||
// Comparator is a thrift concept, not CQL concept, and we want to avoid
|
||||
@@ -172,7 +172,7 @@ modification_statement::create_clustering_prefix_internal(const query_options& o
|
||||
} else if (first_empty_key) {
|
||||
throw exceptions::invalid_request_exception(sprint("Missing PRIMARY KEY part %s since %s is set", first_empty_key->name_as_text(), def.name_as_text()));
|
||||
} else {
|
||||
auto values = r->values(options);
|
||||
auto values = i->second->values(options);
|
||||
assert(values.size() == 1);
|
||||
auto val = values[0];
|
||||
if (!val) {
|
||||
@@ -230,12 +230,12 @@ modification_statement::build_partition_keys(const query_options& options) {
|
||||
auto remaining = s->partition_key.size();
|
||||
|
||||
for (auto& def : s->partition_key) {
|
||||
auto r = _processed_keys[&def];
|
||||
if (!r) {
|
||||
auto i = _processed_keys.find(&def);
|
||||
if (i == _processed_keys.end()) {
|
||||
throw exceptions::invalid_request_exception(sprint("Missing mandatory PRIMARY KEY part %s", def.name_as_text()));
|
||||
}
|
||||
|
||||
auto values = r->values(options);
|
||||
auto values = i->second->values(options);
|
||||
|
||||
if (remaining == 1) {
|
||||
if (values.size() == 1) {
|
||||
@@ -277,7 +277,7 @@ modification_statement::build_partition_keys(const query_options& options) {
|
||||
return result;
|
||||
}
|
||||
|
||||
future<std::experimental::optional<transport::messages::result_message>>
|
||||
future<::shared_ptr<transport::messages::result_message>>
|
||||
modification_statement::execute(service::storage_proxy& proxy, service::query_state& qs, const query_options& options) {
|
||||
if (has_conditions() && options.get_protocol_version() == 1) {
|
||||
throw new exceptions::invalid_request_exception("Conditional updates are not supported by the protocol version in use. You need to upgrade to a driver using the native protocol v2.");
|
||||
@@ -288,8 +288,8 @@ modification_statement::execute(service::storage_proxy& proxy, service::query_st
|
||||
}
|
||||
|
||||
return execute_without_condition(proxy, qs, options).then([] {
|
||||
return make_ready_future<std::experimental::optional<transport::messages::result_message>>(
|
||||
std::experimental::optional<transport::messages::result_message>{});
|
||||
return make_ready_future<::shared_ptr<transport::messages::result_message>>(
|
||||
::shared_ptr<transport::messages::result_message>{});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ modification_statement::execute_without_condition(service::storage_proxy& proxy,
|
||||
});
|
||||
}
|
||||
|
||||
future<std::experimental::optional<transport::messages::result_message>>
|
||||
future<::shared_ptr<transport::messages::result_message>>
|
||||
modification_statement::execute_with_condition(service::storage_proxy& proxy, service::query_state& qs, const query_options& options) {
|
||||
unimplemented::lwt();
|
||||
#if 0
|
||||
@@ -378,7 +378,7 @@ modification_statement::process_where_clause(std::vector<relation_ptr> where_cla
|
||||
case column_definition::column_kind::CLUSTERING:
|
||||
if (rel->is_EQ() || (def->is_partition_key() && rel->is_IN())) {
|
||||
add_key_values(*def, rel->to_restriction(s, std::move(names)));
|
||||
return;
|
||||
break;
|
||||
}
|
||||
throw exceptions::invalid_request_exception(sprint("Invalid operator %s for PRIMARY KEY part %s", rel->get_operator(), def->name_as_text()));
|
||||
default:
|
||||
@@ -446,6 +446,21 @@ modification_statement::parsed::prepare(database& db, ::shared_ptr<variable_spec
|
||||
return stmt;
|
||||
}
|
||||
|
||||
void
|
||||
modification_statement::validate(const service::client_state& state) {
|
||||
if (has_conditions() && attrs->is_timestamp_set()) {
|
||||
throw exceptions::invalid_request_exception("Cannot provide custom timestamp for conditional updates");
|
||||
}
|
||||
|
||||
if (is_counter() && attrs->is_timestamp_set()) {
|
||||
throw exceptions::invalid_request_exception("Cannot provide custom timestamp for counter updates");
|
||||
}
|
||||
|
||||
if (is_counter() && attrs->is_time_to_live_set()) {
|
||||
throw exceptions::invalid_request_exception("Cannot provide custom TTL for counter updates");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
const statement_type type;
|
||||
|
||||
private:
|
||||
const int32_t _bound_terms;
|
||||
const uint32_t _bound_terms;
|
||||
|
||||
public:
|
||||
const schema_ptr s;
|
||||
@@ -122,7 +122,7 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
modification_statement(statement_type type_, int32_t bound_terms, schema_ptr schema_, std::unique_ptr<attributes> attrs_)
|
||||
modification_statement(statement_type type_, uint32_t bound_terms, schema_ptr schema_, std::unique_ptr<attributes> attrs_)
|
||||
: type{type_}
|
||||
, _bound_terms{bound_terms}
|
||||
, s{schema_}
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
|
||||
virtual void add_update_for_key(mutation& m, const clustering_prefix& prefix, const update_parameters& params) = 0;
|
||||
|
||||
virtual int get_bound_terms() override {
|
||||
virtual uint32_t get_bound_terms() override {
|
||||
return _bound_terms;
|
||||
}
|
||||
|
||||
@@ -191,6 +191,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void check_access(const service::client_state& state) override {
|
||||
unimplemented::permissions();
|
||||
#if 0
|
||||
state.hasColumnFamilyAccess(keyspace(), columnFamily(), Permission.MODIFY);
|
||||
|
||||
@@ -198,22 +199,9 @@ public:
|
||||
if (hasConditions())
|
||||
state.hasColumnFamilyAccess(keyspace(), columnFamily(), Permission.SELECT);
|
||||
#endif
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
|
||||
virtual void validate(const service::client_state& state) override {
|
||||
#if 0
|
||||
if (hasConditions() && attrs.isTimestampSet())
|
||||
throw new InvalidRequestException("Cannot provide custom timestamp for conditional updates");
|
||||
|
||||
if (isCounter() && attrs.isTimestampSet())
|
||||
throw new InvalidRequestException("Cannot provide custom timestamp for counter updates");
|
||||
|
||||
if (isCounter() && attrs.isTimeToLiveSet())
|
||||
throw new InvalidRequestException("Cannot provide custom TTL for counter updates");
|
||||
#endif
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual void validate(const service::client_state& state);
|
||||
|
||||
void add_operation(::shared_ptr<operation> op) {
|
||||
if (op->column.is_static()) {
|
||||
@@ -295,10 +283,10 @@ public:
|
||||
return _if_not_exists || _if_exists || !_column_conditions.empty() || !_static_conditions.empty();
|
||||
}
|
||||
|
||||
virtual future<std::experimental::optional<transport::messages::result_message>>
|
||||
virtual future<::shared_ptr<transport::messages::result_message>>
|
||||
execute(service::storage_proxy& proxy, service::query_state& qs, const query_options& options) override;
|
||||
|
||||
virtual future<std::experimental::optional<transport::messages::result_message>>
|
||||
virtual future<::shared_ptr<transport::messages::result_message>>
|
||||
execute_internal(database& db, service::query_state& qs, const query_options& options) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
@@ -307,7 +295,7 @@ private:
|
||||
future<>
|
||||
execute_without_condition(service::storage_proxy& proxy, service::query_state& qs, const query_options& options);
|
||||
|
||||
future<std::experimental::optional<transport::messages::result_message>>
|
||||
future<::shared_ptr<transport::messages::result_message>>
|
||||
execute_with_condition(service::storage_proxy& proxy, service::query_state& qs, const query_options& options);
|
||||
|
||||
#if 0
|
||||
@@ -466,7 +454,7 @@ public:
|
||||
const bool _if_not_exists;
|
||||
const bool _if_exists;
|
||||
protected:
|
||||
parsed(std::experimental::optional<cf_name> name, ::shared_ptr<attributes::raw> attrs, const conditions_vector& conditions, bool if_not_exists, bool if_exists)
|
||||
parsed(::shared_ptr<cf_name> name, ::shared_ptr<attributes::raw> attrs, const conditions_vector& conditions, bool if_not_exists, bool if_exists)
|
||||
: cf_statement{std::move(name)}
|
||||
, _attrs{attrs}
|
||||
, _conditions{conditions}
|
||||
|
||||
@@ -45,17 +45,17 @@ private:
|
||||
|
||||
protected:
|
||||
schema_altering_statement()
|
||||
: cf_statement{std::experimental::optional<cf_name>{}}
|
||||
: cf_statement{::shared_ptr<cf_name>{}}
|
||||
, _is_column_family_level{false}
|
||||
{ }
|
||||
|
||||
schema_altering_statement(std::experimental::optional<cf_name>&& name)
|
||||
schema_altering_statement(::shared_ptr<cf_name>&& name)
|
||||
: cf_statement{std::move(name)}
|
||||
, _is_column_family_level{true}
|
||||
{ }
|
||||
|
||||
|
||||
virtual int get_bound_terms() override {
|
||||
virtual uint32_t get_bound_terms() override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ protected:
|
||||
public abstract boolean announceMigration(boolean isLocalOnly) throws RequestValidationException;
|
||||
#endif
|
||||
|
||||
virtual future<std::experimental::optional<transport::messages::result_message>>
|
||||
virtual future<::shared_ptr<transport::messages::result_message>>
|
||||
execute(service::storage_proxy& proxy, service::query_state& state, const query_options& options) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
#if 0
|
||||
@@ -96,7 +96,7 @@ protected:
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual future<std::experimental::optional<transport::messages::result_message>>
|
||||
virtual future<::shared_ptr<transport::messages::result_message>>
|
||||
execute_internal(database& db, service::query_state& state, const query_options& options) override {
|
||||
throw std::runtime_error("unsupported operation");
|
||||
#if 0
|
||||
|
||||
@@ -36,11 +36,11 @@ namespace statements {
|
||||
|
||||
class truncate_statement : public cf_statement, public virtual cql_statement, public ::enable_shared_from_this<truncate_statement> {
|
||||
public:
|
||||
truncate_statement(std::experimental::optional<cf_name>&& name)
|
||||
truncate_statement(::shared_ptr<cf_name>&& name)
|
||||
: cf_statement{std::move(name)}
|
||||
{ }
|
||||
|
||||
virtual int get_bound_terms() override {
|
||||
virtual uint32_t get_bound_terms() override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual future<std::experimental::optional<transport::messages::result_message>>
|
||||
virtual future<::shared_ptr<transport::messages::result_message>>
|
||||
execute(service::storage_proxy& proxy, service::query_state& state, const query_options& options) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
#if 0
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual future<std::experimental::optional<transport::messages::result_message>>
|
||||
virtual future<::shared_ptr<transport::messages::result_message>>
|
||||
execute_internal(database& db, service::query_state& state, const query_options& options) override {
|
||||
throw std::runtime_error("unsupported operation");
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
private static final Constants.Value EMPTY = new Constants.Value(ByteBufferUtil.EMPTY_BYTE_BUFFER);
|
||||
#endif
|
||||
|
||||
update_statement(statement_type type, int32_t bound_terms, schema_ptr s, std::unique_ptr<attributes> attrs)
|
||||
update_statement(statement_type type, uint32_t bound_terms, schema_ptr s, std::unique_ptr<attributes> attrs)
|
||||
: modification_statement{type, bound_terms, std::move(s), std::move(attrs)}
|
||||
{ }
|
||||
|
||||
@@ -75,7 +75,7 @@ private:
|
||||
}
|
||||
|
||||
virtual void add_update_for_key(mutation& m, const clustering_prefix& prefix, const update_parameters& params) override;
|
||||
|
||||
public:
|
||||
class parsed_insert : public modification_statement::parsed {
|
||||
private:
|
||||
const std::vector<::shared_ptr<column_identifier::raw>> _column_names;
|
||||
@@ -89,14 +89,14 @@ private:
|
||||
* @param columnValues list of column values (corresponds to names)
|
||||
* @param attrs additional attributes for statement (CL, timestamp, timeToLive)
|
||||
*/
|
||||
parsed_insert(std::experimental::optional<cf_name> name,
|
||||
parsed_insert(::shared_ptr<cf_name> name,
|
||||
::shared_ptr<attributes::raw> attrs,
|
||||
std::vector<::shared_ptr<column_identifier::raw>> column_names,
|
||||
std::vector<::shared_ptr<term::raw>> column_values,
|
||||
bool if_not_exists)
|
||||
: modification_statement::parsed{std::move(name), attrs, conditions_vector{}, if_not_exists, false}
|
||||
, _column_names{column_names}
|
||||
, _column_values{column_values}
|
||||
: modification_statement::parsed{std::move(name), std::move(attrs), conditions_vector{}, if_not_exists, false}
|
||||
, _column_names{std::move(column_names)}
|
||||
, _column_values{std::move(column_values)}
|
||||
{ }
|
||||
|
||||
virtual ::shared_ptr<modification_statement> prepare_internal(schema_ptr schema,
|
||||
@@ -119,7 +119,7 @@ private:
|
||||
* @param updates a map of column operations to perform
|
||||
* @param whereClause the where clause
|
||||
*/
|
||||
parsed_update(std::experimental::optional<cf_name> name,
|
||||
parsed_update(::shared_ptr<cf_name> name,
|
||||
::shared_ptr<attributes::raw> attrs,
|
||||
std::vector<std::pair<::shared_ptr<column_identifier::raw>, ::shared_ptr<operation::raw_update>>> updates,
|
||||
std::vector<relation_ptr> where_clause,
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
: _keyspace(keyspace)
|
||||
{ }
|
||||
|
||||
virtual int get_bound_terms() override {
|
||||
virtual uint32_t get_bound_terms() override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
virtual void validate(const service::client_state& state) override {
|
||||
}
|
||||
|
||||
virtual future<std::experimental::optional<transport::messages::result_message>>
|
||||
virtual future<::shared_ptr<transport::messages::result_message>>
|
||||
execute(service::storage_proxy& proxy, service::query_state& state, const query_options& options) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
#if 0
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual future<std::experimental::optional<transport::messages::result_message>>
|
||||
virtual future<::shared_ptr<transport::messages::result_message>>
|
||||
execute_internal(database& db, service::query_state& state, const query_options& options) override {
|
||||
// Internal queries are exclusively on the system keyspace and 'use' is thus useless
|
||||
throw std::runtime_error("unsupported operation");
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "variable_specifications.hh"
|
||||
#include "cql3/assignment_testable.hh"
|
||||
#include "cql3/query_options.hh"
|
||||
#include "types.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
@@ -36,8 +37,6 @@ class terminal;
|
||||
|
||||
class term;
|
||||
|
||||
using bytes_opt = std::experimental::optional<bytes>;
|
||||
|
||||
/**
|
||||
* A CQL3 term, i.e. a column value with or without bind variables.
|
||||
*
|
||||
@@ -160,6 +159,8 @@ public:
|
||||
virtual bytes_opt bind_and_get(const query_options& options) override {
|
||||
return get(options);
|
||||
}
|
||||
|
||||
virtual sstring to_string() const = 0;
|
||||
};
|
||||
|
||||
class multi_item_terminal : public terminal {
|
||||
|
||||
63
database.cc
63
database.cc
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "log.hh"
|
||||
#include "database.hh"
|
||||
#include "unimplemented.hh"
|
||||
#include "core/future-util.hh"
|
||||
|
||||
#include "cql3/column_identifier.hh"
|
||||
@@ -229,7 +230,7 @@ column_definition::name() const {
|
||||
}
|
||||
|
||||
column_family*
|
||||
keyspace::find_column_family(sstring cf_name) {
|
||||
keyspace::find_column_family(const sstring& cf_name) {
|
||||
auto i = column_families.find(cf_name);
|
||||
if (i == column_families.end()) {
|
||||
return nullptr;
|
||||
@@ -238,7 +239,7 @@ keyspace::find_column_family(sstring cf_name) {
|
||||
}
|
||||
|
||||
schema_ptr
|
||||
keyspace::find_schema(sstring cf_name) {
|
||||
keyspace::find_schema(const sstring& cf_name) {
|
||||
auto cf = find_column_family(cf_name);
|
||||
if (!cf) {
|
||||
return {};
|
||||
@@ -247,7 +248,7 @@ keyspace::find_schema(sstring cf_name) {
|
||||
}
|
||||
|
||||
keyspace*
|
||||
database::find_keyspace(sstring name) {
|
||||
database::find_keyspace(const sstring& name) {
|
||||
auto i = keyspaces.find(name);
|
||||
if (i != keyspaces.end()) {
|
||||
return &i->second;
|
||||
@@ -297,7 +298,8 @@ compare_for_merge(const column_definition& def,
|
||||
}
|
||||
}
|
||||
|
||||
void mutation_partition::apply(schema_ptr schema, mutation_partition&& p) {
|
||||
void
|
||||
mutation_partition::apply(schema_ptr schema, mutation_partition&& p) {
|
||||
_tombstone.apply(p._tombstone);
|
||||
|
||||
for (auto&& entry : p._row_tombstones) {
|
||||
@@ -333,3 +335,56 @@ void mutation_partition::apply(schema_ptr schema, mutation_partition&& p) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tombstone
|
||||
mutation_partition::tombstone_for_row(schema_ptr schema, const clustering_key& key) {
|
||||
tombstone t = _tombstone;
|
||||
|
||||
auto i = _row_tombstones.lower_bound(key);
|
||||
if (i != _row_tombstones.end() && schema->clustering_key_prefix_type->is_prefix_of(i->first, key)) {
|
||||
t.apply(i->second);
|
||||
}
|
||||
|
||||
auto j = _rows.find(key);
|
||||
if (j != _rows.end()) {
|
||||
t.apply(j->second.t);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
mutation_partition::apply_row_tombstone(schema_ptr schema, std::pair<bytes, tombstone> row_tombstone) {
|
||||
auto& prefix = row_tombstone.first;
|
||||
auto i = _row_tombstones.lower_bound(prefix);
|
||||
if (i == _row_tombstones.end() || !schema->clustering_key_prefix_type->equal(prefix, i->first)) {
|
||||
_row_tombstones.emplace_hint(i, std::move(row_tombstone));
|
||||
} else if (row_tombstone.second > i->second) {
|
||||
i->second = row_tombstone.second;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mutation_partition::apply_delete(schema_ptr schema, const clustering_prefix& prefix, tombstone t) {
|
||||
if (prefix.empty()) {
|
||||
apply(t);
|
||||
} else if (prefix.size() == schema->clustering_key.size()) {
|
||||
_rows[serialize_value(*schema->clustering_key_type, prefix)].t.apply(t);
|
||||
} else {
|
||||
apply_row_tombstone(schema, {serialize_value(*schema->clustering_key_prefix_type, prefix), t});
|
||||
}
|
||||
}
|
||||
|
||||
row*
|
||||
mutation_partition::find_row(const clustering_key& key) {
|
||||
auto i = _rows.find(key);
|
||||
if (i == _rows.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &i->second.cells;
|
||||
}
|
||||
|
||||
bool column_definition::is_compact_value() const {
|
||||
unimplemented::compact_tables();
|
||||
return false;
|
||||
}
|
||||
|
||||
93
database.hh
93
database.hh
@@ -48,10 +48,9 @@ timestamp_type constexpr max_timestamp = std::numeric_limits<timestamp_type>::ma
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents deletion operation. Can be commuted with other tombstones via apply() method.
|
||||
* Can be empty.
|
||||
*
|
||||
*/
|
||||
* Represents deletion operation. Can be commuted with other tombstones via apply() method.
|
||||
* Can be empty.
|
||||
*/
|
||||
struct tombstone final {
|
||||
api::timestamp_type timestamp;
|
||||
gc_clock::time_point ttl;
|
||||
@@ -157,81 +156,19 @@ public:
|
||||
: _rows(key_compare(s->clustering_key_type))
|
||||
, _row_tombstones(serialized_compare(s->clustering_key_prefix_type))
|
||||
{ }
|
||||
|
||||
void apply(tombstone t) {
|
||||
_tombstone.apply(t);
|
||||
}
|
||||
|
||||
void apply_delete(schema_ptr schema, const clustering_prefix& prefix, tombstone t) {
|
||||
if (prefix.empty()) {
|
||||
apply(t);
|
||||
} else if (prefix.size() == schema->clustering_key.size()) {
|
||||
_rows[serialize_value(*schema->clustering_key_type, prefix)].t.apply(t);
|
||||
} else {
|
||||
apply_row_tombstone(schema, {serialize_value(*schema->clustering_key_prefix_type, prefix), t});
|
||||
}
|
||||
}
|
||||
|
||||
void apply(tombstone t) { _tombstone.apply(t); }
|
||||
void apply_delete(schema_ptr schema, const clustering_prefix& prefix, tombstone t);
|
||||
void apply_row_tombstone(schema_ptr schema, bytes prefix, tombstone t) {
|
||||
apply_row_tombstone(schema, {std::move(prefix), std::move(t)});
|
||||
}
|
||||
|
||||
void apply_row_tombstone(schema_ptr schema, std::pair<bytes, tombstone> row_tombstone) {
|
||||
auto& prefix = row_tombstone.first;
|
||||
auto i = _row_tombstones.lower_bound(prefix);
|
||||
if (i == _row_tombstones.end() || !schema->clustering_key_prefix_type->equal(prefix, i->first)) {
|
||||
_row_tombstones.emplace_hint(i, std::move(row_tombstone));
|
||||
} else if (row_tombstone.second > i->second) {
|
||||
i->second = row_tombstone.second;
|
||||
}
|
||||
}
|
||||
|
||||
void apply_row_tombstone(schema_ptr schema, std::pair<bytes, tombstone> row_tombstone);
|
||||
void apply(schema_ptr schema, mutation_partition&& p);
|
||||
|
||||
const row_tombstone_set& row_tombstones() {
|
||||
return _row_tombstones;
|
||||
}
|
||||
|
||||
row& static_row() {
|
||||
return _static_row;
|
||||
}
|
||||
|
||||
row& clustered_row(const clustering_key& key) {
|
||||
return _rows[key].cells;
|
||||
}
|
||||
|
||||
row& clustered_row(clustering_key&& key) {
|
||||
return _rows[std::move(key)].cells;
|
||||
}
|
||||
|
||||
row* find_row(const clustering_key& key) {
|
||||
auto i = _rows.find(key);
|
||||
if (i == _rows.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &i->second.cells;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base tombstone for all cells of given clustering row. Such tombstone
|
||||
* holds all information necessary to decide whether cells in a row are deleted or not,
|
||||
* in addition to any information inside individual cells.
|
||||
*/
|
||||
tombstone tombstone_for_row(schema_ptr schema, const clustering_key& key) {
|
||||
tombstone t = _tombstone;
|
||||
|
||||
auto i = _row_tombstones.lower_bound(key);
|
||||
if (i != _row_tombstones.end() && schema->clustering_key_prefix_type->is_prefix_of(i->first, key)) {
|
||||
t.apply(i->second);
|
||||
}
|
||||
|
||||
auto j = _rows.find(key);
|
||||
if (j != _rows.end()) {
|
||||
t.apply(j->second.t);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
const row_tombstone_set& row_tombstones() const { return _row_tombstones; }
|
||||
row& static_row() { return _static_row; }
|
||||
row& clustered_row(const clustering_key& key) { return _rows[key].cells; }
|
||||
row& clustered_row(clustering_key&& key) { return _rows[std::move(key)].cells; }
|
||||
row* find_row(const clustering_key& key);
|
||||
tombstone tombstone_for_row(schema_ptr schema, const clustering_key& key);
|
||||
};
|
||||
|
||||
class mutation final {
|
||||
@@ -280,15 +217,15 @@ class keyspace {
|
||||
public:
|
||||
std::unordered_map<sstring, column_family> column_families;
|
||||
static future<keyspace> populate(sstring datadir);
|
||||
schema_ptr find_schema(sstring cf_name);
|
||||
column_family* find_column_family(sstring cf_name);
|
||||
schema_ptr find_schema(const sstring& cf_name);
|
||||
column_family* find_column_family(const sstring& cf_name);
|
||||
};
|
||||
|
||||
class database {
|
||||
public:
|
||||
std::unordered_map<sstring, keyspace> keyspaces;
|
||||
static future<database> populate(sstring datadir);
|
||||
keyspace* find_keyspace(sstring name);
|
||||
keyspace* find_keyspace(const sstring& name);
|
||||
};
|
||||
|
||||
|
||||
|
||||
150
enum_set.hh
Normal file
150
enum_set.hh
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
|
||||
/**
|
||||
*
|
||||
* Allows to take full advantage of compile-time information when operating
|
||||
* on a set of enum values.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* enum class x { A, B, C };
|
||||
* using my_enum = super_enum<x, x::A, x::B, x::C>;
|
||||
* using my_enumset = enum_set<my_enum>;
|
||||
*
|
||||
* static_assert(my_enumset::frozen<x::A, x::B>::contains<x::A>(), "it should...");
|
||||
*
|
||||
* assert(my_enumset::frozen<x::A, x::B>::contains(my_enumset::prepare<x::A>()));
|
||||
*
|
||||
* assert(my_enumset::frozen<x::A, x::B>::contains(x::A));
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
template<typename EnumType, EnumType... Items>
|
||||
struct super_enum {
|
||||
using enum_type = EnumType;
|
||||
|
||||
template<enum_type... values>
|
||||
struct max {
|
||||
static constexpr enum_type max_of(enum_type a, enum_type b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template<enum_type first, enum_type second, enum_type... rest>
|
||||
static constexpr enum_type get() {
|
||||
return max_of(first, get<second, rest...>());
|
||||
}
|
||||
|
||||
template<enum_type first>
|
||||
static constexpr enum_type get() { return first; }
|
||||
|
||||
static constexpr enum_type value = get<values...>();
|
||||
};
|
||||
|
||||
template<enum_type... values>
|
||||
struct min {
|
||||
static constexpr enum_type min_of(enum_type a, enum_type b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template<enum_type first, enum_type second, enum_type... rest>
|
||||
static constexpr enum_type get() {
|
||||
return min_of(first, get<second, rest...>());
|
||||
}
|
||||
|
||||
template<enum_type first>
|
||||
static constexpr enum_type get() { return first; }
|
||||
|
||||
static constexpr enum_type value = get<values...>();
|
||||
};
|
||||
|
||||
using sequence_type = typename std::underlying_type<enum_type>::type;
|
||||
|
||||
template<enum_type Elem>
|
||||
static constexpr sequence_type sequence_for() {
|
||||
return static_cast<sequence_type>(Elem);
|
||||
}
|
||||
|
||||
static sequence_type sequence_for(enum_type elem) {
|
||||
return static_cast<sequence_type>(elem);
|
||||
}
|
||||
|
||||
static constexpr sequence_type max_sequence = sequence_for<max<Items...>::value>();
|
||||
static constexpr sequence_type min_sequence = sequence_for<min<Items...>::value>();
|
||||
|
||||
static_assert(min_sequence >= 0, "negative enum values unsupported");
|
||||
};
|
||||
|
||||
template<typename Enum>
|
||||
struct enum_set {
|
||||
using mask_type = size_t; // TODO: use the smallest sufficient type
|
||||
using enum_type = typename Enum::enum_type;
|
||||
|
||||
static inline mask_type mask_for(enum_type e) {
|
||||
return mask_type(1) << Enum::sequence_for(e);
|
||||
}
|
||||
|
||||
template<enum_type Elem>
|
||||
static constexpr mask_type mask_for() {
|
||||
// FIXME: for some reason Enum::sequence_for<Elem>() does not compile
|
||||
return mask_type(1) << static_cast<typename Enum::sequence_type>(Elem);
|
||||
}
|
||||
|
||||
struct prepared {
|
||||
mask_type mask;
|
||||
bool operator==(const prepared& o) const {
|
||||
return mask == o.mask;
|
||||
}
|
||||
};
|
||||
|
||||
static prepared prepare(enum_type e) {
|
||||
return {mask_for(e)};
|
||||
}
|
||||
|
||||
template<enum_type e>
|
||||
static constexpr prepared prepare() {
|
||||
return {mask_for<e>()};
|
||||
}
|
||||
|
||||
static_assert(std::numeric_limits<mask_type>::max() >= ((size_t)1 << Enum::max_sequence), "mask type too small");
|
||||
|
||||
template<enum_type... items>
|
||||
struct frozen {
|
||||
template<enum_type first>
|
||||
static constexpr mask_type make_mask() {
|
||||
return mask_for<first>();
|
||||
}
|
||||
|
||||
static constexpr mask_type make_mask() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<enum_type first, enum_type second, enum_type... rest>
|
||||
static constexpr mask_type make_mask() {
|
||||
return mask_for<first>() | make_mask<second, rest...>();
|
||||
}
|
||||
|
||||
static constexpr mask_type mask = make_mask<items...>();
|
||||
|
||||
template<enum_type Elem>
|
||||
static constexpr bool contains() {
|
||||
return mask & mask_for<Elem>();
|
||||
}
|
||||
|
||||
static bool contains(enum_type e) {
|
||||
return mask & mask_for(e);
|
||||
}
|
||||
|
||||
static bool contains(prepared e) {
|
||||
return mask & e.mask;
|
||||
}
|
||||
};
|
||||
};
|
||||
31
exceptions/TransportException.java
Normal file
31
exceptions/TransportException.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.cassandra.exceptions;
|
||||
|
||||
public interface TransportException
|
||||
{
|
||||
/**
|
||||
* The exception code.
|
||||
*/
|
||||
public ExceptionCode code();
|
||||
|
||||
/**
|
||||
* The exception message.
|
||||
*/
|
||||
public String getMessage();
|
||||
}
|
||||
@@ -1,7 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
#ifndef EXCEPTIONS_HH
|
||||
#define EXCEPTIONS_HH
|
||||
|
||||
#include <stdexcept>
|
||||
#include "core/sstring.hh"
|
||||
|
||||
namespace exceptions {
|
||||
|
||||
@@ -26,6 +51,66 @@ public:
|
||||
{ }
|
||||
};
|
||||
|
||||
enum exception_code {
|
||||
SERVER_ERROR = 0x0000,
|
||||
PROTOCOL_ERROR = 0x000A,
|
||||
|
||||
BAD_CREDENTIALS = 0x0100,
|
||||
|
||||
// 1xx: problem during request execution
|
||||
UNAVAILABLE = 0x1000,
|
||||
OVERLOADED = 0x1001,
|
||||
IS_BOOTSTRAPPING= 0x1002,
|
||||
TRUNCATE_ERROR = 0x1003,
|
||||
WRITE_TIMEOUT = 0x1100,
|
||||
READ_TIMEOUT = 0x1200,
|
||||
|
||||
// 2xx: problem validating the request
|
||||
SYNTAX_ERROR = 0x2000,
|
||||
UNAUTHORIZED = 0x2100,
|
||||
INVALID = 0x2200,
|
||||
CONFIG_ERROR = 0x2300,
|
||||
ALREADY_EXISTS = 0x2400,
|
||||
UNPREPARED = 0x2500
|
||||
};
|
||||
|
||||
class transport_exception {
|
||||
public:
|
||||
virtual exception_code code() const = 0;
|
||||
virtual sstring get_message() const = 0;
|
||||
};
|
||||
|
||||
class cassandra_exception : public std::exception, public transport_exception {
|
||||
private:
|
||||
exception_code _code;
|
||||
sstring _msg;
|
||||
public:
|
||||
cassandra_exception(exception_code code, sstring msg)
|
||||
: _code(code)
|
||||
, _msg(std::move(msg))
|
||||
{ }
|
||||
virtual const char* what() const noexcept override { return _msg.begin(); }
|
||||
virtual exception_code code() const override { return _code; }
|
||||
virtual sstring get_message() const override { return what(); }
|
||||
};
|
||||
|
||||
class request_validation_exception : public cassandra_exception {
|
||||
public:
|
||||
using cassandra_exception::cassandra_exception;
|
||||
};
|
||||
|
||||
class syntax_exception : public request_validation_exception {
|
||||
public:
|
||||
syntax_exception(sstring msg)
|
||||
: request_validation_exception(exception_code::SYNTAX_ERROR, std::move(msg))
|
||||
{ }
|
||||
};
|
||||
|
||||
class recognition_exception : public std::runtime_error {
|
||||
public:
|
||||
recognition_exception(const std::string& msg) : std::runtime_error(msg) {};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,7 +26,9 @@ public:
|
||||
::shared_ptr<cql3::column_specification> column_specification;
|
||||
bool is_static() const { return kind == column_kind::STATIC; }
|
||||
bool is_partition_key() const { return kind == column_kind::PARTITION; }
|
||||
bool is_primary_key() const { return kind == column_kind::PARTITION || kind == column_kind::CLUSTERING; }
|
||||
bool is_atomic() const { return !type->is_multi_cell(); }
|
||||
bool is_compact_value() const;
|
||||
const sstring& name_as_text() const;
|
||||
const bytes& name() const;
|
||||
};
|
||||
@@ -115,6 +117,9 @@ public:
|
||||
column_definition& regular_column_at(column_id id) {
|
||||
return regular_columns[id];
|
||||
}
|
||||
bool is_last_partition_key(column_definition& def) {
|
||||
return &partition_key[partition_key.size() - 1] == &def;
|
||||
}
|
||||
};
|
||||
|
||||
using schema_ptr = lw_shared_ptr<schema>;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "exceptions/exceptions.hh"
|
||||
#include "unimplemented.hh"
|
||||
#include "database.hh"
|
||||
|
||||
namespace service {
|
||||
|
||||
@@ -84,10 +85,12 @@ private:
|
||||
|
||||
// The remote address of the client - null for internal clients.
|
||||
private final SocketAddress remoteAddress;
|
||||
#endif
|
||||
|
||||
// The biggest timestamp that was returned by getTimestamp/assigned to a query
|
||||
private final AtomicLong lastTimestampMicros = new AtomicLong(0);
|
||||
api::timestamp_type _last_timestamp_micros = 0;
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Construct a new, empty ClientState for internal calls.
|
||||
*/
|
||||
@@ -120,23 +123,22 @@ private:
|
||||
{
|
||||
return new ClientState(remoteAddress);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This clock guarantees that updates for the same ClientState will be ordered
|
||||
* in the sequence seen, even if multiple updates happen in the same millisecond.
|
||||
*/
|
||||
public long getTimestamp()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
long current = System.currentTimeMillis() * 1000;
|
||||
long last = lastTimestampMicros.get();
|
||||
long tstamp = last >= current ? last + 1 : current;
|
||||
if (lastTimestampMicros.compareAndSet(last, tstamp))
|
||||
return tstamp;
|
||||
}
|
||||
public:
|
||||
api::timestamp_type get_timestamp() {
|
||||
auto current = db_clock::now().time_since_epoch().count() * 1000;
|
||||
auto last = _last_timestamp_micros;
|
||||
auto result = last >= current ? last + 1 : current;
|
||||
_last_timestamp_micros = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Can be use when a timestamp has been assigned by a query, but that timestamp is
|
||||
* not directly one returned by getTimestamp() (see SP.beginAndRepairPaxos()).
|
||||
@@ -181,7 +183,7 @@ public:
|
||||
_keyspace = keyspace;
|
||||
}
|
||||
|
||||
sstring get_keyspace() const {
|
||||
const sstring& get_keyspace() const {
|
||||
if (_keyspace.empty()) {
|
||||
throw exceptions::invalid_request_exception("No keyspace has been specified. USE a keyspace, or explicitly specify keyspace.tablename");
|
||||
}
|
||||
|
||||
96
service/pager/paging_state.hh
Normal file
96
service/pager/paging_state.hh
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace service {
|
||||
|
||||
namespace pager {
|
||||
|
||||
class paging_state final {
|
||||
#if 0
|
||||
public final ByteBuffer partitionKey;
|
||||
public final ByteBuffer cellName;
|
||||
public final int remaining;
|
||||
|
||||
public PagingState(ByteBuffer partitionKey, ByteBuffer cellName, int remaining)
|
||||
{
|
||||
this.partitionKey = partitionKey == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : partitionKey;
|
||||
this.cellName = cellName == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : cellName;
|
||||
this.remaining = remaining;
|
||||
}
|
||||
|
||||
public static PagingState deserialize(ByteBuffer bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
DataInputStream in = new DataInputStream(ByteBufferUtil.inputStream(bytes));
|
||||
ByteBuffer pk = ByteBufferUtil.readWithShortLength(in);
|
||||
ByteBuffer cn = ByteBufferUtil.readWithShortLength(in);
|
||||
int remaining = in.readInt();
|
||||
return new PagingState(pk, cn, remaining);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new ProtocolException("Invalid value for the paging state");
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuffer serialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
DataOutputBuffer out = new DataOutputBuffer(serializedSize());
|
||||
ByteBufferUtil.writeWithShortLength(partitionKey, out);
|
||||
ByteBufferUtil.writeWithShortLength(cellName, out);
|
||||
out.writeInt(remaining);
|
||||
return out.asByteBuffer();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private int serializedSize()
|
||||
{
|
||||
return 2 + partitionKey.remaining()
|
||||
+ 2 + cellName.remaining()
|
||||
+ 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("PagingState(key=%s, cellname=%s, remaining=%d", ByteBufferUtil.bytesToHex(partitionKey), ByteBufferUtil.bytesToHex(cellName), remaining);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,21 @@
|
||||
#ifndef SERVICE_QUERY_STATE_HH
|
||||
#define SERVICE_QUERY_STATE_HH
|
||||
|
||||
#include "service/client_state.hh"
|
||||
|
||||
namespace service {
|
||||
|
||||
class query_state {
|
||||
// FIXME: stub
|
||||
class query_state final {
|
||||
private:
|
||||
client_state& _client_state;
|
||||
public:
|
||||
query_state(client_state& client_state_) : _client_state(client_state_) {}
|
||||
client_state& get_client_state() const {
|
||||
return _client_state;
|
||||
}
|
||||
api::timestamp_type get_timestamp() {
|
||||
return _client_state.get_timestamp();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
1
test.py
1
test.py
@@ -12,6 +12,7 @@ all_tests = [
|
||||
'output_stream_test',
|
||||
'urchin/types_test',
|
||||
'urchin/mutation_test',
|
||||
'urchin/cql_query_test',
|
||||
]
|
||||
|
||||
last_len = 0
|
||||
|
||||
83
tests/urchin/cql_query_test.cc
Normal file
83
tests/urchin/cql_query_test.cc
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#include "cql3/query_processor.hh"
|
||||
#include "cql3/query_options.hh"
|
||||
#include "tests/test-utils.hh"
|
||||
#include "core/future-util.hh"
|
||||
|
||||
struct conversation_state {
|
||||
service::storage_proxy proxy;
|
||||
cql3::query_processor qp;
|
||||
service::client_state client_state;
|
||||
service::query_state query_state;
|
||||
cql3::query_options& options;
|
||||
|
||||
conversation_state(database& db, const sstring& ks_name)
|
||||
: proxy(db)
|
||||
, qp(proxy, db)
|
||||
, query_state(client_state)
|
||||
, options(cql3::query_options::DEFAULT)
|
||||
{
|
||||
client_state.set_keyspace(ks_name);
|
||||
}
|
||||
|
||||
future<> execute_cql(const sstring& text) {
|
||||
return qp.process(text, query_state, options).discard_result();
|
||||
}
|
||||
};
|
||||
|
||||
static const sstring ks_name = "ks";
|
||||
static const sstring table_name = "cf";
|
||||
|
||||
static void require_column_has_value(database& db, const sstring& ks_name, const sstring& table_name,
|
||||
std::vector<boost::any> pk, std::vector<boost::any> ck, const sstring& column_name, boost::any expected)
|
||||
{
|
||||
auto ks = db.find_keyspace(ks_name);
|
||||
BOOST_REQUIRE(ks != nullptr);
|
||||
auto cf = ks->find_column_family(table_name);
|
||||
BOOST_REQUIRE(cf != nullptr);
|
||||
auto schema = cf->_schema;
|
||||
auto p = cf->find_partition(schema->partition_key_type->serialize_value_deep(pk));
|
||||
BOOST_REQUIRE(p != nullptr);
|
||||
auto row = p->find_row(schema->clustering_key_type->serialize_value_deep(ck));
|
||||
BOOST_REQUIRE(row != nullptr);
|
||||
auto col_def = schema->get_column_definition(utf8_type->decompose(column_name));
|
||||
BOOST_REQUIRE(col_def != nullptr);
|
||||
auto i = row->find(col_def->id);
|
||||
if (i == row->end()) {
|
||||
BOOST_FAIL("column not set");
|
||||
}
|
||||
auto& cell = boost::any_cast<const atomic_cell&>(i->second);
|
||||
BOOST_REQUIRE(cell.is_live());
|
||||
BOOST_REQUIRE(col_def->type->equal(cell.as_live().value, col_def->type->decompose(expected)));
|
||||
}
|
||||
|
||||
SEASTAR_TEST_CASE(test_insert_statement) {
|
||||
auto db = make_shared<database>();
|
||||
|
||||
// CQL: create table cf (p1 varchar, c1 int, r1 int, PRIMARY KEY (p1, c1));
|
||||
keyspace ks;
|
||||
auto cf_schema = make_lw_shared<schema>(ks_name, table_name,
|
||||
std::vector<schema::column>({{"p1", utf8_type}}),
|
||||
std::vector<schema::column>({{"c1", int32_type}}),
|
||||
std::vector<schema::column>({{"r1", int32_type}}),
|
||||
utf8_type
|
||||
);
|
||||
ks.column_families.emplace(table_name, column_family(cf_schema));
|
||||
db->keyspaces.emplace(ks_name, std::move(ks));
|
||||
|
||||
auto state = make_shared<conversation_state>(*db, ks_name);
|
||||
|
||||
return now().then([state, db] {
|
||||
return state->execute_cql("insert into cf (p1, c1, r1) values ('key1', 1, 100);");
|
||||
}).then([state, db] {
|
||||
require_column_has_value(*db, ks_name, table_name, {sstring("key1")}, {1}, "r1", 100);
|
||||
}).then([state, db] {
|
||||
return state->execute_cql("update cf set r1 = 66 where p1 = 'key1' and c1 = 1;");
|
||||
}).then([state, db] {
|
||||
require_column_has_value(*db, ks_name, table_name, {sstring("key1")}, {1}, "r1", 66);
|
||||
});
|
||||
}
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/sstring.hh"
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
/**
|
||||
* Converts a vector of pointers to Printable elements.
|
||||
* Printable is an object which has to_string() method.
|
||||
|
||||
@@ -5,8 +5,14 @@ namespace transport {
|
||||
|
||||
namespace messages {
|
||||
|
||||
// FIXME: stub
|
||||
class result_message {
|
||||
// FIXME: stub
|
||||
virtual ~result_message() {}
|
||||
|
||||
class void_message;
|
||||
};
|
||||
|
||||
class result_message::void_message : public result_message {
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -362,10 +362,10 @@ future<> cql_server::connection::process_query(uint16_t stream, temporary_buffer
|
||||
auto flags = read_byte(buf);
|
||||
#endif
|
||||
print("processing query: '%s' ...\n", query);
|
||||
cql3::CqlLexer::InputStreamType input{reinterpret_cast<const ANTLR_UINT8*>(query.begin()), ANTLR_ENC_UTF8, static_cast<ANTLR_UINT32>(query.size()), nullptr};
|
||||
cql3::CqlLexer lexer{&input};
|
||||
cql3::CqlParser::TokenStreamType tstream(ANTLR_SIZE_HINT, lexer.get_tokSource());
|
||||
cql3::CqlParser parser{&tstream};
|
||||
cql3_parser::CqlLexer::InputStreamType input{reinterpret_cast<const ANTLR_UINT8*>(query.begin()), ANTLR_ENC_UTF8, static_cast<ANTLR_UINT32>(query.size()), nullptr};
|
||||
cql3_parser::CqlLexer lexer{&input};
|
||||
cql3_parser::CqlParser::TokenStreamType tstream(ANTLR_SIZE_HINT, lexer.get_tokSource());
|
||||
cql3_parser::CqlParser parser{&tstream};
|
||||
auto stmt = parser.query();
|
||||
assert(stmt != nullptr);
|
||||
return make_ready_future<>();
|
||||
|
||||
15
tuple.hh
15
tuple.hh
@@ -59,6 +59,16 @@ public:
|
||||
bytes serialize_value(const value_type& values) {
|
||||
return ::serialize_value(*this, values);
|
||||
}
|
||||
bytes serialize_value_deep(const std::vector<boost::any>& values) {
|
||||
// TODO: Optimize
|
||||
std::vector<bytes_opt> partial;
|
||||
auto i = types.begin();
|
||||
for (auto&& component : values) {
|
||||
assert(i != types.end());
|
||||
partial.push_back({(*i++)->decompose(component)});
|
||||
}
|
||||
return serialize_value(partial);
|
||||
}
|
||||
bytes decompose_value(const value_type& values) {
|
||||
return ::serialize_value(*this, values);
|
||||
}
|
||||
@@ -162,7 +172,7 @@ public:
|
||||
// TODO: make the length byte-order comparable by adding numeric_limits<int32_t>::min() when serializing
|
||||
return false;
|
||||
}
|
||||
virtual bytes from_string(const sstring& s) override {
|
||||
virtual bytes from_string(sstring_view s) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) override {
|
||||
@@ -214,6 +224,9 @@ public:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
|
||||
assert(0);
|
||||
}
|
||||
};
|
||||
|
||||
using tuple_prefix = tuple_type<true>;
|
||||
|
||||
60
types.cc
60
types.cc
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "cql3/cql3_type.hh"
|
||||
#include "types.hh"
|
||||
|
||||
template <typename T, typename Compare>
|
||||
@@ -66,14 +67,14 @@ struct int32_type_impl : simple_type_impl<int32_t> {
|
||||
*reinterpret_cast<int32_t*>(b.begin()) = (int32_t)net::hton((uint32_t)v);
|
||||
return b;
|
||||
}
|
||||
int32_t parse_int(const sstring& s) {
|
||||
int32_t parse_int(sstring_view s) {
|
||||
try {
|
||||
return boost::lexical_cast<int32_t>(s);
|
||||
return boost::lexical_cast<int32_t>(s.begin(), s.size());
|
||||
} catch (const boost::bad_lexical_cast& e) {
|
||||
throw marshal_exception(sprint("Invalid number format '%s'", s));
|
||||
}
|
||||
}
|
||||
virtual bytes from_string(const sstring& s) override {
|
||||
virtual bytes from_string(sstring_view s) override {
|
||||
return decompose_value(parse_int(s));
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) override {
|
||||
@@ -82,6 +83,9 @@ struct int32_type_impl : simple_type_impl<int32_t> {
|
||||
}
|
||||
return to_sstring(compose_value(b));
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
|
||||
return cql3::native_cql3_type::int_;
|
||||
}
|
||||
};
|
||||
|
||||
struct long_type_impl : simple_type_impl<int64_t> {
|
||||
@@ -103,16 +107,20 @@ struct long_type_impl : simple_type_impl<int64_t> {
|
||||
auto v = int64_t(net::ntoh(u));
|
||||
return boost::any(v);
|
||||
}
|
||||
virtual bytes from_string(const sstring& s) override {
|
||||
virtual bytes from_string(sstring_view s) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
|
||||
return cql3::native_cql3_type::bigint;
|
||||
}
|
||||
};
|
||||
|
||||
struct string_type_impl : public abstract_type {
|
||||
string_type_impl(sstring name) : abstract_type(name) {}
|
||||
string_type_impl(sstring name, shared_ptr<cql3::cql3_type> cql3_type)
|
||||
: abstract_type(name), _cql3_type(cql3_type) {}
|
||||
virtual void serialize(const boost::any& value, std::ostream& out) override {
|
||||
auto& v = boost::any_cast<const sstring&>(value);
|
||||
out.write(v.c_str(), v.size());
|
||||
@@ -135,15 +143,19 @@ struct string_type_impl : public abstract_type {
|
||||
virtual size_t hash(const bytes& v) override {
|
||||
return std::hash<bytes>()(v);
|
||||
}
|
||||
virtual bytes from_string(const sstring& s) override {
|
||||
virtual bytes from_string(sstring_view s) override {
|
||||
return to_bytes(s);
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) override {
|
||||
return sstring(b);
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
|
||||
return _cql3_type;
|
||||
}
|
||||
shared_ptr<cql3::cql3_type> _cql3_type;
|
||||
};
|
||||
|
||||
struct bytes_type_impl : public abstract_type {
|
||||
struct bytes_type_impl final : public abstract_type {
|
||||
bytes_type_impl() : abstract_type("bytes") {}
|
||||
virtual void serialize(const boost::any& value, std::ostream& out) override {
|
||||
auto& v = boost::any_cast<const bytes&>(value);
|
||||
@@ -166,12 +178,15 @@ struct bytes_type_impl : public abstract_type {
|
||||
virtual size_t hash(const bytes& v) override {
|
||||
return std::hash<bytes>()(v);
|
||||
}
|
||||
virtual bytes from_string(const sstring& s) override {
|
||||
virtual bytes from_string(sstring_view s) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
|
||||
return cql3::native_cql3_type::blob;
|
||||
}
|
||||
};
|
||||
|
||||
struct boolean_type_impl : public simple_type_impl<bool> {
|
||||
@@ -189,12 +204,15 @@ struct boolean_type_impl : public simple_type_impl<bool> {
|
||||
}
|
||||
return boost::any(tmp != 0);
|
||||
}
|
||||
virtual bytes from_string(const sstring& s) override {
|
||||
virtual bytes from_string(sstring_view s) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
|
||||
return cql3::native_cql3_type::boolean;
|
||||
}
|
||||
};
|
||||
|
||||
struct date_type_impl : public abstract_type {
|
||||
@@ -226,12 +244,15 @@ struct date_type_impl : public abstract_type {
|
||||
virtual size_t hash(const bytes& v) override {
|
||||
return std::hash<bytes>()(v);
|
||||
}
|
||||
virtual bytes from_string(const sstring& s) override {
|
||||
virtual bytes from_string(sstring_view s) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
|
||||
return cql3::native_cql3_type::timestamp;
|
||||
}
|
||||
};
|
||||
|
||||
struct timeuuid_type_impl : public abstract_type {
|
||||
@@ -272,12 +293,15 @@ struct timeuuid_type_impl : public abstract_type {
|
||||
virtual size_t hash(const bytes& v) override {
|
||||
return std::hash<bytes>()(v);
|
||||
}
|
||||
virtual bytes from_string(const sstring& s) override {
|
||||
virtual bytes from_string(sstring_view s) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
|
||||
return cql3::native_cql3_type::timeuuid;
|
||||
}
|
||||
private:
|
||||
static int compare_bytes(const bytes& o1, const bytes& o2) {
|
||||
auto compare_pos = [&] (unsigned pos, int mask, int ifequal) {
|
||||
@@ -315,12 +339,15 @@ struct timestamp_type_impl : simple_type_impl<db_clock::time_point> {
|
||||
return boost::any(db_clock::time_point(db_clock::duration(net::ntoh(v))));
|
||||
}
|
||||
// FIXME: isCompatibleWith(timestampuuid)
|
||||
virtual bytes from_string(const sstring& s) override {
|
||||
virtual bytes from_string(sstring_view s) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
|
||||
return cql3::native_cql3_type::timestamp;
|
||||
}
|
||||
};
|
||||
|
||||
struct uuid_type_impl : abstract_type {
|
||||
@@ -372,19 +399,22 @@ struct uuid_type_impl : abstract_type {
|
||||
virtual size_t hash(const bytes& v) override {
|
||||
return std::hash<bytes>()(v);
|
||||
}
|
||||
virtual bytes from_string(const sstring& s) override {
|
||||
virtual bytes from_string(sstring_view s) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) override {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
|
||||
return cql3::native_cql3_type::uuid;
|
||||
}
|
||||
};
|
||||
|
||||
thread_local shared_ptr<abstract_type> int32_type(make_shared<int32_type_impl>());
|
||||
thread_local shared_ptr<abstract_type> long_type(make_shared<long_type_impl>());
|
||||
thread_local shared_ptr<abstract_type> ascii_type(make_shared<string_type_impl>("ascii"));
|
||||
thread_local shared_ptr<abstract_type> ascii_type(make_shared<string_type_impl>("ascii", cql3::native_cql3_type::ascii));
|
||||
thread_local shared_ptr<abstract_type> bytes_type(make_shared<bytes_type_impl>());
|
||||
thread_local shared_ptr<abstract_type> utf8_type(make_shared<string_type_impl>("utf8"));
|
||||
thread_local shared_ptr<abstract_type> utf8_type(make_shared<string_type_impl>("utf8", cql3::native_cql3_type::text));
|
||||
thread_local shared_ptr<abstract_type> boolean_type(make_shared<boolean_type_impl>());
|
||||
thread_local shared_ptr<abstract_type> date_type(make_shared<date_type_impl>());
|
||||
thread_local shared_ptr<abstract_type> timeuuid_type(make_shared<timeuuid_type_impl>());
|
||||
|
||||
16
types.hh
16
types.hh
@@ -16,10 +16,17 @@
|
||||
#include "net/byteorder.hh"
|
||||
#include "db_clock.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
class cql3_type;
|
||||
|
||||
}
|
||||
|
||||
// FIXME: should be int8_t
|
||||
using bytes = basic_sstring<char, uint32_t, 31>;
|
||||
using bytes_view = std::experimental::string_view;
|
||||
using bytes_opt = std::experimental::optional<bytes>;
|
||||
using sstring_view = std::experimental::string_view;
|
||||
|
||||
sstring to_hex(const bytes& b);
|
||||
sstring to_hex(const bytes_opt& b);
|
||||
@@ -113,10 +120,11 @@ public:
|
||||
return to_string(b);
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) = 0;
|
||||
virtual bytes from_string(const sstring& text) = 0;
|
||||
virtual bytes from_string(sstring_view text) = 0;
|
||||
virtual bool is_counter() { return false; }
|
||||
virtual bool is_collection() { return false; }
|
||||
virtual bool is_multi_cell() { return false; }
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() = 0;
|
||||
protected:
|
||||
template <typename T, typename Compare = std::less<T>>
|
||||
bool default_less(const bytes& b1, const bytes& b2, Compare compare = Compare());
|
||||
@@ -193,6 +201,12 @@ to_bytes(const std::string& x) {
|
||||
return bytes(reinterpret_cast<const char*>(x.data()), x.size());
|
||||
}
|
||||
|
||||
inline
|
||||
bytes
|
||||
to_bytes(sstring_view x) {
|
||||
return bytes(x.begin(), x.size());
|
||||
}
|
||||
|
||||
inline
|
||||
bytes
|
||||
to_bytes(const sstring& x) {
|
||||
|
||||
@@ -40,9 +40,28 @@ void auth() {
|
||||
warn("auth");
|
||||
}
|
||||
|
||||
static inline
|
||||
void permissions() {
|
||||
warn("permissions");
|
||||
}
|
||||
|
||||
static inline
|
||||
void triggers() {
|
||||
warn("triggers");
|
||||
}
|
||||
|
||||
static inline
|
||||
void collections() __attribute__((noreturn));
|
||||
|
||||
static inline
|
||||
void collections() {
|
||||
fail("collections");
|
||||
}
|
||||
|
||||
static inline
|
||||
void metrics() {}
|
||||
|
||||
static inline
|
||||
void compact_tables() {}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user