SqlProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DLinq / Dlinq / SqlClient / SqlProvider.cs / 3 / SqlProvider.cs

                            using System; 
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; 
using System.Data;
using System.Data.Common; 
using System.Data.Linq; 
using System.Data.Linq.Mapping;
using System.Data.Linq.Provider; 
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Linq; 
using System.Linq.Expressions;
using System.Reflection; 
using System.Text; 
using System.Globalization;
using System.Diagnostics.CodeAnalysis; 
using Me = System.Data.Linq.SqlClient;

namespace System.Data.Linq.SqlClient {
    public sealed class Sql2000Provider : SqlProvider { 
        public Sql2000Provider()
            : base(ProviderMode.Sql2000) { 
        } 
    }
 
    public sealed class Sql2005Provider : SqlProvider {
        public Sql2005Provider()
            : base(ProviderMode.Sql2005) {
        } 
    }
 
    public sealed class Sql2008Provider : SqlProvider { 
        public Sql2008Provider()
            : base(ProviderMode.Sql2008) { 
        }
    }

    [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification="Unknown reason.")] 
    public class SqlProvider : IReaderProvider, IConnectionUser {
        private IDataServices services; 
        private SqlConnectionManager conManager; 
        private TypeSystemProvider typeProvider;
        private SqlFactory sqlFactory; 
        private Translator translator;
        private IObjectReaderCompiler readerCompiler;
        private bool disposed;
        private int commandTimeout; 

        private TextWriter log; 
        string dbName = string.Empty; 

        // stats and flags 
        private int queryCount;
        private bool checkQueries;
        private OptimizationFlags optimizationFlags = OptimizationFlags.All;
        private bool enableCacheLookup = true; 
        private ProviderMode mode = ProviderMode.NotYetDecided;
        private bool deleted = false; 
 
#if PERFORMANCE_BUILD
        private bool collectPerfInfo; 
        private bool collectPerfInfoInitialized = false;
        private bool collectQueryPerf;

        internal bool CollectPerfInfo { 
            get {
                if (!collectPerfInfoInitialized) { 
                    string s = System.Environment.GetEnvironmentVariable("CollectDLinqPerfInfo"); 
                    collectPerfInfo = (s != null) && (s == "On");
                    collectPerfInfoInitialized = true; 
                }
                return this.collectPerfInfo;
            }
        } 

        internal bool CollectQueryPerf { 
            get { return this.collectQueryPerf; } 
        }
#endif 

        internal enum ProviderMode {
            NotYetDecided,
            Sql2000, 
            Sql2005,
            Sql2008, 
            SqlCE 
        }
 
        const string SqlCeProviderInvariantName = "System.Data.SqlServerCe.3.5";
        const string SqlCeDataReaderTypeName = "System.Data.SqlServerCe.SqlCeDataReader";
        const string SqlCeConnectionTypeName = "System.Data.SqlServerCe.SqlCeConnection";
        const string SqlCeTransactionTypeName = "System.Data.SqlServerCe.SqlCeTransaction"; 

        internal ProviderMode Mode { 
            get { 
                this.CheckDispose();
                this.CheckInitialized(); 
                this.InitializeProviderMode();
                return this.mode;
            }
        } 

        private void InitializeProviderMode() { 
            if (this.mode == ProviderMode.NotYetDecided) { 
                if (this.IsSqlCe) {
                    this.mode = ProviderMode.SqlCE; 
                } else if (this.IsServer2KOrEarlier) {
                    this.mode = ProviderMode.Sql2000;
                }
                else if (this.IsServer2005) { 
                    this.mode = ProviderMode.Sql2005;
                } else { 
                    this.mode = ProviderMode.Sql2008; 
                }
            } 
            if (this.typeProvider == null) {
                switch (this.mode) {
                    case ProviderMode.Sql2000:
                        this.typeProvider = SqlTypeSystem.Create2000Provider(); 
                        break;
                    case ProviderMode.Sql2005: 
                        this.typeProvider = SqlTypeSystem.Create2005Provider(); 
                        break;
                    case ProviderMode.Sql2008: 
                        this.typeProvider = SqlTypeSystem.Create2008Provider();
                        break;
                    case ProviderMode.SqlCE:
                        this.typeProvider = SqlTypeSystem.CreateCEProvider(); 
                        break;
                    default: 
                        System.Diagnostics.Debug.Assert(false); 
                        break;
                } 
            }
            if (this.sqlFactory == null) {
                this.sqlFactory = new SqlFactory(this.typeProvider, this.services.Model);
                this.translator = new Translator(this.services, this.sqlFactory, this.typeProvider); 
            }
        } 
 
        /// 
        /// Return true if the current connection is SQLCE. 
        /// 
        private bool IsSqlCe {
            get {
                DbConnection con = conManager.UseConnection(this); 
                try {
                    if (String.CompareOrdinal(con.GetType().FullName, SqlCeConnectionTypeName) == 0) { 
                        return true; 
                    }
                } finally { 
                    conManager.ReleaseConnection(this);
                }
                return false;
            } 
        }
 
        ///  
        /// Return true if this is a 2K (or earlier) server. This may be a round trip to the server.
        ///  
        private bool IsServer2KOrEarlier {
            get {
                DbConnection con = conManager.UseConnection(this);
                try { 
                    string serverVersion = con.ServerVersion;
                    if (serverVersion.StartsWith("06.00.", StringComparison.Ordinal)) { 
                        return true; 
                    }
                    else if (serverVersion.StartsWith("06.50.", StringComparison.Ordinal)) { 
                        return true;
                    }
                    else if (serverVersion.StartsWith("07.00.", StringComparison.Ordinal)) {
                        return true; 
                    }
                    else if (serverVersion.StartsWith("08.00.", StringComparison.Ordinal)) { 
                        return true; 
                    }
                    return false; 
                }
                finally {
                    conManager.ReleaseConnection(this);
                } 
            }
        } 
 
        /// 
        /// Return true if this is a SQL 2005 server. This may be a round trip to the server. 
        /// 
        private bool IsServer2005 {
            get {
                DbConnection con = conManager.UseConnection(this); 
                try {
                    string serverVersion = con.ServerVersion; 
                    if (serverVersion.StartsWith("09.00.", StringComparison.Ordinal)) { 
                        return true;
                    } 
                    return false;
                }
                finally {
                    conManager.ReleaseConnection(this); 
                }
            } 
        } 

        DbConnection IProvider.Connection { 
            get {
                this.CheckDispose();
                this.CheckInitialized();
                return this.conManager.Connection; 
            }
        } 
 
        TextWriter IProvider.Log {
            get { 
                this.CheckDispose();
                this.CheckInitialized();
                return this.log;
            } 
            set {
                this.CheckDispose(); 
                this.CheckInitialized(); 
                this.log = value;
            } 
        }

        DbTransaction IProvider.Transaction {
            get { 
                this.CheckDispose();
                this.CheckInitialized(); 
                return this.conManager.Transaction; 
            }
            set { 
                this.CheckDispose();
                this.CheckInitialized();
                this.conManager.Transaction = value;
            } 
        }
 
        int IProvider.CommandTimeout { 
            get {
                this.CheckDispose(); 
                return this.commandTimeout;
            }
            set {
                this.CheckDispose(); 
                this.commandTimeout = value;
            } 
        } 

        ///  
        /// Expose a test hook which controls which SQL optimizations are executed.
        /// 
        internal OptimizationFlags OptimizationFlags {
            get { 
                CheckDispose();
                return this.optimizationFlags; 
            } 
            set {
                CheckDispose(); 
                this.optimizationFlags = value;
            }
        }
 
        /// 
        /// Validate queries as they are generated. 
        ///  
        internal bool CheckQueries {
            get { 
                CheckDispose();
                return checkQueries;
            }
            set { 
                CheckDispose();
                checkQueries = value; 
            } 
        }
 
        internal bool EnableCacheLookup {
            get {
                CheckDispose();
                return this.enableCacheLookup; 
            }
            set { 
                CheckDispose(); 
                this.enableCacheLookup = value;
            } 
        }

        internal int QueryCount {
            get { 
                CheckDispose();
                return this.queryCount; 
            } 
        }
 
        internal int MaxUsers {
            get {
                CheckDispose();
                return this.conManager.MaxUsers; 
            }
        } 
 
        IDataServices IReaderProvider.Services {
            get { return this.services; } 
        }

        IConnectionManager IReaderProvider.ConnectionManager {
            get { return this.conManager; } 
        }
 
        public SqlProvider() { 
            this.mode = ProviderMode.NotYetDecided;
        } 

        internal SqlProvider(ProviderMode mode) {
            this.mode = mode;
        } 

        private void CheckInitialized() { 
            if (this.services == null) { 
                throw Error.ContextNotInitialized();
            } 
        }
        private void CheckNotDeleted() {
            if (this.deleted) {
                throw Error.DatabaseDeleteThroughContext(); 
            }
        } 
 
        void IProvider.Initialize(IDataServices dataServices, object connection) {
            if (dataServices == null) { 
                throw Error.ArgumentNull("dataServices");
            }
            this.services = dataServices;
 
            DbConnection con;
            DbTransaction tx = null; 
 
            string fileOrServerOrConnectionString = connection as string;
            if (fileOrServerOrConnectionString != null) { 
                string connectionString = this.GetConnectionString(fileOrServerOrConnectionString);
                this.dbName = this.GetDatabaseName(connectionString);
                if (this.dbName.EndsWith(".sdf", StringComparison.OrdinalIgnoreCase)) {
                    this.mode = ProviderMode.SqlCE; 
                }
                if (this.mode == ProviderMode.SqlCE) { 
                    DbProviderFactory factory = SqlProvider.GetProvider(SqlCeProviderInvariantName); 
                    if (factory == null) {
                        throw Error.ProviderNotInstalled(this.dbName, SqlCeProviderInvariantName); 
                    }
                    con = factory.CreateConnection();
                }
                else { 
                    con = new SqlConnection();
                } 
                con.ConnectionString = connectionString; 
            }
            else { 
                // We only support SqlTransaction and SqlCeTransaction
                tx = connection as SqlTransaction;
                if (tx == null) {
                    // See if it's a SqlCeTransaction 
                    if (connection.GetType().FullName == SqlCeTransactionTypeName) {
                        tx = connection as DbTransaction; 
                    } 
                }
                if (tx != null) { 
                    connection = tx.Connection;
                }
                con = connection as DbConnection;
                if (con == null) { 
                    throw Error.InvalidConnectionArgument("connection");
                } 
                if (con.GetType().FullName == SqlCeConnectionTypeName) { 
                    this.mode = ProviderMode.SqlCE;
                } 
                this.dbName = this.GetDatabaseName(con.ConnectionString);
            }

            // initialize to the default command timeout 
            using (DbCommand c = con.CreateCommand()) {
                this.commandTimeout = c.CommandTimeout; 
            } 

            int maxUsersPerConnection = 1; 
            if (con.ConnectionString.Contains("MultipleActiveResultSets")) {
                DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
                builder.ConnectionString = con.ConnectionString;
                if (string.Compare((string)builder["MultipleActiveResultSets"], "true", StringComparison.OrdinalIgnoreCase) == 0) { 
                    maxUsersPerConnection = 10;
                } 
            } 

            this.conManager = new SqlConnectionManager(this, con, maxUsersPerConnection); 
            if (tx != null) {
                this.conManager.Transaction = tx;
            }
 
#if DEBUG
            SqlNode.Formatter = new SqlFormatter(); 
#endif 

#if ILGEN 
            Type readerType;
            if (this.mode == ProviderMode.SqlCE) {
                readerType = con.GetType().Module.GetType(SqlCeDataReaderTypeName);
            } 
            else if (con is SqlConnection) {
                readerType = typeof(SqlDataReader); 
            } 
            else {
                readerType = typeof(DbDataReader); 
            }
            this.readerCompiler = new ObjectReaderCompiler(readerType, this.services);
#else
            this.readerCompiler = new ObjectReaderBuilder(this, this.services); 
#endif
        } 
 
        private static DbProviderFactory GetProvider(string providerName) {
            bool hasProvider = 
                DbProviderFactories.GetFactoryClasses().Rows.OfType()
                .Select(r => (string)r["InvariantName"])
                .Contains(providerName, StringComparer.OrdinalIgnoreCase);
            if (hasProvider) { 
                return DbProviderFactories.GetFactory(providerName);
            } 
            return null; 
        }
 
        #region Dispose\Finalize
        public void Dispose() {
            this.disposed = true;
            Dispose(true); 
            //GC.SuppressFinalize(this);  We don't have a finalize method
        } 
        // Not implementing finalizer here because there are no unmanaged resources 
        // to release. See http://msdnwiki.microsoft.com/en-us/mtpswiki/12afb1ea-3a17-4a3f-a1f0-fcdb853e2359.aspx
 
        // The bulk of the clean-up code is implemented in Dispose(bool)
        protected virtual void Dispose(bool disposing) {
            // Implemented but empty so that derived contexts can implement
            // a finalizer that potentially cleans up unmanaged resources. 
            if (disposing) {
                this.services = null; 
                if (this.conManager != null) { 
                    this.conManager.DisposeConnection();
                } 
                this.conManager = null;
                this.typeProvider = null;
                this.sqlFactory = null;
                this.translator = null; 
                this.readerCompiler = null;
                this.log = null; 
            } 
        }
 
        internal void CheckDispose() {
            if (this.disposed) {
                throw Error.ProviderCannotBeUsedAfterDispose();
            } 
        }
        #endregion 
 
        private string GetConnectionString(string fileOrServerOrConnectionString) {
            if (fileOrServerOrConnectionString.IndexOf('=') >= 0) { 
                return fileOrServerOrConnectionString;
            }
            else {
                DbConnectionStringBuilder builder = new DbConnectionStringBuilder(); 
                if (fileOrServerOrConnectionString.EndsWith(".mdf", StringComparison.OrdinalIgnoreCase)) {
                    // if just a database file is specified, default to local SqlExpress instance 
                    builder.Add("AttachDBFileName", fileOrServerOrConnectionString); 
                    builder.Add("Server", "localhost\\sqlexpress");
                    builder.Add("Integrated Security", "SSPI"); 
                    builder.Add("User Instance", "true");
                    builder.Add("MultipleActiveResultSets", "true");
                }
                else if (fileOrServerOrConnectionString.EndsWith(".sdf", StringComparison.OrdinalIgnoreCase)) { 
                    // A SqlCE database file has been specified
                    builder.Add("Data Source", fileOrServerOrConnectionString); 
                } 
                else {
                    builder.Add("Server", fileOrServerOrConnectionString); 
                    builder.Add("Database", this.services.Model.DatabaseName);
                    builder.Add("Integrated Security", "SSPI");
                }
                return builder.ToString(); 
            }
        } 
 
        private string GetDatabaseName(string constr) {
            DbConnectionStringBuilder builder = new DbConnectionStringBuilder(); 
            builder.ConnectionString = constr;

            if (builder.ContainsKey("Initial Catalog")) {
                return (string)builder["Initial Catalog"]; 
            }
            else if (builder.ContainsKey("Database")) { 
                return (string)builder["Database"]; 
            }
            else if (builder.ContainsKey("AttachDBFileName")) { 
                return (string)builder["AttachDBFileName"];
            }
            else if (builder.ContainsKey("Data Source")
                && ((string)builder["Data Source"]).EndsWith(".sdf", StringComparison.OrdinalIgnoreCase)) { 
                return (string)builder["Data Source"];
            } 
            else { 
                return this.services.Model.DatabaseName;
            } 
        }

        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
        void IProvider.CreateDatabase() { 
            this.CheckDispose();
            this.CheckInitialized(); 
            // Don't need to call CheckNotDeleted() here since we allow CreateDatabase after DeleteDatabase 
            // Don't need to call InitializeProviderMode() here since we don't need to know the provider to do this.
            string catalog = null; 
            string filename = null;

            DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
            builder.ConnectionString = this.conManager.Connection.ConnectionString; 

            if (this.conManager.Connection.State == ConnectionState.Closed) { 
                if (this.mode == ProviderMode.SqlCE) { 
                    if (!File.Exists(this.dbName)) {
                        Type engineType = this.conManager.Connection.GetType().Module.GetType("System.Data.SqlServerCe.SqlCeEngine"); 
                        object engine = Activator.CreateInstance(engineType, new object[] { builder.ToString() });
                        try {
                            engineType.InvokeMember("CreateDatabase", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, engine, new object[] { }, CultureInfo.InvariantCulture);
                        } 
                        catch (TargetInvocationException tie) {
                            throw tie.InnerException; 
                        } 
                        finally {
                            IDisposable disp = engine as IDisposable; 
                            if (disp != null) {
                                disp.Dispose();
                            }
                        } 
                    }
                    else { 
                        throw Error.CreateDatabaseFailedBecauseSqlCEDatabaseAlreadyExists(this.dbName); 
                    }
                } 
                else {
                    // get connection string w/o reference to new catalog
                    object val;
                    if (builder.TryGetValue("Initial Catalog", out val)) { 
                        catalog = val.ToString();
                        builder.Remove("Initial Catalog"); 
                    } 
                    if (builder.TryGetValue("Database", out val)) {
                        catalog = val.ToString(); 
                        builder.Remove("Database");
                    }
                    if (builder.TryGetValue("AttachDBFileName", out val)) {
                        filename = val.ToString(); 
                        builder.Remove("AttachDBFileName");
                    } 
                } 
                this.conManager.Connection.ConnectionString = builder.ToString();
            } 
            else {
                if (this.mode == ProviderMode.SqlCE) {
                    if (File.Exists(this.dbName)) {
                        throw Error.CreateDatabaseFailedBecauseSqlCEDatabaseAlreadyExists(this.dbName); 
                    }
                } 
                object val; 
                if (builder.TryGetValue("Initial Catalog", out val)) {
                    catalog = val.ToString(); 
                }
                if (builder.TryGetValue("Database", out val)) {
                    catalog = val.ToString();
                } 
                if (builder.TryGetValue("AttachDBFileName", out val)) {
                    filename = val.ToString(); 
                } 
            }
 
            if (String.IsNullOrEmpty(catalog)) {
                if (!String.IsNullOrEmpty(filename)) {
                    catalog = Path.GetFullPath(filename);
                } 
                else if (!String.IsNullOrEmpty(this.dbName)) {
                    catalog = this.dbName; 
                } 
                else {
                    throw Error.CouldNotDetermineCatalogName(); 
                }
            }

            this.conManager.UseConnection(this); 
            this.conManager.AutoClose = false;
 
            try { 
                if (this.services.Model.GetTables().FirstOrDefault() == null) {
                    // we have no tables to create 
                    throw Error.CreateDatabaseFailedBecauseOfContextWithNoTables(this.services.Model.DatabaseName);
                }

                this.deleted = false; 

                // create database 
                if (this.mode == ProviderMode.SqlCE) { 

                    // create tables 
                    foreach (MetaTable table in this.services.Model.GetTables()) {
                        string command = SqlBuilder.GetCreateTableCommand(table);
                        if (!String.IsNullOrEmpty(command)) {
                            this.ExecuteCommand(command); 
                        }
                    } 
                    // create all foreign keys after all tables are defined 
                    foreach (MetaTable table in this.services.Model.GetTables()) {
                        foreach (string command in SqlBuilder.GetCreateForeignKeyCommands(table)) { 
                            if (!String.IsNullOrEmpty(command)) {
                                this.ExecuteCommand(command);
                            }
                        } 
                    }
                } 
                else { 
                    string createdb = SqlBuilder.GetCreateDatabaseCommand(catalog, filename, Path.ChangeExtension(filename, ".ldf"));
                    this.ExecuteCommand(createdb); 
                    this.conManager.Connection.ChangeDatabase(catalog);

                    // create the schemas that our tables will need
                    // cannot be batched together with the rest of the CREATE TABLES 
                    if (this.mode == ProviderMode.Sql2005 || this.mode == ProviderMode.Sql2008) {
                        HashSet schemaCommands = new HashSet(); 
 
                        foreach (MetaTable table in this.services.Model.GetTables()) {
                            string schemaCommand = SqlBuilder.GetCreateSchemaForTableCommand(table); 
                            if (!string.IsNullOrEmpty(schemaCommand)) {
                                schemaCommands.Add(schemaCommand);
                            }
                        } 

                        foreach (string schemaCommand in schemaCommands) { 
                            this.ExecuteCommand(schemaCommand); 
                        }
                    } 

                    StringBuilder sb = new StringBuilder();

                    // create tables 
                    foreach (MetaTable table in this.services.Model.GetTables()) {
                        string createTable = SqlBuilder.GetCreateTableCommand(table); 
                        if (!string.IsNullOrEmpty(createTable)) { 
                            sb.AppendLine(createTable);
                        } 
                    }

                    // create all foreign keys after all tables are defined
                    foreach (MetaTable table in this.services.Model.GetTables()) { 
                        foreach (string createFK in SqlBuilder.GetCreateForeignKeyCommands(table)) {
                            if (!string.IsNullOrEmpty(createFK)) { 
                                sb.AppendLine(createFK); 
                            }
                        } 
                    }

                    if (sb.Length > 0) {
                        // must be on when creating indexes on computed columns 
                        sb.Insert(0, "SET ARITHABORT ON" + Environment.NewLine);
                        this.ExecuteCommand(sb.ToString()); 
                    } 
                }
            } 
            finally {
                this.conManager.ReleaseConnection(this);
                if (this.conManager.Connection is SqlConnection) {
                    SqlConnection.ClearAllPools(); 
                }
            } 
        } 

        void IProvider.DeleteDatabase() { 
            this.CheckDispose();
            this.CheckInitialized();
            // Don't need to call InitializeProviderMode() here since we don't need to know the provider to do this.
            if (this.deleted) { 
                // 2nd delete is no-op.
                return; 
            } 

            if (this.mode == ProviderMode.SqlCE) { 
                ((IProvider)this).ClearConnection();
                System.Diagnostics.Debug.Assert(this.conManager.Connection.State == ConnectionState.Closed);
                File.Delete(this.dbName);
                this.deleted = true; 
            }
            else { 
                string holdConnStr = conManager.Connection.ConnectionString; 
                DbConnection con = this.conManager.UseConnection(this);
                try { 
                    con.ChangeDatabase("MASTER");
                    if (con is SqlConnection) {
                        SqlConnection.ClearAllPools();
                    } 
                    if (this.log != null) {
                        this.log.WriteLine(Strings.LogAttemptingToDeleteDatabase(this.dbName)); 
                    } 
                    this.ExecuteCommand(SqlBuilder.GetDropDatabaseCommand(this.dbName));
                    this.deleted = true; 
                }
                finally {
                    this.conManager.ReleaseConnection(this);
                    if (conManager.Connection.State == ConnectionState.Closed && 
                        string.Compare(conManager.Connection.ConnectionString, holdConnStr, StringComparison.Ordinal) != 0) {
                        // Credential information may have been stripped from the connection 
                        // string as a result of opening the connection. Restore the full 
                        // connection string.
                        conManager.Connection.ConnectionString = holdConnStr; 
                    }
                }
            }
        } 

        // 
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification="[....]: Code needs to return false regarless of exception.")] 
        bool IProvider.DatabaseExists() {
            this.CheckDispose(); 
            this.CheckInitialized();
            if (this.deleted) {
                return false;
            } 
            // Don't need to call InitializeProviderMode() here since we don't need to know the provider to do this.
 
            bool exists = false; 
            if (this.mode == ProviderMode.SqlCE) {
                exists = File.Exists(this.dbName); 
            }
            else {
                string holdConnStr = conManager.Connection.ConnectionString;
                try { 
                    // If no database name is explicitly specified on the connection,
                    // UseConnection will connect to 'Master', which is why after connecting 
                    // we call ChangeDatabase to verify that the database actually exists. 
                    this.conManager.UseConnection(this);
                    this.conManager.Connection.ChangeDatabase(this.dbName); 
                    this.conManager.ReleaseConnection(this);
                    exists = true;
                } catch (Exception) {
                } finally { 
                    if (conManager.Connection.State == ConnectionState.Closed &&
                        string.Compare(conManager.Connection.ConnectionString, holdConnStr, StringComparison.Ordinal) != 0) { 
                        // Credential information may have been stripped from the connection 
                        // string as a result of opening the connection. Restore the full
                        // connection string. 
                        conManager.Connection.ConnectionString = holdConnStr;
                    }
                }
            } 
            return exists;
        } 
 
        void IConnectionUser.CompleteUse() {
        } 

        void IProvider.ClearConnection() {
            this.CheckDispose();
            this.CheckInitialized(); 
            this.conManager.ClearConnection();
        } 
 
        private void ExecuteCommand(string command) {
            if (this.log != null) { 
                this.log.WriteLine(command);
                this.log.WriteLine();
            }
            IDbCommand cmd = this.conManager.Connection.CreateCommand(); 
            cmd.CommandTimeout = this.commandTimeout;
            cmd.Transaction = this.conManager.Transaction; 
            cmd.CommandText = command; 
            cmd.ExecuteNonQuery();
        } 

        ICompiledQuery IProvider.Compile(Expression query) {
            this.CheckDispose();
            this.CheckInitialized(); 
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            } 
            this.InitializeProviderMode();
 
            SqlNodeAnnotations annotations = new SqlNodeAnnotations();
            QueryInfo[] qis = this.BuildQuery(query, annotations);
            CheckSqlCompatibility(qis, annotations);
 
            LambdaExpression lambda = query as LambdaExpression;
            if (lambda != null) { 
                query = lambda.Body; 
            }
 
            IObjectReaderFactory factory = null;
            ICompiledSubQuery[] subQueries = null;
            QueryInfo qi = qis[qis.Length - 1];
            if (qi.ResultShape == ResultShape.Singleton) { 
                subQueries = this.CompileSubQueries(qi.Query);
                factory = this.GetReaderFactory(qi.Query, qi.ResultType); 
            } 
            else if (qi.ResultShape == ResultShape.Sequence) {
                subQueries = this.CompileSubQueries(qi.Query); 
                factory = this.GetReaderFactory(qi.Query, TypeSystem.GetElementType(qi.ResultType));
            }

            return new CompiledQuery(this, query, qis, factory, subQueries); 
        }
 
        private ICompiledSubQuery CompileSubQuery(SqlNode query, Type elementType, ReadOnlyCollection parameters) { 
            query = SqlDuplicator.Copy(query);
            SqlNodeAnnotations annotations = new SqlNodeAnnotations(); 

            QueryInfo[] qis = this.BuildQuery(ResultShape.Sequence, TypeSystem.GetSequenceType(elementType), query, parameters, annotations);
            System.Diagnostics.Debug.Assert(qis.Length == 1);
            QueryInfo qi = qis[0]; 
            ICompiledSubQuery[] subQueries = this.CompileSubQueries(qi.Query);
            IObjectReaderFactory factory = this.GetReaderFactory(qi.Query, elementType); 
 
            CheckSqlCompatibility(qis, annotations);
 
            return new CompiledSubQuery(qi, factory, parameters, subQueries);
        }

        IExecuteResult IProvider.Execute(Expression query) { 
            this.CheckDispose();
            this.CheckInitialized(); 
            this.CheckNotDeleted(); 
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            }
            this.InitializeProviderMode();

#if PERFORMANCE_BUILD 
            PerformanceCounter pcBuildQuery = null, bpcBuildQuery = null, pcExecQuery = null, bpcExecQuery = null,
                   pcSession = null, bpcSession = null; 
            PerfTimer timerAll = null, timer = null; 
            if (this.CollectPerfInfo) {
                string s = System.Environment.GetEnvironmentVariable("EnableDLinqQueryPerf"); 
                collectQueryPerf = (s != null && s == "On");
            }
            if (collectQueryPerf) {
                pcBuildQuery = new PerformanceCounter("DLinq", "BuildQueryElapsedTime", false); 
                bpcBuildQuery = new PerformanceCounter("DLinq", "BuildQueryElapsedTimeBase", false);
                pcExecQuery = new PerformanceCounter("DLinq", "ExecuteQueryElapsedTime", false); 
                bpcExecQuery = new PerformanceCounter("DLinq", "ExecuteQueryElapsedTimeBase", false); 
                pcSession = new PerformanceCounter("DLinq", "SessionExecuteQueryElapsedTime", false);
                bpcSession = new PerformanceCounter("DLinq", "SessionExecuteQueryElapsedTimeBase", false); 
                timerAll = new PerfTimer();
                timer = new PerfTimer();
                timerAll.Start();
            } 
#endif
            query = Funcletizer.Funcletize(query); 
 
            if (this.EnableCacheLookup) {
                IExecuteResult cached = this.GetCachedResult(query); 
                if (cached != null) {
                    return cached;
                }
            } 

#if PERFORMANCE_BUILD 
            if (collectQueryPerf) { 
                timer.Start();
            } 
#endif
            SqlNodeAnnotations annotations = new SqlNodeAnnotations();
            QueryInfo[] qis = this.BuildQuery(query, annotations);
            CheckSqlCompatibility(qis, annotations); 

            LambdaExpression lambda = query as LambdaExpression; 
            if (lambda != null) { 
                query = lambda.Body;
            } 

            IObjectReaderFactory factory = null;
            ICompiledSubQuery[] subQueries = null;
            QueryInfo qi = qis[qis.Length - 1]; 
            if (qi.ResultShape == ResultShape.Singleton) {
                subQueries = this.CompileSubQueries(qi.Query); 
                factory = this.GetReaderFactory(qi.Query, qi.ResultType); 
            }
            else if (qi.ResultShape == ResultShape.Sequence) { 
                subQueries = this.CompileSubQueries(qi.Query);
                factory = this.GetReaderFactory(qi.Query, TypeSystem.GetElementType(qi.ResultType));
            }
 
#if PERFORMANCE_BUILD
                if (collectQueryPerf) { 
                    timer.Stop(); 
                    pcBuildQuery.IncrementBy(timer.Duration);
                    bpcBuildQuery.Increment(); 
                }
#endif

#if PERFORMANCE_BUILD 
            if (collectQueryPerf) {
                timer.Start(); 
            } 

#endif 
            IExecuteResult result = this.ExecuteAll(query, qis, factory, null, subQueries);

#if PERFORMANCE_BUILD
            if (collectQueryPerf) { 
                timer.Stop();
                pcSession.IncrementBy(timer.Duration); 
                bpcSession.Increment(); 
                timerAll.Stop();
                pcExecQuery.IncrementBy(timerAll.Duration); 
                bpcExecQuery.Increment();
            }
#endif
            return result; 
        }
 
        private ICompiledSubQuery[] CompileSubQueries(SqlNode query) { 
            return new SubQueryCompiler(this).Compile(query);
        } 

        class SubQueryCompiler : SqlVisitor {
            SqlProvider provider;
            List subQueries; 

            internal SubQueryCompiler(SqlProvider provider) { 
                this.provider = provider; 
            }
 
            internal ICompiledSubQuery[] Compile(SqlNode node) {
                this.subQueries = new List();
                this.Visit(node);
                return this.subQueries.ToArray(); 
            }
 
            internal override SqlSelect VisitSelect(SqlSelect select) { 
                this.Visit(select.Selection);
                return select; 
            }

            internal override SqlExpression VisitSubSelect(SqlSubSelect ss) {
                return ss; 
            }
 
            internal override SqlExpression VisitClientQuery(SqlClientQuery cq) { 
                Type clientElementType = cq.Query.NodeType == SqlNodeType.Multiset ? TypeSystem.GetElementType(cq.ClrType) : cq.ClrType;
                ICompiledSubQuery c = this.provider.CompileSubQuery(cq.Query.Select, clientElementType, cq.Parameters.AsReadOnly()); 
                cq.Ordinal = this.subQueries.Count;
                this.subQueries.Add(c);
                return cq;
            } 
        }
 
        ///  
        /// Look for compatibility annotations for the set of providers we
        /// add annotations for. 
        /// 
        private void CheckSqlCompatibility(QueryInfo[] queries, SqlNodeAnnotations annotations) {
            if (this.Mode == ProviderMode.Sql2000 ||
                this.Mode == ProviderMode.SqlCE) { 
                for (int i = 0, n = queries.Length; i < n; i++) {
                    SqlServerCompatibilityCheck.ThrowIfUnsupported(queries[i].Query, annotations, this.Mode); 
                } 
            }
        } 

        private IExecuteResult ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, object[] userArguments, ICompiledSubQuery[] subQueries) {
            IExecuteResult result = null;
            object lastResult = null; 
            for (int i = 0, n = queryInfos.Length; i < n; i++) {
                if (i < n - 1) { 
                    result = this.Execute(query, queryInfos[i], null, null, userArguments, subQueries, lastResult); 
                }
                else { 
                    result = this.Execute(query, queryInfos[i], factory, null, userArguments, subQueries, lastResult);
                }
                if (queryInfos[i].ResultShape == ResultShape.Return) {
                    lastResult = result.ReturnValue; 
                }
            } 
            return result; 
        }
 
        private IExecuteResult GetCachedResult(Expression query) {
            object obj = this.services.GetCachedObject(query);
            if (obj != null) {
                switch (this.GetResultShape(query)) { 
                    case ResultShape.Singleton:
                        return new ExecuteResult(null, null, null, obj); 
                    case ResultShape.Sequence: 
                        return new ExecuteResult(null, null, null,
                            Activator.CreateInstance( 
                                typeof(SequenceOfOne<>).MakeGenericType(TypeSystem.GetElementType(this.GetResultType(query))),
                                BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { obj }, null
                                ));
                } 
            }
            return null; 
        } 

        [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification="Unknown reason.")] 
        private IExecuteResult Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, object[] parentArgs, object[] userArgs, ICompiledSubQuery[] subQueries, object lastResult) {
            this.InitializeProviderMode();

            DbConnection con = this.conManager.UseConnection(this); 
            try {
                DbCommand cmd = con.CreateCommand(); 
                cmd.CommandText = queryInfo.CommandText; 
                cmd.Transaction = this.conManager.Transaction;
                cmd.CommandTimeout = this.commandTimeout; 
                AssignParameters(cmd, queryInfo.Parameters, userArgs, lastResult);
                LogCommand(this.log, cmd);
                this.queryCount += 1;
 
                switch (queryInfo.ResultShape) {
                    default: 
                    case ResultShape.Return: { 
                            return new ExecuteResult(cmd, queryInfo.Parameters, null, cmd.ExecuteNonQuery(), true);
                        } 
                    case ResultShape.Singleton: {
                            DbDataReader reader = cmd.ExecuteReader();
                            IObjectReader objReader = factory.Create(reader, true, this, parentArgs, userArgs, subQueries);
                            this.conManager.UseConnection(objReader.Session); 
                            try {
                                IEnumerable sequence = (IEnumerable)Activator.CreateInstance( 
                                    typeof(OneTimeEnumerable<>).MakeGenericType(queryInfo.ResultType), 
                                    BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null,
                                    new object[] { objReader }, null 
                                    );
                                object value = null;
                                MethodCallExpression mce = query as MethodCallExpression;
                                MethodInfo sequenceMethod = null; 
                                if (mce != null && (
                                    mce.Method.DeclaringType == typeof(Queryable) || 
                                    mce.Method.DeclaringType == typeof(Enumerable)) 
                                    ) {
                                    switch (mce.Method.Name) { 
                                        case "First":
                                        case "FirstOrDefault":
                                        case "SingleOrDefault":
                                            sequenceMethod = TypeSystem.FindSequenceMethod(mce.Method.Name, sequence); 
                                            break;
                                        case "Single": 
                                        default: 
                                            sequenceMethod = TypeSystem.FindSequenceMethod("Single", sequence);
                                            break; 
                                    }
                                }
                                else {
                                    sequenceMethod = TypeSystem.FindSequenceMethod("SingleOrDefault", sequence); 
                                }
 
                                // When dynamically invoking the sequence method, we want to 
                                // return the inner exception if the invocation fails
                                if (sequenceMethod != null) { 
                                    try {
                                        value = sequenceMethod.Invoke(null, new object[] { sequence });
                                    }
                                    catch (TargetInvocationException tie) { 
                                        if (tie.InnerException != null) {
                                            throw tie.InnerException; 
                                        } 
                                        throw;
                                    } 
                                }

                                return new ExecuteResult(cmd, queryInfo.Parameters, objReader.Session, value);
                            } 
                            finally {
                                objReader.Dispose(); 
                            } 
                        }
                    case ResultShape.Sequence: { 
                            DbDataReader reader = cmd.ExecuteReader();
                            IObjectReader objReader = factory.Create(reader, true, this, parentArgs, userArgs, subQueries);
                            this.conManager.UseConnection(objReader.Session);
                            IEnumerable sequence = (IEnumerable)Activator.CreateInstance( 
                                typeof(OneTimeEnumerable<>).MakeGenericType(TypeSystem.GetElementType(queryInfo.ResultType)),
                                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, 
                                new object[] { objReader }, null 
                                );
                            if (typeof(IQueryable).IsAssignableFrom(queryInfo.ResultType)) { 
                                sequence = sequence.AsQueryable();
                            }
                            ExecuteResult result = new ExecuteResult(cmd, queryInfo.Parameters, objReader.Session);
                            MetaFunction function = this.GetFunction(query); 
                            if (function != null && !function.IsComposable) {
                                sequence = (IEnumerable)Activator.CreateInstance( 
                                typeof(SingleResult<>).MakeGenericType(TypeSystem.GetElementType(queryInfo.ResultType)), 
                                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null,
                                new object[] { sequence, result, this.services.Context }, null 
                                );
                            }
                            result.ReturnValue = sequence;
                            return result; 
                        }
                    case ResultShape.MultipleResults: { 
                            DbDataReader reader = cmd.ExecuteReader(); 
                            IObjectReaderSession session = this.readerCompiler.CreateSession(reader, this, parentArgs, userArgs, subQueries);
                            this.conManager.UseConnection(session); 
                            MetaFunction function = this.GetFunction(query);
                            ExecuteResult result = new ExecuteResult(cmd, queryInfo.Parameters, session);
                            result.ReturnValue = new MultipleResults(this, function, session, result);
                            return result; 
                        }
                } 
            } 
            finally {
                this.conManager.ReleaseConnection(this); 
            }
        }

        private MetaFunction GetFunction(Expression query) { 
            LambdaExpression lambda = query as LambdaExpression;
            if (lambda != null) { 
                query = lambda.Body; 
            }
            MethodCallExpression mc = query as MethodCallExpression; 
            if (mc != null && typeof(DataContext).IsAssignableFrom(mc.Method.DeclaringType)) {
                return this.services.Model.GetFunction(mc.Method);
            }
            return null; 
        }
 
        private void LogCommand(TextWriter writer, DbCommand cmd) { 
            if (writer != null) {
                writer.WriteLine(cmd.CommandText); 
                foreach (DbParameter p in cmd.Parameters) {
                    int prec = 0;
                    int scale = 0;
                    PropertyInfo piPrecision = p.GetType().GetProperty("Precision"); 
                    if (piPrecision != null) {
                        prec = (int)Convert.ChangeType(piPrecision.GetValue(p, null), typeof(int), CultureInfo.InvariantCulture); 
                    } 
                    PropertyInfo piScale = p.GetType().GetProperty("Scale");
                    if (piScale != null) { 
                        scale = (int)Convert.ChangeType(piScale.GetValue(p, null), typeof(int), CultureInfo.InvariantCulture);
                    }
                    var sp = p as System.Data.SqlClient.SqlParameter;
                    writer.WriteLine("-- {0}: {1} {2} (Size = {3}; Prec = {4}; Scale = {5}) [{6}]", 
                        p.ParameterName,
                        p.Direction, 
                        sp == null ? p.DbType.ToString() : sp.SqlDbType.ToString(), 
                        p.Size.ToString(System.Globalization.CultureInfo.CurrentCulture),
                        prec, 
                        scale,
                        sp == null ? p.Value : sp.SqlValue);
                }
                writer.WriteLine("-- Context: {0}({1}) Model: {2} Build: {3}", this.GetType().Name, this.Mode, this.services.Model.GetType().Name, ThisAssembly.InformationalVersion); 
                writer.WriteLine();
            } 
        } 

        private void AssignParameters(DbCommand cmd, ReadOnlyCollection parms, object[] userArguments, object lastResult) { 
            if (parms != null) {
                foreach (SqlParameterInfo pi in parms) {
                    DbParameter p = cmd.CreateParameter();
                    p.ParameterName = pi.Parameter.Name; 
                    p.Direction = pi.Parameter.Direction;
                    if (pi.Parameter.Direction == ParameterDirection.Input || 
                        pi.Parameter.Direction == ParameterDirection.InputOutput) { 
                        object value = pi.Value;
                        switch (pi.Type) { 
                            case SqlParameterType.UserArgument:
                                try {
                                    value = pi.Accessor.DynamicInvoke(new object[] { userArguments });
                                } catch (System.Reflection.TargetInvocationException e) { 
                                    throw e.InnerException;
                                } 
                                break; 
                            case SqlParameterType.PreviousResult:
                                value = lastResult; 
                                break;
                        }
                        this.typeProvider.InitializeParameter(pi.Parameter.SqlType, p, value);
                    } 
                    else {
                        this.typeProvider.InitializeParameter(pi.Parameter.SqlType, p, null); 
                    } 
                    cmd.Parameters.Add(p);
                } 
            }
        }

        IEnumerable IProvider.Translate(Type elementType, DbDataReader reader) { 
            this.CheckDispose();
            this.CheckInitialized(); 
            this.InitializeProviderMode(); 
            if (elementType == null) {
                throw Error.ArgumentNull("elementType"); 
            }
            if (reader == null) {
                throw Error.ArgumentNull("reader");
            } 
            MetaType rowType = services.Model.GetMetaType(elementType);
            IObjectReaderFactory factory = this.GetDefaultFactory(rowType); 
            IEnumerator e = factory.Create(reader, true, this, null, null, null); 
            Type enumerableType = typeof(OneTimeEnumerable<>).MakeGenericType(elementType);
            return (IEnumerable)Activator.CreateInstance(enumerableType, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { e }, null); 
        }

        IMultipleResults IProvider.Translate(DbDataReader reader) {
            this.CheckDispose(); 
            this.CheckInitialized();
            this.InitializeProviderMode(); 
            if (reader == null) { 
                throw Error.ArgumentNull("reader");
            } 
            IObjectReaderSession session = this.readerCompiler.CreateSession(reader, this, null, null, null);
            return new MultipleResults(this, null, session, null);
        }
 
         string IProvider.GetQueryText(Expression query) {
            this.CheckDispose(); 
            this.CheckInitialized(); 
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            }
            this.InitializeProviderMode();
            SqlNodeAnnotations annotations = new SqlNodeAnnotations();
            QueryInfo[] qis = this.BuildQuery(query, annotations); 

            StringBuilder sb = new StringBuilder(); 
            for (int i = 0, n = qis.Length; i < n; i++) { 
                QueryInfo qi = qis[i];
#if DEBUG 
                StringWriter writer = new StringWriter(System.Globalization.CultureInfo.InvariantCulture);
                DbCommand cmd = this.conManager.Connection.CreateCommand();
                cmd.CommandText = qi.CommandText;
                AssignParameters(cmd, qi.Parameters, null, null); 
                LogCommand(writer, cmd);
                sb.Append(writer.ToString()); 
#else 
                sb.Append(qi.CommandText);
                sb.AppendLine(); 
#endif
            }
            return sb.ToString();
        } 

        DbCommand IProvider.GetCommand(Expression query) { 
            this.CheckDispose(); 
            this.CheckInitialized();
            if (query == null) { 
                throw Error.ArgumentNull("query");
            }
            this.InitializeProviderMode();
            SqlNodeAnnotations annotations = new SqlNodeAnnotations(); 
            QueryInfo[] qis = this.BuildQuery(query, annotations);
            QueryInfo qi = qis[qis.Length - 1]; 
            DbCommand cmd = this.conManager.Connection.CreateCommand(); 
            cmd.CommandText = qi.CommandText;
            cmd.Transaction = (SqlTransaction) this.conManager.Transaction; 
            cmd.CommandTimeout = this.commandTimeout;
            AssignParameters(cmd, qi.Parameters, null, null);
            return cmd;
        } 

        internal class QueryInfo { 
            SqlNode query; 
            string commandText;
            ReadOnlyCollection parameters; 
            ResultShape resultShape;
            Type resultType;

            internal QueryInfo(SqlNode query, string commandText, ReadOnlyCollection parameters, ResultShape resultShape, Type resultType) { 
                this.query = query;
                this.commandText = commandText; 
                this.parameters = parameters; 
                this.resultShape = resultShape;
                this.resultType = resultType; 
            }
            internal SqlNode Query {
                get { return this.query; }
            } 
            internal string CommandText {
                get { return this.commandText; } 
            } 
            internal ReadOnlyCollection Parameters {
                get { return this.parameters; } 
            }
            internal ResultShape ResultShape {
                get { return this.resultShape; }
            } 
            internal Type ResultType {
                get { return this.resultType; } 
            } 
        }
 
        internal enum ResultShape {
            Return,
            Singleton,
            Sequence, 
            MultipleResults
        } 
 
        private ResultShape GetResultShape(Expression query) {
            LambdaExpression lambda = query as LambdaExpression; 
            if (lambda != null) {
                query = lambda.Body;
            }
 
            if (query.Type == typeof(void)) {
                return ResultShape.Return; 
            } 
            else if (query.Type == typeof(IMultipleResults)) {
                return ResultShape.MultipleResults; 
            }

            bool isSequence = typeof(IEnumerable).IsAssignableFrom(query.Type);
            ProviderType pt = this.typeProvider.From(query.Type); 
            bool isScalar = !pt.IsRuntimeOnlyType && !pt.IsApplicationType;
            bool isSingleton = isScalar || !isSequence; 
 
            MethodCallExpression mce = query as MethodCallExpression;
            if (mce != null) { 
                // query operators
                if (mce.Method.DeclaringType == typeof(Queryable) ||
                    mce.Method.DeclaringType == typeof(Enumerable)) {
                    switch (mce.Method.Name) { 
                        // methods known to produce singletons
                        case "First": 
                        case "FirstOrDefault": 
                        case "Single":
                        case "SingleOrDefault": 
                            isSingleton = true;
                            break;
                    }
                } 
                else if (mce.Method.DeclaringType == typeof(DataContext)) {
                    if (mce.Method.Name == "ExecuteCommand") { 
                        return ResultShape.Return; 
                    }
                } 
                else if (mce.Method.DeclaringType.IsSubclassOf(typeof(DataContext))) {
                    MetaFunction f = this.GetFunction(query);
                    if (f != null) {
                        if (!f.IsComposable) { 
                            isSingleton = false;
                        } 
                        else if (isScalar) { 
                            isSingleton = true;
                        } 
                    }
                }
                else if (mce.Method.DeclaringType == typeof(DataManipulation) && mce.Method.ReturnType == typeof(int)) {
                    return ResultShape.Return; 
                }
            } 
 
            if (isSingleton) {
                return ResultShape.Singleton; 
            }
            else if (isScalar) {
                return ResultShape.Return;
            } 
            else {
                return ResultShape.Sequence; 
            } 
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")]
        private Type GetResultType(Expression query) {
            LambdaExpression lambda = query as LambdaExpression;
            if (lambda != null) { 
                query = lambda.Body;
            } 
            return query.Type; 
        }
 
        internal QueryInfo[] BuildQuery(Expression query, SqlNodeAnnotations annotations) {
            this.CheckDispose();

            // apply maximal funcletization 
            query = Funcletizer.Funcletize(query);
 
            // convert query nodes into sql nodes 
            QueryConverter converter = new QueryConverter(this.services, this.typeProvider, this.translator, this.sqlFactory);
            switch (this.Mode) { 
                case ProviderMode.Sql2000:
                    converter.ConverterStrategy =
                        ConverterStrategy.CanUseScopeIdentity |
                        ConverterStrategy.CanUseJoinOn | 
                        ConverterStrategy.CanUseRowStatus;
                    break; 
                case ProviderMode.Sql2005: 
                case ProviderMode.Sql2008:
                    converter.ConverterStrategy = 
                        ConverterStrategy.CanUseScopeIdentity |
                        ConverterStrategy.SkipWithRowNumber |
                        ConverterStrategy.CanUseRowStatus |
                        ConverterStrategy.CanUseJoinOn | 
                        ConverterStrategy.CanUseOuterApply |
                        ConverterStrategy.CanOutputFromInsert; 
                    break; 
                case ProviderMode.SqlCE:
                    converter.ConverterStrategy = ConverterStrategy.CanUseOuterApply; 
                    // Can't set ConverterStrategy.CanUseJoinOn because scalar subqueries in the ON clause
                    // can't be converted into anything.
                    break;
            } 
            SqlNode node = converter.ConvertOuter(query);
 
            return this.BuildQuery(this.GetResultShape(query), this.GetResultType(query), node, null, annotations); 
        }
 
        private bool CanBeColumn(SqlExpression expression) {
            if (expression.SqlType.CanBeColumn) {
                switch (expression.NodeType) {
                    case SqlNodeType.MethodCall: 
                    case SqlNodeType.Member:
                    case SqlNodeType.New: 
                        return PostBindDotNetConverter.CanConvert(expression); 
                    default:
                        return true; 
                }
            }
            return false;
        } 

        [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
        private QueryInfo[] BuildQuery(ResultShape resultShape, Type resultType, SqlNode node, ReadOnlyCollection parentParameters, SqlNodeAnnotations annotations) { 
            System.Diagnostics.Debug.Assert(resultType != null);
            System.Diagnostics.Debug.Assert(node != null); 

            SqlSupersetValidator validator = new SqlSupersetValidator();

            // These are the rules that apply to every SQL tree. 
            if (this.checkQueries) {
                validator.AddValidator(new ColumnTypeValidator()); /* Column CLR Type must agree with its Expressions CLR Type */ 
                validator.AddValidator(new LiteralValidator()); /* Constrain literal Types */ 
            }
 
            validator.Validate(node);

            SqlColumnizer columnizer = new SqlColumnizer(this.CanBeColumn);
 
            // resolve member references
            SqlBinder binder = new SqlBinder(this.translator, this.sqlFactory, this.services.Model, this.services.Context.LoadOptions, columnizer); 
            binder.OptimizeLinkExpansions = (optimizationFlags & OptimizationFlags.OptimizeLinkExpansions) != 0; 
            binder.SimplifyCaseStatements = (optimizationFlags & OptimizationFlags.SimplifyCaseStatements) != 0;
            binder.PreBinder = delegate(SqlNode n) { 
                // convert methods into known reversable operators
                return PreBindDotNetConverter.Convert(n, this.sqlFactory, this.services.Model);
            };
            node = binder.Bind(node); 
            if (this.checkQueries) {
                validator.AddValidator(new ExpectNoAliasRefs()); 
                validator.AddValidator(new ExpectNoSharedExpressions()); 
            }
            validator.Validate(node); 

            node = PostBindDotNetConverter.Convert(node, this.sqlFactory, this.Mode);

            // identify true flow of sql data types 
            SqlRetyper retyper = new SqlRetyper(this.typeProvider, this.services.Model);
            node = retyper.Retype(node); 
            validator.Validate(node); 

            // change CONVERT to special conversions like UNICODE,CHAR,... 
            SqlTypeConverter converter = new SqlTypeConverter(this.sqlFactory);
            node = converter.Visit(node);
            validator.Validate(node);
 
            // transform type-sensitive methods such as LEN (to DATALENGTH), ...
            SqlMethodTransformer methodTransformer = new SqlMethodTransformer(this.sqlFactory); 
            node = methodTransformer.Visit(node); 
            validator.Validate(node);
 
            // convert multisets into separate queries
            SqlMultiplexer.Options options = (this.Mode == ProviderMode.Sql2008 ||
                                              this.Mode == ProviderMode.Sql2005 ||
                                              this.Mode == ProviderMode.SqlCE) 
                ? SqlMultiplexer.Options.EnableBigJoin : SqlMultiplexer.Options.None;
            SqlMultiplexer mux = new SqlMultiplexer(options, parentParameters, this.sqlFactory); 
            node = mux.Multiplex(node); 
            validator.Validate(node);
 
            // convert object construction expressions into flat row projections
            SqlFlattener flattener = new SqlFlattener(this.sqlFactory, columnizer);
            node = flattener.Flatten(node);
            validator.Validate(node); 

            if (this.mode == ProviderMode.SqlCE) { 
                SqlRewriteScalarSubqueries rss = new SqlRewriteScalarSubqueries(this.sqlFactory); 
                node = rss.Rewrite(node);
            } 

            // Simplify case statements where all alternatives map to the same thing.
            // Doing this before deflator because the simplified results may lead to
            // more deflation opportunities. 
            // Doing this before booleanizer because it may convert CASE statements (non-predicates) into
            // predicate expressions. 
            // Doing this before reorderer because it may reduce some orders to constant nodes which should not 
            // be passed onto ROW_NUMBER.
            node = SqlCaseSimplifier.Simplify(node, this.sqlFactory); 

            // Rewrite order-by clauses so that they only occur at the top-most select
            // or in selects with TOP
            SqlReorderer reorderer = new SqlReorderer(this.typeProvider, this.sqlFactory); 
            node = reorderer.Reorder(node);
            validator.Validate(node); 
 
            // Inject code to turn predicates into bits, and bits into predicates where necessary
            node = SqlBooleanizer.Rationalize(node, this.typeProvider, this.services.Model); 
            if (this.checkQueries) {
                validator.AddValidator(new ExpectRationalizedBooleans()); /* From now on all boolean expressions should remain rationalized. */
            }
            validator.Validate(node); 

            if (this.checkQueries) { 
                validator.AddValidator(new ExpectNoFloatingColumns()); 
            }
 
            // turning predicates into bits/ints can change Sql types, propagate changes
            node = retyper.Retype(node);
            validator.Validate(node);
 
            // assign aliases to columns
            // we need to do this now so that the sql2k lifters will work 
            SqlAliaser aliaser = new SqlAliaser(); 
            node = aliaser.AssociateColumnsWithAliases(node);
            validator.Validate(node); 

            // SQL2K enablers.
            node = SqlLiftWhereClauses.Lift(node, this.typeProvider, this.services.Model);
            node = SqlLiftIndependentRowExpressions.Lift(node); 
            node = SqlOuterApplyReducer.Reduce(node, this.sqlFactory, annotations);
            node = SqlTopReducer.Reduce(node, annotations, this.sqlFactory); 
 
            // resolve references to columns in other scopes by adding them
            // to the intermediate selects 
            SqlResolver resolver = new SqlResolver();
            node = resolver.Resolve(node);
            validator.Validate(node);
 
            // re-assign aliases after resolving (new columns may have been added)
            node = aliaser.AssociateColumnsWithAliases(node); 
            validator.Validate(node); 

            // fixup union projections 
            node = SqlUnionizer.Unionize(node);

            // remove order-by of literals
            node = SqlRemoveConstantOrderBy.Remove(node); 

            // throw out unused columns and redundant sub-queries... 
            SqlDeflator deflator = new SqlDeflator(); 
            node = deflator.Deflate(node);
            validator.Validate(node); 

            // Positioning after deflator because it may remove unnecessary columns
            // from SELECT projection lists and allow more CROSS APPLYs to be reduced
            // to CROSS JOINs. 
            node = SqlCrossApplyToCrossJoin.Reduce(node, annotations);
 
            // fixup names for aliases, columns, locals, etc.. 
            SqlNamer namer = new SqlNamer();
            node = namer.AssignNames(node); 
            validator.Validate(node);

            // Convert [N]Text,Image to [N]VarChar(MAX),VarBinary(MAX) where necessary.
            // These new types do not exist on SQL2k, so add annotations. 
            LongTypeConverter longTypeConverter = new LongTypeConverter(this.sqlFactory);
            node = longTypeConverter.AddConversions(node, annotations); 
 
            // final validation
            validator.AddValidator(new ExpectNoMethodCalls()); 
            validator.AddValidator(new ValidateNoInvalidComparison());
            validator.Validate(node);

            SqlParameterizer parameterizer = new SqlParameterizer(this.typeProvider, annotations); 
            SqlFormatter formatter = new SqlFormatter();
            if (this.mode == ProviderMode.SqlCE || 
                this.mode == ProviderMode.Sql2005 || 
                this.mode == ProviderMode.Sql2008) {
                formatter.ParenthesizeTop = true; 
            }

            SqlBlock block = node as SqlBlock;
            if (block != null && this.mode == ProviderMode.SqlCE) { 
                // SQLCE cannot batch multiple statements.
                ReadOnlyCollection> parameters = parameterizer.ParameterizeBlock(block); 
                string[] commands = formatter.FormatBlock(block, false); 
                QueryInfo[] queries = new QueryInfo[commands.Length];
                for (int i = 0, n = commands.Length; i < n; i++) { 
                    queries[i] = new QueryInfo(
                        block.Statements[i],
                        commands[i],
                        parameters[i], 
                        (i < n - 1) ? ResultShape.Return : resultShape,
                        (i < n - 1) ? typeof(int) : resultType 
                        ); 
                }
                return queries; 
            }
            else {
                // build only one result
                ReadOnlyCollection parameters = parameterizer.Parameterize(node); 
                string commandText = formatter.Format(node);
                return new QueryInfo[] { 
                    new QueryInfo(node, commandText, parameters, resultShape, resultType) 
                    };
            } 
        }

        private SqlSelect GetFinalSelect(SqlNode node) {
            switch (node.NodeType) { 
                case SqlNodeType.Select:
                    return (SqlSelect)node; 
                case SqlNodeType.Block: { 
                        SqlBlock b = (SqlBlock)node;
                        return GetFinalSelect(b.Statements[b.Statements.Count - 1]); 
                    }
            }
            return null;
        } 

        private IObjectReaderFactory GetReaderFactory(SqlNode node, Type elemType) { 
            SqlSelect sel = node as SqlSelect; 
            SqlExpression projection = null;
            if (sel == null && node.NodeType == SqlNodeType.Block) { 
                sel = this.GetFinalSelect(node);
            }
            if (sel != null) {
                projection = sel.Selection; 
            }
            else { 
                SqlUserQuery suq = node as SqlUserQuery; 
                if (suq != null && suq.Projection != null) {
                    projection = suq.Projection; 
                }
            }
            IObjectReaderFactory factory;
            if (projection != null) { 
                factory = this.readerCompiler.Compile(projection, elemType);
            } 
            else { 
                return this.GetDefaultFactory(services.Model.GetMetaType(elemType));
            } 
            return factory;
        }

        private IObjectReaderFactory GetDefaultFactory(MetaType rowType) { 
            if (rowType == null) {
                throw Error.ArgumentNull("rowType"); 
            } 
            SqlNodeAnnotations annotations = new SqlNodeAnnotations();
            Expression tmp = Expression.Constant(null); 
            SqlUserQuery suq = new SqlUserQuery(string.Empty, null, null, tmp);
            if (TypeSystem.IsSimpleType(rowType.Type)) {
                // if the element type is a simple type (int, bool, etc.) we create
                // a single column binding 
                SqlUserColumn col = new SqlUserColumn(rowType.Type, typeProvider.From(rowType.Type), suq, "", false, suq.SourceExpression);
                suq.Columns.Add(col); 
                suq.Projection = col; 
            }
            else { 
                // ... otherwise we generate a default projection
                SqlUserRow rowExp = new SqlUserRow(rowType.InheritanceRoot, this.typeProvider.GetApplicationType((int)ConverterSpecialTypes.Row), suq, tmp);
                suq.Projection = this.translator.BuildProjection(rowExp, rowType, true, null, tmp);
            } 
            Type resultType = TypeSystem.GetSequenceType(rowType.Type);
            QueryInfo[] qis = this.BuildQuery(ResultShape.Sequence, resultType, suq, null, annotations); 
            return this.GetReaderFactory(qis[qis.Length - 1].Query, rowType.Type); 
        }
 
        class CompiledQuery : ICompiledQuery {
            DataLoadOptions originalShape;
            Expression query;
            QueryInfo[] queryInfos; 
            IObjectReaderFactory factory;
            ICompiledSubQuery[] subQueries; 
 
            internal CompiledQuery(SqlProvider provider, Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, ICompiledSubQuery[] subQueries) {
                this.originalShape = provider.services.Context.LoadOptions; 
                this.query = query;
                this.queryInfos = queryInfos;
                this.factory = factory;
                this.subQueries = subQueries; 
            }
 
            public IExecuteResult Execute(IProvider provider, object[] arguments) { 
                if (provider == null) {
                    throw Error.ArgumentNull("provider"); 
                }

                SqlProvider sqlProvider = provider as SqlProvider;
                if (sqlProvider == null) { 
                    throw Error.ArgumentTypeMismatch("provider");
                } 
 
                // verify shape is compatibile with original.
                if (!AreEquivalentShapes(this.originalShape, sqlProvider.services.Context.LoadOptions)) { 
                    throw Error.CompiledQueryAgainstMultipleShapesNotSupported();
                }

                // execute query (only last query produces results) 
                return sqlProvider.ExecuteAll(this.query, this.queryInfos, this.factory, arguments, subQueries);
            } 
 
            private static bool AreEquivalentShapes(DataLoadOptions shape1, DataLoadOptions shape2) {
                if (shape1 == shape2) { 
                    return true;
                }
                else if (shape1 == null) {
                    return shape2.IsEmpty; 
                }
                else if (shape2 == null) { 
                    return shape1.IsEmpty; 
                }
                else if (shape1.IsEmpty && shape2.IsEmpty) { 
                    return true;
                }
                return false;
            } 
        }
 
        class CompiledSubQuery : ICompiledSubQuery { 
            QueryInfo queryInfo;
            IObjectReaderFactory factory; 
            ReadOnlyCollection parameters;
            ICompiledSubQuery[] subQueries;

            internal CompiledSubQuery(QueryInfo queryInfo, IObjectReaderFactory factory, ReadOnlyCollection parameters, ICompiledSubQuery[] subQueries) { 
                this.queryInfo = queryInfo;
                this.factory = factory; 
                this.parameters = parameters; 
                this.subQueries = subQueries;
            } 

            public IExecuteResult Execute(IProvider provider, object[] parentArgs, object[] userArgs) {
                if (parentArgs == null && !(this.parameters == null || this.parameters.Count == 0)) {
                    throw Error.ArgumentNull("arguments"); 
                }
 
                SqlProvider sqlProvider = provider as SqlProvider; 
                if (sqlProvider == null) {
                    throw Error.ArgumentTypeMismatch("provider"); 
                }

                // construct new copy of query info
                List spis = new List(this.queryInfo.Parameters); 

                // add call arguments 
                for (int i = 0, n = this.parameters.Count; i < n; i++) { 
                    spis.Add(new SqlParameterInfo(this.parameters[i], parentArgs[i]));
                } 

                QueryInfo qi = new QueryInfo(
                    this.queryInfo.Query,
                    this.queryInfo.CommandText, 
                    spis.AsReadOnly(),
                    this.queryInfo.ResultShape, 
                    this.queryInfo.ResultType 
                    );
 
                // execute query
                return sqlProvider.Execute(null, qi, this.factory, parentArgs, userArgs, subQueries, null);
            }
        } 

        class ExecuteResult : IExecuteResult, IDisposable { 
            DbCommand command; 
            ReadOnlyCollection parameters;
            IObjectReaderSession session; 
            int iReturnParameter = -1;
            object value;
            [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "[....]: used in an assert in ReturnValue.set")]
            bool useReturnValue; 
            bool isDisposed;
 
            internal ExecuteResult(DbCommand command, ReadOnlyCollection parameters, IObjectReaderSession session, object value, bool useReturnValue) 
                : this(command, parameters, session) {
                this.value = value; 
                this.useReturnValue = useReturnValue;
                if (this.command != null && this.parameters != null && useReturnValue) {
                    iReturnParameter = GetParameterIndex("@RETURN_VALUE");
                } 
            }
 
            internal ExecuteResult(DbCommand command, ReadOnlyCollection parameters, IObjectReaderSession session) { 
                this.command = command;
                this.parameters = parameters; 
                this.session = session;
            }

            internal ExecuteResult(DbCommand command, ReadOnlyCollection parameters, IObjectReaderSession session, object value) 
                : this(command, parameters, session, value, false) {
            } 
 
            [SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "value", Justification="FxCop Error -- False positive during code analysis")]
            public object ReturnValue { 
                get {
                    if (this.iReturnParameter >= 0) {
                        return this.GetParameterValue(this.iReturnParameter);
                    } 
                    return this.value;
                } 
                internal set { 
                    Debug.Assert(!useReturnValue);
                    this.value = value; 
                }
            }

            private int GetParameterIndex(string paramName) { 
                int idx = -1;
                for (int i = 0, n = this.parameters.Count; i < n; i++) { 
                    if (string.Compare(parameters[i].Parameter.Name, paramName, StringComparison.OrdinalIgnoreCase) == 0) { 
                        idx = i;
                        break; 
                    }
                }
                return idx;
            } 

            internal object GetParameterValue(string paramName) { 
                int idx = GetParameterIndex(paramName); 
                if (idx >= 0) {
                    return GetParameterValue(idx); 
                }
                return null;
            }
 
            public object GetParameterValue(int parameterIndex) {
                if (this.parameters == null || parameterIndex < 0 || parameterIndex > this.parameters.Count) { 
                    throw Error.ArgumentOutOfRange("parameterIndex"); 
                }
 
                // SQL server requires all results to be read before output parameters are visible
                if (this.session != null && !this.session.IsBuffered) {
                    this.session.Buffer();
                } 

                SqlParameterInfo pi = this.parameters[parameterIndex]; 
                object parameterValue = this.command.Parameters[parameterIndex].Value; 
                if (parameterValue == DBNull.Value) parameterValue = null;
                if (parameterValue != null && parameterValue.GetType() != pi.Parameter.ClrType) { 
                    return DBConvert.ChangeType(parameterValue, pi.Parameter.ClrType);
                }

                return parameterValue; 
            }
 
            public void Dispose() { 
                if (!this.isDisposed) {
                    this.isDisposed = true; 
                    if (this.session!=null) {
                        this.session.Dispose();
                    }
                } 
            }
        } 
 
        class SequenceOfOne : IEnumerable, IEnumerable {
            T[] sequence; 
            internal SequenceOfOne(T value) {
                this.sequence = new T[] { value };
            }
            public IEnumerator GetEnumerator() { 
                return ((IEnumerable)this.sequence).GetEnumerator();
            } 
 
            IEnumerator IEnumerable.GetEnumerator() {
                return this.GetEnumerator(); 
            }
        }

        class OneTimeEnumerable : IEnumerable, IEnumerable { 
            IEnumerator enumerator;
 
            internal OneTimeEnumerable(IEnumerator enumerator) { 
                System.Diagnostics.Debug.Assert(enumerator != null);
                this.enumerator = enumerator; 
            }

            public IEnumerator GetEnumerator() {
                if (this.enumerator == null) { 
                    throw Error.CannotEnumerateResultsMoreThanOnce();
                } 
                IEnumerator e = this.enumerator; 
                this.enumerator = null;
                return e; 
            }

            IEnumerator IEnumerable.GetEnumerator() {
                return this.GetEnumerator(); 
            }
        } 
 
        /// 
        /// Result type for single rowset returning stored procedures. 
        /// 
        class SingleResult : ISingleResult, IDisposable, IListSource {
            private IEnumerable enumerable;
            private ExecuteResult executeResult; 
            private DataContext context;
            private IBindingList cachedList; 
 
            internal SingleResult(IEnumerable enumerable, ExecuteResult executeResult, DataContext context) {
                System.Diagnostics.Debug.Assert(enumerable != null); 
                System.Diagnostics.Debug.Assert(executeResult != null);
                this.enumerable = enumerable;
                this.executeResult = executeResult;
                this.context = context; 
            }
 
            public IEnumerator GetEnumerator() { 
                return enumerable.GetEnumerator();
            } 

            IEnumerator IEnumerable.GetEnumerator() {
                return this.GetEnumerator();
            } 

            public object ReturnValue { 
                get { 
                    return executeResult.GetParameterValue("@RETURN_VALUE");
                } 
            }

            public void Dispose() {
                this.executeResult.Dispose(); 
            }
 
            IList IListSource.GetList() { 
                if (this.cachedList == null) {
                    this.cachedList = BindingList.Create(this.context, this); 
                }
                return this.cachedList;
            }
 
            bool IListSource.ContainsListCollection {
                get { return false; } 
            } 
        }
 
        class MultipleResults : IMultipleResults, IDisposable {
            SqlProvider provider;
            MetaFunction function;
            IObjectReaderSession session; 
            bool isDisposed;
            private ExecuteResult executeResult; 
 
            internal MultipleResults(SqlProvider provider, MetaFunction function, IObjectReaderSession session, ExecuteResult executeResult) {
                this.provider = provider; 
                this.function = function;
                this.session = session;
                this.executeResult = executeResult;
            } 

            public IEnumerable GetResult() { 
                MetaType metaType = null; 
                // Check the inheritance hierarchy of each mapped result row type
                // for the function. 
                if (this.function != null) {
                    foreach (MetaType mt in function.ResultRowTypes) {
                        metaType = mt.InheritanceTypes.SingleOrDefault(it => it.Type == typeof(T));
                        if (metaType != null) { 
                            break;
                        } 
                    } 
                }
                if (metaType == null) { 
                    metaType = this.provider.services.Model.GetMetaType(typeof(T));
                }
                IObjectReaderFactory factory = this.provider.GetDefaultFactory(metaType);
                IObjectReader objReader = factory.GetNextResult(this.session, false); 
                if (objReader == null) {
                    this.Dispose(); 
                    return null; 
                }
                return new SingleResult(new OneTimeEnumerable((IEnumerator)objReader), this.executeResult, this.provider.services.Context); 
            }

            public void Dispose() {
                if (!this.isDisposed) { 
                    this.isDisposed = true;
                    if (this.executeResult != null) { 
                        this.executeResult.Dispose(); 
                    }
                    else { 
                        this.session.Dispose();
                    }
                }
            } 

            public object ReturnValue { 
                get { 
                    if (this.executeResult != null) {
                        return executeResult.GetParameterValue("@RETURN_VALUE"); 
                    } else {
                        return null;
                    }
                } 
            }
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
using System; 
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; 
using System.Data;
using System.Data.Common; 
using System.Data.Linq; 
using System.Data.Linq.Mapping;
using System.Data.Linq.Provider; 
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Linq; 
using System.Linq.Expressions;
using System.Reflection; 
using System.Text; 
using System.Globalization;
using System.Diagnostics.CodeAnalysis; 
using Me = System.Data.Linq.SqlClient;

namespace System.Data.Linq.SqlClient {
    public sealed class Sql2000Provider : SqlProvider { 
        public Sql2000Provider()
            : base(ProviderMode.Sql2000) { 
        } 
    }
 
    public sealed class Sql2005Provider : SqlProvider {
        public Sql2005Provider()
            : base(ProviderMode.Sql2005) {
        } 
    }
 
    public sealed class Sql2008Provider : SqlProvider { 
        public Sql2008Provider()
            : base(ProviderMode.Sql2008) { 
        }
    }

    [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification="Unknown reason.")] 
    public class SqlProvider : IReaderProvider, IConnectionUser {
        private IDataServices services; 
        private SqlConnectionManager conManager; 
        private TypeSystemProvider typeProvider;
        private SqlFactory sqlFactory; 
        private Translator translator;
        private IObjectReaderCompiler readerCompiler;
        private bool disposed;
        private int commandTimeout; 

        private TextWriter log; 
        string dbName = string.Empty; 

        // stats and flags 
        private int queryCount;
        private bool checkQueries;
        private OptimizationFlags optimizationFlags = OptimizationFlags.All;
        private bool enableCacheLookup = true; 
        private ProviderMode mode = ProviderMode.NotYetDecided;
        private bool deleted = false; 
 
#if PERFORMANCE_BUILD
        private bool collectPerfInfo; 
        private bool collectPerfInfoInitialized = false;
        private bool collectQueryPerf;

        internal bool CollectPerfInfo { 
            get {
                if (!collectPerfInfoInitialized) { 
                    string s = System.Environment.GetEnvironmentVariable("CollectDLinqPerfInfo"); 
                    collectPerfInfo = (s != null) && (s == "On");
                    collectPerfInfoInitialized = true; 
                }
                return this.collectPerfInfo;
            }
        } 

        internal bool CollectQueryPerf { 
            get { return this.collectQueryPerf; } 
        }
#endif 

        internal enum ProviderMode {
            NotYetDecided,
            Sql2000, 
            Sql2005,
            Sql2008, 
            SqlCE 
        }
 
        const string SqlCeProviderInvariantName = "System.Data.SqlServerCe.3.5";
        const string SqlCeDataReaderTypeName = "System.Data.SqlServerCe.SqlCeDataReader";
        const string SqlCeConnectionTypeName = "System.Data.SqlServerCe.SqlCeConnection";
        const string SqlCeTransactionTypeName = "System.Data.SqlServerCe.SqlCeTransaction"; 

        internal ProviderMode Mode { 
            get { 
                this.CheckDispose();
                this.CheckInitialized(); 
                this.InitializeProviderMode();
                return this.mode;
            }
        } 

        private void InitializeProviderMode() { 
            if (this.mode == ProviderMode.NotYetDecided) { 
                if (this.IsSqlCe) {
                    this.mode = ProviderMode.SqlCE; 
                } else if (this.IsServer2KOrEarlier) {
                    this.mode = ProviderMode.Sql2000;
                }
                else if (this.IsServer2005) { 
                    this.mode = ProviderMode.Sql2005;
                } else { 
                    this.mode = ProviderMode.Sql2008; 
                }
            } 
            if (this.typeProvider == null) {
                switch (this.mode) {
                    case ProviderMode.Sql2000:
                        this.typeProvider = SqlTypeSystem.Create2000Provider(); 
                        break;
                    case ProviderMode.Sql2005: 
                        this.typeProvider = SqlTypeSystem.Create2005Provider(); 
                        break;
                    case ProviderMode.Sql2008: 
                        this.typeProvider = SqlTypeSystem.Create2008Provider();
                        break;
                    case ProviderMode.SqlCE:
                        this.typeProvider = SqlTypeSystem.CreateCEProvider(); 
                        break;
                    default: 
                        System.Diagnostics.Debug.Assert(false); 
                        break;
                } 
            }
            if (this.sqlFactory == null) {
                this.sqlFactory = new SqlFactory(this.typeProvider, this.services.Model);
                this.translator = new Translator(this.services, this.sqlFactory, this.typeProvider); 
            }
        } 
 
        /// 
        /// Return true if the current connection is SQLCE. 
        /// 
        private bool IsSqlCe {
            get {
                DbConnection con = conManager.UseConnection(this); 
                try {
                    if (String.CompareOrdinal(con.GetType().FullName, SqlCeConnectionTypeName) == 0) { 
                        return true; 
                    }
                } finally { 
                    conManager.ReleaseConnection(this);
                }
                return false;
            } 
        }
 
        ///  
        /// Return true if this is a 2K (or earlier) server. This may be a round trip to the server.
        ///  
        private bool IsServer2KOrEarlier {
            get {
                DbConnection con = conManager.UseConnection(this);
                try { 
                    string serverVersion = con.ServerVersion;
                    if (serverVersion.StartsWith("06.00.", StringComparison.Ordinal)) { 
                        return true; 
                    }
                    else if (serverVersion.StartsWith("06.50.", StringComparison.Ordinal)) { 
                        return true;
                    }
                    else if (serverVersion.StartsWith("07.00.", StringComparison.Ordinal)) {
                        return true; 
                    }
                    else if (serverVersion.StartsWith("08.00.", StringComparison.Ordinal)) { 
                        return true; 
                    }
                    return false; 
                }
                finally {
                    conManager.ReleaseConnection(this);
                } 
            }
        } 
 
        /// 
        /// Return true if this is a SQL 2005 server. This may be a round trip to the server. 
        /// 
        private bool IsServer2005 {
            get {
                DbConnection con = conManager.UseConnection(this); 
                try {
                    string serverVersion = con.ServerVersion; 
                    if (serverVersion.StartsWith("09.00.", StringComparison.Ordinal)) { 
                        return true;
                    } 
                    return false;
                }
                finally {
                    conManager.ReleaseConnection(this); 
                }
            } 
        } 

        DbConnection IProvider.Connection { 
            get {
                this.CheckDispose();
                this.CheckInitialized();
                return this.conManager.Connection; 
            }
        } 
 
        TextWriter IProvider.Log {
            get { 
                this.CheckDispose();
                this.CheckInitialized();
                return this.log;
            } 
            set {
                this.CheckDispose(); 
                this.CheckInitialized(); 
                this.log = value;
            } 
        }

        DbTransaction IProvider.Transaction {
            get { 
                this.CheckDispose();
                this.CheckInitialized(); 
                return this.conManager.Transaction; 
            }
            set { 
                this.CheckDispose();
                this.CheckInitialized();
                this.conManager.Transaction = value;
            } 
        }
 
        int IProvider.CommandTimeout { 
            get {
                this.CheckDispose(); 
                return this.commandTimeout;
            }
            set {
                this.CheckDispose(); 
                this.commandTimeout = value;
            } 
        } 

        ///  
        /// Expose a test hook which controls which SQL optimizations are executed.
        /// 
        internal OptimizationFlags OptimizationFlags {
            get { 
                CheckDispose();
                return this.optimizationFlags; 
            } 
            set {
                CheckDispose(); 
                this.optimizationFlags = value;
            }
        }
 
        /// 
        /// Validate queries as they are generated. 
        ///  
        internal bool CheckQueries {
            get { 
                CheckDispose();
                return checkQueries;
            }
            set { 
                CheckDispose();
                checkQueries = value; 
            } 
        }
 
        internal bool EnableCacheLookup {
            get {
                CheckDispose();
                return this.enableCacheLookup; 
            }
            set { 
                CheckDispose(); 
                this.enableCacheLookup = value;
            } 
        }

        internal int QueryCount {
            get { 
                CheckDispose();
                return this.queryCount; 
            } 
        }
 
        internal int MaxUsers {
            get {
                CheckDispose();
                return this.conManager.MaxUsers; 
            }
        } 
 
        IDataServices IReaderProvider.Services {
            get { return this.services; } 
        }

        IConnectionManager IReaderProvider.ConnectionManager {
            get { return this.conManager; } 
        }
 
        public SqlProvider() { 
            this.mode = ProviderMode.NotYetDecided;
        } 

        internal SqlProvider(ProviderMode mode) {
            this.mode = mode;
        } 

        private void CheckInitialized() { 
            if (this.services == null) { 
                throw Error.ContextNotInitialized();
            } 
        }
        private void CheckNotDeleted() {
            if (this.deleted) {
                throw Error.DatabaseDeleteThroughContext(); 
            }
        } 
 
        void IProvider.Initialize(IDataServices dataServices, object connection) {
            if (dataServices == null) { 
                throw Error.ArgumentNull("dataServices");
            }
            this.services = dataServices;
 
            DbConnection con;
            DbTransaction tx = null; 
 
            string fileOrServerOrConnectionString = connection as string;
            if (fileOrServerOrConnectionString != null) { 
                string connectionString = this.GetConnectionString(fileOrServerOrConnectionString);
                this.dbName = this.GetDatabaseName(connectionString);
                if (this.dbName.EndsWith(".sdf", StringComparison.OrdinalIgnoreCase)) {
                    this.mode = ProviderMode.SqlCE; 
                }
                if (this.mode == ProviderMode.SqlCE) { 
                    DbProviderFactory factory = SqlProvider.GetProvider(SqlCeProviderInvariantName); 
                    if (factory == null) {
                        throw Error.ProviderNotInstalled(this.dbName, SqlCeProviderInvariantName); 
                    }
                    con = factory.CreateConnection();
                }
                else { 
                    con = new SqlConnection();
                } 
                con.ConnectionString = connectionString; 
            }
            else { 
                // We only support SqlTransaction and SqlCeTransaction
                tx = connection as SqlTransaction;
                if (tx == null) {
                    // See if it's a SqlCeTransaction 
                    if (connection.GetType().FullName == SqlCeTransactionTypeName) {
                        tx = connection as DbTransaction; 
                    } 
                }
                if (tx != null) { 
                    connection = tx.Connection;
                }
                con = connection as DbConnection;
                if (con == null) { 
                    throw Error.InvalidConnectionArgument("connection");
                } 
                if (con.GetType().FullName == SqlCeConnectionTypeName) { 
                    this.mode = ProviderMode.SqlCE;
                } 
                this.dbName = this.GetDatabaseName(con.ConnectionString);
            }

            // initialize to the default command timeout 
            using (DbCommand c = con.CreateCommand()) {
                this.commandTimeout = c.CommandTimeout; 
            } 

            int maxUsersPerConnection = 1; 
            if (con.ConnectionString.Contains("MultipleActiveResultSets")) {
                DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
                builder.ConnectionString = con.ConnectionString;
                if (string.Compare((string)builder["MultipleActiveResultSets"], "true", StringComparison.OrdinalIgnoreCase) == 0) { 
                    maxUsersPerConnection = 10;
                } 
            } 

            this.conManager = new SqlConnectionManager(this, con, maxUsersPerConnection); 
            if (tx != null) {
                this.conManager.Transaction = tx;
            }
 
#if DEBUG
            SqlNode.Formatter = new SqlFormatter(); 
#endif 

#if ILGEN 
            Type readerType;
            if (this.mode == ProviderMode.SqlCE) {
                readerType = con.GetType().Module.GetType(SqlCeDataReaderTypeName);
            } 
            else if (con is SqlConnection) {
                readerType = typeof(SqlDataReader); 
            } 
            else {
                readerType = typeof(DbDataReader); 
            }
            this.readerCompiler = new ObjectReaderCompiler(readerType, this.services);
#else
            this.readerCompiler = new ObjectReaderBuilder(this, this.services); 
#endif
        } 
 
        private static DbProviderFactory GetProvider(string providerName) {
            bool hasProvider = 
                DbProviderFactories.GetFactoryClasses().Rows.OfType()
                .Select(r => (string)r["InvariantName"])
                .Contains(providerName, StringComparer.OrdinalIgnoreCase);
            if (hasProvider) { 
                return DbProviderFactories.GetFactory(providerName);
            } 
            return null; 
        }
 
        #region Dispose\Finalize
        public void Dispose() {
            this.disposed = true;
            Dispose(true); 
            //GC.SuppressFinalize(this);  We don't have a finalize method
        } 
        // Not implementing finalizer here because there are no unmanaged resources 
        // to release. See http://msdnwiki.microsoft.com/en-us/mtpswiki/12afb1ea-3a17-4a3f-a1f0-fcdb853e2359.aspx
 
        // The bulk of the clean-up code is implemented in Dispose(bool)
        protected virtual void Dispose(bool disposing) {
            // Implemented but empty so that derived contexts can implement
            // a finalizer that potentially cleans up unmanaged resources. 
            if (disposing) {
                this.services = null; 
                if (this.conManager != null) { 
                    this.conManager.DisposeConnection();
                } 
                this.conManager = null;
                this.typeProvider = null;
                this.sqlFactory = null;
                this.translator = null; 
                this.readerCompiler = null;
                this.log = null; 
            } 
        }
 
        internal void CheckDispose() {
            if (this.disposed) {
                throw Error.ProviderCannotBeUsedAfterDispose();
            } 
        }
        #endregion 
 
        private string GetConnectionString(string fileOrServerOrConnectionString) {
            if (fileOrServerOrConnectionString.IndexOf('=') >= 0) { 
                return fileOrServerOrConnectionString;
            }
            else {
                DbConnectionStringBuilder builder = new DbConnectionStringBuilder(); 
                if (fileOrServerOrConnectionString.EndsWith(".mdf", StringComparison.OrdinalIgnoreCase)) {
                    // if just a database file is specified, default to local SqlExpress instance 
                    builder.Add("AttachDBFileName", fileOrServerOrConnectionString); 
                    builder.Add("Server", "localhost\\sqlexpress");
                    builder.Add("Integrated Security", "SSPI"); 
                    builder.Add("User Instance", "true");
                    builder.Add("MultipleActiveResultSets", "true");
                }
                else if (fileOrServerOrConnectionString.EndsWith(".sdf", StringComparison.OrdinalIgnoreCase)) { 
                    // A SqlCE database file has been specified
                    builder.Add("Data Source", fileOrServerOrConnectionString); 
                } 
                else {
                    builder.Add("Server", fileOrServerOrConnectionString); 
                    builder.Add("Database", this.services.Model.DatabaseName);
                    builder.Add("Integrated Security", "SSPI");
                }
                return builder.ToString(); 
            }
        } 
 
        private string GetDatabaseName(string constr) {
            DbConnectionStringBuilder builder = new DbConnectionStringBuilder(); 
            builder.ConnectionString = constr;

            if (builder.ContainsKey("Initial Catalog")) {
                return (string)builder["Initial Catalog"]; 
            }
            else if (builder.ContainsKey("Database")) { 
                return (string)builder["Database"]; 
            }
            else if (builder.ContainsKey("AttachDBFileName")) { 
                return (string)builder["AttachDBFileName"];
            }
            else if (builder.ContainsKey("Data Source")
                && ((string)builder["Data Source"]).EndsWith(".sdf", StringComparison.OrdinalIgnoreCase)) { 
                return (string)builder["Data Source"];
            } 
            else { 
                return this.services.Model.DatabaseName;
            } 
        }

        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
        void IProvider.CreateDatabase() { 
            this.CheckDispose();
            this.CheckInitialized(); 
            // Don't need to call CheckNotDeleted() here since we allow CreateDatabase after DeleteDatabase 
            // Don't need to call InitializeProviderMode() here since we don't need to know the provider to do this.
            string catalog = null; 
            string filename = null;

            DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
            builder.ConnectionString = this.conManager.Connection.ConnectionString; 

            if (this.conManager.Connection.State == ConnectionState.Closed) { 
                if (this.mode == ProviderMode.SqlCE) { 
                    if (!File.Exists(this.dbName)) {
                        Type engineType = this.conManager.Connection.GetType().Module.GetType("System.Data.SqlServerCe.SqlCeEngine"); 
                        object engine = Activator.CreateInstance(engineType, new object[] { builder.ToString() });
                        try {
                            engineType.InvokeMember("CreateDatabase", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, engine, new object[] { }, CultureInfo.InvariantCulture);
                        } 
                        catch (TargetInvocationException tie) {
                            throw tie.InnerException; 
                        } 
                        finally {
                            IDisposable disp = engine as IDisposable; 
                            if (disp != null) {
                                disp.Dispose();
                            }
                        } 
                    }
                    else { 
                        throw Error.CreateDatabaseFailedBecauseSqlCEDatabaseAlreadyExists(this.dbName); 
                    }
                } 
                else {
                    // get connection string w/o reference to new catalog
                    object val;
                    if (builder.TryGetValue("Initial Catalog", out val)) { 
                        catalog = val.ToString();
                        builder.Remove("Initial Catalog"); 
                    } 
                    if (builder.TryGetValue("Database", out val)) {
                        catalog = val.ToString(); 
                        builder.Remove("Database");
                    }
                    if (builder.TryGetValue("AttachDBFileName", out val)) {
                        filename = val.ToString(); 
                        builder.Remove("AttachDBFileName");
                    } 
                } 
                this.conManager.Connection.ConnectionString = builder.ToString();
            } 
            else {
                if (this.mode == ProviderMode.SqlCE) {
                    if (File.Exists(this.dbName)) {
                        throw Error.CreateDatabaseFailedBecauseSqlCEDatabaseAlreadyExists(this.dbName); 
                    }
                } 
                object val; 
                if (builder.TryGetValue("Initial Catalog", out val)) {
                    catalog = val.ToString(); 
                }
                if (builder.TryGetValue("Database", out val)) {
                    catalog = val.ToString();
                } 
                if (builder.TryGetValue("AttachDBFileName", out val)) {
                    filename = val.ToString(); 
                } 
            }
 
            if (String.IsNullOrEmpty(catalog)) {
                if (!String.IsNullOrEmpty(filename)) {
                    catalog = Path.GetFullPath(filename);
                } 
                else if (!String.IsNullOrEmpty(this.dbName)) {
                    catalog = this.dbName; 
                } 
                else {
                    throw Error.CouldNotDetermineCatalogName(); 
                }
            }

            this.conManager.UseConnection(this); 
            this.conManager.AutoClose = false;
 
            try { 
                if (this.services.Model.GetTables().FirstOrDefault() == null) {
                    // we have no tables to create 
                    throw Error.CreateDatabaseFailedBecauseOfContextWithNoTables(this.services.Model.DatabaseName);
                }

                this.deleted = false; 

                // create database 
                if (this.mode == ProviderMode.SqlCE) { 

                    // create tables 
                    foreach (MetaTable table in this.services.Model.GetTables()) {
                        string command = SqlBuilder.GetCreateTableCommand(table);
                        if (!String.IsNullOrEmpty(command)) {
                            this.ExecuteCommand(command); 
                        }
                    } 
                    // create all foreign keys after all tables are defined 
                    foreach (MetaTable table in this.services.Model.GetTables()) {
                        foreach (string command in SqlBuilder.GetCreateForeignKeyCommands(table)) { 
                            if (!String.IsNullOrEmpty(command)) {
                                this.ExecuteCommand(command);
                            }
                        } 
                    }
                } 
                else { 
                    string createdb = SqlBuilder.GetCreateDatabaseCommand(catalog, filename, Path.ChangeExtension(filename, ".ldf"));
                    this.ExecuteCommand(createdb); 
                    this.conManager.Connection.ChangeDatabase(catalog);

                    // create the schemas that our tables will need
                    // cannot be batched together with the rest of the CREATE TABLES 
                    if (this.mode == ProviderMode.Sql2005 || this.mode == ProviderMode.Sql2008) {
                        HashSet schemaCommands = new HashSet(); 
 
                        foreach (MetaTable table in this.services.Model.GetTables()) {
                            string schemaCommand = SqlBuilder.GetCreateSchemaForTableCommand(table); 
                            if (!string.IsNullOrEmpty(schemaCommand)) {
                                schemaCommands.Add(schemaCommand);
                            }
                        } 

                        foreach (string schemaCommand in schemaCommands) { 
                            this.ExecuteCommand(schemaCommand); 
                        }
                    } 

                    StringBuilder sb = new StringBuilder();

                    // create tables 
                    foreach (MetaTable table in this.services.Model.GetTables()) {
                        string createTable = SqlBuilder.GetCreateTableCommand(table); 
                        if (!string.IsNullOrEmpty(createTable)) { 
                            sb.AppendLine(createTable);
                        } 
                    }

                    // create all foreign keys after all tables are defined
                    foreach (MetaTable table in this.services.Model.GetTables()) { 
                        foreach (string createFK in SqlBuilder.GetCreateForeignKeyCommands(table)) {
                            if (!string.IsNullOrEmpty(createFK)) { 
                                sb.AppendLine(createFK); 
                            }
                        } 
                    }

                    if (sb.Length > 0) {
                        // must be on when creating indexes on computed columns 
                        sb.Insert(0, "SET ARITHABORT ON" + Environment.NewLine);
                        this.ExecuteCommand(sb.ToString()); 
                    } 
                }
            } 
            finally {
                this.conManager.ReleaseConnection(this);
                if (this.conManager.Connection is SqlConnection) {
                    SqlConnection.ClearAllPools(); 
                }
            } 
        } 

        void IProvider.DeleteDatabase() { 
            this.CheckDispose();
            this.CheckInitialized();
            // Don't need to call InitializeProviderMode() here since we don't need to know the provider to do this.
            if (this.deleted) { 
                // 2nd delete is no-op.
                return; 
            } 

            if (this.mode == ProviderMode.SqlCE) { 
                ((IProvider)this).ClearConnection();
                System.Diagnostics.Debug.Assert(this.conManager.Connection.State == ConnectionState.Closed);
                File.Delete(this.dbName);
                this.deleted = true; 
            }
            else { 
                string holdConnStr = conManager.Connection.ConnectionString; 
                DbConnection con = this.conManager.UseConnection(this);
                try { 
                    con.ChangeDatabase("MASTER");
                    if (con is SqlConnection) {
                        SqlConnection.ClearAllPools();
                    } 
                    if (this.log != null) {
                        this.log.WriteLine(Strings.LogAttemptingToDeleteDatabase(this.dbName)); 
                    } 
                    this.ExecuteCommand(SqlBuilder.GetDropDatabaseCommand(this.dbName));
                    this.deleted = true; 
                }
                finally {
                    this.conManager.ReleaseConnection(this);
                    if (conManager.Connection.State == ConnectionState.Closed && 
                        string.Compare(conManager.Connection.ConnectionString, holdConnStr, StringComparison.Ordinal) != 0) {
                        // Credential information may have been stripped from the connection 
                        // string as a result of opening the connection. Restore the full 
                        // connection string.
                        conManager.Connection.ConnectionString = holdConnStr; 
                    }
                }
            }
        } 

        // 
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification="[....]: Code needs to return false regarless of exception.")] 
        bool IProvider.DatabaseExists() {
            this.CheckDispose(); 
            this.CheckInitialized();
            if (this.deleted) {
                return false;
            } 
            // Don't need to call InitializeProviderMode() here since we don't need to know the provider to do this.
 
            bool exists = false; 
            if (this.mode == ProviderMode.SqlCE) {
                exists = File.Exists(this.dbName); 
            }
            else {
                string holdConnStr = conManager.Connection.ConnectionString;
                try { 
                    // If no database name is explicitly specified on the connection,
                    // UseConnection will connect to 'Master', which is why after connecting 
                    // we call ChangeDatabase to verify that the database actually exists. 
                    this.conManager.UseConnection(this);
                    this.conManager.Connection.ChangeDatabase(this.dbName); 
                    this.conManager.ReleaseConnection(this);
                    exists = true;
                } catch (Exception) {
                } finally { 
                    if (conManager.Connection.State == ConnectionState.Closed &&
                        string.Compare(conManager.Connection.ConnectionString, holdConnStr, StringComparison.Ordinal) != 0) { 
                        // Credential information may have been stripped from the connection 
                        // string as a result of opening the connection. Restore the full
                        // connection string. 
                        conManager.Connection.ConnectionString = holdConnStr;
                    }
                }
            } 
            return exists;
        } 
 
        void IConnectionUser.CompleteUse() {
        } 

        void IProvider.ClearConnection() {
            this.CheckDispose();
            this.CheckInitialized(); 
            this.conManager.ClearConnection();
        } 
 
        private void ExecuteCommand(string command) {
            if (this.log != null) { 
                this.log.WriteLine(command);
                this.log.WriteLine();
            }
            IDbCommand cmd = this.conManager.Connection.CreateCommand(); 
            cmd.CommandTimeout = this.commandTimeout;
            cmd.Transaction = this.conManager.Transaction; 
            cmd.CommandText = command; 
            cmd.ExecuteNonQuery();
        } 

        ICompiledQuery IProvider.Compile(Expression query) {
            this.CheckDispose();
            this.CheckInitialized(); 
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            } 
            this.InitializeProviderMode();
 
            SqlNodeAnnotations annotations = new SqlNodeAnnotations();
            QueryInfo[] qis = this.BuildQuery(query, annotations);
            CheckSqlCompatibility(qis, annotations);
 
            LambdaExpression lambda = query as LambdaExpression;
            if (lambda != null) { 
                query = lambda.Body; 
            }
 
            IObjectReaderFactory factory = null;
            ICompiledSubQuery[] subQueries = null;
            QueryInfo qi = qis[qis.Length - 1];
            if (qi.ResultShape == ResultShape.Singleton) { 
                subQueries = this.CompileSubQueries(qi.Query);
                factory = this.GetReaderFactory(qi.Query, qi.ResultType); 
            } 
            else if (qi.ResultShape == ResultShape.Sequence) {
                subQueries = this.CompileSubQueries(qi.Query); 
                factory = this.GetReaderFactory(qi.Query, TypeSystem.GetElementType(qi.ResultType));
            }

            return new CompiledQuery(this, query, qis, factory, subQueries); 
        }
 
        private ICompiledSubQuery CompileSubQuery(SqlNode query, Type elementType, ReadOnlyCollection parameters) { 
            query = SqlDuplicator.Copy(query);
            SqlNodeAnnotations annotations = new SqlNodeAnnotations(); 

            QueryInfo[] qis = this.BuildQuery(ResultShape.Sequence, TypeSystem.GetSequenceType(elementType), query, parameters, annotations);
            System.Diagnostics.Debug.Assert(qis.Length == 1);
            QueryInfo qi = qis[0]; 
            ICompiledSubQuery[] subQueries = this.CompileSubQueries(qi.Query);
            IObjectReaderFactory factory = this.GetReaderFactory(qi.Query, elementType); 
 
            CheckSqlCompatibility(qis, annotations);
 
            return new CompiledSubQuery(qi, factory, parameters, subQueries);
        }

        IExecuteResult IProvider.Execute(Expression query) { 
            this.CheckDispose();
            this.CheckInitialized(); 
            this.CheckNotDeleted(); 
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            }
            this.InitializeProviderMode();

#if PERFORMANCE_BUILD 
            PerformanceCounter pcBuildQuery = null, bpcBuildQuery = null, pcExecQuery = null, bpcExecQuery = null,
                   pcSession = null, bpcSession = null; 
            PerfTimer timerAll = null, timer = null; 
            if (this.CollectPerfInfo) {
                string s = System.Environment.GetEnvironmentVariable("EnableDLinqQueryPerf"); 
                collectQueryPerf = (s != null && s == "On");
            }
            if (collectQueryPerf) {
                pcBuildQuery = new PerformanceCounter("DLinq", "BuildQueryElapsedTime", false); 
                bpcBuildQuery = new PerformanceCounter("DLinq", "BuildQueryElapsedTimeBase", false);
                pcExecQuery = new PerformanceCounter("DLinq", "ExecuteQueryElapsedTime", false); 
                bpcExecQuery = new PerformanceCounter("DLinq", "ExecuteQueryElapsedTimeBase", false); 
                pcSession = new PerformanceCounter("DLinq", "SessionExecuteQueryElapsedTime", false);
                bpcSession = new PerformanceCounter("DLinq", "SessionExecuteQueryElapsedTimeBase", false); 
                timerAll = new PerfTimer();
                timer = new PerfTimer();
                timerAll.Start();
            } 
#endif
            query = Funcletizer.Funcletize(query); 
 
            if (this.EnableCacheLookup) {
                IExecuteResult cached = this.GetCachedResult(query); 
                if (cached != null) {
                    return cached;
                }
            } 

#if PERFORMANCE_BUILD 
            if (collectQueryPerf) { 
                timer.Start();
            } 
#endif
            SqlNodeAnnotations annotations = new SqlNodeAnnotations();
            QueryInfo[] qis = this.BuildQuery(query, annotations);
            CheckSqlCompatibility(qis, annotations); 

            LambdaExpression lambda = query as LambdaExpression; 
            if (lambda != null) { 
                query = lambda.Body;
            } 

            IObjectReaderFactory factory = null;
            ICompiledSubQuery[] subQueries = null;
            QueryInfo qi = qis[qis.Length - 1]; 
            if (qi.ResultShape == ResultShape.Singleton) {
                subQueries = this.CompileSubQueries(qi.Query); 
                factory = this.GetReaderFactory(qi.Query, qi.ResultType); 
            }
            else if (qi.ResultShape == ResultShape.Sequence) { 
                subQueries = this.CompileSubQueries(qi.Query);
                factory = this.GetReaderFactory(qi.Query, TypeSystem.GetElementType(qi.ResultType));
            }
 
#if PERFORMANCE_BUILD
                if (collectQueryPerf) { 
                    timer.Stop(); 
                    pcBuildQuery.IncrementBy(timer.Duration);
                    bpcBuildQuery.Increment(); 
                }
#endif

#if PERFORMANCE_BUILD 
            if (collectQueryPerf) {
                timer.Start(); 
            } 

#endif 
            IExecuteResult result = this.ExecuteAll(query, qis, factory, null, subQueries);

#if PERFORMANCE_BUILD
            if (collectQueryPerf) { 
                timer.Stop();
                pcSession.IncrementBy(timer.Duration); 
                bpcSession.Increment(); 
                timerAll.Stop();
                pcExecQuery.IncrementBy(timerAll.Duration); 
                bpcExecQuery.Increment();
            }
#endif
            return result; 
        }
 
        private ICompiledSubQuery[] CompileSubQueries(SqlNode query) { 
            return new SubQueryCompiler(this).Compile(query);
        } 

        class SubQueryCompiler : SqlVisitor {
            SqlProvider provider;
            List subQueries; 

            internal SubQueryCompiler(SqlProvider provider) { 
                this.provider = provider; 
            }
 
            internal ICompiledSubQuery[] Compile(SqlNode node) {
                this.subQueries = new List();
                this.Visit(node);
                return this.subQueries.ToArray(); 
            }
 
            internal override SqlSelect VisitSelect(SqlSelect select) { 
                this.Visit(select.Selection);
                return select; 
            }

            internal override SqlExpression VisitSubSelect(SqlSubSelect ss) {
                return ss; 
            }
 
            internal override SqlExpression VisitClientQuery(SqlClientQuery cq) { 
                Type clientElementType = cq.Query.NodeType == SqlNodeType.Multiset ? TypeSystem.GetElementType(cq.ClrType) : cq.ClrType;
                ICompiledSubQuery c = this.provider.CompileSubQuery(cq.Query.Select, clientElementType, cq.Parameters.AsReadOnly()); 
                cq.Ordinal = this.subQueries.Count;
                this.subQueries.Add(c);
                return cq;
            } 
        }
 
        ///  
        /// Look for compatibility annotations for the set of providers we
        /// add annotations for. 
        /// 
        private void CheckSqlCompatibility(QueryInfo[] queries, SqlNodeAnnotations annotations) {
            if (this.Mode == ProviderMode.Sql2000 ||
                this.Mode == ProviderMode.SqlCE) { 
                for (int i = 0, n = queries.Length; i < n; i++) {
                    SqlServerCompatibilityCheck.ThrowIfUnsupported(queries[i].Query, annotations, this.Mode); 
                } 
            }
        } 

        private IExecuteResult ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, object[] userArguments, ICompiledSubQuery[] subQueries) {
            IExecuteResult result = null;
            object lastResult = null; 
            for (int i = 0, n = queryInfos.Length; i < n; i++) {
                if (i < n - 1) { 
                    result = this.Execute(query, queryInfos[i], null, null, userArguments, subQueries, lastResult); 
                }
                else { 
                    result = this.Execute(query, queryInfos[i], factory, null, userArguments, subQueries, lastResult);
                }
                if (queryInfos[i].ResultShape == ResultShape.Return) {
                    lastResult = result.ReturnValue; 
                }
            } 
            return result; 
        }
 
        private IExecuteResult GetCachedResult(Expression query) {
            object obj = this.services.GetCachedObject(query);
            if (obj != null) {
                switch (this.GetResultShape(query)) { 
                    case ResultShape.Singleton:
                        return new ExecuteResult(null, null, null, obj); 
                    case ResultShape.Sequence: 
                        return new ExecuteResult(null, null, null,
                            Activator.CreateInstance( 
                                typeof(SequenceOfOne<>).MakeGenericType(TypeSystem.GetElementType(this.GetResultType(query))),
                                BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { obj }, null
                                ));
                } 
            }
            return null; 
        } 

        [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification="Unknown reason.")] 
        private IExecuteResult Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, object[] parentArgs, object[] userArgs, ICompiledSubQuery[] subQueries, object lastResult) {
            this.InitializeProviderMode();

            DbConnection con = this.conManager.UseConnection(this); 
            try {
                DbCommand cmd = con.CreateCommand(); 
                cmd.CommandText = queryInfo.CommandText; 
                cmd.Transaction = this.conManager.Transaction;
                cmd.CommandTimeout = this.commandTimeout; 
                AssignParameters(cmd, queryInfo.Parameters, userArgs, lastResult);
                LogCommand(this.log, cmd);
                this.queryCount += 1;
 
                switch (queryInfo.ResultShape) {
                    default: 
                    case ResultShape.Return: { 
                            return new ExecuteResult(cmd, queryInfo.Parameters, null, cmd.ExecuteNonQuery(), true);
                        } 
                    case ResultShape.Singleton: {
                            DbDataReader reader = cmd.ExecuteReader();
                            IObjectReader objReader = factory.Create(reader, true, this, parentArgs, userArgs, subQueries);
                            this.conManager.UseConnection(objReader.Session); 
                            try {
                                IEnumerable sequence = (IEnumerable)Activator.CreateInstance( 
                                    typeof(OneTimeEnumerable<>).MakeGenericType(queryInfo.ResultType), 
                                    BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null,
                                    new object[] { objReader }, null 
                                    );
                                object value = null;
                                MethodCallExpression mce = query as MethodCallExpression;
                                MethodInfo sequenceMethod = null; 
                                if (mce != null && (
                                    mce.Method.DeclaringType == typeof(Queryable) || 
                                    mce.Method.DeclaringType == typeof(Enumerable)) 
                                    ) {
                                    switch (mce.Method.Name) { 
                                        case "First":
                                        case "FirstOrDefault":
                                        case "SingleOrDefault":
                                            sequenceMethod = TypeSystem.FindSequenceMethod(mce.Method.Name, sequence); 
                                            break;
                                        case "Single": 
                                        default: 
                                            sequenceMethod = TypeSystem.FindSequenceMethod("Single", sequence);
                                            break; 
                                    }
                                }
                                else {
                                    sequenceMethod = TypeSystem.FindSequenceMethod("SingleOrDefault", sequence); 
                                }
 
                                // When dynamically invoking the sequence method, we want to 
                                // return the inner exception if the invocation fails
                                if (sequenceMethod != null) { 
                                    try {
                                        value = sequenceMethod.Invoke(null, new object[] { sequence });
                                    }
                                    catch (TargetInvocationException tie) { 
                                        if (tie.InnerException != null) {
                                            throw tie.InnerException; 
                                        } 
                                        throw;
                                    } 
                                }

                                return new ExecuteResult(cmd, queryInfo.Parameters, objReader.Session, value);
                            } 
                            finally {
                                objReader.Dispose(); 
                            } 
                        }
                    case ResultShape.Sequence: { 
                            DbDataReader reader = cmd.ExecuteReader();
                            IObjectReader objReader = factory.Create(reader, true, this, parentArgs, userArgs, subQueries);
                            this.conManager.UseConnection(objReader.Session);
                            IEnumerable sequence = (IEnumerable)Activator.CreateInstance( 
                                typeof(OneTimeEnumerable<>).MakeGenericType(TypeSystem.GetElementType(queryInfo.ResultType)),
                                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, 
                                new object[] { objReader }, null 
                                );
                            if (typeof(IQueryable).IsAssignableFrom(queryInfo.ResultType)) { 
                                sequence = sequence.AsQueryable();
                            }
                            ExecuteResult result = new ExecuteResult(cmd, queryInfo.Parameters, objReader.Session);
                            MetaFunction function = this.GetFunction(query); 
                            if (function != null && !function.IsComposable) {
                                sequence = (IEnumerable)Activator.CreateInstance( 
                                typeof(SingleResult<>).MakeGenericType(TypeSystem.GetElementType(queryInfo.ResultType)), 
                                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null,
                                new object[] { sequence, result, this.services.Context }, null 
                                );
                            }
                            result.ReturnValue = sequence;
                            return result; 
                        }
                    case ResultShape.MultipleResults: { 
                            DbDataReader reader = cmd.ExecuteReader(); 
                            IObjectReaderSession session = this.readerCompiler.CreateSession(reader, this, parentArgs, userArgs, subQueries);
                            this.conManager.UseConnection(session); 
                            MetaFunction function = this.GetFunction(query);
                            ExecuteResult result = new ExecuteResult(cmd, queryInfo.Parameters, session);
                            result.ReturnValue = new MultipleResults(this, function, session, result);
                            return result; 
                        }
                } 
            } 
            finally {
                this.conManager.ReleaseConnection(this); 
            }
        }

        private MetaFunction GetFunction(Expression query) { 
            LambdaExpression lambda = query as LambdaExpression;
            if (lambda != null) { 
                query = lambda.Body; 
            }
            MethodCallExpression mc = query as MethodCallExpression; 
            if (mc != null && typeof(DataContext).IsAssignableFrom(mc.Method.DeclaringType)) {
                return this.services.Model.GetFunction(mc.Method);
            }
            return null; 
        }
 
        private void LogCommand(TextWriter writer, DbCommand cmd) { 
            if (writer != null) {
                writer.WriteLine(cmd.CommandText); 
                foreach (DbParameter p in cmd.Parameters) {
                    int prec = 0;
                    int scale = 0;
                    PropertyInfo piPrecision = p.GetType().GetProperty("Precision"); 
                    if (piPrecision != null) {
                        prec = (int)Convert.ChangeType(piPrecision.GetValue(p, null), typeof(int), CultureInfo.InvariantCulture); 
                    } 
                    PropertyInfo piScale = p.GetType().GetProperty("Scale");
                    if (piScale != null) { 
                        scale = (int)Convert.ChangeType(piScale.GetValue(p, null), typeof(int), CultureInfo.InvariantCulture);
                    }
                    var sp = p as System.Data.SqlClient.SqlParameter;
                    writer.WriteLine("-- {0}: {1} {2} (Size = {3}; Prec = {4}; Scale = {5}) [{6}]", 
                        p.ParameterName,
                        p.Direction, 
                        sp == null ? p.DbType.ToString() : sp.SqlDbType.ToString(), 
                        p.Size.ToString(System.Globalization.CultureInfo.CurrentCulture),
                        prec, 
                        scale,
                        sp == null ? p.Value : sp.SqlValue);
                }
                writer.WriteLine("-- Context: {0}({1}) Model: {2} Build: {3}", this.GetType().Name, this.Mode, this.services.Model.GetType().Name, ThisAssembly.InformationalVersion); 
                writer.WriteLine();
            } 
        } 

        private void AssignParameters(DbCommand cmd, ReadOnlyCollection parms, object[] userArguments, object lastResult) { 
            if (parms != null) {
                foreach (SqlParameterInfo pi in parms) {
                    DbParameter p = cmd.CreateParameter();
                    p.ParameterName = pi.Parameter.Name; 
                    p.Direction = pi.Parameter.Direction;
                    if (pi.Parameter.Direction == ParameterDirection.Input || 
                        pi.Parameter.Direction == ParameterDirection.InputOutput) { 
                        object value = pi.Value;
                        switch (pi.Type) { 
                            case SqlParameterType.UserArgument:
                                try {
                                    value = pi.Accessor.DynamicInvoke(new object[] { userArguments });
                                } catch (System.Reflection.TargetInvocationException e) { 
                                    throw e.InnerException;
                                } 
                                break; 
                            case SqlParameterType.PreviousResult:
                                value = lastResult; 
                                break;
                        }
                        this.typeProvider.InitializeParameter(pi.Parameter.SqlType, p, value);
                    } 
                    else {
                        this.typeProvider.InitializeParameter(pi.Parameter.SqlType, p, null); 
                    } 
                    cmd.Parameters.Add(p);
                } 
            }
        }

        IEnumerable IProvider.Translate(Type elementType, DbDataReader reader) { 
            this.CheckDispose();
            this.CheckInitialized(); 
            this.InitializeProviderMode(); 
            if (elementType == null) {
                throw Error.ArgumentNull("elementType"); 
            }
            if (reader == null) {
                throw Error.ArgumentNull("reader");
            } 
            MetaType rowType = services.Model.GetMetaType(elementType);
            IObjectReaderFactory factory = this.GetDefaultFactory(rowType); 
            IEnumerator e = factory.Create(reader, true, this, null, null, null); 
            Type enumerableType = typeof(OneTimeEnumerable<>).MakeGenericType(elementType);
            return (IEnumerable)Activator.CreateInstance(enumerableType, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { e }, null); 
        }

        IMultipleResults IProvider.Translate(DbDataReader reader) {
            this.CheckDispose(); 
            this.CheckInitialized();
            this.InitializeProviderMode(); 
            if (reader == null) { 
                throw Error.ArgumentNull("reader");
            } 
            IObjectReaderSession session = this.readerCompiler.CreateSession(reader, this, null, null, null);
            return new MultipleResults(this, null, session, null);
        }
 
         string IProvider.GetQueryText(Expression query) {
            this.CheckDispose(); 
            this.CheckInitialized(); 
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            }
            this.InitializeProviderMode();
            SqlNodeAnnotations annotations = new SqlNodeAnnotations();
            QueryInfo[] qis = this.BuildQuery(query, annotations); 

            StringBuilder sb = new StringBuilder(); 
            for (int i = 0, n = qis.Length; i < n; i++) { 
                QueryInfo qi = qis[i];
#if DEBUG 
                StringWriter writer = new StringWriter(System.Globalization.CultureInfo.InvariantCulture);
                DbCommand cmd = this.conManager.Connection.CreateCommand();
                cmd.CommandText = qi.CommandText;
                AssignParameters(cmd, qi.Parameters, null, null); 
                LogCommand(writer, cmd);
                sb.Append(writer.ToString()); 
#else 
                sb.Append(qi.CommandText);
                sb.AppendLine(); 
#endif
            }
            return sb.ToString();
        } 

        DbCommand IProvider.GetCommand(Expression query) { 
            this.CheckDispose(); 
            this.CheckInitialized();
            if (query == null) { 
                throw Error.ArgumentNull("query");
            }
            this.InitializeProviderMode();
            SqlNodeAnnotations annotations = new SqlNodeAnnotations(); 
            QueryInfo[] qis = this.BuildQuery(query, annotations);
            QueryInfo qi = qis[qis.Length - 1]; 
            DbCommand cmd = this.conManager.Connection.CreateCommand(); 
            cmd.CommandText = qi.CommandText;
            cmd.Transaction = (SqlTransaction) this.conManager.Transaction; 
            cmd.CommandTimeout = this.commandTimeout;
            AssignParameters(cmd, qi.Parameters, null, null);
            return cmd;
        } 

        internal class QueryInfo { 
            SqlNode query; 
            string commandText;
            ReadOnlyCollection parameters; 
            ResultShape resultShape;
            Type resultType;

            internal QueryInfo(SqlNode query, string commandText, ReadOnlyCollection parameters, ResultShape resultShape, Type resultType) { 
                this.query = query;
                this.commandText = commandText; 
                this.parameters = parameters; 
                this.resultShape = resultShape;
                this.resultType = resultType; 
            }
            internal SqlNode Query {
                get { return this.query; }
            } 
            internal string CommandText {
                get { return this.commandText; } 
            } 
            internal ReadOnlyCollection Parameters {
                get { return this.parameters; } 
            }
            internal ResultShape ResultShape {
                get { return this.resultShape; }
            } 
            internal Type ResultType {
                get { return this.resultType; } 
            } 
        }
 
        internal enum ResultShape {
            Return,
            Singleton,
            Sequence, 
            MultipleResults
        } 
 
        private ResultShape GetResultShape(Expression query) {
            LambdaExpression lambda = query as LambdaExpression; 
            if (lambda != null) {
                query = lambda.Body;
            }
 
            if (query.Type == typeof(void)) {
                return ResultShape.Return; 
            } 
            else if (query.Type == typeof(IMultipleResults)) {
                return ResultShape.MultipleResults; 
            }

            bool isSequence = typeof(IEnumerable).IsAssignableFrom(query.Type);
            ProviderType pt = this.typeProvider.From(query.Type); 
            bool isScalar = !pt.IsRuntimeOnlyType && !pt.IsApplicationType;
            bool isSingleton = isScalar || !isSequence; 
 
            MethodCallExpression mce = query as MethodCallExpression;
            if (mce != null) { 
                // query operators
                if (mce.Method.DeclaringType == typeof(Queryable) ||
                    mce.Method.DeclaringType == typeof(Enumerable)) {
                    switch (mce.Method.Name) { 
                        // methods known to produce singletons
                        case "First": 
                        case "FirstOrDefault": 
                        case "Single":
                        case "SingleOrDefault": 
                            isSingleton = true;
                            break;
                    }
                } 
                else if (mce.Method.DeclaringType == typeof(DataContext)) {
                    if (mce.Method.Name == "ExecuteCommand") { 
                        return ResultShape.Return; 
                    }
                } 
                else if (mce.Method.DeclaringType.IsSubclassOf(typeof(DataContext))) {
                    MetaFunction f = this.GetFunction(query);
                    if (f != null) {
                        if (!f.IsComposable) { 
                            isSingleton = false;
                        } 
                        else if (isScalar) { 
                            isSingleton = true;
                        } 
                    }
                }
                else if (mce.Method.DeclaringType == typeof(DataManipulation) && mce.Method.ReturnType == typeof(int)) {
                    return ResultShape.Return; 
                }
            } 
 
            if (isSingleton) {
                return ResultShape.Singleton; 
            }
            else if (isScalar) {
                return ResultShape.Return;
            } 
            else {
                return ResultShape.Sequence; 
            } 
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")]
        private Type GetResultType(Expression query) {
            LambdaExpression lambda = query as LambdaExpression;
            if (lambda != null) { 
                query = lambda.Body;
            } 
            return query.Type; 
        }
 
        internal QueryInfo[] BuildQuery(Expression query, SqlNodeAnnotations annotations) {
            this.CheckDispose();

            // apply maximal funcletization 
            query = Funcletizer.Funcletize(query);
 
            // convert query nodes into sql nodes 
            QueryConverter converter = new QueryConverter(this.services, this.typeProvider, this.translator, this.sqlFactory);
            switch (this.Mode) { 
                case ProviderMode.Sql2000:
                    converter.ConverterStrategy =
                        ConverterStrategy.CanUseScopeIdentity |
                        ConverterStrategy.CanUseJoinOn | 
                        ConverterStrategy.CanUseRowStatus;
                    break; 
                case ProviderMode.Sql2005: 
                case ProviderMode.Sql2008:
                    converter.ConverterStrategy = 
                        ConverterStrategy.CanUseScopeIdentity |
                        ConverterStrategy.SkipWithRowNumber |
                        ConverterStrategy.CanUseRowStatus |
                        ConverterStrategy.CanUseJoinOn | 
                        ConverterStrategy.CanUseOuterApply |
                        ConverterStrategy.CanOutputFromInsert; 
                    break; 
                case ProviderMode.SqlCE:
                    converter.ConverterStrategy = ConverterStrategy.CanUseOuterApply; 
                    // Can't set ConverterStrategy.CanUseJoinOn because scalar subqueries in the ON clause
                    // can't be converted into anything.
                    break;
            } 
            SqlNode node = converter.ConvertOuter(query);
 
            return this.BuildQuery(this.GetResultShape(query), this.GetResultType(query), node, null, annotations); 
        }
 
        private bool CanBeColumn(SqlExpression expression) {
            if (expression.SqlType.CanBeColumn) {
                switch (expression.NodeType) {
                    case SqlNodeType.MethodCall: 
                    case SqlNodeType.Member:
                    case SqlNodeType.New: 
                        return PostBindDotNetConverter.CanConvert(expression); 
                    default:
                        return true; 
                }
            }
            return false;
        } 

        [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
        private QueryInfo[] BuildQuery(ResultShape resultShape, Type resultType, SqlNode node, ReadOnlyCollection parentParameters, SqlNodeAnnotations annotations) { 
            System.Diagnostics.Debug.Assert(resultType != null);
            System.Diagnostics.Debug.Assert(node != null); 

            SqlSupersetValidator validator = new SqlSupersetValidator();

            // These are the rules that apply to every SQL tree. 
            if (this.checkQueries) {
                validator.AddValidator(new ColumnTypeValidator()); /* Column CLR Type must agree with its Expressions CLR Type */ 
                validator.AddValidator(new LiteralValidator()); /* Constrain literal Types */ 
            }
 
            validator.Validate(node);

            SqlColumnizer columnizer = new SqlColumnizer(this.CanBeColumn);
 
            // resolve member references
            SqlBinder binder = new SqlBinder(this.translator, this.sqlFactory, this.services.Model, this.services.Context.LoadOptions, columnizer); 
            binder.OptimizeLinkExpansions = (optimizationFlags & OptimizationFlags.OptimizeLinkExpansions) != 0; 
            binder.SimplifyCaseStatements = (optimizationFlags & OptimizationFlags.SimplifyCaseStatements) != 0;
            binder.PreBinder = delegate(SqlNode n) { 
                // convert methods into known reversable operators
                return PreBindDotNetConverter.Convert(n, this.sqlFactory, this.services.Model);
            };
            node = binder.Bind(node); 
            if (this.checkQueries) {
                validator.AddValidator(new ExpectNoAliasRefs()); 
                validator.AddValidator(new ExpectNoSharedExpressions()); 
            }
            validator.Validate(node); 

            node = PostBindDotNetConverter.Convert(node, this.sqlFactory, this.Mode);

            // identify true flow of sql data types 
            SqlRetyper retyper = new SqlRetyper(this.typeProvider, this.services.Model);
            node = retyper.Retype(node); 
            validator.Validate(node); 

            // change CONVERT to special conversions like UNICODE,CHAR,... 
            SqlTypeConverter converter = new SqlTypeConverter(this.sqlFactory);
            node = converter.Visit(node);
            validator.Validate(node);
 
            // transform type-sensitive methods such as LEN (to DATALENGTH), ...
            SqlMethodTransformer methodTransformer = new SqlMethodTransformer(this.sqlFactory); 
            node = methodTransformer.Visit(node); 
            validator.Validate(node);
 
            // convert multisets into separate queries
            SqlMultiplexer.Options options = (this.Mode == ProviderMode.Sql2008 ||
                                              this.Mode == ProviderMode.Sql2005 ||
                                              this.Mode == ProviderMode.SqlCE) 
                ? SqlMultiplexer.Options.EnableBigJoin : SqlMultiplexer.Options.None;
            SqlMultiplexer mux = new SqlMultiplexer(options, parentParameters, this.sqlFactory); 
            node = mux.Multiplex(node); 
            validator.Validate(node);
 
            // convert object construction expressions into flat row projections
            SqlFlattener flattener = new SqlFlattener(this.sqlFactory, columnizer);
            node = flattener.Flatten(node);
            validator.Validate(node); 

            if (this.mode == ProviderMode.SqlCE) { 
                SqlRewriteScalarSubqueries rss = new SqlRewriteScalarSubqueries(this.sqlFactory); 
                node = rss.Rewrite(node);
            } 

            // Simplify case statements where all alternatives map to the same thing.
            // Doing this before deflator because the simplified results may lead to
            // more deflation opportunities. 
            // Doing this before booleanizer because it may convert CASE statements (non-predicates) into
            // predicate expressions. 
            // Doing this before reorderer because it may reduce some orders to constant nodes which should not 
            // be passed onto ROW_NUMBER.
            node = SqlCaseSimplifier.Simplify(node, this.sqlFactory); 

            // Rewrite order-by clauses so that they only occur at the top-most select
            // or in selects with TOP
            SqlReorderer reorderer = new SqlReorderer(this.typeProvider, this.sqlFactory); 
            node = reorderer.Reorder(node);
            validator.Validate(node); 
 
            // Inject code to turn predicates into bits, and bits into predicates where necessary
            node = SqlBooleanizer.Rationalize(node, this.typeProvider, this.services.Model); 
            if (this.checkQueries) {
                validator.AddValidator(new ExpectRationalizedBooleans()); /* From now on all boolean expressions should remain rationalized. */
            }
            validator.Validate(node); 

            if (this.checkQueries) { 
                validator.AddValidator(new ExpectNoFloatingColumns()); 
            }
 
            // turning predicates into bits/ints can change Sql types, propagate changes
            node = retyper.Retype(node);
            validator.Validate(node);
 
            // assign aliases to columns
            // we need to do this now so that the sql2k lifters will work 
            SqlAliaser aliaser = new SqlAliaser(); 
            node = aliaser.AssociateColumnsWithAliases(node);
            validator.Validate(node); 

            // SQL2K enablers.
            node = SqlLiftWhereClauses.Lift(node, this.typeProvider, this.services.Model);
            node = SqlLiftIndependentRowExpressions.Lift(node); 
            node = SqlOuterApplyReducer.Reduce(node, this.sqlFactory, annotations);
            node = SqlTopReducer.Reduce(node, annotations, this.sqlFactory); 
 
            // resolve references to columns in other scopes by adding them
            // to the intermediate selects 
            SqlResolver resolver = new SqlResolver();
            node = resolver.Resolve(node);
            validator.Validate(node);
 
            // re-assign aliases after resolving (new columns may have been added)
            node = aliaser.AssociateColumnsWithAliases(node); 
            validator.Validate(node); 

            // fixup union projections 
            node = SqlUnionizer.Unionize(node);

            // remove order-by of literals
            node = SqlRemoveConstantOrderBy.Remove(node); 

            // throw out unused columns and redundant sub-queries... 
            SqlDeflator deflator = new SqlDeflator(); 
            node = deflator.Deflate(node);
            validator.Validate(node); 

            // Positioning after deflator because it may remove unnecessary columns
            // from SELECT projection lists and allow more CROSS APPLYs to be reduced
            // to CROSS JOINs. 
            node = SqlCrossApplyToCrossJoin.Reduce(node, annotations);
 
            // fixup names for aliases, columns, locals, etc.. 
            SqlNamer namer = new SqlNamer();
            node = namer.AssignNames(node); 
            validator.Validate(node);

            // Convert [N]Text,Image to [N]VarChar(MAX),VarBinary(MAX) where necessary.
            // These new types do not exist on SQL2k, so add annotations. 
            LongTypeConverter longTypeConverter = new LongTypeConverter(this.sqlFactory);
            node = longTypeConverter.AddConversions(node, annotations); 
 
            // final validation
            validator.AddValidator(new ExpectNoMethodCalls()); 
            validator.AddValidator(new ValidateNoInvalidComparison());
            validator.Validate(node);

            SqlParameterizer parameterizer = new SqlParameterizer(this.typeProvider, annotations); 
            SqlFormatter formatter = new SqlFormatter();
            if (this.mode == ProviderMode.SqlCE || 
                this.mode == ProviderMode.Sql2005 || 
                this.mode == ProviderMode.Sql2008) {
                formatter.ParenthesizeTop = true; 
            }

            SqlBlock block = node as SqlBlock;
            if (block != null && this.mode == ProviderMode.SqlCE) { 
                // SQLCE cannot batch multiple statements.
                ReadOnlyCollection> parameters = parameterizer.ParameterizeBlock(block); 
                string[] commands = formatter.FormatBlock(block, false); 
                QueryInfo[] queries = new QueryInfo[commands.Length];
                for (int i = 0, n = commands.Length; i < n; i++) { 
                    queries[i] = new QueryInfo(
                        block.Statements[i],
                        commands[i],
                        parameters[i], 
                        (i < n - 1) ? ResultShape.Return : resultShape,
                        (i < n - 1) ? typeof(int) : resultType 
                        ); 
                }
                return queries; 
            }
            else {
                // build only one result
                ReadOnlyCollection parameters = parameterizer.Parameterize(node); 
                string commandText = formatter.Format(node);
                return new QueryInfo[] { 
                    new QueryInfo(node, commandText, parameters, resultShape, resultType) 
                    };
            } 
        }

        private SqlSelect GetFinalSelect(SqlNode node) {
            switch (node.NodeType) { 
                case SqlNodeType.Select:
                    return (SqlSelect)node; 
                case SqlNodeType.Block: { 
                        SqlBlock b = (SqlBlock)node;
                        return GetFinalSelect(b.Statements[b.Statements.Count - 1]); 
                    }
            }
            return null;
        } 

        private IObjectReaderFactory GetReaderFactory(SqlNode node, Type elemType) { 
            SqlSelect sel = node as SqlSelect; 
            SqlExpression projection = null;
            if (sel == null && node.NodeType == SqlNodeType.Block) { 
                sel = this.GetFinalSelect(node);
            }
            if (sel != null) {
                projection = sel.Selection; 
            }
            else { 
                SqlUserQuery suq = node as SqlUserQuery; 
                if (suq != null && suq.Projection != null) {
                    projection = suq.Projection; 
                }
            }
            IObjectReaderFactory factory;
            if (projection != null) { 
                factory = this.readerCompiler.Compile(projection, elemType);
            } 
            else { 
                return this.GetDefaultFactory(services.Model.GetMetaType(elemType));
            } 
            return factory;
        }

        private IObjectReaderFactory GetDefaultFactory(MetaType rowType) { 
            if (rowType == null) {
                throw Error.ArgumentNull("rowType"); 
            } 
            SqlNodeAnnotations annotations = new SqlNodeAnnotations();
            Expression tmp = Expression.Constant(null); 
            SqlUserQuery suq = new SqlUserQuery(string.Empty, null, null, tmp);
            if (TypeSystem.IsSimpleType(rowType.Type)) {
                // if the element type is a simple type (int, bool, etc.) we create
                // a single column binding 
                SqlUserColumn col = new SqlUserColumn(rowType.Type, typeProvider.From(rowType.Type), suq, "", false, suq.SourceExpression);
                suq.Columns.Add(col); 
                suq.Projection = col; 
            }
            else { 
                // ... otherwise we generate a default projection
                SqlUserRow rowExp = new SqlUserRow(rowType.InheritanceRoot, this.typeProvider.GetApplicationType((int)ConverterSpecialTypes.Row), suq, tmp);
                suq.Projection = this.translator.BuildProjection(rowExp, rowType, true, null, tmp);
            } 
            Type resultType = TypeSystem.GetSequenceType(rowType.Type);
            QueryInfo[] qis = this.BuildQuery(ResultShape.Sequence, resultType, suq, null, annotations); 
            return this.GetReaderFactory(qis[qis.Length - 1].Query, rowType.Type); 
        }
 
        class CompiledQuery : ICompiledQuery {
            DataLoadOptions originalShape;
            Expression query;
            QueryInfo[] queryInfos; 
            IObjectReaderFactory factory;
            ICompiledSubQuery[] subQueries; 
 
            internal CompiledQuery(SqlProvider provider, Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, ICompiledSubQuery[] subQueries) {
                this.originalShape = provider.services.Context.LoadOptions; 
                this.query = query;
                this.queryInfos = queryInfos;
                this.factory = factory;
                this.subQueries = subQueries; 
            }
 
            public IExecuteResult Execute(IProvider provider, object[] arguments) { 
                if (provider == null) {
                    throw Error.ArgumentNull("provider"); 
                }

                SqlProvider sqlProvider = provider as SqlProvider;
                if (sqlProvider == null) { 
                    throw Error.ArgumentTypeMismatch("provider");
                } 
 
                // verify shape is compatibile with original.
                if (!AreEquivalentShapes(this.originalShape, sqlProvider.services.Context.LoadOptions)) { 
                    throw Error.CompiledQueryAgainstMultipleShapesNotSupported();
                }

                // execute query (only last query produces results) 
                return sqlProvider.ExecuteAll(this.query, this.queryInfos, this.factory, arguments, subQueries);
            } 
 
            private static bool AreEquivalentShapes(DataLoadOptions shape1, DataLoadOptions shape2) {
                if (shape1 == shape2) { 
                    return true;
                }
                else if (shape1 == null) {
                    return shape2.IsEmpty; 
                }
                else if (shape2 == null) { 
                    return shape1.IsEmpty; 
                }
                else if (shape1.IsEmpty && shape2.IsEmpty) { 
                    return true;
                }
                return false;
            } 
        }
 
        class CompiledSubQuery : ICompiledSubQuery { 
            QueryInfo queryInfo;
            IObjectReaderFactory factory; 
            ReadOnlyCollection parameters;
            ICompiledSubQuery[] subQueries;

            internal CompiledSubQuery(QueryInfo queryInfo, IObjectReaderFactory factory, ReadOnlyCollection parameters, ICompiledSubQuery[] subQueries) { 
                this.queryInfo = queryInfo;
                this.factory = factory; 
                this.parameters = parameters; 
                this.subQueries = subQueries;
            } 

            public IExecuteResult Execute(IProvider provider, object[] parentArgs, object[] userArgs) {
                if (parentArgs == null && !(this.parameters == null || this.parameters.Count == 0)) {
                    throw Error.ArgumentNull("arguments"); 
                }
 
                SqlProvider sqlProvider = provider as SqlProvider; 
                if (sqlProvider == null) {
                    throw Error.ArgumentTypeMismatch("provider"); 
                }

                // construct new copy of query info
                List spis = new List(this.queryInfo.Parameters); 

                // add call arguments 
                for (int i = 0, n = this.parameters.Count; i < n; i++) { 
                    spis.Add(new SqlParameterInfo(this.parameters[i], parentArgs[i]));
                } 

                QueryInfo qi = new QueryInfo(
                    this.queryInfo.Query,
                    this.queryInfo.CommandText, 
                    spis.AsReadOnly(),
                    this.queryInfo.ResultShape, 
                    this.queryInfo.ResultType 
                    );
 
                // execute query
                return sqlProvider.Execute(null, qi, this.factory, parentArgs, userArgs, subQueries, null);
            }
        } 

        class ExecuteResult : IExecuteResult, IDisposable { 
            DbCommand command; 
            ReadOnlyCollection parameters;
            IObjectReaderSession session; 
            int iReturnParameter = -1;
            object value;
            [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "[....]: used in an assert in ReturnValue.set")]
            bool useReturnValue; 
            bool isDisposed;
 
            internal ExecuteResult(DbCommand command, ReadOnlyCollection parameters, IObjectReaderSession session, object value, bool useReturnValue) 
                : this(command, parameters, session) {
                this.value = value; 
                this.useReturnValue = useReturnValue;
                if (this.command != null && this.parameters != null && useReturnValue) {
                    iReturnParameter = GetParameterIndex("@RETURN_VALUE");
                } 
            }
 
            internal ExecuteResult(DbCommand command, ReadOnlyCollection parameters, IObjectReaderSession session) { 
                this.command = command;
                this.parameters = parameters; 
                this.session = session;
            }

            internal ExecuteResult(DbCommand command, ReadOnlyCollection parameters, IObjectReaderSession session, object value) 
                : this(command, parameters, session, value, false) {
            } 
 
            [SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "value", Justification="FxCop Error -- False positive during code analysis")]
            public object ReturnValue { 
                get {
                    if (this.iReturnParameter >= 0) {
                        return this.GetParameterValue(this.iReturnParameter);
                    } 
                    return this.value;
                } 
                internal set { 
                    Debug.Assert(!useReturnValue);
                    this.value = value; 
                }
            }

            private int GetParameterIndex(string paramName) { 
                int idx = -1;
                for (int i = 0, n = this.parameters.Count; i < n; i++) { 
                    if (string.Compare(parameters[i].Parameter.Name, paramName, StringComparison.OrdinalIgnoreCase) == 0) { 
                        idx = i;
                        break; 
                    }
                }
                return idx;
            } 

            internal object GetParameterValue(string paramName) { 
                int idx = GetParameterIndex(paramName); 
                if (idx >= 0) {
                    return GetParameterValue(idx); 
                }
                return null;
            }
 
            public object GetParameterValue(int parameterIndex) {
                if (this.parameters == null || parameterIndex < 0 || parameterIndex > this.parameters.Count) { 
                    throw Error.ArgumentOutOfRange("parameterIndex"); 
                }
 
                // SQL server requires all results to be read before output parameters are visible
                if (this.session != null && !this.session.IsBuffered) {
                    this.session.Buffer();
                } 

                SqlParameterInfo pi = this.parameters[parameterIndex]; 
                object parameterValue = this.command.Parameters[parameterIndex].Value; 
                if (parameterValue == DBNull.Value) parameterValue = null;
                if (parameterValue != null && parameterValue.GetType() != pi.Parameter.ClrType) { 
                    return DBConvert.ChangeType(parameterValue, pi.Parameter.ClrType);
                }

                return parameterValue; 
            }
 
            public void Dispose() { 
                if (!this.isDisposed) {
                    this.isDisposed = true; 
                    if (this.session!=null) {
                        this.session.Dispose();
                    }
                } 
            }
        } 
 
        class SequenceOfOne : IEnumerable, IEnumerable {
            T[] sequence; 
            internal SequenceOfOne(T value) {
                this.sequence = new T[] { value };
            }
            public IEnumerator GetEnumerator() { 
                return ((IEnumerable)this.sequence).GetEnumerator();
            } 
 
            IEnumerator IEnumerable.GetEnumerator() {
                return this.GetEnumerator(); 
            }
        }

        class OneTimeEnumerable : IEnumerable, IEnumerable { 
            IEnumerator enumerator;
 
            internal OneTimeEnumerable(IEnumerator enumerator) { 
                System.Diagnostics.Debug.Assert(enumerator != null);
                this.enumerator = enumerator; 
            }

            public IEnumerator GetEnumerator() {
                if (this.enumerator == null) { 
                    throw Error.CannotEnumerateResultsMoreThanOnce();
                } 
                IEnumerator e = this.enumerator; 
                this.enumerator = null;
                return e; 
            }

            IEnumerator IEnumerable.GetEnumerator() {
                return this.GetEnumerator(); 
            }
        } 
 
        /// 
        /// Result type for single rowset returning stored procedures. 
        /// 
        class SingleResult : ISingleResult, IDisposable, IListSource {
            private IEnumerable enumerable;
            private ExecuteResult executeResult; 
            private DataContext context;
            private IBindingList cachedList; 
 
            internal SingleResult(IEnumerable enumerable, ExecuteResult executeResult, DataContext context) {
                System.Diagnostics.Debug.Assert(enumerable != null); 
                System.Diagnostics.Debug.Assert(executeResult != null);
                this.enumerable = enumerable;
                this.executeResult = executeResult;
                this.context = context; 
            }
 
            public IEnumerator GetEnumerator() { 
                return enumerable.GetEnumerator();
            } 

            IEnumerator IEnumerable.GetEnumerator() {
                return this.GetEnumerator();
            } 

            public object ReturnValue { 
                get { 
                    return executeResult.GetParameterValue("@RETURN_VALUE");
                } 
            }

            public void Dispose() {
                this.executeResult.Dispose(); 
            }
 
            IList IListSource.GetList() { 
                if (this.cachedList == null) {
                    this.cachedList = BindingList.Create(this.context, this); 
                }
                return this.cachedList;
            }
 
            bool IListSource.ContainsListCollection {
                get { return false; } 
            } 
        }
 
        class MultipleResults : IMultipleResults, IDisposable {
            SqlProvider provider;
            MetaFunction function;
            IObjectReaderSession session; 
            bool isDisposed;
            private ExecuteResult executeResult; 
 
            internal MultipleResults(SqlProvider provider, MetaFunction function, IObjectReaderSession session, ExecuteResult executeResult) {
                this.provider = provider; 
                this.function = function;
                this.session = session;
                this.executeResult = executeResult;
            } 

            public IEnumerable GetResult() { 
                MetaType metaType = null; 
                // Check the inheritance hierarchy of each mapped result row type
                // for the function. 
                if (this.function != null) {
                    foreach (MetaType mt in function.ResultRowTypes) {
                        metaType = mt.InheritanceTypes.SingleOrDefault(it => it.Type == typeof(T));
                        if (metaType != null) { 
                            break;
                        } 
                    } 
                }
                if (metaType == null) { 
                    metaType = this.provider.services.Model.GetMetaType(typeof(T));
                }
                IObjectReaderFactory factory = this.provider.GetDefaultFactory(metaType);
                IObjectReader objReader = factory.GetNextResult(this.session, false); 
                if (objReader == null) {
                    this.Dispose(); 
                    return null; 
                }
                return new SingleResult(new OneTimeEnumerable((IEnumerator)objReader), this.executeResult, this.provider.services.Context); 
            }

            public void Dispose() {
                if (!this.isDisposed) { 
                    this.isDisposed = true;
                    if (this.executeResult != null) { 
                        this.executeResult.Dispose(); 
                    }
                    else { 
                        this.session.Dispose();
                    }
                }
            } 

            public object ReturnValue { 
                get { 
                    if (this.executeResult != null) {
                        return executeResult.GetParameterValue("@RETURN_VALUE"); 
                    } else {
                        return null;
                    }
                } 
            }
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK