mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of github.com:triAGENS/ArangoDB into devel
This commit is contained in:
commit
ab99e17876
|
@ -8,7 +8,6 @@ make setup || exit 1
|
||||||
echo
|
echo
|
||||||
echo "$0: configuring ArangoDB"
|
echo "$0: configuring ArangoDB"
|
||||||
# V8 needs lib realtime:
|
# V8 needs lib realtime:
|
||||||
export LDFLAGS='-lrt -pthread'
|
|
||||||
./configure \
|
./configure \
|
||||||
--enable-relative \
|
--enable-relative \
|
||||||
--enable-all-in-one-libev \
|
--enable-all-in-one-libev \
|
||||||
|
|
|
@ -140,6 +140,7 @@ AM_LDFLAGS = \
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
LIBS = \
|
LIBS = \
|
||||||
|
@RT_LIBS@ \
|
||||||
@LIBEV_LIBS@ \
|
@LIBEV_LIBS@ \
|
||||||
@MATH_LIBS@ \
|
@MATH_LIBS@ \
|
||||||
@OPENSSL_LIBS@ \
|
@OPENSSL_LIBS@ \
|
||||||
|
|
|
@ -555,6 +555,7 @@ SHELL_SERVER_AQL = @top_srcdir@/js/server/tests/aql-arithmetic.js \
|
||||||
@top_srcdir@/js/server/tests/aql-modify-noncluster.js \
|
@top_srcdir@/js/server/tests/aql-modify-noncluster.js \
|
||||||
@top_srcdir@/js/server/tests/aql-modify-noncluster-serializetest.js \
|
@top_srcdir@/js/server/tests/aql-modify-noncluster-serializetest.js \
|
||||||
@top_srcdir@/js/server/tests/aql-operators.js \
|
@top_srcdir@/js/server/tests/aql-operators.js \
|
||||||
|
@top_srcdir@/js/server/tests/aql-optimizer-collect-into.js \
|
||||||
@top_srcdir@/js/server/tests/aql-optimizer-count.js \
|
@top_srcdir@/js/server/tests/aql-optimizer-count.js \
|
||||||
@top_srcdir@/js/server/tests/aql-optimizer-dynamic-bounds.js \
|
@top_srcdir@/js/server/tests/aql-optimizer-dynamic-bounds.js \
|
||||||
@top_srcdir@/js/server/tests/aql-optimizer-filters.js \
|
@top_srcdir@/js/server/tests/aql-optimizer-filters.js \
|
||||||
|
|
|
@ -786,6 +786,33 @@ AqlValue AqlValue::CreateFromBlocks (triagens::arango::AqlTransaction* trx,
|
||||||
return AqlValue(json.release());
|
return AqlValue(json.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create an AqlValue from a vector of AqlItemBlock*s
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AqlValue AqlValue::CreateFromBlocks (triagens::arango::AqlTransaction* trx,
|
||||||
|
std::vector<AqlItemBlock*> const& src,
|
||||||
|
triagens::aql::RegisterId expressionRegister) {
|
||||||
|
size_t totalSize = 0;
|
||||||
|
|
||||||
|
for (auto it = src.begin(); it != src.end(); ++it) {
|
||||||
|
totalSize += (*it)->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Json> json(new Json(Json::List, totalSize));
|
||||||
|
|
||||||
|
for (auto it = src.begin(); it != src.end(); ++it) {
|
||||||
|
auto current = (*it);
|
||||||
|
auto document = current->getDocumentCollection(expressionRegister);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < current->size(); ++i) {
|
||||||
|
json->add(current->getValueReference(i, expressionRegister).toJson(trx, document));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AqlValue(json.release());
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief 3-way comparison for AqlValue objects
|
/// @brief 3-way comparison for AqlValue objects
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
#include "Aql/Range.h"
|
#include "Aql/Range.h"
|
||||||
|
#include "Aql/types.h"
|
||||||
#include "Basics/JsonHelper.h"
|
#include "Basics/JsonHelper.h"
|
||||||
#include "Utils/V8TransactionContext.h"
|
#include "Utils/V8TransactionContext.h"
|
||||||
#include "Utils/AqlTransaction.h"
|
#include "Utils/AqlTransaction.h"
|
||||||
|
@ -257,6 +258,14 @@ namespace triagens {
|
||||||
std::vector<AqlItemBlock*> const&,
|
std::vector<AqlItemBlock*> const&,
|
||||||
std::vector<std::string> const&);
|
std::vector<std::string> const&);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create an AqlValue from a vector of AqlItemBlock*s
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static AqlValue CreateFromBlocks (triagens::arango::AqlTransaction*,
|
||||||
|
std::vector<AqlItemBlock*> const&,
|
||||||
|
triagens::aql::RegisterId);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief 3-way comparison for AqlValue objects
|
/// @brief 3-way comparison for AqlValue objects
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -353,11 +353,29 @@ AstNode* Ast::createNodeCollect (AstNode const* list,
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create an AST collect node, COUNT
|
/// @brief create an AST collect node, INTO var = expr
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AstNode* Ast::createNodeCollect (AstNode const* list,
|
AstNode* Ast::createNodeCollectExpression (AstNode const* list,
|
||||||
char const* name) {
|
char const* name,
|
||||||
|
AstNode const* expression) {
|
||||||
|
AstNode* node = createNode(NODE_TYPE_COLLECT_EXPRESSION);
|
||||||
|
node->addMember(list);
|
||||||
|
|
||||||
|
AstNode* variable = createNodeVariable(name, true);
|
||||||
|
node->addMember(variable);
|
||||||
|
|
||||||
|
node->addMember(expression);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create an AST collect node, COUNT INTO
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode* Ast::createNodeCollectCount (AstNode const* list,
|
||||||
|
char const* name) {
|
||||||
AstNode* node = createNode(NODE_TYPE_COLLECT_COUNT);
|
AstNode* node = createNode(NODE_TYPE_COLLECT_COUNT);
|
||||||
node->addMember(list);
|
node->addMember(list);
|
||||||
|
|
||||||
|
|
|
@ -273,11 +273,19 @@ namespace triagens {
|
||||||
AstNode const*);
|
AstNode const*);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create an AST collect node, COUNT
|
/// @brief create an AST collect node
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AstNode* createNodeCollect (AstNode const*,
|
AstNode* createNodeCollectExpression (AstNode const*,
|
||||||
char const*);
|
char const*,
|
||||||
|
AstNode const*);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create an AST collect node, COUNT INTO
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode* createNodeCollectCount (AstNode const*,
|
||||||
|
char const*);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create an AST sort node
|
/// @brief create an AST sort node
|
||||||
|
|
|
@ -119,7 +119,8 @@ std::unordered_map<int, std::string const> const AstNode::TypeNames{
|
||||||
{ static_cast<int>(NODE_TYPE_FCALL_USER), "user function call" },
|
{ static_cast<int>(NODE_TYPE_FCALL_USER), "user function call" },
|
||||||
{ static_cast<int>(NODE_TYPE_RANGE), "range" },
|
{ static_cast<int>(NODE_TYPE_RANGE), "range" },
|
||||||
{ static_cast<int>(NODE_TYPE_NOP), "no-op" },
|
{ static_cast<int>(NODE_TYPE_NOP), "no-op" },
|
||||||
{ static_cast<int>(NODE_TYPE_COLLECT_COUNT), "collect count" }
|
{ static_cast<int>(NODE_TYPE_COLLECT_COUNT), "collect count" },
|
||||||
|
{ static_cast<int>(NODE_TYPE_COLLECT_EXPRESSION), "collect expression" }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<int, std::string const> const AstNode::valueTypeNames{
|
std::unordered_map<int, std::string const> const AstNode::valueTypeNames{
|
||||||
|
@ -492,6 +493,7 @@ AstNode::AstNode (Ast* ast,
|
||||||
case NODE_TYPE_REPLACE:
|
case NODE_TYPE_REPLACE:
|
||||||
case NODE_TYPE_COLLECT:
|
case NODE_TYPE_COLLECT:
|
||||||
case NODE_TYPE_COLLECT_COUNT:
|
case NODE_TYPE_COLLECT_COUNT:
|
||||||
|
case NODE_TYPE_COLLECT_EXPRESSION:
|
||||||
case NODE_TYPE_SORT:
|
case NODE_TYPE_SORT:
|
||||||
case NODE_TYPE_SORT_ELEMENT:
|
case NODE_TYPE_SORT_ELEMENT:
|
||||||
case NODE_TYPE_LIMIT:
|
case NODE_TYPE_LIMIT:
|
||||||
|
|
|
@ -158,7 +158,8 @@ namespace triagens {
|
||||||
NODE_TYPE_FCALL_USER = 48,
|
NODE_TYPE_FCALL_USER = 48,
|
||||||
NODE_TYPE_RANGE = 49,
|
NODE_TYPE_RANGE = 49,
|
||||||
NODE_TYPE_NOP = 50,
|
NODE_TYPE_NOP = 50,
|
||||||
NODE_TYPE_COLLECT_COUNT = 51
|
NODE_TYPE_COLLECT_COUNT = 51,
|
||||||
|
NODE_TYPE_COLLECT_EXPRESSION = 52
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(NODE_TYPE_VALUE < NODE_TYPE_LIST, "incorrect node types");
|
static_assert(NODE_TYPE_VALUE < NODE_TYPE_LIST, "incorrect node types");
|
||||||
|
|
|
@ -2709,6 +2709,7 @@ AggregateBlock::AggregateBlock (ExecutionEngine* engine,
|
||||||
: ExecutionBlock(engine, en),
|
: ExecutionBlock(engine, en),
|
||||||
_aggregateRegisters(),
|
_aggregateRegisters(),
|
||||||
_currentGroup(en->_countOnly),
|
_currentGroup(en->_countOnly),
|
||||||
|
_expressionRegister(ExecutionNode::MaxRegisterId),
|
||||||
_groupRegister(ExecutionNode::MaxRegisterId),
|
_groupRegister(ExecutionNode::MaxRegisterId),
|
||||||
_variableNames() {
|
_variableNames() {
|
||||||
|
|
||||||
|
@ -2732,6 +2733,12 @@ AggregateBlock::AggregateBlock (ExecutionEngine* engine,
|
||||||
_groupRegister = (*it).second.registerId;
|
_groupRegister = (*it).second.registerId;
|
||||||
TRI_ASSERT(_groupRegister > 0 && _groupRegister < ExecutionNode::MaxRegisterId);
|
TRI_ASSERT(_groupRegister > 0 && _groupRegister < ExecutionNode::MaxRegisterId);
|
||||||
|
|
||||||
|
if (en->_expressionVariable != nullptr) {
|
||||||
|
auto it = registerPlan.find(en->_expressionVariable->id);
|
||||||
|
TRI_ASSERT(it != registerPlan.end());
|
||||||
|
_expressionRegister = (*it).second.registerId;
|
||||||
|
}
|
||||||
|
|
||||||
// construct a mapping of all register ids to variable names
|
// construct a mapping of all register ids to variable names
|
||||||
// we need this mapping to generate the grouped output
|
// we need this mapping to generate the grouped output
|
||||||
|
|
||||||
|
@ -2978,9 +2985,18 @@ void AggregateBlock::emitGroup (AqlItemBlock const* cur,
|
||||||
_currentGroup.addValues(cur, _groupRegister);
|
_currentGroup.addValues(cur, _groupRegister);
|
||||||
|
|
||||||
if (static_cast<AggregateNode const*>(_exeNode)->_countOnly) {
|
if (static_cast<AggregateNode const*>(_exeNode)->_countOnly) {
|
||||||
|
// only set group count in result register
|
||||||
res->setValue(row, _groupRegister, AqlValue(new Json(static_cast<double>(_currentGroup.groupLength))));
|
res->setValue(row, _groupRegister, AqlValue(new Json(static_cast<double>(_currentGroup.groupLength))));
|
||||||
}
|
}
|
||||||
|
else if (static_cast<AggregateNode const*>(_exeNode)->_expressionVariable != nullptr) {
|
||||||
|
// copy expression result into result register
|
||||||
|
res->setValue(row, _groupRegister,
|
||||||
|
AqlValue::CreateFromBlocks(_trx,
|
||||||
|
_currentGroup.groupBlocks,
|
||||||
|
_expressionRegister));
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
|
// copy variables / keep variables into result register
|
||||||
res->setValue(row, _groupRegister,
|
res->setValue(row, _groupRegister,
|
||||||
AqlValue::CreateFromBlocks(_trx,
|
AqlValue::CreateFromBlocks(_trx,
|
||||||
_currentGroup.groupBlocks,
|
_currentGroup.groupBlocks,
|
||||||
|
|
|
@ -1084,6 +1084,13 @@ namespace triagens {
|
||||||
|
|
||||||
AggregatorGroup _currentGroup;
|
AggregatorGroup _currentGroup;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief the optional register that contains the input expression values for
|
||||||
|
/// each group
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
RegisterId _expressionRegister;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief the optional register that contains the values for each group
|
/// @brief the optional register that contains the values for each group
|
||||||
/// if no values should be returned, then this has a value of 0
|
/// if no values should be returned, then this has a value of 0
|
||||||
|
|
|
@ -151,6 +151,7 @@ ExecutionNode* ExecutionNode::fromJsonFactory (ExecutionPlan* plan,
|
||||||
return new SortNode(plan, oneNode, elements, stable);
|
return new SortNode(plan, oneNode, elements, stable);
|
||||||
}
|
}
|
||||||
case AGGREGATE: {
|
case AGGREGATE: {
|
||||||
|
Variable* expressionVariable = varFromJson(plan->getAst(), oneNode, "expressionVariable", Optional);
|
||||||
Variable* outVariable = varFromJson(plan->getAst(), oneNode, "outVariable", Optional);
|
Variable* outVariable = varFromJson(plan->getAst(), oneNode, "outVariable", Optional);
|
||||||
|
|
||||||
triagens::basics::Json jsonAggregates = oneNode.get("aggregates");
|
triagens::basics::Json jsonAggregates = oneNode.get("aggregates");
|
||||||
|
@ -175,10 +176,10 @@ ExecutionNode* ExecutionNode::fromJsonFactory (ExecutionPlan* plan,
|
||||||
aggregateVariables.reserve(len);
|
aggregateVariables.reserve(len);
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
triagens::basics::Json oneJsonAggregate = jsonAggregates.at(static_cast<int>(i));
|
triagens::basics::Json oneJsonAggregate = jsonAggregates.at(static_cast<int>(i));
|
||||||
Variable* outVariable = varFromJson(plan->getAst(), oneJsonAggregate, "outVariable");
|
Variable* outVar = varFromJson(plan->getAst(), oneJsonAggregate, "outVariable");
|
||||||
Variable* inVariable = varFromJson(plan->getAst(), oneJsonAggregate, "inVariable");
|
Variable* inVar = varFromJson(plan->getAst(), oneJsonAggregate, "inVariable");
|
||||||
|
|
||||||
aggregateVariables.emplace_back(std::make_pair(outVariable, inVariable));
|
aggregateVariables.emplace_back(std::make_pair(outVar, inVar));
|
||||||
}
|
}
|
||||||
|
|
||||||
triagens::basics::Json jsonCount = oneNode.get("count");
|
triagens::basics::Json jsonCount = oneNode.get("count");
|
||||||
|
@ -186,6 +187,7 @@ ExecutionNode* ExecutionNode::fromJsonFactory (ExecutionPlan* plan,
|
||||||
|
|
||||||
return new AggregateNode(plan,
|
return new AggregateNode(plan,
|
||||||
oneNode,
|
oneNode,
|
||||||
|
expressionVariable,
|
||||||
outVariable,
|
outVariable,
|
||||||
keepVariables,
|
keepVariables,
|
||||||
plan->getAst()->variables()->variables(false),
|
plan->getAst()->variables()->variables(false),
|
||||||
|
@ -1980,6 +1982,7 @@ double SortNode::estimateCost (size_t& nrItems) const {
|
||||||
|
|
||||||
AggregateNode::AggregateNode (ExecutionPlan* plan,
|
AggregateNode::AggregateNode (ExecutionPlan* plan,
|
||||||
triagens::basics::Json const& base,
|
triagens::basics::Json const& base,
|
||||||
|
Variable const* expressionVariable,
|
||||||
Variable const* outVariable,
|
Variable const* outVariable,
|
||||||
std::vector<Variable const*> const& keepVariables,
|
std::vector<Variable const*> const& keepVariables,
|
||||||
std::unordered_map<VariableId, std::string const> const& variableMap,
|
std::unordered_map<VariableId, std::string const> const& variableMap,
|
||||||
|
@ -1987,6 +1990,7 @@ AggregateNode::AggregateNode (ExecutionPlan* plan,
|
||||||
bool countOnly)
|
bool countOnly)
|
||||||
: ExecutionNode(plan, base),
|
: ExecutionNode(plan, base),
|
||||||
_aggregateVariables(aggregateVariables),
|
_aggregateVariables(aggregateVariables),
|
||||||
|
_expressionVariable(expressionVariable),
|
||||||
_outVariable(outVariable),
|
_outVariable(outVariable),
|
||||||
_keepVariables(keepVariables),
|
_keepVariables(keepVariables),
|
||||||
_variableMap(variableMap),
|
_variableMap(variableMap),
|
||||||
|
@ -2015,6 +2019,11 @@ void AggregateNode::toJsonHelper (triagens::basics::Json& nodes,
|
||||||
}
|
}
|
||||||
json("aggregates", values);
|
json("aggregates", values);
|
||||||
|
|
||||||
|
// expression variable might be empty
|
||||||
|
if (_expressionVariable != nullptr) {
|
||||||
|
json("expressionVariable", _expressionVariable->toJson());
|
||||||
|
}
|
||||||
|
|
||||||
// output variable might be empty
|
// output variable might be empty
|
||||||
if (_outVariable != nullptr) {
|
if (_outVariable != nullptr) {
|
||||||
json("outVariable", _outVariable->toJson());
|
json("outVariable", _outVariable->toJson());
|
||||||
|
@ -2044,9 +2053,14 @@ ExecutionNode* AggregateNode::clone (ExecutionPlan* plan,
|
||||||
bool withDependencies,
|
bool withDependencies,
|
||||||
bool withProperties) const {
|
bool withProperties) const {
|
||||||
auto outVariable = _outVariable;
|
auto outVariable = _outVariable;
|
||||||
|
auto expressionVariable = _expressionVariable;
|
||||||
auto aggregateVariables = _aggregateVariables;
|
auto aggregateVariables = _aggregateVariables;
|
||||||
|
|
||||||
if (withProperties) {
|
if (withProperties) {
|
||||||
|
if (expressionVariable != nullptr) {
|
||||||
|
expressionVariable = plan->getAst()->variables()->createVariable(expressionVariable);
|
||||||
|
}
|
||||||
|
|
||||||
if (outVariable != nullptr) {
|
if (outVariable != nullptr) {
|
||||||
outVariable = plan->getAst()->variables()->createVariable(outVariable);
|
outVariable = plan->getAst()->variables()->createVariable(outVariable);
|
||||||
}
|
}
|
||||||
|
@ -2059,7 +2073,14 @@ ExecutionNode* AggregateNode::clone (ExecutionPlan* plan,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto c = new AggregateNode(plan, _id, aggregateVariables, outVariable, _keepVariables, _variableMap, _countOnly);
|
auto c = new AggregateNode(plan,
|
||||||
|
_id,
|
||||||
|
aggregateVariables,
|
||||||
|
expressionVariable,
|
||||||
|
outVariable,
|
||||||
|
_keepVariables,
|
||||||
|
_variableMap,
|
||||||
|
_countOnly);
|
||||||
|
|
||||||
CloneHelper(c, plan, withDependencies, withProperties);
|
CloneHelper(c, plan, withDependencies, withProperties);
|
||||||
|
|
||||||
|
@ -2110,6 +2131,10 @@ std::vector<Variable const*> AggregateNode::getVariablesUsedHere () const {
|
||||||
v.insert(p.second);
|
v.insert(p.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_expressionVariable != nullptr) {
|
||||||
|
v.insert(_expressionVariable);
|
||||||
|
}
|
||||||
|
|
||||||
if (_outVariable != nullptr && ! _countOnly) {
|
if (_outVariable != nullptr && ! _countOnly) {
|
||||||
if (_keepVariables.empty()) {
|
if (_keepVariables.empty()) {
|
||||||
// Here we have to find all user defined variables in this query
|
// Here we have to find all user defined variables in this query
|
||||||
|
|
|
@ -1930,12 +1930,14 @@ namespace triagens {
|
||||||
AggregateNode (ExecutionPlan* plan,
|
AggregateNode (ExecutionPlan* plan,
|
||||||
size_t id,
|
size_t id,
|
||||||
std::vector<std::pair<Variable const*, Variable const*>> const& aggregateVariables,
|
std::vector<std::pair<Variable const*, Variable const*>> const& aggregateVariables,
|
||||||
|
Variable const* expressionVariable,
|
||||||
Variable const* outVariable,
|
Variable const* outVariable,
|
||||||
std::vector<Variable const*> const& keepVariables,
|
std::vector<Variable const*> const& keepVariables,
|
||||||
std::unordered_map<VariableId, std::string const> const& variableMap,
|
std::unordered_map<VariableId, std::string const> const& variableMap,
|
||||||
bool countOnly)
|
bool countOnly)
|
||||||
: ExecutionNode(plan, id),
|
: ExecutionNode(plan, id),
|
||||||
_aggregateVariables(aggregateVariables),
|
_aggregateVariables(aggregateVariables),
|
||||||
|
_expressionVariable(expressionVariable),
|
||||||
_outVariable(outVariable),
|
_outVariable(outVariable),
|
||||||
_keepVariables(keepVariables),
|
_keepVariables(keepVariables),
|
||||||
_variableMap(variableMap),
|
_variableMap(variableMap),
|
||||||
|
@ -1945,6 +1947,7 @@ namespace triagens {
|
||||||
|
|
||||||
AggregateNode (ExecutionPlan*,
|
AggregateNode (ExecutionPlan*,
|
||||||
triagens::basics::Json const& base,
|
triagens::basics::Json const& base,
|
||||||
|
Variable const* expressionVariable,
|
||||||
Variable const* outVariable,
|
Variable const* outVariable,
|
||||||
std::vector<Variable const*> const& keepVariables,
|
std::vector<Variable const*> const& keepVariables,
|
||||||
std::unordered_map<VariableId, std::string const> const& variableMap,
|
std::unordered_map<VariableId, std::string const> const& variableMap,
|
||||||
|
@ -2042,6 +2045,12 @@ namespace triagens {
|
||||||
|
|
||||||
std::vector<std::pair<Variable const*, Variable const*>> _aggregateVariables;
|
std::vector<std::pair<Variable const*, Variable const*>> _aggregateVariables;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief input expression variable (might be null)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Variable const* _expressionVariable;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief output variable to write to (might be null)
|
/// @brief output variable to write to (might be null)
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -562,7 +562,8 @@ ExecutionNode* ExecutionPlan::fromNodeSort (ExecutionNode* previous,
|
||||||
|
|
||||||
ExecutionNode* ExecutionPlan::fromNodeCollect (ExecutionNode* previous,
|
ExecutionNode* ExecutionPlan::fromNodeCollect (ExecutionNode* previous,
|
||||||
AstNode const* node) {
|
AstNode const* node) {
|
||||||
TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_COLLECT);
|
TRI_ASSERT(node != nullptr &&
|
||||||
|
node->type == NODE_TYPE_COLLECT);
|
||||||
size_t const n = node->numMembers();
|
size_t const n = node->numMembers();
|
||||||
|
|
||||||
TRI_ASSERT(n >= 1);
|
TRI_ASSERT(n >= 1);
|
||||||
|
@ -635,12 +636,101 @@ ExecutionNode* ExecutionPlan::fromNodeCollect (ExecutionNode* previous,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto en = registerNode(new AggregateNode(this, nextId(), aggregateVariables,
|
auto en = registerNode(new AggregateNode(this, nextId(), aggregateVariables, nullptr,
|
||||||
outVariable, keepVariables, _ast->variables()->variables(false), false));
|
outVariable, keepVariables, _ast->variables()->variables(false), false));
|
||||||
|
|
||||||
return addDependency(previous, en);
|
return addDependency(previous, en);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create an execution plan element from an AST COLLECT node
|
||||||
|
/// note that also a sort plan node will be added in front of the collect plan
|
||||||
|
/// node
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ExecutionNode* ExecutionPlan::fromNodeCollectExpression (ExecutionNode* previous,
|
||||||
|
AstNode const* node) {
|
||||||
|
TRI_ASSERT(node != nullptr &&
|
||||||
|
node->type == NODE_TYPE_COLLECT_EXPRESSION);
|
||||||
|
size_t const n = node->numMembers();
|
||||||
|
|
||||||
|
TRI_ASSERT(n == 3);
|
||||||
|
|
||||||
|
auto list = node->getMember(0);
|
||||||
|
size_t const numVars = list->numMembers();
|
||||||
|
|
||||||
|
std::vector<std::pair<Variable const*, bool>> sortElements;
|
||||||
|
|
||||||
|
std::vector<std::pair<Variable const*, Variable const*>> aggregateVariables;
|
||||||
|
aggregateVariables.reserve(numVars);
|
||||||
|
for (size_t i = 0; i < numVars; ++i) {
|
||||||
|
auto assigner = list->getMember(i);
|
||||||
|
|
||||||
|
if (assigner == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_ASSERT(assigner->type == NODE_TYPE_ASSIGN);
|
||||||
|
auto out = assigner->getMember(0);
|
||||||
|
TRI_ASSERT(out != nullptr);
|
||||||
|
auto v = static_cast<Variable*>(out->getData());
|
||||||
|
TRI_ASSERT(v != nullptr);
|
||||||
|
|
||||||
|
auto expression = assigner->getMember(1);
|
||||||
|
|
||||||
|
if (expression->type == NODE_TYPE_REFERENCE) {
|
||||||
|
// operand is a variable
|
||||||
|
auto e = static_cast<Variable*>(expression->getData());
|
||||||
|
aggregateVariables.push_back(std::make_pair(v, e));
|
||||||
|
sortElements.push_back(std::make_pair(e, true));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// operand is some misc expression
|
||||||
|
auto calc = createTemporaryCalculation(expression);
|
||||||
|
|
||||||
|
calc->addDependency(previous);
|
||||||
|
previous = calc;
|
||||||
|
|
||||||
|
aggregateVariables.emplace_back(std::make_pair(v, calc->outVariable()));
|
||||||
|
sortElements.emplace_back(std::make_pair(calc->outVariable(), true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Variable const* expressionVariable = nullptr;
|
||||||
|
auto expression = node->getMember(2);
|
||||||
|
if (expression->type == NODE_TYPE_REFERENCE) {
|
||||||
|
// expression is already a variable
|
||||||
|
auto variable = static_cast<Variable*>(expression->getData());
|
||||||
|
TRI_ASSERT(variable != nullptr);
|
||||||
|
expressionVariable = variable;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// expression is some misc expression
|
||||||
|
auto calc = createTemporaryCalculation(expression);
|
||||||
|
calc->addDependency(previous);
|
||||||
|
previous = calc;
|
||||||
|
expressionVariable = calc->outVariable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// inject a sort node for all expressions / variables that we just picked up...
|
||||||
|
// note that this sort is stable
|
||||||
|
auto sort = registerNode(new SortNode(this, nextId(), sortElements, true));
|
||||||
|
sort->addDependency(previous);
|
||||||
|
previous = sort;
|
||||||
|
|
||||||
|
// output variable
|
||||||
|
auto v = node->getMember(1);
|
||||||
|
Variable* outVariable = static_cast<Variable*>(v->getData());
|
||||||
|
|
||||||
|
std::unordered_map<VariableId, std::string const> variableMap;
|
||||||
|
|
||||||
|
auto en = registerNode(new AggregateNode(this, nextId(), aggregateVariables,
|
||||||
|
expressionVariable, outVariable, std::vector<Variable const*>(), variableMap, false));
|
||||||
|
|
||||||
|
return addDependency(previous, en);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create an execution plan element from an AST COLLECT node, COUNT
|
/// @brief create an execution plan element from an AST COLLECT node, COUNT
|
||||||
/// note that also a sort plan node will be added in front of the collect plan
|
/// note that also a sort plan node will be added in front of the collect plan
|
||||||
|
@ -649,7 +739,8 @@ ExecutionNode* ExecutionPlan::fromNodeCollect (ExecutionNode* previous,
|
||||||
|
|
||||||
ExecutionNode* ExecutionPlan::fromNodeCollectCount (ExecutionNode* previous,
|
ExecutionNode* ExecutionPlan::fromNodeCollectCount (ExecutionNode* previous,
|
||||||
AstNode const* node) {
|
AstNode const* node) {
|
||||||
TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_COLLECT_COUNT);
|
TRI_ASSERT(node != nullptr &&
|
||||||
|
node->type == NODE_TYPE_COLLECT_COUNT);
|
||||||
size_t const n = node->numMembers();
|
size_t const n = node->numMembers();
|
||||||
|
|
||||||
TRI_ASSERT(n == 2);
|
TRI_ASSERT(n == 2);
|
||||||
|
@ -705,7 +796,7 @@ ExecutionNode* ExecutionPlan::fromNodeCollectCount (ExecutionNode* previous,
|
||||||
// handle out variable
|
// handle out variable
|
||||||
Variable* outVariable = static_cast<Variable*>(v->getData());
|
Variable* outVariable = static_cast<Variable*>(v->getData());
|
||||||
|
|
||||||
auto en = registerNode(new AggregateNode(this, nextId(), aggregateVariables,
|
auto en = registerNode(new AggregateNode(this, nextId(), aggregateVariables, nullptr,
|
||||||
outVariable, std::vector<Variable const*>(), _ast->variables()->variables(false), true));
|
outVariable, std::vector<Variable const*>(), _ast->variables()->variables(false), true));
|
||||||
|
|
||||||
return addDependency(previous, en);
|
return addDependency(previous, en);
|
||||||
|
@ -997,6 +1088,11 @@ ExecutionNode* ExecutionPlan::fromNode (AstNode const* node) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case NODE_TYPE_COLLECT_EXPRESSION: {
|
||||||
|
en = fromNodeCollectExpression(en, member);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case NODE_TYPE_COLLECT_COUNT: {
|
case NODE_TYPE_COLLECT_COUNT: {
|
||||||
en = fromNodeCollectCount(en, member);
|
en = fromNodeCollectCount(en, member);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -381,6 +381,13 @@ namespace triagens {
|
||||||
ExecutionNode* fromNodeCollect (ExecutionNode*,
|
ExecutionNode* fromNodeCollect (ExecutionNode*,
|
||||||
AstNode const*);
|
AstNode const*);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create an execution plan element from an AST COLLECT node, var = expr
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ExecutionNode* fromNodeCollectExpression (ExecutionNode*,
|
||||||
|
AstNode const*);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create an execution plan element from an AST COLLECT node, COUNT
|
/// @brief create an execution plan element from an AST COLLECT node, COUNT
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -309,7 +309,7 @@ collect_statement:
|
||||||
scopes->start(triagens::aql::AQL_SCOPE_COLLECT);
|
scopes->start(triagens::aql::AQL_SCOPE_COLLECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto node = parser->ast()->createNodeCollect(parser->ast()->createNodeList(), $2);
|
auto node = parser->ast()->createNodeCollectCount(parser->ast()->createNodeList(), $2);
|
||||||
parser->ast()->addOperation(node);
|
parser->ast()->addOperation(node);
|
||||||
}
|
}
|
||||||
| collect_variable_list count_into {
|
| collect_variable_list count_into {
|
||||||
|
@ -336,7 +336,7 @@ collect_statement:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto node = parser->ast()->createNodeCollect($1, $2);
|
auto node = parser->ast()->createNodeCollectCount($1, $2);
|
||||||
parser->ast()->addOperation(node);
|
parser->ast()->addOperation(node);
|
||||||
}
|
}
|
||||||
| collect_variable_list optional_into optional_keep {
|
| collect_variable_list optional_into optional_keep {
|
||||||
|
@ -370,6 +370,33 @@ collect_statement:
|
||||||
auto node = parser->ast()->createNodeCollect($1, $2, $3);
|
auto node = parser->ast()->createNodeCollect($1, $2, $3);
|
||||||
parser->ast()->addOperation(node);
|
parser->ast()->addOperation(node);
|
||||||
}
|
}
|
||||||
|
| collect_variable_list T_INTO variable_name T_ASSIGN expression {
|
||||||
|
auto scopes = parser->ast()->scopes();
|
||||||
|
|
||||||
|
// check if we are in the main scope
|
||||||
|
bool reRegisterVariables = (scopes->type() != triagens::aql::AQL_SCOPE_MAIN);
|
||||||
|
|
||||||
|
if (reRegisterVariables) {
|
||||||
|
// end the active scopes
|
||||||
|
scopes->endNested();
|
||||||
|
// start a new scope
|
||||||
|
scopes->start(triagens::aql::AQL_SCOPE_COLLECT);
|
||||||
|
|
||||||
|
size_t const n = $1->numMembers();
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
auto member = $1->getMember(i);
|
||||||
|
|
||||||
|
if (member != nullptr) {
|
||||||
|
TRI_ASSERT(member->type == NODE_TYPE_ASSIGN);
|
||||||
|
auto v = static_cast<Variable*>(member->getMember(0)->getData());
|
||||||
|
scopes->addVariable(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto node = parser->ast()->createNodeCollectExpression($1, $3, $5);
|
||||||
|
parser->ast()->addOperation(node);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
collect_list:
|
collect_list:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*jshint browser: true */
|
/*jshint browser: true */
|
||||||
/*jshint strict: false, unused: false */
|
/*jshint strict: false, unused: false */
|
||||||
/*global Backbone, $, window, arangoHelper, templateEngine, Joi, alert, _*/
|
/*global require, Backbone, $, window, arangoHelper, templateEngine, Joi, alert, _*/
|
||||||
(function() {
|
(function() {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
/*jshint strict: false, maxlen: 500 */
|
||||||
|
/*global require, assertEqual, AQL_EXECUTE */
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief tests for COLLECT w/ INTO var = expr
|
||||||
|
///
|
||||||
|
/// @file
|
||||||
|
///
|
||||||
|
/// DISCLAIMER
|
||||||
|
///
|
||||||
|
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// @author Jan Steemann
|
||||||
|
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
var jsunity = require("jsunity");
|
||||||
|
var db = require("org/arangodb").db;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test suite
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function optimizerCollectExpressionTestSuite () {
|
||||||
|
var c;
|
||||||
|
|
||||||
|
return {
|
||||||
|
setUp : function () {
|
||||||
|
db._drop("UnitTestsCollection");
|
||||||
|
c = db._create("UnitTestsCollection");
|
||||||
|
|
||||||
|
for (var i = 0; i < 1000; ++i) {
|
||||||
|
c.save({ gender: (i % 2 === 0 ? "m" : "f"), age: 11 + (i % 71), value: i });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
tearDown : function () {
|
||||||
|
db._drop("UnitTestsCollection");
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test expression
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testReference : function () {
|
||||||
|
var query = "FOR i IN " + c.name() + " COLLECT gender = i.gender INTO docs = i RETURN { gender: gender, age: MIN(docs[*].age) }";
|
||||||
|
|
||||||
|
var results = AQL_EXECUTE(query);
|
||||||
|
assertEqual(2, results.json.length);
|
||||||
|
assertEqual("f", results.json[0].gender);
|
||||||
|
assertEqual(11, results.json[0].age);
|
||||||
|
assertEqual("m", results.json[1].gender);
|
||||||
|
assertEqual(11, results.json[1].age);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test expression
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testSubAttribute : function () {
|
||||||
|
var query = "FOR i IN " + c.name() + " COLLECT gender = i.gender INTO ages = i.age RETURN { gender: gender, age: MIN(ages) }";
|
||||||
|
|
||||||
|
var results = AQL_EXECUTE(query);
|
||||||
|
assertEqual(2, results.json.length);
|
||||||
|
assertEqual("f", results.json[0].gender);
|
||||||
|
assertEqual(11, results.json[0].age);
|
||||||
|
assertEqual("m", results.json[1].gender);
|
||||||
|
assertEqual(11, results.json[1].age);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test expression
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testConst : function () {
|
||||||
|
var query = "FOR i IN " + c.name() + " COLLECT gender = i.gender INTO values = 1 RETURN { gender: gender, values: values }";
|
||||||
|
|
||||||
|
var values = [ ];
|
||||||
|
for (var i = 0; i < 500; ++i) {
|
||||||
|
values.push(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = AQL_EXECUTE(query);
|
||||||
|
assertEqual(2, results.json.length);
|
||||||
|
assertEqual("f", results.json[0].gender);
|
||||||
|
assertEqual(values, results.json[0].values);
|
||||||
|
assertEqual("m", results.json[1].gender);
|
||||||
|
assertEqual(values, results.json[1].values);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test expression
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testDocAttribute : function () {
|
||||||
|
var query = "FOR i IN " + c.name() + " COLLECT gender = i.gender INTO values = i.value RETURN { gender: gender, values: values }";
|
||||||
|
|
||||||
|
var f = [ ], m = [ ];
|
||||||
|
for (var i = 0; i < 500; ++i) {
|
||||||
|
m.push(i * 2);
|
||||||
|
f.push((i * 2) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = AQL_EXECUTE(query);
|
||||||
|
assertEqual(2, results.json.length);
|
||||||
|
assertEqual("f", results.json[0].gender);
|
||||||
|
assertEqual(f, results.json[0].values.sort(function (l, r) { return l - r; }));
|
||||||
|
assertEqual("m", results.json[1].gender);
|
||||||
|
assertEqual(m, results.json[1].values.sort(function (l, r) { return l - r; }));
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test expression
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testCalculation : function () {
|
||||||
|
var query = "FOR i IN " + c.name() + " COLLECT gender = i.gender INTO names = (i.gender == 'f' ? 'female' : 'male') RETURN { gender: gender, names: names }";
|
||||||
|
|
||||||
|
var m = [ ], f = [ ];
|
||||||
|
for (var i = 0; i < 500; ++i) {
|
||||||
|
m.push('male');
|
||||||
|
f.push('female');
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = AQL_EXECUTE(query);
|
||||||
|
assertEqual(2, results.json.length);
|
||||||
|
assertEqual("f", results.json[0].gender);
|
||||||
|
assertEqual(f, results.json[0].names);
|
||||||
|
assertEqual("m", results.json[1].gender);
|
||||||
|
assertEqual(m, results.json[1].names);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief executes the test suite
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
jsunity.run(optimizerCollectExpressionTestSuite);
|
||||||
|
|
||||||
|
return jsunity.done();
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// mode: outline-minor
|
||||||
|
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
|
||||||
|
// End:
|
|
@ -5,7 +5,7 @@ AC_DEFUN([AC_CLOCK],
|
||||||
[
|
[
|
||||||
have_clock_gettime=no
|
have_clock_gettime=no
|
||||||
|
|
||||||
AC_MSG_CHECKING([for clock_gettime oooooooooooooooooooooooooooooo])
|
AC_MSG_CHECKING([for clock_gettime])
|
||||||
|
|
||||||
AC_TRY_LINK([ #include <time.h> ], [struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);], [
|
AC_TRY_LINK([ #include <time.h> ], [struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);], [
|
||||||
have_clock_gettime=yes
|
have_clock_gettime=yes
|
||||||
|
@ -17,7 +17,7 @@ AC_DEFUN([AC_CLOCK],
|
||||||
if test "$have_clock_gettime" = "no"; then
|
if test "$have_clock_gettime" = "no"; then
|
||||||
AC_MSG_CHECKING([for clock_gettime in -lrt])
|
AC_MSG_CHECKING([for clock_gettime in -lrt])
|
||||||
|
|
||||||
SAVED_LIBS="$LIBS"
|
SAVED_LIBS=$LIBS
|
||||||
LIBS="$LIBS -lrt"
|
LIBS="$LIBS -lrt"
|
||||||
|
|
||||||
AC_TRY_LINK([ #include <time.h> ], [struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);], [
|
AC_TRY_LINK([ #include <time.h> ], [struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);], [
|
||||||
|
@ -69,6 +69,9 @@ AC_DEFUN([AC_CLOCK],
|
||||||
if test "$have_clock_get_time" = "yes"; then
|
if test "$have_clock_get_time" = "yes"; then
|
||||||
AC_DEFINE([HAVE_CLOCK_GET_TIME], 1, [do we have clock_get_time?])
|
AC_DEFINE([HAVE_CLOCK_GET_TIME], 1, [do we have clock_get_time?])
|
||||||
fi
|
fi
|
||||||
|
RT_LIBS=$LIBS
|
||||||
|
AC_SUBST(RT_LIBS)
|
||||||
|
SAVED_LIBS=$LIBS
|
||||||
])
|
])
|
||||||
|
|
||||||
dnl Local Variables:
|
dnl Local Variables:
|
||||||
|
|
|
@ -253,3 +253,30 @@ AC_DEFUN([TR_LIBRARY],[
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
])
|
])
|
||||||
|
|
||||||
|
dnl ----------------------------------------------------------------------------
|
||||||
|
dnl check for std::unordered_map::emplace()
|
||||||
|
dnl ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
AC_DEFUN([AX_CXX_CHECK_UNORDERED_MAP_EMPLACE], [
|
||||||
|
AC_LANG_PUSH([C++])
|
||||||
|
AC_MSG_CHECKING([whether C++ has support for std::unordered_map::emplace()])
|
||||||
|
AC_COMPILE_IFELSE(
|
||||||
|
[AC_LANG_SOURCE[
|
||||||
|
#include <unordered_map>
|
||||||
|
void test () {
|
||||||
|
std::unordered_map<int, int> x;
|
||||||
|
x.emplace(1, 1);
|
||||||
|
}
|
||||||
|
]],
|
||||||
|
[eval unordered_map_emplace=yes],
|
||||||
|
[eval unordered_map_emplace=no]
|
||||||
|
)
|
||||||
|
AC_MSG_RESULT([$unordered_map_emplace])
|
||||||
|
AC_LANG_POP([C++])
|
||||||
|
if test x$unordered_map_emplace = xno; then
|
||||||
|
AC_MSG_ERROR([C++ has no support for std::unordered_map::emplace()])
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
AX_CXX_CHECK_UNORDERED_MAP_EMPLACE
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue