mirror of https://gitee.com/bigwinds/arangodb
fixes for AQL
This commit is contained in:
parent
c814332503
commit
44070b149e
|
@ -64,7 +64,7 @@ uint64_t AqlValue::hash(arangodb::AqlTransaction* trx) const {
|
|||
|
||||
bool AqlValue::isNull(bool emptyIsNull) const {
|
||||
AqlValueType t = type();
|
||||
if (t == DOCUMENT || t == DOCVEC || t == RANGE) {
|
||||
if (t == DOCVEC || t == RANGE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ bool AqlValue::isNull(bool emptyIsNull) const {
|
|||
|
||||
bool AqlValue::isNumber() const {
|
||||
AqlValueType t = type();
|
||||
if (t == DOCUMENT || t == DOCVEC || t == RANGE) {
|
||||
if (t == DOCVEC || t == RANGE) {
|
||||
return false;
|
||||
}
|
||||
return slice().isNumber();
|
||||
|
@ -90,7 +90,7 @@ bool AqlValue::isNumber() const {
|
|||
|
||||
bool AqlValue::isString() const {
|
||||
AqlValueType t = type();
|
||||
if (t == DOCUMENT || t == DOCVEC || t == RANGE) {
|
||||
if (t == DOCVEC || t == RANGE) {
|
||||
return false;
|
||||
}
|
||||
return slice().isString();
|
||||
|
@ -147,11 +147,13 @@ size_t AqlValue::length() const {
|
|||
/// @brief get the (array) element at position
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlValue AqlValue::at(int64_t position, bool copy) const {
|
||||
AqlValue AqlValue::at(int64_t position, bool& mustDestroy,
|
||||
bool doCopy) const {
|
||||
mustDestroy = false;
|
||||
switch (type()) {
|
||||
case DOCUMENT:
|
||||
case VPACK_INLINE:
|
||||
copy = false;
|
||||
doCopy = false;
|
||||
// fall-through intentional
|
||||
case VPACK_EXTERNAL: {
|
||||
VPackSlice s(slice());
|
||||
|
@ -162,7 +164,8 @@ AqlValue AqlValue::at(int64_t position, bool copy) const {
|
|||
position = n + position;
|
||||
}
|
||||
if (position >= 0 && position < n) {
|
||||
if (copy || s.byteSize() < sizeof(_data.internal)) {
|
||||
if (doCopy || s.byteSize() < sizeof(_data.internal)) {
|
||||
mustDestroy = true;
|
||||
return AqlValue(s.at(position));
|
||||
}
|
||||
// return a reference to an existing slice
|
||||
|
@ -172,7 +175,6 @@ AqlValue AqlValue::at(int64_t position, bool copy) const {
|
|||
// fall-through intentional
|
||||
break;
|
||||
}
|
||||
|
||||
case DOCVEC: {
|
||||
size_t const n = docvecSize();
|
||||
if (position < 0) {
|
||||
|
@ -185,7 +187,8 @@ AqlValue AqlValue::at(int64_t position, bool copy) const {
|
|||
for (auto const& it : *_data.docvec) {
|
||||
if (position < static_cast<int64_t>(total + it->size())) {
|
||||
// found the correct vector
|
||||
if (copy) {
|
||||
if (doCopy) {
|
||||
mustDestroy = true;
|
||||
return it->getValueReference(position - total, 0).clone();
|
||||
}
|
||||
return it->getValue(position - total, 0);
|
||||
|
@ -207,6 +210,7 @@ AqlValue AqlValue::at(int64_t position, bool copy) const {
|
|||
// only look up the value if it is within array bounds
|
||||
VPackBuilder builder;
|
||||
builder.add(VPackValue(_data.range->at(static_cast<size_t>(position))));
|
||||
mustDestroy = true;
|
||||
return AqlValue(builder);
|
||||
}
|
||||
// fall-through intentional
|
||||
|
@ -223,11 +227,13 @@ AqlValue AqlValue::at(int64_t position, bool copy) const {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
|
||||
std::string const& name, bool copy) const {
|
||||
std::string const& name, bool& mustDestroy,
|
||||
bool doCopy) const {
|
||||
mustDestroy = false;
|
||||
switch (type()) {
|
||||
case DOCUMENT:
|
||||
case VPACK_INLINE:
|
||||
copy = false;
|
||||
doCopy = false;
|
||||
// fall-through intentional
|
||||
case VPACK_EXTERNAL: {
|
||||
VPackSlice s(slice());
|
||||
|
@ -238,7 +244,8 @@ AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
|
|||
return AqlValue(trx->extractIdString(s));
|
||||
}
|
||||
if (!found.isNone()) {
|
||||
if (copy || found.byteSize() < sizeof(_data.internal)) {
|
||||
if (doCopy || found.byteSize() < sizeof(_data.internal)) {
|
||||
mustDestroy = true;
|
||||
return AqlValue(found);
|
||||
}
|
||||
// return a reference to an existing slice
|
||||
|
@ -248,7 +255,6 @@ AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
|
|||
// fall-through intentional
|
||||
break;
|
||||
}
|
||||
|
||||
case DOCVEC:
|
||||
case RANGE: {
|
||||
// will return null
|
||||
|
@ -265,11 +271,13 @@ AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
|
||||
std::vector<char const*> const& names, bool copy) const {
|
||||
std::vector<char const*> const& names,
|
||||
bool& mustDestroy, bool doCopy) const {
|
||||
mustDestroy = false;
|
||||
switch (type()) {
|
||||
case DOCUMENT:
|
||||
case VPACK_INLINE:
|
||||
copy = false;
|
||||
doCopy = false;
|
||||
// fall-through intentional
|
||||
case VPACK_EXTERNAL: {
|
||||
VPackSlice s(slice());
|
||||
|
@ -280,7 +288,8 @@ AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
|
|||
return AqlValue(trx->extractIdString(s));
|
||||
}
|
||||
if (!found.isNone()) {
|
||||
if (copy || found.byteSize() < sizeof(_data.internal)) {
|
||||
if (doCopy || found.byteSize() < sizeof(_data.internal)) {
|
||||
mustDestroy = true;
|
||||
return AqlValue(found);
|
||||
}
|
||||
// return a reference to an existing slice
|
||||
|
@ -290,7 +299,6 @@ AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
|
|||
// fall-through intentional
|
||||
break;
|
||||
}
|
||||
|
||||
case DOCVEC:
|
||||
case RANGE: {
|
||||
// will return null
|
||||
|
@ -334,17 +342,18 @@ double AqlValue::toDouble(bool& failed) const {
|
|||
}
|
||||
else if (s.isArray()) {
|
||||
if (s.length() == 1) {
|
||||
return at(0, false).toDouble();
|
||||
bool mustDestroy; // we can ignore destruction here
|
||||
return at(0, mustDestroy, false).toDouble();
|
||||
}
|
||||
}
|
||||
// fall-through intentional
|
||||
break;
|
||||
}
|
||||
|
||||
case DOCVEC:
|
||||
case RANGE: {
|
||||
if (length() == 1) {
|
||||
return at(0, false).toDouble();
|
||||
bool mustDestroy; // we can ignore destruction here
|
||||
return at(0, mustDestroy, false).toDouble();
|
||||
}
|
||||
// will return 0
|
||||
break;
|
||||
|
@ -379,17 +388,19 @@ int64_t AqlValue::toInt64() const {
|
|||
}
|
||||
else if (s.isArray()) {
|
||||
if (s.length() == 1) {
|
||||
return at(0, false).toInt64();
|
||||
// we can ignore destruction here
|
||||
bool mustDestroy;
|
||||
return at(0, mustDestroy, false).toInt64();
|
||||
}
|
||||
}
|
||||
// fall-through intentional
|
||||
break;
|
||||
}
|
||||
|
||||
case DOCVEC:
|
||||
case RANGE: {
|
||||
if (length() == 1) {
|
||||
return at(0, false).toInt64();
|
||||
bool mustDestroy;
|
||||
return at(0, mustDestroy, false).toInt64();
|
||||
}
|
||||
// will return 0
|
||||
break;
|
||||
|
|
|
@ -221,16 +221,17 @@ struct AqlValue final {
|
|||
/// @brief get the (array) element at position
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlValue at(int64_t position, bool copy) const;
|
||||
AqlValue at(int64_t position, bool& mustDestroy, bool copy) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the (object) element by name(s)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlValue get(arangodb::AqlTransaction* trx,
|
||||
std::string const& name, bool copy) const;
|
||||
std::string const& name, bool& mustDestroy, bool copy) const;
|
||||
AqlValue get(arangodb::AqlTransaction* trx,
|
||||
std::vector<char const*> const& names, bool copy) const;
|
||||
std::vector<char const*> const& names, bool& mustDestroy,
|
||||
bool copy) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the numeric value of an AqlValue
|
||||
|
|
|
@ -55,8 +55,7 @@ AqlValue AttributeAccessor::get(arangodb::AqlTransaction* trx,
|
|||
for (auto it = vars.begin(); it != vars.end(); ++it, ++i) {
|
||||
if ((*it)->id == _variable->id) {
|
||||
// get the AQL value
|
||||
mustDestroy = true;
|
||||
return argv->getValueReference(startPos, regs[i]).get(trx, _attributeParts, true);
|
||||
return argv->getValueReference(startPos, regs[i]).get(trx, _attributeParts, mustDestroy, true);
|
||||
}
|
||||
// fall-through intentional
|
||||
}
|
||||
|
|
|
@ -49,8 +49,8 @@ class AttributeAccessor {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlValue get(arangodb::AqlTransaction* trx, AqlItemBlock const*, size_t,
|
||||
std::vector<Variable const*> const&,
|
||||
std::vector<RegisterId> const&, bool& mustDestroy);
|
||||
std::vector<Variable const*> const&,
|
||||
std::vector<RegisterId> const&, bool& mustDestroy);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -250,7 +250,8 @@ AqlValue EnumerateListBlock::getAqlValue(AqlValue const& inVarReg) {
|
|||
return out;
|
||||
}
|
||||
|
||||
return inVarReg.at(_index++, true);
|
||||
bool mustDestroy; // we can ignore destruction here
|
||||
return inVarReg.at(_index++, mustDestroy, true);
|
||||
}
|
||||
|
||||
void EnumerateListBlock::throwArrayExpectedException() {
|
||||
|
|
|
@ -272,7 +272,11 @@ bool Expression::findInArray(AqlValue const& left, AqlValue const& right,
|
|||
// determine midpoint
|
||||
size_t m = l + ((r - l) / 2);
|
||||
|
||||
int compareResult = AqlValue::Compare(trx, left, right.at(m, false), true);
|
||||
bool localMustDestroy;
|
||||
AqlValue a = right.at(m, localMustDestroy, false);
|
||||
AqlValueGuard guard(a, localMustDestroy);
|
||||
|
||||
int compareResult = AqlValue::Compare(trx, left, a, true);
|
||||
|
||||
if (compareResult == 0) {
|
||||
// item found in the list
|
||||
|
@ -296,7 +300,11 @@ bool Expression::findInArray(AqlValue const& left, AqlValue const& right,
|
|||
|
||||
// use linear search
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
int compareResult = AqlValue::Compare(trx, left, right.at(i, false), false);
|
||||
bool mustDestroy;
|
||||
AqlValue a = right.at(i, mustDestroy, false);
|
||||
AqlValueGuard guard(a, mustDestroy);
|
||||
|
||||
int compareResult = AqlValue::Compare(trx, left, a, false);
|
||||
|
||||
if (compareResult == 0) {
|
||||
// item found in the list
|
||||
|
@ -559,8 +567,7 @@ AqlValue Expression::executeSimpleExpressionAttributeAccess(
|
|||
|
||||
AqlValueGuard guard(result, mustDestroy);
|
||||
|
||||
AqlValue a = result.get(trx, name, true);
|
||||
mustDestroy = true; // result may be dynamic
|
||||
AqlValue a = result.get(trx, name, mustDestroy, true);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
@ -602,8 +609,7 @@ AqlValue Expression::executeSimpleExpressionIndexedAccess(
|
|||
AqlValueGuard guard(indexResult, mustDestroy);
|
||||
|
||||
if (indexResult.isNumber()) {
|
||||
mustDestroy = true; // as we are copying
|
||||
return result.at(indexResult.toInt64(), true);
|
||||
return result.at(indexResult.toInt64(), mustDestroy, true);
|
||||
}
|
||||
|
||||
if (indexResult.isString()) {
|
||||
|
@ -612,8 +618,7 @@ AqlValue Expression::executeSimpleExpressionIndexedAccess(
|
|||
try {
|
||||
// stoll() might throw an exception if the string is not a number
|
||||
int64_t position = static_cast<int64_t>(std::stoll(value));
|
||||
mustDestroy = true; // as we are copying
|
||||
return result.at(position, true);
|
||||
return result.at(position, mustDestroy, true);
|
||||
} catch (...) {
|
||||
// no number found.
|
||||
}
|
||||
|
@ -628,14 +633,12 @@ AqlValue Expression::executeSimpleExpressionIndexedAccess(
|
|||
|
||||
if (indexResult.isNumber()) {
|
||||
std::string const indexString = std::to_string(indexResult.toInt64());
|
||||
mustDestroy = true; // as we are copying
|
||||
return result.get(trx, indexString, true);
|
||||
return result.get(trx, indexString, mustDestroy, true);
|
||||
}
|
||||
|
||||
if (indexResult.isString()) {
|
||||
std::string const indexString = indexResult.slice().copyString();
|
||||
mustDestroy = true; // as we are copying
|
||||
return result.get(trx, indexString, true);
|
||||
return result.get(trx, indexString, mustDestroy, true);
|
||||
}
|
||||
|
||||
// fall-through to returning null
|
||||
|
@ -1054,7 +1057,10 @@ AqlValue Expression::executeSimpleExpressionArrayComparison(
|
|||
size_t numLeft = n;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
AqlValue leftItemValue = left.at(i, false);
|
||||
bool localMustDestroy;
|
||||
AqlValue leftItemValue = left.at(i, localMustDestroy, false);
|
||||
AqlValueGuard guard(leftItemValue, localMustDestroy);
|
||||
|
||||
bool result;
|
||||
|
||||
// IN and NOT IN
|
||||
|
@ -1239,7 +1245,10 @@ AqlValue Expression::executeSimpleExpressionExpansion(
|
|||
|
||||
size_t const n = v.length();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
AqlValue item = v.at(i, false);
|
||||
bool localMustDestroy;
|
||||
AqlValue item = v.at(i, localMustDestroy, false);
|
||||
AqlValueGuard guard(item, localMustDestroy);
|
||||
|
||||
bool const isArray = item.isArray();
|
||||
|
||||
if (!isArray || level == levels) {
|
||||
|
@ -1247,7 +1256,6 @@ AqlValue Expression::executeSimpleExpressionExpansion(
|
|||
} else if (isArray && level < levels) {
|
||||
flatten(item, level + 1);
|
||||
}
|
||||
// item.destroy(); TODO: check if we need to destroy the item??
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1289,7 +1297,10 @@ AqlValue Expression::executeSimpleExpressionExpansion(
|
|||
|
||||
size_t const n = value.length();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
AqlValue item = value.at(i, false);
|
||||
bool localMustDestroy;
|
||||
AqlValue item = value.at(i, localMustDestroy, false);
|
||||
AqlValueGuard guard(item, localMustDestroy);
|
||||
|
||||
AqlValueMaterializer materializer(trx);
|
||||
setVariable(variable, materializer.slice(item));
|
||||
|
||||
|
@ -1321,7 +1332,6 @@ AqlValue Expression::executeSimpleExpressionExpansion(
|
|||
}
|
||||
|
||||
clearVariable(variable);
|
||||
//item.destroy(); // TODO: do we need to destroy here?
|
||||
|
||||
if (takeItem && count > 0) {
|
||||
// number of items to pick was restricted
|
||||
|
|
|
@ -158,10 +158,12 @@ AqlItemBlock* ModificationBlock::getSome(size_t atLeast, size_t atMost) {
|
|||
int ModificationBlock::extractKey(AqlValue const& value,
|
||||
std::string& key) {
|
||||
if (value.isObject()) {
|
||||
AqlValue sub = value.get(_trx, TRI_VOC_ATTRIBUTE_KEY, false);
|
||||
bool mustDestroy;
|
||||
AqlValue sub = value.get(_trx, TRI_VOC_ATTRIBUTE_KEY, mustDestroy, false);
|
||||
AqlValueGuard guard(sub, mustDestroy);
|
||||
|
||||
if (sub.isString()) {
|
||||
key.assign(sub.slice().copyString());
|
||||
sub.destroy();
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
} else if (value.isString()) {
|
||||
|
|
Loading…
Reference in New Issue