You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by al...@apache.org on 2014/11/14 16:20:52 UTC

[2/2] cassandra git commit: Deal with conflicts between system functions and UDFs

Deal with conflicts between system functions and UDFs

patch by Robert Stupp; reviewed by Benjamin Lerer for CASSANDRA-7813


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

Branch: refs/heads/trunk
Commit: b4d7f3bed0687b449f6a275d9dd675e25d794aeb
Parents: 41a35ec
Author: Robert Stupp <sn...@snazy.de>
Authored: Fri Nov 14 18:18:38 2014 +0300
Committer: Aleksey Yeschenko <al...@apache.org>
Committed: Fri Nov 14 18:20:29 2014 +0300

----------------------------------------------------------------------
 CHANGES.txt                                     |   4 +-
 build.xml                                       |   2 +
 pylib/cqlshlib/cql3handling.py                  |   2 +-
 src/java/org/apache/cassandra/auth/Auth.java    |   6 +-
 .../org/apache/cassandra/config/KSMetaData.java |   1 +
 .../org/apache/cassandra/cql3/Attributes.java   |   6 +
 .../org/apache/cassandra/cql3/CQLStatement.java |   2 +
 .../apache/cassandra/cql3/ColumnCondition.java  |  16 +-
 src/java/org/apache/cassandra/cql3/Cql.g        |   8 +-
 .../org/apache/cassandra/cql3/Operation.java    |   6 +-
 .../apache/cassandra/cql3/QueryProcessor.java   |  29 +-
 src/java/org/apache/cassandra/cql3/Term.java    |  12 +
 .../org/apache/cassandra/cql3/UserTypes.java    |   9 +
 .../cassandra/cql3/functions/FunctionCall.java  |  13 +-
 .../cassandra/cql3/functions/FunctionName.java  |  36 +-
 .../cassandra/cql3/functions/Functions.java     |  27 +-
 .../cql3/functions/NativeFunction.java          |   8 +-
 .../cassandra/cql3/functions/UDFunction.java    |  21 +-
 .../selection/AbstractFunctionSelector.java     |   7 +-
 .../cassandra/cql3/selection/Selection.java     |  10 +
 .../cassandra/cql3/selection/Selector.java      |   5 +
 .../cql3/selection/SelectorFactories.java       |   8 +
 .../cql3/statements/BatchStatement.java         |  10 +
 .../statements/CreateFunctionStatement.java     |  28 +-
 .../cql3/statements/DropFunctionStatement.java  |  28 +-
 .../cql3/statements/ModificationStatement.java  |  20 +-
 .../cql3/statements/ParsedStatement.java        |   5 +
 .../cassandra/cql3/statements/Restriction.java  |   2 +
 .../cql3/statements/SelectStatement.java        |  22 +-
 .../statements/SingleColumnRestriction.java     |  40 ++
 .../org/apache/cassandra/db/DefsTables.java     |   5 +-
 .../org/apache/cassandra/db/SystemKeyspace.java |   7 +-
 .../cassandra/service/IMigrationListener.java   |   6 +-
 .../cassandra/service/MigrationManager.java     |  26 +-
 .../org/apache/cassandra/transport/Event.java   |  24 +-
 .../org/apache/cassandra/transport/Server.java  |   8 +-
 .../apache/cassandra/cql3/AggregationTest.java  |  10 +-
 .../org/apache/cassandra/cql3/PgStringTest.java |   4 +-
 test/unit/org/apache/cassandra/cql3/UFTest.java | 378 +++++++++++++------
 39 files changed, 637 insertions(+), 224 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index f250edc..ff255d8 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,7 +1,7 @@
 3.0
  * Fix aggregate fn results on empty selection, result column name,
    and cqlsh parsing (CASSANDRA-8229)
- * Mark sstables as repaired after full repair (CASSANDRA-7586) 
+ * Mark sstables as repaired after full repair (CASSANDRA-7586)
  * Extend Descriptor to include a format value and refactor reader/writer apis (CASSANDRA-7443)
  * Integrate JMH for microbenchmarks (CASSANDRA-8151)
  * Keep sstable levels when bootstrapping (CASSANDRA-7460)
@@ -15,7 +15,7 @@
  * Remove YamlFileNetworkTopologySnitch (CASSANDRA-7917)
  * Do anticompaction in groups (CASSANDRA-6851)
  * Support pure user-defined functions (CASSANDRA-7395, 7526, 7562, 7740, 7781, 7929,
-   7924, 7812, 8063)
+   7924, 7812, 8063, 7813)
  * Permit configurable timestamps with cassandra-stress (CASSANDRA-7416)
  * Move sstable RandomAccessReader to nio2, which allows using the
    FILE_SHARE_DELETE flag on Windows (CASSANDRA-4050)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/build.xml
----------------------------------------------------------------------
diff --git a/build.xml b/build.xml
index c4e27a7..c7aa83e 100644
--- a/build.xml
+++ b/build.xml
@@ -212,6 +212,8 @@
          <arg value="${build.src.java}/org/apache/cassandra/cql3/Cql.g" />
          <arg value="-fo" />
          <arg value="${build.src.gen-java}/org/apache/cassandra/cql3/" />
+         <arg value="-Xmaxinlinedfastates"/>
+         <arg value="10"/> <!-- default is 60 -->
       </java>
     </target>
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/pylib/cqlshlib/cql3handling.py
----------------------------------------------------------------------
diff --git a/pylib/cqlshlib/cql3handling.py b/pylib/cqlshlib/cql3handling.py
index 261161c..f8a3069 100644
--- a/pylib/cqlshlib/cql3handling.py
+++ b/pylib/cqlshlib/cql3handling.py
@@ -209,7 +209,7 @@ JUNK ::= /([ \t\r\f\v]+|(--|[/][/])[^\n\r]*([\n\r]|$)|[/][*].*?[*][/])/ ;
 <mapLiteral> ::= "{" <term> ":" <term> ( "," <term> ":" <term> )* "}"
                ;
 
-<functionName> ::= <identifier> ( ":" ":" <identifier> )? 
+<functionName> ::= <identifier> ( "." <identifier> )?
                  | "TOKEN"
                  ;
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/auth/Auth.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/auth/Auth.java b/src/java/org/apache/cassandra/auth/Auth.java
index 07c9a67..8c12df6 100644
--- a/src/java/org/apache/cassandra/auth/Auth.java
+++ b/src/java/org/apache/cassandra/auth/Auth.java
@@ -337,7 +337,7 @@ public class Auth implements AuthMBean
         {
         }
 
-        public void onDropFunction(String namespace, String functionName)
+        public void onDropFunction(String ksName, String functionName)
         {
         }
 
@@ -353,7 +353,7 @@ public class Auth implements AuthMBean
         {
         }
 
-        public void onCreateFunction(String namespace, String functionName)
+        public void onCreateFunction(String ksName, String functionName)
         {
         }
 
@@ -369,7 +369,7 @@ public class Auth implements AuthMBean
         {
         }
 
-        public void onUpdateFunction(String namespace, String functionName)
+        public void onUpdateFunction(String ksName, String functionName)
         {
         }
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/config/KSMetaData.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/KSMetaData.java b/src/java/org/apache/cassandra/config/KSMetaData.java
index d3ff62c..494f98b 100644
--- a/src/java/org/apache/cassandra/config/KSMetaData.java
+++ b/src/java/org/apache/cassandra/config/KSMetaData.java
@@ -185,6 +185,7 @@ public final class KSMetaData
         mutation.delete(SystemKeyspace.SCHEMA_COLUMNS_TABLE, timestamp);
         mutation.delete(SystemKeyspace.SCHEMA_TRIGGERS_TABLE, timestamp);
         mutation.delete(SystemKeyspace.SCHEMA_USER_TYPES_TABLE, timestamp);
