cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tylerho...@apache.org
Subject [3/3] cassandra git commit: User/role permissions for UDFs
Date Tue, 14 Apr 2015 17:46:57 GMT
User/role permissions for UDFs

Patch by Sam Tunnicliffe; reviewed by Tyler Hobbs for CASSANDRA-7557


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/cb5897f3
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/cb5897f3
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/cb5897f3

Branch: refs/heads/trunk
Commit: cb5897f3cb425334e693773fc88988de944fe247
Parents: d6a4b45
Author: Sam Tunnicliffe <sam@beobal.com>
Authored: Tue Apr 14 12:45:52 2015 -0500
Committer: Tyler Hobbs <tyler@datastax.com>
Committed: Tue Apr 14 12:46:40 2015 -0500

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 pylib/cqlshlib/cql3handling.py                  |   8 +-
 .../cassandra/auth/AuthMigrationListener.java   |  10 +
 .../cassandra/auth/CassandraRoleManager.java    |   8 +-
 .../apache/cassandra/auth/FunctionResource.java | 327 +++++++
 .../org/apache/cassandra/auth/Permission.java   |   7 +-
 .../org/apache/cassandra/auth/Resources.java    |   2 +
 .../apache/cassandra/cql3/AbstractMarker.java   |   8 +
 .../org/apache/cassandra/cql3/Attributes.java   |  16 +
 .../org/apache/cassandra/cql3/CQLStatement.java |   7 +-
 .../apache/cassandra/cql3/ColumnCondition.java  |  23 +-
 src/java/org/apache/cassandra/cql3/Cql.g        |  27 +-
 src/java/org/apache/cassandra/cql3/Json.java    |  15 +-
 src/java/org/apache/cassandra/cql3/Lists.java   |  12 +-
 src/java/org/apache/cassandra/cql3/Maps.java    |  11 +-
 .../org/apache/cassandra/cql3/Operation.java    |   7 +
 src/java/org/apache/cassandra/cql3/Sets.java    |   7 +-
 src/java/org/apache/cassandra/cql3/Term.java    |  13 +
 src/java/org/apache/cassandra/cql3/Terms.java   |  45 +
 src/java/org/apache/cassandra/cql3/Tuples.java  |  10 +-
 .../org/apache/cassandra/cql3/UserTypes.java    |   8 +-
 .../cql3/functions/AbstractFunction.java        |   6 +
 .../cassandra/cql3/functions/Function.java      |   3 +-
 .../cassandra/cql3/functions/FunctionCall.java  |  15 +-
 .../cassandra/cql3/functions/UDAggregate.java   |   8 +-
 .../ForwardingPrimaryKeyRestrictions.java       |   7 +
 .../restrictions/MultiColumnRestriction.java    |  33 +-
 .../restrictions/PrimaryKeyRestrictionSet.java  |   7 +
 .../cql3/restrictions/Restriction.java          |   3 +
 .../cql3/restrictions/RestrictionSet.java       |  20 +-
 .../cql3/restrictions/Restrictions.java         |   5 +-
 .../restrictions/SingleColumnRestriction.java   |  46 +-
 .../restrictions/StatementRestrictions.java     |  19 +-
 .../cassandra/cql3/restrictions/TermSlice.java  |  17 +
 .../cql3/restrictions/TokenRestriction.java     |  13 +
 .../selection/AbstractFunctionSelector.java     |   6 +
 .../cassandra/cql3/selection/Selection.java     |  27 +-
 .../cassandra/cql3/selection/Selector.java      |   9 +-
 .../cql3/selection/SelectorFactories.java       |  20 +-
 .../cql3/statements/BatchStatement.java         |  16 +-
 .../statements/CreateAggregateStatement.java    | 130 ++-
 .../statements/CreateFunctionStatement.java     |  59 +-
 .../statements/CreateKeyspaceStatement.java     |  14 +-
 .../cql3/statements/DropFunctionStatement.java  | 121 ++-
 .../cql3/statements/ModificationStatement.java  |  68 +-
 .../cql3/statements/ParsedStatement.java        |   6 +
 .../PermissionsManagementStatement.java         |  13 +-
 .../cql3/statements/SelectStatement.java        |  21 +-
 .../apache/cassandra/service/ClientState.java   |  31 +
 .../org/apache/cassandra/cql3/UFAuthTest.java   | 945 +++++++++++++++++++
 .../cassandra/cql3/UFIdentificationTest.java    | 375 ++++++++
 test/unit/org/apache/cassandra/cql3/UFTest.java |  45 +-
 52 files changed, 2443 insertions(+), 237 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 4a1cd1c..973b1bd 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0
+ * Add user/role permissions for user-defined functions (CASSANDRA-7557)
  * Allow cassandra config to be updated to restart daemon without unloading classes (CASSANDRA-9046)
  * Don't initialize compaction writer before checking if iter is empty (CASSANDRA-9117)
  * Remove line number generation from default logback.xml

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/pylib/cqlshlib/cql3handling.py
----------------------------------------------------------------------
diff --git a/pylib/cqlshlib/cql3handling.py b/pylib/cqlshlib/cql3handling.py
index a728fed..bc638b6 100644
--- a/pylib/cqlshlib/cql3handling.py
+++ b/pylib/cqlshlib/cql3handling.py
@@ -1207,7 +1207,7 @@ syntax_rules += r'''
 '''
 
 syntax_rules += r'''
-<grantStatement> ::= "GRANT" <permissionExpr> "ON" <resource>  "TO" <rolename>
+<grantStatement> ::= "GRANT" <permissionExpr> "ON" <resource> "TO" <rolename>
                    ;
 
 <revokeStatement> ::= "REVOKE" <permissionExpr> "ON" <resource> "FROM" <rolename>
@@ -1224,6 +1224,7 @@ syntax_rules += r'''
                | "SELECT"
                | "MODIFY"
                | "DESCRIBE"
+               | "EXECUTE"
                ;
 
 <permissionExpr> ::= ( <permission> "PERMISSION"? )
@@ -1232,6 +1233,7 @@ syntax_rules += r'''
 
 <resource> ::= <dataResource>
              | <roleResource>
+             | <functionResource>
              ;
 
 <dataResource> ::= ( "ALL" "KEYSPACES" )
@@ -1242,6 +1244,10 @@ syntax_rules += r'''
 <roleResource> ::= ("ALL" "ROLES")
                  | ("ROLE" <rolename>)
                  ;
