Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[submodule "modules/accord"]
path = modules/accord
url = https://github.com/apache/cassandra-accord.git
branch = trunk
url = https://github.com/alanwang67/cassandra-accord.git
branch = linearIntersectionBug
21 changes: 20 additions & 1 deletion doc/modules/cassandra/pages/developing/cql/transactions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -318,12 +318,26 @@ END IF
IF account_info IS NOT NULL AND account_info.balance > 0 THEN
-- statements
END IF

-- IF, ELSE IF, ELSE conditions
IF account_info IS NOT NULL AND account_info.balance > 0 THEN
-- statements
ELSE IF account_info.balance < 0 THEN
-- statements
ELSE
-- statements
END IF

-- Trailing update after conditions
IF account_info IS NOT NULL AND account_info.balance > 0 THEN
-- statements
-- statements
END IF
----

**Important Notes:**

* Null handling is strict (any null comparison returns false)
* All modification statements must be inside the IF block when using conditions

== Restrictions

Expand Down Expand Up @@ -354,6 +368,11 @@ BEGIN TRANSACTION
[SELECT selectStatement | SELECT rowDataReferences]
[IF conditionalExpression THEN]
[modificationStatements]
[ELSE IF conditionalExpression THEN]
[modificationStatements]
[ELSE]
[modificationStatements]
[modificationStatements]
[END IF]
COMMIT TRANSACTION
----
Expand Down
1 change: 1 addition & 0 deletions src/antlr/Lexer.g
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ K_ALLOW: A L L O W;
K_FILTERING: F I L T E R I N G;
K_IF: I F;
K_THEN: T H E N;
K_ELSE: E L S E;
K_END: E N D;
K_IS: I S;
K_CONTAINS: C O N T A I N S;
Expand Down
24 changes: 18 additions & 6 deletions src/antlr/Parser.g
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ options {

// enables parsing txn specific syntax when true
protected boolean isParsingTxn = false;
// tracks whether a txn has conditional updates
protected boolean isTxnConditional = false;

protected List<RowDataReference.Raw> references;

Expand Down Expand Up @@ -783,20 +781,33 @@ batchTxnStatement returns [TransactionStatement.Parsed expr]
List<SelectStatement.RawStatement> assignments = new ArrayList<>();
SelectStatement.RawStatement select = null;
List<RowDataReference.Raw> returning = null;
List<ModificationStatement.Parsed> updates = new ArrayList<>();
List<List<ConditionStatement.Raw>> conditions = new ArrayList<>();
List<List<ModificationStatement.Parsed>> updates = new ArrayList<>();
}
: K_BEGIN K_TRANSACTION
( let=letStatement ';' { assignments.add(let); })*
( ( (selectStatement) => s=selectStatement ';' { select = s; }) | ( K_SELECT drs=rowDataReferences ';' { returning = drs; }) )?
( K_IF conditions=txnConditions K_THEN { isTxnConditional = true; } )?
( upd=batchStatementObjective ';' { updates.add(upd); } )*
( {!isTxnConditional}? (K_COMMIT K_TRANSACTION) | {isTxnConditional}? (K_END K_IF K_COMMIT K_TRANSACTION))
(
K_IF c=txnConditions K_THEN u=updateStatements { conditions.add(c); updates.add(u); }
( K_ELSE K_IF c=txnConditions K_THEN u=updateStatements { conditions.add(c); updates.add(u); } )*
( K_ELSE u=updateStatements { conditions.add(Collections.singletonList(new ConditionStatement.Raw(null, ConditionStatement.Kind.ELSE, null))); updates.add(u); } )?
K_END K_IF
)?
( (updateStatements) => u=updateStatements { if (!u.isEmpty()) updates.add(u); } )?
(K_COMMIT K_TRANSACTION)
{
$expr = new TransactionStatement.Parsed(assignments, select, returning, updates, conditions, references);
}
;
finally { isParsingTxn = false; }

updateStatements returns [List<ModificationStatement.Parsed> updates]
@init {
updates = new ArrayList<ModificationStatement.Parsed>();
}
: (upd=batchStatementObjective ';' { updates.add(upd); })*
;

