1
0
Fork 0
arangodb/arangod/Aql/AqlValue.h

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: