diff --git a/arangod/Aql/AqlValue.cpp b/arangod/Aql/AqlValue.cpp index a82274ad1f..c075f2e60a 100644 --- a/arangod/Aql/AqlValue.cpp +++ b/arangod/Aql/AqlValue.cpp @@ -34,6 +34,7 @@ using namespace triagens::aql; using Json = triagens::basics::Json; +using JsonHelper = triagens::basics::JsonHelper; //////////////////////////////////////////////////////////////////////////////// /// @brief a quick method to decide whether a value is true @@ -156,6 +157,106 @@ bool AqlValue::isString () const { return false; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the AqlValue contains a list value +//////////////////////////////////////////////////////////////////////////////// + +bool AqlValue::isList () const { + switch (_type) { + case JSON: { + TRI_json_t const* json = _json->json(); + return TRI_IsListJson(json); + } + + case SHAPED: { + return false; + } + + case DOCVEC: + case RANGE: { + return true; + } + + case EMPTY: { + return false; + } + } + + THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the AqlValue contains an array value +//////////////////////////////////////////////////////////////////////////////// + +bool AqlValue::isArray () const { + switch (_type) { + case JSON: { + TRI_json_t const* json = _json->json(); + return TRI_IsArrayJson(json); + } + + case SHAPED: { + return true; + } + + case DOCVEC: + case RANGE: + case EMPTY: { + return false; + } + } + + THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get a string representation of the AqlValue +//////////////////////////////////////////////////////////////////////////////// + +std::string AqlValue::toString () const { + switch (_type) { + case JSON: { + TRI_json_t const* json = _json->json(); + TRI_ASSERT(TRI_IsStringJson(json)); + return std::string(json->_value._string.data, json->_value._string.length - 1); + } + + case SHAPED: + case DOCVEC: + case RANGE: + case EMPTY: { + // cannot convert these types + } + } + + return std::string(""); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get a string representation of the AqlValue +//////////////////////////////////////////////////////////////////////////////// + +char const* AqlValue::toChar () const { + switch (_type) { + case JSON: { + TRI_json_t const* json = _json->json(); + TRI_ASSERT(TRI_IsStringJson(json)); + return json->_value._string.data; + } + + case SHAPED: + case DOCVEC: + case RANGE: + case EMPTY: { + // cannot convert these types + } + } + + return ""; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief construct a V8 value as input for the expression execution in V8 //////////////////////////////////////////////////////////////////////////////// @@ -327,6 +428,96 @@ Json AqlValue::toJson (AQL_TRANSACTION_V8* trx, THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief extract an attribute value from the AqlValue +/// this will fail if the value is not an array +//////////////////////////////////////////////////////////////////////////////// + +Json AqlValue::extractArrayMember (AQL_TRANSACTION_V8* trx, + TRI_document_collection_t const* document, + char const* name) const { + switch (_type) { + case JSON: { + TRI_ASSERT(_json != nullptr); + TRI_json_t const* json = _json->json(); + + if (TRI_IsArrayJson(json)) { + TRI_json_t const* found = TRI_LookupArrayJson(json, name); + + if (found != nullptr) { + return Json(TRI_UNKNOWN_MEM_ZONE, TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, found)); + } + } + + // attribute does not exist or something went wrong - fall-through to returning null below + return Json(Json::Null); + } + + case SHAPED: { + TRI_ASSERT(document != nullptr); + TRI_ASSERT(_marker != nullptr); + + auto shaper = document->getShaper(); + + // look for the attribute name in the shape + if (*name == '_') { + if (strcmp(name, "_key") == 0) { + // _key value is copied into JSON + return Json(TRI_UNKNOWN_MEM_ZONE, TRI_EXTRACT_MARKER_KEY(_marker)); + } + else if (strcmp(name, "_id") == 0) { + std::string id(trx->resolver()->getCollectionName(document->_info._cid)); + id.push_back('/'); + id.append(TRI_EXTRACT_MARKER_KEY(_marker)); + return Json(TRI_UNKNOWN_MEM_ZONE, id); + } + else if (strcmp(name, "_rev") == 0) { + TRI_voc_rid_t rid = TRI_EXTRACT_MARKER_RID(_marker); + return Json(TRI_UNKNOWN_MEM_ZONE, JsonHelper::uint64String(TRI_UNKNOWN_MEM_ZONE, rid)); + } + else if (strcmp(name, "_from") == 0) { + std::string from(trx->resolver()->getCollectionName(TRI_EXTRACT_MARKER_FROM_CID(_marker))); + from.push_back('/'); + from.append(TRI_EXTRACT_MARKER_FROM_KEY(_marker)); + return Json(TRI_UNKNOWN_MEM_ZONE, from); + } + else if (strcmp(name, "_to") == 0) { + std::string to(trx->resolver()->getCollectionName(TRI_EXTRACT_MARKER_TO_CID(_marker))); + to.push_back('/'); + to.append(TRI_EXTRACT_MARKER_TO_KEY(_marker)); + return Json(TRI_UNKNOWN_MEM_ZONE, to); + } + } + + TRI_shape_pid_t pid = shaper->lookupAttributePathByName(shaper, name); + if (pid != 0) { + // attribute exists + TRI_shaped_json_t document; + TRI_EXTRACT_SHAPED_JSON_MARKER(document, _marker); + + TRI_shaped_json_t json; + TRI_shape_t const* shape; + + bool ok = TRI_ExtractShapedJsonVocShaper(shaper, &document, 0, pid, &json, &shape); + if (ok && shape != nullptr) { + return Json(TRI_UNKNOWN_MEM_ZONE, TRI_JsonShapedJson(shaper, &json)); + } + } + + // attribute does not exist or something went wrong - fall-through to returning null + break; + } + + case DOCVEC: + case RANGE: + case EMPTY: { + break; + } + } + + return Json(Json::Null); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief create an AqlValue from a vector of AqlItemBlock*s //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/AqlValue.h b/arangod/Aql/AqlValue.h index 7e960d2774..c54d566e38 100644 --- a/arangod/Aql/AqlValue.h +++ b/arangod/Aql/AqlValue.h @@ -156,6 +156,32 @@ namespace triagens { bool isString () const; +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the AqlValue contains a list value +//////////////////////////////////////////////////////////////////////////////// + + bool isList () const; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the AqlValue contains an array value +//////////////////////////////////////////////////////////////////////////////// + + bool isArray () const; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get a string representation of the AqlValue +/// this will fail if the value is not a string +//////////////////////////////////////////////////////////////////////////////// + + std::string toString () const; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get a string representation of the AqlValue +/// this will fail if the value is not a string +//////////////////////////////////////////////////////////////////////////////// + + char const* toChar () const; + //////////////////////////////////////////////////////////////////////////////// /// @brief construct a V8 value as input for the expression execution in V8 //////////////////////////////////////////////////////////////////////////////// @@ -170,6 +196,15 @@ namespace triagens { triagens::basics::Json toJson (AQL_TRANSACTION_V8*, TRI_document_collection_t const*) const; +//////////////////////////////////////////////////////////////////////////////// +/// @brief extract an attribute value from the AqlValue +/// this will fail if the value is not an array +//////////////////////////////////////////////////////////////////////////////// + + triagens::basics::Json extractArrayMember (AQL_TRANSACTION_V8*, + TRI_document_collection_t const*, + char const*) const; + //////////////////////////////////////////////////////////////////////////////// /// @brief create an AqlValue from a vector of AqlItemBlock*s //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Ast.cpp b/arangod/Aql/Ast.cpp index e1dbfb178a..0db9141cd8 100644 --- a/arangod/Aql/Ast.cpp +++ b/arangod/Aql/Ast.cpp @@ -36,7 +36,17 @@ #include "VocBase/collection.h" using namespace triagens::aql; - + +// ----------------------------------------------------------------------------- +// --SECTION-- static initialization +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief initialize a singleton NOP node instance +//////////////////////////////////////////////////////////////////////////////// + +AstNode const Ast::NopNode = { NODE_TYPE_NOP }; + // ----------------------------------------------------------------------------- // --SECTION-- constructors / destructors // ----------------------------------------------------------------------------- @@ -181,12 +191,18 @@ AstNode* Ast::createNodeReturn (AstNode const* expression) { AstNode* Ast::createNodeRemove (AstNode const* expression, AstNode const* collection, - AstNode* options) { + AstNode const* options) { AstNode* node = createNode(NODE_TYPE_REMOVE); + + if (options == nullptr) { + // no options given. now use default options + options = &NopNode; + } + + node->addMember(options); node->addMember(collection); node->addMember(expression); - // TODO: handle options return node; } @@ -714,9 +730,7 @@ AstNode* Ast::createNodeRange (AstNode const* start, //////////////////////////////////////////////////////////////////////////////// AstNode* Ast::createNodeNop () { - AstNode* node = createNode(NODE_TYPE_NOP); - - return node; + return const_cast(&NopNode); } //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Ast.h b/arangod/Aql/Ast.h index 64f219b13b..80ee063f84 100644 --- a/arangod/Aql/Ast.h +++ b/arangod/Aql/Ast.h @@ -253,7 +253,7 @@ namespace triagens { AstNode* createNodeRemove (AstNode const*, AstNode const*, - AstNode*); + AstNode const*); //////////////////////////////////////////////////////////////////////////////// /// @brief create an AST insert node @@ -679,6 +679,12 @@ namespace triagens { AstNode const* _writeOptions; +//////////////////////////////////////////////////////////////////////////////// +/// @brief a singleton NOP node instance +//////////////////////////////////////////////////////////////////////////////// + + static AstNode const NopNode; + }; } diff --git a/arangod/Aql/AstNode.cpp b/arangod/Aql/AstNode.cpp index 1d942c9695..92043e18b4 100644 --- a/arangod/Aql/AstNode.cpp +++ b/arangod/Aql/AstNode.cpp @@ -236,6 +236,35 @@ void AstNode::toJson (TRI_json_t* json, TRI_PushBack3ListJson(zone, json, node); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert the node's value to a boolean value +//////////////////////////////////////////////////////////////////////////////// + +bool AstNode::toBoolean () const { + if (type == NODE_TYPE_VALUE) { + switch (value.type) { + case VALUE_TYPE_BOOL: { + return value.value._bool; + } + case VALUE_TYPE_INT: { + return (value.value._int != 0); + } + case VALUE_TYPE_DOUBLE: { + return value.value._double != 0.0; + } + case VALUE_TYPE_STRING: { + return (*value.value._string != '\0'); + } + case VALUE_TYPE_NULL: + case VALUE_TYPE_FAIL: { + return false; + } + } + } + + return false; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not a node is simple enough to be used in a simple /// expression diff --git a/arangod/Aql/AstNode.h b/arangod/Aql/AstNode.h index 4a17d663e4..c37953b827 100644 --- a/arangod/Aql/AstNode.h +++ b/arangod/Aql/AstNode.h @@ -181,6 +181,12 @@ namespace triagens { void toJson (TRI_json_t*, TRI_memory_zone_t*) const; +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert the node's value to a boolean value +//////////////////////////////////////////////////////////////////////////////// + + bool toBoolean () const; + //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not a value node is of numeric type //////////////////////////////////////////////////////////////////////////////// @@ -421,13 +427,31 @@ namespace triagens { // ----------------------------------------------------------------------------- public: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief the node type +//////////////////////////////////////////////////////////////////////////////// AstNodeType const type; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief the node value +//////////////////////////////////////////////////////////////////////////////// + AstNodeValue value; + +// ----------------------------------------------------------------------------- +// --SECTION-- private variables +// ----------------------------------------------------------------------------- private: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief the node's sub nodes +//////////////////////////////////////////////////////////////////////////////// TRI_vector_pointer_t members; + }; } diff --git a/arangod/Aql/ExecutionBlock.cpp b/arangod/Aql/ExecutionBlock.cpp index 02defcc177..71c3ccf6d3 100644 --- a/arangod/Aql/ExecutionBlock.cpp +++ b/arangod/Aql/ExecutionBlock.cpp @@ -1888,65 +1888,114 @@ RemoveBlock::RemoveBlock (AQL_TRANSACTION_V8* trx, RemoveBlock::~RemoveBlock () { } +//////////////////////////////////////////////////////////////////////////////// +/// @brief get some - this accumulates all input and calls the remove() method +//////////////////////////////////////////////////////////////////////////////// + AqlItemBlock* RemoveBlock::getSome (size_t atLeast, size_t atMost) { + + std::vector blocks; + // loop over input until it is exhausted + try { + while (true) { + auto res = ExecutionBlock::getSome(atLeast, atMost); + + if (res == nullptr) { + break; + } + + blocks.push_back(res); + } + + remove(blocks); + for (auto it = blocks.begin(); it != blocks.end(); ++it) { + delete (*it); + } + return nullptr; + } + catch (...) { + for (auto it = blocks.begin(); it != blocks.end(); ++it) { + delete (*it); + } + throw; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief the actual work horse for removing data +//////////////////////////////////////////////////////////////////////////////// + +void RemoveBlock::remove (std::vector& blocks) { auto ep = static_cast(getPlanNode()); auto it = _varOverview->varInfo.find(ep->_inVariable->id); TRI_ASSERT(it != _varOverview->varInfo.end()); RegisterId const registerId = it->second.registerId; auto trxCollection = _trx->trxCollection(_collection->cid()); - + if (ep->_outVariable == nullptr) { // don't return anything - // loop over input until it is exhausted - while (true) { - auto res = ExecutionBlock::getSome(atLeast, atMost); - - if (res == nullptr) { - return nullptr; - } - + // loop over all blocks + for (auto it = blocks.begin(); it != blocks.end(); ++it) { + auto res = (*it); auto document = res->getDocumentCollection(registerId); - try { - size_t const n = res->size(); + size_t const n = res->size(); - for (size_t i = 0; i < n; i++) { - AqlValue a = res->getValue(i, registerId); + // loop over the complete block + for (size_t i = 0; i < n; i++) { + AqlValue a = res->getValue(i, registerId); - if (a.isEmpty()) { - // no value for _key. TODO: should we fail with an error in this case? + char const* key = nullptr; + int errorCode = TRI_ERROR_NO_ERROR; + + if (a.isArray()) { + // value is an array. now extract the _key attribute + Json member(a.extractArrayMember(_trx, document, "_key")); + + TRI_json_t* json = member.json(); + if (TRI_IsStringJson(json)) { + key = json->_value._string.data; + } + else { + errorCode = TRI_ERROR_ARANGO_DOCUMENT_KEY_MISSING; + } + } + else if (a.isString()) { + // value is a string + key = a.toChar(); + } + else { + errorCode = TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID; + } + + if (errorCode != TRI_ERROR_NO_ERROR) { + if (ep->_options.ignoreErrors) { continue; } - - if (a.isString()) { - std::cout << "VALUE IS A STRING\n"; - } - - std::cout << JsonHelper::toString(a.toJson(_trx, document)) << "\n"; - std::string key = "gig"; - - int removed = TRI_RemoveShapedJsonDocumentCollection(trxCollection, (TRI_voc_key_t) key.c_str(), 0, nullptr, nullptr, false, false); - - std::cout << "REMOVE RESULT: " << removed << "\n"; + THROW_ARANGO_EXCEPTION(errorCode); + } + else { + // no error. we expect to have a key + TRI_ASSERT(key != nullptr); + + errorCode = TRI_RemoveShapedJsonDocumentCollection(trxCollection, + (TRI_voc_key_t) key, + 0, + nullptr, + nullptr, + false, + ep->_options.waitForSync); } - delete res; - } - catch (...) { - delete res; - throw; } + + (*it) = nullptr; + delete res; } - - // will never get here } - - // NOT YET IMPLEMENTED - TRI_ASSERT(false); - return nullptr; } // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/ExecutionBlock.h b/arangod/Aql/ExecutionBlock.h index 23040cda44..3c176910a1 100644 --- a/arangod/Aql/ExecutionBlock.h +++ b/arangod/Aql/ExecutionBlock.h @@ -1058,6 +1058,18 @@ namespace triagens { virtual AqlItemBlock* getSome (size_t atLeast, size_t atMost); +// ----------------------------------------------------------------------------- +// --SECTION-- private methods +// ----------------------------------------------------------------------------- + + private: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief the actual work horse for removing data +//////////////////////////////////////////////////////////////////////////////// + + void remove (std::vector&); + // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/ExecutionNode.h b/arangod/Aql/ExecutionNode.h index 08d63acbcd..2a4197d89c 100644 --- a/arangod/Aql/ExecutionNode.h +++ b/arangod/Aql/ExecutionNode.h @@ -36,6 +36,7 @@ #include "Aql/Collection.h" #include "Aql/Expression.h" +#include "Aql/ModificationOptions.h" #include "Aql/Variable.h" #include "Aql/Types.h" #include "Aql/WalkerWorker.h" @@ -1087,6 +1088,63 @@ namespace triagens { }; +// ----------------------------------------------------------------------------- +// --SECTION-- class ModificationNode +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief abstract base class for modification operations +//////////////////////////////////////////////////////////////////////////////// + + class ModificationNode : public ExecutionNode { + + friend class ExecutionBlock; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief constructor with a vocbase and a collection and options +//////////////////////////////////////////////////////////////////////////////// + + protected: + + ModificationNode (TRI_vocbase_t* vocbase, + Collection* collection, + ModificationOptions const& options) + : ExecutionNode(), + _vocbase(vocbase), + _collection(collection), + _options(options) { + + TRI_ASSERT(_vocbase != nullptr); + TRI_ASSERT(_collection != nullptr); + } + +// ----------------------------------------------------------------------------- +// --SECTION-- protected variables +// ----------------------------------------------------------------------------- + + protected: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief _vocbase, the database +//////////////////////////////////////////////////////////////////////////////// + + TRI_vocbase_t* _vocbase; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief collection +//////////////////////////////////////////////////////////////////////////////// + + Collection* _collection; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief modification operation options +//////////////////////////////////////////////////////////////////////////////// + + ModificationOptions _options; + + }; + + // ----------------------------------------------------------------------------- // --SECTION-- class RemoveNode // ----------------------------------------------------------------------------- @@ -1095,7 +1153,7 @@ namespace triagens { /// @brief class RemoveNode //////////////////////////////////////////////////////////////////////////////// - class RemoveNode : public ExecutionNode { + class RemoveNode : public ModificationNode { friend class ExecutionBlock; friend class RemoveBlock; @@ -1108,16 +1166,13 @@ namespace triagens { RemoveNode (TRI_vocbase_t* vocbase, Collection* collection, + ModificationOptions const& options, Variable const* inVariable, Variable const* outVariable) - : ExecutionNode(), - _vocbase(vocbase), - _collection(collection), + : ModificationNode(vocbase, collection, options), _inVariable(inVariable), _outVariable(outVariable) { - TRI_ASSERT(_vocbase != nullptr); - TRI_ASSERT(_collection != nullptr); TRI_ASSERT(_inVariable != nullptr); // _outVariable might be a nullptr } @@ -1143,7 +1198,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// virtual ExecutionNode* clone () const { - auto c = new RemoveNode(_vocbase, _collection, _inVariable, _outVariable); + auto c = new RemoveNode(_vocbase, _collection, _options, _inVariable, _outVariable); cloneDependencies(c); return static_cast(c); } @@ -1164,18 +1219,6 @@ namespace triagens { private: -//////////////////////////////////////////////////////////////////////////////// -/// @brief _vocbase, the database -//////////////////////////////////////////////////////////////////////////////// - - TRI_vocbase_t* _vocbase; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief collection -//////////////////////////////////////////////////////////////////////////////// - - Collection* _collection; - //////////////////////////////////////////////////////////////////////////////// /// @brief input variable //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/ExecutionPlan.cpp b/arangod/Aql/ExecutionPlan.cpp index 2372c57dcd..fba25398bf 100644 --- a/arangod/Aql/ExecutionPlan.cpp +++ b/arangod/Aql/ExecutionPlan.cpp @@ -99,6 +99,37 @@ ExecutionPlan* ExecutionPlan::instanciateFromAst (Ast const* ast) { // --SECTION-- private functions // ----------------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// +/// @brief create modification options from an AST node +//////////////////////////////////////////////////////////////////////////////// + +ModificationOptions ExecutionPlan::createOptions (AstNode const* node) { + ModificationOptions options; + + // parse the modification options we got + if (node != nullptr && node->type == NODE_TYPE_ARRAY) { + size_t n = node->numMembers(); + for (size_t i = 0; i < n; ++i) { + auto member = node->getMember(i); + if (member != nullptr && member->type == NODE_TYPE_ARRAY_ELEMENT) { + auto name = member->getStringValue(); + auto value = member->getMember(0); + + TRI_ASSERT(value->isConstant()); + + if (strcmp(name, "waitForSync") == 0) { + options.waitForSync = value->toBoolean(); + } + else if (strcmp(name, "ignoreErrors") == 0) { + options.ignoreErrors = value->toBoolean(); + } + } + } + } + + return options; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief add a node to the plan, will delete node if addition fails //////////////////////////////////////////////////////////////////////////////// @@ -487,9 +518,10 @@ ExecutionNode* ExecutionPlan::fromNodeRemove (Ast const* ast, ExecutionNode* previous, AstNode const* node) { TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_REMOVE); - TRI_ASSERT(node->numMembers() == 2); + TRI_ASSERT(node->numMembers() == 3); - char const* collectionName = node->getMember(0)->getStringValue(); + auto options = createOptions(node->getMember(0)); + char const* collectionName = node->getMember(1)->getStringValue(); auto collections = ast->query()->collections(); auto collection = collections->get(collectionName); @@ -497,20 +529,20 @@ ExecutionNode* ExecutionPlan::fromNodeRemove (Ast const* ast, THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); } - auto expression = node->getMember(1); + auto expression = node->getMember(2); ExecutionNode* en = nullptr; if (expression->type == NODE_TYPE_REFERENCE) { // operand is already a variable auto v = static_cast(expression->getData()); TRI_ASSERT(v != nullptr); - en = addNode(new RemoveNode(ast->query()->vocbase(), collection, v, nullptr)); + en = addNode(new RemoveNode(ast->query()->vocbase(), collection, options, v, nullptr)); } else { // operand is some misc expression auto calc = createTemporaryCalculation(ast, expression); calc->addDependency(previous); - en = addNode(new RemoveNode(ast->query()->vocbase(), collection, calc->outVariable(), nullptr)); + en = addNode(new RemoveNode(ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr)); previous = calc; } diff --git a/arangod/Aql/ExecutionPlan.h b/arangod/Aql/ExecutionPlan.h index 1077dc3677..36201ae562 100644 --- a/arangod/Aql/ExecutionPlan.h +++ b/arangod/Aql/ExecutionPlan.h @@ -32,6 +32,7 @@ #include "Basics/Common.h" #include "arangod/Aql/ExecutionNode.h" +#include "arangod/Aql/ModificationOptions.h" namespace triagens { namespace aql { @@ -109,6 +110,12 @@ namespace triagens { private: +//////////////////////////////////////////////////////////////////////////////// +/// @brief create modification options from an AST node +//////////////////////////////////////////////////////////////////////////////// + + ModificationOptions createOptions (AstNode const*); + //////////////////////////////////////////////////////////////////////////////// /// @brief add a node to the plan, will delete node if addition fails //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Expression.cpp b/arangod/Aql/Expression.cpp index 3339b089af..445cc75149 100644 --- a/arangod/Aql/Expression.cpp +++ b/arangod/Aql/Expression.cpp @@ -162,8 +162,6 @@ void Expression::analyzeExpression () { _type = V8; _canThrow = _node->canThrow(); } - - std::cout << "CAN THROW: " << _canThrow << "\n"; } //////////////////////////////////////////////////////////////////////////////// @@ -191,70 +189,10 @@ AqlValue Expression::executeSimpleExpression (AstNode const* node, if (result._type == AqlValue::SHAPED) { TRI_ASSERT(myCollection != nullptr); - auto shaper = myCollection->getShaper(); - - // look for the attribute name in the shape - if (*name == '_') { - if (strcmp(name, "_key") == 0) { - // _key value is copied into JSON - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, TRI_EXTRACT_MARKER_KEY(result._marker))); - } - else if (strcmp(name, "_id") == 0) { - std::string id(trx->resolver()->getCollectionName(myCollection->_info._cid)); - id.push_back('/'); - id.append(TRI_EXTRACT_MARKER_KEY(result._marker)); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, id)); - } - else if (strcmp(name, "_rev") == 0) { - TRI_voc_rid_t rid = TRI_EXTRACT_MARKER_RID(result._marker); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, JsonHelper::uint64String(TRI_UNKNOWN_MEM_ZONE, rid))); - } - else if (strcmp(name, "_from") == 0) { - std::string from(trx->resolver()->getCollectionName(TRI_EXTRACT_MARKER_FROM_CID(result._marker))); - from.push_back('/'); - from.append(TRI_EXTRACT_MARKER_FROM_KEY(result._marker)); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, from)); - } - else if (strcmp(name, "_to") == 0) { - std::string to(trx->resolver()->getCollectionName(TRI_EXTRACT_MARKER_TO_CID(result._marker))); - to.push_back('/'); - to.append(TRI_EXTRACT_MARKER_TO_KEY(result._marker)); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, to)); - } - } - - TRI_shape_pid_t pid = shaper->lookupAttributePathByName(shaper, name); - if (pid != 0) { - // attribute exists - TRI_shaped_json_t document; - TRI_EXTRACT_SHAPED_JSON_MARKER(document, result._marker); - - TRI_shaped_json_t json; - TRI_shape_t const* shape; - - bool ok = TRI_ExtractShapedJsonVocShaper(shaper, &document, 0, pid, &json, &shape); - if (ok && shape != nullptr) { - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, TRI_JsonShapedJson(shaper, &json))); - } - } - - // attribute does not exist or something went wrong - fall-through to returning null below + auto j = result.extractArrayMember(trx, myCollection, name); + return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal())); } - else if (result._type == AqlValue::JSON) { - TRI_json_t const* json = result._json->json(); - - if (TRI_IsArrayJson(json)) { - TRI_json_t const* found = TRI_LookupArrayJson(json, name); - - if (found != nullptr) { - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, found))); - } - } - - // attribute does not exist or something went wrong - fall-through to returning null below - } - return AqlValue(new Json(Json::Null)); } diff --git a/arangod/Aql/ModificationOptions.h b/arangod/Aql/ModificationOptions.h new file mode 100644 index 0000000000..0f1c7b584f --- /dev/null +++ b/arangod/Aql/ModificationOptions.h @@ -0,0 +1,73 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief AQL, data-modification query options +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2010-2014 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 Max Neunhoeffer +/// @author Copyright 2014, triagens GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ARANGODB_AQL_MODIFICATION_OPTIONS_H +#define ARANGODB_AQL_MODIFICATION_OPTIONS_H 1 + +#include "Basics/Common.h" + +namespace triagens { + namespace aql { + +//////////////////////////////////////////////////////////////////////////////// +/// @brief ModificationOptions +//////////////////////////////////////////////////////////////////////////////// + + struct ModificationOptions { + +// ----------------------------------------------------------------------------- +// --SECTION-- constructors / destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief constructor, using default values +//////////////////////////////////////////////////////////////////////////////// + + ModificationOptions () + : ignoreErrors(false), + waitForSync(false) { + } + +// ----------------------------------------------------------------------------- +// --SECTION-- public variables +// ----------------------------------------------------------------------------- + + bool ignoreErrors; + bool waitForSync; + + }; + + } // namespace triagens::aql +} // namespace triagens + +#endif + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: +