int OGRFeatureQuery::CanUseIndex( OGRLayer *poLayer ) { swq_expr_node *psExpr = (swq_expr_node *) pSWQExpr; /* -------------------------------------------------------------------- */ /* Do we have an index on the targetted layer? */ /* -------------------------------------------------------------------- */ if ( poLayer->GetIndex() == FALSE ) return FALSE; return CanUseIndex( psExpr, poLayer ); }
int OGRFeatureQuery::CanUseIndex( swq_expr_node *psExpr, OGRLayer *poLayer ) { OGRAttrIndex *poIndex; /* -------------------------------------------------------------------- */ /* Does the expression meet our requirements? */ /* -------------------------------------------------------------------- */ if( psExpr == NULL || psExpr->eNodeType != SNT_OPERATION ) return FALSE; if ((psExpr->nOperation == SWQ_OR || psExpr->nOperation == SWQ_AND) && psExpr->nSubExprCount == 2) { return CanUseIndex( psExpr->papoSubExpr[0], poLayer ) && CanUseIndex( psExpr->papoSubExpr[1], poLayer ); } if( !(psExpr->nOperation == SWQ_EQ || psExpr->nOperation == SWQ_IN) || psExpr->nSubExprCount < 2 ) return FALSE; swq_expr_node *poColumn = psExpr->papoSubExpr[0]; swq_expr_node *poValue = psExpr->papoSubExpr[1]; if( poColumn->eNodeType != SNT_COLUMN || poValue->eNodeType != SNT_CONSTANT ) return FALSE; poIndex = poLayer->GetIndex()->GetFieldIndex( poColumn->field_index ); if( poIndex == NULL ) return FALSE; /* -------------------------------------------------------------------- */ /* OK, we have an index */ /* -------------------------------------------------------------------- */ return TRUE; }
TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context, const TRI_vector_pointer_t* const availableIndexes, const char* const collectionName, const TRI_vector_pointer_t* candidates) { TRI_aql_index_t* picked = NULL; TRI_vector_pointer_t matches; size_t i, n; TRI_InitVectorPointer(&matches, TRI_UNKNOWN_MEM_ZONE); assert(context); assert(collectionName); assert(candidates); n = availableIndexes->_length; for (i = 0; i < n; ++i) { TRI_index_t* idx = (TRI_index_t*) availableIndexes->_buffer[i]; size_t numIndexFields; bool lastTypeWasExact; size_t j; if (! CanUseIndex(idx)) { continue; } LogIndexString("checking", idx, collectionName); TRI_ClearVectorPointer(&matches); lastTypeWasExact = true; numIndexFields = idx->_fields._length; // now loop over all index fields, from left to right // index field order is important because skiplists can be used with leftmost prefixes as well, // but not with rightmost prefixes for (j = 0; j < numIndexFields; ++j) { char* indexedFieldName; char* fieldName; size_t k; indexedFieldName = idx->_fields._buffer[j]; if (indexedFieldName == NULL) { continue; } // now loop over all candidates for (k = 0; k < candidates->_length; ++k) { TRI_aql_field_access_t* candidate = (TRI_aql_field_access_t*) TRI_AtVectorPointer(candidates, k); if (candidate->_type == TRI_AQL_ACCESS_IMPOSSIBLE || candidate->_type == TRI_AQL_ACCESS_ALL) { // wrong index type, doesn't help us at all continue; } fieldName = candidate->_fullName + candidate->_variableNameLength + 1; if (idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX) { // primary index key names must be treated differently. _id and _key are the same if (! TRI_EqualString("_id", fieldName) && ! TRI_EqualString(TRI_VOC_ATTRIBUTE_KEY, fieldName)) { continue; } } else if (idx->_type == TRI_IDX_TYPE_EDGE_INDEX) { // edge index key names must be treated differently. _from and _to can be used independently if (! TRI_EqualString(TRI_VOC_ATTRIBUTE_FROM, fieldName) && ! TRI_EqualString(TRI_VOC_ATTRIBUTE_TO, fieldName)) { continue; } } else if (! TRI_EqualString(indexedFieldName, fieldName)) { // different attribute, doesn't help continue; } // attribute is used in index if (idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX || idx->_type == TRI_IDX_TYPE_EDGE_INDEX) { if (! IsExactCandidate(candidate)) { // wrong access type for primary index continue; } TRI_PushBackVectorPointer(&matches, candidate); } else if (idx->_type == TRI_IDX_TYPE_HASH_INDEX) { if (! IsExactCandidate(candidate)) { // wrong access type for hash index continue; } if (candidate->_type == TRI_AQL_ACCESS_LIST && numIndexFields != 1) { // we found a list, but the index covers multiple attributes. that means we cannot use list access continue; } TRI_PushBackVectorPointer(&matches, candidate); } else if (idx->_type == TRI_IDX_TYPE_BITARRAY_INDEX) { if (! IsExactCandidate(candidate)) { // wrong access type for hash index continue; } if (candidate->_type == TRI_AQL_ACCESS_LIST) { // we found a list, but the index covers multiple attributes. that means we cannot use list access continue; } TRI_PushBackVectorPointer(&matches, candidate); } else if (idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) { bool candidateIsExact; if (candidate->_type != TRI_AQL_ACCESS_EXACT && candidate->_type != TRI_AQL_ACCESS_LIST && candidate->_type != TRI_AQL_ACCESS_RANGE_SINGLE && candidate->_type != TRI_AQL_ACCESS_RANGE_DOUBLE && candidate->_type != TRI_AQL_ACCESS_REFERENCE) { // wrong access type for skiplists continue; } if (candidate->_type == TRI_AQL_ACCESS_LIST && numIndexFields != 1) { // we found a list, but the index covers multiple attributes. that means we cannot use list access continue; } candidateIsExact = IsExactCandidate(candidate); if ((candidateIsExact && ! lastTypeWasExact) || (! candidateIsExact && ! lastTypeWasExact)) { // if we already had a range query, we cannot check for equality after that // if we already had a range query, we cannot check another range after that continue; } if (candidate->_type == TRI_AQL_ACCESS_RANGE_SINGLE) { // range type. check if the compare value is a list or an object TRI_json_t* value = candidate->_value._singleRange._value; if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { // list or object, we cannot use this for comparison in a skiplist continue; } } else if (candidate->_type == TRI_AQL_ACCESS_RANGE_DOUBLE) { // range type. check if the compare value is a list or an object TRI_json_t* value = candidate->_value._between._lower._value; if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { // list or object, we cannot use this for comparison in a skiplist continue; } value = candidate->_value._between._upper._value; if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { // list or object, we cannot use this for comparison in a skiplist continue; } } lastTypeWasExact = candidateIsExact; TRI_PushBackVectorPointer(&matches, candidate); } } // finished iterating over all candidates if (matches._length != j + 1) { // we already have picked less candidate fields than we should break; } } if (matches._length < 1) { // nothing found continue; } // we now do or don't have an index candidate in the matches vector if (matches._length < numIndexFields && TRI_NeedsFullCoverageIndex(idx->_type)) { // the matches vector does not fully cover the indexed fields, but the index requires it continue; } // if we can use the primary index, we'll use it picked = PickIndex(context, picked, idx, &matches); } TRI_DestroyVectorPointer(&matches); if (picked) { LogIndexString("using", picked->_idx, collectionName); } return picked; }