mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2
This commit is contained in:
commit
fb1d69bbae
|
@ -234,15 +234,21 @@ AstNode* Ast::createNodeInsert (AstNode const* expression,
|
||||||
AstNode* Ast::createNodeUpdate (AstNode const* keyExpression,
|
AstNode* Ast::createNodeUpdate (AstNode const* keyExpression,
|
||||||
AstNode const* docExpression,
|
AstNode const* docExpression,
|
||||||
AstNode const* collection,
|
AstNode const* collection,
|
||||||
AstNode* options) {
|
AstNode const* options) {
|
||||||
AstNode* node = createNode(NODE_TYPE_UPDATE);
|
AstNode* node = createNode(NODE_TYPE_UPDATE);
|
||||||
|
|
||||||
|
if (options == nullptr) {
|
||||||
|
// no options given. now use default options
|
||||||
|
options = &NopNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->addMember(options);
|
||||||
node->addMember(collection);
|
node->addMember(collection);
|
||||||
node->addMember(docExpression);
|
node->addMember(docExpression);
|
||||||
|
|
||||||
if (keyExpression != nullptr) {
|
if (keyExpression != nullptr) {
|
||||||
node->addMember(keyExpression);
|
node->addMember(keyExpression);
|
||||||
}
|
}
|
||||||
// TODO: handle options
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -254,15 +260,21 @@ AstNode* Ast::createNodeUpdate (AstNode const* keyExpression,
|
||||||
AstNode* Ast::createNodeReplace (AstNode const* keyExpression,
|
AstNode* Ast::createNodeReplace (AstNode const* keyExpression,
|
||||||
AstNode const* docExpression,
|
AstNode const* docExpression,
|
||||||
AstNode const* collection,
|
AstNode const* collection,
|
||||||
AstNode* options) {
|
AstNode const* options) {
|
||||||
AstNode* node = createNode(NODE_TYPE_REPLACE);
|
AstNode* node = createNode(NODE_TYPE_REPLACE);
|
||||||
|
|
||||||
|
if (options == nullptr) {
|
||||||
|
// no options given. now use default options
|
||||||
|
options = &NopNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->addMember(options);
|
||||||
node->addMember(collection);
|
node->addMember(collection);
|
||||||
node->addMember(docExpression);
|
node->addMember(docExpression);
|
||||||
|
|
||||||
if (keyExpression != nullptr) {
|
if (keyExpression != nullptr) {
|
||||||
node->addMember(keyExpression);
|
node->addMember(keyExpression);
|
||||||
}
|
}
|
||||||
// TODO: handle options
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,7 @@ namespace triagens {
|
||||||
AstNode* createNodeUpdate (AstNode const*,
|
AstNode* createNodeUpdate (AstNode const*,
|
||||||
AstNode const*,
|
AstNode const*,
|
||||||
AstNode const*,
|
AstNode const*,
|
||||||
AstNode*);
|
AstNode const*);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create an AST replace node
|
/// @brief create an AST replace node
|
||||||
|
@ -271,7 +271,7 @@ namespace triagens {
|
||||||
AstNode* createNodeReplace (AstNode const*,
|
AstNode* createNodeReplace (AstNode const*,
|
||||||
AstNode const*,
|
AstNode const*,
|
||||||
AstNode const*,
|
AstNode const*,
|
||||||
AstNode*);
|
AstNode const*);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create an AST collect node
|
/// @brief create an AST collect node
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include "Aql/ExecutionBlock.h"
|
#include "Aql/ExecutionBlock.h"
|
||||||
#include "Basics/StringUtils.h"
|
#include "Basics/StringUtils.h"
|
||||||
|
#include "Basics/json-utilities.h"
|
||||||
#include "Utils/Exception.h"
|
#include "Utils/Exception.h"
|
||||||
#include "VocBase/vocbase.h"
|
#include "VocBase/vocbase.h"
|
||||||
|
|
||||||
|
@ -1877,24 +1878,24 @@ AqlItemBlock* ReturnBlock::getSome (size_t atLeast,
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- class RemoveBlock
|
// --SECTION-- class ModificationBlock
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
RemoveBlock::RemoveBlock (AQL_TRANSACTION_V8* trx,
|
ModificationBlock::ModificationBlock (AQL_TRANSACTION_V8* trx,
|
||||||
RemoveNode const* ep)
|
ModificationNode const* ep)
|
||||||
: ExecutionBlock(trx, ep),
|
: ExecutionBlock(trx, ep),
|
||||||
_collection(ep->_collection) {
|
_collection(ep->_collection) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RemoveBlock::~RemoveBlock () {
|
ModificationBlock::~ModificationBlock () {
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief get some - this accumulates all input and calls the remove() method
|
/// @brief get some - this accumulates all input and calls the work() method
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AqlItemBlock* RemoveBlock::getSome (size_t atLeast,
|
AqlItemBlock* ModificationBlock::getSome (size_t atLeast,
|
||||||
size_t atMost) {
|
size_t atMost) {
|
||||||
|
|
||||||
std::vector<AqlItemBlock*> blocks;
|
std::vector<AqlItemBlock*> blocks;
|
||||||
|
@ -1919,7 +1920,7 @@ AqlItemBlock* RemoveBlock::getSome (size_t atLeast,
|
||||||
blocks.push_back(res);
|
blocks.push_back(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(blocks);
|
work(blocks);
|
||||||
freeBlocks(blocks);
|
freeBlocks(blocks);
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -1930,11 +1931,73 @@ AqlItemBlock* RemoveBlock::getSome (size_t atLeast,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief resolve a collection name and return cid and document key
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int ModificationBlock::resolve (char const* handle,
|
||||||
|
TRI_voc_cid_t& cid,
|
||||||
|
std::string& key) const {
|
||||||
|
char const* p = strchr(handle, TRI_DOCUMENT_HANDLE_SEPARATOR_CHR);
|
||||||
|
if (p == nullptr || *p == '\0') {
|
||||||
|
return TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*handle >= '0' && *handle <= '9') {
|
||||||
|
cid = triagens::basics::StringUtils::uint64(handle, p - handle);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::string const name(handle, p - handle);
|
||||||
|
cid = _trx->resolver()->getCollectionIdCluster(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cid == 0) {
|
||||||
|
return TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = std::string(p + 1);
|
||||||
|
|
||||||
|
return TRI_ERROR_NO_ERROR;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief extract a key from the AqlValue passed
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int ModificationBlock::extractKey (AqlValue const& value,
|
||||||
|
TRI_document_collection_t const* document,
|
||||||
|
std::string& key) const {
|
||||||
|
Json member(value.extractArrayMember(_trx, document, TRI_VOC_ATTRIBUTE_KEY));
|
||||||
|
|
||||||
|
// TODO: allow _id, too
|
||||||
|
|
||||||
|
TRI_json_t const* json = member.json();
|
||||||
|
if (TRI_IsStringJson(json)) {
|
||||||
|
key = std::string(json->_value._string.data, json->_value._string.length - 1);
|
||||||
|
return TRI_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRI_ERROR_ARANGO_DOCUMENT_KEY_MISSING;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- class RemoveBlock
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
RemoveBlock::RemoveBlock (AQL_TRANSACTION_V8* trx,
|
||||||
|
RemoveNode const* ep)
|
||||||
|
: ModificationBlock(trx, ep) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RemoveBlock::~RemoveBlock () {
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief the actual work horse for removing data
|
/// @brief the actual work horse for removing data
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void RemoveBlock::remove (std::vector<AqlItemBlock*>& blocks) {
|
void RemoveBlock::work (std::vector<AqlItemBlock*>& blocks) {
|
||||||
auto ep = static_cast<RemoveNode const*>(getPlanNode());
|
auto ep = static_cast<RemoveNode const*>(getPlanNode());
|
||||||
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
|
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
|
||||||
TRI_ASSERT(it != _varOverview->varInfo.end());
|
TRI_ASSERT(it != _varOverview->varInfo.end());
|
||||||
|
@ -1956,20 +2019,12 @@ void RemoveBlock::remove (std::vector<AqlItemBlock*>& blocks) {
|
||||||
for (size_t i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
AqlValue a = res->getValue(i, registerId);
|
AqlValue a = res->getValue(i, registerId);
|
||||||
|
|
||||||
char const* key = nullptr;
|
std::string key;
|
||||||
int errorCode = TRI_ERROR_NO_ERROR;
|
int errorCode = TRI_ERROR_NO_ERROR;
|
||||||
|
|
||||||
if (a.isArray()) {
|
if (a.isArray()) {
|
||||||
// value is an array. now extract the _key attribute
|
// value is an array. now extract the _key attribute
|
||||||
Json member(a.extractArrayMember(_trx, document, "_key"));
|
errorCode = extractKey(a, document, key);
|
||||||
|
|
||||||
TRI_json_t const* json = member.json();
|
|
||||||
if (TRI_IsStringJson(json)) {
|
|
||||||
key = json->_value._string.data;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
errorCode = TRI_ERROR_ARANGO_DOCUMENT_KEY_MISSING;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (a.isString()) {
|
else if (a.isString()) {
|
||||||
// value is a string
|
// value is a string
|
||||||
|
@ -1981,10 +2036,10 @@ void RemoveBlock::remove (std::vector<AqlItemBlock*>& blocks) {
|
||||||
|
|
||||||
if (errorCode == TRI_ERROR_NO_ERROR) {
|
if (errorCode == TRI_ERROR_NO_ERROR) {
|
||||||
// no error. we expect to have a key
|
// no error. we expect to have a key
|
||||||
TRI_ASSERT(key != nullptr);
|
|
||||||
|
|
||||||
|
// all exceptions are caught in _trx->remove()
|
||||||
errorCode = _trx->remove(trxCollection,
|
errorCode = _trx->remove(trxCollection,
|
||||||
std::string(key),
|
key,
|
||||||
0,
|
0,
|
||||||
TRI_DOC_UPDATE_LAST_WRITE,
|
TRI_DOC_UPDATE_LAST_WRITE,
|
||||||
0,
|
0,
|
||||||
|
@ -2013,59 +2068,17 @@ void RemoveBlock::remove (std::vector<AqlItemBlock*>& blocks) {
|
||||||
|
|
||||||
InsertBlock::InsertBlock (AQL_TRANSACTION_V8* trx,
|
InsertBlock::InsertBlock (AQL_TRANSACTION_V8* trx,
|
||||||
InsertNode const* ep)
|
InsertNode const* ep)
|
||||||
: ExecutionBlock(trx, ep),
|
: ModificationBlock(trx, ep) {
|
||||||
_collection(ep->_collection) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
InsertBlock::~InsertBlock () {
|
InsertBlock::~InsertBlock () {
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief get some - this accumulates all input and calls the insert() method
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
AqlItemBlock* InsertBlock::getSome (size_t atLeast,
|
|
||||||
size_t atMost) {
|
|
||||||
|
|
||||||
std::vector<AqlItemBlock*> blocks;
|
|
||||||
|
|
||||||
auto freeBlocks = [](std::vector<AqlItemBlock*>& blocks) {
|
|
||||||
for (auto it = blocks.begin(); it != blocks.end(); ++it) {
|
|
||||||
if ((*it) != nullptr) {
|
|
||||||
delete (*it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// loop over input until it is exhausted
|
|
||||||
try {
|
|
||||||
while (true) {
|
|
||||||
auto res = ExecutionBlock::getSome(atLeast, atMost);
|
|
||||||
|
|
||||||
if (res == nullptr) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
blocks.push_back(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
insert(blocks);
|
|
||||||
freeBlocks(blocks);
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
freeBlocks(blocks);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief the actual work horse for inserting data
|
/// @brief the actual work horse for inserting data
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void InsertBlock::insert (std::vector<AqlItemBlock*>& blocks) {
|
void InsertBlock::work (std::vector<AqlItemBlock*>& blocks) {
|
||||||
auto ep = static_cast<InsertNode const*>(getPlanNode());
|
auto ep = static_cast<InsertNode const*>(getPlanNode());
|
||||||
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
|
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
|
||||||
TRI_ASSERT(it != _varOverview->varInfo.end());
|
TRI_ASSERT(it != _varOverview->varInfo.end());
|
||||||
|
@ -2075,30 +2088,6 @@ void InsertBlock::insert (std::vector<AqlItemBlock*>& blocks) {
|
||||||
|
|
||||||
bool const isEdgeCollection = _collection->isEdgeCollection();
|
bool const isEdgeCollection = _collection->isEdgeCollection();
|
||||||
|
|
||||||
auto resolve = [&](char const* handle, TRI_voc_cid_t& cid, std::string& key) -> int {
|
|
||||||
char const* p = strchr(handle, TRI_DOCUMENT_HANDLE_SEPARATOR_CHR);
|
|
||||||
if (p == nullptr || *p == '\0') {
|
|
||||||
return TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*handle >= '0' && *handle <= '9') {
|
|
||||||
cid = triagens::basics::StringUtils::uint64(handle, p - handle);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
std::string const name(handle, p - handle);
|
|
||||||
cid = _trx->resolver()->getCollectionIdCluster(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cid == 0) {
|
|
||||||
return TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
key = std::string(p + 1);
|
|
||||||
|
|
||||||
return TRI_ERROR_NO_ERROR;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
if (ep->_outVariable == nullptr) {
|
if (ep->_outVariable == nullptr) {
|
||||||
// don't return anything
|
// don't return anything
|
||||||
|
|
||||||
|
@ -2129,10 +2118,10 @@ void InsertBlock::insert (std::vector<AqlItemBlock*>& blocks) {
|
||||||
// value is an array
|
// value is an array
|
||||||
|
|
||||||
if (isEdgeCollection) {
|
if (isEdgeCollection) {
|
||||||
// array must have "_from" and "_to"
|
// array must have _from and _to attributes
|
||||||
TRI_json_t const* json;
|
TRI_json_t const* json;
|
||||||
|
|
||||||
Json member(a.extractArrayMember(_trx, document, "_from"));
|
Json member(a.extractArrayMember(_trx, document, TRI_VOC_ATTRIBUTE_FROM));
|
||||||
json = member.json();
|
json = member.json();
|
||||||
|
|
||||||
if (TRI_IsStringJson(json)) {
|
if (TRI_IsStringJson(json)) {
|
||||||
|
@ -2143,7 +2132,7 @@ void InsertBlock::insert (std::vector<AqlItemBlock*>& blocks) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorCode == TRI_ERROR_NO_ERROR) {
|
if (errorCode == TRI_ERROR_NO_ERROR) {
|
||||||
Json member(a.extractArrayMember(_trx, document, "_to"));
|
Json member(a.extractArrayMember(_trx, document, TRI_VOC_ATTRIBUTE_TO));
|
||||||
json = member.json();
|
json = member.json();
|
||||||
if (TRI_IsStringJson(json)) {
|
if (TRI_IsStringJson(json)) {
|
||||||
errorCode = resolve(json->_value._string.data, edge._toCid, to);
|
errorCode = resolve(json->_value._string.data, edge._toCid, to);
|
||||||
|
@ -2188,6 +2177,177 @@ void InsertBlock::insert (std::vector<AqlItemBlock*>& blocks) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- class UpdateBlock
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UpdateBlock::UpdateBlock (AQL_TRANSACTION_V8* trx,
|
||||||
|
UpdateNode const* ep)
|
||||||
|
: ModificationBlock(trx, ep) {
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateBlock::~UpdateBlock () {
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief the actual work horse for inserting data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void UpdateBlock::work (std::vector<AqlItemBlock*>& blocks) {
|
||||||
|
auto ep = static_cast<UpdateNode const*>(getPlanNode());
|
||||||
|
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
|
||||||
|
TRI_ASSERT(it != _varOverview->varInfo.end());
|
||||||
|
RegisterId const registerId = it->second.registerId;
|
||||||
|
|
||||||
|
auto trxCollection = _trx->trxCollection(_collection->cid());
|
||||||
|
|
||||||
|
if (ep->_outVariable == nullptr) {
|
||||||
|
// don't return anything
|
||||||
|
|
||||||
|
// loop over all blocks
|
||||||
|
for (auto it = blocks.begin(); it != blocks.end(); ++it) {
|
||||||
|
auto res = (*it);
|
||||||
|
auto document = res->getDocumentCollection(registerId);
|
||||||
|
|
||||||
|
size_t const n = res->size();
|
||||||
|
|
||||||
|
// loop over the complete block
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
AqlValue a = res->getValue(i, registerId);
|
||||||
|
|
||||||
|
int errorCode = TRI_ERROR_NO_ERROR;
|
||||||
|
std::string key;
|
||||||
|
|
||||||
|
if (a.isArray()) {
|
||||||
|
// value is an array. now extract the _key attribute
|
||||||
|
errorCode = extractKey(a, document, key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errorCode = TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorCode == TRI_ERROR_NO_ERROR) {
|
||||||
|
TRI_doc_mptr_copy_t mptr;
|
||||||
|
auto json = a.toJson(_trx, document);
|
||||||
|
|
||||||
|
// read old document
|
||||||
|
TRI_doc_mptr_copy_t oldDocument;
|
||||||
|
errorCode = _trx->readSingle(trxCollection, &oldDocument, key);
|
||||||
|
|
||||||
|
if (errorCode == TRI_ERROR_NO_ERROR) {
|
||||||
|
if (oldDocument.getDataPtr() != nullptr) {
|
||||||
|
TRI_shaped_json_t shapedJson;
|
||||||
|
TRI_EXTRACT_SHAPED_JSON_MARKER(shapedJson, oldDocument.getDataPtr()); // PROTECTED by trx here
|
||||||
|
TRI_json_t* old = TRI_JsonShapedJson(_collection->documentCollection()->getShaper(), &shapedJson);
|
||||||
|
|
||||||
|
if (old != nullptr) {
|
||||||
|
TRI_json_t* patchedJson = TRI_MergeJson(TRI_UNKNOWN_MEM_ZONE, old, json.json(), ep->_options.nullMeansRemove);
|
||||||
|
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, old);
|
||||||
|
|
||||||
|
if (patchedJson != nullptr) {
|
||||||
|
// all exceptions are caught in _trx->update()
|
||||||
|
errorCode = _trx->update(trxCollection, key, 0, &mptr, patchedJson, TRI_DOC_UPDATE_LAST_WRITE, 0, nullptr, ep->_options.waitForSync);
|
||||||
|
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, patchedJson);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errorCode = TRI_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errorCode = TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorCode != TRI_ERROR_NO_ERROR &&
|
||||||
|
! ep->_options.ignoreErrors) {
|
||||||
|
THROW_ARANGO_EXCEPTION(errorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// done with a block
|
||||||
|
|
||||||
|
// now free it already
|
||||||
|
(*it) = nullptr;
|
||||||
|
delete res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- class ReplaceBlock
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ReplaceBlock::ReplaceBlock (AQL_TRANSACTION_V8* trx,
|
||||||
|
ReplaceNode const* ep)
|
||||||
|
: ModificationBlock(trx, ep) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplaceBlock::~ReplaceBlock () {
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief the actual work horse for replacing data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void ReplaceBlock::work (std::vector<AqlItemBlock*>& blocks) {
|
||||||
|
auto ep = static_cast<ReplaceNode const*>(getPlanNode());
|
||||||
|
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
|
||||||
|
TRI_ASSERT(it != _varOverview->varInfo.end());
|
||||||
|
RegisterId const registerId = it->second.registerId;
|
||||||
|
|
||||||
|
auto trxCollection = _trx->trxCollection(_collection->cid());
|
||||||
|
|
||||||
|
if (ep->_outVariable == nullptr) {
|
||||||
|
// don't return anything
|
||||||
|
|
||||||
|
// loop over all blocks
|
||||||
|
for (auto it = blocks.begin(); it != blocks.end(); ++it) {
|
||||||
|
auto res = (*it);
|
||||||
|
auto document = res->getDocumentCollection(registerId);
|
||||||
|
|
||||||
|
size_t const n = res->size();
|
||||||
|
|
||||||
|
// loop over the complete block
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
AqlValue a = res->getValue(i, registerId);
|
||||||
|
|
||||||
|
int errorCode = TRI_ERROR_NO_ERROR;
|
||||||
|
std::string key;
|
||||||
|
|
||||||
|
if (a.isArray()) {
|
||||||
|
// value is an array. now extract the _key attribute
|
||||||
|
errorCode = extractKey(a, document, key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errorCode = TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorCode == TRI_ERROR_NO_ERROR) {
|
||||||
|
TRI_doc_mptr_copy_t mptr;
|
||||||
|
auto json = a.toJson(_trx, document);
|
||||||
|
|
||||||
|
// all exceptions are caught in _trx->update()
|
||||||
|
errorCode = _trx->update(trxCollection, key, 0, &mptr, json.json(), TRI_DOC_UPDATE_LAST_WRITE, 0, nullptr, ep->_options.waitForSync);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorCode != TRI_ERROR_NO_ERROR &&
|
||||||
|
! ep->_options.ignoreErrors) {
|
||||||
|
THROW_ARANGO_EXCEPTION(errorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// done with a block
|
||||||
|
|
||||||
|
// now free it already
|
||||||
|
(*it) = nullptr;
|
||||||
|
delete res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- struct ExecutionBlock::VarOverview
|
// --SECTION-- struct ExecutionBlock::VarOverview
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -1031,11 +1031,81 @@ namespace triagens {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- ModificationBlock
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ModificationBlock : public ExecutionBlock {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ModificationBlock (AQL_TRANSACTION_V8*, ModificationNode const*);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief destructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
virtual ~ModificationBlock ();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief getSome
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
virtual AqlItemBlock* getSome (size_t atLeast,
|
||||||
|
size_t atMost);
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- protected methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief the actual work horse
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
virtual void work (std::vector<AqlItemBlock*>&) = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief resolve a collection name and return cid and document key
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int resolve (char const*,
|
||||||
|
TRI_voc_cid_t&,
|
||||||
|
std::string&) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief extract a key from the AqlValue passed
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int extractKey (AqlValue const&,
|
||||||
|
TRI_document_collection_t const*,
|
||||||
|
std::string&) const;
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- protected variables
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief collection
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Collection* _collection;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- RemoveBlock
|
// --SECTION-- RemoveBlock
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class RemoveBlock : public ExecutionBlock {
|
class RemoveBlock : public ModificationBlock {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -1051,36 +1121,17 @@ namespace triagens {
|
||||||
|
|
||||||
~RemoveBlock ();
|
~RemoveBlock ();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief getSome
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
virtual AqlItemBlock* getSome (size_t atLeast,
|
|
||||||
size_t atMost);
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private methods
|
// --SECTION-- protected methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief the actual work horse for removing data
|
/// @brief the actual work horse for removing data
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void remove (std::vector<AqlItemBlock*>&);
|
void work (std::vector<AqlItemBlock*>&);
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- private variables
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief collection
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
Collection* _collection;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1088,7 +1139,7 @@ namespace triagens {
|
||||||
// --SECTION-- InsertBlock
|
// --SECTION-- InsertBlock
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class InsertBlock : public ExecutionBlock {
|
class InsertBlock : public ModificationBlock {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -1104,36 +1155,85 @@ namespace triagens {
|
||||||
|
|
||||||
~InsertBlock ();
|
~InsertBlock ();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief getSome
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
virtual AqlItemBlock* getSome (size_t atLeast,
|
|
||||||
size_t atMost);
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private methods
|
// --SECTION-- protected methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief the actual work horse for inserting data
|
/// @brief the actual work horse for inserting data
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void insert (std::vector<AqlItemBlock*>&);
|
void work (std::vector<AqlItemBlock*>&);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private variables
|
// --SECTION-- UpdateBlock
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
private:
|
class UpdateBlock : public ModificationBlock {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief collection
|
/// @brief constructor
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Collection* _collection;
|
UpdateBlock (AQL_TRANSACTION_V8* trx, UpdateNode const* ep);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief destructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
~UpdateBlock ();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- protected methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief the actual work horse for updating data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void work (std::vector<AqlItemBlock*>&);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- ReplaceBlock
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ReplaceBlock : public ModificationBlock {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ReplaceBlock (AQL_TRANSACTION_V8* trx, ReplaceNode const* ep);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief destructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
~ReplaceBlock ();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- protected methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief the actual work horse for replacing data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void work (std::vector<AqlItemBlock*>&);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,20 @@ struct Instanciator : public WalkerWorker<ExecutionNode> {
|
||||||
root = eb;
|
root = eb;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ExecutionNode::UPDATE: {
|
||||||
|
eb = new UpdateBlock(engine->getTransaction(),
|
||||||
|
static_cast<UpdateNode const*>(en));
|
||||||
|
|
||||||
|
root = eb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExecutionNode::REPLACE: {
|
||||||
|
eb = new ReplaceBlock(engine->getTransaction(),
|
||||||
|
static_cast<ReplaceNode const*>(en));
|
||||||
|
|
||||||
|
root = eb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||||
|
|
|
@ -294,7 +294,7 @@ void IndexRangeNode::toJsonHelper (std::map<ExecutionNode*, int>& indexTab,
|
||||||
|
|
||||||
// put together the range info . . .
|
// put together the range info . . .
|
||||||
Json ranges(Json::List);
|
Json ranges(Json::List);
|
||||||
|
/*
|
||||||
for (auto x : *_ranges) {
|
for (auto x : *_ranges) {
|
||||||
Json item(Json::Array);
|
Json item(Json::Array);
|
||||||
item("name", Json(x._name))
|
item("name", Json(x._name))
|
||||||
|
@ -304,7 +304,7 @@ void IndexRangeNode::toJsonHelper (std::map<ExecutionNode*, int>& indexTab,
|
||||||
("highOpen", Json(x._highOpen));
|
("highOpen", Json(x._highOpen));
|
||||||
ranges(item);
|
ranges(item);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// Now put info about vocbase and cid in there
|
// Now put info about vocbase and cid in there
|
||||||
json("database", Json(_vocbase->_name))
|
json("database", Json(_vocbase->_name))
|
||||||
("collection", Json(_collection->name))
|
("collection", Json(_collection->name))
|
||||||
|
@ -594,8 +594,13 @@ void UpdateNode::toJsonHelper (std::map<ExecutionNode*, int>& indexTab,
|
||||||
|
|
||||||
// Now put info about vocbase and cid in there
|
// Now put info about vocbase and cid in there
|
||||||
json("database", Json(_vocbase->_name))
|
json("database", Json(_vocbase->_name))
|
||||||
("collection", Json(_collname))
|
("collection", Json(_collection->name))
|
||||||
("outVariable", _outVariable->toJson());
|
("inVariable", _inVariable->toJson());
|
||||||
|
|
||||||
|
// output variable might be empty
|
||||||
|
if (_outVariable != nullptr) {
|
||||||
|
json("outVariable", _outVariable->toJson());
|
||||||
|
}
|
||||||
|
|
||||||
// And add it:
|
// And add it:
|
||||||
int len = static_cast<int>(nodes.size());
|
int len = static_cast<int>(nodes.size());
|
||||||
|
@ -622,8 +627,13 @@ void ReplaceNode::toJsonHelper (std::map<ExecutionNode*, int>& indexTab,
|
||||||
|
|
||||||
// Now put info about vocbase and cid in there
|
// Now put info about vocbase and cid in there
|
||||||
json("database", Json(_vocbase->_name))
|
json("database", Json(_vocbase->_name))
|
||||||
("collection", Json(_collname))
|
("collection", Json(_collection->name))
|
||||||
("outVariable", _outVariable->toJson());
|
("inVariable", _inVariable->toJson());
|
||||||
|
|
||||||
|
// output variable might be empty
|
||||||
|
if (_outVariable != nullptr) {
|
||||||
|
json("outVariable", _outVariable->toJson());
|
||||||
|
}
|
||||||
|
|
||||||
// And add it:
|
// And add it:
|
||||||
int len = static_cast<int>(nodes.size());
|
int len = static_cast<int>(nodes.size());
|
||||||
|
|
|
@ -1455,6 +1455,7 @@ namespace triagens {
|
||||||
class ModificationNode : public ExecutionNode {
|
class ModificationNode : public ExecutionNode {
|
||||||
|
|
||||||
friend class ExecutionBlock;
|
friend class ExecutionBlock;
|
||||||
|
friend class ModificationBlock;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief constructor with a vocbase and a collection and options
|
/// @brief constructor with a vocbase and a collection and options
|
||||||
|
@ -1728,7 +1729,7 @@ namespace triagens {
|
||||||
/// @brief class UpdateNode
|
/// @brief class UpdateNode
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class UpdateNode : public ExecutionNode {
|
class UpdateNode : public ModificationNode {
|
||||||
|
|
||||||
friend class ExecutionBlock;
|
friend class ExecutionBlock;
|
||||||
friend class UpdateBlock;
|
friend class UpdateBlock;
|
||||||
|
@ -1740,13 +1741,16 @@ namespace triagens {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
UpdateNode (TRI_vocbase_t* vocbase,
|
UpdateNode (TRI_vocbase_t* vocbase,
|
||||||
std::string collname,
|
Collection* collection,
|
||||||
|
ModificationOptions const& options,
|
||||||
|
Variable const* inVariable,
|
||||||
Variable const* outVariable)
|
Variable const* outVariable)
|
||||||
: ExecutionNode(), _vocbase(vocbase), _collname(collname),
|
: ModificationNode(vocbase, collection, options),
|
||||||
|
_inVariable(inVariable),
|
||||||
_outVariable(outVariable) {
|
_outVariable(outVariable) {
|
||||||
|
|
||||||
TRI_ASSERT(_vocbase != nullptr);
|
TRI_ASSERT(_inVariable != nullptr);
|
||||||
TRI_ASSERT(_outVariable != nullptr);
|
// _outVariable might be a nullptr
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1770,7 +1774,7 @@ namespace triagens {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
virtual ExecutionNode* clone () const {
|
virtual ExecutionNode* clone () const {
|
||||||
auto c = new UpdateNode(_vocbase, _collname, _outVariable);
|
auto c = new UpdateNode(_vocbase, _collection, _options, _inVariable, _outVariable);
|
||||||
cloneDependencies(c);
|
cloneDependencies(c);
|
||||||
return static_cast<ExecutionNode*>(c);
|
return static_cast<ExecutionNode*>(c);
|
||||||
}
|
}
|
||||||
|
@ -1784,6 +1788,28 @@ namespace triagens {
|
||||||
return 1000 * _dependencies.at(0)->getCost(); //FIXME change this!
|
return 1000 * _dependencies.at(0)->getCost(); //FIXME change this!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief getVariablesUsedHere
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
virtual std::vector<Variable const*> getVariablesUsedHere () {
|
||||||
|
std::vector<Variable const*> v;
|
||||||
|
v.push_back(_inVariable);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief getVariablesSetHere
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
virtual std::vector<Variable const*> getVariablesSetHere () {
|
||||||
|
std::vector<Variable const*> v;
|
||||||
|
if (_outVariable != nullptr) {
|
||||||
|
v.push_back(_outVariable);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private variables
|
// --SECTION-- private variables
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -1791,16 +1817,10 @@ namespace triagens {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief _vocbase, the database
|
/// @brief input variable
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TRI_vocbase_t* _vocbase;
|
Variable const* _inVariable;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief _collname, the collection name
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
std::string _collname;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief output variable
|
/// @brief output variable
|
||||||
|
@ -1818,7 +1838,7 @@ namespace triagens {
|
||||||
/// @brief class ReplaceNode
|
/// @brief class ReplaceNode
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class ReplaceNode : public ExecutionNode {
|
class ReplaceNode : public ModificationNode {
|
||||||
|
|
||||||
friend class ExecutionBlock;
|
friend class ExecutionBlock;
|
||||||
friend class ReplaceBlock;
|
friend class ReplaceBlock;
|
||||||
|
@ -1830,13 +1850,16 @@ namespace triagens {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ReplaceNode (TRI_vocbase_t* vocbase,
|
ReplaceNode (TRI_vocbase_t* vocbase,
|
||||||
std::string collname,
|
Collection* collection,
|
||||||
|
ModificationOptions const& options,
|
||||||
|
Variable const* inVariable,
|
||||||
Variable const* outVariable)
|
Variable const* outVariable)
|
||||||
: ExecutionNode(), _vocbase(vocbase), _collname(collname),
|
: ModificationNode(vocbase, collection, options),
|
||||||
|
_inVariable(inVariable),
|
||||||
_outVariable(outVariable) {
|
_outVariable(outVariable) {
|
||||||
|
|
||||||
TRI_ASSERT(_vocbase != nullptr);
|
TRI_ASSERT(_inVariable != nullptr);
|
||||||
TRI_ASSERT(_outVariable != nullptr);
|
// _outVariable might be a nullptr
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1860,7 +1883,7 @@ namespace triagens {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
virtual ExecutionNode* clone () const {
|
virtual ExecutionNode* clone () const {
|
||||||
auto c = new UpdateNode(_vocbase, _collname, _outVariable);
|
auto c = new ReplaceNode(_vocbase, _collection, _options, _inVariable, _outVariable);
|
||||||
cloneDependencies(c);
|
cloneDependencies(c);
|
||||||
return static_cast<ExecutionNode*>(c);
|
return static_cast<ExecutionNode*>(c);
|
||||||
}
|
}
|
||||||
|
@ -1874,6 +1897,28 @@ namespace triagens {
|
||||||
return 1000 * _dependencies.at(0)->getCost(); //FIXME change this!
|
return 1000 * _dependencies.at(0)->getCost(); //FIXME change this!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief getVariablesUsedHere
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
virtual std::vector<Variable const*> getVariablesUsedHere () {
|
||||||
|
std::vector<Variable const*> v;
|
||||||
|
v.push_back(_inVariable);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief getVariablesSetHere
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
virtual std::vector<Variable const*> getVariablesSetHere () {
|
||||||
|
std::vector<Variable const*> v;
|
||||||
|
if (_outVariable != nullptr) {
|
||||||
|
v.push_back(_outVariable);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private variables
|
// --SECTION-- private variables
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -1881,16 +1926,10 @@ namespace triagens {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief _vocbase, the database
|
/// @brief input variable
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TRI_vocbase_t* _vocbase;
|
Variable const* _inVariable;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief _collname, the collection name
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
std::string _collname;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief output variable
|
/// @brief output variable
|
||||||
|
|
|
@ -120,7 +120,6 @@ ModificationOptions ExecutionPlan::createOptions (AstNode const* node) {
|
||||||
auto name = member->getStringValue();
|
auto name = member->getStringValue();
|
||||||
auto value = member->getMember(0);
|
auto value = member->getMember(0);
|
||||||
|
|
||||||
std::cout << "VALUE: " << value->typeString() << "\n";
|
|
||||||
TRI_ASSERT(value->isConstant());
|
TRI_ASSERT(value->isConstant());
|
||||||
|
|
||||||
if (strcmp(name, "waitForSync") == 0) {
|
if (strcmp(name, "waitForSync") == 0) {
|
||||||
|
@ -129,6 +128,10 @@ std::cout << "VALUE: " << value->typeString() << "\n";
|
||||||
else if (strcmp(name, "ignoreErrors") == 0) {
|
else if (strcmp(name, "ignoreErrors") == 0) {
|
||||||
options.ignoreErrors = value->toBoolean();
|
options.ignoreErrors = value->toBoolean();
|
||||||
}
|
}
|
||||||
|
else if (strcmp(name, "keepNull") == 0) {
|
||||||
|
// nullMeansRemove is the opposite of keepNull
|
||||||
|
options.nullMeansRemove = (! value->toBoolean());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -597,26 +600,27 @@ ExecutionNode* ExecutionPlan::fromNodeUpdate (Ast const* ast,
|
||||||
ExecutionNode* previous,
|
ExecutionNode* previous,
|
||||||
AstNode const* node) {
|
AstNode const* node) {
|
||||||
TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_UPDATE);
|
TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_UPDATE);
|
||||||
TRI_ASSERT(node->numMembers() >= 2);
|
TRI_ASSERT(node->numMembers() >= 3);
|
||||||
|
|
||||||
auto collection = node->getMember(0);
|
auto options = createOptions(node->getMember(0));
|
||||||
auto expression = node->getMember(1);
|
char const* collectionName = node->getMember(1)->getStringValue();
|
||||||
|
auto collections = ast->query()->collections();
|
||||||
// collection, expression
|
auto collection = collections->get(collectionName);
|
||||||
char const* collectionName = collection->getStringValue();
|
auto expression = node->getMember(2);
|
||||||
|
// auto keyExpression = node->getMember(3);
|
||||||
ExecutionNode* en = nullptr;
|
ExecutionNode* en = nullptr;
|
||||||
|
|
||||||
if (expression->type == NODE_TYPE_REFERENCE) {
|
if (expression->type == NODE_TYPE_REFERENCE) {
|
||||||
// operand is already a variable
|
// operand is already a variable
|
||||||
auto v = static_cast<Variable*>(expression->getData());
|
auto v = static_cast<Variable*>(expression->getData());
|
||||||
TRI_ASSERT(v != nullptr);
|
TRI_ASSERT(v != nullptr);
|
||||||
en = addNode(new UpdateNode(ast->query()->vocbase(), std::string(collectionName), v));
|
en = addNode(new UpdateNode(ast->query()->vocbase(), collection, options, v, nullptr));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// operand is some misc expression
|
// operand is some misc expression
|
||||||
auto calc = createTemporaryCalculation(ast, expression);
|
auto calc = createTemporaryCalculation(ast, expression);
|
||||||
calc->addDependency(previous);
|
calc->addDependency(previous);
|
||||||
en = addNode(new UpdateNode(ast->query()->vocbase(), std::string(collectionName), calc->outVariable()));
|
en = addNode(new UpdateNode(ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr));
|
||||||
previous = calc;
|
previous = calc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,26 +635,27 @@ ExecutionNode* ExecutionPlan::fromNodeReplace (Ast const* ast,
|
||||||
ExecutionNode* previous,
|
ExecutionNode* previous,
|
||||||
AstNode const* node) {
|
AstNode const* node) {
|
||||||
TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_REPLACE);
|
TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_REPLACE);
|
||||||
TRI_ASSERT(node->numMembers() >= 2);
|
TRI_ASSERT(node->numMembers() >= 3);
|
||||||
|
|
||||||
auto collection = node->getMember(0);
|
auto options = createOptions(node->getMember(0));
|
||||||
auto expression = node->getMember(1);
|
char const* collectionName = node->getMember(1)->getStringValue();
|
||||||
|
auto collections = ast->query()->collections();
|
||||||
// collection, expression
|
auto collection = collections->get(collectionName);
|
||||||
char const* collectionName = collection->getStringValue();
|
auto expression = node->getMember(2);
|
||||||
|
// auto keyExpression = node->getMember(3);
|
||||||
ExecutionNode* en = nullptr;
|
ExecutionNode* en = nullptr;
|
||||||
|
|
||||||
if (expression->type == NODE_TYPE_REFERENCE) {
|
if (expression->type == NODE_TYPE_REFERENCE) {
|
||||||
// operand is already a variable
|
// operand is already a variable
|
||||||
auto v = static_cast<Variable*>(expression->getData());
|
auto v = static_cast<Variable*>(expression->getData());
|
||||||
TRI_ASSERT(v != nullptr);
|
TRI_ASSERT(v != nullptr);
|
||||||
en = addNode(new ReplaceNode(ast->query()->vocbase(), std::string(collectionName), v));
|
en = addNode(new ReplaceNode(ast->query()->vocbase(), collection, options, v, nullptr));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// operand is some misc expression
|
// operand is some misc expression
|
||||||
auto calc = createTemporaryCalculation(ast, expression);
|
auto calc = createTemporaryCalculation(ast, expression);
|
||||||
calc->addDependency(previous);
|
calc->addDependency(previous);
|
||||||
en = addNode(new ReplaceNode(ast->query()->vocbase(), std::string(collectionName), calc->outVariable()));
|
en = addNode(new ReplaceNode(ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr));
|
||||||
previous = calc;
|
previous = calc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,13 +728,11 @@ ExecutionNode* ExecutionPlan::fromNode (Ast const* ast,
|
||||||
}
|
}
|
||||||
|
|
||||||
case NODE_TYPE_UPDATE: {
|
case NODE_TYPE_UPDATE: {
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
|
||||||
en = fromNodeUpdate(ast, en, member);
|
en = fromNodeUpdate(ast, en, member);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NODE_TYPE_REPLACE: {
|
case NODE_TYPE_REPLACE: {
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
|
||||||
en = fromNodeReplace(ast, en, member);
|
en = fromNodeReplace(ast, en, member);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,8 @@ namespace triagens {
|
||||||
|
|
||||||
ModificationOptions ()
|
ModificationOptions ()
|
||||||
: ignoreErrors(false),
|
: ignoreErrors(false),
|
||||||
waitForSync(false) {
|
waitForSync(false),
|
||||||
|
nullMeansRemove(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -58,6 +59,7 @@ namespace triagens {
|
||||||
|
|
||||||
bool ignoreErrors;
|
bool ignoreErrors;
|
||||||
bool waitForSync;
|
bool waitForSync;
|
||||||
|
bool nullMeansRemove;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -637,8 +637,8 @@ namespace triagens {
|
||||||
|
|
||||||
#define YY_INPUT(resultBuffer, resultState, maxBytesToRead) { \
|
#define YY_INPUT(resultBuffer, resultState, maxBytesToRead) { \
|
||||||
size_t length = yyextra->remainingLength(); \
|
size_t length = yyextra->remainingLength(); \
|
||||||
if (length > maxBytesToRead) { \
|
if (length > static_cast<size_t>(maxBytesToRead)) { \
|
||||||
length = maxBytesToRead; \
|
length = static_cast<size_t>(maxBytesToRead); \
|
||||||
} \
|
} \
|
||||||
if (length > 0) { \
|
if (length > 0) { \
|
||||||
yyextra->fillBuffer(resultBuffer, length); \
|
yyextra->fillBuffer(resultBuffer, length); \
|
||||||
|
|
|
@ -38,8 +38,8 @@ namespace triagens {
|
||||||
|
|
||||||
#define YY_INPUT(resultBuffer, resultState, maxBytesToRead) { \
|
#define YY_INPUT(resultBuffer, resultState, maxBytesToRead) { \
|
||||||
size_t length = yyextra->remainingLength(); \
|
size_t length = yyextra->remainingLength(); \
|
||||||
if (length > maxBytesToRead) { \
|
if (length > static_cast<size_t>(maxBytesToRead)) { \
|
||||||
length = maxBytesToRead; \
|
length = static_cast<size_t>(maxBytesToRead); \
|
||||||
} \
|
} \
|
||||||
if (length > 0) { \
|
if (length > 0) { \
|
||||||
yyextra->fillBuffer(resultBuffer, length); \
|
yyextra->fillBuffer(resultBuffer, length); \
|
||||||
|
|
|
@ -495,6 +495,74 @@ namespace triagens {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief update a single document, using JSON
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int update (TRI_transaction_collection_t* trxCollection,
|
||||||
|
std::string const& key,
|
||||||
|
TRI_voc_rid_t rid,
|
||||||
|
TRI_doc_mptr_copy_t* mptr,
|
||||||
|
TRI_json_t* const json,
|
||||||
|
TRI_doc_update_policy_e policy,
|
||||||
|
TRI_voc_rid_t expectedRevision,
|
||||||
|
TRI_voc_rid_t* actualRevision,
|
||||||
|
bool forceSync) {
|
||||||
|
|
||||||
|
TRI_shaper_t* shaper = this->shaper(trxCollection);
|
||||||
|
TRI_memory_zone_t* zone = shaper->_memoryZone;
|
||||||
|
TRI_shaped_json_t* shaped = TRI_ShapedJsonJson(shaper, json, true, isLocked(trxCollection, TRI_TRANSACTION_WRITE));
|
||||||
|
|
||||||
|
if (shaped == nullptr) {
|
||||||
|
return TRI_ERROR_ARANGO_SHAPER_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orderBarrier(trxCollection) == nullptr) {
|
||||||
|
return TRI_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = update(trxCollection,
|
||||||
|
key,
|
||||||
|
rid,
|
||||||
|
mptr,
|
||||||
|
shaped,
|
||||||
|
policy,
|
||||||
|
expectedRevision,
|
||||||
|
actualRevision,
|
||||||
|
forceSync);
|
||||||
|
|
||||||
|
TRI_FreeShapedJson(zone, shaped);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief read a single document, identified by key
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int readSingle (TRI_transaction_collection_t* trxCollection,
|
||||||
|
TRI_doc_mptr_copy_t* mptr,
|
||||||
|
std::string const& key) {
|
||||||
|
|
||||||
|
TRI_ASSERT(mptr != nullptr);
|
||||||
|
|
||||||
|
if (orderBarrier(trxCollection) == nullptr) {
|
||||||
|
return TRI_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return TRI_ReadShapedJsonDocumentCollection(trxCollection,
|
||||||
|
(TRI_voc_key_t) key.c_str(),
|
||||||
|
mptr,
|
||||||
|
! isLocked(trxCollection, TRI_TRANSACTION_READ));
|
||||||
|
}
|
||||||
|
catch (triagens::arango::Exception const& ex) {
|
||||||
|
return ex.code();
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
return TRI_ERROR_INTERNAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- protected methods
|
// --SECTION-- protected methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -696,34 +764,6 @@ namespace triagens {
|
||||||
return TRI_ERROR_NO_ERROR;
|
return TRI_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief read a single document, identified by key
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int readSingle (TRI_transaction_collection_t* trxCollection,
|
|
||||||
TRI_doc_mptr_copy_t* mptr,
|
|
||||||
std::string const& key) {
|
|
||||||
|
|
||||||
TRI_ASSERT(mptr != nullptr);
|
|
||||||
|
|
||||||
if (orderBarrier(trxCollection) == nullptr) {
|
|
||||||
return TRI_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return TRI_ReadShapedJsonDocumentCollection(trxCollection,
|
|
||||||
(TRI_voc_key_t) key.c_str(),
|
|
||||||
mptr,
|
|
||||||
! isLocked(trxCollection, TRI_TRANSACTION_READ));
|
|
||||||
}
|
|
||||||
catch (triagens::arango::Exception const& ex) {
|
|
||||||
return ex.code();
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
return TRI_ERROR_INTERNAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief read all documents
|
/// @brief read all documents
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -997,46 +1037,6 @@ namespace triagens {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief update a single document, using JSON
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int update (TRI_transaction_collection_t* trxCollection,
|
|
||||||
std::string const& key,
|
|
||||||
TRI_voc_rid_t rid,
|
|
||||||
TRI_doc_mptr_copy_t* mptr,
|
|
||||||
TRI_json_t* const json,
|
|
||||||
TRI_doc_update_policy_e policy,
|
|
||||||
TRI_voc_rid_t expectedRevision,
|
|
||||||
TRI_voc_rid_t* actualRevision,
|
|
||||||
bool forceSync) {
|
|
||||||
|
|
||||||
TRI_shaper_t* shaper = this->shaper(trxCollection);
|
|
||||||
TRI_memory_zone_t* zone = shaper->_memoryZone;
|
|
||||||
TRI_shaped_json_t* shaped = TRI_ShapedJsonJson(shaper, json, true, isLocked(trxCollection, TRI_TRANSACTION_WRITE));
|
|
||||||
|
|
||||||
if (shaped == nullptr) {
|
|
||||||
return TRI_ERROR_ARANGO_SHAPER_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (orderBarrier(trxCollection) == nullptr) {
|
|
||||||
return TRI_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
int res = update(trxCollection,
|
|
||||||
key,
|
|
||||||
rid,
|
|
||||||
mptr,
|
|
||||||
shaped,
|
|
||||||
policy,
|
|
||||||
expectedRevision,
|
|
||||||
actualRevision,
|
|
||||||
forceSync);
|
|
||||||
|
|
||||||
TRI_FreeShapedJson(zone, shaped);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief update a single document, using shaped json
|
/// @brief update a single document, using shaped json
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Reference in New Issue