1
0
Fork 0

issue 381.6: enforce use of VIEW keyword for bound views and disallow for bound collections (#5522)

This commit is contained in:
Vasiliy 2018-06-05 14:45:53 +03:00 committed by Andrey Abramov
parent 5aa46ee0cd
commit 3e983adb2d
15 changed files with 1382 additions and 1363 deletions

View File

@ -731,6 +731,28 @@ AstNode* Ast::createNodeParameter(
return node;
}
AstNode* Ast::createNodeParameterCollection(char const* name, size_t length) {
auto node = createNodeParameter(name, length);
if (node) {
node->reserve(1);
node->addMember(createNode(NODE_TYPE_COLLECTION));
}
return node;
}
AstNode* Ast::createNodeParameterView(char const* name, size_t length) {
auto node = createNodeParameter(name, length);
if (node) {
node->reserve(1);
node->addMember(createNode(NODE_TYPE_VIEW));
}
return node;
}
/// @brief create an AST quantifier node
AstNode* Ast::createNodeQuantifier(int64_t type) {
AstNode* node = createNode(NODE_TYPE_QUANTIFIER);
@ -1467,71 +1489,90 @@ void Ast::injectBindParameters(BindParameters& parameters) {
TRI_ASSERT(!param.empty());
if ('@' == param[0]) {
// bound data source parameter
TRI_ASSERT(value.isString());
// bound data source parameter
TRI_ASSERT(value.isString());
char const* name = nullptr;
VPackValueLength length;
char const* stringValue = value.getString(length);
// should have arrived here via createNodeParameterCollection(...) or createNodeParameterView(...)
if (1 != node->numMembers() || !node->getMemberUnchecked(0)) {
THROW_ARANGO_EXCEPTION_MESSAGE(
TRI_ERROR_INTERNAL, "missing data source category"
);
}
// FIXME use external resolver
arangodb::CollectionNameResolver resolver(_query->vocbase());
std::shared_ptr<LogicalDataSource> dataSource;
// FIXME use external resolver
arangodb::CollectionNameResolver resolver(_query->vocbase());
if (length > 0 && stringValue[0] >= '0' && stringValue[0] <= '9') {
dataSource = resolver.getDataSource(basics::StringUtils::uint64(stringValue, length));
} else {
dataSource = resolver.getDataSource(std::string(stringValue, length));
}
switch (node->getMemberUnchecked(0)->type) {
case NODE_TYPE_COLLECTION: {
auto dataSource = resolver.getCollection(value.copyString());
if (!dataSource) {
THROW_ARANGO_EXCEPTION_FORMAT(
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND, "%s",
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
"collection: %s",
value.copyString().c_str()
);
}
// TODO: can we get away without registering the string value here?
auto& dataSourceName = dataSource->name();
auto* name = _query->registerString(dataSource->name());
name = _query->registerString(dataSourceName.c_str(), dataSourceName.size());
// check if the collection was used in a data-modification query
bool isWriteCollection = false;
if (LogicalCollection::category() == dataSource->category()) {
// check if the collection was used in a data-modification query
bool isWriteCollection = false;
arangodb::StringRef paramRef(param);
for (auto const& it : _writeCollections) {
auto const& c = it.first;
if (c->type == NODE_TYPE_PARAMETER && StringRef(param) == StringRef(c->getStringValue(), c->getStringLength())) {
isWriteCollection = true;
break;
for (auto const& it : _writeCollections) {
auto const& c = it.first;
if (c->type == NODE_TYPE_PARAMETER
&& paramRef == StringRef(c->getStringValue(), c->getStringLength())) {
isWriteCollection = true;
break;
}
}
node = createNodeCollection(name, isWriteCollection
? AccessMode::Type::WRITE
: AccessMode::Type::READ);
if (isWriteCollection) {
// must update AST info now for all nodes that contained this parameter
for (size_t i = 0; i < _writeCollections.size(); ++i) {
auto& c = _writeCollections[i].first;
if (c->type == NODE_TYPE_PARAMETER
&& paramRef == StringRef(c->getStringValue(), c->getStringLength())) {
c = node;
// no break here. replace all occurrences
}
}
}
node = createNodeCollection(name, isWriteCollection
? AccessMode::Type::WRITE
: AccessMode::Type::READ);
break;
}
case NODE_TYPE_VIEW: {
auto dataSource = resolver.getView(value.copyString());
if (isWriteCollection) {
// must update AST info now for all nodes that contained this
// parameter
for (size_t i = 0; i < _writeCollections.size(); ++i) {
auto& c = _writeCollections[i].first;
if (c->type == NODE_TYPE_PARAMETER &&
StringRef(param) == StringRef(c->getStringValue(), c->getStringLength())) {
c = node;
// no break here. replace all occurrences
}
}
}
} else if (LogicalView::category() == dataSource->category()) {
node = createNodeView(name);
} else {
THROW_ARANGO_EXCEPTION_MESSAGE(
TRI_ERROR_INTERNAL,
"unexpected data source category"
if (!dataSource) {
THROW_ARANGO_EXCEPTION_FORMAT(
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
"view: %s",
value.copyString().c_str()
);
}
// TODO: can we get away without registering the string value here?
node = createNodeView(_query->registerString(dataSource->name()));
break;
}
default:
THROW_ARANGO_EXCEPTION_MESSAGE(
TRI_ERROR_INTERNAL, "unexpected data source category"
);
}
} else {
// regular bound parameter
node = nodeFromVPack(value, true);
@ -3636,4 +3677,4 @@ AstNode* Ast::createNode(AstNodeType type) {
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -244,6 +244,8 @@ class Ast {
char const* name,
size_t length
);
AstNode* createNodeParameterCollection(char const* name, size_t length);
AstNode* createNodeParameterView(char const* name, size_t length);
/// @brief create an AST quantifier node
AstNode* createNodeQuantifier(int64_t);
@ -588,7 +590,8 @@ public:
/// @brief a singleton empty string node instance
static AstNode const EmptyStringNode;
};
}
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -126,7 +126,7 @@ extern int Aqldebug;
union YYSTYPE
{
#line 21 "Aql/grammar.y" /* yacc.c:1909 */
#line 19 "Aql/grammar.y" /* yacc.c:1909 */
arangodb::aql::AstNode* node;
struct {

View File

@ -126,7 +126,7 @@ extern int Aqldebug;
union YYSTYPE
{
#line 21 "Aql/grammar.y" /* yacc.c:1909 */
#line 19 "Aql/grammar.y" /* yacc.c:1909 */
arangodb::aql::AstNode* node;
struct {

View File

@ -326,7 +326,6 @@ static AstNode const* GetIntoExpression(AstNode const* node) {
%type <node> simple_value;
%type <node> value_literal;
%type <node> collection_name;
%type <node> view_name;
%type <node> in_or_into_collection;
%type <node> bind_parameter;
%type <strval> variable_name;
@ -447,13 +446,7 @@ statement_block_statement:
;
for_statement:
T_FOR variable_name T_IN T_VIEW view_name {
parser->ast()->scopes()->start(arangodb::aql::AQL_SCOPE_FOR);
auto node = parser->ast()->createNodeFor($2.value, $2.length, $5, true);
parser->ast()->addOperation(node);
}
| T_FOR variable_name T_IN expression {
T_FOR variable_name T_IN expression {
parser->ast()->scopes()->start(arangodb::aql::AQL_SCOPE_FOR);
auto node = parser->ast()->createNodeFor($2.value, $2.length, $4, true);
@ -1471,7 +1464,15 @@ graph_direction_steps:
;
reference:
T_STRING {
T_VIEW T_STRING {
auto* ast = parser->ast();
auto* node = ast->createNodeView($2.value);
TRI_ASSERT(node != nullptr);
$$ = node;
}
| T_STRING {
// variable or collection
auto ast = parser->ast();
AstNode* node = nullptr;
@ -1680,29 +1681,20 @@ collection_name:
}
;
view_name:
T_STRING {
$$ = parser->ast()->createNodeView($1.value);
}
| T_QUOTED_STRING {
$$ = parser->ast()->createNodeView($1.value);
bind_parameter:
T_VIEW T_DATA_SOURCE_PARAMETER {
if ($2.length < 2 || $2.value[0] != '@') {
parser->registerParseError(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE, TRI_errno_string(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE), $2.value, yylloc.first_line, yylloc.first_column);
}
$$ = parser->ast()->createNodeParameterView($2.value, $2.length);
}
| T_DATA_SOURCE_PARAMETER {
if ($1.length < 2 || $1.value[0] != '@') {
parser->registerParseError(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE, TRI_errno_string(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE), $1.value, yylloc.first_line, yylloc.first_column);
}
$$ = parser->ast()->createNodeParameter($1.value, $1.length);
}
;
bind_parameter:
T_DATA_SOURCE_PARAMETER {
if ($1.length < 2 || $1.value[0] != '@') {
parser->registerParseError(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE, TRI_errno_string(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE), $1.value, yylloc.first_line, yylloc.first_column);
}
$$ = parser->ast()->createNodeParameter($1.value, $1.length);
$$ = parser->ast()->createNodeParameterCollection($1.value, $1.length);
}
| T_PARAMETER {
$$ = parser->ast()->createNodeParameter($1.value, $1.length);

View File

@ -231,7 +231,7 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
if (view) {
wiew = logicalView; // remeber the DBServer view instance
logicalView = view->ensure(id()); // repoint LogicalView at the per-cid instance
logicalView = view->ensure(_collection->id()); // repoint LogicalView at the per-cid instance
} else {
logicalView = nullptr;
}
@ -547,4 +547,4 @@ NS_END // arangodb
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -405,18 +405,15 @@ std::shared_ptr<arangodb::LogicalView> IResearchViewDBServer::ensure(
return nullptr;
}
auto id = view->id();
// hold a reference to the original view in the deleter so that the view is still valid inside the deleter
// hold a reference to the original view in the deleter so that the view is still valid for the duration of the pointer wrapper
return std::shared_ptr<arangodb::LogicalView>(
view.get(),
[this, id, cid](arangodb::LogicalView* ptr)->void {
[this, view, cid](arangodb::LogicalView*)->void {
static const auto visitor = [](TRI_voc_cid_t)->bool { return false; };
// same view in vocbase and with no collections
if (ptr
&& ptr == vocbase().lookupView(id).get() // avoid double dropView(...)
&& ptr->visitCollections(visitor)) {
if (view.get() == vocbase().lookupView(view->id()).get() // avoid double dropView(...)
&& view->visitCollections(visitor)) {
drop(cid);
}
}

View File

@ -132,6 +132,10 @@ void RocksDBTransactionCollection::freeOperations(
bool RocksDBTransactionCollection::canAccess(
AccessMode::Type accessType) const {
if (!_collection) {
return false; // not opened. probably a mistake made by the caller
}
// check if access type matches
if (AccessMode::isWriteOrExclusive(accessType) &&
!AccessMode::isWriteOrExclusive(_accessType)) {

View File

@ -168,6 +168,10 @@ static OperationResult emptyResult(OperationOptions const& options) {
getStateRegistrationCallbacks().emplace_back(callback);
}
/*static*/ void transaction::Methods::clearStateRegistrationCallbacks() {
getStateRegistrationCallbacks().clear();
}
/// @brief Get the field names of the used index
std::vector<std::vector<std::string>>
transaction::Methods::IndexHandle::fieldNames() const {

View File

@ -154,6 +154,12 @@ class Methods {
/// @note not thread-safe on the assumption of static factory registration
static void addStateRegistrationCallback(StateRegistrationCallback callback);
/// @brief clear all called for state instance association events
/// @note not thread-safe on the assumption of static factory registration
/// @note FOR USE IN TESTS ONLY to reset test state
/// FIXME TODO StateRegistrationCallback logic should be moved into its own feature
static void clearStateRegistrationCallbacks();
/// @brief default batch size for index and other operations
static constexpr uint64_t defaultBatchSize() { return 1000; }
@ -609,4 +615,4 @@ class Methods {
}
}
#endif
#endif

View File

@ -439,78 +439,50 @@ TEST_CASE("IResearchQueryTestJoinDuplicateDataSource", "[iresearch][iresearch-qu
view->sync();
}
// explicit collection and view with the same 'collection' name
{
std::string const query = "LET c=5 FOR x IN collection_1 FILTER x.seq == c FOR d IN VIEW collection_1 FILTER x.seq == d.seq RETURN x";
auto const boundParameters = arangodb::velocypack::Parser::fromJson("{ }");
CHECK((arangodb::tests::assertRules(vocbase, query, {}, boundParameters)));
// arangodb::aql::ExecutionPlan::fromNodeFor(...) throws TRI_ERROR_INTERNAL
auto queryResult = arangodb::tests::executeQuery(vocbase, query, boundParameters);
CHECK((TRI_ERROR_INTERNAL == queryResult.code));
}
// explicit collection and view with the same 'view' name
{
std::string const query = "LET c=5 FOR x IN testView FILTER x.seq == c FOR d IN VIEW testView FILTER x.seq == d.seq RETURN x";
auto const boundParameters = arangodb::velocypack::Parser::fromJson("{ }");
CHECK(arangodb::tests::assertRules(vocbase, query, {}, boundParameters));
// arangodb::transaction::Methods::addCollectionAtRuntime(...) throws TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND
auto queryResult = arangodb::tests::executeQuery(vocbase, query, boundParameters);
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == queryResult.code));
}
// bind collection and view with the same name
{
std::string const query = "LET c=5 FOR x IN @@dataSource FILTER x.seq == c FOR d IN VIEW @@dataSource FILTER x.seq == d.seq RETURN x";
auto const boundParameters = arangodb::velocypack::Parser::fromJson("{ \"@dataSource\" : \"testView\" }");
/* FIXME will fail
* on TRI_ASSERT(trxCollection->collection() != nullptr);
* in transaction::Methods::documentCollection(...)
CHECK(arangodb::tests::assertRules(
vocbase, query, {
arangodb::aql::OptimizerRule::handleViewsRule_pass6,
},
boundParameters
));
std::vector<arangodb::velocypack::Slice> expectedDocs {
arangodb::velocypack::Slice(insertedDocsCollectionWithTheSameNameAsView[5].vpack()),
};
CHECK(arangodb::tests::assertRules(vocbase, query, {}, boundParameters));
auto queryResult = arangodb::tests::executeQuery(vocbase, query, boundParameters);
REQUIRE(TRI_ERROR_INTERNAL == queryResult.code);
// FIXME remove line above and uncomment lines below
// will not return any results because of the:
// https://github.com/arangodb/backlog/issues/342
// unable to resolve collection and view with the same name for the time being
//
// REQUIRE(TRI_ERROR_NO_ERROR == queryResult.code);
//
// auto result = queryResult.result->slice();
// CHECK(result.isArray());
//
// arangodb::velocypack::ArrayIterator resultIt(result);
// REQUIRE(expectedDocs.size() == resultIt.size());
//
// // Check documents
// auto expectedDoc = expectedDocs.begin();
// for (;resultIt.valid(); resultIt.next(), ++expectedDoc) {
// auto const actualDoc = resultIt.value();
// auto const resolved = actualDoc.resolveExternals();
//
// CHECK((0 == arangodb::basics::VelocyPackHelper::compare(arangodb::velocypack::Slice(*expectedDoc), resolved, true)));
// }
// CHECK(expectedDoc == expectedDocs.end());
*/
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == queryResult.code));
}
// bind collection and view with the same name
//
// FIXME
// will not return any results because of the:
// https://github.com/arangodb/backlog/issues/342
{
std::string const query = "LET c=5 FOR x IN @@dataSource FILTER x.seq == c FOR d IN VIEW @@dataSource FILTER x.seq == d.seq RETURN d";
auto const boundParameters = arangodb::velocypack::Parser::fromJson("{ \"@dataSource\" : \"testView\" }");
/* FIXME will fail
* on TRI_ASSERT(trxCollection->collection() != nullptr);
* in transaction::Methods::documentCollection(...)
CHECK(arangodb::tests::assertRules(
vocbase, query, {
arangodb::aql::OptimizerRule::handleViewsRule_pass6,
},
boundParameters
));
std::vector<arangodb::velocypack::Slice> expectedDocs {
arangodb::velocypack::Slice(insertedDocsCollectionWithTheSameNameAsView[5].vpack()),
};
CHECK(arangodb::tests::assertRules(vocbase, query, {}, boundParameters));
auto queryResult = arangodb::tests::executeQuery(vocbase, query, boundParameters);
REQUIRE(TRI_ERROR_INTERNAL == queryResult.code);
*/
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == queryResult.code));
}
}

View File

@ -386,6 +386,8 @@ SECTION("test_query") {
REQUIRE((false == !wiewImpl));
auto logicalView = wiewImpl->ensure(42);
REQUIRE((false == !logicalView));
auto* viewImpl = dynamic_cast<arangodb::iresearch::IResearchView*>(logicalView.get());
REQUIRE((false == !viewImpl));
arangodb::CollectionNameResolver resolver(vocbase);
auto state = s.engine.createTransactionState(resolver, arangodb::transaction::Options());
@ -891,7 +893,8 @@ SECTION("test_updateProperties") {
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"properties\": { \"collections\": [ 3, 4, 5 ], \"threadsMaxIdle\": 24, \"threadsMaxTotal\": 42 } }");
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
vocbase.createCollection(collectionJson->slice());
auto* logicalCollection = vocbase.createCollection(collectionJson->slice());
CHECK((nullptr != logicalCollection));
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
CHECK((false == !wiew));
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
@ -952,7 +955,8 @@ SECTION("test_updateProperties") {
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"properties\": { \"collections\": [ 3, 4, 5 ], \"threadsMaxIdle\": 24, \"threadsMaxTotal\": 42 } }");
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
vocbase.createCollection(collectionJson->slice());
auto* logicalCollection = vocbase.createCollection(collectionJson->slice());
CHECK((nullptr != logicalCollection));
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
CHECK((false == !wiew));
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
@ -1013,7 +1017,8 @@ SECTION("test_updateProperties") {
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"properties\": { \"collections\": [ 3, 4, 5 ], \"threadsMaxIdle\": 24, \"threadsMaxTotal\": 42 } }");
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
vocbase.createCollection(collectionJson->slice());
auto* logicalCollection = vocbase.createCollection(collectionJson->slice());
CHECK((nullptr != logicalCollection));
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
CHECK((false == !wiew));
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
@ -1073,10 +1078,14 @@ SECTION("test_updateProperties") {
s.agency->responses.clear();
s.agency->responses["POST /_api/agency/read HTTP/1.1\r\n\r\n[[\"/Sync/LatestID\"]]"] = "http/1.0 200\n\n[ { \"\": { \"Sync\": { \"LatestID\" : 1 } } } ]";
s.agency->responses["POST /_api/agency/write HTTP/1.1"] = "http/1.0 200\n\n{\"results\": []}";
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
auto collection0Json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
auto collection1Json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection1\", \"id\": \"123\" }");
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"properties\": { \"collections\": [ 3, 4, 5 ], \"threadsMaxIdle\": 24, \"threadsMaxTotal\": 42 } }");
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
vocbase.createCollection(collectionJson->slice());
auto* logicalCollection0 = vocbase.createCollection(collection0Json->slice());
CHECK((nullptr != logicalCollection0));
auto* logicalCollection1 = vocbase.createCollection(collection1Json->slice());
CHECK((nullptr != logicalCollection1));
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
CHECK((false == !wiew));
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
@ -1111,7 +1120,7 @@ SECTION("test_updateProperties") {
wiew->toVelocyPack(builder, true, false);
builder.close();
auto slice = builder.slice().get("properties");
CHECK((slice.hasKey("collections") && slice.get("collections").isArray() && 2 == slice.get("collections").length()));
CHECK((slice.hasKey("collections") && slice.get("collections").isArray() && 1 == slice.get("collections").length()));
CHECK((!slice.hasKey("links")));
CHECK((slice.hasKey("threadsMaxIdle") && slice.get("threadsMaxIdle").isNumber<size_t>() && 5 == slice.get("threadsMaxIdle").getNumber<size_t>()));
CHECK((slice.hasKey("threadsMaxTotal") && slice.get("threadsMaxTotal").isNumber<size_t>() && 52 == slice.get("threadsMaxTotal").getNumber<size_t>()));
@ -1180,4 +1189,4 @@ SECTION("test_visitCollections") {
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -1402,7 +1402,7 @@ TransactionCollectionMock::TransactionCollectionMock(arangodb::TransactionState*
}
bool TransactionCollectionMock::canAccess(arangodb::AccessMode::Type accessType) const {
return true;
return nullptr != _collection; // collection must have be opened previously
}
void TransactionCollectionMock::freeOperations(arangodb::transaction::Methods* activeTrx, bool mustRollback) {
@ -1491,7 +1491,16 @@ arangodb::Result TransactionStateMock::beginTransaction(arangodb::transaction::H
static std::atomic<TRI_voc_tid_t> lastId(0);
++beginTransactionCount;
useCollections(_nestingLevel);
auto res = useCollections(_nestingLevel);
if (!res.ok()) {
updateStatus(arangodb::transaction::Status::ABORTED);
const_cast<TRI_voc_tid_t&>(_id) = 0; // avoid use of TransactionManagerFeature::manager()->unregisterTransaction(...)
return res;
}
const_cast<TRI_voc_tid_t&>(_id) = ++lastId; // ensure each transaction state has a unique ID
updateStatus(arangodb::transaction::Status::RUNNING);

View File

@ -47,7 +47,9 @@ NS_END
NS_BEGIN(arangodb)
NS_BEGIN(tests)
void init(bool withICU /*= false*/) {} // nothing to do here
void init(bool withICU /*= false*/) {
arangodb::transaction::Methods::clearStateRegistrationCallbacks();
}
bool assertRules(
TRI_vocbase_t& vocbase,
@ -156,4 +158,4 @@ NS_END // arangodb
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------