Modified: cassandra/trunk/src/java/org/apache/cassandra/thrift/ThriftValidation.java URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/thrift/ThriftValidation.java?rev=1101615&r1=1101614&r2=1101615&view=diff ============================================================================== --- cassandra/trunk/src/java/org/apache/cassandra/thrift/ThriftValidation.java (original) +++ cassandra/trunk/src/java/org/apache/cassandra/thrift/ThriftValidation.java Tue May 10 19:47:50 2011 @@ -26,6 +26,7 @@ import java.util.*; import org.apache.cassandra.config.*; import org.apache.cassandra.db.*; import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.AsciiType; import org.apache.cassandra.db.marshal.MarshalException; import org.apache.cassandra.dht.IPartitioner; import org.apache.cassandra.dht.RandomPartitioner; @@ -515,6 +516,22 @@ public class ThriftValidation { try { + if (cf_def.key_alias != null) + { + if (!cf_def.key_alias.hasRemaining()) + throw new InvalidRequestException("key_alias may not be empty"); + try + { + // it's hard to use a key in a select statement if we can't type it. + // for now let's keep it simple and require ascii. + AsciiType.instance.validate(cf_def.key_alias); + } + catch (MarshalException e) + { + throw new InvalidRequestException("Key aliases must be ascii"); + } + } + ColumnFamilyType cfType = ColumnFamilyType.create(cf_def.column_type); if (cfType == null) throw new InvalidRequestException("invalid column type " + cf_def.column_type); @@ -574,11 +591,11 @@ public class ThriftValidation } } - static void validateKsDef(KsDef ks_def) throws ConfigurationException + public static void validateKsDef(KsDef ks_def) throws ConfigurationException { // Attempt to instantiate the ARS, which will throw a ConfigException if // the strategy_options aren't fully formed or if the ARS Classname is invalid. - Map<String, String> options = KSMetaData.backwardsCompatibleOptions(ks_def); + Map<String, String> options = KSMetaData.forwardsCompatibleOptions(ks_def); TokenMetadata tmd = StorageService.instance.getTokenMetadata(); IEndpointSnitch eps = DatabaseDescriptor.getEndpointSnitch(); Class<? extends AbstractReplicationStrategy> cls = AbstractReplicationStrategy.getClass(ks_def.strategy_class);
Modified: cassandra/trunk/src/java/org/apache/cassandra/utils/FBUtilities.java URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/utils/FBUtilities.java?rev=1101615&r1=1101614&r2=1101615&view=diff ============================================================================== --- cassandra/trunk/src/java/org/apache/cassandra/utils/FBUtilities.java (original) +++ cassandra/trunk/src/java/org/apache/cassandra/utils/FBUtilities.java Tue May 10 19:47:50 2011 @@ -44,6 +44,7 @@ import org.apache.cassandra.config.Confi import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.db.DecoratedKey; import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.TypeParser; import org.apache.cassandra.dht.IPartitioner; import org.apache.cassandra.dht.Range; import org.apache.cassandra.dht.Token; @@ -523,25 +524,7 @@ public class FBUtilities public static AbstractType getComparator(String compareWith) throws ConfigurationException { - String className = compareWith.contains(".") ? compareWith : "org.apache.cassandra.db.marshal." + compareWith; - Class<? extends AbstractType> typeClass = FBUtilities.<AbstractType>classForName(className, "abstract-type"); - try - { - Field field = typeClass.getDeclaredField("instance"); - return (AbstractType) field.get(null); - } - catch (NoSuchFieldException e) - { - ConfigurationException ex = new ConfigurationException("Invalid comparator " + compareWith + " : must define a public static instance field."); - ex.initCause(e); - throw ex; - } - catch (IllegalAccessException e) - { - ConfigurationException ex = new ConfigurationException("Invalid comparator " + compareWith + " : must define a public static instance field."); - ex.initCause(e); - throw ex; - } + return TypeParser.parse(compareWith); } /** Modified: cassandra/trunk/src/resources/org/apache/cassandra/cli/CliHelp.yaml URL: http://svn.apache.org/viewvc/cassandra/trunk/src/resources/org/apache/cassandra/cli/CliHelp.yaml?rev=1101615&r1=1101614&r2=1101615&view=diff ============================================================================== --- cassandra/trunk/src/resources/org/apache/cassandra/cli/CliHelp.yaml (original) +++ cassandra/trunk/src/resources/org/apache/cassandra/cli/CliHelp.yaml Tue May 10 19:47:50 2011 @@ -391,7 +391,7 @@ commands: It is also valid to specify the fully-qualified class name to a class that extends org.apache.Cassandra.db.marshal.AbstractType. - - key_valiation_class: Validator to use for keys. + - key_validation_class: Validator to use for keys. Default is BytesType which applies no validation. Supported values are: Modified: cassandra/trunk/test/system/test_cql.py URL: http://svn.apache.org/viewvc/cassandra/trunk/test/system/test_cql.py?rev=1101615&r1=1101614&r2=1101615&view=diff ============================================================================== --- cassandra/trunk/test/system/test_cql.py (original) +++ cassandra/trunk/test/system/test_cql.py Tue May 10 19:47:50 2011 @@ -127,11 +127,11 @@ class TestCql(ThriftTester): def test_select_simple(self): "single-row named column queries" cursor = init() - cursor.execute("SELECT 'ca1' FROM StandardString1 WHERE KEY='ka'") + cursor.execute("SELECT KEY, ca1 FROM StandardString1 WHERE KEY='ka'") r = cursor.fetchone() d = cursor.description - assert d[0][0] == cql.ROW_KEY + assert d[0][0] == 'KEY' assert r[0] == 'ka' assert d[1][0] == 'ca1' @@ -144,10 +144,10 @@ class TestCql(ThriftTester): """) d = cursor.description - assert ['Row Key', 'ca1', 'col', 'cd1'] == [col_dscptn[0] for col_dscptn in d], d + assert ['ca1', 'col', 'cd1'] == [col_dscptn[0] for col_dscptn in d], d row = cursor.fetchone() # check that the column that didn't exist in the row comes back as null - assert ['kd', None, 'val', 'vd1'] == row, row + assert [None, 'val', 'vd1'] == row, row def test_select_row_range(self): "retrieve a range of rows with columns" @@ -219,51 +219,39 @@ class TestCql(ThriftTester): "column slice tests" cursor = init() - # all columns + # * includes row key, explicit slice does not cursor.execute("SELECT * FROM StandardString1 WHERE KEY = 'ka';") - r = cursor.fetchone() - assert len(r) == 3 + row = cursor.fetchone() + assert ['ka', 'va1', 'val'] == row, row + cursor.execute("SELECT ''..'' FROM StandardString1 WHERE KEY = 'ka';") - r = cursor.fetchone() - assert len(r) == 3 + row = cursor.fetchone() + assert ['va1', 'val'] == row, row # column subsets cursor.execute("SELECT 1..3 FROM StandardLongA WHERE KEY = 'aa';") assert cursor.rowcount == 1 - r = cursor.fetchone() - assert r[0] == "aa" - assert r[1] == "1" - assert r[2] == "2" - assert r[3] == "3" + row = cursor.fetchone() + assert ['1', '2', '3'] == row, row - cursor.execute("SELECT 10..30 FROM StandardIntegerA WHERE KEY='k1'") - assert cursor.rowcount == 1 - r = cursor.fetchone() - assert r[0] == "k1" - assert r[1] == "a" - assert r[2] == "b" - assert r[3] == "c" - - # range of columns (slice) by row with FIRST cursor.execute(""" - SELECT FIRST 1 1..3 FROM StandardLongA WHERE KEY = 'aa'; + SELECT key,20,40 FROM StandardIntegerA + WHERE KEY > 'k1' AND KEY < 'k7' LIMIT 5 """) + row = cursor.fetchone() + assert ['k2', 'f', 'h'] == row, row + + # range of columns (slice) by row with FIRST + cursor.execute("SELECT FIRST 1 1..3 FROM StandardLongA WHERE KEY = 'aa'") assert cursor.rowcount == 1 - r = cursor.fetchone() - assert len(r) == 2 - assert r[0] == "aa" - assert r[1] == "1" + row = cursor.fetchone() + assert ['1'] == row, row # range of columns (slice) by row reversed - cursor.execute(""" - SELECT FIRST 2 REVERSED 3..1 FROM StandardLongA WHERE KEY = 'aa'; - """) + cursor.execute("SELECT FIRST 2 REVERSED 3..1 FROM StandardLongA WHERE KEY = 'aa'") assert cursor.rowcount == 1, "%d != 1" % cursor.rowcount - r = cursor.fetchone() - assert len(r) == 3 - assert r[0] == 'aa' - assert r[1] == "3" - assert r[2] == "2" + row = cursor.fetchone() + assert ['3', '2'] == row, row def test_select_range_with_single_column_results(self): "range should not fail when keys were not set" @@ -277,7 +265,7 @@ class TestCql(ThriftTester): """) cursor.execute(""" - SELECT name FROM StandardString2 + SELECT KEY, name FROM StandardString2 """) assert cursor.rowcount == 3, "expected 3 results, got %d" % cursor.rowcount @@ -298,7 +286,7 @@ class TestCql(ThriftTester): "indexed scan where column equals value" cursor = init() cursor.execute(""" - SELECT 'birthdate' FROM IndexedA WHERE 'birthdate' = 100 + SELECT KEY, birthdate FROM IndexedA WHERE birthdate = 100 """) assert cursor.rowcount == 2 @@ -314,19 +302,19 @@ class TestCql(ThriftTester): "indexed scan where a column is greater than a value" cursor = init() cursor.execute(""" - SELECT 'birthdate' FROM IndexedA WHERE 'birthdate' = 100 - AND 'unindexed' > 200 + SELECT KEY, 'birthdate' FROM IndexedA + WHERE 'birthdate' = 100 AND 'unindexed' > 200 """) assert cursor.rowcount == 1 - r = cursor.fetchone() - assert r[0] == "asmith" + row = cursor.fetchone() + assert row[0] == "asmith", row def test_index_scan_with_start_key(self): "indexed scan with a starting key" cursor = init() cursor.execute(""" - SELECT 'birthdate' FROM IndexedA WHERE 'birthdate' = 100 - AND KEY >= 'asmithZ' + SELECT KEY, 'birthdate' FROM IndexedA + WHERE 'birthdate' = 100 AND KEY >= 'asmithZ' """) assert cursor.rowcount == 1 r = cursor.fetchone() @@ -335,7 +323,7 @@ class TestCql(ThriftTester): def test_no_where_clause(self): "empty where clause (range query w/o start key)" cursor = init() - cursor.execute("SELECT 'col' FROM StandardString1 LIMIT 3") + cursor.execute("SELECT KEY, 'col' FROM StandardString1 LIMIT 3") assert cursor.rowcount == 3 rows = cursor.fetchmany(3) assert rows[0][0] == "ka" @@ -369,7 +357,8 @@ class TestCql(ThriftTester): cursor.execute(""" SELECT 'cd1', 'col' FROM StandardString1 WHERE KEY = 'kd' """) - assert ['Row Key', 'cd1', 'col'] == [col_d[0] for col_d in cursor.description] + desc = [col_d[0] for col_d in cursor.description] + assert ['cd1', 'col'] == desc, desc cursor.execute(""" DELETE 'cd1', 'col' FROM StandardString1 WHERE KEY = 'kd' @@ -377,31 +366,31 @@ class TestCql(ThriftTester): cursor.execute(""" SELECT 'cd1', 'col' FROM StandardString1 WHERE KEY = 'kd' """) - r = cursor.fetchone() - assert ['kd', None, None] == r, r + row = cursor.fetchone() + assert [None, None] == row, row def test_delete_columns_multi_rows(self): "delete columns from multiple rows" cursor = init() + # verify rows exist initially cursor.execute("SELECT 'col' FROM StandardString1 WHERE KEY = 'kc'") - r = cursor.fetchone() - assert ['kc', 'val'] == r, r - + row = cursor.fetchone() + assert ['val'] == row, row cursor.execute("SELECT 'col' FROM StandardString1 WHERE KEY = 'kd'") - r = cursor.fetchone() - assert ['kd', 'val'] == r, r + row = cursor.fetchone() + assert ['val'] == row, row + # delete and verify data is gone cursor.execute(""" DELETE 'col' FROM StandardString1 WHERE KEY IN ('kc', 'kd') """) cursor.execute("SELECT 'col' FROM StandardString1 WHERE KEY = 'kc'") - r = cursor.fetchone() - assert ['kc', None] == r, r - + row = cursor.fetchone() + assert [None] == row, row cursor.execute("SELECT 'col' FROM StandardString1 WHERE KEY = 'kd'") r = cursor.fetchone() - assert ['kd', None] == r, r + assert [None] == r, r def test_delete_rows(self): "delete entire rows" @@ -409,13 +398,13 @@ class TestCql(ThriftTester): cursor.execute(""" SELECT 'cd1', 'col' FROM StandardString1 WHERE KEY = 'kd' """) - assert ['Row Key', 'cd1', 'col'] == [col_d[0] for col_d in cursor.description] + assert ['cd1', 'col'] == [col_d[0] for col_d in cursor.description] cursor.execute("DELETE FROM StandardString1 WHERE KEY = 'kd'") cursor.execute(""" SELECT 'cd1', 'col' FROM StandardString1 WHERE KEY = 'kd' """) - r = cursor.fetchone() - assert ['kd', None, None] == r, r + row = cursor.fetchone() + assert [None, None] == row, row def test_create_keyspace(self): "create a new keyspace" @@ -571,7 +560,7 @@ class TestCql(ThriftTester): SELECT '%s' FROM StandardTimeUUID WHERE KEY = 'uuidtest' """ % str(timeuuid)) d = cursor.description - assert d[1][0] == timeuuid, "%s, %s" % (str(d[1][0]), str(timeuuid)) + assert d[0][0] == timeuuid, "%s, %s" % (str(d[1][0]), str(timeuuid)) # Tests a node-side conversion from bigint to UUID. ms = uuid1bytes_to_millis(uuid.uuid1().bytes) @@ -583,7 +572,7 @@ class TestCql(ThriftTester): SELECT 'id' FROM StandardTimeUUIDValues WHERE KEY = 'uuidtest' """) r = cursor.fetchone() - assert uuid1bytes_to_millis(r[1].bytes) == ms + assert uuid1bytes_to_millis(r[0].bytes) == ms # Tests a node-side conversion from ISO8601 to UUID. cursor.execute(""" @@ -596,7 +585,7 @@ class TestCql(ThriftTester): """) # 2011-01-31 17:00:00-0000 == 1296493200000ms r = cursor.fetchone() - ms = uuid1bytes_to_millis(r[1].bytes) + ms = uuid1bytes_to_millis(r[0].bytes) assert ms == 1296493200000, \ "%d != 1296493200000 (2011-01-31 17:00:00-0000)" % ms @@ -610,7 +599,7 @@ class TestCql(ThriftTester): SELECT 'id3' FROM StandardTimeUUIDValues WHERE KEY = 'uuidtest' """) r = cursor.fetchone() - ms = uuid1bytes_to_millis(r[1].bytes) + ms = uuid1bytes_to_millis(r[0].bytes) assert ((time.time() * 1e3) - ms) < 100, \ "new timeuuid not within 100ms of now (UPDATE vs. SELECT)" @@ -624,7 +613,7 @@ class TestCql(ThriftTester): SELECT :start..:finish FROM StandardTimeUUID WHERE KEY = slicetest """, dict(start=uuid_range[0], finish=uuid_range[len(uuid_range)-1])) d = cursor.description - for (i, col_d) in enumerate(d[1:]): + for (i, col_d) in enumerate(d): assert uuid_range[i] == col_d[0] @@ -638,7 +627,7 @@ class TestCql(ThriftTester): cursor.execute("SELECT :name FROM StandardUUID WHERE KEY = 'uuidtest'", dict(name=uid)) d = cursor.description - assert d[1][0] == uid, "expected %s, got %s (%s)" % \ + assert d[0][0] == uid, "expected %s, got %s (%s)" % \ (uid.bytes.encode('hex'), str(d[1][0]).encode('hex'), d[1][1]) # TODO: slices of uuids from cf w/ LexicalUUIDType comparator @@ -654,18 +643,19 @@ class TestCql(ThriftTester): cursor.execute("SELECT * FROM StandardUtf82 WHERE KEY = k1") d = cursor.description + assert d[0][0] == 'KEY', d[0][0] assert d[1][0] == u"¢", d[1][0] assert d[2][0] == u"©", d[2][0] assert d[3][0] == u"®", d[3][0] assert d[4][0] == u"¿", d[4][0] cursor.execute("SELECT :start..'' FROM StandardUtf82 WHERE KEY = k1", dict(start="©")) - r = cursor.fetchone() - assert len(r) == 4 + row = cursor.fetchone() + assert len(row) == 3, row d = cursor.description - assert d[1][0] == u"©" - assert d[2][0] == u"®" - assert d[3][0] == u"¿" + assert d[0][0] == u"©" + assert d[1][0] == u"®" + assert d[2][0] == u"¿" def test_read_write_negative_numerics(self): "reading and writing negative numeric values" @@ -678,11 +668,11 @@ class TestCql(ThriftTester): cursor.execute("SELECT :start..:finish FROM :cf WHERE KEY = negatives;", dict(start=-10, finish=-1, cf=cf)) r = cursor.fetchone() - assert len(r) == 11, \ + assert len(r) == 10, \ "returned %d columns, expected %d" % (len(r) - 1, 10) d = cursor.description - assert d[1][0] == -10 - assert d[10][0] == -1 + assert d[0][0] == -10 + assert d[9][0] == -1 def test_escaped_quotes(self): "reading and writing strings w/ escaped quotes" @@ -697,17 +687,17 @@ class TestCql(ThriftTester): """, dict(key="test_escaped_quotes")) assert cursor.rowcount == 1 r = cursor.fetchone() - assert len(r) == 2, "wrong number of results" + assert len(r) == 1, "wrong number of results" d = cursor.description - assert d[1][0] == "x\'and\'y" - + assert d[0][0] == "x'and'y" + def test_typed_keys(self): "using typed keys" cursor = init() cursor.execute("SELECT * FROM StandardString1 WHERE KEY = :key", dict(key="ka")) - r = cursor.fetchone() - assert isinstance(r[0], unicode), \ - "wrong key-type returned, expected unicode, got %s" % type(r[0]) + row = cursor.fetchone() + assert isinstance(row[0], unicode), \ + "wrong key-type returned, expected unicode, got %s" % type(row[0]) # FIXME: The above is woefully inadequate, but the test config uses # CollatingOrderPreservingPartitioner which only supports UTF8. @@ -753,11 +743,9 @@ class TestCql(ThriftTester): assert cursor.rowcount == 1, "expected 1 result, got %d" % cursor.rowcount colnames = [col_d[0] for col_d in cursor.description] - assert colnames[1] == "some_name", \ - "unrecognized name '%s'" % colnames[1] - r = cursor.fetchone() - assert r[1] == "some_value", \ - "unrecognized value '%s'" % r[1] + assert ['some_name'] == colnames, colnames + row = cursor.fetchone() + assert ['some_value'] == row, row def test_batch_with_mixed_statements(self): "handle BATCH with INSERT/UPDATE/DELETE statements mixed in it" @@ -778,34 +766,28 @@ class TestCql(ThriftTester): assert cursor.rowcount == 1, "expected 1 result, got %d" % cursor.rowcount colnames = [col_d[0] for col_d in cursor.description] - assert colnames[1] == "bName", \ - "unrecognized name '%s'" % colnames[1] + assert ['bName'] == colnames, colnames r = cursor.fetchone() - assert r[1] == "bVal", \ - "unrecognized value '%s'" % r[1] + assert ['bVal'] == r, r cursor.execute("SELECT :name FROM StandardString1 WHERE KEY = :key", dict(name="bCol2", key="bKey3")) assert cursor.rowcount == 1, "expected 1 result, got %d" % cursor.rowcount colnames = [col_d[0] for col_d in cursor.description] - assert colnames[1] == "bCol2", \ - "unrecognized name '%s'" % colnames[1] + assert ['bCol2'] == colnames, colnames # was deleted by DELETE statement r = cursor.fetchone() - assert r[1] == None, \ - "unrecognized value '%s'" % r[1] + assert [None] == r, r cursor.execute("SELECT :name FROM StandardString1 WHERE KEY = :key", dict(name="bCol1", key="bKey2")) assert cursor.rowcount == 1, "expected 1 result, got %d" % cursor.rowcount colnames = [col_d[0] for col_d in cursor.description] - assert colnames[1] == "bCol1", \ - "unrecognized name '%s'" % colnames[1] + assert ['bCol1'] == colnames, colnames r = cursor.fetchone() - assert r[1] == "bVal", \ - "unrecognized value '%s'" % r[1] + assert ['bVal'] == r, r # using all 3 types of statements allowed in batch to test timestamp cursor.execute(""" @@ -825,6 +807,15 @@ class TestCql(ThriftTester): APPLY BATCH """) + # BATCH should not allow setting global TTL + assert_raises(cql.ProgrammingError, + cursor.execute, + """ + BEGIN BATCH USING TTL 130374 + UPDATE StandardString1 SET name = 'name here' WHERE KEY = 'TimestampedUser4' + APPLY BATCH + """) + assert_raises(cql.ProgrammingError, cursor.execute, """ @@ -860,7 +851,7 @@ class TestCql(ThriftTester): assert r[2] == "p4ssw0rd", \ "unrecognized value '%s'" % r[1] - def test_insert_with_timestamp(self): + def test_insert_with_timestamp_and_ttl(self): "insert statement should support setting timestamp" cursor = init() cursor.compression = 'NONE' @@ -895,7 +886,50 @@ class TestCql(ThriftTester): assert r[1] == "name here", \ "unrecognized value '%s'" % r[1] - def test_update_with_timestamp(self): + # and INSERT with TTL + cursor.execute("INSERT INTO StandardString1 (KEY, name) VALUES ('TimestampedUser2', 'name here') USING TTL 5678") + + # try to read it + cursor.execute("SELECT * FROM StandardString1 WHERE KEY = 'TimestampedUser2'") + assert cursor.rowcount == 1, "expected 1 results, got %d" % cursor.rowcount + colnames = [col_d[0] for col_d in cursor.description] + + assert colnames[1] == "name", \ + "unrecognized name '%s'" % colnames[1] + + r = cursor.fetchone() + assert r[1] == "name here", \ + "unrecognized value '%s'" % r[1] + + # and INSERT with CONSISTENCY, TIMESTAMP and TTL together + cursor.execute("INSERT INTO StandardString1 (KEY, name) VALUES ('TimestampedUser3', 'name here') USING TTL 4587 AND TIMESTAMP 1303743619771318 AND CONSISTENCY ONE") + + # try to read it + cursor.execute("SELECT * FROM StandardString1 WHERE KEY = 'TimestampedUser3'") + assert cursor.rowcount == 1, "expected 1 results, got %d" % cursor.rowcount + colnames = [col_d[0] for col_d in cursor.description] + + assert colnames[1] == "name", \ + "unrecognized name '%s'" % colnames[1] + + r = cursor.fetchone() + assert r[1] == "name here", \ + "unrecognized value '%s'" % r[1] + + # and INSERT with TTL + cursor.execute("INSERT INTO StandardString1 (KEY, name) VALUES ('TimestampedUser14', 'name here') USING TTL 1 AND CONSISTENCY ONE") + + # wait for column to expire + time.sleep(5) + + # try to read it + cursor.execute("SELECT * FROM StandardString1 WHERE KEY = 'TimestampedUser14'") + assert cursor.rowcount == 1, "expected 1 results, got %d" % cursor.rowcount + + r = cursor.fetchone() + assert len(r) == 1, "expected 0 results, got %d" % len(r) + + def test_update_with_timestamp_and_ttl(self): "update statement should support setting timestamp" cursor = init() cursor.compression = 'NONE' @@ -930,4 +964,45 @@ class TestCql(ThriftTester): assert r[1] == "name here", \ "unrecognized value '%s'" % r[1] + # UPDATE with TTL + cursor.execute("UPDATE StandardString1 USING TTL 13030 SET name = 'name here' WHERE KEY = 'TimestampedUser4'") + + # try to read it + cursor.execute("SELECT * FROM StandardString1 WHERE KEY = 'TimestampedUser4'") + assert cursor.rowcount == 1, "expected 1 results, got %d" % cursor.rowcount + colnames = [col_d[0] for col_d in cursor.description] + + assert colnames[1] == "name", \ + "unrecognized name '%s'" % colnames[1] + + r = cursor.fetchone() + assert r[1] == "name here", \ + "unrecognized value '%s'" % r[1] + + # UPDATE with CONSISTENCY, TIMESTAMP and TTL together + cursor.execute("UPDATE StandardString1 USING CONSISTENCY ONE AND TIMESTAMP 1303743619771318 AND TTL 13037 SET name = 'name here' WHERE KEY = 'TimestampedUser5'") + + # try to read it + cursor.execute("SELECT * FROM StandardString1 WHERE KEY = 'TimestampedUser5'") + assert cursor.rowcount == 1, "expected 1 results, got %d" % cursor.rowcount + colnames = [col_d[0] for col_d in cursor.description] + + assert colnames[1] == "name", \ + "unrecognized name '%s'" % colnames[1] + + r = cursor.fetchone() + assert r[1] == "name here", \ + "unrecognized value '%s'" % r[1] + + # UPDATE with TTL + cursor.execute("UPDATE StandardString1 USING CONSISTENCY ONE TTL 1 SET name = 'name here' WHERE KEY = 'TimestampedUser6'") + # wait for column to expire + time.sleep(5) + + # try to read it + cursor.execute("SELECT * FROM StandardString1 WHERE KEY = 'TimestampedUser6'") + assert cursor.rowcount == 1, "expected 1 results, got %d" % cursor.rowcount + + r = cursor.fetchone() + assert len(r) == 1, "expected 0 results, got %d" % len(r) Modified: cassandra/trunk/test/unit/org/apache/cassandra/SchemaLoader.java URL: http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/SchemaLoader.java?rev=1101615&r1=1101614&r2=1101615&view=diff ============================================================================== --- cassandra/trunk/test/unit/org/apache/cassandra/SchemaLoader.java (original) +++ cassandra/trunk/test/unit/org/apache/cassandra/SchemaLoader.java Tue May 10 19:47:50 2011 @@ -54,7 +54,7 @@ public class SchemaLoader } } - public static Collection<KSMetaData> schemaDefinition() + public static Collection<KSMetaData> schemaDefinition() throws ConfigurationException { List<KSMetaData> schema = new ArrayList<KSMetaData>(); @@ -78,6 +78,12 @@ public class SchemaLoader ColumnFamilyType st = ColumnFamilyType.Standard; ColumnFamilyType su = ColumnFamilyType.Super; AbstractType bytes = BytesType.instance; + + AbstractType composite = CompositeType.getInstance(Arrays.asList(new AbstractType[]{BytesType.instance, TimeUUIDType.instance, IntegerType.instance})); + Map<Byte, AbstractType> aliases = new HashMap<Byte, AbstractType>(); + aliases.put((byte)'b', BytesType.instance); + aliases.put((byte)'t', TimeUUIDType.instance); + AbstractType dynamicComposite = DynamicCompositeType.getInstance(aliases); // these column definitions will will be applied to the jdbc utf and integer column familes respectively. Map<ByteBuffer, ColumnDefinition> integerColumn = new HashMap<ByteBuffer, ColumnDefinition>(); @@ -134,7 +140,17 @@ public class SchemaLoader jdbcCFMD(ks1, "JdbcUtf8", UTF8Type.instance).columnMetadata(utf8Column), jdbcCFMD(ks1, "JdbcLong", LongType.instance), jdbcCFMD(ks1, "JdbcBytes", bytes), - jdbcCFMD(ks1, "JdbcAscii", AsciiType.instance))); + jdbcCFMD(ks1, "JdbcAscii", AsciiType.instance), + new CFMetaData(ks1, + "StandardComposite", + st, + composite, + null), + new CFMetaData(ks1, + "StandardDynamicComposite", + st, + dynamicComposite, + null))); // Keyspace 2 schema.add(new KSMetaData(ks2,
