Return-Path: Delivered-To: apmail-cassandra-commits-archive@www.apache.org Received: (qmail 71734 invoked from network); 16 Apr 2011 23:09:12 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 16 Apr 2011 23:09:12 -0000 Received: (qmail 26355 invoked by uid 500); 16 Apr 2011 23:09:12 -0000 Delivered-To: apmail-cassandra-commits-archive@cassandra.apache.org Received: (qmail 26329 invoked by uid 500); 16 Apr 2011 23:09:12 -0000 Mailing-List: contact commits-help@cassandra.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cassandra.apache.org Delivered-To: mailing list commits@cassandra.apache.org Received: (qmail 26321 invoked by uid 99); 16 Apr 2011 23:09:12 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 16 Apr 2011 23:09:12 +0000 X-ASF-Spam-Status: No, hits=-1998.0 required=5.0 tests=ALL_TRUSTED,FB_GET_MEDS X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 16 Apr 2011 23:09:08 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 9BBBE2388901; Sat, 16 Apr 2011 23:08:46 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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/ Date: Sat, 16 Apr 2011 23:08:46 -0000 To: commits@cassandra.apache.org From: gdusbabek@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110416230846.9BBBE2388901@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 cfDefs = new HashMap(); @@ -58,8 +60,29 @@ class ColumnDecoder public ColumnDecoder(List 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 // (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 validator; public TypedColumn(AbstractType comparator, byte[] name, AbstractType validator, byte[] value) { @@ -43,6 +44,7 @@ class TypedColumn 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 { return valueString; } + + public AbstractType 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 integerColumn = new HashMap(); + integerColumn.put(IntegerType.instance.fromString("42"), new ColumnDefinition( + IntegerType.instance.fromString("42"), + UTF8Type.instance, + null, + "Column42")); + Map utf8Column = new HashMap(); + 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)));