1
0
Fork 0

Merge branch 'spdvpk' of github.com:arangodb/arangodb into spdvpk

This commit is contained in:
Michael Hackstein 2016-03-21 13:11:48 +01:00
commit b04ec0f4fe
12 changed files with 73 additions and 106 deletions

View File

@ -1408,25 +1408,36 @@ AqlValue Expression::executeSimpleExpressionArithmetic(
VPackBuilder builder; VPackBuilder builder;
mustDestroy = true; // builder = dynamic data mustDestroy = true; // builder = dynamic data
double result;
switch (node->type) { switch (node->type) {
case NODE_TYPE_OPERATOR_BINARY_PLUS: case NODE_TYPE_OPERATOR_BINARY_PLUS:
builder.add(VPackValue(l + r)); result = l + r;
return AqlValue(builder); break;
case NODE_TYPE_OPERATOR_BINARY_MINUS: case NODE_TYPE_OPERATOR_BINARY_MINUS:
builder.add(VPackValue(l - r)); result = l - r;
return AqlValue(builder); break;
case NODE_TYPE_OPERATOR_BINARY_TIMES: case NODE_TYPE_OPERATOR_BINARY_TIMES:
builder.add(VPackValue(l * r)); result = l * r;
return AqlValue(builder); break;
case NODE_TYPE_OPERATOR_BINARY_DIV: case NODE_TYPE_OPERATOR_BINARY_DIV:
builder.add(VPackValue(l / r)); result = l / r;
return AqlValue(builder); break;
case NODE_TYPE_OPERATOR_BINARY_MOD: case NODE_TYPE_OPERATOR_BINARY_MOD:
builder.add(VPackValue(fmod(l, r))); result = fmod(l, r);
return AqlValue(builder); break;
default: default:
mustDestroy = false; mustDestroy = false;
return AqlValue(VelocyPackHelper::NullValue()); return AqlValue(VelocyPackHelper::NullValue());
} }
if (std::isnan(result) || !std::isfinite(result) || result == HUGE_VAL || result == -HUGE_VAL) {
// convert NaN, +inf & -inf to 0
mustDestroy = false;
builder.add(VPackValue(0.0));
return AqlValue(builder);
}
builder.add(VPackValue(result));
return AqlValue(builder);
} }

View File

