mirror of https://gitee.com/bigwinds/arangodb
further work on RemoveNode
This commit is contained in:
parent
655d7759bf
commit
773c29cecf
|
@ -34,6 +34,7 @@
|
|||
|
||||
using namespace triagens::aql;
|
||||
using Json = triagens::basics::Json;
|
||||
using JsonHelper = triagens::basics::JsonHelper;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief a quick method to decide whether a value is true
|
||||
|
@ -156,6 +157,106 @@ bool AqlValue::isString () const {
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the AqlValue contains a list value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool AqlValue::isList () const {
|
||||
switch (_type) {
|
||||
case JSON: {
|
||||
TRI_json_t const* json = _json->json();
|
||||
return TRI_IsListJson(json);
|
||||
}
|
||||
|
||||
case SHAPED: {
|
||||
return false;
|
||||
}
|
||||
|
||||
case DOCVEC:
|
||||
case RANGE: {
|
||||
return true;
|
||||
}
|
||||
|
||||
case EMPTY: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the AqlValue contains an array value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool AqlValue::isArray () const {
|
||||
switch (_type) {
|
||||
case JSON: {
|
||||
TRI_json_t const* json = _json->json();
|
||||
return TRI_IsArrayJson(json);
|
||||
}
|
||||
|
||||
case SHAPED: {
|
||||
return true;
|
||||
}
|
||||
|
||||
case DOCVEC:
|
||||
case RANGE:
|
||||
case EMPTY: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a string representation of the AqlValue
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string AqlValue::toString () const {
|
||||
switch (_type) {
|
||||
case JSON: {
|
||||
TRI_json_t const* json = _json->json();
|
||||
TRI_ASSERT(TRI_IsStringJson(json));
|
||||
return std::string(json->_value._string.data, json->_value._string.length - 1);
|
||||
}
|
||||
|
||||
case SHAPED:
|
||||
case DOCVEC:
|
||||
case RANGE:
|
||||
case EMPTY: {
|
||||
// cannot convert these types
|
||||
}
|
||||
}
|
||||
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a string representation of the AqlValue
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char const* AqlValue::toChar () const {
|
||||
switch (_type) {
|
||||
case JSON: {
|
||||
TRI_json_t const* json = _json->json();
|
||||
TRI_ASSERT(TRI_IsStringJson(json));
|
||||
return json->_value._string.data;
|
||||
}
|
||||
|
||||
case SHAPED:
|
||||
case DOCVEC:
|
||||
case RANGE:
|
||||
case EMPTY: {
|
||||
// cannot convert these types
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief construct a V8 value as input for the expression execution in V8
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -327,6 +428,96 @@ Json AqlValue::toJson (AQL_TRANSACTION_V8* trx,
|
|||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract an attribute value from the AqlValue
|
||||
/// this will fail if the value is not an array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Json AqlValue::extractArrayMember (AQL_TRANSACTION_V8* trx,
|
||||
TRI_document_collection_t const* document,
|
||||
char const* name) const {
|
||||
switch (_type) {
|
||||
case JSON: {
|
||||
TRI_ASSERT(_json != nullptr);
|
||||
TRI_json_t const* json = _json->json();
|
||||
|
||||
if (TRI_IsArrayJson(json)) {
|
||||
TRI_json_t const* found = TRI_LookupArrayJson(json, name);
|
||||
|
||||
if (found != nullptr) {
|
||||
return Json(TRI_UNKNOWN_MEM_ZONE, TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, found));
|
||||
}
|
||||
}
|
||||
|
||||
// attribute does not exist or something went wrong - fall-through to returning null below
|
||||
return Json(Json::Null);
|
||||
}
|
||||
|
||||
case SHAPED: {
|
||||
TRI_ASSERT(document != nullptr);
|
||||
TRI_ASSERT(_marker != nullptr);
|
||||
|
||||
auto shaper = document->getShaper();
|
||||
|
||||
// look for the attribute name in the shape
|
||||
if (*name == '_') {
|
||||
if (strcmp(name, "_key") == 0) {
|
||||
// _key value is copied into JSON
|
||||
return Json(TRI_UNKNOWN_MEM_ZONE, TRI_EXTRACT_MARKER_KEY(_marker));
|
||||
}
|
||||
else if (strcmp(name, "_id") == 0) {
|
||||
std::string id(trx->resolver()->getCollectionName(document->_info._cid));
|
||||
id.push_back('/');
|
||||
id.append(TRI_EXTRACT_MARKER_KEY(_marker));
|
||||
return Json(TRI_UNKNOWN_MEM_ZONE, id);
|
||||
}
|
||||
else if (strcmp(name, "_rev") == 0) {
|
||||
TRI_voc_rid_t rid = TRI_EXTRACT_MARKER_RID(_marker);
|
||||
return Json(TRI_UNKNOWN_MEM_ZONE, JsonHelper::uint64String(TRI_UNKNOWN_MEM_ZONE, rid));
|
||||
}
|
||||
else if (strcmp(name, "_from") == 0) {
|
||||
std::string from(trx->resolver()->getCollectionName(TRI_EXTRACT_MARKER_FROM_CID(_marker)));
|
||||
from.push_back('/');
|
||||
from.append(TRI_EXTRACT_MARKER_FROM_KEY(_marker));
|
||||
return Json(TRI_UNKNOWN_MEM_ZONE, from);
|
||||
}
|
||||
else if (strcmp(name, "_to") == 0) {
|
||||
std::string to(trx->resolver()->getCollectionName(TRI_EXTRACT_MARKER_TO_CID(_marker)));
|
||||
to.push_back('/');
|
||||
to.append(TRI_EXTRACT_MARKER_TO_KEY(_marker));
|
||||
return Json(TRI_UNKNOWN_MEM_ZONE, to);
|
||||
}
|
||||
}
|
||||
|
||||
TRI_shape_pid_t pid = shaper->lookupAttributePathByName(shaper, name);
|
||||
if (pid != 0) {
|
||||
// attribute exists
|
||||
TRI_shaped_json_t document;
|
||||
TRI_EXTRACT_SHAPED_JSON_MARKER(document, _marker);
|
||||
|
||||
TRI_shaped_json_t json;
|
||||
TRI_shape_t const* shape;
|
||||
|
||||
bool ok = TRI_ExtractShapedJsonVocShaper(shaper, &document, 0, pid, &json, &shape);
|
||||
if (ok && shape != nullptr) {
|
||||
return Json(TRI_UNKNOWN_MEM_ZONE, TRI_JsonShapedJson(shaper, &json));
|
||||
}
|
||||
}
|
||||
|
||||
// attribute does not exist or something went wrong - fall-through to returning null
|
||||
break;
|
||||
}
|
||||
|
||||
case DOCVEC:
|
||||
case RANGE:
|
||||
case EMPTY: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Json(Json::Null);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AqlValue from a vector of AqlItemBlock*s
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -156,6 +156,32 @@ namespace triagens {
|
|||
|
||||
bool isString () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the AqlValue contains a list value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool isList () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the AqlValue contains an array value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool isArray () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a string representation of the AqlValue
|
||||
/// this will fail if the value is not a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string toString () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a string representation of the AqlValue
|
||||
/// this will fail if the value is not a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char const* toChar () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief construct a V8 value as input for the expression execution in V8
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -170,6 +196,15 @@ namespace triagens {
|
|||
triagens::basics::Json toJson (AQL_TRANSACTION_V8*,
|
||||
TRI_document_collection_t const*) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract an attribute value from the AqlValue
|
||||
/// this will fail if the value is not an array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
triagens::basics::Json extractArrayMember (AQL_TRANSACTION_V8*,
|
||||
TRI_document_collection_t const*,
|
||||
char const*) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AqlValue from a vector of AqlItemBlock*s
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -36,7 +36,17 @@
|
|||
#include "VocBase/collection.h"
|
||||
|
||||
using namespace triagens::aql;
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- static initialization
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initialize a singleton NOP node instance
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode const Ast::NopNode = { NODE_TYPE_NOP };
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors / destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -181,12 +191,18 @@ AstNode* Ast::createNodeReturn (AstNode const* expression) {
|
|||
|
||||
AstNode* Ast::createNodeRemove (AstNode const* expression,
|
||||
AstNode const* collection,
|
||||
AstNode* options) {
|
||||
AstNode const* options) {
|
||||
AstNode* node = createNode(NODE_TYPE_REMOVE);
|
||||
|
||||
if (options == nullptr) {
|
||||
// no options given. now use default options
|
||||
options = &NopNode;
|
||||
}
|
||||
|
||||
node->addMember(options);
|
||||
node->addMember(collection);
|
||||
node->addMember(expression);
|
||||
|
||||
// TODO: handle options
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -714,9 +730,7 @@ AstNode* Ast::createNodeRange (AstNode const* start,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeNop () {
|
||||
AstNode* node = createNode(NODE_TYPE_NOP);
|
||||
|
||||
return node;
|
||||
return const_cast<AstNode*>(&NopNode);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -253,7 +253,7 @@ namespace triagens {
|
|||
|
||||
AstNode* createNodeRemove (AstNode const*,
|
||||
AstNode const*,
|
||||
AstNode*);
|
||||
AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST insert node
|
||||
|
@ -679,6 +679,12 @@ namespace triagens {
|
|||
|
||||
AstNode const* _writeOptions;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief a singleton NOP node instance
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static AstNode const NopNode;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -236,6 +236,35 @@ void AstNode::toJson (TRI_json_t* json,
|
|||
TRI_PushBack3ListJson(zone, json, node);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief convert the node's value to a boolean value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool AstNode::toBoolean () const {
|
||||
if (type == NODE_TYPE_VALUE) {
|
||||
switch (value.type) {
|
||||
case VALUE_TYPE_BOOL: {
|
||||
return value.value._bool;
|
||||
}
|
||||
case VALUE_TYPE_INT: {
|
||||
return (value.value._int != 0);
|
||||
}
|
||||
case VALUE_TYPE_DOUBLE: {
|
||||
return value.value._double != 0.0;
|
||||
}
|
||||
case VALUE_TYPE_STRING: {
|
||||
return (*value.value._string != '\0');
|
||||
}
|
||||
case VALUE_TYPE_NULL:
|
||||
case VALUE_TYPE_FAIL: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not a node is simple enough to be used in a simple
|
||||
/// expression
|
||||
|
|
|
@ -181,6 +181,12 @@ namespace triagens {
|
|||
void toJson (TRI_json_t*,
|
||||
TRI_memory_zone_t*) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief convert the node's value to a boolean value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool toBoolean () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not a value node is of numeric type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -421,13 +427,31 @@ namespace triagens {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the node type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNodeType const type;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the node value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNodeValue value;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the node's sub nodes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vector_pointer_t members;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1888,65 +1888,114 @@ RemoveBlock::RemoveBlock (AQL_TRANSACTION_V8* trx,
|
|||
RemoveBlock::~RemoveBlock () {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get some - this accumulates all input and calls the remove() method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlItemBlock* RemoveBlock::getSome (size_t atLeast,
|
||||
size_t atMost) {
|
||||
|
||||
std::vector<AqlItemBlock*> blocks;
|
||||
|
||||
// loop over input until it is exhausted
|
||||
try {
|
||||
while (true) {
|
||||
auto res = ExecutionBlock::getSome(atLeast, atMost);
|
||||
|
||||
if (res == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
blocks.push_back(res);
|
||||
}
|
||||
|
||||
remove(blocks);
|
||||
for (auto it = blocks.begin(); it != blocks.end(); ++it) {
|
||||
delete (*it);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
catch (...) {
|
||||
for (auto it = blocks.begin(); it != blocks.end(); ++it) {
|
||||
delete (*it);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the actual work horse for removing data
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RemoveBlock::remove (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());
|
||||
RegisterId const registerId = it->second.registerId;
|
||||
|
||||
auto trxCollection = _trx->trxCollection(_collection->cid());
|
||||
|
||||
|
||||
if (ep->_outVariable == nullptr) {
|
||||
// don't return anything
|
||||
|
||||
// loop over input until it is exhausted
|
||||
while (true) {
|
||||
auto res = ExecutionBlock::getSome(atLeast, atMost);
|
||||
|
||||
if (res == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// loop over all blocks
|
||||
for (auto it = blocks.begin(); it != blocks.end(); ++it) {
|
||||
auto res = (*it);
|
||||
auto document = res->getDocumentCollection(registerId);
|
||||
|
||||
try {
|
||||
size_t const n = res->size();
|
||||
size_t const n = res->size();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
AqlValue a = res->getValue(i, registerId);
|
||||
// loop over the complete block
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
AqlValue a = res->getValue(i, registerId);
|
||||
|
||||
if (a.isEmpty()) {
|
||||
// no value for _key. TODO: should we fail with an error in this case?
|
||||
char const* key = nullptr;
|
||||
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* json = member.json();
|
||||
if (TRI_IsStringJson(json)) {
|
||||
key = json->_value._string.data;
|
||||
}
|
||||
else {
|
||||
errorCode = TRI_ERROR_ARANGO_DOCUMENT_KEY_MISSING;
|
||||
}
|
||||
}
|
||||
else if (a.isString()) {
|
||||
// value is a string
|
||||
key = a.toChar();
|
||||
}
|
||||
else {
|
||||
errorCode = TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID;
|
||||
}
|
||||
|
||||
if (errorCode != TRI_ERROR_NO_ERROR) {
|
||||
if (ep->_options.ignoreErrors) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (a.isString()) {
|
||||
std::cout << "VALUE IS A STRING\n";
|
||||
}
|
||||
|
||||
std::cout << JsonHelper::toString(a.toJson(_trx, document)) << "\n";
|
||||
std::string key = "gig";
|
||||
|
||||
int removed = TRI_RemoveShapedJsonDocumentCollection(trxCollection, (TRI_voc_key_t) key.c_str(), 0, nullptr, nullptr, false, false);
|
||||
|
||||
std::cout << "REMOVE RESULT: " << removed << "\n";
|
||||
THROW_ARANGO_EXCEPTION(errorCode);
|
||||
}
|
||||
else {
|
||||
// no error. we expect to have a key
|
||||
TRI_ASSERT(key != nullptr);
|
||||
|
||||
errorCode = TRI_RemoveShapedJsonDocumentCollection(trxCollection,
|
||||
(TRI_voc_key_t) key,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr,
|
||||
false,
|
||||
ep->_options.waitForSync);
|
||||
}
|
||||
delete res;
|
||||
}
|
||||
catch (...) {
|
||||
delete res;
|
||||
throw;
|
||||
}
|
||||
|
||||
(*it) = nullptr;
|
||||
delete res;
|
||||
}
|
||||
|
||||
// will never get here
|
||||
}
|
||||
|
||||
// NOT YET IMPLEMENTED
|
||||
TRI_ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -1058,6 +1058,18 @@ namespace triagens {
|
|||
virtual AqlItemBlock* getSome (size_t atLeast,
|
||||
size_t atMost);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the actual work horse for removing data
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void remove (std::vector<AqlItemBlock*>&);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "Aql/Collection.h"
|
||||
#include "Aql/Expression.h"
|
||||
#include "Aql/ModificationOptions.h"
|
||||
#include "Aql/Variable.h"
|
||||
#include "Aql/Types.h"
|
||||
#include "Aql/WalkerWorker.h"
|
||||
|
@ -1087,6 +1088,63 @@ namespace triagens {
|
|||
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class ModificationNode
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief abstract base class for modification operations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ModificationNode : public ExecutionNode {
|
||||
|
||||
friend class ExecutionBlock;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor with a vocbase and a collection and options
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
|
||||
ModificationNode (TRI_vocbase_t* vocbase,
|
||||
Collection* collection,
|
||||
ModificationOptions const& options)
|
||||
: ExecutionNode(),
|
||||
_vocbase(vocbase),
|
||||
_collection(collection),
|
||||
_options(options) {
|
||||
|
||||
TRI_ASSERT(_vocbase != nullptr);
|
||||
TRI_ASSERT(_collection != nullptr);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- protected variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
protected:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief _vocbase, the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* _vocbase;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Collection* _collection;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief modification operation options
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ModificationOptions _options;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class RemoveNode
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -1095,7 +1153,7 @@ namespace triagens {
|
|||
/// @brief class RemoveNode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class RemoveNode : public ExecutionNode {
|
||||
class RemoveNode : public ModificationNode {
|
||||
|
||||
friend class ExecutionBlock;
|
||||
friend class RemoveBlock;
|
||||
|
@ -1108,16 +1166,13 @@ namespace triagens {
|
|||
|
||||
RemoveNode (TRI_vocbase_t* vocbase,
|
||||
Collection* collection,
|
||||
ModificationOptions const& options,
|
||||
Variable const* inVariable,
|
||||
Variable const* outVariable)
|
||||
: ExecutionNode(),
|
||||
_vocbase(vocbase),
|
||||
_collection(collection),
|
||||
: ModificationNode(vocbase, collection, options),
|
||||
_inVariable(inVariable),
|
||||
_outVariable(outVariable) {
|
||||
|
||||
TRI_ASSERT(_vocbase != nullptr);
|
||||
TRI_ASSERT(_collection != nullptr);
|
||||
TRI_ASSERT(_inVariable != nullptr);
|
||||
// _outVariable might be a nullptr
|
||||
}
|
||||
|
@ -1143,7 +1198,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ExecutionNode* clone () const {
|
||||
auto c = new RemoveNode(_vocbase, _collection, _inVariable, _outVariable);
|
||||
auto c = new RemoveNode(_vocbase, _collection, _options, _inVariable, _outVariable);
|
||||
cloneDependencies(c);
|
||||
return static_cast<ExecutionNode*>(c);
|
||||
}
|
||||
|
@ -1164,18 +1219,6 @@ namespace triagens {
|
|||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief _vocbase, the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* _vocbase;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Collection* _collection;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief input variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -99,6 +99,37 @@ ExecutionPlan* ExecutionPlan::instanciateFromAst (Ast const* ast) {
|
|||
// --SECTION-- private functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create modification options from an AST node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ModificationOptions ExecutionPlan::createOptions (AstNode const* node) {
|
||||
ModificationOptions options;
|
||||
|
||||
// parse the modification options we got
|
||||
if (node != nullptr && node->type == NODE_TYPE_ARRAY) {
|
||||
size_t n = node->numMembers();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto member = node->getMember(i);
|
||||
if (member != nullptr && member->type == NODE_TYPE_ARRAY_ELEMENT) {
|
||||
auto name = member->getStringValue();
|
||||
auto value = member->getMember(0);
|
||||
|
||||
TRI_ASSERT(value->isConstant());
|
||||
|
||||
if (strcmp(name, "waitForSync") == 0) {
|
||||
options.waitForSync = value->toBoolean();
|
||||
}
|
||||
else if (strcmp(name, "ignoreErrors") == 0) {
|
||||
options.ignoreErrors = value->toBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a node to the plan, will delete node if addition fails
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -487,9 +518,10 @@ ExecutionNode* ExecutionPlan::fromNodeRemove (Ast const* ast,
|
|||
ExecutionNode* previous,
|
||||
AstNode const* node) {
|
||||
TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_REMOVE);
|
||||
TRI_ASSERT(node->numMembers() == 2);
|
||||
TRI_ASSERT(node->numMembers() == 3);
|
||||
|
||||
char const* collectionName = node->getMember(0)->getStringValue();
|
||||
auto options = createOptions(node->getMember(0));
|
||||
char const* collectionName = node->getMember(1)->getStringValue();
|
||||
auto collections = ast->query()->collections();
|
||||
auto collection = collections->get(collectionName);
|
||||
|
||||
|
@ -497,20 +529,20 @@ ExecutionNode* ExecutionPlan::fromNodeRemove (Ast const* ast,
|
|||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
auto expression = node->getMember(1);
|
||||
auto expression = node->getMember(2);
|
||||
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 RemoveNode(ast->query()->vocbase(), collection, v, nullptr));
|
||||
en = addNode(new RemoveNode(ast->query()->vocbase(), collection, options, v, nullptr));
|
||||
}
|
||||
else {
|
||||
// operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(ast, expression);
|
||||
calc->addDependency(previous);
|
||||
en = addNode(new RemoveNode(ast->query()->vocbase(), collection, calc->outVariable(), nullptr));
|
||||
en = addNode(new RemoveNode(ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr));
|
||||
previous = calc;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "Basics/Common.h"
|
||||
#include "arangod/Aql/ExecutionNode.h"
|
||||
#include "arangod/Aql/ModificationOptions.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace aql {
|
||||
|
@ -109,6 +110,12 @@ namespace triagens {
|
|||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create modification options from an AST node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ModificationOptions createOptions (AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a node to the plan, will delete node if addition fails
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -162,8 +162,6 @@ void Expression::analyzeExpression () {
|
|||
_type = V8;
|
||||
_canThrow = _node->canThrow();
|
||||
}
|
||||
|
||||
std::cout << "CAN THROW: " << _canThrow << "\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -191,70 +189,10 @@ AqlValue Expression::executeSimpleExpression (AstNode const* node,
|
|||
if (result._type == AqlValue::SHAPED) {
|
||||
TRI_ASSERT(myCollection != nullptr);
|
||||
|
||||
auto shaper = myCollection->getShaper();
|
||||
|
||||
// look for the attribute name in the shape
|
||||
if (*name == '_') {
|
||||
if (strcmp(name, "_key") == 0) {
|
||||
// _key value is copied into JSON
|
||||
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, TRI_EXTRACT_MARKER_KEY(result._marker)));
|
||||
}
|
||||
else if (strcmp(name, "_id") == 0) {
|
||||
std::string id(trx->resolver()->getCollectionName(myCollection->_info._cid));
|
||||
id.push_back('/');
|
||||
id.append(TRI_EXTRACT_MARKER_KEY(result._marker));
|
||||
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, id));
|
||||
}
|
||||
else if (strcmp(name, "_rev") == 0) {
|
||||
TRI_voc_rid_t rid = TRI_EXTRACT_MARKER_RID(result._marker);
|
||||
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, JsonHelper::uint64String(TRI_UNKNOWN_MEM_ZONE, rid)));
|
||||
}
|
||||
else if (strcmp(name, "_from") == 0) {
|
||||
std::string from(trx->resolver()->getCollectionName(TRI_EXTRACT_MARKER_FROM_CID(result._marker)));
|
||||
from.push_back('/');
|
||||
from.append(TRI_EXTRACT_MARKER_FROM_KEY(result._marker));
|
||||
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, from));
|
||||
}
|
||||
else if (strcmp(name, "_to") == 0) {
|
||||
std::string to(trx->resolver()->getCollectionName(TRI_EXTRACT_MARKER_TO_CID(result._marker)));
|
||||
to.push_back('/');
|
||||
to.append(TRI_EXTRACT_MARKER_TO_KEY(result._marker));
|
||||
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, to));
|
||||
}
|
||||
}
|
||||
|
||||
TRI_shape_pid_t pid = shaper->lookupAttributePathByName(shaper, name);
|
||||
if (pid != 0) {
|
||||
// attribute exists
|
||||
TRI_shaped_json_t document;
|
||||
TRI_EXTRACT_SHAPED_JSON_MARKER(document, result._marker);
|
||||
|
||||
TRI_shaped_json_t json;
|
||||
TRI_shape_t const* shape;
|
||||
|
||||
bool ok = TRI_ExtractShapedJsonVocShaper(shaper, &document, 0, pid, &json, &shape);
|
||||
if (ok && shape != nullptr) {
|
||||
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, TRI_JsonShapedJson(shaper, &json)));
|
||||
}
|
||||
}
|
||||
|
||||
// attribute does not exist or something went wrong - fall-through to returning null below
|
||||
auto j = result.extractArrayMember(trx, myCollection, name);
|
||||
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal()));
|
||||
}
|
||||
|
||||
else if (result._type == AqlValue::JSON) {
|
||||
TRI_json_t const* json = result._json->json();
|
||||
|
||||
if (TRI_IsArrayJson(json)) {
|
||||
TRI_json_t const* found = TRI_LookupArrayJson(json, name);
|
||||
|
||||
if (found != nullptr) {
|
||||
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, found)));
|
||||
}
|
||||
}
|
||||
|
||||
// attribute does not exist or something went wrong - fall-through to returning null below
|
||||
}
|
||||
|
||||
return AqlValue(new Json(Json::Null));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief AQL, data-modification query options
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2014 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Max Neunhoeffer
|
||||
/// @author Copyright 2014, triagens GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_AQL_MODIFICATION_OPTIONS_H
|
||||
#define ARANGODB_AQL_MODIFICATION_OPTIONS_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace aql {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief ModificationOptions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct ModificationOptions {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors / destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor, using default values
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ModificationOptions ()
|
||||
: ignoreErrors(false),
|
||||
waitForSync(false) {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool ignoreErrors;
|
||||
bool waitForSync;
|
||||
|
||||
};
|
||||
|
||||
} // namespace triagens::aql
|
||||
} // namespace triagens
|
||||
|
||||
#endif
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
|
||||
// End:
|
||||
|
Loading…
Reference in New Issue