mirror of https://gitee.com/bigwinds/arangodb
fixed and simplified subqueries
This commit is contained in:
parent
4ceb707090
commit
85cde255e3
|
@ -233,7 +233,6 @@ TRI_aql_node_t* TRI_CreateNodeForAql (TRI_aql_context_t* const context,
|
|||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST let node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -241,34 +240,25 @@ TRI_aql_node_t* TRI_CreateNodeForAql (TRI_aql_context_t* const context,
|
|||
TRI_aql_node_t* TRI_CreateNodeLetAql (TRI_aql_context_t* const context,
|
||||
const char* const name,
|
||||
const TRI_aql_node_t* const expression) {
|
||||
TRI_aql_node_let_t* node;
|
||||
TRI_aql_node_t* variableNode;
|
||||
CREATE_NODE(AQL_NODE_LET)
|
||||
|
||||
assert(context);
|
||||
|
||||
if (!name || !expression) {
|
||||
if (!name) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
node = (TRI_aql_node_let_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_node_let_t), false);
|
||||
|
||||
if (!node) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
InitNode(context, (TRI_aql_node_t*) node, AQL_NODE_LET);
|
||||
|
||||
variableNode = TRI_CreateNodeVariableAql(context, name);
|
||||
if (!variableNode) {
|
||||
if (!TRI_IsValidVariableNameAql(name)) {
|
||||
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_VARIABLE_NAME_INVALID, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->_variable = variableNode;
|
||||
node->_expression = (TRI_aql_node_t*) expression;
|
||||
|
||||
return (TRI_aql_node_t*) node;
|
||||
{
|
||||
TRI_aql_node_t* variable = TRI_CreateNodeVariableAql(context, name);
|
||||
ADD_MEMBER(variable)
|
||||
ADD_MEMBER(expression)
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST filter node
|
||||
|
@ -744,13 +734,20 @@ TRI_aql_node_t* TRI_CreateNodeOperatorTernaryAql (TRI_aql_context_t* const conte
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST subquery node
|
||||
/// @brief create an AST subquery (execution) node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_aql_node_t* TRI_CreateNodeSubqueryAql (TRI_aql_context_t* const context,
|
||||
const TRI_aql_node_t* const query) {
|
||||
CREATE_NODE(AQL_NODE_SUBQUERY)
|
||||
|
||||
{
|
||||
// add the temporary variable
|
||||
TRI_aql_node_t* variable = TRI_CreateNodeVariableAql(context, TRI_GetNameParseAql(context));
|
||||
ADD_MEMBER(variable)
|
||||
}
|
||||
|
||||
// add the actual subquery
|
||||
ADD_MEMBER(query)
|
||||
|
||||
return node;
|
||||
|
|
|
@ -55,8 +55,8 @@ extern "C" {
|
|||
|
||||
#define TRI_AQL_IDX_FOR_VARIABLE 0
|
||||
#define TRI_AQL_IDX_FOR_EXPRESSION 1
|
||||
#define TRI_AQL_IDX_ASSIGN_VARIABLE 0
|
||||
#define TRI_AQL_IDX_ASSIGN_EXPRESSION 1
|
||||
#define TRI_AQL_IDX_LET_VARIABLE 0
|
||||
#define TRI_AQL_IDX_LET_EXPRESSION 1
|
||||
#define TRI_AQL_IDX_FILTER_EXPRESSION 0
|
||||
#define TRI_AQL_IDX_COLLECT_LIST 0
|
||||
#define TRI_AQL_IDX_COLLECT_INTO 1
|
||||
|
@ -68,13 +68,16 @@ extern "C" {
|
|||
#define TRI_AQL_IDX_INDEXED_INDEX 1
|
||||
#define TRI_AQL_IDX_EXPAND_EXPANDED 0
|
||||
#define TRI_AQL_IDX_EXPAND_EXPANSION 1
|
||||
#define TRI_AQL_IDX_ASSIGN_VARIABLE 0
|
||||
#define TRI_AQL_IDX_ASSIGN_EXPRESSION 1
|
||||
#define TRI_AQL_IDX_UNARY_OPERAND 0
|
||||
#define TRI_AQL_IDX_BINARY_LHS 0
|
||||
#define TRI_AQL_IDX_BINARY_RHS 1
|
||||
#define TRI_AQL_IDX_TERNARY_CONDITION 0
|
||||
#define TRI_AQL_IDX_TERNARY_TRUEPART 1
|
||||
#define TRI_AQL_IDX_TERNARY_FALSEPART 2
|
||||
#define TRI_AQL_IDX_SUBQUERY_QUERY 0
|
||||
#define TRI_AQL_IDX_SUBQUERY_VARIABLE 0
|
||||
#define TRI_AQL_IDX_SUBQUERY_QUERY 1
|
||||
#define TRI_AQL_IDX_FCALL_PARAMETERS 0
|
||||
#define TRI_AQL_IDX_ARRAY_ELEMENT_SUBNODE 0
|
||||
#define TRI_AQL_IDX_ARRAY_VALUES 0
|
||||
|
@ -492,7 +495,7 @@ TRI_aql_node_t* TRI_CreateNodeOperatorTernaryAql (TRI_aql_context_t* const,
|
|||
const TRI_aql_node_t* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST subquery node
|
||||
/// @brief create an AST subquery (execution) node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_aql_node_t* TRI_CreateNodeSubqueryAql (TRI_aql_context_t* const,
|
||||
|
|
|
@ -520,6 +520,7 @@ static void EnterSymbol (TRI_aql_codegen_js_t* const generator,
|
|||
|
||||
if (TRI_InsertKeyAssociativePointer(&scope->_variables, name, (void*) variable, false)) {
|
||||
// variable already exists in symbol table. this should never happen
|
||||
LOG_TRACE("variable already registered: %s", name);
|
||||
generator->_error = true;
|
||||
}
|
||||
}
|
||||
|
@ -545,7 +546,8 @@ static TRI_aql_codegen_register_t LookupSymbol (TRI_aql_codegen_js_t* const gene
|
|||
}
|
||||
}
|
||||
|
||||
// variable not found. this should not happen
|
||||
// variable not found. this should never happen
|
||||
LOG_TRACE("variable not found: %s", name);
|
||||
generator->_error = true;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1142,33 +1144,24 @@ static void ProcessSubquery (TRI_aql_codegen_js_t* const generator,
|
|||
const TRI_aql_node_t* const node) {
|
||||
TRI_aql_codegen_register_t scopeRegister = IncRegister(generator);
|
||||
TRI_aql_codegen_register_t resultRegister = IncRegister(generator);
|
||||
TRI_aql_codegen_register_t subFunction = IncFunction(generator);
|
||||
TRI_aql_node_t* nameNode = TRI_AQL_NODE_MEMBER(node, 0);
|
||||
|
||||
StartScope(generator, &generator->_functionBuffer, TRI_AQL_SCOPE_FUNCTION, 0, 0, 0, resultRegister, NULL, "subquery");
|
||||
ScopeOutput(generator, "function ");
|
||||
ScopeOutputFunction(generator, subFunction);
|
||||
ScopeOutput(generator, " () {\n");
|
||||
InitList(generator, resultRegister);
|
||||
StartScope(generator, &generator->_buffer, TRI_AQL_SCOPE_SUBQUERY, 0, 0, 0, scopeRegister, NULL, "subquery");
|
||||
InitList(generator, scopeRegister);
|
||||
|
||||
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0));
|
||||
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1));
|
||||
|
||||
// register might have changed
|
||||
resultRegister = CurrentScope(generator)->_resultRegister;
|
||||
|
||||
ScopeOutput(generator, "return ");
|
||||
ScopeOutputRegister(generator, resultRegister);
|
||||
ScopeOutput(generator, ";\n");
|
||||
ScopeOutput(generator, "}\n");
|
||||
|
||||
scopeRegister = CurrentScope(generator)->_resultRegister;
|
||||
EndScope(generator);
|
||||
|
||||
ScopeOutput(generator, "var ");
|
||||
ScopeOutputRegister(generator, scopeRegister);
|
||||
ScopeOutputRegister(generator, resultRegister);
|
||||
ScopeOutput(generator, " = ");
|
||||
ScopeOutputFunction(generator, subFunction);
|
||||
ScopeOutput(generator, "();\n");
|
||||
ScopeOutputRegister(generator, scopeRegister);
|
||||
ScopeOutput(generator, ";\n");
|
||||
|
||||
CurrentScope(generator)->_resultRegister = scopeRegister;
|
||||
EnterSymbol(generator, nameNode->_value._value._string, resultRegister);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1190,11 +1183,7 @@ static void ProcessFcall (TRI_aql_codegen_js_t* const generator,
|
|||
|
||||
static void ProcessFor (TRI_aql_codegen_js_t* const generator,
|
||||
const TRI_aql_node_t* const node) {
|
||||
TRI_aql_node_t* nameNode;
|
||||
|
||||
nameNode = TRI_AQL_NODE_MEMBER(node, 0);
|
||||
|
||||
if (((TRI_aql_node_t*) TRI_AQL_NODE_MEMBER(node, 1))->_type != AQL_NODE_SUBQUERY) {
|
||||
TRI_aql_node_t* nameNode = TRI_AQL_NODE_MEMBER(node, 0);
|
||||
TRI_aql_codegen_register_t sourceRegister = IncRegister(generator);
|
||||
|
||||
ScopeOutput(generator, "var ");
|
||||
|
@ -1205,18 +1194,6 @@ static void ProcessFor (TRI_aql_codegen_js_t* const generator,
|
|||
|
||||
StartFor(generator, sourceRegister, nameNode->_value._value._string);
|
||||
}
|
||||
else {
|
||||
TRI_aql_codegen_register_t resultRegister = IncRegister(generator);
|
||||
TRI_aql_codegen_register_t sourceRegister;
|
||||
|
||||
InitList(generator, resultRegister);
|
||||
|
||||
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1));
|
||||
sourceRegister = CurrentScope(generator)->_resultRegister;
|
||||
CurrentScope(generator)->_resultRegister = resultRegister;
|
||||
StartFor(generator, sourceRegister, nameNode->_value._value._string);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate code for sort keyword
|
||||
|
@ -1443,6 +1420,25 @@ static void ProcessReturn (TRI_aql_codegen_js_t* const generator,
|
|||
CloseLoops(generator);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate code for let keyword
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void ProcessLet (TRI_aql_codegen_js_t* const generator,
|
||||
const TRI_aql_node_t* const node) {
|
||||
TRI_aql_node_t* nameNode = TRI_AQL_NODE_MEMBER(node, 0);
|
||||
TRI_aql_codegen_register_t resultRegister = IncRegister(generator);
|
||||
|
||||
ScopeOutput(generator, "var ");
|
||||
ScopeOutputRegister(generator, resultRegister);
|
||||
ScopeOutput(generator, " = ");
|
||||
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1));
|
||||
ScopeOutput(generator, ";\n");
|
||||
|
||||
// enter the new variable in the symbol table
|
||||
EnterSymbol(generator, nameNode->_value._value._string, resultRegister);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate code for an assignment (used in COLLECT)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1456,7 +1452,7 @@ static void ProcessAssign (TRI_aql_codegen_js_t* const generator,
|
|||
|
||||
InitList(generator, resultRegister);
|
||||
|
||||
StartScope(generator, scope->_buffer, TRI_AQL_SCOPE_LET, 0, 0, 0, resultRegister, NULL, "let");
|
||||
StartScope(generator, scope->_buffer, TRI_AQL_SCOPE_SUBQUERY, 0, 0, 0, resultRegister, NULL, "let");
|
||||
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1));
|
||||
|
||||
lastResultRegister = CurrentScope(generator)->_resultRegister;
|
||||
|
@ -1586,6 +1582,9 @@ static void ProcessNode (TRI_aql_codegen_js_t* generator, const TRI_aql_node_t*
|
|||
case AQL_NODE_FOR:
|
||||
ProcessFor(generator, node);
|
||||
break;
|
||||
case AQL_NODE_LET:
|
||||
ProcessLet(generator, node);
|
||||
break;
|
||||
case AQL_NODE_COLLECT:
|
||||
ProcessCollect(generator, node);
|
||||
break;
|
||||
|
|
|
@ -63,7 +63,7 @@ typedef uint32_t TRI_aql_codegen_register_t;
|
|||
|
||||
typedef enum {
|
||||
TRI_AQL_SCOPE_MAIN,
|
||||
TRI_AQL_SCOPE_LET,
|
||||
TRI_AQL_SCOPE_SUBQUERY,
|
||||
TRI_AQL_SCOPE_FOR,
|
||||
TRI_AQL_SCOPE_FOR_NESTED,
|
||||
TRI_AQL_SCOPE_FUNCTION,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +1,8 @@
|
|||
/* A Bison parser, made by GNU Bison 2.5. */
|
||||
|
||||
/* A Bison parser, made by GNU Bison 2.4.1. */
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
/* Skeleton interface for Bison's Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -96,7 +94,7 @@
|
|||
typedef union YYSTYPE
|
||||
{
|
||||
|
||||
/* Line 1676 of yacc.c */
|
||||
/* Line 2068 of yacc.c */
|
||||
#line 25 "Ahuacatl/ahuacatl-grammar.y"
|
||||
|
||||
TRI_aql_node_t* node;
|
||||
|
@ -106,8 +104,8 @@ typedef union YYSTYPE
|
|||
|
||||
|
||||
|
||||
/* Line 1676 of yacc.c */
|
||||
#line 111 "Ahuacatl/ahuacatl-grammar.h"
|
||||
/* Line 2068 of yacc.c */
|
||||
#line 109 "Ahuacatl/ahuacatl-grammar.h"
|
||||
} YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
|
|
|
@ -242,16 +242,8 @@ filter_statement:
|
|||
;
|
||||
|
||||
let_statement:
|
||||
T_LET variable_name {
|
||||
if (!TRI_PushStackParseAql(context, $2) || !TRI_StartScopeContextAql(context)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
} T_ASSIGN T_OPEN expression T_CLOSE {
|
||||
TRI_aql_node_t* node;
|
||||
|
||||
TRI_EndScopeContextAql(context);
|
||||
|
||||
node = TRI_CreateNodeAssignAql(context, TRI_PopStackParseAql(context), $6);
|
||||
T_LET variable_name T_ASSIGN T_OPEN expression T_CLOSE {
|
||||
TRI_aql_node_t* node = TRI_CreateNodeLetAql(context, $2, $5);
|
||||
if (!node) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
@ -429,12 +421,32 @@ expression:
|
|||
$$ = $2;
|
||||
}
|
||||
| T_OPEN query T_CLOSE {
|
||||
TRI_aql_node_t* node = TRI_CreateNodeSubqueryAql(context, $2);
|
||||
if (!node) {
|
||||
TRI_aql_node_t* subQuery;
|
||||
TRI_aql_node_t* result;
|
||||
TRI_aql_node_t* nameNode;
|
||||
|
||||
subQuery = TRI_CreateNodeSubqueryAql(context, $2);
|
||||
if (!subQuery) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
$$ = node;
|
||||
// push the sub query execution into the statement list
|
||||
if (!TRI_AddStatementAql(context, subQuery)) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
nameNode = TRI_AQL_NODE_MEMBER(subQuery, 0);
|
||||
if (!nameNode) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
result = TRI_CreateNodeReferenceAql(context, TRI_AQL_NODE_STRING(nameNode));
|
||||
if (!result) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
// return the result
|
||||
$$ = result;
|
||||
}
|
||||
| operator_unary {
|
||||
$$ = $1;
|
||||
|
|
|
@ -201,9 +201,14 @@ static void StartScope (TRI_aql_context_t* const context,
|
|||
/// @brief end an optimiser scope
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void EndScope (TRI_aql_context_t* const context) {
|
||||
static void EndScope (TRI_aql_context_t* const context, const bool isReturn) {
|
||||
TRI_aql_optimiser_scope_t* scope = CurrentScope(&context->_optimiser._scopes);
|
||||
|
||||
if (isReturn && (scope->_type == TRI_AQL_SCOPE_MAIN || scope->_type == TRI_AQL_SCOPE_SUBQUERY)) {
|
||||
// dont't close these scopes with a return as they are closed by other functions
|
||||
return;
|
||||
}
|
||||
|
||||
// we are closing at least one scope
|
||||
while (true) {
|
||||
TRI_aql_codegen_scope_e type = scope->_type;
|
||||
|
@ -838,9 +843,6 @@ static TRI_aql_node_t* ModifyNode (void* data, TRI_aql_node_t* node) {
|
|||
else if (node->_type == AQL_NODE_SUBQUERY) {
|
||||
StartScope(context, TRI_AQL_SCOPE_FUNCTION, NULL, NULL);
|
||||
}
|
||||
else if (node->_type == AQL_NODE_ASSIGN) {
|
||||
StartScope(context, TRI_AQL_SCOPE_LET, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
result = OptimiseNode(context, node);
|
||||
|
@ -849,13 +851,10 @@ static TRI_aql_node_t* ModifyNode (void* data, TRI_aql_node_t* node) {
|
|||
// scope handling
|
||||
if (node->_type == AQL_NODE_RETURN) {
|
||||
PatchForLoops(context);
|
||||
EndScope(context);
|
||||
EndScope(context, true);
|
||||
}
|
||||
else if (node->_type == AQL_NODE_SUBQUERY) {
|
||||
EndScope(context);
|
||||
}
|
||||
else if (node->_type == AQL_NODE_LET) {
|
||||
EndScope(context);
|
||||
EndScope(context, false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -897,7 +896,7 @@ TRI_aql_node_t* TRI_OptimiseAql (TRI_aql_context_t* const context,
|
|||
node = TRI_ModifyWalkTreeAql(walker, node);
|
||||
|
||||
#ifdef RANGE_OPTIMIZER
|
||||
EndScope(context);
|
||||
EndScope(context, false);
|
||||
#endif
|
||||
|
||||
TRI_FreeModifyTreeWalkerAql(walker);
|
||||
|
|
|
@ -133,6 +133,23 @@ void* TRI_PeekStackParseAql (TRI_aql_context_t* const context) {
|
|||
return context->_parser->_stack._buffer[context->_parser->_stack._length - 1];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a new unique variable name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_GetNameParseAql (TRI_aql_context_t* const context) {
|
||||
char buffer[16];
|
||||
|
||||
assert(context);
|
||||
|
||||
// fill buffer with 0 bytes
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
snprintf(buffer, sizeof(buffer) - 1, "_%d", (int) ++context->_variableIndex);
|
||||
|
||||
// register the string and return the copy of it
|
||||
return TRI_RegisterStringAql(context, buffer, strlen(buffer), false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -123,6 +123,12 @@ void* TRI_PopStackParseAql (TRI_aql_context_t* const);
|
|||
|
||||
void* TRI_PeekStackParseAql (TRI_aql_context_t* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a new unique variable name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_GetNameParseAql (TRI_aql_context_t* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue