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

DOAN DuyHai commented on CASSANDRA-12149:
-----------------------------------------

The query used = {{SELECT namespace, entity, timestamp, feature1, feature2 FROM 
mykeyspace.myrecordtable WHERE namespace = 'ns2' AND entity = 'entity2' AND 
feature1= 11 AND token(namespace, entity) <= 9223372036854775807;}}

Ok, after successfully re-producing the NPE in debug mode, it is *not* a SASI 
bug but is rather related to how Cassandra optimises the *WHERE* clause in 
general.

 NPE root cause is {{slice.bound(b) == null}} in 
{{TokenRestriction.bounds(Bound b, QueryOptions options)}}:

{code:java}
        public List<ByteBuffer> bounds(Bound b, QueryOptions options) throws 
InvalidRequestException
        {
            return 
Collections.singletonList(slice.bound(b).bindAndGet(options));
        }
{code}

Going up the call stack, the culprit is at 
{{StatementRestrictions.getPartitionKeyBounds(IPartitioner p, QueryOptions 
options)}}:

{code:java}
    private AbstractBounds<PartitionPosition> 
getPartitionKeyBounds(IPartitioner p,
                                                                    
QueryOptions options)
    {
        ByteBuffer startKeyBytes = getPartitionKeyBound(Bound.START, options);
        ByteBuffer finishKeyBytes = getPartitionKeyBound(Bound.END, options);
        ....
{code}

 Since we have no lower bound restriction on the {{token(namespace, entity)}}, 
the call to {{getPartitionKeyBound(Bound.START, options)}} generates the NPE.

 I try another query without using secondary index {{SELECT namespace, entity, 
timestamp, feature1, feature2 FROM mykeyspace.myrecordtable WHERE namespace = 
'ns2' AND entity = 'entity2' AND token(namespace, entity) <= 
9223372036854775807;}} and this time, no NPE.

 The place in the call stack where both queries diverge is at 
{{SelectStatements.getQuery(QueryOptions options, int nowInSec, int userLimit, 
int perPartitionLimit)}}:

{code:java}
    public ReadQuery getQuery(QueryOptions options, int nowInSec, int 
userLimit, int perPartitionLimit) throws RequestValidationException
    {
        DataLimits limit = getDataLimits(userLimit, perPartitionLimit);
        if (restrictions.isKeyRange() || restrictions.usesSecondaryIndexing())
            return getRangeCommand(options, limit, nowInSec);

        return getSliceCommands(options, limit, nowInSec);
    }
{code}

 When using secondary index, we fall in the *if* condition obviously. When NOT 
using secondary index as per my 2nd SELECT statement, the *if* condition is not 
verified so the code path is {{return getSliceCommands(options, limit, 
nowInSec);}}.

 Strangely enough, even with the 2nd SELECT, {{restrictions.isKeyRange()}} 
should be *true*, why is it *false* ????

 The culprit is at 
{{StatementRestrictions.processPartitionKeyRestrictions(boolean 
hasQueriableIndex)}}

{code:java}
...
if (partitionKeyRestrictions.isOnToken())
            isKeyRange = true;

            if (hasUnrestrictedPartitionKeyComponents())
            {
                if (!partitionKeyRestrictions.isEmpty())
                {
                    if (!hasQueriableIndex)
                        throw invalidRequest("Partition key parts: %s must be 
restricted as other parts are",
                                             Joiner.on(", 
").join(getPartitionKeyUnrestrictedComponents()));
                }

                isKeyRange = true;
                usesSecondaryIndexing = hasQueriableIndex;
            }
        }
{code}

 Condition {{if (partitionKeyRestrictions.isOnToken())}} evaluates to *false* 
so variable _isKeyRange_ is never set to *true*.

 Condition {{if (partitionKeyRestrictions.isOnToken())}} evaluates to *false* 
because of {{TokenFilter.isOnToken()}}:

{code:java}
    public boolean isOnToken()
    {
        // if all partition key columns have non-token restrictions, we can 
simply use the token range to filter
        // those restrictions and then ignore the token range
        return restrictions.size() < tokenRestriction.size();
    }
{code}

 Here, since there are *more* conditions on primary key than on token 
restriction, the SELECT is not considered to be a token restriction, which is 
sensible.

 By the way, if we look at the original WHERE clause {{WHERE namespace = 'ns2' 
AND entity = 'entity2' AND feature1= 11 AND token(namespace, entity) <= 
9223372036854775807;}}, the restriction using *token* function is *useless* 
because we already provide the complete partition key restriction.

 And I tried the original query by removing {{token(namespace, entity) <= 
9223372036854775807}} and it works like a charm.

 I would consider this JIRA to be *not an issue*

cc [~xedin]  [~beobal] and [~avkonst]
 




> NullPointerException on SELECT with SASI index
> ----------------------------------------------
>
>                 Key: CASSANDRA-12149
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-12149
>             Project: Cassandra
>          Issue Type: Bug
>          Components: sasi
>            Reporter: Andrey Konstantinov
>         Attachments: CASSANDRA-12149.txt
>
>
> If I execute the sequence of queries (see the attached file), Cassandra 
> aborts a connection reporting NPE on server side. SELECT query without token 
> range filter works, but does not work when token range filter is specified. 
> My intent was to issue multiple SELECT queries targeting the same single 
> partition, filtered by a column indexed by SASI, partitioning results by 
> different token ranges.
> Output from cqlsh on SELECT is the following:
> cqlsh> SELECT namespace, entity, timestamp, feature1, feature2 FROM 
> mykeyspace.myrecordtable WHERE namespace = 'ns2' AND entity = 'entity2' AND 
> feature1 > 11 AND feature1 < 31  AND token(namespace, entity) <= 
> 9223372036854775807;
> ServerError: <ErrorMessage code=0000 [Server error] 
> message="java.lang.NullPointerException">



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

Reply via email to