rowDataReferences returns [List<RowDataReference.Raw> refs]
: r1=rowDataReference { refs = new ArrayList<RowDataReference.Raw>(); refs.add(r1); } (',' rN=rowDataReference { refs.add(rN); })*
;
Expand Down Expand Up @@ -2473,6 +2484,7 @@ basic_unreserved_keyword returns [String str]
| K_END
| K_LET
| K_THEN
| K_ELSE
| K_TRANSACTION
| K_COMMENT
| K_COMMENTS
Expand Down
176 changes: 125 additions & 51 deletions src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ public enum Kind
GT(TxnCondition.Kind.GREATER_THAN, TxnCondition.Kind.LESS_THAN),
GTE(TxnCondition.Kind.GREATER_THAN_OR_EQUAL, TxnCondition.Kind.LESS_THAN_OR_EQUAL),
LT(TxnCondition.Kind.LESS_THAN, TxnCondition.Kind.GREATER_THAN),
LTE(TxnCondition.Kind.LESS_THAN_OR_EQUAL, TxnCondition.Kind.GREATER_THAN_OR_EQUAL);

LTE(TxnCondition.Kind.LESS_THAN_OR_EQUAL, TxnCondition.Kind.GREATER_THAN_OR_EQUAL),
ELSE(TxnCondition.Kind.ELSE, null);

// TODO: Support for IN, CONTAINS, CONTAINS KEY

private final TxnCondition.Kind kind;
private final TxnCondition.Kind reversedKind;

Kind(TxnCondition.Kind kind, TxnCondition.Kind reversedKind)
{
this.kind = kind;
Expand Down Expand Up @@ -80,15 +81,18 @@ public static class Raw

public Raw(Term.Raw lhs, Kind kind, Term.Raw rhs)
{
Preconditions.checkArgument(lhs != null);
Preconditions.checkArgument((rhs == null) == (kind == Kind.IS_NOT_NULL || kind == Kind.IS_NULL));
Preconditions.checkArgument(lhs != null || kind == Kind.ELSE);
Preconditions.checkArgument((rhs == null) == (kind == Kind.IS_NOT_NULL || kind == Kind.IS_NULL || kind == Kind.ELSE));
this.lhs = lhs;
this.kind = kind;
this.rhs = rhs;
}

public ConditionStatement prepare(String keyspace, VariableSpecifications bindVariables)
{
if (kind == Kind.ELSE)
return new ConditionStatement(null, kind, null, false);

if (rhs == null)
{
// In the IS NULL/IS NOT NULL case, the reference will always be on the LHS
Expand Down Expand Up @@ -134,6 +138,8 @@ public TxnCondition createCondition(QueryOptions options)
{
switch (kind)
{
case ELSE:
return TxnCondition.Else.instance;
case IS_NOT_NULL:
case IS_NULL:
return new TxnCondition.Exists(reference.toTxnReference(options), kind.toTxnKind(reversed));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ public enum Kind
GREATER_THAN_OR_EQUAL(">=", Operator.GTE),
LESS_THAN("<", Operator.LT),
LESS_THAN_OR_EQUAL("<=", Operator.LTE),
COLUMN_CONDITIONS("COLUMN_CONDITIONS", null);
COLUMN_CONDITIONS("COLUMN_CONDITIONS", null),
ELSE("ELSE", null);

@Nonnull
private final String symbol;
Expand Down Expand Up @@ -152,6 +153,8 @@ private ConditionSerializer serializer()
return None.serializer;
case COLUMN_CONDITIONS:
return ColumnConditionsAdapter.serializer;
case ELSE:
return Else.serializer;
default:
throw new IllegalArgumentException("No serializer exists for kind " + this);
}
Expand Down Expand Up @@ -231,6 +234,43 @@ public static TxnCondition none()
return None.instance;
}

public static class Else extends TxnCondition
{
public static final Else instance = new Else();

private Else()
{
super(Kind.ELSE);
}

@Override
public String toString()
{
return kind.toString();
}

@Override
public void collect(TableMetadatas.Collector collector)
{
}

@Override
public boolean applies(TxnData data)
{
return true;
}

private static final ConditionSerializer<Else> serializer = new ConditionSerializer<>()
{
@Override
public void serialize(Else condition, TableMetadatas tables, DataOutputPlus out) {}
@Override
public Else deserialize(TableMetadatas tables, DataInputPlus in, Kind kind) { return instance; }
@Override
public long serializedSize(Else condition, TableMetadatas tables) { return 0; }
};
}

public static class Exists extends TxnCondition
{
private static final Set<Kind> KINDS = ImmutableSet.of(Kind.IS_NOT_NULL, Kind.IS_NULL);
Expand Down
Loading