Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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);
        }
      }
    }
  }
}