From bad22fe50e1fd0dfd63e898248ad4fc73d666ce9 Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Wed, 4 Feb 2015 10:14:45 +0100 Subject: [PATCH] cql3: Convert ModificationStatement.Parsed.prepare() Together with ParsedInsert descendant. --- cql3/statements/modification_statement.cc | 51 ++++++ cql3/statements/modification_statement.hh | 210 ++++++++-------------- cql3/statements/update_statement.cc | 56 ++++++ cql3/statements/update_statement.hh | 52 +----- 4 files changed, 183 insertions(+), 186 deletions(-) diff --git a/cql3/statements/modification_statement.cc b/cql3/statements/modification_statement.cc index 6d82ee2980..25a7607fd9 100644 --- a/cql3/statements/modification_statement.cc +++ b/cql3/statements/modification_statement.cc @@ -23,6 +23,8 @@ */ #include "cql3/statements/modification_statement.hh" +#include "cql3/restrictions/single_column_restriction.hh" +#include "cql3/single_column_relation.hh" #include "validation.hh" #include "core/shared_ptr.hh" @@ -336,6 +338,55 @@ modification_statement::execute_with_condition(service::query_state& qs, const q #endif } +void +modification_statement::add_key_values(column_definition& def, ::shared_ptr values) { + if (def.kind == column_definition::CLUSTERING) { + _has_no_clustering_columns = false; + } + + auto insert_result = _processed_keys.insert({&def, values}); + if (!insert_result.second) { + throw exceptions::invalid_request_exception(sprint("Multiple definitions found for PRIMARY KEY part %s", def.name_as_text())); + } +} + +void +modification_statement::add_key_value(column_definition& def, ::shared_ptr value) { + add_key_values(def, ::make_shared(def, value)); +} + +void +modification_statement::precess_where_clause(std::vector where_clause, ::shared_ptr names) { + for (auto&& relation : where_clause) { + if (relation->is_multi_column()) { + throw exceptions::invalid_request_exception(sprint("Multi-column relations cannot be used in WHERE clauses for UPDATE and DELETE statements: %s", relation->to_string())); + } + + auto rel = dynamic_pointer_cast(relation); + if (rel->on_token()) { + throw exceptions::invalid_request_exception(sprint("The token function cannot be used in WHERE clauses for UPDATE and DELETE statements: %s", relation->to_string())); + } + + auto id = rel->get_entity()->prepare_column_identifier(s); + auto def = get_column_definition(s, *id); + if (!def) { + throw exceptions::invalid_request_exception(sprint("Unknown key identifier %s", *id)); + } + + switch (def->kind) { + case column_definition::column_kind::PARTITION: + 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; + } + throw exceptions::invalid_request_exception(sprint("Invalid operator %s for PRIMARY KEY part %s", rel->get_operator(), def->name_as_text())); + default: + throw exceptions::invalid_request_exception(sprint("Non PRIMARY KEY %s found in where clause", def->name_as_text())); + } + } +} + } } diff --git a/cql3/statements/modification_statement.hh b/cql3/statements/modification_statement.hh index f4438e2aa8..d24ae96111 100644 --- a/cql3/statements/modification_statement.hh +++ b/cql3/statements/modification_statement.hh @@ -33,13 +33,16 @@ #include "cql3/cql_statement.hh" #include "cql3/attributes.hh" #include "cql3/operation.hh" +#include "cql3/relation.hh" #include "db/column_family.hh" #include "db/consistency_level.hh" #include "core/shared_ptr.hh" #include "core/future-util.hh" + #include "unimplemented.hh" +#include "validation.hh" #include "service/storage_proxy.hh" #include @@ -213,16 +216,16 @@ public: throw std::runtime_error("not implemented"); } -#if 0 - public void addOperation(Operation op) - { - if (op.column.isStatic()) - setsStaticColumns = true; - else - setsRegularColumns = true; - columnOperations.add(op); + void add_operation(::shared_ptr op) { + if (op->column.is_static()) { + _sets_static_columns = true; + } else { + _sets_regular_columns = true; + } + _column_operations.push_back(std::move(op)); } +#if 0 public Iterable getColumnsWithConditions() { if (ifNotExists || ifExists) @@ -231,27 +234,17 @@ public: return Iterables.concat(columnConditions == null ? Collections.emptyList() : Iterables.transform(columnConditions, getColumnForCondition), staticConditions == null ? Collections.emptyList() : Iterables.transform(staticConditions, getColumnForCondition)); } - - public void addCondition(ColumnCondition cond) - { - List conds = null; - if (cond.column.isStatic()) - { - setsStaticColumns = true; - if (staticConditions == null) - staticConditions = new ArrayList(); - conds = staticConditions; - } - else - { - setsRegularColumns = true; - if (columnConditions == null) - columnConditions = new ArrayList(); - conds = columnConditions; - } - conds.add(cond); - } #endif +public: + void add_condition(::shared_ptr cond) { + if (cond->column.is_static()) { + _sets_static_columns = true; + _static_conditions.emplace_back(std::move(cond)); + } else { + _sets_regular_columns = true; + _column_conditions.emplace_back(std::move(cond)); + } + } void set_if_not_exist_condition() { _if_not_exists = true; @@ -269,63 +262,12 @@ public: return _if_exists; } -#if 0 - private void addKeyValues(ColumnDefinition def, Restriction values) throws InvalidRequestException - { - if (def.kind == ColumnDefinition.Kind.CLUSTERING_COLUMN) - hasNoClusteringColumns = false; - if (processedKeys.put(def.name, values) != null) - throw new InvalidRequestException(String.format("Multiple definitions found for PRIMARY KEY part %s", def.name)); - } - - public void addKeyValue(ColumnDefinition def, Term value) throws InvalidRequestException - { - addKeyValues(def, new SingleColumnRestriction.EQ(def, value)); - } - - public void processWhereClause(List whereClause, VariableSpecifications names) throws InvalidRequestException - { - for (Relation relation : whereClause) - { - if (relation.isMultiColumn()) - { - throw new InvalidRequestException( - String.format("Multi-column relations cannot be used in WHERE clauses for UPDATE and DELETE statements: %s", relation)); - } - SingleColumnRelation rel = (SingleColumnRelation) relation; - - if (rel.onToken()) - throw new InvalidRequestException(String.format("The token function cannot be used in WHERE clauses for UPDATE and DELETE statements: %s", relation)); - - ColumnIdentifier id = rel.getEntity().prepare(cfm); - ColumnDefinition def = cfm.getColumnDefinition(id); - if (def == null) - throw new InvalidRequestException(String.format("Unknown key identifier %s", id)); - - switch (def.kind) - { - case PARTITION_KEY: - case CLUSTERING_COLUMN: - Restriction restriction; - - if (rel.isEQ() || (def.isPartitionKey() && rel.isIN())) - { - restriction = rel.toRestriction(cfm, names); - } - else - { - throw new InvalidRequestException(String.format("Invalid operator %s for PRIMARY KEY part %s", rel.operator(), def.name)); - } - - addKeyValues(def, restriction); - break; - default: - throw new InvalidRequestException(String.format("Non PRIMARY KEY %s found in where clause", def.name)); - } - } - } -#endif +private: + void add_key_values(column_definition& def, ::shared_ptr values); +public: + void add_key_value(column_definition& def, ::shared_ptr value); + void precess_where_clause(std::vector where_clause, ::shared_ptr names); std::vector build_partition_keys(const query_options& options); private: @@ -525,7 +467,7 @@ public: const bool _if_not_exists; const bool _if_exists; protected: - parsed(std::experimental::optional&& name, ::shared_ptr attrs, const conditions_vector& conditions, bool if_not_exists, bool if_exists) + parsed(std::experimental::optional name, ::shared_ptr attrs, const conditions_vector& conditions, bool if_not_exists, bool if_exists) : cf_statement{std::move(name)} , _attrs{attrs} , _conditions{conditions} @@ -533,76 +475,66 @@ public: , _if_exists{if_exists} { } -#if 0 - public ParsedStatement.Prepared prepare() throws InvalidRequestException - { - VariableSpecifications boundNames = getBoundVariables(); - ModificationStatement statement = prepare(boundNames); - return new ParsedStatement.Prepared(statement, boundNames); + public: + std::unique_ptr prepare(database& db) override { + auto bound_names = get_bound_variables(); + auto statement = prepare(db, bound_names); + return std::make_unique(std::move(statement), *bound_names); } - public ModificationStatement prepare(VariableSpecifications boundNames) throws InvalidRequestException - { - CFMetaData metadata = ThriftValidation.validateColumnFamily(keyspace(), columnFamily()); + ::shared_ptr prepare(database& db, ::shared_ptr bound_names) { + schema_ptr schema = validation::validate_column_family(db, keyspace(), column_family()); - Attributes preparedAttributes = attrs.prepare(keyspace(), columnFamily()); - preparedAttributes.collectMarkerSpecification(boundNames); + auto prepared_attributes = _attrs->prepare(keyspace(), column_family()); + prepared_attributes->collect_marker_specification(bound_names); - ModificationStatement stmt = prepareInternal(metadata, boundNames, preparedAttributes); + ::shared_ptr stmt = prepare_internal(schema, bound_names, std::move(prepared_attributes)); - if (ifNotExists || ifExists || !conditions.isEmpty()) - { - if (stmt.isCounter()) - throw new InvalidRequestException("Conditional updates are not supported on counter tables"); + if (_if_not_exists || _if_exists || !_conditions.empty()) { + if (stmt->is_counter()) { + throw exceptions::invalid_request_exception("Conditional updates are not supported on counter tables"); + } + if (_attrs->timestamp) { + throw exceptions::invalid_request_exception("Cannot provide custom timestamp for conditional updates"); + } - if (attrs.timestamp != null) - throw new InvalidRequestException("Cannot provide custom timestamp for conditional updates"); - - if (ifNotExists) - { + if (_if_not_exists) { // To have both 'IF NOT EXISTS' and some other conditions doesn't make sense. // So far this is enforced by the parser, but let's assert it for sanity if ever the parse changes. - assert conditions.isEmpty(); - assert !ifExists; - stmt.setIfNotExistCondition(); - } - else if (ifExists) - { - assert conditions.isEmpty(); - assert !ifNotExists; - stmt.setIfExistCondition(); - } - else - { - for (Pair entry : conditions) - { - ColumnIdentifier id = entry.left.prepare(metadata); - ColumnDefinition def = metadata.getColumnDefinition(id); - if (def == null) - throw new InvalidRequestException(String.format("Unknown identifier %s", id)); + assert(_conditions.empty()); + assert(!_if_exists); + stmt->set_if_not_exist_condition(); + } else if (_if_exists) { + assert(_conditions.empty()); + assert(!_if_not_exists); + stmt->set_if_exist_condition(); + } else { + for (auto&& entry : _conditions) { + auto id = entry.first->prepare_column_identifier(schema); + column_definition* def = get_column_definition(schema, *id); + if (!def) { + throw exceptions::invalid_request_exception(sprint("Unknown identifier %s", *id)); + } - ColumnCondition condition = entry.right.prepare(keyspace(), def); - condition.collectMarkerSpecification(boundNames); + auto condition = entry.second->prepare(keyspace(), *def); + condition->collect_marker_specificaton(bound_names); - switch (def.kind) - { - case PARTITION_KEY: - case CLUSTERING_COLUMN: - throw new InvalidRequestException(String.format("PRIMARY KEY column '%s' cannot have IF conditions", id)); + switch (def->kind) { + case column_definition::PARTITION: + case column_definition::CLUSTERING: + throw exceptions::invalid_request_exception(sprint("PRIMARY KEY column '%s' cannot have IF conditions", *id)); default: - stmt.addCondition(condition); - break; + stmt->add_condition(condition); } } } - - stmt.validateWhereClauseForConditions(); + stmt->validate_where_clause_for_conditions(); } return stmt; - } - - protected abstract ModificationStatement prepareInternal(CFMetaData cfm, VariableSpecifications boundNames, Attributes attrs) throws InvalidRequestException; -#endif + }; + protected: + virtual ::shared_ptr prepare_internal(schema_ptr schema, + ::shared_ptr bound_names, std::unique_ptr attrs) = 0; }; }; diff --git a/cql3/statements/update_statement.cc b/cql3/statements/update_statement.cc index 9abf0ad422..bb7899c913 100644 --- a/cql3/statements/update_statement.cc +++ b/cql3/statements/update_statement.cc @@ -25,6 +25,8 @@ #include "update_statement.hh" #include "unimplemented.hh" +#include "cql3/operation_impl.hh" + namespace cql3 { namespace statements { @@ -80,6 +82,60 @@ void update_statement::add_update_for_key(api::mutation& m, const api::clusterin #endif } +::shared_ptr +update_statement::parsed_insert::prepare_internal(schema_ptr schema, + ::shared_ptr bound_names, std::unique_ptr attrs) +{ + auto stmt = ::make_shared(statement_type::INSERT, bound_names->size(), schema, std::move(attrs)); + + // Created from an INSERT + if (stmt->is_counter()) { + throw exceptions::invalid_request_exception("INSERT statement are not allowed on counter tables, use UPDATE instead"); + } + + if (_column_names.size() != _column_values.size()) { + throw exceptions::invalid_request_exception("Unmatched column names/values"); + } + + if (_column_names.empty()) { + throw exceptions::invalid_request_exception("No columns provided to INSERT"); + } + + for (size_t i = 0; i < _column_names.size(); i++) { + auto id = _column_names[i]->prepare_column_identifier(schema); + auto def = get_column_definition(schema, *id); + if (!def) { + throw exceptions::invalid_request_exception(sprint("Unknown identifier %s", *id)); + } + + for (size_t j = 0; j < i; j++) { + auto other_id = _column_names[j]->prepare_column_identifier(schema); + if (*id == *other_id) { + throw exceptions::invalid_request_exception(sprint("Multiple definitions found for column %s", *id)); + } + } + + auto&& value = _column_values[i]; + + switch(def->kind) { + case column_definition::PARTITION: + case column_definition::CLUSTERING: { + auto t = value->prepare(keyspace(), def->column_specification); + t->collect_marker_specification(bound_names); + stmt->add_key_value(*def, std::move(t)); + break; + } + default: { + auto operation = operation::set_value(value).prepare(keyspace(), *def); + operation->collect_marker_specification(bound_names); + stmt->add_operation(std::move(operation)); + break; + } + }; + } + return stmt; +} + } } diff --git a/cql3/statements/update_statement.hh b/cql3/statements/update_statement.hh index ac49158cd5..8dee40cffe 100644 --- a/cql3/statements/update_statement.hh +++ b/cql3/statements/update_statement.hh @@ -60,15 +60,16 @@ namespace statements { * */ class update_statement : public modification_statement { -private: +public: #if 0 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&& attrs) + update_statement(statement_type type, int32_t bound_terms, schema_ptr s, std::unique_ptr attrs) : modification_statement{type, bound_terms, std::move(s), std::move(attrs)} { } +private: virtual bool require_full_clustering_key() const override { return true; } @@ -97,53 +98,10 @@ private: , _column_names{column_names} , _column_values{column_values} { } -#if 0 - protected ModificationStatement prepareInternal(CFMetaData cfm, VariableSpecifications boundNames, Attributes attrs) throws InvalidRequestException - { - UpdateStatement stmt = new UpdateStatement(ModificationStatement.StatementType.INSERT,boundNames.size(), cfm, attrs); - // Created from an INSERT - if (stmt.isCounter()) - throw new InvalidRequestException("INSERT statement are not allowed on counter tables, use UPDATE instead"); - if (columnNames.size() != columnValues.size()) - throw new InvalidRequestException("Unmatched column names/values"); - if (columnNames.isEmpty()) - throw new InvalidRequestException("No columns provided to INSERT"); + virtual ::shared_ptr prepare_internal(schema_ptr schema, + ::shared_ptr bound_names, std::unique_ptr attrs) override; - for (int i = 0; i < columnNames.size(); i++) - { - ColumnIdentifier id = columnNames.get(i).prepare(cfm); - ColumnDefinition def = cfm.getColumnDefinition(id); - if (def == null) - throw new InvalidRequestException(String.format("Unknown identifier %s", id)); - - for (int j = 0; j < i; j++) - { - ColumnIdentifier otherId = columnNames.get(j).prepare(cfm); - if (id.equals(otherId)) - throw new InvalidRequestException(String.format("Multiple definitions found for column %s", id)); - } - - Term.Raw value = columnValues.get(i); - - switch (def.kind) - { - case PARTITION_KEY: - case CLUSTERING_COLUMN: - Term t = value.prepare(keyspace(), def); - t.collectMarkerSpecification(boundNames); - stmt.addKeyValue(def, t); - break; - default: - Operation operation = new Operation.SetValue(value).prepare(keyspace(), def); - operation.collectMarkerSpecification(boundNames); - stmt.addOperation(operation); - break; - } - } - return stmt; - } -#endif }; #if 0