Author: jbellis Date: Mon May 9 21:40:27 2011 New Revision: 1101234 URL: http://svn.apache.org/viewvc?rev=1101234&view=rev Log: add CQL TTL support patch by pyaskevich; reviewed by jbellis for CASSANDRA-2476
Added: cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/Attributes.java Modified: cassandra/branches/cassandra-0.8.1/CHANGES.txt cassandra/branches/cassandra-0.8.1/doc/cql/CQL.textile cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/AbstractModification.java cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/BatchStatement.java cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/Cql.g cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/DeleteStatement.java cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/QueryProcessor.java cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/UpdateStatement.java cassandra/branches/cassandra-0.8.1/test/system/test_cql.py Modified: cassandra/branches/cassandra-0.8.1/CHANGES.txt URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/CHANGES.txt?rev=1101234&r1=1101233&r2=1101234&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8.1/CHANGES.txt (original) +++ cassandra/branches/cassandra-0.8.1/CHANGES.txt Mon May 9 21:40:27 2011 @@ -1,12 +1,15 @@ 1.0-dev + + +0.8.1 * add support for insert, delete in cql BATCH (CASSANDRA-2537) * add support for IN to cql SELECT, UPDATE (CASSANDRA-2553) * add timestamp support to cql INSERT, UPDATE, and BATCH (CASSANDRA-2555) - -0.8.1 * add support for comparator parameters and a generic ReverseType (CASSANDRA-2355) * add CompositeType and DynamicCompositeType (CASSANDRA-2231) + * add CQL TTL support (CASSANDRA-2476) + 0.8.0-? * faster flushes and compaction from fixing excessively pessimistic Modified: cassandra/branches/cassandra-0.8.1/doc/cql/CQL.textile URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/doc/cql/CQL.textile?rev=1101234&r1=1101233&r2=1101234&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8.1/doc/cql/CQL.textile (original) +++ cassandra/branches/cassandra-0.8.1/doc/cql/CQL.textile Mon May 9 21:40:27 2011 @@ -74,7 +74,7 @@ h2. INSERT _Synopsis:_ bc. -INSERT INTO <COLUMN FAMILY> (KEY, <col>, <col>, ...) VALUES (<key>, <val>, <val>, ...) [USING CONSISTENCY <LEVEL> [AND TIMESTAMP <timestamp>]]; +INSERT INTO <COLUMN FAMILY> (KEY, <col>, <col>, ...) VALUES (<key>, <val>, <val>, ...) [USING CONSISTENCY <LEVEL> [AND TIMESTAMP <timestamp>] [AND TTL <timeToLive>]]; An @INSERT@ is used to write one or more columns to a record in a Cassandra column family. No results are returned. @@ -85,7 +85,7 @@ h2. UPDATE _Synopsis:_ bc. -UPDATE <COLUMN FAMILY> [USING <CONSISTENCY> [AND TIMESTAMP <timestamp>]] +UPDATE <COLUMN FAMILY> [USING <CONSISTENCY> [AND TIMESTAMP <timestamp>] [AND TTL <timeToLive>]] SET name1 = value1, name2 = value2 WHERE KEY = keyname; An @UPDATE@ is used to write one or more columns to a record in a Cassandra column family. No results are returned. @@ -111,6 +111,13 @@ UPDATE ... [USING TIMESTAMP <timestamp>] @UPDATE@ supports setting client-supplied optional timestamp for modification. +h3. TTL + +bc. +UPDATE ... [USING TTL <timeToLive>] ... + +@UPDATE@ supports setting time to live (TTL) for each of the columns in @UPDATE@ statement. + h3. Specifying Columns and Row bc. Modified: cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/AbstractModification.java URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/AbstractModification.java?rev=1101234&r1=1101233&r2=1101234&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/AbstractModification.java (original) +++ cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/AbstractModification.java Mon May 9 21:40:27 2011 @@ -33,17 +33,19 @@ public abstract class AbstractModificati protected final String columnFamily; protected final ConsistencyLevel cLevel; protected final Long timestamp; + protected final int timeToLive; - public AbstractModification(String columnFamily, ConsistencyLevel cLevel) + public AbstractModification(String columnFamily, Attributes attrs) { - this(columnFamily, cLevel, null); + this(columnFamily, attrs.getConsistencyLevel(), attrs.getTimestamp(), attrs.getTimeToLive()); } - public AbstractModification(String columnFamily, ConsistencyLevel cLevel, Long timestamp) + public AbstractModification(String columnFamily, ConsistencyLevel cLevel, Long timestamp, int timeToLive) { this.columnFamily = columnFamily; this.cLevel = cLevel; this.timestamp = timestamp; + this.timeToLive = timeToLive; } public String getColumnFamily() @@ -76,6 +78,11 @@ public abstract class AbstractModificati return timestamp != null; } + public int getTimeToLive() + { + return timeToLive; + } + /** * Convert statement into a list of mutations to apply on the server * Added: cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/Attributes.java URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/Attributes.java?rev=1101234&view=auto ============================================================================== --- cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/Attributes.java (added) +++ cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/Attributes.java Mon May 9 21:40:27 2011 @@ -0,0 +1,79 @@ +/* + * + * 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.cql; + +import org.apache.cassandra.thrift.ConsistencyLevel; + +/** + * Class to contain attributes for statements + */ +public class Attributes +{ + private ConsistencyLevel cLevel; + private Long timestamp; + private int timeToLive; + + public Attributes() + {} + + public Attributes(ConsistencyLevel cLevel, Long timestamp, int timeToLive) + { + this.cLevel = cLevel; + this.timestamp = timestamp; + this.timeToLive = timeToLive; + } + + public ConsistencyLevel getConsistencyLevel() + { + return cLevel; + } + + public void setConsistencyLevel(ConsistencyLevel cLevel) + { + this.cLevel = cLevel; + } + + public Long getTimestamp() + { + return timestamp; + } + + public void setTimestamp(Long timestamp) + { + this.timestamp = timestamp; + } + + public int getTimeToLive() + { + return timeToLive; + } + + public void setTimeToLive(int timeToLive) + { + this.timeToLive = timeToLive; + } + + public String toString() + { + return String.format("Attributes(consistency=%s, timestamp=%s, timeToLive=%s)", cLevel, timestamp, timeToLive); + } + +} Modified: cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/BatchStatement.java URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/BatchStatement.java?rev=1101234&r1=1101233&r2=1101234&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/BatchStatement.java (original) +++ cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/BatchStatement.java Mon May 9 21:40:27 2011 @@ -43,18 +43,22 @@ public class BatchStatement // global timestamp to apply for each mutation protected final Long timestamp; + // global time to live + protected final int timeToLive; + /** * Creates a new BatchStatement from a list of statements and a * Thrift consistency level. * * @param statements a list of UpdateStatements - * @param level Thrift consistency level enum + * @param attrs additional attributes for statement (CL, timestamp, timeToLive) */ - public BatchStatement(List<AbstractModification> statements, ConsistencyLevel level, Long timestamp) + public BatchStatement(List<AbstractModification> statements, Attributes attrs) { this.statements = statements; - consistency = level; - this.timestamp = timestamp; + this.consistency = attrs.getConsistencyLevel(); + this.timestamp = attrs.getTimestamp(); + this.timeToLive = attrs.getTimeToLive(); } public List<AbstractModification> getStatements() @@ -67,6 +71,11 @@ public class BatchStatement return consistency; } + public int getTimeToLive() + { + return timeToLive; + } + public List<RowMutation> getMutations(String keyspace, ClientState clientState) throws InvalidRequestException { List<RowMutation> batch = new LinkedList<RowMutation>(); Modified: cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/Cql.g URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/Cql.g?rev=1101234&r1=1101233&r2=1101234&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/Cql.g (original) +++ cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/Cql.g Mon May 9 21:40:27 2011 @@ -201,9 +201,7 @@ whereClause returns [WhereClause clause] */ insertStatement returns [UpdateStatement expr] : { - Long timestamp = null; - ConsistencyLevel cLevel = null; - + Attributes attrs = new Attributes(); Map<Term, Term> columns = new HashMap<Term, Term>(); List<Term> columnNames = new ArrayList<Term>(); @@ -213,19 +211,20 @@ insertStatement returns [UpdateStatement '(' K_KEY ( ',' column_name=term { columnNames.add($column_name.item); } )+ ')' K_VALUES '(' key=term ( ',' column_value=term { columnValues.add($column_value.item); })+ ')' - ( usingClause[cLevel, timestamp] )? + ( usingClause[attrs] )? { - return new UpdateStatement($columnFamily.text, cLevel, columnNames, columnValues, Collections.singletonList(key), timestamp); + return new UpdateStatement($columnFamily.text, columnNames, columnValues, Collections.singletonList(key), attrs); } ; -usingClause[ConsistencyLevel cLevel, Long timestamp] - : K_USING usingClauseObjective[cLevel, timestamp] ( K_AND? usingClauseObjective[cLevel, timestamp] )? +usingClause[Attributes attrs] + : K_USING usingClauseObjective[attrs] ( K_AND? usingClauseObjective[attrs] )* ; -usingClauseObjective[ConsistencyLevel cLevel, Long timestamp] - : K_CONSISTENCY K_LEVEL { cLevel = ConsistencyLevel.valueOf($K_LEVEL.text); } - | K_TIMESTAMP ts=INTEGER { timestamp = Long.valueOf($ts.text); } +usingClauseObjective[Attributes attrs] + : K_CONSISTENCY K_LEVEL { attrs.setConsistencyLevel(ConsistencyLevel.valueOf($K_LEVEL.text)); } + | K_TIMESTAMP ts=INTEGER { attrs.setTimestamp(Long.valueOf($ts.text)); } + | K_TTL t=INTEGER { attrs.setTimeToLive(Integer.parseInt($t.text)); } ; /** @@ -254,15 +253,16 @@ usingClauseObjective[ConsistencyLevel cL */ batchStatement returns [BatchStatement expr] : { - Long timestamp = null; - ConsistencyLevel cLevel = ConsistencyLevel.ONE; + Attributes attrs = new Attributes(); + attrs.setConsistencyLevel(ConsistencyLevel.ONE); + List<AbstractModification> statements = new ArrayList<AbstractModification>(); } - K_BEGIN K_BATCH ( usingClause[cLevel, timestamp] )? + K_BEGIN K_BATCH ( usingClause[attrs] )? s1=batchStatementObjective ';'? { statements.add(s1); } ( sN=batchStatementObjective ';'? { statements.add(sN); } )* K_APPLY K_BATCH endStmnt { - return new BatchStatement(statements, cLevel, timestamp); + return new BatchStatement(statements, attrs); } ; @@ -287,19 +287,18 @@ batchStatementObjective returns [Abstrac */ updateStatement returns [UpdateStatement expr] : { - Long timestamp = null; - ConsistencyLevel cLevel = null; + Attributes attrs = new Attributes(); Map<Term, Term> columns = new HashMap<Term, Term>(); List<Term> keyList = null; } K_UPDATE columnFamily=( IDENT | STRING_LITERAL | INTEGER ) - ( usingClause[cLevel, timestamp] )? + ( usingClause[attrs] )? K_SET termPair[columns] (',' termPair[columns])* K_WHERE ( K_KEY '=' key=term { keyList = Collections.singletonList(key); } | K_KEY K_IN '(' keys=termList { keyList = $keys.items; } ')' ) { - return new UpdateStatement($columnFamily.text, cLevel, columns, keyList, timestamp); + return new UpdateStatement($columnFamily.text, columns, keyList, attrs); } ; @@ -321,7 +320,8 @@ deleteStatement returns [DeleteStatement } K_DELETE ( cols=termList { columnsList = $cols.items; })? - K_FROM columnFamily=( IDENT | STRING_LITERAL | INTEGER ) ( K_USING K_CONSISTENCY K_LEVEL )? + K_FROM columnFamily=( IDENT | STRING_LITERAL | INTEGER ) + ( K_USING K_CONSISTENCY K_LEVEL { cLevel = ConsistencyLevel.valueOf($K_LEVEL.text); } )? K_WHERE ( K_KEY '=' key=term { keyList = Collections.singletonList(key); } | K_KEY K_IN '(' keys=termList { keyList = $keys.items; } ')' )? @@ -466,6 +466,7 @@ K_PRIMARY: P R I M A R Y; K_INTO: I N T O; K_VALUES: V A L U E S; K_TIMESTAMP: T I M E S T A M P; +K_TTL: T T L; // Case-insensitive alpha characters fragment A: ('a'|'A'); Modified: cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/DeleteStatement.java URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/DeleteStatement.java?rev=1101234&r1=1101233&r2=1101234&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/DeleteStatement.java (original) +++ cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/DeleteStatement.java Mon May 9 21:40:27 2011 @@ -48,7 +48,7 @@ public class DeleteStatement extends Abs public DeleteStatement(List<Term> columns, String columnFamily, ConsistencyLevel cLevel, List<Term> keys) { - super(columnFamily, cLevel, null); + super(columnFamily, cLevel, null, 0); this.columns = columns; this.keys = keys; Modified: cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/QueryProcessor.java URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/QueryProcessor.java?rev=1101234&r1=1101233&r2=1101234&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/QueryProcessor.java (original) +++ cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/QueryProcessor.java Mon May 9 21:40:27 2011 @@ -559,6 +559,9 @@ public class QueryProcessor case BATCH: BatchStatement batch = (BatchStatement) statement.statement; + if (batch.getTimeToLive() != 0) + throw new InvalidRequestException("Global TTL on the BATCH statement is not supported."); + for (AbstractModification up : batch.getStatements()) { if (up.isSetConsistencyLevel()) Modified: cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/UpdateStatement.java URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/UpdateStatement.java?rev=1101234&r1=1101233&r2=1101234&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/UpdateStatement.java (original) +++ cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cql/UpdateStatement.java Mon May 9 21:40:27 2011 @@ -53,32 +53,20 @@ public class UpdateStatement extends Abs * level, and key term. * * @param columnFamily column family name - * @param cLevel the thrift consistency level * @param columns a map of column name/values pairs * @param keys the keys to update - * @param timestamp timestamp to use for mutation, if set to null then System.currentTimeMillis() + * @param attrs additional attributes for statement (CL, timestamp, timeToLive) */ - public UpdateStatement(String columnFamily, ConsistencyLevel cLevel, Map<Term, Term> columns, List<Term> keys, Long timestamp) + public UpdateStatement(String columnFamily, + Map<Term, Term> columns, + List<Term> keys, + Attributes attrs) { - super(columnFamily, cLevel, timestamp); + super(columnFamily, attrs); this.columns = columns; this.keys = keys; } - - /** - * Creates a new UpdateStatement from a column family name, columns map, - * and key term. - * - * @param columnFamily column family name - * @param columns a map of column name/values pairs - * @param keys the keys to update - * @param timestamp timestamp to use for mutation, if set to null then System.currentTimeMillis() - */ - public UpdateStatement(String columnFamily, Map<Term, Term> columns, List<Term> keys, Long timestamp) - { - this(columnFamily, null, columns, keys, timestamp); - } /** * Creates a new UpdateStatement from a column family name, a consistency level, @@ -86,20 +74,18 @@ public class UpdateStatement extends Abs * alternate update format, <code>INSERT</code>. * * @param columnFamily column family name - * @param cLevel the thrift consistency level * @param columnNames list of column names * @param columnValues list of column values (corresponds to names) * @param keys the keys to update - * @param timestamp timestamp to use for mutation, if set to null then System.currentTimeMillis() + * @param attrs additional attributes for statement (CL, timestamp, timeToLive) */ public UpdateStatement(String columnFamily, - ConsistencyLevel cLevel, List<Term> columnNames, List<Term> columnValues, List<Term> keys, - Long timestamp) + Attributes attrs) { - super(columnFamily, cLevel, timestamp); + super(columnFamily, attrs); this.columnNames = columnNames; this.columnValues = columnValues; @@ -184,7 +170,8 @@ public class UpdateStatement extends Abs validateColumn(metadata, colName, colValue); rm.add(new QueryPath(columnFamily, null, colName), colValue, - (timestamp == null) ? getTimestamp() : timestamp); + (timestamp == null) ? getTimestamp() : timestamp, + getTimeToLive()); } return rm; @@ -224,11 +211,13 @@ public class UpdateStatement extends Abs public String toString() { - return String.format("UpdateStatement(columnFamily=%s, keys=%s, columns=%s, consistency=%s)", + return String.format("UpdateStatement(columnFamily=%s, keys=%s, columns=%s, consistency=%s, timestamp=%s, timeToLive=%s)", columnFamily, keys, columns, - cLevel); + getConsistencyLevel(), + timestamp, + timeToLive); } public AbstractType<?> getKeyType(String keyspace) Modified: cassandra/branches/cassandra-0.8.1/test/system/test_cql.py URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/test/system/test_cql.py?rev=1101234&r1=1101233&r2=1101234&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8.1/test/system/test_cql.py (original) +++ cassandra/branches/cassandra-0.8.1/test/system/test_cql.py Mon May 9 21:40:27 2011 @@ -807,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, """ @@ -842,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' @@ -877,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' @@ -911,3 +963,46 @@ class TestCql(ThriftTester): r = cursor.fetchone() 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)