[ 
https://issues.apache.org/jira/browse/CASSANDRA-11935?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15565286#comment-15565286
 ] 

Sylvain Lebresne commented on CASSANDRA-11935:
----------------------------------------------


General functionality lgtm. A bunch of remark though:
* This is more for the record (not really asking anything here), but the 
grammar is starting to be unreadable imo. I don't meant that as a criticism of 
this patch, as I don't have a better idea for dealing with this without a much 
larger refactor of the CQL code, but we may want to keep an eye on this moving 
forward. This also mean that while I've looked at the grammar changes and did 
not notice an obvious problem, I want to be clear that I'm not confident in my 
own capacity to vet grammar changes properly at this point.
* It's not fully clear to me what purposes the {{WithOperation}} and 
{{WithNegation}} classes in {{Selectable}} serves. I would *really* prefer we 
deal with operators as normal functions internally as much as possible 
(operators are "just" syntactic sugar for true functions calls) and so I'd 
rather use {{WithFunction}} directly in both cases.
* I'm also unsure about {{Selectable.BetweenParentheses}}. It seems to assume 
we can't have a tuple of size 1 but I don't think that's true. I believe we 
should do as for {{WithMapOrUDT}}: keep it a tuple/undetermined until we get 
the type and decide then. Though we probably need to be careful with things 
like {{((1))}} (where the internal one is a tuple) (meaning, we should handle 
it and have a test for it).
* The patch adds extended support for collections in select statement. Namely, 
you can now do {{SELECT \[a, f(a)\] FROM...}} which didn't worked before. It's 
nice (though unrelated to this ticket and ideally would have been kept for a 
follow up) but I don't see much test of this.
* Not sure about the hard-coding of {{MathContext.DECIMAL128}} as 
precision/rounding settings for {{BigDecimal}}. As in, I'm not knowledgable 
enough on decimal arithmetic to decide if this is the best choice or not. But 
in doubt, I would have maybe stick to the default {{BigDecimal}} behavior.
* On {{Type.getPreferedTypeFor()}}:
** the javadoc is kind of wrong: it wouldn't be called "getPreferedType" if it 
was returning "the exact type". I think it'll also be useful to call out when 
that function is used (namely, during during function resolution to force a 
choice between multiple possible overrides).
** not sure why we stop at {{int}} for integers. Why not return a {{tinyint}} 
if it fits? I'd expect users to be surprised if {{c + 1}} returns a {{int}} 
when {{c}} is a {{tinyint}}/{{smallint}}, especially when {{c + c}} does return 
a {{tinyint}}/{{smallint}}. Worst, with {{c}} still a {{tinyint}}, this means 
{{WHERE c = 2}} works but {{WHERE c = 1 + 1}} doesn't.
** It's a nit I suppose, but smallish values are likely much more common, so 
creating {{BigInteger}}//{{BigDecimal}} by default feels wasteful. I would have 
done a {{Long.parseLong()}} by default and fallback on {{BigInteger}} on 
failure.
** Maybe it's worth going though the end of the idea and implement that method 
for some other literals? At least UUIDs could prefer {{TimeUUIDType}} if it 
looks like a version 1 uuid, {{UUIDType}} otherwise (if you have 2 overrides, 
one for {{TimeUUIDType}} and {{UUIDType}}, what are the changes you don't want 
to pick the {{TimeUUIDType}} one if the string is a v1 uuid? And it's actually 
somewhat stupid being ambiguous if the uuid isn't a v1 uuid). No reason to no 
return something for {{HEX}} and {{BOOLEAN}} either, even though this actually 
won't have any practical consequence (outside of making the code look less 
arbitrary that is). Strings are little more debatable though, so happy to leave 
them out for now.
* In {{OperationFcts}}, making an enum for the operations:
{code}
public enum OPERATOR
{
    ADDITION("+", "_add"),
    SUBSTRACTION("-", "_substract"),
    ...
}
{code}
would allow making some of the code a tiny bit cleaner imo. In particular, 
instead of having {{add}}, {{substract}}, ... methods in {{NumberType}}, we 
could just have a single {{compute}} that takes the operation, which would 
reduce the amount of boilerplate in the implementations of those method (for a 
given type, all have the exact same body except for the operation). Can also 
avoid the 5 boilerplate classes in {{OperationFcts}}.
* Regarding the {{NumberType}} new methods: the code does tons of 
boxing/unboxing for not that much clarity benefit imo (granted, we have another 
inefficiency in the fact that we serialize/deserialize to bytes for every 
function call, and we should certainly fix that at some point. No reason to be 
more inefficient that we have to in the meantime though). Anyway, I'd probably 
put all the {{toXXX()}} method in {{NumberType}} as "unsupported" and override 
with a non-boxing implementation when appropriate.
* The last one is more of a nitpick because it doesn't matter much in practice, 
but the {{OperationFcts.returnType()}} function can do quite a bit of 
comparisons and I don't find it easy to proof-read: the logic, which is to pick 
the precision of the bigger argument and favor floating point if any operand 
is, isn't easily apparent. So I'd have gone with something along the lines of:
{code}
private static NumberType<?> returnType(NumberType<?> left, NumberType<?> right)
{
    boolean isFloatingPoint = isFloatingPoint(left) || isFloatingPoint(right);
    int precision = Math.max(precision(left), precision(right));
    return isFloatingPoint
         ? floatPointType(precision)
         : integerType(precision);
}

private static boolean isFloatingPoint(NumberType<?> type)
{
    switch ((Native)type.asCQL3Type())
    {
        case DECIMAL:
        case DOUBLE:
        case FLOAT:
            return true;
        default:
            return false;
    }
}

private static int precision(NumberType<?> type)
{
    switch ((Native)type.asCQL3Type())
    {
        case DECIMAL:
        case VARINT:
            return Integer.MAX_VALUE;
        case DOUBLE:
        case BIGINT:
        case COUNTER:
            return 8;
        case INT:
        case FLOAT:
            return 4;
        case SMALLINT;
            return 2;
        case TINYINT;
            return 1;
    }
}

private static NumberType<?> floatPointType(int precision)
{
    switch (precision)
    {
        case 4: return FloatType.instance;
        case 8: return DoubleType.instance;
        case Integer.MAX_VALUE: return DecimalType.instance;
    }
}

private static NumberType<?> integerType(int precision)
{
    switch (precision)
    {
        case 1: return ByteType.instance;
        case 2: return ShortType.instance;
        case 4: return Int32Type.instance;
        case 8: return LongType.instance;
        case Integer.MAX_VALUE: return IntegerType.instance;
    }
}
{code}


> Add support for arithmetic operators
> ------------------------------------
>
>                 Key: CASSANDRA-11935
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-11935
>             Project: Cassandra
>          Issue Type: Sub-task
>          Components: CQL
>            Reporter: Benjamin Lerer
>            Assignee: Benjamin Lerer
>             Fix For: 3.x
>
>
> The goal of this ticket is to add support for arithmetic operators:
> * {{-}}: Change the sign of the argument
> * {{+}}: Addition operator
> * {{-}}: Minus operator
> * {{*}}: Multiplication operator
> * {{/}}: Division operator
> * {{%}}: Modulo operator
> This ticket we should focus on adding operator only for numeric types to keep 
> the scope as small as possible. Dates and string operations will be adressed 
> in follow up tickets.
> The operation precedence should be:
> # {{*}}, {{/}}, {{%}}
> # {{+}}, {{-}}
> Some implicit data conversion should be performed when operations are 
> performed on different types (e.g. double + int).



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to