1
0
Fork 0

Merge branch 'devel' of https://github.com/arangodb/arangodb into devel

This commit is contained in:
Kaveh Vahedipour 2016-05-23 17:35:21 +02:00
commit fce32ab69e
18 changed files with 419 additions and 595 deletions

View File

@ -205,7 +205,7 @@ check-docublocks:
grep -v '.*#.*:.*' \
>> /tmp/rawindoc.txt
cat /tmp/rawindoc.txt | sed -e "s;.*ck ;;" -e "s;.*ne ;;" |sort -u > /tmp/indoc.txt
grep -R '^/// @startDocuBlock' ../DocuBlocks --include "*.md" --include "*.mdpp" |grep -v aardvark > /tmp/rawinprog.txt
grep -R '^@startDocuBlock' ../DocuBlocks --include "*.md" --include "*.mdpp" |grep -v aardvark > /tmp/rawinprog.txt
# searching the Inline docublocks needs some more blacklisting:
grep -R '@startDocuBlockInline' --include "*.h" --include "*.cpp" --include "*.js" --include "*.mdpp" . |\
grep -v ppbook |\
@ -264,9 +264,9 @@ build-books:
make build-books-keep-md NAME=AQL
make build-books-keep-md NAME=HTTP
make ppbook-check-html-link NAME=Users
make ppbook-check-html-link NAME=AQL
make ppbook-check-html-link NAME=HTTP
#make ppbook-check-html-link NAME=Users
#make ppbook-check-html-link NAME=AQL
#make ppbook-check-html-link NAME=HTTP
make check-docublocks

View File

@ -293,7 +293,7 @@ BOOST_AUTO_TEST_CASE (tst_json_string_utf8_1) {
BOOST_CHECK_EQUAL(true, TRI_IsStringJson(json));
STRINGIFY
BOOST_CHECK_EQUAL("\"\\uCF54\\uB9AC\\uC544\\uB2F7\\uCEF4 \\uBA54\\uC77C\\uC54C\\uB9AC\\uBBF8 \\uC11C\\uBE44\\uC2A4 \\uC911\\uB2E8\\uC548\\uB0B4 [\\uC548\\uB0B4] \\uAC1C\\uC778\\uC815\\uBCF4\\uCDE8\\uAE09\\uBC29\\uCE68 \\uBCC0\\uACBD \\uC548\\uB0B4 \\uD68C\\uC0AC\\uC18C\\uAC1C | \\uAD11\\uACE0\\uC548\\uB0B4 | \\uC81C\\uD734\\uC548\\uB0B4 | \\uAC1C\\uC778\\uC815\\uBCF4\\uCDE8\\uAE09\\uBC29\\uCE68 | \\uCCAD\\uC18C\\uB144\\uBCF4\\uD638\\uC815\\uCC45 | \\uC2A4\\uD338\\uBC29\\uC9C0\\uC815\\uCC45 | \\uC0AC\\uC774\\uBC84\\uACE0\\uAC1D\\uC13C\\uD130 | \\uC57D\\uAD00\\uC548\\uB0B4 | \\uC774\\uBA54\\uC77C \\uBB34\\uB2E8\\uC218\\uC9D1\\uAC70\\uBD80 | \\uC11C\\uBE44\\uC2A4 \\uC804\\uCCB4\\uBCF4\\uAE30\"", STRING_VALUE);
BOOST_CHECK_EQUAL("\"코리아닷컴 메일알리미 서비스 중단안내 [안내] 개인정보취급방침 변경 안내 회사소개 | 광고안내 | 제휴안내 | 개인정보취급방침 | 청소년보호정책 | 스팸방지정책 | 사이버고객센터 | 약관안내 | 이메일 무단수집거부 | 서비스 전체보기\"", STRING_VALUE);
FREE_JSON
FREE_BUFFER
@ -310,7 +310,7 @@ BOOST_AUTO_TEST_CASE (tst_json_string_utf8_2) {
TRI_json_t* json = TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, value, strlen(value));
STRINGIFY
BOOST_CHECK_EQUAL("\"\\u00E4\\u00F6\\u00FC\\u00DF\\u00C4\\u00D6\\u00DC\\u20AC\\u00B5\"", STRING_VALUE);
BOOST_CHECK_EQUAL("\"äöüßÄÖÜ€µ\"", STRING_VALUE);
FREE_JSON
FREE_BUFFER
@ -327,7 +327,7 @@ BOOST_AUTO_TEST_CASE (tst_json_string_utf8_3) {
TRI_json_t* json = TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, value, strlen(value));
STRINGIFY
BOOST_CHECK_EQUAL("\"a\\uD835\\uDEE2\"", STRING_VALUE);
BOOST_CHECK_EQUAL("\"a𝛢\"", STRING_VALUE);
FREE_JSON
FREE_BUFFER
@ -509,7 +509,7 @@ BOOST_AUTO_TEST_CASE (tst_json_array_keys_utf8) {
TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "мадридского", TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, 4));
STRINGIFY
BOOST_CHECK_EQUAL("{\"\\u00E4\\u00F6\\u00FC\\u00C4\\u00D6\\u00DC\\u00DF\":1,\"\\uCF54\\uB9AC\\uC544\\uB2F7\\uCEF4\":2,\"\\u30B8\\u30E3\\u30D1\\u30F3\":3,\"\\u043C\\u0430\\u0434\\u0440\\u0438\\u0434\\u0441\\u043A\\u043E\\u0433\\u043E\":4}", STRING_VALUE);
BOOST_CHECK_EQUAL("{\"äöüÄÖÜß\":1,\"코리아닷컴\":2,\"ジャパン\":3,\"мадридского\":4}", STRING_VALUE);
FREE_JSON
FREE_BUFFER

View File

