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/03/14 20:46:36 UTC

svn commit: r1081542 - in /cassandra/trunk/drivers/java: src/org/apache/cassandra/cql/jdbc/ test/org/apache/cassandra/cql/

Author: gdusbabek
Date: Mon Mar 14 19:46:36 2011
New Revision: 1081542

URL: http://svn.apache.org/viewvc?rev=1081542&view=rev
Log:
RowData exposes sparse column attributes through CassandraResultSet

Added:
    cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/RowMetaData.java
    cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/TypedColumn.java
      - copied, changed from r1080774, cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/Col.java
Removed:
    cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/Col.java
Modified:
    cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraResultSet.java
    cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraStatement.java
    cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/ColumnDecoder.java
    cassandra/trunk/drivers/java/test/org/apache/cassandra/cql/JdbcDriverTest.java

Modified: cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraResultSet.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraResultSet.java?rev=1081542&r1=1081541&r2=1081542&view=diff
==============================================================================
--- cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraResultSet.java (original)
+++ cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraResultSet.java Mon Mar 14 19:46:36 2011
@@ -68,11 +68,11 @@ class CassandraResultSet implements Resu
     /** The r set iter. */
     private Iterator<CqlRow> rSetIter;
     
-//    /** The row. */
-//    private CqlRow row;
+    // the current row key when iterating through results.
+    private byte[] curRowKey = null;
     
     /** The values. */
-    private List<Col> values = new ArrayList<Col>();
+    private List<TypedColumn> values = new ArrayList<TypedColumn>();
     
     /** The value map. */
     private Map<String, Object> valueMap = new WeakHashMap<String, Object>();
@@ -102,17 +102,6 @@ class CassandraResultSet implements Resu
     }
 
     /**
-     * @param <T>
-     * @param iface
-     * @return
-     * @throws SQLException
-     */
-    public <T> T unwrap(Class<T> iface) throws SQLException
-    {
-        throw new UnsupportedOperationException("method not supported");
-    }
-
-    /**
      * @param arg0
      * @return
      * @throws SQLException
@@ -1034,7 +1023,22 @@ class CassandraResultSet implements Resu
     {
         throw new UnsupportedOperationException("method not supported");
     }
-
+    
+    /**
+     * @param <T>
+     * @param iface
+     * @return
+     * @throws SQLException
+     */
+    public <T> T unwrap(Class<T> iface) throws SQLException
+    {
+        // exposes the current row only.
+        if (iface.equals(RowMetaData.class))
+            return (T)new CassandraRowMetaData(this);
+        else
+            throw new SQLException("Unsupported unwrap interface: " + iface.getSimpleName());
+    }
+    
     /**
      * @return
      * @throws SQLException
@@ -1049,12 +1053,13 @@ class CassandraResultSet implements Resu
         if (rSetIter != null && rSetIter.hasNext())
         {
             CqlRow row = rSetIter.next();
+            curRowKey = row.getKey();
             List<Column> cols = row.getColumns();
             for (Column col : cols)
             {
                 byte[] name = col.getName();
                 byte[] value = col.getValue();
-                Col c = decoder.makeCol(keyspace, columnFamily, name, value);
+                TypedColumn c = decoder.makeCol(keyspace, columnFamily, name, value);
                 values.add(c);
                 valueMap.put(decoder.colNameAsString(keyspace, columnFamily, name), c.getValue());
             }
@@ -1995,4 +2000,29 @@ class CassandraResultSet implements Resu
         throw new UnsupportedOperationException("method not supported");
     }
 
+    private class CassandraRowMetaData implements RowMetaData
+    {
+        private final List<TypedColumn> cols;
+        private final byte[] key;
+        
+        private CassandraRowMetaData(CassandraResultSet rs) {
+            cols = new ArrayList<TypedColumn>(rs.values);
+            key = curRowKey;
+        }
+
+        public int getColumnCount()
+        {
+            return cols.size();
+        }
+
+        public TypedColumn getColumn(int index)
+        {
+            return cols.get(index);
+        }
+
+        public byte[] getKey()
+        {
+            return key;
+        }
+    }
 }

Modified: cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraStatement.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraStatement.java?rev=1081542&r1=1081541&r2=1081542&view=diff
==============================================================================
--- cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraStatement.java (original)
+++ cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/CassandraStatement.java Mon Mar 14 19:46:36 2011
@@ -42,8 +42,10 @@ import java.sql.SQLXML;
 import java.sql.Time;
 import java.sql.Timestamp;
 import java.util.Calendar;
+import java.util.regex.Pattern;
 
 import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.thrift.CqlResultType;
 import org.apache.cassandra.thrift.InvalidRequestException;
 import org.apache.cassandra.thrift.TimedOutException;
 import org.apache.cassandra.thrift.UnavailableException;
@@ -55,6 +57,7 @@ import org.apache.thrift.TException;
 
 class CassandraStatement implements PreparedStatement
 {
+    private static final Pattern UpdatePattern = Pattern.compile("UPDATE .*", Pattern.CASE_INSENSITIVE);
     
     /** The connection. */
     private org.apache.cassandra.cql.jdbc.Connection connection;
