cql3: Convert ModificationStatement.Parsed.prepare()

Together with ParsedInsert descendant.
This commit is contained in:
Tomasz Grabiec
2015-02-04 10:14:45 +01:00
parent 89f924f9f9
commit bad22fe50e
4 changed files with 183 additions and 186 deletions

View File

@@ -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<restrictions::restriction> 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<term> value) {
add_key_values(def, ::make_shared<restrictions::single_column_restriction::EQ>(def, value));
}
void
modification_statement::precess_where_clause(std::vector<relation_ptr> where_clause, ::shared_ptr<variable_specifications> 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<single_column_relation>(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()));
}
}
}
}
}

View File

@@ -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 <memory>
@@ -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<operation> 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<ColumnDefinition> getColumnsWithConditions()
{
if (ifNotExists || ifExists)
@@ -231,27 +234,17 @@ public:
return Iterables.concat(columnConditions == null ? Collections.<ColumnDefinition>emptyList() : Iterables.transform(columnConditions, getColumnForCondition),
staticConditions == null ? Collections.<ColumnDefinition>emptyList() : Iterables.transform(staticConditions, getColumnForCondition));
}
public void addCondition(ColumnCondition cond)
{
List<ColumnCondition> conds = null;
if (cond.column.isStatic())
{
setsStaticColumns = true;
if (staticConditions == null)
staticConditions = new ArrayList<ColumnCondition>();
conds = staticConditions;
}
else
{
setsRegularColumns = true;
if (columnConditions == null)
columnConditions = new ArrayList<ColumnCondition>();
conds = columnConditions;
}
conds.add(cond);
}
#endif
public:
void add_condition(::shared_ptr<column_condition> 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<Relation> 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<restrictions::restriction> values);
public:
void add_key_value(column_definition& def, ::shared_ptr<term> value);
void precess_where_clause(std::vector<relation_ptr> where_clause, ::shared_ptr<variable_specifications> names);
std::vector<api::partition_key> 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<cf_name>&& name, ::shared_ptr<attributes::raw> attrs, const conditions_vector& conditions, bool if_not_exists, bool if_exists)
parsed(std::experimental::optional<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}
@@ -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<parsed_statement::prepared> prepare(database& db) override {
auto bound_names = get_bound_variables();
auto statement = prepare(db, bound_names);
return std::make_unique<parsed_statement::prepared>(std::move(statement), *bound_names);
}
public ModificationStatement prepare(VariableSpecifications boundNames) throws InvalidRequestException
{
CFMetaData metadata = ThriftValidation.validateColumnFamily(keyspace(), columnFamily());
::shared_ptr<modification_statement> prepare(database& db, ::shared_ptr<variable_specifications> 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<modification_statement> 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<ColumnIdentifier.Raw, ColumnCondition.Raw> 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<modification_statement> prepare_internal(schema_ptr schema,
::shared_ptr<variable_specifications> bound_names, std::unique_ptr<attributes> attrs) = 0;
};
};

View File

@@ -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<modification_statement>
update_statement::parsed_insert::prepare_internal(schema_ptr schema,
::shared_ptr<variable_specifications> bound_names, std::unique_ptr<attributes> attrs)
{
auto stmt = ::make_shared<update_statement>(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;
}
}
}

View File

@@ -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<attributes>&& attrs)
update_statement(statement_type type, int32_t bound_terms, schema_ptr s, std::unique_ptr<attributes> 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<modification_statement> prepare_internal(schema_ptr schema,
::shared_ptr<variable_specifications> bound_names, std::unique_ptr<attributes> 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