mirror of https://gitee.com/bigwinds/arangodb
issue #248: allow AQL optimiser to pull out completely uncorrelated subqueries to the top level, resulting in less repeated evaluation of the subquery
This commit is contained in:
parent
0499d8b4e2
commit
6d1201b2ec
|
@ -32,6 +32,9 @@ v1.1.beta1 (2012-XX-XX)
|
|||
- if the length of the HTTP headers is greated than the maximum allowed size (1 MB),
|
||||
the server will fail with HTTP 431 (request header fields too large)
|
||||
|
||||
* issue #248: allow AQL optimiser to pull out completely uncorrelated subqueries to the
|
||||
top level, resulting in less repeated evaluation of the subquery
|
||||
|
||||
* upgraded to Doxygen 1.8.0
|
||||
|
||||
* issue #247: added AQL function MERGE_RECURSIVE
|
||||
|
|
|
@ -258,12 +258,12 @@ SHELL_SERVER_AHUACATL = @top_srcdir@/js/server/tests/ahuacatl-ranges.js \
|
|||
@top_srcdir@/js/server/tests/ahuacatl-skiplist.js \
|
||||
@top_srcdir@/js/server/tests/ahuacatl-refaccess-variable.js \
|
||||
@top_srcdir@/js/server/tests/ahuacatl-refaccess-attribute.js \
|
||||
@top_srcdir@/js/server/tests/ahuacatl-skiplist.js \
|
||||
@top_srcdir@/js/server/tests/ahuacatl-queries-simple.js \
|
||||
@top_srcdir@/js/server/tests/ahuacatl-queries-variables.js \
|
||||
@top_srcdir@/js/server/tests/ahuacatl-queries-geo.js \
|
||||
@top_srcdir@/js/server/tests/ahuacatl-queries-collection.js \
|
||||
@top_srcdir@/js/server/tests/ahuacatl-queries-noncollection.js \
|
||||
@top_srcdir@/js/server/tests/ahuacatl-subquery.js \
|
||||
@top_srcdir@/js/server/tests/ahuacatl-operators.js
|
||||
|
||||
SHELL_SERVER_AHUACATL_EXTENDED = \
|
||||
|
|
|
@ -143,11 +143,11 @@ static inline TRI_aql_codegen_scope_t* CurrentScope (TRI_aql_codegen_js_t* const
|
|||
|
||||
static inline bool OutputString (TRI_string_buffer_t* const buffer,
|
||||
const char* const value) {
|
||||
if (!buffer) {
|
||||
if (buffer == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
if (value == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ static inline bool OutputString (TRI_string_buffer_t* const buffer,
|
|||
|
||||
static inline bool OutputChar (TRI_string_buffer_t* const buffer,
|
||||
const char value) {
|
||||
if (!buffer) {
|
||||
if (buffer == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ static inline bool OutputChar (TRI_string_buffer_t* const buffer,
|
|||
|
||||
static inline bool OutputUInt (TRI_string_buffer_t* const buffer,
|
||||
const uint64_t value) {
|
||||
if (!buffer) {
|
||||
if (buffer == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ static inline bool OutputUInt (TRI_string_buffer_t* const buffer,
|
|||
|
||||
static inline bool OutputInt (TRI_string_buffer_t* const buffer,
|
||||
const int64_t value) {
|
||||
if (!buffer) {
|
||||
if (buffer == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ static inline void ScopeOutput (TRI_aql_codegen_js_t* const generator,
|
|||
const char* const value) {
|
||||
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||
|
||||
if (!OutputString(scope->_buffer, value)) {
|
||||
if (! OutputString(scope->_buffer, value)) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ static inline void ScopeOutputInt (TRI_aql_codegen_js_t* const generator,
|
|||
const int64_t value) {
|
||||
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||
|
||||
if (!OutputInt(scope->_buffer, value)) {
|
||||
if (! OutputInt(scope->_buffer, value)) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ static inline void ScopeOutputUInt (TRI_aql_codegen_js_t* const generator,
|
|||
const uint64_t value) {
|
||||
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||
|
||||
if (!OutputUInt(scope->_buffer, value)) {
|
||||
if (! OutputUInt(scope->_buffer, value)) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
@ -240,13 +240,13 @@ static inline void ScopeOutputQuoted (TRI_aql_codegen_js_t* const generator,
|
|||
const char* const value) {
|
||||
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||
|
||||
if (!OutputChar(scope->_buffer, '\'')) {
|
||||
if (! OutputChar(scope->_buffer, '\'')) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (!OutputString(scope->_buffer, value)) {
|
||||
if (! OutputString(scope->_buffer, value)) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (!OutputChar(scope->_buffer, '\'')) {
|
||||
if (! OutputChar(scope->_buffer, '\'')) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
@ -261,13 +261,13 @@ static inline void ScopeOutputQuoted2 (TRI_aql_codegen_js_t* const generator,
|
|||
char* escaped;
|
||||
size_t outLength;
|
||||
|
||||
if (!OutputChar(scope->_buffer, '"')) {
|
||||
if (! OutputChar(scope->_buffer, '"')) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
escaped = TRI_EscapeUtf8StringZ(TRI_UNKNOWN_MEM_ZONE, value, strlen(value), false, &outLength);
|
||||
if (escaped) {
|
||||
if (!OutputString(scope->_buffer, escaped)) {
|
||||
if (! OutputString(scope->_buffer, escaped)) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
|
@ -277,7 +277,7 @@ static inline void ScopeOutputQuoted2 (TRI_aql_codegen_js_t* const generator,
|
|||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (!OutputChar(scope->_buffer, '"')) {
|
||||
if (! OutputChar(scope->_buffer, '"')) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
@ -290,7 +290,7 @@ static inline void ScopeOutputJson (TRI_aql_codegen_js_t* const generator,
|
|||
const TRI_json_t* const json) {
|
||||
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||
|
||||
if (!scope->_buffer) {
|
||||
if (! scope->_buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -321,10 +321,10 @@ static inline void ScopeOutputFunction (TRI_aql_codegen_js_t* const generator,
|
|||
const TRI_aql_codegen_register_t functionIndex) {
|
||||
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||
|
||||
if (!OutputString(scope->_buffer, FUNCTION_PREFIX)) {
|
||||
if (! OutputString(scope->_buffer, FUNCTION_PREFIX)) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (!OutputInt(scope->_buffer, (int64_t) functionIndex)) {
|
||||
if (! OutputInt(scope->_buffer, (int64_t) functionIndex)) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
@ -337,10 +337,10 @@ static inline void ScopeOutputRegister (TRI_aql_codegen_js_t* const generator,
|
|||
const TRI_aql_codegen_register_t registerIndex) {
|
||||
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||
|
||||
if (!OutputString(scope->_buffer, REGISTER_PREFIX)) {
|
||||
if (! OutputString(scope->_buffer, REGISTER_PREFIX)) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (!OutputInt(scope->_buffer, (int64_t) registerIndex)) {
|
||||
if (! OutputInt(scope->_buffer, (int64_t) registerIndex)) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
@ -432,7 +432,7 @@ static void StartScope (TRI_aql_codegen_js_t* const generator,
|
|||
TRI_aql_codegen_scope_t* scope;
|
||||
|
||||
scope = (TRI_aql_codegen_scope_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_codegen_scope_t), false);
|
||||
if (!scope) {
|
||||
if (scope == NULL) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
@ -633,7 +633,7 @@ static void EnterSymbol (TRI_aql_codegen_js_t* const generator,
|
|||
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||
TRI_aql_codegen_variable_t* variable = CreateVariable(name, registerIndex);
|
||||
|
||||
if (!variable) {
|
||||
if (variable == NULL) {
|
||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
@ -2368,7 +2368,8 @@ char* TRI_GenerateCodeAql (TRI_aql_context_t* const context) {
|
|||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// errorCode might have changed, no else!
|
||||
if (generator->_errorCode != TRI_ERROR_NO_ERROR) {
|
||||
// register the error
|
||||
TRI_SetErrorContextAql(context, generator->_errorCode, generator->_errorValue);
|
||||
|
|
|
@ -146,7 +146,6 @@ bool OpenCollections (TRI_aql_context_t* const context) {
|
|||
n = context->_collections._length;
|
||||
for (i = 0; i < n; ++i) {
|
||||
TRI_aql_collection_t* collection = context->_collections._buffer[i];
|
||||
char* name;
|
||||
|
||||
assert(collection);
|
||||
assert(collection->_name);
|
||||
|
@ -155,11 +154,10 @@ bool OpenCollections (TRI_aql_context_t* const context) {
|
|||
assert(!collection->_readLocked);
|
||||
|
||||
LOG_TRACE("locking collection '%s'", collection->_name);
|
||||
collection->_collection = TRI_UseCollectionByNameVocBase(context->_vocbase, collection->_name);
|
||||
if (collection->_collection == NULL) {
|
||||
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_COLLECTION_NOT_FOUND, collection->_name);
|
||||
|
||||
name = collection->_name;
|
||||
collection->_collection = TRI_UseCollectionByNameVocBase(context->_vocbase, name);
|
||||
if (!collection->_collection) {
|
||||
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_COLLECTION_NOT_FOUND, name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -341,7 +339,7 @@ void TRI_UnlockCollectionsAql (TRI_aql_context_t* const context) {
|
|||
assert(collection);
|
||||
assert(collection->_name);
|
||||
|
||||
if (!collection->_collection) {
|
||||
if (collection->_collection == NULL) {
|
||||
// collection not yet opened
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -156,6 +156,8 @@ TRI_aql_context_t* TRI_CreateContextAql (TRI_vocbase_t* vocbase,
|
|||
|
||||
assert(vocbase);
|
||||
assert(query);
|
||||
|
||||
LOG_TRACE("creating context");
|
||||
|
||||
context = (TRI_aql_context_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_context_t), false);
|
||||
if (context == NULL) {
|
||||
|
@ -235,6 +237,8 @@ TRI_aql_context_t* TRI_CreateContextAql (TRI_vocbase_t* vocbase,
|
|||
void TRI_FreeContextAql (TRI_aql_context_t* const context) {
|
||||
assert(context);
|
||||
|
||||
LOG_TRACE("freeing context");
|
||||
|
||||
// remove barriers for all collections used
|
||||
TRI_RemoveBarrierCollectionsAql(context);
|
||||
|
||||
|
@ -347,6 +351,7 @@ bool TRI_OptimiseQueryContextAql (TRI_aql_context_t* const context) {
|
|||
}
|
||||
|
||||
TRI_CompactStatementListAql(context->_statements);
|
||||
TRI_PulloutStatementListAql(context->_statements);
|
||||
|
||||
// TRI_DumpStatementsAql(context->_statements);
|
||||
|
||||
|
|
|
@ -1769,7 +1769,7 @@ yyreduce:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
;}
|
||||
|
@ -1785,7 +1785,7 @@ yyreduce:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
;}
|
||||
|
@ -1801,7 +1801,7 @@ yyreduce:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
;}
|
||||
|
@ -1832,7 +1832,7 @@ yyreduce:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
;}
|
||||
|
@ -1914,7 +1914,7 @@ yyreduce:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
;}
|
||||
|
@ -1993,11 +1993,11 @@ yyreduce:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
;}
|
||||
|
@ -2013,7 +2013,7 @@ yyreduce:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
;}
|
||||
|
@ -2029,7 +2029,7 @@ yyreduce:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
|
@ -2080,7 +2080,7 @@ yyreduce:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, subQuery)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, subQuery)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
|
@ -2674,7 +2674,7 @@ yyreduce:
|
|||
// push the actual expand node into the statement list
|
||||
expand = TRI_CreateNodeExpandAql(context, varname, expanded, (yyvsp[(4) - (4)].node));
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, expand)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, expand)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
|
|
|
@ -212,7 +212,7 @@ for_statement:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ filter_statement:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ let_statement:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ collect_statement:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ sort_statement:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
}
|
||||
|
@ -359,11 +359,11 @@ limit_statement:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
}
|
||||
|
@ -373,7 +373,7 @@ limit_statement:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ return_statement:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
|
@ -422,7 +422,7 @@ expression:
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, subQuery)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, subQuery)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
|
@ -767,7 +767,7 @@ reference:
|
|||
// push the actual expand node into the statement list
|
||||
expand = TRI_CreateNodeExpandAql(context, varname, expanded, $4);
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, expand)) {
|
||||
if (!TRI_AppendStatementListAql(context->_statements, expand)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,29 @@ static TRI_aql_node_t* ProcessStatement (TRI_aql_statement_walker_t* const,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup Ahuacatl
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief a local optimiser structure that is used temporarily during the
|
||||
/// AST traversal
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct aql_optimiser_s {
|
||||
TRI_aql_context_t* _context;
|
||||
}
|
||||
aql_optimiser_t;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private functions
|
||||
|
@ -69,6 +92,34 @@ static TRI_aql_node_t* ProcessStatement (TRI_aql_statement_walker_t* const,
|
|||
/// @addtogroup Ahuacatl
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an optimiser structure
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static aql_optimiser_t* CreateOptimiser (TRI_aql_context_t* const context) {
|
||||
aql_optimiser_t* optimiser;
|
||||
|
||||
optimiser = (aql_optimiser_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(aql_optimiser_t), false);
|
||||
|
||||
if (optimiser == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
optimiser->_context = context;
|
||||
|
||||
return optimiser;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief free an optimiser structure
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void FreeOptimiser (aql_optimiser_t* const optimiser) {
|
||||
assert(optimiser);
|
||||
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, optimiser);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief pick an index for the ranges found
|
||||
|
@ -133,15 +184,15 @@ static void AttachCollectionHint (TRI_aql_context_t* const context,
|
|||
|
||||
static TRI_aql_node_t* AnnotateNode (TRI_aql_statement_walker_t* const walker,
|
||||
TRI_aql_node_t* node) {
|
||||
TRI_aql_context_t* context;
|
||||
aql_optimiser_t* optimiser;
|
||||
|
||||
if (node->_type != TRI_AQL_NODE_COLLECTION) {
|
||||
return node;
|
||||
}
|
||||
|
||||
context = (TRI_aql_context_t*) walker->_data;
|
||||
optimiser = (aql_optimiser_t*) walker->_data;
|
||||
|
||||
AttachCollectionHint(context, node);
|
||||
AttachCollectionHint(optimiser->_context, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -323,7 +374,7 @@ static TRI_aql_node_t* OptimiseFcall (TRI_aql_context_t* const context,
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief optimise a for statement
|
||||
/// @brief optimise a FOR statement
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_aql_node_t* OptimiseFor (TRI_aql_statement_walker_t* const walker,
|
||||
|
@ -342,9 +393,9 @@ static TRI_aql_node_t* OptimiseFor (TRI_aql_statement_walker_t* const walker,
|
|||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief optimise a sort statement
|
||||
/// @brief optimise a SORT statement
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_aql_node_t* OptimiseSort (TRI_aql_statement_walker_t* const walker,
|
||||
|
@ -387,7 +438,7 @@ static TRI_aql_node_t* OptimiseSort (TRI_aql_statement_walker_t* const walker,
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief optimise a constant filter expression
|
||||
/// @brief optimise a constant FILTER expression
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_aql_node_t* OptimiseConstantFilter (TRI_aql_node_t* const node) {
|
||||
|
@ -405,12 +456,12 @@ static TRI_aql_node_t* OptimiseConstantFilter (TRI_aql_node_t* const node) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief optimise a filter statement
|
||||
/// @brief optimise a FILTER statement
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_aql_node_t* OptimiseFilter (TRI_aql_statement_walker_t* const walker,
|
||||
TRI_aql_node_t* node) {
|
||||
TRI_aql_context_t* context = (TRI_aql_context_t*) walker->_data;
|
||||
aql_optimiser_t* optimiser = (aql_optimiser_t*) walker->_data;
|
||||
TRI_aql_node_t* expression = TRI_AQL_NODE_MEMBER(node, 0);
|
||||
|
||||
while (true) {
|
||||
|
@ -431,7 +482,7 @@ static TRI_aql_node_t* OptimiseFilter (TRI_aql_statement_walker_t* const walker,
|
|||
oldRanges = TRI_GetCurrentRangesStatementWalkerAql(walker);
|
||||
|
||||
changed = false;
|
||||
newRanges = TRI_OptimiseRangesAql(context, expression, &changed, oldRanges);
|
||||
newRanges = TRI_OptimiseRangesAql(optimiser->_context, expression, &changed, oldRanges);
|
||||
|
||||
if (newRanges) {
|
||||
TRI_SetCurrentRangesStatementWalkerAql(walker, newRanges);
|
||||
|
@ -840,7 +891,7 @@ static TRI_aql_node_t* OptimiseTernaryOperation (TRI_aql_context_t* const contex
|
|||
|
||||
static TRI_aql_node_t* OptimiseNode (TRI_aql_statement_walker_t* const walker,
|
||||
TRI_aql_node_t* node) {
|
||||
TRI_aql_context_t* context = (TRI_aql_context_t*) walker->_data;
|
||||
TRI_aql_context_t* context = ((aql_optimiser_t*) walker->_data)->_context;
|
||||
|
||||
assert(node);
|
||||
|
||||
|
@ -910,7 +961,7 @@ static TRI_aql_node_t* OptimiseStatement (TRI_aql_statement_walker_t* const walk
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void PatchVariables (TRI_aql_statement_walker_t* const walker) {
|
||||
TRI_aql_context_t* context = (TRI_aql_context_t*) walker->_data;
|
||||
TRI_aql_context_t* context = ((aql_optimiser_t*) walker->_data)->_context;
|
||||
TRI_vector_pointer_t* ranges;
|
||||
size_t i, n;
|
||||
|
||||
|
@ -1012,21 +1063,21 @@ static TRI_aql_node_t* ProcessStatement (TRI_aql_statement_walker_t* const walke
|
|||
/// @brief optimise the AST, first iteration
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool OptimiseAst (TRI_aql_context_t* const context) {
|
||||
static bool OptimiseAst (aql_optimiser_t* const optimiser) {
|
||||
TRI_aql_statement_walker_t* walker;
|
||||
|
||||
walker = TRI_CreateStatementWalkerAql((void*) context,
|
||||
walker = TRI_CreateStatementWalkerAql((void*) optimiser,
|
||||
true,
|
||||
&OptimiseNode,
|
||||
NULL,
|
||||
&ProcessStatement);
|
||||
if (walker == NULL) {
|
||||
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
||||
TRI_SetErrorContextAql(optimiser->_context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TRI_WalkStatementsAql(walker, context->_statements);
|
||||
TRI_WalkStatementsAql(walker, optimiser->_context->_statements);
|
||||
|
||||
TRI_FreeStatementWalkerAql(walker);
|
||||
|
||||
|
@ -1037,21 +1088,21 @@ static bool OptimiseAst (TRI_aql_context_t* const context) {
|
|||
/// @brief determine which indexes to use in the query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool DetermineIndexes (TRI_aql_context_t* const context) {
|
||||
static bool DetermineIndexes (aql_optimiser_t* const optimiser) {
|
||||
TRI_aql_statement_walker_t* walker;
|
||||
|
||||
walker = TRI_CreateStatementWalkerAql((void*) context,
|
||||
walker = TRI_CreateStatementWalkerAql((void*) optimiser,
|
||||
false,
|
||||
&AnnotateNode,
|
||||
NULL,
|
||||
NULL);
|
||||
if (walker == NULL) {
|
||||
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
||||
TRI_SetErrorContextAql(optimiser->_context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TRI_WalkStatementsAql(walker, context->_statements);
|
||||
TRI_WalkStatementsAql(walker, optimiser->_context->_statements);
|
||||
|
||||
TRI_FreeStatementWalkerAql(walker);
|
||||
|
||||
|
@ -1076,15 +1127,19 @@ static bool DetermineIndexes (TRI_aql_context_t* const context) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_OptimiseAql (TRI_aql_context_t* const context) {
|
||||
if (!OptimiseAst(context)) {
|
||||
aql_optimiser_t* optimiser;
|
||||
bool result;
|
||||
|
||||
optimiser = CreateOptimiser(context);
|
||||
if (optimiser == NULL) {
|
||||
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DetermineIndexes(context)) {
|
||||
return false;
|
||||
}
|
||||
result = (OptimiseAst(optimiser) && DetermineIndexes(optimiser));
|
||||
FreeOptimiser(optimiser);
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -46,19 +46,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup Ahuacatl
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -118,6 +118,7 @@ static TRI_aql_scope_t* CreateScope (TRI_aql_context_t* const context,
|
|||
scope->_id = NextId(context);
|
||||
scope->_type = NextType(context, type);
|
||||
scope->_ranges = NULL;
|
||||
scope->_selfContained = true;
|
||||
|
||||
TRI_InitAssociativePointer(&scope->_variables,
|
||||
TRI_UNKNOWN_MEM_ZONE,
|
||||
|
@ -250,7 +251,7 @@ bool TRI_StartScopeAql (TRI_aql_context_t* const context, const TRI_aql_scope_e
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (! TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -279,7 +280,7 @@ bool TRI_EndScopeAql (TRI_aql_context_t* const context) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (! TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -318,7 +319,7 @@ bool TRI_EndScopeByReturnAql (TRI_aql_context_t* const context) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!TRI_AddStatementListAql(context->_statements, node)) {
|
||||
if (! TRI_AppendStatementListAql(context->_statements, node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -388,7 +389,7 @@ bool TRI_AddVariableScopeAql (TRI_aql_context_t* const context,
|
|||
}
|
||||
|
||||
scope = CurrentScope(context);
|
||||
assert(!TRI_InsertKeyAssociativePointer(&scope->_variables, variable->_name, (void*) variable, false));
|
||||
assert(! TRI_InsertKeyAssociativePointer(&scope->_variables, variable->_name, (void*) variable, false));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ typedef struct TRI_aql_scope_s {
|
|||
TRI_associative_pointer_t _variables;
|
||||
TRI_vector_pointer_t* _ranges;
|
||||
TRI_aql_scope_e _type;
|
||||
bool _selfContained;
|
||||
size_t _id;
|
||||
}
|
||||
TRI_aql_scope_t;
|
||||
|
|
|
@ -226,6 +226,12 @@ TRI_vector_pointer_t* TRI_GetScopesStatementWalkerAql (TRI_aql_statement_walker_
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a pointer to a variable, identified by its name
|
||||
///
|
||||
/// The variable will be searched in the current and the surrounding scopes.
|
||||
/// If the variable is not found and the reference to it is coming from a
|
||||
/// subquery scope, we'll mark the subquery as not self-contained. This prevents
|
||||
/// moving of the subquery to some other position (which would break the query
|
||||
/// in this case)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_aql_variable_t* TRI_GetVariableStatementWalkerAql (TRI_aql_statement_walker_t* const walker,
|
||||
|
@ -253,7 +259,14 @@ TRI_aql_variable_t* TRI_GetVariableStatementWalkerAql (TRI_aql_statement_walker_
|
|||
|
||||
if (n == 0 || scope->_type == TRI_AQL_SCOPE_SUBQUERY) {
|
||||
// reached the outermost scope
|
||||
break;
|
||||
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
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Ahuacatl/ahuacatl-statementlist.h"
|
||||
|
||||
#include "BasicsC/logging.h"
|
||||
|
||||
#include "Ahuacatl/ahuacatl-ast-node.h"
|
||||
#include "Ahuacatl/ahuacatl-scope.h"
|
||||
|
||||
|
@ -177,11 +180,106 @@ TRI_aql_node_t* TRI_GetDummyReturnEmptyNodeAql (void) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a statement to the statement list
|
||||
/// @brief pull out uncorrelated subqueries from the middle of the statement
|
||||
/// list to the beginning
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_AddStatementListAql (TRI_aql_statement_list_t* const list,
|
||||
TRI_aql_node_t* const node) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a statement to the front of the statement list
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_InsertStatementListAql (TRI_aql_statement_list_t* const list,
|
||||
TRI_aql_node_t* const node,
|
||||
const size_t position) {
|
||||
int result;
|
||||
|
||||
assert(list);
|
||||
assert(node);
|
||||
|
||||
result = TRI_InsertVectorPointer(&list->_statements, node, position);
|
||||
|
||||
return result == TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a statement to the end of the statement list
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_AppendStatementListAql (TRI_aql_statement_list_t* const list,
|
||||
TRI_aql_node_t* const node) {
|
||||
TRI_aql_node_type_e type;
|
||||
int result;
|
||||
|
||||
|
|
|
@ -114,6 +114,13 @@ TRI_aql_node_t* TRI_GetDummyNopNodeAql (void);
|
|||
|
||||
TRI_aql_node_t* TRI_GetDummyReturnEmptyNodeAql (void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief pull out subqueries in the statement list from the middle to the
|
||||
/// beginning
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_PulloutStatementListAql (TRI_aql_statement_list_t* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remove all non-ops from the statement list
|
||||
///
|
||||
|
@ -131,11 +138,19 @@ size_t TRI_InvalidateStatementListAql (TRI_aql_statement_list_t* const,
|
|||
const size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a statement to the statement list
|
||||
/// @brief insert a statement into the statement list
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_AddStatementListAql (TRI_aql_statement_list_t* const list,
|
||||
TRI_aql_node_t* const);
|
||||
bool TRI_InsertStatementListAql (TRI_aql_statement_list_t* const,
|
||||
TRI_aql_node_t* const,
|
||||
const size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a statement to the end of the statement list
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_AppendStatementListAql (TRI_aql_statement_list_t* const,
|
||||
TRI_aql_node_t* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tests for Ahuacatl, subqueries
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var internal = require("internal");
|
||||
var jsunity = require("jsunity");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function ahuacatlSubqueryTestSuite () {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief execute a given query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function executeQuery (query, bindVars) {
|
||||
var cursor = AHUACATL_RUN(query, bindVars);
|
||||
return cursor;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief execute a given query and return the results as an array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function getQueryResults (query, bindVars) {
|
||||
var result = executeQuery(query, bindVars).getRows();
|
||||
var results = [ ];
|
||||
|
||||
for (var i in result) {
|
||||
if (!result.hasOwnProperty(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.push(result[i]);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set up
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
setUp : function () {
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tear down
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
tearDown : function () {
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test subquery evaluation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSubqueryDependent1 : function () {
|
||||
var expected = [ 2, 4, 6 ];
|
||||
var actual = getQueryResults("FOR i IN [ 1, 2, 3 ] LET s = (FOR j IN [ 1, 2, 3 ] RETURN i * 2) RETURN s[i - 1]");
|
||||
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test subquery evaluation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSubqueryDependent2 : function () {
|
||||
var expected = [ 2, 4, 6 ];
|
||||
var actual = getQueryResults("FOR i IN [ 1, 2, 3 ] LET t = (FOR k IN [ 1, 2, 3 ] RETURN k) LET s = (FOR j IN [ 1, 2, 3 ] RETURN t[i - 1] * 2) RETURN s[i - 1]");
|
||||
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test subquery evaluation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSubqueryDependent3 : function () {
|
||||
var expected = [ 4, 5, 6, 8, 10, 12, 12, 15, 18 ];
|
||||
var actual = getQueryResults("FOR i IN [ 1, 2, 3 ] FOR j IN [ 4, 5, 6 ] LET s = (FOR k IN [ 1 ] RETURN i * j) RETURN s[0]");
|
||||
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test subquery optimisation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSubqueryIndependent1 : function () {
|
||||
var expected = [ 9, 8, 7 ];
|
||||
var actual = getQueryResults("FOR i IN [ 1, 2, 3 ] LET s = (FOR j IN [ 9, 8, 7 ] RETURN j) RETURN s[i - 1]");
|
||||
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test subquery optimisation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSubqueryIndependent2 : function () {
|
||||
var expected = [ [ 9, 8, 7 ] ];
|
||||
var actual = getQueryResults("LET s = (FOR j IN [ 9, 8, 7 ] RETURN j) RETURN s");
|
||||
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test subquery optimisation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSubqueryIndependent3 : function () {
|
||||
var expected = [ [ 25 ], [ 25 ], [ 25 ], [ 25 ], [ 25 ], [ 25 ], [ 25 ], [ 25 ], [ 25 ] ];
|
||||
var actual = getQueryResults("FOR i IN [ 1, 2, 3 ] FOR j IN [ 1, 2, 3 ] LET s = (FOR k IN [ 25 ] RETURN k) RETURN s");
|
||||
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test subquery optimisation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSubqueryIndependent4 : function () {
|
||||
var expected = [ [ 2, 4, 6 ] ];
|
||||
var actual = getQueryResults("LET a = (FOR i IN [ 1, 2, 3 ] LET s = (FOR j IN [ 1, 2 ] RETURN j) RETURN i * s[1]) RETURN a");
|
||||
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes the test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
jsunity.run(ahuacatlSubqueryTestSuite);
|
||||
|
||||
return jsunity.done();
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
|
||||
// End:
|
Loading…
Reference in New Issue