+        mutation.delete(SystemKeyspace.SCHEMA_FUNCTIONS_TABLE, timestamp);
         mutation.delete(SystemKeyspace.BUILT_INDEXES_TABLE, timestamp);
 
         return mutation;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 df40b0c..851e1b4 100644
--- a/src/java/org/apache/cassandra/cql3/Attributes.java
+++ b/src/java/org/apache/cassandra/cql3/Attributes.java
@@ -45,6 +45,12 @@ 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 boolean isTimestampSet()
     {
         return timestamp != null;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 a1642ef..d555ec3 100644
--- a/src/java/org/apache/cassandra/cql3/CQLStatement.java
+++ b/src/java/org/apache/cassandra/cql3/CQLStatement.java
@@ -58,4 +58,6 @@ public interface CQLStatement
      * @param state the current query state
      */
     public ResultMessage executeInternal(QueryState state, QueryOptions options) throws RequestValidationException, RequestExecutionException;
+
+    boolean usesFunction(String ksName, String functionName);
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 fc45fdc..7daec02 100644
--- a/src/java/org/apache/cassandra/cql3/ColumnCondition.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnCondition.java
@@ -34,15 +34,12 @@ 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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * A CQL3 condition on the value of a column or collection element.  For example, "UPDATE .. IF a = 0".
  */
 public class ColumnCondition
 {
-    private static final Logger logger = LoggerFactory.getLogger(ColumnCondition.class);
 
     public final ColumnDefinition column;
 
@@ -96,6 +93,19 @@ 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;
+    }
+
     /**
      * Collects the column specification for the bind variables of this operation.
      *

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 37e94b7..4c051e3 100644
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@ -310,7 +310,7 @@ selectionFunctionArgs returns [List<Selectable.Raw> a]
 
 selectCountClause returns [List<RawSelector> expr]
     @init{ ColumnIdentifier alias = new ColumnIdentifier("count", false); }
-    : K_COUNT '(' countArgument ')' (K_AS c=ident { alias = c; })? { $expr = new ArrayList<RawSelector>(); $expr.add( new RawSelector(new Selectable.WithFunction.Raw(new FunctionName("countRows"), Collections.<Selectable.Raw>emptyList()), alias));}
+    : K_COUNT '(' countArgument ')' (K_AS c=ident { alias = c; })? { $expr = new ArrayList<RawSelector>(); $expr.add( new RawSelector(new Selectable.WithFunction.Raw(FunctionName.nativeFunction("countRows"), Collections.<Selectable.Raw>emptyList()), alias));}
     ;
 
 countArgument
@@ -977,12 +977,12 @@ intValue returns [Term.Raw value]
     ;
 
 functionName returns [FunctionName s]
-    : f=allowedFunctionName                            { $s = new FunctionName(f); }
-    | b=allowedFunctionName '::' f=allowedFunctionName { $s = new FunctionName(b, f); }
+    : (ks=keyspaceName '.')? f=allowedFunctionName   { $s = new FunctionName(ks, f); }
     ;
 
 allowedFunctionName returns [String s]
-    : f=IDENT                       { $s = $f.text; }
+    : f=IDENT                       { $s = $f.text.toLowerCase(); }
+    | f=QUOTED_NAME                 { $s = $f.text; }
     | u=unreserved_function_keyword { $s = u; }
     | K_TOKEN                       { $s = "token"; }
     | K_COUNT                       { $s = "count"; }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 816acb2..583158b 100644
--- a/src/java/org/apache/cassandra/cql3/Operation.java
+++ b/src/java/org/apache/cassandra/cql3/Operation.java
@@ -19,7 +19,6 @@ package org.apache.cassandra.cql3;
 
 import java.nio.ByteBuffer;
 
-import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.db.ColumnFamily;
 import org.apache.cassandra.db.composites.Composite;
@@ -56,6 +55,11 @@ public abstract class Operation
         this.t = t;
     }
 
+    public boolean usesFunction(String ksName, String functionName)
+    {
+        return t != null && t.usesFunction(ksName, functionName);
+    }
+
     /**
      * @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/b4d7f3be/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 680f9f2..cd56075 100644
--- a/src/java/org/apache/cassandra/cql3/QueryProcessor.java
+++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
@@ -31,6 +31,7 @@ import org.antlr.runtime.*;
 import org.github.jamm.MemoryMeter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.cassandra.cql3.functions.*;
 import org.apache.cassandra.cql3.statements.*;
 import org.apache.cassandra.db.*;
 import org.apache.cassandra.db.composites.*;
@@ -591,11 +592,20 @@ public class QueryProcessor implements QueryHandler
         public void onCreateKeyspace(String ksName) { }
         public void onCreateColumnFamily(String ksName, String cfName) { }
         public void onCreateUserType(String ksName, String typeName) { }
-        public void onCreateFunction(String namespace, String functionName) { }
+        public void onCreateFunction(String ksName, String functionName) {
+            if (Functions.getOverloadCount(new FunctionName(ksName, functionName)) > 1)
+            {
+                // in case there are other overloads, we have to remove all overloads since argument type
+                // matching may change (due to type casting)
+                removeInvalidPreparedStatementsForFunction(preparedStatements.values().iterator(), ksName, functionName);
+                removeInvalidPreparedStatementsForFunction(thriftPreparedStatements.values().iterator(), ksName, functionName);
+            }
+        }
+
         public void onUpdateKeyspace(String ksName) { }
         public void onUpdateColumnFamily(String ksName, String cfName) { }
         public void onUpdateUserType(String ksName, String typeName) { }
-        public void onUpdateFunction(String namespace, String functionName) { }
+        public void onUpdateFunction(String ksName, String functionName) { }
 
         public void onDropKeyspace(String ksName)
         {
@@ -608,6 +618,17 @@ public class QueryProcessor implements QueryHandler
         }
 
         public void onDropUserType(String ksName, String typeName) { }
-        public void onDropFunction(String namespace, String functionName) { }
-	}
+        public void onDropFunction(String ksName, String functionName) {
+            removeInvalidPreparedStatementsForFunction(preparedStatements.values().iterator(), ksName, functionName);
+            removeInvalidPreparedStatementsForFunction(thriftPreparedStatements.values().iterator(), ksName, functionName);
+        }
+
+        private void removeInvalidPreparedStatementsForFunction(Iterator<ParsedStatement.Prepared> iterator,
+                                                                String ksName, String functionName)
+        {
+            while (iterator.hasNext())
+                if (iterator.next().statement.usesFunction(ksName, functionName))
+                    iterator.remove();
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 3f4d728..7e20df8 100644
--- a/src/java/org/apache/cassandra/cql3/Term.java
+++ b/src/java/org/apache/cassandra/cql3/Term.java
@@ -67,6 +67,8 @@ public interface Term
      */
     public abstract boolean containsBindMarker();
 
+    boolean usesFunction(String ksName, String functionName);
+
     /**
      * A parsed, non prepared (thus untyped) term.
      *
@@ -115,6 +117,11 @@ public interface Term
         public void collectMarkerSpecification(VariableSpecifications boundNames) {}
         public Terminal bind(QueryOptions options) { return this; }
 
+        public boolean usesFunction(String ksName, String functionName)
+        {
+            return false;
+        }
+
         // While some NonTerminal may not have bind markers, no Term can be Terminal
         // with a bind marker
         public boolean containsBindMarker()
@@ -156,6 +163,11 @@ public interface Term
      */
     public abstract class NonTerminal implements Term
     {
+        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/b4d7f3be/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 22063ff..934344c 100644
--- a/src/java/org/apache/cassandra/cql3/UserTypes.java
+++ b/src/java/org/apache/cassandra/cql3/UserTypes.java
@@ -148,6 +148,15 @@ 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 boolean containsBindMarker()
         {
             for (Term t : values)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 3b80fc0..efaa12a 100644
--- a/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java
+++ b/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java
@@ -41,6 +41,11 @@ public class FunctionCall extends Term.NonTerminal
         this.terms = terms;
     }
 
+    public boolean usesFunction(String ksName, String functionName)
+    {
+        return fun.name().keyspace.equals(ksName) && fun.name().name.equals(functionName);
+    }
+
     public void collectMarkerSpecification(VariableSpecifications boundNames)
     {
         for (Term t : terms)
@@ -54,7 +59,7 @@ public class FunctionCall extends Term.NonTerminal
 
     public ByteBuffer bindAndGet(QueryOptions options) throws InvalidRequestException
     {
-        List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(terms.size());
+        List<ByteBuffer> buffers = new ArrayList<>(terms.size());
         for (Term t : terms)
         {
             // For now, we don't allow nulls as argument as no existing function needs it and it
@@ -110,7 +115,7 @@ public class FunctionCall extends Term.NonTerminal
 
     public static class Raw implements Term.Raw
     {
-        private final FunctionName name;
+        private FunctionName name;
         private final List<Term.Raw> terms;
 
         public Raw(FunctionName name, List<Term.Raw> terms)
@@ -140,7 +145,7 @@ public class FunctionCall extends Term.NonTerminal
                 throw new InvalidRequestException(String.format("Incorrect number of arguments specified for function %s (expected %d, found %d)",
                                                                 fun.name(), fun.argTypes().size(), terms.size()));
 
-            List<Term> parameters = new ArrayList<Term>(terms.size());
+            List<Term> parameters = new ArrayList<>(terms.size());
             boolean allTerminal = true;
             for (int i = 0; i < terms.size(); i++)
             {
@@ -160,7 +165,7 @@ public class FunctionCall extends Term.NonTerminal
         // All parameters must be terminal
         private static ByteBuffer execute(ScalarFunction fun, List<Term> parameters) throws InvalidRequestException
         {
-            List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(parameters.size());
+            List<ByteBuffer> buffers = new ArrayList<>(parameters.size());
             for (Term t : parameters)
             {
                 assert t instanceof Term.Terminal;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/cql3/functions/FunctionName.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/FunctionName.java b/src/java/org/apache/cassandra/cql3/functions/FunctionName.java
index 814bbbf..460e7a6 100644
--- a/src/java/org/apache/cassandra/cql3/functions/FunctionName.java
+++ b/src/java/org/apache/cassandra/cql3/functions/FunctionName.java
@@ -19,32 +19,40 @@ package org.apache.cassandra.cql3.functions;
 
 import com.google.common.base.Objects;
 
-public class FunctionName
+import org.apache.cassandra.db.Keyspace;
+import org.apache.cassandra.db.SystemKeyspace;
+
+public final class FunctionName
 {
-    public final String namespace;
+    public final String keyspace;
     public final String name;
 
-    // Use by toString rather than built from 'bundle' and 'name' so as to
-    // preserve the original case.
-    private final String displayName;
+    public static FunctionName nativeFunction(String name)
+    {
+        return new FunctionName(SystemKeyspace.NAME, name);
+    }
 
-    public FunctionName(String name)
+    public FunctionName(String keyspace, String name)
     {
-        this("", name);
+        assert name != null : "Name parameter must not be null";
+        this.keyspace = keyspace != null ? keyspace : null;
+        this.name = name;
     }
 
-    public FunctionName(String namespace, String name)
+    public FunctionName asNativeFunction()
     {
-        this.namespace = namespace.toLowerCase();
-        this.name = name.toLowerCase();
+        return FunctionName.nativeFunction(name);
+    }
 
-        this.displayName = namespace.isEmpty() ? name : namespace + "::" + name;
+    public boolean hasKeyspace()
+    {
+        return keyspace != null;
     }
 
     @Override
     public final int hashCode()
     {
-        return Objects.hashCode(namespace, name);
+        return Objects.hashCode(keyspace, name);
     }
 
     @Override
@@ -54,13 +62,13 @@ public class FunctionName
             return false;
 
         FunctionName that = (FunctionName)o;
-        return Objects.equal(this.namespace, that.namespace)
+        return Objects.equal(this.keyspace, that.keyspace)
             && Objects.equal(this.name, that.name);
     }
 
     @Override
     public String toString()
     {
-        return displayName;
+        return keyspace == null ? name : keyspace + "." + name;
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/cql3/functions/Functions.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/Functions.java b/src/java/org/apache/cassandra/cql3/functions/Functions.java
index 62de2bc..7021475 100644
--- a/src/java/org/apache/cassandra/cql3/functions/Functions.java
+++ b/src/java/org/apache/cassandra/cql3/functions/Functions.java
@@ -37,7 +37,7 @@ public abstract class Functions
     // We special case the token function because that's the only function whose argument types actually
     // depend on the table on which the function is called. Because it's the sole exception, it's easier
     // to handle it as a special case.
-    private static final FunctionName TOKEN_FUNCTION_NAME = new FunctionName("token");
+    private static final FunctionName TOKEN_FUNCTION_NAME = FunctionName.nativeFunction("token");
 
     private static final String SELECT_UDFS = "SELECT * FROM " + SystemKeyspace.NAME + '.' + SystemKeyspace.SCHEMA_FUNCTIONS_TABLE;
 
@@ -108,6 +108,11 @@ public abstract class Functions
                                        fun.argTypes().get(i));
     }
 
+    public static int getOverloadCount(FunctionName name)
+    {
+        return declared.get(name).size();
+    }
+
     public static Function get(String keyspace,
                                FunctionName name,
                                List<? extends AssignmentTestable> providedArgs,
@@ -115,10 +120,25 @@ public abstract class Functions
                                String receiverCf)
     throws InvalidRequestException
     {
-        if (name.equals(TOKEN_FUNCTION_NAME))
+        if (name.hasKeyspace()
+            ? name.equals(TOKEN_FUNCTION_NAME)
+            : name.name.equals(TOKEN_FUNCTION_NAME.name))
             return new TokenFct(Schema.instance.getCFMetaData(receiverKs, receiverCf));
 
-        List<Function> candidates = declared.get(name);
+        List<Function> candidates;
+        if (!name.hasKeyspace())
+        {
+            // function name not fully qualified
+            candidates = new ArrayList<>();
+            // add 'SYSTEM' (native) candidates
+            candidates.addAll(declared.get(name.asNativeFunction()));
+            // add 'current keyspace' candidates
+            candidates.addAll(declared.get(new FunctionName(keyspace, name.name)));
+        }
+        else
+            // function name is fully qualified (keyspace + name)
+            candidates = declared.get(name);
+
         if (candidates.isEmpty())
             return null;
 
@@ -165,6 +185,7 @@ public abstract class Functions
 
     public static Function find(FunctionName name, List<AbstractType<?>> argTypes)
     {
+        assert name.hasKeyspace() : "function name not fully qualified";
         for (Function f : declared.get(name))
         {
             if (f.argTypes().equals(argTypes))

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/cql3/functions/NativeFunction.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/NativeFunction.java b/src/java/org/apache/cassandra/cql3/functions/NativeFunction.java
index d658d9d..bff7688 100644
--- a/src/java/org/apache/cassandra/cql3/functions/NativeFunction.java
+++ b/src/java/org/apache/cassandra/cql3/functions/NativeFunction.java
@@ -28,12 +28,7 @@ public abstract class NativeFunction extends AbstractFunction
 {
     protected NativeFunction(String name, AbstractType<?> returnType, AbstractType<?>... argTypes)
     {
-        this(new FunctionName(name), returnType, argTypes);
-    }
-
-    protected NativeFunction(FunctionName name, AbstractType<?> returnType, AbstractType<?>... argTypes)
-    {
-        super(name, Arrays.asList(argTypes), returnType);
+        super(FunctionName.nativeFunction(name), Arrays.asList(argTypes), returnType);
     }
 
     // Most of our functions are pure, the other ones should override this
@@ -47,4 +42,3 @@ public abstract class NativeFunction extends AbstractFunction
         return true;
     }
 }
-

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/UDFunction.java b/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
index bf011a7..42418c6 100644
--- a/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
+++ b/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
@@ -30,7 +30,6 @@ import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.db.*;
 import org.apache.cassandra.db.composites.Composite;
 import org.apache.cassandra.db.marshal.AbstractType;
-import org.apache.cassandra.db.marshal.CompositeType;
 import org.apache.cassandra.db.marshal.UTF8Type;
 import org.apache.cassandra.db.marshal.TypeParser;
 import org.apache.cassandra.exceptions.*;
@@ -152,8 +151,8 @@ public abstract class UDFunction extends AbstractFunction implements ScalarFunct
 
     private static Mutation makeSchemaMutation(FunctionName name)
     {
-        CompositeType kv = (CompositeType)SystemKeyspace.SchemaFunctionsTable.getKeyValidator();
-        return new Mutation(SystemKeyspace.NAME, kv.decompose(name.namespace, name.name));
+        UTF8Type kv = (UTF8Type)SystemKeyspace.SchemaFunctionsTable.getKeyValidator();
+        return new Mutation(SystemKeyspace.NAME, kv.decompose(name.keyspace));
     }
 
     public Mutation toSchemaDrop(long timestamp)
@@ -161,7 +160,7 @@ public abstract class UDFunction extends AbstractFunction implements ScalarFunct
         Mutation mutation = makeSchemaMutation(name);
         ColumnFamily cf = mutation.addOrGet(SystemKeyspace.SCHEMA_FUNCTIONS_TABLE);
 
-        Composite prefix = SystemKeyspace.SchemaFunctionsTable.comparator.make(computeSignature(argTypes));
+        Composite prefix = SystemKeyspace.SchemaFunctionsTable.comparator.make(name.name, computeSignature(argTypes));
         int ldt = (int) (System.currentTimeMillis() / 1000);
         cf.addAtom(new RangeTombstone(prefix, prefix.end(), timestamp, ldt));
 
@@ -173,7 +172,7 @@ public abstract class UDFunction extends AbstractFunction implements ScalarFunct
         Mutation mutation = makeSchemaMutation(name);
         ColumnFamily cf = mutation.addOrGet(SystemKeyspace.SCHEMA_FUNCTIONS_TABLE);
 
-        Composite prefix = SystemKeyspace.SchemaFunctionsTable.comparator.make(computeSignature(argTypes));
+        Composite prefix = SystemKeyspace.SchemaFunctionsTable.comparator.make(name.name, computeSignature(argTypes));
         CFRowAdder adder = new CFRowAdder(cf, prefix, timestamp);
 
         adder.resetCollection("argument_names");
@@ -194,9 +193,9 @@ public abstract class UDFunction extends AbstractFunction implements ScalarFunct
 
     public static UDFunction fromSchema(UntypedResultSet.Row row)
     {
-        String namespace = row.getString("namespace");
-        String fname = row.getString("name");
-        FunctionName name = new FunctionName(namespace, fname);
+        String ksName = row.getString("keyspace_name");
+        String functionName = row.getString("function_name");
+        FunctionName name = new FunctionName(ksName, functionName);
 
         List<String> names = row.getList("argument_names", UTF8Type.instance);
         List<String> types = row.getList("argument_types", UTF8Type.instance);
@@ -251,12 +250,12 @@ public abstract class UDFunction extends AbstractFunction implements ScalarFunct
         }
     }
 
-    public static Map<ByteBuffer, UDFunction> fromSchema(Row row)
+    public static Map<Composite, UDFunction> fromSchema(Row row)
     {
         UntypedResultSet results = QueryProcessor.resultify("SELECT * FROM system." + SystemKeyspace.SCHEMA_FUNCTIONS_TABLE, row);
-        Map<ByteBuffer, UDFunction> udfs = new HashMap<>(results.size());
+        Map<Composite, UDFunction> udfs = new HashMap<>(results.size());
         for (UntypedResultSet.Row result : results)
-            udfs.put(result.getBlob("signature"), fromSchema(result));
+            udfs.put(SystemKeyspace.SchemaFunctionsTable.comparator.make(result.getString("function_name"), result.getBlob("signature")), fromSchema(result));
         return udfs;
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 4660e1d..3778d41 100644
--- a/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java
+++ b/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java
@@ -49,7 +49,7 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
         {
             if (factories.doesAggregation() && !factories.containsOnlyAggregateFunctions())
                 throw new InvalidRequestException(String.format("the %s function arguments must be either all aggregates or all none aggregates",
-                                                                fun.name().name));
+                                                                fun.name()));
         }
 
         return new Factory()
@@ -67,6 +67,11 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
                 return fun.returnType();
             }
 
+            public boolean usesFunction(String ksName, String functionName)
+            {
+                return fun.name().keyspace.equals(ksName) && fun.name().name.equals(functionName);
+            }
+
             public Selector newInstance()
             {
                 return fun.isAggregate() ? new AggregateFunctionSelector(fun, factories.newInstances())

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 7c3d34c..7c7dab7 100644
--- a/src/java/org/apache/cassandra/cql3/selection/Selection.java
+++ b/src/java/org/apache/cassandra/cql3/selection/Selection.java
@@ -82,6 +82,11 @@ public abstract class Selection
         return columns.size() - 1;
     }
 
+    public boolean usesFunction(String ksName, String functionName)
+    {
+        return false;
+    }
+
     private static boolean isUsingFunction(List<RawSelector> rawSelectors)
     {
         for (RawSelector rawSelector : rawSelectors)
@@ -346,6 +351,11 @@ public abstract class Selection
                 throw new InvalidRequestException("the select clause must either contains only aggregates or none");
         }
 
+        public boolean usesFunction(String ksName, String functionName)
+        {
+            return factories.usesFunction(ksName, functionName);
+        }
+
         public boolean isAggregate()
         {
             return factories.containsOnlyAggregateFunctions();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 889da70..f2c729b 100644
--- a/src/java/org/apache/cassandra/cql3/selection/Selector.java
+++ b/src/java/org/apache/cassandra/cql3/selection/Selector.java
@@ -40,6 +40,11 @@ public abstract class Selector implements AssignmentTestable
      */
     public static abstract class Factory
     {
+        public boolean usesFunction(String ksName, String functionName)
+        {
+            return false;
+        }
+
         /**
          * Returns the column specification corresponding to the output value of the selector instances created by
          * this factory.

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 6922994..4d3e974 100644
--- a/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java
+++ b/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java
@@ -89,6 +89,14 @@ 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;
+    }
+
     /**
      * Checks if this <code>SelectorFactories</code> contains only factories for aggregates.
      *

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 f0874c1..2db00df 100644
--- a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
@@ -77,6 +77,16 @@ public class BatchStatement implements CQLStatement, MeasurableForPreparedCache
         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 long measureForPreparedCache(MemoryMeter meter)
     {
         long size = meter.measure(this)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
index 712a474..c41fb08 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
@@ -22,6 +22,7 @@ import java.util.HashSet;
 import java.util.List;
 
 import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.config.Schema;
 import org.apache.cassandra.cql3.CQL3Type;
 import org.apache.cassandra.cql3.ColumnIdentifier;
 import org.apache.cassandra.cql3.functions.*;
@@ -31,6 +32,7 @@ import org.apache.cassandra.exceptions.RequestValidationException;
 import org.apache.cassandra.exceptions.UnauthorizedException;
 import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.MigrationManager;
+import org.apache.cassandra.thrift.ThriftValidation;
 import org.apache.cassandra.transport.Event;
 
 /**
@@ -40,7 +42,7 @@ public final class CreateFunctionStatement extends SchemaAlteringStatement
 {
     private final boolean orReplace;
     private final boolean ifNotExists;
-    private final FunctionName functionName;
+    private FunctionName functionName;
     private final String language;
     private final String body;
     private final boolean deterministic;
@@ -70,17 +72,31 @@ public final class CreateFunctionStatement extends SchemaAlteringStatement
         this.ifNotExists = ifNotExists;
     }
 
-    public void checkAccess(ClientState state) throws UnauthorizedException
+    public void prepareKeyspace(ClientState state) throws InvalidRequestException
+    {
+        if (!functionName.hasKeyspace() && state.getRawKeyspace() != null)
+            functionName = new FunctionName(state.getKeyspace(), functionName.name);
+
+        if (!functionName.hasKeyspace())
+            throw new InvalidRequestException("You need to be logged in a keyspace or use a fully qualified function name");
+
+        ThriftValidation.validateKeyspaceNotSystem(functionName.keyspace);
+    }
+
+    public void checkAccess(ClientState state) throws UnauthorizedException, InvalidRequestException
     {
         // TODO CASSANDRA-7557 (function DDL permission)
 
-        state.hasAllKeyspacesAccess(Permission.CREATE);
+        state.hasKeyspaceAccess(functionName.keyspace, Permission.CREATE);
     }
 
     public void validate(ClientState state) throws InvalidRequestException
     {
         if (ifNotExists && orReplace)
             throw new InvalidRequestException("Cannot use both 'OR REPLACE' and 'IF NOT EXISTS' directives");
+
+        if (Schema.instance.getKSMetaData(functionName.keyspace) == null)
+            throw new InvalidRequestException(String.format("Cannot add function '%s' to non existing keyspace '%s'.", functionName.name, functionName.keyspace));
     }
 
     public Event.SchemaChange changeEvent()
@@ -98,7 +114,7 @@ public final class CreateFunctionStatement extends SchemaAlteringStatement
         for (CQL3Type.Raw rawType : argRawTypes)
             // We have no proper keyspace to give, which means that this will break (NPE currently)
             // for UDT: #7791 is open to fix this
-            argTypes.add(rawType.prepare(null).getType());
+            argTypes.add(rawType.prepare(functionName.keyspace).getType());
 
         AbstractType<?> returnType = rawReturnType.prepare(null).getType();
 
@@ -110,10 +126,6 @@ public final class CreateFunctionStatement extends SchemaAlteringStatement
             if (!orReplace)
                 throw new InvalidRequestException(String.format("Function %s already exists", old));
 
-            // Means we're replacing the function. We still need to validate that 1) it's not a native function and 2) that the return type
-            // matches (or that could break existing code badly)
-            if (old.isNative())
-                throw new InvalidRequestException(String.format("Cannot replace native function %s", old));
             if (!old.returnType().isValueCompatibleWith(returnType))
                 throw new InvalidRequestException(String.format("Cannot replace function %s, the new return type %s is not compatible with the return type %s of existing function",
                                                                 functionName, returnType.asCQL3Type(), old.returnType().asCQL3Type()));

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java b/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
index 78c8607..5aaf9b1 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
@@ -29,6 +29,7 @@ import org.apache.cassandra.exceptions.RequestValidationException;
 import org.apache.cassandra.exceptions.UnauthorizedException;
 import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.MigrationManager;
+import org.apache.cassandra.thrift.ThriftValidation;
 import org.apache.cassandra.transport.Event;
 
 /**
@@ -36,7 +37,7 @@ import org.apache.cassandra.transport.Event;
  */
 public final class DropFunctionStatement extends SchemaAlteringStatement
 {
-    private final FunctionName functionName;
+    private FunctionName functionName;
     private final boolean ifExists;
     private final List<CQL3Type.Raw> argRawTypes;
     private final boolean argsPresent;
@@ -52,11 +53,22 @@ public final class DropFunctionStatement extends SchemaAlteringStatement
         this.ifExists = ifExists;
     }
 
-    public void checkAccess(ClientState state) throws UnauthorizedException
+    public void prepareKeyspace(ClientState state) throws InvalidRequestException
+    {
+        if (!functionName.hasKeyspace() && state.getRawKeyspace() != null)
+            functionName = new FunctionName(state.getKeyspace(), functionName.name);
+
+        if (!functionName.hasKeyspace())
+            throw new InvalidRequestException("You need to be logged in a keyspace or use a fully qualified function name");
+
+        ThriftValidation.validateKeyspaceNotSystem(functionName.keyspace);
+    }
+
+    public void checkAccess(ClientState state) throws UnauthorizedException, InvalidRequestException
     {
         // TODO CASSANDRA-7557 (function DDL permission)
 
-        state.hasAllKeyspacesAccess(Permission.DROP);
+        state.hasKeyspaceAccess(functionName.keyspace, Permission.DROP);
     }
 
     /**
@@ -88,11 +100,7 @@ public final class DropFunctionStatement extends SchemaAlteringStatement
 
         List<AbstractType<?>> argTypes = new ArrayList<>(argRawTypes.size());
         for (CQL3Type.Raw rawType : argRawTypes)
-        {
-            // We have no proper keyspace to give, which means that this will break (NPE currently)
-            // for UDT: #7791 is open to fix this
-            argTypes.add(rawType.prepare(null).getType());
-        }
+            argTypes.add(rawType.prepare(functionName.keyspace).getType());
 
         Function old;
         if (argsPresent)
@@ -125,10 +133,6 @@ public final class DropFunctionStatement extends SchemaAlteringStatement
             old = olds.get(0);
         }
 
-        if (old.isNative())
-            throw new InvalidRequestException(String.format("Cannot drop function '%s' because it is a " +
-                                                            "native (built-in) function", functionName));
-
         MigrationManager.announceFunctionDrop((UDFunction)old, isLocalOnly);
         return true;
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 61f6401..7dc9c66 100644
--- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
@@ -22,7 +22,6 @@ import java.util.*;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Iterables;
-import org.apache.cassandra.db.marshal.AbstractType;
 import org.github.jamm.MemoryMeter;
 
 import org.apache.cassandra.auth.Permission;
@@ -88,6 +87,25 @@ public abstract class ModificationStatement implements CQLStatement, MeasurableF
         this.attrs = attrs;
     }
 
+    public boolean usesFunction(String ksName, String functionName)
+    {
+        if (attrs.usesFunction(ksName, functionName))
+            return true;
+        for (Restriction restriction : processedKeys.values())
+            if (restriction != null && restriction.usesFunction(ksName, functionName))
+                return true;
+        for (Operation operation : columnOperations)
+            if (operation != null && operation.usesFunction(ksName, functionName))
+                return true;
+        for (ColumnCondition condition : columnConditions)
+            if (condition != null && condition.usesFunction(ksName, functionName))
+                return true;
+        for (ColumnCondition condition : staticConditions)
+            if (condition != null && condition.usesFunction(ksName, functionName))
+                return true;
+        return false;
+    }
+
     public long measureForPreparedCache(MemoryMeter meter)
     {
         return meter.measure(this)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 d048327..bcce9ce 100644
--- a/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java
@@ -61,4 +61,9 @@ public abstract class ParsedStatement
             this(statement, Collections.<ColumnSpecification>emptyList());
         }
     }
+
+    public boolean usesFunction(String ksName, String functionName)
+    {
+        return false;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/cql3/statements/Restriction.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/Restriction.java b/src/java/org/apache/cassandra/cql3/statements/Restriction.java
index 659ed95..b264156 100644
--- a/src/java/org/apache/cassandra/cql3/statements/Restriction.java
+++ b/src/java/org/apache/cassandra/cql3/statements/Restriction.java
@@ -49,6 +49,8 @@ public interface Restriction
     // Not supported by Slice, but it's convenient to have here
     public List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException;
 
+    boolean usesFunction(String ksName, String functionName);
+
     public static interface EQ extends Restriction {}
 
     public static interface IN extends Restriction

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/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 f214774..621c4db 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -56,8 +56,6 @@ import org.apache.cassandra.thrift.ThriftValidation;
 import org.apache.cassandra.serializers.MarshalException;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Encapsulates a completely parsed SELECT query, including the target
@@ -66,8 +64,6 @@ import org.slf4j.LoggerFactory;
  */
 public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
 {
-    private static final Logger logger = LoggerFactory.getLogger(SelectStatement.class);
-
     private static final int DEFAULT_COUNT_PAGE_SIZE = 10000;
 
     private final int boundTerms;
@@ -125,6 +121,24 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         initStaticColumnsInfo();
     }
 
+    public boolean usesFunction(String ksName, String functionName)
+    {
+        if (selection.usesFunction(ksName, functionName))
+            return true;
+        if (limit != null && limit.usesFunction(ksName, functionName))
+            return true;
+        for (Restriction restriction : metadataRestrictions.values())
+            if (restriction != null && restriction.usesFunction(ksName, functionName))
+                return true;
+        for (Restriction restriction : keyRestrictions)
+            if (restriction != null && restriction.usesFunction(ksName, functionName))
+                return true;
+        for (Restriction restriction : columnRestrictions)
+            if (restriction != null && restriction.usesFunction(ksName, functionName))
+                return true;
+        return false;
+    }
+
     private void initStaticColumnsInfo()
     {
         if (!cfm.hasStaticColumns())

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/cql3/statements/SingleColumnRestriction.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SingleColumnRestriction.java b/src/java/org/apache/cassandra/cql3/statements/SingleColumnRestriction.java
index b1c6ccc..b6ca640 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SingleColumnRestriction.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SingleColumnRestriction.java
@@ -43,6 +43,11 @@ public abstract class SingleColumnRestriction implements Restriction
             this.onToken = onToken;
         }
 
+        public boolean usesFunction(String ksName, String functionName)
+        {
+            return value != null && value.usesFunction(ksName, functionName);
+        }
+
         public List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException
         {
             return Collections.singletonList(value.bindAndGet(options));
@@ -94,6 +99,15 @@ public abstract class SingleColumnRestriction implements Restriction
             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 List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException
         {
             List<ByteBuffer> buffers = new ArrayList<>(values.size());
@@ -153,6 +167,11 @@ public abstract class SingleColumnRestriction implements Restriction
             this.marker = marker;
         }
 
+        public boolean usesFunction(String ksName, String functionName)
+        {
+            return false;
+        }
+
         public List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException
         {
             Term.MultiItemTerminal lval = (Term.MultiItemTerminal)marker.bind(options);
@@ -216,6 +235,14 @@ public abstract class SingleColumnRestriction implements Restriction
             this.onToken = onToken;
         }
 
+        public boolean usesFunction(String ksName, String functionName)
+        {
+            for (Term value : bounds)
+                if (value != null && value.usesFunction(ksName, functionName))
+                    return true;
+            return false;
+        }
+
         public boolean isSlice()
         {
             return true;
@@ -343,6 +370,19 @@ public abstract class SingleColumnRestriction implements Restriction
         private List<Term> values; // for CONTAINS
         private List<Term> keys;   // for CONTAINS_KEY
 
+        public boolean usesFunction(String ksName, String functionName)
+        {
+            if (values != null)
+                for (Term value : values)
+                    if (value != null && value.usesFunction(ksName, functionName))
+                        return true;
+            if (keys != null)
+                for (Term key : keys)
+                    if (key != null && key.usesFunction(ksName, functionName))
+                        return true;
+            return false;
+        }
+
         public boolean hasContains()
         {
             return values != null;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/db/DefsTables.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/DefsTables.java b/src/java/org/apache/cassandra/db/DefsTables.java
index a02f65e..bcb0893 100644
--- a/src/java/org/apache/cassandra/db/DefsTables.java
+++ b/src/java/org/apache/cassandra/db/DefsTables.java
@@ -37,6 +37,7 @@ import org.apache.cassandra.cql3.functions.Functions;
 import org.apache.cassandra.cql3.functions.UDFunction;
 import org.apache.cassandra.db.commitlog.CommitLog;
 import org.apache.cassandra.db.compaction.CompactionManager;
+import org.apache.cassandra.db.composites.Composite;
 import org.apache.cassandra.db.filter.QueryFilter;
 import org.apache.cassandra.db.marshal.AsciiType;
 import org.apache.cassandra.db.marshal.UserType;
@@ -303,7 +304,7 @@ public class DefsTables
 
         MapDifference<DecoratedKey, ColumnFamily> diff = Maps.difference(before, after);
 
-        // New namespace with functions
+        // New keyspace with functions
         for (Map.Entry<DecoratedKey, ColumnFamily> entry : diff.entriesOnlyOnRight().entrySet())
             if (entry.getValue().hasColumns())
                 created.addAll(UDFunction.fromSchema(new Row(entry.getKey(), entry.getValue())).values());
@@ -315,7 +316,7 @@ public class DefsTables
 
             if (pre.hasColumns() && post.hasColumns())
             {
-                MapDifference<ByteBuffer, UDFunction> delta =
+                MapDifference<Composite, UDFunction> delta =
                         Maps.difference(UDFunction.fromSchema(new Row(entry.getKey(), pre)),
                                         UDFunction.fromSchema(new Row(entry.getKey(), post)));
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/db/SystemKeyspace.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/SystemKeyspace.java b/src/java/org/apache/cassandra/db/SystemKeyspace.java
index 49c1502..7806d5f 100644
--- a/src/java/org/apache/cassandra/db/SystemKeyspace.java
+++ b/src/java/org/apache/cassandra/db/SystemKeyspace.java
@@ -182,11 +182,12 @@ public final class SystemKeyspace
                 + "PRIMARY KEY ((keyspace_name), type_name))")
                 .gcGraceSeconds(WEEK);
 
+
     public static final CFMetaData SchemaFunctionsTable =
         compile(SCHEMA_FUNCTIONS_TABLE, "user defined function definitions",
                 "CREATE TABLE %s ("
-                + "namespace text,"
-                + "name text,"
+                + "keyspace_name text,"
+                + "function_name text,"
                 + "signature blob,"
                 + "argument_names list<text>,"
                 + "argument_types list<text>,"
@@ -194,7 +195,7 @@ public final class SystemKeyspace
                 + "deterministic boolean,"
                 + "language text,"
                 + "return_type text,"
-                + "PRIMARY KEY ((namespace, name), signature))")
+                + "PRIMARY KEY ((keyspace_name), function_name, signature))")
                 .gcGraceSeconds(WEEK);
 
     public static final CFMetaData BuiltIndexesTable =

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/service/IMigrationListener.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/IMigrationListener.java b/src/java/org/apache/cassandra/service/IMigrationListener.java
index b4eb392..bc67e8a 100644
--- a/src/java/org/apache/cassandra/service/IMigrationListener.java
+++ b/src/java/org/apache/cassandra/service/IMigrationListener.java
@@ -22,16 +22,16 @@ public interface IMigrationListener
     public void onCreateKeyspace(String ksName);
     public void onCreateColumnFamily(String ksName, String cfName);
     public void onCreateUserType(String ksName, String typeName);
-    public void onCreateFunction(String namespace, String functionName);
+    public void onCreateFunction(String ksName, String functionName);
 
     public void onUpdateKeyspace(String ksName);
     public void onUpdateColumnFamily(String ksName, String cfName);
     public void onUpdateUserType(String ksName, String typeName);
-    public void onUpdateFunction(String namespace, String functionName);
+    public void onUpdateFunction(String ksName, String functionName);
 
     public void onDropKeyspace(String ksName);
     public void onDropColumnFamily(String ksName, String cfName);
     public void onDropUserType(String ksName, String typeName);
-    public void onDropFunction(String namespace, String functionName);
+    public void onDropFunction(String ksName, String functionName);
 
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/service/MigrationManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/MigrationManager.java b/src/java/org/apache/cassandra/service/MigrationManager.java
index a5d4628..8c3199f 100644
--- a/src/java/org/apache/cassandra/service/MigrationManager.java
+++ b/src/java/org/apache/cassandra/service/MigrationManager.java
@@ -38,8 +38,11 @@ import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.KSMetaData;
 import org.apache.cassandra.config.UTMetaData;
 import org.apache.cassandra.config.Schema;
+import org.apache.cassandra.cql3.functions.AggregateFunction;
+import org.apache.cassandra.cql3.functions.ScalarFunction;
 import org.apache.cassandra.cql3.functions.UDFunction;
 import org.apache.cassandra.db.*;
+import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.db.marshal.UserType;
 import org.apache.cassandra.exceptions.AlreadyExistsException;
 import org.apache.cassandra.exceptions.ConfigurationException;
@@ -177,19 +180,36 @@ public class MigrationManager
     public void notifyCreateFunction(UDFunction udf)
     {
         for (IMigrationListener listener : listeners)
-            listener.onCreateFunction(udf.name().namespace, udf.name().name);
+            listener.onCreateFunction(udf.name().keyspace, udf.name().name);
     }
 
     public void notifyUpdateFunction(UDFunction udf)
     {
         for (IMigrationListener listener : listeners)
-            listener.onUpdateFunction(udf.name().namespace, udf.name().name);
+            listener.onUpdateFunction(udf.name().keyspace, udf.name().name);
     }
 
     public void notifyDropFunction(UDFunction udf)
     {
         for (IMigrationListener listener : listeners)
-            listener.onDropFunction(udf.name().namespace, udf.name().name);
+            listener.onDropFunction(udf.name().keyspace, udf.name().name);
+    }
+
+    private List<String> asString(List<AbstractType<?>> abstractTypes)
+    {
+        List<String> r = new ArrayList<>(abstractTypes.size());
+        for (AbstractType<?> abstractType : abstractTypes)
+            r.add(abstractType.asCQL3Type().toString());
+        return r;
+    }
+
+    private String udType(UDFunction udf)
+    {
+        if (udf instanceof ScalarFunction)
+            return "scalar";
+        if (udf instanceof AggregateFunction)
+            return "aggregate";
+        return "";
     }
 
     public void notifyUpdateKeyspace(KSMetaData ksm)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/transport/Event.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/transport/Event.java b/src/java/org/apache/cassandra/transport/Event.java
index 85943cf..9962599 100644
--- a/src/java/org/apache/cassandra/transport/Event.java
+++ b/src/java/org/apache/cassandra/transport/Event.java
@@ -208,15 +208,15 @@ public abstract class Event
 
         public final Change change;
         public final Target target;
-        public final String keyOrNamespace;
+        public final String keyspace;
         public final String tableOrTypeOrFunction;
 
-        public SchemaChange(Change change, Target target, String keyOrNamespace, String tableOrTypeOrFunction)
+        public SchemaChange(Change change, Target target, String keyspace, String tableOrTypeOrFunction)
         {
             super(Type.SCHEMA_CHANGE);
             this.change = change;
             this.target = target;
-            this.keyOrNamespace = keyOrNamespace;
+            this.keyspace = keyspace;
             this.tableOrTypeOrFunction = tableOrTypeOrFunction;
             if (target != Target.KEYSPACE)
                 assert this.tableOrTypeOrFunction != null : "Table or type should be set for non-keyspace schema change events";
@@ -252,7 +252,7 @@ public abstract class Event
             {
                 CBUtil.writeEnumValue(change, dest);
                 CBUtil.writeEnumValue(target, dest);
-                CBUtil.writeString(keyOrNamespace, dest);
+                CBUtil.writeString(keyspace, dest);
                 if (target != Target.KEYSPACE)
                     CBUtil.writeString(tableOrTypeOrFunction, dest);
             }
@@ -263,13 +263,13 @@ public abstract class Event
                     // For the v1/v2 protocol, we have no way to represent type changes, so we simply say the keyspace
                     // was updated.  See CASSANDRA-7617.
                     CBUtil.writeEnumValue(Change.UPDATED, dest);
-                    CBUtil.writeString(keyOrNamespace, dest);
+                    CBUtil.writeString(keyspace, dest);
                     CBUtil.writeString("", dest);
                 }
                 else
                 {
                     CBUtil.writeEnumValue(change, dest);
-                    CBUtil.writeString(keyOrNamespace, dest);
+                    CBUtil.writeString(keyspace, dest);
                     CBUtil.writeString(target == Target.KEYSPACE ? "" : tableOrTypeOrFunction, dest);
                 }
             }
@@ -281,7 +281,7 @@ public abstract class Event
             {
                 int size = CBUtil.sizeOfEnumValue(change)
                          + CBUtil.sizeOfEnumValue(target)
-                         + CBUtil.sizeOfString(keyOrNamespace);
+                         + CBUtil.sizeOfString(keyspace);
 
                 if (target != Target.KEYSPACE)
                     size += CBUtil.sizeOfString(tableOrTypeOrFunction);
@@ -293,11 +293,11 @@ public abstract class Event
                 if (target == Target.TYPE)
                 {
                     return CBUtil.sizeOfEnumValue(Change.UPDATED)
-                         + CBUtil.sizeOfString(keyOrNamespace)
+                         + CBUtil.sizeOfString(keyspace)
                          + CBUtil.sizeOfString("");
                 }
                 return CBUtil.sizeOfEnumValue(change)
-                     + CBUtil.sizeOfString(keyOrNamespace)
+                     + CBUtil.sizeOfString(keyspace)
                      + CBUtil.sizeOfString(target == Target.KEYSPACE ? "" : tableOrTypeOrFunction);
             }
         }
@@ -305,13 +305,13 @@ public abstract class Event
         @Override
         public String toString()
         {
-            return change + " " + target + " " + keyOrNamespace + (tableOrTypeOrFunction == null ? "" : "." + tableOrTypeOrFunction);
+            return change + " " + target + " " + keyspace + (tableOrTypeOrFunction == null ? "" : "." + tableOrTypeOrFunction);
         }
 
         @Override
         public int hashCode()
         {
-            return Objects.hashCode(change, target, keyOrNamespace, tableOrTypeOrFunction);
+            return Objects.hashCode(change, target, keyspace, tableOrTypeOrFunction);
         }
 
         @Override
@@ -323,7 +323,7 @@ public abstract class Event
             SchemaChange scc = (SchemaChange)other;
             return Objects.equal(change, scc.change)
                 && Objects.equal(target, scc.target)
-                && Objects.equal(keyOrNamespace, scc.keyOrNamespace)
+                && Objects.equal(keyspace, scc.keyspace)
                 && Objects.equal(tableOrTypeOrFunction, scc.tableOrTypeOrFunction);
         }
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/src/java/org/apache/cassandra/transport/Server.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/transport/Server.java b/src/java/org/apache/cassandra/transport/Server.java
index f8822a5..15fad88 100644
--- a/src/java/org/apache/cassandra/transport/Server.java
+++ b/src/java/org/apache/cassandra/transport/Server.java
@@ -27,8 +27,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
 
-import io.netty.buffer.ByteBufAllocator;
-import io.netty.buffer.PooledByteBufAllocator;
 import io.netty.channel.epoll.Epoll;
 import io.netty.channel.epoll.EpollEventLoopGroup;
 import io.netty.channel.epoll.EpollServerSocketChannel;
@@ -411,7 +409,7 @@ public class Server implements CassandraDaemon.Server
             server.connectionTracker.send(new Event.SchemaChange(Event.SchemaChange.Change.CREATED, Event.SchemaChange.Target.TYPE, ksName, typeName));
         }
 
-        public void onCreateFunction(String namespace, String functionName)
+        public void onCreateFunction(String ksName, String functionName)
         {
         }
 
@@ -430,7 +428,7 @@ public class Server implements CassandraDaemon.Server
             server.connectionTracker.send(new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TYPE, ksName, typeName));
         }
 
-        public void onUpdateFunction(String namespace, String functionName)
+        public void onUpdateFunction(String ksName, String functionName)
         {
         }
 
@@ -449,7 +447,7 @@ public class Server implements CassandraDaemon.Server
             server.connectionTracker.send(new Event.SchemaChange(Event.SchemaChange.Change.DROPPED, Event.SchemaChange.Target.TYPE, ksName, typeName));
         }
 
-        public void onDropFunction(String namespace, String functionName)
+        public void onDropFunction(String ksName, String functionName)
         {
         }
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/test/unit/org/apache/cassandra/cql3/AggregationTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/AggregationTest.java b/test/unit/org/apache/cassandra/cql3/AggregationTest.java
index 99db62a..859fe65 100644
--- a/test/unit/org/apache/cassandra/cql3/AggregationTest.java
+++ b/test/unit/org/apache/cassandra/cql3/AggregationTest.java
@@ -37,7 +37,7 @@ public class AggregationTest extends CQLTester
         assertColumnNames(execute("SELECT COUNT(*) FROM %s"), "count");
         assertRows(execute("SELECT COUNT(*) FROM %s"), row(0L));
         assertColumnNames(execute("SELECT max(b), min(b), sum(b), avg(b) , max(c), sum(c), avg(c), sum(d), avg(d) FROM %s"),
-                          "max(b)", "min(b)", "sum(b)", "avg(b)" , "max(c)", "sum(c)", "avg(c)", "sum(d)", "avg(d)");
+                          "system.max(b)", "system.min(b)", "system.sum(b)", "system.avg(b)" , "system.max(c)", "system.sum(c)", "system.avg(c)", "system.sum(d)", "system.avg(d)");
         assertRows(execute("SELECT max(b), min(b), sum(b), avg(b) , max(c), sum(c), avg(c), sum(d), avg(d) FROM %s"),
                    row(null, null, 0, 0, null, 0.0, 0.0, new BigDecimal("0"), new BigDecimal("0")));
 
@@ -94,15 +94,15 @@ public class AggregationTest extends CQLTester
     {
         createTable("CREATE TABLE %s (a int primary key, b timeuuid, c double, d double)");
 
-        execute("CREATE OR REPLACE FUNCTION copySign(magnitude double, sign double) RETURNS double LANGUAGE JAVA\n" +
+        execute("CREATE OR REPLACE FUNCTION "+KEYSPACE+".copySign(magnitude double, sign double) RETURNS double LANGUAGE JAVA\n" +
                 "AS 'return Double.valueOf(Math.copySign(magnitude.doubleValue(), sign.doubleValue()));';");
 
-        assertColumnNames(execute("SELECT max(a), max(unixTimestampOf(b)) FROM %s"), "max(a)", "max(unixtimestampof(b))");
+        assertColumnNames(execute("SELECT max(a), max(unixTimestampOf(b)) FROM %s"), "system.max(a)", "system.max(system.unixtimestampof(b))");
         assertRows(execute("SELECT max(a), max(unixTimestampOf(b)) FROM %s"), row(null, null));
-        assertColumnNames(execute("SELECT max(a), unixTimestampOf(max(b)) FROM %s"), "max(a)", "unixtimestampof(max(b))");
+        assertColumnNames(execute("SELECT max(a), unixTimestampOf(max(b)) FROM %s"), "system.max(a)", "system.unixtimestampof(system.max(b))");
         assertRows(execute("SELECT max(a), unixTimestampOf(max(b)) FROM %s"), row(null, null));
 
-        assertColumnNames(execute("SELECT max(copySign(c, d)) FROM %s"), "max(copysign(c, d))");
+        assertColumnNames(execute("SELECT max(copySign(c, d)) FROM %s"), "system.max("+KEYSPACE+".copysign(c, d))");
         assertRows(execute("SELECT max(copySign(c, d)) FROM %s"), row((Object) null));
 
         execute("INSERT INTO %s (a, b, c, d) VALUES (1, maxTimeuuid('2011-02-03 04:05:00+0000'), -1.2, 2.1)");

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b4d7f3be/test/unit/org/apache/cassandra/cql3/PgStringTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/PgStringTest.java b/test/unit/org/apache/cassandra/cql3/PgStringTest.java
index 856a255..1870a9a 100644
--- a/test/unit/org/apache/cassandra/cql3/PgStringTest.java
+++ b/test/unit/org/apache/cassandra/cql3/PgStringTest.java
@@ -26,7 +26,7 @@ public class PgStringTest extends CQLTester
     @Test
     public void testPgSyleFunction() throws Throwable
     {
-        execute("create or replace function pg::pgfun1 ( input double ) returns text language java\n" +
+        execute("create or replace function "+KEYSPACE+".pgfun1 ( input double ) returns text language java\n" +
                 "AS $$return \"foobar\";$$");
     }
 
@@ -70,7 +70,7 @@ public class PgStringTest extends CQLTester
     public void testMarkerPgFail() throws Throwable
     {
         // must throw SyntaxException - not StringIndexOutOfBoundsException or similar
-        execute("create function foo::pgfun1 ( input double ) returns text language java\n" +
+        execute("create function "+KEYSPACE+".pgfun1 ( input double ) returns text language java\n" +
                 "AS $javasrc$return 0L;$javasrc$;");
     }
 }