You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by gd...@apache.org on 2011/04/17 01:08:46 UTC

svn commit: r1094085 - in /cassandra/branches/cassandra-0.8: drivers/java/src/org/apache/cassandra/cql/jdbc/ drivers/java/test/org/apache/cassandra/cql/ test/unit/org/apache/cassandra/

Author: gdusbabek
Date: Sat Apr 16 23:08:46 2011
New Revision: 1094085

URL: http://svn.apache.org/viewvc?rev=1094085&view=rev
Log:
honor specific column validators in JDBC driver. patch by gdusbabek, reviewed by jbellis. CASSANDRA-2410

Modified:
    cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraResultSet.java
    cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/ColumnDecoder.java
    cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/TypedColumn.java
    cassandra/branches/cassandra-0.8/drivers/java/test/org/apache/cassandra/cql/JdbcDriverTest.java
    cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/SchemaLoader.java

Modified: cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraResultSet.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraResultSet.java?rev=1094085&r1=1094084&r2=1094085&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraResultSet.java (original)
+++ cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraResultSet.java Sat Apr 16 23:08:46 2011
@@ -42,13 +42,7 @@ import java.sql.SQLXML;
 import java.sql.Statement;
 import java.sql.Time;
 import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import java.util.WeakHashMap;
+import java.util.*;
 
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.db.marshal.BytesType;
@@ -58,7 +52,6 @@ import org.apache.cassandra.thrift.Colum
 import org.apache.cassandra.thrift.CqlResult;
 import org.apache.cassandra.thrift.CqlRow;
 
-// todo: get by index is off by one.
 /**
  * The Class CassandraResultSet.
  */
@@ -87,7 +80,6 @@ class CassandraResultSet implements Resu
     private final RsMetaData meta;
     
     private final AbstractType nameType;
