Skip to content

CASSANDRA-21458 Update serializers to allow comparison between two LET variables#4879

Open
alanwang67 wants to merge 16 commits into
apache:trunkfrom
alanwang67:serialization
Open

CASSANDRA-21458 Update serializers to allow comparison between two LET variables#4879
alanwang67 wants to merge 16 commits into
apache:trunkfrom
alanwang67:serialization

Conversation

@alanwang67

Copy link
Copy Markdown
Contributor

Update serializers to allow comparison between two LET variables

patch by Alan Wang;

reviewed by for CASSANDRA-21458

Co-authored-by: Name1
Co-authored-by: Name2

Comment thread src/antlr/Parser.g Outdated
| '!=' { $op = ConditionStatement.Kind.NEQ; }
;

txnConditionKindRef returns [ConditionStatement.Kind op]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this a duplicate of

txnConditionKind returns [ConditionStatement.Kind op]
    : '='  { $op = ConditionStatement.Kind.EQ; }
    | '<'  { $op = ConditionStatement.Kind.LT; }
    | '<=' { $op = ConditionStatement.Kind.LTE; }
    | '>'  { $op = ConditionStatement.Kind.GT; }
    | '>=' { $op = ConditionStatement.Kind.GTE; }
    | '!=' { $op = ConditionStatement.Kind.NEQ; }
    ;

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),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you duplicating this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline, leaving here as documentation. This was done in order to allow for node upgrade compatibility. Since we decide which serializer to use based off the operator and ref op val and ref op ref, can not be differentiated by just the operator, the thinking was to create a new operator to differentiate the two. However, this resulted in duplicate code. The implementation now chooses to encode this information by using an extra bit within the TxnCondition.Kind ordinal that is serialized.

throw new IllegalStateException(String.format("Row reference (%s) can only be used with IS NULL/IS NOT NULL conditions", lhs.getText()));
if (((RowDataReference.Raw) rhs).column() == null)
throw new IllegalStateException(String.format("Row reference (%s) can only be used with IS NULL/IS NOT NULL conditions", rhs.getText()));
if (!((RowDataReference.Raw) lhs).column().type.equals(((RowDataReference.Raw) rhs).column().type))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think strictly speaking this isn't required as int < long I believe we support; but its fine for now

@alanwang67 alanwang67 Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering if we allowed for comparisons between an int and a boolean today or would we raise a type error or more generically two types that don't make sense to be compared.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually think IllegalStateException is the wrong type as we are validating the CQL, looking at TransactionStatement we use

package org.apache.cassandra.exceptions;

public class InvalidRequestException extends RequestValidationException

from

    public static InvalidRequestException invalidRequest(String messageTemplate, Object... messageArgs)
    {
        return new InvalidRequestException(String.format(messageTemplate, messageArgs));
    }

But back to the type thing. its fine to go specific type and if we ever have the time we can do castable types; I think its far more work than just undoing this if condition so fine to leave as is for now

Comment on lines +801 to +802
// This is so done to preserve upgrade compatibility with the prior serializer.
// Nodes that are not yet upgraded can still deserialize all values modulo those that are

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order for Accord to make changes to the serialization it needs to support V2 first which requires global configs, which is not in scope in the immediate future; given this we need work-arounds to support users who have been deploying off trunk to upgrade without breaking them; this is why we have the TOP_BIT concept, to enable this type of upgrade for users.

This change is safe under the following assumptions

1) `ref op ref` feature is only used after all nodes have been upgraded
2) cluster can be mixed mode as long as `ref op ref` is not used

If a user tries to use `ref op ref` in a mixed mode this will lead to undefined errors where the only recovery process is to force older nodes to upgrade

Something like that. Its very detailed on why this is the case...

}

@Override
public boolean applies(TxnData data)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isn't correct; there is a reason why Value doesn't do this as this is just SimpleBounds. row1.foo.bar and row1.foo['key'] are not correct I believe

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IF row1.user.id == row2.user.id

the above is actually the following in your code

IF row1.user == row2.user

as the toByteBuffer takes all complex types and returns the top level type, and not what is actually referenced

serializer.serialize(value, out);
}

public static <T, P> void serializeNullable(T value, P param, DataOutputPlus out, ParameterisedUnversionedSerializer<T, P> serializer) throws IOException

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is all dead code right? can we remove it if not used?


cluster.coordinator(1).executeWithResult(insert, ConsistencyLevel.SERIAL);

String query = "BEGIN TRANSACTION\n" +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pointed out in the code you have a bug with complex types. if you are doing a UDT field access we convert that to a UDT compare. If you are working with collection elements we convert that to a collection compare

AbstractType<?> typeRHS = getColumnType(referenceRHS);

if (typeLHS != typeRHS)
throw new InvalidRequestException(String.format("Invalid type comparison: cannot compare type %s with type %s", typeLHS.asCQL3Type(), typeRHS.asCQL3Type()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this too late? won't you deadlock accord? We already accepted we can't reject anymore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants