mirror of https://gitee.com/bigwinds/arangodb
issue 381.6: enforce use of VIEW keyword for bound views and disallow for bound collections (#5522)
This commit is contained in:
parent
5aa46ee0cd
commit
3e983adb2d
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -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
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
Loading…
Reference in New Issue