-    private final AbstractType valueType;
 
     /**
      * Instantiates a new cassandra result set.
@@ -103,7 +95,6 @@ class CassandraResultSet implements Resu
         rSetIter = rSet.getRowsIterator();
         meta = new RsMetaData();
         nameType = decoder.getComparator(keyspace, columnFamily, ColumnDecoder.Specifier.Comparator, null);
-        valueType = decoder.getComparator(keyspace, columnFamily, ColumnDecoder.Specifier.Validator, null);
     }
 
     /**
@@ -2037,10 +2028,11 @@ class CassandraResultSet implements Resu
         {
             column--;
             checkIndex(column);
-            if (valueType instanceof ColumnMetaData)
-                return ((ColumnMetaData)valueType).isCaseSensitive();
+            TypedColumn tc = values.get(column);
+            if (tc.getValidator() instanceof ColumnMetaData)
+                return ((ColumnMetaData)tc.getValidator()).isCaseSensitive();
             else 
-                return valueType.getType().equals(String.class);
+                return tc.getValidator().getType().equals(String.class);
         }
 
         public boolean isNameCurrency(int column) throws SQLException
@@ -2057,8 +2049,9 @@ class CassandraResultSet implements Resu
         {
             column--;
             checkIndex(column);
-            if (valueType instanceof ColumnMetaData)
-                return ((ColumnMetaData)valueType).isCurrency();
+            TypedColumn tc = values.get(column);
+            if (tc.getValidator() instanceof ColumnMetaData)
+                return ((ColumnMetaData)tc.getValidator()).isCurrency();
             else
                 return false;
         }
@@ -2074,7 +2067,8 @@ class CassandraResultSet implements Resu
         {
             column--;
             checkIndex(column);
-            return Utils.isTypeSigned(valueType);
+            TypedColumn tc = values.get(column);
+            return Utils.isTypeSigned(tc.getValidator());
         }
 
         public int getNameDisplaySize(int column) throws SQLException
@@ -2113,15 +2107,15 @@ class CassandraResultSet implements Resu
             column--;
             checkIndex(column);
             TypedColumn col = values.get(column);
-            if (valueType instanceof ColumnMetaData)
-                return ((ColumnMetaData)valueType).getPrecision();
-            else if (valueType.getType().equals(String.class))
+            if (col.getValidator() instanceof ColumnMetaData)
+                return ((ColumnMetaData)col.getValidator()).getPrecision();
+            else if (col.getValidator().getType().equals(String.class))
                 return col.getValueString().length();
-            else if (valueType == BytesType.instance)
+            else if (col.getValidator() == BytesType.instance)
                 return col.getValueString().length();
-            else if (valueType.getType().equals(UUID.class))
+            else if (col.getValidator().getType().equals(UUID.class))
                 return 36; // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-            else if (valueType == LongType.instance)
+            else if (col.getValidator() == LongType.instance)
                 return 19; // number of digits in 2**63-1.
             else 
                 return 0;
@@ -2138,7 +2132,7 @@ class CassandraResultSet implements Resu
         {
             column--;
             checkIndex(column);
-            return Utils.getTypeScale(valueType);
+            return Utils.getTypeScale(values.get(column).getValidator());
         }
 
         public int getNameType(int column) throws SQLException
@@ -2152,7 +2146,7 @@ class CassandraResultSet implements Resu
         {
             column--;
             checkIndex(column);
-            return Utils.getJdbcType(valueType);
+            return Utils.getJdbcType(values.get(column).getValidator());
         }
         
         public String getNameTypeName(int column) throws SQLException
@@ -2166,7 +2160,7 @@ class CassandraResultSet implements Resu
         {
             column--;
             checkIndex(column);
-            return valueType.getClass().getSimpleName();
+            return values.get(column).getValidator().getClass().getSimpleName();
         }
 
         public String getNameClassName(int column) throws SQLException
@@ -2180,7 +2174,7 @@ class CassandraResultSet implements Resu
         {
             column--;
             checkIndex(column);
-            return valueType.getType().getName();
+            return values.get(column).getValidator().getType().getName();
         }
         
         //
@@ -2202,7 +2196,7 @@ class CassandraResultSet implements Resu
         {
             column--;
             checkIndex(column);
-            return valueType instanceof CounterColumnType; // todo: check Value is correct.
+            return values.get(column).getValidator() instanceof CounterColumnType; // todo: check Value is correct.
         }
 
         public boolean isCaseSensitive(int column) throws SQLException

Modified: cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/ColumnDecoder.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/ColumnDecoder.java?rev=1094085&r1=1094084&r2=1094085&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/ColumnDecoder.java (original)
+++ cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/ColumnDecoder.java Sat Apr 16 23:08:46 2011
@@ -24,6 +24,7 @@ package org.apache.cassandra.cql.jdbc;
 import org.apache.cassandra.config.ConfigurationException;
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.thrift.CfDef;
+import org.apache.cassandra.thrift.ColumnDef;
 import org.apache.cassandra.thrift.KsDef;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
@@ -39,14 +40,15 @@ import java.util.Map;
 class ColumnDecoder 
 {
     private static final Logger logger = LoggerFactory.getLogger(ColumnDecoder.class);
-    private static final String MapFormatString = "%s.%s.%s";
+    private static final String MapFormatString = "%s.%s.%s.%s";
     
     // basically denotes column or value.
     enum Specifier
     {
         Comparator,
         Validator,
-        Key
+        Key,
+        ColumnSpecific
     }
     
     private Map<String, CfDef> cfDefs = new HashMap<String, CfDef>();
@@ -58,8 +60,29 @@ class ColumnDecoder 
     public ColumnDecoder(List<KsDef> defs)
     {
         for (KsDef ks : defs) 
+        {
             for (CfDef cf : ks.getCf_defs())
+            {
                 cfDefs.put(String.format("%s.%s", ks.getName(), cf.getName()), cf);
+                for (ColumnDef cd : cf.getColumn_metadata()) 
+                {
+                    try 
+                    {
+                        // prefill the validators (because they aren't kept in a convenient lookup map and we don't
+                        // want to iterate over the list for every miss in getComparator.
+                        comparators.put(String.format(MapFormatString, 
+                                ks.getName(), 
+                                cf.getName(),
+                                Specifier.ColumnSpecific.name(),
+                                ByteBufferUtil.bytesToHex(cd.bufferForName())), 
+                                   FBUtilities.getComparator(cd.getValidation_class()));
+                    } 
+                    catch (ConfigurationException ex) {
+                        throw new RuntimeException(ex);
+                    }
+                }
+            }
+        }
     }
 
     /**
@@ -69,10 +92,20 @@ class ColumnDecoder 
      * @param def avoids additional map lookup if specified. null is ok though.
      * @return
      */
