Beispiel #1
0
        /// <summary>
        /// Creates all of the spatial functions
        /// </summary>
        /// <param name="functions">Dictionary of functions to add to.</param>
        internal static void CreateSpatialFunctions(IDictionary <string, FunctionSignatureWithReturnType[]> functions)
        {
            // double geo.distance(geographyPoint, geographyPoint)
            // double geo.distance(geometryPoint, geometryPoint)
            FunctionSignatureWithReturnType[] signatures = new FunctionSignatureWithReturnType[]
            {
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetDouble(true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true)),
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetDouble(true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true))
            };
            functions.Add("geo.distance", signatures);

            // bool geo.intersects(geometry.Point, geometry.Polygon)
            // bool geo.intersects(geometry.Polygon, geometry.Point)
            // bool geo.intersects(geography.Point, geography.Polygon)
            // bool geo.intersects(geography.Polygon, geography.Point)
            signatures = new FunctionSignatureWithReturnType[]
            {
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetBoolean(true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPolygon, true)),
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetBoolean(true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPolygon, true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true)),
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetBoolean(true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPolygon, true)),
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetBoolean(true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPolygon, true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true))
            };
            functions.Add("geo.intersects", signatures);

            // double geo.length(geometryLineString)
            // double geo.length(geographyLineString)
            signatures = new FunctionSignatureWithReturnType[]
            {
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetDouble(true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryLineString, true)),
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetDouble(true),
                    EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyLineString, true)),
            };
            functions.Add("geo.length", signatures);
        }
Beispiel #2
0
        /// <summary>
        /// Builds an array of signatures for date time functions.
        /// </summary>
        /// <returns>The array of signatures for a date time functions.</returns>
        private static FunctionSignatureWithReturnType[] CreateDateTimeFunctionSignatureArray()
        {
            FunctionSignatureWithReturnType dateTimeOffsetNonNullable = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetInt32(false),
                EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.DateTimeOffset, false));

            FunctionSignatureWithReturnType dateTimeOffsetNullable = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetInt32(false),
                EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.DateTimeOffset, true));

            return(new[] { dateTimeOffsetNonNullable, dateTimeOffsetNullable });
        }
Beispiel #3
0
 /// <summary>
 /// Promotes types of arguments to match signature if possible.
 /// </summary>
 /// <param name="signature">The signature to match the types to.</param>
 /// <param name="argumentNodes">The types to promote.</param>
 internal static void TypePromoteArguments(FunctionSignatureWithReturnType signature, List <QueryNode> argumentNodes)
 {
     // Convert all argument nodes to the best signature argument type
     Debug.Assert(signature.ArgumentTypes.Length == argumentNodes.Count, "The best signature match doesn't have the same number of arguments.");
     for (int i = 0; i < argumentNodes.Count; i++)
     {
         Debug.Assert(argumentNodes[i] is SingleValueNode, "We should have already verified that all arguments are single values.");
         SingleValueNode   argumentNode          = (SingleValueNode)argumentNodes[i];
         IEdmTypeReference signatureArgumentType = signature.ArgumentTypes[i];
         Debug.Assert(signatureArgumentType.IsODataPrimitiveTypeKind() || signatureArgumentType.IsODataEnumTypeKind(), "Only primitive or enum types should be able to get here.");
         argumentNodes[i] = MetadataBindingUtils.ConvertToTypeIfNeeded(argumentNode, signatureArgumentType);
     }
 }
Beispiel #4
0
        /// <summary>
        /// Builds an array of signatures for math functions.
        /// </summary>
        /// <returns>The array of signatures for math functions.</returns>
        private static FunctionSignatureWithReturnType[] CreateMathFunctionSignatureArray()
        {
            FunctionSignatureWithReturnType doubleSignature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetDouble(false),
                EdmCoreModel.Instance.GetDouble(false));
            FunctionSignatureWithReturnType nullableDoubleSignature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetDouble(false),
                EdmCoreModel.Instance.GetDouble(true));
            FunctionSignatureWithReturnType decimalSignature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetDecimal(false),
                EdmCoreModel.Instance.GetDecimal(false));
            FunctionSignatureWithReturnType nullableDecimalSignature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetDecimal(false),
                EdmCoreModel.Instance.GetDecimal(true));

            return(new FunctionSignatureWithReturnType[] { doubleSignature, decimalSignature, nullableDoubleSignature, nullableDecimalSignature });
        }
