File: fx\src\data\System\Data\Filter\DataExpression.cs
Project: ndp\System.Data.csproj (System.Data)
//------------------------------------------------------------------------------
// <copyright file="DataExpression.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
// <owner current="false" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------
 
namespace System.Data {
    using System;
    using System.Diagnostics;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data.SqlTypes;
    using System.Data.Common;
 
    internal sealed class DataExpression : IFilter {
        internal string originalExpression = null;  // original, unoptimized string
 
        private bool parsed = false;
        private bool bound = false;
        private ExpressionNode expr = null;
        private DataTable table = null;
        private readonly StorageType _storageType;
        private readonly Type _dataType;  // This set if the expression is part of ExpressionCoulmn
        private DataColumn[] dependency = DataTable.zeroColumns;
 
        internal DataExpression(DataTable table, string expression) : this(table, expression, null) {
        }
 
        internal DataExpression(DataTable table, string expression, Type type) {
            ExpressionParser parser = new ExpressionParser(table);
            parser.LoadExpression(expression);
 
            originalExpression = expression;
            expr = null;
 
            if (expression != null) {
                _storageType = DataStorage.GetStorageType(type);
                if (_storageType == StorageType.BigInteger)
                {
                    throw ExprException.UnsupportedDataType(type);
                }
 
                _dataType = type;
                expr = parser.Parse();
                parsed = true;
                if (expr != null && table != null) {
                    this.Bind(table);
                }
                else {
                    bound = false;
                }
            }
        }
 
        internal string Expression {
            get {
                return (originalExpression != null ? originalExpression : ""); // 
            }
        }
 
        internal ExpressionNode ExpressionNode {
            get {
                return expr;
            }
        }
 
        internal bool HasValue {
            get {
                return (null != expr);
            }
        }
 
        internal void Bind(DataTable table) {
            this.table = table;
 
            if (table == null)
                return;
 
            if (expr != null) {
                Debug.Assert(parsed, "Invalid calling order: Bind() before Parse()");
                List<DataColumn> list = new List<DataColumn>();
                expr.Bind(table, list);
                expr = expr.Optimize();
                this.table = table;
                bound = true;
                dependency = list.ToArray();
            }
        }
 
        internal bool DependsOn(DataColumn column) {
            if (expr != null) {
                return expr.DependsOn(column);
            }
            else {
                return false;
            }
        }
 
        internal object Evaluate() {
            return Evaluate((DataRow)null, DataRowVersion.Default);
        }
 
        internal object Evaluate(DataRow row, DataRowVersion version) {
            object result;
 
            if (!bound) {
                this.Bind(this.table);
            }
            if (expr != null) {
                result = expr.Eval(row, version);
                // if the type is a SqlType (StorageType.Uri < _storageType), convert DBNull values.
                if (result != DBNull.Value || StorageType.Uri < _storageType) {
                    // we need to convert the return value to the column.Type;
                    try {
                        if (StorageType.Object != _storageType) {
                            result = SqlConvert.ChangeType2(result, _storageType, _dataType, table.FormatProvider);
                        }
                    }
                    catch (Exception e) {
                        // 
                        if (!ADP.IsCatchableExceptionType(e)) {
                            throw;
                        }
                        ExceptionBuilder.TraceExceptionForCapture(e);
 
                        // 
 
                        throw ExprException.DatavalueConvertion(result, _dataType, e);
                    }
                }
            }
            else {
                result = null;
            }
            return result;
        }
 
        internal object Evaluate(DataRow[] rows) {
            return Evaluate(rows, DataRowVersion.Default);
        }
 
 
        internal object Evaluate(DataRow[] rows, DataRowVersion version) {
            if (!bound) {
                this.Bind(this.table);
            }
            if (expr != null) {
                List<int> recordList = new List<int>();
                foreach(DataRow row in rows) {
                    if (row.RowState == DataRowState.Deleted)
                        continue;
                    if (version == DataRowVersion.Original && row.oldRecord == -1)
                        continue;
                    recordList.Add(row.GetRecordFromVersion(version));
                }
                int[]  records = recordList.ToArray();
                return expr.Eval(records);
            }
            else {
                return DBNull.Value;
            }
        }
 
        public bool Invoke(DataRow row, DataRowVersion version) {
            if (expr == null)
                return true;
 
            if (row == null) {
                throw ExprException.InvokeArgument();
            }
            object val = expr.Eval(row, version);
            bool result;
            try {
                result = ToBoolean(val);
            }
            catch (EvaluateException) {
                throw ExprException.FilterConvertion(Expression);
            }
            return result;
        }
 
        internal DataColumn[] GetDependency() {
            Debug.Assert(dependency != null, "GetDependencies: null, we should have created an empty list");
            return dependency;
        }
 
        internal bool IsTableAggregate() {
            if (expr != null)
                return expr.IsTableConstant();
            else
                return false;
        }
 
        internal static bool IsUnknown(object value) {
            return DataStorage.IsObjectNull(value);
        }
 
        internal bool HasLocalAggregate() {
            if (expr != null)
                return expr.HasLocalAggregate();
            else
                return false;
        }
        
        internal bool HasRemoteAggregate() {
            if (expr != null)
                return expr.HasRemoteAggregate();
            else
                return false;
        }
 
        internal static bool ToBoolean(object value) {
            if (IsUnknown(value))
                return false;
            if (value is bool)
                return(bool)value;
            if (value is SqlBoolean){
                return (((SqlBoolean)value).IsTrue);
            }
//check for SqlString is not added, value for true and false should be given with String, not with SqlString
            if (value is string) {
                try {
                    return Boolean.Parse((string)value);
                }
                catch (Exception e) {
                    // 
                    if (!ADP.IsCatchableExceptionType(e)) {
                        throw;
                    }
                    ExceptionBuilder.TraceExceptionForCapture(e);
                    // 
                    throw ExprException.DatavalueConvertion(value, typeof(bool), e);
                }
            }
 
            throw ExprException.DatavalueConvertion(value, typeof(bool), null);
        }
    }
 
    
}