Exemplo n.º 1
0
static bool CheckPathRestriction (TRI_aql_field_access_t* fieldAccess,
                                  TRI_aql_context_t* const context,
                                  TRI_aql_node_t* vertexCollection,
                                  const char* lookFor,
                                  char* name,
                                  const size_t n) {
  size_t len;

  assert(fieldAccess);
  assert(lookFor);

  len = strlen(lookFor);
  if (len == 0) {
    return false;
  }

  if (n > fieldAccess->_variableNameLength + len &&
      memcmp((void*) lookFor, (void*) name, len) == 0) {
    // we'll now patch the collection hint
    TRI_aql_collection_hint_t* hint;

    // field name is collection.source.abc, e.g. users.source._id
    LOG_DEBUG("optimising PATHS() field access %s", fieldAccess->_fullName);

    // we can now modify this fieldaccess in place to collection.abc, e.g. users._id
    // copy trailing \0 byte as well
    memmove(name, name + len - 1, n - fieldAccess->_variableNameLength - len + 2);

    // attach the modified fieldaccess to the collection
    hint = (TRI_aql_collection_hint_t*) (TRI_AQL_NODE_DATA(vertexCollection));
    hint->_ranges = TRI_AddAccessAql(context, hint->_ranges, fieldAccess);

    return true;
  }

  return false;
}
Exemplo n.º 2
0
static void OptimisePaths (const TRI_aql_node_t* const fcallNode,
                           TRI_aql_context_t* const context,
                           TRI_aql_field_access_t* fieldAccess) {
  TRI_aql_collection_hint_t* hint;
  TRI_aql_node_t* args;
  TRI_aql_node_t* vertexCollection;
  TRI_aql_node_t* edgeCollection;
  TRI_aql_node_t* direction;
  char* directionValue;
  char* name;
  const char* lookFor;
  size_t len;
  size_t n;
  
  args = TRI_AQL_NODE_MEMBER(fcallNode, 0);

  if (args == NULL) {
    return;
  }

  vertexCollection = TRI_AQL_NODE_MEMBER(args, 0);
  edgeCollection = TRI_AQL_NODE_MEMBER(args, 1);
  direction = TRI_AQL_NODE_MEMBER(args, 2);

  assert(vertexCollection);
  assert(edgeCollection);
  assert(direction);
  assert(fieldAccess);

  n = strlen(fieldAccess->_fullName);
  name = fieldAccess->_fullName + fieldAccess->_variableNameLength;

  directionValue = TRI_AQL_NODE_STRING(direction);

  // try to optimise the vertex collection access
  if (TRI_EqualString(directionValue, "outbound")) {
    lookFor = ".source.";
    len = strlen(lookFor);
  }
  else if (TRI_EqualString(directionValue, "inbound")) {
    lookFor = ".destination.";
    len = strlen(lookFor);
  }
  else {
    lookFor = NULL;
    len = 0;
  }

  if (len > 0 && 
      n > fieldAccess->_variableNameLength + len && 
      memcmp((void*) lookFor, (void*) name, len) == 0) {
    // field name is collection.source.XXX, e.g. users.source._id
    LOG_DEBUG("optimising PATHS() field access %s", fieldAccess->_fullName);
 
    // we can now modify this fieldaccess in place to collection.XXX, e.g. users._id
    // copy trailing \0 byte as well
    memmove(name, name + len - 1, n - fieldAccess->_variableNameLength - len + 2);
    
    // attach the modified fieldaccess to the collection
    hint = (TRI_aql_collection_hint_t*) (TRI_AQL_NODE_DATA(vertexCollection));
    hint->_ranges = TRI_AddAccessAql(context, hint->_ranges, fieldAccess);
  }
}
Exemplo n.º 3
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);
      }
    }
  } 
}