1
0
Fork 0

fixed and simplified subqueries

This commit is contained in:
Jan Steemann 2012-05-10 11:17:01 +02:00
parent 4ceb707090
commit 85cde255e3
10 changed files with 1014 additions and 920 deletions

View File

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

View File

@ -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,

View File

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

View File

@ -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

View File

@ -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 */

View File

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

View File

@ -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);

View File

@ -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);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////