Merge branch cassandra-2.2 into cassandra-3.0
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/a8807391
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/a8807391
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/a8807391
Branch: refs/heads/cassandra-3.0
Commit: a880739187ea5521e8e558a19871985a846b330e
Parents: fa909cc a337907
Author: blerer <benjamin.lerer@datastax.com>
Authored: Tue Oct 20 14:09:16 2015 +0200
Committer: blerer <benjamin.lerer@datastax.com>
Committed: Tue Oct 20 14:10:15 2015 +0200
----------------------------------------------------------------------
CHANGES.txt | 1 +
pylib/cqlshlib/cql3handling.py | 4 ++--
.../org/apache/cassandra/cql3/Operations.java | 16 ++++++++++++-
.../cql3/statements/DeleteStatement.java | 7 +++---
.../cql3/statements/ModificationStatement.java | 21 +++++++++-------
.../cql3/statements/UpdateStatement.java | 25 ++++++++++----------
.../operations/InsertUpdateIfConditionTest.java | 11 +++++++++
7 files changed, 57 insertions(+), 28 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/a8807391/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 5a118ca,261a53a..25ad1fb
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,34 -1,19 +1,35 @@@
-2.2.4
+3.0
+Merged from 2.2:
* Expose phi values from failure detector via JMX and tweak debug
and trace logging (CASSANDRA-9526)
- * Fix RangeNamesQueryPager (CASSANDRA-10509)
- * Deprecate Pig support (CASSANDRA-10542)
- * Reduce contention getting instances of CompositeType (CASSANDRA-10433)
Merged from 2.1:
+ * Fix conditions on static columns (CASSANDRA-10264)
* AssertionError: attempted to delete non-existing file CommitLog (CASSANDRA-10377)
- * (cqlsh) Distinguish negative and positive infinity in output (CASSANDRA-10523)
- * (cqlsh) allow custom time_format for COPY TO (CASSANDRA-8970)
- * Don't allow startup if the node's rack has changed (CASSANDRA-10242)
- * (cqlsh) show partial trace if incomplete after max_trace_wait (CASSANDRA-7645)
-2.2.3
+3.0-rc2
+ * Fix SELECT DISTINCT queries between 2.2.2 nodes and 3.0 nodes (CASSANDRA-10473)
+ * Remove circular references in SegmentedFile (CASSANDRA-10543)
+ * Ensure validation of indexed values only occurs once per-partition (CASSANDRA-10536)
+ * Fix handling of static columns for range tombstones in thrift (CASSANDRA-10174)
+ * Support empty ColumnFilter for backward compatility on empty IN (CASSANDRA-10471)
+ * Remove Pig support (CASSANDRA-10542)
+ * Fix LogFile throws Exception when assertion is disabled (CASSANDRA-10522)
+ * Revert CASSANDRA-7486, make CMS default GC, move GC config to
+ conf/jvm.options (CASSANDRA-10403)
+ * Fix TeeingAppender causing some logs to be truncated/empty (CASSANDRA-10447)
+ * Allow EACH_QUORUM for reads (CASSANDRA-9602)
+ * Fix potential ClassCastException while upgrading (CASSANDRA-10468)
+ * Fix NPE in MVs on update (CASSANDRA-10503)
+ * Only include modified cell data in indexing deltas (CASSANDRA-10438)
+ * Do not load keyspace when creating sstable writer (CASSANDRA-10443)
+ * If node is not yet gossiping write all MV updates to batchlog only (CASSANDRA-10413)
+ * Re-populate token metadata after commit log recovery (CASSANDRA-10293)
+ * Provide additional metrics for materialized views (CASSANDRA-10323)
+ * Flush system schema tables after local schema changes (CASSANDRA-10429)
+Merged from 2.2:
+ * Reduce contention getting instances of CompositeType (CASSANDRA-10433)
+ * Fix the regression when using LIMIT with aggregates (CASSANDRA-10487)
* Avoid NoClassDefFoundError during DataDescriptor initialization on windows (CASSANDRA-10412)
* Preserve case of quoted Role & User names (CASSANDRA-10394)
* cqlsh pg-style-strings broken (CASSANDRA-10484)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/a8807391/pylib/cqlshlib/cql3handling.py
----------------------------------------------------------------------
diff --cc pylib/cqlshlib/cql3handling.py
index 1398e0d,b4edac1..42e542f
--- a/pylib/cqlshlib/cql3handling.py
+++ b/pylib/cqlshlib/cql3handling.py
@@@ -894,7 -874,7 +894,7 @@@ syntax_rules += r''
;
<conditions> ::= <condition> ( "AND" <condition> )*
;
--<condition> ::= <cident> ( "[" <term> "]" )? ( ( "=" | "<" | ">"
| "<=" | ">=" | "!=" ) <term>
++<condition> ::= <cident> ( "[" <term> "]" )? (("=" | "<" | ">" |
"<=" | ">=" | "!=") <term>
| "IN" "(" <term> ( "," <term>
)* ")")
;
'''
http://git-wip-us.apache.org/repos/asf/cassandra/blob/a8807391/src/java/org/apache/cassandra/cql3/Operations.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Operations.java
index c4cade1,0000000..0ef8517
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/Operations.java
+++ b/src/java/org/apache/cassandra/cql3/Operations.java
@@@ -1,135 -1,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.
+ */
+package org.apache.cassandra.cql3;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.cassandra.cql3.functions.Function;
++import org.apache.cassandra.cql3.statements.StatementType;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+
+/**
+ * A set of <code>Operation</code>s.
+ *
+ */
+public final class Operations implements Iterable<Operation>
+{
+ /**
++ * The type of statement.
++ */
++ private final StatementType type;
++
++ /**
+ * The operations on regular columns.
+ */
+ private final List<Operation> regularOperations = new ArrayList<>();
+
+ /**
+ * The operations on static columns.
+ */
+ private final List<Operation> staticOperations = new ArrayList<>();
+
++ public Operations(StatementType type)
++ {
++ this.type = type;
++ }
++
+ /**
+ * Checks if some of the operations apply to static columns.
+ *
+ * @return <code>true</code> if some of the operations apply to static columns,
<code>false</code> otherwise.
+ */
+ public boolean appliesToStaticColumns()
+ {
+ return !staticOperations.isEmpty();
+ }
+
+ /**
+ * Checks if some of the operations apply to regular columns.
+ *
+ * @return <code>true</code> if some of the operations apply to regular
columns, <code>false</code> otherwise.
+ */
+ public boolean appliesToRegularColumns()
+ {
- return !regularOperations.isEmpty();
++ // If we have regular operations, this applies to regular columns.
++ // Otherwise, if the statement is a DELETE and staticOperations is also empty, this
means we have no operations,
++ // which for a DELETE means a full row deletion. Which means the operation applies
to all columns and regular ones in particular.
++ return !regularOperations.isEmpty() || (type.isDelete() && staticOperations.isEmpty());
+ }
+
+ /**
+ * Returns the operation on regular columns.
+ * @return the operation on regular columns
+ */
+ public List<Operation> regularOperations()
+ {
+ return regularOperations;
+ }
+
+ /**
+ * Returns the operation on static columns.
+ * @return the operation on static columns
+ */
+ public List<Operation> staticOperations()
+ {
+ return staticOperations;
+ }
+
+ /**
+ * Adds the specified <code>Operation</code> to this set of operations.
+ * @param operation the operation to add
+ */
+ public void add(Operation operation)
+ {
+ if (operation.column.isStatic())
+ staticOperations.add(operation);
+ else
+ regularOperations.add(operation);
+ }
+
+ /**
+ * Checks if one of the operations requires a read.
+ *
+ * @return <code>true</code> if one of the operations requires a read, <code>false</code>
otherwise.
+ */
+ public boolean requiresRead()
+ {
+ // Lists SET operation incurs a read.
+ for (Operation operation : this)
+ if (operation.requiresRead())
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Checks if this <code>Operations</code> is empty.
+ * @return <code>true</code> if this <code>Operations</code>
is empty, <code>false</code> otherwise.
+ */
+ public boolean isEmpty()
+ {
+ return staticOperations.isEmpty() && regularOperations.isEmpty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<Operation> iterator()
+ {
+ return Iterators.concat(staticOperations.iterator(), regularOperations.iterator());
+ }
+
+ public Iterable<? extends Function> getFunctions()
+ {
+ List<Function> functions = new ArrayList<>();
+ for (Operation operation : this)
+ Iterables.addAll(functions, operation.getFunctions());
+ return functions;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/a8807391/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
index d51f261,ff685cf..0efe35c
--- a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
@@@ -119,19 -116,14 +119,19 @@@ public class DeleteStatement extends Mo
List<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>>
conditions,
boolean ifExists)
{
-- super(name, attrs, conditions, false, ifExists);
++ super(name, StatementType.DELETE, attrs, conditions, false, ifExists);
this.deletions = deletions;
this.whereClause = whereClause;
}
- protected ModificationStatement prepareInternal(CFMetaData cfm, VariableSpecifications
boundNames, Attributes attrs) throws InvalidRequestException
+
+ @Override
+ protected ModificationStatement prepareInternal(CFMetaData cfm,
+ VariableSpecifications boundNames,
+ Conditions conditions,
+ Attributes attrs)
{
- Operations operations = new Operations();
- DeleteStatement stmt = new DeleteStatement(ModificationStatement.StatementType.DELETE,
boundNames.size(), cfm, attrs);
++ Operations operations = new Operations(type);
for (Operation.RawDeletion deletion : deletions)
{
@@@ -143,27 -139,10 +143,26 @@@
Operation op = deletion.prepare(cfm.ksName, def);
op.collectMarkerSpecification(boundNames);
- stmt.addOperation(op);
+ operations.add(op);
}
- StatementRestrictions restrictions = newRestrictions(StatementType.DELETE,
- cfm,
- stmt.processWhereClause(whereClause, boundNames);
++ StatementRestrictions restrictions = newRestrictions(cfm,
+ boundNames,
+ operations,
+ whereClause,
+ conditions);
+
+ DeleteStatement stmt = new DeleteStatement(boundNames.size(),
+ cfm,
+ operations,
+ restrictions,
+ conditions,
+ attrs);
+
+ if (stmt.hasConditions())
+ checkTrue(restrictions.hasAllPKColumnsRestrictedByEqualities(),
+ "DELETE statements must restrict all PRIMARY KEY columns with
equality relations" +
+ " in order to use IF conditions");
return stmt;
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/a8807391/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
index 0e989e6,8b594dd..1ea1e4d
--- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
@@@ -734,14 -748,14 +734,21 @@@ public abstract class ModificationState
public static abstract class Parsed extends CFStatement
{
- protected final Attributes.Raw attrs;
- protected final List<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>>
conditions;
++ protected final StatementType type;
+ private final Attributes.Raw attrs;
+ private final List<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>>
conditions;
private final boolean ifNotExists;
private final boolean ifExists;
-- protected Parsed(CFName name, Attributes.Raw attrs, List<Pair<ColumnIdentifier.Raw,
ColumnCondition.Raw>> conditions, boolean ifNotExists, boolean ifExists)
++ protected Parsed(CFName name,
++ StatementType type,
++ Attributes.Raw attrs,
++ List<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>>
conditions,
++ boolean ifNotExists,
++ boolean ifExists)
{
super(name);
++ this.type = type;
this.attrs = attrs;
this.conditions = conditions == null ? Collections.<Pair<ColumnIdentifier.Raw,
ColumnCondition.Raw>>emptyList() : conditions;
this.ifNotExists = ifNotExists;
@@@ -763,114 -777,59 +770,112 @@@
Attributes preparedAttributes = attrs.prepare(keyspace(), columnFamily());
preparedAttributes.collectMarkerSpecification(boundNames);
- ModificationStatement stmt = prepareInternal(metadata, boundNames, preparedAttributes);
+ Conditions preparedConditions = prepareConditions(metadata, boundNames);
- if (ifNotExists || ifExists || !conditions.isEmpty())
+ return prepareInternal(metadata,
+ boundNames,
+ preparedConditions,
+ preparedAttributes);
+ }
+
+ /**
+ * Returns the column conditions.
+ *
+ * @param metadata the column family meta data
+ * @param boundNames the bound names
+ * @return the column conditions.
+ */
+ private Conditions prepareConditions(CFMetaData metadata, VariableSpecifications
boundNames)
+ {
+ // To have both 'IF EXISTS'/'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.
+ if (ifExists)
{
- if (stmt.isCounter())
- throw new InvalidRequestException("Conditional updates are not supported
on counter tables");
+ assert conditions.isEmpty();
+ assert !ifNotExists;
+ return Conditions.IF_EXISTS_CONDITION;
+ }
- if (attrs.timestamp != null)
- throw new InvalidRequestException("Cannot provide custom timestamp for
conditional updates");
+ if (ifNotExists)
+ {
+ assert conditions.isEmpty();
+ assert !ifExists;
+ return Conditions.IF_NOT_EXISTS_CONDITION;
+ }
- if (ifNotExists)
- {
- // 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));
-
- ColumnCondition condition = entry.right.prepare(keyspace(), def);
- condition.collectMarkerSpecification(boundNames);
-
- switch (def.kind)
- {
- case PARTITION_KEY:
- case CLUSTERING_COLUMN:
- throw new InvalidRequestException(String.format("PRIMARY
KEY column '%s' cannot have IF conditions", id));
- default:
- stmt.addCondition(condition);
- break;
- }
- }
- }
+ if (conditions.isEmpty())
+ return Conditions.EMPTY_CONDITION;
+
+ return prepareColumnConditions(metadata, boundNames);
+ }
+
+ /**
+ * Returns the column conditions.
+ *
+ * @param metadata the column family meta data
+ * @param boundNames the bound names
+ * @return the column conditions.
+ */
+ private ColumnConditions prepareColumnConditions(CFMetaData metadata, VariableSpecifications
boundNames)
+ {
+ checkNull(attrs.timestamp, "Cannot provide custom timestamp for conditional
updates");
+
+ ColumnConditions.Builder builder = ColumnConditions.newBuilder();
+
+ for (Pair<ColumnIdentifier.Raw, ColumnCondition.Raw> entry : conditions)
+ {
+ ColumnIdentifier id = entry.left.prepare(metadata);
+ ColumnDefinition def = metadata.getColumnDefinition(id);
+ checkNotNull(metadata.getColumnDefinition(id), "Unknown identifier %s in
IF conditions", id);
+
+ ColumnCondition condition = entry.right.prepare(keyspace(), def);
+ condition.collectMarkerSpecification(boundNames);
- stmt.validateWhereClauseForConditions();
+ checkFalse(def.isPrimaryKeyColumn(), "PRIMARY KEY column '%s' cannot have
IF conditions", id);
+ builder.add(condition);
}
- return stmt;
+ return builder.build();
}
- protected abstract ModificationStatement prepareInternal(CFMetaData cfm, VariableSpecifications
boundNames, Attributes attrs) throws InvalidRequestException;
+ protected abstract ModificationStatement prepareInternal(CFMetaData cfm,
+ VariableSpecifications
boundNames,
+ Conditions conditions,
+ Attributes attrs);
+
+ /**
+ * Creates the restrictions.
+ *
- * @param type the statement type
+ * @param cfm the column family meta data
+ * @param boundNames the bound names
+ * @param operations the column operations
+ * @param where the where clause
+ * @param conditions the conditions
+ * @return the restrictions
+ */
- protected static StatementRestrictions newRestrictions(StatementType type,
- CFMetaData cfm,
- VariableSpecifications boundNames,
- Operations operations,
- WhereClause where,
- Conditions conditions)
++ protected StatementRestrictions newRestrictions(CFMetaData cfm,
++ VariableSpecifications boundNames,
++ Operations operations,
++ WhereClause where,
++ Conditions conditions)
+ {
+ if (where.containsCustomExpressions())
+ throw new InvalidRequestException(CUSTOM_EXPRESSIONS_NOT_ALLOWED);
+
+ boolean applyOnlyToStaticColumns = appliesOnlyToStaticColumns(operations, conditions);
+ return new StatementRestrictions(type, cfm, where, boundNames, applyOnlyToStaticColumns,
false, false, false);
+ }
+
+ /**
+ * Retrieves the <code>ColumnDefinition</code> corresponding to the
specified raw <code>ColumnIdentifier</code>.
+ *
+ * @param cfm the column family meta data
+ * @param rawId the raw <code>ColumnIdentifier</code>
+ * @return the <code>ColumnDefinition</code> corresponding to the specified
raw <code>ColumnIdentifier</code>
+ */
+ protected static ColumnDefinition getColumnDefinition(CFMetaData cfm, Raw rawId)
+ {
+ ColumnIdentifier id = rawId.prepare(cfm);
+ return checkNotNull(cfm.getColumnDefinition(id), "Unknown identifier %s", id);
+ }
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/a8807391/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
index d6d0266,ad46a0f..6f872d4
--- a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
@@@ -131,42 -166,47 +131,42 @@@ public class UpdateStatement extends Mo
List<Term.Raw> columnValues,
boolean ifNotExists)
{
-- super(name, attrs, null, ifNotExists, false);
++ super(name, StatementType.INSERT, attrs, null, ifNotExists, false);
this.columnNames = columnNames;
this.columnValues = columnValues;
}
- protected ModificationStatement prepareInternal(CFMetaData cfm, VariableSpecifications
boundNames, Attributes attrs) throws InvalidRequestException
+ @Override
+ protected ModificationStatement prepareInternal(CFMetaData cfm,
+ VariableSpecifications boundNames,
+ Conditions conditions,
+ Attributes attrs)
{
- UpdateStatement stmt = new UpdateStatement(ModificationStatement.StatementType.INSERT,
boundNames.size(), cfm, attrs);
// Created from an INSERT
- if (stmt.isCounter())
- throw new InvalidRequestException("INSERT statements are not allowed on
counter tables, use UPDATE instead");
+ checkFalse(cfm.isCounter(), "INSERT statements are not allowed on counter tables,
use UPDATE instead");
- if (columnNames == null)
- throw new InvalidRequestException("Column names for INSERT must be provided
when using VALUES");
- if (columnNames.isEmpty())
- throw new InvalidRequestException("No columns provided to INSERT");
- if (columnNames.size() != columnValues.size())
- throw new InvalidRequestException("Unmatched column names/values");
+ checkFalse(columnNames == null, "Column names for INSERT must be provided when
using VALUES");
+ checkFalse(columnNames.isEmpty(), "No columns provided to INSERT");
+ checkFalse(columnNames.size() != columnValues.size(), "Unmatched column names/values");
+ checkContainsNoDuplicates(columnNames, "The column names contains duplicates");
+
+ WhereClause.Builder whereClause = new WhereClause.Builder();
- Operations operations = new Operations();
++ Operations operations = new Operations(type);
+ boolean hasClusteringColumnsSet = false;
- String ks = keyspace();
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));
+ ColumnDefinition def = getColumnDefinition(cfm, columnNames.get(i));
- 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));
- }
+ if (def.isClusteringColumn())
+ hasClusteringColumnsSet = true;
Term.Raw value = columnValues.get(i);
+
if (def.isPrimaryKeyColumn())
{
- Term t = value.prepare(ks, def);
- t.collectMarkerSpecification(boundNames);
- stmt.addKeyValue(def, t);
+ whereClause.add(new SingleColumnRelation(columnNames.get(i), Operator.EQ,
value));
}
else
{
@@@ -176,24 -216,7 +176,24 @@@
}
}
- return stmt;
+ boolean applyOnlyToStaticColumns = appliesOnlyToStaticColumns(operations, conditions)
&& !hasClusteringColumnsSet;
+
- StatementRestrictions restrictions = new StatementRestrictions(StatementType.INSERT,
++ StatementRestrictions restrictions = new StatementRestrictions(type,
+ cfm,
+ whereClause.build(),
+ boundNames,
+ applyOnlyToStaticColumns,
+ false,
+ false,
+ false);
+
- return new UpdateStatement(StatementType.INSERT,
++ return new UpdateStatement(type,
+ boundNames.size(),
+ cfm,
+ operations,
+ restrictions,
+ conditions,
+ attrs);
}
}
@@@ -206,7 -229,7 +206,7 @@@
public ParsedInsertJson(CFName name, Attributes.Raw attrs, Json.Raw jsonValue, boolean
ifNotExists)
{
-- super(name, attrs, null, ifNotExists, false);
++ super(name, StatementType.INSERT, attrs, null, ifNotExists, false);
this.jsonValue = jsonValue;
}
@@@ -221,48 -242,15 +221,48 @@@
Collection<ColumnDefinition> defs = cfm.allColumns();
Json.Prepared prepared = jsonValue.prepareAndCollectMarkers(cfm, defs, boundNames);
+ WhereClause.Builder whereClause = new WhereClause.Builder();
- Operations operations = new Operations();
++ Operations operations = new Operations(type);
+ boolean hasClusteringColumnsSet = false;
+
for (ColumnDefinition def : defs)
{
+ if (def.isClusteringColumn())
+ hasClusteringColumnsSet = true;
+
+ Term.Raw raw = prepared.getRawTermForColumn(def);
if (def.isPrimaryKeyColumn())
- stmt.addKeyValue(def, prepared.getPrimaryKeyValueForColumn(def));
+ {
+ whereClause.add(new SingleColumnRelation(new ColumnIdentifier.ColumnIdentifierValue(def.name),
+ Operator.EQ,
+ raw));
+ }
else
- stmt.addOperation(prepared.getSetOperationForColumn(def));
+ {
+ Operation operation = new Operation.SetValue(raw).prepare(keyspace(),
def);
+ operation.collectMarkerSpecification(boundNames);
+ operations.add(operation);
+ }
}
- return stmt;
+ boolean applyOnlyToStaticColumns = appliesOnlyToStaticColumns(operations, conditions)
&& !hasClusteringColumnsSet;
+
- StatementRestrictions restrictions = new StatementRestrictions(StatementType.INSERT,
++ StatementRestrictions restrictions = new StatementRestrictions(type,
+ cfm,
+ whereClause.build(),
+ boundNames,
+ applyOnlyToStaticColumns,
+ false,
+ false,
+ false);
+
- return new UpdateStatement(StatementType.INSERT,
++ return new UpdateStatement(type,
+ boundNames.size(),
+ cfm,
+ operations,
+ restrictions,
+ conditions,
+ attrs);
}
}
@@@ -289,18 -277,14 +289,18 @@@
List<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>>
conditions,
boolean ifExists)
{
-- super(name, attrs, conditions, false, ifExists);
++ super(name, StatementType.UPDATE, attrs, conditions, false, ifExists);
this.updates = updates;
this.whereClause = whereClause;
}
- protected ModificationStatement prepareInternal(CFMetaData cfm, VariableSpecifications
boundNames, Attributes attrs) throws InvalidRequestException
+ @Override
+ protected ModificationStatement prepareInternal(CFMetaData cfm,
+ VariableSpecifications boundNames,
+ Conditions conditions,
+ Attributes attrs)
{
- Operations operations = new Operations();
- UpdateStatement stmt = new UpdateStatement(ModificationStatement.StatementType.UPDATE,
boundNames.size(), cfm, attrs);
++ Operations operations = new Operations(type);
for (Pair<ColumnIdentifier.Raw, Operation.RawUpdate> entry : updates)
{
@@@ -310,23 -294,20 +310,22 @@@
Operation operation = entry.right.prepare(keyspace(), def);
operation.collectMarkerSpecification(boundNames);
-
- switch (def.kind)
- {
- case PARTITION_KEY:
- case CLUSTERING_COLUMN:
- throw new InvalidRequestException(String.format("PRIMARY KEY part
%s found in SET part", entry.left));
- default:
- stmt.addOperation(operation);
- break;
- }
+ operations.add(operation);
}
- StatementRestrictions restrictions = newRestrictions(StatementType.UPDATE,
- cfm,
- stmt.processWhereClause(whereClause, boundNames);
- return stmt;
++ StatementRestrictions restrictions = newRestrictions(cfm,
+ boundNames,
+ operations,
+ whereClause,
+ conditions);
+
- return new UpdateStatement(StatementType.UPDATE,
++ return new UpdateStatement(type,
+ boundNames.size(),
+ cfm,
+ operations,
+ restrictions,
+ conditions,
+ attrs);
}
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/a8807391/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
index 9cde6d7,b73ecdf..ade80bb
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
@@@ -188,25 -175,22 +188,36 @@@ public class InsertUpdateIfConditionTes
assertRows(execute("DELETE FROM %s WHERE k='k' AND i=0 IF EXISTS"), row(false));
// CASSANDRA-6430
- assertInvalid("DELETE FROM %s WHERE k = 'k' IF EXISTS");
- assertInvalid("DELETE FROM %s WHERE k = 'k' IF v = 'foo'");
- assertInvalid("DELETE FROM %s WHERE i = 0 IF EXISTS");
- assertInvalid("DELETE FROM %s WHERE k = 0 AND i > 0 IF EXISTS");
- assertInvalid("DELETE FROM %s WHERE k = 0 AND i > 0 IF v = 'foo'");
+ assertInvalidMessage("DELETE statements must restrict all PRIMARY KEY columns with
equality relations in order to use IF conditions",
+ "DELETE FROM %s WHERE k = 'k' IF EXISTS");
+ assertInvalidMessage("DELETE statements must restrict all PRIMARY KEY columns with
equality relations in order to use IF conditions",
+ "DELETE FROM %s WHERE k = 'k' IF v = 'foo'");
+ assertInvalidMessage("Some partition key parts are missing: k",
+ "DELETE FROM %s WHERE i = 0 IF EXISTS");
+
+ assertInvalidMessage("Invalid INTEGER constant (0) for \"k\" of type text",
+ "DELETE FROM %s WHERE k = 0 AND i > 0 IF EXISTS");
+ assertInvalidMessage("Invalid INTEGER constant (0) for \"k\" of type text",
+ "DELETE FROM %s WHERE k = 0 AND i > 0 IF v = 'foo'");
+ assertInvalidMessage("DELETE statements must restrict all PRIMARY KEY columns with
equality relations in order to use IF conditions",
+ "DELETE FROM %s WHERE k = 'k' AND i > 0 IF EXISTS");
+ assertInvalidMessage("DELETE statements must restrict all PRIMARY KEY columns with
equality relations in order to use IF conditions",
+ "DELETE FROM %s WHERE k = 'k' AND i > 0 IF v = 'foo'");
+ assertInvalidMessage("IN on the clustering key columns is not supported with conditional
deletions",
+ "DELETE FROM %s WHERE k = 'k' AND i IN (0, 1) IF v = 'foo'");
+ assertInvalidMessage("IN on the clustering key columns is not supported with conditional
deletions",
+ "DELETE FROM %s WHERE k = 'k' AND i IN (0, 1) IF EXISTS");
+
+ createTable("CREATE TABLE %s(k int, s int static, i int, v text, PRIMARY KEY(k,
i))");
+ execute("INSERT INTO %s (k, s, i, v) VALUES ( 1, 1, 2, '1')");
+ assertRows(execute("DELETE v FROM %s WHERE k = 1 AND i = 2 IF s != 1"), row(false,
1));
+ assertRows(execute("DELETE v FROM %s WHERE k = 1 AND i = 2 IF s = 1"), row(true));
+ assertRows(execute("SELECT * FROM %s WHERE k = 1 AND i = 2"), row(1, 2, 1, null));
+
+ assertRows(execute("DELETE FROM %s WHERE k = 1 AND i = 2 IF s != 1"), row(false,
1));
+ assertRows(execute("DELETE FROM %s WHERE k = 1 AND i = 2 IF s = 1"), row(true));
+ assertEmpty(execute("SELECT * FROM %s WHERE k = 1 AND i = 2"));
+ assertRows(execute("SELECT * FROM %s WHERE k = 1"), row(1, null, 1, null));
}
/**
|