1
0
Fork 0

specialized attribute accessor for AQL

This commit is contained in:
Jan Steemann 2015-04-20 13:26:04 +02:00
parent 0ffac810d4
commit d20c104d0c
7 changed files with 301 additions and 41 deletions

View File

@ -831,36 +831,40 @@ Json AqlValue::extractObjectMember (triagens::arango::AqlTransaction* trx,
TRI_ASSERT(_marker != nullptr);
// look for the attribute name in the shape
if (*name == '_') {
if (strcmp(name, TRI_VOC_ATTRIBUTE_KEY) == 0) {
if (*name == '_' && name[1] != '\0') {
if (name[1] == 'k' && strcmp(name, TRI_VOC_ATTRIBUTE_KEY) == 0) {
// _key value is copied into JSON
return Json(TRI_UNKNOWN_MEM_ZONE, TRI_EXTRACT_MARKER_KEY(_marker));
}
else if (strcmp(name, TRI_VOC_ATTRIBUTE_ID) == 0) {
if (name[1] == 'i' && strcmp(name, TRI_VOC_ATTRIBUTE_ID) == 0) {
// _id
buffer.reset();
trx->resolver()->getCollectionName(document->_info._cid, buffer);
buffer.appendChar('/');
buffer.appendText(TRI_EXTRACT_MARKER_KEY(_marker));
return Json(TRI_UNKNOWN_MEM_ZONE, buffer.c_str(), buffer.length());
}
else if (strcmp(name, TRI_VOC_ATTRIBUTE_REV) == 0) {
if (name[1] == 'r' && strcmp(name, TRI_VOC_ATTRIBUTE_REV) == 0) {
// _rev
TRI_voc_rid_t rid = TRI_EXTRACT_MARKER_RID(_marker);
buffer.reset();
buffer.appendInteger(rid);
return Json(TRI_UNKNOWN_MEM_ZONE, buffer.c_str(), buffer.length());
}
else if (strcmp(name, TRI_VOC_ATTRIBUTE_FROM) == 0 &&
(_marker->_type == TRI_DOC_MARKER_KEY_EDGE ||
_marker->_type == TRI_WAL_MARKER_EDGE)) {
if (name[1] == 'f' &&
strcmp(name, TRI_VOC_ATTRIBUTE_FROM) == 0 &&
(_marker->_type == TRI_DOC_MARKER_KEY_EDGE ||
_marker->_type == TRI_WAL_MARKER_EDGE)) {
buffer.reset();
trx->resolver()->getCollectionNameCluster(TRI_EXTRACT_MARKER_FROM_CID(_marker), buffer);
buffer.appendChar('/');
buffer.appendText(TRI_EXTRACT_MARKER_FROM_KEY(_marker));
return Json(TRI_UNKNOWN_MEM_ZONE, buffer.c_str(), buffer.length());
}
else if (strcmp(name, TRI_VOC_ATTRIBUTE_TO) == 0 &&
(_marker->_type == TRI_DOC_MARKER_KEY_EDGE ||
_marker->_type == TRI_WAL_MARKER_EDGE)) {
if (name[1] == 't' &&
strcmp(name, TRI_VOC_ATTRIBUTE_TO) == 0 &&
(_marker->_type == TRI_DOC_MARKER_KEY_EDGE ||
_marker->_type == TRI_WAL_MARKER_EDGE)) {
buffer.reset();
trx->resolver()->getCollectionNameCluster(TRI_EXTRACT_MARKER_TO_CID(_marker), buffer);
buffer.appendChar('/');

View File

@ -0,0 +1,107 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief AQL, specialized attribute accessor for expressions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-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 ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "AttributeAccessor.h"
#include "Aql/Variable.h"
#include "Basics/StringBuffer.h"
#include "Basics/json.h"
#include "ShapedJson/shaped-json.h"
#include "VocBase/document-collection.h"
using namespace triagens::aql;
using Json = triagens::basics::Json;
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief create the accessor
////////////////////////////////////////////////////////////////////////////////
AttributeAccessor::AttributeAccessor (char const* name,
Variable const* variable)
: _name(name),
_variable(variable),
_buffer(TRI_UNKNOWN_MEM_ZONE) {
TRI_ASSERT(_name != nullptr);
TRI_ASSERT(_variable != nullptr);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroy the accessor
////////////////////////////////////////////////////////////////////////////////
AttributeAccessor::~AttributeAccessor () {
}
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief execute the accessor
////////////////////////////////////////////////////////////////////////////////
AqlValue AttributeAccessor::get (triagens::arango::AqlTransaction* trx,
std::vector<TRI_document_collection_t const*>& docColls,
std::vector<AqlValue>& argv,
size_t startPos,
std::vector<Variable*> const& vars,
std::vector<RegisterId> const& regs) {
size_t i = 0;
for (auto it = vars.begin(); it != vars.end(); ++it, ++i) {
if ((*it)->id == _variable->id) {
// save the collection info
TRI_document_collection_t const* collection = docColls[regs[i]];
// get the AQL value
auto& result = argv[startPos + regs[i]];
// extract the attribute
auto j = result.extractObjectMember(trx, collection, _name, true, _buffer);
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal()));
}
// fall-through intentional
}
return AqlValue(new Json(Json::Null));
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,117 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief AQL, specialized attribute accessor for expressions
///
/// @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_ATTRIBUTE_ACCESSOR_H
#define ARANGODB_AQL_ATTRIBUTE_ACCESSOR_H 1
#include "Basics/Common.h"
#include "Aql/AqlValue.h"
#include "Aql/types.h"
#include "Basics/StringBuffer.h"
#include "Utils/AqlTransaction.h"
struct TRI_document_collection_t;
namespace triagens {
namespace aql {
class Variable;
////////////////////////////////////////////////////////////////////////////////
/// @brief AttributeAccessor
////////////////////////////////////////////////////////////////////////////////
class AttributeAccessor {
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////
AttributeAccessor (char const*,
Variable const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////
~AttributeAccessor ();
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief execute the accessor
////////////////////////////////////////////////////////////////////////////////
AqlValue get (triagens::arango::AqlTransaction* trx,
std::vector<TRI_document_collection_t const*>&,
std::vector<AqlValue>&,
size_t,
std::vector<Variable*> const&,
std::vector<RegisterId> const&);
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief the attribute name
////////////////////////////////////////////////////////////////////////////////
char const* _name;
////////////////////////////////////////////////////////////////////////////////
/// @brief the accessed variable
////////////////////////////////////////////////////////////////////////////////
Variable const* _variable;
////////////////////////////////////////////////////////////////////////////////
/// @brief buffer for temporary strings
////////////////////////////////////////////////////////////////////////////////
triagens::basics::StringBuffer _buffer;
};
} // namespace triagens::aql
} // namespace triagens
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -30,15 +30,16 @@
#include "Aql/Expression.h"
#include "Aql/AqlValue.h"
#include "Aql/Ast.h"
#include "Aql/AttributeAccessor.h"
#include "Aql/Executor.h"
#include "Aql/V8Expression.h"
#include "Aql/Variable.h"
#include "Basics/Exceptions.h"
#include "Basics/JsonHelper.h"
#include "Basics/StringBuffer.h"
#include "Basics/json.h"
#include "ShapedJson/shaped-json.h"
#include "VocBase/document-collection.h"
#include "Basics/Exceptions.h"
using namespace triagens::aql;
using Json = triagens::basics::Json;
@ -112,15 +113,28 @@ Expression::Expression (Ast* ast,
Expression::~Expression () {
if (_built) {
if (_type == V8) {
delete _func;
_func = nullptr;
}
else if (_type == JSON) {
TRI_ASSERT(_data != nullptr);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _data);
_data = nullptr;
// _json is freed automatically by AqlItemBlock
switch (_type) {
case JSON:
TRI_ASSERT(_data != nullptr);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _data);
break;
case ATTRIBUTE: {
TRI_ASSERT(_accessor != nullptr);
delete _accessor;
break;
}
case V8:
delete _func;
break;
case SIMPLE:
case UNPROCESSED: {
// nothing to do
break;
}
}
}
}
@ -163,6 +177,15 @@ AqlValue Expression::execute (triagens::arango::AqlTransaction* trx,
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, _data, Json::NOFREE));
}
case SIMPLE: {
return executeSimpleExpression(_node, collection, trx, docColls, argv, startPos, vars, regs);
}
case ATTRIBUTE: {
TRI_ASSERT(_accessor != nullptr);
return _accessor->get(trx, docColls, argv, startPos, vars, regs);
}
case V8: {
TRI_ASSERT(_func != nullptr);
try {
@ -184,10 +207,6 @@ AqlValue Expression::execute (triagens::arango::AqlTransaction* trx,
}
}
case SIMPLE: {
return executeSimpleExpression(_node, collection, trx, docColls, argv, startPos, vars, regs);
}
case UNPROCESSED: {
// fall-through to exception
}
@ -323,6 +342,20 @@ void Expression::analyzeExpression () {
_canThrow = _node->canThrow();
_canRunOnDBServer = _node->canRunOnDBServer();
_isDeterministic = _node->isDeterministic();
if (_node->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
TRI_ASSERT_EXPENSIVE(_node->numMembers() == 1);
auto member = _node->getMemberUnchecked(0);
if (member->type == NODE_TYPE_REFERENCE) {
auto name = static_cast<char const*>(_node->getData());
auto v = static_cast<Variable const*>(member->getData());
// specialize the simple expression into an attribute accessor
_accessor = new AttributeAccessor(name, v);
_type = ATTRIBUTE;
}
}
}
else {
// expression is a V8 expression
@ -772,13 +805,13 @@ bool Expression::isConstant () const {
////////////////////////////////////////////////////////////////////////////////
/// @brief this gives you ("variable.access", "Reference")
/// call isSimpleAccessReference in advance to ensure no exceptions.
/// call isAttributeAccess in advance to ensure no exceptions.
////////////////////////////////////////////////////////////////////////////////
std::pair<std::string, std::string> Expression::getMultipleAttributes() {
if (! isSimple()) {
if (_type != SIMPLE && _type != ATTRIBUTE) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"getAccessNRef works only on simple expressions!");
"getMultipleAttributes works only on simple expressions or attribute accesses!");
}
auto expNode = _node;

View File

@ -50,6 +50,7 @@ namespace triagens {
class AqlItemBlock;
struct AqlValue;
class Ast;
class AttributeAccessor;
class Executor;
struct V8Expression;
@ -63,7 +64,8 @@ namespace triagens {
UNPROCESSED,
JSON,
V8,
SIMPLE
SIMPLE,
ATTRIBUTE
};
// -----------------------------------------------------------------------------
@ -164,22 +166,12 @@ namespace triagens {
AqlValue execute (triagens::arango::AqlTransaction* trx,
std::vector<TRI_document_collection_t const*>&,
std::vector<AqlValue>&, size_t,
std::vector<AqlValue>&,
size_t,
std::vector<Variable*> const&,
std::vector<RegisterId> const&,
TRI_document_collection_t const**);
////////////////////////////////////////////////////////////////////////////////
/// @brief check whether this is a simple expression
////////////////////////////////////////////////////////////////////////////////
inline bool isSimple () {
if (_type == UNPROCESSED) {
analyzeExpression();
}
return _type == SIMPLE;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check whether this is a JSON expression
////////////////////////////////////////////////////////////////////////////////
@ -210,11 +202,14 @@ namespace triagens {
if (_type == UNPROCESSED) {
analyzeExpression();
}
switch (_type) {
case JSON:
return "json";
case SIMPLE:
return "simple";
case ATTRIBUTE:
return "attribute";
case V8:
return "v8";
case UNPROCESSED: {
@ -245,7 +240,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
/// @brief this gives you ("variable.access", "Reference")
/// call isSimpleAccessReference in advance to ensure no exceptions.
/// call isAttributeAccess in advance to ensure no exceptions.
////////////////////////////////////////////////////////////////////////////////
std::pair<std::string, std::string> getMultipleAttributes();
@ -348,6 +343,8 @@ namespace triagens {
V8Expression* _func;
struct TRI_json_t* _data;
AttributeAccessor* _accessor;
};
////////////////////////////////////////////////////////////////////////////////

View File

@ -46,6 +46,7 @@ add_executable(
Aql/AqlValue.cpp
Aql/Ast.cpp
Aql/AstNode.cpp
Aql/AttributeAccessor.cpp
Aql/BindParameters.cpp
Aql/Collection.cpp
Aql/CollectionScanner.cpp

View File

@ -19,6 +19,7 @@ arangod_libarangod_a_SOURCES = \
arangod/Aql/AqlValue.cpp \
arangod/Aql/Ast.cpp \
arangod/Aql/AstNode.cpp \
arangod/Aql/AttributeAccessor.cpp \
arangod/Aql/BindParameters.cpp \
arangod/Aql/Collection.cpp \
arangod/Aql/CollectionScanner.cpp \