mirror of https://gitee.com/bigwinds/arangodb
defer evaluation of subqueries
This commit is contained in:
parent
d5383d2be8
commit
dc8fdf8ca0
|
@ -1,6 +1,8 @@
|
||||||
v1.4.5-rc1 (XXXX-XX-XX)
|
v1.4.5-rc1 (XXXX-XX-XX)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
* defer evaluation of AQL subqueries and logical operators (lazy evaluation)
|
||||||
|
|
||||||
* generally allow function return values as call parameters to AQL functions
|
* generally allow function return values as call parameters to AQL functions
|
||||||
|
|
||||||
* fixed potential deadlock in global context method execution
|
* fixed potential deadlock in global context method execution
|
||||||
|
|
|
@ -94,6 +94,124 @@ static void ProcessNode (TRI_aql_codegen_js_t* const,
|
||||||
/// @{
|
/// @{
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief free a scope variable
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static void FreeVariable (TRI_aql_codegen_variable_t* const variable) {
|
||||||
|
assert(variable);
|
||||||
|
assert(variable->_name);
|
||||||
|
|
||||||
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, variable->_name);
|
||||||
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create a scope variable
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static TRI_aql_codegen_variable_t* CreateVariable (const char* const name,
|
||||||
|
const TRI_aql_codegen_register_t registerIndex,
|
||||||
|
bool isCachedSubquery) {
|
||||||
|
TRI_aql_codegen_variable_t* variable;
|
||||||
|
|
||||||
|
variable = (TRI_aql_codegen_variable_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_codegen_variable_t), false);
|
||||||
|
|
||||||
|
if (variable == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
variable->_register = registerIndex;
|
||||||
|
variable->_name = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, name);
|
||||||
|
variable->_isCachedSubquery = isCachedSubquery;
|
||||||
|
|
||||||
|
if (variable->_name == NULL) {
|
||||||
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, variable);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief get the current scope
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static inline TRI_aql_codegen_scope_t* CurrentScope (TRI_aql_codegen_js_t* const generator) {
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
if (generator->_errorCode != TRI_ERROR_NO_ERROR) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = generator->_scopes._length;
|
||||||
|
if (n == 0) {
|
||||||
|
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (TRI_aql_codegen_scope_t*) TRI_AtVectorPointer(&generator->_scopes, n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief enter a variable into the symbol table
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static void EnterSymbol (TRI_aql_codegen_js_t* const generator,
|
||||||
|
const char* const name,
|
||||||
|
const TRI_aql_codegen_register_t registerIndex,
|
||||||
|
bool isCachedSubquery) {
|
||||||
|
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||||
|
TRI_aql_codegen_variable_t* variable;
|
||||||
|
|
||||||
|
if (scope == NULL) {
|
||||||
|
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
variable = CreateVariable(name, registerIndex, isCachedSubquery);
|
||||||
|
|
||||||
|
if (variable == NULL) {
|
||||||
|
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TRI_InsertKeyAssociativePointer(&scope->_variables, name, (void*) variable, false) != NULL) {
|
||||||
|
// variable already exists in symbol table. this should never happen
|
||||||
|
LOG_TRACE("variable already registered: %s", name);
|
||||||
|
generator->_errorCode = TRI_ERROR_QUERY_VARIABLE_REDECLARED;
|
||||||
|
generator->_errorValue = (char*) name;
|
||||||
|
|
||||||
|
FreeVariable(variable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief look up a variable in the symbol table
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static TRI_aql_codegen_variable_t* LookupVariable (TRI_aql_codegen_js_t* const generator,
|
||||||
|
const char* const name) {
|
||||||
|
size_t i = generator->_scopes._length;
|
||||||
|
|
||||||
|
assert(name);
|
||||||
|
|
||||||
|
// iterate from current scope to the top level scope
|
||||||
|
while (i-- > 0) {
|
||||||
|
TRI_aql_codegen_scope_t* scope = (TRI_aql_codegen_scope_t*) generator->_scopes._buffer[i];
|
||||||
|
TRI_aql_codegen_variable_t* variable;
|
||||||
|
|
||||||
|
variable = (TRI_aql_codegen_variable_t*) TRI_LookupByKeyAssociativePointer(&scope->_variables, name);
|
||||||
|
// variable found in scope
|
||||||
|
if (variable != NULL) {
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief hash a variable
|
/// @brief hash a variable
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -133,26 +251,6 @@ static inline TRI_aql_codegen_register_t IncFunction (TRI_aql_codegen_js_t* cons
|
||||||
return ++generator->_functionIndex;
|
return ++generator->_functionIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief get the current scope
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static inline TRI_aql_codegen_scope_t* CurrentScope (TRI_aql_codegen_js_t* const generator) {
|
|
||||||
size_t n;
|
|
||||||
|
|
||||||
if (generator->_errorCode != TRI_ERROR_NO_ERROR) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = generator->_scopes._length;
|
|
||||||
if (n == 0) {
|
|
||||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (TRI_aql_codegen_scope_t*) TRI_AtVectorPointer(&generator->_scopes, n - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief append a string to the buffer
|
/// @brief append a string to the buffer
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -387,6 +485,41 @@ static inline void ScopeOutputRegister (TRI_aql_codegen_js_t* const generator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief print a register name in the current scope
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static void ScopeOutputSymbol (TRI_aql_codegen_js_t* const generator,
|
||||||
|
char const* name) {
|
||||||
|
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||||
|
TRI_aql_codegen_variable_t* variable;
|
||||||
|
|
||||||
|
if (scope == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
variable = LookupVariable(generator, name);
|
||||||
|
|
||||||
|
if (variable == NULL) {
|
||||||
|
generator->_errorCode = TRI_ERROR_QUERY_VARIABLE_NAME_UNKNOWN;
|
||||||
|
generator->_errorValue = (char*) name;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variable->_isCachedSubquery) {
|
||||||
|
ScopeOutput(generator, "(");
|
||||||
|
ScopeOutputRegister(generator, variable->_register);
|
||||||
|
ScopeOutput(generator, ".executed ? ");
|
||||||
|
ScopeOutputRegister(generator, variable->_register);
|
||||||
|
ScopeOutput(generator, ".data : ");
|
||||||
|
ScopeOutputRegister(generator, variable->_register);
|
||||||
|
ScopeOutput(generator, ".execute())");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ScopeOutputRegister(generator, variable->_register);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief generate code for indexed register access
|
/// @brief generate code for indexed register access
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -400,44 +533,6 @@ static void ScopeOutputIndexedName (TRI_aql_codegen_js_t* const generator,
|
||||||
ScopeOutput(generator, "]");
|
ScopeOutput(generator, "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief free a scope variable
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static void FreeVariable (TRI_aql_codegen_variable_t* const variable) {
|
|
||||||
assert(variable);
|
|
||||||
assert(variable->_name);
|
|
||||||
|
|
||||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, variable->_name);
|
|
||||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, variable);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief create a scope variable
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static TRI_aql_codegen_variable_t* CreateVariable (const char* const name,
|
|
||||||
const TRI_aql_codegen_register_t registerIndex) {
|
|
||||||
TRI_aql_codegen_variable_t* variable;
|
|
||||||
|
|
||||||
variable = (TRI_aql_codegen_variable_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_codegen_variable_t), false);
|
|
||||||
|
|
||||||
if (variable == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
variable->_register = registerIndex;
|
|
||||||
variable->_name = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, name);
|
|
||||||
|
|
||||||
if (variable->_name == NULL) {
|
|
||||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, variable);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return variable;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief get the type for the next scope
|
/// @brief get the type for the next scope
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -518,6 +613,7 @@ static void StartScope (TRI_aql_codegen_js_t* const generator,
|
||||||
scope->_offsetRegister = offsetRegister;
|
scope->_offsetRegister = offsetRegister;
|
||||||
scope->_limitRegister = limitRegister;
|
scope->_limitRegister = limitRegister;
|
||||||
scope->_resultRegister = resultRegister;
|
scope->_resultRegister = resultRegister;
|
||||||
|
scope->_subqueryRegister = 0;
|
||||||
scope->_prefix = NULL;
|
scope->_prefix = NULL;
|
||||||
scope->_hint = hint; // for-loop hint
|
scope->_hint = hint; // for-loop hint
|
||||||
|
|
||||||
|
@ -763,69 +859,6 @@ static void InitArray (TRI_aql_codegen_js_t* const generator,
|
||||||
ScopeOutput(generator, " = { };\n");
|
ScopeOutput(generator, " = { };\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief enter a variable into the symbol table
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static void EnterSymbol (TRI_aql_codegen_js_t* const generator,
|
|
||||||
const char* const name,
|
|
||||||
const TRI_aql_codegen_register_t registerIndex) {
|
|
||||||
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
|
||||||
TRI_aql_codegen_variable_t* variable;
|
|
||||||
|
|
||||||
if (scope == NULL) {
|
|
||||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
variable = CreateVariable(name, registerIndex);
|
|
||||||
|
|
||||||
if (variable == NULL) {
|
|
||||||
generator->_errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TRI_InsertKeyAssociativePointer(&scope->_variables, name, (void*) variable, false) != NULL) {
|
|
||||||
// variable already exists in symbol table. this should never happen
|
|
||||||
LOG_TRACE("variable already registered: %s", name);
|
|
||||||
generator->_errorCode = TRI_ERROR_QUERY_VARIABLE_REDECLARED;
|
|
||||||
generator->_errorValue = (char*) name;
|
|
||||||
|
|
||||||
FreeVariable(variable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief look up a variable in the symbol table
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static TRI_aql_codegen_register_t LookupSymbol (TRI_aql_codegen_js_t* const generator,
|
|
||||||
const char* const name) {
|
|
||||||
size_t i = generator->_scopes._length;
|
|
||||||
|
|
||||||
assert(name);
|
|
||||||
|
|
||||||
// iterate from current scope to the top level scope
|
|
||||||
while (i-- > 0) {
|
|
||||||
TRI_aql_codegen_scope_t* scope = (TRI_aql_codegen_scope_t*) generator->_scopes._buffer[i];
|
|
||||||
TRI_aql_codegen_variable_t* variable;
|
|
||||||
|
|
||||||
variable = (TRI_aql_codegen_variable_t*) TRI_LookupByKeyAssociativePointer(&scope->_variables, name);
|
|
||||||
// variable found in scope
|
|
||||||
if (variable) {
|
|
||||||
// return the variable register
|
|
||||||
return variable->_register;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// variable not found. this should never happen
|
|
||||||
LOG_TRACE("variable not found: %s", name);
|
|
||||||
generator->_errorCode = TRI_ERROR_QUERY_VARIABLE_NAME_UNKNOWN;
|
|
||||||
generator->_errorValue = (char*) name;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief start a for loop
|
/// @brief start a for loop
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -861,7 +894,7 @@ static void StartFor (TRI_aql_codegen_js_t* const generator,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variableName) {
|
if (variableName) {
|
||||||
EnterSymbol(generator, variableName, ownRegister);
|
EnterSymbol(generator, variableName, ownRegister, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeOutput(generator, "var ");
|
ScopeOutput(generator, "var ");
|
||||||
|
@ -1135,7 +1168,7 @@ static void RestoreSymbols (TRI_aql_codegen_js_t* const generator,
|
||||||
|
|
||||||
// re-enter symbols
|
// re-enter symbols
|
||||||
if (variableName) {
|
if (variableName) {
|
||||||
EnterSymbol(generator, variableName, registerIndex);
|
EnterSymbol(generator, variableName, registerIndex, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// unpack variables from current scope's iterator register
|
// unpack variables from current scope's iterator register
|
||||||
|
@ -1188,7 +1221,7 @@ static void GeneratePrimaryAccess (TRI_aql_codegen_js_t* const generator,
|
||||||
fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN);
|
fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN);
|
||||||
|
|
||||||
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
||||||
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name));
|
ScopeOutputSymbol(generator, fieldAccess->_value._reference._ref._name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
||||||
|
@ -1240,7 +1273,7 @@ static void GenerateHashAccess (TRI_aql_codegen_js_t* const generator,
|
||||||
ScopeOutput(generator, ", ");
|
ScopeOutput(generator, ", ");
|
||||||
|
|
||||||
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
||||||
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name));
|
ScopeOutputSymbol(generator, fieldAccess->_value._reference._ref._name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
||||||
|
@ -1278,7 +1311,7 @@ static void GenerateHashAccess (TRI_aql_codegen_js_t* const generator,
|
||||||
fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN);
|
fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN);
|
||||||
|
|
||||||
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
||||||
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name));
|
ScopeOutputSymbol(generator, fieldAccess->_value._reference._ref._name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
||||||
|
@ -1331,7 +1364,7 @@ static void GenerateEdgeAccess (TRI_aql_codegen_js_t* const generator,
|
||||||
fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN);
|
fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN);
|
||||||
|
|
||||||
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
||||||
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name));
|
ScopeOutputSymbol(generator, fieldAccess->_value._reference._ref._name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
||||||
|
@ -1383,7 +1416,7 @@ static void GenerateSkiplistAccess (TRI_aql_codegen_js_t* const generator,
|
||||||
ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1);
|
ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1);
|
||||||
ScopeOutput(generator, ", ");
|
ScopeOutput(generator, ", ");
|
||||||
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
||||||
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name));
|
ScopeOutputSymbol(generator, fieldAccess->_value._reference._ref._name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
||||||
|
@ -1448,7 +1481,7 @@ static void GenerateSkiplistAccess (TRI_aql_codegen_js_t* const generator,
|
||||||
ScopeOutput(generator, "\", ");
|
ScopeOutput(generator, "\", ");
|
||||||
|
|
||||||
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
||||||
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name));
|
ScopeOutputSymbol(generator, fieldAccess->_value._reference._ref._name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
||||||
|
@ -1504,7 +1537,7 @@ static void GenerateBitarrayAccess (TRI_aql_codegen_js_t* const generator,
|
||||||
ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1);
|
ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1);
|
||||||
ScopeOutput(generator, ", ");
|
ScopeOutput(generator, ", ");
|
||||||
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
||||||
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name));
|
ScopeOutputSymbol(generator, fieldAccess->_value._reference._ref._name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
||||||
|
@ -1545,7 +1578,7 @@ static void GenerateBitarrayAccess (TRI_aql_codegen_js_t* const generator,
|
||||||
|
|
||||||
case TRI_AQL_ACCESS_REFERENCE: {
|
case TRI_AQL_ACCESS_REFERENCE: {
|
||||||
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) {
|
||||||
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name));
|
ScopeOutputSymbol(generator, fieldAccess->_value._reference._ref._name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
|
||||||
|
@ -1589,8 +1622,7 @@ static void ProcessReference (TRI_aql_codegen_js_t* const generator,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// regular scope, we are using a register
|
// regular scope, we are using a register
|
||||||
TRI_aql_codegen_register_t registerIndex = LookupSymbol(generator, name);
|
ScopeOutputSymbol(generator, name);
|
||||||
ScopeOutputRegister(generator, registerIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1887,7 +1919,7 @@ static void ProcessExpand (TRI_aql_codegen_js_t* const generator,
|
||||||
|
|
||||||
// for
|
// for
|
||||||
StartFor(generator, scope->_buffer, sourceRegister, isList, NULL, NULL);
|
StartFor(generator, scope->_buffer, sourceRegister, isList, NULL, NULL);
|
||||||
EnterSymbol(generator, TRI_AQL_NODE_STRING(nameNode1), CurrentScope(generator)->_ownRegister);
|
EnterSymbol(generator, TRI_AQL_NODE_STRING(nameNode1), CurrentScope(generator)->_ownRegister, false);
|
||||||
|
|
||||||
ScopeOutputRegister(generator, resultRegister);
|
ScopeOutputRegister(generator, resultRegister);
|
||||||
ScopeOutput(generator, ".push(");
|
ScopeOutput(generator, ".push(");
|
||||||
|
@ -1901,7 +1933,7 @@ static void ProcessExpand (TRI_aql_codegen_js_t* const generator,
|
||||||
EndScope(generator);
|
EndScope(generator);
|
||||||
|
|
||||||
// register the variable for the result
|
// register the variable for the result
|
||||||
EnterSymbol(generator, TRI_AQL_NODE_STRING(nameNode2), resultRegister);
|
EnterSymbol(generator, TRI_AQL_NODE_STRING(nameNode2), resultRegister, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -2142,24 +2174,59 @@ static void ProcessTernary (TRI_aql_codegen_js_t* const generator,
|
||||||
|
|
||||||
static void ProcessSubquery (TRI_aql_codegen_js_t* const generator,
|
static void ProcessSubquery (TRI_aql_codegen_js_t* const generator,
|
||||||
const TRI_aql_node_t* const node) {
|
const TRI_aql_node_t* const node) {
|
||||||
TRI_aql_codegen_register_t subQueryRegister;
|
|
||||||
TRI_aql_codegen_register_t resultRegister = IncRegister(generator);
|
TRI_aql_codegen_register_t resultRegister = IncRegister(generator);
|
||||||
TRI_aql_node_t* nameNode = TRI_AQL_NODE_MEMBER(node, 0);
|
TRI_aql_node_t* nameNode = TRI_AQL_NODE_MEMBER(node, 0);
|
||||||
|
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||||
|
|
||||||
// get the subquery scope's result register
|
if (scope == NULL) {
|
||||||
subQueryRegister = generator->_lastResultRegister;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ScopeOutput(generator, "var ");
|
ScopeOutput(generator, "var ");
|
||||||
ScopeOutputRegister(generator, resultRegister);
|
ScopeOutputRegister(generator, resultRegister);
|
||||||
ScopeOutput(generator, " = ");
|
ScopeOutput(generator, " = ");
|
||||||
ScopeOutputRegister(generator, subQueryRegister);
|
if (scope->_subqueryRegister > 0) {
|
||||||
|
ScopeOutputRegister(generator, scope->_subqueryRegister);
|
||||||
|
|
||||||
#if AQL_VERBOSE
|
#if AQL_VERBOSE
|
||||||
ScopeOutput(generator, "; /* subquery */\n");
|
ScopeOutput(generator, "(); /* subquery */\n");
|
||||||
#else
|
#else
|
||||||
ScopeOutput(generator, ";\n");
|
ScopeOutput(generator, "();\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// subquery has been optimised away
|
||||||
|
ScopeOutput(generator, "[ ];\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
EnterSymbol(generator, nameNode->_value._value._string, resultRegister, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief generate code for cached subqueries (nested fors etc.)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static void ProcessSubqueryCached (TRI_aql_codegen_js_t* const generator,
|
||||||
|
const TRI_aql_node_t* const node) {
|
||||||
|
TRI_aql_codegen_register_t resultRegister = IncRegister(generator);
|
||||||
|
TRI_aql_node_t* nameNode = TRI_AQL_NODE_MEMBER(node, 0);
|
||||||
|
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
|
||||||
|
|
||||||
|
if (scope == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopeOutput(generator, "var ");
|
||||||
|
ScopeOutputRegister(generator, resultRegister);
|
||||||
|
ScopeOutput(generator, " = { data: null, executed: false, fn: ");
|
||||||
|
ScopeOutputRegister(generator, scope->_subqueryRegister);
|
||||||
|
#if AQL_VERBOSE
|
||||||
|
ScopeOutput(generator, ", execute: function () { this.executed = true; return this.data = this.fn(); } }; /* subquery */\n");
|
||||||
|
#else
|
||||||
|
ScopeOutput(generator, ", execute: function () { this.executed = true; return this.data = this.fn(); } };\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
EnterSymbol(generator, nameNode->_value._value._string, resultRegister);
|
EnterSymbol(generator, nameNode->_value._value._string, resultRegister, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -2197,11 +2264,24 @@ static void ProcessScopeStart (TRI_aql_codegen_js_t* const generator,
|
||||||
TRI_aql_codegen_register_t resultRegister;
|
TRI_aql_codegen_register_t resultRegister;
|
||||||
TRI_aql_codegen_register_t sourceRegister;
|
TRI_aql_codegen_register_t sourceRegister;
|
||||||
TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AQL_NODE_DATA(node);
|
TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AQL_NODE_DATA(node);
|
||||||
|
TRI_aql_codegen_scope_t* s;
|
||||||
|
|
||||||
if (scope->_type != TRI_AQL_SCOPE_SUBQUERY) {
|
if (scope->_type != TRI_AQL_SCOPE_SUBQUERY) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s = CurrentScope(generator);
|
||||||
|
|
||||||
|
if (s == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->_subqueryRegister = IncRegister(generator);
|
||||||
|
|
||||||
|
ScopeOutput(generator, "var ");
|
||||||
|
ScopeOutputRegister(generator, s->_subqueryRegister);
|
||||||
|
ScopeOutput(generator, " = function() {\n");
|
||||||
|
|
||||||
resultRegister = IncRegister(generator);
|
resultRegister = IncRegister(generator);
|
||||||
InitList(generator, resultRegister);
|
InitList(generator, resultRegister);
|
||||||
StartScope(generator, &generator->_buffer, TRI_AQL_SCOPE_SUBQUERY, 0, 0, 0, resultRegister, NULL);
|
StartScope(generator, &generator->_buffer, TRI_AQL_SCOPE_SUBQUERY, 0, 0, 0, resultRegister, NULL);
|
||||||
|
@ -2226,12 +2306,18 @@ static void ProcessScopeStart (TRI_aql_codegen_js_t* const generator,
|
||||||
static void ProcessScopeEnd (TRI_aql_codegen_js_t* const generator,
|
static void ProcessScopeEnd (TRI_aql_codegen_js_t* const generator,
|
||||||
const TRI_aql_node_t* const node) {
|
const TRI_aql_node_t* const node) {
|
||||||
TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AQL_NODE_DATA(node);
|
TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AQL_NODE_DATA(node);
|
||||||
|
TRI_aql_codegen_register_t resultRegister;
|
||||||
|
|
||||||
if (scope->_type != TRI_AQL_SCOPE_SUBQUERY) {
|
if (scope->_type != TRI_AQL_SCOPE_SUBQUERY) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resultRegister = CurrentScope(generator)->_resultRegister;
|
||||||
EndScope(generator);
|
EndScope(generator);
|
||||||
|
|
||||||
|
ScopeOutput(generator, "return ");
|
||||||
|
ScopeOutputRegister(generator, resultRegister);
|
||||||
|
ScopeOutput(generator, ";\n};\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -2444,7 +2530,7 @@ static void ProcessCollect (TRI_aql_codegen_js_t* const generator,
|
||||||
ScopeOutputIndexedName(generator, scope->_ownRegister, TRI_AQL_NODE_STRING(varNode));
|
ScopeOutputIndexedName(generator, scope->_ownRegister, TRI_AQL_NODE_STRING(varNode));
|
||||||
ScopeOutput(generator, ";\n");
|
ScopeOutput(generator, ";\n");
|
||||||
|
|
||||||
EnterSymbol(generator, TRI_AQL_NODE_STRING(varNode), varRegister);
|
EnterSymbol(generator, TRI_AQL_NODE_STRING(varNode), varRegister, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// re-enter symbol for into
|
// re-enter symbol for into
|
||||||
|
@ -2459,7 +2545,7 @@ static void ProcessCollect (TRI_aql_codegen_js_t* const generator,
|
||||||
ScopeOutputIndexedName(generator, scope->_ownRegister, TRI_AQL_NODE_STRING(nameNode));
|
ScopeOutputIndexedName(generator, scope->_ownRegister, TRI_AQL_NODE_STRING(nameNode));
|
||||||
ScopeOutput(generator, ";\n");
|
ScopeOutput(generator, ";\n");
|
||||||
|
|
||||||
EnterSymbol(generator, TRI_AQL_NODE_STRING(nameNode), intoRegister);
|
EnterSymbol(generator, TRI_AQL_NODE_STRING(nameNode), intoRegister, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if AQL_VERBOSE
|
#if AQL_VERBOSE
|
||||||
|
@ -2560,8 +2646,6 @@ static void ProcessReturn (TRI_aql_codegen_js_t* const generator,
|
||||||
ScopeOutputRegister(generator, rowRegister);
|
ScopeOutputRegister(generator, rowRegister);
|
||||||
ScopeOutput(generator, ");\n");
|
ScopeOutput(generator, ");\n");
|
||||||
|
|
||||||
generator->_lastResultRegister = scope->_resultRegister;
|
|
||||||
|
|
||||||
// }
|
// }
|
||||||
CloseLoops(generator);
|
CloseLoops(generator);
|
||||||
}
|
}
|
||||||
|
@ -2583,8 +2667,6 @@ static void ProcessReturnEmpty (TRI_aql_codegen_js_t* const generator,
|
||||||
ScopeOutput(generator, " = [ ];\n");
|
ScopeOutput(generator, " = [ ];\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
generator->_lastResultRegister = resultRegister;
|
|
||||||
|
|
||||||
// }
|
// }
|
||||||
CloseLoops(generator);
|
CloseLoops(generator);
|
||||||
}
|
}
|
||||||
|
@ -2606,7 +2688,7 @@ static void ProcessLet (TRI_aql_codegen_js_t* const generator,
|
||||||
ScopeOutput(generator, ";\n");
|
ScopeOutput(generator, ";\n");
|
||||||
|
|
||||||
// enter the new variable in the symbol table
|
// enter the new variable in the symbol table
|
||||||
EnterSymbol(generator, nameNode->_value._value._string, resultRegister);
|
EnterSymbol(generator, nameNode->_value._value._string, resultRegister, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -2643,7 +2725,7 @@ static void ProcessAssign (TRI_aql_codegen_js_t* const generator,
|
||||||
}
|
}
|
||||||
|
|
||||||
// enter the new variable in the symbol table
|
// enter the new variable in the symbol table
|
||||||
EnterSymbol(generator, nameNode->_value._value._string, resultRegister);
|
EnterSymbol(generator, nameNode->_value._value._string, resultRegister, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -2827,6 +2909,9 @@ static void ProcessNode (TRI_aql_codegen_js_t* const generator, const TRI_aql_no
|
||||||
case TRI_AQL_NODE_SUBQUERY:
|
case TRI_AQL_NODE_SUBQUERY:
|
||||||
ProcessSubquery(generator, node);
|
ProcessSubquery(generator, node);
|
||||||
break;
|
break;
|
||||||
|
case TRI_AQL_NODE_SUBQUERY_CACHED:
|
||||||
|
ProcessSubqueryCached(generator, node);
|
||||||
|
break;
|
||||||
case TRI_AQL_NODE_SCOPE_START:
|
case TRI_AQL_NODE_SCOPE_START:
|
||||||
ProcessScopeStart(generator, node);
|
ProcessScopeStart(generator, node);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -66,6 +66,7 @@ typedef uint32_t TRI_aql_codegen_register_t;
|
||||||
typedef struct TRI_aql_codegen_variable_s {
|
typedef struct TRI_aql_codegen_variable_s {
|
||||||
char* _name; // variable name
|
char* _name; // variable name
|
||||||
TRI_aql_codegen_register_t _register; // the assigned register
|
TRI_aql_codegen_register_t _register; // the assigned register
|
||||||
|
bool _isCachedSubquery;
|
||||||
}
|
}
|
||||||
TRI_aql_codegen_variable_t;
|
TRI_aql_codegen_variable_t;
|
||||||
|
|
||||||
|
@ -82,6 +83,7 @@ typedef struct TRI_aql_codegen_scope_s {
|
||||||
TRI_aql_codegen_register_t _resultRegister;
|
TRI_aql_codegen_register_t _resultRegister;
|
||||||
TRI_aql_codegen_register_t _offsetRegister; // limit offset, limit
|
TRI_aql_codegen_register_t _offsetRegister; // limit offset, limit
|
||||||
TRI_aql_codegen_register_t _limitRegister; // limit offset, limit
|
TRI_aql_codegen_register_t _limitRegister; // limit offset, limit
|
||||||
|
TRI_aql_codegen_register_t _subqueryRegister;
|
||||||
TRI_associative_pointer_t _variables; // list of variables in scope
|
TRI_associative_pointer_t _variables; // list of variables in scope
|
||||||
char* _prefix; // prefix for variable names, used in FUNCTION scopes only
|
char* _prefix; // prefix for variable names, used in FUNCTION scopes only
|
||||||
TRI_aql_for_hint_t* _hint; // generic hint
|
TRI_aql_for_hint_t* _hint; // generic hint
|
||||||
|
@ -97,7 +99,6 @@ typedef struct TRI_aql_codegen_js_s {
|
||||||
TRI_string_buffer_t _buffer;
|
TRI_string_buffer_t _buffer;
|
||||||
TRI_string_buffer_t _functionBuffer;
|
TRI_string_buffer_t _functionBuffer;
|
||||||
TRI_vector_pointer_t _scopes;
|
TRI_vector_pointer_t _scopes;
|
||||||
TRI_aql_codegen_register_t _lastResultRegister;
|
|
||||||
TRI_aql_codegen_register_t _registerIndex;
|
TRI_aql_codegen_register_t _registerIndex;
|
||||||
TRI_aql_codegen_register_t _functionIndex;
|
TRI_aql_codegen_register_t _functionIndex;
|
||||||
int _errorCode; // error number
|
int _errorCode; // error number
|
||||||
|
|
|
@ -292,7 +292,8 @@ static TRI_aql_node_t* ProcessStatement (TRI_aql_statement_walker_t* const walke
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TRI_AQL_NODE_SUBQUERY: {
|
case TRI_AQL_NODE_SUBQUERY:
|
||||||
|
case TRI_AQL_NODE_SUBQUERY_CACHED: {
|
||||||
TRI_json_t* row;
|
TRI_json_t* row;
|
||||||
|
|
||||||
row = GetRowProtoType(explain, node->_type);
|
row = GetRowProtoType(explain, node->_type);
|
||||||
|
|
|
@ -40,6 +40,7 @@ bool TRI_IsTopLevelTypeAql (const TRI_aql_node_type_e type) {
|
||||||
if (type == TRI_AQL_NODE_SCOPE_START ||
|
if (type == TRI_AQL_NODE_SCOPE_START ||
|
||||||
type == TRI_AQL_NODE_SCOPE_END ||
|
type == TRI_AQL_NODE_SCOPE_END ||
|
||||||
type == TRI_AQL_NODE_SUBQUERY ||
|
type == TRI_AQL_NODE_SUBQUERY ||
|
||||||
|
type == TRI_AQL_NODE_SUBQUERY_CACHED ||
|
||||||
type == TRI_AQL_NODE_EXPAND ||
|
type == TRI_AQL_NODE_EXPAND ||
|
||||||
type == TRI_AQL_NODE_FOR ||
|
type == TRI_AQL_NODE_FOR ||
|
||||||
type == TRI_AQL_NODE_FILTER ||
|
type == TRI_AQL_NODE_FILTER ||
|
||||||
|
@ -165,6 +166,8 @@ const char* TRI_NodeNameAql (const TRI_aql_node_type_e type) {
|
||||||
return "ternary";
|
return "ternary";
|
||||||
case TRI_AQL_NODE_SUBQUERY:
|
case TRI_AQL_NODE_SUBQUERY:
|
||||||
return "subquery";
|
return "subquery";
|
||||||
|
case TRI_AQL_NODE_SUBQUERY_CACHED:
|
||||||
|
return "subquery (cached)";
|
||||||
case TRI_AQL_NODE_ATTRIBUTE_ACCESS:
|
case TRI_AQL_NODE_ATTRIBUTE_ACCESS:
|
||||||
return "attribute access";
|
return "attribute access";
|
||||||
case TRI_AQL_NODE_BOUND_ATTRIBUTE_ACCESS:
|
case TRI_AQL_NODE_BOUND_ATTRIBUTE_ACCESS:
|
||||||
|
|
|
@ -171,6 +171,7 @@ typedef enum {
|
||||||
TRI_AQL_NODE_OPERATOR_BINARY_IN,
|
TRI_AQL_NODE_OPERATOR_BINARY_IN,
|
||||||
TRI_AQL_NODE_OPERATOR_TERNARY,
|
TRI_AQL_NODE_OPERATOR_TERNARY,
|
||||||
TRI_AQL_NODE_SUBQUERY,
|
TRI_AQL_NODE_SUBQUERY,
|
||||||
|
TRI_AQL_NODE_SUBQUERY_CACHED,
|
||||||
TRI_AQL_NODE_ATTRIBUTE_ACCESS,
|
TRI_AQL_NODE_ATTRIBUTE_ACCESS,
|
||||||
TRI_AQL_NODE_BOUND_ATTRIBUTE_ACCESS,
|
TRI_AQL_NODE_BOUND_ATTRIBUTE_ACCESS,
|
||||||
TRI_AQL_NODE_INDEXED,
|
TRI_AQL_NODE_INDEXED,
|
||||||
|
|
|
@ -228,6 +228,8 @@ void TRI_PulloutStatementListAql (TRI_aql_statement_list_t* const list) {
|
||||||
size_t j = moveStart;
|
size_t j = moveStart;
|
||||||
size_t inserted = 0;
|
size_t inserted = 0;
|
||||||
|
|
||||||
|
node->_type = TRI_AQL_NODE_SUBQUERY_CACHED;
|
||||||
|
|
||||||
// moving statements from the middle to the beginning of the list will also
|
// moving statements from the middle to the beginning of the list will also
|
||||||
// modify the positions we're moving from
|
// modify the positions we're moving from
|
||||||
while (j < i + 2) {
|
while (j < i + 2) {
|
||||||
|
|
|
@ -51,6 +51,97 @@ function ahuacatlQueryNonCollectionTestSuite () {
|
||||||
tearDown : function () {
|
tearDown : function () {
|
||||||
},
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief multiple subqueries
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testMultipleSubqueries1 : function () {
|
||||||
|
var expected = [ [ [ 2, 4 ], [ 6, 8 ] ] ];
|
||||||
|
var actual = getQueryResults("LET a = (FOR i IN [ 1, 2 ] RETURN i * 2), b = (FOR i IN [ 3, 4 ] RETURN i * 2) RETURN [ a, b ]");
|
||||||
|
assertEqual(expected, actual);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief multiple subqueries
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testMultipleSubqueries2 : function () {
|
||||||
|
var expected = [ [ [ 2, 4 ], [ 6, 8 ] ] ];
|
||||||
|
var actual = getQueryResults("LET a = (FOR i IN [ 1, 2 ] RETURN i * 2) LET b = (FOR i IN [ 3, 4 ] RETURN i * 2) RETURN [ a, b ]");
|
||||||
|
assertEqual(expected, actual);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test deferred evaluation
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testDeferredEval1 : function () {
|
||||||
|
var expected = [ ];
|
||||||
|
|
||||||
|
var actual = getQueryResults("FOR year IN [ 2010, 2011, 2012 ] FILTER year > 2013 && FAIL() RETURN year");
|
||||||
|
assertEqual(expected, actual);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test deferred evaluation
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testDeferredEval2 : function () {
|
||||||
|
var expected = [ ];
|
||||||
|
|
||||||
|
var actual = getQueryResults("FOR year IN [ 2010, 2011, 2012 ] FILTER year > 2013 RETURN FAIL()");
|
||||||
|
assertEqual(expected, actual);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test deferred evaluation
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testDeferredEval3 : function () {
|
||||||
|
var expected = [ ];
|
||||||
|
|
||||||
|
var actual = getQueryResults("FOR year IN [ 2010, 2011, 2012 ] FILTER year > 2013 && FAIL() RETURN FAIL()");
|
||||||
|
assertEqual(expected, actual);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test deferred evaluation
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testDeferredEval4 : function () {
|
||||||
|
var expected = [ ];
|
||||||
|
|
||||||
|
var actual = getQueryResults("FOR year IN [ 2010, 2011, 2012 ] FILTER year > 2020 LET x = (FOR i IN [ 1, 2 ] RETURN FAIL()) RETURN year");
|
||||||
|
assertEqual(expected, actual);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test deferred evaluation
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testDeferredEval5 : function () {
|
||||||
|
var expected = [ ];
|
||||||
|
|
||||||
|
var actual = getQueryResults("FOR year IN [ 2010, 2011, 2012 ] FILTER year > 2020 LET x = (FOR i IN [ 1, 2 ] RETURN FAIL()) RETURN FAIL()");
|
||||||
|
assertEqual(expected, actual);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test deferred evaluation
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testDeferredEval6 : function () {
|
||||||
|
assertException(function() { getQueryResults("FOR year IN [ 2010, 2011, 2012 ] FILTER year < 2020 RETURN FAIL()"); });
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test deferred evaluation
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testDeferredEval7 : function () {
|
||||||
|
assertException(function() { getQueryResults("FOR year IN [ 2010, 2011, 2012 ] FILTER year < 2020 LET x = (FOR i IN [ 1, 2 ] RETURN FAIL()) RETURN year") });
|
||||||
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief return a single value from a list
|
/// @brief return a single value from a list
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Reference in New Issue