示例#1
0
static void FreeScope (TRI_aql_scope_t* const scope) {
  size_t i, n;

  // free variables lookup hash
  n = scope->_variables._nrAlloc;
  for (i = 0; i < n; ++i) {
    TRI_aql_variable_t* variable = scope->_variables._table[i];

    if (variable) {
      TRI_FreeVariableAql(variable);
    }
  }

  TRI_DestroyAssociativePointer(&scope->_variables);

  if (scope->_ranges) {
    // free ranges if set
    TRI_FreeAccessesAql(scope->_ranges);
  }

  for (i = 0; i < scope->_sorts._length; ++i) {
    char* criterion = (char*) TRI_AtVectorPointer(&scope->_sorts, i);

    TRI_Free(TRI_UNKNOWN_MEM_ZONE, criterion);
  }

  TRI_DestroyVectorPointer(&scope->_sorts);

  TRI_Free(TRI_UNKNOWN_MEM_ZONE, scope);
}
示例#2
0
bool TRI_VariableExistsScopeAql (TRI_aql_context_t* const context,
                                 const char* const name) {
  size_t n;

  if (name == NULL) {
    TRI_SetErrorContextAql(__FILE__, __LINE__, context, TRI_ERROR_OUT_OF_MEMORY, NULL);
    return false;
  }

  n = context->_currentScopes._length;
  assert(n > 0);

  while (n > 0) {
    TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AtVectorPointer(&context->_currentScopes, --n);
    assert(scope);

    if (TRI_LookupByKeyAssociativePointer(&scope->_variables, (void*) name)) {
      // duplicate variable
      return true;
    }

    if (n == 0) {
      // reached the outermost scope
      break;
    }
  }

  return false;
}
static void VisitMembers (TRI_aql_statement_walker_t* const walker,
                          TRI_aql_node_t* const node) {
    size_t i, n;

    assert(node);

    n = node->_members._length;
    for (i = 0; i < n; ++i) {
        TRI_aql_node_t* member;
        TRI_aql_node_t* modified;

        member = (TRI_aql_node_t*) TRI_AtVectorPointer(&node->_members, i);

        if (!member) {
            continue;
        }

        VisitMembers(walker, member);

        modified = walker->visitMember(walker, member);
        if (walker->_canModify && modified != member) {
            if (modified == NULL) {
                modified = TRI_GetDummyNopNodeAql();
            }

            node->_members._buffer[i] = modified;
        }
    }
}
示例#4
0
bool TRI_KillExternalProcess (TRI_external_id_t pid) {
  TRI_external_t* external = nullptr;  // just to please the compiler
  size_t i;
  bool ok = true;

  LOG_DEBUG("killing process: %d", (int) pid._pid);

  TRI_LockMutex(&ExternalProcessesLock);

  for (i = 0;  i < ExternalProcesses._length;  ++i) {
    external = static_cast<TRI_external_t*>(TRI_AtVectorPointer(&ExternalProcesses, i));

    if (external->_pid == pid._pid) {
      break;
    }
  }

  if (i == ExternalProcesses._length) {
    TRI_UnlockMutex(&ExternalProcessesLock);
    LOG_DEBUG("kill: process not found: %d", (int) pid._pid);
#ifndef _WIN32
    // Kill just in case:
    if (0 == kill(pid._pid, SIGTERM)) {
      int count;

      // Otherwise we just let it be.
      for (count = 0; count < 10; count++) {
        int loc;
        pid_t p;

        // And wait for it to avoid a zombie:
        sleep(1);
        p = waitpid(pid._pid, &loc, WUNTRACED | WNOHANG);
        if (p == pid._pid) {
          return true;
        }
        if (count == 8) {
          kill(pid._pid, SIGKILL);
        }
      }
    }
    return false;
#else
    return ourKillProcessPID(pid._pid);
#endif
  }

  if (external->_status == TRI_EXT_RUNNING ||
      external->_status == TRI_EXT_STOPPED) {
    ok = ourKillProcess(external);
  }

  TRI_RemoveVectorPointer(&ExternalProcesses, i);
  TRI_UnlockMutex(&ExternalProcessesLock);
  FreeExternal(external);

  return ok;
}
TRI_aql_scope_t* TRI_GetCurrentScopeStatementWalkerAql (TRI_aql_statement_walker_t* const walker) {
    size_t n;

    assert(walker);
    n = walker->_currentScopes._length;

    assert(n > 0);

    return (TRI_aql_scope_t*) TRI_AtVectorPointer(&walker->_currentScopes, n - 1);
}
示例#6
0
static inline TRI_aql_scope_t* CurrentScope (TRI_aql_context_t* const context) {
  TRI_aql_scope_t* scope;
  size_t n;

  assert(context);

  n = context->_currentScopes._length;
  assert(n > 0);

  scope = (TRI_aql_scope_t*) TRI_AtVectorPointer(&context->_currentScopes, n - 1);
  assert(scope);

  return scope;
}
static void RunWalk (TRI_aql_statement_walker_t* const walker) {
    size_t i, n;

    assert(walker);
    n = walker->_statements->_statements._length;

    for (i = 0; i < n; ++i) {
        TRI_aql_node_t* node;
        TRI_aql_node_type_e nodeType;

        node = (TRI_aql_node_t*) TRI_AtVectorPointer(&walker->_statements->_statements, i);

        if (!node) {
            continue;
        }

        nodeType = node->_type;

        // handle scopes
        if (nodeType == TRI_AQL_NODE_SCOPE_START) {
            TRI_PushBackVectorPointer(&walker->_currentScopes, TRI_AQL_NODE_DATA(node));
        }

        // preprocess node
        if (walker->preVisitStatement != NULL) {
            // this might change the node ptr
            VisitStatement(walker, i, walker->preVisitStatement);
            node = walker->_statements->_statements._buffer[i];
        }


        // process node's members
        if (walker->visitMember != NULL) {
            VisitMembers(walker, node);
        }

        // post process node
        if (walker->postVisitStatement != NULL) {
            VisitStatement(walker, i, walker->postVisitStatement);
        }

        if (nodeType == TRI_AQL_NODE_SCOPE_END) {
            size_t len = walker->_currentScopes._length;

            assert(len > 0);
            TRI_RemoveVectorPointer(&walker->_currentScopes, len - 1);
        }
    }
}
示例#8
0
void TRI_FreeScopesAql (TRI_aql_context_t* const context) {
  size_t i, n;

  assert(context);

  n = context->_memory._scopes._length;
  for (i = 0; i < n; ++i) {
    TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AtVectorPointer(&context->_memory._scopes, i);

    FreeScope(scope);
  }

  TRI_DestroyVectorPointer(&context->_memory._scopes);
  TRI_DestroyVectorPointer(&context->_currentScopes);
}
示例#9
0
TRI_aql_collection_t* TRI_GetCollectionAql (const TRI_aql_context_t* const context,
                                            const char* const collectionName) {
  size_t i, n;

  assert(context);

  n = context->_collections._length;
  for (i = 0; i < n; ++i) {
    TRI_aql_collection_t* col = (TRI_aql_collection_t*) TRI_AtVectorPointer(&context->_collections, i);

    if (TRI_EqualString(col->_name, collectionName)) {
      return col;
    }
  }

  return NULL;
}
static void VisitStatement (TRI_aql_statement_walker_t* const walker,
                            const size_t position,
                            TRI_aql_visit_f func) {
    TRI_aql_node_t* node;
    TRI_aql_node_t* modified;

    node = (TRI_aql_node_t*) TRI_AtVectorPointer(&walker->_statements->_statements, position);
    assert(node);

    modified = func(walker, node);
    if (walker->_canModify && modified != node) {
        if (modified == NULL) {
            modified = TRI_GetDummyNopNodeAql();
        }

        walker->_statements->_statements._buffer[position] = modified;
    }
}
TRI_aql_variable_t* TRI_GetVariableStatementWalkerAql (TRI_aql_statement_walker_t* const walker,
        const char* const name,
        size_t* scopeCount) {
    size_t n;

    // init scope counter to 0
    *scopeCount = 0;

    assert(name != NULL);

    n = walker->_currentScopes._length;
    while (n > 0) {
        TRI_aql_scope_t* scope;
        TRI_aql_variable_t* variable;

        scope = (TRI_aql_scope_t*) TRI_AtVectorPointer(&walker->_currentScopes, --n);
        assert(scope);

        variable = TRI_LookupByKeyAssociativePointer(&scope->_variables, (void*) name);
        if (variable != NULL) {
            return variable;
        }

        if (n == 0 || scope->_type == TRI_AQL_SCOPE_SUBQUERY) {
            // reached the outermost scope
            if (scope->_type == TRI_AQL_SCOPE_SUBQUERY) {
                // variable not found but we reached the end of the scope
                // we must mark the scope as not self-contained so it is not moved to
                // some other position

                scope->_selfContained = false;
            }
            return NULL;
        }

        // increase the scope counter
        (*scopeCount)++;
    }

    // variable not found
    return NULL;
}
示例#12
0
static bool IterateDatafilesVector (const TRI_vector_pointer_t* const files,
                                    bool (*iterator)(TRI_df_marker_t const*, void*, TRI_datafile_t*, bool),
                                    void* data) {
  size_t i, n;

  n = files->_length;
  for (i = 0;  i < n;  ++i) {
    TRI_datafile_t* datafile;
    int result;

    datafile = (TRI_datafile_t*) TRI_AtVectorPointer(files, i);
    result = TRI_IterateDatafile(datafile, iterator, data, false);

    if (! result) {
      return false;
    }
  }

  return true;
}
void TRI_EmptyScopeStatementWalkerAql (TRI_aql_statement_walker_t* const walker) {
  size_t n = walker->_currentScopes._length;

  while (n > 0) {
    TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AtVectorPointer(&walker->_currentScopes, n - 1);

    if (scope->_type == TRI_AQL_SCOPE_SUBQUERY) {
      break; 
    }
    
    scope->_empty = true;

    if (scope->_type != TRI_AQL_SCOPE_FOR && 
        scope->_type != TRI_AQL_SCOPE_FOR_NESTED && 
        scope->_type != TRI_AQL_SCOPE_MAIN) {
      break;
    }

    --n;
  }
}
示例#14
0
static TRI_multi_pointer_t* FindEdgesIndex (TRI_document_collection_t* const document) {
  size_t i, n;

  if (document->base.base._info._type != TRI_COL_TYPE_EDGE) {
    // collection is not an edge collection... caller must handle that
    return NULL;
  }

  n = document->_allIndexes._length;
  for (i = 0; i < n; ++i) {
    TRI_index_t* idx = (TRI_index_t*) TRI_AtVectorPointer(&document->_allIndexes, i);
    if (idx->_type == TRI_IDX_TYPE_EDGE_INDEX) {
      TRI_edge_index_t* edgesIndex = (TRI_edge_index_t*) idx;

      return &edgesIndex->_edges;
    }
  }

  // collection does not have an edges index... caller must handle that
  return NULL;
}
示例#15
0
static void PatchVariables (TRI_aql_statement_walker_t* const walker) {
  TRI_aql_context_t* context = ((aql_optimiser_t*) walker->_data)->_context;
  TRI_vector_pointer_t* ranges;
  size_t i, n;

  ranges = TRI_GetCurrentRangesStatementWalkerAql(walker);
  if (ranges == NULL) {
    // no ranges defined, exit early
    return;
  }

  // iterate over all ranges found
  n = ranges->_length;
  for (i = 0; i < n; ++i) {
    TRI_aql_field_access_t* fieldAccess;
    TRI_aql_variable_t* variable;
    TRI_aql_node_t* definingNode;
    TRI_aql_node_t* expressionNode;
    char* variableName;
    size_t scopeCount;
    bool isReference;

    fieldAccess = (TRI_aql_field_access_t*) TRI_AtVectorPointer(ranges, i);
    assert(fieldAccess);
    assert(fieldAccess->_fullName);
    assert(fieldAccess->_variableNameLength > 0);

    variableName = TRI_DuplicateString2Z(TRI_UNKNOWN_MEM_ZONE, fieldAccess->_fullName, fieldAccess->_variableNameLength);
    if (variableName == NULL) {
      // out of memory!
      TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
      return;
    }

    isReference = (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE);

    variable = TRI_GetVariableStatementWalkerAql(walker, variableName, &scopeCount);
    TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, variableName);

    if (variable == NULL) {
      continue;
    }

    if (isReference && scopeCount > 0) {
      // unfortunately, the referenced variable is in an outer scope, so we cannot use it
      continue;
    }

    // note: we must not modify outer variables of subqueries 

    // get the node that defines the variable
    definingNode = variable->_definingNode;

    assert(definingNode != NULL);

    expressionNode = NULL;
    switch (definingNode->_type) {
      case TRI_AQL_NODE_LET:
        expressionNode = TRI_AQL_NODE_MEMBER(definingNode, 1);
        break;
      case TRI_AQL_NODE_FOR:
        expressionNode = TRI_AQL_NODE_MEMBER(definingNode, 1);
        break;
      default: {
      }
    }

    if (expressionNode != NULL) {
      if (expressionNode->_type == TRI_AQL_NODE_FCALL) {
        // the defining node is a function call
        // get the function name
        TRI_aql_function_t* function = TRI_AQL_NODE_DATA(expressionNode);

        if (function->optimise != NULL) {
          // call the function's optimise callback
          function->optimise(expressionNode, context, fieldAccess);
        }
      }

      if (expressionNode->_type == TRI_AQL_NODE_COLLECTION) {
        TRI_aql_collection_hint_t* hint = (TRI_aql_collection_hint_t*) (TRI_AQL_NODE_DATA(expressionNode));

        // set new value
        hint->_ranges = TRI_AddAccessAql(context, hint->_ranges, fieldAccess);
      }
    }
  } 
}
示例#16
0
TRI_external_status_t TRI_CheckExternalProcess (TRI_external_id_t pid,
                                                bool wait) {
  TRI_external_status_t status;
  TRI_external_t* external = nullptr;  // Just to please the compiler
  size_t i;
  
  TRI_LockMutex(&ExternalProcessesLock);

  status._status = TRI_EXT_NOT_FOUND;
  status._exitStatus = 0;

  for (i = 0;  i < ExternalProcesses._length;  ++i) {
    external = static_cast<TRI_external_t*>(TRI_AtVectorPointer(&ExternalProcesses, i));

    if (external->_pid == pid._pid) {
      break;
    }
  }

  if (i == ExternalProcesses._length) {
    TRI_UnlockMutex(&ExternalProcessesLock);
    status._errorMessage =
      std::string("the pid you're looking for is not in our list: ") + 
      triagens::basics::StringUtils::itoa(static_cast<int64_t>(pid._pid));
    status._status = TRI_EXT_NOT_FOUND;
    LOG_WARNING("checkExternal: pid not found: %d", (int) pid._pid);

    return status;
  }

  if (external->_status == TRI_EXT_RUNNING ||
      external->_status == TRI_EXT_STOPPED) {
#ifndef _WIN32
    TRI_pid_t res;
    int opts;
    int loc = 0;

    if (wait) {
      opts = WUNTRACED;
    }
    else {
      opts = WNOHANG | WUNTRACED;
    }

    res = waitpid(external->_pid, &loc, opts);

    if (res == 0) {
      if (wait) {
        status._errorMessage =
          std::string("waitpid returned 0 for pid while it shouldn't ") + 
          triagens::basics::StringUtils::itoa(external->_pid);

        if (WIFEXITED(loc)) {
          external->_status = TRI_EXT_TERMINATED;
          external->_exitStatus = WEXITSTATUS(loc);
        }
        else if (WIFSIGNALED(loc)) {
          external->_status = TRI_EXT_ABORTED;
          external->_exitStatus = WTERMSIG(loc);
        }
        else if (WIFSTOPPED(loc)) {
          external->_status = TRI_EXT_STOPPED;
          external->_exitStatus = 0;
        }
        else {
          external->_status = TRI_EXT_ABORTED;
          external->_exitStatus = 0;
        }
      }
      else {
        external->_exitStatus = 0;
      }
    }
    else if (res == -1) {
      TRI_set_errno(TRI_ERROR_SYS_ERROR);
      LOG_WARNING("waitpid returned error for pid %d (%d): %s", 
                  (int) external->_pid,  
                  (int) wait,
                  TRI_last_error());
      status._errorMessage =
        std::string("waitpid returned error for pid ") + 
        triagens::basics::StringUtils::itoa(external->_pid) + 
        std::string(": ") +        
        std::string(TRI_last_error());
    }
    else if (static_cast<TRI_pid_t>(external->_pid) == static_cast<TRI_pid_t>(res)) {
      if (WIFEXITED(loc)) {
        external->_status = TRI_EXT_TERMINATED;
        external->_exitStatus = WEXITSTATUS(loc);
      }
      else if (WIFSIGNALED(loc)) {
        external->_status = TRI_EXT_ABORTED;
        external->_exitStatus = WTERMSIG(loc);
      }
      else if (WIFSTOPPED(loc)) {
        external->_status = TRI_EXT_STOPPED;
        external->_exitStatus = 0;
      }
      else {
        external->_status = TRI_EXT_ABORTED;
        external->_exitStatus = 0;
      }
    }
    else {
      LOG_WARNING("unexpected waitpid result for pid %d: %d", 
                  (int) external->_pid, 
                  (int) res);
      status._errorMessage =
        std::string("unexpected waitpid result for pid ") + 
        triagens::basics::StringUtils::itoa(external->_pid) + 
        std::string(": ") +
        triagens::basics::StringUtils::itoa(res);
    }
#else
    {
      char windowsErrorBuf[256];
      bool wantGetExitCode = wait;
      if (wait) {
        DWORD result;
        result = WaitForSingleObject(external->_process, INFINITE);
        if (result == WAIT_FAILED) {
          FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                        NULL,
                        GetLastError(),
                        0,
                        windowsErrorBuf,
                        sizeof(windowsErrorBuf), NULL);
          LOG_WARNING("could not wait for subprocess with PID '%ud': %s",
                      (unsigned int) external->_pid, windowsErrorBuf);
          status._errorMessage =
            std::string("could not wait for subprocess with PID '") + 
            triagens::basics::StringUtils::itoa(static_cast<int64_t>(external->_pid)) + 
            std::string("'") + 
            windowsErrorBuf;
          status._exitStatus = GetLastError();
        }
      }
      else {
        DWORD result;
        result = WaitForSingleObject(external->_process, 0);
        switch (result) {
        case WAIT_ABANDONED:
          wantGetExitCode = true;
          LOG_WARNING("WAIT_ABANDONED while waiting for subprocess with PID '%ud'",
                      (unsigned int)external->_pid);
          break;
        case WAIT_OBJECT_0:
          /// this seems to be the exit case - want getExitCodeProcess here.
          wantGetExitCode = true;
          break;
        case WAIT_TIMEOUT:
          // success - everything went well.
          external->_exitStatus = 0;
          break;
        case WAIT_FAILED:
          FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                        NULL,
                        GetLastError(),
                        0,
                        windowsErrorBuf,
                        sizeof(windowsErrorBuf), NULL);
          LOG_WARNING("could not wait for subprocess with PID '%ud': %s",
                      (unsigned int)external->_pid, windowsErrorBuf);
          status._errorMessage =
            std::string("could not wait for subprocess with PID '") +
            triagens::basics::StringUtils::itoa(static_cast<int64_t>(external->_pid)) +
            std::string("'") +
            windowsErrorBuf;
          status._exitStatus = GetLastError();
        default:
          wantGetExitCode = true;
          LOG_WARNING("unexpected status while waiting for subprocess with PID '%ud'",
                      (unsigned int)external->_pid);

        }
      }
      if (wantGetExitCode) {
        DWORD exitCode = STILL_ACTIVE;
        if (!GetExitCodeProcess(external->_process, &exitCode)) {
          LOG_WARNING("exit status could not be determined for PID '%ud'",
                      (unsigned int)external->_pid);
          status._errorMessage =
            std::string("exit status could not be determined for PID '") +
            triagens::basics::StringUtils::itoa(static_cast<int64_t>(external->_pid)) +
            std::string("'");
        }
        else {
          if (exitCode == STILL_ACTIVE) {
            external->_exitStatus = 0;
          }
          else if (exitCode > 255) {
            // this should be one of our signals which we mapped...
            external->_status = TRI_EXT_ABORTED;
            external->_exitStatus = exitCode - 255;            
          }
          else {
            external->_status = TRI_EXT_TERMINATED;
            external->_exitStatus = exitCode;
          }
        }
      }
      else
      {
        external->_status = TRI_EXT_RUNNING;
      }
    }
#endif
  }
  else {
    LOG_WARNING("unexpected process status %d: %d", 
                (int) external->_status, 
                (int) external->_exitStatus);
    status._errorMessage =
      std::string("unexpected process status ") + 
      triagens::basics::StringUtils::itoa(external->_status) + 
      std::string(": ") +
      triagens::basics::StringUtils::itoa(external->_exitStatus);
  }

  status._status = external->_status;
  status._exitStatus = external->_exitStatus;

  // Do we have to free our data?
  if (external->_status != TRI_EXT_RUNNING &&
      external->_status != TRI_EXT_STOPPED) {
    TRI_RemoveVectorPointer(&ExternalProcesses, i);
    FreeExternal(external);
  }

  TRI_UnlockMutex(&ExternalProcessesLock);
  return status;
}
示例#17
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;
}
示例#18
0
static inline TRI_aql_node_t* StatementAt (const TRI_aql_statement_list_t* const list,
                                           const size_t position) {
  return (TRI_aql_node_t*) TRI_AtVectorPointer(&list->_statements, position);
}