289 lines
14 KiB
C#
289 lines
14 KiB
C#
//---------------------------------------------------------------------
|
|
// <copyright file="CqlQuery.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//
|
|
// @owner [....]
|
|
// @backupOwner [....]
|
|
//---------------------------------------------------------------------
|
|
|
|
namespace System.Data.Common.EntitySql
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Metadata.Edm;
|
|
using System.Globalization;
|
|
|
|
/// <summary>
|
|
/// Error reporting Helper
|
|
/// </summary>
|
|
internal static class CqlErrorHelper
|
|
{
|
|
/// <summary>
|
|
/// Reports function overload resolution error.
|
|
/// </summary>
|
|
internal static void ReportFunctionOverloadError(AST.MethodExpr functionExpr, EdmFunction functionType, List<TypeUsage> argTypes)
|
|
{
|
|
string strDelim = "";
|
|
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
|
sb.Append(functionType.Name).Append("(");
|
|
for (int i = 0 ; i < argTypes.Count ; i++)
|
|
{
|
|
sb.Append(strDelim);
|
|
sb.Append(argTypes[i] != null ? argTypes[i].EdmType.FullName : "NULL");
|
|
strDelim = ", ";
|
|
}
|
|
sb.Append(")");
|
|
|
|
Func<object, object, object, string> formatString;
|
|
if (TypeSemantics.IsAggregateFunction(functionType))
|
|
{
|
|
formatString = TypeHelpers.IsCanonicalFunction(functionType) ?
|
|
(Func<object, object, object, string>)System.Data.Entity.Strings.NoCanonicalAggrFunctionOverloadMatch :
|
|
(Func<object, object, object, string>)System.Data.Entity.Strings.NoAggrFunctionOverloadMatch;
|
|
}
|
|
else
|
|
{
|
|
formatString = TypeHelpers.IsCanonicalFunction(functionType) ?
|
|
(Func<object, object, object, string>)System.Data.Entity.Strings.NoCanonicalFunctionOverloadMatch :
|
|
(Func<object, object, object, string>)System.Data.Entity.Strings.NoFunctionOverloadMatch;
|
|
}
|
|
|
|
throw EntityUtil.EntitySqlError(functionExpr.ErrCtx.CommandText,
|
|
formatString(functionType.NamespaceName, functionType.Name, sb.ToString()),
|
|
functionExpr.ErrCtx.InputPosition,
|
|
System.Data.Entity.Strings.CtxFunction(functionType.Name),
|
|
false /* loadContextInfoFromResource */);
|
|
}
|
|
|
|
/// <summary>
|
|
/// provides error feedback for aliases already used in a given context
|
|
/// </summary>
|
|
/// <param name="aliasName"></param>
|
|
/// <param name="errCtx"></param>
|
|
/// <param name="contextMessage"></param>
|
|
internal static void ReportAliasAlreadyUsedError( string aliasName, ErrorContext errCtx, string contextMessage )
|
|
{
|
|
throw EntityUtil.EntitySqlError(errCtx, String.Format(CultureInfo.InvariantCulture, "{0} {1}", System.Data.Entity.Strings.AliasNameAlreadyUsed(aliasName), contextMessage));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reports incompatible type error
|
|
/// </summary>
|
|
/// <param name="errCtx"></param>
|
|
/// <param name="leftType"></param>
|
|
/// <param name="rightType"></param>
|
|
internal static void ReportIncompatibleCommonType( ErrorContext errCtx, TypeUsage leftType, TypeUsage rightType )
|
|
{
|
|
//
|
|
// 'navigate' through the type structure in order to find where the incompability is
|
|
//
|
|
ReportIncompatibleCommonType(errCtx, leftType, rightType, leftType, rightType);
|
|
|
|
//
|
|
// if we hit this point, throw the generic incompatible type error message
|
|
//
|
|
throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.ArgumentTypesAreIncompatible(leftType.Identity, rightType.Identity));
|
|
}
|
|
|
|
/// <summary>
|
|
/// navigates through the type structure to find where the incompatibility happens
|
|
/// </summary>
|
|
/// <param name="errCtx"></param>
|
|
/// <param name="rootLeftType"></param>
|
|
/// <param name="rootRightType"></param>
|
|
/// <param name="leftType"></param>
|
|
/// <param name="rightType"></param>
|
|
private static void ReportIncompatibleCommonType( ErrorContext errCtx, TypeUsage rootLeftType, TypeUsage rootRightType, TypeUsage leftType, TypeUsage rightType )
|
|
{
|
|
TypeUsage commonType = null;
|
|
bool isRootType = (rootLeftType == leftType);
|
|
string errorMessage = String.Empty;
|
|
|
|
if (leftType.EdmType.BuiltInTypeKind != rightType.EdmType.BuiltInTypeKind)
|
|
{
|
|
throw EntityUtil.EntitySqlError(errCtx,
|
|
System.Data.Entity.Strings.TypeKindMismatch(
|
|
GetReadableTypeKind(leftType),
|
|
GetReadableTypeName(leftType),
|
|
GetReadableTypeKind(rightType),
|
|
GetReadableTypeName(rightType)));
|
|
}
|
|
|
|
switch( leftType.EdmType.BuiltInTypeKind )
|
|
{
|
|
case BuiltInTypeKind.RowType:
|
|
RowType leftRow = (RowType)leftType.EdmType;
|
|
RowType rightRow = (RowType)rightType.EdmType;
|
|
|
|
if (leftRow.Members.Count != rightRow.Members.Count)
|
|
{
|
|
if (isRootType)
|
|
{
|
|
errorMessage = System.Data.Entity.Strings.InvalidRootRowType(
|
|
GetReadableTypeName(leftRow),
|
|
GetReadableTypeName(rightRow));
|
|
}
|
|
else
|
|
{
|
|
errorMessage = System.Data.Entity.Strings.InvalidRowType(
|
|
GetReadableTypeName(leftRow),
|
|
GetReadableTypeName(rootLeftType),
|
|
GetReadableTypeName(rightRow),
|
|
GetReadableTypeName(rootRightType));
|
|
}
|
|
|
|
throw EntityUtil.EntitySqlError(errCtx, errorMessage);
|
|
}
|
|
|
|
for (int i = 0 ; i < leftRow.Members.Count ; i++)
|
|
{
|
|
ReportIncompatibleCommonType(errCtx, rootLeftType, rootRightType, leftRow.Members[i].TypeUsage, rightRow.Members[i].TypeUsage);
|
|
}
|
|
break;
|
|
|
|
case BuiltInTypeKind.CollectionType:
|
|
case BuiltInTypeKind.RefType:
|
|
ReportIncompatibleCommonType(errCtx,
|
|
rootLeftType,
|
|
rootRightType,
|
|
TypeHelpers.GetElementTypeUsage(leftType),
|
|
TypeHelpers.GetElementTypeUsage(rightType));
|
|
break;
|
|
|
|
case BuiltInTypeKind.EntityType:
|
|
if (!TypeSemantics.TryGetCommonType(leftType, rightType, out commonType))
|
|
{
|
|
if (isRootType)
|
|
{
|
|
errorMessage = System.Data.Entity.Strings.InvalidEntityRootTypeArgument(
|
|
GetReadableTypeName(leftType),
|
|
GetReadableTypeName(rightType));
|
|
}
|
|
else
|
|
{
|
|
errorMessage = System.Data.Entity.Strings.InvalidEntityTypeArgument(
|
|
GetReadableTypeName(leftType),
|
|
GetReadableTypeName(rootLeftType),
|
|
GetReadableTypeName(rightType),
|
|
GetReadableTypeName(rootRightType));
|
|
}
|
|
throw EntityUtil.EntitySqlError(errCtx, errorMessage);
|
|
}
|
|
break;
|
|
|
|
case BuiltInTypeKind.ComplexType:
|
|
ComplexType leftComplex = (ComplexType)leftType.EdmType;
|
|
ComplexType rightComplex = (ComplexType)rightType.EdmType;
|
|
if (leftComplex.Members.Count != rightComplex.Members.Count)
|
|
{
|
|
if (isRootType)
|
|
{
|
|
errorMessage = System.Data.Entity.Strings.InvalidRootComplexType(
|
|
GetReadableTypeName(leftComplex),
|
|
GetReadableTypeName(rightComplex));
|
|
}
|
|
else
|
|
{
|
|
errorMessage = System.Data.Entity.Strings.InvalidComplexType(
|
|
GetReadableTypeName(leftComplex),
|
|
GetReadableTypeName(rootLeftType),
|
|
GetReadableTypeName(rightComplex),
|
|
GetReadableTypeName(rootRightType));
|
|
}
|
|
throw EntityUtil.EntitySqlError(errCtx, errorMessage);
|
|
}
|
|
|
|
for (int i = 0 ; i < leftComplex.Members.Count ; i++)
|
|
{
|
|
ReportIncompatibleCommonType(errCtx,
|
|
rootLeftType,
|
|
rootRightType,
|
|
leftComplex.Members[i].TypeUsage,
|
|
rightComplex.Members[i].TypeUsage);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (!TypeSemantics.TryGetCommonType(leftType, rightType, out commonType))
|
|
{
|
|
if (isRootType)
|
|
{
|
|
errorMessage = System.Data.Entity.Strings.InvalidPlaceholderRootTypeArgument(
|
|
GetReadableTypeKind(leftType),
|
|
GetReadableTypeName(leftType),
|
|
GetReadableTypeKind(rightType),
|
|
GetReadableTypeName(rightType));
|
|
}
|
|
else
|
|
{
|
|
errorMessage = System.Data.Entity.Strings.InvalidPlaceholderTypeArgument(
|
|
GetReadableTypeKind(leftType),
|
|
GetReadableTypeName(leftType),
|
|
GetReadableTypeName(rootLeftType),
|
|
GetReadableTypeKind(rightType),
|
|
GetReadableTypeName(rightType),
|
|
GetReadableTypeName(rootRightType));
|
|
}
|
|
throw EntityUtil.EntitySqlError(errCtx, errorMessage);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#region Private Type Name Helpers
|
|
private static string GetReadableTypeName( TypeUsage type )
|
|
{
|
|
return GetReadableTypeName(type.EdmType);
|
|
}
|
|
|
|
private static string GetReadableTypeName( EdmType type )
|
|
{
|
|
if (type.BuiltInTypeKind == BuiltInTypeKind.RowType ||
|
|
type.BuiltInTypeKind == BuiltInTypeKind.CollectionType ||
|
|
type.BuiltInTypeKind == BuiltInTypeKind.RefType)
|
|
{
|
|
return type.Name;
|
|
}
|
|
return type.FullName;
|
|
}
|
|
|
|
private static string GetReadableTypeKind( TypeUsage type )
|
|
{
|
|
return GetReadableTypeKind(type.EdmType);
|
|
}
|
|
|
|
private static string GetReadableTypeKind( EdmType type )
|
|
{
|
|
string typeKindName = String.Empty;
|
|
switch( type.BuiltInTypeKind)
|
|
{
|
|
case BuiltInTypeKind.RowType:
|
|
typeKindName = System.Data.Entity.Strings.LocalizedRow;
|
|
break;
|
|
case BuiltInTypeKind.CollectionType:
|
|
typeKindName = System.Data.Entity.Strings.LocalizedCollection;
|
|
break;
|
|
case BuiltInTypeKind.RefType:
|
|
typeKindName = System.Data.Entity.Strings.LocalizedReference;
|
|
break;
|
|
case BuiltInTypeKind.EntityType:
|
|
typeKindName = System.Data.Entity.Strings.LocalizedEntity;
|
|
break;
|
|
case BuiltInTypeKind.ComplexType:
|
|
typeKindName = System.Data.Entity.Strings.LocalizedComplex;
|
|
break;
|
|
case BuiltInTypeKind.PrimitiveType:
|
|
typeKindName = System.Data.Entity.Strings.LocalizedPrimitive;
|
|
break;
|
|
default:
|
|
typeKindName = type.BuiltInTypeKind.ToString();
|
|
break;
|
|
}
|
|
return typeKindName + " " + System.Data.Entity.Strings.LocalizedType;
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
}
|