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; } } }
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; } }
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; }
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; }
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; } }
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; }