TRI_aql_node_t* TRI_JsonNodeAql (TRI_aql_context_t* const context, const TRI_json_t* const json) { TRI_aql_node_t* node = NULL; char* value; switch (json->_type) { case TRI_JSON_UNUSED: break; case TRI_JSON_NULL: node = TRI_CreateNodeValueNullAql(context); break; case TRI_JSON_BOOLEAN: node = TRI_CreateNodeValueBoolAql(context, json->_value._boolean); break; case TRI_JSON_NUMBER: node = TRI_CreateNodeValueDoubleAql(context, json->_value._number); break; case TRI_JSON_STRING: value = TRI_RegisterStringAql(context, json->_value._string.data, strlen(json->_value._string.data), true); node = TRI_CreateNodeValueStringAql(context, value); break; case TRI_JSON_LIST: { size_t i; size_t n; node = TRI_CreateNodeListAql(context); n = json->_value._objects._length; for (i = 0; i < n; ++i) { TRI_json_t* subJson; TRI_aql_node_t* member; subJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i); assert(subJson); member = TRI_JsonNodeAql(context, subJson); if (member) { TRI_PushBackVectorPointer(&node->_members, (void*) member); } else { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return NULL; } } break; } case TRI_JSON_ARRAY: { size_t i; size_t n; node = TRI_CreateNodeArrayAql(context); n = json->_value._objects._length; for (i = 0; i < n; i += 2) { TRI_json_t* nameJson; TRI_json_t* valueJson; TRI_aql_node_t* member; TRI_aql_node_t* valueNode; char* name; // json_t containing the array element name nameJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i); assert(nameJson); assert(nameJson->_value._string.data); name = TRI_RegisterStringAql(context, nameJson->_value._string.data, strlen(nameJson->_value._string.data), false); if (! name) { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return NULL; } // json_t containing the array element value valueJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i + 1); assert(valueJson); valueNode = TRI_JsonNodeAql(context, valueJson); if (! valueNode) { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return NULL; } member = TRI_CreateNodeArrayElementAql(context, name, valueNode); if (member) { TRI_PushBackVectorPointer(&node->_members, (void*) member); } else { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return NULL; } } break; } } if (! node) { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); } return node; }
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); } } } } }