mirror of https://gitee.com/bigwinds/arangodb
resolve actual type of the data source on parsing instead of specifying type in `AstNode`
This commit is contained in:
parent
33bc2f704f
commit
c81cd02014
|
@ -38,6 +38,7 @@
|
|||
#include "Transaction/Helpers.h"
|
||||
#include "Utils/CollectionNameResolver.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/LogicalView.h"
|
||||
|
||||
#include <velocypack/Iterator.h>
|
||||
#include <velocypack/Slice.h>
|
||||
|
@ -586,7 +587,6 @@ AstNode* Ast::createNodeCollection(char const* name,
|
|||
|
||||
AstNode* node = createNode(NODE_TYPE_COLLECTION);
|
||||
node->setStringValue(name, strlen(name));
|
||||
node->dataSourceType = AstNode::DataSourceType::Collection;
|
||||
|
||||
_query->collections()->add(name, accessType);
|
||||
|
||||
|
@ -621,7 +621,6 @@ AstNode* Ast::createNodeView(char const* name) {
|
|||
|
||||
AstNode* node = createNode(NODE_TYPE_VIEW);
|
||||
node->setStringValue(name, strlen(name));
|
||||
node->dataSourceType = AstNode::DataSourceType::View;
|
||||
|
||||
auto* collections = _query->collections();
|
||||
|
||||
|
@ -682,8 +681,7 @@ AstNode* Ast::createNodeReference(Variable const* variable) {
|
|||
/// @brief create an AST parameter node
|
||||
AstNode* Ast::createNodeParameter(
|
||||
char const* name,
|
||||
size_t length,
|
||||
AstNode::DataSourceType dataSourceType /* = AstNode::DataSourceType::Invalid */
|
||||
size_t length
|
||||
) {
|
||||
if (name == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
|
@ -692,7 +690,6 @@ AstNode* Ast::createNodeParameter(
|
|||
AstNode* node = createNode(NODE_TYPE_PARAMETER);
|
||||
|
||||
node->setStringValue(name, length);
|
||||
node->dataSourceType = dataSourceType;
|
||||
|
||||
// insert bind parameter name into list of found parameters
|
||||
_bindParameters.emplace(name);
|
||||
|
@ -1425,107 +1422,89 @@ void Ast::injectBindParameters(BindParameters& parameters) {
|
|||
|
||||
TRI_ASSERT(!param.empty());
|
||||
|
||||
switch (node->getDataSourceType()) {
|
||||
case AstNode::DataSourceType::Collection: {
|
||||
// bound collection parameter
|
||||
if ('@' == param[0]) {
|
||||
// bound data source parameter
|
||||
TRI_ASSERT(value.isString());
|
||||
|
||||
// check if the collection was used in a data-modification query
|
||||
bool isWriteCollection = false;
|
||||
|
||||
for (auto const& it : _writeCollections) {
|
||||
if (it->type == NODE_TYPE_PARAMETER && StringRef(param) == StringRef(it->getStringValue(), it->getStringLength())) {
|
||||
isWriteCollection = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// turn node into a collection node
|
||||
char const* name = nullptr;
|
||||
VPackValueLength length;
|
||||
char const* stringValue = value.getString(length);
|
||||
|
||||
if (length > 0 && stringValue[0] >= '0' && stringValue[0] <= '9') {
|
||||
// emergency translation of collection id to name
|
||||
arangodb::CollectionNameResolver resolver(_query->vocbase());
|
||||
std::string collectionName = resolver.getCollectionNameCluster(basics::StringUtils::uint64(stringValue, length));
|
||||
if (collectionName.empty()) {
|
||||
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND,
|
||||
value.copyString().c_str());
|
||||
}
|
||||
// FIXME use external resolver
|
||||
arangodb::CollectionNameResolver resolver(_query->vocbase());
|
||||
std::shared_ptr<LogicalDataSource> dataSource;
|
||||
|
||||
name = _query->registerString(collectionName.c_str(), collectionName.size());
|
||||
if (length > 0 && stringValue[0] >= '0' && stringValue[0] <= '9') {
|
||||
dataSource = resolver.getDataSource(basics::StringUtils::uint64(stringValue, length));
|
||||
} else {
|
||||
// TODO: can we get away without registering the string value here?
|
||||
name = _query->registerString(stringValue, static_cast<size_t>(length));
|
||||
dataSource = resolver.getDataSource(std::string(stringValue, length));
|
||||
}
|
||||
|
||||
TRI_ASSERT(name != nullptr);
|
||||
if (!dataSource) {
|
||||
// FIXME use TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND
|
||||
THROW_ARANGO_EXCEPTION_PARAMS(
|
||||
TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND,
|
||||
value.copyString().c_str()
|
||||
);
|
||||
}
|
||||
|
||||
node = createNodeCollection(name, isWriteCollection
|
||||
// TODO: can we get away without registering the string value here?
|
||||
auto& dataSourceName = 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
|
||||
bool isWriteCollection = false;
|
||||
|
||||
for (auto const& it : _writeCollections) {
|
||||
if (it->type == NODE_TYPE_PARAMETER && StringRef(param) == StringRef(it->getStringValue(), it->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) {
|
||||
if (_writeCollections[i]->type == NODE_TYPE_PARAMETER &&
|
||||
StringRef(param) == StringRef(_writeCollections[i]->getStringValue(), _writeCollections[i]->getStringLength())) {
|
||||
_writeCollections[i] = node;
|
||||
// no break here. replace all occurrences
|
||||
if (isWriteCollection) {
|
||||
// must update AST info now for all nodes that contained this
|
||||
// parameter
|
||||
for (size_t i = 0; i < _writeCollections.size(); ++i) {
|
||||
if (_writeCollections[i]->type == NODE_TYPE_PARAMETER &&
|
||||
StringRef(param) == StringRef(_writeCollections[i]->getStringValue(), _writeCollections[i]->getStringLength())) {
|
||||
_writeCollections[i] = node;
|
||||
// no break here. replace all occurrences
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case AstNode::DataSourceType::View: {
|
||||
// bound view parameter
|
||||
TRI_ASSERT(value.isString());
|
||||
|
||||
// turn node into a view node
|
||||
char const* name = nullptr;
|
||||
VPackValueLength length;
|
||||
char const* stringValue = value.getString(length);
|
||||
|
||||
if (length > 0 && stringValue[0] >= '0' && stringValue[0] <= '9') {
|
||||
// emergency translation of collection id to name
|
||||
arangodb::CollectionNameResolver resolver(_query->vocbase());
|
||||
std::string viewName = resolver.getViewNameCluster(basics::StringUtils::uint64(stringValue, length));
|
||||
if (viewName .empty()) {
|
||||
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_ARANGO_VIEW_NOT_FOUND,
|
||||
value.copyString().c_str());
|
||||
}
|
||||
|
||||
name = _query->registerString(viewName.c_str(), viewName.size());
|
||||
} else if (LogicalView::category() == dataSource->category()) {
|
||||
node = createNodeView(name);
|
||||
} else {
|
||||
// TODO: can we get away without registering the string value here?
|
||||
name = _query->registerString(stringValue, static_cast<size_t>(length));
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"unexpected data source category"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// regular bound parameter
|
||||
node = nodeFromVPack(value, true);
|
||||
|
||||
TRI_ASSERT(name != nullptr);
|
||||
if (node != nullptr) {
|
||||
// already mark node as constant here
|
||||
node->setFlag(DETERMINED_CONSTANT, VALUE_CONSTANT);
|
||||
// mark node as simple
|
||||
node->setFlag(DETERMINED_SIMPLE, VALUE_SIMPLE);
|
||||
// mark node as executable on db-server
|
||||
node->setFlag(DETERMINED_RUNONDBSERVER, VALUE_RUNONDBSERVER);
|
||||
// mark node as non-throwing
|
||||
node->setFlag(DETERMINED_THROWS);
|
||||
// mark node as deterministic
|
||||
node->setFlag(DETERMINED_NONDETERMINISTIC);
|
||||
|
||||
node = createNodeView(name);
|
||||
} break;
|
||||
default: {
|
||||
// regular bound parameter
|
||||
node = nodeFromVPack(value, true);
|
||||
|
||||
if (node != nullptr) {
|
||||
// already mark node as constant here
|
||||
node->setFlag(DETERMINED_CONSTANT, VALUE_CONSTANT);
|
||||
// mark node as simple
|
||||
node->setFlag(DETERMINED_SIMPLE, VALUE_SIMPLE);
|
||||
// mark node as executable on db-server
|
||||
node->setFlag(DETERMINED_RUNONDBSERVER, VALUE_RUNONDBSERVER);
|
||||
// mark node as non-throwing
|
||||
node->setFlag(DETERMINED_THROWS);
|
||||
// mark node as deterministic
|
||||
node->setFlag(DETERMINED_NONDETERMINISTIC);
|
||||
|
||||
// finally note that the node was created from a bind parameter
|
||||
node->setFlag(FLAG_BIND_PARAMETER);
|
||||
} break;
|
||||
}
|
||||
// finally note that the node was created from a bind parameter
|
||||
node->setFlag(FLAG_BIND_PARAMETER);
|
||||
}
|
||||
}
|
||||
} else if (node->type == NODE_TYPE_BOUND_ATTRIBUTE_ACCESS) {
|
||||
// look at second sub-node. this is the (replaced) bind parameter
|
||||
|
|
|
@ -238,8 +238,7 @@ class Ast {
|
|||
/// @brief create an AST parameter node
|
||||
AstNode* createNodeParameter(
|
||||
char const* name,
|
||||
size_t length,
|
||||
AstNode::DataSourceType dataSourceType = AstNode::DataSourceType::Invalid
|
||||
size_t length
|
||||
);
|
||||
|
||||
/// @brief create an AST quantifier node
|
||||
|
|
|
@ -202,12 +202,6 @@ static_assert(NODE_TYPE_ARRAY < NODE_TYPE_OBJECT, "incorrect node types order");
|
|||
struct AstNode {
|
||||
friend class Ast;
|
||||
|
||||
enum class DataSourceType : uintptr_t {
|
||||
Invalid = 0,
|
||||
Collection,
|
||||
View,
|
||||
};
|
||||
|
||||
static std::unordered_map<int, std::string const> const Operators;
|
||||
static std::unordered_map<int, std::string const> const TypeNames;
|
||||
static std::unordered_map<int, std::string const> const ValueTypeNames;
|
||||
|
@ -395,10 +389,6 @@ struct AstNode {
|
|||
}
|
||||
}
|
||||
|
||||
inline DataSourceType getDataSourceType() const noexcept {
|
||||
return dataSourceType;
|
||||
}
|
||||
|
||||
/// @brief whether or not a value node is of type attribute access that
|
||||
/// refers to a variable reference
|
||||
AstNode const* getAttributeAccessForVariable(bool allowIndexedAccess) const {
|
||||
|
@ -738,13 +728,8 @@ struct AstNode {
|
|||
AstNodeValue value;
|
||||
|
||||
private:
|
||||
union {
|
||||
/// @brief precomputed VPack value (used when executing expressions)
|
||||
uint8_t mutable* computedValue;
|
||||
|
||||
/// @brief type of the data source
|
||||
DataSourceType dataSourceType;
|
||||
};
|
||||
/// @brief precomputed VPack value (used when executing expressions)
|
||||
uint8_t mutable* computedValue;
|
||||
|
||||
/// @brief the node's sub nodes
|
||||
std::vector<AstNode*> members;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -331,7 +331,6 @@ static AstNode const* GetIntoExpression(AstNode const* node) {
|
|||
%type <node> view_name;
|
||||
%type <node> in_or_into_collection;
|
||||
%type <node> bind_parameter;
|
||||
%type <node> bind_view;
|
||||
%type <strval> variable_name;
|
||||
%type <node> numeric_value;
|
||||
%type <intval> update_or_replace;
|
||||
|
@ -1690,8 +1689,12 @@ view_name:
|
|||
| T_QUOTED_STRING {
|
||||
$$ = parser->ast()->createNodeView($1.value);
|
||||
}
|
||||
| bind_view {
|
||||
$$ = $1;
|
||||
| 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);
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -1701,23 +1704,13 @@ bind_parameter:
|
|||
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, AstNode::DataSourceType::Collection);
|
||||
$$ = parser->ast()->createNodeParameter($1.value, $1.length);
|
||||
}
|
||||
| T_PARAMETER {
|
||||
$$ = parser->ast()->createNodeParameter($1.value, $1.length);
|
||||
}
|
||||
;
|
||||
|
||||
bind_view:
|
||||
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, AstNode::DataSourceType::View);
|
||||
}
|
||||
;
|
||||
|
||||
object_element_name:
|
||||
T_STRING {
|
||||
$$ = $1;
|
||||
|
|
|
@ -331,16 +331,14 @@ std::shared_ptr<LogicalDataSource> CollectionNameResolver::getDataSource(
|
|||
}
|
||||
|
||||
try {
|
||||
auto name = std::to_string(id);
|
||||
auto const name = std::to_string(id);
|
||||
auto cinfo = ci->getCollection(_vocbase->name(), name);
|
||||
|
||||
if (cinfo) {
|
||||
return std::static_pointer_cast<LogicalDataSource>(cinfo);
|
||||
return cinfo;
|
||||
}
|
||||
|
||||
return std::static_pointer_cast<LogicalDataSource>(
|
||||
ci->getView(_vocbase->name(), name)
|
||||
);
|
||||
return ci->getView(_vocbase->name(), name);
|
||||
} catch (...) {
|
||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||
<< "caught exception while resolving cluster data-source id: " << id;
|
||||
|
@ -349,6 +347,38 @@ std::shared_ptr<LogicalDataSource> CollectionNameResolver::getDataSource(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<LogicalDataSource> CollectionNameResolver::getDataSource(
|
||||
std::string const& name
|
||||
) const noexcept {
|
||||
// db server / standalone
|
||||
if (!ServerState::isRunningInCluster(_serverRole)
|
||||
|| ServerState::isDBServer(_serverRole)) {
|
||||
return _vocbase ? _vocbase->lookupDataSource(name) : nullptr;
|
||||
}
|
||||
|
||||
// cluster coordinator
|
||||
auto* ci = ClusterInfo::instance();
|
||||
|
||||
if (!ci) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
auto cinfo = ci->getCollection(_vocbase->name(), name);
|
||||
|
||||
if (cinfo) {
|
||||
return cinfo;
|
||||
}
|
||||
|
||||
return ci->getView(_vocbase->name(), name);
|
||||
} catch (...) {
|
||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||
<< "caught exception while resolving cluster data-source name: " << name;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string CollectionNameResolver::getViewNameCluster(
|
||||
TRI_voc_cid_t cid
|
||||
) const {
|
||||
|
|
|
@ -122,12 +122,19 @@ class CollectionNameResolver {
|
|||
std::string getCollectionName(std::string const& nameOrId) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief look up a collection struct for a collection name
|
||||
/// @brief look up a data source struct for an identifier
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
std::shared_ptr<LogicalDataSource> getDataSource(
|
||||
TRI_voc_cid_t id
|
||||
) const noexcept;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief look up a data source struct for a name
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
std::shared_ptr<LogicalDataSource> getDataSource(
|
||||
std::string const& name
|
||||
) const noexcept;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief look up a cluster-wide view name for a cluster-wide view id
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -176,4 +183,4 @@ class CollectionNameResolver {
|
|||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue