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;
        }
    }
}
예제 #2
0
static TRI_aql_node_t* OptimiseConstantFilter (TRI_aql_node_t* const node) {
  if (TRI_GetBooleanNodeValueAql(node)) {
    // filter expression is always true => remove it
    LOG_TRACE("optimised away constant (true) filter");

    return TRI_GetDummyNopNodeAql();
  }

  // filter expression is always false => invalidate surrounding scope(s)
  LOG_TRACE("optimised away scope"); 

  return TRI_GetDummyReturnEmptyNodeAql();
}
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;
    }
}
예제 #4
0
static TRI_aql_node_t* OptimiseSort (TRI_aql_statement_walker_t* const walker,
                                     TRI_aql_node_t* node) {
  TRI_aql_node_t* list = TRI_AQL_NODE_MEMBER(node, 0);
  size_t i, n;
    
  if (!list) {
    return node;
  }

  i = 0;
  n = list->_members._length;
  while (i < n) {
    // sort element
    TRI_aql_node_t* element = TRI_AQL_NODE_MEMBER(list, i);
    TRI_aql_node_t* expression = TRI_AQL_NODE_MEMBER(element, 0);

    // check if the sort element is constant
    if (!expression || !TRI_IsConstantValueNodeAql(expression)) {
      ++i;
      continue;
    }

    // sort element is constant so it can be removed
    TRI_RemoveVectorPointer(&list->_members, i);
    --n;

    LOG_TRACE("optimised away sort element");
  }

  if (n == 0) {
    // no members left => sort removed
    LOG_TRACE("optimised away sort");

    return TRI_GetDummyNopNodeAql();
  }

  return node;
}
예제 #5
0
size_t TRI_InvalidateStatementListAql (TRI_aql_statement_list_t* const list,
                                       const size_t position) {
  size_t i, n;
  size_t start;
  size_t scopes;
  size_t ignoreScopes;

  assert(list);
  assert(position >= 0);
  n = list->_statements._length;

  // walk the scope from the specified position backwards until we find the start of the scope
  scopes = 1;
  ignoreScopes = 0;
  i = position;
  while (true) {
    TRI_aql_node_t* node = StatementAt(list, i);
    TRI_aql_node_type_e type = node->_type;

    list->_statements._buffer[i] = TRI_GetDummyNopNodeAql();
    start = i;

    if (type == TRI_AQL_NODE_SCOPE_START) {
      // node is a scope start
      TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AQL_NODE_DATA(node);

      if (ignoreScopes > 0) {
        // this is an inner, parallel scope that we can ignore
        --ignoreScopes;
      }
      else {
        if (scope->_type != TRI_AQL_SCOPE_FOR_NESTED) {
          // we have reached the scope and need to stop
          break;
        }
        scopes++;
      }
    }
    else if (type == TRI_AQL_NODE_SCOPE_END) {
      // we found the end of another scope
      // we must remember how many other scopes we passed
      ignoreScopes++;
    }

    if (i-- == 0) {
      break;
    }
  }

  assert(ignoreScopes == 0);

  // remove from position forwards to scope end
  i = position;
  while (true) {
    TRI_aql_node_t* node = StatementAt(list, i);
    TRI_aql_node_type_e type = node->_type;
    
    list->_statements._buffer[i] = TRI_GetDummyNopNodeAql();

    if (type == TRI_AQL_NODE_SCOPE_START) {
      ++scopes;
    }
    else if (type == TRI_AQL_NODE_SCOPE_END) {
      assert(scopes > 0);
      if (--scopes == 0) {
        break;
      }
    }

    if (++i == n) {
      break;
    }
  }
  
  list->_statements._buffer[start] = TRI_GetDummyReturnEmptyNodeAql();

  return start + 1;
}
예제 #6
0
void TRI_PulloutStatementListAql (TRI_aql_statement_list_t* const list) {
  size_t i, n;
  size_t scopes = 0;
  size_t targetScope = 0;
  size_t moveStart = 0;
  bool watch = false;

  assert(list);

  i = 0;
  n = list->_statements._length;
  
  while (i < n) {
    TRI_aql_node_t* node = StatementAt(list, i);
    TRI_aql_node_type_e type = node->_type;
    
    if (type == TRI_AQL_NODE_SCOPE_START) {
      // node is a scope start
      TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AQL_NODE_DATA(node);
      
      if (scope->_type == TRI_AQL_SCOPE_SUBQUERY && scope->_selfContained) {
        if (! watch && scopes > 0) {
          watch = true;
          targetScope = scopes;
          moveStart = i;
        }
      }
      
      ++scopes;
    }
    else if (type == TRI_AQL_NODE_SCOPE_END) {
      // node is a scope end
      --scopes;

      if (watch && scopes == targetScope) {
        watch = false;

        node = StatementAt(list, i + 1);

        // check if next statement is a subquery statement
        if (i + 1 < n && node->_type == TRI_AQL_NODE_SUBQUERY) {
          size_t j = moveStart;
          size_t inserted = 0;

          // moving statements from the middle to the beginning of the list will also 
          // modify the positions we're moving from
          while (j < i + 2) {
            node = StatementAt(list, j + inserted);
            if (! TRI_InsertStatementListAql(list, node, inserted + 0)) {
              return;
            }

            // insert a dummy node in place of the moved node 
            list->_statements._buffer[j + inserted + 1] = TRI_GetDummyNopNodeAql();

            // next
            ++j;
            ++inserted;
          }

          // moving statements from the middle to the beginning of the list will also 
          // change the list length and the position we'll be continuing from
          n += inserted;
          i = j + inserted;
        }

      }
    }

    ++i;
  }
}
예제 #7
0
size_t TRI_InvalidateStatementListAql (TRI_aql_statement_list_t* const list,
                                       const size_t position) {
  size_t i, n;
  size_t start;
  size_t scopes;

  assert(list);
  assert(position >= 0);
  n = list->_statements._length;

  // remove from position backwards to scope start
  scopes = 1;
  i = position;
  while (true) {
    TRI_aql_node_t* node = StatementAt(list, i);
    TRI_aql_node_type_e type = node->_type;

    list->_statements._buffer[i] = TRI_GetDummyNopNodeAql();
    start = i;

    if (type == TRI_AQL_NODE_SCOPE_START) {
      TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AQL_NODE_DATA(node);

      if (scope->_type != TRI_AQL_SCOPE_FOR_NESTED) {
        break;
      }
      scopes++;
    }

    if (i-- == 0) {
      break;
    }
  }

  // remove from position forwards to scope end
  i = position;
  while (true) {
    TRI_aql_node_t* node = StatementAt(list, i);
    TRI_aql_node_type_e type = node->_type;
    
    list->_statements._buffer[i] = TRI_GetDummyNopNodeAql();

    if (type == TRI_AQL_NODE_SCOPE_START) {
      ++scopes;
    }
    else if (type == TRI_AQL_NODE_SCOPE_END) {
      assert(scopes > 0);
      if (--scopes == 0) {
        break;
      }
    }

    if (++i == n) {
      break;
    }
  }
  
  list->_statements._buffer[start] = TRI_GetDummyReturnEmptyNodeAql();

  return start + 1;
}