private string BindConstantNode(ConstantNode constantNode) { if (constantNode.Value is string && !_nonApplyString) { return(String.Format("N'{0}'", constantNode.Value)); } if (constantNode.Value == null) { return(" Null "); } if (constantNode.Value is Boolean) { return(Convert.ToInt32(constantNode.Value).ToString()); } return(constantNode.Value.ToString()); }
/// <summary> /// Validate the arguments to either isof or cast /// </summary> /// <param name="state">the current state of the binding algorithm</param> /// <param name="isCast">flag to indicate which function we're validating</param> /// <param name="args">the list of arguments, which could be changed</param> /// <returns>the return type of the function.</returns> private static IEdmTypeReference ValidateIsOfOrCast(BindingState state, bool isCast, ref List <QueryNode> args) { if (args.Count != 1 && args.Count != 2) { throw new ODataErrorException( ODataErrorStrings.MetadataBinder_CastOrIsOfExpressionWithWrongNumberOfOperands(args.Count)); } ConstantNode typeArgument = args.Last() as ConstantNode; IEdmTypeReference returnType = null; if (typeArgument != null) { returnType = TryGetTypeReference(state.Model, typeArgument.Value as string, state.Configuration.Resolver); } if (returnType == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_CastOrIsOfFunctionWithoutATypeArgument); } if (returnType.IsCollection()) { throw new ODataException(ODataErrorStrings.MetadataBinder_CastOrIsOfCollectionsNotSupported); } // if we only have one argument, then add the implicit range variable as the first argument. if (args.Count == 1) { args = new List <QueryNode>() { new ResourceRangeVariableReferenceNode( state.ImplicitRangeVariable.Name, state.ImplicitRangeVariable as ResourceRangeVariable), args[0] }; } else if (!(args[0] is SingleValueNode)) { throw new ODataException(ODataErrorStrings.MetadataBinder_CastOrIsOfCollectionsNotSupported); } if (isCast && (args.Count == 2)) { // throw if cast enum to not-string : if ((args[0].GetEdmTypeReference() is IEdmEnumTypeReference) && !string.Equals(typeArgument.Value as string, Microsoft.OData.Metadata.EdmConstants.EdmStringTypeName, StringComparison.Ordinal)) { throw new ODataException(ODataErrorStrings.CastBinder_EnumOnlyCastToOrFromString); } // throw if cast not-string to enum : while (returnType is IEdmEnumTypeReference) { IEdmTypeReference edmTypeReference = args[0].GetEdmTypeReference(); if (edmTypeReference == null) { // Support cast null to enum break; } IEdmPrimitiveTypeReference referenceTmp = edmTypeReference as IEdmPrimitiveTypeReference; if (referenceTmp != null) { IEdmPrimitiveType typeTmp = referenceTmp.Definition as IEdmPrimitiveType; if ((typeTmp != null) && (typeTmp.PrimitiveKind == EdmPrimitiveTypeKind.String)) { break; } } throw new ODataException(ODataErrorStrings.CastBinder_EnumOnlyCastToOrFromString); } } if (isCast) { return(returnType); } else { return(EdmCoreModel.Instance.GetBoolean(true)); } }
/// <summary> /// If the source node is not of the specified type, then we check if type promotion is possible and inject a convert node. /// If the source node is the same type as the target type (or if the target type is null), we just return the source node as is. /// </summary> /// <param name="source">The source node to apply the conversion to.</param> /// <param name="targetTypeReference">The target primitive type. May be null - this method will do nothing in that case.</param> /// <returns>The converted query node, or the original source node unchanged.</returns> internal static SingleValueNode ConvertToTypeIfNeeded(SingleValueNode source, IEdmTypeReference targetTypeReference) { Debug.Assert(source != null, "source != null"); if (targetTypeReference == null) { return(source); } if (source.TypeReference != null) { if (source.TypeReference.IsEquivalentTo(targetTypeReference)) { // For source is type definition, if source's underlying type == target type. // We create a conversion node from source to its underlying type (target type) // so that the service can convert value of source clr type to underlying clr type. if (source.TypeReference.IsTypeDefinition()) { return(new ConvertNode(source, targetTypeReference)); } return(source); } // Structured type in url will be translated into a node with raw string value. // We create a conversion node from string to structured type. if (targetTypeReference.IsStructured() || targetTypeReference.IsStructuredCollectionType()) { return(new ConvertNode(source, targetTypeReference)); } if (!TypePromotionUtils.CanConvertTo(source, source.TypeReference, targetTypeReference)) { throw new ODataException(ODataErrorStrings.MetadataBinder_CannotConvertToType(source.TypeReference.FullName(), targetTypeReference.FullName())); } else { ConstantNode constantNode = source as ConstantNode; if (source.TypeReference.IsEnum() && constantNode != null) { return(new ConstantNode(constantNode.Value, ODataUriUtils.ConvertToUriLiteral(constantNode.Value, ODataVersion.V4), targetTypeReference)); } object originalPrimitiveValue; if (MetadataUtilsCommon.TryGetConstantNodePrimitiveLDMF(source, out originalPrimitiveValue) && (originalPrimitiveValue != null)) { // L F D M types : directly create a ConvertNode. // 1. NodeToExpressionTranslator.cs won't allow implicitly converting single/double to decimal, which should be done here at Node tree level. // 2. And prevent losing precision in float -> double, e.g. (double)1.234f => 1.2339999675750732d not 1.234d object targetPrimitiveValue = ODataUriConversionUtils.CoerceNumericType(originalPrimitiveValue, targetTypeReference.AsPrimitive().Definition as IEdmPrimitiveType); if (string.IsNullOrEmpty(constantNode.LiteralText)) { return(new ConstantNode(targetPrimitiveValue)); } var candidate = new ConstantNode(targetPrimitiveValue, constantNode.LiteralText); var decimalType = candidate.TypeReference as IEdmDecimalTypeReference; if (decimalType != null) { var targetDecimalType = (IEdmDecimalTypeReference)targetTypeReference; return(decimalType.Precision == targetDecimalType.Precision && decimalType.Scale == targetDecimalType.Scale ? (SingleValueNode)candidate : (SingleValueNode)(new ConvertNode(candidate, targetTypeReference))); } else { return(candidate); } } else { // other type conversion : ConvertNode return(new ConvertNode(source, targetTypeReference)); } } } else { // If the source doesn't have a type (possibly an open property), then it's possible to convert it // cause we don't know for sure. return(new ConvertNode(source, targetTypeReference)); } }