-    AbstractType getComparator(String keyspace, String columnFamily, Specifier specifier, CfDef def) 
+    AbstractType getComparator(String keyspace, String columnFamily, Specifier specifier, CfDef def)
+    {
+        return getComparator(keyspace, columnFamily, null, specifier, def);
+    }
+    
+    // same as above, but can get column-specific validators.
+    AbstractType getComparator(String keyspace, String columnFamily, byte[] column, Specifier specifier, CfDef def) 
     {
         // check cache first.
-        String key = String.format(MapFormatString, keyspace, columnFamily, specifier.name());
+        String key = String.format(MapFormatString, 
+                                   keyspace, 
+                                   columnFamily, 
+                                   specifier.name(), 
+                                   FBUtilities.bytesToHex(column == null ? new byte[] {} : column));
         AbstractType comparator = comparators.get(key);
 
         // make and put in cache.
@@ -90,6 +123,8 @@ class ColumnDecoder 
                     case Key:
                         comparator = FBUtilities.getComparator(def.getKey_validation_class());
                         break;
+                    case ColumnSpecific:
+                        // if we get here this means there is no column-specific validator, so fall through to the default.
                     case Validator:
                         comparator = FBUtilities.getComparator(def.getDefault_validation_class());
                         break;
@@ -154,7 +189,7 @@ class ColumnDecoder 
     {
         CfDef cfDef = cfDefs.get(String.format("%s.%s", keyspace, columnFamily));
         AbstractType comparator = getComparator(keyspace, columnFamily, Specifier.Comparator, cfDef);
-        AbstractType validator = getComparator(keyspace, columnFamily, Specifier.Validator, null);
+        AbstractType validator = getComparator(keyspace, columnFamily, name, Specifier.ColumnSpecific, null);
         return new TypedColumn(comparator, name, validator, value);
     }
 }

Modified: cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/TypedColumn.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/TypedColumn.java?rev=1094085&r1=1094084&r2=1094085&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/TypedColumn.java (original)
+++ cassandra/branches/cassandra-0.8/drivers/java/src/org/apache/cassandra/cql/jdbc/TypedColumn.java Sat Apr 16 23:08:46 2011
@@ -34,6 +34,7 @@ class TypedColumn<N, V>
     // (a good example is byte buffers) as the stringified versions supplied by the AbstractTypes.
     private final String nameString;
     private final String valueString;
+    private final AbstractType<V> validator;
     
     public TypedColumn(AbstractType<N> comparator, byte[] name, AbstractType<V> validator, byte[] value)
     {
@@ -43,6 +44,7 @@ class TypedColumn<N, V>
         this.value = validator.compose(bbValue);
         nameString = comparator.getString(bbName);
         valueString = validator.getString(bbValue);
+        this.validator = validator;
     }
     
     public N getName()
@@ -64,4 +66,9 @@ class TypedColumn<N, V>
     {
         return valueString;
     }
+    
+    public AbstractType<V> getValidator()
+    {
+        return validator;
+    }
 }

Modified: cassandra/branches/cassandra-0.8/drivers/java/test/org/apache/cassandra/cql/JdbcDriverTest.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/drivers/java/test/org/apache/cassandra/cql/JdbcDriverTest.java?rev=1094085&r1=1094084&r2=1094085&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/drivers/java/test/org/apache/cassandra/cql/JdbcDriverTest.java (original)
+++ cassandra/branches/cassandra-0.8/drivers/java/test/org/apache/cassandra/cql/JdbcDriverTest.java Sat Apr 16 23:08:46 2011
@@ -68,12 +68,12 @@ public class JdbcDriverTest extends Embe
         String[] inserts = 
         {
             String.format("UPDATE Standard1 SET '%s' = '%s', '%s' = '%s' WHERE KEY = '%s'", first, firstrec, last, lastrec, jsmith),    
-            "UPDATE JdbcInteger SET 1 = 11, 2 = 22 WHERE KEY = '" + jsmith + "'",
+            "UPDATE JdbcInteger SET 1 = 11, 2 = 22, 42='fortytwo' WHERE KEY = '" + jsmith + "'",
             "UPDATE JdbcInteger SET 3 = 33, 4 = 44 WHERE KEY = '" + jsmith + "'",
             "UPDATE JdbcLong SET 1 = 11, 2 = 22 WHERE KEY = '" + jsmith + "'",
             "UPDATE JdbcAscii SET 'first' = 'firstrec', 'last' = 'lastrec' WHERE key = '" + jsmith + "'",
             String.format("UPDATE JdbcBytes SET '%s' = '%s', '%s' = '%s' WHERE key = '%s'", first, firstrec, last, lastrec, jsmith),
-            "UPDATE JdbcUtf8 SET 'first' = 'firstrec', 'last' = 'lastrec' WHERE key = '" + jsmith + "'",
+            "UPDATE JdbcUtf8 SET 'first' = 'firstrec', 'fortytwo' = '42', 'last' = 'lastrec' WHERE key = '" + jsmith + "'",
         };
         for (String q : inserts)
         {
@@ -119,6 +119,37 @@ public class JdbcDriverTest extends Embe
         assert valuCaseSense == md.isValueCaseSensitive(col);
     }
     
