1
0
Fork 0

Bug fix/pre release woes (#2988)

* fixed issue #2982

* updated CHANGELOG
This commit is contained in:
Jan 2017-08-10 09:39:28 +02:00 committed by Frank Celler
parent e8d6ff21d0
commit e6c6c5acda
14 changed files with 113 additions and 83 deletions

View File

@ -1,6 +1,12 @@
devel
-----
* fixed issue #2978: log something more obvious when you log a Buffer
* fixed issue #2982: AQL parse error?
* fixed docs for issue #2968: Collection _key autoincrement value increases on error
* fixed issue #3011: Optimizer rule reduce-extraction-to-projection breaks queries
* Now allowing to restore users in a sharded environment as well

View File

@ -23,10 +23,10 @@
#include "Aql/Ast.h"
#include "Aql/Arithmetic.h"
#include "Aql/Executor.h"
#include "Aql/Function.h"
#include "Aql/Graphs.h"
#include "Aql/Query.h"
#include "Aql/V8Executor.h"
#include "Basics/Exceptions.h"
#include "Basics/StringRef.h"
#include "Basics/StringUtils.h"
@ -1683,30 +1683,35 @@ void Ast::validateAndOptimize() {
std::unordered_map<Variable const*, AstNode const*> variableDefinitions;
int64_t stopOptimizationRequests = 0;
int64_t nestingLevel = 0;
bool isInFilter = false;
int64_t filterDepth = -1; // -1 = not in filter
bool hasSeenAnyWriteNode = false;
bool hasSeenWriteNodeInCurrentScope = false;
};
auto preVisitor = [&](AstNode const* node, void* data) -> bool {
auto ctx = static_cast<TraversalContext*>(data);
if (ctx->filterDepth >= 0) {
++ctx->filterDepth;
}
if (node->type == NODE_TYPE_FILTER) {
static_cast<TraversalContext*>(data)->isInFilter = true;
TRI_ASSERT(ctx->filterDepth == -1);
ctx->filterDepth = 0;
} else if (node->type == NODE_TYPE_FCALL) {
auto func = static_cast<Function*>(node->getData());
TRI_ASSERT(func != nullptr);
if (func->externalName == "NOOPT") {
// NOOPT will turn all function optimizations off
++(static_cast<TraversalContext*>(data)->stopOptimizationRequests);
++(ctx->stopOptimizationRequests);
}
} else if (node->type == NODE_TYPE_COLLECTION) {
// note the level on which we first saw a collection
auto c = static_cast<TraversalContext*>(data);
c->collectionsFirstSeen.emplace(node->getString(), c->nestingLevel);
ctx->collectionsFirstSeen.emplace(node->getString(), ctx->nestingLevel);
} else if (node->type == NODE_TYPE_AGGREGATIONS) {
++(static_cast<TraversalContext*>(data)->stopOptimizationRequests);
++ctx->stopOptimizationRequests;
} else if (node->type == NODE_TYPE_SUBQUERY) {
++static_cast<TraversalContext*>(data)->nestingLevel;
++ctx->nestingLevel;
} else if (node->hasFlag(FLAG_BIND_PARAMETER)) {
return false;
} else if (node->type == NODE_TYPE_REMOVE ||
@ -1714,42 +1719,44 @@ void Ast::validateAndOptimize() {
node->type == NODE_TYPE_UPDATE ||
node->type == NODE_TYPE_REPLACE ||
node->type == NODE_TYPE_UPSERT) {
auto c = static_cast<TraversalContext*>(data);
if (c->hasSeenWriteNodeInCurrentScope) {
if (ctx->hasSeenWriteNodeInCurrentScope) {
// no two data-modification nodes are allowed in the same scope
THROW_ARANGO_EXCEPTION(TRI_ERROR_QUERY_MULTI_MODIFY);
}
c->hasSeenWriteNodeInCurrentScope = true;
ctx->hasSeenWriteNodeInCurrentScope = true;
}
return true;
};
auto postVisitor = [&](AstNode const* node, void* data) -> void {
auto ctx = static_cast<TraversalContext*>(data);
if (ctx->filterDepth >= 0) {
--ctx->filterDepth;
}
if (node->type == NODE_TYPE_FILTER) {
static_cast<TraversalContext*>(data)->isInFilter = false;
ctx->filterDepth = -1;
} else if (node->type == NODE_TYPE_SUBQUERY) {
--static_cast<TraversalContext*>(data)->nestingLevel;
--ctx->nestingLevel;
} else if (node->type == NODE_TYPE_REMOVE ||
node->type == NODE_TYPE_INSERT ||
node->type == NODE_TYPE_UPDATE ||
node->type == NODE_TYPE_REPLACE ||
node->type == NODE_TYPE_UPSERT) {
auto c = static_cast<TraversalContext*>(data);
c->hasSeenAnyWriteNode = true;
ctx->hasSeenAnyWriteNode = true;
TRI_ASSERT(c->hasSeenWriteNodeInCurrentScope);
c->hasSeenWriteNodeInCurrentScope = false;
TRI_ASSERT(ctx->hasSeenWriteNodeInCurrentScope);
ctx->hasSeenWriteNodeInCurrentScope = false;
auto collection = node->getMember(1);
std::string name = collection->getString();
c->writeCollectionsSeen.emplace(name);
ctx->writeCollectionsSeen.emplace(name);
auto it = c->collectionsFirstSeen.find(name);
auto it = ctx->collectionsFirstSeen.find(name);
if (it != c->collectionsFirstSeen.end()) {
if ((*it).second < c->nestingLevel) {
if (it != ctx->collectionsFirstSeen.end()) {
if ((*it).second < ctx->nestingLevel) {
name = "collection '" + name;
name.push_back('\'');
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_ACCESS_AFTER_MODIFICATION, name.c_str());
@ -1761,10 +1768,10 @@ void Ast::validateAndOptimize() {
if (func->externalName == "NOOPT") {
// NOOPT will turn all function optimizations off
--(static_cast<TraversalContext*>(data)->stopOptimizationRequests);
--ctx->stopOptimizationRequests;
}
} else if (node->type == NODE_TYPE_AGGREGATIONS) {
--(static_cast<TraversalContext*>(data)->stopOptimizationRequests);
--ctx->stopOptimizationRequests;
}
};
@ -1787,7 +1794,7 @@ void Ast::validateAndOptimize() {
if (node->type == NODE_TYPE_OPERATOR_BINARY_AND ||
node->type == NODE_TYPE_OPERATOR_BINARY_OR) {
return this->optimizeBinaryOperatorLogical(
node, static_cast<TraversalContext*>(data)->isInFilter);
node, static_cast<TraversalContext*>(data)->filterDepth == 1);
}
if (node->type == NODE_TYPE_OPERATOR_BINARY_EQ ||
@ -2585,7 +2592,7 @@ AstNode* Ast::optimizeBinaryOperatorLogical(AstNode* node,
return createNodeValueBool(false);
}
// right-operand was trueish, now return it
// right-operand was trueish, now return just left
return lhs;
} else if (node->type == NODE_TYPE_OPERATOR_BINARY_OR) {
if (rhs->isTrue()) {

View File

@ -21,13 +21,13 @@
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "Aql/AstNode.h"
#include "AstNode.h"
#include "Aql/Ast.h"
#include "Aql/Executor.h"
#include "Aql/Function.h"
#include "Aql/Quantifier.h"
#include "Aql/Query.h"
#include "Aql/Scopes.h"
#include "Aql/V8Executor.h"
#include "Aql/types.h"
#include "Basics/StringBuffer.h"
#include "Basics/Utf8Helper.h"

View File

@ -26,13 +26,13 @@
#include "Aql/AqlValue.h"
#include "Aql/Ast.h"
#include "Aql/AttributeAccessor.h"
#include "Aql/Executor.h"
#include "Aql/ExpressionContext.h"
#include "Aql/BaseExpressionContext.h"
#include "Aql/Function.h"
#include "Aql/Functions.h"
#include "Aql/Quantifier.h"
#include "Aql/Query.h"
#include "Aql/V8Executor.h"
#include "Aql/V8Expression.h"
#include "Aql/Variable.h"
#include "Basics/Exceptions.h"

View File

@ -48,8 +48,8 @@ class AqlItemBlock;
struct AqlValue;
class Ast;
class AttributeAccessor;
class Executor;
class ExpressionContext;
class V8Executor;
struct V8Expression;
/// @brief AqlExpression, used in execution plans and execution blocks
@ -333,7 +333,7 @@ class Expression {
Ast* _ast;
/// @brief the V8 executor
Executor* _executor;
V8Executor* _executor;
/// @brief the AST node that contains the expression to execute
AstNode* _node;

View File

@ -28,7 +28,7 @@
#include "Aql/ExecutionBlock.h"
#include "Aql/ExecutionEngine.h"
#include "Aql/ExecutionPlan.h"
#include "Aql/Executor.h"
#include "Aql/V8Executor.h"
#include "Aql/Optimizer.h"
#include "Aql/Parser.h"
#include "Aql/PlanCache.h"
@ -1044,10 +1044,10 @@ void Query::engine(ExecutionEngine* engine) {
}
/// @brief get v8 executor
Executor* Query::executor() {
V8Executor* Query::executor() {
if (_executor == nullptr) {
// the executor is a singleton per query
_executor.reset(new Executor(_queryOptions.literalSizeThreshold));
_executor.reset(new V8Executor(_queryOptions.literalSizeThreshold));
}
TRI_ASSERT(_executor != nullptr);

View File

@ -61,10 +61,10 @@ struct AstNode;
class Ast;
class ExecutionEngine;
class ExecutionPlan;
class Executor;
class Query;
struct QueryProfile;
class QueryRegistry;
class V8Executor;
/// @brief equery part
enum QueryPart { PART_MAIN, PART_DEPENDENT };
@ -193,7 +193,7 @@ class Query {
QueryResult explain();
/// @brief get v8 executor
Executor* executor();
V8Executor* executor();
/// @brief return the engine, if prepared
ExecutionEngine* engine() const { return _engine.get(); }
@ -289,7 +289,7 @@ class Query {
TRI_vocbase_t* _vocbase;
/// @brief V8 code executor
std::unique_ptr<Executor> _executor;
std::unique_ptr<V8Executor> _executor;
/// @brief the currently used V8 context
V8Context* _context;

View File

@ -21,7 +21,7 @@
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "Executor.h"
#include "V8Executor.h"
#include "Aql/AstNode.h"
#include "Aql/AqlFunctionFeature.h"
#include "Aql/Functions.h"
@ -42,10 +42,10 @@ using namespace arangodb::aql;
/// @brief minimum number of array members / object attributes for considering
/// an array / object literal "big" and pulling it out of the expression
size_t const Executor::DefaultLiteralSizeThreshold = 32;
size_t const V8Executor::DefaultLiteralSizeThreshold = 32;
/// @brief creates an executor
Executor::Executor(int64_t literalSizeThreshold)
V8Executor::V8Executor(int64_t literalSizeThreshold)
: _buffer(nullptr),
_constantRegisters(),
_literalSizeThreshold(literalSizeThreshold >= 0
@ -53,10 +53,10 @@ Executor::Executor(int64_t literalSizeThreshold)
: DefaultLiteralSizeThreshold) {}
/// @brief destroys an executor
Executor::~Executor() { delete _buffer; }
V8Executor::~V8Executor() { delete _buffer; }
/// @brief generates an expression execution object
V8Expression* Executor::generateExpression(AstNode const* node) {
V8Expression* V8Executor::generateExpression(AstNode const* node) {
ISOLATE;
v8::HandleScope scope(isolate);
@ -69,7 +69,7 @@ V8Expression* Executor::generateExpression(AstNode const* node) {
generateCodeExpression(node);
// std::cout << "Executor::generateExpression: " <<
// std::cout << "V8Executor::generateExpression: " <<
// std::string(_buffer->c_str(), _buffer->length()) << "\n";
v8::Handle<v8::Object> constantValues = v8::Object::New(isolate);
for (auto const& it : _constantRegisters) {
@ -115,14 +115,14 @@ V8Expression* Executor::generateExpression(AstNode const* node) {
/// @brief executes an expression directly
/// this method is called during AST optimization and will be used to calculate
/// values for constant expressions
int Executor::executeExpression(Query* query, AstNode const* node,
int V8Executor::executeExpression(Query* query, AstNode const* node,
VPackBuilder& builder) {
ISOLATE;
_constantRegisters.clear();
generateCodeExpression(node);
// std::cout << "Executor::ExecuteExpression: " <<
// std::cout << "V8Executor::ExecuteExpression: " <<
// std::string(_buffer->c_str(), _buffer->length()) << "\n";
v8::HandleScope scope(isolate);
v8::TryCatch tryCatch;
@ -180,13 +180,13 @@ int Executor::executeExpression(Query* query, AstNode const* node,
}
/// @brief returns a reference to a built-in function
Function const* Executor::getFunctionByName(std::string const& name) {
Function const* V8Executor::getFunctionByName(std::string const& name) {
auto functions = AqlFunctionFeature::AQLFUNCTIONS;
return functions->byName(name);
}
/// @brief traverse the expression and note all user-defined functions
void Executor::detectUserFunctions(AstNode const* node) {
void V8Executor::detectUserFunctions(AstNode const* node) {
if (node == nullptr) {
return;
}
@ -202,7 +202,7 @@ void Executor::detectUserFunctions(AstNode const* node) {
}
/// @brief traverse the expression and note all (big) array/object literals
void Executor::detectConstantValues(AstNode const* node, AstNodeType previous) {
void V8Executor::detectConstantValues(AstNode const* node, AstNodeType previous) {
if (node == nullptr) {
return;
}
@ -248,7 +248,7 @@ void Executor::detectConstantValues(AstNode const* node, AstNodeType previous) {
}
/// @brief convert an AST node to a V8 object
v8::Handle<v8::Value> Executor::toV8(v8::Isolate* isolate,
v8::Handle<v8::Value> V8Executor::toV8(v8::Isolate* isolate,
AstNode const* node) const {
if (node->type == NODE_TYPE_ARRAY) {
size_t const n = node->numMembers();
@ -295,7 +295,7 @@ v8::Handle<v8::Value> Executor::toV8(v8::Isolate* isolate,
/// @brief checks if a V8 exception has occurred and throws an appropriate C++
/// exception from it if so
void Executor::HandleV8Error(v8::TryCatch& tryCatch,
void V8Executor::HandleV8Error(v8::TryCatch& tryCatch,
v8::Handle<v8::Value>& result,
arangodb::basics::StringBuffer* const buffer,
bool duringCompile) {
@ -391,7 +391,7 @@ void Executor::HandleV8Error(v8::TryCatch& tryCatch,
}
/// @brief generate JavaScript code for an arbitrary expression
void Executor::generateCodeExpression(AstNode const* node) {
void V8Executor::generateCodeExpression(AstNode const* node) {
// initialize and/or clear the buffer
initializeBuffer();
TRI_ASSERT(_buffer != nullptr);
@ -442,19 +442,19 @@ void Executor::generateCodeExpression(AstNode const* node) {
}
/// @brief generates code for a string value
void Executor::generateCodeString(char const* value, size_t length) {
void V8Executor::generateCodeString(char const* value, size_t length) {
TRI_ASSERT(value != nullptr);
_buffer->appendJsonEncoded(value, length);
}
/// @brief generates code for a string value
void Executor::generateCodeString(std::string const& value) {
void V8Executor::generateCodeString(std::string const& value) {
_buffer->appendJsonEncoded(value.c_str(), value.size());
}
/// @brief generate JavaScript code for an array
void Executor::generateCodeArray(AstNode const* node) {
void V8Executor::generateCodeArray(AstNode const* node) {
TRI_ASSERT(node != nullptr);
size_t const n = node->numMembers();
@ -484,7 +484,7 @@ void Executor::generateCodeArray(AstNode const* node) {
}
/// @brief generate JavaScript code for an array
void Executor::generateCodeForcedArray(AstNode const* node, int64_t levels) {
void V8Executor::generateCodeForcedArray(AstNode const* node, int64_t levels) {
TRI_ASSERT(node != nullptr);
if (levels > 1) {
@ -523,7 +523,7 @@ void Executor::generateCodeForcedArray(AstNode const* node, int64_t levels) {
}
/// @brief generate JavaScript code for an object
void Executor::generateCodeObject(AstNode const* node) {
void V8Executor::generateCodeObject(AstNode const* node) {
TRI_ASSERT(node != nullptr);
if (node->containsDynamicAttributeName()) {
@ -535,7 +535,7 @@ void Executor::generateCodeObject(AstNode const* node) {
/// @brief generate JavaScript code for an object with dynamically named
/// attributes
void Executor::generateCodeDynamicObject(AstNode const* node) {
void V8Executor::generateCodeDynamicObject(AstNode const* node) {
size_t const n = node->numMembers();
// very conservative minimum bound
_buffer->reserve(64 + n * 10);
@ -562,7 +562,7 @@ void Executor::generateCodeDynamicObject(AstNode const* node) {
/// @brief generate JavaScript code for an object without dynamically named
/// attributes
void Executor::generateCodeRegularObject(AstNode const* node) {
void V8Executor::generateCodeRegularObject(AstNode const* node) {
TRI_ASSERT(node != nullptr);
size_t const n = node->numMembers();
@ -598,7 +598,7 @@ void Executor::generateCodeRegularObject(AstNode const* node) {
}
/// @brief generate JavaScript code for a unary operator
void Executor::generateCodeUnaryOperator(AstNode const* node) {
void V8Executor::generateCodeUnaryOperator(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 1);
auto functions = AqlFunctionFeature::AQLFUNCTIONS;
@ -613,7 +613,7 @@ void Executor::generateCodeUnaryOperator(AstNode const* node) {
}
/// @brief generate JavaScript code for a binary operator
void Executor::generateCodeBinaryOperator(AstNode const* node) {
void V8Executor::generateCodeBinaryOperator(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 2);
auto functions = AqlFunctionFeature::AQLFUNCTIONS;
@ -642,7 +642,7 @@ void Executor::generateCodeBinaryOperator(AstNode const* node) {
}
/// @brief generate JavaScript code for a binary array operator
void Executor::generateCodeBinaryArrayOperator(AstNode const* node) {
void V8Executor::generateCodeBinaryArrayOperator(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 3);
auto functions = AqlFunctionFeature::AQLFUNCTIONS;
@ -667,7 +667,7 @@ void Executor::generateCodeBinaryArrayOperator(AstNode const* node) {
}
/// @brief generate JavaScript code for the ternary operator
void Executor::generateCodeTernaryOperator(AstNode const* node) {
void V8Executor::generateCodeTernaryOperator(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 3);
auto functions = AqlFunctionFeature::AQLFUNCTIONS;
@ -686,7 +686,7 @@ void Executor::generateCodeTernaryOperator(AstNode const* node) {
}
/// @brief generate JavaScript code for a variable (read) access
void Executor::generateCodeReference(AstNode const* node) {
void V8Executor::generateCodeReference(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 0);
@ -698,7 +698,7 @@ void Executor::generateCodeReference(AstNode const* node) {
}
/// @brief generate JavaScript code for a variable
void Executor::generateCodeVariable(AstNode const* node) {
void V8Executor::generateCodeVariable(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 0);
@ -710,7 +710,7 @@ void Executor::generateCodeVariable(AstNode const* node) {
}
/// @brief generate JavaScript code for a full collection access
void Executor::generateCodeCollection(AstNode const* node) {
void V8Executor::generateCodeCollection(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 0);
@ -720,7 +720,7 @@ void Executor::generateCodeCollection(AstNode const* node) {
}
/// @brief generate JavaScript code for a call to a built-in function
void Executor::generateCodeFunctionCall(AstNode const* node) {
void V8Executor::generateCodeFunctionCall(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 1);
@ -775,7 +775,7 @@ void Executor::generateCodeFunctionCall(AstNode const* node) {
}
/// @brief generate JavaScript code for a call to a user-defined function
void Executor::generateCodeUserFunctionCall(AstNode const* node) {
void V8Executor::generateCodeUserFunctionCall(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 1);
@ -798,7 +798,7 @@ void Executor::generateCodeUserFunctionCall(AstNode const* node) {
}
/// @brief generate JavaScript code for an expansion (i.e. [*] operator)
void Executor::generateCodeExpansion(AstNode const* node) {
void V8Executor::generateCodeExpansion(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 5);
@ -856,7 +856,7 @@ void Executor::generateCodeExpansion(AstNode const* node) {
}
/// @brief generate JavaScript code for an expansion iterator
void Executor::generateCodeExpansionIterator(AstNode const* node) {
void V8Executor::generateCodeExpansionIterator(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 2);
@ -865,7 +865,7 @@ void Executor::generateCodeExpansionIterator(AstNode const* node) {
}
/// @brief generate JavaScript code for a range (i.e. 1..10)
void Executor::generateCodeRange(AstNode const* node) {
void V8Executor::generateCodeRange(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 2);
@ -877,7 +877,7 @@ void Executor::generateCodeRange(AstNode const* node) {
}
/// @brief generate JavaScript code for a named attribute access
void Executor::generateCodeNamedAccess(AstNode const* node) {
void V8Executor::generateCodeNamedAccess(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 1);
@ -889,7 +889,7 @@ void Executor::generateCodeNamedAccess(AstNode const* node) {
}
/// @brief generate JavaScript code for a bound attribute access
void Executor::generateCodeBoundAccess(AstNode const* node) {
void V8Executor::generateCodeBoundAccess(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 2);
@ -901,7 +901,7 @@ void Executor::generateCodeBoundAccess(AstNode const* node) {
}
/// @brief generate JavaScript code for an indexed attribute access
void Executor::generateCodeIndexedAccess(AstNode const* node) {
void V8Executor::generateCodeIndexedAccess(AstNode const* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 2);
@ -914,7 +914,7 @@ void Executor::generateCodeIndexedAccess(AstNode const* node) {
}
/// @brief generate JavaScript code for a node
void Executor::generateCodeNode(AstNode const* node) {
void V8Executor::generateCodeNode(AstNode const* node) {
TRI_ASSERT(node != nullptr);
switch (node->type) {
@ -1028,7 +1028,7 @@ void Executor::generateCodeNode(AstNode const* node) {
}
/// @brief create the string buffer
arangodb::basics::StringBuffer* Executor::initializeBuffer() {
arangodb::basics::StringBuffer* V8Executor::initializeBuffer() {
if (_buffer == nullptr) {
_buffer = new arangodb::basics::StringBuffer(TRI_UNKNOWN_MEM_ZONE, 512, false);

View File

@ -21,8 +21,8 @@
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_AQL_EXECUTOR_H
#define ARANGOD_AQL_EXECUTOR_H 1
#ifndef ARANGOD_AQL_V8EXECUTOR_H
#define ARANGOD_AQL_V8EXECUTOR_H 1
#include "Basics/Common.h"
#include "Aql/AstNode.h"
@ -44,13 +44,13 @@ struct Function;
class Query;
struct V8Expression;
class Executor {
class V8Executor {
public:
/// @brief create the executor
explicit Executor(int64_t);
explicit V8Executor(int64_t);
/// @brief destroy the executor
~Executor();
~V8Executor();
public:
/// @brief generates an expression execution object

View File

@ -23,9 +23,9 @@
#include "V8Expression.h"
#include "Aql/AqlItemBlock.h"
#include "Aql/Executor.h"
#include "Aql/ExpressionContext.h"
#include "Aql/Query.h"
#include "Aql/V8Executor.h"
#include "Aql/Variable.h"
#include "Basics/VelocyPackHelper.h"
#include "V8/v8-conv.h"
@ -133,7 +133,7 @@ AqlValue V8Expression::execute(v8::Isolate* isolate, Query* query,
v8g->_query = old;
Executor::HandleV8Error(tryCatch, result, nullptr, false);
V8Executor::HandleV8Error(tryCatch, result, nullptr, false);
} catch (...) {
v8g->_query = old;
// bubble up exception

View File

@ -129,7 +129,6 @@ SET(ARANGOD_SOURCES
Aql/ExecutionNode.cpp
Aql/ExecutionPlan.cpp
Aql/ExecutionStats.cpp
Aql/Executor.cpp
Aql/Expression.cpp
Aql/FixedVarExpressionContext.cpp
Aql/Function.cpp
@ -170,6 +169,7 @@ SET(ARANGOD_SOURCES
Aql/TraversalBlock.cpp
Aql/TraversalConditionFinder.cpp
Aql/TraversalNode.cpp
Aql/V8Executor.cpp
Aql/V8Expression.cpp
Aql/Variable.cpp
Aql/VariableGenerator.cpp

View File

@ -17,6 +17,10 @@ global.DEFINE_MODULE('buffer', (function () {
const exports = {};
var SlowBuffer = require('internal').SlowBuffer;
SlowBuffer.prototype._PRINT = function(context) {
context.output += '[Buffer, length: ' + this.length + ']';
};
// Copyright Joyent, Inc. and other Node contributors.
//
@ -230,6 +234,10 @@ global.DEFINE_MODULE('buffer', (function () {
this.offset = 0;
}
this._PRINT = function(context) {
context.output += '[Buffer, length: ' + this.length + ']';
};
// optimize by branching logic for new allocations
if (typeof subject !== 'number') {
if (type === 'string') {

View File

@ -867,3 +867,8 @@ int TRI_AppendCsvDoubleStringBuffer(TRI_string_buffer_t* self, double d) {
AppendChar(self, ';');
return TRI_ERROR_NO_ERROR;
}
std::ostream& operator<<(std::ostream& stream, arangodb::basics::StringBuffer const& buffer) {
stream.write(buffer.begin(), buffer.length());
return stream;
}

View File

@ -29,6 +29,7 @@
#include "Zip/zip.h"
#include <sstream>
#include <iosfwd>
/// @brief string buffer with formatting routines
struct TRI_string_buffer_t {
@ -467,6 +468,7 @@ class StringBuffer {
/// @brief returns length of the character buffer
size_t length() const { return TRI_LengthStringBuffer(&_buffer); }
size_t size() const { return TRI_LengthStringBuffer(&_buffer); }
/// @brief returns capacity of the character buffer
size_t capacity() const { return TRI_CapacityStringBuffer(&_buffer); }
@ -767,4 +769,6 @@ class StringBuffer {
}
}
std::ostream& operator<<(std::ostream&, arangodb::basics::StringBuffer const&);
#endif