@ -2219,70 +2219,59 @@ void AstNode::stringify(arangodb::basics::StringBuffer* buffer, bool verbose,
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
if (verbose || n > 0) {
if (verbose || n > 1) {
buffer->appendChar('[');
buffer->appendChar('[');
for (size_t i = 0; i < n; ++i) {
if (i > 0) {
buffer->appendChar(',');
}
for (size_t i = 0; i < n; ++i) {
if (i > 0) {
buffer->appendChar(',');
}
AstNode* member = getMember(i);
if (member != nullptr) {
member->stringify(buffer, verbose, failIfLong);
}
}
if (verbose || n > 1) {
buffer->appendChar(']');
AstNode* member = getMember(i);
if (member != nullptr) {
member->stringify(buffer, verbose, failIfLong);
}
}
buffer->appendChar(']');
return;
}
if (type == NODE_TYPE_OBJECT) {
// must be JavaScript-compatible!
if (verbose) {
buffer->appendChar('{');
size_t const n = numMembers();
buffer->appendChar('{');
size_t const n = numMembers();
if (failIfLong && n > TooLongThreshold) {
// intentionally do not stringify this node because the output would be
// too long
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
for (size_t i = 0; i < n; ++i) {
if (i > 0) {
buffer->appendChar(',');
}
AstNode* member = getMember(i);
if (member->type == NODE_TYPE_OBJECT_ELEMENT) {
TRI_ASSERT(member->numMembers() == 1);
buffer->appendChar('"');
buffer->appendJsonEncoded(member->getStringValue(),
member->getStringLength());
buffer->appendText(TRI_CHAR_LENGTH_PAIR("\":"));
member->getMember(0)->stringify(buffer, verbose, failIfLong);
} else if (member->type == NODE_TYPE_CALCULATED_OBJECT_ELEMENT) {
TRI_ASSERT(member->numMembers() == 2);
buffer->appendText(TRI_CHAR_LENGTH_PAIR("$["));
member->getMember(0)->stringify(buffer, verbose, failIfLong);
buffer->appendText(TRI_CHAR_LENGTH_PAIR("]:"));
member->getMember(1)->stringify(buffer, verbose, failIfLong);
} else {
TRI_ASSERT(false);
}
}
buffer->appendChar('}');
} else {
buffer->appendText(TRI_CHAR_LENGTH_PAIR("[object Object]"));
if (failIfLong && n > TooLongThreshold) {
// intentionally do not stringify this node because the output would be
// too long
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
for (size_t i = 0; i < n; ++i) {
if (i > 0) {
buffer->appendChar(',');
}
AstNode* member = getMember(i);
if (member->type == NODE_TYPE_OBJECT_ELEMENT) {
TRI_ASSERT(member->numMembers() == 1);
buffer->appendJsonEncoded(member->getStringValue(),
member->getStringLength());
buffer->appendChar(':');
member->getMember(0)->stringify(buffer, verbose, failIfLong);
} else if (member->type == NODE_TYPE_CALCULATED_OBJECT_ELEMENT) {
TRI_ASSERT(member->numMembers() == 2);
buffer->appendText(TRI_CHAR_LENGTH_PAIR("$["));
member->getMember(0)->stringify(buffer, verbose, failIfLong);
buffer->appendText(TRI_CHAR_LENGTH_PAIR("]:"));
member->getMember(1)->stringify(buffer, verbose, failIfLong);
} else {
TRI_ASSERT(false);
}
}
buffer->appendChar('}');
return;
}
@ -2809,9 +2798,7 @@ void AstNode::appendValue(arangodb::basics::StringBuffer* buffer) const {
}
case VALUE_TYPE_STRING: {
buffer->appendChar('"');
buffer->appendJsonEncoded(value.value._string, value.length);
buffer->appendChar('"');
break;
}

View File

@ -150,7 +150,7 @@ std::unordered_map<std::string, Function const> const Executor::FunctionNames{
{"SUBSTRING", Function("SUBSTRING", "AQL_SUBSTRING", "s,n|n", true, true,
false, true, true)},
{"CONTAINS", Function("CONTAINS", "AQL_CONTAINS", "s,s|b", true, true,
false, true, true)},
false, true, true, &Functions::Contains)},
{"LIKE", Function("LIKE", "AQL_LIKE", "s,r|b", true, true, false, true,
true, &Functions::Like)},
{"LEFT",
@ -858,16 +858,12 @@ void Executor::generateCodeExpression(AstNode const* node) {
void Executor::generateCodeString(char const* value, size_t length) {
TRI_ASSERT(value != nullptr);
_buffer->appendChar('"');
_buffer->appendJsonEncoded(value, length);
_buffer->appendChar('"');
}
/// @brief generates code for a string value
void Executor::generateCodeString(std::string const& value) {
_buffer->appendChar('"');
_buffer->appendJsonEncoded(value.c_str(), value.size());
_buffer->appendChar('"');
}
/// @brief generate JavaScript code for an array

View File

@ -60,6 +60,13 @@ using namespace arangodb::aql;
thread_local std::unordered_map<std::string, RegexMatcher*>* RegexCache =
nullptr;
/// @brief convert a number value into an AqlValue
static AqlValue NumberValue(arangodb::AqlTransaction* trx, int value) {
TransactionBuilderLeaser builder(trx);
builder->add(VPackValue(value));
return AqlValue(builder.get());
}
/// @brief convert a number value into an AqlValue
static AqlValue NumberValue(arangodb::AqlTransaction* trx, double value) {
if (std::isnan(value) || !std::isfinite(value) || value == HUGE_VAL || value == -HUGE_VAL) {
@ -337,21 +344,9 @@ void Functions::Stringify(arangodb::AqlTransaction* trx,
return;
}
if (slice.isArray()) {
bool first = true;
for (auto const& sub : VPackArrayIterator(slice, true)) {
if (!first) {
buffer.push_back(',');
} else {
first = false;
}
Stringify(trx, buffer, sub);
}
return;
}
if (slice.isObject()) {
buffer.append("[object Object]");
if (slice.isObject() || slice.isArray()) {
VPackDumper dumper(&buffer, trx->transactionContext()->getVPackOptions());
dumper.dump(slice);
return;
}
@ -1156,6 +1151,62 @@ AqlValue Functions::Nth(arangodb::aql::Query* query,
return value.at(index, mustDestroy, true);
}
/// @brief function CONTAINS
AqlValue Functions::Contains(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
VPackFunctionParameters const& parameters) {
ValidateParameters(parameters, "CONTAINS", 2, 3);
AqlValue value = ExtractFunctionParameterValue(trx, parameters, 0);
AqlValue search = ExtractFunctionParameterValue(trx, parameters, 1);
AqlValue returnIndex = ExtractFunctionParameterValue(trx, parameters, 2);
int result = -1; // default is "not found"
{
StringBufferLeaser buffer(trx);
arangodb::basics::VPackStringBufferAdapter adapter(buffer->stringBuffer());
AppendAsString(trx, adapter, value);
size_t const valueLength = buffer->length();
size_t const searchOffset = buffer->length();
AppendAsString(trx, adapter, search);
size_t const searchLength = buffer->length() - valueLength;
if (searchLength > 0) {
char const* found = static_cast<char const*>(memmem(buffer->c_str(), valueLength, buffer->c_str() + searchOffset, searchLength));
if (found != nullptr) {
// find offset into string
int bytePosition = static_cast<int>(found - buffer->c_str());
char const* p = buffer->c_str();
int pos = 0;
while (pos < bytePosition) {
unsigned char c = static_cast<unsigned char>(*p);
if (c < 128) {
++pos;
} else if (c < 224) {
pos += 2;
} else if (c < 240) {
pos += 3;
} else if (c < 248) {
pos += 4;
}
}
result = pos;
}
}
}
if (returnIndex.toBoolean()) {
// return numeric value
return NumberValue(trx, result);
}
// return boolean
return AqlValue(result != -1);
}
/// @brief function CONCAT
AqlValue Functions::Concat(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
@ -1172,21 +1223,8 @@ AqlValue Functions::Concat(arangodb::aql::Query* query,
continue;
}
if (member.isArray()) {
// append each member individually
AqlValueMaterializer materializer(trx);
VPackSlice slice = materializer.slice(member, false);
for (auto const& sub : VPackArrayIterator(slice, true)) {
if (sub.isNone() || sub.isNull()) {
continue;
}
Stringify(trx, adapter, sub);
}
} else {
// convert member to a string and append
AppendAsString(trx, adapter, member);
}
// convert member to a string and append
AppendAsString(trx, adapter, member);
}
size_t length = buffer->length();

View File

@ -89,6 +89,8 @@ struct Functions {
VPackFunctionParameters const&);
static AqlValue Nth(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Contains(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Concat(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Like(arangodb::aql::Query*, arangodb::AqlTransaction*,

View File

@ -152,6 +152,8 @@ RocksDBFeature* RocksDBFeature::instance() {
}
int RocksDBFeature::syncWal() {
#ifndef _WIN32
// SyncWAL() always reports a "not implemented" error on Windows
if (Instance == nullptr || !Instance->isEnabled()) {
return TRI_ERROR_NO_ERROR;
}
@ -164,7 +166,7 @@ int RocksDBFeature::syncWal() {
LOG(ERR) << "error syncing rocksdb WAL: " << status.ToString();
return TRI_ERROR_INTERNAL;
}
#endif
return TRI_ERROR_NO_ERROR;
}

View File

@ -1317,7 +1317,6 @@ static void JS_PropertiesVocbaseCol(
}
TRI_document_collection_t* document = collection->_collection;
TRI_collection_t* base = document;
// check if we want to change some parameters
if (0 < args.Length()) {
@ -1337,18 +1336,18 @@ static void JS_PropertiesVocbaseCol(
// only work under the lock
WRITE_LOCKER(writeLocker, document->_infoLock);
if (base->_info.isVolatile() &&
if (document->_info.isVolatile() &&
arangodb::basics::VelocyPackHelper::getBooleanValue(
slice, "waitForSync", base->_info.waitForSync())) {
slice, "waitForSync", document->_info.waitForSync())) {
ReleaseCollection(collection);
// the combination of waitForSync and isVolatile makes no sense
TRI_V8_THROW_EXCEPTION_PARAMETER(
"volatile collections do not support the waitForSync option");
}
if (base->_info.isVolatile() !=
if (document->_info.isVolatile() !=
arangodb::basics::VelocyPackHelper::getBooleanValue(
slice, "isVolatile", base->_info.isVolatile())) {
slice, "isVolatile", document->_info.isVolatile())) {
TRI_V8_THROW_EXCEPTION_PARAMETER(
"isVolatile option cannot be changed at runtime");
}
@ -1363,11 +1362,11 @@ static void JS_PropertiesVocbaseCol(
"indexBuckets must be a two-power between 1 and 1024");
}
} // Leave the scope and free the JOURNAL lock
} // Leave the scope and free the lock
// try to write new parameter to file
bool doSync = base->_vocbase->_settings.forceSyncProperties;
res = base->updateCollectionInfo(base->_vocbase, slice, doSync);
bool doSync = document->_vocbase->_settings.forceSyncProperties;
res = document->updateCollectionInfo(document->_vocbase, slice, doSync);
if (res != TRI_ERROR_NO_ERROR) {
ReleaseCollection(collection);
@ -1377,7 +1376,7 @@ static void JS_PropertiesVocbaseCol(
try {
VPackBuilder infoBuilder;
infoBuilder.openObject();
TRI_CreateVelocyPackCollectionInfo(base->_info, infoBuilder);
TRI_CreateVelocyPackCollectionInfo(document->_info, infoBuilder);
infoBuilder.close();
// now log the property changes
@ -1411,12 +1410,12 @@ static void JS_PropertiesVocbaseCol(
TRI_GET_GLOBAL_STRING(IsSystemKey);
TRI_GET_GLOBAL_STRING(IsVolatileKey);
TRI_GET_GLOBAL_STRING(JournalSizeKey);
result->Set(DoCompactKey, v8::Boolean::New(isolate, base->_info.doCompact()));
result->Set(IsSystemKey, v8::Boolean::New(isolate, base->_info.isSystem()));
result->Set(DoCompactKey, v8::Boolean::New(isolate, document->_info.doCompact()));
result->Set(IsSystemKey, v8::Boolean::New(isolate, document->_info.isSystem()));
result->Set(IsVolatileKey,
v8::Boolean::New(isolate, base->_info.isVolatile()));
v8::Boolean::New(isolate, document->_info.isVolatile()));
result->Set(JournalSizeKey,
v8::Number::New(isolate, base->_info.maximalSize()));
v8::Number::New(isolate, document->_info.maximalSize()));
result->Set(TRI_V8_ASCII_STRING("indexBuckets"),
v8::Number::New(isolate, document->_info.indexBuckets()));
@ -1434,7 +1433,7 @@ static void JS_PropertiesVocbaseCol(
}
TRI_GET_GLOBAL_STRING(WaitForSyncKey);
result->Set(WaitForSyncKey,
v8::Boolean::New(isolate, base->_info.waitForSync()));
v8::Boolean::New(isolate, document->_info.waitForSync()));
ReleaseCollection(collection);
TRI_V8_RETURN(result);
@ -1458,11 +1457,11 @@ static int RenameGraphCollections(v8::Isolate* isolate,
v8::HandleScope scope(isolate);
StringBuffer buffer(TRI_UNKNOWN_MEM_ZONE);
buffer.appendText("require('@arangodb/general-graph')._renameCollection(\"");
buffer.appendText("require('@arangodb/general-graph')._renameCollection(");
buffer.appendJsonEncoded(oldName.c_str(), oldName.size());
buffer.appendText("\", \"");
buffer.appendChar(',');
buffer.appendJsonEncoded(newName.c_str(), newName.size());
buffer.appendText("\");");
buffer.appendText(");");
TRI_ExecuteJavaScriptString(
isolate, isolate->GetCurrentContext(),

View File

@ -476,9 +476,7 @@ void ImportHelper::addField(char const* field, size_t fieldLength, size_t row,
if (row == 0 || escaped) {
// head line or escaped value
_lineBuffer.appendChar('"');
_lineBuffer.appendJsonEncoded(field);
_lineBuffer.appendChar('"');
_lineBuffer.appendJsonEncoded(field, fieldLength);
return;
}
@ -514,9 +512,7 @@ void ImportHelper::addField(char const* field, size_t fieldLength, size_t row,
_lineBuffer.appendInteger(num);
} catch (...) {
// conversion failed
_lineBuffer.appendChar('"');
_lineBuffer.appendJsonEncoded(field);
_lineBuffer.appendChar('"');
_lineBuffer.appendJsonEncoded(field, fieldLength);
}
} else if (IsDecimal(field, fieldLength)) {
// double value
@ -539,9 +535,7 @@ void ImportHelper::addField(char const* field, size_t fieldLength, size_t row,
_lineBuffer.appendText(field, fieldLength);
_lineBuffer.appendChar('"');
} else {
_lineBuffer.appendChar('"');
_lineBuffer.appendJsonEncoded(field);
_lineBuffer.appendChar('"');
_lineBuffer.appendJsonEncoded(field, fieldLength);
}
}

View File

@ -2122,7 +2122,7 @@ function ARITHMETIC_MODULUS (lhs, rhs) {
function AQL_CONCAT () {
'use strict';
var result = '', i, j;
var result = '', i;
for (i = 0; i < arguments.length; ++i) {
var element = arguments[i];
@ -2130,16 +2130,7 @@ function AQL_CONCAT () {
if (weight === TYPEWEIGHT_NULL) {
continue;
}
else if (weight === TYPEWEIGHT_ARRAY) {
for (j = 0; j < element.length; ++j) {
if (TYPEWEIGHT(element[j]) !== TYPEWEIGHT_NULL) {
result += AQL_TO_STRING(element[j]);
}
}
}
else {
result += AQL_TO_STRING(element);
}
result += AQL_TO_STRING(element);
}
return result;
@ -2161,28 +2152,13 @@ function AQL_CONCAT_SEPARATOR () {
if (i > 0 && weight === TYPEWEIGHT_NULL) {
continue;
}
if (i === 0) {
separator = AQL_TO_STRING(element);
continue;
}
else if (found) {
result += separator;
}
if (weight === TYPEWEIGHT_ARRAY) {
found = false;
for (j = 0; j < element.length; ++j) {
if (TYPEWEIGHT(element[j]) !== TYPEWEIGHT_NULL) {
if (found) {
result += separator;
}
result += AQL_TO_STRING(element[j]);
found = true;
}
}
}
else {
if (found) {
result += separator;
}
result += AQL_TO_STRING(element);
found = true;
}
@ -2718,9 +2694,10 @@ function AQL_TO_STRING (value) {
case TYPEWEIGHT_STRING:
return value;
case TYPEWEIGHT_NUMBER:
return value.toString();
case TYPEWEIGHT_ARRAY:
case TYPEWEIGHT_OBJECT:
return value.toString();
return JSON.stringify(value);
}
}

View File

@ -73,8 +73,8 @@ function ahuacatlDynamicAttributesTestSuite () {
////////////////////////////////////////////////////////////////////////////////
testDynamicAttributesNonStringNames : function () {
var expected = { "true" : 12, "false" : 15, "123" : 21, "-42.5" : 99, "" : 117, "1,2,3,4" : 131, "[object Object]" : 149 };
var query = "{ [ PASSTHRU(null) ] : 7, [ PASSTHRU(true) ] : 12, [ PASSTHRU(false) ] : 15, [ PASSTHRU(123) ] : 21, [ PASSTHRU(-42.5) ] : 99, [ PASSTHRU([ ]) ] : 117, [ PASSTHRU([ 1, 2, 3, 4 ]) ] : 131, [ PASSTHRU({ a: 1 }) ] : 149 }";
var expected = { "" : 7, "true" : 12, "false" : 15, "123" : 21, "-42.5" : 99, "[]" : 117, "[1]" : 121, "[1,2,3,4]" : 131, "{\"a\":1}" : 149 };
var query = "{ [ PASSTHRU(null) ] : 7, [ PASSTHRU(true) ] : 12, [ PASSTHRU(false) ] : 15, [ PASSTHRU(123) ] : 21, [ PASSTHRU(-42.5) ] : 99, [ PASSTHRU([ ]) ] : 117, [ PASSTHRU([ 1 ]) ] : 121, [ PASSTHRU([ 1, 2, 3, 4 ]) ] : 131, [ PASSTHRU({ a: 1 }) ] : 149 }";
checkResult(query, expected);
},

View File

@ -288,8 +288,12 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ -1 ], getQueryResults(buildQuery(i, "\"test\", \"test2\", \"test3\"")));
assertEqual([ false ], getQueryResults(buildQuery(i, "null, null")));
assertEqual([ true ], getQueryResults(buildQuery(i, "4, 4")));
assertEqual([ true ], getQueryResults(buildQuery(i, "{ }, { }")));
assertEqual([ false ], getQueryResults(buildQuery(i, "[ ], [ ]")));
assertEqual([ true ], getQueryResults(buildQuery(i, "{}, {}")));
assertEqual([ true ], getQueryResults(buildQuery(i, "{a:1,b:2}, {a:1,b:2}")));
assertEqual([ true ], getQueryResults(buildQuery(i, "[], []")));
assertEqual([ true ], getQueryResults(buildQuery(i, "[1,2,3], [1,2,3]")));
assertEqual([ true ], getQueryResults(buildQuery(i, "[1,2], [1,2]")));
assertEqual([ true ], getQueryResults(buildQuery(i, "[1,2,3], 2")));
assertEqual([ false ], getQueryResults(buildQuery(i, "null, \"yes\"")));
assertEqual([ false ], getQueryResults(buildQuery(i, "3, null")));
}
@ -460,8 +464,10 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ "" ], getQueryResults("RETURN LEFT(null, 2)"));
assertEqual([ "tr" ], getQueryResults("RETURN LEFT(true, 2)"));
assertEqual([ "4" ], getQueryResults("RETURN LEFT(4, 2)"));
assertEqual([ "" ], getQueryResults("RETURN LEFT([ ], 2)"));
assertEqual([ "[o" ], getQueryResults("RETURN LEFT({ }, 2)"));
assertEqual([ "[]" ], getQueryResults("RETURN LEFT([ ], 2)"));
assertEqual([ "[" ], getQueryResults("RETURN LEFT([ ], 1)"));
assertEqual([ "{}" ], getQueryResults("RETURN LEFT({ }, 2)"));
assertEqual([ "{" ], getQueryResults("RETURN LEFT({ }, 1)"));
assertEqual([ "" ], getQueryResults("RETURN LEFT('foo', null)"));
assertEqual([ "f" ], getQueryResults("RETURN LEFT('foo', true)"));
assertEqual([ "" ], getQueryResults("RETURN LEFT('foo', 'bar')"));
@ -493,8 +499,10 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ "" ], getQueryResults("RETURN RIGHT(null, 2)"));
assertEqual([ "ue" ], getQueryResults("RETURN RIGHT(true, 2)"));
assertEqual([ "4" ], getQueryResults("RETURN RIGHT(4, 2)"));
assertEqual([ "" ], getQueryResults("RETURN RIGHT([ ], 2)"));
assertEqual([ "t]" ], getQueryResults("RETURN RIGHT({ }, 2)"));
assertEqual([ "[]" ], getQueryResults("RETURN RIGHT([ ], 2)"));
assertEqual([ "]" ], getQueryResults("RETURN RIGHT([ ], 1)"));
assertEqual([ "{}" ], getQueryResults("RETURN RIGHT({ }, 2)"));
assertEqual([ "}" ], getQueryResults("RETURN RIGHT({ }, 1)"));
assertEqual([ "" ], getQueryResults("RETURN RIGHT('foo', null)"));
assertEqual([ "o" ], getQueryResults("RETURN RIGHT('foo', true)"));
assertEqual([ "" ], getQueryResults("RETURN RIGHT('foo', 'bar')"));
@ -672,13 +680,13 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ "" ], getQueryResults("RETURN TRIM(null)"));
assertEqual([ "true" ], getQueryResults("RETURN TRIM(true)"));
assertEqual([ "4" ], getQueryResults("RETURN TRIM(4)"));
assertEqual([ "" ], getQueryResults("RETURN TRIM([ ])"));
assertEqual([ "[object Object]" ], getQueryResults("RETURN TRIM({ })"));
assertEqual([ "[]" ], getQueryResults("RETURN TRIM([ ])"));
assertEqual([ "{}" ], getQueryResults("RETURN TRIM({ })"));
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', null)"));
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', true)"));
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', 'bar')"));
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', [ ])"));
assertEqual([ "f" ], getQueryResults("RETURN TRIM('foo', { })")); // { } = "[object Object]"
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', { })"));
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', -1)"));
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', -1.5)"));
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', 3)"));
@ -836,12 +844,15 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST(null, 'foo')"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST(true, 'foo')"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST(4, 'foo')"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST([], 'foo')"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST([ ], 'foo')"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST({}, 'foo')"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST({ }, 'foo')"));
assertEqual([ 0 ], getQueryResults("RETURN FIND_FIRST('foo', null)"));
assertEqual([ 0 ], getQueryResults("RETURN FIND_FIRST('foo', '')"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', true)"));
assertEqual([ 0 ], getQueryResults("RETURN FIND_FIRST('foo', [ ])"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', [])"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', [1,2])"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', { })"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', -1)"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', -1.5)"));
@ -948,7 +959,7 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ 3 ], getQueryResults("RETURN FIND_LAST('foo', null)"));
assertEqual([ 3 ], getQueryResults("RETURN FIND_LAST('foo', '')"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_LAST('foo', true)"));
assertEqual([ 3 ], getQueryResults("RETURN FIND_LAST('foo', [ ])"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_LAST('foo', [ ])"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_LAST('foo', { })"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_LAST('foo', -1)"));
assertEqual([ -1 ], getQueryResults("RETURN FIND_LAST('foo', -1.5)"));
@ -986,7 +997,7 @@ function ahuacatlStringFunctionsTestSuite () {
testConcatList : function () {
var expected = [ "theQuickBrownアボカドJumps名称について" ];
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT([ 'the', 'Quick', '', null, 'Brown', null, 'アボカド', 'Jumps', '名称について' ])");
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT('the', 'Quick', '', null, 'Brown', null, 'アボカド', 'Jumps', '名称について' )");
assertEqual(expected, actual);
},
@ -998,12 +1009,12 @@ function ahuacatlStringFunctionsTestSuite () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN CONCAT()");
assertEqual([ "yestrue" ], getQueryResults("RETURN CONCAT(\"yes\", true)"));
assertEqual([ "yes4" ], getQueryResults("RETURN CONCAT(\"yes\", 4)"));
assertEqual([ "yes" ], getQueryResults("RETURN CONCAT(\"yes\", [ ])"));
assertEqual([ "yes[object Object]" ], getQueryResults("RETURN CONCAT(\"yes\", { })"));
assertEqual([ "yes[]" ], getQueryResults("RETURN CONCAT(\"yes\", [ ])"));
assertEqual([ "yes{}" ], getQueryResults("RETURN CONCAT(\"yes\", { })"));
assertEqual([ "trueyes" ], getQueryResults("RETURN CONCAT(true, \"yes\")"));
assertEqual([ "4yes" ], getQueryResults("RETURN CONCAT(4, \"yes\")"));
assertEqual([ "yes" ], getQueryResults("RETURN CONCAT([ ], \"yes\")"));
assertEqual([ "[object Object]yes" ], getQueryResults("RETURN CONCAT({ }, \"yes\")"));
assertEqual([ "[]yes" ], getQueryResults("RETURN CONCAT([ ], \"yes\")"));
assertEqual([ "{}yes" ], getQueryResults("RETURN CONCAT({ }, \"yes\")"));
},
////////////////////////////////////////////////////////////////////////////////
@ -1032,7 +1043,7 @@ function ahuacatlStringFunctionsTestSuite () {
testConcatCxxList : function () {
var expected = [ "theQuickBrownアボカドJumps名称について" ];
var actual = getQueryResults("FOR r IN [ 1 ] return NOOPT(CONCAT([ 'the', 'Quick', '', null, 'Brown', null, 'アボカド', 'Jumps', '名称について' ]))");
var actual = getQueryResults("FOR r IN [ 1 ] return NOOPT(CONCAT('the', 'Quick', '', null, 'Brown', null, 'アボカド', 'Jumps', '名称について'))");
assertEqual(expected, actual);
},
@ -1044,12 +1055,15 @@ function ahuacatlStringFunctionsTestSuite () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(CONCAT())");
assertEqual([ "yestrue" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", true))"));
assertEqual([ "yes4" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", 4))"));
assertEqual([ "yes" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", [ ]))"));
assertEqual([ "yes[object Object]" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", { }))"));
assertEqual([ "yes[]" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", [ ]))"));
assertEqual([ "yes{}" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", { }))"));
assertEqual([ "trueyes" ], getQueryResults("RETURN NOOPT(CONCAT(true, \"yes\"))"));
assertEqual([ "4yes" ], getQueryResults("RETURN NOOPT(CONCAT(4, \"yes\"))"));
assertEqual([ "yes" ], getQueryResults("RETURN NOOPT(CONCAT([ ], \"yes\"))"));
assertEqual([ "[object Object]yes" ], getQueryResults("RETURN NOOPT(CONCAT({ }, \"yes\"))"));
assertEqual([ "[]yes" ], getQueryResults("RETURN NOOPT(CONCAT([ ], \"yes\"))"));
assertEqual([ "[1,2,3]yes" ], getQueryResults("RETURN NOOPT(CONCAT([ 1,2,3], \"yes\"))"));
assertEqual([ "[1,2,3]yes" ], getQueryResults("RETURN NOOPT(CONCAT([ 1 , 2, 3 ], \"yes\"))"));
assertEqual([ "{}yes" ], getQueryResults("RETURN NOOPT(CONCAT({ }, \"yes\"))"));
assertEqual([ "{\"a\":\"foo\",\"b\":2}yes" ], getQueryResults("RETURN NOOPT(CONCAT({ a: \"foo\", b: 2 }, \"yes\"))"));
},
////////////////////////////////////////////////////////////////////////////////
@ -1077,7 +1091,7 @@ function ahuacatlStringFunctionsTestSuite () {
////////////////////////////////////////////////////////////////////////////////
testConcatSeparatorList1 : function () {
var expected = [ "the,Quick,Brown,Fox,Jumps,higher,than,you" ];
var expected = [ "[\"the\",\"Quick\",null,\"Brown\",null,\"Fox\",\"Jumps\"],higher,[\"than\",\"you\"]" ];
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT_SEPARATOR(',', [ 'the', 'Quick', null, 'Brown', null, 'Fox', 'Jumps' ], 'higher', [ 'than', 'you' ])");
assertEqual(expected, actual);
},
@ -1087,11 +1101,21 @@ function ahuacatlStringFunctionsTestSuite () {
////////////////////////////////////////////////////////////////////////////////
testConcatSeparatorList2 : function () {
var expected = [ "the*/*/Quick*/*/Brown*/*/*/*/Fox*/*/Jumps*/*/higher*/*/than*/*/you" ];
var expected = [ "[\"the\",\"Quick\",null,\"Brown\",\"\",\"Fox\",\"Jumps\"]*/*/[]*/*/higher*/*/[\"than\",\"you\"]" ];
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT_SEPARATOR('*/*/', [ 'the', 'Quick', null, 'Brown', '', 'Fox', 'Jumps' ], [ ], 'higher', [ 'than', 'you' ])");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test concat_separator function
////////////////////////////////////////////////////////////////////////////////
testConcatSeparatorList3 : function () {
var expected = [ "the*/*/Quick*/*/Brown*/*/*/*/Fox*/*/Jumps*/*/[]*/*/higher*/*/[\"than\",\"you\"]" ];
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT_SEPARATOR('*/*/', 'the', 'Quick', null, 'Brown', '', 'Fox', 'Jumps', [ ], 'higher', [ 'than', 'you' ])");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test concat_separator function
////////////////////////////////////////////////////////////////////////////////
@ -1102,16 +1126,17 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ "yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(null, \"yes\", \"yes\")"));
assertEqual([ "yestrueyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(true, \"yes\", \"yes\")"));
assertEqual([ "yes4yes" ], getQueryResults("RETURN CONCAT_SEPARATOR(4, \"yes\", \"yes\")"));
assertEqual([ "yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR([ ], \"yes\", \"yes\")"));
assertEqual([ "yes[object Object]yes" ], getQueryResults("RETURN CONCAT_SEPARATOR({ }, \"yes\", \"yes\")"));
assertEqual([ "yes[]yes" ], getQueryResults("RETURN CONCAT_SEPARATOR([ ], \"yes\", \"yes\")"));
assertEqual([ "yes{}yes" ], getQueryResults("RETURN CONCAT_SEPARATOR({ }, \"yes\", \"yes\")"));
assertEqual([ "trueyesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", true, \"yes\")"));
assertEqual([ "4yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", 4, \"yes\")"));
assertEqual([ "yes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", [ ], \"yes\")"));
assertEqual([ "[object Object]yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", { }, \"yes\")"));
assertEqual([ "[]yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", [ ], \"yes\")"));
assertEqual([ "{}yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", { }, \"yes\")"));
assertEqual([ "yesyestrue" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", true)"));
assertEqual([ "yesyes4" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", 4)"));
assertEqual([ "yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", [ ])"));
assertEqual([ "yesyes[object Object]" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", { })"));
assertEqual([ "yesyes[]" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", [ ])"));
assertEqual([ "yesyes[1,2,3]" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", [ 1,2,3 ])"));
assertEqual([ "yesyes{}" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", { })"));
},
////////////////////////////////////////////////////////////////////////////////
@ -1154,8 +1179,12 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ 0 ], getQueryResults("RETURN CHAR_LENGTH(null)"));
assertEqual([ 4 ], getQueryResults("RETURN CHAR_LENGTH(true)"));
assertEqual([ 1 ], getQueryResults("RETURN CHAR_LENGTH(3)"));
assertEqual([ 0 ], getQueryResults("RETURN CHAR_LENGTH([ ])"));
assertEqual([ 15 ], getQueryResults("RETURN CHAR_LENGTH({ })"));
assertEqual([ 2 ], getQueryResults("RETURN CHAR_LENGTH([ ])"));
assertEqual([ 7 ], getQueryResults("RETURN CHAR_LENGTH([ 1, 2, 3 ])"));
assertEqual([ 2 ], getQueryResults("RETURN CHAR_LENGTH({ })"));
assertEqual([ 7 ], getQueryResults("RETURN CHAR_LENGTH({ a:1 })"));
assertEqual([ 11 ], getQueryResults("RETURN CHAR_LENGTH({ a: \"foo\" })"));
assertEqual([ 13 ], getQueryResults("RETURN CHAR_LENGTH({ a:1, b: 2 })"));
},
////////////////////////////////////////////////////////////////////////////////
@ -1198,8 +1227,11 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ "" ], getQueryResults("RETURN LOWER(null)"));
assertEqual([ "true" ], getQueryResults("RETURN LOWER(true)"));
assertEqual([ "3" ], getQueryResults("RETURN LOWER(3)"));
assertEqual([ "" ], getQueryResults("RETURN LOWER([])"));
assertEqual([ "[object object]" ], getQueryResults("RETURN LOWER({})"));
assertEqual([ "[]" ], getQueryResults("RETURN LOWER([])"));
assertEqual([ "[1,2,3]" ], getQueryResults("RETURN LOWER([1,2,3])"));
assertEqual([ "{}" ], getQueryResults("RETURN LOWER({})"));
assertEqual([ "{\"a\":1,\"b\":2}" ], getQueryResults("RETURN LOWER({A:1,b:2})"));
assertEqual([ "{\"a\":1,\"a\":2,\"b\":3}" ], getQueryResults("RETURN LOWER({A:1,a:2,b:3})"));
},
////////////////////////////////////////////////////////////////////////////////
@ -1232,8 +1264,10 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ "" ], getQueryResults("RETURN UPPER(null)"));
assertEqual([ "TRUE" ], getQueryResults("RETURN UPPER(true)"));
assertEqual([ "3" ], getQueryResults("RETURN UPPER(3)"));
assertEqual([ "" ], getQueryResults("RETURN UPPER([])"));
assertEqual([ "[OBJECT OBJECT]" ], getQueryResults("RETURN UPPER({})"));
assertEqual([ "[]" ], getQueryResults("RETURN UPPER([])"));
assertEqual([ "[1,2,3]" ], getQueryResults("RETURN UPPER([1,2,3])"));
assertEqual([ "{}" ], getQueryResults("RETURN UPPER({})"));
assertEqual([ "{\"A\":1,\"B\":2}" ], getQueryResults("RETURN UPPER({a:1, b:2})"));
},
////////////////////////////////////////////////////////////////////////////////
@ -1309,8 +1343,10 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ "" ], getQueryResults(buildQuery(i, "null, 1")));
assertEqual([ "true" ], getQueryResults(buildQuery(i, "true, 0")));
assertEqual([ "3" ], getQueryResults(buildQuery(i, "3, 0")));
assertEqual([ "" ], getQueryResults(buildQuery(i, "[ ], 0")));
assertEqual([ "[object Object]" ], getQueryResults(buildQuery(i, "{ }, 0")));
assertEqual([ "[]" ], getQueryResults(buildQuery(i, "[ ], 0")));
assertEqual([ "[1,2,3]" ], getQueryResults(buildQuery(i, "[ 1, 2, 3 ], 0")));
assertEqual([ "2,3]" ], getQueryResults(buildQuery(i, "[ 1, 2, 3 ], 3")));
assertEqual([ "{}" ], getQueryResults(buildQuery(i, "{ }, 0")));
assertEqual([ "" ], getQueryResults(buildQuery(i, "\"yes\", null, 0")));
assertEqual([ "" ], getQueryResults(buildQuery(i, "\"yes\", true, 0")));
assertEqual([ "" ], getQueryResults(buildQuery(i, "\"yes\", \"yes\", 0")));
@ -1444,8 +1480,13 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ "c4ca4238a0b923820dcc509a6f75849b" ], getQueryResults("RETURN MD5(1)"));
assertEqual([ "6bb61e3b7bce0931da574d19d1d82c88" ], getQueryResults("RETURN MD5(-1)"));
assertEqual([ "d41d8cd98f00b204e9800998ecf8427e" ], getQueryResults("RETURN MD5(null)"));
assertEqual([ "d751713988987e9331980363e24189ce" ], getQueryResults("RETURN MD5([])"));
assertEqual([ "8d5162ca104fa7e79fe80fd92bb657fb" ], getQueryResults("RETURN MD5([0])"));
assertEqual([ "35dba5d75538a9bbe0b4da4422759a0e" ], getQueryResults("RETURN MD5('[1]')"));
assertEqual([ "1441a7909c087dbbe7ce59881b9df8b9" ], getQueryResults("RETURN MD5({ })"));
assertEqual([ "f79408e5ca998cd53faf44af31e6eb45" ], getQueryResults("RETURN MD5([1,2])"));
assertEqual([ "99914b932bd37a50b983c5e7c90ae93b" ], getQueryResults("RETURN MD5({ })"));
assertEqual([ "99914b932bd37a50b983c5e7c90ae93b" ], getQueryResults("RETURN MD5({})"));
assertEqual([ "608de49a4600dbb5b173492759792e4a" ], getQueryResults("RETURN MD5({a:1,b:2})"));
},
////////////////////////////////////////////////////////////////////////////////
@ -1499,7 +1540,7 @@ function ahuacatlStringFunctionsTestSuite () {
assertEqual([ "6bb61e3b7bce0931da574d19d1d82c88" ], getQueryResults("RETURN NOOPT(MD5(-1))"));
assertEqual([ "d41d8cd98f00b204e9800998ecf8427e" ], getQueryResults("RETURN NOOPT(MD5(null))"));
assertEqual([ "35dba5d75538a9bbe0b4da4422759a0e" ], getQueryResults("RETURN NOOPT(MD5('[1]'))"));
assertEqual([ "1441a7909c087dbbe7ce59881b9df8b9" ], getQueryResults("RETURN NOOPT(MD5({ }))"));
assertEqual([ "99914b932bd37a50b983c5e7c90ae93b" ], getQueryResults("RETURN NOOPT(MD5({}))"));
assertEqual([ "c7cb8c1df686c0219d540849efe3bce3" ], getQueryResults("RETURN NOOPT(MD5('[1,2,4,7,11,16,22,29,37,46,56,67,79,92,106,121,137,154,172,191,211,232,254,277,301,326,352,379,407,436,466,497,529,562,596,631,667,704,742,781,821,862,904,947,991,1036,1082,1129,1177,1226,1276,1327,1379,1432,1486,1541,1597,1654,1712,1771,1831,1892,1954,2017,2081,2146,2212,2279,2347,2416,2486,2557,2629,2702,2776,2851,2927,3004,3082,3161,3241,3322,3404,3487,3571,3656,3742,3829,3917,4006,4096,4187,4279,4372,4466,4561,4657,4754,4852,4951]'))"));
},

View File

@ -679,23 +679,23 @@ function ahuacatlOperatorsTestSuite () {
{ex: "1 ", val: "'1 '"},
{ex: "0", val: "'0'"},
{ex: "-1", val: "'-1'"},
{ex: "", val: "[ ]"},
{ex: "0", val: "[ 0 ]"},
{ex: "0,1", val: "[ 0, 1 ]"},
{ex: "1,2", val: "[ 1, 2 ]"},
{ex: "-1,0", val: "[ -1, 0 ]"},
{ex: "0,1,1,2,9,4", val: "[ 0, 1, [1, 2], [ [ 9, 4 ] ] ]"},
{ex: "[object Object]", val: "[ { } ]"},
{ex: "0,1,[object Object]", val: "[ 0, 1, { } ]"},
{ex: "[object Object],[object Object]", val: "[ { }, { } ]"},
{ex: "", val: "['']"},
{ex: "false", val: "[ false ]"},
{ex: "true", val: "[ true ]"},
{ex: "[object Object]", val: "{ }"},
{ex: "[object Object]", val: "{ 'a' : true }"},
{ex: "[object Object]", val: "{ 'a' : true, 'b' : 0 }"},
{ex: "[object Object]", val: "{ 'a' : { }, 'b' : { } }"},
{ex: "[object Object]", val: "{ 'a' : [ ], 'b' : [ ] }"}
{ex: "[]", val: "[ ]"},
{ex: "[0]", val: "[ 0 ]"},
{ex: "[0,1]", val: "[ 0, 1 ]"},
{ex: "[1,2]", val: "[ 1, 2 ]"},
{ex: "[-1,0]", val: "[ -1, 0 ]"},
{ex: "[0,1,[1,2],[[9,4]]]", val: "[ 0, 1, [1, 2], [ [ 9, 4 ] ] ]"},
{ex: "[{}]", val: "[ { } ]"},
{ex: "[0,1,{}]", val: "[ 0, 1, { } ]"},
{ex: "[{},{}]", val: "[ { }, { } ]"},
{ex: "[\"\"]", val: "['']"},
{ex: "[false]", val: "[ false ]"},
{ex: "[true]", val: "[ true ]"},
{ex: "{}", val: "{ }"},
{ex: "{\"a\":true}", val: "{ 'a' : true }"},
{ex: "{\"a\":true,\"b\":0}", val: "{ 'a' : true, 'b' : 0 }"},
{ex: "{\"a\":{},\"b\":{}}", val: "{ 'a' : { }, 'b' : { } }"},
{ex: "{\"a\":[],\"b\":[]}", val: "{ 'a' : [ ], 'b' : [ ] }"}
];
values.forEach(function(v) {
var q = `RETURN TO_STRING(${v.val})`;
@ -4126,22 +4126,22 @@ function ahuacatlOperatorsTestSuite () {
assertEqual("1", aql.AQL_CONCAT(undefined, 1));
assertEqual("2", aql.AQL_CONCAT(undefined, 2));
assertEqual("-1", aql.AQL_CONCAT(undefined, -1));
assertEqual("", aql.AQL_CONCAT(undefined, [ ]));
assertEqual("1", aql.AQL_CONCAT(undefined, [ 1 ]));
assertEqual("12", aql.AQL_CONCAT(undefined, [ 1, 2 ]));
assertEqual("[object Object]", aql.AQL_CONCAT(undefined, { }));
assertEqual("[object Object]", aql.AQL_CONCAT(undefined, { 'a' : 0 }));
assertEqual("[]", aql.AQL_CONCAT(undefined, [ ]));
assertEqual("[1]", aql.AQL_CONCAT(undefined, [ 1 ]));
assertEqual("[1,2]", aql.AQL_CONCAT(undefined, [ 1, 2 ]));
assertEqual("{}", aql.AQL_CONCAT(undefined, { }));
assertEqual("{\"a\":0}", aql.AQL_CONCAT(undefined, { 'a' : 0 }));
assertEqual("false", aql.AQL_CONCAT(false, undefined));
assertEqual("true", aql.AQL_CONCAT(true, undefined));
assertEqual("0", aql.AQL_CONCAT(0, undefined));
assertEqual("1", aql.AQL_CONCAT(1, undefined));
assertEqual("2", aql.AQL_CONCAT(2, undefined));
assertEqual("-1", aql.AQL_CONCAT(-1, undefined));
assertEqual("", aql.AQL_CONCAT([ ], undefined));
assertEqual("1", aql.AQL_CONCAT([ 1 ], undefined));
assertEqual("12", aql.AQL_CONCAT([ 1, 2 ], undefined));
assertEqual("[object Object]", aql.AQL_CONCAT({ }, undefined));
assertEqual("[object Object]", aql.AQL_CONCAT({ 'a' : 0 }, undefined));
assertEqual("[]", aql.AQL_CONCAT([ ], undefined));
assertEqual("[1]", aql.AQL_CONCAT([ 1 ], undefined));
assertEqual("[1,2]", aql.AQL_CONCAT([ 1, 2 ], undefined));
assertEqual("{}", aql.AQL_CONCAT({ }, undefined));
assertEqual("{\"a\":0}", aql.AQL_CONCAT({ 'a' : 0 }, undefined));
assertEqual("1", aql.AQL_CONCAT(1, NaN));
assertEqual("1", aql.AQL_CONCAT(1, null));
assertEqual("1false", aql.AQL_CONCAT(1, false));
@ -4151,10 +4151,10 @@ function ahuacatlOperatorsTestSuite () {
assertEqual("10", aql.AQL_CONCAT(1, '0'));
assertEqual("11", aql.AQL_CONCAT(1, '1'));
assertEqual("1a", aql.AQL_CONCAT(1, 'a'));
assertEqual("1", aql.AQL_CONCAT(1, [ ]));
assertEqual("10", aql.AQL_CONCAT(1, [ 0 ]));
assertEqual("1[object Object]", aql.AQL_CONCAT(1, { }));
assertEqual("1[object Object]", aql.AQL_CONCAT(1, { 'a' : 0 }));
assertEqual("1[]", aql.AQL_CONCAT(1, [ ]));
assertEqual("1[0]", aql.AQL_CONCAT(1, [ 0 ]));
assertEqual("1{}", aql.AQL_CONCAT(1, { }));
assertEqual("1{\"a\":0}", aql.AQL_CONCAT(1, { 'a' : 0 }));
assertEqual("1", aql.AQL_CONCAT(NaN, 1));
assertEqual("1", aql.AQL_CONCAT(null, 1));
assertEqual("false1", aql.AQL_CONCAT(false, 1));
@ -4164,10 +4164,10 @@ function ahuacatlOperatorsTestSuite () {
assertEqual("01", aql.AQL_CONCAT('0', 1));
assertEqual("11", aql.AQL_CONCAT('1', 1));
assertEqual("a1", aql.AQL_CONCAT('a', 1));
assertEqual("1", aql.AQL_CONCAT([ ], 1));
assertEqual("01", aql.AQL_CONCAT([ 0 ], 1));
assertEqual("[object Object]1", aql.AQL_CONCAT({ }, 1));
assertEqual("[object Object]1", aql.AQL_CONCAT({ 'a' : 0 }, 1));
assertEqual("[]1", aql.AQL_CONCAT([ ], 1));
assertEqual("[0]1", aql.AQL_CONCAT([ 0 ], 1));
assertEqual("{}1", aql.AQL_CONCAT({ }, 1));
assertEqual("{\"a\":0}1", aql.AQL_CONCAT({ 'a' : 0 }, 1));
assertEqual("10", aql.AQL_CONCAT(1, 0));
assertEqual("1000", aql.AQL_CONCAT(100, 0));
assertEqual("-10", aql.AQL_CONCAT(-1, 0));
@ -4175,12 +4175,13 @@ function ahuacatlOperatorsTestSuite () {
assertEqual("00", aql.AQL_CONCAT(0, 0));
assertEqual("false", aql.AQL_CONCAT('', false));
assertEqual("true", aql.AQL_CONCAT('', true));
assertEqual("", aql.AQL_CONCAT('', [ ]));
assertEqual("[object Object]", aql.AQL_CONCAT('', { }));
assertEqual("[]", aql.AQL_CONCAT('', [ ]));
assertEqual("{}", aql.AQL_CONCAT('', { }));
assertEqual("afalse", aql.AQL_CONCAT('a', false));
assertEqual("atrue", aql.AQL_CONCAT('a', true));
assertEqual("a", aql.AQL_CONCAT('a', [ ]));
assertEqual("a[object Object]", aql.AQL_CONCAT('a', { }));
assertEqual("a[]", aql.AQL_CONCAT('a', [ ]));
assertEqual("a{}", aql.AQL_CONCAT('a', { }));
assertEqual("a{\"foo\":\"bar\"}", aql.AQL_CONCAT('a', { foo: "bar" }));
},
////////////////////////////////////////////////////////////////////////////////

View File

@ -27,50 +27,6 @@
#include "Basics/fpconv.h"
#include "Zip/zip.h"
////////////////////////////////////////////////////////////////////////////////
/// @brief escape tables
////////////////////////////////////////////////////////////////////////////////
#define Z16 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
////////////////////////////////////////////////////////////////////////////////
/// @brief escape values for characters used in JSON string printing
/// use when forward slashes need no escaping
////////////////////////////////////////////////////////////////////////////////
static char const JsonEscapeTableWithoutSlash[256] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n',
'u', 'f', 'r', 'u', 'u', // 00
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
'u', 'u', 'u', 'u', 'u', // 10
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, // 20
Z16, Z16, // 30~4F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, '\\', 0, 0, 0, // 50
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
};
////////////////////////////////////////////////////////////////////////////////
/// @brief escape values for characters used in JSON string printing
/// use when forward slashes need escaping
////////////////////////////////////////////////////////////////////////////////
static char const JsonEscapeTableWithSlash[256] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n',
'u', 'f', 'r', 'u', 'u', // 00
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
'u', 'u', 'u', 'u', 'u', // 10
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, '/', // 20
Z16, Z16, // 30~4F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, '\\', 0, 0, 0, // 50
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
};
////////////////////////////////////////////////////////////////////////////////
/// @brief append a character without check
////////////////////////////////////////////////////////////////////////////////
@ -136,266 +92,6 @@ static int AppendString(TRI_string_buffer_t* self, char const* str,
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief escapes UTF-8 range U+0000 to U+007F
////////////////////////////////////////////////////////////////////////////////
static void EscapeUtf8Range0000T007F(TRI_string_buffer_t* self,
char const** src) {
uint8_t c = (uint8_t) * (*src);
uint16_t i1 = (((uint16_t)c) & 0xF0) >> 4;
uint16_t i2 = (((uint16_t)c) & 0x0F);
AppendString(self, "00", 2);
AppendChar(self, (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10));
AppendChar(self, (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief escapes UTF-8 range U+0080 to U+07FF
////////////////////////////////////////////////////////////////////////////////
static void EscapeUtf8Range0080T07FF(TRI_string_buffer_t* self,
char const** src) {
uint8_t c = (uint8_t) * ((*src) + 0);
uint8_t d = (uint8_t) * ((*src) + 1);
// correct UTF-8
if ((d & 0xC0) == 0x80) {
uint16_t n = ((c & 0x1F) << 6) | (d & 0x3F);
TRI_ASSERT(n >= 128);
uint16_t i1 = (n & 0xF000) >> 12;
uint16_t i2 = (n & 0x0F00) >> 8;
uint16_t i3 = (n & 0x00F0) >> 4;
uint16_t i4 = (n & 0x000F);
AppendChar(self, '\\');
AppendChar(self, 'u');
AppendChar(self, (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10));
AppendChar(self, (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10));
AppendChar(self, (i3 < 10) ? ('0' + i3) : ('A' + i3 - 10));
AppendChar(self, (i4 < 10) ? ('0' + i4) : ('A' + i4 - 10));
(*src) += 1;
}
// corrupted UTF-8
else {
AppendChar(self, *(*src));
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief escapes UTF-8 range U+0800 to U+D7FF and U+E000 to U+FFFF
////////////////////////////////////////////////////////////////////////////////
static void EscapeUtf8Range0800TFFFF(TRI_string_buffer_t* self,
char const** src) {
uint8_t c = (uint8_t) * ((*src) + 0);
uint8_t d = (uint8_t) * ((*src) + 1);
uint8_t e = (uint8_t) * ((*src) + 2);
// correct UTF-8 (3-byte sequence UTF-8 1110xxxx 10xxxxxx)
if ((d & 0xC0) == 0x80 && (e & 0xC0) == 0x80) {
uint16_t n = ((c & 0x0F) << 12) | ((d & 0x3F) << 6) | (e & 0x3F);
TRI_ASSERT(n >= 2048 && (n < 55296 || n > 57343));
uint16_t i1 = (n & 0xF000) >> 12;
uint16_t i2 = (n & 0x0F00) >> 8;
uint16_t i3 = (n & 0x00F0) >> 4;
uint16_t i4 = (n & 0x000F);
AppendChar(self, '\\');
AppendChar(self, 'u');
AppendChar(self, (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10));
AppendChar(self, (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10));
AppendChar(self, (i3 < 10) ? ('0' + i3) : ('A' + i3 - 10));
AppendChar(self, (i4 < 10) ? ('0' + i4) : ('A' + i4 - 10));
(*src) += 2;
}
// corrupted UTF-8
else {
AppendChar(self, *(*src));
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief escapes UTF-8 range U+10000 to U+10FFFF
////////////////////////////////////////////////////////////////////////////////
static void EscapeUtf8Range10000T10FFFF(TRI_string_buffer_t* self,
char const** src) {
uint8_t c = (uint8_t) * ((*src) + 0);
uint8_t d = (uint8_t) * ((*src) + 1);
uint8_t e = (uint8_t) * ((*src) + 2);
uint8_t f = (uint8_t) * ((*src) + 3);
// correct UTF-8 (4-byte sequence UTF-8 1110xxxx 10xxxxxx 10xxxxxx)
if ((d & 0xC0) == 0x80 && (e & 0xC0) == 0x80 && (f & 0xC0) == 0x80) {
uint32_t n = ((c & 0x0F) << 18) | ((d & 0x3F) << 12) | ((e & 0x3F) << 6) |
(f & 0x3F);
TRI_ASSERT(n >= 65536 && n <= 1114111);
// construct the surrogate pairs
n -= 0x10000;
uint32_t s1 = ((n & 0xFFC00) >> 10) + 0xD800;
uint32_t s2 = (n & 0x3FF) + 0xDC00;
// encode high surrogate
uint16_t i1 = (s1 & 0xF000) >> 12;
uint16_t i2 = (s1 & 0x0F00) >> 8;
uint16_t i3 = (s1 & 0x00F0) >> 4;
uint16_t i4 = (s1 & 0x000F);
AppendChar(self, '\\');
AppendChar(self, 'u');
AppendChar(self, (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10));
AppendChar(self, (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10));
AppendChar(self, (i3 < 10) ? ('0' + i3) : ('A' + i3 - 10));
AppendChar(self, (i4 < 10) ? ('0' + i4) : ('A' + i4 - 10));
// encode low surrogate
i1 = (s2 & 0xF000) >> 12;
i2 = (s2 & 0x0F00) >> 8;
i3 = (s2 & 0x00F0) >> 4;
i4 = (s2 & 0x000F);
AppendChar(self, '\\');
AppendChar(self, 'u');
AppendChar(self, (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10));
AppendChar(self, (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10));
AppendChar(self, (i3 < 10) ? ('0' + i3) : ('A' + i3 - 10));
AppendChar(self, (i4 < 10) ? ('0' + i4) : ('A' + i4 - 10));
// advance src
(*src) += 3;
}
// corrupted UTF-8
else {
AppendChar(self, *(*src));
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief appends characters but json-encode the string
////////////////////////////////////////////////////////////////////////////////
static int AppendJsonEncodedValue(TRI_string_buffer_t* self, char const*& ptr,
bool escapeSlash) {
int res = Reserve(self, 2);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
// next character as unsigned char
uint8_t c = (uint8_t)*ptr;
// character is in the normal latin1 range
if ((c & 0x80) == 0) {
// special character, escape
char esc;
if (escapeSlash) {
esc = JsonEscapeTableWithSlash[c];
} else {
esc = JsonEscapeTableWithoutSlash[c];
}
if (esc) {
AppendChar(self, '\\');
AppendChar(self, esc);
if (esc == 'u') {
// unicode output, must allocate more memory
res = Reserve(self, 4);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
EscapeUtf8Range0000T007F(self, &ptr);
}
}
// normal latin1
else {
AppendChar(self, *ptr);
}
}
// unicode range 0080 - 07ff (2-byte sequence UTF-8)
else if ((c & 0xE0) == 0xC0) {
// hopefully correct UTF-8
if (*(ptr + 1) != '\0') {
res = Reserve(self, 6);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
EscapeUtf8Range0080T07FF(self, &ptr);
}
// corrupted UTF-8
else {
AppendChar(self, *ptr);
}
}
// unicode range 0800 - ffff (3-byte sequence UTF-8)
else if ((c & 0xF0) == 0xE0) {
// hopefully correct UTF-8
if (*(ptr + 1) != '\0' && *(ptr + 2) != '\0') {
res = Reserve(self, 6);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
EscapeUtf8Range0800TFFFF(self, &ptr);
}
// corrupted UTF-8
else {
AppendChar(self, *ptr);
}
}
// unicode range 10000 - 10ffff (4-byte sequence UTF-8)
else if ((c & 0xF8) == 0xF0) {
// hopefully correct UTF-8
if (*(ptr + 1) != '\0' && *(ptr + 2) != '\0' && *(ptr + 3) != '\0') {
res = Reserve(self, 12);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
EscapeUtf8Range10000T10FFFF(self, &ptr);
}
// corrupted UTF-8
else {
AppendChar(self, *ptr);
}
}
// unicode range above 10ffff -- NOT IMPLEMENTED
else {
AppendChar(self, *ptr);
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a new string buffer and initialize it
////////////////////////////////////////////////////////////////////////////////
@ -803,25 +499,112 @@ int TRI_AppendString2StringBuffer(TRI_string_buffer_t* self, char const* str,
return AppendString(self, str, len);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief appends characters but json-encode the null-terminated string
////////////////////////////////////////////////////////////////////////////////
int AppendJsonEncoded(TRI_string_buffer_t* self, char const* src,
size_t length, bool escapeForwardSlashes) {
static char const EscapeTable[256] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E
// F
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r',
'u',
'u', // 00
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
'u',
'u', // 10
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
'/', // 20
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
0, // 30~4F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
'\\', 0, 0, 0, // 50
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
0, // 60~FF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0};
int TRI_AppendJsonEncodedStringStringBuffer(TRI_string_buffer_t* self,
char const* src, bool escapeSlash) {
char const* ptr = src;
// reserve enough room for the whole string at once
int res = Reserve(self, 6 * length + 2);
while (*ptr != '\0') {
int res = AppendJsonEncodedValue(self, ptr, escapeSlash);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
AppendChar(self, '"');
if (res != TRI_ERROR_NO_ERROR) {
return res;
uint8_t const* p = reinterpret_cast<uint8_t const*>(src);
uint8_t const* e = p + length;
while (p < e) {
uint8_t c = *p;
if ((c & 0x80) == 0) {
// check for control characters
char esc = EscapeTable[c];
if (esc) {
if (c != '/' || escapeForwardSlashes) {
// escape forward slashes only when requested
AppendChar(self, '\\');
}
AppendChar(self, static_cast<char>(esc));
if (esc == 'u') {
uint16_t i1 = (((uint16_t)c) & 0xf0) >> 4;
uint16_t i2 = (((uint16_t)c) & 0x0f);
AppendChar(self, '0');
AppendChar(self, '0');
AppendChar(self, static_cast<char>((i1 < 10) ? ('0' + i1) : ('A' + i1 - 10)));
AppendChar(self, static_cast<char>((i2 < 10) ? ('0' + i2) : ('A' + i2 - 10)));
}
} else {
AppendChar(self, static_cast<char>(c));
}
} else if ((c & 0xe0) == 0xc0) {
// two-byte sequence
if (p + 1 >= e) {
return TRI_ERROR_INTERNAL;
}
memcpy(self->_current, reinterpret_cast<char const*>(p), 2);
self->_current += 2;
++p;
} else if ((c & 0xf0) == 0xe0) {
// three-byte sequence
if (p + 2 >= e) {
return TRI_ERROR_INTERNAL;
}
memcpy(self->_current, reinterpret_cast<char const*>(p), 3);
self->_current += 3;
p += 2;
} else if ((c & 0xf8) == 0xf0) {
// four-byte sequence
if (p + 3 >= e) {
return TRI_ERROR_INTERNAL;
}
memcpy(self->_current, reinterpret_cast<char const*>(p), 4);
self->_current += 4;
p += 3;
}
++ptr;
++p;
}
return TRI_ERROR_NO_ERROR;
AppendChar(self, '"');
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
@ -831,20 +614,7 @@ int TRI_AppendJsonEncodedStringStringBuffer(TRI_string_buffer_t* self,
int TRI_AppendJsonEncodedStringStringBuffer(TRI_string_buffer_t* self,
char const* src, size_t length,
bool escapeSlash) {
char const* ptr = src;
char const* end = src + length;
while (ptr < end) {
int res = AppendJsonEncodedValue(self, ptr, escapeSlash);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
++ptr;
}
return TRI_ERROR_NO_ERROR;
return AppendJsonEncoded(self, src, length, escapeSlash);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -229,13 +229,6 @@ static inline void TRI_AppendStringUnsafeStringBuffer(TRI_string_buffer_t* self,
self->_current += str.size();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief appends characters but json-encode the null-terminated string
////////////////////////////////////////////////////////////////////////////////
int TRI_AppendJsonEncodedStringStringBuffer(TRI_string_buffer_t* self,
char const* str, bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief appends characters but json-encode the string
////////////////////////////////////////////////////////////////////////////////
@ -791,15 +784,6 @@ class StringBuffer {
/// @brief appends as json-encoded
//////////////////////////////////////////////////////////////////////////////
StringBuffer& appendJsonEncoded(char const* str) {
TRI_AppendJsonEncodedStringStringBuffer(&_buffer, str, true);
return *this;
}
//////////////////////////////////////////////////////////////////////////////
/// @brief appends as json-encoded
//////////////////////////////////////////////////////////////////////////////
StringBuffer& appendJsonEncoded(char const* str, size_t length) {
TRI_AppendJsonEncodedStringStringBuffer(&_buffer, str, length, true);
return *this;

View File

@ -78,27 +78,17 @@ static int StringifyJson(TRI_memory_zone_t* zone, TRI_string_buffer_t* buffer,
case TRI_JSON_STRING:
case TRI_JSON_STRING_REFERENCE: {
res = TRI_AppendCharStringBuffer(buffer, '\"');
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
if (object->_value._string.length > 0) {
// optimisation for the empty string
res = TRI_AppendJsonEncodedStringStringBuffer(
buffer, object->_value._string.data,
object->_value._string.length - 1, false);
if (res != TRI_ERROR_NO_ERROR) {
return TRI_ERROR_OUT_OF_MEMORY;
}
} else {
res = TRI_AppendString2StringBuffer(buffer, "\"\"", 2);
}
res = TRI_AppendCharStringBuffer(buffer, '\"');
if (res != TRI_ERROR_NO_ERROR) {
return res;
return TRI_ERROR_OUT_OF_MEMORY;
}
break;

View File

@ -46,6 +46,41 @@ void* memrchr(void const* block, int c, size_t size) {
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief memmem
////////////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
void* xmemmem(void const* haystack, size_t haystackLength,
void const* needle, size_t needleLength) {
if (haystackLength == 0 ||
needleLength == 0 ||
haystackLength < needleLength) {
return nullptr;
}
char const* n = static_cast<char const*>(needle);
if (needleLength == 1) {
return memchr(const_cast<void*>(haystack), static_cast<int>(*n), haystackLength);
}
char const* current = static_cast<char const*>(haystack);
char const* end = static_cast<char const*>(haystack) + haystackLength - needleLength;
for (; current <= end; ++current) {
if (*current == *n &&
memcmp(needle, current, needleLength) == 0) {
return const_cast<void*>(static_cast<void const*>(current));
}
}
return nullptr;
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief get the time of day
////////////////////////////////////////////////////////////////////////////////

View File

@ -36,6 +36,14 @@
void* memrchr(void const* block, int c, size_t size);
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief memmem
////////////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
void* memmem(void const* haystack, size_t haystackLength, void const* needle, size_t needleLength);
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief get the time of day
////////////////////////////////////////////////////////////////////////////////