mirror of https://gitee.com/bigwinds/arangodb
parent
f5f0b66c06
commit
f74822483c
|
@ -1,6 +1,9 @@
|
||||||
v3.3.4 (XXXX-XX-XX)
|
v3.3.4 (XXXX-XX-XX)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
* fix issue #4677: AQL WITH with bind parameters results in "access after data-modification"
|
||||||
|
for two independent UPSERTs
|
||||||
|
|
||||||
* fix issue #4457: create /var/tmp/arangod with correct user in supervisor mode
|
* fix issue #4457: create /var/tmp/arangod with correct user in supervisor mode
|
||||||
|
|
||||||
* remove long disfunctional admin/long_echo handler
|
* remove long disfunctional admin/long_echo handler
|
||||||
|
|
|
@ -1700,7 +1700,7 @@ void Ast::validateAndOptimize() {
|
||||||
if (ctx->filterDepth >= 0) {
|
if (ctx->filterDepth >= 0) {
|
||||||
++ctx->filterDepth;
|
++ctx->filterDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->type == NODE_TYPE_FILTER) {
|
if (node->type == NODE_TYPE_FILTER) {
|
||||||
TRI_ASSERT(ctx->filterDepth == -1);
|
TRI_ASSERT(ctx->filterDepth == -1);
|
||||||
ctx->filterDepth = 0;
|
ctx->filterDepth = 0;
|
||||||
|
@ -1712,6 +1712,12 @@ void Ast::validateAndOptimize() {
|
||||||
// NOOPT will turn all function optimizations off
|
// NOOPT will turn all function optimizations off
|
||||||
++(ctx->stopOptimizationRequests);
|
++(ctx->stopOptimizationRequests);
|
||||||
}
|
}
|
||||||
|
} else if (node->type == NODE_TYPE_COLLECTION_LIST) {
|
||||||
|
// a collection list is produced by WITH a, b, c
|
||||||
|
// or by traversal declarations
|
||||||
|
// we do not want to descend further, in order to not track
|
||||||
|
// the collections in collectionsFirstSeen
|
||||||
|
return false;
|
||||||
} else if (node->type == NODE_TYPE_COLLECTION) {
|
} else if (node->type == NODE_TYPE_COLLECTION) {
|
||||||
// note the level on which we first saw a collection
|
// note the level on which we first saw a collection
|
||||||
ctx->collectionsFirstSeen.emplace(node->getString(), ctx->nestingLevel);
|
ctx->collectionsFirstSeen.emplace(node->getString(), ctx->nestingLevel);
|
||||||
|
|
|
@ -120,6 +120,52 @@ function ahuacatlMultiModifySuite () {
|
||||||
assertTrue(found);
|
assertTrue(found);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
testWithDeclarationAndModification : function () {
|
||||||
|
var q = "WITH @@cn RETURN (INSERT {} INTO @@cn)";
|
||||||
|
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
|
||||||
|
assertEqual([ [ ] ], actual.json);
|
||||||
|
assertEqual(1, actual.stats.writesExecuted);
|
||||||
|
assertEqual(1, c1.count());
|
||||||
|
assertEqual(0, c2.count());
|
||||||
|
},
|
||||||
|
|
||||||
|
testWithDeclarationsAndSingleModificationMultipleCollections : function () {
|
||||||
|
var q = "WITH @@cn1, @@cn2 RETURN (INSERT {} INTO @@cn1)";
|
||||||
|
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2" : cn2 });
|
||||||
|
assertEqual([ [ ] ], actual.json);
|
||||||
|
assertEqual(1, actual.stats.writesExecuted);
|
||||||
|
assertEqual(1, c1.count());
|
||||||
|
assertEqual(0, c2.count());
|
||||||
|
},
|
||||||
|
|
||||||
|
testWithDeclarationsAndMultiModificationMultipleCollections : function () {
|
||||||
|
var q = "WITH @@cn1, @@cn2 RETURN [(INSERT {} INTO @@cn1), (INSERT {} INTO @@cn2)]";
|
||||||
|
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2" : cn2 });
|
||||||
|
assertEqual([ [ [ ], [ ] ] ], actual.json);
|
||||||
|
assertEqual(2, actual.stats.writesExecuted);
|
||||||
|
assertEqual(1, c1.count());
|
||||||
|
assertEqual(1, c2.count());
|
||||||
|
},
|
||||||
|
|
||||||
|
testWithDeclarationsAndModificationWriteRead : function () {
|
||||||
|
var q = "WITH @@cn1, @@cn2 RETURN [(INSERT {} INTO @@cn1), (FOR doc IN @@cn2 RETURN doc)]";
|
||||||
|
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2" : cn2 });
|
||||||
|
assertEqual([ [ [ ], [ ] ] ], actual.json);
|
||||||
|
assertEqual(1, actual.stats.writesExecuted);
|
||||||
|
assertEqual(1, c1.count());
|
||||||
|
assertEqual(0, c2.count());
|
||||||
|
},
|
||||||
|
|
||||||
|
testWithDeclarationSameCollectionWriteThenRead : function () {
|
||||||
|
var q = "WITH @@cn1 RETURN [(INSERT {} INTO @@cn1), (FOR doc IN @@cn1 RETURN doc)]";
|
||||||
|
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn1": cn1 });
|
||||||
|
},
|
||||||
|
|
||||||
|
testWithDeclarationAndModificationMultipleCollectionsThenRead : function () {
|
||||||
|
var q = "WITH @@cn1 LET x = (INSERT {} INTO @@cn1) FOR doc IN @@cn1 RETURN doc";
|
||||||
|
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn1": cn1 });
|
||||||
|
},
|
||||||
|
|
||||||
testTraversalAfterModification : function () {
|
testTraversalAfterModification : function () {
|
||||||
var q = "INSERT { _key: '1', foo: 'bar' } INTO @@cn FOR doc IN OUTBOUND 'v/1' @@e RETURN doc";
|
var q = "INSERT { _key: '1', foo: 'bar' } INTO @@cn FOR doc IN OUTBOUND 'v/1' @@e RETURN doc";
|
||||||
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1, "@e": cn3 });
|
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1, "@e": cn3 });
|
||||||
|
|
Loading…
Reference in New Issue