bool TRI_ExcludeCollectionReplication (const char* name) { if (name == nullptr) { // name invalid return true; } if (*name != '_') { // all regular collections are included return false; } if (TRI_EqualString(name, TRI_COL_NAME_REPLICATION) || TRI_EqualString(name, TRI_COL_NAME_TRANSACTION) || TRI_EqualString(name, TRI_COL_NAME_USERS) || TRI_IsPrefixString(name, TRI_COL_NAME_STATISTICS) || TRI_EqualString(name, "_aal") || TRI_EqualString(name, "_configuration") || TRI_EqualString(name, "_cluster_kickstarter_plans") || TRI_EqualString(name, "_fishbowl") || TRI_EqualString(name, "_modules") || TRI_EqualString(name, "_routing")) { // these system collections will be excluded return true; } return false; }
TRI_json_t* TRI_LookupArrayJson (const TRI_json_t* const object, char const* name) { size_t i, n; if (object == NULL) { return NULL; } TRI_ASSERT(object->_type == TRI_JSON_ARRAY); TRI_ASSERT(name != NULL); n = object->_value._objects._length; for (i = 0; i < n; i += 2) { TRI_json_t* key; key = (TRI_json_t*) TRI_AtVector(&object->_value._objects, i); if (! IsString(key)) { continue; } if (TRI_EqualString(key->_value._string.data, name)) { return (TRI_json_t*) TRI_AtVector(&object->_value._objects, i + 1); } } return NULL; }
static bool EqualName (TRI_associative_pointer_t* array, void const* key, void const* element) { TRI_aql_function_t* function = (TRI_aql_function_t*) element; return TRI_EqualString(key, function->_externalName); }
bool TRI_EqualVariableAql (TRI_associative_pointer_t* array, void const* key, void const* element) { TRI_aql_variable_t* variable = (TRI_aql_variable_t*) element; return TRI_EqualString(key, variable->_name); }
bool TRI_EqualBindParameterAql (TRI_associative_pointer_t* array, void const* key, void const* element) { TRI_aql_bind_parameter_t* parameter = (TRI_aql_bind_parameter_t*) element; return TRI_EqualString(key, parameter->_name); }
TRI_json_t* TRI_LookupArrayJson (TRI_json_t* object, char const* name) { size_t n; size_t i; assert(object->_type == TRI_JSON_ARRAY); assert(name); n = object->_value._objects._length; for (i = 0; i < n; i += 2) { TRI_json_t* key; key = TRI_AtVector(&object->_value._objects, i); if (key->_type != TRI_JSON_STRING) { continue; } if (TRI_EqualString(key->_value._string.data, name)) { return TRI_AtVector(&object->_value._objects, i + 1); } } return NULL; }
bool TRI_ExcludeCollectionReplication(char const* name, bool includeSystem) { if (name == nullptr) { // name invalid return true; } if (*name != '_') { // all regular collections are included return false; } if (!includeSystem) { // do not include any system collections return true; } if (TRI_IsPrefixString(name, "_statistics") || TRI_EqualString(name, "_apps") || TRI_EqualString(name, "_configuration") || TRI_EqualString(name, "_cluster_kickstarter_plans") || TRI_EqualString(name, "_foxxlog") || TRI_EqualString(name, "_jobs") || TRI_EqualString(name, "_queues") || TRI_EqualString(name, "_sessions")) { // these system collections will always be excluded return true; } return false; }
static bool EqualNameKeyAttributePath (TRI_associative_synced_t* array, void const* key, void const* element) { char const* k; char const* e; TRI_shape_path_t const* ee; k = (char const*) key; e = (char const*) element; ee = (TRI_shape_path_t const*) element; return TRI_EqualString(k,e + sizeof(TRI_shape_path_t) + ee->_aidLength * sizeof(TRI_shape_aid_t)); }
TRI_aql_collection_t* TRI_GetCollectionAql (const TRI_aql_context_t* const context, const char* const collectionName) { size_t i, n; assert(context); n = context->_collections._length; for (i = 0; i < n; ++i) { TRI_aql_collection_t* col = (TRI_aql_collection_t*) TRI_AtVectorPointer(&context->_collections, i); if (TRI_EqualString(col->_name, collectionName)) { return col; } } return NULL; }
bool TRI_DeleteArrayJson (TRI_memory_zone_t* zone, TRI_json_t* object, char const* name) { size_t n; size_t i; TRI_ASSERT(object->_type == TRI_JSON_ARRAY); TRI_ASSERT(name); n = object->_value._objects._length; for (i = 0; i < n; i += 2) { TRI_json_t* key; key = (TRI_json_t*) TRI_AtVector(&object->_value._objects, i); if (! IsString(key)) { continue; } if (TRI_EqualString(key->_value._string.data, name)) { TRI_json_t* old; // remove key old = (TRI_json_t*) TRI_AtVector(&object->_value._objects, i); if (old != NULL) { TRI_DestroyJson(zone, old); } TRI_RemoveVector(&object->_value._objects, i); // remove value old = (TRI_json_t*) TRI_AtVector(&object->_value._objects, i); if (old != NULL) { TRI_DestroyJson(zone, old); } TRI_RemoveVector(&object->_value._objects, i); return true; } } return false; }
bool TRI_ReplaceArrayJson (TRI_memory_zone_t* zone, TRI_json_t* object, char const* name, TRI_json_t* replacement) { size_t n; size_t i; TRI_ASSERT(object->_type == TRI_JSON_ARRAY); TRI_ASSERT(name); n = object->_value._objects._length; for (i = 0; i < n; i += 2) { TRI_json_t* key; key = (TRI_json_t*) TRI_AtVector(&object->_value._objects, i); if (! IsString(key)) { continue; } if (TRI_EqualString(key->_value._string.data, name)) { TRI_json_t copy; // retrieve the old element TRI_json_t* old = (TRI_json_t*) TRI_AtVector(&object->_value._objects, i + 1); if (old != NULL) { TRI_DestroyJson(zone, old); } TRI_CopyToJson(zone, ©, replacement); TRI_SetVector(&object->_value._objects, i + 1, ©); return true; } } // object not found in array, now simply add it TRI_Insert2ArrayJson(zone, object, name, replacement); return false; }
bool TRI_DeleteObjectJson (TRI_memory_zone_t* zone, TRI_json_t* object, char const* name) { TRI_ASSERT(object->_type == TRI_JSON_OBJECT); TRI_ASSERT(name != nullptr); size_t const n = TRI_LengthVector(&object->_value._objects); for (size_t i = 0; i < n; i += 2) { TRI_json_t* key = static_cast<TRI_json_t*>(TRI_AtVector(&object->_value._objects, i)); if (! IsString(key)) { continue; } if (TRI_EqualString(key->_value._string.data, name)) { // remove key TRI_json_t* old = static_cast<TRI_json_t*>(TRI_AtVector(&object->_value._objects, i)); if (old != nullptr) { TRI_DestroyJson(zone, old); } TRI_RemoveVector(&object->_value._objects, i); // remove value old = static_cast<TRI_json_t*>(TRI_AtVector(&object->_value._objects, i)); if (old != nullptr) { TRI_DestroyJson(zone, old); } TRI_RemoveVector(&object->_value._objects, i); return true; } } return false; }
bool TRI_BooleanString (char const* str) { if (TRI_CaseEqualString(str, "true")) { return true; } if (TRI_CaseEqualString(str, "yes")) { return true; } if (TRI_CaseEqualString(str, "on")) { return true; } if (TRI_CaseEqualString(str, "y")) { return true; } if (TRI_EqualString(str, "1")) { return true; } return false; }
bool TRI_ReplaceObjectJson (TRI_memory_zone_t* zone, TRI_json_t* object, char const* name, TRI_json_t const* replacement) { TRI_ASSERT(object->_type == TRI_JSON_OBJECT); TRI_ASSERT(name != nullptr); size_t const n = TRI_LengthVector(&object->_value._objects); for (size_t i = 0; i < n; i += 2) { TRI_json_t* key = static_cast<TRI_json_t*>(TRI_AtVector(&object->_value._objects, i)); if (! IsString(key)) { continue; } if (TRI_EqualString(key->_value._string.data, name)) { // retrieve the old element TRI_json_t* old = static_cast<TRI_json_t*>(TRI_AtVector(&object->_value._objects, i + 1)); if (old != nullptr) { TRI_DestroyJson(zone, old); } TRI_json_t copy; TRI_CopyToJson(zone, ©, replacement); TRI_SetVector(&object->_value._objects, i + 1, ©); return true; } } // object not found in array, now simply add it TRI_Insert2ObjectJson(zone, object, name, replacement); return false; }
std::string arangodb::options::EnvironmentTranslator(std::string const& value) { if (value.empty()) { return value; } char const* p = value.c_str(); char const* e = p + value.size(); std::string result; for (char const* q = p; q < e; q++) { if (*q == '@') { q++; if (*q == '@') { result.push_back('@'); } else { char const* t = q; for (; q < e && *q != '@'; q++) ; if (q < e) { std::string k = std::string(t, q); char* v = getenv(k.c_str()); std::string vv; if (v != nullptr && *v == '\0') { v = nullptr; } if (v == nullptr) { #if _WIN32 if (TRI_EqualString(k.c_str(), "ROOTDIR")) { vv = TRI_LocateInstallDirectory(); if (! vv.empty()) { char c = *(vv.rbegin()); if (c == TRI_DIR_SEPARATOR_CHAR || c == '/') { vv.pop_back(); } } } #endif } else { vv = v; } result += vv; } else { result += std::string(t - 1); } } } else { result.push_back(*q); } } return result; }
int TRI_LoadCollectionInfo (char const* path, TRI_col_info_t* parameter) { TRI_json_t* json; char* filename; char* error = NULL; size_t i; size_t n; memset(parameter, 0, sizeof(TRI_col_info_t)); // find parameter file filename = TRI_Concatenate2File(path, TRI_COL_PARAMETER_FILE); if (filename == NULL) { LOG_ERROR("cannot load parameter info for collection '%s', out of memory", path); return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); } if (! TRI_ExistsFile(filename)) { TRI_FreeString(TRI_CORE_MEM_ZONE, filename); return TRI_set_errno(TRI_ERROR_ARANGO_ILLEGAL_PARAMETER_FILE); } json = TRI_JsonFile(TRI_UNKNOWN_MEM_ZONE, filename, &error); if (json == NULL) { if (error != NULL) { LOG_ERROR("cannot open '%s', parameter block not readable: %s", filename, error); TRI_FreeString(TRI_CORE_MEM_ZONE, error); } else { LOG_ERROR("cannot open '%s', parameter block not readable", filename); } TRI_FreeString(TRI_CORE_MEM_ZONE, filename); return TRI_set_errno(TRI_ERROR_ARANGO_ILLEGAL_PARAMETER_FILE); } if (json->_type != TRI_JSON_ARRAY) { LOG_ERROR("cannot open '%s', file does not contain a json array", filename); TRI_FreeString(TRI_CORE_MEM_ZONE, filename); return TRI_set_errno(TRI_ERROR_ARANGO_ILLEGAL_PARAMETER_FILE); } TRI_FreeString(TRI_CORE_MEM_ZONE, filename); // convert json n = json->_value._objects._length; for (i = 0; i < n; i += 2) { TRI_json_t* key; TRI_json_t* value; key = TRI_AtVector(&json->_value._objects, i); value = TRI_AtVector(&json->_value._objects, i + 1); if (key->_type == TRI_JSON_STRING && value->_type == TRI_JSON_NUMBER) { if (TRI_EqualString(key->_value._string.data, "version")) { parameter->_version = value->_value._number; } else if (TRI_EqualString(key->_value._string.data, "type")) { parameter->_type = value->_value._number; } else if (TRI_EqualString(key->_value._string.data, "cid")) { parameter->_cid = value->_value._number; } else if (TRI_EqualString(key->_value._string.data, "maximalSize")) { parameter->_maximalSize = value->_value._number; } } else if (key->_type == TRI_JSON_STRING && value->_type == TRI_JSON_STRING) { if (TRI_EqualString(key->_value._string.data, "name")) { TRI_CopyString(parameter->_name, value->_value._string.data, sizeof(parameter->_name)); parameter->_isSystem = TRI_IsSystemCollectionName(parameter->_name); } } else if (key->_type == TRI_JSON_STRING && value->_type == TRI_JSON_BOOLEAN) { if (TRI_EqualString(key->_value._string.data, "deleted")) { parameter->_deleted = value->_value._boolean; } else if (TRI_EqualString(key->_value._string.data, "isVolatile")) { parameter->_isVolatile = value->_value._boolean; } else if (TRI_EqualString(key->_value._string.data, "waitForSync")) { parameter->_waitForSync = value->_value._boolean; } } else if (key->_type == TRI_JSON_STRING && value->_type == TRI_JSON_ARRAY) { if (TRI_EqualString(key->_value._string.data, "keyOptions")) { parameter->_keyOptions = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, value); } } } TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); return TRI_ERROR_NO_ERROR; }
TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context, const TRI_vector_pointer_t* const availableIndexes, const char* const collectionName, const TRI_vector_pointer_t* candidates) { TRI_aql_index_t* picked = NULL; TRI_vector_pointer_t matches; size_t i, n; TRI_InitVectorPointer(&matches, TRI_UNKNOWN_MEM_ZONE); assert(context); assert(collectionName); assert(candidates); n = availableIndexes->_length; for (i = 0; i < n; ++i) { TRI_index_t* idx = (TRI_index_t*) availableIndexes->_buffer[i]; size_t numIndexFields; bool lastTypeWasExact; size_t j; if (! CanUseIndex(idx)) { continue; } LogIndexString("checking", idx, collectionName); TRI_ClearVectorPointer(&matches); lastTypeWasExact = true; numIndexFields = idx->_fields._length; // now loop over all index fields, from left to right // index field order is important because skiplists can be used with leftmost prefixes as well, // but not with rightmost prefixes for (j = 0; j < numIndexFields; ++j) { char* indexedFieldName; char* fieldName; size_t k; indexedFieldName = idx->_fields._buffer[j]; if (indexedFieldName == NULL) { continue; } // now loop over all candidates for (k = 0; k < candidates->_length; ++k) { TRI_aql_field_access_t* candidate = (TRI_aql_field_access_t*) TRI_AtVectorPointer(candidates, k); if (candidate->_type == TRI_AQL_ACCESS_IMPOSSIBLE || candidate->_type == TRI_AQL_ACCESS_ALL) { // wrong index type, doesn't help us at all continue; } fieldName = candidate->_fullName + candidate->_variableNameLength + 1; if (idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX) { // primary index key names must be treated differently. _id and _key are the same if (! TRI_EqualString("_id", fieldName) && ! TRI_EqualString(TRI_VOC_ATTRIBUTE_KEY, fieldName)) { continue; } } else if (idx->_type == TRI_IDX_TYPE_EDGE_INDEX) { // edge index key names must be treated differently. _from and _to can be used independently if (! TRI_EqualString(TRI_VOC_ATTRIBUTE_FROM, fieldName) && ! TRI_EqualString(TRI_VOC_ATTRIBUTE_TO, fieldName)) { continue; } } else if (! TRI_EqualString(indexedFieldName, fieldName)) { // different attribute, doesn't help continue; } // attribute is used in index if (idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX || idx->_type == TRI_IDX_TYPE_EDGE_INDEX) { if (! IsExactCandidate(candidate)) { // wrong access type for primary index continue; } TRI_PushBackVectorPointer(&matches, candidate); } else if (idx->_type == TRI_IDX_TYPE_HASH_INDEX) { if (! IsExactCandidate(candidate)) { // wrong access type for hash index continue; } if (candidate->_type == TRI_AQL_ACCESS_LIST && numIndexFields != 1) { // we found a list, but the index covers multiple attributes. that means we cannot use list access continue; } TRI_PushBackVectorPointer(&matches, candidate); } else if (idx->_type == TRI_IDX_TYPE_BITARRAY_INDEX) { if (! IsExactCandidate(candidate)) { // wrong access type for hash index continue; } if (candidate->_type == TRI_AQL_ACCESS_LIST) { // we found a list, but the index covers multiple attributes. that means we cannot use list access continue; } TRI_PushBackVectorPointer(&matches, candidate); } else if (idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) { bool candidateIsExact; if (candidate->_type != TRI_AQL_ACCESS_EXACT && candidate->_type != TRI_AQL_ACCESS_LIST && candidate->_type != TRI_AQL_ACCESS_RANGE_SINGLE && candidate->_type != TRI_AQL_ACCESS_RANGE_DOUBLE && candidate->_type != TRI_AQL_ACCESS_REFERENCE) { // wrong access type for skiplists continue; } if (candidate->_type == TRI_AQL_ACCESS_LIST && numIndexFields != 1) { // we found a list, but the index covers multiple attributes. that means we cannot use list access continue; } candidateIsExact = IsExactCandidate(candidate); if ((candidateIsExact && ! lastTypeWasExact) || (! candidateIsExact && ! lastTypeWasExact)) { // if we already had a range query, we cannot check for equality after that // if we already had a range query, we cannot check another range after that continue; } if (candidate->_type == TRI_AQL_ACCESS_RANGE_SINGLE) { // range type. check if the compare value is a list or an object TRI_json_t* value = candidate->_value._singleRange._value; if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { // list or object, we cannot use this for comparison in a skiplist continue; } } else if (candidate->_type == TRI_AQL_ACCESS_RANGE_DOUBLE) { // range type. check if the compare value is a list or an object TRI_json_t* value = candidate->_value._between._lower._value; if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { // list or object, we cannot use this for comparison in a skiplist continue; } value = candidate->_value._between._upper._value; if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { // list or object, we cannot use this for comparison in a skiplist continue; } } lastTypeWasExact = candidateIsExact; TRI_PushBackVectorPointer(&matches, candidate); } } // finished iterating over all candidates if (matches._length != j + 1) { // we already have picked less candidate fields than we should break; } } if (matches._length < 1) { // nothing found continue; } // we now do or don't have an index candidate in the matches vector if (matches._length < numIndexFields && TRI_NeedsFullCoverageIndex(idx->_type)) { // the matches vector does not fully cover the indexed fields, but the index requires it continue; } // if we can use the primary index, we'll use it picked = PickIndex(context, picked, idx, &matches); } TRI_DestroyVectorPointer(&matches); if (picked) { LogIndexString("using", picked->_idx, collectionName); } return picked; }
bool IsEqualElementElement (TRI_associative_pointer_t* a, void const* l, void const* r) { data_container_s* left = (data_container_s*) l; data_container_s* right = (data_container_s*) r; return TRI_EqualString(left->key, right->key); }
static bool EqualKeyCollectionName (TRI_associative_pointer_t* array, void const* key, void const* element) { char const* k = (char const*) key; TRI_vocbase_col_t const* e = element; return TRI_EqualString(k, e->_name); }
bool TRI_CheckAuthenticationAuthInfo (char const* username, char const* password) { TRI_vocbase_auth_t* auth; bool res; char* hex; char* sha256; size_t hexLen; size_t len; size_t sha256Len; assert(DefaultAuthInfo); // look up username TRI_ReadLockReadWriteLock(&DefaultAuthInfo->_authInfoLock); auth = TRI_LookupByKeyAssociativePointer(&DefaultAuthInfo->_authInfo, username); if (auth == NULL || ! auth->_active) { TRI_ReadUnlockReadWriteLock(&DefaultAuthInfo->_authInfoLock); return false; } // convert password res = false; if (TRI_IsPrefixString(auth->_password, "$1$")) { if (strlen(auth->_password) < 12 || auth->_password[11] != '$') { LOG_WARNING("found corrupted password for user '%s'", username); } else { char* salted; len = 8 + strlen(password); salted = TRI_Allocate(TRI_CORE_MEM_ZONE, len + 1, false); memcpy(salted, auth->_password + 3, 8); memcpy(salted + 8, password, len - 8); salted[len] = '\0'; sha256 = TRI_SHA256String(salted, len, &sha256Len); TRI_FreeString(TRI_CORE_MEM_ZONE, salted); hex = TRI_EncodeHexString(sha256, sha256Len, &hexLen); TRI_FreeString(TRI_CORE_MEM_ZONE, sha256); LOG_DEBUG("found active user '%s', expecting password '%s', got '%s'", username, auth->_password + 12, hex); res = TRI_EqualString(auth->_password + 12, hex); TRI_FreeString(TRI_CORE_MEM_ZONE, hex); } } else { len = strlen(password); sha256 = TRI_SHA256String(password, len, &sha256Len); hex = TRI_EncodeHexString(sha256, sha256Len, &hexLen); TRI_FreeString(TRI_CORE_MEM_ZONE, sha256); LOG_DEBUG("found active user '%s', expecting password '%s', got '%s'", username, auth->_password + 12, hex); res = TRI_EqualString(auth->_password, hex); TRI_FreeString(TRI_CORE_MEM_ZONE, hex); } TRI_ReadUnlockReadWriteLock(&DefaultAuthInfo->_authInfoLock); return res; }
bool TRI_EqualStringKeyAssociativePointer (TRI_associative_pointer_t* array, void const* key, void const* element) { return TRI_EqualString((char*) key, (char*) element); }
static void OptimisePaths (const TRI_aql_node_t* const fcallNode, TRI_aql_context_t* const context, TRI_aql_field_access_t* fieldAccess) { TRI_aql_node_t* args; TRI_aql_node_t* vertexCollection; TRI_aql_node_t* edgeCollection; TRI_aql_node_t* direction; char* directionValue; char* name; size_t n; args = TRI_AQL_NODE_MEMBER(fcallNode, 0); if (args == NULL) { return; } vertexCollection = TRI_AQL_NODE_MEMBER(args, 0); edgeCollection = TRI_AQL_NODE_MEMBER(args, 1); direction = TRI_AQL_NODE_MEMBER(args, 2); assert(vertexCollection); assert(edgeCollection); assert(direction); assert(fieldAccess); n = strlen(fieldAccess->_fullName); name = fieldAccess->_fullName + fieldAccess->_variableNameLength; directionValue = TRI_AQL_NODE_STRING(direction); // try to optimise the vertex collection access if (TRI_EqualString(directionValue, "outbound")) { CheckPathRestriction(fieldAccess, context, vertexCollection, ".source.", name, n); } else if (TRI_EqualString(directionValue, "inbound")) { CheckPathRestriction(fieldAccess, context, vertexCollection, ".source.", name, n); } else if (TRI_EqualString(directionValue, "any")) { // "any" cannot be optimised sanely becuase the conditions would be AND-combined // (but for "any", we'd need them OR-combined) // CheckPathRestriction(fieldAccess, context, vertexCollection, ".source.", name, n); // CheckPathRestriction(fieldAccess, context, vertexCollection, ".destination.", name, n); } // check if we have a filter on LENGTH(edges) if (args->_members._length <= 4 && TRI_EqualString(name, ".edges.LENGTH()")) { // length restriction, can only be applied if length parameters are not already set TRI_json_t* value; double minValue = 0.0; double maxValue = 0.0; bool useMin = false; bool useMax = false; if (fieldAccess->_type == TRI_AQL_ACCESS_EXACT) { value = fieldAccess->_value._value; if (value != NULL && value->_type == TRI_JSON_NUMBER) { // LENGTH(p.edges) == const minValue = maxValue = value->_value._number; useMin = useMax = true; } } else if (fieldAccess->_type == TRI_AQL_ACCESS_RANGE_SINGLE) { value = fieldAccess->_value._singleRange._value; if (value != NULL && value->_type == TRI_JSON_NUMBER) { // LENGTH(p.edges) operator const if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_LOWER_INCLUDED) { minValue = value->_value._number; useMin = true; } else if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_UPPER_INCLUDED) { maxValue = value->_value._number; useMax = true; } else if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_LOWER_EXCLUDED) { if ((double) ((int) value->_value._number) == value->_value._number) { minValue = value->_value._number + 1.0; useMin = true; } } else if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_UPPER_EXCLUDED) { if ((double) ((int) value->_value._number) == value->_value._number) { maxValue = value->_value._number - 1.0; useMax = true; } } } } else if (fieldAccess->_type == TRI_AQL_ACCESS_RANGE_DOUBLE) { // LENGTH(p.edges) > const && LENGTH(p.edges) < const value = fieldAccess->_value._between._lower._value; if (value != NULL && value->_type == TRI_JSON_NUMBER) { if (fieldAccess->_value._between._lower._type == TRI_AQL_RANGE_LOWER_INCLUDED) { minValue = value->_value._number; useMin = true; } else if (fieldAccess->_value._between._lower._type == TRI_AQL_RANGE_LOWER_EXCLUDED) { if ((double) ((int) value->_value._number) == value->_value._number) { minValue = value->_value._number + 1.0; useMin = true; } } } value = fieldAccess->_value._between._upper._value; if (value != NULL && value->_type == TRI_JSON_NUMBER) { if (fieldAccess->_value._between._upper._type == TRI_AQL_RANGE_UPPER_INCLUDED) { maxValue = value->_value._number; useMax = true; } else if (fieldAccess->_value._between._upper._type == TRI_AQL_RANGE_UPPER_EXCLUDED) { if ((double) ((int) value->_value._number) == value->_value._number) { maxValue = value->_value._number - 1.0; useMax = true; } } } } if (useMin || useMax) { TRI_aql_node_t* argNode; // minLength and maxLength are parameters 5 & 6 // add as many null value nodes as are missing while (args->_members._length < 4) { argNode = TRI_CreateNodeValueNullAql(context); if (argNode) { TRI_PushBackVectorPointer(&args->_members, (void*) argNode); } } // add min and max values to the function call argument list argNode = TRI_CreateNodeValueIntAql(context, useMin ? (int64_t) minValue : (int64_t) 0); if (argNode) { // min value node TRI_PushBackVectorPointer(&args->_members, (void*) argNode); argNode = TRI_CreateNodeValueIntAql(context, useMax ? (int64_t) maxValue : (int64_t) (1024 * 1024)); if (argNode) { // max value node TRI_PushBackVectorPointer(&args->_members, (void*) argNode); } } } } }
static void OptimisePaths (const TRI_aql_node_t* const fcallNode, TRI_aql_context_t* const context, TRI_aql_field_access_t* fieldAccess) { TRI_aql_collection_hint_t* hint; TRI_aql_node_t* args; TRI_aql_node_t* vertexCollection; TRI_aql_node_t* edgeCollection; TRI_aql_node_t* direction; char* directionValue; char* name; const char* lookFor; size_t len; size_t n; args = TRI_AQL_NODE_MEMBER(fcallNode, 0); if (args == NULL) { return; } vertexCollection = TRI_AQL_NODE_MEMBER(args, 0); edgeCollection = TRI_AQL_NODE_MEMBER(args, 1); direction = TRI_AQL_NODE_MEMBER(args, 2); assert(vertexCollection); assert(edgeCollection); assert(direction); assert(fieldAccess); n = strlen(fieldAccess->_fullName); name = fieldAccess->_fullName + fieldAccess->_variableNameLength; directionValue = TRI_AQL_NODE_STRING(direction); // try to optimise the vertex collection access if (TRI_EqualString(directionValue, "outbound")) { lookFor = ".source."; len = strlen(lookFor); } else if (TRI_EqualString(directionValue, "inbound")) { lookFor = ".destination."; len = strlen(lookFor); } else { lookFor = NULL; len = 0; } if (len > 0 && n > fieldAccess->_variableNameLength + len && memcmp((void*) lookFor, (void*) name, len) == 0) { // field name is collection.source.XXX, e.g. users.source._id LOG_DEBUG("optimising PATHS() field access %s", fieldAccess->_fullName); // we can now modify this fieldaccess in place to collection.XXX, e.g. users._id // copy trailing \0 byte as well memmove(name, name + len - 1, n - fieldAccess->_variableNameLength - len + 2); // attach the modified fieldaccess to the collection hint = (TRI_aql_collection_hint_t*) (TRI_AQL_NODE_DATA(vertexCollection)); hint->_ranges = TRI_AddAccessAql(context, hint->_ranges, fieldAccess); } }
bool IsEqualKeyElement (TRI_associative_pointer_t* a, void const* k, void const* r) { data_container_s* element = (data_container_s*) r; return TRI_EqualString((char*) k, element->key); }