cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sn...@apache.org
Subject cassandra git commit: UFPureScriptTest fails with pre-3.0 java-driver
Date Wed, 30 Sep 2015 11:26:03 GMT
Repository: cassandra
Updated Branches:
  refs/heads/cassandra-3.0 8bb7077e8 -> 3ae01ddcc


UFPureScriptTest fails with pre-3.0 java-driver

patch by Robert Stupp; reviewed by Joshua McKenzie for CASSANDRA-10141


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

Branch: refs/heads/cassandra-3.0
Commit: 3ae01ddcc0c11a77f34eb48d334e7d3746a26381
Parents: 8bb7077
Author: Robert Stupp <snazy@snazy.de>
Authored: Wed Sep 30 13:24:55 2015 +0200
Committer: Robert Stupp <snazy@snazy.de>
Committed: Wed Sep 30 13:24:55 2015 +0200

----------------------------------------------------------------------
 .../cql3/functions/JavaBasedUDFunction.java     |   2 +-
 .../cql3/functions/ScriptBasedUDFunction.java   |   4 +-
 .../cql3/functions/SecurityThreadGroup.java     |  19 ++-
 .../functions/ThreadAwareSecurityManager.java   |  57 +++++---
 .../cassandra/cql3/functions/UDFunction.java    |  12 +-
 .../validation/entities/UFPureScriptTest.java   |  99 -------------
 .../UFPureScriptTupleCollectionTest.java        | 138 +++++++++++++++++++
 7 files changed, 207 insertions(+), 124 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ae01ddc/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java b/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java
index 1db13e3..0fb8123 100644
--- a/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java
+++ b/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java
@@ -70,7 +70,7 @@ final class JavaBasedUDFunction extends UDFunction
         new UDFExecutorService(new NamedThreadFactory("UserDefinedFunctions",
                                                       Thread.MIN_PRIORITY,
                                                       udfClassLoader,
-                                                      new SecurityThreadGroup("UserDefinedFunctions",
null)),
+                                                      new SecurityThreadGroup("UserDefinedFunctions",
null, UDFunction::initializeThread)),
                                "userfunction");
 
     private static final EcjTargetClassLoader targetClassLoader = new EcjTargetClassLoader();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ae01ddc/src/java/org/apache/cassandra/cql3/functions/ScriptBasedUDFunction.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/ScriptBasedUDFunction.java b/src/java/org/apache/cassandra/cql3/functions/ScriptBasedUDFunction.java