Beispiel #5
0
        /// <summary>
        /// Bind this function call token as a Uri function
        /// </summary>
        /// <param name="functionCallToken">the function call token to bind</param>
        /// <param name="argumentNodes">list of semantically bound arguments</param>
        /// <returns>A function call node bound to this function.</returns>
        private QueryNode BindAsUriFunction(FunctionCallToken functionCallToken, List <QueryNode> argumentNodes)
        {
            if (functionCallToken.Source != null)
            {
                // the parent must be null for a Uri function.
                throw new ODataException(ODataErrorStrings.FunctionCallBinder_UriFunctionMustHaveHaveNullParent(functionCallToken.Name));
            }

            // There are some functions (IsOf and Cast for example) that don't necessarily need to be bound to a function signature,
            // for these, we just Bind them directly to a SingleValueFunctionCallNode
            string matchedFunctionCallTokenName = IsUnboundFunction(functionCallToken.Name);

            if (matchedFunctionCallTokenName != null)
            {
                return(CreateUnboundFunctionNode(matchedFunctionCallTokenName, argumentNodes));
            }

            // Do some validation and get potential Uri functions that could match what we saw
            IList <KeyValuePair <string, FunctionSignatureWithReturnType> > nameSignatures = GetUriFunctionSignatures(functionCallToken.Name,
                                                                                                                      this.state.Configuration.EnableCaseInsensitiveUriFunctionIdentifier);

            SingleValueNode[] argumentNodeArray = ValidateArgumentsAreSingleValue(functionCallToken.Name, argumentNodes);
            KeyValuePair <string, FunctionSignatureWithReturnType> nameSignature = MatchSignatureToUriFunction(functionCallToken.Name, argumentNodeArray, nameSignatures);

            Debug.Assert(nameSignature.Key != null, "nameSignature.Key != null");

            string canonicalName = nameSignature.Key;
            FunctionSignatureWithReturnType signature = nameSignature.Value;

            if (signature.ReturnType != null)
            {
                TypePromoteArguments(signature, argumentNodes);
            }

            if (signature.ReturnType != null && signature.ReturnType.IsStructured())
            {
                return(new SingleResourceFunctionCallNode(canonicalName, new ReadOnlyCollection <QueryNode>(argumentNodes), signature.ReturnType.AsStructured(), null));
            }

            return(new SingleValueFunctionCallNode(canonicalName, new ReadOnlyCollection <QueryNode>(argumentNodes), signature.ReturnType));
        }
        /// <summary>
        /// Finds the signature that best matches the arguments
        /// </summary>
        /// <param name="functionName">The name of the function</param>
        /// <param name="argumentNodes">The nodes of the arguments, can be new {null,null}.</param>
        /// <param name="signatures">The signatures to match against</param>
        /// <returns>Returns the matching signature or throws</returns>
        internal static FunctionSignatureWithReturnType MatchSignatureToUriFunction(string functionName, SingleValueNode[] argumentNodes, FunctionSignatureWithReturnType[] signatures)
        {
            FunctionSignatureWithReturnType signature;

            IEdmTypeReference[] argumentTypes = argumentNodes.Select(s => s.TypeReference).ToArray();

            // Handle the cases where we don't have type information (null literal, open properties) for ANY of the arguments
            int argumentCount = argumentTypes.Length;

            if (argumentTypes.All(a => a == null) && argumentCount > 0)
            {
                // we specifically want to find just the first function that matches the number of arguments, we don't care about
                // ambiguity here because we're already in an ambiguous case where we don't know what kind of types
                // those arguments are.
                signature = signatures.FirstOrDefault(candidateFunction => candidateFunction.ArgumentTypes.Count() == argumentCount);
                if (signature == null)
                {
                    throw new ODataException(ODataErrorStrings.FunctionCallBinder_CannotFindASuitableOverload(functionName, argumentTypes.Count()));
                }
                else
                {
                    // in this case we can't assert the return type, we can only assert that a function exists... so
                    // we need to set the return type to null.
                    signature = new FunctionSignatureWithReturnType(null, signature.ArgumentTypes);
                }
            }
            else
            {
                signature = TypePromotionUtils.FindBestFunctionSignature(signatures, argumentNodes);
                if (signature == null)
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_NoApplicableFunctionFound(
                                                 functionName,
                                                 UriFunctionsHelper.BuildFunctionSignatureListDescription(functionName, signatures)));
                }
            }

            return(signature);
        }
