diff --git a/3rdParty/velocypack/include/velocypack/Slice.h b/3rdParty/velocypack/include/velocypack/Slice.h index 17a16b3496..e12541ad2d 100644 --- a/3rdParty/velocypack/include/velocypack/Slice.h +++ b/3rdParty/velocypack/include/velocypack/Slice.h @@ -326,10 +326,39 @@ class Slice { return last; } + + // look for the specified attribute path inside an Object + // returns a Slice(ValueType::None) if not found + Slice get(std::vector const& attributes) const { + size_t const n = attributes.size(); + if (n == 0) { + throw Exception(Exception::InvalidAttributePath); + } + + // use ourselves as the starting point + Slice last = Slice(start()); + for (size_t i = 0; i < attributes.size(); ++i) { + // fetch subattribute + last = last.get(attributes[i]); + + // abort as early as possible + if (last.isNone() || (i + 1 < n && !last.isObject())) { + return Slice(); + } + } + + return last; + } // look for the specified attribute inside an Object // returns a Slice(ValueType::None) if not found Slice get(std::string const& attribute) const; + + // look for the specified attribute inside an Object + // returns a Slice(ValueType::None) if not found + Slice get(char const* attribute) const { + return get(std::string(attribute)); + } Slice operator[](std::string const& attribute) const { return get(attribute); diff --git a/arangod/Aql/AqlValue.cpp b/arangod/Aql/AqlValue.cpp index 20a5436131..41c0c1eeb7 100644 --- a/arangod/Aql/AqlValue.cpp +++ b/arangod/Aql/AqlValue.cpp @@ -731,6 +731,16 @@ Json AqlValue::toJson(arangodb::AqlTransaction* trx, THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief Constructor +//////////////////////////////////////////////////////////////////////////////// + +AqlValue$::AqlValue$() { + VPackBuilder builder; + memcpy(_data.internal, builder.slice().begin(), builder.slice().byteSize()); + _data.internal[15] = AqlValueType::INTERNAL; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief Constructor //////////////////////////////////////////////////////////////////////////////// @@ -754,7 +764,7 @@ AqlValue$::AqlValue$(VPackBuilder const& data) { /// @brief Constructor //////////////////////////////////////////////////////////////////////////////// -AqlValue$::AqlValue$(VPackBuilder const* data) : AqlValue$(*data){}; +AqlValue$::AqlValue$(VPackBuilder const* data) : AqlValue$(*data) {} //////////////////////////////////////////////////////////////////////////////// /// @brief Constructor @@ -772,8 +782,7 @@ AqlValue$::AqlValue$(VPackSlice const& data) { memcpy(_data.external->data(), data.start(), l); _data.internal[15] = AqlValueType::EXTERNAL; } -}; - +} //////////////////////////////////////////////////////////////////////////////// /// @brief Copy Constructor. @@ -877,6 +886,105 @@ AqlValue$::AqlValue$(AqlValue const& other, arangodb::AqlTransaction* trx, AqlValue$::AqlValueType AqlValue$::type() const { return static_cast(_data.internal[15]); } + +////////////////////////////////////////////////////////////////////////////// +/// @brief get the numeric value of an AqlValue +////////////////////////////////////////////////////////////////////////////// + +double AqlValue$::toDouble() const { + if (slice().isCustom()) { +#warning FIX custom + // range. TODO + //size_t rangeSize = _range->size(); + //if (rangeSize == 1) { + // return _range->at(0); + //} + return 0.0; + } + if (slice().isBoolean()) { + return slice().getBoolean() ? 1.0 : 0.0; + } + if (slice().isNumber()) { + return slice().getNumber(); + } + if (slice().isString()) { + try { + return std::stod(slice().copyString()); + } catch (...) { + // conversion failed + } + return 0.0; + } + if (slice().isArray()) { + if (slice().length() == 1) { + AqlValue$ tmp(slice().at(0)); + return tmp.toDouble(); + } + return 0.0; + } + + return 0.0; +} + +////////////////////////////////////////////////////////////////////////////// +/// @brief get the numeric value of an AqlValue +////////////////////////////////////////////////////////////////////////////// + +int64_t AqlValue$::toInt64() const { + if (slice().isCustom()) { +#warning FIX custom + // range. TODO + //size_t rangeSize = _range->size(); + //if (rangeSize == 1) { + // return _range->at(0); + //} + return 0; + } + if (slice().isBoolean()) { + return slice().getBoolean() ? 1 : 0; + } + if (slice().isNumber()) { + return slice().getNumber(); + } + if (slice().isString()) { + try { + return static_cast(std::stoll(slice().copyString())); + } catch (...) { + // conversion failed + } + return 0; + } + if (slice().isArray()) { + if (slice().length() == 1) { + AqlValue$ tmp(slice().at(0)); + return tmp.toInt64(); + } + return 0; + } + + return 0; +} + +bool AqlValue$::isTrue() const { + if (slice().isBoolean() && slice().getBoolean()) { + return true; + } + if (slice().isNumber() && slice().getNumber() != 0.0) { + return true; + } + if (slice().isString() && !slice().copyString().empty()) { + return true; + } + if (slice().isArray() || slice().isObject()) { + return true; + } + if (slice().isCustom()) { + // range + return true; + } + + return false; +} VPackSlice AqlValue$::slice() const { if (type()) { diff --git a/arangod/Aql/AqlValue.h b/arangod/Aql/AqlValue.h index 2353887c14..0dc61af117 100644 --- a/arangod/Aql/AqlValue.h +++ b/arangod/Aql/AqlValue.h @@ -393,9 +393,11 @@ struct AqlValue$ { } _data; public: - AqlValue$(arangodb::velocypack::Builder const&); - AqlValue$(arangodb::velocypack::Builder const*); - AqlValue$(arangodb::velocypack::Slice const&); + explicit AqlValue$(arangodb::velocypack::Builder const&); + explicit AqlValue$(arangodb::velocypack::Builder const*); + explicit AqlValue$(arangodb::velocypack::Slice const&); + + AqlValue$(); AqlValue$(AqlValue const&, arangodb::AqlTransaction*, TRI_document_collection_t const*); @@ -407,7 +409,7 @@ struct AqlValue$ { } //////////////////////////////////////////////////////////////////////////////// - /// @brief Copy Constructor. + /// @brief Copy Constructor //////////////////////////////////////////////////////////////////////////////// AqlValue$(AqlValue$ const& other); @@ -423,10 +425,34 @@ struct AqlValue$ { ////////////////////////////////////////////////////////////////////////////// /// @brief Returns a slice to read this Value's data ////////////////////////////////////////////////////////////////////////////// + arangodb::velocypack::Slice slice() const; + + ////////////////////////////////////////////////////////////////////////////// + /// @brief get the numeric value of an AqlValue + ////////////////////////////////////////////////////////////////////////////// + + double toDouble() const; + int64_t toInt64() const; + + ////////////////////////////////////////////////////////////////////////////// + /// @brief whether or not an AqlValue evaluates to true + ////////////////////////////////////////////////////////////////////////////// + + bool isTrue() const; + + ////////////////////////////////////////////////////////////////////////////// + /// @brief compare function for two values + /// TODO: implement + ////////////////////////////////////////////////////////////////////////////// + + static int Compare(arangodb::AqlTransaction*, AqlValue$ const& left, AqlValue$ const& right, bool useUtf8) { + // TODO: implement + return 0; + } }; -static_assert(sizeof(AqlValue$) < 17, "invalid AqlValue size."); +static_assert(sizeof(AqlValue$) == 16, "invalid AqlValue$ size"); } // closes namespace arangodb::aql } // closes namespace arangodb diff --git a/arangod/Aql/AttributeAccessor.cpp b/arangod/Aql/AttributeAccessor.cpp index 068ec638ce..a58128ed60 100644 --- a/arangod/Aql/AttributeAccessor.cpp +++ b/arangod/Aql/AttributeAccessor.cpp @@ -22,16 +22,15 @@ //////////////////////////////////////////////////////////////////////////////// #include "AttributeAccessor.h" +#include "Basics/JsonHelper.h" #include "Aql/AqlItemBlock.h" #include "Aql/Variable.h" -#include "Basics/StringBuffer.h" -#include "Basics/json.h" -#include "VocBase/document-collection.h" -#include "VocBase/shaped-json.h" -#include "VocBase/VocShaper.h" +#include "Utils/AqlTransaction.h" + +#include +#include using namespace arangodb::aql; -using Json = arangodb::basics::Json; //////////////////////////////////////////////////////////////////////////////// /// @brief create the accessor @@ -41,38 +40,8 @@ AttributeAccessor::AttributeAccessor( std::vector const& attributeParts, Variable const* variable) : _attributeParts(attributeParts), _combinedName(), - _variable(variable), - _buffer(TRI_UNKNOWN_MEM_ZONE), - _shaper(nullptr), - _pid(0), - _nameCache({"", 0}), - _attributeType(ATTRIBUTE_TYPE_REGULAR) { + _variable(variable) { TRI_ASSERT(_variable != nullptr); - - if (_attributeParts.size() == 1) { - char const* n = _attributeParts[0]; - - if (strcmp(n, TRI_VOC_ATTRIBUTE_KEY) == 0) { - _attributeType = ATTRIBUTE_TYPE_KEY; - } else if (strcmp(n, TRI_VOC_ATTRIBUTE_REV) == 0) { - _attributeType = ATTRIBUTE_TYPE_REV; - } else if (strcmp(n, TRI_VOC_ATTRIBUTE_ID) == 0) { - _attributeType = ATTRIBUTE_TYPE_ID; - } else if (strcmp(n, TRI_VOC_ATTRIBUTE_FROM) == 0) { - _attributeType = ATTRIBUTE_TYPE_FROM; - } else if (strcmp(n, TRI_VOC_ATTRIBUTE_TO) == 0) { - _attributeType = ATTRIBUTE_TYPE_TO; - } - } - - if (_attributeType == ATTRIBUTE_TYPE_REGULAR) { - for (auto const& it : _attributeParts) { - if (!_combinedName.empty()) { - _combinedName.push_back('.'); - } - _combinedName.append(it); - } - } } //////////////////////////////////////////////////////////////////////////////// @@ -96,206 +65,15 @@ AqlValue AttributeAccessor::get(arangodb::AqlTransaction* trx, auto& result = argv->getValueReference(startPos, regs[i]); // extract the attribute - if (result.isShaped()) { - switch (_attributeType) { - case ATTRIBUTE_TYPE_KEY: { - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, - TRI_EXTRACT_MARKER_KEY(result._marker))); - } - - case ATTRIBUTE_TYPE_REV: { - return extractRev(result); - } - - case ATTRIBUTE_TYPE_ID: { - TRI_document_collection_t const* collection = - argv->getDocumentCollection(regs[i]); - return extractId(result, trx, collection); - } - - case ATTRIBUTE_TYPE_FROM: { - return extractFrom(result, trx); - } - - case ATTRIBUTE_TYPE_TO: { - return extractTo(result, trx); - } - - case ATTRIBUTE_TYPE_REGULAR: - default: { - TRI_document_collection_t const* collection = - argv->getDocumentCollection(regs[i]); - return extractRegular(result, trx, collection); - } - } - } else if (result.isJson()) { - TRI_json_t const* json = result._json->json(); - size_t const n = _attributeParts.size(); - size_t i = 0; - - while (TRI_IsObjectJson(json)) { - TRI_ASSERT(i < n); - - json = TRI_LookupObjectJson(json, _attributeParts[i]); - - if (json == nullptr) { - break; - } - - ++i; - - if (i == n) { - // reached the end - std::unique_ptr copy( - TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, json)); - - if (copy == nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } - - auto result = new Json(TRI_UNKNOWN_MEM_ZONE, copy.get()); - copy.release(); - return AqlValue(result); - } - } - - // fall-through intentional - } - - break; + VPackSlice const slice; +#warning TODO: fill slice from AqlValue (result) + VPackSlice extracted = slice.get(_attributeParts); +#warning TODO: build result from extracted + return AqlValue(new arangodb::basics::Json(arangodb::basics::Json::Null)); } // fall-through intentional } - return AqlValue(new Json(Json::Null)); + return AqlValue(new arangodb::basics::Json(arangodb::basics::Json::Null)); } -//////////////////////////////////////////////////////////////////////////////// -/// @brief extract the _rev attribute from a ShapedJson marker -//////////////////////////////////////////////////////////////////////////////// - -AqlValue AttributeAccessor::extractRev(AqlValue const& src) { - _buffer.reset(); - _buffer.appendInteger(TRI_EXTRACT_MARKER_RID(src._marker)); - - auto json = new Json(TRI_UNKNOWN_MEM_ZONE, _buffer.c_str(), _buffer.length()); - - return AqlValue(json); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief extract the _id attribute from a ShapedJson marker -//////////////////////////////////////////////////////////////////////////////// - -AqlValue AttributeAccessor::extractId( - AqlValue const& src, arangodb::AqlTransaction* trx, - TRI_document_collection_t const* document) { - if (_nameCache.value.empty()) { - _nameCache.value = trx->resolver()->getCollectionName(document->_info.id()); - } - - _buffer.reset(); - _buffer.appendText(_nameCache.value); - _buffer.appendChar('/'); - _buffer.appendText(TRI_EXTRACT_MARKER_KEY(src._marker)); - - auto json = new Json(TRI_UNKNOWN_MEM_ZONE, _buffer.c_str(), _buffer.length()); - - return AqlValue(json); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief extract the _from attribute from a ShapedJson marker -//////////////////////////////////////////////////////////////////////////////// - -AqlValue AttributeAccessor::extractFrom(AqlValue const& src, - arangodb::AqlTransaction* trx) { - // TODO vpack - if (src._marker->getType() != TRI_DOC_MARKER_KEY_EDGE) { - return AqlValue(new Json(Json::Null)); - } - - auto cid = TRI_EXTRACT_MARKER_FROM_CID(src._marker); - - if (_nameCache.value.empty() || _nameCache.cid != cid) { - _nameCache.cid = cid; - _nameCache.value = trx->resolver()->getCollectionNameCluster(cid); - } - - _buffer.reset(); - _buffer.appendText(_nameCache.value); - _buffer.appendChar('/'); - _buffer.appendText(TRI_EXTRACT_MARKER_FROM_KEY(src._marker)); - - auto json = new Json(TRI_UNKNOWN_MEM_ZONE, _buffer.c_str(), _buffer.length()); - - return AqlValue(json); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief extract the _to attribute from a ShapedJson marker -//////////////////////////////////////////////////////////////////////////////// - -AqlValue AttributeAccessor::extractTo(AqlValue const& src, - arangodb::AqlTransaction* trx) { - // TODO vpack - if (src._marker->getType() != TRI_DOC_MARKER_KEY_EDGE) { - return AqlValue(new Json(Json::Null)); - } - - auto cid = TRI_EXTRACT_MARKER_TO_CID(src._marker); - - if (_nameCache.value.empty() || _nameCache.cid != cid) { - _nameCache.cid = cid; - _nameCache.value = trx->resolver()->getCollectionNameCluster(cid); - } - - _buffer.reset(); - _buffer.appendText(_nameCache.value); - _buffer.appendChar('/'); - _buffer.appendText(TRI_EXTRACT_MARKER_TO_KEY(src._marker)); - - auto json = new Json(TRI_UNKNOWN_MEM_ZONE, _buffer.c_str(), _buffer.length()); - - return AqlValue(json); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief extract any other attribute from a ShapedJson marker -//////////////////////////////////////////////////////////////////////////////// - -AqlValue AttributeAccessor::extractRegular( - AqlValue const& src, arangodb::AqlTransaction* trx, - TRI_document_collection_t const* document) { - if (_shaper == nullptr) { - _shaper = document->getShaper(); - _pid = _shaper->lookupAttributePathByName(_combinedName.c_str()); - } - - if (_pid != 0) { - // attribute exists - TRI_ASSERT(_shaper != nullptr); - - TRI_shaped_json_t shapedJson; - TRI_EXTRACT_SHAPED_JSON_MARKER(shapedJson, src._marker); - - TRI_shaped_json_t json; - TRI_shape_t const* shape; - - bool ok = _shaper->extractShapedJson(&shapedJson, 0, _pid, &json, &shape); - - if (ok && shape != nullptr) { - std::unique_ptr extracted(TRI_JsonShapedJson(_shaper, &json)); - - if (extracted == nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } - - auto j = new Json(TRI_UNKNOWN_MEM_ZONE, extracted.get()); - extracted.release(); - return AqlValue(j); - } - } - - return AqlValue(new Json(Json::Null)); -} diff --git a/arangod/Aql/AttributeAccessor.h b/arangod/Aql/AttributeAccessor.h index 5c86ccda0f..d5a15cb9e4 100644 --- a/arangod/Aql/AttributeAccessor.h +++ b/arangod/Aql/AttributeAccessor.h @@ -27,17 +27,12 @@ #include "Basics/Common.h" #include "Aql/AqlValue.h" #include "Aql/types.h" -#include "Basics/StringBuffer.h" -#include "Utils/AqlTransaction.h" -#include "VocBase/shaped-json.h" - -struct TRI_document_collection_t; -class VocShaper; namespace arangodb { namespace aql { class AqlItemBlock; +class AqlTransaction; struct Variable; //////////////////////////////////////////////////////////////////////////////// @@ -45,15 +40,6 @@ struct Variable; //////////////////////////////////////////////////////////////////////////////// class AttributeAccessor { - enum AttributeType { - ATTRIBUTE_TYPE_KEY, - ATTRIBUTE_TYPE_REV, - ATTRIBUTE_TYPE_ID, - ATTRIBUTE_TYPE_FROM, - ATTRIBUTE_TYPE_TO, - ATTRIBUTE_TYPE_REGULAR - }; - public: AttributeAccessor(std::vector const&, Variable const*); @@ -67,39 +53,6 @@ class AttributeAccessor { std::vector const&, std::vector const&); - private: - ////////////////////////////////////////////////////////////////////////////// - /// @brief extract the _rev attribute from a ShapedJson marker - ////////////////////////////////////////////////////////////////////////////// - - AqlValue extractRev(AqlValue const&); - - ////////////////////////////////////////////////////////////////////////////// - /// @brief extract the _id attribute from a ShapedJson marker - ////////////////////////////////////////////////////////////////////////////// - - AqlValue extractId(AqlValue const&, arangodb::AqlTransaction*, - struct TRI_document_collection_t const*); - - ////////////////////////////////////////////////////////////////////////////// - /// @brief extract the _from attribute from a ShapedJson marker - ////////////////////////////////////////////////////////////////////////////// - - AqlValue extractFrom(AqlValue const&, arangodb::AqlTransaction*); - - ////////////////////////////////////////////////////////////////////////////// - /// @brief extract the _to attribute from a ShapedJson marker - ////////////////////////////////////////////////////////////////////////////// - - AqlValue extractTo(AqlValue const&, arangodb::AqlTransaction*); - - ////////////////////////////////////////////////////////////////////////////// - /// @brief extract any other attribute from a ShapedJson marker - ////////////////////////////////////////////////////////////////////////////// - - AqlValue extractRegular(AqlValue const&, arangodb::AqlTransaction*, - struct TRI_document_collection_t const*); - private: ////////////////////////////////////////////////////////////////////////////// /// @brief the attribute names vector (e.g. [ "a", "b", "c" ] for a.b.c) @@ -119,38 +72,6 @@ class AttributeAccessor { Variable const* _variable; - ////////////////////////////////////////////////////////////////////////////// - /// @brief buffer for temporary strings - ////////////////////////////////////////////////////////////////////////////// - - arangodb::basics::StringBuffer _buffer; - - ////////////////////////////////////////////////////////////////////////////// - /// @brief shaper - ////////////////////////////////////////////////////////////////////////////// - - VocShaper* _shaper; - - ////////////////////////////////////////////////////////////////////////////// - /// @brief attribute path id cache for shapes - ////////////////////////////////////////////////////////////////////////////// - - TRI_shape_pid_t _pid; - - ////////////////////////////////////////////////////////////////////////////// - /// @brief collection name lookup cache - ////////////////////////////////////////////////////////////////////////////// - - struct { - std::string value; - TRI_voc_cid_t cid; - } _nameCache; - - ////////////////////////////////////////////////////////////////////////////// - /// @brief attribute type (to save repeated strcmp calls) - ////////////////////////////////////////////////////////////////////////////// - - AttributeType _attributeType; }; } // namespace arangodb::aql diff --git a/arangod/Aql/CalculationBlock.cpp b/arangod/Aql/CalculationBlock.cpp index db091ba70c..391ab13cb0 100644 --- a/arangod/Aql/CalculationBlock.cpp +++ b/arangod/Aql/CalculationBlock.cpp @@ -128,17 +128,13 @@ void CalculationBlock::executeExpression(AqlItemBlock* result) { TRI_IF_FAILURE("CalculationBlock::executeExpressionWithCondition") { THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG); } - result->setValue(i, _outReg, AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, - &Expression::NullJson, - Json::NOFREE))); + result->setValue(i, _outReg, AqlValue(new Json(Json::Null))); continue; } } // execute the expression - TRI_document_collection_t const* myCollection = nullptr; - AqlValue a = - _expression->execute(_trx, result, i, _inVars, _inRegs, &myCollection); + AqlValue a = _expression->execute(_trx, result, i, _inVars, _inRegs); try { TRI_IF_FAILURE("CalculationBlock::executeExpression") { diff --git a/arangod/Aql/Expression.cpp b/arangod/Aql/Expression.cpp index bb952ad496..50d4d06b44 100644 --- a/arangod/Aql/Expression.cpp +++ b/arangod/Aql/Expression.cpp @@ -21,45 +21,31 @@ /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// -#include "Aql/Expression.h" +#include "Expression.h" #include "Aql/AqlItemBlock.h" #include "Aql/AqlValue.h" #include "Aql/Ast.h" #include "Aql/AttributeAccessor.h" #include "Aql/Executor.h" #include "Aql/Quantifier.h" +#include "Aql/Query.h" #include "Aql/V8Expression.h" #include "Aql/Variable.h" #include "Basics/Exceptions.h" #include "Basics/JsonHelper.h" #include "Basics/StringBuffer.h" +#include "Basics/VelocyPackHelper.h" #include "Basics/json.h" -#include "VocBase/document-collection.h" + +#include +#include +#include +#include using namespace arangodb::aql; using Json = arangodb::basics::Json; using JsonHelper = arangodb::basics::JsonHelper; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief "constant" global object for NULL which can be shared by all -/// expressions but must never be freed -//////////////////////////////////////////////////////////////////////////////// - -TRI_json_t const Expression::NullJson = {TRI_JSON_NULL, {false}}; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief "constant" global object for TRUE which can be shared by all -/// expressions but must never be freed -//////////////////////////////////////////////////////////////////////////////// - -TRI_json_t const Expression::TrueJson = {TRI_JSON_BOOLEAN, {true}}; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief "constant" global object for FALSE which can be shared by all -/// expressions but must never be freed -//////////////////////////////////////////////////////////////////////////////// - -TRI_json_t const Expression::FalseJson = {TRI_JSON_BOOLEAN, {false}}; +using VelocyPackHelper = arangodb::basics::VelocyPackHelper; //////////////////////////////////////////////////////////////////////////////// /// @brief register warning @@ -155,8 +141,7 @@ void Expression::variables(std::unordered_set& result) const { AqlValue Expression::execute(arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, - std::vector const& regs, - TRI_document_collection_t const** collection) { + std::vector const& regs) { if (!_built) { buildExpression(); } @@ -172,8 +157,8 @@ AqlValue Expression::execute(arangodb::AqlTransaction* trx, } case SIMPLE: { - return executeSimpleExpression(_node, collection, trx, argv, startPos, - vars, regs, true); + return AqlValue(executeSimpleExpression(_node, trx, argv, startPos, + vars, regs, true)); } case ATTRIBUTE: { @@ -185,9 +170,6 @@ AqlValue Expression::execute(arangodb::AqlTransaction* trx, TRI_ASSERT(_func != nullptr); try { ISOLATE; - // Dump the expression in question - // std::cout << arangodb::basics::Json(TRI_UNKNOWN_MEM_ZONE, - // _node->toJson(TRI_UNKNOWN_MEM_ZONE, true)).toString()<< "\n"; return _func->execute(isolate, _ast->query(), trx, argv, startPos, vars, regs); } catch (arangodb::basics::Exception& ex) { @@ -283,14 +265,12 @@ void Expression::invalidate() { /// linear search (if the node is not sorted) //////////////////////////////////////////////////////////////////////////////// -bool Expression::findInArray(AqlValue const& left, AqlValue const& right, - TRI_document_collection_t const* leftCollection, - TRI_document_collection_t const* rightCollection, +bool Expression::findInArray(AqlValue$ const& left, AqlValue$ const& right, arangodb::AqlTransaction* trx, AstNode const* node) const { - TRI_ASSERT(right.isArray()); + TRI_ASSERT(right.slice().isArray()); - size_t const n = right.arraySize(); + size_t const n = right.slice().length(); if (n > 3 && (node->getMember(1)->isSorted() || @@ -303,11 +283,10 @@ bool Expression::findInArray(AqlValue const& left, AqlValue const& right, while (true) { // determine midpoint size_t m = l + ((r - l) / 2); - auto arrayItem = right.extractArrayMember(trx, rightCollection, m, false); - AqlValue arrayItemValue(&arrayItem); + VPackSlice arrayItem = right.slice().at(m); + AqlValue$ arrayItemValue(arrayItem); - int compareResult = AqlValue::Compare(trx, left, leftCollection, - arrayItemValue, nullptr, false); + int compareResult = AqlValue$::Compare(trx, left, arrayItemValue, true); if (compareResult == 0) { // item found in the list @@ -329,13 +308,9 @@ bool Expression::findInArray(AqlValue const& left, AqlValue const& right, } } else { // use linear search - for (size_t i = 0; i < n; ++i) { + for (auto const& it : VPackArrayIterator(right.slice())) { // do not copy the list element we're looking at - auto arrayItem = right.extractArrayMember(trx, rightCollection, i, false); - AqlValue arrayItemValue(&arrayItem); - - int compareResult = AqlValue::Compare(trx, left, leftCollection, - arrayItemValue, nullptr, false); + int compareResult = AqlValue$::Compare(trx, left, AqlValue$(it), false); if (compareResult == 0) { // item found in the list @@ -458,9 +433,8 @@ void Expression::buildExpression() { /// the resulting AqlValue will be destroyed outside eventually //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpression( - AstNode const* node, TRI_document_collection_t const** collection, - arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, +AqlValue$ Expression::executeSimpleExpression( + AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, std::vector const& regs, bool doCopy) { switch (node->type) { @@ -479,7 +453,7 @@ AqlValue Expression::executeSimpleExpression( case NODE_TYPE_VALUE: return executeSimpleExpressionValue(node); case NODE_TYPE_REFERENCE: - return executeSimpleExpressionReference(node, collection, argv, startPos, + return executeSimpleExpressionReference(node, trx, argv, startPos, vars, regs, doCopy); case NODE_TYPE_FCALL: return executeSimpleExpressionFCall(node, trx, argv, startPos, vars, @@ -520,7 +494,7 @@ AqlValue Expression::executeSimpleExpression( return executeSimpleExpressionExpansion(node, trx, argv, startPos, vars, regs); case NODE_TYPE_ITERATOR: - return executeSimpleExpressionIterator(node, collection, trx, argv, + return executeSimpleExpressionIterator(node, trx, argv, startPos, vars, regs); case NODE_TYPE_OPERATOR_BINARY_PLUS: case NODE_TYPE_OPERATOR_BINARY_MINUS: @@ -583,7 +557,7 @@ void Expression::stringifyIfNotTooLong( /// @brief execute an expression of type SIMPLE with ATTRIBUTE ACCESS //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionAttributeAccess( +AqlValue$ Expression::executeSimpleExpressionAttributeAccess( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, @@ -594,20 +568,24 @@ AqlValue Expression::executeSimpleExpressionAttributeAccess( auto member = node->getMemberUnchecked(0); auto name = static_cast(node->getData()); - TRI_document_collection_t const* myCollection = nullptr; - AqlValue result = executeSimpleExpression(member, &myCollection, trx, argv, - startPos, vars, regs, false); + AqlValue$ result = executeSimpleExpression(member, trx, argv, + startPos, vars, regs, false); - auto j = result.extractObjectMember(trx, myCollection, name, true, _buffer); - result.destroy(); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal())); + VPackSlice slice = result.slice(); + if (slice.isObject()) { + VPackSlice value = slice.get(name); + if (!value.isNone()) { + return AqlValue$(value); + } + } + return AqlValue$(VelocyPackHelper::NullValue()); } //////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with INDEXED ACCESS //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionIndexedAccess( +AqlValue$ Expression::executeSimpleExpressionIndexedAccess( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, @@ -627,75 +605,62 @@ AqlValue Expression::executeSimpleExpressionIndexedAccess( auto member = node->getMember(0); auto index = node->getMember(1); - TRI_document_collection_t const* myCollection = nullptr; - AqlValue result = executeSimpleExpression(member, &myCollection, trx, argv, - startPos, vars, regs, false); + AqlValue$ result = executeSimpleExpression(member, trx, argv, + startPos, vars, regs, false); - if (result.isArray()) { - TRI_document_collection_t const* myCollection2 = nullptr; - AqlValue indexResult = executeSimpleExpression( - index, &myCollection2, trx, argv, startPos, vars, regs, false); + if (result.slice().isArray()) { + AqlValue$ indexResult = executeSimpleExpression( + index, trx, argv, startPos, vars, regs, false); - if (indexResult.isNumber()) { - auto j = result.extractArrayMember(trx, myCollection, - indexResult.toInt64(), true); - indexResult.destroy(); - result.destroy(); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal())); - } else if (indexResult.isString()) { - auto value(indexResult.toString()); - indexResult.destroy(); + if (indexResult.slice().isNumber()) { + return AqlValue$(result.slice().at(indexResult.toInt64())); + } + + if (indexResult.slice().isString()) { + std::string const value = indexResult.slice().copyString(); try { // stoll() might throw an exception if the string is not a number - int64_t position = static_cast(std::stoll(value.c_str())); - auto j = result.extractArrayMember(trx, myCollection, position, true); - result.destroy(); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal())); + int64_t position = static_cast(std::stoll(value)); + return AqlValue$(result.slice().at(position)); } catch (...) { // no number found. } - } else { - indexResult.destroy(); - } + } // fall-through to returning null - } else if (result.isObject()) { - TRI_document_collection_t const* myCollection2 = nullptr; - AqlValue indexResult = executeSimpleExpression( - index, &myCollection2, trx, argv, startPos, vars, regs, false); + } else if (result.slice().isObject()) { + AqlValue$ indexResult = executeSimpleExpression( + index, trx, argv, startPos, vars, regs, false); - if (indexResult.isNumber()) { - auto indexString(std::to_string(indexResult.toInt64())); - auto j = result.extractObjectMember(trx, myCollection, - indexString.c_str(), true, _buffer); - indexResult.destroy(); - result.destroy(); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal())); - } else if (indexResult.isString()) { - auto value(indexResult.toString()); - indexResult.destroy(); - - auto j = result.extractObjectMember(trx, myCollection, value.c_str(), - true, _buffer); - result.destroy(); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal())); - } else { - indexResult.destroy(); + if (indexResult.slice().isNumber()) { + std::string const indexString = std::to_string(indexResult.slice().getNumber()); + VPackSlice value = result.slice().get(indexString); + if (!value.isNone()) { + return AqlValue$(value); + } + return AqlValue$(VelocyPackHelper::NullValue()); } - + + if (indexResult.slice().isString()) { + std::string const indexString = indexResult.slice().copyString(); + VPackSlice value = result.slice().get(indexString); + if (!value.isNone()) { + return AqlValue$(value); + } + return AqlValue$(VelocyPackHelper::NullValue()); + } // fall-through to returning null } - result.destroy(); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, &NullJson, Json::NOFREE)); + return AqlValue$(VelocyPackHelper::NullValue()); } //////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with ARRAY //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionArray( +AqlValue$ Expression::executeSimpleExpressionArray( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, @@ -707,31 +672,33 @@ AqlValue Expression::executeSimpleExpressionArray( THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } - // we do not own the JSON but the node does! - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, json, Json::NOFREE)); + VPackBuilder builder; + JsonHelper::toVelocyPack(json, builder); + + return AqlValue$(builder); } size_t const n = node->numMembers(); - auto array = std::make_unique(Json::Array, n); + + VPackBuilder builder; + builder.openArray(); for (size_t i = 0; i < n; ++i) { auto member = node->getMemberUnchecked(i); - TRI_document_collection_t const* myCollection = nullptr; - - AqlValue result = executeSimpleExpression(member, &myCollection, trx, argv, - startPos, vars, regs, false); - array->add(result.toJson(trx, myCollection, true)); - result.destroy(); + AqlValue$ result = executeSimpleExpression(member, trx, argv, + startPos, vars, regs, false); + builder.add(result.slice()); } + builder.close(); - return AqlValue(array.release()); + return AqlValue$(builder); } //////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with OBJECT //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionObject( +AqlValue$ Expression::executeSimpleExpressionObject( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, @@ -742,51 +709,54 @@ AqlValue Expression::executeSimpleExpressionObject( if (json == nullptr) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } + + VPackBuilder builder; + JsonHelper::toVelocyPack(json, builder); - // we do not own the JSON but the node does! - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, json, Json::NOFREE)); + return AqlValue$(builder); } + VPackBuilder builder; + builder.openObject(); + size_t const n = node->numMembers(); - auto object = std::make_unique(Json::Object, n); - for (size_t i = 0; i < n; ++i) { auto member = node->getMemberUnchecked(i); - TRI_document_collection_t const* myCollection = nullptr; - TRI_ASSERT(member->type == NODE_TYPE_OBJECT_ELEMENT); - auto key = member->getStringValue(); + char const* key = member->getStringValue(); member = member->getMember(0); - AqlValue result = executeSimpleExpression(member, &myCollection, trx, argv, - startPos, vars, regs, false); - object->set(key, result.toJson(trx, myCollection, true)); - result.destroy(); + AqlValue$ result = executeSimpleExpression(member, trx, argv, + startPos, vars, regs, false); + builder.add(key, result.slice()); } - return AqlValue(object.release()); + builder.close(); + + return AqlValue$(builder); } //////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with VALUE //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionValue(AstNode const* node) { +AqlValue$ Expression::executeSimpleExpressionValue(AstNode const* node) { auto json = node->computeJson(); if (json == nullptr) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } - // we do not own the JSON but the node does! - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, json, Json::NOFREE)); + VPackBuilder builder; + JsonHelper::toVelocyPack(json, builder); + return AqlValue$(builder); } //////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with REFERENCE //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionReference( - AstNode const* node, TRI_document_collection_t const** collection, +AqlValue$ Expression::executeSimpleExpressionReference( + AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, std::vector const& regs, bool doCopy) { @@ -796,34 +766,17 @@ AqlValue Expression::executeSimpleExpressionReference( auto it = _variables.find(v); if (it != _variables.end()) { - *collection = nullptr; - auto copy = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, (*it).second); - - if (copy == nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } - - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, copy)); + return AqlValue$((*it).second); } } size_t i = 0; for (auto it = vars.begin(); it != vars.end(); ++it, ++i) { if ((*it)->name == v->name) { - TRI_ASSERT(collection != nullptr); - - // save the collection info - *collection = argv->getDocumentCollection(regs[i]); - - if (doCopy) { - return argv->getValueReference(startPos, regs[i]).clone(); - } - - // AqlValue.destroy() will be called for the returned value soon, - // so we must not return the original AqlValue from the AqlItemBlock here - return argv->getValueReference(startPos, regs[i]).shallowClone(); + return AqlValue$(argv->getValueReference(startPos, regs[i]), trx, nullptr); } } + std::string msg("variable not found '"); msg.append(v->name); msg.append("' in executeSimpleExpression()"); @@ -834,32 +787,36 @@ AqlValue Expression::executeSimpleExpressionReference( /// @brief execute an expression of type SIMPLE with RANGE //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionRange( +AqlValue$ Expression::executeSimpleExpressionRange( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, std::vector const& regs) { - TRI_document_collection_t const* leftCollection = nullptr; - TRI_document_collection_t const* rightCollection = nullptr; auto low = node->getMember(0); auto high = node->getMember(1); - AqlValue resultLow = executeSimpleExpression(low, &leftCollection, trx, argv, - startPos, vars, regs, false); - AqlValue resultHigh = executeSimpleExpression( - high, &rightCollection, trx, argv, startPos, vars, regs, false); - AqlValue res = AqlValue(resultLow.toInt64(), resultHigh.toInt64()); - resultLow.destroy(); - resultHigh.destroy(); - - return res; + AqlValue$ resultLow = executeSimpleExpression(low, trx, argv, + startPos, vars, regs, false); + AqlValue$ resultHigh = executeSimpleExpression( + high, trx, argv, startPos, vars, regs, false); + + // build a custom type for the range + VPackBuilder builder; + uint8_t* p = builder.add(VPackValuePair(2 + 2 * sizeof(int64_t), VPackValueType::Custom)); + *p++ = 0xf4; // custom type for range + *p++ = 2 * sizeof(int64_t); + memcpy(p, &low, sizeof(int64_t)); + p += sizeof(int64_t); + memcpy(p, &high, sizeof(int64_t)); + + return AqlValue$(builder); } //////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with FCALL //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionFCall( +AqlValue$ Expression::executeSimpleExpressionFCall( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, @@ -881,132 +838,109 @@ AqlValue Expression::executeSimpleExpressionFCall( #warning Check if this is correct w.r.t. Memory Management for (size_t i = 0; i < n; ++i) { - builder.clear(); - TRI_document_collection_t const* myCollection = nullptr; auto arg = member->getMemberUnchecked(i); if (arg->type == NODE_TYPE_COLLECTION) { + builder.clear(); builder.add(VPackValue( std::string(arg->getStringValue(), arg->getStringLength()))); parameters.emplace_back(AqlValue$(builder)); } else { - AqlValue tmp = executeSimpleExpression(arg, &myCollection, trx, argv, - startPos, vars, regs, false); - parameters.emplace_back(AqlValue$(tmp, trx, myCollection)); + parameters.emplace_back(executeSimpleExpression(arg, trx, argv, + startPos, vars, regs, false)); } } - auto res2 = func->implementation(_ast->query(), trx, parameters); - - // parameters go out if scope and free themselves. - return AqlValue(res2); + return func->implementation(_ast->query(), trx, parameters); } //////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with NOT //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionNot( +AqlValue$ Expression::executeSimpleExpressionNot( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, std::vector const& regs) { - TRI_document_collection_t const* myCollection = nullptr; - AqlValue operand = - executeSimpleExpression(node->getMember(0), &myCollection, trx, argv, + AqlValue$ operand = + executeSimpleExpression(node->getMember(0), trx, argv, startPos, vars, regs, false); - bool const operandIsTrue = operand.isTrue(); - operand.destroy(); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, - operandIsTrue ? &FalseJson : &TrueJson, - Json::NOFREE)); + return AqlValue$(operand.isTrue() ? VelocyPackHelper::FalseValue() : VelocyPackHelper::TrueValue()); } //////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with AND or OR //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionAndOr( +AqlValue$ Expression::executeSimpleExpressionAndOr( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, std::vector const& regs) { - TRI_document_collection_t const* leftCollection = nullptr; - AqlValue left = - executeSimpleExpression(node->getMember(0), &leftCollection, trx, argv, + AqlValue$ left = + executeSimpleExpression(node->getMember(0), trx, argv, startPos, vars, regs, true); - TRI_document_collection_t const* rightCollection = nullptr; - AqlValue right = - executeSimpleExpression(node->getMember(1), &rightCollection, trx, argv, + AqlValue$ right = + executeSimpleExpression(node->getMember(1), trx, argv, startPos, vars, regs, true); if (node->type == NODE_TYPE_OPERATOR_BINARY_AND) { // AND if (left.isTrue()) { // left is true => return right - left.destroy(); return right; } // left is false, return left - right.destroy(); return left; - } else { - // OR - if (left.isTrue()) { - // left is true => return left - right.destroy(); - return left; - } - - // left is false => return right - left.destroy(); - return right; + } + + // OR + if (left.isTrue()) { + // left is true => return left + return left; } + + // left is false => return right + return right; } //////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with COMPARISON //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionComparison( +AqlValue$ Expression::executeSimpleExpressionComparison( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, std::vector const& regs) { - TRI_document_collection_t const* leftCollection = nullptr; - AqlValue left = - executeSimpleExpression(node->getMember(0), &leftCollection, trx, argv, + AqlValue$ left = + executeSimpleExpression(node->getMember(0), trx, argv, startPos, vars, regs, false); - TRI_document_collection_t const* rightCollection = nullptr; - AqlValue right = - executeSimpleExpression(node->getMember(1), &rightCollection, trx, argv, + AqlValue$ right = + executeSimpleExpression(node->getMember(1), trx, argv, startPos, vars, regs, false); if (node->type == NODE_TYPE_OPERATOR_BINARY_IN || node->type == NODE_TYPE_OPERATOR_BINARY_NIN) { // IN and NOT IN - if (!right.isArray()) { + if (!right.slice().isArray()) { // right operand must be a list, otherwise we return false - left.destroy(); - right.destroy(); // do not throw, but return "false" instead - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, &FalseJson, Json::NOFREE)); + return AqlValue$(VelocyPackHelper::FalseValue()); } bool result = - findInArray(left, right, leftCollection, rightCollection, trx, node); + findInArray(left, right, trx, node); if (node->type == NODE_TYPE_OPERATOR_BINARY_NIN) { // revert the result in case of a NOT IN result = !result; } - left.destroy(); - right.destroy(); - - return AqlValue(new arangodb::basics::Json(result)); + return AqlValue$(result ? VelocyPackHelper::TrueValue() : VelocyPackHelper::FalseValue()); } // all other comparison operators... @@ -1015,35 +949,20 @@ AqlValue Expression::executeSimpleExpressionComparison( bool compareUtf8 = (node->type != NODE_TYPE_OPERATOR_BINARY_EQ && node->type != NODE_TYPE_OPERATOR_BINARY_NE); - int compareResult = AqlValue::Compare(trx, left, leftCollection, right, - rightCollection, compareUtf8); - left.destroy(); - right.destroy(); + int compareResult = AqlValue$::Compare(trx, left, right, compareUtf8); switch (node->type) { case NODE_TYPE_OPERATOR_BINARY_EQ: - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, - (compareResult == 0) ? &TrueJson : &FalseJson, - Json::NOFREE)); + return AqlValue$((compareResult == 0) ? VelocyPackHelper::TrueValue() : VelocyPackHelper::FalseValue()); case NODE_TYPE_OPERATOR_BINARY_NE: - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, - (compareResult != 0) ? &TrueJson : &FalseJson, - Json::NOFREE)); + return AqlValue$((compareResult != 0) ? VelocyPackHelper::TrueValue() : VelocyPackHelper::FalseValue()); case NODE_TYPE_OPERATOR_BINARY_LT: - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, - (compareResult < 0) ? &TrueJson : &FalseJson, - Json::NOFREE)); + return AqlValue$((compareResult < 0) ? VelocyPackHelper::TrueValue() : VelocyPackHelper::FalseValue()); case NODE_TYPE_OPERATOR_BINARY_LE: - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, - (compareResult <= 0) ? &TrueJson : &FalseJson, - Json::NOFREE)); + return AqlValue$((compareResult <= 0) ? VelocyPackHelper::TrueValue() : VelocyPackHelper::FalseValue()); case NODE_TYPE_OPERATOR_BINARY_GT: - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, - (compareResult > 0) ? &TrueJson : &FalseJson, - Json::NOFREE)); + return AqlValue$((compareResult > 0) ? VelocyPackHelper::TrueValue() : VelocyPackHelper::FalseValue()); case NODE_TYPE_OPERATOR_BINARY_GE: - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, - (compareResult >= 0) ? &TrueJson : &FalseJson, - Json::NOFREE)); + return AqlValue$((compareResult >= 0) ? VelocyPackHelper::TrueValue() : VelocyPackHelper::FalseValue()); default: std::string msg("unhandled type '"); msg.append(node->getTypeString()); @@ -1056,41 +975,35 @@ AqlValue Expression::executeSimpleExpressionComparison( /// @brief execute an expression of type SIMPLE with ARRAY COMPARISON //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionArrayComparison( +AqlValue$ Expression::executeSimpleExpressionArrayComparison( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, std::vector const& regs) { - TRI_document_collection_t const* leftCollection = nullptr; - AqlValue left = - executeSimpleExpression(node->getMember(0), &leftCollection, trx, argv, + AqlValue$ left = + executeSimpleExpression(node->getMember(0), trx, argv, startPos, vars, regs, false); - TRI_document_collection_t const* rightCollection = nullptr; - AqlValue right = - executeSimpleExpression(node->getMember(1), &rightCollection, trx, argv, + AqlValue$ right = + executeSimpleExpression(node->getMember(1), trx, argv, startPos, vars, regs, false); - if (!left.isArray()) { + if (!left.slice().isArray()) { // left operand must be an array - left.destroy(); - right.destroy(); // do not throw, but return "false" instead - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, &FalseJson, Json::NOFREE)); + return AqlValue$(VelocyPackHelper::FalseValue()); } if (node->type == NODE_TYPE_OPERATOR_BINARY_ARRAY_IN || node->type == NODE_TYPE_OPERATOR_BINARY_ARRAY_NIN) { // IN and NOT IN - if (!right.isArray()) { + if (!right.slice().isArray()) { // right operand must be a list, otherwise we return false - left.destroy(); - right.destroy(); // do not throw, but return "false" instead - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, &FalseJson, Json::NOFREE)); + return AqlValue$(VelocyPackHelper::FalseValue()); } } - size_t const n = left.arraySize(); + size_t const n = left.slice().length(); std::pair requiredMatches = Quantifier::RequiredMatches(n, node->getMember(2)); TRI_ASSERT(requiredMatches.first <= requiredMatches.second); @@ -1102,17 +1015,16 @@ AqlValue Expression::executeSimpleExpressionArrayComparison( bool overallResult = true; size_t matches = 0; size_t numLeft = n; - - for (size_t i = 0; i < n; ++i) { - auto leftItem = left.extractArrayMember(trx, leftCollection, static_cast(i), false); - AqlValue leftItemValue(&leftItem); + + for (auto const& it : VPackArrayIterator(left.slice())) { + AqlValue$ leftItemValue(it); bool result; // IN and NOT IN if (node->type == NODE_TYPE_OPERATOR_BINARY_ARRAY_IN || node->type == NODE_TYPE_OPERATOR_BINARY_ARRAY_NIN) { result = - findInArray(leftItemValue, right, nullptr, rightCollection, trx, node); + findInArray(leftItemValue, right, trx, node); if (node->type == NODE_TYPE_OPERATOR_BINARY_ARRAY_NIN) { // revert the result in case of a NOT IN @@ -1121,8 +1033,7 @@ AqlValue Expression::executeSimpleExpressionArrayComparison( } else { // other operators - int compareResult = AqlValue::Compare(trx, leftItemValue, nullptr, - right, rightCollection, compareUtf8); + int compareResult = AqlValue$::Compare(trx, leftItemValue, right, compareUtf8); result = false; switch (node->type) { @@ -1173,35 +1084,30 @@ AqlValue Expression::executeSimpleExpressionArrayComparison( } } - left.destroy(); - right.destroy(); - return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, overallResult ? &TrueJson : &FalseJson, Json::NOFREE)); + return AqlValue$(overallResult ? VelocyPackHelper::TrueValue() : VelocyPackHelper::FalseValue()); } //////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with TERNARY //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionTernary( +AqlValue$ Expression::executeSimpleExpressionTernary( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, std::vector const& regs) { - TRI_document_collection_t const* myCollection = nullptr; - AqlValue condition = - executeSimpleExpression(node->getMember(0), &myCollection, trx, argv, + AqlValue$ condition = + executeSimpleExpression(node->getMember(0), trx, argv, startPos, vars, regs, false); - bool const isTrue = condition.isTrue(); - condition.destroy(); - if (isTrue) { + if (condition.isTrue()) { // return true part - return executeSimpleExpression(node->getMember(1), &myCollection, trx, argv, + return executeSimpleExpression(node->getMember(1), trx, argv, startPos, vars, regs, true); } // return false part - return executeSimpleExpression(node->getMember(2), &myCollection, trx, argv, + return executeSimpleExpression(node->getMember(2), trx, argv, startPos, vars, regs, true); } @@ -1209,7 +1115,7 @@ AqlValue Expression::executeSimpleExpressionTernary( /// @brief execute an expression of type SIMPLE with EXPANSION //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionExpansion( +AqlValue$ Expression::executeSimpleExpressionExpansion( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, @@ -1223,23 +1129,22 @@ AqlValue Expression::executeSimpleExpressionExpansion( auto limitNode = node->getMember(3); if (limitNode->type != NODE_TYPE_NOP) { - TRI_document_collection_t const* subCollection = nullptr; - AqlValue sub = - executeSimpleExpression(limitNode->getMember(0), &subCollection, trx, + AqlValue$ sub = + executeSimpleExpression(limitNode->getMember(0), trx, argv, startPos, vars, regs, false); offset = sub.toInt64(); - sub.destroy(); - subCollection = nullptr; - sub = executeSimpleExpression(limitNode->getMember(1), &subCollection, trx, + sub = executeSimpleExpression(limitNode->getMember(1), trx, argv, startPos, vars, regs, false); count = sub.toInt64(); - sub.destroy(); } - + if (offset < 0 || count <= 0) { // no items to return... can already stop here - return AqlValue(new arangodb::basics::Json(arangodb::basics::Json::Array)); + VPackBuilder builder; + builder.openArray(); + builder.close(); + return AqlValue$(builder); } // FILTER @@ -1253,8 +1158,10 @@ AqlValue Expression::executeSimpleExpressionExpansion( filterNode = nullptr; } else { // filter expression is always false - return AqlValue( - new arangodb::basics::Json(arangodb::basics::Json::Array)); + VPackBuilder builder; + builder.openArray(); + builder.close(); + return AqlValue$(builder); } } @@ -1262,67 +1169,52 @@ AqlValue Expression::executeSimpleExpressionExpansion( auto variable = static_cast(iterator->getMember(0)->getData()); auto levels = node->getIntValue(true); - AqlValue value; + AqlValue$ value; if (levels > 1) { // flatten value... - - // generate a new temporary for the flattened array - auto flattened = std::make_unique(Json::Array); - - TRI_document_collection_t const* myCollection = nullptr; - value = executeSimpleExpression(node->getMember(0), &myCollection, trx, + value = executeSimpleExpression(node->getMember(0), trx, argv, startPos, vars, regs, false); + + VPackBuilder builder; + builder.openArray(); - if (!value.isArray()) { - value.destroy(); - return AqlValue( - new arangodb::basics::Json(arangodb::basics::Json::Array)); + if (!value.slice().isArray()) { + builder.close(); + return AqlValue$(builder); } - - std::function flatten = - [&](TRI_json_t const* json, int64_t level) { - if (!TRI_IsArrayJson(json)) { + + // generate a new temporary for the flattened array + std::function flatten = + [&](VPackSlice const& json, int64_t level) { + if (!json.isArray()) { return; } - size_t const n = TRI_LengthArrayJson(json); - - for (size_t i = 0; i < n; ++i) { - auto item = static_cast( - TRI_AtVector(&json->_value._objects, i)); - - bool const isArray = TRI_IsArrayJson(item); + for (auto const& it : VPackArrayIterator(json)) { + bool const isArray = it.isArray(); if (!isArray || level == levels) { - auto copy = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, item); - - if (copy == nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } - - flattened->add(copy); + builder.add(it); } else if (isArray && level < levels) { - flatten(item, level + 1); + flatten(it, level + 1); } } }; - auto subJson = value.toJson(trx, myCollection, false); - flatten(subJson.json(), 1); - value.destroy(); + flatten(value.slice(), 1); + builder.close(); - value = AqlValue(flattened.release()); + value = AqlValue$(builder); } else { - TRI_document_collection_t const* myCollection = nullptr; - value = executeSimpleExpression(node->getMember(0), &myCollection, trx, + value = executeSimpleExpression(node->getMember(0), trx, argv, startPos, vars, regs, false); - if (!value.isArray()) { - // must cast value to array first - value.destroy(); - return AqlValue( - new arangodb::basics::Json(arangodb::basics::Json::Array)); + if (!value.slice().isArray()) { + VPackBuilder builder; + builder.openArray(); + builder.close(); + return AqlValue$(builder); } } @@ -1335,26 +1227,19 @@ AqlValue Expression::executeSimpleExpressionExpansion( projectionNode = node->getMember(4); } - size_t const n = value.arraySize(); - auto array = std::make_unique(Json::Array, n); + VPackBuilder builder; + builder.openArray(); - for (size_t i = 0; i < n; ++i) { - // TODO: check why we must copy the array member. will crash without - // copying! - TRI_document_collection_t const* myCollection = nullptr; - auto arrayItem = value.extractArrayMember(trx, myCollection, i, true); - - setVariable(variable, arrayItem.json()); + for (auto const& it : VPackArrayIterator(value.slice())) { + setVariable(variable, it); bool takeItem = true; if (filterNode != nullptr) { // have a filter - TRI_document_collection_t const* subCollection = nullptr; - AqlValue sub = executeSimpleExpression(filterNode, &subCollection, trx, + AqlValue$ sub = executeSimpleExpression(filterNode, trx, argv, startPos, vars, regs, false); takeItem = sub.isTrue(); - sub.destroy(); } if (takeItem && offset > 0) { @@ -1364,18 +1249,14 @@ AqlValue Expression::executeSimpleExpressionExpansion( } if (takeItem) { - TRI_document_collection_t const* subCollection = nullptr; - AqlValue sub = - executeSimpleExpression(projectionNode, &subCollection, trx, argv, + AqlValue$ sub = + executeSimpleExpression(projectionNode, trx, argv, startPos, vars, regs, true); - array->add(sub.toJson(trx, subCollection, true)); - sub.destroy(); + builder.add(sub.slice()); } clearVariable(variable); - arrayItem.destroy(); - if (takeItem && count > 0) { // number of items to pick was restricted if (--count == 0) { @@ -1385,24 +1266,24 @@ AqlValue Expression::executeSimpleExpressionExpansion( } } - value.destroy(); - return AqlValue(array.release()); + builder.close(); + + return AqlValue$(builder); } //////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with ITERATOR //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionIterator( - AstNode const* node, TRI_document_collection_t const** collection, +AqlValue$ Expression::executeSimpleExpressionIterator( + AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, std::vector const& regs) { TRI_ASSERT(node != nullptr); TRI_ASSERT(node->numMembers() == 2); - *collection = nullptr; - return executeSimpleExpression(node->getMember(1), collection, trx, argv, + return executeSimpleExpression(node->getMember(1), trx, argv, startPos, vars, regs, true); } @@ -1410,62 +1291,54 @@ AqlValue Expression::executeSimpleExpressionIterator( /// @brief execute an expression of type SIMPLE with BINARY_* (+, -, * , /, %) //////////////////////////////////////////////////////////////////////////////// -AqlValue Expression::executeSimpleExpressionArithmetic( +AqlValue$ Expression::executeSimpleExpressionArithmetic( AstNode const* node, arangodb::AqlTransaction* trx, AqlItemBlock const* argv, size_t startPos, std::vector const& vars, std::vector const& regs) { - TRI_document_collection_t const* leftCollection = nullptr; - AqlValue lhs = executeSimpleExpression(node->getMember(0), &leftCollection, - trx, argv, startPos, vars, regs, true); + AqlValue$ lhs = executeSimpleExpression(node->getMember(0), + trx, argv, startPos, vars, regs, true); - if (lhs.isObject()) { - lhs.destroy(); - return AqlValue(new Json(Json::Null)); + if (lhs.slice().isObject()) { + return AqlValue$(VelocyPackHelper::NullValue()); } - TRI_document_collection_t const* rightCollection = nullptr; - AqlValue rhs = executeSimpleExpression(node->getMember(1), &rightCollection, - trx, argv, startPos, vars, regs, true); + AqlValue$ rhs = executeSimpleExpression(node->getMember(1), + trx, argv, startPos, vars, regs, true); - if (rhs.isObject()) { - lhs.destroy(); - rhs.destroy(); - return AqlValue(new Json(Json::Null)); + if (rhs.slice().isObject()) { + return AqlValue$(VelocyPackHelper::NullValue()); } - bool failed = false; - double l = lhs.toNumber(failed); - lhs.destroy(); + double const l = lhs.slice().getNumber(); + double const r = rhs.slice().getNumber(); - if (failed) { - rhs.destroy(); - return AqlValue(new Json(Json::Null)); - } - - double r = rhs.toNumber(failed); - rhs.destroy(); - - if (failed) { - return AqlValue(new Json(Json::Null)); - } + VPackBuilder builder; switch (node->type) { case NODE_TYPE_OPERATOR_BINARY_PLUS: - return AqlValue(new Json(l + r)); + builder.add(VPackValue(l + r)); + return AqlValue$(builder); case NODE_TYPE_OPERATOR_BINARY_MINUS: - return AqlValue(new Json(l - r)); + builder.add(VPackValue(l - r)); + return AqlValue$(builder); case NODE_TYPE_OPERATOR_BINARY_TIMES: - return AqlValue(new Json(l * r)); + builder.add(VPackValue(l * r)); + return AqlValue$(builder); case NODE_TYPE_OPERATOR_BINARY_DIV: - if (r == 0) { + if (r == 0.0) { RegisterWarning(_ast, "/", TRI_ERROR_QUERY_DIVISION_BY_ZERO); - return AqlValue(new Json(Json::Null)); + return AqlValue$(VelocyPackHelper::NullValue()); } - return AqlValue(new Json(l / r)); + return AqlValue$(builder); case NODE_TYPE_OPERATOR_BINARY_MOD: - return AqlValue(new Json(fmod(l, r))); + if (r == 0.0) { + RegisterWarning(_ast, "/", TRI_ERROR_QUERY_DIVISION_BY_ZERO); + return AqlValue$(VelocyPackHelper::NullValue()); + } + builder.add(VPackValue(fmod(l, r))); + return AqlValue$(builder); default: - return AqlValue(new Json(Json::Null)); + return AqlValue$(VelocyPackHelper::NullValue()); } } diff --git a/arangod/Aql/Expression.h b/arangod/Aql/Expression.h index 50a711a476..71410384a6 100644 --- a/arangod/Aql/Expression.h +++ b/arangod/Aql/Expression.h @@ -26,25 +26,29 @@ #include "Basics/Common.h" #include "Aql/AstNode.h" -#include "Aql/Query.h" #include "Aql/Range.h" #include "Aql/Variable.h" #include "Aql/types.h" #include "Basics/JsonHelper.h" -#include "Basics/StringBuffer.h" -#include "Utils/AqlTransaction.h" + +#include +#include struct TRI_json_t; namespace arangodb { +class AqlTransaction; + namespace basics { class Json; +class StringBuffer; } namespace aql { class AqlItemBlock; struct AqlValue; +struct AqlValue$; class Ast; class AttributeAccessor; class Executor; @@ -167,8 +171,7 @@ class Expression { AqlValue execute(arangodb::AqlTransaction* trx, AqlItemBlock const*, size_t, std::vector const&, - std::vector const&, - TRI_document_collection_t const**); + std::vector const&); ////////////////////////////////////////////////////////////////////////////// /// @brief check whether this is a JSON expression @@ -278,8 +281,7 @@ class Expression { void invalidate(); private: - void setVariable(Variable const* variable, TRI_json_t const* value) { - TRI_ASSERT(value != nullptr); + void setVariable(Variable const* variable, arangodb::velocypack::Slice value) { _variables.emplace(variable, value); } @@ -289,9 +291,8 @@ class Expression { /// @brief find a value in an array ////////////////////////////////////////////////////////////////////////////// - bool findInArray(AqlValue const&, AqlValue const&, - TRI_document_collection_t const*, - TRI_document_collection_t const*, arangodb::AqlTransaction*, + bool findInArray(AqlValue$ const&, AqlValue$ const&, + arangodb::AqlTransaction*, AstNode const*) const; ////////////////////////////////////////////////////////////////////////////// @@ -311,18 +312,17 @@ class Expression { /// @brief execute an expression of type SIMPLE ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpression(AstNode const*, - TRI_document_collection_t const**, - arangodb::AqlTransaction*, - AqlItemBlock const*, size_t, - std::vector const&, - std::vector const&, bool); + AqlValue$ executeSimpleExpression(AstNode const*, + arangodb::AqlTransaction*, + AqlItemBlock const*, size_t, + std::vector const&, + std::vector const&, bool); ////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with ATTRIBUTE ACCESS ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionAttributeAccess( + AqlValue$ executeSimpleExpressionAttributeAccess( AstNode const*, arangodb::AqlTransaction*, AqlItemBlock const*, size_t, std::vector const&, std::vector const&); @@ -330,7 +330,7 @@ class Expression { /// @brief execute an expression of type SIMPLE with INDEXED ACCESS ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionIndexedAccess( + AqlValue$ executeSimpleExpressionIndexedAccess( AstNode const*, arangodb::AqlTransaction*, AqlItemBlock const*, size_t, std::vector const&, std::vector const&); @@ -338,17 +338,17 @@ class Expression { /// @brief execute an expression of type SIMPLE with ARRAY ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionArray(AstNode const*, - arangodb::AqlTransaction*, - AqlItemBlock const*, size_t, - std::vector const&, - std::vector const&); + AqlValue$ executeSimpleExpressionArray(AstNode const*, + arangodb::AqlTransaction*, + AqlItemBlock const*, size_t, + std::vector const&, + std::vector const&); ////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with OBJECT ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionObject(AstNode const*, + AqlValue$ executeSimpleExpressionObject(AstNode const*, arangodb::AqlTransaction*, AqlItemBlock const*, size_t, std::vector const&, @@ -358,63 +358,63 @@ class Expression { /// @brief execute an expression of type SIMPLE with VALUE ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionValue(AstNode const*); + AqlValue$ executeSimpleExpressionValue(AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with REFERENCE ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionReference(AstNode const*, - TRI_document_collection_t const**, - AqlItemBlock const*, size_t, - std::vector const&, - std::vector const&, - bool); + AqlValue$ executeSimpleExpressionReference(AstNode const*, + arangodb::AqlTransaction*, + AqlItemBlock const*, size_t, + std::vector const&, + std::vector const&, + bool); ////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with FCALL ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionFCall(AstNode const*, - arangodb::AqlTransaction*, - AqlItemBlock const*, size_t, - std::vector const&, - std::vector const&); + AqlValue$ executeSimpleExpressionFCall(AstNode const*, + arangodb::AqlTransaction*, + AqlItemBlock const*, size_t, + std::vector const&, + std::vector const&); ////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with RANGE ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionRange(AstNode const*, - arangodb::AqlTransaction*, - AqlItemBlock const*, size_t, - std::vector const&, - std::vector const&); + AqlValue$ executeSimpleExpressionRange(AstNode const*, + arangodb::AqlTransaction*, + AqlItemBlock const*, size_t, + std::vector const&, + std::vector const&); ////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with NOT ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionNot(AstNode const*, arangodb::AqlTransaction*, - AqlItemBlock const*, size_t, - std::vector const&, - std::vector const&); + AqlValue$ executeSimpleExpressionNot(AstNode const*, arangodb::AqlTransaction*, + AqlItemBlock const*, size_t, + std::vector const&, + std::vector const&); ////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with AND or OR ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionAndOr(AstNode const*, - arangodb::AqlTransaction*, - AqlItemBlock const*, size_t, - std::vector const&, - std::vector const&); + AqlValue$ executeSimpleExpressionAndOr(AstNode const*, + arangodb::AqlTransaction*, + AqlItemBlock const*, size_t, + std::vector const&, + std::vector const&); ////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with COMPARISON ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionComparison( + AqlValue$ executeSimpleExpressionComparison( AstNode const*, arangodb::AqlTransaction*, AqlItemBlock const*, size_t, std::vector const&, std::vector const&); @@ -422,7 +422,7 @@ class Expression { /// @brief execute an expression of type SIMPLE with ARRAY COMPARISON ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionArrayComparison( + AqlValue$ executeSimpleExpressionArrayComparison( AstNode const*, arangodb::AqlTransaction*, AqlItemBlock const*, size_t, std::vector const&, std::vector const&); @@ -430,38 +430,37 @@ class Expression { /// @brief execute an expression of type SIMPLE with TERNARY ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionTernary(AstNode const*, - arangodb::AqlTransaction*, - AqlItemBlock const*, size_t, - std::vector const&, - std::vector const&); - - ////////////////////////////////////////////////////////////////////////////// - /// @brief execute an expression of type SIMPLE with EXPANSION - ////////////////////////////////////////////////////////////////////////////// - - AqlValue executeSimpleExpressionExpansion(AstNode const*, - arangodb::AqlTransaction*, - AqlItemBlock const*, size_t, - std::vector const&, - std::vector const&); - - ////////////////////////////////////////////////////////////////////////////// - /// @brief execute an expression of type SIMPLE with EXPANSION - ////////////////////////////////////////////////////////////////////////////// - - AqlValue executeSimpleExpressionIterator(AstNode const*, - TRI_document_collection_t const**, + AqlValue$ executeSimpleExpressionTernary(AstNode const*, arangodb::AqlTransaction*, AqlItemBlock const*, size_t, std::vector const&, std::vector const&); + ////////////////////////////////////////////////////////////////////////////// + /// @brief execute an expression of type SIMPLE with EXPANSION + ////////////////////////////////////////////////////////////////////////////// + + AqlValue$ executeSimpleExpressionExpansion(AstNode const*, + arangodb::AqlTransaction*, + AqlItemBlock const*, size_t, + std::vector const&, + std::vector const&); + + ////////////////////////////////////////////////////////////////////////////// + /// @brief execute an expression of type SIMPLE with EXPANSION + ////////////////////////////////////////////////////////////////////////////// + + AqlValue$ executeSimpleExpressionIterator(AstNode const*, + arangodb::AqlTransaction*, + AqlItemBlock const*, size_t, + std::vector const&, + std::vector const&); + ////////////////////////////////////////////////////////////////////////////// /// @brief execute an expression of type SIMPLE with BINARY_* (+, -, * , /, %) ////////////////////////////////////////////////////////////////////////////// - AqlValue executeSimpleExpressionArithmetic( + AqlValue$ executeSimpleExpressionArithmetic( AstNode const*, arangodb::AqlTransaction*, AqlItemBlock const*, size_t, std::vector const&, std::vector const&); @@ -552,29 +551,8 @@ class Expression { /// @brief variables only temporarily valid during execution ////////////////////////////////////////////////////////////////////////////// - std::unordered_map _variables; + std::unordered_map _variables; - public: - ////////////////////////////////////////////////////////////////////////////// - /// @brief "constant" global object for NULL which can be shared by all - /// expressions but must never be freed - ////////////////////////////////////////////////////////////////////////////// - - static TRI_json_t const NullJson; - - ////////////////////////////////////////////////////////////////////////////// - /// @brief "constant" global object for TRUE which can be shared by all - /// expressions but must never be freed - ////////////////////////////////////////////////////////////////////////////// - - static TRI_json_t const TrueJson; - - ////////////////////////////////////////////////////////////////////////////// - /// @brief "constant" global object for FALSE which can be shared by all - /// expressions but must never be freed - ////////////////////////////////////////////////////////////////////////////// - - static TRI_json_t const FalseJson; }; } // namespace arangodb::aql diff --git a/arangod/Aql/IndexBlock.cpp b/arangod/Aql/IndexBlock.cpp index eebdff141f..51819587ce 100644 --- a/arangod/Aql/IndexBlock.cpp +++ b/arangod/Aql/IndexBlock.cpp @@ -107,7 +107,7 @@ void IndexBlock::executeExpressions() { auto exp = toReplace->expression; TRI_document_collection_t const* myCollection = nullptr; AqlValue a = exp->execute(_trx, cur, _pos, _inVars[posInExpressions], - _inRegs[posInExpressions], &myCollection); + _inRegs[posInExpressions]); auto jsonified = a.toJson(_trx, myCollection, true); a.destroy(); AstNode* evaluatedNode = ast->nodeFromJson(jsonified.json(), true); diff --git a/arangod/Aql/TraversalBlock.cpp b/arangod/Aql/TraversalBlock.cpp index ff62ace26e..32f037d88c 100644 --- a/arangod/Aql/TraversalBlock.cpp +++ b/arangod/Aql/TraversalBlock.cpp @@ -184,7 +184,7 @@ void TraversalBlock::executeExpressions() { // inVars and inRegs needs fixx TRI_document_collection_t const* myCollection = nullptr; AqlValue a = it->expression->execute(_trx, cur, _pos, _inVars[i], - _inRegs[i], &myCollection); + _inRegs[i]); it->compareTo.reset(new Json(a.toJson(_trx, myCollection, true))); a.destroy(); } diff --git a/arangod/V8Server/v8-collection.cpp b/arangod/V8Server/v8-collection.cpp index 8f7a1ca500..24d6fc28c3 100644 --- a/arangod/V8Server/v8-collection.cpp +++ b/arangod/V8Server/v8-collection.cpp @@ -1483,7 +1483,7 @@ static void ModifyVocbaseCol(TRI_voc_document_operation_e operation, auto workOnOneSearchVal = [&](v8::Local const searchVal) { std::string collName; if (!ExtractDocumentHandle(isolate, searchVal, collName, - updateBuilder, false)) { + updateBuilder, true)) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD); } }; diff --git a/arangod/VocBase/document-collection.cpp b/arangod/VocBase/document-collection.cpp index 0b3b69a88d..c466d9017d 100644 --- a/arangod/VocBase/document-collection.cpp +++ b/arangod/VocBase/document-collection.cpp @@ -3283,6 +3283,18 @@ int TRI_document_collection_t::insert(Transaction* trx, VPackSlice const* slice, TRI_doc_mptr_t* mptr, OperationOptions& options, bool lock) { + + if (_info.type() == TRI_COL_TYPE_EDGE) { + VPackSlice s = slice->get(TRI_VOC_ATTRIBUTE_FROM); + if (!s.isString()) { + return TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE; + } + s = slice->get(TRI_VOC_ATTRIBUTE_TO); + if (!s.isString()) { + return TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE; + } + } + TRI_ASSERT(mptr != nullptr); mptr->setDataPtr(nullptr); @@ -3475,6 +3487,18 @@ int TRI_document_collection_t::replace(Transaction* trx, OperationOptions& options, bool lock, TRI_voc_rid_t& prevRev) { + + if (_info.type() == TRI_COL_TYPE_EDGE) { + VPackSlice s = newSlice.get(TRI_VOC_ATTRIBUTE_FROM); + if (!s.isString()) { + return TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE; + } + s = newSlice.get(TRI_VOC_ATTRIBUTE_TO); + if (!s.isString()) { + return TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE; + } + } + // initialize the result TRI_ASSERT(mptr != nullptr); mptr->setDataPtr(nullptr); diff --git a/lib/Basics/VelocyPackHelper.cpp b/lib/Basics/VelocyPackHelper.cpp index bee0320965..7f0665c0a6 100644 --- a/lib/Basics/VelocyPackHelper.cpp +++ b/lib/Basics/VelocyPackHelper.cpp @@ -21,7 +21,7 @@ /// @author Michael Hackstein //////////////////////////////////////////////////////////////////////////////// -#include "Basics/VelocyPackHelper.h" +#include "VelocyPackHelper.h" #include "Basics/conversions.h" #include "Basics/Exceptions.h" #include "Basics/Logger.h" @@ -43,6 +43,28 @@ using VelocyPackHelper = arangodb::basics::VelocyPackHelper; static std::unique_ptr Translator; static std::unique_ptr ExcludeHandler; +//////////////////////////////////////////////////////////////////////////////// +/// @brief "constant" global object for NULL which can be shared by all +/// expressions but must never be freed +//////////////////////////////////////////////////////////////////////////////// + +static VPackBuilder NullBuilder; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief "constant" global object for TRUE which can be shared by all +/// expressions but must never be freed +//////////////////////////////////////////////////////////////////////////////// + +static VPackBuilder TrueBuilder; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief "constant" global object for FALSE which can be shared by all +/// expressions but must never be freed +//////////////////////////////////////////////////////////////////////////////// + +static VPackBuilder FalseBuilder; + + // attribute exclude handler for skipping over system attributes struct SystemAttributeExcludeHandler : public VPackAttributeExcludeHandler { bool shouldExclude(VPackSlice const& key, int nesting) override final { @@ -92,6 +114,22 @@ void VelocyPackHelper::initialize() { // initialize exclude handler for system attributes ExcludeHandler.reset(new SystemAttributeExcludeHandler); + + NullBuilder.add(VPackValue(VPackValueType::Null)); + TrueBuilder.add(VPackValue(true)); + FalseBuilder.add(VPackValue(false)); +} + +arangodb::velocypack::Slice VelocyPackHelper::NullValue() { + return NullBuilder.slice(); +} + +arangodb::velocypack::Slice VelocyPackHelper::TrueValue() { + return TrueBuilder.slice(); +} + +arangodb::velocypack::Slice VelocyPackHelper::FalseValue() { + return FalseBuilder.slice(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/Basics/VelocyPackHelper.h b/lib/Basics/VelocyPackHelper.h index c3b4a256dd..15330908b8 100644 --- a/lib/Basics/VelocyPackHelper.h +++ b/lib/Basics/VelocyPackHelper.h @@ -26,6 +26,7 @@ #include "Basics/JsonHelper.h" +#include #include #include #include @@ -207,6 +208,10 @@ class VelocyPackHelper { ////////////////////////////////////////////////////////////////////////////// static double toDouble(VPackSlice const&, bool&); + + static arangodb::velocypack::Slice NullValue(); + static arangodb::velocypack::Slice TrueValue(); + static arangodb::velocypack::Slice FalseValue(); }; } } @@ -214,7 +219,7 @@ class VelocyPackHelper { ////////////////////////////////////////////////////////////////////////////// /// @brief Simple and limited logging of VelocyPack slices ////////////////////////////////////////////////////////////////////////////// -#include "Basics/Logger.h" + arangodb::LoggerStream& operator<<(arangodb::LoggerStream&, arangodb::velocypack::Slice const&);