private ResultSqlType ( StorageType left, StorageType right, bool lc, bool rc, int op ) : StorageType | ||
left | StorageType | |
right | StorageType | |
lc | bool | |
rc | bool | |
op | int | |
리턴 | StorageType |
internal StorageType ResultSqlType(StorageType left, StorageType right, bool lc, bool rc, int op)
{
int leftPrecedence = (int)GetPrecedence(left);
if (leftPrecedence == (int)DataTypePrecedence.Error)
{
return StorageType.Empty;
}
int rightPrecedence = (int)GetPrecedence(right);
if (rightPrecedence == (int)DataTypePrecedence.Error)
{
return StorageType.Empty;
}
if (Operators.IsLogical(op))
{
if ((left != StorageType.Boolean && left != StorageType.SqlBoolean) || (right != StorageType.Boolean && right != StorageType.SqlBoolean))
return StorageType.Empty;
if (left == StorageType.Boolean && right == StorageType.Boolean)
return StorageType.Boolean;
return StorageType.SqlBoolean;
}
if (op == Operators.Plus)
{
if ((left == StorageType.SqlString) || (right == StorageType.SqlString))
return StorageType.SqlString;
if ((left == StorageType.String) || (right == StorageType.String))
return StorageType.String;
}
//SqlBinary is operable just with SqlBinary
if ((left == StorageType.SqlBinary && right != StorageType.SqlBinary) || (left != StorageType.SqlBinary && right == StorageType.SqlBinary))
return StorageType.Empty;
//SqlGuid is operable just with SqlGuid
if ((left == StorageType.SqlGuid && right != StorageType.SqlGuid) || (left != StorageType.SqlGuid && right == StorageType.SqlGuid))
return StorageType.Empty;
if ((leftPrecedence > (int)DataTypePrecedence.SqlDouble && rightPrecedence < (int)DataTypePrecedence.TimeSpan))
{
return StorageType.Empty;
}
if ((leftPrecedence < (int)DataTypePrecedence.TimeSpan && rightPrecedence > (int)DataTypePrecedence.SqlDouble))
{
return StorageType.Empty;
}
if (leftPrecedence > (int)DataTypePrecedence.SqlDouble)
{
if (op == Operators.Plus || op == Operators.Minus)
{
if (left == StorageType.TimeSpan)
return right;
if (right == StorageType.TimeSpan)
return left;
return StorageType.Empty; // for plus or minus operations for time types, one of them MUST be time span
}
if (!Operators.IsRelational(op))
return StorageType.Empty; // we just have relational operations amoung time types
return left;
}
// time types finished
// continue with numerical types, numbers
DataTypePrecedence higherPrec = (DataTypePrecedence)Math.Max(leftPrecedence, rightPrecedence);
StorageType result = GetPrecedenceType(higherPrec);
// if we have at least one Sql type, the intermediate result should be Sql type
result = GetPrecedenceType((DataTypePrecedence)SqlResultType((int)higherPrec));
if (Operators.IsArithmetical(op))
{
if (result != StorageType.String && result != StorageType.Char && result != StorageType.SqlString)
{
if (!IsNumericSql(left))
return StorageType.Empty;
if (!IsNumericSql(right))
return StorageType.Empty;
}
}
// if the operation is a division the result should be at least a double
if ((op == Operators.Divide) && IsIntegerSql(result))
{
return StorageType.SqlDouble;
}
if (result == StorageType.SqlMoney)
{
if ((left != StorageType.SqlMoney) && (right != StorageType.SqlMoney))
result = StorageType.SqlDecimal;
}
if (IsMixedSql(left, right))
{
// we are dealing with one signed and one unsigned type so
// try to see if one of them is a ConstNode
if (IsUnsignedSql(result))
{
if (higherPrec < DataTypePrecedence.UInt64)
// left and right are mixed integers but with the same length
// so promote to the next signed type
result = GetPrecedenceType(higherPrec + 1);
else
throw ExprException.AmbiguousBinop(op, DataStorage.GetTypeStorage(left), DataStorage.GetTypeStorage(right));
}
}
return result;
}
private int Eval(BinaryNode expr, DataRow row, DataRowVersion version) { if (expr.op == Operators.And) { int lResult = Eval((BinaryNode)expr.left,row,version); if (lResult != 0) return lResult; int rResult = Eval((BinaryNode)expr.right,row,version); if (rResult != 0) return rResult; return 0; } long c = 0; object vLeft = expr.left.Eval(row, version); if (expr.op != Operators.Is && expr.op != Operators.IsNot) { object vRight = expr.right.Eval(row, version); bool isLConst = (expr.left is ConstNode); bool isRConst = (expr.right is ConstNode); if ((vLeft == DBNull.Value)||(expr.left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) return -1; if ((vRight == DBNull.Value)||(expr.right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) return 1; StorageType leftType = DataStorage.GetStorageType(vLeft.GetType()); if (StorageType.Char == leftType) { if ((isRConst)||(!expr.right.IsSqlColumn)) vRight = Convert.ToChar(vRight, table.FormatProvider); else vRight = SqlConvert.ChangeType2(vRight, StorageType.Char, typeof(char), table.FormatProvider); } StorageType rightType = DataStorage.GetStorageType(vRight.GetType()); StorageType resultType; if (expr.left.IsSqlColumn || expr.right.IsSqlColumn) { resultType = expr.ResultSqlType(leftType, rightType, isLConst, isRConst, expr.op); } else { resultType = expr.ResultType(leftType, rightType, isLConst, isRConst, expr.op); } if (StorageType.Empty == resultType) { expr.SetTypeMismatchError(expr.op, vLeft.GetType(), vRight.GetType()); } // if comparing a Guid column value against a string literal // use InvariantCulture instead of DataTable.Locale because in the Danish related cultures // sorting a Guid as a string has different results than in Invariant and English related cultures. // This fix is restricted to DataTable.Select("GuidColumn = 'string literal'") types of queries NameNode namedNode = null; System.Globalization.CompareInfo comparer = ((isLConst && !isRConst && (leftType == StorageType.String) && (rightType == StorageType.Guid) && (null != (namedNode = expr.right as NameNode)) && (namedNode.column.DataType == typeof(Guid))) || (isRConst && !isLConst && (rightType == StorageType.String) && (leftType == StorageType.Guid) && (null != (namedNode = expr.left as NameNode)) && (namedNode.column.DataType == typeof(Guid)))) ? System.Globalization.CultureInfo.InvariantCulture.CompareInfo : null; c = expr.BinaryCompare(vLeft, vRight, resultType, expr.op, comparer); } switch(expr.op) { case Operators.EqualTo: c = (c == 0 ? 0 : c < 0 ? -1 : 1); break; case Operators.GreaterThen: c = (c > 0 ? 0 : -1); break; case Operators.LessThen: c = (c < 0 ? 0 : 1); break; case Operators.GreaterOrEqual: c = (c >= 0 ? 0 : -1); break; case Operators.LessOrEqual: c = (c <= 0 ? 0 : 1); break; case Operators.Is: c = (vLeft == DBNull.Value ? 0 : -1); break; case Operators.IsNot: c = (vLeft != DBNull.Value ? 0 : 1); break; default: Debug.Assert(true, "Unsupported Binary Search Operator!"); break; } return (int)c; }