+
+<functionResource> ::= ( "ALL" "FUNCTIONS" ("IN KEYSPACE" <keyspaceName>)? )
+                     | ("FUNCTION" <userFunctionName>)
+                     ;
 '''
 
 @completer_for('username', 'name')

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/auth/AuthMigrationListener.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/auth/AuthMigrationListener.java b/src/java/org/apache/cassandra/auth/AuthMigrationListener.java
index f990bec..fe34329 100644
--- a/src/java/org/apache/cassandra/auth/AuthMigrationListener.java
+++ b/src/java/org/apache/cassandra/auth/AuthMigrationListener.java
@@ -17,7 +17,10 @@
  */
 package org.apache.cassandra.auth;
 
+import java.util.List;
+
 import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.service.MigrationListener;
 
 /**
@@ -28,10 +31,17 @@ public class AuthMigrationListener extends MigrationListener
     public void onDropKeyspace(String ksName)
     {
         DatabaseDescriptor.getAuthorizer().revokeAllOn(DataResource.keyspace(ksName));
+        DatabaseDescriptor.getAuthorizer().revokeAllOn(FunctionResource.keyspace(ksName));
     }
 
     public void onDropColumnFamily(String ksName, String cfName)
     {
         DatabaseDescriptor.getAuthorizer().revokeAllOn(DataResource.table(ksName, cfName));
     }
+
+    public void onDropFunction(String ksName, String functionName, List<AbstractType<?>> argTypes)
+    {
+        DatabaseDescriptor.getAuthorizer()
+                          .revokeAllOn(FunctionResource.function(ksName, functionName, argTypes));
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/auth/CassandraRoleManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/auth/CassandraRoleManager.java b/src/java/org/apache/cassandra/auth/CassandraRoleManager.java
index 66b283d..261631d 100644
--- a/src/java/org/apache/cassandra/auth/CassandraRoleManager.java
+++ b/src/java/org/apache/cassandra/auth/CassandraRoleManager.java
@@ -187,15 +187,15 @@ public class CassandraRoleManager implements IRoleManager
                                          AuthKeyspace.NAME,
                                          AuthKeyspace.ROLES,
                                          escape(role.getRoleName()),
-                                         options.getSuperuser().get(),
-                                         options.getLogin().get(),
+                                         options.getSuperuser().or(false),
+                                         options.getLogin().or(false),
                                          escape(hashpw(options.getPassword().get())))
                          : String.format("INSERT INTO %s.%s (role, is_superuser, can_login) VALUES ('%s', %s, %s)",
                                          AuthKeyspace.NAME,
                                          AuthKeyspace.ROLES,
                                          escape(role.getRoleName()),
-                                         options.getSuperuser().get(),
-                                         options.getLogin().get());
+                                         options.getSuperuser().or(false),
+                                         options.getLogin().or(false));
         process(insertCql, consistencyForRole(role.getRoleName()));
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/auth/FunctionResource.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/auth/FunctionResource.java b/src/java/org/apache/cassandra/auth/FunctionResource.java
new file mode 100644
index 0000000..1421541
--- /dev/null
+++ b/src/java/org/apache/cassandra/auth/FunctionResource.java
@@ -0,0 +1,327 @@
+/*
+ * 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.auth;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Sets;
+import org.apache.commons.lang3.StringUtils;
+
+import org.apache.cassandra.config.Schema;
+import org.apache.cassandra.cql3.CQL3Type;
+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.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.TypeParser;
+
+/**
+ * IResource implementation representing functions.
+ *
+ * The root level "functions" resource represents the collection of all Functions.
+ * "functions"                          - root level resource representing all functions defined across every keyspace
+ * "functions/keyspace"                 - keyspace level resource to apply permissions to all functions within a keyspace
+ * "functions/keyspace/function"        - a specific function, scoped to a given keyspace
+ */
+public class FunctionResource implements IResource
+{
+    enum Level
+    {
+        ROOT, KEYSPACE, FUNCTION
+    }
+
+    // permissions which may be granted on either a resource representing some collection of functions
+    // i.e. the root resource (all functions) or a keyspace level resource (all functions in a given keyspace)
+    private static final Set<Permission> COLLECTION_LEVEL_PERMISSIONS = Sets.immutableEnumSet(Permission.CREATE,
+                                                                                              Permission.ALTER,
+                                                                                              Permission.DROP,
+                                                                                              Permission.AUTHORIZE,
+                                                                                              Permission.EXECUTE);
+    // permissions which may be granted on resources representing a specific function
+    private static final Set<Permission> SCALAR_FUNCTION_PERMISSIONS = Sets.immutableEnumSet(Permission.ALTER,
+                                                                                             Permission.DROP,
+                                                                                             Permission.AUTHORIZE,
+                                                                                             Permission.EXECUTE);
+
+    private static final Set<Permission> AGGREGATE_FUNCTION_PERMISSIONS = Sets.immutableEnumSet(Permission.ALTER,
+                                                                                                Permission.DROP,
+                                                                                                Permission.AUTHORIZE,
+                                                                                                Permission.EXECUTE);
+
+    private static final String ROOT_NAME = "functions";
+    private static final FunctionResource ROOT_RESOURCE = new FunctionResource();
+
+    private final Level level;
+    private final String keyspace;
+    private final String name;
+    private final List<AbstractType<?>> argTypes;
+
+    private FunctionResource()
+    {
+        level = Level.ROOT;
+        keyspace = null;
+        name = null;
+        argTypes = null;
+    }
+
+    private FunctionResource(String keyspace)
+    {
+        level = Level.KEYSPACE;
+        this.keyspace = keyspace;
+        name = null;
+        argTypes = null;
+    }
+
+    private FunctionResource(String keyspace, String name, List<AbstractType<?>> argTypes)
+    {
+        level = Level.FUNCTION;
+        this.keyspace = keyspace;
+        this.name = name;
+        this.argTypes = argTypes;
+    }
+
+    /**
+     * @return the root-level resource.
+     */
+    public static FunctionResource root()
+    {
+        return ROOT_RESOURCE;
+    }
+
+    /**
+     * Creates a FunctionResource representing the collection of functions scoped
+     * to a specific keyspace.
+     *
+     * @param keyspace name of the keyspace
+     * @return FunctionResource instance representing all of the keyspace's functions
+     */
+    public static FunctionResource keyspace(String keyspace)
+    {
+        return new FunctionResource(keyspace);
+    }
+
+    /**
+     * Creates a FunctionResource representing a specific, keyspace-scoped function.
+     *
+     * @param keyspace the keyspace in which the function is scoped
+     * @param name     name of the function.
+     * @param argTypes the types of the arguments to the function
+     * @return FunctionResource instance reresenting the function.
+     */
+    public static FunctionResource function(String keyspace, String name, List<AbstractType<?>> argTypes)
+    {
+        return new FunctionResource(keyspace, name, argTypes);
+    }
+
+    /**
+     * Creates a FunctionResource representing a specific, keyspace-scoped function.
+     * This variant is used to create an instance during parsing of a CQL statement.
+     * It includes transposition of the arg types from CQL types to AbstractType
+     * implementations
+     *
+     * @param keyspace the keyspace in which the function is scoped
+     * @param name     name of the function.
+     * @param argTypes the types of the function arguments in raw CQL form
+     * @return FunctionResource instance reresenting the function.
+     */
+    public static FunctionResource functionFromCql(String keyspace, String name, List<CQL3Type.Raw> argTypes)
+    {
+        List<AbstractType<?>> abstractTypes = new ArrayList<>();
+        for (CQL3Type.Raw cqlType : argTypes)
+            abstractTypes.add(cqlType.prepare(keyspace).getType());
+
+        return new FunctionResource(keyspace, name, abstractTypes);
+    }
+
+    /**
+     * Parses a resource name into a FunctionResource instance.
+     *
+     * @param name Name of the function resource.
+     * @return FunctionResource instance matching the name.
+     */
+    public static FunctionResource fromName(String name)
+    {
+        String[] parts = StringUtils.split(name, '/');
+
+        if (!parts[0].equals(ROOT_NAME) || parts.length > 3)
+            throw new IllegalArgumentException(String.format("%s is not a valid function resource name", name));
+
+        if (parts.length == 1)
+            return root();
+
+        if (parts.length == 2)
+            return keyspace(parts[1]);
+
+        String[] nameAndArgs = StringUtils.split(parts[2], "[|]");
+        return function(parts[1], nameAndArgs[0], argsListFromString(nameAndArgs[1]));
+    }
+
+    /**
+     * @return Printable name of the resource.
+     */
+    public String getName()
+    {
+        switch (level)
+        {
+            case ROOT:
+                return ROOT_NAME;
+            case KEYSPACE:
+                return String.format("%s/%s", ROOT_NAME, keyspace);
+            case FUNCTION:
+                return String.format("%s/%s/%s[%s]", ROOT_NAME, keyspace, name, argListAsString());
+        }
+        throw new AssertionError();
+    }
+
+    /**
+     * Get the name of the keyspace this resource relates to. In the case of the
+     * global root resource, return null
+     *
+     * @return the keyspace name of this resource, or null for the root resource
+     */
+    public String getKeyspace()
+    {
+        return keyspace;
+    }
+
+    /**
+     * @return a qualified FunctionName instance for a function-level resource.
+     * Throws IllegalStateException if called on the resource which doens't represent a single function.
+     */
+    public FunctionName getFunctionName()
+    {
+        if (level != Level.FUNCTION)
+            throw new IllegalStateException(String.format("%s function resource has no function name", level));
+        return new FunctionName(keyspace, name);
+    }
+
+    /**
+     * @return Parent of the resource, if any. Throws IllegalStateException if it's the root-level resource.
+     */
+    public IResource getParent()
+    {
+        switch (level)
+        {
+            case KEYSPACE:
+                return root();
+            case FUNCTION:
+                return keyspace(keyspace);
+        }
+        throw new IllegalStateException("Root-level resource can't have a parent");
+    }
+
+    public boolean hasParent()
+    {
+        return level != Level.ROOT;
+    }
+
+    public boolean exists()
+    {
+        switch (level)
+        {
+            case ROOT:
+                return true;
+            case KEYSPACE:
+                return Schema.instance.getKeyspaces().contains(keyspace);
+            case FUNCTION:
+                return Functions.find(getFunctionName(), argTypes) != null;
+        }
+        throw new AssertionError();
+    }
+
+    public Set<Permission> applicablePermissions()
+    {
+        switch (level)
+        {
+            case ROOT:
+            case KEYSPACE:
+                return COLLECTION_LEVEL_PERMISSIONS;
+            case FUNCTION:
+            {
+                Function function = Functions.find(getFunctionName(), argTypes);
+                assert function != null : "Unable to find function object for resource " + toString();
+                return function.isAggregate() ? AGGREGATE_FUNCTION_PERMISSIONS : SCALAR_FUNCTION_PERMISSIONS;
+            }
+        }
+        throw new AssertionError();
+    }
+
+    public int compareTo(FunctionResource o)
+    {
+        return this.name.compareTo(o.name);
+    }
+
+    @Override
+    public String toString()
+    {
+        switch (level)
+        {
+            case ROOT:
+                return "<all functions>";
+            case KEYSPACE:
+                return String.format("<all functions in %s>", keyspace);
+            case FUNCTION:
+                return String.format("<function %s.%s(%s)>",
+                                     keyspace,
+                                     name,
+                                     Joiner.on(", ").join(AbstractType.asCQLTypeStringList(argTypes)));
+        }
+        throw new AssertionError();
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+            return true;
+
+        if (!(o instanceof FunctionResource))
+            return false;
+
+        FunctionResource f = (FunctionResource) o;
+
+        return Objects.equal(level, f.level)
+               && Objects.equal(keyspace, f.keyspace)
+               && Objects.equal(name, f.name)
+               && Objects.equal(argTypes, f.argTypes);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return Objects.hashCode(level, keyspace, name, argTypes);
+    }
+
+    private String argListAsString()
+    {
+        return Joiner.on("^").join(argTypes);
+    }
+
+    private static List<AbstractType<?>> argsListFromString(String s)
+    {
+        List<AbstractType<?>> argTypes = new ArrayList<>();
+        for(String type : Splitter.on("^").omitEmptyStrings().trimResults().split(s))
+            argTypes.add(TypeParser.parse(type));
+        return argTypes;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/auth/Permission.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/auth/Permission.java b/src/java/org/apache/cassandra/auth/Permission.java
index 320d745..d552280 100644
--- a/src/java/org/apache/cassandra/auth/Permission.java
+++ b/src/java/org/apache/cassandra/auth/Permission.java
@@ -58,9 +58,12 @@ public enum Permission
     // permission management
     AUTHORIZE, // required for GRANT and REVOKE of permissions or roles.
 
-    DESCRIBE; // required on the root-level RoleResource to list all Roles
+    DESCRIBE, // required on the root-level RoleResource to list all Roles
+
+    // UDF permissions
+    EXECUTE;  // required to invoke any user defined function or aggregate
 
     public static final Set<Permission> ALL =
-            Sets.immutableEnumSet(EnumSet.range(Permission.CREATE, Permission.DESCRIBE));
+            Sets.immutableEnumSet(EnumSet.range(Permission.CREATE, Permission.EXECUTE));
     public static final Set<Permission> NONE = ImmutableSet.of();
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/auth/Resources.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/auth/Resources.java b/src/java/org/apache/cassandra/auth/Resources.java
index 393e18a..ebcfc16 100644
--- a/src/java/org/apache/cassandra/auth/Resources.java
+++ b/src/java/org/apache/cassandra/auth/Resources.java
@@ -56,6 +56,8 @@ public final class Resources
             return RoleResource.fromName(name);
         else if (name.startsWith(DataResource.root().getName()))
             return DataResource.fromName(name);
+        else if (name.startsWith(FunctionResource.root().getName()))
+            return FunctionResource.fromName(name);
         else
             throw new IllegalArgumentException(String.format("Name %s is not valid for any resource type", name));
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/cql3/AbstractMarker.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/AbstractMarker.java b/src/java/org/apache/cassandra/cql3/AbstractMarker.java
index 87344b6..d11b8e2 100644
--- a/src/java/org/apache/cassandra/cql3/AbstractMarker.java
+++ b/src/java/org/apache/cassandra/cql3/AbstractMarker.java
@@ -17,6 +17,9 @@
  */
 package org.apache.cassandra.cql3;
 
+import java.util.Collections;
+
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.marshal.CollectionType;
 import org.apache.cassandra.db.marshal.ListType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
@@ -45,6 +48,11 @@ public abstract class AbstractMarker extends Term.NonTerminal
         return true;
     }
 
+    public Iterable<Function> getFunctions()
+    {
+        return Collections.emptySet();
+    }
+
     /**
      * A parsed, but non prepared, bind marker.
      */

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 0ab42a2..4136ec5 100644
--- a/src/java/org/apache/cassandra/cql3/Attributes.java
+++ b/src/java/org/apache/cassandra/cql3/Attributes.java
@@ -18,7 +18,11 @@
 package org.apache.cassandra.cql3;
 
 import java.nio.ByteBuffer;
+import java.util.Collections;
 
+import com.google.common.collect.Iterables;
+
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.ExpiringCell;
 import org.apache.cassandra.db.marshal.Int32Type;
 import org.apache.cassandra.db.marshal.LongType;
@@ -51,6 +55,18 @@ public class Attributes
             || (timeToLive != null && timeToLive.usesFunction(ksName, functionName));
     }
 
+    public Iterable<Function> getFunctions()
+    {
+        if (timestamp != null && timeToLive != null)
+            return Iterables.concat(timestamp.getFunctions(), timeToLive.getFunctions());
+        else if (timestamp != null)
+            return timestamp.getFunctions();
+        else if (timeToLive != null)
+            return timeToLive.getFunctions();
+        else
+            return Collections.emptySet();
+    }
+
     public boolean isTimestampSet()
     {
         return timestamp != null;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 d555ec3..80220a8 100644
--- a/src/java/org/apache/cassandra/cql3/CQLStatement.java
+++ b/src/java/org/apache/cassandra/cql3/CQLStatement.java
@@ -17,10 +17,11 @@
  */
 package org.apache.cassandra.cql3;
 
-import org.apache.cassandra.transport.messages.ResultMessage;
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.exceptions.*;
 import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.QueryState;
-import org.apache.cassandra.exceptions.*;
+import org.apache.cassandra.transport.messages.ResultMessage;
 
 public interface CQLStatement
 {
@@ -60,4 +61,6 @@ public interface CQLStatement
     public ResultMessage executeInternal(QueryState state, QueryOptions options) throws RequestValidationException, RequestExecutionException;
 
     boolean usesFunction(String ksName, String functionName);
+
+    public Iterable<Function> getFunctions();
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 dfe2415..dcd8bca 100644
--- a/src/java/org/apache/cassandra/cql3/ColumnCondition.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnCondition.java
@@ -21,21 +21,24 @@ import java.nio.ByteBuffer;
 import java.util.*;
 
 import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Iterators;
-import static com.google.common.collect.Lists.newArrayList;
 
 import org.apache.cassandra.config.ColumnDefinition;
-import org.apache.cassandra.db.*;
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.db.Cell;
+import org.apache.cassandra.db.ColumnFamily;
 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.filter.ColumnSlice;
 import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.exceptions.InvalidRequestException;
-import org.apache.cassandra.serializers.CollectionSerializer;
 import org.apache.cassandra.transport.Server;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
+import static com.google.common.collect.Lists.newArrayList;
+
 /**
  * A CQL3 condition on the value of a column or collection element.  For example, "UPDATE .. IF a = 0".
  */
@@ -107,6 +110,20 @@ public class ColumnCondition
         return false;
     }
 
+    public Iterable<Function> getFunctions()
+    {
+        Iterable<Function> iter = Collections.emptyList();
+        if (collectionElement != null)
+           iter = Iterables.concat(iter, collectionElement.getFunctions());
+        if (value != null)
+            iter = Iterables.concat(iter, value.getFunctions());
+        if (inValues != null)
+            for (Term value : inValues)
+                if (value != null)
+                    iter = Iterables.concat(iter, value.getFunctions());
+        return iter;
+    }
+
     /**
      * Collects the column specification for the bind variables of this operation.
      *

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/cql3/Cql.g
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Cql.g b/src/java/org/apache/cassandra/cql3/Cql.g
index e5b0efd..ca68396 100644
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@ -913,7 +913,7 @@ listPermissionsStatement returns [ListPermissionsStatement stmt]
     ;
 
 permission returns [Permission perm]
-    : p=(K_CREATE | K_ALTER | K_DROP | K_SELECT | K_MODIFY | K_AUTHORIZE | K_DESCRIBE)
+    : p=(K_CREATE | K_ALTER | K_DROP | K_SELECT | K_MODIFY | K_AUTHORIZE | K_DESCRIBE | K_EXECUTE)
     { $perm = Permission.valueOf($p.text.toUpperCase()); }
     ;
 
@@ -925,6 +925,7 @@ permissionOrAll returns [Set<Permission> perms]
 resource returns [IResource res]
     : d=dataResource { $res = $d.res; }
     | r=roleResource { $res = $r.res; }
+    | f=functionResource { $res = $f.res; }
     ;
 
 dataResource returns [DataResource res]
@@ -934,11 +935,30 @@ dataResource returns [DataResource res]
       { $res = DataResource.table($cf.name.getKeyspace(), $cf.name.getColumnFamily()); }
     ;
 
-roleResource  returns [RoleResource res]
+roleResource returns [RoleResource res]
     : K_ALL K_ROLES { $res = RoleResource.root(); }
     | K_ROLE role = userOrRoleName { $res = RoleResource.role($role.name.getName()); }
     ;
 
+functionResource returns [FunctionResource res]
+    @init {
+        List<CQL3Type.Raw> argsTypes = new ArrayList<>();
+    }
+    : K_ALL K_FUNCTIONS { $res = FunctionResource.root(); }
+    | K_ALL K_FUNCTIONS K_IN K_KEYSPACE ks = keyspaceName { $res = FunctionResource.keyspace($ks.id); }
+    // Arg types are mandatory for DCL statements on Functions
+    | K_FUNCTION fn=functionName
+      (
+        '('
+          (
+            v=comparatorType { argsTypes.add(v); }
+            ( ',' v=comparatorType { argsTypes.add(v); } )*
+          )?
+        ')'
+      )
+      { $res = FunctionResource.functionFromCql($fn.s.keyspace, $fn.s.name, argsTypes); }
+    ;
+
 /**
  * CREATE USER [IF NOT EXISTS] <username> [WITH PASSWORD <password>] [SUPERUSER|NOSUPERUSER]
  */
@@ -1522,6 +1542,7 @@ basic_unreserved_keyword returns [String str]
         | K_FROZEN
         | K_TUPLE
         | K_FUNCTION
+        | K_FUNCTIONS
         | K_AGGREGATE
         | K_SFUNC
         | K_STYPE
@@ -1601,6 +1622,7 @@ K_REVOKE:      R E V O K E;
 K_MODIFY:      M O D I F Y;
 K_AUTHORIZE:   A U T H O R I Z E;
 K_DESCRIBE:    D E S C R I B E;
+K_EXECUTE:     E X E C U T E;
 K_NORECURSIVE: N O R E C U R S I V E;
 
 K_USER:        U S E R;
@@ -1650,6 +1672,7 @@ K_STATIC:      S T A T I C;
 K_FROZEN:      F R O Z E N;
 
 K_FUNCTION:    F U N C T I O N;
+K_FUNCTIONS:   F U N C T I O N S;
 K_AGGREGATE:   A G G R E G A T E;
 K_SFUNC:       S F U N C;
 K_STYPE:       S T Y P E;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/cql3/Json.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Json.java b/src/java/org/apache/cassandra/cql3/Json.java
index 8929cc0..905f6e0 100644
--- a/src/java/org/apache/cassandra/cql3/Json.java
+++ b/src/java/org/apache/cassandra/cql3/Json.java
@@ -17,18 +17,19 @@
  */
 package org.apache.cassandra.cql3;
 
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.*;
+
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.marshal.UTF8Type;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.serializers.MarshalException;
 import org.codehaus.jackson.io.JsonStringEncoder;
 import org.codehaus.jackson.map.ObjectMapper;
 
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.*;
-
 /** Term-related classes for INSERT JSON support. */
 public class Json
 {
@@ -251,6 +252,12 @@ public class Json
             Term term = marker.getValue(column);
             return term == null ? null : term.bind(options);
         }
+
+        @Override
+        public Iterable<Function> getFunctions()
+        {
+            return Collections.emptyList();
+        }
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/cql3/Lists.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Lists.java b/src/java/org/apache/cassandra/cql3/Lists.java
index ae2417e..8b8375d 100644
--- a/src/java/org/apache/cassandra/cql3/Lists.java
+++ b/src/java/org/apache/cassandra/cql3/Lists.java
@@ -23,31 +23,26 @@ import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.Cell;
 import org.apache.cassandra.db.ColumnFamily;
 import org.apache.cassandra.db.composites.CellName;
 import org.apache.cassandra.db.composites.Composite;
-import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.db.marshal.Int32Type;
 import org.apache.cassandra.db.marshal.ListType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.serializers.CollectionSerializer;
-import org.apache.cassandra.serializers.ListSerializer;
 import org.apache.cassandra.serializers.MarshalException;
 import org.apache.cassandra.transport.Server;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.UUIDGen;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Static helper methods and classes for lists.
  */
 public abstract class Lists
 {
-    private static final Logger logger = LoggerFactory.getLogger(Lists.class);
-
     private Lists() {}
 
     public static ColumnSpecification indexSpecOf(ColumnSpecification column)
@@ -224,6 +219,11 @@ public abstract class Lists
             }
             return new Value(buffers);
         }
+
+        public Iterable<Function> getFunctions()
+        {
+            return Terms.getFunctions(elements);
+        }
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/cql3/Maps.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Maps.java b/src/java/org/apache/cassandra/cql3/Maps.java
index d91b9d8..6c7cfa6 100644
--- a/src/java/org/apache/cassandra/cql3/Maps.java
+++ b/src/java/org/apache/cassandra/cql3/Maps.java
@@ -20,15 +20,16 @@ package org.apache.cassandra.cql3;
 import java.nio.ByteBuffer;
 import java.util.*;
 
+import com.google.common.collect.Iterables;
+
 import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.ColumnFamily;
 import org.apache.cassandra.db.composites.CellName;
 import org.apache.cassandra.db.composites.Composite;
-import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.db.marshal.MapType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.serializers.CollectionSerializer;
-import org.apache.cassandra.serializers.MapSerializer;
 import org.apache.cassandra.serializers.MarshalException;
 import org.apache.cassandra.transport.Server;
 import org.apache.cassandra.utils.FBUtilities;
@@ -247,6 +248,12 @@ public abstract class Maps
             }
             return new Value(buffers);
         }
+
+        public Iterable<Function> getFunctions()
+        {
+            return Iterables.concat(Terms.getFunctions(elements.keySet()),
+                                    Terms.getFunctions(elements.values()));
+        }
     }
 
     public static class Marker extends AbstractMarker

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 cc32647..d99a00d 100644
--- a/src/java/org/apache/cassandra/cql3/Operation.java
+++ b/src/java/org/apache/cassandra/cql3/Operation.java
@@ -18,8 +18,10 @@
 package org.apache.cassandra.cql3;
 
 import java.nio.ByteBuffer;
+import java.util.Collections;
 
 import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.ColumnFamily;
 import org.apache.cassandra.db.composites.Composite;
 import org.apache.cassandra.db.marshal.*;
@@ -60,6 +62,11 @@ public abstract class Operation
         return t != null && t.usesFunction(ksName, functionName);
     }
 
+    public Iterable<Function> getFunctions()
+    {
+        return t != null ? t.getFunctions() : Collections.<Function>emptySet();
+    }
+
     /**
      * @return whether the operation requires a read of the previous value to be executed
      * (only lists setterByIdx, discard and discardByIdx requires that).

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/cql3/Sets.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Sets.java b/src/java/org/apache/cassandra/cql3/Sets.java
index e0a53ad..ce372f8 100644
--- a/src/java/org/apache/cassandra/cql3/Sets.java
+++ b/src/java/org/apache/cassandra/cql3/Sets.java
@@ -23,6 +23,7 @@ import java.util.*;
 import com.google.common.base.Joiner;
 
 import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.ColumnFamily;
 import org.apache.cassandra.db.composites.CellName;
 import org.apache.cassandra.db.composites.Composite;
@@ -32,7 +33,6 @@ import org.apache.cassandra.db.marshal.SetType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.serializers.CollectionSerializer;
 import org.apache.cassandra.serializers.MarshalException;
-import org.apache.cassandra.serializers.SetSerializer;
 import org.apache.cassandra.transport.Server;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
@@ -222,6 +222,11 @@ public abstract class Sets
             }
             return new Value(buffers);
         }
+
+        public Iterable<Function> getFunctions()
+        {
+            return Terms.getFunctions(elements);
+        }
     }
 
     public static class Marker extends AbstractMarker

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 fe8e51e..6997f78 100644
--- a/src/java/org/apache/cassandra/cql3/Term.java
+++ b/src/java/org/apache/cassandra/cql3/Term.java
@@ -18,8 +18,11 @@
 package org.apache.cassandra.cql3;
 
 import java.nio.ByteBuffer;
+import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 
 /**
@@ -69,6 +72,8 @@ public interface Term
 
     boolean usesFunction(String ksName, String functionName);
 
+    Iterable<Function> getFunctions();
+
     /**
      * A parsed, non prepared (thus untyped) term.
      *
@@ -122,6 +127,11 @@ public interface Term
             return false;
         }
 
+        public Set<Function> getFunctions()
+        {
+            return Collections.emptySet();
+        }
+
         // While some NonTerminal may not have bind markers, no Term can be Terminal
         // with a bind marker
         public boolean containsBindMarker()
@@ -158,6 +168,9 @@ 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;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/cql3/Terms.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Terms.java b/src/java/org/apache/cassandra/cql3/Terms.java
new file mode 100644
index 0000000..0b049b9
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/Terms.java
@@ -0,0 +1,45 @@
+/*
+ * 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.Collections;
+
+import com.google.common.collect.Iterables;
+
+import org.apache.cassandra.cql3.functions.Function;
+
+public class Terms
+{
+
+    private static com.google.common.base.Function<Term, Iterable<Function>> TO_FUNCTION_ITERABLE =
+    new com.google.common.base.Function<Term, Iterable<Function>>()
+    {
+        public Iterable<Function> apply(Term term)
+        {
+            return term.getFunctions();
+        }
+    };
+
+    public static Iterable<Function> getFunctions(Iterable<Term> terms)
+    {
+        if (terms == null)
+            return Collections.emptySet();
+
+        return Iterables.concat(Iterables.transform(terms, TO_FUNCTION_ITERABLE));
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/cql3/Tuples.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Tuples.java b/src/java/org/apache/cassandra/cql3/Tuples.java
index 6d82218..967ce37 100644
--- a/src/java/org/apache/cassandra/cql3/Tuples.java
+++ b/src/java/org/apache/cassandra/cql3/Tuples.java
@@ -18,12 +18,15 @@
 package org.apache.cassandra.cql3;
 
 import java.nio.ByteBuffer;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.cassandra.cql3.Term.MultiColumnRaw;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.serializers.MarshalException;
@@ -226,6 +229,11 @@ public class Tuples
         {
             return tupleToString(elements);
         }
+
+        public Iterable<Function> getFunctions()
+        {
+            return Terms.getFunctions(elements);
+        }
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 934344c..f00a376 100644
--- a/src/java/org/apache/cassandra/cql3/UserTypes.java
+++ b/src/java/org/apache/cassandra/cql3/UserTypes.java
@@ -20,9 +20,10 @@ package org.apache.cassandra.cql3;
 import java.nio.ByteBuffer;
 import java.util.*;
 
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.marshal.CollectionType;
-import org.apache.cassandra.db.marshal.UserType;
 import org.apache.cassandra.db.marshal.UTF8Type;
+import org.apache.cassandra.db.marshal.UserType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.transport.Server;
 
@@ -157,6 +158,11 @@ public abstract class UserTypes
             return false;
         }
 
+        public Iterable<Function> getFunctions()
+        {
+            return Terms.getFunctions(values);
+        }
+
         public boolean containsBindMarker()
         {
             for (Term t : values)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 e2d69b8..15ae757 100644
--- a/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java
+++ b/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java
@@ -20,6 +20,7 @@ package org.apache.cassandra.cql3.functions;
 import java.util.List;
 
 import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
 
 import org.apache.cassandra.db.marshal.AbstractType;
 
@@ -71,6 +72,11 @@ public abstract class AbstractFunction implements Function
         return name.keyspace.equals(ksName) && name.name.equals(functionName);
     }
 
+    public Iterable<Function> getFunctions()
+    {
+        return ImmutableSet.<Function>of(this);
+    }
+
     public boolean hasReferenceTo(Function function)
     {
         return false;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 1b7952a..3c2e5a7 100644
--- a/src/java/org/apache/cassandra/cql3/functions/Function.java
+++ b/src/java/org/apache/cassandra/cql3/functions/Function.java
@@ -20,7 +20,6 @@ package org.apache.cassandra.cql3.functions;
 import java.util.List;
 
 import org.apache.cassandra.db.marshal.AbstractType;
-
 import org.github.jamm.Unmetered;
 
 @Unmetered
@@ -53,5 +52,7 @@ public interface Function
 
     boolean usesFunction(String ksName, String functionName);
 
+    Iterable<Function> getFunctions();
+
     boolean hasReferenceTo(Function function);
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 a3bd669..d8efa7f 100644
--- a/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java
+++ b/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java
@@ -21,15 +21,13 @@ import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
 
+import com.google.common.collect.Iterables;
+
 import org.apache.cassandra.cql3.*;
-import org.apache.cassandra.db.marshal.CollectionType;
-import org.apache.cassandra.db.marshal.ListType;
-import org.apache.cassandra.db.marshal.MapType;
-import org.apache.cassandra.db.marshal.SetType;
+import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.exceptions.InvalidRequestException;
-import org.apache.cassandra.transport.Server;
-import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.serializers.MarshalException;
+import org.apache.cassandra.utils.ByteBufferUtil;
 
 public class FunctionCall extends Term.NonTerminal
 {
@@ -47,6 +45,11 @@ public class FunctionCall extends Term.NonTerminal
         return fun.usesFunction(ksName, functionName);
     }
 
+    public Iterable<Function> getFunctions()
+    {
+        return Iterables.concat(Terms.getFunctions(terms), fun.getFunctions());
+    }
+
     public void collectMarkerSpecification(VariableSpecifications boundNames)
     {
         for (Term t : terms)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 e9c33ba..59f8daa 100644
--- a/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java
+++ b/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java
@@ -21,11 +21,12 @@ import java.nio.ByteBuffer;
 import java.util.*;
 
 import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.cassandra.db.marshal.AbstractType;
-import org.apache.cassandra.exceptions.*;
+import org.apache.cassandra.exceptions.InvalidRequestException;
 
 /**
  * Base class for user-defined-aggregates.
@@ -104,6 +105,11 @@ public class UDAggregate extends AbstractFunction implements AggregateFunction
             || finalFunction != null && finalFunction.name().keyspace.equals(ksName) && finalFunction.name().name.equals(functionName);
     }
 
+    public Iterable<Function> getFunctions()
+    {
+        return ImmutableSet.of(this, stateFunction, finalFunction);
+    }
+
     public boolean isAggregate()
     {
         return true;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 537481f..fd40b7a 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java
@@ -23,6 +23,7 @@ import java.util.List;
 
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.cql3.QueryOptions;
+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.Composite;
@@ -50,6 +51,12 @@ abstract class ForwardingPrimaryKeyRestrictions implements PrimaryKeyRestriction
     }
 
     @Override
+    public Iterable<Function> getFunctions()
+    {
+        return getDelegate().getFunctions();
+    }
+
+    @Override
     public Collection<ColumnDefinition> getColumnDefs()
     {
         return getDelegate().getColumnDefs();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 be6d905..3a755f0 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java
@@ -21,14 +21,11 @@ import java.nio.ByteBuffer;
 import java.util.*;
 
 import org.apache.cassandra.config.ColumnDefinition;
-import org.apache.cassandra.cql3.AbstractMarker;
-import org.apache.cassandra.cql3.Operator;
-import org.apache.cassandra.cql3.QueryOptions;
-import org.apache.cassandra.cql3.Term;
-import org.apache.cassandra.cql3.Tuples;
+import org.apache.cassandra.cql3.*;
+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.*;
+import org.apache.cassandra.db.composites.CompositesBuilder;
 import org.apache.cassandra.db.index.SecondaryIndex;
 import org.apache.cassandra.db.index.SecondaryIndexManager;
 import org.apache.cassandra.exceptions.InvalidRequestException;
@@ -144,6 +141,12 @@ public abstract class MultiColumnRestriction extends AbstractRestriction
         }
 
         @Override
+        public Iterable<Function> getFunctions()
+        {
+            return value.getFunctions();
+        }
+
+        @Override
         public String toString()
         {
             return String.format("EQ(%s)", value);
@@ -273,6 +276,12 @@ public abstract class MultiColumnRestriction extends AbstractRestriction
         }
 
         @Override
+        public Iterable<Function> getFunctions()
+        {
+            return Terms.getFunctions(values);
+        }
+
+        @Override
         public String toString()
         {
             return String.format("IN(%s)", values);
@@ -312,6 +321,12 @@ public abstract class MultiColumnRestriction extends AbstractRestriction
         }
 
         @Override
+        public Iterable<Function> getFunctions()
+        {
+            return Collections.emptySet();
+        }
+
+        @Override
         public String toString()
         {
             return "IN ?";
@@ -387,6 +402,12 @@ public abstract class MultiColumnRestriction extends AbstractRestriction
         }
 
         @Override
+        public Iterable<Function> getFunctions()
+        {
+            return slice.getFunctions();
+        }
+
+        @Override
         public boolean isInclusive(Bound b)
         {
             return slice.isInclusive(b);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 194f4d5..ab61628 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java
@@ -24,6 +24,7 @@ import java.util.List;
 
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.cql3.QueryOptions;
+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.*;
@@ -146,6 +147,12 @@ final class PrimaryKeyRestrictionSet extends AbstractPrimaryKeyRestrictions
     }
 
     @Override
+    public Iterable<Function> getFunctions()
+    {
+        return restrictions.getFunctions();
+    }
+
+    @Override
     public PrimaryKeyRestrictions mergeWith(Restriction restriction) throws InvalidRequestException
     {
         if (restriction.isOnToken())

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 49af20c..71dc373 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.cql3.QueryOptions;
+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;
@@ -70,6 +71,8 @@ public interface Restriction
      */
     public boolean usesFunction(String ksName, String functionName);
 
+    public Iterable<Function> getFunctions();
+
     /**
      * Checks if the specified bound is set or not.
      * @param b the bound type

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 b422749..3a236cc 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java
@@ -19,8 +19,11 @@ package org.apache.cassandra.cql3.restrictions;
 
 import java.util.*;
 
+import com.google.common.collect.Iterables;
+
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.cql3.restrictions.SingleColumnRestriction.Contains;
 import org.apache.cassandra.db.IndexExpression;
 import org.apache.cassandra.db.index.SecondaryIndexManager;
@@ -88,6 +91,21 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction>
     }
 
     @Override
+    public Iterable<Function> getFunctions()
+    {
+        com.google.common.base.Function<Restriction, Iterable<Function>> transform =
+            new com.google.common.base.Function<Restriction, Iterable<Function>>()
+        {
+            public Iterable<Function> apply(Restriction restriction)
+            {
+                return restriction.getFunctions();
+            }
+        };
+
+        return Iterables.concat(Iterables.transform(restrictions.values(), transform));
+    }
+
+    @Override
     public final boolean isEmpty()
     {
         return getColumnDefs().isEmpty();
@@ -249,4 +267,4 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction>
     {
         return new LinkedHashSet<>(restrictions.values()).iterator();
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 e2b31dd..7487734 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.IndexExpression;
 import org.apache.cassandra.db.index.SecondaryIndexManager;
 import org.apache.cassandra.exceptions.InvalidRequestException;
@@ -46,6 +47,8 @@ interface Restrictions
      */
     public boolean usesFunction(String ksName, String functionName);
 
+    public Iterable<Function> getFunctions();
+
     /**
      * Check if the restriction is on indexed columns.
      *
@@ -81,4 +84,4 @@ interface Restrictions
      * @return the number of columns that have a restriction.
      */
     public int size();
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 b25d5a4..ad4893f 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java
@@ -18,16 +18,13 @@
 package org.apache.cassandra.cql3.restrictions;
 
 import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
+
+import com.google.common.collect.Iterables;
 
 import org.apache.cassandra.config.ColumnDefinition;
-import org.apache.cassandra.cql3.AbstractMarker;
-import org.apache.cassandra.cql3.Operator;
-import org.apache.cassandra.cql3.QueryOptions;
-import org.apache.cassandra.cql3.Term;
+import org.apache.cassandra.cql3.*;
+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;
@@ -114,6 +111,12 @@ public abstract class SingleColumnRestriction extends AbstractRestriction
         }
 
         @Override
+        public Iterable getFunctions()
+        {
+            return value.getFunctions();
+        }
+
+        @Override
         public boolean isEQ()
         {
             return true;
@@ -220,6 +223,12 @@ public abstract class SingleColumnRestriction extends AbstractRestriction
         }
 
         @Override
+        public Iterable<Function> getFunctions()
+        {
+            return Terms.getFunctions(values);
+        }
+
+        @Override
         protected List<ByteBuffer> getValues(QueryOptions options) throws InvalidRequestException
         {
             List<ByteBuffer> buffers = new ArrayList<>(values.size());
@@ -252,6 +261,12 @@ public abstract class SingleColumnRestriction extends AbstractRestriction
         }
 
         @Override
+        public Iterable<Function> getFunctions()
+        {
+            return Collections.emptySet();
+        }
+
+        @Override
         protected List<ByteBuffer> getValues(QueryOptions options) throws InvalidRequestException
         {
             Term.MultiItemTerminal lval = (Term.MultiItemTerminal) marker.bind(options);
@@ -285,6 +300,12 @@ public abstract class SingleColumnRestriction extends AbstractRestriction
         }
 
         @Override
+        public Iterable<Function> getFunctions()
+        {
+            return slice.getFunctions();
+        }
+
+        @Override
         public boolean isSlice()
         {
             return true;
@@ -483,6 +504,15 @@ public abstract class SingleColumnRestriction extends AbstractRestriction
         }
 
         @Override
+        public Iterable<Function> getFunctions()
+        {
+            return Iterables.concat(Terms.getFunctions(values),
+                                    Terms.getFunctions(keys),
+                                    Terms.getFunctions(entryKeys),
+                                    Terms.getFunctions(entryValues));
+        }
+
+        @Override
         public String toString()
         {
             return String.format("CONTAINS(values=%s, keys=%s, entryKeys=%s, entryValues=%s)", values, keys, entryKeys, entryValues);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 cea1699..dcaad47 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
@@ -21,18 +21,14 @@ import java.nio.ByteBuffer;
 import java.util.*;
 
 import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
 
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ColumnDefinition;
-import org.apache.cassandra.cql3.ColumnIdentifier;
-import org.apache.cassandra.cql3.QueryOptions;
-import org.apache.cassandra.cql3.Relation;
-import org.apache.cassandra.cql3.VariableSpecifications;
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.cql3.statements.Bound;
-import org.apache.cassandra.db.ColumnFamilyStore;
-import org.apache.cassandra.db.IndexExpression;
-import org.apache.cassandra.db.Keyspace;
-import org.apache.cassandra.db.RowPosition;
+import org.apache.cassandra.db.*;
 import org.apache.cassandra.db.composites.Composite;
 import org.apache.cassandra.db.index.SecondaryIndexManager;
 import org.apache.cassandra.dht.*;
@@ -184,6 +180,13 @@ public final class StatementRestrictions
                 || nonPrimaryKeyRestrictions.usesFunction(ksName, functionName);
     }
 
+    public Iterable<Function> getFunctions()
+    {
+        return Iterables.concat(partitionKeyRestrictions.getFunctions(),
+                                clusteringColumnsRestrictions.getFunctions(),
+                                nonPrimaryKeyRestrictions.getFunctions());
+    }
+
     private void addSingleColumnRestriction(SingleColumnRestriction restriction) throws InvalidRequestException
     {
         ColumnDefinition def = restriction.columnDef;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/src/java/org/apache/cassandra/cql3/restrictions/TermSlice.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/restrictions/TermSlice.java b/src/java/org/apache/cassandra/cql3/restrictions/TermSlice.java
index 3622220..d082cc3 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/TermSlice.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/TermSlice.java
@@ -17,8 +17,13 @@
  */
 package org.apache.cassandra.cql3.restrictions;
 
+import java.util.Collections;
+
+import com.google.common.collect.Iterables;
+
 import org.apache.cassandra.cql3.Operator;
 import org.apache.cassandra.cql3.Term;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.cql3.statements.Bound;
 import org.apache.cassandra.db.index.SecondaryIndex;
 
@@ -164,4 +169,16 @@ final class TermSlice
 
         return supported;
     }
+
+    public Iterable<Function> getFunctions()
+    {
+        if (hasBound(Bound.START) && hasBound(Bound.END))
+            return Iterables.concat(bound(Bound.START).getFunctions(), bound(Bound.END).getFunctions());
+        else if (hasBound(Bound.START))
+            return bound(Bound.START).getFunctions();
+        else if (hasBound(Bound.END))
+            return bound(Bound.END).getFunctions();
+        else
+            return Collections.emptySet();
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 5848c91..5a00bd4 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java
@@ -27,6 +27,7 @@ import com.google.common.base.Joiner;
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.cql3.QueryOptions;
 import org.apache.cassandra.cql3.Term;
+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.CType;
@@ -178,6 +179,12 @@ public abstract class TokenRestriction extends AbstractPrimaryKeyRestrictions
         }
 
         @Override
+        public Iterable<Function> getFunctions()
+        {
+            return value.getFunctions();
+        }
+
+        @Override
         protected PrimaryKeyRestrictions doMergeWith(TokenRestriction otherRestriction) throws InvalidRequestException
         {
             throw invalidRequest("%s cannot be restricted by more than one relation if it includes an Equal",
@@ -233,6 +240,12 @@ public abstract class TokenRestriction extends AbstractPrimaryKeyRestrictions
         }
 
         @Override
+        public Iterable<Function> getFunctions()
+        {
+            return slice.getFunctions();
+        }
+
+        @Override
         public boolean isInclusive(Bound b)
         {
             return slice.isInclusive(b);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 d6a0c71..11e7e48 100644
--- a/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java
+++ b/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java
@@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.List;
 
+import com.google.common.collect.Iterables;
 import org.apache.commons.lang3.text.StrBuilder;
 
 import org.apache.cassandra.cql3.functions.Function;
@@ -72,6 +73,11 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
                 return fun.usesFunction(ksName, functionName);
             }
 
+            public Iterable<Function> getFunctions()
+            {
+                return Iterables.concat(fun.getFunctions(), factories.getFunctions());
+            }
+
             public Selector newInstance() throws InvalidRequestException
             {
                 return fun.isAggregate() ? new AggregateFunctionSelector(fun, factories.newInstances())

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 cbca97d..25bce78 100644
--- a/src/java/org/apache/cassandra/cql3/selection/Selection.java
+++ b/src/java/org/apache/cassandra/cql3/selection/Selection.java
@@ -20,12 +20,15 @@ package org.apache.cassandra.cql3.selection;
 import java.nio.ByteBuffer;
 import java.util.*;
 
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ColumnDefinition;
-import org.apache.cassandra.cql3.ColumnIdentifier;
-import org.apache.cassandra.cql3.ColumnSpecification;
-import org.apache.cassandra.cql3.Json;
-import org.apache.cassandra.cql3.ResultSet;
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.Cell;
 import org.apache.cassandra.db.CounterCell;
 import org.apache.cassandra.db.ExpiringCell;
@@ -34,11 +37,6 @@ import org.apache.cassandra.db.marshal.UTF8Type;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
-import com.google.common.base.Predicate;
-import com.google.common.base.Objects;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Iterators;
-
 public abstract class Selection
 {
     /**
@@ -181,6 +179,11 @@ public abstract class Selection
         return false;
     }
 
+    public Iterable<Function> getFunctions()
+    {
+        return Collections.emptySet();
+    }
+
     private static boolean processesSelection(List<RawSelector> rawSelectors)
     {
         for (RawSelector rawSelector : rawSelectors)
@@ -486,6 +489,12 @@ public abstract class Selection
         }
 
         @Override
+        public Iterable<Function> getFunctions()
+        {
+            return factories.getFunctions();
+        }
+
+        @Override
         public int addColumnForOrdering(ColumnDefinition c)
         {
             int index = super.addColumnForOrdering(c);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 3ed773b..8c1e6b8 100644
--- a/src/java/org/apache/cassandra/cql3/selection/Selector.java
+++ b/src/java/org/apache/cassandra/cql3/selection/Selector.java
@@ -18,11 +18,13 @@
 package org.apache.cassandra.cql3.selection;
 
 import java.nio.ByteBuffer;
+import java.util.Collections;
 
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.cql3.AssignmentTestable;
 import org.apache.cassandra.cql3.ColumnIdentifier;
 import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
@@ -45,6 +47,11 @@ public abstract class Selector implements AssignmentTestable
             return false;
         }
 
+        public Iterable<Function> getFunctions()
+        {
+            return Collections.emptySet();
+        }
+
         /**
          * Returns the column specification corresponding to the output value of the selector instances created by
          * this factory.
@@ -167,4 +174,4 @@ public abstract class Selector implements AssignmentTestable
         else
             return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 4e6970b..6de766a 100644
--- a/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java
+++ b/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java
@@ -17,15 +17,14 @@
  */
 package org.apache.cassandra.cql3.selection;
 
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
 
-import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.cql3.selection.Selector.Factory;
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
@@ -98,6 +97,15 @@ final class SelectorFactories implements Iterable<Selector.Factory>
         return false;
     }
 
+    public Iterable<Function> getFunctions()
+    {
+        Iterable<Function> functions = Collections.emptySet();
+        for (Factory factory : factories)
+            if (factory != null)
+                functions = Iterables.concat(functions, factory.getFunctions());
+        return functions;
+    }
+
     /**
      * Adds a new <code>Selector.Factory</code> for a column that is needed only for ORDER BY purposes.
      * @param def the column that is needed for ordering
@@ -179,7 +187,7 @@ final class SelectorFactories implements Iterable<Selector.Factory>
      */
     public List<String> getColumnNames()
     {
-        return Lists.transform(factories, new Function<Selector.Factory, String>()
+        return Lists.transform(factories, new com.google.common.base.Function<Selector.Factory, String>()
         {
             public String apply(Selector.Factory factory)
             {
@@ -195,7 +203,7 @@ final class SelectorFactories implements Iterable<Selector.Factory>
      */
     public List<AbstractType<?>> getReturnTypes()
     {
-        return Lists.transform(factories, new Function<Selector.Factory, AbstractType<?>>()
+        return Lists.transform(factories, new com.google.common.base.Function<Selector.Factory, AbstractType<?>>()
         {
             public AbstractType<?> apply(Selector.Factory factory)
             {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cb5897f3/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 84f35ff..3f873e7 100644
--- a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
@@ -21,15 +21,12 @@ import java.nio.ByteBuffer;
 import java.util.*;
 
 import com.google.common.base.Function;
-import com.google.common.collect.*;
-import org.apache.cassandra.config.DatabaseDescriptor;
-
-import org.apache.cassandra.tracing.Tracing;
-
+import com.google.common.collect.Iterables;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.db.*;
 import org.apache.cassandra.db.composites.Composite;
@@ -37,6 +34,7 @@ import org.apache.cassandra.exceptions.*;
 import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.QueryState;
 import org.apache.cassandra.service.StorageProxy;
+import org.apache.cassandra.tracing.Tracing;
 import org.apache.cassandra.transport.messages.ResultMessage;
 
 /**
@@ -88,6 +86,14 @@ public class BatchStatement implements CQLStatement
         return false;
     }
 
+    public Iterable<org.apache.cassandra.cql3.functions.Function> getFunctions()
+    {
+        Iterable<org.apache.cassandra.cql3.functions.Function> functions = attrs.getFunctions();
+        for (ModificationStatement statement : statements)
+            functions = Iterables.concat(functions, statement.getFunctions());
+        return functions;
+    }
+
     public int getBoundTerms()
     {
         return boundTerms;


Mime
View raw message