Beispiel #7
0
        /// <summary>
        /// Removes the specific function overload from the custum uri functions.
        /// </summary>
        /// <param name="functionName">Custom function name to remove</param>
        /// <param name="functionSignature">The specific signature overload of the function to remove</param>
        /// <returns>'False' if custom function signature doesn't exist. 'True' if function has been removed successfully</returns>
        /// <exception cref="ArgumentNullException">Arguments are null, or function signature return type is null</exception>
        public static bool RemoveCustomUriFunction(string functionName, FunctionSignatureWithReturnType functionSignature)
        {
            ExceptionUtils.CheckArgumentStringNotNullOrEmpty(functionName, "customFunctionName");
            ExceptionUtils.CheckArgumentNotNull(functionSignature, "customFunctionSignature");

            ValidateFunctionWithReturnType(functionSignature);

            lock (Locker)
            {
                FunctionSignatureWithReturnType[] existingCustomFunctionOverloads;
                if (!CustomFunctions.TryGetValue(functionName, out existingCustomFunctionOverloads))
                {
                    return(false);
                }

                // Get all function sigature overloads without the overload which is requested to be removed
                FunctionSignatureWithReturnType[] customFunctionOverloadsWithoutTheOneToRemove =
                    existingCustomFunctionOverloads.SkipWhile(funcOverload => AreFunctionsSignatureEqual(funcOverload, functionSignature)).ToArray();

                // Nothing was removed - Requested overload doesn't exist
                if (customFunctionOverloadsWithoutTheOneToRemove.Length == existingCustomFunctionOverloads.Length)
                {
                    return(false);
                }

                // No overloads have left in this function name. Delete the function name
                if (customFunctionOverloadsWithoutTheOneToRemove.Length == 0)
                {
                    return(CustomFunctions.Remove(functionName));
                }
                else
                {
                    // Requested overload has been removed.
                    // Update the custom functions to the overloads wihtout that one requested to be removed
                    CustomFunctions[functionName] = customFunctionOverloadsWithoutTheOneToRemove;
                    return(true);
                }
            }
        }
Beispiel #8
0
        /// <summary>
        /// Creates all string functions.
        /// </summary>
        /// <param name="functions">Dictionary of functions to add to.</param>
        private static void CreateStringFunctions(IDictionary <string, FunctionSignatureWithReturnType[]> functions)
        {
            FunctionSignatureWithReturnType signature;

            FunctionSignatureWithReturnType[] signatures;

            // bool endswith(string, string)
            signature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetBoolean(false),
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true));
            functions.Add("endswith", new FunctionSignatureWithReturnType[] { signature });

            // int indexof(string, string)
            signature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetInt32(false),
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true));
            functions.Add("indexof", new FunctionSignatureWithReturnType[] { signature });

            // string replace(string, string, string)
            signature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true));
            functions.Add("replace", new FunctionSignatureWithReturnType[] { signature });

            // bool startswith(string, string)
            signature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetBoolean(false),
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true));
            functions.Add("startswith", new FunctionSignatureWithReturnType[] { signature });

            // string tolower(string)
            signature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true));
            functions.Add("tolower", new FunctionSignatureWithReturnType[] { signature });

            // string toupper(string)
            signature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true));
            functions.Add("toupper", new FunctionSignatureWithReturnType[] { signature });

            // string trim(string)
            signature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true));
            functions.Add("trim", new FunctionSignatureWithReturnType[] { signature });

            signatures = new FunctionSignatureWithReturnType[]
            {
                // string substring(string, int)
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetInt32(false)),

                // string substring(string, int?)
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetInt32(true)),

                // string substring(string, int, int)
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetInt32(false),
                    EdmCoreModel.Instance.GetInt32(false)),

                // string substring(string, int?, int)
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetInt32(true),
                    EdmCoreModel.Instance.GetInt32(false)),

                // string substring(string, int, int?)
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetInt32(false),
                    EdmCoreModel.Instance.GetInt32(true)),

                // string substring(string, int?, int?)
                new FunctionSignatureWithReturnType(
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetString(true),
                    EdmCoreModel.Instance.GetInt32(true),
                    EdmCoreModel.Instance.GetInt32(true)),
            };
            functions.Add("substring", signatures);

            // bool contains(string, string)
            signature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetBoolean(false),
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true));
            functions.Add("contains", new FunctionSignatureWithReturnType[] { signature });

            // string concat(string, string)
            signature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.Instance.GetString(true));
            functions.Add("concat", new FunctionSignatureWithReturnType[] { signature });

            // int length(string)
            signature = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetInt32(false),
                EdmCoreModel.Instance.GetString(true));
            functions.Add("length", new FunctionSignatureWithReturnType[] { signature });
        }
Beispiel #9
0
        private static bool AreFunctionsSignatureEqual(FunctionSignatureWithReturnType functionOne, FunctionSignatureWithReturnType functionTwo)
        {
            Debug.Assert(functionOne != null, "functionOne != null");
            Debug.Assert(functionTwo != null, "functionTwo != null");

            // Check if ReturnTypes are equal
            if (!functionOne.ReturnType.IsEquivalentTo(functionTwo.ReturnType))
            {
                return(false);
            }

            // Check the length of the Arguments of the two functions
            if (functionOne.ArgumentTypes.Length != functionTwo.ArgumentTypes.Length)
            {
                return(false);
            }

            // Check if the arguments are equal
            for (int argumentIndex = 0; argumentIndex < functionOne.ArgumentTypes.Length; argumentIndex++)
            {
                if (!functionOne.ArgumentTypes[argumentIndex].IsEquivalentTo(functionTwo.ArgumentTypes[argumentIndex]))
                {
                    return(false);
                }
            }

            return(true);
        }