diff --git a/arangod/Aql/Functions.cpp b/arangod/Aql/Functions.cpp index bf0d9f1b4b..970410fb01 100644 --- a/arangod/Aql/Functions.cpp +++ b/arangod/Aql/Functions.cpp @@ -2395,7 +2395,7 @@ AqlValue Functions::Right(ExpressionContext*, transaction::Methods* trx, } namespace { -void ltrimInternal(uint32_t& startOffset, uint32_t& endOffset, icu::UnicodeString& unicodeStr, +void ltrimInternal(int32_t& startOffset, int32_t& endOffset, icu::UnicodeString& unicodeStr, uint32_t numWhitespaces, UChar32* spaceChars) { for (; startOffset < endOffset; startOffset = unicodeStr.moveIndex32(startOffset, 1)) { bool found = false; @@ -2412,22 +2412,26 @@ void ltrimInternal(uint32_t& startOffset, uint32_t& endOffset, icu::UnicodeStrin } } // for } -void rtrimInternal(uint32_t& startOffset, uint32_t& endOffset, icu::UnicodeString& unicodeStr, + +void rtrimInternal(int32_t& startOffset, int32_t& endOffset, icu::UnicodeString& unicodeStr, uint32_t numWhitespaces, UChar32* spaceChars) { - for (uint32_t codeUnitPos = unicodeStr.moveIndex32(unicodeStr.length(), -1); - startOffset < codeUnitPos; - codeUnitPos = unicodeStr.moveIndex32(codeUnitPos, -1)) { + if (unicodeStr.length() == 0) { + return; + } + for (int32_t codePos = unicodeStr.moveIndex32(endOffset, -1); + startOffset <= codePos; + codePos = unicodeStr.moveIndex32(codePos, -1)) { bool found = false; for (uint32_t pos = 0; pos < numWhitespaces; pos++) { - if (unicodeStr.char32At(codeUnitPos) == spaceChars[pos]) { + if (unicodeStr.char32At(codePos) == spaceChars[pos]) { found = true; + --endOffset; break; } } - endOffset = unicodeStr.moveIndex32(codeUnitPos, 1); - if (!found) { + if (!found || codePos == 0) { break; } } // for @@ -2475,7 +2479,7 @@ AqlValue Functions::Trim(ExpressionContext* expressionContext, transaction::Meth return AqlValue(AqlValueHintNull()); } - uint32_t startOffset = 0, endOffset = unicodeStr.length(); + int32_t startOffset = 0, endOffset = unicodeStr.length(); if (howToTrim <= 1) { ltrimInternal(startOffset, endOffset, unicodeStr, numWhitespaces, spaceChars.get()); @@ -2521,7 +2525,7 @@ AqlValue Functions::LTrim(ExpressionContext* expressionContext, transaction::Met return AqlValue(AqlValueHintNull()); } - uint32_t startOffset = 0, endOffset = unicodeStr.length(); + int32_t startOffset = 0, endOffset = unicodeStr.length(); ltrimInternal(startOffset, endOffset, unicodeStr, numWhitespaces, spaceChars.get()); @@ -2561,7 +2565,7 @@ AqlValue Functions::RTrim(ExpressionContext* expressionContext, transaction::Met return AqlValue(AqlValueHintNull()); } - uint32_t startOffset = 0, endOffset = unicodeStr.length(); + int32_t startOffset = 0, endOffset = unicodeStr.length(); rtrimInternal(startOffset, endOffset, unicodeStr, numWhitespaces, spaceChars.get()); diff --git a/tests/js/server/aql/aql-functions-string.js b/tests/js/server/aql/aql-functions-string.js index 056a447a0f..731f23a7c5 100644 --- a/tests/js/server/aql/aql-functions-string.js +++ b/tests/js/server/aql/aql-functions-string.js @@ -1480,12 +1480,18 @@ function ahuacatlStringFunctionsTestSuite () { // ////////////////////////////////////////////////////////////////////////////// testRtrim: function () { - var expected = [ ' foo', - '\t\r\nabc', - '\ta\rb\nc', - '\r\nThis\nis\r\na\ttest' - ]; + var expected = [ '', + '', + '', + ' foo', + '\t\r\nabc', + '\ta\rb\nc', + '\r\nThis\nis\r\na\ttest' + ]; var actual = getQueryResults(`FOR t IN [ +'', +' ', +' ', ' foo ', '\t\r\nabc\n\r\t', '\ta\rb\nc ', @@ -1499,11 +1505,21 @@ function ahuacatlStringFunctionsTestSuite () { // ////////////////////////////////////////////////////////////////////////////// testRtrimSpecial1: function () { - var expected = [ ' foo', - '\t\r\nabc\n\r\t', - '\ta\rb\nc', - '\r\nThis\nis\r\na\ttest' ]; + var expected = [ '', + '', + '', + '', + '\t', + ' foo', + '\t\r\nabc\n\r\t', + '\ta\rb\nc', + '\r\nThis\nis\r\na\ttest' ]; var actual = getQueryResults(`FOR t IN [ +'', +'\r', +'\r\n', +' \r\n', +'\t\r\n', ' foo ', '\t\r\nabc\n\r\t', '\ta\rb\nc ', @@ -1529,6 +1545,20 @@ function ahuacatlStringFunctionsTestSuite () { assertEqual(expected, actual); }, + testRtrimChars: function () { + var expected = [ '10000', '1000', '100', '10', '1', '', '' ]; + var actual = getQueryResults(`FOR t IN [ +'10000x', +'1000x', +'100x', +'10x', +'1x', +'x', +'' +] RETURN NOOPT((RTRIM(t, 'x') ))`); + assertEqual(expected, actual); + }, + // ////////////////////////////////////////////////////////////////////////////// // / @brief test find_first function // //////////////////////////////////////////////////////////////////////////////