diff --git a/3rdParty/velocypack/include/velocypack/Builder.h b/3rdParty/velocypack/include/velocypack/Builder.h index 84949d0d4f..329740d85d 100644 --- a/3rdParty/velocypack/include/velocypack/Builder.h +++ b/3rdParty/velocypack/include/velocypack/Builder.h @@ -252,6 +252,8 @@ class Builder { // get a const reference to the Builder's Buffer object std::shared_ptr> const& buffer() const { return _buffer; } + // steal the Builder's Buffer object. afterwards the Builder + // is unusable std::shared_ptr> steal() { // After a steal the Builder is broken! std::shared_ptr> res = _buffer; @@ -259,7 +261,7 @@ class Builder { _pos = 0; return res; } - + uint8_t const* data() const { return _buffer.get()->data(); } @@ -283,6 +285,7 @@ class Builder { void clear() { _pos = 0; _stack.clear(); + _keyWritten = false; } // Return a pointer to the start of the result: @@ -332,14 +335,17 @@ class Builder { // Add a subvalue into an object from a Value: uint8_t* add(std::string const& attrName, Value const& sub); uint8_t* add(char const* attrName, Value const& sub); + uint8_t* add(char const* attrName, size_t attrLength, Value const& sub); // Add a subvalue into an object from a Slice: uint8_t* add(std::string const& attrName, Slice const& sub); uint8_t* add(char const* attrName, Slice const& sub); + uint8_t* add(char const* attrName, size_t attrLength, Slice const& sub); // Add a subvalue into an object from a ValuePair: uint8_t* add(std::string const& attrName, ValuePair const& sub); uint8_t* add(char const* attrName, ValuePair const& sub); + uint8_t* add(char const* attrName, size_t attrLength, ValuePair const& sub); // Add all subkeys and subvalues into an object from an ObjectIterator // and leaves open the object intentionally @@ -365,6 +371,7 @@ class Builder { } } try { + checkKeyIsString(Slice(sub).isString()); auto oldPos = _pos; reserveSpace(1 + sizeof(void*)); // store pointer. this doesn't need to be portable @@ -627,6 +634,11 @@ private: template uint8_t* addInternal(char const* attrName, T const& sub) { + return addInternal(attrName, strlen(attrName), sub); + } + + template + uint8_t* addInternal(char const* attrName, size_t attrLength, T const& sub) { bool haveReported = false; if (!_stack.empty()) { ValueLength& tos = _stack.back(); @@ -640,8 +652,6 @@ private: haveReported = true; } - ValueLength attrLength = strlen(attrName); - try { if (options->attributeTranslator != nullptr) { // check if a translation for the attribute name exists diff --git a/3rdParty/velocypack/include/velocypack/Slice.h b/3rdParty/velocypack/include/velocypack/Slice.h index 5dc631df42..b854580511 100644 --- a/3rdParty/velocypack/include/velocypack/Slice.h +++ b/3rdParty/velocypack/include/velocypack/Slice.h @@ -42,6 +42,12 @@ #include "velocypack/Value.h" #include "velocypack/ValueType.h" +#ifndef VELOCYPACK_XXHASH +#ifndef VELOCYPACK_FASTHASH +#define VELOCYPACK_XXHASH +#endif +#endif + #ifdef VELOCYPACK_XXHASH // forward for XXH64 function declared elsewhere extern "C" unsigned long long XXH64(void const*, size_t, unsigned long long); diff --git a/3rdParty/velocypack/include/velocypack/velocypack-aliases.h b/3rdParty/velocypack/include/velocypack/velocypack-aliases.h index 11319c4242..42c6158e1c 100644 --- a/3rdParty/velocypack/include/velocypack/velocypack-aliases.h +++ b/3rdParty/velocypack/include/velocypack/velocypack-aliases.h @@ -55,6 +55,8 @@ using VPackObjectIterator = arangodb::velocypack::ObjectIterator; using VPackBuilder = arangodb::velocypack::Builder; using VPackObjectBuilder = arangodb::velocypack::ObjectBuilder; using VPackArrayBuilder = arangodb::velocypack::ArrayBuilder; +using VPackBuilderNonDeleter = arangodb::velocypack::BuilderNonDeleter; +using VPackBuilderContainer = arangodb::velocypack::BuilderContainer; #endif #endif @@ -149,6 +151,13 @@ using VPackSlimBuffer = arangodb::velocypack::SliceContainer; #endif #endif +#ifdef VELOCYPACK_VALIDATOR_H +#ifndef VELOCYPACK_ALIAS_VALIDATOR +#define VELOCYPACK_ALIAS_VALIDATOR +using VPackValidator = arangodb::velocypack::Validator; +#endif +#endif + #ifdef VELOCYPACK_VALUE_H #ifndef VELOCYPACK_ALIAS_VALUE #define VELOCYPACK_ALIAS_VALUE diff --git a/3rdParty/velocypack/include/velocypack/velocypack-common.h b/3rdParty/velocypack/include/velocypack/velocypack-common.h index 83b29a1961..7371c6d5e9 100644 --- a/3rdParty/velocypack/include/velocypack/velocypack-common.h +++ b/3rdParty/velocypack/include/velocypack/velocypack-common.h @@ -162,7 +162,6 @@ static inline int64_t toInt64(uint64_t v) noexcept { // specified length, starting at the specified byte offset template static inline T readInteger(uint8_t const* start, ValueLength length) noexcept { - VELOCYPACK_ASSERT(length > 0); uint64_t value = 0; uint64_t x = 0; uint8_t const* end = start + length; diff --git a/3rdParty/velocypack/src/Builder.cpp b/3rdParty/velocypack/src/Builder.cpp index e204f06b30..64940d9dd4 100644 --- a/3rdParty/velocypack/src/Builder.cpp +++ b/3rdParty/velocypack/src/Builder.cpp @@ -33,7 +33,7 @@ #include "velocypack/Sink.h" using namespace arangodb::velocypack; - + std::string Builder::toString() const { Options options; options.prettyPrint = true; @@ -799,6 +799,10 @@ uint8_t* Builder::add(char const* attrName, Value const& sub) { return addInternal(attrName, sub); } +uint8_t* Builder::add(char const* attrName, size_t attrLength, Value const& sub) { + return addInternal(attrName, attrLength, sub); +} + uint8_t* Builder::add(std::string const& attrName, ValuePair const& sub) { return addInternal(attrName, sub); } @@ -807,6 +811,10 @@ uint8_t* Builder::add(char const* attrName, ValuePair const& sub) { return addInternal(attrName, sub); } +uint8_t* Builder::add(char const* attrName, size_t attrLength, ValuePair const& sub) { + return addInternal(attrName, attrLength, sub); +} + uint8_t* Builder::add(std::string const& attrName, Slice const& sub) { return addInternal(attrName, sub); } @@ -814,6 +822,10 @@ uint8_t* Builder::add(std::string const& attrName, Slice const& sub) { uint8_t* Builder::add(char const* attrName, Slice const& sub) { return addInternal(attrName, sub); } + +uint8_t* Builder::add(char const* attrName, size_t attrLength, Slice const& sub) { + return addInternal(attrName, attrLength, sub); +} // Add all subkeys and subvalues into an object from an ObjectIterator // and leaves open the object intentionally diff --git a/Documentation/Books/AQL/CommonErrors.mdpp b/Documentation/Books/AQL/CommonErrors.mdpp index 15f3f1cb14..f6e798ab4f 100644 --- a/Documentation/Books/AQL/CommonErrors.mdpp +++ b/Documentation/Books/AQL/CommonErrors.mdpp @@ -1 +1,42 @@ !CHAPTER Common Errors + +!SECTION String concatenation + +In AQL, strings must be concatenated using the [CONCAT()](Functions/String.md#concat) +function. Joining them together with the `+` operator is not supported. Especially +as JavaScript programmer it is easy to walk into this trap: + +```js +RETURN "foo" + "bar" // [ 0 ] +RETURN "foo" + 123 // [ 123 ] +RETURN "123" + 200 // [ 323 ] +``` + +The arithmetic plus operator expects numbers as operands, and will try to implicitly +cast them to numbers if they are of different type. `"foo"` and `"bar"` are casted +to `0` and then added to together (still zero). If an actual number is added, that +number will be returned (adding zero doesn't change the result). If the string is a +valid string representation of a number, then it is casted to a number. Thus, adding +`"123"` and `200` results in two numbers being added up to `323`. + +To concatenate elements (with implicit casting to string for non-string values), do: + +```js +RETURN CONCAT("foo", "bar") // [ "foobar" ] +RETURN CONCAT("foo", 123) // [ "foo123" ] +RETURN CONCAT("123", 200) // [ "123200" ] +``` + + \ No newline at end of file diff --git a/Documentation/Books/AQL/Examples/Grouping.mdpp b/Documentation/Books/AQL/Examples/Grouping.mdpp index 741f033fbb..3f1519c303 100644 --- a/Documentation/Books/AQL/Examples/Grouping.mdpp +++ b/Documentation/Books/AQL/Examples/Grouping.mdpp @@ -54,39 +54,11 @@ FOR u IN users ```json [ - { - "age": 37, - "users": [ - "John", - "Sophia" - ] - }, - { - "age": 36, - "users": [ - "Fred", - "Emma" - ] - }, - { - "age": 34, - "users": [ - "Madison" - ] - }, - { - "age": 33, - "users": [ - "Chloe", - "Michael" - ] - }, - { - "age": 32, - "users": [ - "Alexander" - ] - } + { "age": 37, "users": [ "John", "Sophia" ] }, + { "age": 36, "users": [ "Fred", "Emma" ] }, + { "age": 34, "users": [ "Madison" ] }, + { "age": 33, "users": [ "Chloe", "Michael" ] }, + { "age": 32, "users": [ "Alexander" ] } ] ``` @@ -132,30 +104,12 @@ FOR u IN users ```json [ - { - "ageGroup": 35, - "gender": "f" - }, - { - "ageGroup": 35, - "gender": "m" - }, - { - "ageGroup": 30, - "gender": "f" - }, - { - "ageGroup": 30, - "gender": "m" - }, - { - "ageGroup": 25, - "gender": "f" - }, - { - "ageGroup": 25, - "gender": "m" - } + { "ageGroup": 35, "gender": "f" }, + { "ageGroup": 35, "gender": "m" }, + { "ageGroup": 30, "gender": "f" }, + { "ageGroup": 30, "gender": "m" }, + { "ageGroup": 25, "gender": "f" }, + { "ageGroup": 25, "gender": "m" } ] ``` @@ -180,36 +134,12 @@ FOR u IN users ```json [ - { - "ageGroup": 35, - "gender": "f", - "numUsers": 2 - }, - { - "ageGroup": 35, - "gender": "m", - "numUsers": 2 - }, - { - "ageGroup": 30, - "gender": "f", - "numUsers": 4 - }, - { - "ageGroup": 30, - "gender": "m", - "numUsers": 4 - }, - { - "ageGroup": 25, - "gender": "f", - "numUsers": 2 - }, - { - "ageGroup": 25, - "gender": "m", - "numUsers": 2 - } + { "ageGroup": 35, "gender": "f", "numUsers": 2 }, + { "ageGroup": 35, "gender": "m", "numUsers": 2 }, + { "ageGroup": 30, "gender": "f", "numUsers": 4 }, + { "ageGroup": 30, "gender": "m", "numUsers": 4 }, + { "ageGroup": 25, "gender": "f", "numUsers": 2 }, + { "ageGroup": 25, "gender": "m", "numUsers": 2 } ] ``` diff --git a/Documentation/Books/AQL/Functions/String.mdpp b/Documentation/Books/AQL/Functions/String.mdpp index 261390675d..99e342460e 100644 --- a/Documentation/Books/AQL/Functions/String.mdpp +++ b/Documentation/Books/AQL/Functions/String.mdpp @@ -64,8 +64,8 @@ CONCAT_SEPARATOR(", ", [ "foo", "bar", "baz" ]) CONCAT_SEPARATOR(", ", [ "foo", [ "b", "a", "r" ], "baz" ]) // [ "foo, b,a,r, baz" ] -/* "1-2-3-4-5" */ CONCAT_SEPARATOR("-", [1, 2, 3, null], [4, null, 5]) +// "1-2-3-4-5" ``` !SUBSECTION CONTAINS() diff --git a/Documentation/Books/AQL/Graphs/Traversals.mdpp b/Documentation/Books/AQL/Graphs/Traversals.mdpp index 1211e4e56a..705120baf0 100644 --- a/Documentation/Books/AQL/Graphs/Traversals.mdpp +++ b/Documentation/Books/AQL/Graphs/Traversals.mdpp @@ -160,6 +160,9 @@ FOR vertex[, edge[, path]] Instead of `GRAPH graphName` you may specify a list of edge collections. Vertex collections are determined by the edges in the edge collections. The rest of the behavior is similar to the named version. +If the same edge collection is specified multiple times, it will behave as if it +were specified only once. Specifying the same edge collection is only allowed when +the collections do not have conflicting traversal directions. !SUBSECTION Traversing in mixed directions diff --git a/Documentation/Books/AQL/HEADER.html b/Documentation/Books/AQL/HEADER.html index 68f47770d2..c032e7ddec 100644 --- a/Documentation/Books/AQL/HEADER.html +++ b/Documentation/Books/AQL/HEADER.html @@ -10,7 +10,8 @@ - + + @@ -25,16 +26,16 @@