mirror of https://gitee.com/bigwinds/arangodb
488 lines
19 KiB
C++
488 lines
19 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief fundamental types for the optimisation and execution of AQL
|
|
///
|
|
/// @file arangod/Aql/AqlValue.h
|
|
///
|
|
/// 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_AQL_VALUE_H
|
|
#define ARANGODB_AQL_AQL_VALUE_H 1
|
|
|
|
#include "Basics/Common.h"
|
|
#include "Aql/Range.h"
|
|
#include "Aql/types.h"
|
|
#include "Basics/JsonHelper.h"
|
|
#include "Basics/StringBuffer.h"
|
|
#include "Utils/V8TransactionContext.h"
|
|
#include "Utils/AqlTransaction.h"
|
|
#include "VocBase/document-collection.h"
|
|
|
|
namespace triagens {
|
|
namespace aql {
|
|
|
|
class AqlItemBlock;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- struct AqlValue
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief a struct to hold a value, registers hole AqlValue* during the
|
|
/// execution
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct AqlValue {
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- typedefs
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief AqlValueType, indicates what sort of value we have
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
enum AqlValueType {
|
|
EMPTY, // contains no data
|
|
JSON, // Json*
|
|
SHAPED, // TRI_df_marker_t*
|
|
DOCVEC, // a vector of blocks of results coming from a subquery
|
|
RANGE // a pointer to a range remembering lower and upper bound
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- constructors / destructors
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructors for the various value types, note that they all take
|
|
/// ownership of the corresponding pointers
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
AqlValue ()
|
|
: _json(nullptr),
|
|
_type(EMPTY) {
|
|
}
|
|
|
|
explicit AqlValue (triagens::basics::Json* json)
|
|
: _json(json),
|
|
_type(JSON) {
|
|
}
|
|
|
|
explicit AqlValue (TRI_df_marker_t const* marker)
|
|
: _marker(marker),
|
|
_type(SHAPED) {
|
|
}
|
|
|
|
explicit AqlValue (std::vector<AqlItemBlock*>* vector)
|
|
: _vector(vector),
|
|
_type(DOCVEC) {
|
|
}
|
|
|
|
AqlValue (int64_t low, int64_t high)
|
|
: _range(nullptr),
|
|
_type(RANGE) {
|
|
_range = new Range(low, high);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief destructor, doing nothing automatically!
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
~AqlValue () {
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief return the value type
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline AqlValueType type () const throw() {
|
|
return _type;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief a quick method to decide whether the destroy value needs to be
|
|
/// called for a value
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool requiresDestruction () const throw() {
|
|
return (_type != EMPTY && _type != SHAPED);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief a quick method to decide whether a value is empty
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool isEmpty () const throw() {
|
|
return _type == EMPTY;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief whether or not the AqlValue is a shape
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool isShaped () const throw() {
|
|
return _type == SHAPED;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief whether or not the AqlValue is a JSON
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool isJson () const throw() {
|
|
return _type == JSON;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief whether or not the AqlValue is a RANGE
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool isRange () const throw() {
|
|
return _type == RANGE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief return the shape marker
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_df_marker_t const* getMarker () const {
|
|
TRI_ASSERT_EXPENSIVE(isShaped());
|
|
return _marker;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief return the range
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline Range const* getRange () const {
|
|
TRI_ASSERT(isRange());
|
|
return _range;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief a quick method to decide whether a value is true
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isTrue () const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief erase, this does not free the stuff in the AqlValue, it only
|
|
/// erases the pointers and makes the AqlValue structure EMPTY, this
|
|
/// is used when the AqlValue is stolen and stored in another object
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline void erase () throw() {
|
|
_type = EMPTY;
|
|
_json = nullptr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief destroy, explicit destruction, only when needed
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void destroy ();
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get the name of an AqlValue type
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
std::string getTypeString () const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief clone for recursive copying
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
AqlValue clone () const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief shallow clone
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
AqlValue shallowClone () const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief whether or not the AqlValue contains a string value
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isString () const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief whether or not the AqlValue contains a numeric value
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isNumber () const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief whether or not the AqlValue contains a boolean value
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isBoolean () const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief whether or not the AqlValue contains an array value
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isArray () const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief whether or not the AqlValue contains an object value
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isObject () const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief whether or not the AqlValue contains a null value
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isNull (bool emptyIsNull) const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns the array member at position i
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
triagens::basics::Json at (triagens::arango::AqlTransaction*,
|
|
size_t i) const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns the length of an AqlValue containing an array
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
size_t arraySize () const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get the numeric value of an AqlValue
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int64_t toInt64 () const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get the numeric value of an AqlValue
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
double toNumber () 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
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
v8::Handle<v8::Value> toV8 (v8::Isolate* isolate,
|
|
triagens::arango::AqlTransaction*,
|
|
TRI_document_collection_t const*) const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief construct a V8 value as input for the expression execution in V8
|
|
/// only construct those attributes that are needed in the expression
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
v8::Handle<v8::Value> toV8Partial (v8::Isolate* isolate,
|
|
triagens::arango::AqlTransaction*,
|
|
std::unordered_set<std::string> const&,
|
|
TRI_document_collection_t const*) const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief toJson method
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
triagens::basics::Json toJson (triagens::arango::AqlTransaction*,
|
|
TRI_document_collection_t const*,
|
|
bool) const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief creates a hash value for the AqlValue
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
uint64_t hash (triagens::arango::AqlTransaction*,
|
|
TRI_document_collection_t const*) const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief extract an attribute value from the AqlValue
|
|
/// this will return null if the value is not an object
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
triagens::basics::Json extractObjectMember (triagens::arango::AqlTransaction*,
|
|
TRI_document_collection_t const*,
|
|
char const*,
|
|
bool,
|
|
triagens::basics::StringBuffer&) const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief extract a value from an array AqlValue
|
|
/// this will return null if the value is not an array
|
|
/// depending on the last parameter, the return value will either contain a
|
|
/// copy of the original value in the array or a reference to it (which must
|
|
/// not be freed)
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
triagens::basics::Json extractArrayMember (triagens::arango::AqlTransaction*,
|
|
TRI_document_collection_t const*,
|
|
int64_t,
|
|
bool) const;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AqlValue from a vector of AqlItemBlock*s
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static AqlValue CreateFromBlocks (triagens::arango::AqlTransaction*,
|
|
std::vector<AqlItemBlock*> const&,
|
|
std::vector<std::string> const&);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AqlValue from a vector of AqlItemBlock*s
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static AqlValue CreateFromBlocks (triagens::arango::AqlTransaction*,
|
|
std::vector<AqlItemBlock*> const&,
|
|
triagens::aql::RegisterId);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief 3-way comparison for AqlValue objects
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int Compare (triagens::arango::AqlTransaction*,
|
|
AqlValue const&,
|
|
TRI_document_collection_t const*,
|
|
AqlValue const&,
|
|
TRI_document_collection_t const*,
|
|
bool compareUtf8);
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public variables
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief the actual data
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
union {
|
|
triagens::basics::Json* _json;
|
|
TRI_df_marker_t const* _marker;
|
|
std::vector<AqlItemBlock*>* _vector;
|
|
Range const* _range;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief _type, the type of value
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
AqlValueType _type;
|
|
|
|
};
|
|
|
|
} //closes namespace triagens::aql
|
|
} //closes namespace triagens
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- hash function helpers for AqlValue
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief hash function for AqlValue objects
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace std {
|
|
|
|
template<> struct hash<triagens::aql::AqlValue> {
|
|
size_t operator () (triagens::aql::AqlValue const& x) const {
|
|
std::hash<uint32_t> intHash;
|
|
std::hash<void const*> ptrHash;
|
|
size_t res = intHash(static_cast<uint32_t>(x._type));
|
|
switch (x._type) {
|
|
case triagens::aql::AqlValue::JSON: {
|
|
return res ^ ptrHash(x._json);
|
|
}
|
|
case triagens::aql::AqlValue::SHAPED: {
|
|
return res ^ ptrHash(x._marker);
|
|
}
|
|
case triagens::aql::AqlValue::DOCVEC: {
|
|
return res ^ ptrHash(x._vector);
|
|
}
|
|
case triagens::aql::AqlValue::RANGE: {
|
|
return res ^ ptrHash(x._range);
|
|
}
|
|
case triagens::aql::AqlValue::EMPTY: {
|
|
return res;
|
|
}
|
|
}
|
|
|
|
TRI_ASSERT(false);
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
template<> struct equal_to<triagens::aql::AqlValue> {
|
|
bool operator () (triagens::aql::AqlValue const& a,
|
|
triagens::aql::AqlValue const& b) const {
|
|
if (a._type != b._type) {
|
|
return false;
|
|
}
|
|
switch (a._type) {
|
|
case triagens::aql::AqlValue::JSON: {
|
|
return a._json == b._json;
|
|
}
|
|
case triagens::aql::AqlValue::SHAPED: {
|
|
return a._marker == b._marker;
|
|
}
|
|
case triagens::aql::AqlValue::DOCVEC: {
|
|
return a._vector == b._vector;
|
|
}
|
|
case triagens::aql::AqlValue::RANGE: {
|
|
return a._range == b._range;
|
|
}
|
|
// case triagens::aql::AqlValue::EMPTY intentionally not handled here!
|
|
// (should fall through and fail!)
|
|
|
|
default: {
|
|
TRI_ASSERT(false);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
} //closes namespace std
|
|
|
|
#endif
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
|
|
// End:
|
|
|