@ -86,6 +86,7 @@ arangodb::aql::AstNode* IndexBlock::makeUnique(
} }
void IndexBlock::executeExpressions() { void IndexBlock::executeExpressions() {
DEBUG_BEGIN_BLOCK();
TRI_ASSERT(_condition != nullptr); TRI_ASSERT(_condition != nullptr);
// The following are needed to evaluate expressions with local data from // The following are needed to evaluate expressions with local data from
@ -114,9 +115,11 @@ void IndexBlock::executeExpressions() {
->getMember(toReplace->andMember) ->getMember(toReplace->andMember)
->changeMember(toReplace->operatorMember, evaluatedNode); ->changeMember(toReplace->operatorMember, evaluatedNode);
} }
DEBUG_END_BLOCK();
} }
int IndexBlock::initialize() { int IndexBlock::initialize() {
DEBUG_BEGIN_BLOCK();
int res = ExecutionBlock::initialize(); int res = ExecutionBlock::initialize();
cleanupNonConstExpressions(); cleanupNonConstExpressions();
@ -203,6 +206,7 @@ int IndexBlock::initialize() {
} }
return res; return res;
DEBUG_END_BLOCK();
} }
// init the ranges for reading, this should be called once per new incoming // init the ranges for reading, this should be called once per new incoming
@ -222,6 +226,7 @@ int IndexBlock::initialize() {
// _pos to evaluate the variable bounds. // _pos to evaluate the variable bounds.
bool IndexBlock::initIndexes() { bool IndexBlock::initIndexes() {
DEBUG_BEGIN_BLOCK();
// We start with a different context. Return documents found in the previous // We start with a different context. Return documents found in the previous
// context again. // context again.
_alreadyReturned.clear(); _alreadyReturned.clear();
@ -304,6 +309,7 @@ bool IndexBlock::initIndexes() {
} }
} }
return true; return true;
DEBUG_END_BLOCK();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -311,6 +317,7 @@ bool IndexBlock::initIndexes() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::shared_ptr<arangodb::OperationCursor> IndexBlock::createCursor() { std::shared_ptr<arangodb::OperationCursor> IndexBlock::createCursor() {
DEBUG_BEGIN_BLOCK();
IndexNode const* node = static_cast<IndexNode const*>(getPlanNode()); IndexNode const* node = static_cast<IndexNode const*>(getPlanNode());
auto outVariable = node->outVariable(); auto outVariable = node->outVariable();
auto ast = node->_plan->getAst(); auto ast = node->_plan->getAst();
@ -327,6 +334,7 @@ std::shared_ptr<arangodb::OperationCursor> IndexBlock::createCursor() {
_collection->getName(), _indexes[_currentIndex], ast, _collection->getName(), _indexes[_currentIndex], ast,
_condition->getMember(_currentIndex), outVariable, UINT64_MAX, _condition->getMember(_currentIndex), outVariable, UINT64_MAX,
TRI_DEFAULT_BATCH_SIZE, node->_reverse); TRI_DEFAULT_BATCH_SIZE, node->_reverse);
DEBUG_END_BLOCK();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -334,6 +342,7 @@ std::shared_ptr<arangodb::OperationCursor> IndexBlock::createCursor() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void IndexBlock::startNextCursor() { void IndexBlock::startNextCursor() {
DEBUG_BEGIN_BLOCK();
IndexNode const* node = static_cast<IndexNode const*>(getPlanNode()); IndexNode const* node = static_cast<IndexNode const*>(getPlanNode());
if (node->_reverse) { if (node->_reverse) {
@ -347,11 +356,13 @@ void IndexBlock::startNextCursor() {
} else { } else {
_cursor = nullptr; _cursor = nullptr;
} }
DEBUG_END_BLOCK();
} }
// this is called every time everything in _documents has been passed on // this is called every time everything in _documents has been passed on
bool IndexBlock::readIndex(size_t atMost) { bool IndexBlock::readIndex(size_t atMost) {
DEBUG_BEGIN_BLOCK();
// this is called every time we want more in _documents. // this is called every time we want more in _documents.
// For the primary key index, this only reads the index once, and never // For the primary key index, this only reads the index once, and never
// again (although there might be multiple calls to this function). // again (although there might be multiple calls to this function).
@ -416,9 +427,11 @@ bool IndexBlock::readIndex(size_t atMost) {
} }
_posInDocs = 0; _posInDocs = 0;
return (!_documents.empty()); return (!_documents.empty());
DEBUG_END_BLOCK();
} }
int IndexBlock::initializeCursor(AqlItemBlock* items, size_t pos) { int IndexBlock::initializeCursor(AqlItemBlock* items, size_t pos) {
DEBUG_BEGIN_BLOCK();
int res = ExecutionBlock::initializeCursor(items, pos); int res = ExecutionBlock::initializeCursor(items, pos);
if (res != TRI_ERROR_NO_ERROR) { if (res != TRI_ERROR_NO_ERROR) {
@ -428,6 +441,7 @@ int IndexBlock::initializeCursor(AqlItemBlock* items, size_t pos) {
_posInDocs = 0; _posInDocs = 0;
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
DEBUG_END_BLOCK();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -435,6 +449,7 @@ int IndexBlock::initializeCursor(AqlItemBlock* items, size_t pos) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AqlItemBlock* IndexBlock::getSome(size_t atLeast, size_t atMost) { AqlItemBlock* IndexBlock::getSome(size_t atLeast, size_t atMost) {
DEBUG_BEGIN_BLOCK();
if (_done) { if (_done) {
return nullptr; return nullptr;
} }
@ -528,6 +543,7 @@ AqlItemBlock* IndexBlock::getSome(size_t atLeast, size_t atMost) {
// Clear out registers no longer needed later: // Clear out registers no longer needed later:
clearRegisters(res.get()); clearRegisters(res.get());
return res.release(); return res.release();
DEBUG_END_BLOCK();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -535,6 +551,7 @@ AqlItemBlock* IndexBlock::getSome(size_t atLeast, size_t atMost) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
size_t IndexBlock::skipSome(size_t atLeast, size_t atMost) { size_t IndexBlock::skipSome(size_t atLeast, size_t atMost) {
DEBUG_BEGIN_BLOCK();
if (_done) { if (_done) {
return 0; return 0;
} }
@ -589,6 +606,7 @@ size_t IndexBlock::skipSome(size_t atLeast, size_t atMost) {
} }
return skipped; return skipped;
DEBUG_END_BLOCK();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -57,10 +57,12 @@ void IndexNode::toVelocyPackHelper(VPackBuilder& nodes, bool verbose) const {
nodes.add(VPackValue("indexes")); nodes.add(VPackValue("indexes"));
{ {
#warning Old Implementation did use AqlIndex -> toVelocyPack, that contained unique, sparse, selectivity etc.
VPackArrayBuilder guard(&nodes); VPackArrayBuilder guard(&nodes);
for (auto& index : _indexes) { for (auto& index : _indexes) {
nodes.add(VPackValue(index)); arangodb::Index* idx = trx()->getIndexByIdentifier(_collection->name, index);
nodes.openObject();
idx->toVelocyPack(nodes, false);
nodes.close();
} }
} }
nodes.add(VPackValue("condition")); nodes.add(VPackValue("condition"));
@ -108,12 +110,8 @@ IndexNode::IndexNode(ExecutionPlan* plan, arangodb::basics::Json const& json)
for (size_t i = 0; i < length; ++i) { for (size_t i = 0; i < length; ++i) {
auto entry = TRI_LookupArrayJson(indexes, i); auto entry = TRI_LookupArrayJson(indexes, i);
if (!TRI_IsStringJson(entry)) { std::string iid = JsonHelper::checkAndGetStringValue(entry, "id");
std::string msg = "The attribute index id is not a string."; _indexes.emplace_back(iid);
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, msg);
}
_indexes.emplace_back(
std::string(entry->_value._string.data, entry->_value._string.length - 1));
} }
TRI_json_t const* condition = TRI_json_t const* condition =

View File

@ -360,6 +360,7 @@ std::shared_ptr<VPackBuilder> Index::toVelocyPack(bool withFigures) const {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief create a VelocyPack representation of the index /// @brief create a VelocyPack representation of the index
/// base functionality (called from derived classes) /// base functionality (called from derived classes)
/// note: needs an already-opened object as its input!
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Index::toVelocyPack(VPackBuilder& builder, bool withFigures) const { void Index::toVelocyPack(VPackBuilder& builder, bool withFigures) const {

View File

@ -107,6 +107,9 @@ struct TRI_index_element_t {
void* space = TRI_Allocate( void* space = TRI_Allocate(
TRI_UNKNOWN_MEM_ZONE, TRI_UNKNOWN_MEM_ZONE,
sizeof(TRI_doc_mptr_t*) + (sizeof(TRI_vpack_sub_t) * numSubs), false); sizeof(TRI_doc_mptr_t*) + (sizeof(TRI_vpack_sub_t) * numSubs), false);
if (space == nullptr) {
return nullptr;
}
// FIXME: catch nullptr case? // FIXME: catch nullptr case?
return new (space) TRI_index_element_t(); return new (space) TRI_index_element_t();
} }

View File

@ -483,6 +483,14 @@ class Transaction {
TRI_document_collection_t* documentCollection(TRI_voc_cid_t) const; TRI_document_collection_t* documentCollection(TRI_voc_cid_t) const;
//////////////////////////////////////////////////////////////////////////////
/// @brief get the index by its identifier. Will either throw or
/// return a valid index. nullptr is impossible.
//////////////////////////////////////////////////////////////////////////////
arangodb::Index* getIndexByIdentifier(std::string const& collectionName,
std::string const& indexId);
private: private:
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -646,14 +654,6 @@ class Transaction {
std::vector<arangodb::Index*> indexesForCollection(std::string const&) const; std::vector<arangodb::Index*> indexesForCollection(std::string const&) const;
//////////////////////////////////////////////////////////////////////////////
/// @brief get the index by it's identifier. Will either throw or
/// return a valid index. nullptr is impossible.
//////////////////////////////////////////////////////////////////////////////
arangodb::Index* getIndexByIdentifier(std::string const& collectionName,
std::string const& indexId);
private: private:
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////

View File

@ -4006,7 +4006,8 @@ int TRI_document_collection_t::insertSecondaryIndexes(
// in case of no-memory, return immediately // in case of no-memory, return immediately
if (res == TRI_ERROR_OUT_OF_MEMORY) { if (res == TRI_ERROR_OUT_OF_MEMORY) {
return res; return res;
} else if (res != TRI_ERROR_NO_ERROR) { }
if (res != TRI_ERROR_NO_ERROR) {
if (res == TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED || if (res == TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED ||
result == TRI_ERROR_NO_ERROR) { result == TRI_ERROR_NO_ERROR) {
// "prefer" unique constraint violated // "prefer" unique constraint violated

View File

@ -3675,7 +3675,7 @@ function ahuacatlUpdateSuite () {
db._drop("UnitTestsAhuacatlEdge"); db._drop("UnitTestsAhuacatlEdge");
var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge"); var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");
assertQueryError(errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code, "FOR i IN 1..50 UPSERT { foo: 1 } INSERT { foo: 'bar'} UPDATE { } INTO @@cn", { "@cn": edge.name() }); assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 UPSERT { foo: 1 } INSERT { foo: 'bar'} UPDATE { } INTO @@cn", { "@cn": edge.name() });
assertEqual(0, edge.count()); assertEqual(0, edge.count());
db._drop("UnitTestsAhuacatlEdge"); db._drop("UnitTestsAhuacatlEdge");
@ -3689,7 +3689,7 @@ function ahuacatlUpdateSuite () {
db._drop("UnitTestsAhuacatlEdge"); db._drop("UnitTestsAhuacatlEdge");
var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge"); var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");
assertQueryError(errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code, "FOR i IN 1..50 UPSERT { foo: 1 } INSERT { _to: CONCAT('UnitTestsAhuacatlUpdate1/', TO_STRING(i)) } UPDATE { } INTO @@cn", { "@cn": edge.name() }); assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 UPSERT { foo: 1 } INSERT { _to: CONCAT('UnitTestsAhuacatlUpdate1/', TO_STRING(i)) } UPDATE { } INTO @@cn", { "@cn": edge.name() });
assertEqual(0, edge.count()); assertEqual(0, edge.count());
db._drop("UnitTestsAhuacatlEdge"); db._drop("UnitTestsAhuacatlEdge");
@ -3703,7 +3703,7 @@ function ahuacatlUpdateSuite () {
db._drop("UnitTestsAhuacatlEdge"); db._drop("UnitTestsAhuacatlEdge");
var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge"); var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");
assertQueryError(errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code, "FOR i IN 1..50 UPSERT { foo: 1 } INSERT { _from: CONCAT('UnitTestsAhuacatlUpdate1/', TO_STRING(i)) } UPDATE { } INTO @@cn", { "@cn": edge.name() }); assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 UPSERT { foo: 1 } INSERT { _from: CONCAT('UnitTestsAhuacatlUpdate1/', TO_STRING(i)) } UPDATE { } INTO @@cn", { "@cn": edge.name() });
assertEqual(0, edge.count()); assertEqual(0, edge.count());
db._drop("UnitTestsAhuacatlEdge"); db._drop("UnitTestsAhuacatlEdge");

View File

@ -441,7 +441,7 @@ function ahuacatlQueryOptimizerLimitTestSuite () {
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief check limit optimisation with index /// @brief check limit optimization with index
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testLimitFullCollectionHashIndex1 : function () { testLimitFullCollectionHashIndex1 : function () {

View File

@ -1051,7 +1051,7 @@ function ahuacatlQuerySimpleTestSuite () {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testOverflowExecutionInt: function () { testOverflowExecutionInt: function () {
assertEqual([ null ], getQueryResults("FOR l IN [ 33939359949454345354858882332 ] RETURN l * l * l * l * l * l * l * l * l * l * l")); assertEqual([ 0 ], getQueryResults("FOR l IN [ 33939359949454345354858882332 ] RETURN l * l * l * l * l * l * l * l * l * l * l"));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1067,7 +1067,7 @@ function ahuacatlQuerySimpleTestSuite () {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testUnderflowExecutionInt: function () { testUnderflowExecutionInt: function () {
assertEqual([ null ], getQueryResults("FOR l IN [ -33939359949454345354858882332 ] RETURN l * l * l * l * l * l * l * l * l * l * l")); assertEqual([ 0 ], getQueryResults("FOR l IN [ -33939359949454345354858882332 ] RETURN l * l * l * l * l * l * l * l * l * l * l"));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -270,77 +270,6 @@ function ahuacatlQueryCacheTestSuite () {
assertEqual([ ], result.json); assertEqual([ ], result.json);
}, },
////////////////////////////////////////////////////////////////////////////////
/// @brief test adding indexes
////////////////////////////////////////////////////////////////////////////////
testAddIndexCapConstraint : function () {
var query = "FOR doc IN @@collection SORT doc.value RETURN doc.value";
var result, i;
for (i = 1; i <= 5; ++i) {
c1.save({ value: i });
}
AQL_QUERY_CACHE_PROPERTIES({ mode: "on" });
result = AQL_EXECUTE(query, { "@collection": c1.name() });
assertFalse(result.cached);
assertEqual([ 1, 2, 3, 4, 5 ], result.json);
result = AQL_EXECUTE(query, { "@collection": c1.name() });
assertTrue(result.cached);
assertEqual([ 1, 2, 3, 4, 5 ], result.json);
c1.ensureCapConstraint(3);
result = AQL_EXECUTE(query, { "@collection": c1.name() });
assertFalse(result.cached);
assertEqual([ 3, 4, 5 ], result.json);
result = AQL_EXECUTE(query, { "@collection": c1.name() });
assertTrue(result.cached);
assertEqual([ 3, 4, 5 ], result.json);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test dropping indexes
////////////////////////////////////////////////////////////////////////////////
testDropIndexCapConstraint : function () {
var query = "FOR doc IN @@collection SORT doc.value RETURN doc.value";
var result, i;
c1.ensureCapConstraint(3);
for (i = 1; i <= 5; ++i) {
c1.save({ value: i });
}
AQL_QUERY_CACHE_PROPERTIES({ mode: "on" });
result = AQL_EXECUTE(query, { "@collection": c1.name() });
assertFalse(result.cached);
assertEqual([ 3, 4, 5 ], result.json);
result = AQL_EXECUTE(query, { "@collection": c1.name() });
assertTrue(result.cached);
assertEqual([ 3, 4, 5 ], result.json);
var indexes = c1.getIndexes();
assertEqual(2, indexes.length);
assertEqual("cap", indexes[1].type);
assertTrue(c1.dropIndex(indexes[1].id));
indexes = c1.getIndexes();
assertEqual(1, indexes.length);
result = AQL_EXECUTE(query, { "@collection": c1.name() });
assertFalse(result.cached);
assertEqual([ 3, 4, 5 ], result.json);
result = AQL_EXECUTE(query, { "@collection": c1.name() });
assertTrue(result.cached);
assertEqual([ 3, 4, 5 ], result.json);
},
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief test queries w/ parse error /// @brief test queries w/ parse error
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -112,8 +112,14 @@ v8::Handle<v8::Value> TRI_VPackToV8(v8::Isolate* isolate,
return v8::Null(isolate); return v8::Null(isolate);
case VPackValueType::Bool: case VPackValueType::Bool:
return v8::Boolean::New(isolate, slice.getBool()); return v8::Boolean::New(isolate, slice.getBool());
case VPackValueType::Double: case VPackValueType::Double: {
// convert NaN, +inf & -inf to null
double value = slice.getDouble();
if (std::isnan(value) || !std::isfinite(value) || value == HUGE_VAL || value == -HUGE_VAL) {
return v8::Null(isolate);
}
return v8::Number::New(isolate, slice.getDouble()); return v8::Number::New(isolate, slice.getDouble());
}
case VPackValueType::Int: case VPackValueType::Int:
return v8::Number::New(isolate, static_cast<double>(slice.getInt())); return v8::Number::New(isolate, static_cast<double>(slice.getInt()));
case VPackValueType::UInt: case VPackValueType::UInt: