From bd60683228a2425eed3322b647e1bb4cbbef059f Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 11 Jun 2012 13:36:11 +0200 Subject: [PATCH] explain command, 1st version, still unfinished --- Makefile.in | 30 +- Makefile.unittests | 6 +- arangod/Ahuacatl/ahuacatl-bind-parameter.c | 9 +- arangod/Ahuacatl/ahuacatl-context.c | 50 +-- arangod/Ahuacatl/ahuacatl-context.h | 11 - arangod/Ahuacatl/ahuacatl-conversions.c | 250 +++++++++++++- arangod/Ahuacatl/ahuacatl-conversions.h | 15 + arangod/Ahuacatl/ahuacatl-explain.c | 328 +++++++++++++++++++ arangod/Ahuacatl/ahuacatl-explain.h | 92 ++++++ arangod/Ahuacatl/ahuacatl-node.c | 2 +- arangod/Ahuacatl/ahuacatl-optimiser.c | 24 +- arangod/Ahuacatl/ahuacatl-scope.c | 3 + arangod/Ahuacatl/ahuacatl-statement-dump.c | 28 +- arangod/Ahuacatl/ahuacatl-statement-walker.c | 31 +- arangod/Ahuacatl/ahuacatl-statement-walker.h | 34 +- arangod/Makefile.files | 1 + 16 files changed, 788 insertions(+), 126 deletions(-) create mode 100644 arangod/Ahuacatl/ahuacatl-explain.c create mode 100644 arangod/Ahuacatl/ahuacatl-explain.h diff --git a/Makefile.in b/Makefile.in index fd2328b0b3..f03564627a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -454,6 +454,7 @@ am__bin_arangod_SOURCES_DIST = arangod/Actions/actions.cpp \ arangod/Ahuacatl/ahuacatl-context.c \ arangod/Ahuacatl/ahuacatl-conversions.c \ arangod/Ahuacatl/ahuacatl-error.c \ + arangod/Ahuacatl/ahuacatl-explain.c \ arangod/Ahuacatl/ahuacatl-functions.c \ arangod/Ahuacatl/ahuacatl-grammar.c \ arangod/Ahuacatl/ahuacatl-index.c \ @@ -508,6 +509,7 @@ am_bin_arangod_OBJECTS = \ arangod/Ahuacatl/bin_arangod-ahuacatl-context.$(OBJEXT) \ arangod/Ahuacatl/bin_arangod-ahuacatl-conversions.$(OBJEXT) \ arangod/Ahuacatl/bin_arangod-ahuacatl-error.$(OBJEXT) \ + arangod/Ahuacatl/bin_arangod-ahuacatl-explain.$(OBJEXT) \ arangod/Ahuacatl/bin_arangod-ahuacatl-functions.$(OBJEXT) \ arangod/Ahuacatl/bin_arangod-ahuacatl-grammar.$(OBJEXT) \ arangod/Ahuacatl/bin_arangod-ahuacatl-index.$(OBJEXT) \ @@ -1209,6 +1211,7 @@ bin_arangod_SOURCES = arangod/Actions/actions.cpp \ arangod/Ahuacatl/ahuacatl-context.c \ arangod/Ahuacatl/ahuacatl-conversions.c \ arangod/Ahuacatl/ahuacatl-error.c \ + arangod/Ahuacatl/ahuacatl-explain.c \ arangod/Ahuacatl/ahuacatl-functions.c \ arangod/Ahuacatl/ahuacatl-grammar.c \ arangod/Ahuacatl/ahuacatl-index.c \ @@ -1327,8 +1330,7 @@ UNITTESTS_SERVER = $(addprefix --unit-tests ,$(SHELL_SERVER)) ################################################################################ ################################################################################ -SHELL_SERVER_AHUACATL = @srcdir@/js/server/tests/ahuacatl-operators.js \ - @srcdir@/js/server/tests/ahuacatl-escaping.js \ +SHELL_SERVER_AHUACATL = @srcdir@/js/server/tests/ahuacatl-escaping.js \ @srcdir@/js/server/tests/ahuacatl-functions.js \ @srcdir@/js/server/tests/ahuacatl-variables.js \ @srcdir@/js/server/tests/ahuacatl-bind.js \ @@ -1344,7 +1346,8 @@ SHELL_SERVER_AHUACATL = @srcdir@/js/server/tests/ahuacatl-operators.js \ @srcdir@/js/server/tests/ahuacatl-queries-variables.js \ @srcdir@/js/server/tests/ahuacatl-queries-geo.js \ @srcdir@/js/server/tests/ahuacatl-queries-collection.js \ - @srcdir@/js/server/tests/ahuacatl-queries-noncollection.js + @srcdir@/js/server/tests/ahuacatl-queries-noncollection.js \ + @srcdir@/js/server/tests/ahuacatl-operators.js UNITTESTS_SERVER_AHUACATL = $(addprefix --unit-tests ,$(SHELL_SERVER_AHUACATL)) @@ -2142,6 +2145,9 @@ arangod/Ahuacatl/bin_arangod-ahuacatl-conversions.$(OBJEXT): \ arangod/Ahuacatl/bin_arangod-ahuacatl-error.$(OBJEXT): \ arangod/Ahuacatl/$(am__dirstamp) \ arangod/Ahuacatl/$(DEPDIR)/$(am__dirstamp) +arangod/Ahuacatl/bin_arangod-ahuacatl-explain.$(OBJEXT): \ + arangod/Ahuacatl/$(am__dirstamp) \ + arangod/Ahuacatl/$(DEPDIR)/$(am__dirstamp) arangod/Ahuacatl/bin_arangod-ahuacatl-functions.$(OBJEXT): \ arangod/Ahuacatl/$(am__dirstamp) \ arangod/Ahuacatl/$(DEPDIR)/$(am__dirstamp) @@ -2419,6 +2425,7 @@ mostlyclean-compile: -rm -f arangod/Ahuacatl/bin_arangod-ahuacatl-context.$(OBJEXT) -rm -f arangod/Ahuacatl/bin_arangod-ahuacatl-conversions.$(OBJEXT) -rm -f arangod/Ahuacatl/bin_arangod-ahuacatl-error.$(OBJEXT) + -rm -f arangod/Ahuacatl/bin_arangod-ahuacatl-explain.$(OBJEXT) -rm -f arangod/Ahuacatl/bin_arangod-ahuacatl-functions.$(OBJEXT) -rm -f arangod/Ahuacatl/bin_arangod-ahuacatl-grammar.$(OBJEXT) -rm -f arangod/Ahuacatl/bin_arangod-ahuacatl-index.$(OBJEXT) @@ -2664,6 +2671,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-context.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-conversions.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-error.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-explain.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-functions.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-grammar.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-index.Po@am__quote@ @@ -3043,6 +3051,22 @@ arangod/Ahuacatl/bin_arangod-ahuacatl-error.obj: arangod/Ahuacatl/ahuacatl-error @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_arangod_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o arangod/Ahuacatl/bin_arangod-ahuacatl-error.obj `if test -f 'arangod/Ahuacatl/ahuacatl-error.c'; then $(CYGPATH_W) 'arangod/Ahuacatl/ahuacatl-error.c'; else $(CYGPATH_W) '$(srcdir)/arangod/Ahuacatl/ahuacatl-error.c'; fi` +arangod/Ahuacatl/bin_arangod-ahuacatl-explain.o: arangod/Ahuacatl/ahuacatl-explain.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_arangod_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT arangod/Ahuacatl/bin_arangod-ahuacatl-explain.o -MD -MP -MF arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-explain.Tpo -c -o arangod/Ahuacatl/bin_arangod-ahuacatl-explain.o `test -f 'arangod/Ahuacatl/ahuacatl-explain.c' || echo '$(srcdir)/'`arangod/Ahuacatl/ahuacatl-explain.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-explain.Tpo arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-explain.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='arangod/Ahuacatl/ahuacatl-explain.c' object='arangod/Ahuacatl/bin_arangod-ahuacatl-explain.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_arangod_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o arangod/Ahuacatl/bin_arangod-ahuacatl-explain.o `test -f 'arangod/Ahuacatl/ahuacatl-explain.c' || echo '$(srcdir)/'`arangod/Ahuacatl/ahuacatl-explain.c + +arangod/Ahuacatl/bin_arangod-ahuacatl-explain.obj: arangod/Ahuacatl/ahuacatl-explain.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_arangod_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT arangod/Ahuacatl/bin_arangod-ahuacatl-explain.obj -MD -MP -MF arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-explain.Tpo -c -o arangod/Ahuacatl/bin_arangod-ahuacatl-explain.obj `if test -f 'arangod/Ahuacatl/ahuacatl-explain.c'; then $(CYGPATH_W) 'arangod/Ahuacatl/ahuacatl-explain.c'; else $(CYGPATH_W) '$(srcdir)/arangod/Ahuacatl/ahuacatl-explain.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-explain.Tpo arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-explain.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='arangod/Ahuacatl/ahuacatl-explain.c' object='arangod/Ahuacatl/bin_arangod-ahuacatl-explain.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_arangod_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o arangod/Ahuacatl/bin_arangod-ahuacatl-explain.obj `if test -f 'arangod/Ahuacatl/ahuacatl-explain.c'; then $(CYGPATH_W) 'arangod/Ahuacatl/ahuacatl-explain.c'; else $(CYGPATH_W) '$(srcdir)/arangod/Ahuacatl/ahuacatl-explain.c'; fi` + arangod/Ahuacatl/bin_arangod-ahuacatl-functions.o: arangod/Ahuacatl/ahuacatl-functions.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_arangod_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT arangod/Ahuacatl/bin_arangod-ahuacatl-functions.o -MD -MP -MF arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-functions.Tpo -c -o arangod/Ahuacatl/bin_arangod-ahuacatl-functions.o `test -f 'arangod/Ahuacatl/ahuacatl-functions.c' || echo '$(srcdir)/'`arangod/Ahuacatl/ahuacatl-functions.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-functions.Tpo arangod/Ahuacatl/$(DEPDIR)/bin_arangod-ahuacatl-functions.Po diff --git a/Makefile.unittests b/Makefile.unittests index bcc95913c9..8f584470a6 100644 --- a/Makefile.unittests +++ b/Makefile.unittests @@ -178,8 +178,7 @@ unittests-shell-server: ## SHELL SERVER TESTS (AHUACATL) ################################################################################ -SHELL_SERVER_AHUACATL = @srcdir@/js/server/tests/ahuacatl-operators.js \ - @srcdir@/js/server/tests/ahuacatl-escaping.js \ +SHELL_SERVER_AHUACATL = @srcdir@/js/server/tests/ahuacatl-escaping.js \ @srcdir@/js/server/tests/ahuacatl-functions.js \ @srcdir@/js/server/tests/ahuacatl-variables.js \ @srcdir@/js/server/tests/ahuacatl-bind.js \ @@ -195,7 +194,8 @@ SHELL_SERVER_AHUACATL = @srcdir@/js/server/tests/ahuacatl-operators.js \ @srcdir@/js/server/tests/ahuacatl-queries-variables.js \ @srcdir@/js/server/tests/ahuacatl-queries-geo.js \ @srcdir@/js/server/tests/ahuacatl-queries-collection.js \ - @srcdir@/js/server/tests/ahuacatl-queries-noncollection.js + @srcdir@/js/server/tests/ahuacatl-queries-noncollection.js \ + @srcdir@/js/server/tests/ahuacatl-operators.js .PHONY: unittests-shell-server-ahuacatl diff --git a/arangod/Ahuacatl/ahuacatl-bind-parameter.c b/arangod/Ahuacatl/ahuacatl-bind-parameter.c index 1184aa174f..4c0a3d9642 100644 --- a/arangod/Ahuacatl/ahuacatl-bind-parameter.c +++ b/arangod/Ahuacatl/ahuacatl-bind-parameter.c @@ -42,7 +42,7 @@ /// @brief check if a node is a bind parameter and convert it into a value node //////////////////////////////////////////////////////////////////////////////// -static TRI_aql_node_t* ModifyNode (void* data, +static TRI_aql_node_t* ModifyNode (TRI_aql_statement_walker_t* const walker, TRI_aql_node_t* node) { TRI_aql_bind_parameter_t* bind; TRI_associative_pointer_t* bindValues; @@ -54,7 +54,7 @@ static TRI_aql_node_t* ModifyNode (void* data, } // we found a parameter node - context = (TRI_aql_context_t*) data; + context = (TRI_aql_context_t*) walker->_data; assert(context); bindValues = (TRI_associative_pointer_t*) &context->_parameters._values; @@ -68,7 +68,10 @@ static TRI_aql_node_t* ModifyNode (void* data, if (*name == '@') { // a collection name bind parameter if (bind->_value->_type == TRI_JSON_STRING) { - char* collectionName = TRI_RegisterStringAql(context, bind->_value->_value._string.data, strlen(bind->_value->_value._string.data), false); + char* collectionName = TRI_RegisterStringAql(context, + bind->_value->_value._string.data, + strlen(bind->_value->_value._string.data), + false); node = TRI_CreateNodeCollectionAql(context, collectionName); } else { diff --git a/arangod/Ahuacatl/ahuacatl-context.c b/arangod/Ahuacatl/ahuacatl-context.c index 15245b32df..d4518e861e 100644 --- a/arangod/Ahuacatl/ahuacatl-context.c +++ b/arangod/Ahuacatl/ahuacatl-context.c @@ -30,6 +30,7 @@ #include "Ahuacatl/ahuacatl-ast-node.h" #include "Ahuacatl/ahuacatl-bind-parameter.h" #include "Ahuacatl/ahuacatl-collections.h" +#include "Ahuacatl/ahuacatl-explain.h" #include "Ahuacatl/ahuacatl-optimiser.h" #include "Ahuacatl/ahuacatl-parser-functions.h" #include "Ahuacatl/ahuacatl-scope.h" @@ -340,6 +341,7 @@ bool TRI_OptimiseQueryContextAql (TRI_aql_context_t* const context) { return false; } + // TRI_ExplainAql(context); // TRI_DumpStatementsAql(context->_statements); return true; @@ -372,54 +374,6 @@ bool TRI_LockQueryContextAql (TRI_aql_context_t* const context) { return true; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief create a new variable scope -//////////////////////////////////////////////////////////////////////////////// - -TRI_aql_scope2_t* TRI_CreateScopeAql (void) { - TRI_aql_scope2_t* scope; - - scope = (TRI_aql_scope2_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_scope2_t), false); - if (!scope) { - return NULL; - } - - TRI_InitAssociativePointer(&scope->_variables, - TRI_UNKNOWN_MEM_ZONE, - &TRI_HashStringKeyAssociativePointer, - &TRI_HashVariableAql, - &TRI_EqualVariableAql, - 0); - - scope->_last = NULL; - - return scope; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief free a variable scope -//////////////////////////////////////////////////////////////////////////////// - -void TRI_FreeScopeAql (TRI_aql_scope2_t* const scope) { - size_t i, length; - - assert(scope); - - // free variables lookup hash - length = scope->_variables._nrAlloc; - for (i = 0; i < length; ++i) { - TRI_aql_variable_t* variable = scope->_variables._table[i]; - - if (variable) { - TRI_FreeVariableAql(variable); - } - } - - TRI_DestroyAssociativePointer(&scope->_variables); - - TRI_Free(TRI_UNKNOWN_MEM_ZONE, scope); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief register a node //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Ahuacatl/ahuacatl-context.h b/arangod/Ahuacatl/ahuacatl-context.h index e7a4e2f470..e2269d0193 100644 --- a/arangod/Ahuacatl/ahuacatl-context.h +++ b/arangod/Ahuacatl/ahuacatl-context.h @@ -55,17 +55,6 @@ extern "C" { /// @{ //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// @brief a variable scope -//////////////////////////////////////////////////////////////////////////////// - -typedef struct TRI_aql_scope2_s { - struct TRI_aql_scope_s* _parent; // parent scope - TRI_associative_pointer_t _variables; // symbol table - void* _last; -} -TRI_aql_scope2_t; - //////////////////////////////////////////////////////////////////////////////// /// @brief the context for parsing a query //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Ahuacatl/ahuacatl-conversions.c b/arangod/Ahuacatl/ahuacatl-conversions.c index 292113594d..e8c89216e0 100644 --- a/arangod/Ahuacatl/ahuacatl-conversions.c +++ b/arangod/Ahuacatl/ahuacatl-conversions.c @@ -26,13 +26,85 @@ //////////////////////////////////////////////////////////////////////////////// #include "Ahuacatl/ahuacatl-conversions.h" +#include "Ahuacatl/ahuacatl-node.h" + +// ----------------------------------------------------------------------------- +// --SECTION-- private types +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief typedef for value list iteration callback function +//////////////////////////////////////////////////////////////////////////////// + +typedef bool (*convert_f) (TRI_string_buffer_t* const, const TRI_aql_node_t* const); + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- private functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +static const char* GetStringOperator (const TRI_aql_node_type_e type) { + switch (type) { + case TRI_AQL_NODE_OPERATOR_UNARY_PLUS: + return " + "; + case TRI_AQL_NODE_OPERATOR_UNARY_MINUS: + return " - "; + case TRI_AQL_NODE_OPERATOR_UNARY_NOT: + return " ! "; + case TRI_AQL_NODE_OPERATOR_BINARY_AND: + return " && "; + case TRI_AQL_NODE_OPERATOR_BINARY_OR: + return " || "; + case TRI_AQL_NODE_OPERATOR_BINARY_PLUS: + return " + "; + case TRI_AQL_NODE_OPERATOR_BINARY_MINUS: + return " - "; + case TRI_AQL_NODE_OPERATOR_BINARY_TIMES: + return " * "; + case TRI_AQL_NODE_OPERATOR_BINARY_DIV: + return " / "; + case TRI_AQL_NODE_OPERATOR_BINARY_MOD: + return " % "; + case TRI_AQL_NODE_OPERATOR_BINARY_EQ: + return " == "; + case TRI_AQL_NODE_OPERATOR_BINARY_NE: + return " != "; + case TRI_AQL_NODE_OPERATOR_BINARY_LT: + return " < "; + case TRI_AQL_NODE_OPERATOR_BINARY_LE: + return " <= "; + case TRI_AQL_NODE_OPERATOR_BINARY_GT: + return " > "; + case TRI_AQL_NODE_OPERATOR_BINARY_GE: + return " >= "; + case TRI_AQL_NODE_OPERATOR_BINARY_IN: + return " in "; + default: + assert(false); + return NULL; + } +} //////////////////////////////////////////////////////////////////////////////// /// @brief append list values to a string buffer //////////////////////////////////////////////////////////////////////////////// static bool AppendListValues (TRI_string_buffer_t* const buffer, - const TRI_aql_node_t* const node) { + const TRI_aql_node_t* const node, + convert_f func) { size_t i, n; n = node->_members._length; @@ -43,7 +115,7 @@ static bool AppendListValues (TRI_string_buffer_t* const buffer, } } - if (!TRI_NodeJavascriptAql(buffer, TRI_AQL_NODE_MEMBER(node, i))) { + if (!func(buffer, TRI_AQL_NODE_MEMBER(node, i))) { return false; } } @@ -51,6 +123,10 @@ static bool AppendListValues (TRI_string_buffer_t* const buffer, return true; } +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- @@ -307,7 +383,7 @@ bool TRI_NodeJavascriptAql (TRI_string_buffer_t* const buffer, return false; } - if (!AppendListValues(buffer, node)) { + if (!AppendListValues(buffer, node, &TRI_NodeJavascriptAql)) { return false; } @@ -317,7 +393,7 @@ bool TRI_NodeJavascriptAql (TRI_string_buffer_t* const buffer, return false; } - if (!AppendListValues(buffer, node)) { + if (!AppendListValues(buffer, node, &TRI_NodeJavascriptAql)) { return false; } @@ -327,6 +403,172 @@ bool TRI_NodeJavascriptAql (TRI_string_buffer_t* const buffer, } } +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert a value node to a string representation, used for printing it +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_ValueStringAql (TRI_string_buffer_t* const buffer, + const TRI_aql_value_t* const value, + const TRI_aql_value_type_e type) { + switch (type) { + case TRI_AQL_TYPE_FAIL: + return (TRI_AppendStringStringBuffer(buffer, "fail") == TRI_ERROR_NO_ERROR); + + case TRI_AQL_TYPE_NULL: + return (TRI_AppendStringStringBuffer(buffer, "null") == TRI_ERROR_NO_ERROR); + + case TRI_AQL_TYPE_BOOL: + return (TRI_AppendStringStringBuffer(buffer, value->_value._bool ? "true" : "false") == TRI_ERROR_NO_ERROR); + + case TRI_AQL_TYPE_INT: + return (TRI_AppendInt64StringBuffer(buffer, value->_value._int) == TRI_ERROR_NO_ERROR); + + case TRI_AQL_TYPE_DOUBLE: + return (TRI_AppendDoubleStringBuffer(buffer, value->_value._double) == TRI_ERROR_NO_ERROR); + + case TRI_AQL_TYPE_STRING: { + if (TRI_AppendCharStringBuffer(buffer, '"') != TRI_ERROR_NO_ERROR) { + return false; + } + + if (TRI_AppendStringStringBuffer(buffer, value->_value._string) != TRI_ERROR_NO_ERROR) { + return false; + } + + return (TRI_AppendCharStringBuffer(buffer, '"') == TRI_ERROR_NO_ERROR); + } + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert a node to its string representation, used for printing it +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_NodeStringAql (TRI_string_buffer_t* const buffer, + const TRI_aql_node_t* const node) { + switch (node->_type) { + case TRI_AQL_NODE_VALUE: + return TRI_ValueStringAql(buffer, &node->_value, node->_value._type); + case TRI_AQL_NODE_ARRAY_ELEMENT: + if (!TRI_ValueStringAql(buffer, &node->_value, TRI_AQL_TYPE_STRING)) { + return false; + } + + if (TRI_AppendCharStringBuffer(buffer, ':') != TRI_ERROR_NO_ERROR) { + return false; + } + + return TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 0)); + case TRI_AQL_NODE_LIST: + if (TRI_AppendCharStringBuffer(buffer, '[') != TRI_ERROR_NO_ERROR) { + return false; + } + + if (!AppendListValues(buffer, node, &TRI_NodeStringAql)) { + return false; + } + + return (TRI_AppendCharStringBuffer(buffer, ']') == TRI_ERROR_NO_ERROR); + case TRI_AQL_NODE_ARRAY: + if (TRI_AppendCharStringBuffer(buffer, '{') != TRI_ERROR_NO_ERROR) { + return false; + } + + if (!AppendListValues(buffer, node, &TRI_NodeStringAql)) { + return false; + } + + return (TRI_AppendCharStringBuffer(buffer, '}') == TRI_ERROR_NO_ERROR); + case TRI_AQL_NODE_OPERATOR_UNARY_PLUS: + case TRI_AQL_NODE_OPERATOR_UNARY_MINUS: + case TRI_AQL_NODE_OPERATOR_UNARY_NOT: + if (!TRI_AppendStringStringBuffer(buffer, GetStringOperator(node->_type)) == TRI_ERROR_NO_ERROR) { + return false; + } + return TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 0)); + case TRI_AQL_NODE_OPERATOR_BINARY_AND: + case TRI_AQL_NODE_OPERATOR_BINARY_OR: + case TRI_AQL_NODE_OPERATOR_BINARY_PLUS: + case TRI_AQL_NODE_OPERATOR_BINARY_MINUS: + case TRI_AQL_NODE_OPERATOR_BINARY_TIMES: + case TRI_AQL_NODE_OPERATOR_BINARY_DIV: + case TRI_AQL_NODE_OPERATOR_BINARY_MOD: + case TRI_AQL_NODE_OPERATOR_BINARY_EQ: + case TRI_AQL_NODE_OPERATOR_BINARY_NE: + case TRI_AQL_NODE_OPERATOR_BINARY_LT: + case TRI_AQL_NODE_OPERATOR_BINARY_LE: + case TRI_AQL_NODE_OPERATOR_BINARY_GT: + case TRI_AQL_NODE_OPERATOR_BINARY_GE: + case TRI_AQL_NODE_OPERATOR_BINARY_IN: + if (!TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 0))) { + return false; + } + + if (!TRI_AppendStringStringBuffer(buffer, GetStringOperator(node->_type)) == TRI_ERROR_NO_ERROR) { + return false; + } + return TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 1)); + case TRI_AQL_NODE_OPERATOR_TERNARY: + if (!TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 0))) { + return false; + } + + if (!TRI_AppendStringStringBuffer(buffer, " ? ") == TRI_ERROR_NO_ERROR) { + return false; + } + + if (!TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 1))) { + return false; + } + + if (!TRI_AppendStringStringBuffer(buffer, " : ") == TRI_ERROR_NO_ERROR) { + return false; + } + + return TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 2)); + case TRI_AQL_NODE_ATTRIBUTE_ACCESS: + if (!TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 0))) { + return false; + } + + if (!TRI_AppendStringStringBuffer(buffer, ".") == TRI_ERROR_NO_ERROR) { + return false; + } + + return TRI_AppendStringStringBuffer(buffer, TRI_AQL_NODE_STRING(node)) == TRI_ERROR_NO_ERROR; + case TRI_AQL_NODE_INDEXED: + if (!TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 0))) { + return false; + } + + if (!TRI_AppendStringStringBuffer(buffer, "[") == TRI_ERROR_NO_ERROR) { + return false; + } + + if (!TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 1))) { + return false; + } + + return TRI_AppendStringStringBuffer(buffer, "]") == TRI_ERROR_NO_ERROR; + case TRI_AQL_NODE_EXPAND: + // TODO + break; + case TRI_AQL_NODE_REFERENCE: + return TRI_AppendStringStringBuffer(buffer, TRI_AQL_NODE_STRING(node)) == TRI_ERROR_NO_ERROR; + case TRI_AQL_NODE_COLLECTION: + if (!TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 0))) { + return false; + } + return true; + default: { + } + } + + return true; +} + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Ahuacatl/ahuacatl-conversions.h b/arangod/Ahuacatl/ahuacatl-conversions.h index 1d16ce8734..bebec5959f 100644 --- a/arangod/Ahuacatl/ahuacatl-conversions.h +++ b/arangod/Ahuacatl/ahuacatl-conversions.h @@ -77,6 +77,21 @@ bool TRI_ValueJavascriptAql (TRI_string_buffer_t* const, bool TRI_NodeJavascriptAql (TRI_string_buffer_t* const, const TRI_aql_node_t* const); +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert a value node to a string representation +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_ValueStringAql (TRI_string_buffer_t* const, + const TRI_aql_value_t* const, + const TRI_aql_value_type_e); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert a node to its string representation, used for printing it +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_NodeStringAql (TRI_string_buffer_t* const , + const TRI_aql_node_t* const); + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Ahuacatl/ahuacatl-explain.c b/arangod/Ahuacatl/ahuacatl-explain.c new file mode 100644 index 0000000000..7b17cd8758 --- /dev/null +++ b/arangod/Ahuacatl/ahuacatl-explain.c @@ -0,0 +1,328 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief Ahuacatl, explain +/// +/// @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 +//////////////////////////////////////////////////////////////////////////////// + +#include "Ahuacatl/ahuacatl-explain.h" +#include "Ahuacatl/ahuacatl-conversions.h" +#include "Ahuacatl/ahuacatl-scope.h" +#include "Ahuacatl/ahuacatl-statement-walker.h" + +// ----------------------------------------------------------------------------- +// --SECTION-- private functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert a node to its string representation +//////////////////////////////////////////////////////////////////////////////// + +static TRI_json_t* StringifyNode (const TRI_aql_node_t* const node) { + TRI_json_t* result; + TRI_string_buffer_t buffer; + + assert(node); + + TRI_InitStringBuffer(&buffer, TRI_UNKNOWN_MEM_ZONE); + + if (!TRI_NodeStringAql(&buffer, node)) { + return NULL; + } + + result = TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, buffer._buffer); + + TRI_DestroyStringBuffer(&buffer); + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief add a row to the result json structure +//////////////////////////////////////////////////////////////////////////////// + +static inline bool AddRow (TRI_aql_explain_t* const explain, TRI_json_t* value) { + return TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, explain->_result, value) == TRI_ERROR_NO_ERROR; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get an empty row protoype +//////////////////////////////////////////////////////////////////////////////// + +static inline TRI_json_t* GetRowProtoType (TRI_aql_explain_t* const explain, + const TRI_aql_node_t* const node) { + TRI_json_t* row; + + row = TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE); + if (row == NULL) { + return NULL; + } + + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, + row, + "id", + TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, (double) ++explain->_count)); + + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, + row, + "level", + TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, (double) explain->_level - 1)); + + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, + row, + "type", + TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, TRI_NodeNameAql(node->_type))); + + return row; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief create an explain structure +//////////////////////////////////////////////////////////////////////////////// + +static TRI_aql_explain_t* CreateExplain (void) { + TRI_aql_explain_t* explain; + + explain = (TRI_aql_explain_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_explain_t), false); + + if (explain == NULL) { + return NULL; + } + + explain->_count = 0; + explain->_level = 0; + + explain->_result = TRI_CreateListJson(TRI_UNKNOWN_MEM_ZONE); + if (explain->_result == NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, explain); + + return NULL; + } + + return explain; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief free an explain structure +//////////////////////////////////////////////////////////////////////////////// + +static void FreeExplain (TRI_aql_explain_t* const explain) { + assert(explain); + assert(explain->_result); + + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, explain->_result); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, explain); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief process a single statement +//////////////////////////////////////////////////////////////////////////////// + +static TRI_aql_node_t* ProcessStatement (TRI_aql_statement_walker_t* const walker, + TRI_aql_node_t* node) { + TRI_aql_explain_t* explain; + TRI_aql_node_type_e type = node->_type; + + explain = (TRI_aql_explain_t*) walker->_data; + + switch (type) { + case TRI_AQL_NODE_SCOPE_START: { + ++explain->_level; + break; + } + case TRI_AQL_NODE_SCOPE_END: { + --explain->_level; + break; + } + case TRI_AQL_NODE_FOR: { + TRI_aql_node_t* variableNode = TRI_AQL_NODE_MEMBER(node, 0); + TRI_aql_node_t* expressionNode = TRI_AQL_NODE_MEMBER(node, 1); + TRI_json_t* row; + TRI_json_t* condition; + + row = GetRowProtoType(explain, node); + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, + row, + "variable", + TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, TRI_AQL_NODE_STRING(variableNode))); + + condition = StringifyNode(expressionNode); + if (condition != NULL) { + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, + row, + "value", + condition); + } + AddRow(explain, row); + break; + } + case TRI_AQL_NODE_FILTER: { + // TODO + TRI_aql_node_t* expressionNode = TRI_AQL_NODE_MEMBER(node, 0); + TRI_json_t* row; + TRI_json_t* condition; + + row = GetRowProtoType(explain, node); + condition = StringifyNode(expressionNode); + if (condition != NULL) { + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, + row, + "condition", + condition); + } + AddRow(explain, row); + break; + } + case TRI_AQL_NODE_LET: { + // TODO + TRI_json_t* row; + + TRI_aql_node_t* variableNode = TRI_AQL_NODE_MEMBER(node, 0); + + row = GetRowProtoType(explain, node); + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, + row, + "variable", + TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, TRI_AQL_NODE_STRING(variableNode))); + AddRow(explain, row); + break; + } + case TRI_AQL_NODE_SORT: { + // TODO + /* + TRI_aql_node_t* conditionNode = TRI_AQL_NODE_MEMBER(node, 0); + + value = GetRowProtoType(explain, node); + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, + value, + "condition", + TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, TRI_AQL_NODE_STRING(variableNode))); + AddRow(explain, value); + */ + break; + } + case TRI_AQL_NODE_LIMIT: { + TRI_aql_node_t* offsetNode = TRI_AQL_NODE_MEMBER(node, 0); + TRI_aql_node_t* countNode = TRI_AQL_NODE_MEMBER(node, 1); + TRI_json_t* row; + + row = GetRowProtoType(explain, node); + + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, + row, + "offset", + TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, TRI_AQL_NODE_DOUBLE(offsetNode))); + + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, + row, + "count", + TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, (double) TRI_AQL_NODE_DOUBLE(countNode))); + + AddRow(explain, row); + break; + } + + case TRI_AQL_NODE_COLLECT: { + // TODO + break; + } + + default: { + } + } + + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief explain a query +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_ExplainAql (TRI_aql_context_t* const context) { + TRI_aql_statement_walker_t* walker; + TRI_aql_explain_t* explain; + + explain = CreateExplain(); + if (explain == NULL) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + + return false; + } + + walker = TRI_CreateStatementWalkerAql((void*) explain, + false, + NULL, + &ProcessStatement, + NULL); + + if (walker == NULL) { + FreeExplain(explain); + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + + return false; + } + + TRI_WalkStatementsAql(walker, context->_statements); + + { // TODO: move to function + TRI_string_buffer_t sb; + + TRI_InitStringBuffer(&sb, TRI_UNKNOWN_MEM_ZONE); + TRI_StringifyJson(&sb, explain->_result); + printf("%s\n", sb._buffer); + TRI_DestroyStringBuffer(&sb); + } + + FreeExplain(explain); + + TRI_FreeStatementWalkerAql(walker); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: diff --git a/arangod/Ahuacatl/ahuacatl-explain.h b/arangod/Ahuacatl/ahuacatl-explain.h new file mode 100644 index 0000000000..17fefbdcf3 --- /dev/null +++ b/arangod/Ahuacatl/ahuacatl-explain.h @@ -0,0 +1,92 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief Ahuacatl, explain +/// +/// @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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TRIAGENS_DURHAM_AHUACATL_EXPLAIN_H +#define TRIAGENS_DURHAM_AHUACATL_EXPLAIN_H 1 + +#include +#include +#include + +#include "Ahuacatl/ahuacatl-context.h" +#include "Ahuacatl/ahuacatl-node.h" +#include "Ahuacatl/ahuacatl-log.h" +#include "Ahuacatl/ahuacatl-scope.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ----------------------------------------------------------------------------- +// --SECTION-- public types +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +typedef struct TRI_aql_explain_s { + size_t _count; + size_t _level; + TRI_json_t* _result; +} +TRI_aql_explain_t; + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief explain a query +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_ExplainAql (TRI_aql_context_t* const); + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +} +#endif + +#endif + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: diff --git a/arangod/Ahuacatl/ahuacatl-node.c b/arangod/Ahuacatl/ahuacatl-node.c index cbeb7fdc40..bcff2b4098 100644 --- a/arangod/Ahuacatl/ahuacatl-node.c +++ b/arangod/Ahuacatl/ahuacatl-node.c @@ -149,7 +149,7 @@ const char* TRI_NodeNameAql (const TRI_aql_node_type_e type) { case TRI_AQL_NODE_FCALL: return "function call"; } - + assert(false); return "undefined"; } diff --git a/arangod/Ahuacatl/ahuacatl-optimiser.c b/arangod/Ahuacatl/ahuacatl-optimiser.c index fa53c7b7a7..78f386fd04 100644 --- a/arangod/Ahuacatl/ahuacatl-optimiser.c +++ b/arangod/Ahuacatl/ahuacatl-optimiser.c @@ -46,13 +46,15 @@ /// @brief optimise a node recursively //////////////////////////////////////////////////////////////////////////////// -static TRI_aql_node_t* ProcessNode (void*, TRI_aql_node_t*); +static TRI_aql_node_t* ProcessNode (TRI_aql_statement_walker_t* const, + TRI_aql_node_t*); //////////////////////////////////////////////////////////////////////////////// /// @brief optimise a statement //////////////////////////////////////////////////////////////////////////////// -static TRI_aql_node_t* ProcessStatement (void*, TRI_aql_node_t*); +static TRI_aql_node_t* ProcessStatement (TRI_aql_statement_walker_t* const, + TRI_aql_node_t*); //////////////////////////////////////////////////////////////////////////////// /// @} @@ -980,8 +982,9 @@ static TRI_aql_node_t* OptimiseStatement (TRI_aql_context_t* const context, /// this is the callback function used by the statement walker //////////////////////////////////////////////////////////////////////////////// -static TRI_aql_node_t* ProcessNode (void* data, TRI_aql_node_t* node) { - TRI_aql_context_t* context = (TRI_aql_context_t*) data; +static TRI_aql_node_t* ProcessNode (TRI_aql_statement_walker_t* const walker, + TRI_aql_node_t* node) { + TRI_aql_context_t* context = (TRI_aql_context_t*) walker->_data; return OptimiseNode(context, node); } @@ -992,8 +995,9 @@ static TRI_aql_node_t* ProcessNode (void* data, TRI_aql_node_t* node) { /// this is the callback function used by the statement walker //////////////////////////////////////////////////////////////////////////////// -static TRI_aql_node_t* ProcessStatement (void* data, TRI_aql_node_t* node) { - TRI_aql_context_t* context = (TRI_aql_context_t*) data; +static TRI_aql_node_t* ProcessStatement (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_node_t* result = node; if (node) { @@ -1003,9 +1007,6 @@ static TRI_aql_node_t* ProcessStatement (void* data, TRI_aql_node_t* node) { StartScope(context, TRI_AQL_SCOPE_FOR, node, TRI_AQL_NODE_STRING(nameNode)); } -/* else if (node->_type == TRI_AQL_NODE_SUBQUERY) { - StartScope(context, TRI_AQL_SCOPE_FUNCTION, NULL, NULL); - }*/ // TODO: REMOVE result = OptimiseStatement(context, node); @@ -1014,11 +1015,6 @@ static TRI_aql_node_t* ProcessStatement (void* data, TRI_aql_node_t* node) { PatchForLoops(context); EndScope(context, true); } - /* TODO: REMOVE - else if (node->_type == TRI_AQL_NODE_SUBQUERY) { - EndScope(context, false); - } - */ } return result; diff --git a/arangod/Ahuacatl/ahuacatl-scope.c b/arangod/Ahuacatl/ahuacatl-scope.c index a443c2f66b..a66d6d0db4 100644 --- a/arangod/Ahuacatl/ahuacatl-scope.c +++ b/arangod/Ahuacatl/ahuacatl-scope.c @@ -74,6 +74,9 @@ static inline TRI_aql_scope_e CurrentType (TRI_aql_context_t* const context) { //////////////////////////////////////////////////////////////////////////////// /// @brief get the type for the next scope +/// +/// this returns TRI_AQL_SCOPE_FOR_NESTED for a nested for scope, and the +/// originally requested type in all other cases //////////////////////////////////////////////////////////////////////////////// static TRI_aql_scope_e NextType (TRI_aql_context_t* const context, diff --git a/arangod/Ahuacatl/ahuacatl-statement-dump.c b/arangod/Ahuacatl/ahuacatl-statement-dump.c index 2150bc9c8b..ca21ea42c4 100644 --- a/arangod/Ahuacatl/ahuacatl-statement-dump.c +++ b/arangod/Ahuacatl/ahuacatl-statement-dump.c @@ -101,9 +101,7 @@ static void DumpValue (TRI_aql_dump_t* const state, const TRI_aql_node_t* const /// @brief increase the indent level by one //////////////////////////////////////////////////////////////////////////////// -static void Indent (void* data) { - TRI_aql_dump_t* state = (TRI_aql_dump_t*) data; - +static inline void Indent (TRI_aql_dump_t* const state) { ++state->_indent; } @@ -111,8 +109,7 @@ static void Indent (void* data) { /// @brief decrease the indent level by one //////////////////////////////////////////////////////////////////////////////// -static void Outdent (void* data) { - TRI_aql_dump_t* state = (TRI_aql_dump_t*) data; +static inline void Outdent (TRI_aql_dump_t* const state) { assert(state->_indent > 0); --state->_indent; @@ -122,13 +119,16 @@ static void Outdent (void* data) { /// @brief dump an AST node //////////////////////////////////////////////////////////////////////////////// -static TRI_aql_node_t* DumpNode (void* data, TRI_aql_node_t* const node) { - TRI_aql_dump_t* state = (TRI_aql_dump_t*) data; +static TRI_aql_node_t* DumpNode (TRI_aql_statement_walker_t* const walker, + TRI_aql_node_t* const node) { + TRI_aql_dump_t* state = (TRI_aql_dump_t*) walker->_data; if (node == NULL) { return node; } + assert(state); + PrintType(state, node->_type); Indent(state); @@ -168,26 +168,30 @@ static TRI_aql_node_t* DumpNode (void* data, TRI_aql_node_t* const node) { /// @brief dump a statement //////////////////////////////////////////////////////////////////////////////// -static TRI_aql_node_t* DumpStatementStart (void* data, TRI_aql_node_t* const node) { +static TRI_aql_node_t* DumpStatementStart (TRI_aql_statement_walker_t* const walker, + TRI_aql_node_t* const node) { if (node == NULL) { return node; } - Indent((TRI_aql_dump_t*) data); + assert(walker); + Indent((TRI_aql_dump_t*) walker->_data); - return DumpNode(data, node); + return DumpNode(walker, node); } //////////////////////////////////////////////////////////////////////////////// /// @brief dump an AST node //////////////////////////////////////////////////////////////////////////////// -static TRI_aql_node_t* DumpStatementEnd (void* data, TRI_aql_node_t* const node) { +static TRI_aql_node_t* DumpStatementEnd (TRI_aql_statement_walker_t* const walker, + TRI_aql_node_t* const node) { if (node == NULL) { return node; } - Outdent((TRI_aql_dump_t*) data); + assert(walker); + Outdent((TRI_aql_dump_t*) walker->_data); return node; } diff --git a/arangod/Ahuacatl/ahuacatl-statement-walker.c b/arangod/Ahuacatl/ahuacatl-statement-walker.c index d0c9b549bb..e5643cbe59 100644 --- a/arangod/Ahuacatl/ahuacatl-statement-walker.c +++ b/arangod/Ahuacatl/ahuacatl-statement-walker.c @@ -46,14 +46,25 @@ static void VisitStatement (TRI_aql_statement_walker_t* const walker, const size_t position, - TRI_aql_visit_statement_f func) { + TRI_aql_visit_f func) { TRI_aql_node_t* node; TRI_aql_node_t* modified; node = (TRI_aql_node_t*) TRI_AtVectorPointer(&walker->_statements->_statements, position); assert(node); - modified = func(walker->_data, node); + // handle scopes + if (node->_type == TRI_AQL_NODE_SCOPE_START) { + TRI_PushBackVectorPointer(&walker->_currentScopes, TRI_AQL_NODE_DATA(node)); + } + else if (node->_type == TRI_AQL_NODE_SCOPE_END) { + size_t n = walker->_currentScopes._length; + + assert(n > 0); + TRI_RemoveVectorPointer(&walker->_currentScopes, n - 1); + } + + modified = func(walker, node); if (walker->_canModify && modified != node) { if (modified == NULL) { modified = TRI_GetNopNodeAql(); @@ -86,7 +97,7 @@ static void VisitMembers (TRI_aql_statement_walker_t* const walker, VisitMembers(walker, member); - modified = walker->visitMember(walker->_data, member); + modified = walker->visitMember(walker, member); if (walker->_canModify && modified != member) { if (modified == NULL) { modified = TRI_GetNopNodeAql(); @@ -112,6 +123,10 @@ static void RunWalk (TRI_aql_statement_walker_t* const walker) { node = (TRI_aql_node_t*) TRI_AtVectorPointer(&walker->_statements->_statements, i); + if (!node) { + continue; + } + if (walker->preVisitStatement != NULL) { // this might change the node ptr VisitStatement(walker, i, walker->preVisitStatement); @@ -148,9 +163,9 @@ static void RunWalk (TRI_aql_statement_walker_t* const walker) { TRI_aql_statement_walker_t* TRI_CreateStatementWalkerAql (void* data, const bool canModify, - TRI_aql_visit_node_f visitMember, - TRI_aql_visit_statement_f preVisitStatement, - TRI_aql_visit_statement_f postVisitStatement) { + TRI_aql_visit_f visitMember, + TRI_aql_visit_f preVisitStatement, + TRI_aql_visit_f postVisitStatement) { TRI_aql_statement_walker_t* walker; walker = (TRI_aql_statement_walker_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_statement_walker_t), false); @@ -165,6 +180,8 @@ TRI_aql_statement_walker_t* TRI_CreateStatementWalkerAql (void* data, walker->preVisitStatement = preVisitStatement; walker->postVisitStatement = postVisitStatement; + TRI_InitVectorPointer(&walker->_currentScopes, TRI_UNKNOWN_MEM_ZONE); + return walker; } @@ -175,6 +192,8 @@ TRI_aql_statement_walker_t* TRI_CreateStatementWalkerAql (void* data, void TRI_FreeStatementWalkerAql (TRI_aql_statement_walker_t* const walker) { assert(walker); + TRI_DestroyVectorPointer(&walker->_currentScopes); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, walker); } diff --git a/arangod/Ahuacatl/ahuacatl-statement-walker.h b/arangod/Ahuacatl/ahuacatl-statement-walker.h index e4aa07e1ed..c1c8899afe 100644 --- a/arangod/Ahuacatl/ahuacatl-statement-walker.h +++ b/arangod/Ahuacatl/ahuacatl-statement-walker.h @@ -30,10 +30,7 @@ #include #include -#include #include -#include -#include #include "Ahuacatl/ahuacatl-ast-node.h" #include "Ahuacatl/ahuacatl-context.h" @@ -56,18 +53,6 @@ extern "C" { /// @{ //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// @brief typedef for node visitation function -//////////////////////////////////////////////////////////////////////////////// - -typedef TRI_aql_node_t* (*TRI_aql_visit_node_f)(void*, TRI_aql_node_t*); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief typedef for statement visitation function -//////////////////////////////////////////////////////////////////////////////// - -typedef TRI_aql_node_t* (*TRI_aql_visit_statement_f)(void*, TRI_aql_node_t*); - //////////////////////////////////////////////////////////////////////////////// /// @brief tree walker container //////////////////////////////////////////////////////////////////////////////// @@ -76,13 +61,20 @@ typedef struct TRI_aql_statement_walker_s { void* _data; bool _canModify; TRI_aql_statement_list_t* _statements; + TRI_vector_pointer_t _currentScopes; - TRI_aql_visit_node_f visitMember; - TRI_aql_visit_statement_f preVisitStatement; - TRI_aql_visit_statement_f postVisitStatement; + TRI_aql_node_t* (*visitMember)(struct TRI_aql_statement_walker_s* const, TRI_aql_node_t*); + TRI_aql_node_t* (*preVisitStatement)(struct TRI_aql_statement_walker_s* const, TRI_aql_node_t*); + TRI_aql_node_t* (*postVisitStatement)(struct TRI_aql_statement_walker_s* const, TRI_aql_node_t*); } TRI_aql_statement_walker_t; +//////////////////////////////////////////////////////////////////////////////// +/// @brief typedef for node visitation function +//////////////////////////////////////////////////////////////////////////////// + +typedef TRI_aql_node_t* (*TRI_aql_visit_f)(TRI_aql_statement_walker_t* const, TRI_aql_node_t*); + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// @@ -102,9 +94,9 @@ TRI_aql_statement_walker_t; TRI_aql_statement_walker_t* TRI_CreateStatementWalkerAql (void*, const bool, - TRI_aql_visit_node_f, - TRI_aql_visit_statement_f, - TRI_aql_visit_statement_f); + TRI_aql_visit_f, + TRI_aql_visit_f, + TRI_aql_visit_f); //////////////////////////////////////////////////////////////////////////////// /// @brief free a statement walker diff --git a/arangod/Makefile.files b/arangod/Makefile.files index cb04f77c84..ae490ae232 100644 --- a/arangod/Makefile.files +++ b/arangod/Makefile.files @@ -23,6 +23,7 @@ bin_arangod_SOURCES = \ arangod/Ahuacatl/ahuacatl-context.c \ arangod/Ahuacatl/ahuacatl-conversions.c \ arangod/Ahuacatl/ahuacatl-error.c \ + arangod/Ahuacatl/ahuacatl-explain.c \ arangod/Ahuacatl/ahuacatl-functions.c \ arangod/Ahuacatl/ahuacatl-grammar.c \ arangod/Ahuacatl/ahuacatl-index.c \