diff --git a/arangod/Aql/ExecutionBlock.h b/arangod/Aql/ExecutionBlock.h index 01ee1c79f2..cd5c209e16 100644 --- a/arangod/Aql/ExecutionBlock.h +++ b/arangod/Aql/ExecutionBlock.h @@ -33,9 +33,82 @@ #include "Aql/Types.h" #include "Aql/ExecutionPlan.h" +struct TRI_json_s; + namespace triagens { namespace aql { + class ExecutionBlock { + public: + ExecutionBlock (ExecutionPlan const* ep) + : _exePlan(ep) { } + + virtual ~ExecutionBlock () { + std::cout << "EXECUTIONBLOCK DTOR\n"; + for (auto i = _dependencies.begin(); i != _dependencies.end(); ++i) { + delete *i; + } + } + + // Methods for execution: + int initialise () { + return TRI_ERROR_NO_ERROR; + } + + int bind (std::map* params); + + std::map* getParameters (); + + int execute () { + return TRI_ERROR_NO_ERROR; + } + + int shutdown () { + return TRI_ERROR_NO_ERROR; + } + + virtual AqlValue* getOne () = 0; + + std::vector getSome (int atLeast, int atMost); + + bool skip (int number); + + int64_t count (); + + int64_t remaining (); + + protected: + ExecutionPlan const* _exePlan; + std::vector _dependencies; + std::deque _buffer; + }; + + + class EnumerateCollectionBlock : public ExecutionBlock { + + public: + + EnumerateCollectionBlock (EnumerateCollectionPlan const* ep) + : ExecutionBlock(ep) { + + } + + ~EnumerateCollectionBlock () { + std::cout << "ENUMERATECOLLECTIONBLOCK DTOR\n"; + } + + AqlValue* getOne () { + if (_buffer.empty()) { + + } + + auto value = _buffer.front(); + _buffer.pop_front(); + return value; + } + + }; + } // namespace triagens::aql } // namespace triagens diff --git a/arangod/Aql/ExecutionPlan.h b/arangod/Aql/ExecutionPlan.h index 81f2c27983..1f06bd629d 100644 --- a/arangod/Aql/ExecutionPlan.h +++ b/arangod/Aql/ExecutionPlan.h @@ -40,6 +40,8 @@ namespace triagens { namespace aql { + class ExecutionBlock; + //////////////////////////////////////////////////////////////////////////////// /// @brief class ExecutionPlan, abstract base class of all execution plans //////////////////////////////////////////////////////////////////////////////// @@ -202,6 +204,9 @@ namespace triagens { virtual void appendAsString (std::string& st, int indent = 0); + + virtual ExecutionBlock* instanciate () = 0; + // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- @@ -216,6 +221,84 @@ namespace triagens { }; +// ----------------------------------------------------------------------------- +// --SECTION-- class RootPlan +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief class RootPlan, derived from ExecutionPlan +//////////////////////////////////////////////////////////////////////////////// + + class RootPlan : public ExecutionPlan { + + friend class RootBlock; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief constructor +//////////////////////////////////////////////////////////////////////////////// + + public: + + RootPlan () + : ExecutionPlan() { + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief return the type of the node +//////////////////////////////////////////////////////////////////////////////// + + virtual NodeType getType () { + return ROOT; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief return the type of the node as a string +//////////////////////////////////////////////////////////////////////////////// + + virtual std::string getTypeString () { + return std::string("RootPlan"); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief export to JSON +//////////////////////////////////////////////////////////////////////////////// + + virtual triagens::basics::Json toJson ( + TRI_memory_zone_t* zone = TRI_UNKNOWN_MEM_ZONE); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief clone execution plan recursively +//////////////////////////////////////////////////////////////////////////////// + + virtual ExecutionPlan* clone () { + auto c = new RootPlan(); + cloneDependencies(c); + return static_cast(c); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief turn the plan node into an execution block node +//////////////////////////////////////////////////////////////////////////////// + + ExecutionBlock* instanciate () { + return nullptr; + } + +// ----------------------------------------------------------------------------- +// --SECTION-- private variables +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief we need to know the database and the collection +//////////////////////////////////////////////////////////////////////////////// + + private: + + TRI_vocbase_t* _vocbase; + std::string _collname; + + }; + // ----------------------------------------------------------------------------- // --SECTION-- class EnumerateCollectionPlan // ----------------------------------------------------------------------------- @@ -226,6 +309,8 @@ namespace triagens { class EnumerateCollectionPlan : public ExecutionPlan { + friend class EnumerateCollectionBlock; + //////////////////////////////////////////////////////////////////////////////// /// @brief constructor with a vocbase and a collection name //////////////////////////////////////////////////////////////////////////////// @@ -269,6 +354,18 @@ namespace triagens { return static_cast(c); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief turn the plan node into an execution block node +//////////////////////////////////////////////////////////////////////////////// + + ExecutionBlock* instanciate () { + return nullptr; + } + +// ----------------------------------------------------------------------------- +// --SECTION-- private variables +// ----------------------------------------------------------------------------- + //////////////////////////////////////////////////////////////////////////////// /// @brief we need to know the database and the collection //////////////////////////////////////////////////////////////////////////////// @@ -337,6 +434,14 @@ namespace triagens { return static_cast(c); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief turn the plan node into an execution block node +//////////////////////////////////////////////////////////////////////////////// + + ExecutionBlock* instanciate () { + return nullptr; + } + //////////////////////////////////////////////////////////////////////////////// /// @brief we need to know the offset and limit //////////////////////////////////////////////////////////////////////////////// @@ -401,6 +506,14 @@ namespace triagens { return static_cast(c); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief turn the plan node into an execution block node +//////////////////////////////////////////////////////////////////////////////// + + ExecutionBlock* instanciate () { + return nullptr; + } + //////////////////////////////////////////////////////////////////////////////// /// @brief we need to know the offset and limit //////////////////////////////////////////////////////////////////////////////// @@ -466,6 +579,14 @@ namespace triagens { return static_cast(c); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief turn the plan node into an execution block node +//////////////////////////////////////////////////////////////////////////////// + + ExecutionBlock* instanciate () { + return nullptr; + } + //////////////////////////////////////////////////////////////////////////////// /// @brief we need to know the offset and limit //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Types.h b/arangod/Aql/Types.h index e9a3a246db..ed1092632e 100644 --- a/arangod/Aql/Types.h +++ b/arangod/Aql/Types.h @@ -37,12 +37,12 @@ namespace triagens { namespace aql { // ----------------------------------------------------------------------------- -// --SECTION-- AqlDocuments +// --SECTION-- AqlValues // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -/// @brief struct AqlDocument, used to pipe documents through executions -/// the execution engine keeps one AqlDocument struct for each document +/// @brief struct AqlValue, used to pipe documents through executions +/// the execution engine keeps one AqlValue struct for each document /// that is piped through the engine. Note that the document can exist /// in one of two formats throughout its lifetime in the engine. /// When it resides originally in the WAl or a datafile, it stays @@ -60,25 +60,24 @@ namespace triagens { /// Note that both Json subobjects are constructed as AUTOFREE. //////////////////////////////////////////////////////////////////////////////// - struct AqlDocument { + struct AqlValue { triagens::basics::Json _json; - TRI_doc_mptr_copy_t* _mptr; + TRI_doc_mptr_t* _mptr; triagens::basics::Json _vars; //////////////////////////////////////////////////////////////////////////////// /// @brief convenience constructors //////////////////////////////////////////////////////////////////////////////// - AqlDocument () + AqlValue () : _json(), _mptr(nullptr), _vars() { } - AqlDocument (TRI_doc_mptr_t* mptr) - : _json(), _vars() { - _mptr = new TRI_doc_mptr_copy_t(*mptr); + AqlValue (TRI_doc_mptr_t* mptr) + : _json(), _mptr(mptr), _vars() { } - AqlDocument (triagens::basics::Json json) + AqlValue (triagens::basics::Json json) : _json(json), _mptr(nullptr), _vars() { } @@ -86,12 +85,32 @@ namespace triagens { /// @brief destructor //////////////////////////////////////////////////////////////////////////////// - ~AqlDocument () { + ~AqlValue () { if (_mptr != nullptr) { delete _mptr; } } +//////////////////////////////////////////////////////////////////////////////// +/// @brief return a string representation of the value +//////////////////////////////////////////////////////////////////////////////// + + std::string toString () const { + std::string out; + if (! _json.isEmpty()) { + out += _json.toString(); + } + else if (_mptr != nullptr) { + out.append("got a master pointer"); + } + + if (! _vars.isEmpty()) { + out += _vars.toString(); + } + + return out; + } + //////////////////////////////////////////////////////////////////////////////// /// @brief getValue, get the current value of a variable or attribute //////////////////////////////////////////////////////////////////////////////// @@ -157,7 +176,7 @@ namespace triagens { /// @brief execute the expression //////////////////////////////////////////////////////////////////////////////// - triagens::basics::Json execute (AqlDocument* aqldoc); + triagens::basics::Json execute (AqlValue* aqldoc); //////////////////////////////////////////////////////////////////////////////// /// @brief private members diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index 1cdcd1d2b8..79484bee9e 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -34,6 +34,8 @@ #include "Ahuacatl/ahuacatl-context.h" #include "Ahuacatl/ahuacatl-explain.h" #include "Ahuacatl/ahuacatl-result.h" +#include "Aql/ExecutionPlan.h" +#include "Aql/ExecutionBlock.h" #include "Aql/Query.h" #include "Basics/StringUtils.h" #include "Basics/Utf8Helper.h" @@ -5395,6 +5397,42 @@ static v8::Handle JS_ParseAql (v8::Arguments const& argv) { return scope.Close(result); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief peng an AQL query +//////////////////////////////////////////////////////////////////////////////// + +static v8::Handle JS_PengAql (v8::Arguments const& argv) { + v8::HandleScope scope; + + TRI_vocbase_t* vocbase = GetContextVocBase(); + + if (vocbase == nullptr) { + TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); + } + + if (argv.Length() != 0) { + TRI_V8_EXCEPTION_USAGE(scope, "AQL_PENG()"); + } + + triagens::aql::ExecutionPlan* enumPlan = new triagens::aql::EnumerateCollectionPlan(vocbase, "fuxx"); + triagens::aql::ExecutionPlan* rootPlan = new triagens::aql::RootPlan(); + rootPlan->addDependency(enumPlan); + + triagens::aql::ExecutionBlock* exec = rootPlan->instanciate(); + exec->initialise(); + exec->execute(); + + triagens::aql::AqlValue* value; + while (nullptr != (value = exec->getOne())) { + std::cout << value->toString(); + delete value; + } + + exec->shutdown(); + + return scope.Close(v8::Undefined()); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief executes an AQL query //////////////////////////////////////////////////////////////////////////////// @@ -10710,6 +10748,7 @@ void TRI_InitV8VocBridge (v8::Handle context, // new AQL functions. not intended to be used directly by end users TRI_AddGlobalFunctionVocbase(context, "AQL_EXECUTE", JS_ExecuteAql, true); TRI_AddGlobalFunctionVocbase(context, "AQL_PARSE", JS_ParseAql, true); + TRI_AddGlobalFunctionVocbase(context, "AQL_PENG", JS_PengAql, true); // cursor functions. not intended to be used by end users TRI_AddGlobalFunctionVocbase(context, "CURSOR", JS_Cursor, true); diff --git a/lib/Basics/JsonHelper.h b/lib/Basics/JsonHelper.h index cabc00d798..6371e3af26 100644 --- a/lib/Basics/JsonHelper.h +++ b/lib/Basics/JsonHelper.h @@ -615,7 +615,7 @@ namespace triagens { } //////////////////////////////////////////////////////////////////////////////// -/// @brief append an Json value to the end of a Json list, an exception +/// @brief append a Json value to the end of a Json list, an exception /// is thrown if *this is not a Json list. Note that you can call this with /// a Json as argument because of the automatic type conversion /// to TRI_json_t* with steal semantics. Therefore @@ -752,7 +752,7 @@ namespace triagens { /// @brief checks whether *this is an empty Json (not even null). //////////////////////////////////////////////////////////////////////////////// - bool isEmpty () throw() { + bool isEmpty () const throw() { return _json == nullptr; } @@ -760,7 +760,7 @@ namespace triagens { /// @brief converts the Json recursively into a string. //////////////////////////////////////////////////////////////////////////////// - std::string toString () { + std::string toString () const { if (_json != nullptr) { return JsonHelper::toString(_json); }