@@ -148,12 +151,11 @@ class CassandraStatement implements Prep
 
     
     /**
+     * This is a no-op.
      * @throws SQLException
      */
     public void close() throws SQLException
     {
-        throw new UnsupportedOperationException("method not supported");
-
     }
 
     
@@ -264,15 +266,38 @@ class CassandraStatement implements Prep
         }
     }
 
-    
     /**
-     * @param arg0
+     * @param query
      * @return
      * @throws SQLException
      */
-    public int executeUpdate(String arg0) throws SQLException
+    public int executeUpdate(String query) throws SQLException
     {
-        throw new UnsupportedOperationException("method not supported");
+        if (!UpdatePattern.matcher(query).matches())
+            throw new SQLException("Not an update statement.");
+        try
+        {
+            CqlResult rSet = connection.execute(query);
+            assert rSet.getType().equals(CqlResultType.VOID);
+            // if only we knew how many rows were updated.
+            return 0;
+        }
+        catch (InvalidRequestException e)
+        {
+            throw new SQLException(e.getWhy());
+        }
+        catch (UnavailableException e)
+        {
+            throw new SQLException(e.getMessage());
+        }
+        catch (TimedOutException e)
+        {
+            throw new SQLException(e.getMessage());
+        }
+        catch (TException e)
+        {
+            throw new SQLException(e.getMessage());
+        }
     }
 
     

Modified: cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/ColumnDecoder.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/ColumnDecoder.java?rev=1081542&r1=1081541&r2=1081542&view=diff
==============================================================================
--- cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/ColumnDecoder.java (original)
+++ cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/ColumnDecoder.java Mon Mar 14 19:46:36 2011
@@ -122,12 +122,12 @@ class ColumnDecoder 
     }
     
     /** constructs a typed column */
-    public Col makeCol(String keyspace, String columnFamily, byte[] name, byte[] value)
+    public TypedColumn makeCol(String keyspace, String columnFamily, byte[] name, byte[] value)
     {
         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);
         // todo: generate less garbage.
-        return new Col(comparator.compose(ByteBuffer.wrap(name)), validator.compose(ByteBuffer.wrap(value)));
+        return new TypedColumn(comparator.compose(ByteBuffer.wrap(name)), validator.compose(ByteBuffer.wrap(value)));
     }
 }

