1
0
Fork 0

Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2

This commit is contained in:
James 2014-08-18 14:12:10 +02:00
commit fb1d69bbae
12 changed files with 606 additions and 266 deletions

View File

@ -234,15 +234,21 @@ AstNode* Ast::createNodeInsert (AstNode const* expression,
AstNode* Ast::createNodeUpdate (AstNode const* keyExpression,
AstNode const* docExpression,
AstNode const* collection,
AstNode* options) {
AstNode const* options) {
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(docExpression);
if (keyExpression != nullptr) {
node->addMember(keyExpression);
}
// TODO: handle options
return node;
}
@ -254,15 +260,21 @@ AstNode* Ast::createNodeUpdate (AstNode const* keyExpression,
AstNode* Ast::createNodeReplace (AstNode const* keyExpression,
AstNode const* docExpression,
AstNode const* collection,
AstNode* options) {
AstNode const* options) {
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(docExpression);
if (keyExpression != nullptr) {
node->addMember(keyExpression);
}
// TODO: handle options
return node;
}

View File

@ -262,7 +262,7 @@ namespace triagens {
AstNode* createNodeUpdate (AstNode const*,
AstNode const*,
AstNode const*,
AstNode*);
AstNode const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST replace node
@ -271,7 +271,7 @@ namespace triagens {
AstNode* createNodeReplace (AstNode const*,
AstNode const*,
AstNode const*,
AstNode*);
AstNode const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST collect node

View File

@ -27,6 +27,7 @@
#include "Aql/ExecutionBlock.h"
#include "Basics/StringUtils.h"
#include "Basics/json-utilities.h"
#include "Utils/Exception.h"
#include "VocBase/vocbase.h"
@ -1877,25 +1878,25 @@ AqlItemBlock* ReturnBlock::getSome (size_t atLeast,
}
// -----------------------------------------------------------------------------
// --SECTION-- class RemoveBlock
// --SECTION-- class ModificationBlock
// -----------------------------------------------------------------------------
RemoveBlock::RemoveBlock (AQL_TRANSACTION_V8* trx,
RemoveNode const* ep)
ModificationBlock::ModificationBlock (AQL_TRANSACTION_V8* trx,
ModificationNode const* ep)
: ExecutionBlock(trx, ep),
_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,
size_t atMost) {
AqlItemBlock* ModificationBlock::getSome (size_t atLeast,
size_t atMost) {
std::vector<AqlItemBlock*> blocks;
@ -1919,7 +1920,7 @@ AqlItemBlock* RemoveBlock::getSome (size_t atLeast,
blocks.push_back(res);
}
remove(blocks);
work(blocks);
freeBlocks(blocks);
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
////////////////////////////////////////////////////////////////////////////////
void RemoveBlock::remove (std::vector<AqlItemBlock*>& blocks) {
void RemoveBlock::work (std::vector<AqlItemBlock*>& blocks) {
auto ep = static_cast<RemoveNode const*>(getPlanNode());
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
@ -1949,27 +2012,19 @@ void RemoveBlock::remove (std::vector<AqlItemBlock*>& 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);
char const* key = nullptr;
std::string key;
int errorCode = TRI_ERROR_NO_ERROR;
if (a.isArray()) {
// value is an array. now extract the _key attribute
Json member(a.extractArrayMember(_trx, 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;
}
errorCode = extractKey(a, document, key);
}
else if (a.isString()) {
// value is a string
@ -1981,10 +2036,10 @@ void RemoveBlock::remove (std::vector<AqlItemBlock*>& blocks) {
if (errorCode == TRI_ERROR_NO_ERROR) {
// no error. we expect to have a key
TRI_ASSERT(key != nullptr);
// all exceptions are caught in _trx->remove()
errorCode = _trx->remove(trxCollection,
std::string(key),
key,
0,
TRI_DOC_UPDATE_LAST_WRITE,
0,
@ -2013,59 +2068,17 @@ void RemoveBlock::remove (std::vector<AqlItemBlock*>& blocks) {
InsertBlock::InsertBlock (AQL_TRANSACTION_V8* trx,
InsertNode const* ep)
: ExecutionBlock(trx, ep),
_collection(ep->_collection) {
: ModificationBlock(trx, ep) {
}
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
////////////////////////////////////////////////////////////////////////////////
void InsertBlock::insert (std::vector<AqlItemBlock*>& blocks) {
void InsertBlock::work (std::vector<AqlItemBlock*>& blocks) {
auto ep = static_cast<InsertNode const*>(getPlanNode());
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
@ -2075,30 +2088,6 @@ void InsertBlock::insert (std::vector<AqlItemBlock*>& blocks) {
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) {
// don't return anything
@ -2116,7 +2105,7 @@ void InsertBlock::insert (std::vector<AqlItemBlock*>& 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
@ -2129,10 +2118,10 @@ void InsertBlock::insert (std::vector<AqlItemBlock*>& blocks) {
// value is an array
if (isEdgeCollection) {
// array must have "_from" and "_to"
// array must have _from and _to attributes
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();
if (TRI_IsStringJson(json)) {
@ -2143,7 +2132,7 @@ void InsertBlock::insert (std::vector<AqlItemBlock*>& blocks) {
}
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();
if (TRI_IsStringJson(json)) {
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
// -----------------------------------------------------------------------------

View File

@ -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
// -----------------------------------------------------------------------------
class RemoveBlock : public ExecutionBlock {
class RemoveBlock : public ModificationBlock {
public:
@ -1051,36 +1121,17 @@ namespace triagens {
~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
////////////////////////////////////////////////////////////////////////////////
void remove (std::vector<AqlItemBlock*>&);
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief collection
////////////////////////////////////////////////////////////////////////////////
Collection* _collection;
void work (std::vector<AqlItemBlock*>&);
};
@ -1088,7 +1139,7 @@ namespace triagens {
// --SECTION-- InsertBlock
// -----------------------------------------------------------------------------
class InsertBlock : public ExecutionBlock {
class InsertBlock : public ModificationBlock {
public:
@ -1104,36 +1155,85 @@ namespace triagens {
~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
////////////////////////////////////////////////////////////////////////////////
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*>&);
};

View File

@ -159,6 +159,20 @@ struct Instanciator : public WalkerWorker<ExecutionNode> {
root = eb;
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: {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);

View File

@ -294,7 +294,7 @@ void IndexRangeNode::toJsonHelper (std::map<ExecutionNode*, int>& indexTab,
// put together the range info . . .
Json ranges(Json::List);
/*
for (auto x : *_ranges) {
Json item(Json::Array);
item("name", Json(x._name))
@ -304,7 +304,7 @@ void IndexRangeNode::toJsonHelper (std::map<ExecutionNode*, int>& indexTab,
("highOpen", Json(x._highOpen));
ranges(item);
}
*/
// Now put info about vocbase and cid in there
json("database", Json(_vocbase->_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
json("database", Json(_vocbase->_name))
("collection", Json(_collname))
("outVariable", _outVariable->toJson());
("collection", Json(_collection->name))
("inVariable", _inVariable->toJson());
// output variable might be empty
if (_outVariable != nullptr) {
json("outVariable", _outVariable->toJson());
}
// And add it:
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
json("database", Json(_vocbase->_name))
("collection", Json(_collname))
("outVariable", _outVariable->toJson());
("collection", Json(_collection->name))
("inVariable", _inVariable->toJson());
// output variable might be empty
if (_outVariable != nullptr) {
json("outVariable", _outVariable->toJson());
}
// And add it:
int len = static_cast<int>(nodes.size());

View File

@ -1455,6 +1455,7 @@ namespace triagens {
class ModificationNode : public ExecutionNode {
friend class ExecutionBlock;
friend class ModificationBlock;
////////////////////////////////////////////////////////////////////////////////
/// @brief constructor with a vocbase and a collection and options
@ -1728,7 +1729,7 @@ namespace triagens {
/// @brief class UpdateNode
////////////////////////////////////////////////////////////////////////////////
class UpdateNode : public ExecutionNode {
class UpdateNode : public ModificationNode {
friend class ExecutionBlock;
friend class UpdateBlock;
@ -1740,13 +1741,16 @@ namespace triagens {
public:
UpdateNode (TRI_vocbase_t* vocbase,
std::string collname,
Collection* collection,
ModificationOptions const& options,
Variable const* inVariable,
Variable const* outVariable)
: ExecutionNode(), _vocbase(vocbase), _collname(collname),
: ModificationNode(vocbase, collection, options),
_inVariable(inVariable),
_outVariable(outVariable) {
TRI_ASSERT(_vocbase != nullptr);
TRI_ASSERT(_outVariable != nullptr);
TRI_ASSERT(_inVariable != nullptr);
// _outVariable might be a nullptr
}
////////////////////////////////////////////////////////////////////////////////
@ -1770,7 +1774,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
virtual ExecutionNode* clone () const {
auto c = new UpdateNode(_vocbase, _collname, _outVariable);
auto c = new UpdateNode(_vocbase, _collection, _options, _inVariable, _outVariable);
cloneDependencies(c);
return static_cast<ExecutionNode*>(c);
}
@ -1784,6 +1788,28 @@ namespace triagens {
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
// -----------------------------------------------------------------------------
@ -1791,16 +1817,10 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief _vocbase, the database
/// @brief input variable
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_t* _vocbase;
////////////////////////////////////////////////////////////////////////////////
/// @brief _collname, the collection name
////////////////////////////////////////////////////////////////////////////////
std::string _collname;
Variable const* _inVariable;
////////////////////////////////////////////////////////////////////////////////
/// @brief output variable
@ -1818,7 +1838,7 @@ namespace triagens {
/// @brief class ReplaceNode
////////////////////////////////////////////////////////////////////////////////
class ReplaceNode : public ExecutionNode {
class ReplaceNode : public ModificationNode {
friend class ExecutionBlock;
friend class ReplaceBlock;
@ -1830,13 +1850,16 @@ namespace triagens {
public:
ReplaceNode (TRI_vocbase_t* vocbase,
std::string collname,
Collection* collection,
ModificationOptions const& options,
Variable const* inVariable,
Variable const* outVariable)
: ExecutionNode(), _vocbase(vocbase), _collname(collname),
: ModificationNode(vocbase, collection, options),
_inVariable(inVariable),
_outVariable(outVariable) {
TRI_ASSERT(_vocbase != nullptr);
TRI_ASSERT(_outVariable != nullptr);
TRI_ASSERT(_inVariable != nullptr);
// _outVariable might be a nullptr
}
////////////////////////////////////////////////////////////////////////////////
@ -1860,7 +1883,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
virtual ExecutionNode* clone () const {
auto c = new UpdateNode(_vocbase, _collname, _outVariable);
auto c = new ReplaceNode(_vocbase, _collection, _options, _inVariable, _outVariable);
cloneDependencies(c);
return static_cast<ExecutionNode*>(c);
}
@ -1874,6 +1897,28 @@ namespace triagens {
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
// -----------------------------------------------------------------------------
@ -1881,16 +1926,10 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief _vocbase, the database
/// @brief input variable
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_t* _vocbase;
////////////////////////////////////////////////////////////////////////////////
/// @brief _collname, the collection name
////////////////////////////////////////////////////////////////////////////////
std::string _collname;
Variable const* _inVariable;
////////////////////////////////////////////////////////////////////////////////
/// @brief output variable

View File

@ -120,7 +120,6 @@ ModificationOptions ExecutionPlan::createOptions (AstNode const* node) {
auto name = member->getStringValue();
auto value = member->getMember(0);
std::cout << "VALUE: " << value->typeString() << "\n";
TRI_ASSERT(value->isConstant());
if (strcmp(name, "waitForSync") == 0) {
@ -129,6 +128,10 @@ std::cout << "VALUE: " << value->typeString() << "\n";
else if (strcmp(name, "ignoreErrors") == 0) {
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,
AstNode const* node) {
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 expression = node->getMember(1);
// collection, expression
char const* collectionName = collection->getStringValue();
auto options = createOptions(node->getMember(0));
char const* collectionName = node->getMember(1)->getStringValue();
auto collections = ast->query()->collections();
auto collection = collections->get(collectionName);
auto expression = node->getMember(2);
// auto keyExpression = node->getMember(3);
ExecutionNode* en = nullptr;
if (expression->type == NODE_TYPE_REFERENCE) {
// operand is already a variable
auto v = static_cast<Variable*>(expression->getData());
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 {
// operand is some misc expression
auto calc = createTemporaryCalculation(ast, expression);
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;
}
@ -631,26 +635,27 @@ ExecutionNode* ExecutionPlan::fromNodeReplace (Ast const* ast,
ExecutionNode* previous,
AstNode const* node) {
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 expression = node->getMember(1);
// collection, expression
char const* collectionName = collection->getStringValue();
auto options = createOptions(node->getMember(0));
char const* collectionName = node->getMember(1)->getStringValue();
auto collections = ast->query()->collections();
auto collection = collections->get(collectionName);
auto expression = node->getMember(2);
// auto keyExpression = node->getMember(3);
ExecutionNode* en = nullptr;
if (expression->type == NODE_TYPE_REFERENCE) {
// operand is already a variable
auto v = static_cast<Variable*>(expression->getData());
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 {
// operand is some misc expression
auto calc = createTemporaryCalculation(ast, expression);
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;
}
@ -723,13 +728,11 @@ ExecutionNode* ExecutionPlan::fromNode (Ast const* ast,
}
case NODE_TYPE_UPDATE: {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
en = fromNodeUpdate(ast, en, member);
break;
}
case NODE_TYPE_REPLACE: {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
en = fromNodeReplace(ast, en, member);
break;
}

View File

@ -49,7 +49,8 @@ namespace triagens {
ModificationOptions ()
: ignoreErrors(false),
waitForSync(false) {
waitForSync(false),
nullMeansRemove(false) {
}
// -----------------------------------------------------------------------------
@ -58,6 +59,7 @@ namespace triagens {
bool ignoreErrors;
bool waitForSync;
bool nullMeansRemove;
};

View File

@ -637,8 +637,8 @@ namespace triagens {
#define YY_INPUT(resultBuffer, resultState, maxBytesToRead) { \
size_t length = yyextra->remainingLength(); \
if (length > maxBytesToRead) { \
length = maxBytesToRead; \
if (length > static_cast<size_t>(maxBytesToRead)) { \
length = static_cast<size_t>(maxBytesToRead); \
} \
if (length > 0) { \
yyextra->fillBuffer(resultBuffer, length); \

View File

@ -38,8 +38,8 @@ namespace triagens {
#define YY_INPUT(resultBuffer, resultState, maxBytesToRead) { \
size_t length = yyextra->remainingLength(); \
if (length > maxBytesToRead) { \
length = maxBytesToRead; \
if (length > static_cast<size_t>(maxBytesToRead)) { \
length = static_cast<size_t>(maxBytesToRead); \
} \
if (length > 0) { \
yyextra->fillBuffer(resultBuffer, length); \

View File

@ -495,6 +495,74 @@ namespace triagens {
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
// -----------------------------------------------------------------------------
@ -696,34 +764,6 @@ namespace triagens {
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
////////////////////////////////////////////////////////////////////////////////
@ -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
////////////////////////////////////////////////////////////////////////////////