mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'spdvpk' of github.com:arangodb/arangodb into spdvpk
This commit is contained in:
commit
16208d78f6
|
@ -902,6 +902,8 @@ AqlValue AqlValue::CreateFromBlocks(
|
|||
int AqlValue::Compare(arangodb::AqlTransaction* trx, AqlValue const& left,
|
||||
AqlValue const& right,
|
||||
bool compareUtf8) {
|
||||
VPackOptions* options = trx->transactionContext()->getVPackOptions();
|
||||
|
||||
AqlValue::AqlValueType const leftType = left.type();
|
||||
AqlValue::AqlValueType const rightType = right.type();
|
||||
|
||||
|
@ -914,7 +916,7 @@ int AqlValue::Compare(arangodb::AqlTransaction* trx, AqlValue const& left,
|
|||
VPackBuilder rightBuilder;
|
||||
right.toVelocyPack(trx, rightBuilder);
|
||||
|
||||
return arangodb::basics::VelocyPackHelper::compare(leftBuilder.slice(), rightBuilder.slice(), compareUtf8);
|
||||
return arangodb::basics::VelocyPackHelper::compare(leftBuilder.slice(), rightBuilder.slice(), compareUtf8, options);
|
||||
}
|
||||
// fall-through to other types intentional
|
||||
}
|
||||
|
@ -926,7 +928,7 @@ int AqlValue::Compare(arangodb::AqlTransaction* trx, AqlValue const& left,
|
|||
case VPACK_POINTER:
|
||||
case VPACK_INLINE:
|
||||
case VPACK_EXTERNAL: {
|
||||
return arangodb::basics::VelocyPackHelper::compare(left.slice(), right.slice(), compareUtf8);
|
||||
return arangodb::basics::VelocyPackHelper::compare(left.slice(), right.slice(), compareUtf8, options);
|
||||
}
|
||||
case DOCVEC: {
|
||||
// use lexicographic ordering of AqlValues regardless of block,
|
||||
|
|
|
@ -1946,7 +1946,8 @@ AqlValue Functions::SortedUnique(arangodb::aql::Query* query,
|
|||
AqlValueMaterializer materializer(trx);
|
||||
VPackSlice slice = materializer.slice(value);
|
||||
|
||||
std::set<VPackSlice, arangodb::basics::VelocyPackHelper::VPackLess<true>> values;
|
||||
arangodb::basics::VelocyPackHelper::VPackLess<true> less(trx->transactionContext()->getVPackOptions(), &slice, &slice);
|
||||
std::set<VPackSlice, arangodb::basics::VelocyPackHelper::VPackLess<true>> values(less);
|
||||
for (auto const& it : VPackArrayIterator(slice)) {
|
||||
if (!it.isNone()) {
|
||||
values.insert(it);
|
||||
|
|
|
@ -200,142 +200,6 @@ void ModificationBlock::handleResult(int code, bool ignoreErrors,
|
|||
THROW_ARANGO_EXCEPTION(code);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief execute an update or replace document modification operation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlItemBlock* ModificationBlock::modify(std::vector<AqlItemBlock*>& blocks,
|
||||
bool isReplace) {
|
||||
size_t const count = countBlocksRows(blocks);
|
||||
|
||||
if (count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<AqlItemBlock> result;
|
||||
auto ep = static_cast<UpdateNode const*>(getPlanNode());
|
||||
auto it = ep->getRegisterPlan()->varInfo.find(ep->_inDocVariable->id);
|
||||
TRI_ASSERT(it != ep->getRegisterPlan()->varInfo.end());
|
||||
RegisterId const docRegisterId = it->second.registerId;
|
||||
RegisterId keyRegisterId = 0; // default initialization
|
||||
|
||||
bool const ignoreDocumentNotFound = ep->getOptions().ignoreDocumentNotFound;
|
||||
bool const producesOutput =
|
||||
(ep->_outVariableOld != nullptr || ep->_outVariableNew != nullptr);
|
||||
|
||||
bool const hasKeyVariable = (ep->_inKeyVariable != nullptr);
|
||||
std::string errorMessage;
|
||||
VPackBuilder keyBuilder;
|
||||
VPackBuilder object;
|
||||
|
||||
if (hasKeyVariable) {
|
||||
it = ep->getRegisterPlan()->varInfo.find(ep->_inKeyVariable->id);
|
||||
TRI_ASSERT(it != ep->getRegisterPlan()->varInfo.end());
|
||||
keyRegisterId = it->second.registerId;
|
||||
}
|
||||
|
||||
result.reset(new AqlItemBlock(
|
||||
count,
|
||||
getPlanNode()->getRegisterPlan()->nrRegs[getPlanNode()->getDepth()]));
|
||||
|
||||
OperationOptions options;
|
||||
options.silent = !producesOutput;
|
||||
options.waitForSync = ep->_options.waitForSync;
|
||||
options.mergeObjects = ep->_options.mergeObjects;
|
||||
options.keepNull = !ep->_options.nullMeansRemove;
|
||||
options.returnOld = (producesOutput && ep->_outVariableOld != nullptr);
|
||||
options.returnNew = (producesOutput && ep->_outVariableNew != nullptr);
|
||||
options.ignoreRevs = true;
|
||||
|
||||
// loop over all blocks
|
||||
size_t dstRow = 0;
|
||||
for (auto it = blocks.begin(); it != blocks.end(); ++it) {
|
||||
auto* res = (*it); // This is intentionally a copy!
|
||||
|
||||
throwIfKilled(); // check if we were aborted
|
||||
|
||||
size_t const n = res->size();
|
||||
|
||||
// loop over the complete block
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
AqlValue const& a = res->getValueReference(i, docRegisterId);
|
||||
|
||||
int errorCode = TRI_ERROR_NO_ERROR;
|
||||
std::string key;
|
||||
|
||||
if (a.isObject()) {
|
||||
// value is an object
|
||||
if (hasKeyVariable) {
|
||||
// seperate key specification
|
||||
AqlValue const& k = res->getValueReference(i, keyRegisterId);
|
||||
errorCode = extractKey(k, key);
|
||||
} else {
|
||||
errorCode = extractKey(a, key);
|
||||
}
|
||||
} else {
|
||||
errorCode = TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID;
|
||||
errorMessage += std::string("expecting 'Object', got: ") +
|
||||
a.slice().typeName() + std::string(" while handling: ") +
|
||||
_exeNode->getTypeString();
|
||||
}
|
||||
|
||||
if (errorCode == TRI_ERROR_NO_ERROR) {
|
||||
keyBuilder.clear();
|
||||
keyBuilder.openObject();
|
||||
keyBuilder.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(key));
|
||||
keyBuilder.close();
|
||||
|
||||
VPackSlice toUpdate;
|
||||
|
||||
if (hasKeyVariable) {
|
||||
object = VPackCollection::merge(a.slice(), keyBuilder.slice(), false, false);
|
||||
toUpdate = object.slice();
|
||||
}
|
||||
else {
|
||||
// use original slice for updating
|
||||
toUpdate = a.slice();
|
||||
}
|
||||
|
||||
// fetch old revision
|
||||
OperationResult opRes;
|
||||
if (isReplace) {
|
||||
opRes = _trx->replace(_collection->name, toUpdate, options);
|
||||
} else {
|
||||
opRes = _trx->update(_collection->name, toUpdate, options);
|
||||
}
|
||||
errorCode = opRes.code;
|
||||
|
||||
if (producesOutput && errorCode == TRI_ERROR_NO_ERROR) {
|
||||
if (ep->_outVariableOld != nullptr) {
|
||||
// store $OLD
|
||||
result->setValue(dstRow, _outRegOld, AqlValue(opRes.slice().get("old")));
|
||||
}
|
||||
if (ep->_outVariableNew != nullptr) {
|
||||
// store $NEW
|
||||
result->setValue(dstRow, _outRegNew, AqlValue(opRes.slice().get("new")));
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCode == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND && _isDBServer &&
|
||||
ignoreDocumentNotFound) {
|
||||
// Ignore document not found on the DBserver:
|
||||
errorCode = TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
handleResult(errorCode, ep->_options.ignoreErrors, &errorMessage);
|
||||
++dstRow;
|
||||
}
|
||||
// done with a block
|
||||
|
||||
// now free it already
|
||||
(*it) = nullptr;
|
||||
delete res;
|
||||
}
|
||||
|
||||
return result.release();
|
||||
}
|
||||
|
||||
RemoveBlock::RemoveBlock(ExecutionEngine* engine, RemoveNode const* ep)
|
||||
: ModificationBlock(engine, ep) {}
|
||||
|
||||
|
@ -522,7 +386,129 @@ UpdateBlock::UpdateBlock(ExecutionEngine* engine, UpdateNode const* ep)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlItemBlock* UpdateBlock::work(std::vector<AqlItemBlock*>& blocks) {
|
||||
return modify(blocks, false);
|
||||
size_t const count = countBlocksRows(blocks);
|
||||
|
||||
if (count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<AqlItemBlock> result;
|
||||
auto ep = static_cast<UpdateNode const*>(getPlanNode());
|
||||
auto it = ep->getRegisterPlan()->varInfo.find(ep->_inDocVariable->id);
|
||||
TRI_ASSERT(it != ep->getRegisterPlan()->varInfo.end());
|
||||
RegisterId const docRegisterId = it->second.registerId;
|
||||
RegisterId keyRegisterId = 0; // default initialization
|
||||
|
||||
bool const ignoreDocumentNotFound = ep->getOptions().ignoreDocumentNotFound;
|
||||
bool const producesOutput =
|
||||
(ep->_outVariableOld != nullptr || ep->_outVariableNew != nullptr);
|
||||
|
||||
bool const hasKeyVariable = (ep->_inKeyVariable != nullptr);
|
||||
std::string errorMessage;
|
||||
VPackBuilder keyBuilder;
|
||||
VPackBuilder object;
|
||||
|
||||
if (hasKeyVariable) {
|
||||
it = ep->getRegisterPlan()->varInfo.find(ep->_inKeyVariable->id);
|
||||
TRI_ASSERT(it != ep->getRegisterPlan()->varInfo.end());
|
||||
keyRegisterId = it->second.registerId;
|
||||
}
|
||||
|
||||
result.reset(new AqlItemBlock(
|
||||
count,
|
||||
getPlanNode()->getRegisterPlan()->nrRegs[getPlanNode()->getDepth()]));
|
||||
|
||||
OperationOptions options;
|
||||
options.silent = !producesOutput;
|
||||
options.waitForSync = ep->_options.waitForSync;
|
||||
options.mergeObjects = ep->_options.mergeObjects;
|
||||
options.keepNull = !ep->_options.nullMeansRemove;
|
||||
options.returnOld = (producesOutput && ep->_outVariableOld != nullptr);
|
||||
options.returnNew = (producesOutput && ep->_outVariableNew != nullptr);
|
||||
options.ignoreRevs = true;
|
||||
|
||||
// loop over all blocks
|
||||
size_t dstRow = 0;
|
||||
for (auto it = blocks.begin(); it != blocks.end(); ++it) {
|
||||
auto* res = (*it); // This is intentionally a copy!
|
||||
|
||||
throwIfKilled(); // check if we were aborted
|
||||
|
||||
size_t const n = res->size();
|
||||
|
||||
// loop over the complete block
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
AqlValue const& a = res->getValueReference(i, docRegisterId);
|
||||
|
||||
int errorCode = TRI_ERROR_NO_ERROR;
|
||||
std::string key;
|
||||
|
||||
if (a.isObject()) {
|
||||
// value is an object
|
||||
if (hasKeyVariable) {
|
||||
// seperate key specification
|
||||
AqlValue const& k = res->getValueReference(i, keyRegisterId);
|
||||
errorCode = extractKey(k, key);
|
||||
} else {
|
||||
errorCode = extractKey(a, key);
|
||||
}
|
||||
} else {
|
||||
errorCode = TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID;
|
||||
errorMessage += std::string("expecting 'Object', got: ") +
|
||||
a.slice().typeName() + std::string(" while handling: ") +
|
||||
_exeNode->getTypeString();
|
||||
}
|
||||
|
||||
if (errorCode == TRI_ERROR_NO_ERROR) {
|
||||
keyBuilder.clear();
|
||||
keyBuilder.openObject();
|
||||
keyBuilder.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(key));
|
||||
keyBuilder.close();
|
||||
|
||||
VPackSlice toUpdate;
|
||||
|
||||
if (hasKeyVariable) {
|
||||
object = VPackCollection::merge(a.slice(), keyBuilder.slice(), false, false);
|
||||
toUpdate = object.slice();
|
||||
}
|
||||
else {
|
||||
// use original slice for updating
|
||||
toUpdate = a.slice();
|
||||
}
|
||||
|
||||
// fetch old revision
|
||||
OperationResult opRes = _trx->update(_collection->name, toUpdate, options);
|
||||
errorCode = opRes.code;
|
||||
|
||||
if (producesOutput && errorCode == TRI_ERROR_NO_ERROR) {
|
||||
if (ep->_outVariableOld != nullptr) {
|
||||
// store $OLD
|
||||
result->setValue(dstRow, _outRegOld, AqlValue(opRes.slice().get("old")));
|
||||
}
|
||||
if (ep->_outVariableNew != nullptr) {
|
||||
// store $NEW
|
||||
result->setValue(dstRow, _outRegNew, AqlValue(opRes.slice().get("new")));
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCode == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND && _isDBServer &&
|
||||
ignoreDocumentNotFound) {
|
||||
// Ignore document not found on the DBserver:
|
||||
errorCode = TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
handleResult(errorCode, ep->_options.ignoreErrors, &errorMessage);
|
||||
++dstRow;
|
||||
}
|
||||
// done with a block
|
||||
|
||||
// now free it already
|
||||
(*it) = nullptr;
|
||||
delete res;
|
||||
}
|
||||
|
||||
return result.release();
|
||||
}
|
||||
|
||||
UpsertBlock::UpsertBlock(ExecutionEngine* engine, UpsertNode const* ep)
|
||||
|
@ -668,5 +654,127 @@ ReplaceBlock::ReplaceBlock(ExecutionEngine* engine, ReplaceNode const* ep)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlItemBlock* ReplaceBlock::work(std::vector<AqlItemBlock*>& blocks) {
|
||||
return modify(blocks, true);
|
||||
size_t const count = countBlocksRows(blocks);
|
||||
|
||||
if (count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<AqlItemBlock> result;
|
||||
auto ep = static_cast<ReplaceNode const*>(getPlanNode());
|
||||
auto it = ep->getRegisterPlan()->varInfo.find(ep->_inDocVariable->id);
|
||||
TRI_ASSERT(it != ep->getRegisterPlan()->varInfo.end());
|
||||
RegisterId const docRegisterId = it->second.registerId;
|
||||
RegisterId keyRegisterId = 0; // default initialization
|
||||
|
||||
bool const ignoreDocumentNotFound = ep->getOptions().ignoreDocumentNotFound;
|
||||
bool const producesOutput =
|
||||
(ep->_outVariableOld != nullptr || ep->_outVariableNew != nullptr);
|
||||
|
||||
bool const hasKeyVariable = (ep->_inKeyVariable != nullptr);
|
||||
std::string errorMessage;
|
||||
VPackBuilder keyBuilder;
|
||||
VPackBuilder object;
|
||||
|
||||
if (hasKeyVariable) {
|
||||
it = ep->getRegisterPlan()->varInfo.find(ep->_inKeyVariable->id);
|
||||
TRI_ASSERT(it != ep->getRegisterPlan()->varInfo.end());
|
||||
keyRegisterId = it->second.registerId;
|
||||
}
|
||||
|
||||
result.reset(new AqlItemBlock(
|
||||
count,
|
||||
getPlanNode()->getRegisterPlan()->nrRegs[getPlanNode()->getDepth()]));
|
||||
|
||||
OperationOptions options;
|
||||
options.silent = !producesOutput;
|
||||
options.waitForSync = ep->_options.waitForSync;
|
||||
options.mergeObjects = ep->_options.mergeObjects;
|
||||
options.keepNull = !ep->_options.nullMeansRemove;
|
||||
options.returnOld = (producesOutput && ep->_outVariableOld != nullptr);
|
||||
options.returnNew = (producesOutput && ep->_outVariableNew != nullptr);
|
||||
options.ignoreRevs = true;
|
||||
|
||||
// loop over all blocks
|
||||
size_t dstRow = 0;
|
||||
for (auto it = blocks.begin(); it != blocks.end(); ++it) {
|
||||
auto* res = (*it); // This is intentionally a copy!
|
||||
|
||||
throwIfKilled(); // check if we were aborted
|
||||
|
||||
size_t const n = res->size();
|
||||
|
||||
// loop over the complete block
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
AqlValue const& a = res->getValueReference(i, docRegisterId);
|
||||
|
||||
int errorCode = TRI_ERROR_NO_ERROR;
|
||||
std::string key;
|
||||
|
||||
if (a.isObject()) {
|
||||
// value is an object
|
||||
if (hasKeyVariable) {
|
||||
// seperate key specification
|
||||
AqlValue const& k = res->getValueReference(i, keyRegisterId);
|
||||
errorCode = extractKey(k, key);
|
||||
} else {
|
||||
errorCode = extractKey(a, key);
|
||||
}
|
||||
} else {
|
||||
errorCode = TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID;
|
||||
errorMessage += std::string("expecting 'Object', got: ") +
|
||||
a.slice().typeName() + std::string(" while handling: ") +
|
||||
_exeNode->getTypeString();
|
||||
}
|
||||
|
||||
if (errorCode == TRI_ERROR_NO_ERROR) {
|
||||
keyBuilder.clear();
|
||||
keyBuilder.openObject();
|
||||
keyBuilder.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(key));
|
||||
keyBuilder.close();
|
||||
|
||||
VPackSlice toUpdate;
|
||||
|
||||
if (hasKeyVariable) {
|
||||
object = VPackCollection::merge(a.slice(), keyBuilder.slice(), false, false);
|
||||
toUpdate = object.slice();
|
||||
}
|
||||
else {
|
||||
// use original slice for updating
|
||||
toUpdate = a.slice();
|
||||
}
|
||||
|
||||
// fetch old revision
|
||||
OperationResult opRes = _trx->replace(_collection->name, toUpdate, options);
|
||||
errorCode = opRes.code;
|
||||
|
||||
if (producesOutput && errorCode == TRI_ERROR_NO_ERROR) {
|
||||
if (ep->_outVariableOld != nullptr) {
|
||||
// store $OLD
|
||||
result->setValue(dstRow, _outRegOld, AqlValue(opRes.slice().get("old")));
|
||||
}
|
||||
if (ep->_outVariableNew != nullptr) {
|
||||
// store $NEW
|
||||
result->setValue(dstRow, _outRegNew, AqlValue(opRes.slice().get("new")));
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCode == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND && _isDBServer &&
|
||||
ignoreDocumentNotFound) {
|
||||
// Ignore document not found on the DBserver:
|
||||
errorCode = TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
handleResult(errorCode, ep->_options.ignoreErrors, &errorMessage);
|
||||
++dstRow;
|
||||
}
|
||||
// done with a block
|
||||
|
||||
// now free it already
|
||||
(*it) = nullptr;
|
||||
delete res;
|
||||
}
|
||||
|
||||
return result.release();
|
||||
}
|
||||
|
|
|
@ -65,24 +65,12 @@ class ModificationBlock : public ExecutionBlock {
|
|||
|
||||
int extractKey(AqlValue const&, std::string&);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check whether a shard key was set when it must not be set
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool isShardKeyError(struct TRI_json_t const*) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief process the result of a data-modification operation
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void handleResult(int, bool, std::string const* errorMessage = nullptr);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief execute an update or replace document modification operation
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlItemBlock* modify(std::vector<AqlItemBlock*>& blocks, bool isReplace);
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief output register ($OLD)
|
||||
|
|
|
@ -1799,7 +1799,8 @@ static void ModifyVocbase(TRI_voc_document_operation_e operation,
|
|||
|
||||
VPackBuilder updateBuilder;
|
||||
|
||||
{ VPackObjectBuilder guard(&updateBuilder);
|
||||
{
|
||||
VPackObjectBuilder guard(&updateBuilder);
|
||||
int res = V8ToVPackNoKeyRevId(isolate, updateBuilder, args[1]);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_V8_THROW_EXCEPTION(res);
|
||||
|
|
|
@ -3408,6 +3408,12 @@ int TRI_document_collection_t::update(Transaction* trx,
|
|||
}
|
||||
}
|
||||
|
||||
if (newSlice.length() <= 1) {
|
||||
// no need to do anything
|
||||
*mptr = *oldHeader;
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// merge old and new values
|
||||
TransactionBuilderLeaser builder(trx);
|
||||
if (options.recoveryMarker == nullptr) {
|
||||
|
|
|
@ -1965,7 +1965,7 @@ function ahuacatlInsertSuite () {
|
|||
db._drop("UnitTestsAhuacatlEdge");
|
||||
var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");
|
||||
|
||||
assertQueryError(errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code, "FOR i IN 1..50 INSERT { } INTO @@cn", { "@cn": edge.name() });
|
||||
assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 INSERT { } INTO @@cn", { "@cn": edge.name() });
|
||||
assertEqual(0, edge.count());
|
||||
|
||||
db._drop("UnitTestsAhuacatlEdge");
|
||||
|
@ -1979,7 +1979,7 @@ function ahuacatlInsertSuite () {
|
|||
db._drop("UnitTestsAhuacatlEdge");
|
||||
var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");
|
||||
|
||||
assertQueryError(errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code, "FOR i IN 1..50 INSERT { } INTO @@cn LET inserted = NEW RETURN inserted", { "@cn": edge.name() });
|
||||
assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 INSERT { } INTO @@cn LET inserted = NEW RETURN inserted", { "@cn": edge.name() });
|
||||
assertEqual(0, edge.count());
|
||||
|
||||
db._drop("UnitTestsAhuacatlEdge");
|
||||
|
@ -1993,7 +1993,7 @@ function ahuacatlInsertSuite () {
|
|||
db._drop("UnitTestsAhuacatlEdge");
|
||||
var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");
|
||||
|
||||
assertQueryError(errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code, "FOR i IN 1..50 INSERT { _to: CONCAT('UnitTestsAhuacatlInsert1/', TO_STRING(i)) } INTO @@cn", { "@cn": edge.name() });
|
||||
assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 INSERT { _to: CONCAT('UnitTestsAhuacatlInsert1/', TO_STRING(i)) } INTO @@cn", { "@cn": edge.name() });
|
||||
assertEqual(0, edge.count());
|
||||
|
||||
db._drop("UnitTestsAhuacatlEdge");
|
||||
|
@ -2007,7 +2007,7 @@ function ahuacatlInsertSuite () {
|
|||
db._drop("UnitTestsAhuacatlEdge");
|
||||
var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");
|
||||
|
||||
assertQueryError(errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code, "FOR i IN 1..50 INSERT { _to: CONCAT('UnitTestsAhuacatlInsert1/', TO_STRING(i)) } INTO @@cn LET inserted = NEW RETURN inserted", { "@cn": edge.name() });
|
||||
assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 INSERT { _to: CONCAT('UnitTestsAhuacatlInsert1/', TO_STRING(i)) } INTO @@cn LET inserted = NEW RETURN inserted", { "@cn": edge.name() });
|
||||
assertEqual(0, edge.count());
|
||||
|
||||
db._drop("UnitTestsAhuacatlEdge");
|
||||
|
@ -2021,7 +2021,7 @@ function ahuacatlInsertSuite () {
|
|||
db._drop("UnitTestsAhuacatlEdge");
|
||||
var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");
|
||||
|
||||
assertQueryError(errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code, "FOR i IN 1..50 INSERT { _from: CONCAT('UnitTestsAhuacatlInsert1/', TO_STRING(i)) } INTO @@cn", { "@cn": edge.name() });
|
||||
assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 INSERT { _from: CONCAT('UnitTestsAhuacatlInsert1/', TO_STRING(i)) } INTO @@cn", { "@cn": edge.name() });
|
||||
assertEqual(0, edge.count());
|
||||
|
||||
db._drop("UnitTestsAhuacatlEdge");
|
||||
|
@ -2035,7 +2035,7 @@ function ahuacatlInsertSuite () {
|
|||
db._drop("UnitTestsAhuacatlEdge");
|
||||
var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");
|
||||
|
||||
assertQueryError(errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code, "FOR i IN 1..50 INSERT { _from: CONCAT('UnitTestsAhuacatlInsert1/', TO_STRING(i)) } INTO @@cn LET inserted = NEW RETURN inserted", { "@cn": edge.name() });
|
||||
assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 INSERT { _from: CONCAT('UnitTestsAhuacatlInsert1/', TO_STRING(i)) } INTO @@cn LET inserted = NEW RETURN inserted", { "@cn": edge.name() });
|
||||
assertEqual(0, edge.count());
|
||||
|
||||
db._drop("UnitTestsAhuacatlEdge");
|
||||
|
|
|
@ -196,6 +196,8 @@ static int TypeWeight(VPackSlice const& slice) {
|
|||
case VPackValueType::SmallInt:
|
||||
return 2;
|
||||
case VPackValueType::String:
|
||||
case VPackValueType::Custom:
|
||||
// custom type is used for id
|
||||
return 3;
|
||||
case VPackValueType::Array:
|
||||
return 4;
|
||||
|
@ -374,24 +376,19 @@ static bool PrintVelocyPack(int fd, VPackSlice const& slice,
|
|||
bool VelocyPackHelper::velocyPackToFile(char const* filename,
|
||||
VPackSlice const& slice,
|
||||
bool syncFile) {
|
||||
char* tmp = TRI_Concatenate2String(filename, ".tmp");
|
||||
|
||||
if (tmp == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::string const tmp = std::string(filename) + ".tmp";
|
||||
|
||||
// remove a potentially existing temporary file
|
||||
if (TRI_ExistsFile(tmp)) {
|
||||
TRI_UnlinkFile(tmp);
|
||||
if (TRI_ExistsFile(tmp.c_str())) {
|
||||
TRI_UnlinkFile(tmp.c_str());
|
||||
}
|
||||
|
||||
int fd = TRI_CREATE(tmp, O_CREAT | O_TRUNC | O_EXCL | O_RDWR | TRI_O_CLOEXEC,
|
||||
int fd = TRI_CREATE(tmp.c_str(), O_CREAT | O_TRUNC | O_EXCL | O_RDWR | TRI_O_CLOEXEC,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
|
||||
if (fd < 0) {
|
||||
TRI_set_errno(TRI_ERROR_SYS_ERROR);
|
||||
LOG(ERR) << "cannot create json file '" << tmp << "': " << TRI_LAST_ERROR_STR;
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -399,8 +396,7 @@ bool VelocyPackHelper::velocyPackToFile(char const* filename,
|
|||
TRI_CLOSE(fd);
|
||||
TRI_set_errno(TRI_ERROR_SYS_ERROR);
|
||||
LOG(ERR) << "cannot write to json file '" << tmp << "': " << TRI_LAST_ERROR_STR;
|
||||
TRI_UnlinkFile(tmp);
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp);
|
||||
TRI_UnlinkFile(tmp.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -411,8 +407,7 @@ bool VelocyPackHelper::velocyPackToFile(char const* filename,
|
|||
TRI_CLOSE(fd);
|
||||
TRI_set_errno(TRI_ERROR_SYS_ERROR);
|
||||
LOG(ERR) << "cannot sync saved json '" << tmp << "': " << TRI_LAST_ERROR_STR;
|
||||
TRI_UnlinkFile(tmp);
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp);
|
||||
TRI_UnlinkFile(tmp.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -422,29 +417,26 @@ bool VelocyPackHelper::velocyPackToFile(char const* filename,
|
|||
if (res < 0) {
|
||||
TRI_set_errno(TRI_ERROR_SYS_ERROR);
|
||||
LOG(ERR) << "cannot close saved file '" << tmp << "': " << TRI_LAST_ERROR_STR;
|
||||
TRI_UnlinkFile(tmp);
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp);
|
||||
TRI_UnlinkFile(tmp.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
res = TRI_RenameFile(tmp, filename);
|
||||
res = TRI_RenameFile(tmp.c_str(), filename);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_set_errno(res);
|
||||
LOG(ERR) << "cannot rename saved file '" << tmp << "' to '" << filename << "': " << TRI_LAST_ERROR_STR;
|
||||
TRI_UnlinkFile(tmp);
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp);
|
||||
TRI_UnlinkFile(tmp.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int VelocyPackHelper::compare(VPackSlice const& lhs, VPackSlice const& rhs,
|
||||
bool useUTF8) {
|
||||
bool useUTF8, VPackOptions const* options,
|
||||
VPackSlice const* lhsBase, VPackSlice const* rhsBase) {
|
||||
{
|
||||
int lWeight = TypeWeight(lhs);
|
||||
int rWeight = TypeWeight(rhs);
|
||||
|
@ -499,12 +491,41 @@ int VelocyPackHelper::compare(VPackSlice const& lhs, VPackSlice const& rhs,
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
case VPackValueType::Custom:
|
||||
case VPackValueType::String: {
|
||||
int res;
|
||||
std::string lhsString;
|
||||
VPackValueLength nl;
|
||||
char const* left;
|
||||
if (lhs.isCustom()) {
|
||||
if (lhsBase == nullptr || options == nullptr || options->customTypeHandler == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
||||
"Could not extract custom attribute.");
|
||||
}
|
||||
lhsString.assign(options->customTypeHandler->toString(lhs, options, *lhsBase));
|
||||
left = lhsString.c_str();
|
||||
nl = lhsString.size();
|
||||
} else {
|
||||
left = lhs.getString(nl);
|
||||
}
|
||||
TRI_ASSERT(left != nullptr);
|
||||
|
||||
std::string rhsString;
|
||||
VPackValueLength nr;
|
||||
char const* left = lhs.getString(nl);
|
||||
char const* right = rhs.getString(nr);
|
||||
char const* right;
|
||||
if (rhs.isCustom()) {
|
||||
if (rhsBase == nullptr || options == nullptr || options->customTypeHandler == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
||||
"Could not extract custom attribute.");
|
||||
}
|
||||
rhsString.assign(options->customTypeHandler->toString(rhs, options, *rhsBase));
|
||||
right = rhsString.c_str();
|
||||
nr = rhsString.size();
|
||||
} else {
|
||||
right = rhs.getString(nr);
|
||||
}
|
||||
TRI_ASSERT(right != nullptr);
|
||||
|
||||
int res;
|
||||
if (useUTF8) {
|
||||
res = TRI_compare_utf8(left, nl, right, nr);
|
||||
} else {
|
||||
|
@ -513,7 +534,8 @@ int VelocyPackHelper::compare(VPackSlice const& lhs, VPackSlice const& rhs,
|
|||
}
|
||||
if (res < 0) {
|
||||
return -1;
|
||||
} else if (res > 0) {
|
||||
}
|
||||
if (res > 0) {
|
||||
return 1;
|
||||
}
|
||||
// res == 0
|
||||
|
@ -537,7 +559,7 @@ int VelocyPackHelper::compare(VPackSlice const& lhs, VPackSlice const& rhs,
|
|||
rhsValue = rhs.at(i);
|
||||
}
|
||||
|
||||
int result = compare(lhsValue, rhsValue, useUTF8);
|
||||
int result = compare(lhsValue, rhsValue, useUTF8, options, &lhs, &rhs);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
@ -558,7 +580,7 @@ int VelocyPackHelper::compare(VPackSlice const& lhs, VPackSlice const& rhs,
|
|||
rhsValue = rhs.get(key);
|
||||
}
|
||||
|
||||
int result = compare(lhsValue, rhsValue, useUTF8);
|
||||
int result = compare(lhsValue, rhsValue, useUTF8, options, &lhs, &rhs);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
@ -595,9 +617,8 @@ double VelocyPackHelper::toDouble(VPackSlice const& slice, bool& failed) {
|
|||
case VPackValueType::UInt:
|
||||
case VPackValueType::SmallInt:
|
||||
return slice.getNumericValue<double>();
|
||||
case VPackValueType::String:
|
||||
{
|
||||
std::string tmp = slice.copyString();
|
||||
case VPackValueType::String: {
|
||||
std::string tmp(slice.copyString());
|
||||
try {
|
||||
// try converting string to number
|
||||
return std::stod(tmp);
|
||||
|
@ -609,8 +630,7 @@ double VelocyPackHelper::toDouble(VPackSlice const& slice, bool& failed) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case VPackValueType::Array:
|
||||
{
|
||||
case VPackValueType::Array: {
|
||||
VPackValueLength const n = slice.length();
|
||||
|
||||
if (n == 0) {
|
||||
|
@ -642,8 +662,7 @@ arangodb::LoggerStream& operator<< (arangodb::LoggerStream& logger,
|
|||
bool longer = sliceStr.size() > cutoff;
|
||||
if (longer) {
|
||||
logger << sliceStr.substr(cutoff) << "...";
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
logger << sliceStr;
|
||||
}
|
||||
return logger;
|
||||
|
|
|
@ -75,10 +75,19 @@ class VelocyPackHelper {
|
|||
|
||||
template <bool useUtf8>
|
||||
struct VPackLess {
|
||||
VPackLess(arangodb::velocypack::Options const* options = &arangodb::velocypack::Options::Defaults,
|
||||
arangodb::velocypack::Slice const* lhsBase = nullptr,
|
||||
arangodb::velocypack::Slice const* rhsBase = nullptr)
|
||||
: options(options), lhsBase(lhsBase), rhsBase(rhsBase) {}
|
||||
|
||||
inline bool operator()(arangodb::velocypack::Slice const& lhs,
|
||||
arangodb::velocypack::Slice const& rhs) const {
|
||||
return VelocyPackHelper::compare(lhs, rhs, useUtf8) < 0;
|
||||
return VelocyPackHelper::compare(lhs, rhs, useUtf8, options, lhsBase, rhsBase) < 0;
|
||||
}
|
||||
|
||||
arangodb::velocypack::Options const* options;
|
||||
arangodb::velocypack::Slice const* lhsBase;
|
||||
arangodb::velocypack::Slice const* rhsBase;
|
||||
};
|
||||
|
||||
struct AttributeSorter {
|
||||
|
@ -193,7 +202,11 @@ class VelocyPackHelper {
|
|||
/// @brief Compares two VelocyPack slices
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int compare(VPackSlice const&, VPackSlice const&, bool);
|
||||
static int compare(arangodb::velocypack::Slice const& lhs,
|
||||
arangodb::velocypack::Slice const& rhs,
|
||||
bool useUTF8, arangodb::velocypack::Options const* options = &arangodb::velocypack::Options::Defaults,
|
||||
arangodb::velocypack::Slice const* lhsBase = nullptr,
|
||||
arangodb::velocypack::Slice const* rhsBase = nullptr);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Merges two VelocyPack Slices
|
||||
|
|
Loading…
Reference in New Issue