Search in sources :

Example 6 with CollectionType

use of org.apache.geode.cache.query.types.CollectionType in project geode by apache.

the class CompiledSelect method evaluate.

public SelectResults evaluate(ExecutionContext context) throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
    context.newScope((Integer) context.cacheGet(scopeID));
    context.pushExecCache((Integer) context.cacheGet(scopeID));
    context.setDistinct(this.distinct);
    if (this.hasUnmappedOrderByCols && context.getBucketList() != null) {
        throw new QueryInvalidException(LocalizedStrings.DefaultQuery_ORDER_BY_ATTRIBS_NOT_PRESENT_IN_PROJ.toLocalizedString());
    }
    if (hints != null) {
        context.cachePut(QUERY_INDEX_HINTS, hints);
    }
    try {
        // set flag to keep objects serialized for "select *" queries
        if ((DefaultQuery) context.getQuery() != null) {
            ((DefaultQuery) context.getQuery()).keepResultsSerialized(this, context);
        }
        Iterator iter = iterators.iterator();
        while (iter.hasNext()) {
            CompiledIteratorDef iterDef = (CompiledIteratorDef) iter.next();
            RuntimeIterator rIter = iterDef.getRuntimeIterator(context);
            context.bindIterator(rIter);
        // Ideally the function below should always be called after binding has occurred
        // So that the internal ID gets set during binding to the scope. If not so then chances
        // are that internal_id is still null causing index_internal_id to be null.
        // Though in our case it may not be an issue as the compute dependency phase must have
        // already set the index id
        }
        Integer limitValue = evaluateLimitValue(context, this.limit);
        SelectResults result = null;
        boolean evalAsFilters = false;
        if (this.whereClause == null) {
            result = doIterationEvaluate(context, false);
        } else {
            if (!this.whereClause.isDependentOnCurrentScope(context)) {
                // independent
                // where
                // @todo
                // check
                // for
                // dependency
                // on
                // current
                // scope
                // only?
                // clause
                Object b = this.whereClause.evaluate(context);
                if (b == null || b == QueryService.UNDEFINED) {
                    // treat as if all elements are undefined
                    result = prepareEmptyResultSet(context, false);
                // ResultsSet.emptyResultsSet(resultSet, 0);
                // return result;
                } else if (!(b instanceof Boolean)) {
                    throw new TypeMismatchException(LocalizedStrings.CompiledSelect_THE_WHERE_CLAUSE_WAS_TYPE_0_INSTEAD_OF_BOOLEAN.toLocalizedString(b.getClass().getName()));
                } else if ((Boolean) b) {
                    result = doIterationEvaluate(context, false);
                } else {
                    result = prepareEmptyResultSet(context, false);
                // ResultsSet.emptyResultsSet(resultSet, 0);
                // return result;
                }
            } else {
                // Check the numer of independent iterators
                int numInd = context.getAllIndependentIteratorsOfCurrentScope().size();
                // If order by clause is defined, then the first column should be the preferred index
                if (this.orderByAttrs != null && numInd == 1) {
                    CompiledSortCriterion csc = (CompiledSortCriterion) orderByAttrs.get(0);
                    StringBuilder preferredIndexCondn = new StringBuilder();
                    this.evalCanonicalizedExpressionForCSC(csc, context, preferredIndexCondn);
                    context.cachePut(PREF_INDEX_COND, preferredIndexCondn.toString());
                }
                boolean unlock = true;
                Object obj = context.cacheGet(this.whereClause);
                if (obj != null && (obj instanceof IndexInfo[] || obj.equals(CLAUSE_EVALUATED))) {
                    // if indexinfo is cached means the read lock
                    // is not being taken this time, so releasing
                    // the lock is not required
                    unlock = false;
                }
                // see if we should evaluate as filters,
                // and count how many actual index lookups will be performed
                PlanInfo planInfo = this.whereClause.getPlanInfo(context);
                if (context.cacheGet(this.whereClause) == null) {
                    context.cachePut(this.whereClause, CLAUSE_EVALUATED);
                }
                try {
                    evalAsFilters = planInfo.evalAsFilter;
                    // let context know if there is exactly one index lookup
                    context.setOneIndexLookup(planInfo.indexes.size() == 1);
                    if (evalAsFilters) {
                        ((QueryExecutionContext) context).setIndexUsed(true);
                        // Ignore order by attribs for a while
                        boolean canApplyOrderByAtIndex = false;
                        if (limitValue >= 0 && numInd == 1 && ((Filter) this.whereClause).isLimitApplicableAtIndexLevel(context)) {
                            context.cachePut(CAN_APPLY_LIMIT_AT_INDEX, Boolean.TRUE);
                        }
                        StringBuilder temp = null;
                        if (this.orderByAttrs != null) {
                            temp = new StringBuilder();
                            CompiledSortCriterion csc = (CompiledSortCriterion) this.orderByAttrs.get(0);
                            this.evalCanonicalizedExpressionForCSC(csc, context, temp);
                        }
                        boolean needsTopLevelOrdering = true;
                        if (temp != null && numInd == 1 && ((Filter) this.whereClause).isOrderByApplicableAtIndexLevel(context, temp.toString())) {
                            context.cachePut(CAN_APPLY_ORDER_BY_AT_INDEX, Boolean.TRUE);
                            context.cachePut(ORDERBY_ATTRIB, this.orderByAttrs);
                            canApplyOrderByAtIndex = true;
                            if (this.orderByAttrs.size() == 1) {
                                needsTopLevelOrdering = false;
                                // we should use a sorted set
                                if (this.limit != null) {
                                    // Currently check bucket list to determine if it's a pr query
                                    if (context.getBucketList() != null && context.getBucketList().size() > 0) {
                                        needsTopLevelOrdering = true;
                                    }
                                }
                            }
                        } else if (temp != null) {
                            // If order by is present but cannot be applied at index level,
                            // then limit also cannot be applied
                            // at index level
                            context.cachePut(CAN_APPLY_LIMIT_AT_INDEX, Boolean.FALSE);
                        }
                        context.cachePut(RESULT_LIMIT, limitValue);
                        if (numInd == 1 && ((Filter) this.whereClause).isProjectionEvaluationAPossibility(context) && (this.orderByAttrs == null || (canApplyOrderByAtIndex && !needsTopLevelOrdering)) && this.projAttrs != null) {
                            // Possibility of evaluating the resultset as filter itself
                            ObjectType resultType = this.cachedElementTypeForOrderBy != null ? this.cachedElementTypeForOrderBy : this.prepareResultType(context);
                            context.cachePut(RESULT_TYPE, resultType);
                            context.cachePut(PROJ_ATTRIB, this.projAttrs);
                        }
                        result = ((Filter) this.whereClause).filterEvaluate(context, null);
                        if (!(context.cacheGet(RESULT_TYPE) instanceof Boolean)) {
                            QueryObserverHolder.getInstance().beforeApplyingProjectionOnFilterEvaluatedResults(result);
                            result = applyProjectionOnCollection(result, context, !needsTopLevelOrdering);
                        }
                    } else {
                        // otherwise iterate over the single from var to evaluate
                        result = doIterationEvaluate(context, true);
                    }
                } finally {
                    // because we need to select index which can be read-locked.
                    if (unlock) {
                        releaseReadLockOnUsedIndex(planInfo);
                    }
                }
            }
        }
        // if (result == null) { return QueryService.UNDEFINED; }
        assert result != null;
        // drop duplicates if this is DISTINCT
        if (result instanceof SelectResults) {
            SelectResults sr = (SelectResults) result;
            CollectionType colnType = sr.getCollectionType();
            // if (this.distinct && colnType.allowsDuplicates()) {
            if (this.distinct) {
                Collection r;
                // Set s = sr.asSet();
                if (colnType.allowsDuplicates()) {
                    // don't just convert to a ResultsSet (or StructSet), since
                    // the bags can convert themselves to a Set more efficiently
                    r = sr.asSet();
                } else {
                    r = sr;
                }
                result = new ResultsCollectionWrapper(colnType.getElementType(), r, limitValue);
                if (r instanceof Bag.SetView) {
                    ((ResultsCollectionWrapper) result).setModifiable(false);
                }
            } else {
                // SelectResults is of type
                if (limitValue > -1) {
                    ((Bag) sr).applyLimit(limitValue);
                }
            }
            /*
         * We still have to get size of SelectResults in some cases like, if index was used OR query
         * is a distinct query.
         * 
         * If SelectResult size is zero then we need to put Integer for 0 count.
         */
            if (this.count) {
                SelectResults res = (SelectResults) result;
                if ((this.distinct || evalAsFilters || countStartQueryResult == 0)) {
                    // at coordinator node for PR queries.
                    if (context.getBucketList() != null && this.distinct) {
                        return result;
                    }
                    // Take size and empty the results
                    int resultCount = res.size();
                    res.clear();
                    ResultsBag countResult = new ResultsBag(new ObjectTypeImpl(Integer.class), context.getCachePerfStats());
                    countResult.addAndGetOccurence(resultCount);
                    result = countResult;
                } else {
                    ((Bag) res).addAndGetOccurence(countStartQueryResult);
                }
            }
        }
        return result;
    } finally {
        context.popScope();
        context.popExecCache();
    }
}
Also used : TypeMismatchException(org.apache.geode.cache.query.TypeMismatchException) ObjectType(org.apache.geode.cache.query.types.ObjectType) SelectResults(org.apache.geode.cache.query.SelectResults) CollectionType(org.apache.geode.cache.query.types.CollectionType) Iterator(java.util.Iterator) QueryInvalidException(org.apache.geode.cache.query.QueryInvalidException) ObjectTypeImpl(org.apache.geode.cache.query.internal.types.ObjectTypeImpl) Collection(java.util.Collection)

Example 7 with CollectionType

use of org.apache.geode.cache.query.types.CollectionType in project geode by apache.

the class BaseCommandQuery method processQueryUsingParams.

/**
   * Process the give query and sends the resulset back to the client.
   *
   * @param msg
   * @param query
   * @param queryString
   * @param regionNames
   * @param start
   * @param cqQuery
   * @param queryContext
   * @param servConn
   * @return true if successful execution false in case of failure.
   * @throws IOException
   */
protected boolean processQueryUsingParams(Message msg, Query query, String queryString, Set regionNames, long start, ServerCQ cqQuery, QueryOperationContext queryContext, ServerConnection servConn, boolean sendResults, Object[] params) throws IOException, InterruptedException {
    ChunkedMessage queryResponseMsg = servConn.getQueryResponseMessage();
    CacheServerStats stats = servConn.getCacheServerStats();
    CachedRegionHelper crHelper = servConn.getCachedRegionHelper();
    {
        long oldStart = start;
        start = DistributionStats.getStatTime();
        stats.incReadQueryRequestTime(start - oldStart);
    }
    // object type
    if (servConn.getClientVersion().compareTo(Version.GFE_70) >= 0) {
        ((DefaultQuery) query).setRemoteQuery(true);
    }
    // Process the query request
    try {
        // integrated security
        for (Object regionName : regionNames) {
            this.securityService.authorizeRegionRead(regionName.toString());
        }
        // Execute query
        // startTime = GenericStats.getTime();
        // startTime = System.currentTimeMillis();
        // For now we assume the results are a SelectResults
        // which is the only possibility now, but this may change
        // in the future if we support arbitrary queries
        Object result = null;
        if (params != null) {
            result = query.execute(params);
        } else {
            result = query.execute();
        }
        // Asif : Before conditioning the results check if any
        // of the regions involved in the query have been destroyed
        // or not. If yes, throw an Exception.
        // This is a workaround/fix for Bug 36969
        Iterator itr = regionNames.iterator();
        while (itr.hasNext()) {
            String regionName = (String) itr.next();
            if (crHelper.getRegion(regionName) == null) {
                throw new RegionDestroyedException(LocalizedStrings.BaseCommand_REGION_DESTROYED_DURING_THE_EXECUTION_OF_THE_QUERY.toLocalizedString(), regionName);
            }
        }
        AuthorizeRequestPP postAuthzRequest = servConn.getPostAuthzRequest();
        if (postAuthzRequest != null) {
            if (cqQuery == null) {
                queryContext = postAuthzRequest.queryAuthorize(queryString, regionNames, result, queryContext, params);
            } else {
                queryContext = postAuthzRequest.executeCQAuthorize(cqQuery.getName(), queryString, regionNames, result, queryContext);
            }
            result = queryContext.getQueryResult();
        }
        if (result instanceof SelectResults) {
            SelectResults selectResults = (SelectResults) result;
            if (logger.isDebugEnabled()) {
                logger.debug("Query Result size for : {} is {}", query.getQueryString(), selectResults.size());
            }
            CollectionType collectionType = null;
            boolean sendCqResultsWithKey = true;
            boolean isStructs = false;
            // check if resultset has serialized objects, so that they could be sent
            // as ObjectPartList
            boolean hasSerializedObjects = ((DefaultQuery) query).isKeepSerialized();
            if (logger.isDebugEnabled()) {
                logger.debug("Query Result for :{} has serialized objects: {}", query.getQueryString(), hasSerializedObjects);
            }
            // Don't convert to a Set, there might be duplicates now
            // The results in a StructSet are stored in Object[]s
            // Get them as Object[]s for the objs[] in order to avoid duplicating
            // the StructTypes
            // Object[] objs = new Object[selectResults.size()];
            // Get the collection type (which includes the element type)
            // (used to generate the appropriate instance on the client)
            // Get the collection type (which includes the element type)
            // (used to generate the appropriate instance on the client)
            collectionType = getCollectionType(selectResults);
            isStructs = collectionType.getElementType().isStructType();
            // Check if the Query is from CQ execution.
            if (cqQuery != null) {
                // Check if the key can be sent to the client based on its version.
                sendCqResultsWithKey = sendCqResultsWithKey(servConn);
                if (sendCqResultsWithKey) {
                    // Update the collection type to include key info.
                    collectionType = new CollectionTypeImpl(Collection.class, new StructTypeImpl(new String[] { "key", "value" }));
                    isStructs = collectionType.getElementType().isStructType();
                }
            }
            int numberOfChunks = (int) Math.ceil(selectResults.size() * 1.0 / MAXIMUM_CHUNK_SIZE);
            if (logger.isTraceEnabled()) {
                logger.trace("{}: Query results size: {}: Entries in chunk: {}: Number of chunks: {}", servConn.getName(), selectResults.size(), MAXIMUM_CHUNK_SIZE, numberOfChunks);
            }
            long oldStart = start;
            start = DistributionStats.getStatTime();
            stats.incProcessQueryTime(start - oldStart);
            if (sendResults) {
                queryResponseMsg.setMessageType(MessageType.RESPONSE);
                queryResponseMsg.setTransactionId(msg.getTransactionId());
                queryResponseMsg.sendHeader();
            }
            if (sendResults && numberOfChunks == 0) {
                // Send 1 empty chunk
                if (logger.isTraceEnabled()) {
                    logger.trace("{}: Creating chunk: 0", servConn.getName());
                }
                writeQueryResponseChunk(new Object[0], collectionType, true, servConn);
                if (logger.isDebugEnabled()) {
                    logger.debug("{}: Sent chunk (1 of 1) of query response for query {}", servConn.getName(), queryString);
                }
            } else {
                // send it as a part of ObjectPartList
                if (hasSerializedObjects) {
                    sendResultsAsObjectPartList(numberOfChunks, servConn, selectResults.asList(), isStructs, collectionType, queryString, cqQuery, sendCqResultsWithKey, sendResults);
                } else {
                    sendResultsAsObjectArray(selectResults, numberOfChunks, servConn, isStructs, collectionType, queryString, cqQuery, sendCqResultsWithKey, sendResults);
                }
            }
            if (cqQuery != null) {
                // Set the CQ query result cache initialized flag.
                cqQuery.setCqResultsCacheInitialized();
            }
        } else if (result instanceof Integer) {
            if (sendResults) {
                queryResponseMsg.setMessageType(MessageType.RESPONSE);
                queryResponseMsg.setTransactionId(msg.getTransactionId());
                queryResponseMsg.sendHeader();
                writeQueryResponseChunk(result, null, true, servConn);
            }
        } else {
            throw new QueryInvalidException(LocalizedStrings.BaseCommand_UNKNOWN_RESULT_TYPE_0.toLocalizedString(result.getClass()));
        }
        msg.clearParts();
    } catch (QueryInvalidException e) {
        // Handle this exception differently since it can contain
        // non-serializable objects.
        // java.io.NotSerializableException: antlr.CommonToken
        // Log a warning to show stack trace and create a new
        // QueryInvalidEsception on the original one's message (not cause).
        logger.warn(LocalizedMessage.create(LocalizedStrings.BaseCommand_UNEXPECTED_QUERYINVALIDEXCEPTION_WHILE_PROCESSING_QUERY_0, queryString), e);
        QueryInvalidException qie = new QueryInvalidException(LocalizedStrings.BaseCommand_0_QUERYSTRING_IS_1.toLocalizedString(new Object[] { e.getLocalizedMessage(), queryString }));
        writeQueryResponseException(msg, qie, servConn);
        return false;
    } catch (DistributedSystemDisconnectedException se) {
        if (msg != null && logger.isDebugEnabled()) {
            logger.debug("{}: ignoring message of type {} from client {} because shutdown occurred during message processing.", servConn.getName(), MessageType.getString(msg.getMessageType()), servConn.getProxyID());
        }
        servConn.setFlagProcessMessagesAsFalse();
        servConn.setClientDisconnectedException(se);
        return false;
    } catch (Exception e) {
        // If an interrupted exception is thrown , rethrow it
        checkForInterrupt(servConn, e);
        // Otherwise, write a query response and continue
        // Check if query got canceled from QueryMonitor.
        DefaultQuery defaultQuery = (DefaultQuery) query;
        if ((defaultQuery).isCanceled()) {
            e = new QueryException(defaultQuery.getQueryCanceledException().getMessage(), e.getCause());
        }
        writeQueryResponseException(msg, e, servConn);
        return false;
    } finally {
    // Since the query object is being shared in case of bind queries,
    // resetting the flag may cause inconsistency.
    // Also since this flag is only being set in code path executed by
    // remote query execution, resetting it is not required.
    // ((DefaultQuery)query).setRemoteQuery(false);
    }
    if (logger.isDebugEnabled()) {
        logger.debug("{}: Sent query response for query {}", servConn.getName(), queryString);
    }
    stats.incWriteQueryResponseTime(DistributionStats.getStatTime() - start);
    return true;
}
Also used : DistributedSystemDisconnectedException(org.apache.geode.distributed.DistributedSystemDisconnectedException) DefaultQuery(org.apache.geode.cache.query.internal.DefaultQuery) RegionDestroyedException(org.apache.geode.cache.RegionDestroyedException) QueryInvalidException(org.apache.geode.cache.query.QueryInvalidException) AuthorizeRequestPP(org.apache.geode.internal.security.AuthorizeRequestPP) RegionDestroyedException(org.apache.geode.cache.RegionDestroyedException) DistributedSystemDisconnectedException(org.apache.geode.distributed.DistributedSystemDisconnectedException) QueryInvalidException(org.apache.geode.cache.query.QueryInvalidException) IOException(java.io.IOException) QueryException(org.apache.geode.cache.query.QueryException) CachedRegionHelper(org.apache.geode.internal.cache.tier.CachedRegionHelper) QueryException(org.apache.geode.cache.query.QueryException) SelectResults(org.apache.geode.cache.query.SelectResults) CollectionTypeImpl(org.apache.geode.cache.query.internal.types.CollectionTypeImpl) CollectionType(org.apache.geode.cache.query.types.CollectionType) Iterator(java.util.Iterator) StructTypeImpl(org.apache.geode.cache.query.internal.types.StructTypeImpl) Collection(java.util.Collection)

