bool DocumentAccessor::hasKey (std::string const& attribute) const { if (! isObject()) { return false; } if (_current == nullptr) { if (attribute.size() > 1 && attribute[0] == '_') { if (attribute == TRI_VOC_ATTRIBUTE_ID || attribute == TRI_VOC_ATTRIBUTE_KEY || attribute == TRI_VOC_ATTRIBUTE_REV) { return true; } if (TRI_IS_EDGE_MARKER(_mptr) && (attribute == TRI_VOC_ATTRIBUTE_FROM || attribute == TRI_VOC_ATTRIBUTE_TO)) { return true; } } auto shaper = _document->getShaper(); TRI_shape_pid_t pid = shaper->lookupAttributePathByName(attribute.c_str()); if (pid != 0) { return true; } return false; } return (TRI_LookupObjectJson(_current, attribute.c_str()) != nullptr); }
void DocumentAccessor::lookupJsonAttribute (char const* name, size_t nameLength) { TRI_ASSERT(_current != nullptr); if (! isObject()) { setToNull(); return; } TRI_json_t const* value = TRI_LookupObjectJson(_current, name); if (value == nullptr) { // attribute not found setToNull(); } else { // found _current = value; } }
uint64_t TRI_HashJsonByAttributes (TRI_json_t const* json, char const *attributes[], int nrAttributes, bool docComplete, int* error) { if (error != nullptr) { *error = TRI_ERROR_NO_ERROR; } uint64_t hash = TRI_FnvHashBlockInitial(); if (TRI_IsObjectJson(json)) { for (int i = 0; i < nrAttributes; i++) { TRI_json_t const* subjson = TRI_LookupObjectJson(json, attributes[i]); if (subjson == nullptr && ! docComplete && error != nullptr) { *error = TRI_ERROR_CLUSTER_NOT_ALL_SHARDING_ATTRIBUTES_GIVEN; } hash = HashJsonRecursive(hash, subjson); } } return hash; }
KeyGenerator::GeneratorType KeyGenerator::generatorType (TRI_json_t const* parameters) { if (! TRI_IsObjectJson(parameters)) { return KeyGenerator::TYPE_TRADITIONAL; } TRI_json_t const* type = TRI_LookupObjectJson(parameters, "type"); if (! TRI_IsStringJson(type)) { return KeyGenerator::TYPE_TRADITIONAL; } char const* typeName = type->_value._string.data; if (TRI_CaseEqualString(typeName, TraditionalKeyGenerator::name().c_str())) { return KeyGenerator::TYPE_TRADITIONAL; } if (TRI_CaseEqualString(typeName, AutoIncrementKeyGenerator::name().c_str())) { return KeyGenerator::TYPE_AUTOINCREMENT; } // error return KeyGenerator::TYPE_UNKNOWN; }
static TRI_json_t* MergeRecursive (TRI_memory_zone_t* zone, TRI_json_t const* lhs, TRI_json_t const* rhs, bool nullMeansRemove, bool mergeObjects) { TRI_ASSERT(lhs != nullptr); std::unique_ptr<TRI_json_t> result(TRI_CopyJson(zone, lhs)); if (result == nullptr) { return nullptr; } auto r = result.get(); // shortcut variable size_t const n = TRI_LengthVector(&rhs->_value._objects); for (size_t i = 0; i < n; i += 2) { // enumerate all the replacement values auto key = static_cast<TRI_json_t const*>(TRI_AtVector(&rhs->_value._objects, i)); auto value = static_cast<TRI_json_t const*>(TRI_AtVector(&rhs->_value._objects, i + 1)); if (value->_type == TRI_JSON_NULL && nullMeansRemove) { // replacement value is a null and we don't want to store nulls => delete attribute from the result TRI_DeleteObjectJson(zone, r, key->_value._string.data); } else { // replacement value is not a null or we want to store nulls TRI_json_t const* lhsValue = TRI_LookupObjectJson(lhs, key->_value._string.data); if (lhsValue == nullptr) { // existing array does not have the attribute => append new attribute if (value->_type == TRI_JSON_OBJECT && nullMeansRemove) { TRI_json_t empty; TRI_InitObjectJson(TRI_UNKNOWN_MEM_ZONE, &empty); TRI_json_t* merged = MergeRecursive(zone, &empty, value, nullMeansRemove, mergeObjects); if (merged == nullptr) { return nullptr; } TRI_json_t* copy = TRI_CopyJson(zone, value); if (copy == nullptr) { return nullptr; } TRI_Insert3ObjectJson(zone, r, key->_value._string.data, copy); } else { TRI_Insert3ObjectJson(zone, r, key->_value._string.data, TRI_CopyJson(zone, value)); } } else { // existing array already has the attribute => replace attribute if (lhsValue->_type == TRI_JSON_OBJECT && value->_type == TRI_JSON_OBJECT && mergeObjects) { TRI_json_t* merged = MergeRecursive(zone, lhsValue, value, nullMeansRemove, mergeObjects); if (merged == nullptr) { return nullptr; } TRI_ReplaceObjectJson(zone, r, key->_value._string.data, merged); TRI_FreeJson(zone, merged); } else { TRI_ReplaceObjectJson(zone, r, key->_value._string.data, value); } } } } return result.release(); }
int TRI_CompareValuesJson (TRI_json_t const* lhs, TRI_json_t const* rhs, bool useUTF8) { // note: both lhs and rhs may be NULL! { int lWeight = TypeWeight(lhs); int rWeight = TypeWeight(rhs); if (lWeight < rWeight) { return -1; } if (lWeight > rWeight) { return 1; } TRI_ASSERT_EXPENSIVE(lWeight == rWeight); } // lhs and rhs have equal weights if (lhs == nullptr || rhs == nullptr) { // either lhs or rhs is a nullptr. we cannot be sure here that both are nullptrs. // there can also exist the situation that lhs is a nullptr and rhs is a JSON null value // (or vice versa). Anyway, the compare value is the same for both, return 0; } switch (lhs->_type) { case TRI_JSON_UNUSED: case TRI_JSON_NULL: { return 0; // null == null; } case TRI_JSON_BOOLEAN: { if (lhs->_value._boolean == rhs->_value._boolean) { return 0; } if (! lhs->_value._boolean && rhs->_value._boolean) { return -1; } return 1; } case TRI_JSON_NUMBER: { if (lhs->_value._number == rhs->_value._number) { return 0; } if (lhs->_value._number < rhs->_value._number) { return -1; } return 1; } case TRI_JSON_STRING: case TRI_JSON_STRING_REFERENCE: { // same for STRING and STRING_REFERENCE TRI_ASSERT(lhs->_value._string.data != nullptr); TRI_ASSERT(rhs->_value._string.data != nullptr); int res; size_t const nl = lhs->_value._string.length - 1; size_t const nr = rhs->_value._string.length - 1; if (useUTF8) { res = TRI_compare_utf8(lhs->_value._string.data, nl, rhs->_value._string.data, nr); } else { // beware of strings containing NUL bytes size_t len = nl < nr ? nl : nr; res = memcmp(lhs->_value._string.data, rhs->_value._string.data, len); } if (res < 0) { return -1; } else if (res > 0) { return 1; } // res == 0 if (nl == nr) { return 0; } // res == 0, but different string lengths return nl < nr ? -1 : 1; } case TRI_JSON_ARRAY: { size_t const nl = TRI_LengthVector(&lhs->_value._objects); size_t const nr = TRI_LengthVector(&rhs->_value._objects); size_t n; if (nl > nr) { n = nl; } else { n = nr; } 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); if (result != 0) { return result; } } return 0; } case TRI_JSON_OBJECT: { TRI_ASSERT(lhs->_type == TRI_JSON_OBJECT); TRI_ASSERT(rhs->_type == TRI_JSON_OBJECT); std::unique_ptr<TRI_json_t> keys(GetMergedKeyArray(lhs, rhs)); if (keys != nullptr) { auto json = keys.get(); size_t const n = TRI_LengthVector(&json->_value._objects); for (size_t i = 0; i < n; ++i) { auto keyElement = static_cast<TRI_json_t const*>(TRI_AtVector(&json->_value._objects, i)); TRI_ASSERT(TRI_IsStringJson(keyElement)); 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 int result = TRI_CompareValuesJson(lhsValue, rhsValue, useUTF8); if (result != 0) { return result; } } } // fall-through to returning 0 } } return 0; }
KeyGenerator* KeyGenerator::factory (TRI_json_t const* options) { KeyGenerator::GeneratorType type; bool const readOptions = TRI_IsObjectJson(options); if (readOptions) { type = generatorType(options); } else { type = TYPE_TRADITIONAL; } if (type == TYPE_UNKNOWN) { return nullptr; } bool allowUserKeys = true; if (readOptions) { TRI_json_t* option = TRI_LookupObjectJson(options, "allowUserKeys"); if (TRI_IsBooleanJson(option)) { allowUserKeys = option->_value._boolean; } } if (type == TYPE_TRADITIONAL) { return new TraditionalKeyGenerator(allowUserKeys); } else if (type == TYPE_AUTOINCREMENT) { uint64_t offset = 0; uint64_t increment = 1; if (readOptions) { TRI_json_t* option; option = TRI_LookupObjectJson(options, "increment"); if (TRI_IsNumberJson(option)) { if (option->_value._number <= 0.0) { // negative or 0 offset is not allowed return nullptr; } increment = static_cast<uint64_t>(option->_value._number); if (increment == 0 || increment >= (1ULL << 16)) { return nullptr; } } option = TRI_LookupObjectJson(options, "offset"); if (TRI_IsNumberJson(option)) { if (option->_value._number < 0.0) { return nullptr; } offset = static_cast<uint64_t>(option->_value._number); if (offset >= UINT64_MAX) { return nullptr; } } } return new AutoIncrementKeyGenerator(allowUserKeys, offset, increment); } return nullptr; }