index ce4ea5e..4ffb992 100644
--- a/src/java/org/apache/cassandra/cql3/functions/ScriptBasedUDFunction.java
+++ b/src/java/org/apache/cassandra/cql3/functions/ScriptBasedUDFunction.java
@@ -86,7 +86,9 @@ final class ScriptBasedUDFunction extends UDFunction
         new UDFExecutorService(new NamedThreadFactory("UserDefinedScriptFunctions",
                                                       Thread.MIN_PRIORITY,
                                                       udfClassLoader,
-                                                      new SecurityThreadGroup("UserDefinedScriptFunctions",
Collections.unmodifiableSet(new HashSet<>(Arrays.asList(allowedPackagesArray))))),
+                                                      new SecurityThreadGroup("UserDefinedScriptFunctions",
+                                                                              Collections.unmodifiableSet(new
HashSet<>(Arrays.asList(allowedPackagesArray))),
+                                                                              UDFunction::initializeThread)),
                                "userscripts");
 
     static

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ae01ddc/src/java/org/apache/cassandra/cql3/functions/SecurityThreadGroup.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/SecurityThreadGroup.java b/src/java/org/apache/cassandra/cql3/functions/SecurityThreadGroup.java
index fb821d5..8f50dc8 100644
--- a/src/java/org/apache/cassandra/cql3/functions/SecurityThreadGroup.java
+++ b/src/java/org/apache/cassandra/cql3/functions/SecurityThreadGroup.java
@@ -26,15 +26,28 @@ import java.util.Set;
 public final class SecurityThreadGroup extends ThreadGroup
 {
     private final Set<String> allowedPackages;
+    private final ThreadInitializer threadInitializer;
 
-    public SecurityThreadGroup(String name, Set<String> allowedPackages)
+    public SecurityThreadGroup(String name, Set<String> allowedPackages, ThreadInitializer
threadInitializer)
     {
         super(name);
         this.allowedPackages = allowedPackages;
+        this.threadInitializer = threadInitializer;
     }
 
-    public Set<String> getAllowedPackages()
+    public void initializeThread()
     {
-        return allowedPackages;
+        threadInitializer.initializeThread();
+    }
+
+    public boolean isPackageAllowed(String pkg)
+    {
+        return allowedPackages == null || allowedPackages.contains(pkg);
+    }
+
+    @FunctionalInterface
+    interface ThreadInitializer
+    {
+        void initializeThread();
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ae01ddc/src/java/org/apache/cassandra/cql3/functions/ThreadAwareSecurityManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/ThreadAwareSecurityManager.java
b/src/java/org/apache/cassandra/cql3/functions/ThreadAwareSecurityManager.java
index edc03a7..b96c80f 100644
--- a/src/java/org/apache/cassandra/cql3/functions/ThreadAwareSecurityManager.java
+++ b/src/java/org/apache/cassandra/cql3/functions/ThreadAwareSecurityManager.java
@@ -28,9 +28,6 @@ import java.security.Policy;
 import java.security.ProtectionDomain;
 import java.util.Collections;
 import java.util.Enumeration;
-import java.util.Set;
-
-import sun.security.util.SecurityConstants;
 
 /**
  * Custom {@link SecurityManager} and {@link Policy} implementation that only performs access
checks
@@ -61,6 +58,10 @@ public final class ThreadAwareSecurityManager extends SecurityManager
         }
     };
 
+    private static final RuntimePermission CHECK_MEMBER_ACCESS_PERMISSION = new RuntimePermission("accessDeclaredMembers");
+    private static final RuntimePermission MODIFY_THREAD_PERMISSION = new RuntimePermission("modifyThread");
+    private static final RuntimePermission MODIFY_THREADGROUP_PERMISSION = new RuntimePermission("modifyThreadGroup");
+
     private static volatile boolean installed;
 
     public static void install()
@@ -131,37 +132,59 @@ public final class ThreadAwareSecurityManager extends SecurityManager
         });
     }
 
+    private static final ThreadLocal<Boolean> initializedThread = new ThreadLocal<>();
+
     private ThreadAwareSecurityManager()
     {
     }
 
     private static boolean isSecuredThread()
     {
-        return Thread.currentThread().getThreadGroup() instanceof SecurityThreadGroup;
+        ThreadGroup tg = Thread.currentThread().getThreadGroup();
+        if (!(tg instanceof SecurityThreadGroup))
+            return false;
+        Boolean threadInitialized = initializedThread.get();
+        if (threadInitialized == null)
+        {
+            initializedThread.set(false);
+            ((SecurityThreadGroup) tg).initializeThread();
+            initializedThread.set(true);
+            threadInitialized = true;
+        }
+        return threadInitialized;
     }
 
     public void checkAccess(Thread t)
     {
-        // need to override since the default implementation is kind of ...
+        // need to override since the default implementation only checks the permission if
the current thread's
+        // in the root-thread-group
 
         if (isSecuredThread())
-            throw new AccessControlException("access denied: " + SecurityConstants.MODIFY_THREAD_PERMISSION,
SecurityConstants.MODIFY_THREAD_PERMISSION);
+            throw new AccessControlException("access denied: " + MODIFY_THREAD_PERMISSION,
MODIFY_THREAD_PERMISSION);
         super.checkAccess(t);
     }
 
     public void checkAccess(ThreadGroup g)
     {
-        // need to override since the default implementation is kind of ...
+        // need to override since the default implementation only checks the permission if
the current thread's
+        // in the root-thread-group
 
         if (isSecuredThread())
-            throw new AccessControlException("access denied: " + SecurityConstants.MODIFY_THREADGROUP_PERMISSION,
SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
+            throw new AccessControlException("access denied: " + MODIFY_THREADGROUP_PERMISSION,
MODIFY_THREADGROUP_PERMISSION);
         super.checkAccess(g);
     }
 
     public void checkPermission(Permission perm)
     {
-        if (isSecuredThread())
-            super.checkPermission(perm);
+        if (!isSecuredThread())
+            return;
+
+        // required by JavaDriver 2.2.0-rc3 and 3.0.0-a2 or newer
+        // code in com.datastax.driver.core.CodecUtils uses Guava stuff, which in turns requires
this permission
+        if (CHECK_MEMBER_ACCESS_PERMISSION.equals(perm))
+            return;
+
+        super.checkPermission(perm);
     }
 
     public void checkPermission(Permission perm, Object context)
@@ -172,13 +195,15 @@ public final class ThreadAwareSecurityManager extends SecurityManager
 
     public void checkPackageAccess(String pkg)
     {
-        ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
-        if (threadGroup instanceof SecurityThreadGroup)
+        if (!isSecuredThread())
+            return;
+
+        if (!((SecurityThreadGroup) Thread.currentThread().getThreadGroup()).isPackageAllowed(pkg))
         {
-            Set<String> allowedPackages = ((SecurityThreadGroup) threadGroup).getAllowedPackages();
-            if (allowedPackages != null && !allowedPackages.contains(pkg))
-                throw new AccessControlException("access denied: " + new RuntimePermission("accessClassInPackage."
+ pkg), new RuntimePermission("accessClassInPackage." + pkg));
-            super.checkPackageAccess(pkg);
+            RuntimePermission perm = new RuntimePermission("accessClassInPackage." + pkg);
+            throw new AccessControlException("access denied: " + perm, perm);
         }
+
+        super.checkPackageAccess(pkg);
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ae01ddc/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 a07852d..36cdb15 100644
--- a/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
+++ b/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
@@ -296,6 +296,14 @@ public abstract class UDFunction extends AbstractFunction implements
ScalarFunct
             throw new InvalidRequestException("Scripted user-defined functions are disabled
in cassandra.yaml - set enable_scripted_user_defined_functions=true to enable if you are aware
of the security risks");
     }
 
+    static void initializeThread()
+    {
+        // Get the TypeCodec stuff in Java Driver initialized.
+        // This is to get the classes loaded outside of the restricted sandbox's security
context of a UDF.
+        UDHelper.codecRegistry.codecFor(DataType.inet()).format(InetAddress.getLoopbackAddress());
+        UDHelper.codecRegistry.codecFor(DataType.ascii()).format("");
+    }
+
     private static final class ThreadIdAndCpuTime extends CompletableFuture<Object>
     {
         long threadId;
@@ -309,10 +317,6 @@ public abstract class UDFunction extends AbstractFunction implements
ScalarFunct
             // because class loading would be deferred until setup() is executed - but setup()
is called with
             // limited privileges.
             threadMXBean.getCurrentThreadCpuTime();
-            //
-            // Get the TypeCodec stuff in Java Driver initialized.
-            UDHelper.codecRegistry.codecFor(DataType.inet()).format(InetAddress.getLoopbackAddress());
-            UDHelper.codecRegistry.codecFor(DataType.ascii()).format("");
         }
 
         void setup()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ae01ddc/test/unit/org/apache/cassandra/cql3/validation/entities/UFPureScriptTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFPureScriptTest.java
b/test/unit/org/apache/cassandra/cql3/validation/entities/UFPureScriptTest.java
index ef06dbf..82ed63d 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFPureScriptTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFPureScriptTest.java
@@ -32,15 +32,11 @@ import java.util.UUID;
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.datastax.driver.core.DataType;
-import com.datastax.driver.core.TupleType;
-import com.datastax.driver.core.TupleValue;
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.cql3.CQLTester;
 import org.apache.cassandra.cql3.UntypedResultSet;
 import org.apache.cassandra.cql3.functions.FunctionName;
 import org.apache.cassandra.exceptions.FunctionExecutionException;
-import org.apache.cassandra.transport.Server;
 import org.apache.cassandra.utils.UUIDGen;
 
 public class UFPureScriptTest extends CQLTester
@@ -119,101 +115,6 @@ public class UFPureScriptTest extends CQLTester
     }
 
     @Test
-    public void testJavascriptTupleTypeCollection() throws Throwable
-    {
-        String tupleTypeDef = "tuple<double, list<double>, set<text>, map<int,
boolean>>";
-        createTable("CREATE TABLE %s (key int primary key, tup frozen<" + tupleTypeDef
+ ">)");
-
-        String fTup1 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
-                                      "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
-                                      "RETURNS NULL ON NULL INPUT " +
-                                      "RETURNS tuple<double, list<double>, set<text>,
map<int, boolean>> " +
-                                      "LANGUAGE javascript\n" +
-                                      "AS $$" +
-                                      "       tup;$$;");
-        String fTup2 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
-                                      "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
-                                      "RETURNS NULL ON NULL INPUT " +
-                                      "RETURNS double " +
-                                      "LANGUAGE javascript\n" +
-                                      "AS $$" +
-                                      "       tup.getDouble(0);$$;");
-        String fTup3 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
-                                      "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
-                                      "RETURNS NULL ON NULL INPUT " +
-                                      "RETURNS list<double> " +
-                                      "LANGUAGE javascript\n" +
-                                      "AS $$" +
-                                      "       tup.getList(1, java.lang.Double.class);$$;");
-        String fTup4 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
-                                      "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
-                                      "RETURNS NULL ON NULL INPUT " +
-                                      "RETURNS set<text> " +
-                                      "LANGUAGE javascript\n" +
-                                      "AS $$" +
-                                      "       tup.getSet(2, java.lang.String.class);$$;");
-        String fTup5 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
-                                      "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
-                                      "RETURNS NULL ON NULL INPUT " +
-                                      "RETURNS map<int, boolean> " +
-                                      "LANGUAGE javascript\n" +
-                                      "AS $$" +
-                                      "       tup.getMap(3, java.lang.Integer.class, java.lang.Boolean.class);$$;");
-
-        List<Double> list = Arrays.asList(1d, 2d, 3d);
-        Set<String> set = new TreeSet<>(Arrays.asList("one", "three", "two"));
-        Map<Integer, Boolean> map = new TreeMap<>();
-        map.put(1, true);
-        map.put(2, false);
-        map.put(3, true);
-
-        Object t = tuple(1d, list, set, map);
-
-        execute("INSERT INTO %s (key, tup) VALUES (1, ?)", t);
-
-        assertRows(execute("SELECT " + fTup1 + "(tup) FROM %s WHERE key = 1"),
-                   row(t));
-        assertRows(execute("SELECT " + fTup2 + "(tup) FROM %s WHERE key = 1"),
-                   row(1d));
-        assertRows(execute("SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
-                   row(list));
-        assertRows(execute("SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
-                   row(set));
-        assertRows(execute("SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
-                   row(map));
-
-        // same test - but via native protocol
-        // we use protocol V3 here to encode the expected version because the server
-        // always serializes Collections using V3 - see CollectionSerializer's
-        // serialize and deserialize methods.
-        TupleType tType = tupleTypeOf(Server.VERSION_3,
-                                      DataType.cdouble(),
-                                      DataType.list(DataType.cdouble()),
-                                      DataType.set(DataType.text()),
-                                      DataType.map(DataType.cint(),
-                                                   DataType.cboolean()));
-        TupleValue tup = tType.newValue(1d, list, set, map);
-        for (int version : PROTOCOL_VERSIONS)
-        {
-            assertRowsNet(version,
-                          executeNet(version, "SELECT " + fTup1 + "(tup) FROM %s WHERE key
= 1"),
-                          row(tup));
-            assertRowsNet(version,
-                          executeNet(version, "SELECT " + fTup2 + "(tup) FROM %s WHERE key
= 1"),
-                          row(1d));
-            assertRowsNet(version,
-                          executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key
= 1"),
-                          row(list));
-            assertRowsNet(version,
-                          executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key
= 1"),
-                          row(set));
-            assertRowsNet(version,
-                          executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key
= 1"),
-                          row(map));
-        }
-    }
-
-    @Test
     public void testJavascriptUserType() throws Throwable
     {
         String type = createType("CREATE TYPE %s (txt text, i int)");

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ae01ddc/test/unit/org/apache/cassandra/cql3/validation/entities/UFPureScriptTupleCollectionTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFPureScriptTupleCollectionTest.java
b/test/unit/org/apache/cassandra/cql3/validation/entities/UFPureScriptTupleCollectionTest.java
new file mode 100644
index 0000000..7465a2a
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFPureScriptTupleCollectionTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.validation.entities;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.junit.Test;
+
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.TupleType;
+import com.datastax.driver.core.TupleValue;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.transport.Server;
+
+public class UFPureScriptTupleCollectionTest extends CQLTester
+{
+    // Just JavaScript UDFs to check how UDF - especially security/class-loading/sandboxing
stuff -
+    // behaves, if no Java UDF has been executed before.
+
+    // Do not add any other test here!
+    // See CASSANDRA-10141
+
+    @Test
+    public void testJavascriptTupleTypeCollection() throws Throwable
+    {
+        String tupleTypeDef = "tuple<double, list<double>, set<text>, map<int,
boolean>>";
+        createTable("CREATE TABLE %s (key int primary key, tup frozen<" + tupleTypeDef
+ ">)");
+
+        String fTup1 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
+                                      "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
+                                      "RETURNS NULL ON NULL INPUT " +
+                                      "RETURNS tuple<double, list<double>, set<text>,
map<int, boolean>> " +
+                                      "LANGUAGE javascript\n" +
+                                      "AS $$" +
+                                      "       tup;$$;");
+        String fTup2 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
+                                      "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
+                                      "RETURNS NULL ON NULL INPUT " +
+                                      "RETURNS double " +
+                                      "LANGUAGE javascript\n" +
+                                      "AS $$" +
+                                      "       tup.getDouble(0);$$;");
+        String fTup3 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
+                                      "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
+                                      "RETURNS NULL ON NULL INPUT " +
+                                      "RETURNS list<double> " +
+                                      "LANGUAGE javascript\n" +
+                                      "AS $$" +
+                                      "       tup.getList(1, java.lang.Double.class);$$;");
+        String fTup4 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
+                                      "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
+                                      "RETURNS NULL ON NULL INPUT " +
+                                      "RETURNS set<text> " +
+                                      "LANGUAGE javascript\n" +
+                                      "AS $$" +
+                                      "       tup.getSet(2, java.lang.String.class);$$;");
+        String fTup5 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
+                                      "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
+                                      "RETURNS NULL ON NULL INPUT " +
+                                      "RETURNS map<int, boolean> " +
+                                      "LANGUAGE javascript\n" +
+                                      "AS $$" +
+                                      "       tup.getMap(3, java.lang.Integer.class, java.lang.Boolean.class);$$;");
+
+        List<Double> list = Arrays.asList(1d, 2d, 3d);
+        Set<String> set = new TreeSet<>(Arrays.asList("one", "three", "two"));
+        Map<Integer, Boolean> map = new TreeMap<>();
+        map.put(1, true);
+        map.put(2, false);
+        map.put(3, true);
+
+        Object t = tuple(1d, list, set, map);
+
+        execute("INSERT INTO %s (key, tup) VALUES (1, ?)", t);
+
+        assertRows(execute("SELECT " + fTup1 + "(tup) FROM %s WHERE key = 1"),
+                   row(t));
+        assertRows(execute("SELECT " + fTup2 + "(tup) FROM %s WHERE key = 1"),
+                   row(1d));
+        assertRows(execute("SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
+                   row(list));
+        assertRows(execute("SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
+                   row(set));
+        assertRows(execute("SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
+                   row(map));
+
+        // same test - but via native protocol
+        // we use protocol V3 here to encode the expected version because the server
+        // always serializes Collections using V3 - see CollectionSerializer's
+        // serialize and deserialize methods.
+        TupleType tType = tupleTypeOf(Server.VERSION_3,
+                                      DataType.cdouble(),
+                                      DataType.list(DataType.cdouble()),
+                                      DataType.set(DataType.text()),
+                                      DataType.map(DataType.cint(),
+                                                   DataType.cboolean()));
+        TupleValue tup = tType.newValue(1d, list, set, map);
+        for (int version : PROTOCOL_VERSIONS)
+        {
+            assertRowsNet(version,
+                          executeNet(version, "SELECT " + fTup1 + "(tup) FROM %s WHERE key
= 1"),
+                          row(tup));
+            assertRowsNet(version,
+                          executeNet(version, "SELECT " + fTup2 + "(tup) FROM %s WHERE key
= 1"),
+                          row(1d));
+            assertRowsNet(version,
+                          executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key
= 1"),
+                          row(list));
+            assertRowsNet(version,
+                          executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key
= 1"),
+                          row(set));
+            assertRowsNet(version,
+                          executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key
= 1"),
+                          row(map));
+        }
+    }
+}


Mime
View raw message