+    @Test
+    public void testNonDefaultColumnValidators() throws SQLException
+    {
+        String key = FBUtilities.bytesToHex("Integer".getBytes());
+        Statement stmt = con.createStatement();
+        stmt.executeUpdate("update JdbcInteger set 1=1111, 2=2222, 42='fortytwofortytwo' where key='" + key + "'");
+        ResultSet rs = stmt.executeQuery("select 1, 2, 42 from JdbcInteger where key='" + key + "'");
+        assert rs.next();
+        assert rs.getInt("1") == 1111;
+        assert rs.getInt("2") == 2222;
+        assert rs.getString("42").equals("fortytwofortytwo") : rs.getString("42");
+        
+        ResultSetMetaData md = rs.getMetaData();
+        assert md.getColumnCount() == 3;
+        expectedMetaData(md, 1, BigInteger.class.getName(), "JdbcInteger", "Keyspace1", "1", Types.BIGINT, IntegerType.class.getSimpleName(), true, false);
+        expectedMetaData(md, 2, BigInteger.class.getName(), "JdbcInteger", "Keyspace1", "2", Types.BIGINT, IntegerType.class.getSimpleName(), true, false);
+        expectedMetaData(md, 3, String.class.getName(), "JdbcInteger", "Keyspace1", "42", Types.VARCHAR, UTF8Type.class.getSimpleName(), false, true);
+        
+        stmt.executeUpdate("update JdbcUtf8 set 'a'='aa', 'b'='bb', 'fortytwo'='4242' where key='" + key + "'");
+        rs = stmt.executeQuery("select 'a', 'b', 'fortytwo' from JdbcUtf8 where key='" + key + "'");
+        assert rs.next();
+        assert rs.getString("a").equals("aa");
+        assert rs.getString("b").equals("bb");
+        assert rs.getInt("fortytwo") == 4242L;
+        
+        md = rs.getMetaData();
+        expectedMetaData(md, 1, String.class.getName(), "JdbcUtf8", "Keyspace1", "a", Types.VARCHAR, UTF8Type.class.getSimpleName(), false, true);
+        expectedMetaData(md, 2, String.class.getName(), "JdbcUtf8", "Keyspace1", "b", Types.VARCHAR, UTF8Type.class.getSimpleName(), false, true);
+        expectedMetaData(md, 3, BigInteger.class.getName(), "JdbcUtf8", "Keyspace1", "fortytwo", Types.BIGINT, IntegerType.class.getSimpleName(), true, false);
+    }
+    
     @Test 
     public void testIntegerMetadata() throws SQLException
     {

Modified: cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/SchemaLoader.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/SchemaLoader.java?rev=1094085&r1=1094084&r2=1094085&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/SchemaLoader.java (original)
+++ cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/SchemaLoader.java Sat Apr 16 23:08:46 2011
@@ -77,6 +77,20 @@ public class SchemaLoader
         ColumnFamilyType st = ColumnFamilyType.Standard;
         ColumnFamilyType su = ColumnFamilyType.Super;
         AbstractType bytes = BytesType.instance;
+      
+        // these column definitions will will be applied to the jdbc utf and integer column familes respectively.
+        Map<ByteBuffer, ColumnDefinition> integerColumn = new HashMap<ByteBuffer, ColumnDefinition>();
+        integerColumn.put(IntegerType.instance.fromString("42"), new ColumnDefinition(
+            IntegerType.instance.fromString("42"),
+            UTF8Type.instance,
+            null,
+            "Column42"));
+        Map<ByteBuffer, ColumnDefinition> utf8Column = new HashMap<ByteBuffer, ColumnDefinition>();
+        utf8Column.put(UTF8Type.instance.fromString("fortytwo"), new ColumnDefinition(
+            UTF8Type.instance.fromString("fortytwo"),
+            IntegerType.instance,
+            null,
+            "Column42"));
 
         // Keyspace 1
         schema.add(new KSMetaData(ks1,
@@ -115,8 +129,8 @@ public class SchemaLoader
                                                  bytes,
                                                  bytes)
                                                  .defaultValidator(CounterColumnType.instance),
-                                  jdbcCFMD(ks1, "JdbcInteger", IntegerType.instance),
-                                  jdbcCFMD(ks1, "JdbcUtf8", UTF8Type.instance),
+                                  jdbcCFMD(ks1, "JdbcInteger", IntegerType.instance).columnMetadata(integerColumn),
+                                  jdbcCFMD(ks1, "JdbcUtf8", UTF8Type.instance).columnMetadata(utf8Column),
                                   jdbcCFMD(ks1, "JdbcLong", LongType.instance),
                                   jdbcCFMD(ks1, "JdbcBytes", bytes),
                                   jdbcCFMD(ks1, "JdbcAscii", AsciiType.instance)));