Added: cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/RowMetaData.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/RowMetaData.java?rev=1081542&view=auto
==============================================================================
--- cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/RowMetaData.java (added)
+++ cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/RowMetaData.java Mon Mar 14 19:46:36 2011
@@ -0,0 +1,21 @@
+package org.apache.cassandra.cql.jdbc;
+
+/**
+ * Addresses the metadata needs of a sparse row of columns. ResultSetMetaData doesn't fit the bill because it
+ * expects every row to have the same set of columns.
+ * 
+ * I didn't feel compelled to go the distance and implement distinct getXXXType(), getXXXTypeName(), getXXX() 
+ * methods for both column names and values a la ResultSetMetaData.  If we did want that, I recommend an optional
+ * method in AbstractType called getSqlType() or something like that.
+ */
+public interface RowMetaData
+{
+    /** number of columns in a row of data */
+    public int getColumnCount();
+    
+    /** column name and value */
+    public TypedColumn getColumn(int index);
+    
+    /** key */
+    public byte[] getKey(); // todo: update when typed keys are available.
+}

Copied: cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/TypedColumn.java (from r1080774, cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/Col.java)
URL: http://svn.apache.org/viewvc/cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/TypedColumn.java?p2=cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/TypedColumn.java&p1=cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/Col.java&r1=1080774&r2=1081542&rev=1081542&view=diff
==============================================================================
--- cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/Col.java (original)
+++ cassandra/trunk/drivers/java/src/org/apache/cassandra/cql/jdbc/TypedColumn.java Mon Mar 14 19:46:36 2011
@@ -1,11 +1,11 @@
 package org.apache.cassandra.cql.jdbc;
 
