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;
|
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
|
/// @brief create an AST quantifier node
|
||||||
AstNode* Ast::createNodeQuantifier(int64_t type) {
|
AstNode* Ast::createNodeQuantifier(int64_t type) {
|
||||||
AstNode* node = createNode(NODE_TYPE_QUANTIFIER);
|
AstNode* node = createNode(NODE_TYPE_QUANTIFIER);
|
||||||
|
@ -1470,39 +1492,42 @@ void Ast::injectBindParameters(BindParameters& parameters) {
|
||||||
// bound data source parameter
|
// bound data source parameter
|
||||||
TRI_ASSERT(value.isString());
|
TRI_ASSERT(value.isString());
|
||||||
|
|
||||||
char const* name = nullptr;
|
// should have arrived here via createNodeParameterCollection(...) or createNodeParameterView(...)
|
||||||
VPackValueLength length;
|
if (1 != node->numMembers() || !node->getMemberUnchecked(0)) {
|
||||||
char const* stringValue = value.getString(length);
|
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||||
|
TRI_ERROR_INTERNAL, "missing data source category"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME use external resolver
|
// FIXME use external resolver
|
||||||
arangodb::CollectionNameResolver resolver(_query->vocbase());
|
arangodb::CollectionNameResolver resolver(_query->vocbase());
|
||||||
std::shared_ptr<LogicalDataSource> dataSource;
|
|
||||||
|
|
||||||
if (length > 0 && stringValue[0] >= '0' && stringValue[0] <= '9') {
|
switch (node->getMemberUnchecked(0)->type) {
|
||||||
dataSource = resolver.getDataSource(basics::StringUtils::uint64(stringValue, length));
|
case NODE_TYPE_COLLECTION: {
|
||||||
} else {
|
auto dataSource = resolver.getCollection(value.copyString());
|
||||||
dataSource = resolver.getDataSource(std::string(stringValue, length));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dataSource) {
|
if (!dataSource) {
|
||||||
THROW_ARANGO_EXCEPTION_FORMAT(
|
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()
|
value.copyString().c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: can we get away without registering the string value here?
|
// 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());
|
|
||||||
|
|
||||||
if (LogicalCollection::category() == dataSource->category()) {
|
|
||||||
// check if the collection was used in a data-modification query
|
// check if the collection was used in a data-modification query
|
||||||
bool isWriteCollection = false;
|
bool isWriteCollection = false;
|
||||||
|
|
||||||
|
arangodb::StringRef paramRef(param);
|
||||||
|
|
||||||
|
|
||||||
for (auto const& it : _writeCollections) {
|
for (auto const& it : _writeCollections) {
|
||||||
auto const& c = it.first;
|
auto const& c = it.first;
|
||||||
if (c->type == NODE_TYPE_PARAMETER && StringRef(param) == StringRef(c->getStringValue(), c->getStringLength())) {
|
|
||||||
|
if (c->type == NODE_TYPE_PARAMETER
|
||||||
|
&& paramRef == StringRef(c->getStringValue(), c->getStringLength())) {
|
||||||
isWriteCollection = true;
|
isWriteCollection = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1513,23 +1538,39 @@ void Ast::injectBindParameters(BindParameters& parameters) {
|
||||||
: AccessMode::Type::READ);
|
: AccessMode::Type::READ);
|
||||||
|
|
||||||
if (isWriteCollection) {
|
if (isWriteCollection) {
|
||||||
// must update AST info now for all nodes that contained this
|
// must update AST info now for all nodes that contained this parameter
|
||||||
// parameter
|
|
||||||
for (size_t i = 0; i < _writeCollections.size(); ++i) {
|
for (size_t i = 0; i < _writeCollections.size(); ++i) {
|
||||||
auto& c = _writeCollections[i].first;
|
auto& c = _writeCollections[i].first;
|
||||||
if (c->type == NODE_TYPE_PARAMETER &&
|
|
||||||
StringRef(param) == StringRef(c->getStringValue(), c->getStringLength())) {
|
if (c->type == NODE_TYPE_PARAMETER
|
||||||
|
&& paramRef == StringRef(c->getStringValue(), c->getStringLength())) {
|
||||||
c = node;
|
c = node;
|
||||||
// no break here. replace all occurrences
|
// no break here. replace all occurrences
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (LogicalView::category() == dataSource->category()) {
|
|
||||||
node = createNodeView(name);
|
break;
|
||||||
} else {
|
}
|
||||||
|
case NODE_TYPE_VIEW: {
|
||||||
|
auto dataSource = resolver.getView(value.copyString());
|
||||||
|
|
||||||
|
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(
|
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||||
TRI_ERROR_INTERNAL,
|
TRI_ERROR_INTERNAL, "unexpected data source category"
|
||||||
"unexpected data source category"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -244,6 +244,8 @@ class Ast {
|
||||||
char const* name,
|
char const* name,
|
||||||
size_t length
|
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
|
/// @brief create an AST quantifier node
|
||||||
AstNode* createNodeQuantifier(int64_t);
|
AstNode* createNodeQuantifier(int64_t);
|
||||||
|
@ -588,6 +590,7 @@ public:
|
||||||
/// @brief a singleton empty string node instance
|
/// @brief a singleton empty string node instance
|
||||||
static AstNode const EmptyStringNode;
|
static AstNode const EmptyStringNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -126,7 +126,7 @@ extern int Aqldebug;
|
||||||
|
|
||||||
union YYSTYPE
|
union YYSTYPE
|
||||||
{
|
{
|
||||||
#line 21 "Aql/grammar.y" /* yacc.c:1909 */
|
#line 19 "Aql/grammar.y" /* yacc.c:1909 */
|
||||||
|
|
||||||
arangodb::aql::AstNode* node;
|
arangodb::aql::AstNode* node;
|
||||||
struct {
|
struct {
|
||||||
|
|
|
@ -126,7 +126,7 @@ extern int Aqldebug;
|
||||||
|
|
||||||
union YYSTYPE
|
union YYSTYPE
|
||||||
{
|
{
|
||||||
#line 21 "Aql/grammar.y" /* yacc.c:1909 */
|
#line 19 "Aql/grammar.y" /* yacc.c:1909 */
|
||||||
|
|
||||||
arangodb::aql::AstNode* node;
|
arangodb::aql::AstNode* node;
|
||||||
struct {
|
struct {
|
||||||
|
|
|
@ -326,7 +326,6 @@ static AstNode const* GetIntoExpression(AstNode const* node) {
|
||||||
%type <node> simple_value;
|
%type <node> simple_value;
|
||||||
%type <node> value_literal;
|
%type <node> value_literal;
|
||||||
%type <node> collection_name;
|
%type <node> collection_name;
|
||||||
%type <node> view_name;
|
|
||||||
%type <node> in_or_into_collection;
|
%type <node> in_or_into_collection;
|
||||||
%type <node> bind_parameter;
|
%type <node> bind_parameter;
|
||||||
%type <strval> variable_name;
|
%type <strval> variable_name;
|
||||||
|
@ -447,13 +446,7 @@ statement_block_statement:
|
||||||
;
|
;
|
||||||
|
|
||||||
for_statement:
|
for_statement:
|
||||||
T_FOR variable_name T_IN T_VIEW view_name {
|
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, $5, true);
|
|
||||||
parser->ast()->addOperation(node);
|
|
||||||
}
|
|
||||||
| T_FOR variable_name T_IN expression {
|
|
||||||
parser->ast()->scopes()->start(arangodb::aql::AQL_SCOPE_FOR);
|
parser->ast()->scopes()->start(arangodb::aql::AQL_SCOPE_FOR);
|
||||||
|
|
||||||
auto node = parser->ast()->createNodeFor($2.value, $2.length, $4, true);
|
auto node = parser->ast()->createNodeFor($2.value, $2.length, $4, true);
|
||||||
|
@ -1471,7 +1464,15 @@ graph_direction_steps:
|
||||||
;
|
;
|
||||||
|
|
||||||
reference:
|
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
|
// variable or collection
|
||||||
auto ast = parser->ast();
|
auto ast = parser->ast();
|
||||||
AstNode* node = nullptr;
|
AstNode* node = nullptr;
|
||||||
|
@ -1680,29 +1681,20 @@ collection_name:
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
view_name:
|
bind_parameter:
|
||||||
T_STRING {
|
T_VIEW T_DATA_SOURCE_PARAMETER {
|
||||||
$$ = parser->ast()->createNodeView($1.value);
|
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);
|
||||||
}
|
}
|
||||||
| T_QUOTED_STRING {
|
|
||||||
$$ = parser->ast()->createNodeView($1.value);
|
$$ = parser->ast()->createNodeParameterView($2.value, $2.length);
|
||||||
}
|
}
|
||||||
| T_DATA_SOURCE_PARAMETER {
|
| T_DATA_SOURCE_PARAMETER {
|
||||||
if ($1.length < 2 || $1.value[0] != '@') {
|
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->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);
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
| T_PARAMETER {
|
| T_PARAMETER {
|
||||||
$$ = parser->ast()->createNodeParameter($1.value, $1.length);
|
$$ = parser->ast()->createNodeParameter($1.value, $1.length);
|
||||||
|
|
|
@ -231,7 +231,7 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
|
||||||
|
|
||||||
if (view) {
|
if (view) {
|
||||||
wiew = logicalView; // remeber the DBServer view instance
|
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 {
|
} else {
|
||||||
logicalView = nullptr;
|
logicalView = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -405,18 +405,15 @@ std::shared_ptr<arangodb::LogicalView> IResearchViewDBServer::ensure(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto id = view->id();
|
// hold a reference to the original view in the deleter so that the view is still valid for the duration of the pointer wrapper
|
||||||
|
|
||||||
// hold a reference to the original view in the deleter so that the view is still valid inside the deleter
|
|
||||||
return std::shared_ptr<arangodb::LogicalView>(
|
return std::shared_ptr<arangodb::LogicalView>(
|
||||||
view.get(),
|
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; };
|
static const auto visitor = [](TRI_voc_cid_t)->bool { return false; };
|
||||||
|
|
||||||
// same view in vocbase and with no collections
|
// same view in vocbase and with no collections
|
||||||
if (ptr
|
if (view.get() == vocbase().lookupView(view->id()).get() // avoid double dropView(...)
|
||||||
&& ptr == vocbase().lookupView(id).get() // avoid double dropView(...)
|
&& view->visitCollections(visitor)) {
|
||||||
&& ptr->visitCollections(visitor)) {
|
|
||||||
drop(cid);
|
drop(cid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,6 +132,10 @@ void RocksDBTransactionCollection::freeOperations(
|
||||||
|
|
||||||
bool RocksDBTransactionCollection::canAccess(
|
bool RocksDBTransactionCollection::canAccess(
|
||||||
AccessMode::Type accessType) const {
|
AccessMode::Type accessType) const {
|
||||||
|
if (!_collection) {
|
||||||
|
return false; // not opened. probably a mistake made by the caller
|
||||||
|
}
|
||||||
|
|
||||||
// check if access type matches
|
// check if access type matches
|
||||||
if (AccessMode::isWriteOrExclusive(accessType) &&
|
if (AccessMode::isWriteOrExclusive(accessType) &&
|
||||||
!AccessMode::isWriteOrExclusive(_accessType)) {
|
!AccessMode::isWriteOrExclusive(_accessType)) {
|
||||||
|
|
|
@ -168,6 +168,10 @@ static OperationResult emptyResult(OperationOptions const& options) {
|
||||||
getStateRegistrationCallbacks().emplace_back(callback);
|
getStateRegistrationCallbacks().emplace_back(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*static*/ void transaction::Methods::clearStateRegistrationCallbacks() {
|
||||||
|
getStateRegistrationCallbacks().clear();
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Get the field names of the used index
|
/// @brief Get the field names of the used index
|
||||||
std::vector<std::vector<std::string>>
|
std::vector<std::vector<std::string>>
|
||||||
transaction::Methods::IndexHandle::fieldNames() const {
|
transaction::Methods::IndexHandle::fieldNames() const {
|
||||||
|
|
|
@ -154,6 +154,12 @@ class Methods {
|
||||||
/// @note not thread-safe on the assumption of static factory registration
|
/// @note not thread-safe on the assumption of static factory registration
|
||||||
static void addStateRegistrationCallback(StateRegistrationCallback callback);
|
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
|
/// @brief default batch size for index and other operations
|
||||||
static constexpr uint64_t defaultBatchSize() { return 1000; }
|
static constexpr uint64_t defaultBatchSize() { return 1000; }
|
||||||
|
|
||||||
|
|
|
@ -439,78 +439,50 @@ TEST_CASE("IResearchQueryTestJoinDuplicateDataSource", "[iresearch][iresearch-qu
|
||||||
view->sync();
|
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
|
// 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";
|
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\" }");
|
auto const boundParameters = arangodb::velocypack::Parser::fromJson("{ \"@dataSource\" : \"testView\" }");
|
||||||
|
|
||||||
/* FIXME will fail
|
CHECK(arangodb::tests::assertRules(vocbase, query, {}, boundParameters));
|
||||||
* 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()),
|
|
||||||
};
|
|
||||||
|
|
||||||
auto queryResult = arangodb::tests::executeQuery(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));
|
||||||
// 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());
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// bind collection and view with the same name
|
// 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";
|
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\" }");
|
auto const boundParameters = arangodb::velocypack::Parser::fromJson("{ \"@dataSource\" : \"testView\" }");
|
||||||
|
|
||||||
/* FIXME will fail
|
CHECK(arangodb::tests::assertRules(vocbase, query, {}, boundParameters));
|
||||||
* 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()),
|
|
||||||
};
|
|
||||||
|
|
||||||
auto queryResult = arangodb::tests::executeQuery(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));
|
REQUIRE((false == !wiewImpl));
|
||||||
auto logicalView = wiewImpl->ensure(42);
|
auto logicalView = wiewImpl->ensure(42);
|
||||||
REQUIRE((false == !logicalView));
|
REQUIRE((false == !logicalView));
|
||||||
|
auto* viewImpl = dynamic_cast<arangodb::iresearch::IResearchView*>(logicalView.get());
|
||||||
|
REQUIRE((false == !viewImpl));
|
||||||
|
|
||||||
arangodb::CollectionNameResolver resolver(vocbase);
|
arangodb::CollectionNameResolver resolver(vocbase);
|
||||||
auto state = s.engine.createTransactionState(resolver, arangodb::transaction::Options());
|
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 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 } }");
|
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");
|
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);
|
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||||
CHECK((false == !wiew));
|
CHECK((false == !wiew));
|
||||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
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 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 } }");
|
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");
|
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);
|
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||||
CHECK((false == !wiew));
|
CHECK((false == !wiew));
|
||||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
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 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 } }");
|
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");
|
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);
|
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||||
CHECK((false == !wiew));
|
CHECK((false == !wiew));
|
||||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||||
|
@ -1073,10 +1078,14 @@ SECTION("test_updateProperties") {
|
||||||
s.agency->responses.clear();
|
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/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\": []}";
|
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 } }");
|
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");
|
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);
|
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||||
CHECK((false == !wiew));
|
CHECK((false == !wiew));
|
||||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||||
|
@ -1111,7 +1120,7 @@ SECTION("test_updateProperties") {
|
||||||
wiew->toVelocyPack(builder, true, false);
|
wiew->toVelocyPack(builder, true, false);
|
||||||
builder.close();
|
builder.close();
|
||||||
auto slice = builder.slice().get("properties");
|
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("links")));
|
||||||
CHECK((slice.hasKey("threadsMaxIdle") && slice.get("threadsMaxIdle").isNumber<size_t>() && 5 == slice.get("threadsMaxIdle").getNumber<size_t>()));
|
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>()));
|
CHECK((slice.hasKey("threadsMaxTotal") && slice.get("threadsMaxTotal").isNumber<size_t>() && 52 == slice.get("threadsMaxTotal").getNumber<size_t>()));
|
||||||
|
|
|
@ -1402,7 +1402,7 @@ TransactionCollectionMock::TransactionCollectionMock(arangodb::TransactionState*
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TransactionCollectionMock::canAccess(arangodb::AccessMode::Type accessType) const {
|
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) {
|
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);
|
static std::atomic<TRI_voc_tid_t> lastId(0);
|
||||||
|
|
||||||
++beginTransactionCount;
|
++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
|
const_cast<TRI_voc_tid_t&>(_id) = ++lastId; // ensure each transaction state has a unique ID
|
||||||
updateStatus(arangodb::transaction::Status::RUNNING);
|
updateStatus(arangodb::transaction::Status::RUNNING);
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,9 @@ NS_END
|
||||||
NS_BEGIN(arangodb)
|
NS_BEGIN(arangodb)
|
||||||
NS_BEGIN(tests)
|
NS_BEGIN(tests)
|
||||||
|
|
||||||
void init(bool withICU /*= false*/) {} // nothing to do here
|
void init(bool withICU /*= false*/) {
|
||||||
|
arangodb::transaction::Methods::clearStateRegistrationCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
bool assertRules(
|
bool assertRules(
|
||||||
TRI_vocbase_t& vocbase,
|
TRI_vocbase_t& vocbase,
|
||||||
|
|
Loading…
Reference in New Issue