Aggregations

CollectionType (org.apache.geode.cache.query.types.CollectionType)7 Iterator (java.util.Iterator)6 ObjectType (org.apache.geode.cache.query.types.ObjectType)5 Set (java.util.Set)4 SelectResults (org.apache.geode.cache.query.SelectResults)4 Collection (java.util.Collection)2 QueryInvalidException (org.apache.geode.cache.query.QueryInvalidException)2 Struct (org.apache.geode.cache.query.Struct)2 IOException (java.io.IOException)1 List (java.util.List)1 RegionDestroyedException (org.apache.geode.cache.RegionDestroyedException)1 Query (org.apache.geode.cache.query.Query)1 QueryException (org.apache.geode.cache.query.QueryException)1 TypeMismatchException (org.apache.geode.cache.query.TypeMismatchException)1 DefaultQuery (org.apache.geode.cache.query.internal.DefaultQuery)1 StructSet (org.apache.geode.cache.query.internal.StructSet)1 CollectionTypeImpl (org.apache.geode.cache.query.internal.types.CollectionTypeImpl)1 ObjectTypeImpl (org.apache.geode.cache.query.internal.types.ObjectTypeImpl)1 StructTypeImpl (org.apache.geode.cache.query.internal.types.StructTypeImpl)1 DistributedSystemDisconnectedException (org.apache.geode.distributed.DistributedSystemDisconnectedException)1