-class Col<N, V>
+public class TypedColumn<N, V>
 {
     public final N name;
     public final V value;
     
-    public Col(N name, V value)
+    public TypedColumn(N name, V value)
     {
         this.name = name;
         this.value = value;

Modified: cassandra/trunk/drivers/java/test/org/apache/cassandra/cql/JdbcDriverTest.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/drivers/java/test/org/apache/cassandra/cql/JdbcDriverTest.java?rev=1081542&r1=1081541&r2=1081542&view=diff
==============================================================================
--- cassandra/trunk/drivers/java/test/org/apache/cassandra/cql/JdbcDriverTest.java (original)
+++ cassandra/trunk/drivers/java/test/org/apache/cassandra/cql/JdbcDriverTest.java Mon Mar 14 19:46:36 2011
@@ -23,14 +23,17 @@ package org.apache.cassandra.cql;
 import java.io.File;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.nio.FloatBuffer;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.Arrays;
 
+import org.apache.cassandra.cql.jdbc.RowMetaData;
 import org.apache.cassandra.utils.FBUtilities;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -68,6 +71,96 @@ public class JdbcDriverTest extends Embe
             executeNoResults(con, q);
     }
     
+    @Test 
+    public void testIntegerMetadata() throws SQLException
+    {
+        Statement stmt = con.createStatement();
+        stmt.executeUpdate("UPDATE JdbcInteger SET 1=111, 2=222 WHERE KEY = 'Integer'");
+        ResultSet rs = stmt.executeQuery("SELECT 1, 2 from JdbcInteger WHERE KEY = 'Integer'");
+        assert rs.next();
+        assert rs.getInt("1") == 111;
+        assert rs.getInt("2") == 222;
+        RowMetaData rd = rs.unwrap(RowMetaData.class);
+        assert rd.getColumnCount() == 2;
+        assert rd.getColumn(0).getName().equals(new BigInteger("1"));
+        assert rd.getColumn(0).getValue().equals(new BigInteger("111"));
+        assert rd.getColumn(1).getName().equals(new BigInteger("2"));
+        assert rd.getColumn(1).getValue().equals(new BigInteger("222"));
+    }
+    
+    @Test
+    public void testLongMetadata() throws SQLException
+    {
+        Statement stmt = con.createStatement();
+        stmt.executeUpdate("UPDATE JdbcLong SET 1=111, 2=222 WHERE KEY = 'Long'");
+        ResultSet rs = stmt.executeQuery("SELECT 1, 2 from JdbcLong WHERE KEY = 'Long'");
+        assert rs.next();
+        assert rs.getLong("1") == 111;
+        assert rs.getLong("2") == 222;
+        RowMetaData rd = rs.unwrap(RowMetaData.class);
+        assert rd.getColumnCount() == 2;
+        assert rd.getColumn(0).getName().equals(new Long("1"));
+        assert rd.getColumn(0).getValue().equals(new Long("111"));
+        assert rd.getColumn(1).getName().equals(new Long("2"));
+        assert rd.getColumn(1).getValue().equals(new Long("222"));
+        assert (Long)rd.getColumn(0).getName() == 1L;
+        assert (Long)rd.getColumn(0).getValue() == 111L;
+        assert (Long)rd.getColumn(1).getName() == 2L;
+        assert (Long)rd.getColumn(1).getValue() == 222L;
+    }
+    
+    @Test
+    public void testStringMetadata() throws SQLException
+    {
+        Statement stmt = con.createStatement();
+        stmt.executeUpdate("UPDATE JdbcAscii SET 'a'='aa', 'b'='bb' WHERE KEY = 'ascii'");
+        stmt.executeUpdate("UPDATE JdbcUtf8 SET 'a'='aa', 'b'='bb' WHERE KEY = 'utf8'");
+        ResultSet rs0 = stmt.executeQuery("SELECT 'a', 'b' FROM JdbcAscii WHERE KEY = 'ascii'");
+        ResultSet rs1 = stmt.executeQuery("SELECT 'a', 'b' FROM JdbcUtf8 WHERE KEY = 'utf8'");
+        for (ResultSet rs : new ResultSet[] { rs0, rs1 }) 
+        {
+            assert rs.next();
+            assert rs.getString("a").equals("aa");
+            assert rs.getString("b").equals("bb");
+            RowMetaData rd = rs.unwrap(RowMetaData.class);
+            assert rd.getColumnCount() == 2;
+            assert rd.getColumn(0).getName().equals("a");
+            assert rd.getColumn(0).getValue().equals("aa");
+            assert rd.getColumn(1).getName().equals("b");
+            assert rd.getColumn(1).getValue().equals("bb");
+        }
+    }
+    
+    @Test
+    public void testBytesMetadata() throws SQLException 
+    {
+        Statement stmt = con.createStatement();
+        byte[] a = "a_".getBytes();
+        byte[] b = "b_".getBytes();
+        byte[] aa = "_aa_".getBytes();
+        byte[] bb = "_bb_".getBytes();
+        stmt.executeUpdate(String.format(
+                "UPDATE JdbcBytes set '%s'='%s', '%s'='%s' WHERE KEY = 'bytes'",
+                FBUtilities.bytesToHex(a),
+                FBUtilities.bytesToHex(aa),
+                FBUtilities.bytesToHex(b),
+                FBUtilities.bytesToHex(bb)));
+        ResultSet rs = stmt.executeQuery(String.format(
+                "SELECT '%s', '%s' from JdbcBytes WHERE KEY = 'bytes'",
+                FBUtilities.bytesToHex(a),
+                FBUtilities.bytesToHex(b)));
+        assert rs.next();
+        assert Arrays.equals(aa, rs.getBytes(0));
+        assert Arrays.equals(bb, rs.getBytes(1));
+        assert Arrays.equals(aa, rs.getBytes(FBUtilities.bytesToHex(a)));
+        assert Arrays.equals(bb, rs.getBytes(FBUtilities.bytesToHex(b)));
+        RowMetaData rd = rs.unwrap(RowMetaData.class);
+        assert rd.getColumn(0).getName().equals(ByteBuffer.wrap(a));
+        assert rd.getColumn(1).getName().equals(ByteBuffer.wrap(b));
+        assert rd.getColumn(0).getValue().equals(ByteBuffer.wrap(aa));
+        assert rd.getColumn(1).getValue().equals(ByteBuffer.wrap(bb));
+    }
+    
     /** Method to test statement. */
     @Test
     public void testWithStatement() throws SQLException