Repository: cassandra Updated Branches: refs/heads/trunk e28860b40 -> d9836e0ef
Fix invalidation of prepared statements on function drops patch by Sam Tunnicliffe; reviewed by Aleksey Yeschenko for CASSANDRA-9166 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/d9836e0e Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/d9836e0e Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/d9836e0e Branch: refs/heads/trunk Commit: d9836e0efe66c0cc0e33f32b605f6920893fa7a5 Parents: e28860b Author: Sam Tunnicliffe <s...@beobal.com> Authored: Mon May 4 00:28:16 2015 +0300 Committer: Aleksey Yeschenko <alek...@apache.org> Committed: Mon May 4 00:28:16 2015 +0300 ---------------------------------------------------------------------- .../org/apache/cassandra/cql3/Attributes.java | 6 - .../org/apache/cassandra/cql3/CQLStatement.java | 9 +- .../apache/cassandra/cql3/ColumnCondition.java | 13 --- .../org/apache/cassandra/cql3/Operation.java | 5 - .../apache/cassandra/cql3/QueryProcessor.java | 73 ++++++------ src/java/org/apache/cassandra/cql3/Term.java | 15 --- .../org/apache/cassandra/cql3/UserTypes.java | 9 -- .../cql3/functions/AbstractFunction.java | 5 - .../cassandra/cql3/functions/Function.java | 2 - .../cassandra/cql3/functions/FunctionCall.java | 5 - .../cassandra/cql3/functions/UDAggregate.java | 12 +- .../cql3/restrictions/AbstractRestriction.java | 36 +----- .../ForwardingPrimaryKeyRestrictions.java | 6 - .../restrictions/MultiColumnRestriction.java | 25 ---- .../restrictions/PrimaryKeyRestrictionSet.java | 6 - .../cql3/restrictions/Restriction.java | 10 +- .../cql3/restrictions/RestrictionSet.java | 10 -- .../cql3/restrictions/Restrictions.java | 10 +- .../restrictions/SingleColumnRestriction.java | 39 +------ .../restrictions/StatementRestrictions.java | 7 -- .../cql3/restrictions/TokenRestriction.java | 13 --- .../selection/AbstractFunctionSelector.java | 5 - .../cassandra/cql3/selection/Selection.java | 11 -- .../cassandra/cql3/selection/Selector.java | 5 - .../cql3/selection/SelectorFactories.java | 8 -- .../cql3/statements/BatchStatement.java | 10 -- .../cql3/statements/ModificationStatement.java | 28 ----- .../cql3/statements/ParsedStatement.java | 7 +- .../cql3/statements/SelectStatement.java | 9 -- .../org/apache/cassandra/cql3/CQLTester.java | 4 +- .../cassandra/cql3/UFIdentificationTest.java | 2 +- test/unit/org/apache/cassandra/cql3/UFTest.java | 117 +++++++++++++++++++ 32 files changed, 180 insertions(+), 342 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/Attributes.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/Attributes.java b/src/java/org/apache/cassandra/cql3/Attributes.java index f3d298b..7b38e9f 100644 --- a/src/java/org/apache/cassandra/cql3/Attributes.java +++ b/src/java/org/apache/cassandra/cql3/Attributes.java @@ -50,12 +50,6 @@ public class Attributes this.timeToLive = timeToLive; } - public boolean usesFunction(String ksName, String functionName) - { - return (timestamp != null && timestamp.usesFunction(ksName, functionName)) - || (timeToLive != null && timeToLive.usesFunction(ksName, functionName)); - } - public Iterable<Function> getFunctions() { if (timestamp != null && timeToLive != null) http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/CQLStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/CQLStatement.java b/src/java/org/apache/cassandra/cql3/CQLStatement.java index 80220a8..02292ad 100644 --- a/src/java/org/apache/cassandra/cql3/CQLStatement.java +++ b/src/java/org/apache/cassandra/cql3/CQLStatement.java @@ -54,13 +54,16 @@ public interface CQLStatement public ResultMessage execute(QueryState state, QueryOptions options) throws RequestValidationException, RequestExecutionException; /** - * Variante of execute used for internal query against the system tables, and thus only query the local node. + * Variant of execute used for internal query against the system tables, and thus only query the local node. * * @param state the current query state */ public ResultMessage executeInternal(QueryState state, QueryOptions options) throws RequestValidationException, RequestExecutionException; - boolean usesFunction(String ksName, String functionName); - + /** + * Return an Iterable over all of the functions (both native and user-defined) used by any component + * of the statement + * @return functions all functions found (may contain duplicates) + */ public Iterable<Function> getFunctions(); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/ColumnCondition.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/ColumnCondition.java b/src/java/org/apache/cassandra/cql3/ColumnCondition.java index acebfe7..c7b5ddb 100644 --- a/src/java/org/apache/cassandra/cql3/ColumnCondition.java +++ b/src/java/org/apache/cassandra/cql3/ColumnCondition.java @@ -97,19 +97,6 @@ public class ColumnCondition return new ColumnCondition(column, collectionElement, inMarker, null, Operator.IN); } - public boolean usesFunction(String ksName, String functionName) - { - 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; - } - public Iterable<Function> getFunctions() { Iterable<Function> iter = Collections.emptyList(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/Operation.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/Operation.java b/src/java/org/apache/cassandra/cql3/Operation.java index d99a00d..4701a96 100644 --- a/src/java/org/apache/cassandra/cql3/Operation.java +++ b/src/java/org/apache/cassandra/cql3/Operation.java @@ -57,11 +57,6 @@ public abstract class Operation this.t = t; } - public boolean usesFunction(String ksName, String functionName) - { - return t != null && t.usesFunction(ksName, functionName); - } - public Iterable<Function> getFunctions() { return t != null ? t.getFunctions() : Collections.<Function>emptySet(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/QueryProcessor.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/QueryProcessor.java b/src/java/org/apache/cassandra/cql3/QueryProcessor.java index f494436..2698a8f 100644 --- a/src/java/org/apache/cassandra/cql3/QueryProcessor.java +++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java @@ -18,52 +18,40 @@ 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.Map; -import java.util.concurrent.*; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Iterators; import com.google.common.primitives.Ints; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap; import com.googlecode.concurrentlinkedhashmap.EntryWeigher; import com.googlecode.concurrentlinkedhashmap.EvictionListener; - import org.antlr.runtime.*; -import org.apache.cassandra.exceptions.CassandraException; -import org.apache.cassandra.service.MigrationListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import org.apache.cassandra.concurrent.ScheduledExecutors; -import org.apache.cassandra.cql3.functions.*; - +import org.apache.cassandra.cql3.functions.Function; +import org.apache.cassandra.cql3.functions.FunctionName; +import org.apache.cassandra.cql3.functions.Functions; 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.composites.*; 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.exceptions.*; import org.apache.cassandra.metrics.CQLMetrics; -import org.apache.cassandra.service.ClientState; -import org.apache.cassandra.service.MigrationManager; -import org.apache.cassandra.service.QueryState; +import org.apache.cassandra.service.*; 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.ByteBufferUtil; -import org.apache.cassandra.utils.FBUtilities; -import org.apache.cassandra.utils.MD5Digest; -import org.apache.cassandra.utils.SemanticVersion; +import org.apache.cassandra.utils.*; import org.github.jamm.MemoryMeter; public class QueryProcessor implements QueryHandler @@ -628,22 +616,37 @@ public class QueryProcessor implements QueryHandler removeInvalidPreparedStatements(ksName, cfName); } - public void onDropFunction(String ksName, String functionName, List<AbstractType<?>> argTypes) { + public void onDropFunction(String ksName, String functionName, List<AbstractType<?>> argTypes) + { removeInvalidPreparedStatementsForFunction(preparedStatements.values().iterator(), ksName, functionName); removeInvalidPreparedStatementsForFunction(thriftPreparedStatements.values().iterator(), ksName, functionName); } + public void onDropAggregate(String ksName, String aggregateName, List<AbstractType<?>> argTypes) { removeInvalidPreparedStatementsForFunction(preparedStatements.values().iterator(), ksName, aggregateName); removeInvalidPreparedStatementsForFunction(thriftPreparedStatements.values().iterator(), ksName, aggregateName); } - private static void removeInvalidPreparedStatementsForFunction(Iterator<ParsedStatement.Prepared> iterator, - String ksName, String functionName) + private static void removeInvalidPreparedStatementsForFunction(Iterator<ParsedStatement.Prepared> statements, + final String ksName, + final String functionName) { - while (iterator.hasNext()) - if (iterator.next().statement.usesFunction(ksName, functionName)) - iterator.remove(); + final Predicate<Function> matchesFunction = new Predicate<Function>() + { + public boolean apply(Function f) + { + return ksName.equals(f.name().keyspace) && functionName.equals(f.name().name); + } + }; + + Iterators.removeIf(statements, new Predicate<ParsedStatement.Prepared>() + { + public boolean apply(ParsedStatement.Prepared statement) + { + return Iterables.any(statement.statement.getFunctions(), matchesFunction); + } + }); } } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/Term.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/Term.java b/src/java/org/apache/cassandra/cql3/Term.java index 6997f78..6fa0c76 100644 --- a/src/java/org/apache/cassandra/cql3/Term.java +++ b/src/java/org/apache/cassandra/cql3/Term.java @@ -70,8 +70,6 @@ public interface Term */ public abstract boolean containsBindMarker(); - boolean usesFunction(String ksName, String functionName); - Iterable<Function> getFunctions(); /** @@ -122,11 +120,6 @@ public interface Term public void collectMarkerSpecification(VariableSpecifications boundNames) {} public Terminal bind(QueryOptions options) { return this; } - public boolean usesFunction(String ksName, String functionName) - { - return false; - } - public Set<Function> getFunctions() { return Collections.emptySet(); @@ -168,14 +161,6 @@ public interface Term */ public abstract class NonTerminal implements Term { - // TODO - this is not necessarily false, yet isn't overridden in concrete classes - // representing collection literals - // e,g "UPDATE table SET map_col = { key_function() : val_function() }) WHERE .... - public boolean usesFunction(String ksName, String functionName) - { - return false; - } - public ByteBuffer bindAndGet(QueryOptions options) throws InvalidRequestException { Terminal t = bind(options); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/UserTypes.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/UserTypes.java b/src/java/org/apache/cassandra/cql3/UserTypes.java index b6d8521..de3f545 100644 --- a/src/java/org/apache/cassandra/cql3/UserTypes.java +++ b/src/java/org/apache/cassandra/cql3/UserTypes.java @@ -150,15 +150,6 @@ public abstract class UserTypes this.values = values; } - public boolean usesFunction(String ksName, String functionName) - { - if (values != null) - for (Term value : values) - if (value != null && value.usesFunction(ksName, functionName)) - return true; - return false; - } - public Iterable<Function> getFunctions() { return Terms.getFunctions(values); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java b/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java index 15ae757..1f5349e 100644 --- a/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java +++ b/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java @@ -67,11 +67,6 @@ public abstract class AbstractFunction implements Function && Objects.equal(this.returnType, that.returnType); } - public boolean usesFunction(String ksName, String functionName) - { - return name.keyspace.equals(ksName) && name.name.equals(functionName); - } - public Iterable<Function> getFunctions() { return ImmutableSet.<Function>of(this); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/functions/Function.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/functions/Function.java b/src/java/org/apache/cassandra/cql3/functions/Function.java index 3c2e5a7..6fb9ba2 100644 --- a/src/java/org/apache/cassandra/cql3/functions/Function.java +++ b/src/java/org/apache/cassandra/cql3/functions/Function.java @@ -50,8 +50,6 @@ public interface Function */ public boolean isAggregate(); - boolean usesFunction(String ksName, String functionName); - Iterable<Function> getFunctions(); boolean hasReferenceTo(Function function); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java b/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java index f42a093..689da5a 100644 --- a/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java +++ b/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java @@ -41,11 +41,6 @@ public class FunctionCall extends Term.NonTerminal this.terms = terms; } - public boolean usesFunction(String ksName, String functionName) - { - return fun.usesFunction(ksName, functionName); - } - public Iterable<Function> getFunctions() { return Iterables.concat(Terms.getFunctions(terms), fun.getFunctions()); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java b/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java index 59f8daa..7eed4f0 100644 --- a/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java +++ b/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java @@ -98,16 +98,12 @@ public class UDAggregate extends AbstractFunction implements AggregateFunction return stateFunction == function || finalFunction == function; } - public boolean usesFunction(String ksName, String functionName) - { - return super.usesFunction(ksName, functionName) - || stateFunction != null && stateFunction.name().keyspace.equals(ksName) && stateFunction.name().name.equals(functionName) - || finalFunction != null && finalFunction.name().keyspace.equals(ksName) && finalFunction.name().name.equals(functionName); - } - public Iterable<Function> getFunctions() { - return ImmutableSet.of(this, stateFunction, finalFunction); + if (finalFunction != null) + return ImmutableSet.of(this, stateFunction, finalFunction); + else + return ImmutableSet.of(this, stateFunction); } public boolean isAggregate() http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/restrictions/AbstractRestriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/AbstractRestriction.java b/src/java/org/apache/cassandra/cql3/restrictions/AbstractRestriction.java index d36162c..64c94f4 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/AbstractRestriction.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/AbstractRestriction.java @@ -18,18 +18,16 @@ package org.apache.cassandra.cql3.restrictions; import java.nio.ByteBuffer; -import java.util.List; import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.QueryOptions; -import org.apache.cassandra.cql3.Term; import org.apache.cassandra.cql3.statements.Bound; import org.apache.cassandra.db.composites.CompositesBuilder; import org.apache.cassandra.exceptions.InvalidRequestException; +import static org.apache.cassandra.cql3.statements.RequestValidations.checkBindValueSet; import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse; import static org.apache.cassandra.cql3.statements.RequestValidations.checkNotNull; -import static org.apache.cassandra.cql3.statements.RequestValidations.checkBindValueSet; /** * Base class for <code>Restriction</code>s @@ -99,34 +97,4 @@ abstract class AbstractRestriction implements Restriction checkFalse(value.remaining() > 0xFFFF, "Index expression values may not be larger than 64K"); return value; } - - /** - * Checks if the specified term is using the specified function. - * - * @param term the term to check - * @param ksName the function keyspace name - * @param functionName the function name - * @return <code>true</code> if the specified term is using the specified function, <code>false</code> otherwise. - */ - protected static final boolean usesFunction(Term term, String ksName, String functionName) - { - return term != null && term.usesFunction(ksName, functionName); - } - - /** - * Checks if one of the specified term is using the specified function. - * - * @param terms the terms to check - * @param ksName the function keyspace name - * @param functionName the function name - * @return <code>true</code> if onee of the specified term is using the specified function, <code>false</code> otherwise. - */ - protected static final boolean usesFunction(List<Term> terms, String ksName, String functionName) - { - if (terms != null) - for (Term value : terms) - if (usesFunction(value, ksName, functionName)) - return true; - return false; - } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java index fd40b7a..03c6cbc 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java @@ -45,12 +45,6 @@ abstract class ForwardingPrimaryKeyRestrictions implements PrimaryKeyRestriction protected abstract PrimaryKeyRestrictions getDelegate(); @Override - public boolean usesFunction(String ksName, String functionName) - { - return getDelegate().usesFunction(ksName, functionName); - } - - @Override public Iterable<Function> getFunctions() { return getDelegate().getFunctions(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java b/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java index 6d3ffab..c4bce4c 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java @@ -135,12 +135,6 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - public boolean usesFunction(String ksName, String functionName) - { - return usesFunction(value, ksName, functionName); - } - - @Override public Iterable<Function> getFunctions() { return value.getFunctions(); @@ -270,12 +264,6 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - public boolean usesFunction(String ksName, String functionName) - { - return usesFunction(values, ksName, functionName); - } - - @Override public Iterable<Function> getFunctions() { return Terms.getFunctions(values); @@ -315,12 +303,6 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - public boolean usesFunction(String ksName, String functionName) - { - return false; - } - - @Override public Iterable<Function> getFunctions() { return Collections.emptySet(); @@ -395,13 +377,6 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - public boolean usesFunction(String ksName, String functionName) - { - return (slice.hasBound(Bound.START) && usesFunction(slice.bound(Bound.START), ksName, functionName)) - || (slice.hasBound(Bound.END) && usesFunction(slice.bound(Bound.END), ksName, functionName)); - } - - @Override public Iterable<Function> getFunctions() { return slice.getFunctions(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java b/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java index ab61628..b49d774 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java @@ -141,12 +141,6 @@ final class PrimaryKeyRestrictionSet extends AbstractPrimaryKeyRestrictions } @Override - public boolean usesFunction(String ksName, String functionName) - { - return restrictions.usesFunction(ksName, functionName); - } - - @Override public Iterable<Function> getFunctions() { return restrictions.getFunctions(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java b/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java index 71dc373..c115a3b 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java @@ -63,14 +63,10 @@ public interface Restriction public Collection<ColumnDefinition> getColumnDefs(); /** - * Returns <code>true</code> if one of the restrictions use the specified function. - * - * @param ksName the keyspace name - * @param functionName the function name - * @return <code>true</code> if one of the restrictions use the specified function, <code>false</code> otherwise. + * Return an Iterable over all of the functions (both native and user-defined) used by any component + * of the restriction + * @return functions all functions found (may contain duplicates) */ - public boolean usesFunction(String ksName, String functionName); - public Iterable<Function> getFunctions(); /** http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java b/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java index 3a236cc..6bf7666 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java @@ -81,16 +81,6 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction> } @Override - public boolean usesFunction(String ksName, String functionName) - { - for (Restriction restriction : restrictions.values()) - if (restriction.usesFunction(ksName, functionName)) - return true; - - return false; - } - - @Override public Iterable<Function> getFunctions() { com.google.common.base.Function<Restriction, Iterable<Function>> transform = http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java index 7487734..ab81bf7 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java @@ -39,14 +39,10 @@ interface Restrictions public Collection<ColumnDefinition> getColumnDefs(); /** - * Returns <code>true</code> if one of the restrictions use the specified function. - * - * @param ksName the keyspace name - * @param functionName the function name - * @return <code>true</code> if one of the restrictions use the specified function, <code>false</code> otherwise. + * Return an Iterable over all of the functions (both native and user-defined) used by any component + * of the restrictions + * @return functions all functions found (may contain duplicates) */ - public boolean usesFunction(String ksName, String functionName); - public Iterable<Function> getFunctions(); /** http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java b/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java index 69ef5d2..d32f585 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java @@ -23,12 +23,10 @@ import java.util.*; import com.google.common.collect.Iterables; import org.apache.cassandra.config.ColumnDefinition; - import org.apache.cassandra.cql3.*; import org.apache.cassandra.cql3.Term.Terminal; import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.statements.Bound; - import org.apache.cassandra.db.IndexExpression; import org.apache.cassandra.db.composites.CompositesBuilder; import org.apache.cassandra.db.index.SecondaryIndex; @@ -36,12 +34,11 @@ import org.apache.cassandra.db.index.SecondaryIndexManager; import org.apache.cassandra.db.marshal.CompositeType; import org.apache.cassandra.exceptions.InvalidRequestException; -import static org.apache.cassandra.cql3.statements.RequestValidations.checkNotNull; - +import static org.apache.cassandra.cql3.statements.RequestValidations.checkBindValueSet; import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse; +import static org.apache.cassandra.cql3.statements.RequestValidations.checkNotNull; import static org.apache.cassandra.cql3.statements.RequestValidations.checkTrue; import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest; -import static org.apache.cassandra.cql3.statements.RequestValidations.checkBindValueSet; public abstract class SingleColumnRestriction extends AbstractRestriction { @@ -111,12 +108,6 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public boolean usesFunction(String ksName, String functionName) - { - return usesFunction(value, ksName, functionName); - } - - @Override public Iterable getFunctions() { return value.getFunctions(); @@ -225,12 +216,6 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public boolean usesFunction(String ksName, String functionName) - { - return usesFunction(values, ksName, functionName); - } - - @Override public Iterable<Function> getFunctions() { return Terms.getFunctions(values); @@ -263,12 +248,6 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public boolean usesFunction(String ksName, String functionName) - { - return false; - } - - @Override public Iterable<Function> getFunctions() { return Collections.emptySet(); @@ -302,13 +281,6 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public boolean usesFunction(String ksName, String functionName) - { - return (slice.hasBound(Bound.START) && usesFunction(slice.bound(Bound.START), ksName, functionName)) - || (slice.hasBound(Bound.END) && usesFunction(slice.bound(Bound.END), ksName, functionName)); - } - - @Override public Iterable<Function> getFunctions() { return slice.getFunctions(); @@ -509,13 +481,6 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public boolean usesFunction(String ksName, String functionName) - { - return usesFunction(values, ksName, functionName) || usesFunction(keys, ksName, functionName) || - usesFunction(entryKeys, ksName, functionName) || usesFunction(entryValues, ksName, functionName); - } - - @Override public Iterable<Function> getFunctions() { return Iterables.concat(Terms.getFunctions(values), http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java index dcaad47..f848e2e 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java @@ -173,13 +173,6 @@ public final class StatementRestrictions addSingleColumnRestriction((SingleColumnRestriction) restriction); } - public boolean usesFunction(String ksName, String functionName) - { - return partitionKeyRestrictions.usesFunction(ksName, functionName) - || clusteringColumnsRestrictions.usesFunction(ksName, functionName) - || nonPrimaryKeyRestrictions.usesFunction(ksName, functionName); - } - public Iterable<Function> getFunctions() { return Iterables.concat(partitionKeyRestrictions.getFunctions(), http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java b/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java index 5a00bd4..f8cd0dc 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java @@ -173,12 +173,6 @@ public abstract class TokenRestriction extends AbstractPrimaryKeyRestrictions } @Override - public boolean usesFunction(String ksName, String functionName) - { - return usesFunction(value, ksName, functionName); - } - - @Override public Iterable<Function> getFunctions() { return value.getFunctions(); @@ -233,13 +227,6 @@ public abstract class TokenRestriction extends AbstractPrimaryKeyRestrictions } @Override - public boolean usesFunction(String ksName, String functionName) - { - return (slice.hasBound(Bound.START) && usesFunction(slice.bound(Bound.START), ksName, functionName)) - || (slice.hasBound(Bound.END) && usesFunction(slice.bound(Bound.END), ksName, functionName)); - } - - @Override public Iterable<Function> getFunctions() { return slice.getFunctions(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java b/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java index 11e7e48..1dd1903 100644 --- a/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java +++ b/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java @@ -68,11 +68,6 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector return fun.returnType(); } - public boolean usesFunction(String ksName, String functionName) - { - return fun.usesFunction(ksName, functionName); - } - public Iterable<Function> getFunctions() { return Iterables.concat(fun.getFunctions(), factories.getFunctions()); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/selection/Selection.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/selection/Selection.java b/src/java/org/apache/cassandra/cql3/selection/Selection.java index 25bce78..9c990ce 100644 --- a/src/java/org/apache/cassandra/cql3/selection/Selection.java +++ b/src/java/org/apache/cassandra/cql3/selection/Selection.java @@ -174,11 +174,6 @@ public abstract class Selection return columns.size() - 1; } - public boolean usesFunction(String ksName, String functionName) - { - return false; - } - public Iterable<Function> getFunctions() { return Collections.emptySet(); @@ -483,12 +478,6 @@ public abstract class Selection } @Override - public boolean usesFunction(String ksName, String functionName) - { - return factories.usesFunction(ksName, functionName); - } - - @Override public Iterable<Function> getFunctions() { return factories.getFunctions(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/selection/Selector.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/selection/Selector.java b/src/java/org/apache/cassandra/cql3/selection/Selector.java index 8c1e6b8..2d345de 100644 --- a/src/java/org/apache/cassandra/cql3/selection/Selector.java +++ b/src/java/org/apache/cassandra/cql3/selection/Selector.java @@ -42,11 +42,6 @@ public abstract class Selector implements AssignmentTestable */ public static abstract class Factory { - public boolean usesFunction(String ksName, String functionName) - { - return false; - } - public Iterable<Function> getFunctions() { return Collections.emptySet(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java b/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java index 6de766a..beb7399 100644 --- a/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java +++ b/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java @@ -89,14 +89,6 @@ final class SelectorFactories implements Iterable<Selector.Factory> } } - public boolean usesFunction(String ksName, String functionName) - { - for (Factory factory : factories) - if (factory != null && factory.usesFunction(ksName, functionName)) - return true; - return false; - } - public Iterable<Function> getFunctions() { Iterable<Function> functions = Collections.emptySet(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java index 27a6ffb..465b2d9 100644 --- a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java @@ -76,16 +76,6 @@ public class BatchStatement implements CQLStatement this.hasConditions = hasConditions; } - public boolean usesFunction(String ksName, String functionName) - { - if (attrs.usesFunction(ksName, functionName)) - return true; - for (ModificationStatement statement : statements) - if (statement.usesFunction(ksName, functionName)) - return true; - return false; - } - public Iterable<org.apache.cassandra.cql3.functions.Function> getFunctions() { Iterable<org.apache.cassandra.cql3.functions.Function> functions = attrs.getFunctions(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java index e7a1a20..0862a9f 100644 --- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java @@ -20,7 +20,6 @@ package org.apache.cassandra.cql3.statements; import java.nio.ByteBuffer; import java.util.*; -import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -95,33 +94,6 @@ public abstract class ModificationStatement implements CQLStatement this.attrs = attrs; } - public boolean usesFunction(String ksName, final String functionName) - { - if (attrs.usesFunction(ksName, functionName)) - return true; - - for (Restriction restriction : processedKeys.values()) - if (restriction.usesFunction(ksName, functionName)) - return true; - - if (columnOperations != null) - for (Operation operation : columnOperations) - if (operation.usesFunction(ksName, functionName)) - return true; - - if (columnConditions != null) - for (ColumnCondition condition : columnConditions) - if (condition.usesFunction(ksName, functionName)) - return true; - - if (staticConditions != null) - for (ColumnCondition condition : staticConditions) - if (condition.usesFunction(ksName, functionName)) - return true; - - return false; - } - public Iterable<Function> getFunctions() { Iterable<Function> functions = attrs.getFunctions(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java b/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java index b848df4..539a957 100644 --- a/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java @@ -65,12 +65,7 @@ public abstract class ParsedStatement } } - public boolean usesFunction(String ksName, String functionName) - { - return false; - } - - public List<Function> getFunctions() + public Iterable<Function> getFunctions() { return Collections.emptyList(); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index 8f7f75e..fe473aa 100644 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@ -106,15 +106,6 @@ public class SelectStatement implements CQLStatement this.limit = limit; } - @Override - public boolean usesFunction(String ksName, String functionName) - { - return selection.usesFunction(ksName, functionName) - || restrictions.usesFunction(ksName, functionName) - || (limit != null && limit.usesFunction(ksName, functionName)); - } - - @Override public Iterable<Function> getFunctions() { return Iterables.concat(selection.getFunctions(), http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/test/unit/org/apache/cassandra/cql3/CQLTester.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/CQLTester.java b/test/unit/org/apache/cassandra/cql3/CQLTester.java index b2135aa..c318717 100644 --- a/test/unit/org/apache/cassandra/cql3/CQLTester.java +++ b/test/unit/org/apache/cassandra/cql3/CQLTester.java @@ -303,7 +303,9 @@ public abstract class CQLTester private static boolean containsAny(String filename, List<String> tables) { for (int i = 0, m = tables.size(); i < m; i++) - if (filename.contains(tables.get(i))) + // don't accidentally delete in-use directories with the + // same prefix as a table to delete, i.e. table_1 & table_11 + if (filename.contains(tables.get(i) + "-")) return true; return false; } http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/test/unit/org/apache/cassandra/cql3/UFIdentificationTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/UFIdentificationTest.java b/test/unit/org/apache/cassandra/cql3/UFIdentificationTest.java index cfa42b3..044c98b 100644 --- a/test/unit/org/apache/cassandra/cql3/UFIdentificationTest.java +++ b/test/unit/org/apache/cassandra/cql3/UFIdentificationTest.java @@ -158,7 +158,7 @@ public class UFIdentificationTest extends CQLTester @Test @Ignore // Technically, attributes like timestamp and ttl are Terms so could potentially - // resolve to function calls (& so you can call usesFunction & getFunctions on them) + // resolve to function calls (& so you can call getFunctions on them) // However, this is currently disallowed by CQL syntax public void testModificationStatementWithAttributesFromFunction() throws Throwable { http://git-wip-us.apache.org/repos/asf/cassandra/blob/d9836e0e/test/unit/org/apache/cassandra/cql3/UFTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/UFTest.java b/test/unit/org/apache/cassandra/cql3/UFTest.java index 3c6baf8..42bddf3 100644 --- a/test/unit/org/apache/cassandra/cql3/UFTest.java +++ b/test/unit/org/apache/cassandra/cql3/UFTest.java @@ -29,6 +29,7 @@ import com.datastax.driver.core.*; import org.apache.cassandra.cql3.functions.FunctionName; import org.apache.cassandra.cql3.functions.Functions; import org.apache.cassandra.cql3.functions.UDFunction; +import org.apache.cassandra.db.marshal.CollectionType; import org.apache.cassandra.exceptions.FunctionExecutionException; import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.service.ClientState; @@ -176,6 +177,122 @@ public class UFTest extends CQLTester } @Test + public void testDropFunctionDropsPreparedStatementsWithDelayedValues() throws Throwable + { + // test that dropping a function removes stmts which use + // it to provide a DelayedValue collection from the + // cache in QueryProcessor + checkDelayedValuesCorrectlyIdentifyFunctionsInUse(false); + } + + @Test + public void testDropKeyspaceContainingFunctionDropsPreparedStatementsWithDelayedValues() throws Throwable + { + // test that dropping a function removes stmts which use + // it to provide a DelayedValue collection from the + // cache in QueryProcessor + checkDelayedValuesCorrectlyIdentifyFunctionsInUse(true); + } + + private ResultMessage.Prepared prepareStatementWithDelayedValue(CollectionType.Kind kind, String function) + { + String collectionType; + String literalArgs; + switch (kind) + { + case LIST: + collectionType = "list<double>"; + literalArgs = String.format("[%s(0.0)]", function); + break; + case SET: + collectionType = "set<double>"; + literalArgs = String.format("{%s(0.0)}", function); + break; + case MAP: + collectionType = "map<double, double>"; + literalArgs = String.format("{%s(0.0):0.0}", function); + break; + default: + Assert.fail("Unsupported collection type " + kind); + collectionType = null; + literalArgs = null; + } + + createTable("CREATE TABLE %s (" + + " key int PRIMARY KEY," + + " val " + collectionType + ")"); + + ResultMessage.Prepared prepared = QueryProcessor.prepare( + String.format("INSERT INTO %s.%s (key, val) VALUES (?, %s)", + KEYSPACE, + currentTable(), + literalArgs), + ClientState.forInternalCalls(), false); + Assert.assertNotNull(QueryProcessor.instance.getPrepared(prepared.statementId)); + return prepared; + } + + private ResultMessage.Prepared prepareStatementWithDelayedValueTuple(String function) + { + createTable("CREATE TABLE %s (" + + " key int PRIMARY KEY," + + " val tuple<double> )"); + + ResultMessage.Prepared prepared = QueryProcessor.prepare( + String.format("INSERT INTO %s.%s (key, val) VALUES (?, (%s(0.0)))", + KEYSPACE, + currentTable(), + function), + ClientState.forInternalCalls(), false); + Assert.assertNotNull(QueryProcessor.instance.getPrepared(prepared.statementId)); + return prepared; + } + + public void checkDelayedValuesCorrectlyIdentifyFunctionsInUse(boolean dropKeyspace) throws Throwable + { + // prepare a statement which doesn't use any function for a control + createTable("CREATE TABLE %s (" + + " key int PRIMARY KEY," + + " val double)"); + ResultMessage.Prepared control = QueryProcessor.prepare( + String.format("INSERT INTO %s.%s (key, val) VALUES (?, ?)", + KEYSPACE, + currentTable()), + ClientState.forInternalCalls(), false); + Assert.assertNotNull(QueryProcessor.instance.getPrepared(control.statementId)); + + // a function that we'll drop and verify that statements which use it to + // provide a DelayedValue are removed from the cache in QueryProcessor + String function = createFunction(KEYSPACE_PER_TEST, "double", + "CREATE FUNCTION %s ( input double ) " + + "RETURNS double " + + "LANGUAGE javascript " + + "AS 'input'"); + Assert.assertEquals(1, Functions.find(parseFunctionName(function)).size()); + + List<ResultMessage.Prepared> prepared = new ArrayList<>(); + // prepare statements which use the function to provide a DelayedValue + prepared.add(prepareStatementWithDelayedValue(CollectionType.Kind.LIST, function)); + prepared.add(prepareStatementWithDelayedValue(CollectionType.Kind.SET, function)); + prepared.add(prepareStatementWithDelayedValue(CollectionType.Kind.MAP, function)); + prepared.add(prepareStatementWithDelayedValueTuple(function)); + + // what to drop - the function is scoped to the per-test keyspace, but the prepared statements + // select from the per-fixture keyspace. So if we drop the per-test keyspace, the function + // should be removed along with the statements that reference it. The control statement should + // remain present in the cache. Likewise, if we actually drop the function itself the control + // statement should not be removed, but the others should be + if (dropKeyspace) + dropPerTestKeyspace(); + else + execute("DROP FUNCTION " + function); + + Assert.assertNotNull(QueryProcessor.instance.getPrepared(control.statementId)); + for (ResultMessage.Prepared removed : prepared) + Assert.assertNull(QueryProcessor.instance.getPrepared(removed.statementId)); + } + + @Test public void testFunctionCreationAndDrop() throws Throwable { createTable("CREATE TABLE %s (key int PRIMARY KEY, d double)");