mirror of https://gitee.com/bigwinds/arangodb
Bugfix/early out invalid links in view creation (#6502)
This commit is contained in:
parent
8bd834bcf7
commit
f93b6fd7b8
|
@ -133,7 +133,7 @@ bool IResearchViewCoordinator::emplace(
|
||||||
auto& properties = info.isObject() ? info : emptyObjectSlice(); // if no 'info' then assume defaults
|
auto& properties = info.isObject() ? info : emptyObjectSlice(); // if no 'info' then assume defaults
|
||||||
std::string error;
|
std::string error;
|
||||||
|
|
||||||
bool hasLinks = properties.hasKey("links");
|
bool hasLinks = properties.hasKey(StaticStrings::LinksField);
|
||||||
|
|
||||||
auto view = std::shared_ptr<IResearchViewCoordinator>(
|
auto view = std::shared_ptr<IResearchViewCoordinator>(
|
||||||
new IResearchViewCoordinator(vocbase, info, planVersion)
|
new IResearchViewCoordinator(vocbase, info, planVersion)
|
||||||
|
|
|
@ -57,27 +57,33 @@ namespace iresearch {
|
||||||
auto& properties = info.isObject() ? info : emptyObjectSlice(); // if no 'info' then assume defaults
|
auto& properties = info.isObject() ? info : emptyObjectSlice(); // if no 'info' then assume defaults
|
||||||
std::string error;
|
std::string error;
|
||||||
|
|
||||||
bool hasLinks = properties.hasKey("links");
|
bool hasLinks = properties.hasKey(StaticStrings::LinksField);
|
||||||
|
|
||||||
if (hasLinks && isNew) {
|
if (hasLinks && isNew) {
|
||||||
|
|
||||||
// check link auth as per https://github.com/arangodb/backlog/issues/459
|
arangodb::velocypack::ObjectIterator iterator{info.get(StaticStrings::LinksField)};
|
||||||
if (arangodb::ExecContext::CURRENT) {
|
|
||||||
|
|
||||||
// check new links
|
for (auto itr : iterator) {
|
||||||
if (info.hasKey(StaticStrings::LinksField)) {
|
if (!itr.key.isString()) {
|
||||||
for (arangodb::velocypack::ObjectIterator itr(info.get(StaticStrings::LinksField)); itr.valid(); ++itr) {
|
|
||||||
if (!itr.key().isString()) {
|
|
||||||
continue; // not a resolvable collection (invalid jSON)
|
continue; // not a resolvable collection (invalid jSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto collection= vocbase.lookupCollection(itr.key().copyString());
|
auto colname = itr.key.copyString();
|
||||||
|
|
||||||
if (collection
|
// check if the collection exists
|
||||||
&& !arangodb::ExecContext::CURRENT->canUseCollection(vocbase.name(), collection->name(), arangodb::auth::Level::RO)) {
|
auto collection = vocbase.lookupCollection(colname);
|
||||||
|
if (!collection) {
|
||||||
|
|
||||||
|
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC) << "Could not create view: "
|
||||||
|
<< "Collection not found: " << colname;
|
||||||
|
TRI_set_errno(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// check if the collection can be used
|
||||||
|
if (arangodb::ExecContext::CURRENT &&
|
||||||
|
!arangodb::ExecContext::CURRENT->canUseCollection(vocbase.name(), collection->name(), arangodb::auth::Level::RO)) {
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#include <velocypack/Iterator.h>
|
#include <velocypack/Iterator.h>
|
||||||
#include <velocypack/Slice.h>
|
#include <velocypack/Slice.h>
|
||||||
#include <velocypack/Validator.h>
|
#include <velocypack/Validator.h>
|
||||||
|
#include <velocypack/Collection.h>
|
||||||
#include <velocypack/velocypack-aliases.h>
|
#include <velocypack/velocypack-aliases.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -1520,7 +1521,14 @@ Result DatabaseInitialSyncer::iterateCollections(
|
||||||
/// @brief create non-existing views locally
|
/// @brief create non-existing views locally
|
||||||
Result DatabaseInitialSyncer::handleViewCreation(VPackSlice const& views) {
|
Result DatabaseInitialSyncer::handleViewCreation(VPackSlice const& views) {
|
||||||
for (VPackSlice slice : VPackArrayIterator(views)) {
|
for (VPackSlice slice : VPackArrayIterator(views)) {
|
||||||
Result res = createView(vocbase(), slice);
|
|
||||||
|
// Remove the links from the view slice
|
||||||
|
// This is required since views are created before collections.
|
||||||
|
// Hence, the collection does not exist and the view creation is aborted.
|
||||||
|
// The association views <-> collections is still created via the indexes.
|
||||||
|
auto patchedSlice = VPackCollection::remove(slice, std::vector<std::string>{"links"});
|
||||||
|
|
||||||
|
Result res = createView(vocbase(), patchedSlice.slice());
|
||||||
if (res.fail()) {
|
if (res.fail()) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,20 @@ function IResearchFeatureDDLTestSuite () {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
testStressAddRemoveViewWithDirectLinks : function() {
|
||||||
|
db._drop("TestCollection0");
|
||||||
|
db._dropView("TestView");
|
||||||
|
db._create("TestCollection0");
|
||||||
|
for (let i = 0; i < 100; ++i) {
|
||||||
|
db._createView("TestView", "arangosearch", {links:{"TestCollection0":{}}});
|
||||||
|
var view = db._view("TestView");
|
||||||
|
assertTrue(null != view);
|
||||||
|
assertEqual(Object.keys(view.properties().links).length, 1);
|
||||||
|
db._dropView("TestView");
|
||||||
|
assertTrue(null == db._view("TestView"));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
testStressAddRemoveViewWithLink : function() {
|
testStressAddRemoveViewWithLink : function() {
|
||||||
db._drop("TestCollection0");
|
db._drop("TestCollection0");
|
||||||
db._dropView("TestView");
|
db._dropView("TestView");
|
||||||
|
@ -161,6 +175,12 @@ function IResearchFeatureDDLTestSuite () {
|
||||||
assertTrue(Object === properties.links.constructor);
|
assertTrue(Object === properties.links.constructor);
|
||||||
assertEqual(1, Object.keys(properties.links).length);
|
assertEqual(1, Object.keys(properties.links).length);
|
||||||
|
|
||||||
|
// create with links
|
||||||
|
db._dropView("TestView");
|
||||||
|
view = db._createView("TestView", "arangosearch", meta);
|
||||||
|
properties = view.properties();
|
||||||
|
assertTrue(Object === properties.links.constructor);
|
||||||
|
assertEqual(1, Object.keys(properties.links).length);
|
||||||
|
|
||||||
// consolidate
|
// consolidate
|
||||||
db._dropView("TestView");
|
db._dropView("TestView");
|
||||||
|
|
|
@ -74,12 +74,29 @@ function IResearchLinkSuite () {
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
testHandlingCreateWithLinks : function () {
|
testHandlingCreateWithLinks : function () {
|
||||||
var meta = { links: { 'testCollection' : { includeAllFields: true } } };
|
var meta = { links: { 'testCollection' : { includeAllFields: true } } };
|
||||||
var view = db._createView("badView", "arangosearch", meta);
|
var view = db._createView("someView", "arangosearch", meta);
|
||||||
var links = view.properties().links;
|
var links = view.properties().links;
|
||||||
assertNotEqual(links['testCollection'], undefined);
|
assertNotEqual(links['testCollection'], undefined);
|
||||||
view.drop();
|
view.drop();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief don't create view when collections do not exist or the user
|
||||||
|
/// is not allowed to access them.
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
testHandlingCreateWithBadLinks : function () {
|
||||||
|
var meta = { links: { 'nonExistentCollection': {}, 'testCollection' : { includeAllFields: true } } };
|
||||||
|
var view;
|
||||||
|
try {
|
||||||
|
view = db._createView("someView", "arangosearch", meta);
|
||||||
|
fail();
|
||||||
|
} catch(e) {
|
||||||
|
assertEqual(ERRORS.ERROR_ARANGO_DATA_SOURCE_NOT_FOUND.code, e.errorNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertNull(db._view("someView"));
|
||||||
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create a view and add/drop link
|
/// @brief create a view and add/drop link
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -732,6 +732,42 @@ function BaseTestConfig() {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
testViewCreateWithLinks: function() {
|
||||||
|
connectToMaster();
|
||||||
|
|
||||||
|
compare(
|
||||||
|
function() {},
|
||||||
|
function(state) {
|
||||||
|
try {
|
||||||
|
db._create(cn);
|
||||||
|
let links = {};
|
||||||
|
links[cn] = {
|
||||||
|
includeAllFields: true,
|
||||||
|
fields: {
|
||||||
|
text: { analyzers: [ "text_en" ] }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let view = db._createView("UnitTestsSyncView", "arangosearch", {"links": links});
|
||||||
|
state.arangoSearchEnabled = true;
|
||||||
|
} catch (err) { }
|
||||||
|
},
|
||||||
|
function() {},
|
||||||
|
function(state) {
|
||||||
|
if (!state.arangoSearchEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let view = db._view("UnitTestsSyncView");
|
||||||
|
assertTrue(view !== null);
|
||||||
|
let props = view.properties();
|
||||||
|
assertEqual(Object.keys(props.links).length, 1);
|
||||||
|
assertTrue(props.hasOwnProperty("links"));
|
||||||
|
assertTrue(props.links.hasOwnProperty(cn));
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
testViewRename: function() {
|
testViewRename: function() {
|
||||||
connectToMaster();
|
connectToMaster();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue