mirror of https://gitee.com/bigwinds/arangodb
do not remove constant sorts when creating plans, but during optimization phase
less utf8 comparisons
This commit is contained in:
parent
a27953cf3b
commit
61499432b7
|
@ -56,10 +56,8 @@ AqlItemBlock::AqlItemBlock (size_t nrItems,
|
|||
// this compare value is arbitrary, but having so many registers in a single query seems unlikely
|
||||
TRI_ASSERT(nrRegs <= ExecutionNode::MaxRegisterId);
|
||||
|
||||
_data.reserve(nrItems * nrRegs);
|
||||
for (size_t i = 0; i < nrItems * nrRegs; ++i) {
|
||||
_data.emplace_back();
|
||||
}
|
||||
_data.resize(nrItems * nrRegs);
|
||||
|
||||
_docColls.reserve(nrRegs);
|
||||
for (size_t i = 0; i < nrRegs; ++i) {
|
||||
_docColls.emplace_back(nullptr);
|
||||
|
@ -84,10 +82,7 @@ AqlItemBlock::AqlItemBlock (Json const& json) {
|
|||
|
||||
// Initialize the data vector:
|
||||
if (_nrRegs > 0) {
|
||||
_data.reserve(_nrItems * _nrRegs);
|
||||
for (size_t i = 0; i < _nrItems * _nrRegs; ++i) {
|
||||
_data.emplace_back();
|
||||
}
|
||||
_data.resize(_nrItems * _nrRegs);
|
||||
_docColls.reserve(_nrRegs);
|
||||
for (size_t i = 0; i < _nrRegs; ++i) {
|
||||
_docColls.emplace_back(nullptr);
|
||||
|
@ -178,17 +173,17 @@ AqlItemBlock::AqlItemBlock (Json const& json) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AqlItemBlock::destroy () {
|
||||
for (size_t i = 0; i < _nrItems * _nrRegs; i++) {
|
||||
if (! _data[i].isEmpty()) {
|
||||
for (auto& it : _data) {
|
||||
if (! it.isEmpty()) {
|
||||
try { // can find() really throw???
|
||||
auto it = _valueCount.find(_data[i]);
|
||||
if (it != _valueCount.end()) { // if we know it, we are still responsible
|
||||
TRI_ASSERT_EXPENSIVE(it->second > 0);
|
||||
|
||||
if (--(it->second) == 0) {
|
||||
_data[i].destroy();
|
||||
auto it2 = _valueCount.find(it);
|
||||
if (it2 != _valueCount.end()) { // if we know it, we are still responsible
|
||||
TRI_ASSERT_EXPENSIVE(it2->second > 0);
|
||||
|
||||
if (--(it2->second) == 0) {
|
||||
it.destroy();
|
||||
try {
|
||||
_valueCount.erase(it);
|
||||
_valueCount.erase(it2);
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ namespace triagens {
|
|||
/// @brief setValue, set the current value of a register
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setValue (size_t index, RegisterId varNr, AqlValue value) {
|
||||
void setValue (size_t index, RegisterId varNr, AqlValue const& value) {
|
||||
TRI_ASSERT_EXPENSIVE(_data.capacity() > index * _nrRegs + varNr);
|
||||
TRI_ASSERT_EXPENSIVE(_data.at(index * _nrRegs + varNr).isEmpty());
|
||||
|
||||
|
@ -132,7 +132,7 @@ namespace triagens {
|
|||
}
|
||||
else {
|
||||
TRI_ASSERT_EXPENSIVE(it->second > 0);
|
||||
it->second++;
|
||||
++(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,10 +75,8 @@ bool AqlValue::isTrue () const {
|
|||
void AqlValue::destroy () {
|
||||
switch (_type) {
|
||||
case JSON: {
|
||||
if (_json != nullptr) {
|
||||
delete _json;
|
||||
_json = nullptr;
|
||||
}
|
||||
delete _json;
|
||||
_json = nullptr;
|
||||
break;
|
||||
}
|
||||
case DOCVEC: {
|
||||
|
@ -701,6 +699,100 @@ Json AqlValue::toJson (triagens::arango::AqlTransaction* trx,
|
|||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief toJson method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t AqlValue::hash (triagens::arango::AqlTransaction* trx,
|
||||
TRI_document_collection_t const* document) const {
|
||||
switch (_type) {
|
||||
case JSON: {
|
||||
return TRI_HashJson(_json->json());
|
||||
}
|
||||
|
||||
case SHAPED: {
|
||||
TRI_ASSERT(document != nullptr);
|
||||
TRI_ASSERT(_marker != nullptr);
|
||||
|
||||
TRI_shaper_t* shaper = document->getShaper();
|
||||
TRI_shaped_json_t shaped;
|
||||
TRI_EXTRACT_SHAPED_JSON_MARKER(shaped, _marker);
|
||||
Json json(shaper->_memoryZone, TRI_JsonShapedJson(shaper, &shaped));
|
||||
|
||||
// append the internal attributes
|
||||
|
||||
// _id, _key, _rev
|
||||
char const* key = TRI_EXTRACT_MARKER_KEY(_marker);
|
||||
std::string id(trx->resolver()->getCollectionName(document->_info._cid));
|
||||
id.push_back('/');
|
||||
id.append(key);
|
||||
json(TRI_VOC_ATTRIBUTE_ID, Json(id));
|
||||
json(TRI_VOC_ATTRIBUTE_REV, Json(std::to_string(TRI_EXTRACT_MARKER_RID(_marker))));
|
||||
json(TRI_VOC_ATTRIBUTE_KEY, Json(key));
|
||||
|
||||
if (TRI_IS_EDGE_MARKER(_marker)) {
|
||||
// _from
|
||||
std::string from(trx->resolver()->getCollectionNameCluster(TRI_EXTRACT_MARKER_FROM_CID(_marker)));
|
||||
from.push_back('/');
|
||||
from.append(TRI_EXTRACT_MARKER_FROM_KEY(_marker));
|
||||
json(TRI_VOC_ATTRIBUTE_FROM, Json(from));
|
||||
|
||||
// _to
|
||||
std::string to(trx->resolver()->getCollectionNameCluster(TRI_EXTRACT_MARKER_TO_CID(_marker)));
|
||||
to.push_back('/');
|
||||
to.append(TRI_EXTRACT_MARKER_TO_KEY(_marker));
|
||||
json(TRI_VOC_ATTRIBUTE_TO, Json(to));
|
||||
}
|
||||
|
||||
return TRI_HashJson(json.json());
|
||||
}
|
||||
|
||||
case DOCVEC: {
|
||||
TRI_ASSERT(_vector != nullptr);
|
||||
|
||||
// calculate the result array length
|
||||
size_t totalSize = 0;
|
||||
for (auto it = _vector->begin(); it != _vector->end(); ++it) {
|
||||
totalSize += (*it)->size();
|
||||
}
|
||||
|
||||
// allocate the result array
|
||||
Json json(Json::Array, static_cast<size_t>(totalSize));
|
||||
|
||||
for (auto it = _vector->begin(); it != _vector->end(); ++it) {
|
||||
auto current = (*it);
|
||||
size_t const n = current->size();
|
||||
auto vecCollection = current->getDocumentCollection(0);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
json.add(current->getValue(i, 0).toJson(trx, vecCollection));
|
||||
}
|
||||
}
|
||||
|
||||
return TRI_HashJson(json.json());
|
||||
}
|
||||
|
||||
case RANGE: {
|
||||
TRI_ASSERT(_range != nullptr);
|
||||
|
||||
// allocate the buffer for the result
|
||||
size_t const n = _range->size();
|
||||
Json json(Json::Array, n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
// is it safe to use a double here (precision loss)?
|
||||
json.add(Json(static_cast<double>(_range->at(i))));
|
||||
}
|
||||
|
||||
return TRI_HashJson(json.json());
|
||||
}
|
||||
|
||||
case EMPTY: {
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract an attribute value from the AqlValue
|
||||
/// this will return an empty Json if the value is not an object
|
||||
|
@ -709,7 +801,8 @@ Json AqlValue::toJson (triagens::arango::AqlTransaction* trx,
|
|||
Json AqlValue::extractObjectMember (triagens::arango::AqlTransaction* trx,
|
||||
TRI_document_collection_t const* document,
|
||||
char const* name,
|
||||
bool copy) const {
|
||||
bool copy,
|
||||
triagens::basics::StringBuffer& buffer) const {
|
||||
switch (_type) {
|
||||
case JSON: {
|
||||
TRI_ASSERT(_json != nullptr);
|
||||
|
@ -744,30 +837,35 @@ Json AqlValue::extractObjectMember (triagens::arango::AqlTransaction* trx,
|
|||
return Json(TRI_UNKNOWN_MEM_ZONE, TRI_EXTRACT_MARKER_KEY(_marker));
|
||||
}
|
||||
else if (strcmp(name, TRI_VOC_ATTRIBUTE_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);
|
||||
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) {
|
||||
TRI_voc_rid_t rid = TRI_EXTRACT_MARKER_RID(_marker);
|
||||
return Json(TRI_UNKNOWN_MEM_ZONE, JsonHelper::uint64String(TRI_UNKNOWN_MEM_ZONE, rid));
|
||||
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)) {
|
||||
std::string from(trx->resolver()->getCollectionNameCluster(TRI_EXTRACT_MARKER_FROM_CID(_marker)));
|
||||
from.push_back('/');
|
||||
from.append(TRI_EXTRACT_MARKER_FROM_KEY(_marker));
|
||||
return Json(TRI_UNKNOWN_MEM_ZONE, from);
|
||||
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)) {
|
||||
std::string to(trx->resolver()->getCollectionNameCluster(TRI_EXTRACT_MARKER_TO_CID(_marker)));
|
||||
to.push_back('/');
|
||||
to.append(TRI_EXTRACT_MARKER_TO_KEY(_marker));
|
||||
return Json(TRI_UNKNOWN_MEM_ZONE, to);
|
||||
buffer.reset();
|
||||
trx->resolver()->getCollectionNameCluster(TRI_EXTRACT_MARKER_TO_CID(_marker), buffer);
|
||||
buffer.appendChar('/');
|
||||
buffer.appendText(TRI_EXTRACT_MARKER_TO_KEY(_marker));
|
||||
return Json(TRI_UNKNOWN_MEM_ZONE, buffer.c_str(), buffer.length());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -967,7 +1065,8 @@ int AqlValue::Compare (triagens::arango::AqlTransaction* trx,
|
|||
AqlValue const& left,
|
||||
TRI_document_collection_t const* leftcoll,
|
||||
AqlValue const& right,
|
||||
TRI_document_collection_t const* rightcoll) {
|
||||
TRI_document_collection_t const* rightcoll,
|
||||
bool compareUtf8) {
|
||||
if (left._type != right._type) {
|
||||
if (left._type == AqlValue::EMPTY) {
|
||||
return -1;
|
||||
|
@ -983,7 +1082,7 @@ int AqlValue::Compare (triagens::arango::AqlTransaction* trx,
|
|||
right._type == AqlValue::RANGE ||
|
||||
right._type == AqlValue::DOCVEC)) {
|
||||
triagens::basics::Json rjson = right.toJson(trx, rightcoll);
|
||||
return TRI_CompareValuesJson(left._json->json(), rjson.json(), true);
|
||||
return TRI_CompareValuesJson(left._json->json(), rjson.json(), compareUtf8);
|
||||
}
|
||||
|
||||
// SHAPED against x
|
||||
|
@ -991,12 +1090,12 @@ int AqlValue::Compare (triagens::arango::AqlTransaction* trx,
|
|||
triagens::basics::Json ljson = left.toJson(trx, leftcoll);
|
||||
|
||||
if (right._type == AqlValue::JSON) {
|
||||
return TRI_CompareValuesJson(ljson.json(), right._json->json(), true);
|
||||
return TRI_CompareValuesJson(ljson.json(), right._json->json(), compareUtf8);
|
||||
}
|
||||
else if (right._type == AqlValue::RANGE ||
|
||||
right._type == AqlValue::DOCVEC) {
|
||||
triagens::basics::Json rjson = right.toJson(trx, rightcoll);
|
||||
return TRI_CompareValuesJson(ljson.json(), rjson.json(), true);
|
||||
return TRI_CompareValuesJson(ljson.json(), rjson.json(), compareUtf8);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1005,12 +1104,12 @@ int AqlValue::Compare (triagens::arango::AqlTransaction* trx,
|
|||
triagens::basics::Json ljson = left.toJson(trx, leftcoll);
|
||||
|
||||
if (right._type == AqlValue::JSON) {
|
||||
return TRI_CompareValuesJson(ljson.json(), right._json->json(), true);
|
||||
return TRI_CompareValuesJson(ljson.json(), right._json->json(), compareUtf8);
|
||||
}
|
||||
else if (right._type == AqlValue::SHAPED ||
|
||||
right._type == AqlValue::DOCVEC) {
|
||||
triagens::basics::Json rjson = right.toJson(trx, rightcoll);
|
||||
return TRI_CompareValuesJson(ljson.json(), rjson.json(), true);
|
||||
return TRI_CompareValuesJson(ljson.json(), rjson.json(), compareUtf8);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1019,12 +1118,12 @@ int AqlValue::Compare (triagens::arango::AqlTransaction* trx,
|
|||
triagens::basics::Json ljson = left.toJson(trx, leftcoll);
|
||||
|
||||
if (right._type == AqlValue::JSON) {
|
||||
return TRI_CompareValuesJson(ljson.json(), right._json->json(), true);
|
||||
return TRI_CompareValuesJson(ljson.json(), right._json->json(), compareUtf8);
|
||||
}
|
||||
else if (right._type == AqlValue::SHAPED ||
|
||||
right._type == AqlValue::RANGE) {
|
||||
triagens::basics::Json rjson = right.toJson(trx, rightcoll);
|
||||
return TRI_CompareValuesJson(ljson.json(), rjson.json(), true);
|
||||
return TRI_CompareValuesJson(ljson.json(), rjson.json(), compareUtf8);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1040,7 +1139,7 @@ int AqlValue::Compare (triagens::arango::AqlTransaction* trx,
|
|||
}
|
||||
|
||||
case AqlValue::JSON: {
|
||||
return TRI_CompareValuesJson(left._json->json(), right._json->json(), true);
|
||||
return TRI_CompareValuesJson(left._json->json(), right._json->json(), compareUtf8);
|
||||
}
|
||||
|
||||
case AqlValue::SHAPED: {
|
||||
|
@ -1065,11 +1164,16 @@ int AqlValue::Compare (triagens::arango::AqlTransaction* trx,
|
|||
rblock < right._vector->size()) {
|
||||
AqlValue lval = left._vector->at(lblock)->getValue(litem, 0);
|
||||
AqlValue rval = right._vector->at(rblock)->getValue(ritem, 0);
|
||||
int cmp = Compare(trx,
|
||||
lval,
|
||||
left._vector->at(lblock)->getDocumentCollection(0),
|
||||
rval,
|
||||
right._vector->at(rblock)->getDocumentCollection(0));
|
||||
|
||||
int cmp = Compare(
|
||||
trx,
|
||||
lval,
|
||||
left._vector->at(lblock)->getDocumentCollection(0),
|
||||
rval,
|
||||
right._vector->at(rblock)->getDocumentCollection(0),
|
||||
compareUtf8
|
||||
);
|
||||
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
|
@ -1090,6 +1194,7 @@ int AqlValue::Compare (triagens::arango::AqlTransaction* trx,
|
|||
|
||||
return (lblock < left._vector->size() ? -1 : 1);
|
||||
}
|
||||
|
||||
case AqlValue::RANGE: {
|
||||
if (left._range->_low < right._range->_low) {
|
||||
return -1;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#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"
|
||||
|
@ -118,7 +119,7 @@ namespace triagens {
|
|||
/// @brief return the value type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline AqlValueType type () const {
|
||||
inline AqlValueType type () const throw() {
|
||||
return _type;
|
||||
}
|
||||
|
||||
|
@ -126,7 +127,7 @@ namespace triagens {
|
|||
/// @brief a quick method to decide whether a value is empty
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool isEmpty () const {
|
||||
inline bool isEmpty () const throw() {
|
||||
return _type == EMPTY;
|
||||
}
|
||||
|
||||
|
@ -134,7 +135,7 @@ namespace triagens {
|
|||
/// @brief whether or not the AqlValue is a shape
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool isShaped () const {
|
||||
inline bool isShaped () const throw() {
|
||||
return _type == SHAPED;
|
||||
}
|
||||
|
||||
|
@ -276,6 +277,13 @@ namespace triagens {
|
|||
triagens::basics::Json toJson (triagens::arango::AqlTransaction*,
|
||||
TRI_document_collection_t const*) 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
|
||||
|
@ -284,7 +292,8 @@ namespace triagens {
|
|||
triagens::basics::Json extractObjectMember (triagens::arango::AqlTransaction*,
|
||||
TRI_document_collection_t const*,
|
||||
char const*,
|
||||
bool) const;
|
||||
bool,
|
||||
triagens::basics::StringBuffer&) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract a value from an array AqlValue
|
||||
|
@ -323,7 +332,8 @@ namespace triagens {
|
|||
AqlValue const&,
|
||||
TRI_document_collection_t const*,
|
||||
AqlValue const&,
|
||||
TRI_document_collection_t const*);
|
||||
TRI_document_collection_t const*,
|
||||
bool compareUtf8);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public variables
|
||||
|
|
|
@ -551,6 +551,14 @@ namespace triagens {
|
|||
return static_cast<AstNode*>(members._buffer[i]);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a member of the node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline AstNode* getMemberUnchecked (size_t i) const throw() {
|
||||
return static_cast<AstNode*>(members._buffer[i]);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return an optional member of the node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -57,7 +57,6 @@ using StringBuffer = triagens::basics::StringBuffer;
|
|||
#define LEAVE_BLOCK
|
||||
#endif
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- struct AggregatorGroup
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -189,6 +188,7 @@ ExecutionBlock::~ExecutionBlock () {
|
|||
for (auto it = _buffer.begin(); it != _buffer.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
|
||||
_buffer.clear();
|
||||
}
|
||||
|
||||
|
@ -452,20 +452,23 @@ void ExecutionBlock::inheritRegisters (AqlItemBlock const* src,
|
|||
bool ExecutionBlock::getBlock (size_t atLeast, size_t atMost) {
|
||||
throwIfKilled(); // check if we were aborted
|
||||
|
||||
AqlItemBlock* docs = _dependencies[0]->getSome(atLeast, atMost);
|
||||
std::unique_ptr<AqlItemBlock> docs(_dependencies[0]->getSome(atLeast, atMost));
|
||||
|
||||
if (docs == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
TRI_IF_FAILURE("ExecutionBlock::getBlock") {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
}
|
||||
_buffer.emplace_back(docs);
|
||||
_buffer.emplace_back(docs.get());
|
||||
docs.release();
|
||||
}
|
||||
catch (...) {
|
||||
delete docs;
|
||||
throw;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2697,7 +2700,7 @@ void CalculationBlock::fillBlockWithReference (AqlItemBlock* result) {
|
|||
|
||||
void CalculationBlock::executeExpression (AqlItemBlock* result) {
|
||||
std::vector<AqlValue>& data(result->getData());
|
||||
std::vector<TRI_document_collection_t const*> docColls(result->getDocumentCollections());
|
||||
std::vector<TRI_document_collection_t const*>& docColls(result->getDocumentCollections());
|
||||
|
||||
RegisterId nrRegs = result->getNrRegs();
|
||||
result->setDocumentCollection(_outReg, nullptr);
|
||||
|
@ -2719,10 +2722,11 @@ void CalculationBlock::executeExpression (AqlItemBlock* result) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// execute the expression
|
||||
TRI_document_collection_t const* myCollection = nullptr;
|
||||
AqlValue a = _expression->execute(_trx, docColls, data, nrRegs * i, _inVars, _inRegs, &myCollection);
|
||||
|
||||
try {
|
||||
TRI_IF_FAILURE("CalculationBlock::executeExpression") {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
|
@ -3297,11 +3301,15 @@ int SortedAggregateBlock::getOrSkipSome (size_t atLeast,
|
|||
size_t i = 0;
|
||||
|
||||
for (auto it = _aggregateRegisters.begin(); it != _aggregateRegisters.end(); ++it) {
|
||||
int cmp = AqlValue::Compare(_trx,
|
||||
_currentGroup.groupValues[i],
|
||||
_currentGroup.collections[i],
|
||||
cur->getValue(_pos, (*it).second),
|
||||
cur->getDocumentCollection((*it).second));
|
||||
int cmp = AqlValue::Compare(
|
||||
_trx,
|
||||
_currentGroup.groupValues[i],
|
||||
_currentGroup.collections[i],
|
||||
cur->getValue(_pos, (*it).second),
|
||||
cur->getDocumentCollection((*it).second),
|
||||
false
|
||||
);
|
||||
|
||||
if (cmp != 0) {
|
||||
// group change
|
||||
newGroup = true;
|
||||
|
@ -3530,6 +3538,7 @@ int HashedAggregateBlock::getOrSkipSome (size_t atLeast,
|
|||
bool skipping,
|
||||
AqlItemBlock*& result,
|
||||
size_t& skipped) {
|
||||
|
||||
TRI_ASSERT(result == nullptr && skipped == 0);
|
||||
if (_done) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
|
@ -3544,7 +3553,7 @@ int HashedAggregateBlock::getOrSkipSome (size_t atLeast,
|
|||
}
|
||||
_pos = 0; // this is in the first block
|
||||
}
|
||||
|
||||
|
||||
// If we get here, we do have _buffer.front()
|
||||
AqlItemBlock* cur = _buffer.front();
|
||||
|
||||
|
@ -3616,6 +3625,7 @@ int HashedAggregateBlock::getOrSkipSome (size_t atLeast,
|
|||
groupValues.emplace_back(cur->getValueReference(_pos, _aggregateRegisters[i].second));
|
||||
}
|
||||
|
||||
|
||||
auto it = allGroups.find(groupValues);
|
||||
|
||||
if (it == allGroups.end()) {
|
||||
|
@ -3627,7 +3637,7 @@ int HashedAggregateBlock::getOrSkipSome (size_t atLeast,
|
|||
group.emplace_back(cur->getValue(_pos, _aggregateRegisters[i].second).clone());
|
||||
}
|
||||
|
||||
allGroups.emplace(std::make_pair(group, 1));
|
||||
allGroups.emplace(group, 1);
|
||||
}
|
||||
else {
|
||||
// existing group
|
||||
|
@ -3677,7 +3687,6 @@ int HashedAggregateBlock::getOrSkipSome (size_t atLeast,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (! skipping) {
|
||||
TRI_ASSERT(skipped > 0);
|
||||
}
|
||||
|
@ -3692,13 +3701,10 @@ int HashedAggregateBlock::getOrSkipSome (size_t atLeast,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t HashedAggregateBlock::GroupKeyHash::operator() (std::vector<AqlValue> const& value) const {
|
||||
size_t const n = value.size();
|
||||
uint64_t hash = 0x12345678;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto bound = value[i].toJson(_trx, _colls[i]);
|
||||
|
||||
hash ^= TRI_HashJson(bound.json());
|
||||
for (size_t i = 0; i < _num; ++i) {
|
||||
hash ^= value[i].hash(_trx, _colls[i]);
|
||||
}
|
||||
|
||||
return static_cast<size_t>(hash);
|
||||
|
@ -3713,7 +3719,7 @@ bool HashedAggregateBlock::GroupKeyEqual::operator() (std::vector<AqlValue> cons
|
|||
size_t const n = lhs.size();
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
int res = AqlValue::Compare(_trx, lhs[i], _colls[i], rhs[i], _colls[i]);
|
||||
int res = AqlValue::Compare(_trx, lhs[i], _colls[i], rhs[i], _colls[i], false);
|
||||
|
||||
if (res != 0) {
|
||||
return false;
|
||||
|
@ -3945,11 +3951,15 @@ bool SortBlock::OurLessThan::operator() (std::pair<size_t, size_t> const& a,
|
|||
size_t i = 0;
|
||||
for (auto reg : _sortRegisters) {
|
||||
|
||||
int cmp = AqlValue::Compare(_trx,
|
||||
_buffer[a.first]->getValue(a.second, reg.first),
|
||||
_colls[i],
|
||||
_buffer[b.first]->getValue(b.second, reg.first),
|
||||
_colls[i]);
|
||||
int cmp = AqlValue::Compare(
|
||||
_trx,
|
||||
_buffer[a.first]->getValue(a.second, reg.first),
|
||||
_colls[i],
|
||||
_buffer[b.first]->getValue(b.second, reg.first),
|
||||
_colls[i],
|
||||
true
|
||||
);
|
||||
|
||||
if (cmp == -1) {
|
||||
return reg.second;
|
||||
}
|
||||
|
@ -4133,7 +4143,8 @@ ModificationBlock::ModificationBlock (ExecutionEngine* engine,
|
|||
_outRegNew(ExecutionNode::MaxRegisterId),
|
||||
_collection(ep->_collection),
|
||||
_isDBServer(false),
|
||||
_usesDefaultSharding(true) {
|
||||
_usesDefaultSharding(true),
|
||||
_buffer(TRI_UNKNOWN_MEM_ZONE) {
|
||||
|
||||
auto trxCollection = _trx->trxCollection(_collection->cid());
|
||||
if (trxCollection != nullptr) {
|
||||
|
@ -4246,14 +4257,14 @@ AqlItemBlock* ModificationBlock::getSome (size_t atLeast,
|
|||
|
||||
int ModificationBlock::extractKey (AqlValue const& value,
|
||||
TRI_document_collection_t const* document,
|
||||
std::string& key) const {
|
||||
std::string& key) {
|
||||
if (value.isShaped()) {
|
||||
key = TRI_EXTRACT_MARKER_KEY(value.getMarker());
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
if (value.isObject()) {
|
||||
Json member(value.extractObjectMember(_trx, document, TRI_VOC_ATTRIBUTE_KEY, false));
|
||||
Json member(value.extractObjectMember(_trx, document, TRI_VOC_ATTRIBUTE_KEY, false, _buffer));
|
||||
|
||||
TRI_json_t const* json = member.json();
|
||||
|
||||
|
@ -4539,7 +4550,7 @@ AqlItemBlock* InsertBlock::work (std::vector<AqlItemBlock*>& blocks) {
|
|||
// array must have _from and _to attributes
|
||||
TRI_json_t const* json;
|
||||
|
||||
Json member(a.extractObjectMember(_trx, document, TRI_VOC_ATTRIBUTE_FROM, false));
|
||||
Json member(a.extractObjectMember(_trx, document, TRI_VOC_ATTRIBUTE_FROM, false, _buffer));
|
||||
json = member.json();
|
||||
|
||||
if (TRI_IsStringJson(json)) {
|
||||
|
@ -4550,7 +4561,7 @@ AqlItemBlock* InsertBlock::work (std::vector<AqlItemBlock*>& blocks) {
|
|||
}
|
||||
|
||||
if (errorCode == TRI_ERROR_NO_ERROR) {
|
||||
Json member(a.extractObjectMember(_trx, document, TRI_VOC_ATTRIBUTE_TO, false));
|
||||
Json member(a.extractObjectMember(_trx, document, TRI_VOC_ATTRIBUTE_TO, false, _buffer));
|
||||
json = member.json();
|
||||
if (TRI_IsStringJson(json)) {
|
||||
errorCode = resolve(json->_value._string.data, edge._toCid, to);
|
||||
|
@ -4950,7 +4961,7 @@ AqlItemBlock* UpsertBlock::work (std::vector<AqlItemBlock*>& blocks) {
|
|||
if (insertDoc.isObject()) {
|
||||
if (isEdgeCollection) {
|
||||
// array must have _from and _to attributes
|
||||
Json member(insertDoc.extractObjectMember(_trx, insertDocument, TRI_VOC_ATTRIBUTE_FROM, false));
|
||||
Json member(insertDoc.extractObjectMember(_trx, insertDocument, TRI_VOC_ATTRIBUTE_FROM, false, _buffer));
|
||||
TRI_json_t const* json = member.json();
|
||||
|
||||
if (TRI_IsStringJson(json)) {
|
||||
|
@ -4961,7 +4972,7 @@ AqlItemBlock* UpsertBlock::work (std::vector<AqlItemBlock*>& blocks) {
|
|||
}
|
||||
|
||||
if (errorCode == TRI_ERROR_NO_ERROR) {
|
||||
Json member(insertDoc.extractObjectMember(_trx, document, TRI_VOC_ATTRIBUTE_TO, false));
|
||||
Json member(insertDoc.extractObjectMember(_trx, document, TRI_VOC_ATTRIBUTE_TO, false, _buffer));
|
||||
json = member.json();
|
||||
if (TRI_IsStringJson(json)) {
|
||||
errorCode = resolve(json->_value._string.data, edge._toCid, to);
|
||||
|
@ -5645,11 +5656,13 @@ bool GatherBlock::OurLessThan::operator() (std::pair<size_t, size_t> const& a,
|
|||
for (auto reg : _sortRegisters) {
|
||||
|
||||
int cmp = AqlValue::Compare(
|
||||
_trx,
|
||||
_gatherBlockBuffer.at(a.first).front()->getValue(a.second, reg.first),
|
||||
_colls[i],
|
||||
_gatherBlockBuffer.at(b.first).front()->getValue(b.second, reg.first),
|
||||
_colls[i]);
|
||||
_trx,
|
||||
_gatherBlockBuffer.at(a.first).front()->getValue(a.second, reg.first),
|
||||
_colls[i],
|
||||
_gatherBlockBuffer.at(b.first).front()->getValue(b.second, reg.first),
|
||||
_colls[i],
|
||||
true
|
||||
);
|
||||
|
||||
if (cmp == -1) {
|
||||
return reg.second;
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
#define ARANGODB_AQL_EXECUTION_BLOCK_H 1
|
||||
|
||||
#include "Basics/JsonHelper.h"
|
||||
#include "ShapedJson/shaped-json.h"
|
||||
|
||||
#include "Aql/AqlItemBlock.h"
|
||||
#include "Aql/Collection.h"
|
||||
#include "Aql/CollectionScanner.h"
|
||||
|
@ -38,7 +36,9 @@
|
|||
#include "Aql/Range.h"
|
||||
#include "Aql/WalkerWorker.h"
|
||||
#include "Aql/ExecutionStats.h"
|
||||
#include "Basics/StringBuffer.h"
|
||||
#include "Cluster/ClusterComm.h"
|
||||
#include "ShapedJson/shaped-json.h"
|
||||
#include "Utils/AqlTransaction.h"
|
||||
#include "Utils/transactions.h"
|
||||
#include "Utils/V8TransactionContext.h"
|
||||
|
@ -499,7 +499,7 @@ namespace triagens {
|
|||
/// @brief getSome
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlItemBlock* getSome (size_t atLeast, size_t atMost) override;
|
||||
AqlItemBlock* getSome (size_t atLeast, size_t atMost) override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// skip between atLeast and atMost, returns the number actually skipped . . .
|
||||
|
@ -577,7 +577,7 @@ namespace triagens {
|
|||
|
||||
int initializeCursor (AqlItemBlock* items, size_t pos) override;
|
||||
|
||||
AqlItemBlock* getSome (size_t atLeast, size_t atMost) override;
|
||||
AqlItemBlock* getSome (size_t atLeast, size_t atMost) override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// skip between atLeast and atMost, returns the number actually skipped . . .
|
||||
|
@ -864,7 +864,7 @@ namespace triagens {
|
|||
|
||||
int initializeCursor (AqlItemBlock* items, size_t pos) override;
|
||||
|
||||
AqlItemBlock* getSome (size_t atLeast, size_t atMost) override;
|
||||
AqlItemBlock* getSome (size_t atLeast, size_t atMost) override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// skip between atLeast and atMost returns the number actually skipped . . .
|
||||
|
@ -983,7 +983,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlItemBlock* getSome (size_t atLeast,
|
||||
size_t atMost) override;
|
||||
size_t atMost) override final;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -1054,7 +1054,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlItemBlock* getSome (size_t atLeast,
|
||||
size_t atMost) override;
|
||||
size_t atMost) override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shutdown, tell dependency and the subquery
|
||||
|
@ -1226,7 +1226,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::string> _variableNames;
|
||||
|
||||
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -1267,7 +1267,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RegisterId _groupRegister;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief hasher for a vector of AQL values
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1276,13 +1276,15 @@ namespace triagens {
|
|||
GroupKeyHash (triagens::arango::AqlTransaction* trx,
|
||||
std::vector<TRI_document_collection_t const*>& colls)
|
||||
: _trx(trx),
|
||||
_colls(colls) {
|
||||
_colls(colls),
|
||||
_num(colls.size()) {
|
||||
}
|
||||
|
||||
size_t operator() (std::vector<AqlValue> const& value) const;
|
||||
|
||||
triagens::arango::AqlTransaction* _trx;
|
||||
std::vector<TRI_document_collection_t const*>& _colls;
|
||||
size_t const _num;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1463,7 +1465,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlItemBlock* getSome (size_t atLeast,
|
||||
size_t atMost) override;
|
||||
size_t atMost) override final;
|
||||
|
||||
};
|
||||
|
||||
|
@ -1513,7 +1515,7 @@ namespace triagens {
|
|||
|
||||
int extractKey (AqlValue const&,
|
||||
TRI_document_collection_t const*,
|
||||
std::string&) const;
|
||||
std::string&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a master pointer from the marker passed
|
||||
|
@ -1580,6 +1582,12 @@ namespace triagens {
|
|||
|
||||
bool _usesDefaultSharding;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief temporary string buffer for extracting system attributes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
triagens::basics::StringBuffer _buffer;
|
||||
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -2201,6 +2201,39 @@ std::vector<std::pair<ExecutionNode*, bool>> SortNode::getCalcNodePairs () {
|
|||
return findExp._myVars;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief simplifies the expressions of the sort node
|
||||
/// this will sort expressions if they are constant
|
||||
/// the method will return true if all sort expressions were removed after
|
||||
/// simplification, and false otherwise
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SortNode::simplify (ExecutionPlan* plan) {
|
||||
for (auto it = _elements.begin(); it != _elements.end(); /* no hoisting */) {
|
||||
auto variable = (*it).first;
|
||||
|
||||
TRI_ASSERT(variable != nullptr);
|
||||
auto setter = _plan->getVarSetBy(variable->id);
|
||||
|
||||
if (setter != nullptr) {
|
||||
if (setter->getType() == ExecutionNode::CALCULATION) {
|
||||
// variable introduced by a calculation
|
||||
auto expression = static_cast<CalculationNode*>(setter)->expression();
|
||||
|
||||
if (expression->isConstant()) {
|
||||
// constant expression, remove it!
|
||||
it = _elements.erase(it);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
return _elements.empty();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns all sort information
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2214,7 +2247,7 @@ SortInformation SortNode::getSortInformation (ExecutionPlan* plan,
|
|||
auto variable = (*it).first;
|
||||
TRI_ASSERT(variable != nullptr);
|
||||
auto setter = _plan->getVarSetBy(variable->id);
|
||||
|
||||
|
||||
if (setter == nullptr) {
|
||||
result.isValid = false;
|
||||
break;
|
||||
|
@ -2233,7 +2266,8 @@ SortInformation SortNode::getSortInformation (ExecutionPlan* plan,
|
|||
}
|
||||
|
||||
if (! expression->isAttributeAccess() &&
|
||||
! expression->isReference()) {
|
||||
! expression->isReference() &&
|
||||
! expression->isConstant()) {
|
||||
result.isComplex = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1948,6 +1948,15 @@ namespace triagens {
|
|||
|
||||
std::vector<std::pair<ExecutionNode*, bool>> getCalcNodePairs ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief simplifies the expressions of the sort node
|
||||
/// this will sort expressions if they are constant
|
||||
/// the method will return true if all sort expressions were removed after
|
||||
/// simplification, and false otherwise
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool simplify (ExecutionPlan*);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -527,12 +527,6 @@ ExecutionNode* ExecutionPlan::fromNodeSort (ExecutionNode* previous,
|
|||
TRI_ASSERT(element->numMembers() == 2);
|
||||
|
||||
auto expression = element->getMember(0);
|
||||
|
||||
if (expression->isConstant()) {
|
||||
// expression is constant, so sorting with not provide any benefit
|
||||
continue;
|
||||
}
|
||||
|
||||
auto ascending = element->getMember(1);
|
||||
|
||||
// get sort order
|
||||
|
|
|
@ -87,7 +87,9 @@ Expression::Expression (Ast* ast,
|
|||
_canRunOnDBServer(false),
|
||||
_isDeterministic(false),
|
||||
_hasDeterminedAttributes(false),
|
||||
_built(false) {
|
||||
_built(false),
|
||||
_attributes(),
|
||||
_buffer(TRI_UNKNOWN_MEM_ZONE) {
|
||||
|
||||
TRI_ASSERT(_ast != nullptr);
|
||||
TRI_ASSERT(_executor != nullptr);
|
||||
|
@ -258,7 +260,7 @@ bool Expression::findInList (AqlValue const& left,
|
|||
auto listItem = right.extractArrayMember(trx, rightCollection, m, false);
|
||||
AqlValue listItemValue(&listItem);
|
||||
|
||||
int compareResult = AqlValue::Compare(trx, left, leftCollection, listItemValue, nullptr);
|
||||
int compareResult = AqlValue::Compare(trx, left, leftCollection, listItemValue, nullptr, false);
|
||||
|
||||
if (compareResult == 0) {
|
||||
// item found in the list
|
||||
|
@ -287,7 +289,7 @@ bool Expression::findInList (AqlValue const& left,
|
|||
auto listItem = right.extractArrayMember(trx, rightCollection, i, false);
|
||||
AqlValue listItemValue(&listItem);
|
||||
|
||||
int compareResult = AqlValue::Compare(trx, left, leftCollection, listItemValue, nullptr);
|
||||
int compareResult = AqlValue::Compare(trx, left, leftCollection, listItemValue, nullptr, false);
|
||||
|
||||
if (compareResult == 0) {
|
||||
// item found in the list
|
||||
|
@ -397,15 +399,15 @@ AqlValue Expression::executeSimpleExpression (AstNode const* node,
|
|||
std::vector<RegisterId> const& regs) {
|
||||
if (node->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||
// object lookup, e.g. users.name
|
||||
TRI_ASSERT(node->numMembers() == 1);
|
||||
TRI_ASSERT_EXPENSIVE(node->numMembers() == 1);
|
||||
|
||||
auto member = node->getMember(0);
|
||||
auto member = node->getMemberUnchecked(0);
|
||||
auto name = static_cast<char const*>(node->getData());
|
||||
|
||||
TRI_document_collection_t const* myCollection = nullptr;
|
||||
AqlValue result = executeSimpleExpression(member, &myCollection, trx, docColls, argv, startPos, vars, regs);
|
||||
|
||||
auto j = result.extractObjectMember(trx, myCollection, name, true);
|
||||
auto j = result.extractObjectMember(trx, myCollection, name, true, _buffer);
|
||||
result.destroy();
|
||||
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal()));
|
||||
}
|
||||
|
@ -458,7 +460,7 @@ AqlValue Expression::executeSimpleExpression (AstNode const* node,
|
|||
|
||||
if (indexResult.isNumber()) {
|
||||
auto&& indexString = std::to_string(indexResult.toInt64());
|
||||
auto j = result.extractObjectMember(trx, myCollection, indexString.c_str(), true);
|
||||
auto j = result.extractObjectMember(trx, myCollection, indexString.c_str(), true, _buffer);
|
||||
indexResult.destroy();
|
||||
result.destroy();
|
||||
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal()));
|
||||
|
@ -467,7 +469,7 @@ AqlValue Expression::executeSimpleExpression (AstNode const* node,
|
|||
auto&& value = indexResult.toString();
|
||||
indexResult.destroy();
|
||||
|
||||
auto j = result.extractObjectMember(trx, myCollection, value.c_str(), true);
|
||||
auto j = result.extractObjectMember(trx, myCollection, value.c_str(), true, _buffer);
|
||||
result.destroy();
|
||||
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal()));
|
||||
}
|
||||
|
@ -559,7 +561,7 @@ AqlValue Expression::executeSimpleExpression (AstNode const* node,
|
|||
}
|
||||
|
||||
else if (node->type == NODE_TYPE_REFERENCE) {
|
||||
auto v = static_cast<Variable*>(node->getData());
|
||||
auto v = static_cast<Variable const*>(node->getData());
|
||||
|
||||
size_t i = 0;
|
||||
for (auto it = vars.begin(); it != vars.end(); ++it, ++i) {
|
||||
|
@ -685,8 +687,12 @@ AqlValue Expression::executeSimpleExpression (AstNode const* node,
|
|||
return AqlValue(new triagens::basics::Json(result));
|
||||
}
|
||||
|
||||
// all other comparison operators
|
||||
int compareResult = AqlValue::Compare(trx, left, leftCollection, right, rightCollection);
|
||||
// all other comparison operators...
|
||||
|
||||
// for equality and non-equality we can use a binary comparison
|
||||
bool compareUtf8 = (node->type != NODE_TYPE_OPERATOR_BINARY_EQ && node->type != NODE_TYPE_OPERATOR_BINARY_NE);
|
||||
|
||||
int compareResult = AqlValue::Compare(trx, left, leftCollection, right, rightCollection, compareUtf8);
|
||||
left.destroy();
|
||||
right.destroy();
|
||||
|
||||
|
@ -755,6 +761,14 @@ bool Expression::isAttributeAccess () const {
|
|||
bool Expression::isReference () const {
|
||||
return (_node->type == triagens::aql::NODE_TYPE_REFERENCE);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check whether this is a constant node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Expression::isConstant () const {
|
||||
return _node->isConstant();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief this gives you ("variable.access", "Reference")
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "Aql/Variable.h"
|
||||
#include "Aql/types.h"
|
||||
#include "Basics/JsonHelper.h"
|
||||
#include "Basics/StringBuffer.h"
|
||||
#include "Utils/AqlTransaction.h"
|
||||
|
||||
struct TRI_json_t;
|
||||
|
@ -42,7 +43,6 @@ struct TRI_json_t;
|
|||
namespace triagens {
|
||||
namespace basics {
|
||||
class Json;
|
||||
class StringBuffer;
|
||||
}
|
||||
|
||||
namespace aql {
|
||||
|
@ -237,6 +237,12 @@ namespace triagens {
|
|||
|
||||
bool isReference () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check whether this is a constant node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool isConstant () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief this gives you ("variable.access", "Reference")
|
||||
/// call isSimpleAccessReference in advance to ensure no exceptions.
|
||||
|
@ -387,6 +393,12 @@ namespace triagens {
|
|||
|
||||
std::unordered_map<Variable const*, std::unordered_set<std::string>> _attributes;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief buffer for temporary strings
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
triagens::basics::StringBuffer _buffer;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public static members
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -74,7 +74,6 @@ int triagens::aql::removeRedundantSortsRule (Optimizer* opt,
|
|||
|
||||
if (sortInfo.isValid && ! sortInfo.criteria.empty()) {
|
||||
// we found a sort that we can understand
|
||||
|
||||
std::vector<ExecutionNode*> stack;
|
||||
for (auto dep : sortNode->getDependencies()) {
|
||||
stack.push_back(dep);
|
||||
|
@ -155,7 +154,7 @@ int triagens::aql::removeRedundantSortsRule (Optimizer* opt,
|
|||
}
|
||||
else {
|
||||
// abort at all other type of nodes. we cannot remove a sort beyond them
|
||||
// this include COLLECT and LIMIT
|
||||
// this includes COLLECT and LIMIT
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -171,9 +170,16 @@ int triagens::aql::removeRedundantSortsRule (Optimizer* opt,
|
|||
stack.push_back(dep);
|
||||
}
|
||||
}
|
||||
|
||||
if (toUnlink.find(n) == toUnlink.end() &&
|
||||
sortNode->simplify(plan)) {
|
||||
// sort node had only constant expressions. it will make no difference if we execute it or not
|
||||
// so we can remove it
|
||||
toUnlink.insert(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (! toUnlink.empty()) {
|
||||
plan->unlinkNodes(toUnlink);
|
||||
plan->findVarUsage();
|
||||
|
|
|
@ -31,12 +31,11 @@
|
|||
#define ARANGODB_UTILS_COLLECTION_NAME_RESOLVER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Basics/StringBuffer.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
||||
#include "Cluster/ServerState.h"
|
||||
#include "Cluster/ClusterInfo.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace arango {
|
||||
|
@ -83,7 +82,7 @@ namespace triagens {
|
|||
TRI_voc_cid_t getCollectionId (std::string const& name) const {
|
||||
if (name[0] >= '0' && name[0] <= '9') {
|
||||
// name is a numeric id
|
||||
return (TRI_voc_cid_t) triagens::basics::StringUtils::uint64(name);
|
||||
return static_cast<TRI_voc_cid_t>(triagens::basics::StringUtils::uint64(name));
|
||||
}
|
||||
|
||||
TRI_vocbase_col_t const* collection = getCollectionStruct(name);
|
||||
|
@ -99,12 +98,10 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_col_t const* getCollectionStruct (std::string const& name) const {
|
||||
if (! _resolvedNames.empty()) {
|
||||
auto it = _resolvedNames.find(name);
|
||||
auto it = _resolvedNames.find(name);
|
||||
|
||||
if (it != _resolvedNames.end()) {
|
||||
return (*it).second;
|
||||
}
|
||||
if (it != _resolvedNames.end()) {
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
TRI_vocbase_col_t const* collection = TRI_LookupCollectionByNameVocBase(_vocbase, name.c_str());
|
||||
|
@ -147,12 +144,10 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string getCollectionName (TRI_voc_cid_t cid) const {
|
||||
if (! _resolvedIds.empty()) {
|
||||
auto it = _resolvedIds.find(cid);
|
||||
auto it = _resolvedIds.find(cid);
|
||||
|
||||
if (it != _resolvedIds.end()) {
|
||||
return (*it).second;
|
||||
}
|
||||
if (it != _resolvedIds.end()) {
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
@ -168,7 +163,7 @@ namespace triagens {
|
|||
if (found->_planId == 0) {
|
||||
// DBserver local case
|
||||
char* n = TRI_GetCollectionNameByIdVocBase(_vocbase, cid);
|
||||
if (0 != n) {
|
||||
if (n != nullptr) {
|
||||
name = n;
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, n);
|
||||
}
|
||||
|
@ -213,13 +208,11 @@ namespace triagens {
|
|||
|
||||
size_t getCollectionName (char* buffer,
|
||||
TRI_voc_cid_t cid) const {
|
||||
if (! _resolvedIds.empty()) {
|
||||
auto it = _resolvedIds.find(cid);
|
||||
auto it = _resolvedIds.find(cid);
|
||||
|
||||
if (it != _resolvedIds.end()) {
|
||||
memcpy(buffer, (*it).second.c_str(), (*it).second.size());
|
||||
return (*it).second.size();
|
||||
}
|
||||
if (it != _resolvedIds.end()) {
|
||||
memcpy(buffer, (*it).second.c_str(), (*it).second.size());
|
||||
return (*it).second.size();
|
||||
}
|
||||
|
||||
std::string&& name(getCollectionName(cid));
|
||||
|
@ -228,6 +221,28 @@ namespace triagens {
|
|||
return name.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief look up a collection name for a collection id, this implements
|
||||
/// some magic in the cluster case: a DBserver in a cluster will automatically
|
||||
/// translate the local collection ID into a cluster wide collection name.
|
||||
///
|
||||
/// the name is copied into <buffer>. the caller is responsible for allocating
|
||||
/// a big-enough buffer (that is, at least 64 bytes). no NUL byte is appended
|
||||
/// to the buffer. the length of the collection name is returned.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void getCollectionName (TRI_voc_cid_t cid,
|
||||
triagens::basics::StringBuffer& buffer) const {
|
||||
auto const& it = _resolvedIds.find(cid);
|
||||
|
||||
if (it != _resolvedIds.end()) {
|
||||
buffer.appendText((*it).second.c_str(), (*it).second.size());
|
||||
return;
|
||||
}
|
||||
|
||||
std::string&& name(getCollectionName(cid));
|
||||
buffer.appendText(name.c_str(), name.size());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief look up a cluster-wide collection name for a cluster-wide
|
||||
|
@ -292,6 +307,36 @@ namespace triagens {
|
|||
return strlen("_unknown");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief look up a cluster-wide collection name for a cluster-wide
|
||||
/// collection id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void getCollectionNameCluster (TRI_voc_cid_t cid,
|
||||
triagens::basics::StringBuffer& buffer) const {
|
||||
if (! ServerState::instance()->isRunningInCluster()) {
|
||||
return getCollectionName(cid, buffer);
|
||||
}
|
||||
|
||||
int tries = 0;
|
||||
|
||||
while (tries++ < 2) {
|
||||
std::shared_ptr<CollectionInfo> ci
|
||||
= ClusterInfo::instance()->getCollection(_vocbase->_name,
|
||||
triagens::basics::StringUtils::itoa(cid));
|
||||
std::string name = ci->name();
|
||||
|
||||
if (name.empty()) {
|
||||
ClusterInfo::instance()->flush();
|
||||
continue;
|
||||
}
|
||||
buffer.appendText(name);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.appendText("_unknown");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -122,9 +122,7 @@ TRI_document_collection_t::TRI_document_collection_t ()
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_document_collection_t::~TRI_document_collection_t () {
|
||||
if (_keyGenerator != nullptr) {
|
||||
delete _keyGenerator;
|
||||
}
|
||||
delete _keyGenerator;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -1528,7 +1528,10 @@ int TRI_CompareShapeTypes (char const* leftDocument,
|
|||
attribute_entry_t const* l = static_cast<attribute_entry_t const*>(TRI_AtVector(&leftSorted, i));
|
||||
attribute_entry_t const* r = static_cast<attribute_entry_t const*>(TRI_AtVector(&rightSorted, i));
|
||||
|
||||
result = TRI_compare_utf8(l->_attribute, r->_attribute);
|
||||
// a binary comparison is sufficient here as we're only interested in if the attribute names are
|
||||
// identical. the attribute names are from ShapedJson, so they have been normalized already
|
||||
result = strcmp(l->_attribute, r->_attribute);
|
||||
// result = TRI_compare_utf8(l->_attribute, r->_attribute);
|
||||
|
||||
if (result != 0) {
|
||||
break;
|
||||
|
|
|
@ -124,12 +124,19 @@ function optimizerCollectMethodsTestSuite () {
|
|||
var plan = AQL_EXPLAIN(query[0]).plan;
|
||||
|
||||
var aggregateNodes = 0;
|
||||
var sortNodes = 0;
|
||||
plan.nodes.map(function(node) {
|
||||
if (node.type === "AggregateNode") {
|
||||
++aggregateNodes;
|
||||
assertEqual("hash", node.method);
|
||||
}
|
||||
if (node.type === "SortNode") {
|
||||
++sortNodes;
|
||||
}
|
||||
});
|
||||
|
||||
assertEqual(1, aggregateNodes);
|
||||
assertEqual(1, sortNodes);
|
||||
|
||||
var results = AQL_EXECUTE(query[0]);
|
||||
assertEqual(query[1], results.json.length);
|
||||
|
@ -157,12 +164,19 @@ function optimizerCollectMethodsTestSuite () {
|
|||
var plan = AQL_EXPLAIN(query[0]).plan;
|
||||
|
||||
var aggregateNodes = 0;
|
||||
var sortNodes = 0;
|
||||
plan.nodes.map(function(node) {
|
||||
if (node.type === "AggregateNode") {
|
||||
++aggregateNodes;
|
||||
assertEqual("hash", node.method);
|
||||
}
|
||||
if (node.type === "SortNode") {
|
||||
++sortNodes;
|
||||
}
|
||||
});
|
||||
|
||||
assertEqual(1, aggregateNodes);
|
||||
assertEqual(1, sortNodes);
|
||||
|
||||
var results = AQL_EXECUTE(query[0]);
|
||||
assertEqual(query[1], results.json.length);
|
||||
|
@ -188,12 +202,56 @@ function optimizerCollectMethodsTestSuite () {
|
|||
var plan = AQL_EXPLAIN(query[0]).plan;
|
||||
|
||||
var aggregateNodes = 0;
|
||||
var sortNodes = 0;
|
||||
plan.nodes.map(function(node) {
|
||||
if (node.type === "AggregateNode") {
|
||||
++aggregateNodes;
|
||||
assertEqual("sorted", node.method);
|
||||
}
|
||||
if (node.type === "SortNode") {
|
||||
++sortNodes;
|
||||
}
|
||||
});
|
||||
|
||||
assertEqual(1, aggregateNodes);
|
||||
assertEqual(0, sortNodes);
|
||||
|
||||
var results = AQL_EXECUTE(query[0]);
|
||||
assertEqual(query[1], results.json.length);
|
||||
});
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief expect hash COLLECT w/ sort node removed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSortRemoval : function () {
|
||||
var queries = [
|
||||
[ "FOR j IN " + c.name() + " COLLECT value = j SORT null RETURN value", 1500 ],
|
||||
[ "FOR j IN " + c.name() + " COLLECT value = j._key SORT null RETURN value", 1500 ],
|
||||
[ "FOR j IN " + c.name() + " COLLECT value = j.group SORT null RETURN value", 10 ],
|
||||
[ "FOR j IN " + c.name() + " COLLECT value1 = j.group, value2 = j.value SORT null RETURN [ value1, value2 ]", 1500 ],
|
||||
[ "FOR j IN " + c.name() + " COLLECT value = j.group WITH COUNT INTO l SORT null RETURN [ value, l ]", 10 ],
|
||||
[ "FOR j IN " + c.name() + " COLLECT value1 = j.group, value2 = j.value WITH COUNT INTO l SORT null RETURN [ value1, value2, l ]", 1500 ]
|
||||
];
|
||||
|
||||
queries.forEach(function(query) {
|
||||
var plan = AQL_EXPLAIN(query[0]).plan;
|
||||
|
||||
var aggregateNodes = 0;
|
||||
var sortNodes = 0;
|
||||
plan.nodes.map(function(node) {
|
||||
if (node.type === "AggregateNode") {
|
||||
++aggregateNodes;
|
||||
assertEqual("hash", node.method);
|
||||
}
|
||||
if (node.type === "SortNode") {
|
||||
++sortNodes;
|
||||
}
|
||||
});
|
||||
|
||||
assertEqual(1, aggregateNodes);
|
||||
assertEqual(0, sortNodes);
|
||||
|
||||
var results = AQL_EXECUTE(query[0]);
|
||||
assertEqual(query[1], results.json.length);
|
||||
|
|
|
@ -516,6 +516,19 @@ namespace triagens {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor for a char const*
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
explicit Json (char const* x, size_t length, autofree_e autofree = AUTOFREE)
|
||||
: _zone(TRI_UNKNOWN_MEM_ZONE), _json(nullptr), _autofree(autofree) {
|
||||
_json = TRI_CreateStringCopyJson(_zone, x, length);
|
||||
|
||||
if (_json == nullptr) {
|
||||
throw JsonException("Json: out of memory");
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor for a memzone and a char const*
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -529,6 +542,19 @@ namespace triagens {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor for a memzone and a char const*
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
explicit Json (TRI_memory_zone_t* z, char const* x, size_t length, autofree_e autofree = AUTOFREE)
|
||||
: _zone(z), _json(nullptr), _autofree(autofree) {
|
||||
_json = TRI_CreateStringCopyJson(_zone, x, length);
|
||||
|
||||
if (_json == nullptr) {
|
||||
throw JsonException("Json: out of memory");
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor for a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -54,12 +54,14 @@ Utf8Helper Utf8Helper::DefaultUtf8Helper;
|
|||
// --SECTION-- constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Utf8Helper::Utf8Helper () : _coll(0) {
|
||||
setCollatorLanguage("");
|
||||
Utf8Helper::Utf8Helper (std::string const& lang) :
|
||||
_coll(nullptr) {
|
||||
|
||||
setCollatorLanguage(lang);
|
||||
}
|
||||
|
||||
Utf8Helper::Utf8Helper (std::string const& lang) : _coll(0) {
|
||||
setCollatorLanguage(lang);
|
||||
Utf8Helper::Utf8Helper () :
|
||||
Utf8Helper("") {
|
||||
}
|
||||
|
||||
Utf8Helper::~Utf8Helper () {
|
||||
|
@ -71,15 +73,15 @@ Utf8Helper::~Utf8Helper () {
|
|||
}
|
||||
}
|
||||
|
||||
int Utf8Helper::compareUtf8 (const char* left, const char* right) {
|
||||
if (!_coll) {
|
||||
int Utf8Helper::compareUtf8 (const char* left, const char* right) const {
|
||||
if (! _coll) {
|
||||
LOG_ERROR("no Collator in Utf8Helper::compareUtf8()!");
|
||||
return (strcmp(left, right));
|
||||
}
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int result = _coll->compareUTF8(StringPiece(left), StringPiece(right), status);
|
||||
if(U_FAILURE(status)) {
|
||||
if (U_FAILURE(status)) {
|
||||
LOG_ERROR("error in Collator::compareUTF8(...): %s", u_errorName(status));
|
||||
return (strcmp(left, right));
|
||||
}
|
||||
|
@ -87,7 +89,7 @@ int Utf8Helper::compareUtf8 (const char* left, const char* right) {
|
|||
return result;
|
||||
}
|
||||
|
||||
int Utf8Helper::compareUtf16 (const uint16_t* left, size_t leftLength, const uint16_t* right, size_t rightLength) {
|
||||
int Utf8Helper::compareUtf16 (const uint16_t* left, size_t leftLength, const uint16_t* right, size_t rightLength) const {
|
||||
if (!_coll) {
|
||||
LOG_ERROR("no Collator in Utf8Helper::compareUtf16()!");
|
||||
|
||||
|
@ -208,7 +210,7 @@ std::string Utf8Helper::getCollatorCountry () {
|
|||
std::string Utf8Helper::toLowerCase (std::string const& src) {
|
||||
int32_t utf8len = 0;
|
||||
char* utf8 = tolower(TRI_UNKNOWN_MEM_ZONE, src.c_str(), (int32_t) src.length(), utf8len);
|
||||
if (utf8 == 0) {
|
||||
if (utf8 == nullptr) {
|
||||
return string("");
|
||||
}
|
||||
|
||||
|
@ -224,9 +226,9 @@ std::string Utf8Helper::toLowerCase (std::string const& src) {
|
|||
char* Utf8Helper::tolower (TRI_memory_zone_t* zone, const char *src, int32_t srcLength, int32_t& dstLength) {
|
||||
char* utf8_dest = 0;
|
||||
|
||||
if (src == 0 || srcLength == 0) {
|
||||
if (src == nullptr || srcLength == 0) {
|
||||
utf8_dest = (char*) TRI_Allocate(zone, sizeof(char), false);
|
||||
if (utf8_dest != 0) {
|
||||
if (utf8_dest != nullptr) {
|
||||
utf8_dest[0] = '\0';
|
||||
}
|
||||
dstLength = 0;
|
||||
|
@ -244,8 +246,8 @@ char* Utf8Helper::tolower (TRI_memory_zone_t* zone, const char *src, int32_t src
|
|||
}
|
||||
else {
|
||||
utf8_dest = (char*) TRI_Allocate(zone, (srcLength + 1) * sizeof(char), false);
|
||||
if (utf8_dest == 0) {
|
||||
return 0;
|
||||
if (utf8_dest == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dstLength = ucasemap_utf8ToLower(csm.getAlias(),
|
||||
|
@ -259,8 +261,8 @@ char* Utf8Helper::tolower (TRI_memory_zone_t* zone, const char *src, int32_t src
|
|||
status = U_ZERO_ERROR;
|
||||
TRI_Free(zone, utf8_dest);
|
||||
utf8_dest = (char*) TRI_Allocate(zone, (dstLength + 1) * sizeof(char), false);
|
||||
if (utf8_dest == 0) {
|
||||
return 0;
|
||||
if (utf8_dest == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dstLength = ucasemap_utf8ToLower(csm.getAlias(),
|
||||
|
@ -281,7 +283,7 @@ char* Utf8Helper::tolower (TRI_memory_zone_t* zone, const char *src, int32_t src
|
|||
}
|
||||
|
||||
utf8_dest = TRI_LowerAsciiStringZ(zone, src);
|
||||
if (utf8_dest != 0) {
|
||||
if (utf8_dest != nullptr) {
|
||||
dstLength = (int32_t) strlen(utf8_dest);
|
||||
}
|
||||
return utf8_dest;
|
||||
|
@ -294,7 +296,7 @@ char* Utf8Helper::tolower (TRI_memory_zone_t* zone, const char *src, int32_t src
|
|||
std::string Utf8Helper::toUpperCase (std::string const& src) {
|
||||
int32_t utf8len = 0;
|
||||
char* utf8 = toupper(TRI_UNKNOWN_MEM_ZONE, src.c_str(), (int32_t) src.length(), utf8len);
|
||||
if (utf8 == 0) {
|
||||
if (utf8 == nullptr) {
|
||||
return string("");
|
||||
}
|
||||
|
||||
|
@ -308,9 +310,9 @@ std::string Utf8Helper::toUpperCase (std::string const& src) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* Utf8Helper::toupper (TRI_memory_zone_t* zone, const char *src, int32_t srcLength, int32_t& dstLength) {
|
||||
char* utf8_dest = 0;
|
||||
char* utf8_dest = nullptr;
|
||||
|
||||
if (src == 0 || srcLength == 0) {
|
||||
if (src == nullptr || srcLength == 0) {
|
||||
utf8_dest = (char*) TRI_Allocate(zone, sizeof(char), false);
|
||||
if (utf8_dest != 0) {
|
||||
utf8_dest[0] = '\0';
|
||||
|
@ -330,8 +332,8 @@ char* Utf8Helper::toupper (TRI_memory_zone_t* zone, const char *src, int32_t src
|
|||
}
|
||||
else {
|
||||
utf8_dest = (char*) TRI_Allocate(zone, (srcLength+1) * sizeof(char), false);
|
||||
if (utf8_dest == 0) {
|
||||
return 0;
|
||||
if (utf8_dest == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dstLength = ucasemap_utf8ToUpper(csm.getAlias(),
|
||||
|
@ -345,8 +347,8 @@ char* Utf8Helper::toupper (TRI_memory_zone_t* zone, const char *src, int32_t src
|
|||
status = U_ZERO_ERROR;
|
||||
TRI_Free(zone, utf8_dest);
|
||||
utf8_dest = (char*) TRI_Allocate(zone, (dstLength + 1) * sizeof(char), false);
|
||||
if (utf8_dest == 0) {
|
||||
return 0;
|
||||
if (utf8_dest == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dstLength = ucasemap_utf8ToUpper(csm.getAlias(),
|
||||
|
@ -367,7 +369,7 @@ char* Utf8Helper::toupper (TRI_memory_zone_t* zone, const char *src, int32_t src
|
|||
}
|
||||
|
||||
utf8_dest = TRI_UpperAsciiStringZ(zone, src);
|
||||
if (utf8_dest != NULL) {
|
||||
if (utf8_dest != nullptr) {
|
||||
dstLength = (int32_t) strlen(utf8_dest);
|
||||
}
|
||||
return utf8_dest;
|
||||
|
@ -388,30 +390,30 @@ TRI_vector_string_t* Utf8Helper::getWords (const char* const text,
|
|||
|
||||
if (textLength == 0) {
|
||||
// input text is empty
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (textLength < minimalLength) {
|
||||
// input text is shorter than required minimum length
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t textUtf16Length = 0;
|
||||
UChar* textUtf16 = NULL;
|
||||
UChar* textUtf16 = nullptr;
|
||||
|
||||
if (lowerCase) {
|
||||
// lower case string
|
||||
int32_t lowerLength = 0;
|
||||
char* lower = tolower(TRI_UNKNOWN_MEM_ZONE, text, (int32_t) textLength, lowerLength);
|
||||
|
||||
if (lower == NULL) {
|
||||
if (lower == nullptr) {
|
||||
// out of memory
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (lowerLength == 0) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, lower);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
textUtf16 = TRI_Utf8ToUChar(TRI_UNKNOWN_MEM_ZONE, lower, lowerLength, &textUtf16Length);
|
||||
|
@ -421,8 +423,8 @@ TRI_vector_string_t* Utf8Helper::getWords (const char* const text,
|
|||
textUtf16 = TRI_Utf8ToUChar(TRI_UNKNOWN_MEM_ZONE, text, (int32_t) textLength, &textUtf16Length);
|
||||
}
|
||||
|
||||
if (textUtf16 == NULL) {
|
||||
return NULL;
|
||||
if (textUtf16 == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ULocDataLocaleType type = ULOC_VALID_LOCALE;
|
||||
|
@ -431,22 +433,22 @@ TRI_vector_string_t* Utf8Helper::getWords (const char* const text,
|
|||
if (U_FAILURE(status)) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, textUtf16);
|
||||
LOG_ERROR("error in Collator::getLocale(...): %s", u_errorName(status));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UChar* tempUtf16 = (UChar *) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, (textUtf16Length + 1) * sizeof(UChar), false);
|
||||
|
||||
if (tempUtf16 == NULL) {
|
||||
if (tempUtf16 == nullptr) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, textUtf16);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
words = (TRI_vector_string_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_vector_string_t), false);
|
||||
|
||||
if (words == NULL) {
|
||||
if (words == nullptr) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, textUtf16);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, tempUtf16);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// estimate an initial vector size. this is not accurate, but setting the initial size to some
|
||||
|
@ -496,7 +498,7 @@ TRI_vector_string_t* Utf8Helper::getWords (const char* const text,
|
|||
if (words->_length == 0) {
|
||||
// no words found
|
||||
TRI_FreeVectorString(TRI_UNKNOWN_MEM_ZONE, words);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return words;
|
||||
|
|
|
@ -57,19 +57,19 @@ namespace triagens {
|
|||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Utf8Helper();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor
|
||||
/// @param lang Lowercase two-letter or three-letter ISO-639 code.
|
||||
/// This parameter can instead be an ICU style C locale (e.g. "en_US")
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Utf8Helper (std::string const& lang);
|
||||
explicit Utf8Helper (std::string const& lang);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Utf8Helper();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructor
|
||||
|
@ -90,7 +90,7 @@ namespace triagens {
|
|||
/// 1 : left > right
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int compareUtf8 (const char* left, const char* right);
|
||||
int compareUtf8 (const char* left, const char* right) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compare utf16 strings
|
||||
|
@ -99,7 +99,7 @@ namespace triagens {
|
|||
/// 1 : left > right
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int compareUtf16 (const uint16_t* left, size_t leftLength, const uint16_t* right, size_t rightLength);
|
||||
int compareUtf16 (const uint16_t* left, size_t leftLength, const uint16_t* right, size_t rightLength) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set collator by language
|
||||
|
|
|
@ -202,7 +202,7 @@ int TRI_CompareValuesJson (TRI_json_t const* lhs,
|
|||
return 1;
|
||||
}
|
||||
|
||||
TRI_ASSERT(lWeight == rWeight);
|
||||
TRI_ASSERT_EXPENSIVE(lWeight == rWeight);
|
||||
|
||||
// lhs and rhs have equal weights
|
||||
if (lhs == nullptr) {
|
||||
|
@ -213,21 +213,23 @@ int TRI_CompareValuesJson (TRI_json_t const* lhs,
|
|||
|
||||
switch (lhs->_type) {
|
||||
case TRI_JSON_UNUSED:
|
||||
case TRI_JSON_NULL:
|
||||
case TRI_JSON_NULL: {
|
||||
return 0; // null == null;
|
||||
}
|
||||
|
||||
case TRI_JSON_BOOLEAN:
|
||||
case TRI_JSON_BOOLEAN: {
|
||||
if (lhs->_value._boolean == rhs->_value._boolean) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lhs->_value._boolean && rhs->_value._boolean) {
|
||||
if (! lhs->_value._boolean && rhs->_value._boolean) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
case TRI_JSON_NUMBER:
|
||||
case TRI_JSON_NUMBER: {
|
||||
if (lhs->_value._number == rhs->_value._number) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -237,9 +239,10 @@ int TRI_CompareValuesJson (TRI_json_t const* lhs,
|
|||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
case TRI_JSON_STRING:
|
||||
case TRI_JSON_STRING_REFERENCE:
|
||||
case TRI_JSON_STRING_REFERENCE: {
|
||||
// same for STRING and STRING_REFERENCE
|
||||
int res;
|
||||
if (useUTF8) {
|
||||
|
@ -255,14 +258,13 @@ int TRI_CompareValuesJson (TRI_json_t const* lhs,
|
|||
else if (res > 0) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case TRI_JSON_ARRAY: {
|
||||
size_t nl = lhs->_value._objects._length;
|
||||
size_t nr = rhs->_value._objects._length;
|
||||
size_t i, n;
|
||||
size_t n;
|
||||
|
||||
if (nl > nr) {
|
||||
n = nl;
|
||||
|
@ -271,14 +273,12 @@ int TRI_CompareValuesJson (TRI_json_t const* lhs,
|
|||
n = nr;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
TRI_json_t* lhsValue;
|
||||
TRI_json_t* rhsValue;
|
||||
int result;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto lhsValue = (i >= nl) ? nullptr : static_cast<TRI_json_t const*>(TRI_AtVector(&lhs->_value._objects, i));
|
||||
auto rhsValue = (i >= nr) ? nullptr : static_cast<TRI_json_t const*>(TRI_AtVector(&rhs->_value._objects, i));
|
||||
|
||||
int result = TRI_CompareValuesJson(lhsValue, rhsValue, useUTF8);
|
||||
|
||||
lhsValue = (i >= nl) ? nullptr : reinterpret_cast<TRI_json_t*>(TRI_AtVector(&lhs->_value._objects, i));
|
||||
rhsValue = (i >= nr) ? nullptr : reinterpret_cast<TRI_json_t*>(TRI_AtVector(&rhs->_value._objects, i));
|
||||
result = TRI_CompareValuesJson(lhsValue, rhsValue, useUTF8);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
@ -288,30 +288,21 @@ int TRI_CompareValuesJson (TRI_json_t const* lhs,
|
|||
}
|
||||
|
||||
case TRI_JSON_OBJECT: {
|
||||
TRI_json_t* keys;
|
||||
|
||||
TRI_ASSERT(lhs->_type == TRI_JSON_OBJECT);
|
||||
TRI_ASSERT(rhs->_type == TRI_JSON_OBJECT);
|
||||
|
||||
keys = GetMergedKeyList(lhs, rhs);
|
||||
TRI_json_t* keys = GetMergedKeyList(lhs, rhs);
|
||||
|
||||
if (keys != nullptr) {
|
||||
size_t i, n;
|
||||
|
||||
n = keys->_value._objects._length;
|
||||
for (i = 0; i < n; ++i) {
|
||||
TRI_json_t* keyElement;
|
||||
TRI_json_t* lhsValue;
|
||||
TRI_json_t* rhsValue;
|
||||
int result;
|
||||
|
||||
keyElement = reinterpret_cast<TRI_json_t*>(TRI_AtVector(&keys->_value._objects, i));
|
||||
size_t const n = keys->_value._objects._length;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto keyElement = static_cast<TRI_json_t const*>(TRI_AtVector(&keys->_value._objects, i));
|
||||
TRI_ASSERT(TRI_IsStringJson(keyElement));
|
||||
|
||||
lhsValue = TRI_LookupObjectJson((TRI_json_t*) lhs, keyElement->_value._string.data); // may be NULL
|
||||
rhsValue = TRI_LookupObjectJson((TRI_json_t*) rhs, keyElement->_value._string.data); // may be NULL
|
||||
TRI_json_t const* lhsValue = TRI_LookupObjectJson(lhs, keyElement->_value._string.data); // may be NULL
|
||||
TRI_json_t const* rhsValue = TRI_LookupObjectJson(rhs, keyElement->_value._string.data); // may be NULL
|
||||
|
||||
result = TRI_CompareValuesJson(lhsValue, rhsValue, useUTF8);
|
||||
int result = TRI_CompareValuesJson(lhsValue, rhsValue, useUTF8);
|
||||
|
||||
if (result != 0) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, keys);
|
||||
|
@ -321,13 +312,12 @@ int TRI_CompareValuesJson (TRI_json_t const* lhs,
|
|||
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, keys);
|
||||
}
|
||||
|
||||
return 0;
|
||||
// fall-through to returning 0
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue