예제 #1
0
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 );
}
예제 #2
0
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;
}
예제 #3
0
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;
}