System.Data.SQLite
Check-in [9c7e81cdb4]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added files for building Linq module.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 9c7e81cdb4d20f22b5f14a27f5c90e83366514ab
User & Date: shaneh 2011-04-07 15:12:03
Context
2011-04-07
15:53
Missing file for designer. check-in: dc92d38c29 user: shaneh tags: trunk
15:12
Added files for building Linq module. check-in: 9c7e81cdb4 user: shaneh tags: trunk
2011-04-06
02:06
added files for install project; check-in: f0d5e38f0b user: shaneh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Added System.Data.SQLite.Linq/SQL Generation/DmlSqlGenerator.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="DmlSqlGenerator.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Collections.Generic;
           15  +  using System.Diagnostics;
           16  +  using System.Globalization;
           17  +  using System.IO;
           18  +  using System.Text;
           19  +  using System.Data;
           20  +  using System.Data.Common;
           21  +  using System.Data.Metadata.Edm;
           22  +  using System.Data.Common.CommandTrees;
           23  +  using System.Data.Common.Utils;
           24  +  using System.Data.Mapping.Update.Internal;
           25  +
           26  +  /// <summary>
           27  +  /// Class generating SQL for a DML command tree.
           28  +  /// </summary>
           29  +  internal static class DmlSqlGenerator
           30  +  {
           31  +    private static readonly int s_commandTextBuilderInitialCapacity = 256;
           32  +
           33  +    internal static string GenerateUpdateSql(DbUpdateCommandTree tree, out List<DbParameter> parameters)
           34  +    {
           35  +      StringBuilder commandText = new StringBuilder(s_commandTextBuilderInitialCapacity);
           36  +      ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, null != tree.Returning, "UpdateFunction");
           37  +
           38  +      // update [schemaName].[tableName]
           39  +      commandText.Append("UPDATE ");
           40  +      tree.Target.Expression.Accept(translator);
           41  +      commandText.AppendLine();
           42  +
           43  +      // set c1 = ..., c2 = ..., ...
           44  +      bool first = true;
           45  +      commandText.Append("SET ");
           46  +      foreach (DbSetClause setClause in tree.SetClauses)
           47  +      {
           48  +        if (first) { first = false; }
           49  +        else { commandText.Append(", "); }
           50  +        setClause.Property.Accept(translator);
           51  +        commandText.Append(" = ");
           52  +        setClause.Value.Accept(translator);
           53  +      }
           54  +
           55  +      if (first)
           56  +      {
           57  +        // If first is still true, it indicates there were no set
           58  +        // clauses. Introduce a fake set clause so that:
           59  +        // - we acquire the appropriate locks
           60  +        // - server-gen columns (e.g. timestamp) get recomputed
           61  +        //
           62  +        // We use the following pattern:
           63  +        //
           64  +        //  update Foo
           65  +        //  set @i = 0
           66  +        //  where ...
           67  +        DbParameter parameter = translator.CreateParameter(default(Int32), DbType.Int32);
           68  +        commandText.Append(parameter.ParameterName);
           69  +        commandText.Append(" = 0");
           70  +      }
           71  +      commandText.AppendLine();
           72  +
           73  +      // where c1 = ..., c2 = ...
           74  +      commandText.Append("WHERE ");
           75  +      tree.Predicate.Accept(translator);
           76  +      commandText.AppendLine();
           77  +
           78  +      // generate returning sql
           79  +      GenerateReturningSql(commandText, tree, translator, tree.Returning);
           80  +
           81  +      parameters = translator.Parameters;
           82  +      return commandText.ToString();
           83  +    }
           84  +
           85  +    internal static string GenerateDeleteSql(DbDeleteCommandTree tree, out List<DbParameter> parameters)
           86  +    {
           87  +      StringBuilder commandText = new StringBuilder(s_commandTextBuilderInitialCapacity);
           88  +      ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, false, "DeleteFunction");
           89  +
           90  +      // delete [schemaName].[tableName]
           91  +      commandText.Append("DELETE FROM ");
           92  +      tree.Target.Expression.Accept(translator);
           93  +      commandText.AppendLine();
           94  +
           95  +      // where c1 = ... AND c2 = ...
           96  +      commandText.Append("WHERE ");
           97  +      tree.Predicate.Accept(translator);
           98  +
           99  +      parameters = translator.Parameters;
          100  +
          101  +      commandText.AppendLine(";");
          102  +      return commandText.ToString();
          103  +    }
          104  +
          105  +    internal static string GenerateInsertSql(DbInsertCommandTree tree, out List<DbParameter> parameters)
          106  +    {
          107  +      StringBuilder commandText = new StringBuilder(s_commandTextBuilderInitialCapacity);
          108  +      ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, null != tree.Returning, "InsertFunction");
          109  +
          110  +      // insert [schemaName].[tableName]
          111  +      commandText.Append("INSERT INTO ");
          112  +      tree.Target.Expression.Accept(translator);
          113  +
          114  +      if (tree.SetClauses.Count > 0)
          115  +      {
          116  +        // (c1, c2, c3, ...)
          117  +        commandText.Append("(");
          118  +        bool first = true;
          119  +        foreach (DbSetClause setClause in tree.SetClauses)
          120  +        {
          121  +          if (first) { first = false; }
          122  +          else { commandText.Append(", "); }
          123  +          setClause.Property.Accept(translator);
          124  +        }
          125  +        commandText.AppendLine(")");
          126  +
          127  +        // values c1, c2, ...
          128  +        first = true;
          129  +        commandText.Append(" VALUES (");
          130  +        foreach (DbSetClause setClause in tree.SetClauses)
          131  +        {
          132  +          if (first) { first = false; }
          133  +          else { commandText.Append(", "); }
          134  +          setClause.Value.Accept(translator);
          135  +
          136  +          translator.RegisterMemberValue(setClause.Property, setClause.Value);
          137  +        }
          138  +        commandText.AppendLine(");");
          139  +      }
          140  +      else // No columns specified.  Insert an empty row containing default values by inserting null into the rowid
          141  +      {
          142  +        commandText.AppendLine(" DEFAULT VALUES;");
          143  +      }
          144  +
          145  +      // generate returning sql
          146  +      GenerateReturningSql(commandText, tree, translator, tree.Returning);
          147  +
          148  +      parameters = translator.Parameters;
          149  +      return commandText.ToString();
          150  +    }
          151  +
          152  +    // Generates T-SQL describing a member
          153  +    // Requires: member must belong to an entity type (a safe requirement for DML
          154  +    // SQL gen, where we only access table columns)
          155  +    private static string GenerateMemberTSql(EdmMember member)
          156  +    {
          157  +      return SqlGenerator.QuoteIdentifier(member.Name);
          158  +    }
          159  +
          160  +    /// <summary>
          161  +    /// Generates SQL fragment returning server-generated values.
          162  +    /// Requires: translator knows about member values so that we can figure out
          163  +    /// how to construct the key predicate.
          164  +    /// <code>
          165  +    /// Sample SQL:
          166  +    ///     
          167  +    ///     select IdentityValue
          168  +    ///     from dbo.MyTable
          169  +    ///     where @@ROWCOUNT > 0 and IdentityValue = scope_identity()
          170  +    /// 
          171  +    /// or
          172  +    /// 
          173  +    ///     select TimestamptValue
          174  +    ///     from dbo.MyTable
          175  +    ///     where @@ROWCOUNT > 0 and Id = 1
          176  +    /// 
          177  +    /// Note that we filter on rowcount to ensure no rows are returned if no rows were modified.
          178  +    /// </code>
          179  +    /// </summary>
          180  +    /// <param name="commandText">Builder containing command text</param>
          181  +    /// <param name="tree">Modification command tree</param>
          182  +    /// <param name="translator">Translator used to produce DML SQL statement
          183  +    /// for the tree</param>
          184  +    /// <param name="returning">Returning expression. If null, the method returns
          185  +    /// immediately without producing a SELECT statement.</param>
          186  +    private static void GenerateReturningSql(StringBuilder commandText, DbModificationCommandTree tree,
          187  +        ExpressionTranslator translator, DbExpression returning)
          188  +    {
          189  +      // Nothing to do if there is no Returning expression
          190  +      if (null == returning) { return; }
          191  +
          192  +      // select
          193  +      commandText.Append("SELECT ");
          194  +      returning.Accept(translator);
          195  +      commandText.AppendLine();
          196  +
          197  +      // from
          198  +      commandText.Append("FROM ");
          199  +      tree.Target.Expression.Accept(translator);
          200  +      commandText.AppendLine();
          201  +
          202  +      // where
          203  +      commandText.Append("WHERE last_rows_affected() > 0");
          204  +      EntitySetBase table = ((DbScanExpression)tree.Target.Expression).Target;
          205  +      bool identity = false;
          206  +      foreach (EdmMember keyMember in table.ElementType.KeyMembers)
          207  +      {
          208  +        commandText.Append(" AND ");
          209  +        commandText.Append(GenerateMemberTSql(keyMember));
          210  +        commandText.Append(" = ");
          211  +
          212  +        // retrieve member value sql. the translator remembers member values
          213  +        // as it constructs the DML statement (which precedes the "returning"
          214  +        // SQL)
          215  +        DbParameter value;
          216  +        if (translator.MemberValues.TryGetValue(keyMember, out value))
          217  +        {
          218  +          commandText.Append(value.ParameterName);
          219  +        }
          220  +        else
          221  +        {
          222  +          // if no value is registered for the key member, it means it is an identity
          223  +          // which can be retrieved using the scope_identity() function
          224  +          if (identity)
          225  +          {
          226  +            // there can be only one server generated key
          227  +            throw new NotSupportedException(string.Format("Server generated keys are only supported for identity columns. More than one key column is marked as server generated in table '{0}'.", table.Name));
          228  +          }
          229  +          commandText.AppendLine("last_insert_rowid();");
          230  +          identity = true;
          231  +        }
          232  +      }
          233  +    }
          234  +
          235  +    /// <summary>
          236  +    /// Lightweight expression translator for DML expression trees, which have constrained
          237  +    /// scope and support.
          238  +    /// </summary>
          239  +    private class ExpressionTranslator : DbExpressionVisitor
          240  +    {
          241  +      /// <summary>
          242  +      /// Initialize a new expression translator populating the given string builder
          243  +      /// with command text. Command text builder and command tree must not be null.
          244  +      /// </summary>
          245  +      /// <param name="commandText">Command text with which to populate commands</param>
          246  +      /// <param name="commandTree">Command tree generating SQL</param>
          247  +      /// <param name="preserveMemberValues">Indicates whether the translator should preserve
          248  +      /// member values while compiling t-SQL (only needed for server generation)</param>
          249  +      internal ExpressionTranslator(StringBuilder commandText, DbModificationCommandTree commandTree,
          250  +          bool preserveMemberValues, string kind)
          251  +      {
          252  +        Debug.Assert(null != commandText);
          253  +        Debug.Assert(null != commandTree);
          254  +        _kind = kind;
          255  +        _commandText = commandText;
          256  +        _commandTree = commandTree;
          257  +        _parameters = new List<DbParameter>();
          258  +        _memberValues = preserveMemberValues ? new Dictionary<EdmMember, DbParameter>() :
          259  +            null;
          260  +      }
          261  +
          262  +      private readonly StringBuilder _commandText;
          263  +      private readonly DbModificationCommandTree _commandTree;
          264  +      private readonly List<DbParameter> _parameters;
          265  +      private readonly Dictionary<EdmMember, DbParameter> _memberValues;
          266  +      private int parameterNameCount = 0;
          267  +      private string _kind;
          268  +
          269  +      internal List<DbParameter> Parameters { get { return _parameters; } }
          270  +      internal Dictionary<EdmMember, DbParameter> MemberValues { get { return _memberValues; } }
          271  +
          272  +      // generate parameter (name based on parameter ordinal)
          273  +      internal SQLiteParameter CreateParameter(object value, TypeUsage type)
          274  +      {
          275  +        PrimitiveTypeKind primitiveType = MetadataHelpers.GetPrimitiveTypeKind(type);
          276  +        DbType dbType = MetadataHelpers.GetDbType(primitiveType);
          277  +        return CreateParameter(value, dbType);
          278  +      }
          279  +
          280  +      // Creates a new parameter for a value in this expression translator
          281  +      internal SQLiteParameter CreateParameter(object value, DbType dbType)
          282  +      {
          283  +        string parameterName = string.Concat("@p", parameterNameCount.ToString(CultureInfo.InvariantCulture));
          284  +        parameterNameCount++;
          285  +        SQLiteParameter parameter = new SQLiteParameter(parameterName, value);
          286  +        parameter.DbType = dbType;
          287  +        _parameters.Add(parameter);
          288  +        return parameter;
          289  +      }
          290  +
          291  +      #region Basics
          292  +
          293  +      public override void Visit(DbApplyExpression expression)
          294  +      {
          295  +        if (expression == null) throw new ArgumentException("expression");
          296  +
          297  +        VisitExpressionBindingPre(expression.Input);
          298  +        if (expression.Apply != null)
          299  +        {
          300  +          VisitExpression(expression.Apply.Expression);
          301  +        }
          302  +        VisitExpressionBindingPost(expression.Input);
          303  +      }
          304  +
          305  +      public override void Visit(DbArithmeticExpression expression)
          306  +      {
          307  +        if (expression == null) throw new ArgumentException("expression");
          308  +        VisitExpressionList(expression.Arguments);
          309  +      }
          310  +
          311  +      public override void Visit(DbCaseExpression expression)
          312  +      {
          313  +        if (expression == null) throw new ArgumentException("expression");
          314  +        VisitExpressionList(expression.When);
          315  +        VisitExpressionList(expression.Then);
          316  +        VisitExpression(expression.Else);
          317  +      }
          318  +
          319  +      public override void Visit(DbCastExpression expression)
          320  +      {
          321  +        VisitUnaryExpression(expression);
          322  +      }
          323  +
          324  +      public override void Visit(DbCrossJoinExpression expression)
          325  +      {
          326  +        if (expression == null) throw new ArgumentException("expression");
          327  +        foreach (DbExpressionBinding binding in expression.Inputs)
          328  +        {
          329  +          VisitExpressionBindingPre(binding);
          330  +        }
          331  +        foreach (DbExpressionBinding binding2 in expression.Inputs)
          332  +        {
          333  +          VisitExpressionBindingPost(binding2);
          334  +        }
          335  +      }
          336  +
          337  +      public override void Visit(DbDerefExpression expression)
          338  +      {
          339  +        VisitUnaryExpression(expression);
          340  +      }
          341  +
          342  +      public override void Visit(DbDistinctExpression expression)
          343  +      {
          344  +        VisitUnaryExpression(expression);
          345  +      }
          346  +
          347  +      public override void Visit(DbElementExpression expression)
          348  +      {
          349  +        VisitUnaryExpression(expression);
          350  +      }
          351  +
          352  +      public override void Visit(DbEntityRefExpression expression)
          353  +      {
          354  +        VisitUnaryExpression(expression);
          355  +      }
          356  +
          357  +      public override void Visit(DbExceptExpression expression)
          358  +      {
          359  +        VisitBinary(expression);
          360  +      }
          361  +
          362  +      protected virtual void VisitBinary(DbBinaryExpression expression)
          363  +      {
          364  +        if (expression == null) throw new ArgumentException("expression");
          365  +        this.VisitExpression(expression.Left);
          366  +        this.VisitExpression(expression.Right);
          367  +      }
          368  +
          369  +      public override void Visit(DbExpression expression)
          370  +      {
          371  +        if (expression == null) throw new ArgumentException("expression");
          372  +        throw new NotSupportedException("DbExpression");
          373  +      }
          374  +
          375  +      public override void Visit(DbFilterExpression expression)
          376  +      {
          377  +        if (expression == null) throw new ArgumentException("expression");
          378  +        VisitExpressionBindingPre(expression.Input);
          379  +        VisitExpression(expression.Predicate);
          380  +        VisitExpressionBindingPost(expression.Input);
          381  +      }
          382  +
          383  +      public override void Visit(DbFunctionExpression expression)
          384  +      {
          385  +        if (expression == null) throw new ArgumentException("expression");
          386  +        VisitExpressionList(expression.Arguments);
          387  +        //if (expression.IsLambda)
          388  +        //{
          389  +        //  VisitLambdaFunctionPre(expression.Function, expression.LambdaBody);
          390  +        //  VisitExpression(expression.LambdaBody);
          391  +        //  VisitLambdaFunctionPost(expression.Function, expression.LambdaBody);
          392  +        //}
          393  +      }
          394  +
          395  +      public override void Visit(DbGroupByExpression expression)
          396  +      {
          397  +        if (expression == null) throw new ArgumentException("expression");
          398  +        VisitGroupExpressionBindingPre(expression.Input);
          399  +        VisitExpressionList(expression.Keys);
          400  +        VisitGroupExpressionBindingMid(expression.Input);
          401  +        VisitAggregateList(expression.Aggregates);
          402  +        VisitGroupExpressionBindingPost(expression.Input);
          403  +      }
          404  +
          405  +      public override void Visit(DbIntersectExpression expression)
          406  +      {
          407  +        VisitBinary(expression);
          408  +      }
          409  +
          410  +      public override void Visit(DbIsEmptyExpression expression)
          411  +      {
          412  +        VisitUnaryExpression(expression);
          413  +      }
          414  +
          415  +      public override void Visit(DbIsOfExpression expression)
          416  +      {
          417  +        VisitUnaryExpression(expression);
          418  +      }
          419  +
          420  +      public override void Visit(DbJoinExpression expression)
          421  +      {
          422  +        if (expression == null) throw new ArgumentException("expression");
          423  +        VisitExpressionBindingPre(expression.Left);
          424  +        VisitExpressionBindingPre(expression.Right);
          425  +        VisitExpression(expression.JoinCondition);
          426  +        VisitExpressionBindingPost(expression.Left);
          427  +        VisitExpressionBindingPost(expression.Right);
          428  +      }
          429  +
          430  +      public override void Visit(DbLikeExpression expression)
          431  +      {
          432  +        if (expression == null) throw new ArgumentException("expression");
          433  +        VisitExpression(expression.Argument);
          434  +        VisitExpression(expression.Pattern);
          435  +        VisitExpression(expression.Escape);
          436  +      }
          437  +
          438  +      public override void Visit(DbLimitExpression expression)
          439  +      {
          440  +        if (expression == null) throw new ArgumentException("expression");
          441  +        VisitExpression(expression.Argument);
          442  +        VisitExpression(expression.Limit);
          443  +      }
          444  +
          445  +      public override void Visit(DbOfTypeExpression expression)
          446  +      {
          447  +        VisitUnaryExpression(expression);
          448  +      }
          449  +
          450  +      public override void Visit(DbParameterReferenceExpression expression)
          451  +      {
          452  +        if (expression == null) throw new ArgumentException("expression");
          453  +      }
          454  +
          455  +      public override void Visit(DbProjectExpression expression)
          456  +      {
          457  +        if (expression == null) throw new ArgumentException("expression");
          458  +        VisitExpressionBindingPre(expression.Input);
          459  +        VisitExpression(expression.Projection);
          460  +        VisitExpressionBindingPost(expression.Input);
          461  +      }
          462  +
          463  +      public override void Visit(DbQuantifierExpression expression)
          464  +      {
          465  +        if (expression == null) throw new ArgumentException("expression");
          466  +        VisitExpressionBindingPre(expression.Input);
          467  +        VisitExpression(expression.Predicate);
          468  +        VisitExpressionBindingPost(expression.Input);
          469  +      }
          470  +
          471  +      public override void Visit(DbRefExpression expression)
          472  +      {
          473  +        VisitUnaryExpression(expression);
          474  +      }
          475  +
          476  +      public override void Visit(DbRefKeyExpression expression)
          477  +      {
          478  +        VisitUnaryExpression(expression);
          479  +      }
          480  +
          481  +      public override void Visit(DbRelationshipNavigationExpression expression)
          482  +      {
          483  +        if (expression == null) throw new ArgumentException("expression");
          484  +        VisitExpression(expression.NavigationSource);
          485  +      }
          486  +
          487  +      public override void Visit(DbSkipExpression expression)
          488  +      {
          489  +        if (expression == null) throw new ArgumentException("expression");
          490  +        VisitExpressionBindingPre(expression.Input);
          491  +        foreach (DbSortClause clause in expression.SortOrder)
          492  +        {
          493  +          VisitExpression(clause.Expression);
          494  +        }
          495  +        VisitExpressionBindingPost(expression.Input);
          496  +        VisitExpression(expression.Count);
          497  +      }
          498  +
          499  +      public override void Visit(DbSortExpression expression)
          500  +      {
          501  +        if (expression == null) throw new ArgumentException("expression");
          502  +        VisitExpressionBindingPre(expression.Input);
          503  +        for (int i = 0; i < expression.SortOrder.Count; i++)
          504  +        {
          505  +          VisitExpression(expression.SortOrder[i].Expression);
          506  +        }
          507  +        VisitExpressionBindingPost(expression.Input);
          508  +      }
          509  +
          510  +      public override void Visit(DbTreatExpression expression)
          511  +      {
          512  +        VisitUnaryExpression(expression);
          513  +      }
          514  +
          515  +      public override void Visit(DbUnionAllExpression expression)
          516  +      {
          517  +        VisitBinary(expression);
          518  +      }
          519  +
          520  +      public override void Visit(DbVariableReferenceExpression expression)
          521  +      {
          522  +        if (expression == null) throw new ArgumentException("expression");
          523  +      }
          524  +
          525  +      public virtual void VisitAggregate(DbAggregate aggregate)
          526  +      {
          527  +        if (aggregate == null) throw new ArgumentException("aggregate");
          528  +        VisitExpressionList(aggregate.Arguments);
          529  +      }
          530  +
          531  +      public virtual void VisitAggregateList(IList<DbAggregate> aggregates)
          532  +      {
          533  +        if (aggregates == null) throw new ArgumentException("aggregates");
          534  +        for (int i = 0; i < aggregates.Count; i++)
          535  +        {
          536  +          VisitAggregate(aggregates[i]);
          537  +        }
          538  +      }
          539  +
          540  +      public virtual void VisitExpression(DbExpression expression)
          541  +      {
          542  +        if (expression == null) throw new ArgumentException("expression");
          543  +        expression.Accept(this);
          544  +      }
          545  +
          546  +      protected virtual void VisitExpressionBindingPost(DbExpressionBinding binding)
          547  +      {
          548  +      }
          549  +
          550  +      protected virtual void VisitExpressionBindingPre(DbExpressionBinding binding)
          551  +      {
          552  +        if (binding == null) throw new ArgumentException("binding");
          553  +        VisitExpression(binding.Expression);
          554  +      }
          555  +
          556  +      public virtual void VisitExpressionList(IList<DbExpression> expressionList)
          557  +      {
          558  +        if (expressionList == null) throw new ArgumentException("expressionList");
          559  +        for (int i = 0; i < expressionList.Count; i++)
          560  +        {
          561  +          VisitExpression(expressionList[i]);
          562  +        }
          563  +      }
          564  +
          565  +      protected virtual void VisitGroupExpressionBindingMid(DbGroupExpressionBinding binding)
          566  +      {
          567  +      }
          568  +
          569  +      protected virtual void VisitGroupExpressionBindingPost(DbGroupExpressionBinding binding)
          570  +      {
          571  +      }
          572  +
          573  +      protected virtual void VisitGroupExpressionBindingPre(DbGroupExpressionBinding binding)
          574  +      {
          575  +        if (binding == null) throw new ArgumentException("binding");
          576  +        VisitExpression(binding.Expression);
          577  +      }
          578  +
          579  +      protected virtual void VisitLambdaFunctionPost(EdmFunction function, DbExpression body)
          580  +      {
          581  +      }
          582  +
          583  +      protected virtual void VisitLambdaFunctionPre(EdmFunction function, DbExpression body)
          584  +      {
          585  +        if (function == null) throw new ArgumentException("function");
          586  +        if (body == null) throw new ArgumentException("body");
          587  +      }
          588  +
          589  +      //internal virtual void VisitRelatedEntityReference(DbRelatedEntityRef relatedEntityRef)
          590  +      //{
          591  +      //  VisitExpression(relatedEntityRef.TargetEntityReference);
          592  +      //}
          593  +
          594  +      //internal virtual void VisitRelatedEntityReferenceList(IList<DbRelatedEntityRef> relatedEntityReferences)
          595  +      //{
          596  +      //  for (int i = 0; i < relatedEntityReferences.Count; i++)
          597  +      //  {
          598  +      //    VisitRelatedEntityReference(relatedEntityReferences[i]);
          599  +      //  }
          600  +      //}
          601  +
          602  +      protected virtual void VisitUnaryExpression(DbUnaryExpression expression)
          603  +      {
          604  +        if (expression == null) throw new ArgumentException("expression");
          605  +        VisitExpression(expression.Argument);
          606  +      }
          607  +      #endregion
          608  +
          609  +      public override void Visit(DbAndExpression expression)
          610  +      {
          611  +        VisitBinary(expression, " AND ");
          612  +      }
          613  +
          614  +      public override void Visit(DbOrExpression expression)
          615  +      {
          616  +        VisitBinary(expression, " OR ");
          617  +      }
          618  +
          619  +      public override void Visit(DbComparisonExpression expression)
          620  +      {
          621  +        Debug.Assert(expression.ExpressionKind == DbExpressionKind.Equals,
          622  +            "only equals comparison expressions are produced in DML command trees in V1");
          623  +
          624  +        VisitBinary(expression, " = ");
          625  +
          626  +        RegisterMemberValue(expression.Left, expression.Right);
          627  +      }
          628  +
          629  +      /// <summary>
          630  +      /// Call this method to register a property value pair so the translator "remembers"
          631  +      /// the values for members of the row being modified. These values can then be used
          632  +      /// to form a predicate for server-generation (based on the key of the row)
          633  +      /// </summary>
          634  +      /// <param name="propertyExpression">DbExpression containing the column reference (property expression).</param>
          635  +      /// <param name="value">DbExpression containing the value of the column.</param>
          636  +      internal void RegisterMemberValue(DbExpression propertyExpression, DbExpression value)
          637  +      {
          638  +        if (null != _memberValues)
          639  +        {
          640  +          // register the value for this property
          641  +          Debug.Assert(propertyExpression.ExpressionKind == DbExpressionKind.Property,
          642  +              "DML predicates and setters must be of the form property = value");
          643  +
          644  +          // get name of left property 
          645  +          EdmMember property = ((DbPropertyExpression)propertyExpression).Property;
          646  +
          647  +          // don't track null values
          648  +          if (value.ExpressionKind != DbExpressionKind.Null)
          649  +          {
          650  +            Debug.Assert(value.ExpressionKind == DbExpressionKind.Constant,
          651  +                "value must either constant or null");
          652  +            // retrieve the last parameter added (which describes the parameter)
          653  +            _memberValues[property] = _parameters[_parameters.Count - 1];
          654  +          }
          655  +        }
          656  +      }
          657  +
          658  +      public override void Visit(DbIsNullExpression expression)
          659  +      {
          660  +        expression.Argument.Accept(this);
          661  +        _commandText.Append(" IS NULL");
          662  +      }
          663  +
          664  +      public override void Visit(DbNotExpression expression)
          665  +      {
          666  +        _commandText.Append("NOT (");
          667  +        expression.Accept(this);
          668  +        _commandText.Append(")");
          669  +      }
          670  +
          671  +      public override void Visit(DbConstantExpression expression)
          672  +      {
          673  +        SQLiteParameter parameter = CreateParameter(expression.Value, expression.ResultType);
          674  +        _commandText.Append(parameter.ParameterName);
          675  +      }
          676  +
          677  +      public override void Visit(DbScanExpression expression)
          678  +      {
          679  +        string definingQuery = MetadataHelpers.TryGetValueForMetadataProperty<string>(expression.Target, "DefiningQuery");
          680  +        if (definingQuery != null)
          681  +        {
          682  +          throw new NotSupportedException(String.Format("Unable to update the EntitySet '{0}' because it has a DefiningQuery and no <{1}> element exists in the <ModificationFunctionMapping> element to support the current operation.", expression.Target.Name, _kind));
          683  +        }
          684  +        _commandText.Append(SqlGenerator.GetTargetTSql(expression.Target));
          685  +      }
          686  +
          687  +      public override void Visit(DbPropertyExpression expression)
          688  +      {
          689  +        _commandText.Append(GenerateMemberTSql(expression.Property));
          690  +      }
          691  +
          692  +      public override void Visit(DbNullExpression expression)
          693  +      {
          694  +        _commandText.Append("NULL");
          695  +      }
          696  +
          697  +      public override void Visit(DbNewInstanceExpression expression)
          698  +      {
          699  +        // assumes all arguments are self-describing (no need to use aliases
          700  +        // because no renames are ever used in the projection)
          701  +        bool first = true;
          702  +        foreach (DbExpression argument in expression.Arguments)
          703  +        {
          704  +          if (first) { first = false; }
          705  +          else { _commandText.Append(", "); }
          706  +          argument.Accept(this);
          707  +        }
          708  +      }
          709  +
          710  +      private void VisitBinary(DbBinaryExpression expression, string separator)
          711  +      {
          712  +        _commandText.Append("(");
          713  +        expression.Left.Accept(this);
          714  +        _commandText.Append(separator);
          715  +        expression.Right.Accept(this);
          716  +        _commandText.Append(")");
          717  +      }
          718  +    }
          719  +  }
          720  +}
          721  +

Added System.Data.SQLite.Linq/SQL Generation/ISqlFragment.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="ISqlFragment.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Collections.Generic;
           15  +  using System.Diagnostics;
           16  +  using System.IO;
           17  +  using System.Text;
           18  +  using System.Data.Metadata.Edm;
           19  +  using System.Data.Common.CommandTrees;
           20  +
           21  +  /// <summary>
           22  +  /// Represents the sql fragment for any node in the query tree.
           23  +  /// </summary>
           24  +  /// <remarks>
           25  +  /// The nodes in a query tree produce various kinds of sql
           26  +  /// <list type="bullet">
           27  +  /// <item>A select statement.</item>
           28  +  /// <item>A reference to an extent. (symbol)</item>
           29  +  /// <item>A raw string.</item>
           30  +  /// </list>
           31  +  /// We have this interface to allow for a common return type for the methods
           32  +  /// in the expression visitor <see cref="DbExpressionVisitor{T}"/>
           33  +  /// 
           34  +  /// At the end of translation, the sql fragments are converted into real strings.
           35  +  /// </remarks>
           36  +  internal interface ISqlFragment
           37  +  {
           38  +    /// <summary>
           39  +    /// Write the string represented by this fragment into the stream.
           40  +    /// </summary>
           41  +    /// <param name="writer">The stream that collects the strings.</param>
           42  +    /// <param name="sqlGenerator">Context information used for renaming.
           43  +    /// The global lists are used to generated new names without collisions.</param>
           44  +    void WriteSql(SqlWriter writer, SqlGenerator sqlGenerator);
           45  +  }
           46  +}

Added System.Data.SQLite.Linq/SQL Generation/InternalBase.cs.

            1  +/********************************************************
            2  + * ADO.NET 2.0 Data Provider for SQLite Version 3.X
            3  + * Written by Robert Simpson (robert@blackcastlesoft.com)
            4  + * 
            5  + * Released to the public domain, use at your own risk!
            6  + ********************************************************/
            7  +
            8  +using System;
            9  +using System.Collections.Generic;
           10  +using System.Linq;
           11  +using System.Text;
           12  +using System.Runtime;
           13  +
           14  +namespace System.Data.SQLite
           15  +{
           16  +	internal abstract class InternalBase
           17  +	{
           18  +		// Methods
           19  +		[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
           20  +		protected InternalBase()
           21  +		{
           22  +		}
           23  +
           24  +		internal abstract void ToCompactString(StringBuilder builder);
           25  +		internal virtual string ToFullString()
           26  +		{
           27  +			StringBuilder builder = new StringBuilder();
           28  +			this.ToFullString(builder);
           29  +			return builder.ToString();
           30  +		}
           31  +
           32  +		[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
           33  +		internal virtual void ToFullString(StringBuilder builder)
           34  +		{
           35  +			this.ToCompactString(builder);
           36  +		}
           37  +
           38  +		public override string ToString()
           39  +		{
           40  +			StringBuilder builder = new StringBuilder();
           41  +			this.ToCompactString(builder);
           42  +			return builder.ToString();
           43  +		}
           44  +	}
           45  +}

Added System.Data.SQLite.Linq/SQL Generation/JoinSymbol.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="JoinSymbol.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Collections.Generic;
           15  +  using System.Diagnostics;
           16  +  using System.IO;
           17  +  using System.Text;
           18  +  using System.Data.Metadata.Edm;
           19  +  using System.Data.Common.CommandTrees;
           20  +
           21  +  /// <summary>
           22  +  /// A Join symbol is a special kind of Symbol.
           23  +  /// It has to carry additional information
           24  +  /// <list type="bullet">
           25  +  /// <item>ColumnList for the list of columns in the select clause if this
           26  +  /// symbol represents a sql select statement.  This is set by <see cref="SqlGenerator.AddDefaultColumns"/>. </item>
           27  +  /// <item>ExtentList is the list of extents in the select clause.</item>
           28  +  /// <item>FlattenedExtentList - if the Join has multiple extents flattened at the 
           29  +  /// top level, we need this information to ensure that extent aliases are renamed
           30  +  /// correctly in <see cref="SqlSelectStatement.WriteSql"/></item>
           31  +  /// <item>NameToExtent has all the extents in ExtentList as a dictionary.
           32  +  /// This is used by <see cref="SqlGenerator.Visit(DbPropertyExpression)"/> to flatten
           33  +  /// record accesses.</item>
           34  +  /// <item>IsNestedJoin - is used to determine whether a JoinSymbol is an 
           35  +  /// ordinary join symbol, or one that has a corresponding SqlSelectStatement.</item>
           36  +  /// </list>
           37  +  /// 
           38  +  /// All the lists are set exactly once, and then used for lookups/enumerated.
           39  +  /// </summary>
           40  +  internal sealed class JoinSymbol : Symbol
           41  +  {
           42  +    private List<Symbol> columnList;
           43  +    internal List<Symbol> ColumnList
           44  +    {
           45  +      get
           46  +      {
           47  +        if (null == columnList)
           48  +        {
           49  +          columnList = new List<Symbol>();
           50  +        }
           51  +        return columnList;
           52  +      }
           53  +      set { columnList = value; }
           54  +    }
           55  +
           56  +    private List<Symbol> extentList;
           57  +    internal List<Symbol> ExtentList
           58  +    {
           59  +      get { return extentList; }
           60  +    }
           61  +
           62  +    private List<Symbol> flattenedExtentList;
           63  +    internal List<Symbol> FlattenedExtentList
           64  +    {
           65  +      get
           66  +      {
           67  +        if (null == flattenedExtentList)
           68  +        {
           69  +          flattenedExtentList = new List<Symbol>();
           70  +        }
           71  +        return flattenedExtentList;
           72  +      }
           73  +      set { flattenedExtentList = value; }
           74  +    }
           75  +
           76  +    private Dictionary<string, Symbol> nameToExtent;
           77  +    internal Dictionary<string, Symbol> NameToExtent
           78  +    {
           79  +      get { return nameToExtent; }
           80  +    }
           81  +
           82  +    private bool isNestedJoin;
           83  +    internal bool IsNestedJoin
           84  +    {
           85  +      get { return isNestedJoin; }
           86  +      set { isNestedJoin = value; }
           87  +    }
           88  +
           89  +    public JoinSymbol(string name, TypeUsage type, List<Symbol> extents)
           90  +      : base(name, type)
           91  +    {
           92  +      extentList = new List<Symbol>(extents.Count);
           93  +      nameToExtent = new Dictionary<string, Symbol>(extents.Count, StringComparer.OrdinalIgnoreCase);
           94  +      foreach (Symbol symbol in extents)
           95  +      {
           96  +        this.nameToExtent[symbol.Name] = symbol;
           97  +        this.ExtentList.Add(symbol);
           98  +      }
           99  +    }
          100  +  }
          101  +}

Added System.Data.SQLite.Linq/SQL Generation/KeyToListMap.cs.

            1  +/********************************************************
            2  + * ADO.NET 2.0 Data Provider for SQLite Version 3.X
            3  + * Written by Robert Simpson (robert@blackcastlesoft.com)
            4  + * 
            5  + * Released to the public domain, use at your own risk!
            6  + ********************************************************/
            7  +
            8  +using System;
            9  +using System.Collections.Generic;
           10  +using System.Linq;
           11  +using System.Text;
           12  +using System.Collections.ObjectModel;
           13  +using System.Runtime;
           14  +using System.Runtime.CompilerServices;
           15  +using System.Collections;
           16  +
           17  +namespace System.Data.SQLite
           18  +{
           19  +	internal class KeyToListMap<TKey, TValue> : InternalBase
           20  +	{
           21  +		// Fields
           22  +		private Dictionary<TKey, List<TValue>> m_map;
           23  +
           24  +		// Methods
           25  +		internal KeyToListMap(IEqualityComparer<TKey> comparer)
           26  +		{
           27  +			this.m_map = new Dictionary<TKey, List<TValue>>(comparer);
           28  +		}
           29  +
           30  +		internal void Add(TKey key, TValue value)
           31  +		{
           32  +			List<TValue> list;
           33  +			if (!this.m_map.TryGetValue(key, out list))
           34  +			{
           35  +				list = new List<TValue>();
           36  +				this.m_map[key] = list;
           37  +			}
           38  +			list.Add(value);
           39  +		}
           40  +
           41  +		internal void AddRange(TKey key, IEnumerable<TValue> values)
           42  +		{
           43  +			foreach (TValue local in values)
           44  +			{
           45  +				this.Add(key, local);
           46  +			}
           47  +		}
           48  +
           49  +		internal bool ContainsKey(TKey key)
           50  +		{
           51  +			return this.m_map.ContainsKey(key);
           52  +		}
           53  +
           54  +		internal IEnumerable<TValue> EnumerateValues(TKey key)
           55  +		{
           56  +			List<TValue> values;
           57  +			if (m_map.TryGetValue(key, out values))
           58  +			{
           59  +				foreach (TValue value in values) { yield return value; }
           60  +			}
           61  +		}
           62  +
           63  +		internal ReadOnlyCollection<TValue> ListForKey(TKey key)
           64  +		{
           65  +			return new ReadOnlyCollection<TValue>(this.m_map[key]);
           66  +		}
           67  +
           68  +		internal bool RemoveKey(TKey key)
           69  +		{
           70  +			return this.m_map.Remove(key);
           71  +		}
           72  +
           73  +		internal override void ToCompactString(StringBuilder builder)
           74  +		{
           75  +			foreach (TKey local in this.Keys)
           76  +			{
           77  +				StringUtil.FormatStringBuilder(builder, "{0}", new object[] { local });
           78  +				builder.Append(": ");
           79  +				IEnumerable<TValue> list = this.ListForKey(local);
           80  +				StringUtil.ToSeparatedString(builder, list, ",", "null");
           81  +				builder.Append("; ");
           82  +			}
           83  +		}
           84  +
           85  +		internal bool TryGetListForKey(TKey key, out ReadOnlyCollection<TValue> valueCollection)
           86  +		{
           87  +			List<TValue> list;
           88  +			valueCollection = null;
           89  +			if (this.m_map.TryGetValue(key, out list))
           90  +			{
           91  +				valueCollection = new ReadOnlyCollection<TValue>(list);
           92  +				return true;
           93  +			}
           94  +			return false;
           95  +		}
           96  +
           97  +		// Properties
           98  +		internal IEnumerable<TValue> AllValues
           99  +		{
          100  +			get
          101  +			{
          102  +				foreach (TKey key in Keys)
          103  +				{
          104  +					foreach (TValue value in ListForKey(key))
          105  +					{
          106  +						yield return value;
          107  +					}
          108  +				}
          109  +			}
          110  +		}
          111  +
          112  +		internal IEnumerable<TKey> Keys
          113  +		{
          114  +			get
          115  +			{
          116  +				return this.m_map.Keys;
          117  +			}
          118  +		}
          119  +
          120  +		internal IEnumerable<KeyValuePair<TKey, List<TValue>>> KeyValuePairs
          121  +		{
          122  +			[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
          123  +			get
          124  +			{
          125  +				return this.m_map;
          126  +			}
          127  +		}
          128  +	}
          129  +}

Added System.Data.SQLite.Linq/SQL Generation/License.txt.

            1  +Microsoft Public License (Ms-PL)
            2  +
            3  +This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
            4  +
            5  +1. Definitions
            6  +
            7  +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
            8  +
            9  +A "contribution" is the original software, or any additions or changes to the software.
           10  +
           11  +A "contributor" is any person that distributes its contribution under this license.
           12  +
           13  +"Licensed patents" are a contributor's patent claims that read directly on its contribution.
           14  +
           15  +2. Grant of Rights
           16  +
           17  +(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
           18  +
           19  +(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
           20  +
           21  +3. Conditions and Limitations
           22  +
           23  +(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
           24  +
           25  +(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
           26  +
           27  +(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
           28  +
           29  +(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
           30  +
           31  +(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 

Added System.Data.SQLite.Linq/SQL Generation/MetadataHelpers.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="MetadataHelpers.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Data;
           15  +  using System.Data.Common;
           16  +  using System.Collections.Generic;
           17  +  using System.Data.Metadata.Edm;
           18  +  using System.Diagnostics;
           19  +
           20  +  /// <summary>
           21  +  /// A set of static helpers for type metadata
           22  +  /// </summary>
           23  +  static class MetadataHelpers
           24  +  {
           25  +    #region Type Helpers
           26  +
           27  +    /// <summary>
           28  +    /// Cast the EdmType of the given type usage to the given TEdmType
           29  +    /// </summary>
           30  +    /// <typeparam name="TEdmType"></typeparam>
           31  +    /// <param name="typeUsage"></param>
           32  +    /// <returns></returns>
           33  +    internal static TEdmType GetEdmType<TEdmType>(TypeUsage typeUsage)
           34  +        where TEdmType : EdmType
           35  +    {
           36  +      return (TEdmType)typeUsage.EdmType;
           37  +    }
           38  +
           39  +    /// <summary>
           40  +    /// Gets the TypeUsage of the elment if the given type is a collection type
           41  +    /// </summary>
           42  +    /// <param name="type"></param>
           43  +    /// <returns></returns>
           44  +    internal static TypeUsage GetElementTypeUsage(TypeUsage type)
           45  +    {
           46  +      if (MetadataHelpers.IsCollectionType(type))
           47  +      {
           48  +        return ((CollectionType)type.EdmType).TypeUsage;
           49  +      }
           50  +      return null;
           51  +    }
           52  +
           53  +    /// <summary>
           54  +    /// Retrieves the properties of in the EdmType underlying the input type usage, 
           55  +    ///  if that EdmType is a structured type (EntityType, RowType). 
           56  +    /// </summary>
           57  +    /// <param name="typeUsage"></param>
           58  +    /// <returns></returns>
           59  +    internal static IList<EdmProperty> GetProperties(TypeUsage typeUsage)
           60  +    {
           61  +      return MetadataHelpers.GetProperties(typeUsage.EdmType);
           62  +    }
           63  +
           64  +    /// <summary>
           65  +    /// Retrieves the properties of the given EdmType, if it is
           66  +    ///  a structured type (EntityType, RowType). 
           67  +    /// </summary>
           68  +    /// <param name="edmType"></param>
           69  +    /// <returns></returns>
           70  +    internal static IList<EdmProperty> GetProperties(EdmType edmType)
           71  +    {
           72  +      switch (edmType.BuiltInTypeKind)
           73  +      {
           74  +        case BuiltInTypeKind.ComplexType:
           75  +          return ((ComplexType)edmType).Properties;
           76  +        case BuiltInTypeKind.EntityType:
           77  +          return ((EntityType)edmType).Properties;
           78  +        case BuiltInTypeKind.RowType:
           79  +          return ((RowType)edmType).Properties;
           80  +        default:
           81  +          return new List<EdmProperty>();
           82  +      }
           83  +    }
           84  +
           85  +    /// <summary>
           86  +    /// Is the given type usage over a collection type
           87  +    /// </summary>
           88  +    /// <param name="typeUsage"></param>
           89  +    /// <returns></returns>
           90  +    internal static bool IsCollectionType(TypeUsage typeUsage)
           91  +    {
           92  +      return MetadataHelpers.IsCollectionType(typeUsage.EdmType);
           93  +    }
           94  +
           95  +    /// <summary>
           96  +    /// Is the given type a collection type
           97  +    /// </summary>
           98  +    /// <param name="type"></param>
           99  +    /// <returns></returns>
          100  +    internal static bool IsCollectionType(EdmType type)
          101  +    {
          102  +      return (BuiltInTypeKind.CollectionType == type.BuiltInTypeKind);
          103  +    }
          104  +
          105  +    /// <summary>
          106  +    /// Is the given type usage over a primitive type
          107  +    /// </summary>
          108  +    /// <param name="type"></param>
          109  +    /// <returns></returns>
          110  +    internal static bool IsPrimitiveType(TypeUsage type)
          111  +    {
          112  +      return MetadataHelpers.IsPrimitiveType(type.EdmType);
          113  +    }
          114  +
          115  +    /// <summary>
          116  +    /// Is the given type a primitive type
          117  +    /// </summary>
          118  +    /// <param name="type"></param>
          119  +    /// <returns></returns>
          120  +    internal static bool IsPrimitiveType(EdmType type)
          121  +    {
          122  +      return (BuiltInTypeKind.PrimitiveType == type.BuiltInTypeKind);
          123  +    }
          124  +
          125  +    /// <summary>
          126  +    /// Is the given type usage over a row type
          127  +    /// </summary>
          128  +    /// <param name="type"></param>
          129  +    /// <returns></returns>
          130  +    internal static bool IsRowType(TypeUsage type)
          131  +    {
          132  +      return MetadataHelpers.IsRowType(type.EdmType);
          133  +    }
          134  +
          135  +    /// <summary>
          136  +    /// Is the given type a row type
          137  +    /// </summary>
          138  +    /// <param name="type"></param>
          139  +    /// <returns></returns>
          140  +    internal static bool IsRowType(EdmType type)
          141  +    {
          142  +      return (BuiltInTypeKind.RowType == type.BuiltInTypeKind);
          143  +    }
          144  +
          145  +    /// <summary>
          146  +    /// Gets the type of the given type usage if it is a primitive type
          147  +    /// </summary>
          148  +    /// <param name="type"></param>
          149  +    /// <param name="typeKind"></param>
          150  +    /// <returns></returns>
          151  +    internal static bool TryGetPrimitiveTypeKind(TypeUsage type, out PrimitiveTypeKind typeKind)
          152  +    {
          153  +      if (type != null && type.EdmType != null && type.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType)
          154  +      {
          155  +        typeKind = ((PrimitiveType)type.EdmType).PrimitiveTypeKind;
          156  +        return true;
          157  +      }
          158  +
          159  +      typeKind = default(PrimitiveTypeKind);
          160  +      return false;
          161  +    }
          162  +
          163  +    internal static PrimitiveTypeKind GetPrimitiveTypeKind(TypeUsage type)
          164  +    {
          165  +      PrimitiveTypeKind returnValue;
          166  +      if (!MetadataHelpers.TryGetPrimitiveTypeKind(type, out returnValue))
          167  +      {
          168  +        Debug.Assert(false, "Cannot create parameter of non-primitive type");
          169  +        throw new NotSupportedException("Cannot create parameter of non-primitive type");
          170  +      }
          171  +      return returnValue;
          172  +    }
          173  +
          174  +    /// <summary>
          175  +    /// Gets the value for the metadata property with the given name
          176  +    /// </summary>
          177  +    /// <typeparam name="T"></typeparam>
          178  +    /// <param name="item"></param>
          179  +    /// <param name="propertyName"></param>
          180  +    /// <returns></returns>
          181  +    internal static T TryGetValueForMetadataProperty<T>(MetadataItem item, string propertyName)
          182  +    {
          183  +      MetadataProperty property;
          184  +      if (!item.MetadataProperties.TryGetValue(propertyName, true, out property))
          185  +      {
          186  +        return default(T);
          187  +      }
          188  +
          189  +      return (T)property.Value;
          190  +    }
          191  +
          192  +    internal static bool IsPrimitiveType(TypeUsage type, PrimitiveTypeKind primitiveType)
          193  +    {
          194  +      PrimitiveTypeKind typeKind;
          195  +      if (TryGetPrimitiveTypeKind(type, out typeKind))
          196  +      {
          197  +        return (typeKind == primitiveType);
          198  +      }
          199  +      return false;
          200  +    }
          201  +
          202  +    internal static DbType GetDbType(PrimitiveTypeKind primitiveType)
          203  +    {
          204  +      switch (primitiveType)
          205  +      {
          206  +        case PrimitiveTypeKind.Binary: return DbType.Binary;
          207  +        case PrimitiveTypeKind.Boolean: return DbType.Boolean;
          208  +        case PrimitiveTypeKind.Byte: return DbType.Byte;
          209  +        case PrimitiveTypeKind.DateTime: return DbType.DateTime;
          210  +        case PrimitiveTypeKind.Decimal: return DbType.Decimal;
          211  +        case PrimitiveTypeKind.Double: return DbType.Double;
          212  +        case PrimitiveTypeKind.Single: return DbType.Single;
          213  +        case PrimitiveTypeKind.Guid: return DbType.Guid;
          214  +        case PrimitiveTypeKind.Int16: return DbType.Int16;
          215  +        case PrimitiveTypeKind.Int32: return DbType.Int32;
          216  +        case PrimitiveTypeKind.Int64: return DbType.Int64;
          217  +        //case PrimitiveTypeKind.Money: return DbType.Decimal;
          218  +        case PrimitiveTypeKind.SByte: return DbType.SByte;
          219  +        case PrimitiveTypeKind.String: return DbType.String;
          220  +        //case PrimitiveTypeKind.UInt16: return DbType.UInt16;
          221  +        //case PrimitiveTypeKind.UInt32: return DbType.UInt32;
          222  +        //case PrimitiveTypeKind.UInt64: return DbType.UInt64;
          223  +        //case PrimitiveTypeKind.Xml: return DbType.Xml;
          224  +        default:
          225  +          Debug.Fail("unknown PrimitiveTypeKind" + primitiveType.ToString());
          226  +          throw new InvalidOperationException(string.Format("Unknown PrimitiveTypeKind {0}", primitiveType));
          227  +      }
          228  +    }
          229  +
          230  +    #endregion
          231  +
          232  +    #region Facet Support
          233  +    internal static readonly int UnicodeStringMaxMaxLength = Int32.MaxValue;
          234  +    internal static readonly int AsciiStringMaxMaxLength = Int32.MaxValue;
          235  +    internal static readonly int BinaryMaxMaxLength = Int32.MaxValue;
          236  +
          237  +    #region Facet Names
          238  +    /// <summary>
          239  +    /// Name of the MaxLength Facet
          240  +    /// </summary>
          241  +    public static readonly string MaxLengthFacetName = "MaxLength";
          242  +
          243  +    /// <summary>
          244  +    /// Name of the Unicode Facet
          245  +    /// </summary>
          246  +    public static readonly string UnicodeFacetName = "Unicode";
          247  +
          248  +    /// <summary>
          249  +    /// Name of the FixedLength Facet
          250  +    /// </summary>
          251  +    public static readonly string FixedLengthFacetName = "FixedLength";
          252  +
          253  +    /// <summary>
          254  +    /// Name of the PreserveSeconds Facet
          255  +    /// </summary>
          256  +    public static readonly string PreserveSecondsFacetName = "PreserveSeconds";
          257  +
          258  +    /// <summary>
          259  +    /// Name of the Precision Facet
          260  +    /// </summary>
          261  +    public static readonly string PrecisionFacetName = "Precision";
          262  +
          263  +    /// <summary>
          264  +    /// Name of the Scale Facet
          265  +    /// </summary>
          266  +    public static readonly string ScaleFacetName = "Scale";
          267  +
          268  +    /// <summary>
          269  +    /// Name of the DefaultValue Facet
          270  +    /// </summary>
          271  +    public static readonly string DefaultValueFacetName = "DefaultValue";
          272  +
          273  +    /// <summary>
          274  +    /// Name of the Nullable Facet
          275  +    /// </summary>
          276  +    internal const string NullableFacetName = "Nullable";
          277  +    #endregion
          278  +
          279  +    #region Facet Retreival Helpers
          280  +
          281  +    /// <summary>
          282  +    /// Get the value specified on the given type usage for the given facet name.
          283  +    /// If the faces does not have a value specifid or that value is null returns
          284  +    /// the default value for that facet.
          285  +    /// </summary>
          286  +    /// <typeparam name="T"></typeparam>
          287  +    /// <param name="type"></param>
          288  +    /// <param name="facetName"></param>
          289  +    /// <returns></returns>
          290  +    /// <summary>
          291  +    /// Get the value specified on the given type usage for the given facet name.
          292  +    /// If the faces does not have a value specifid or that value is null returns
          293  +    /// the default value for that facet.
          294  +    /// </summary>
          295  +    /// <typeparam name="T"></typeparam>
          296  +    /// <param name="type"></param>
          297  +    /// <param name="facetName"></param>
          298  +    /// <returns></returns>
          299  +    internal static T GetFacetValueOrDefault<T>(TypeUsage type, string facetName, T defaultValue)
          300  +    {
          301  +      //Get the value for the facet, if any
          302  +      Facet facet;
          303  +      if (type.Facets.TryGetValue(facetName, false, out facet) && facet.Value != null && !facet.IsUnbounded)
          304  +      {
          305  +        return (T)facet.Value;
          306  +      }
          307  +      else
          308  +      {
          309  +        return defaultValue;
          310  +      }
          311  +    }
          312  +
          313  +    internal static bool IsFacetValueConstant(TypeUsage type, string facetName)
          314  +    {
          315  +      return MetadataHelpers.GetFacet(((PrimitiveType)type.EdmType).FacetDescriptions, facetName).IsConstant;
          316  +    }
          317  +
          318  +    private static FacetDescription GetFacet(IEnumerable<FacetDescription> facetCollection, string facetName)
          319  +    {
          320  +      foreach (FacetDescription facetDescription in facetCollection)
          321  +      {
          322  +        if (facetDescription.FacetName == facetName)
          323  +        {
          324  +          return facetDescription;
          325  +        }
          326  +      }
          327  +
          328  +      return null;
          329  +    }
          330  +
          331  +    /// <summary>
          332  +    /// Given a facet name and an EdmType, tries to get that facet's description.
          333  +    /// </summary>
          334  +    /// <param name="edmType"></param>
          335  +    /// <param name="facetName"></param>
          336  +    /// <param name="facetDescription"></param>
          337  +    /// <returns></returns>
          338  +    internal static bool TryGetTypeFacetDescriptionByName(EdmType edmType, string facetName, out FacetDescription facetDescription)
          339  +    {
          340  +      facetDescription = null;
          341  +      if (MetadataHelpers.IsPrimitiveType(edmType))
          342  +      {
          343  +        PrimitiveType primitiveType = (PrimitiveType)edmType;
          344  +        foreach (FacetDescription fd in primitiveType.FacetDescriptions)
          345  +        {
          346  +          if (facetName.Equals(fd.FacetName, StringComparison.OrdinalIgnoreCase))
          347  +          {
          348  +            facetDescription = fd;
          349  +            return true;
          350  +          }
          351  +        }
          352  +      }
          353  +      return false;
          354  +    }
          355  +
          356  +    internal static bool IsNullable(TypeUsage type)
          357  +    {
          358  +      Facet nullableFacet;
          359  +      if (type.Facets.TryGetValue(NullableFacetName, false, out nullableFacet))
          360  +      {
          361  +        return (bool)nullableFacet.Value;
          362  +      }
          363  +      return false;
          364  +    }
          365  +
          366  +    internal static bool TryGetMaxLength(TypeUsage type, out int maxLength)
          367  +    {
          368  +      if (!IsPrimitiveType(type, PrimitiveTypeKind.String) &&
          369  +          !IsPrimitiveType(type, PrimitiveTypeKind.Binary))
          370  +      {
          371  +        maxLength = 0;
          372  +        return false;
          373  +      }
          374  +
          375  +      // Binary and String FixedLength facets share the same name
          376  +      return TryGetIntFacetValue(type, MaxLengthFacetName, out maxLength);
          377  +    }
          378  +
          379  +    internal static bool TryGetIntFacetValue(TypeUsage type, string facetName, out int intValue)
          380  +    {
          381  +      intValue = 0;
          382  +      Facet intFacet;
          383  +
          384  +      if (type.Facets.TryGetValue(facetName, false, out intFacet) && intFacet.Value != null && !intFacet.IsUnbounded)
          385  +      {
          386  +        intValue = (int)intFacet.Value;
          387  +        return true;
          388  +      }
          389  +
          390  +      return false;
          391  +    }
          392  +
          393  +    internal static bool TryGetIsFixedLength(TypeUsage type, out bool isFixedLength)
          394  +    {
          395  +      if (!IsPrimitiveType(type, PrimitiveTypeKind.String) &&
          396  +          !IsPrimitiveType(type, PrimitiveTypeKind.Binary))
          397  +      {
          398  +        isFixedLength = false;
          399  +        return false;
          400  +      }
          401  +
          402  +      // Binary and String MaxLength facets share the same name
          403  +      return TryGetBooleanFacetValue(type, FixedLengthFacetName, out isFixedLength);
          404  +    }
          405  +
          406  +    internal static bool TryGetBooleanFacetValue(TypeUsage type, string facetName, out bool boolValue)
          407  +    {
          408  +      boolValue = false;
          409  +      Facet boolFacet;
          410  +      if (type.Facets.TryGetValue(facetName, false, out boolFacet) && boolFacet.Value != null)
          411  +      {
          412  +        boolValue = (bool)boolFacet.Value;
          413  +        return true;
          414  +      }
          415  +
          416  +      return false;
          417  +    }
          418  +
          419  +    internal static bool TryGetIsUnicode(TypeUsage type, out bool isUnicode)
          420  +    {
          421  +      if (!IsPrimitiveType(type, PrimitiveTypeKind.String))
          422  +      {
          423  +        isUnicode = false;
          424  +        return false;
          425  +      }
          426  +
          427  +      return TryGetBooleanFacetValue(type, UnicodeFacetName, out isUnicode);
          428  +    }
          429  +
          430  +    #endregion
          431  +
          432  +    #endregion
          433  +
          434  +    internal static bool IsCanonicalFunction(EdmFunction function)
          435  +    {
          436  +      return (function.NamespaceName == "Edm");
          437  +    }
          438  +
          439  +    internal static bool IsStoreFunction(EdmFunction function)
          440  +    {
          441  +      return !IsCanonicalFunction(function);
          442  +    }
          443  +
          444  +    // Returns ParameterDirection corresponding to given ParameterMode
          445  +    internal static ParameterDirection ParameterModeToParameterDirection(ParameterMode mode)
          446  +    {
          447  +      switch (mode)
          448  +      {
          449  +        case ParameterMode.In:
          450  +          return ParameterDirection.Input;
          451  +
          452  +        case ParameterMode.InOut:
          453  +          return ParameterDirection.InputOutput;
          454  +
          455  +        case ParameterMode.Out:
          456  +          return ParameterDirection.Output;
          457  +
          458  +        case ParameterMode.ReturnValue:
          459  +          return ParameterDirection.ReturnValue;
          460  +
          461  +        default:
          462  +          Debug.Fail("unrecognized mode " + mode.ToString());
          463  +          return default(ParameterDirection);
          464  +      }
          465  +    }
          466  +  }
          467  +}

Added System.Data.SQLite.Linq/SQL Generation/SqlBuilder.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="SqlBuilder.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Collections.Generic;
           15  +  using System.Diagnostics;
           16  +  using System.IO;
           17  +  using System.Text;
           18  +  using System.Data.Metadata.Edm;
           19  +  using System.Data.Common.CommandTrees;
           20  +
           21  +  /// <summary>
           22  +  /// This class is like StringBuilder.  While traversing the tree for the first time, 
           23  +  /// we do not know all the strings that need to be appended e.g. things that need to be
           24  +  /// renamed, nested select statements etc.  So, we use a builder that can collect
           25  +  /// all kinds of sql fragments.
           26  +  /// </summary>
           27  +  internal sealed class SqlBuilder : ISqlFragment
           28  +  {
           29  +    private List<object> _sqlFragments;
           30  +    private List<object> sqlFragments
           31  +    {
           32  +      get
           33  +      {
           34  +        if (null == _sqlFragments)
           35  +        {
           36  +          _sqlFragments = new List<object>();
           37  +        }
           38  +        return _sqlFragments;
           39  +      }
           40  +    }
           41  +
           42  +
           43  +    /// <summary>
           44  +    /// Add an object to the list - we do not verify that it is a proper sql fragment
           45  +    /// since this is an internal method.
           46  +    /// </summary>
           47  +    /// <param name="s"></param>
           48  +    public void Append(object s)
           49  +    {
           50  +      Debug.Assert(s != null);
           51  +      sqlFragments.Add(s);
           52  +    }
           53  +
           54  +    /// <summary>
           55  +    /// This is to pretty print the SQL.  The writer <see cref="SqlWriter.Write"/>
           56  +    /// needs to know about new lines so that it can add the right amount of 
           57  +    /// indentation at the beginning of lines.
           58  +    /// </summary>
           59  +    public void AppendLine()
           60  +    {
           61  +      sqlFragments.Add("\r\n");
           62  +    }
           63  +
           64  +    /// <summary>
           65  +    /// Whether the builder is empty.  This is used by the <see cref="SqlGenerator.Visit(DbProjectExpression)"/>
           66  +    /// to determine whether a sql statement can be reused.
           67  +    /// </summary>
           68  +    public bool IsEmpty
           69  +    {
           70  +      get { return ((null == _sqlFragments) || (0 == _sqlFragments.Count)); }
           71  +    }
           72  +
           73  +    #region ISqlFragment Members
           74  +
           75  +    /// <summary>
           76  +    /// We delegate the writing of the fragment to the appropriate type.
           77  +    /// </summary>
           78  +    /// <param name="writer"></param>
           79  +    /// <param name="sqlGenerator"></param>
           80  +    public void WriteSql(SqlWriter writer, SqlGenerator sqlGenerator)
           81  +    {
           82  +      if (null != _sqlFragments)
           83  +      {
           84  +        foreach (object o in _sqlFragments)
           85  +        {
           86  +          string str = (o as String);
           87  +          if (null != str)
           88  +          {
           89  +            writer.Write(str);
           90  +          }
           91  +          else
           92  +          {
           93  +            ISqlFragment sqlFragment = (o as ISqlFragment);
           94  +            if (null != sqlFragment)
           95  +            {
           96  +              sqlFragment.WriteSql(writer, sqlGenerator);
           97  +            }
           98  +            else
           99  +            {
          100  +              throw new InvalidOperationException();
          101  +            }
          102  +          }
          103  +        }
          104  +      }
          105  +    }
          106  +
          107  +    #endregion
          108  +  }
          109  +}

Deleted System.Data.SQLite.Linq/SQL Generation/SqlChecker.cs.


Added System.Data.SQLite.Linq/SQL Generation/SqlGenerator.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="SqlGenerator.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Linq;
           15  +  using System.Diagnostics;
           16  +  using System.Globalization;
           17  +  using System.IO;
           18  +  using System.Text;
           19  +  using System.Data.Common;
           20  +  using System.Data.Metadata.Edm;
           21  +  using System.Data.Common.CommandTrees;
           22  +  using System.Data;
           23  +  using System.Collections.ObjectModel;
           24  +  using System.Collections.Generic;
           25  +
           26  +  /// <summary>
           27  +  /// Translates the command object into a SQL string that can be executed on
           28  +  /// SQLite.
           29  +  /// </summary>
           30  +  /// <remarks>
           31  +  /// The translation is implemented as a visitor <see cref="DbExpressionVisitor{T}"/>
           32  +  /// over the query tree.  It makes a single pass over the tree, collecting the sql
           33  +  /// fragments for the various nodes in the tree <see cref="ISqlFragment"/>.
           34  +  ///
           35  +  /// The major operations are
           36  +  /// <list type="bullet">
           37  +  /// <item>Select statement minimization.  Multiple nodes in the query tree
           38  +  /// that can be part of a single SQL select statement are merged. e.g. a
           39  +  /// Filter node that is the input of a Project node can typically share the
           40  +  /// same SQL statement.</item>
           41  +  /// <item>Alpha-renaming.  As a result of the statement minimization above, there
           42  +  /// could be name collisions when using correlated subqueries
           43  +  /// <example>
           44  +  /// <code>
           45  +  /// Filter(
           46  +  ///     b = Project( c.x
           47  +  ///         c = Extent(foo)
           48  +  ///         )
           49  +  ///     exists (
           50  +  ///         Filter(
           51  +  ///             c = Extent(foo)
           52  +  ///             b.x = c.x
           53  +  ///             )
           54  +  ///     )
           55  +  /// )
           56  +  /// </code>
           57  +  /// The first Filter, Project and Extent will share the same SQL select statement.
           58  +  /// The alias for the Project i.e. b, will be replaced with c.
           59  +  /// If the alias c for the Filter within the exists clause is not renamed,
           60  +  /// we will get <c>c.x = c.x</c>, which is incorrect.
           61  +  /// Instead, the alias c within the second filter should be renamed to c1, to give
           62  +  /// <c>c.x = c1.x</c> i.e. b is renamed to c, and c is renamed to c1.
           63  +  /// </example>
           64  +  /// </item>
           65  +  /// <item>Join flattening.  In the query tree, a list of join nodes is typically
           66  +  /// represented as a tree of Join nodes, each with 2 children. e.g.
           67  +  /// <example>
           68  +  /// <code>
           69  +  /// a = Join(InnerJoin
           70  +  ///     b = Join(CrossJoin
           71  +  ///         c = Extent(foo)
           72  +  ///         d = Extent(foo)
           73  +  ///         )
           74  +  ///     e = Extent(foo)
           75  +  ///     on b.c.x = e.x
           76  +  ///     )
           77  +  /// </code>
           78  +  /// If translated directly, this will be translated to
           79  +  /// <code>
           80  +  /// FROM ( SELECT c.*, d.*
           81  +  ///         FROM foo as c
           82  +  ///         CROSS JOIN foo as d) as b
           83  +  /// INNER JOIN foo as e on b.x' = e.x
           84  +  /// </code>
           85  +  /// It would be better to translate this as
           86  +  /// <code>
           87  +  /// FROM foo as c
           88  +  /// CROSS JOIN foo as d
           89  +  /// INNER JOIN foo as e on c.x = e.x
           90  +  /// </code>
           91  +  /// This allows the optimizer to choose an appropriate join ordering for evaluation.
           92  +  /// </example>
           93  +  /// </item>
           94  +  /// <item>Select * and column renaming.  In the example above, we noticed that
           95  +  /// in some cases we add <c>SELECT * FROM ...</c> to complete the SQL
           96  +  /// statement. i.e. there is no explicit PROJECT list.
           97  +  /// In this case, we enumerate all the columns available in the FROM clause
           98  +  /// This is particularly problematic in the case of Join trees, since the columns
           99  +  /// from the extents joined might have the same name - this is illegal.  To solve
          100  +  /// this problem, we will have to rename columns if they are part of a SELECT *
          101  +  /// for a JOIN node - we do not need renaming in any other situation.
          102  +  /// <see cref="SqlGenerator.AddDefaultColumns"/>.
          103  +  /// </item>
          104  +  /// </list>
          105  +  ///
          106  +  /// <para>
          107  +  /// Renaming issues.
          108  +  /// When rows or columns are renamed, we produce names that are unique globally
          109  +  /// with respect to the query.  The names are derived from the original names,
          110  +  /// with an integer as a suffix. e.g. CustomerId will be renamed to CustomerId1,
          111  +  /// CustomerId2 etc.
          112  +  ///
          113  +  /// Since the names generated are globally unique, they will not conflict when the
          114  +  /// columns of a JOIN SELECT statement are joined with another JOIN. 
          115  +  ///
          116  +  /// </para>
          117  +  ///
          118  +  /// <para>
          119  +  /// Record flattening.
          120  +  /// SQL server does not have the concept of records.  However, a join statement
          121  +  /// produces records.  We have to flatten the record accesses into a simple
          122  +  /// <c>alias.column</c> form.  <see cref="SqlGenerator.Visit(DbPropertyExpression)"/>
          123  +  /// </para>
          124  +  ///
          125  +  /// <para>
          126  +  /// Building the SQL.
          127  +  /// There are 2 phases
          128  +  /// <list type="numbered">
          129  +  /// <item>Traverse the tree, producing a sql builder <see cref="SqlBuilder"/></item>
          130  +  /// <item>Write the SqlBuilder into a string, renaming the aliases and columns
          131  +  /// as needed.</item>
          132  +  /// </list>
          133  +  ///
          134  +  /// In the first phase, we traverse the tree.  We cannot generate the SQL string
          135  +  /// right away, since
          136  +  /// <list type="bullet">
          137  +  /// <item>The WHERE clause has to be visited before the from clause.</item>
          138  +  /// <item>extent aliases and column aliases need to be renamed.  To minimize
          139  +  /// renaming collisions, all the names used must be known, before any renaming
          140  +  /// choice is made.</item>
          141  +  /// </list>
          142  +  /// To defer the renaming choices, we use symbols <see cref="Symbol"/>.  These
          143  +  /// are renamed in the second phase.
          144  +  ///
          145  +  /// Since visitor methods cannot transfer information to child nodes through
          146  +  /// parameters, we use some global stacks,
          147  +  /// <list type="bullet">
          148  +  /// <item>A stack for the current SQL select statement.  This is needed by
          149  +  /// <see cref="SqlGenerator.Visit(DbVariableReferenceExpression)"/> to create a
          150  +  /// list of free variables used by a select statement.  This is needed for
          151  +  /// alias renaming.
          152  +  /// </item>
          153  +  /// <item>A stack for the join context.  When visiting a <see cref="DbScanExpression"/>,
          154  +  /// we need to know whether we are inside a join or not.  If we are inside
          155  +  /// a join, we do not create a new SELECT statement.</item>
          156  +  /// </list>
          157  +  /// </para>
          158  +  ///
          159  +  /// <para>
          160  +  /// Global state.
          161  +  /// To enable renaming, we maintain
          162  +  /// <list type="bullet">
          163  +  /// <item>The set of all extent aliases used.</item>
          164  +  /// <item>The set of all column aliases used.</item>
          165  +  /// </list>
          166  +  ///
          167  +  /// Finally, we have a symbol table to lookup variable references.  All references
          168  +  /// to the same extent have the same symbol.
          169  +  /// </para>
          170  +  ///
          171  +  /// <para>
          172  +  /// Sql select statement sharing.
          173  +  ///
          174  +  /// Each of the relational operator nodes
          175  +  /// <list type="bullet">
          176  +  /// <item>Project</item>
          177  +  /// <item>Filter</item>
          178  +  /// <item>GroupBy</item>
          179  +  /// <item>Sort/OrderBy</item>
          180  +  /// </list>
          181  +  /// can add its non-input (e.g. project, predicate, sort order etc.) to
          182  +  /// the SQL statement for the input, or create a new SQL statement.
          183  +  /// If it chooses to reuse the input's SQL statement, we play the following
          184  +  /// symbol table trick to accomplish renaming.  The symbol table entry for
          185  +  /// the alias of the current node points to the symbol for the input in
          186  +  /// the input's SQL statement.
          187  +  /// <example>
          188  +  /// <code>
          189  +  /// Project(b.x
          190  +  ///     b = Filter(
          191  +  ///         c = Extent(foo)
          192  +  ///         c.x = 5)
          193  +  ///     )
          194  +  /// </code>
          195  +  /// The Extent node creates a new SqlSelectStatement.  This is added to the
          196  +  /// symbol table by the Filter as {c, Symbol(c)}.  Thus, <c>c.x</c> is resolved to
          197  +  /// <c>Symbol(c).x</c>.
          198  +  /// Looking at the project node, we add {b, Symbol(c)} to the symbol table if the
          199  +  /// SQL statement is reused, and {b, Symbol(b)}, if there is no reuse.
          200  +  ///
          201  +  /// Thus, <c>b.x</c> is resolved to <c>Symbol(c).x</c> if there is reuse, and to
          202  +  /// <c>Symbol(b).x</c> if there is no reuse.
          203  +  /// </example>
          204  +  /// </para>
          205  +  /// </remarks>
          206  +  internal sealed class SqlGenerator : DbExpressionVisitor<ISqlFragment>
          207  +  {
          208  +    private SQLiteProviderManifest _manifest;
          209  +
          210  +    #region Visitor parameter stacks
          211  +    /// <summary>
          212  +    /// Every relational node has to pass its SELECT statement to its children
          213  +    /// This allows them (DbVariableReferenceExpression eventually) to update the list of
          214  +    /// outer extents (free variables) used by this select statement.
          215  +    /// </summary>
          216  +    Stack<SqlSelectStatement> selectStatementStack;
          217  +
          218  +    /// <summary>
          219  +    /// The top of the stack
          220  +    /// </summary>
          221  +    private SqlSelectStatement CurrentSelectStatement
          222  +    {
          223  +      // There is always something on the stack, so we can always Peek.
          224  +      get { return selectStatementStack.Peek(); }
          225  +    }
          226  +
          227  +    /// <summary>
          228  +    /// Nested joins and extents need to know whether they should create
          229  +    /// a new Select statement, or reuse the parent's.  This flag
          230  +    /// indicates whether the parent is a join or not.
          231  +    /// </summary>
          232  +    Stack<bool> isParentAJoinStack;
          233  +
          234  +    /// <summary>
          235  +    /// The top of the stack
          236  +    /// </summary>
          237  +    private bool IsParentAJoin
          238  +    {
          239  +      // There might be no entry on the stack if a Join node has never
          240  +      // been seen, so we return false in that case.
          241  +      get { return isParentAJoinStack.Count == 0 ? false : isParentAJoinStack.Peek(); }
          242  +    }
          243  +
          244  +    #endregion
          245  +
          246  +    #region Global lists and state
          247  +    Dictionary<string, int> allExtentNames;
          248  +    internal Dictionary<string, int> AllExtentNames
          249  +    {
          250  +      get { return allExtentNames; }
          251  +    }
          252  +
          253  +    // For each column name, we store the last integer suffix that
          254  +    // was added to produce a unique column name.  This speeds up
          255  +    // the creation of the next unique name for this column name.
          256  +    Dictionary<string, int> allColumnNames;
          257  +    internal Dictionary<string, int> AllColumnNames
          258  +    {
          259  +      get { return allColumnNames; }
          260  +    }
          261  +
          262  +    SymbolTable symbolTable = new SymbolTable();
          263  +
          264  +    /// <summary>
          265  +    /// VariableReferenceExpressions are allowed only as children of DbPropertyExpression
          266  +    /// or MethodExpression.  The cheapest way to ensure this is to set the following
          267  +    /// property in DbVariableReferenceExpression and reset it in the allowed parent expressions.
          268  +    /// </summary>
          269  +    bool isVarRefSingle = false;
          270  +
          271  +    #endregion
          272  +
          273  +    private bool HasBuiltMapForIn(DbExpression e, KeyToListMap<DbExpression, DbExpression> values)
          274  +    {
          275  +      DbExpressionKind expressionKind = e.ExpressionKind;
          276  +      if (expressionKind != DbExpressionKind.Equals)
          277  +      {
          278  +        if (expressionKind != DbExpressionKind.IsNull)
          279  +        {
          280  +          if (expressionKind != DbExpressionKind.Or)
          281  +          {
          282  +            return false;
          283  +          }
          284  +          DbBinaryExpression expression2 = e as DbBinaryExpression;
          285  +          return (this.HasBuiltMapForIn(expression2.Left, values) && this.HasBuiltMapForIn(expression2.Right, values));
          286  +        }
          287  +      }
          288  +      else
          289  +      {
          290  +        return this.TryAddExpressionForIn((DbBinaryExpression)e, values);
          291  +      }
          292  +      DbExpression argument = ((DbIsNullExpression)e).Argument;
          293  +      if (this.IsKeyForIn(argument))
          294  +      {
          295  +        values.Add(argument, e);
          296  +        return true;
          297  +      }
          298  +      return false;
          299  +    }
          300  +
          301  +    #region Statics
          302  +    static private readonly Dictionary<string, FunctionHandler> _builtInFunctionHandlers = InitializeBuiltInFunctionHandlers();
          303  +    static private readonly Dictionary<string, FunctionHandler> _canonicalFunctionHandlers = InitializeCanonicalFunctionHandlers();
          304  +    static private readonly Dictionary<string, string> _functionNameToOperatorDictionary = InitializeFunctionNameToOperatorDictionary();
          305  +    static private readonly Dictionary<string, string> _datepartKeywords = InitializeDatepartKeywords();
          306  +    static private readonly char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
          307  +
          308  +    private delegate ISqlFragment FunctionHandler(SqlGenerator sqlgen, DbFunctionExpression functionExpr);
          309  +
          310  +    /// <summary>
          311  +    /// All special built-in functions and their handlers
          312  +    /// </summary>
          313  +    /// <returns></returns>
          314  +    private static Dictionary<string, FunctionHandler> InitializeBuiltInFunctionHandlers()
          315  +    {
          316  +      Dictionary<string, FunctionHandler> functionHandlers = new Dictionary<string, FunctionHandler>(7, StringComparer.Ordinal);
          317  +      functionHandlers.Add("CONCAT", HandleConcatFunction);
          318  +      functionHandlers.Add("DATEPART", HandleDatepartDateFunction);
          319  +      functionHandlers.Add("DatePart", HandleDatepartDateFunction);
          320  +      functionHandlers.Add("GETDATE", HandleGetDateFunction);
          321  +      functionHandlers.Add("GETUTCDATE", HandleGetUtcDateFunction);
          322  +      return functionHandlers;
          323  +    }
          324  +
          325  +    /// <summary>
          326  +    /// All special non-aggregate canonical functions and their handlers
          327  +    /// </summary>
          328  +    /// <returns></returns>
          329  +    private static Dictionary<string, FunctionHandler> InitializeCanonicalFunctionHandlers()
          330  +    {
          331  +      Dictionary<string, FunctionHandler> functionHandlers = new Dictionary<string, FunctionHandler>(16, StringComparer.Ordinal);
          332  +      functionHandlers.Add("IndexOf", HandleCanonicalFunctionIndexOf);
          333  +      functionHandlers.Add("Length", HandleCanonicalFunctionLength);
          334  +      functionHandlers.Add("NewGuid", HandleCanonicalFunctionNewGuid);
          335  +      functionHandlers.Add("Round", HandleCanonicalFunctionRound);
          336  +      functionHandlers.Add("ToLower", HandleCanonicalFunctionToLower);
          337  +      functionHandlers.Add("ToUpper", HandleCanonicalFunctionToUpper);
          338  +      functionHandlers.Add("Trim", HandleCanonicalFunctionTrim);
          339  +      functionHandlers.Add("CurrentDateTime", HandleGetDateFunction);
          340  +      functionHandlers.Add("CurrentUtcDateTime", HandleGetUtcDateFunction);
          341  +
          342  +      //DatePartFunctions
          343  +      functionHandlers.Add("Year", HandleCanonicalFunctionDatepart);
          344  +      functionHandlers.Add("Month", HandleCanonicalFunctionDatepart);
          345  +      functionHandlers.Add("Day", HandleCanonicalFunctionDatepart);
          346  +      functionHandlers.Add("Hour", HandleCanonicalFunctionDatepart);
          347  +      functionHandlers.Add("Minute", HandleCanonicalFunctionDatepart);
          348  +      functionHandlers.Add("Second", HandleCanonicalFunctionDatepart);
          349  +      functionHandlers.Add("DateAdd", HandleCanonicalFunctionDateAdd);
          350  +      functionHandlers.Add("DateDiff", HandleCanonicalFunctionDateSubtract);
          351  +      functionHandlers.Add("DATEADD", HandleCanonicalFunctionDateAdd); // store
          352  +      functionHandlers.Add("DATEDIFF", HandleCanonicalFunctionDateSubtract); // store
          353  +
          354  +      //Functions that translate to operators
          355  +      functionHandlers.Add("Concat", HandleConcatFunction);
          356  +      functionHandlers.Add("BitwiseAnd", HandleCanonicalFunctionBitwise);
          357  +      functionHandlers.Add("BitwiseNot", HandleCanonicalFunctionBitwise);
          358  +      functionHandlers.Add("BitwiseOr", HandleCanonicalFunctionBitwise);
          359  +      functionHandlers.Add("BitwiseXor", HandleCanonicalFunctionBitwise);
          360  +      return functionHandlers;
          361  +    }
          362  +
          363  +    /// <summary>
          364  +    /// Valid datepart values
          365  +    /// </summary>
          366  +    /// <returns></returns>
          367  +    private static Dictionary<string, string> InitializeDatepartKeywords()
          368  +    {
          369  +      #region Datepart Keywords
          370  +      //
          371  +      // valid datepart values
          372  +      //
          373  +      Dictionary<string, string> datepartKeywords = new Dictionary<string, string>(30, StringComparer.OrdinalIgnoreCase);
          374  +      datepartKeywords.Add("d", "%d");
          375  +      datepartKeywords.Add("day", "%d");
          376  +      datepartKeywords.Add("dayofyear", "%j");
          377  +      datepartKeywords.Add("dd", "%d");
          378  +      datepartKeywords.Add("dw", "%w");
          379  +      datepartKeywords.Add("dy", "%j");
          380  +      datepartKeywords.Add("hh", "%H");
          381  +      datepartKeywords.Add("hour", "%H");
          382  +      datepartKeywords.Add("m", "%m");
          383  +      datepartKeywords.Add("mi", "%M");
          384  +      datepartKeywords.Add("millisecond", "%f");
          385  +      datepartKeywords.Add("minute", "%M");
          386  +      datepartKeywords.Add("mm", "%m");
          387  +      datepartKeywords.Add("month", "%m");
          388  +      datepartKeywords.Add("ms", "%f");
          389  +      datepartKeywords.Add("n", "%M");
          390  +      datepartKeywords.Add("s", "%S");
          391  +      datepartKeywords.Add("second", "%S");
          392  +      datepartKeywords.Add("ss", "%S");
          393  +      datepartKeywords.Add("week", "%W");
          394  +      datepartKeywords.Add("weekday", "%w");
          395  +      datepartKeywords.Add("wk", "%W");
          396  +      datepartKeywords.Add("ww", "%W");
          397  +      datepartKeywords.Add("y", "%Y");
          398  +      datepartKeywords.Add("year", "%Y");
          399  +      datepartKeywords.Add("yy", "%Y");
          400  +      datepartKeywords.Add("yyyy", "%Y");
          401  +      return datepartKeywords;
          402  +      #endregion
          403  +    }
          404  +
          405  +    /// <summary>
          406  +    /// Initializes the mapping from functions to T-SQL operators
          407  +    /// for all functions that translate to T-SQL operators
          408  +    /// </summary>
          409  +    /// <returns></returns>
          410  +    private static Dictionary<string, string> InitializeFunctionNameToOperatorDictionary()
          411  +    {
          412  +      Dictionary<string, string> functionNameToOperatorDictionary = new Dictionary<string, string>(5, StringComparer.Ordinal);
          413  +      functionNameToOperatorDictionary.Add("Concat", "||");    //canonical
          414  +      functionNameToOperatorDictionary.Add("CONCAT", "||");    //store
          415  +      functionNameToOperatorDictionary.Add("BitwiseAnd", "&");
          416  +      functionNameToOperatorDictionary.Add("BitwiseNot", "~");
          417  +      functionNameToOperatorDictionary.Add("BitwiseOr", "|");
          418  +      functionNameToOperatorDictionary.Add("BitwiseXor", "^");
          419  +      return functionNameToOperatorDictionary;
          420  +    }
          421  +
          422  +    #endregion
          423  +
          424  +    #region Constructor
          425  +    /// <summary>
          426  +    /// Basic constructor. 
          427  +    /// </summary>
          428  +    private SqlGenerator(SQLiteProviderManifest manifest)
          429  +    {
          430  +      _manifest = manifest;
          431  +    }
          432  +    #endregion
          433  +
          434  +    #region Entry points
          435  +    /// <summary>
          436  +    /// General purpose static function that can be called from System.Data assembly
          437  +    /// </summary>
          438  +    /// <param name="sqlVersion">Server version</param>
          439  +    /// <param name="tree">command tree</param>
          440  +    /// <param name="parameters">Parameters to add to the command tree corresponding
          441  +    /// to constants in the command tree. Used only in ModificationCommandTrees.</param>
          442  +    /// <returns>The string representing the SQL to be executed.</returns>
          443  +    internal static string GenerateSql(SQLiteProviderManifest manifest, DbCommandTree tree, out List<DbParameter> parameters, out CommandType commandType)
          444  +    {
          445  +      commandType = CommandType.Text;
          446  +
          447  +      //Handle Query
          448  +      DbQueryCommandTree queryCommandTree = tree as DbQueryCommandTree;
          449  +      if (queryCommandTree != null)
          450  +      {
          451  +        SqlGenerator sqlGen = new SqlGenerator(manifest);
          452  +        parameters = null;
          453  +        
          454  +        string sql = sqlGen.GenerateSql((DbQueryCommandTree)tree);
          455  +
          456  +        return sql;
          457  +      }
          458  +
          459  +      //Handle Function
          460  +      DbFunctionCommandTree DbFunctionCommandTree = tree as DbFunctionCommandTree;
          461  +      if (DbFunctionCommandTree != null)
          462  +      {
          463  +        SqlGenerator sqlGen = new SqlGenerator(manifest);
          464  +        parameters = null;
          465  +
          466  +        string sql = sqlGen.GenerateFunctionSql(DbFunctionCommandTree, out commandType);
          467  +
          468  +        return sql;
          469  +      }
          470  +
          471  +      //Handle Insert
          472  +      DbInsertCommandTree insertCommandTree = tree as DbInsertCommandTree;
          473  +      if (insertCommandTree != null)
          474  +      {
          475  +        return DmlSqlGenerator.GenerateInsertSql(insertCommandTree, out parameters);
          476  +      }
          477  +
          478  +      //Handle Delete
          479  +      DbDeleteCommandTree deleteCommandTree = tree as DbDeleteCommandTree;
          480  +      if (deleteCommandTree != null)
          481  +      {
          482  +        return DmlSqlGenerator.GenerateDeleteSql(deleteCommandTree, out parameters);
          483  +      }
          484  +
          485  +      //Handle Update
          486  +      DbUpdateCommandTree updateCommandTree = tree as DbUpdateCommandTree;
          487  +      if (updateCommandTree != null)
          488  +      {
          489  +        return DmlSqlGenerator.GenerateUpdateSql(updateCommandTree, out parameters);
          490  +      }
          491  +
          492  +      throw new NotSupportedException("Unrecognized command tree type");
          493  +    }
          494  +    #endregion
          495  +
          496  +    //StringBuilder _typeDefs = new StringBuilder();
          497  +
          498  +    #region Driver Methods
          499  +    /// <summary>
          500  +    /// Translate a command tree to a SQL string.
          501  +    ///
          502  +    /// The input tree could be translated to either a SQL SELECT statement
          503  +    /// or a SELECT expression.  This choice is made based on the return type
          504  +    /// of the expression
          505  +    /// CollectionType => select statement
          506  +    /// non collection type => select expression
          507  +    /// </summary>
          508  +    /// <param name="tree"></param>
          509  +    /// <returns>The string representing the SQL to be executed.</returns>
          510  +    private string GenerateSql(DbQueryCommandTree tree)
          511  +    {
          512  +      tree = SqlChecker.Rewrite(tree);
          513  +      selectStatementStack = new Stack<SqlSelectStatement>();
          514  +      isParentAJoinStack = new Stack<bool>();
          515  +
          516  +      allExtentNames = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
          517  +      allColumnNames = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
          518  +
          519  +      // Literals will not be converted to parameters.
          520  +
          521  +      ISqlFragment result;
          522  +      if (MetadataHelpers.IsCollectionType(tree.Query.ResultType))
          523  +      {
          524  +        SqlSelectStatement sqlStatement = VisitExpressionEnsureSqlStatement(tree.Query);
          525  +        Debug.Assert(sqlStatement != null, "The outer most sql statment is null");
          526  +        sqlStatement.IsTopMost = true;
          527  +        result = sqlStatement;
          528  +
          529  +      }
          530  +      else
          531  +      {
          532  +        SqlBuilder sqlBuilder = new SqlBuilder();
          533  +        sqlBuilder.Append("SELECT ");
          534  +        sqlBuilder.Append(tree.Query.Accept(this));
          535  +
          536  +        result = sqlBuilder;
          537  +      }
          538  +
          539  +      if (isVarRefSingle)
          540  +      {
          541  +        throw new NotSupportedException();
          542  +        // A DbVariableReferenceExpression has to be a child of DbPropertyExpression or MethodExpression
          543  +      }
          544  +
          545  +      // Check that the parameter stacks are not leaking.
          546  +      Debug.Assert(selectStatementStack.Count == 0);
          547  +      Debug.Assert(isParentAJoinStack.Count == 0);
          548  +
          549  +      //if (_typeDefs.Length > 0)
          550  +      //{
          551  +      //  _typeDefs.Insert(0x0, "TYPES ");
          552  +      //  _typeDefs.Append(";\r\n");
          553  +      //  _typeDefs.Append(WriteSql(result));
          554  +      //  return _typeDefs.ToString();
          555  +      //}
          556  +
          557  +      return WriteSql(result);
          558  +    }
          559  +
          560  +    /// <summary>
          561  +    /// Translate a function command tree to a SQL string.
          562  +    /// </summary>
          563  +    private string GenerateFunctionSql(DbFunctionCommandTree tree, out CommandType commandType)
          564  +    {
          565  +      EdmFunction function = tree.EdmFunction;
          566  +
          567  +      // We expect function to always have these properties
          568  +      string userCommandText = (string)function.MetadataProperties["CommandTextAttribute"].Value;
          569  +      //string userSchemaName = (string)function.MetadataProperties["Schema"].Value;
          570  +      string userFuncName = (string)function.MetadataProperties["StoreFunctionNameAttribute"].Value;
          571  +
          572  +      if (String.IsNullOrEmpty(userCommandText))
          573  +      {
          574  +        // build a quoted description of the function
          575  +        commandType = CommandType.StoredProcedure;
          576  +
          577  +        // if the schema name is not explicitly given, it is assumed to be the metadata namespace
          578  +        //string schemaName = String.IsNullOrEmpty(userSchemaName) ?
          579  +        //    function.NamespaceName : userSchemaName;
          580  +
          581  +        // if the function store name is not explicitly given, it is assumed to be the metadata name
          582  +        string functionName = String.IsNullOrEmpty(userFuncName) ?
          583  +            function.Name : userFuncName;
          584  +
          585  +        // quote elements of function text
          586  +        //string quotedSchemaName = QuoteIdentifier(schemaName);
          587  +        string quotedFunctionName = QuoteIdentifier(functionName);
          588  +
          589  +        // separator
          590  +        //const string schemaSeparator = ".";
          591  +
          592  +        // concatenate elements of function text
          593  +        string quotedFunctionText = /* quotedSchemaName + schemaSeparator + */ quotedFunctionName;
          594  +
          595  +        return quotedFunctionText;
          596  +      }
          597  +      else
          598  +      {
          599  +        // if the user has specified the command text, pass it through verbatim and choose CommandType.Text
          600  +        commandType = CommandType.Text;
          601  +        return userCommandText;
          602  +      }
          603  +    }
          604  +
          605  +    /// <summary>
          606  +    /// Convert the SQL fragments to a string.
          607  +    /// We have to setup the Stream for writing.
          608  +    /// </summary>
          609  +    /// <param name="sqlStatement"></param>
          610  +    /// <returns>A string representing the SQL to be executed.</returns>
          611  +    string WriteSql(ISqlFragment sqlStatement)
          612  +    {
          613  +      StringBuilder builder = new StringBuilder(1024);
          614  +      using (SqlWriter writer = new SqlWriter(builder))
          615  +      {
          616  +        sqlStatement.WriteSql(writer, this);
          617  +      }
          618  +
          619  +      return builder.ToString();
          620  +    }
          621  +    #endregion
          622  +
          623  +    private bool TryTranslateIntoIn(DbOrExpression e, out ISqlFragment sqlFragment)
          624  +    {
          625  +      KeyToListMap<DbExpression, DbExpression> values = new KeyToListMap<DbExpression, DbExpression>(KeyFieldExpressionComparer.Singleton);
          626  +      if (!(this.HasBuiltMapForIn(e, values) && (values.Keys.Count<DbExpression>() > 0)))
          627  +      {
          628  +        sqlFragment = null;
          629  +        return false;
          630  +      }
          631  +      SqlBuilder result = new SqlBuilder();
          632  +      bool flag2 = true;
          633  +      foreach (DbExpression expression in values.Keys)
          634  +      {
          635  +        ReadOnlyCollection<DbExpression> source = values.ListForKey(expression);
          636  +        if (!flag2)
          637  +        {
          638  +          result.Append(" OR ");
          639  +        }
          640  +        else
          641  +        {
          642  +          flag2 = false;
          643  +        }
          644  +        IEnumerable<DbExpression> enumerable = source.Where<DbExpression>(delegate(DbExpression v)
          645  +        {
          646  +          return v.ExpressionKind != DbExpressionKind.IsNull;
          647  +        });
          648  +        int num = enumerable.Count<DbExpression>();
          649  +        if (num == 1)
          650  +        {
          651  +          this.ParanthesizeExpressionIfNeeded(expression, result);
          652  +          result.Append(" = ");
          653  +          DbExpression expression2 = enumerable.First<DbExpression>();
          654  +          this.ParenthesizeExpressionWithoutRedundantConstantCasts(expression2, result);
          655  +        }
          656  +        if (num > 1)
          657  +        {
          658  +          this.ParanthesizeExpressionIfNeeded(expression, result);
          659  +          result.Append(" IN (");
          660  +          bool flag3 = true;
          661  +          foreach (DbExpression expression3 in enumerable)
          662  +          {
          663  +            if (!flag3)
          664  +            {
          665  +              result.Append(",");
          666  +            }
          667  +            else
          668  +            {
          669  +              flag3 = false;
          670  +            }
          671  +            this.ParenthesizeExpressionWithoutRedundantConstantCasts(expression3, result);
          672  +          }
          673  +          result.Append(")");
          674  +        }
          675  +        DbIsNullExpression expression4 = source.FirstOrDefault<DbExpression>(delegate(DbExpression v)
          676  +        {
          677  +          return (v.ExpressionKind == DbExpressionKind.IsNull);
          678  +        }) as DbIsNullExpression;
          679  +        if (expression4 != null)
          680  +        {
          681  +          if (num > 0)
          682  +          {
          683  +            result.Append(" OR ");
          684  +          }
          685  +          result.Append(this.VisitIsNullExpression(expression4, false));
          686  +        }
          687  +      }
          688  +      sqlFragment = result;
          689  +      return true;
          690  +    }
          691  +
          692  +    #region DbExpressionVisitor Members
          693  +
          694  +    /// <summary>
          695  +    /// Translate(left) AND Translate(right)
          696  +    /// </summary>
          697  +    /// <param name="e"></param>
          698  +    /// <returns>A <see cref="SqlBuilder"/>.</returns>
          699  +    public override ISqlFragment Visit(DbAndExpression e)
          700  +    {
          701  +      return VisitBinaryExpression(" AND ", e.Left, e.Right);
          702  +    }
          703  +
          704  +    /// <summary>
          705  +    /// An apply is just like a join, so it shares the common join processing
          706  +    /// in <see cref="VisitJoinExpression"/>
          707  +    /// </summary>
          708  +    /// <param name="e"></param>
          709  +    /// <returns>A <see cref="SqlSelectStatement"/>.</returns>
          710  +    public override ISqlFragment Visit(DbApplyExpression e)
          711  +    {
          712  +      throw new NotSupportedException("APPLY joins are not supported");
          713  +    }
          714  +
          715  +    /// <summary>
          716  +    /// For binary expressions, we delegate to <see cref="VisitBinaryExpression"/>.
          717  +    /// We handle the other expressions directly.
          718  +    /// </summary>
          719  +    /// <param name="e"></param>
          720  +    /// <returns>A <see cref="SqlBuilder"/></returns>
          721  +    public override ISqlFragment Visit(DbArithmeticExpression e)
          722  +    {
          723  +      SqlBuilder result;
          724  +
          725  +      switch (e.ExpressionKind)
          726  +      {
          727  +        case DbExpressionKind.Divide:
          728  +          result = VisitBinaryExpression(" / ", e.Arguments[0], e.Arguments[1]);
          729  +          break;
          730  +        case DbExpressionKind.Minus:
          731  +          result = VisitBinaryExpression(" - ", e.Arguments[0], e.Arguments[1]);
          732  +          break;
          733  +        case DbExpressionKind.Modulo:
          734  +          result = VisitBinaryExpression(" % ", e.Arguments[0], e.Arguments[1]);
          735  +          break;
          736  +        case DbExpressionKind.Multiply:
          737  +          result = VisitBinaryExpression(" * ", e.Arguments[0], e.Arguments[1]);
          738  +          break;
          739  +        case DbExpressionKind.Plus:
          740  +          result = VisitBinaryExpression(" + ", e.Arguments[0], e.Arguments[1]);
          741  +          break;
          742  +
          743  +        case DbExpressionKind.UnaryMinus:
          744  +          result = new SqlBuilder();
          745  +          result.Append(" -(");
          746  +          result.Append(e.Arguments[0].Accept(this));
          747  +          result.Append(")");
          748  +          break;
          749  +
          750  +        default:
          751  +          Debug.Assert(false);
          752  +          throw new InvalidOperationException();
          753  +      }
          754  +
          755  +      return result;
          756  +    }
          757  +
          758  +    /// <summary>
          759  +    /// If the ELSE clause is null, we do not write it out.
          760  +    /// </summary>
          761  +    /// <param name="e"></param>
          762  +    /// <returns>A <see cref="SqlBuilder"/></returns>
          763  +    public override ISqlFragment Visit(DbCaseExpression e)
          764  +    {
          765  +      SqlBuilder result = new SqlBuilder();
          766  +
          767  +      Debug.Assert(e.When.Count == e.Then.Count);
          768  +
          769  +      result.Append("CASE");
          770  +      for (int i = 0; i < e.When.Count; ++i)
          771  +      {
          772  +        result.Append(" WHEN (");
          773  +        result.Append(e.When[i].Accept(this));
          774  +        result.Append(") THEN ");
          775  +        result.Append(e.Then[i].Accept(this));
          776  +      }
          777  +      if (e.Else != null && !(e.Else is DbNullExpression))
          778  +      {
          779  +        result.Append(" ELSE ");
          780  +        result.Append(e.Else.Accept(this));
          781  +      }
          782  +
          783  +      result.Append(" END");
          784  +
          785  +      return result;
          786  +    }
          787  +
          788  +    /// <summary>
          789  +    ///
          790  +    /// </summary>
          791  +    /// <param name="e"></param>
          792  +    /// <returns></returns>
          793  +    public override ISqlFragment Visit(DbCastExpression e)
          794  +    {
          795  +      SqlBuilder result = new SqlBuilder();
          796  +      result.Append(e.Argument.Accept(this));
          797  +      return result;
          798  +    }
          799  +
          800  +    /// <summary>
          801  +    /// The parser generates Not(Equals(...)) for &lt;&gt;.
          802  +    /// </summary>
          803  +    /// <param name="e"></param>
          804  +    /// <returns>A <see cref="SqlBuilder"/>.</returns>
          805  +    public override ISqlFragment Visit(DbComparisonExpression e)
          806  +    {
          807  +      SqlBuilder result;
          808  +      switch (e.ExpressionKind)
          809  +      {
          810  +        case DbExpressionKind.Equals:
          811  +            result = VisitBinaryExpression(" = ", e.Left, e.Right);
          812  +          break;
          813  +        case DbExpressionKind.LessThan:
          814  +          result = VisitBinaryExpression(" < ", e.Left, e.Right);
          815  +          break;
          816  +        case DbExpressionKind.LessThanOrEquals:
          817  +          result = VisitBinaryExpression(" <= ", e.Left, e.Right);
          818  +          break;
          819  +        case DbExpressionKind.GreaterThan:
          820  +          result = VisitBinaryExpression(" > ", e.Left, e.Right);
          821  +          break;
          822  +        case DbExpressionKind.GreaterThanOrEquals:
          823  +          result = VisitBinaryExpression(" >= ", e.Left, e.Right);
          824  +          break;
          825  +        // The parser does not generate the expression kind below.
          826  +        case DbExpressionKind.NotEquals:
          827  +          result = VisitBinaryExpression(" <> ", e.Left, e.Right);
          828  +          break;
          829  +
          830  +        default:
          831  +          throw new InvalidOperationException();
          832  +      }
          833  +
          834  +      return result;
          835  +    }
          836  +
          837  +    /// <summary>
          838  +    /// Constants will be send to the store as part of the generated TSQL, not as parameters
          839  +    /// </summary>
          840  +    /// <param name="e"></param>
          841  +    /// <returns>A <see cref="SqlBuilder"/>.  Strings are wrapped in single
          842  +    /// quotes and escaped.  Numbers are written literally.</returns>
          843  +    public override ISqlFragment Visit(DbConstantExpression e)
          844  +    {
          845  +      SqlBuilder result = new SqlBuilder();
          846  +
          847  +      PrimitiveTypeKind typeKind;
          848  +      // Model Types can be (at the time of this implementation):
          849  +      //      Binary, Boolean, Byte, DateTime, Decimal, Double, Guid, Int16, Int32, Int64,Single, String
          850  +      if (MetadataHelpers.TryGetPrimitiveTypeKind(e.ResultType, out typeKind))
          851  +      {
          852  +        switch (typeKind)
          853  +        {
          854  +          case PrimitiveTypeKind.Int32:
          855  +            result.Append(e.Value.ToString());
          856  +            break;
          857  +
          858  +          case PrimitiveTypeKind.Binary:
          859  +            result.Append(" X'");
          860  +            result.Append(ByteArrayToBinaryString((Byte[])e.Value));
          861  +            result.Append("' ");
          862  +            break;
          863  +
          864  +          case PrimitiveTypeKind.Boolean:
          865  +            result.Append((bool)e.Value ? "1" : "0");
          866  +            break;
          867  +
          868  +          case PrimitiveTypeKind.Byte:
          869  +            result.Append(e.Value.ToString());
          870  +            break;
          871  +
          872  +          case PrimitiveTypeKind.DateTime:
          873  +            result.Append(EscapeSingleQuote(((System.DateTime)e.Value).ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture), false /* IsUnicode */));
          874  +            break;
          875  +
          876  +          case PrimitiveTypeKind.Decimal:
          877  +            string strDecimal = ((Decimal)e.Value).ToString(CultureInfo.InvariantCulture);
          878  +            // if the decimal value has no decimal part, cast as decimal to preserve type
          879  +            // if the number has precision > int64 max precision, it will be handled as decimal by sql server
          880  +            // and does not need cast. if precision is lest then 20, then cast using Max(literal precision, sql default precision)
          881  +            if (-1 == strDecimal.IndexOf('.') && (strDecimal.TrimStart(new char[] { '-' }).Length < 20))
          882  +            {
          883  +              byte precision = (Byte)strDecimal.Length;
          884  +              FacetDescription precisionFacetDescription;
          885  +              Debug.Assert(MetadataHelpers.TryGetTypeFacetDescriptionByName(e.ResultType.EdmType, "precision", out precisionFacetDescription), "Decimal primitive type must have Precision facet");
          886  +              if (MetadataHelpers.TryGetTypeFacetDescriptionByName(e.ResultType.EdmType, "precision", out precisionFacetDescription))
          887  +              {
          888  +                if (precisionFacetDescription.DefaultValue != null)
          889  +                {
          890  +                  precision = Math.Max(precision, (byte)precisionFacetDescription.DefaultValue);
          891  +                }
          892  +              }
          893  +              Debug.Assert(precision > 0, "Precision must be greater than zero");
          894  +              result.Append(strDecimal);
          895  +            }
          896  +            else
          897  +            {
          898  +              result.Append(strDecimal);
          899  +            }
          900  +            break;
          901  +
          902  +          case PrimitiveTypeKind.Double:
          903  +            result.Append(((Double)e.Value).ToString(CultureInfo.InvariantCulture));
          904  +            break;
          905  +
          906  +          case PrimitiveTypeKind.Guid:
          907  +            result.Append(EscapeSingleQuote(e.Value.ToString(), false /* IsUnicode */));
          908  +            break;
          909  +
          910  +          case PrimitiveTypeKind.Int16:
          911  +            result.Append(e.Value.ToString());
          912  +            break;
          913  +
          914  +          case PrimitiveTypeKind.Int64:
          915  +            result.Append(e.Value.ToString());
          916  +            break;
          917  +
          918  +          case PrimitiveTypeKind.Single:
          919  +            result.Append(((Single)e.Value).ToString(CultureInfo.InvariantCulture));
          920  +            break;
          921  +
          922  +          case PrimitiveTypeKind.String:
          923  +            bool isUnicode = MetadataHelpers.GetFacetValueOrDefault<bool>(e.ResultType, MetadataHelpers.UnicodeFacetName, true);
          924  +            result.Append(EscapeSingleQuote(e.Value as string, isUnicode));
          925  +            break;
          926  +          case PrimitiveTypeKind.DateTimeOffset:
          927  +            throw new NotSupportedException("datetimeoffset");
          928  +          case PrimitiveTypeKind.Time:
          929  +            throw new NotSupportedException("time");
          930  +          default:
          931  +            // all known scalar types should been handled already.
          932  +            throw new NotSupportedException();
          933  +        }
          934  +      }
          935  +      else
          936  +      {
          937  +        throw new NotSupportedException();
          938  +      }
          939  +
          940  +      return result;
          941  +
          942  +    }
          943  +
          944  +    /// <summary>
          945  +    /// <see cref="DbDerefExpression"/> is illegal at this stage
          946  +    /// </summary>
          947  +    /// <param name="e"></param>
          948  +    /// <returns></returns>
          949  +    public override ISqlFragment Visit(DbDerefExpression e)
          950  +    {
          951  +      throw new NotSupportedException();
          952  +    }
          953  +
          954  +    /// <summary>
          955  +    /// The DISTINCT has to be added to the beginning of SqlSelectStatement.Select,
          956  +    /// but it might be too late for that.  So, we use a flag on SqlSelectStatement
          957  +    /// instead, and add the "DISTINCT" in the second phase.
          958  +    /// </summary>
          959  +    /// <param name="e"></param>
          960  +    /// <returns>A <see cref="SqlSelectStatement"/></returns>
          961  +    public override ISqlFragment Visit(DbDistinctExpression e)
          962  +    {
          963  +      SqlSelectStatement result = VisitExpressionEnsureSqlStatement(e.Argument);
          964  +
          965  +      if (!IsCompatible(result, e.ExpressionKind))
          966  +      {
          967  +        Symbol fromSymbol;
          968  +        TypeUsage inputType = MetadataHelpers.GetElementTypeUsage(e.Argument.ResultType);
          969  +        result = CreateNewSelectStatement(result, "DISTINCT", inputType, out fromSymbol);
          970  +        AddFromSymbol(result, "DISTINCT", fromSymbol, false);
          971  +      }
          972  +
          973  +      result.IsDistinct = true;
          974  +      return result;
          975  +    }
          976  +
          977  +    /// <summary>
          978  +    /// An element expression returns a scalar - so it is translated to
          979  +    /// ( Select ... )
          980  +    /// </summary>
          981  +    /// <param name="e"></param>
          982  +    /// <returns></returns>
          983  +    public override ISqlFragment Visit(DbElementExpression e)
          984  +    {
          985  +      SqlBuilder result = new SqlBuilder();
          986  +      result.Append("(");
          987  +      result.Append(VisitExpressionEnsureSqlStatement(e.Argument));
          988  +      result.Append(")");
          989  +
          990  +      return result;
          991  +    }
          992  +
          993  +    /// <summary>
          994  +    /// <see cref="Visit(DbUnionAllExpression)"/>
          995  +    /// </summary>
          996  +    /// <param name="e"></param>
          997  +    /// <returns></returns>
          998  +    public override ISqlFragment Visit(DbExceptExpression e)
          999  +    {
         1000  +      return VisitSetOpExpression(e.Left, e.Right, "EXCEPT");
         1001  +    }
         1002  +
         1003  +    /// <summary>
         1004  +    /// Only concrete expression types will be visited.
         1005  +    /// </summary>
         1006  +    /// <param name="e"></param>
         1007  +    /// <returns></returns>
         1008  +    public override ISqlFragment Visit(DbExpression e)
         1009  +    {
         1010  +      throw new InvalidOperationException();
         1011  +    }
         1012  +
         1013  +    /// <summary>
         1014  +    ///
         1015  +    /// </summary>
         1016  +    /// <param name="e"></param>
         1017  +    /// <returns>If we are in a Join context, returns a <see cref="SqlBuilder"/>
         1018  +    /// with the extent name, otherwise, a new <see cref="SqlSelectStatement"/>
         1019  +    /// with the From field set.</returns>
         1020  +    public override ISqlFragment Visit(DbScanExpression e)
         1021  +    {
         1022  +      EntitySetBase target = e.Target;
         1023  +
         1024  +      if (IsParentAJoin)
         1025  +      {
         1026  +        SqlBuilder result = new SqlBuilder();
         1027  +        result.Append(GetTargetTSql(target));
         1028  +
         1029  +        return result;
         1030  +      }
         1031  +      else
         1032  +      {
         1033  +        SqlSelectStatement result = new SqlSelectStatement();
         1034  +        result.From.Append(GetTargetTSql(target));
         1035  +
         1036  +        return result;
         1037  +      }
         1038  +    }
         1039  +
         1040  +
         1041  +    /// <summary>
         1042  +    /// Gets escaped TSql identifier describing this entity set.
         1043  +    /// </summary>
         1044  +    /// <returns></returns>
         1045  +    internal static string GetTargetTSql(EntitySetBase entitySetBase)
         1046  +    {
         1047  +      // construct escaped T-SQL referencing entity set
         1048  +      StringBuilder builder = new StringBuilder(50);
         1049  +      string definingQuery = MetadataHelpers.TryGetValueForMetadataProperty<string>(entitySetBase, "DefiningQuery");
         1050  +      if (!string.IsNullOrEmpty(definingQuery))
         1051  +      {
         1052  +        //definingQuery = definingQuery.TrimStart(' ', '\t', '\r', '\n');
         1053  +        //if (String.Compare(definingQuery, 0, "TYPES ", 0, 6, StringComparison.OrdinalIgnoreCase) == 0)
         1054  +        //  definingQuery = definingQuery.Substring(definingQuery.IndexOf(';') + 1).TrimStart(' ', '\t', '\r', '\n');
         1055  +        builder.Append("(");
         1056  +        builder.Append(definingQuery);
         1057  +        builder.Append(")");
         1058  +      }
         1059  +      else
         1060  +      {
         1061  +        //string schemaName = MetadataHelpers.TryGetValueForMetadataProperty<string>(entitySetBase, "Schema");
         1062  +        //if (!string.IsNullOrEmpty(schemaName))
         1063  +        //{
         1064  +        //  builder.Append(SqlGenerator.QuoteIdentifier(schemaName));
         1065  +        //  builder.Append(".");
         1066  +        //}
         1067  +
         1068  +        string tableName = MetadataHelpers.TryGetValueForMetadataProperty<string>(entitySetBase, "Table");
         1069  +        if (!string.IsNullOrEmpty(tableName))
         1070  +        {
         1071  +          builder.Append(SqlGenerator.QuoteIdentifier(tableName));
         1072  +        }
         1073  +        else
         1074  +        {
         1075  +          builder.Append(SqlGenerator.QuoteIdentifier(entitySetBase.Name));
         1076  +        }
         1077  +      }
         1078  +      return builder.ToString();
         1079  +    }
         1080  +
         1081  +    /// <summary>
         1082  +    /// The bodies of <see cref="Visit(DbFilterExpression)"/>, <see cref="Visit(DbGroupByExpression)"/>,
         1083  +    /// <see cref="Visit(DbProjectExpression)"/>, <see cref="Visit(DbSortExpression)"/> are similar.
         1084  +    /// Each does the following.
         1085  +    /// <list type="number">
         1086  +    /// <item> Visit the input expression</item>
         1087  +    /// <item> Determine if the input's SQL statement can be reused, or a new
         1088  +    /// one must be created.</item>
         1089  +    /// <item>Create a new symbol table scope</item>
         1090  +    /// <item>Push the Sql statement onto a stack, so that children can
         1091  +    /// update the free variable list.</item>
         1092  +    /// <item>Visit the non-input expression.</item>
         1093  +    /// <item>Cleanup</item>
         1094  +    /// </list>
         1095  +    /// </summary>
         1096  +    /// <param name="e"></param>
         1097  +    /// <returns>A <see cref="SqlSelectStatement"/></returns>
         1098  +    public override ISqlFragment Visit(DbFilterExpression e)
         1099  +    {
         1100  +      return VisitFilterExpression(e.Input, e.Predicate, false);
         1101  +    }
         1102  +
         1103  +    /// <summary>
         1104  +    /// Lambda functions are not supported.
         1105  +    /// The functions supported are:
         1106  +    /// <list type="number">
         1107  +    /// <item>Canonical Functions - We recognize these by their dataspace, it is DataSpace.CSpace</item>
         1108  +    /// <item>Store Functions - We recognize these by the BuiltInAttribute and not being Canonical</item>
         1109  +    /// <item>User-defined Functions - All the rest except for Lambda functions</item>
         1110  +    /// </list>
         1111  +    /// We handle Canonical and Store functions the same way: If they are in the list of functions 
         1112  +    /// that need special handling, we invoke the appropriate handler, otherwise we translate them to
         1113  +    /// FunctionName(arg1, arg2, ..., argn).
         1114  +    /// We translate user-defined functions to NamespaceName.FunctionName(arg1, arg2, ..., argn).
         1115  +    /// </summary>
         1116  +    /// <param name="e"></param>
         1117  +    /// <returns>A <see cref="SqlBuilder"/></returns>
         1118  +    public override ISqlFragment Visit(DbFunctionExpression e)
         1119  +    {
         1120  +      //
         1121  +      // check if function requires special case processing, if so, delegates to it
         1122  +      //
         1123  +      if (IsSpecialBuiltInFunction(e))
         1124  +      {
         1125  +        return HandleSpecialBuiltInFunction(e);
         1126  +      }
         1127  +
         1128  +      if (IsSpecialCanonicalFunction(e))
         1129  +      {
         1130  +        return HandleSpecialCanonicalFunction(e);
         1131  +      }
         1132  +
         1133  +      return HandleFunctionDefault(e);
         1134  +    }
         1135  +
         1136  +
         1137  +    /// <summary>
         1138  +    /// <see cref="DbEntityRefExpression"/> is illegal at this stage
         1139  +    /// </summary>
         1140  +    /// <param name="e"></param>
         1141  +    /// <returns></returns>
         1142  +    public override ISqlFragment Visit(DbEntityRefExpression e)
         1143  +    {
         1144  +      throw new NotSupportedException();
         1145  +    }
         1146  +
         1147  +    /// <summary>
         1148  +    /// <see cref="DbRefKeyExpression"/> is illegal at this stage
         1149  +    /// </summary>
         1150  +    /// <param name="e"></param>
         1151  +    /// <returns></returns>
         1152  +    public override ISqlFragment Visit(DbRefKeyExpression e)
         1153  +    {
         1154  +      throw new NotSupportedException();
         1155  +    }
         1156  +
         1157  +    /// <summary>
         1158  +    /// <see cref="Visit(DbFilterExpression)"/> for general details.
         1159  +    /// We modify both the GroupBy and the Select fields of the SqlSelectStatement.
         1160  +    /// GroupBy gets just the keys without aliases,
         1161  +    /// and Select gets the keys and the aggregates with aliases.
         1162  +    /// 
         1163  +    /// Whenever there exists at least one aggregate with an argument that is not is not a simple
         1164  +    /// <see cref="DbPropertyExpression"/>  over <see cref="DbVariableReferenceExpression"/>, 
         1165  +    /// we create a nested query in which we alias the arguments to the aggregates. 
         1166  +    /// That is due to the following two limitations of Sql Server:
         1167  +    /// <list type="number">
         1168  +    /// <item>If an expression being aggregated contains an outer reference, then that outer 
         1169  +    /// reference must be the only column referenced in the expression </item>
         1170  +    /// <item>Sql Server cannot perform an aggregate function on an expression containing 
         1171  +    /// an aggregate or a subquery. </item>
         1172  +    /// </list>
         1173  +    /// 
         1174  +    /// The default translation, without inner query is: 
         1175  +    /// 
         1176  +    ///     SELECT 
         1177  +    ///         kexp1 AS key1, kexp2 AS key2,... kexpn AS keyn, 
         1178  +    ///         aggf1(aexpr1) AS agg1, .. aggfn(aexprn) AS aggn
         1179  +    ///     FROM input AS a
         1180  +    ///     GROUP BY kexp1, kexp2, .. kexpn
         1181  +    /// 
         1182  +    /// When we inject an innner query, the equivalent translation is:
         1183  +    /// 
         1184  +    ///     SELECT 
         1185  +    ///         key1 AS key1, key2 AS key2, .. keyn AS keys,  
         1186  +    ///         aggf1(agg1) AS agg1, aggfn(aggn) AS aggn
         1187  +    ///     FROM (
         1188  +    ///             SELECT 
         1189  +    ///                 kexp1 AS key1, kexp2 AS key2,... kexpn AS keyn, 
         1190  +    ///                 aexpr1 AS agg1, .. aexprn AS aggn
         1191  +    ///             FROM input AS a
         1192  +    ///         ) as a
         1193  +    ///     GROUP BY key1, key2, keyn
         1194  +    /// 
         1195  +    /// </summary>
         1196  +    /// <param name="e"></param>
         1197  +    /// <returns>A <see cref="SqlSelectStatement"/></returns>
         1198  +    public override ISqlFragment Visit(DbGroupByExpression e)
         1199  +    {
         1200  +      Symbol fromSymbol;
         1201  +      //SqlSelectStatement result = VisitInputExpression(e.Input.Expression,
         1202  +      SqlSelectStatement innerQuery = VisitInputExpression(e.Input.Expression,
         1203  +          e.Input.VariableName, e.Input.VariableType, out fromSymbol);
         1204  +
         1205  +      // GroupBy is compatible with Filter and OrderBy
         1206  +      // but not with Project, GroupBy
         1207  +      if (!IsCompatible(innerQuery, e.ExpressionKind))
         1208  +      {
         1209  +        innerQuery = CreateNewSelectStatement(innerQuery, e.Input.VariableName, e.Input.VariableType, out fromSymbol);
         1210  +      }
         1211  +
         1212  +      selectStatementStack.Push(innerQuery);
         1213  +      symbolTable.EnterScope();
         1214  +
         1215  +      AddFromSymbol(innerQuery, e.Input.VariableName, fromSymbol);
         1216  +      // This line is not present for other relational nodes.
         1217  +      symbolTable.Add(e.Input.GroupVariableName, fromSymbol);
         1218  +
         1219  +
         1220  +      // The enumerator is shared by both the keys and the aggregates,
         1221  +      // so, we do not close it in between.
         1222  +      RowType groupByType = MetadataHelpers.GetEdmType<RowType>(MetadataHelpers.GetEdmType<CollectionType>(e.ResultType).TypeUsage);
         1223  +
         1224  +      //Whenever there exists at least one aggregate with an argument that is not simply a PropertyExpression 
         1225  +      // over a VarRefExpression, we need a nested query in which we alias the arguments to the aggregates.
         1226  +      bool needsInnerQuery = NeedsInnerQuery(e.Aggregates);
         1227  +
         1228  +      SqlSelectStatement result;
         1229  +      if (needsInnerQuery)
         1230  +      {
         1231  +        //Create the inner query
         1232  +        result = CreateNewSelectStatement(innerQuery, e.Input.VariableName, e.Input.VariableType, false, out fromSymbol);
         1233  +        AddFromSymbol(result, e.Input.VariableName, fromSymbol, false);
         1234  +      }
         1235  +      else
         1236  +      {
         1237  +        result = innerQuery;
         1238  +      }
         1239  +
         1240  +      using (IEnumerator<EdmProperty> members = groupByType.Properties.GetEnumerator())
         1241  +      {
         1242  +        members.MoveNext();
         1243  +        Debug.Assert(result.Select.IsEmpty);
         1244  +
         1245  +        string separator = "";
         1246  +
         1247  +        foreach (DbExpression key in e.Keys)
         1248  +        {
         1249  +          EdmProperty member = members.Current;
         1250  +          string alias = QuoteIdentifier(member.Name);
         1251  +
         1252  +          result.GroupBy.Append(separator);
         1253  +
         1254  +          ISqlFragment keySql = key.Accept(this);
         1255  +
         1256  +          if (!needsInnerQuery)
         1257  +          {
         1258  +            //Default translation: Key AS Alias
         1259  +            result.Select.Append(separator);
         1260  +            result.Select.AppendLine();
         1261  +            result.Select.Append(keySql);
         1262  +            result.Select.Append(" AS ");
         1263  +            result.Select.Append(alias);
         1264  +
         1265  +            result.GroupBy.Append(keySql);
         1266  +          }
         1267  +          else
         1268  +          {
         1269  +            // The inner query contains the default translation Key AS Alias
         1270  +            innerQuery.Select.Append(separator);
         1271  +            innerQuery.Select.AppendLine();
         1272  +            innerQuery.Select.Append(keySql);
         1273  +            innerQuery.Select.Append(" AS ");
         1274  +            innerQuery.Select.Append(alias);
         1275  +
         1276  +            //The outer resulting query projects over the key aliased in the inner query: 
         1277  +            //  fromSymbol.Alias AS Alias
         1278  +            result.Select.Append(separator);
         1279  +            result.Select.AppendLine();
         1280  +            result.Select.Append(fromSymbol);
         1281  +            result.Select.Append(".");
         1282  +            result.Select.Append(alias);
         1283  +            result.Select.Append(" AS ");
         1284  +            result.Select.Append(alias);
         1285  +
         1286  +            result.GroupBy.Append(alias);
         1287  +          }
         1288  +
         1289  +          separator = ", ";
         1290  +          members.MoveNext();
         1291  +        }
         1292  +
         1293  +        foreach (DbAggregate aggregate in e.Aggregates)
         1294  +        {
         1295  +          EdmProperty member = members.Current;
         1296  +          string alias = QuoteIdentifier(member.Name);
         1297  +
         1298  +          Debug.Assert(aggregate.Arguments.Count == 1);
         1299  +          ISqlFragment translatedAggregateArgument = aggregate.Arguments[0].Accept(this);
         1300  +
         1301  +          object aggregateArgument;
         1302  +
         1303  +          if (needsInnerQuery)
         1304  +          {
         1305  +            //In this case the argument to the aggratete is reference to the one projected out by the
         1306  +            // inner query
         1307  +            SqlBuilder wrappingAggregateArgument = new SqlBuilder();
         1308  +            wrappingAggregateArgument.Append(fromSymbol);
         1309  +            wrappingAggregateArgument.Append(".");
         1310  +            wrappingAggregateArgument.Append(alias);
         1311  +            aggregateArgument = wrappingAggregateArgument;
         1312  +
         1313  +            innerQuery.Select.Append(separator);
         1314  +            innerQuery.Select.AppendLine();
         1315  +            innerQuery.Select.Append(translatedAggregateArgument);
         1316  +            innerQuery.Select.Append(" AS ");
         1317  +            innerQuery.Select.Append(alias);
         1318  +          }
         1319  +          else
         1320  +          {
         1321  +            aggregateArgument = translatedAggregateArgument;
         1322  +          }
         1323  +
         1324  +          ISqlFragment aggregateResult = VisitAggregate(aggregate, aggregateArgument);
         1325  +
         1326  +          result.Select.Append(separator);
         1327  +          result.Select.AppendLine();
         1328  +          result.Select.Append(aggregateResult);
         1329  +          result.Select.Append(" AS ");
         1330  +          result.Select.Append(alias);
         1331  +
         1332  +          separator = ", ";
         1333  +          members.MoveNext();
         1334  +        }
         1335  +      }
         1336  +
         1337  +
         1338  +      symbolTable.ExitScope();
         1339  +      selectStatementStack.Pop();
         1340  +
         1341  +      return result;
         1342  +    }
         1343  +
         1344  +    /// <summary>
         1345  +    /// <see cref="Visit(DbUnionAllExpression)"/>
         1346  +    /// </summary>
         1347  +    /// <param name="e"></param>
         1348  +    /// <returns></returns>
         1349  +    public override ISqlFragment Visit(DbIntersectExpression e)
         1350  +    {
         1351  +      return VisitSetOpExpression(e.Left, e.Right, "INTERSECT");
         1352  +    }
         1353  +
         1354  +    /// <summary>
         1355  +    /// Not(IsEmpty) has to be handled specially, so we delegate to
         1356  +    /// <see cref="VisitIsEmptyExpression"/>.
         1357  +    ///
         1358  +    /// </summary>
         1359  +    /// <param name="e"></param>
         1360  +    /// <returns>A <see cref="SqlBuilder"/>.
         1361  +    /// <code>[NOT] EXISTS( ... )</code>
         1362  +    /// </returns>
         1363  +    public override ISqlFragment Visit(DbIsEmptyExpression e)
         1364  +    {
         1365  +      return VisitIsEmptyExpression(e, false);
         1366  +    }
         1367  +
         1368  +    /// <summary>
         1369  +    /// Not(IsNull) is handled specially, so we delegate to
         1370  +    /// <see cref="VisitIsNullExpression"/>
         1371  +    /// </summary>
         1372  +    /// <param name="e"></param>
         1373  +    /// <returns>A <see cref="SqlBuilder"/>
         1374  +    /// <code>IS [NOT] NULL</code>
         1375  +    /// </returns>
         1376  +    public override ISqlFragment Visit(DbIsNullExpression e)
         1377  +    {
         1378  +      return VisitIsNullExpression(e, false);
         1379  +    }
         1380  +
         1381  +    /// <summary>
         1382  +    /// <see cref="DbIsOfExpression"/> is illegal at this stage
         1383  +    /// </summary>
         1384  +    /// <param name="e"></param>
         1385  +    /// <returns>A <see cref="SqlBuilder"/></returns>
         1386  +    public override ISqlFragment Visit(DbIsOfExpression e)
         1387  +    {
         1388  +      throw new NotSupportedException();
         1389  +    }
         1390  +
         1391  +    /// <summary>
         1392  +    /// <see cref="VisitJoinExpression"/>
         1393  +    /// </summary>
         1394  +    /// <param name="e"></param>
         1395  +    /// <returns>A <see cref="SqlSelectStatement"/>.</returns>
         1396  +    public override ISqlFragment Visit(DbCrossJoinExpression e)
         1397  +    {
         1398  +      return VisitJoinExpression(e.Inputs, e.ExpressionKind, "CROSS JOIN", null);
         1399  +    }
         1400  +
         1401  +    /// <summary>
         1402  +    /// <see cref="VisitJoinExpression"/>
         1403  +    /// </summary>
         1404  +    /// <param name="e"></param>
         1405  +    /// <returns>A <see cref="SqlSelectStatement"/>.</returns>
         1406  +    public override ISqlFragment Visit(DbJoinExpression e)
         1407  +    {
         1408  +      #region Map join type to a string
         1409  +      string joinString;
         1410  +      switch (e.ExpressionKind)
         1411  +      {
         1412  +        case DbExpressionKind.FullOuterJoin:
         1413  +          joinString = "FULL OUTER JOIN";
         1414  +          break;
         1415  +
         1416  +        case DbExpressionKind.InnerJoin:
         1417  +          joinString = "INNER JOIN";
         1418  +          break;
         1419  +
         1420  +        case DbExpressionKind.LeftOuterJoin:
         1421  +          joinString = "LEFT OUTER JOIN";
         1422  +          break;
         1423  +
         1424  +        default:
         1425  +          Debug.Assert(false);
         1426  +          joinString = null;
         1427  +          break;
         1428  +      }
         1429  +      #endregion
         1430  +
         1431  +      List<DbExpressionBinding> inputs = new List<DbExpressionBinding>(2);
         1432  +      inputs.Add(e.Left);
         1433  +      inputs.Add(e.Right);
         1434  +
         1435  +      return VisitJoinExpression(inputs, e.ExpressionKind, joinString, e.JoinCondition);
         1436  +    }
         1437  +
         1438  +    /// <summary>
         1439  +    ///
         1440  +    /// </summary>
         1441  +    /// <param name="e"></param>
         1442  +    /// <returns>A <see cref="SqlBuilder"/></returns>
         1443  +    public override ISqlFragment Visit(DbLikeExpression e)
         1444  +    {
         1445  +      SqlBuilder result = new SqlBuilder();
         1446  +      result.Append(e.Argument.Accept(this));
         1447  +      result.Append(" LIKE ");
         1448  +      result.Append(e.Pattern.Accept(this));
         1449  +
         1450  +      // if the ESCAPE expression is a DbNullExpression, then that's tantamount to 
         1451  +      // not having an ESCAPE at all
         1452  +      if (e.Escape.ExpressionKind != DbExpressionKind.Null)
         1453  +      {
         1454  +        result.Append(" ESCAPE ");
         1455  +        result.Append(e.Escape.Accept(this));
         1456  +      }
         1457  +
         1458  +      return result;
         1459  +    }
         1460  +
         1461  +    /// <summary>
         1462  +    ///  Translates to TOP expression.
         1463  +    /// </summary>
         1464  +    /// <param name="e"></param>
         1465  +    /// <returns>A <see cref="SqlBuilder"/></returns>
         1466  +    public override ISqlFragment Visit(DbLimitExpression e)
         1467  +    {
         1468  +      Debug.Assert(e.Limit is DbConstantExpression || e.Limit is DbParameterReferenceExpression, "DbLimitExpression.Limit is of invalid expression type");
         1469  +
         1470  +      SqlSelectStatement result = VisitExpressionEnsureSqlStatement(e.Argument, false);
         1471  +      Symbol fromSymbol;
         1472  +
         1473  +      if (!IsCompatible(result, e.ExpressionKind))
         1474  +      {
         1475  +        TypeUsage inputType = MetadataHelpers.GetElementTypeUsage(e.Argument.ResultType);
         1476  +
         1477  +        result = CreateNewSelectStatement(result, "top", inputType, out fromSymbol);
         1478  +        AddFromSymbol(result, "top", fromSymbol, false);
         1479  +      }
         1480  +
         1481  +      ISqlFragment topCount = HandleCountExpression(e.Limit);
         1482  +
         1483  +      result.Top = new TopClause(topCount, e.WithTies);
         1484  +      return result;
         1485  +    }
         1486  +
         1487  +    /// <summary>
         1488  +    /// DbNewInstanceExpression is allowed as a child of DbProjectExpression only.
         1489  +    /// If anyone else is the parent, we throw.
         1490  +    /// We also perform special casing for collections - where we could convert
         1491  +    /// them into Unions
         1492  +    ///
         1493  +    /// <see cref="VisitNewInstanceExpression"/> for the actual implementation.
         1494  +    ///
         1495  +    /// </summary>
         1496  +    /// <param name="e"></param>
         1497  +    /// <returns></returns>
         1498  +    public override ISqlFragment Visit(DbNewInstanceExpression e)
         1499  +    {
         1500  +      if (MetadataHelpers.IsCollectionType(e.ResultType))
         1501  +      {
         1502  +        return VisitCollectionConstructor(e);
         1503  +      }
         1504  +      throw new NotSupportedException();
         1505  +    }
         1506  +
         1507  +    /// <summary>
         1508  +    /// The Not expression may cause the translation of its child to change.
         1509  +    /// These children are
         1510  +    /// <list type="bullet">
         1511  +    /// <item><see cref="DbNotExpression"/>NOT(Not(x)) becomes x</item>
         1512  +    /// <item><see cref="DbIsEmptyExpression"/>NOT EXISTS becomes EXISTS</item>
         1513  +    /// <item><see cref="DbIsNullExpression"/>IS NULL becomes IS NOT NULL</item>
         1514  +    /// <item><see cref="DbComparisonExpression"/>= becomes&lt;&gt; </item>
         1515  +    /// </list>
         1516  +    /// </summary>
         1517  +    /// <param name="e"></param>
         1518  +    /// <returns>A <see cref="SqlBuilder"/></returns>
         1519  +    public override ISqlFragment Visit(DbNotExpression e)
         1520  +    {
         1521  +      // Flatten Not(Not(x)) to x.
         1522  +      DbNotExpression notExpression = e.Argument as DbNotExpression;
         1523  +      if (notExpression != null)
         1524  +      {
         1525  +        return notExpression.Argument.Accept(this);
         1526  +      }
         1527  +
         1528  +      DbIsEmptyExpression isEmptyExpression = e.Argument as DbIsEmptyExpression;
         1529  +      if (isEmptyExpression != null)
         1530  +      {
         1531  +        return VisitIsEmptyExpression(isEmptyExpression, true);
         1532  +      }
         1533  +
         1534  +      DbIsNullExpression isNullExpression = e.Argument as DbIsNullExpression;
         1535  +      if (isNullExpression != null)
         1536  +      {
         1537  +        return VisitIsNullExpression(isNullExpression, true);
         1538  +      }
         1539  +
         1540  +      DbComparisonExpression comparisonExpression = e.Argument as DbComparisonExpression;
         1541  +      if (comparisonExpression != null)
         1542  +      {
         1543  +        if (comparisonExpression.ExpressionKind == DbExpressionKind.Equals)
         1544  +        {
         1545  +          return VisitBinaryExpression(" <> ", comparisonExpression.Left, comparisonExpression.Right);
         1546  +        }
         1547  +      }
         1548  +
         1549  +      SqlBuilder result = new SqlBuilder();
         1550  +      result.Append(" NOT (");
         1551  +      result.Append(e.Argument.Accept(this));
         1552  +      result.Append(")");
         1553  +
         1554  +      return result;
         1555  +    }
         1556  +
         1557  +    /// <summary>
         1558  +    /// </summary>
         1559  +    /// <param name="e"></param>
         1560  +    /// <returns><see cref="SqlBuilder"/></returns>
         1561  +    public override ISqlFragment Visit(DbNullExpression e)
         1562  +    {
         1563  +      SqlBuilder result = new SqlBuilder();
         1564  +      // always cast nulls - sqlserver doesn't like case expressions where the "then" clause is null
         1565  +      result.Append("NULL");
         1566  +      return result;
         1567  +    }
         1568  +
         1569  +    /// <summary>
         1570  +    /// <see cref="DbOfTypeExpression"/> is illegal at this stage
         1571  +    /// </summary>
         1572  +    /// <param name="e"></param>
         1573  +    /// <returns>A <see cref="SqlBuilder"/></returns>
         1574  +    public override ISqlFragment Visit(DbOfTypeExpression e)
         1575  +    {
         1576  +      throw new NotSupportedException();
         1577  +    }
         1578  +
         1579  +    /// <summary>
         1580  +    ///
         1581  +    /// </summary>
         1582  +    /// <param name="e"></param>
         1583  +    /// <returns>A <see cref="SqlBuilder"/></returns>
         1584  +    /// <seealso cref="Visit(DbAndExpression)"/>
         1585  +    public override ISqlFragment Visit(DbOrExpression e)
         1586  +    {
         1587  +      ISqlFragment sqlFragment = null;
         1588  +      if (this.TryTranslateIntoIn(e, out sqlFragment))
         1589  +      {
         1590  +        return sqlFragment;
         1591  +      }
         1592  +      return VisitBinaryExpression(" OR ", e.Left, e.Right);
         1593  +    }
         1594  +
         1595  +    /// <summary>
         1596  +    ///
         1597  +    /// </summary>
         1598  +    /// <param name="e"></param>
         1599  +    /// <returns>A <see cref="SqlBuilder"/></returns>
         1600  +    public override ISqlFragment Visit(DbParameterReferenceExpression e)
         1601  +    {
         1602  +      SqlBuilder result = new SqlBuilder();
         1603  +      // Do not quote this name.
         1604  +      // We are not checking that e.Name has no illegal characters. e.g. space
         1605  +      result.Append("@" + e.ParameterName);
         1606  +
         1607  +      return result;
         1608  +    }
         1609  +
         1610  +    /// <summary>
         1611  +    /// <see cref="Visit(DbFilterExpression)"/> for the general ideas.
         1612  +    /// </summary>
         1613  +    /// <param name="e"></param>
         1614  +    /// <returns>A <see cref="SqlSelectStatement"/></returns>
         1615  +    /// <seealso cref="Visit(DbFilterExpression)"/>
         1616  +    public override ISqlFragment Visit(DbProjectExpression e)
         1617  +    {
         1618  +      Symbol fromSymbol;
         1619  +      SqlSelectStatement result = VisitInputExpression(e.Input.Expression, e.Input.VariableName, e.Input.VariableType, out fromSymbol);
         1620  +
         1621  +      // Project is compatible with Filter
         1622  +      // but not with Project, GroupBy
         1623  +      if (!IsCompatible(result, e.ExpressionKind))
         1624  +      {
         1625  +        result = CreateNewSelectStatement(result, e.Input.VariableName, e.Input.VariableType, out fromSymbol);
         1626  +      }
         1627  +
         1628  +      selectStatementStack.Push(result);
         1629  +      symbolTable.EnterScope();
         1630  +
         1631  +      AddFromSymbol(result, e.Input.VariableName, fromSymbol);
         1632  +
         1633  +      // Project is the only node that can have DbNewInstanceExpression as a child
         1634  +      // so we have to check it here.
         1635  +      // We call VisitNewInstanceExpression instead of Visit(DbNewInstanceExpression), since
         1636  +      // the latter throws.
         1637  +      DbNewInstanceExpression newInstanceExpression = e.Projection as DbNewInstanceExpression;
         1638  +      if (newInstanceExpression != null)
         1639  +      {
         1640  +        result.Select.Append(VisitNewInstanceExpression(newInstanceExpression));
         1641  +      }
         1642  +      else
         1643  +      {
         1644  +        result.Select.Append(e.Projection.Accept(this));
         1645  +      }
         1646  +
         1647  +      symbolTable.ExitScope();
         1648  +      selectStatementStack.Pop();
         1649  +
         1650  +      return result;
         1651  +    }
         1652  +
         1653  +    /// <summary>
         1654  +    /// This method handles record flattening, which works as follows.
         1655  +    /// consider an expression <c>Prop(y, Prop(x, Prop(d, Prop(c, Prop(b, Var(a)))))</c>
         1656  +    /// where a,b,c are joins, d is an extent and x and y are fields.
         1657  +    /// b has been flattened into a, and has its own SELECT statement.
         1658  +    /// c has been flattened into b.
         1659  +    /// d has been flattened into c.
         1660  +    ///
         1661  +    /// We visit the instance, so we reach Var(a) first.  This gives us a (join)symbol.
         1662  +    /// Symbol(a).b gives us a join symbol, with a SELECT statement i.e. Symbol(b).
         1663  +    /// From this point on , we need to remember Symbol(b) as the source alias,
         1664  +    /// and then try to find the column.  So, we use a SymbolPair.
         1665  +    ///
         1666  +    /// We have reached the end when the symbol no longer points to a join symbol.
         1667  +    /// </summary>
         1668  +    /// <param name="e"></param>
         1669  +    /// <returns>A <see cref="JoinSymbol"/> if we have not reached the first
         1670  +    /// Join node that has a SELECT statement.
         1671  +    /// A <see cref="SymbolPair"/> if we have seen the JoinNode, and it has
         1672  +    /// a SELECT statement.
         1673  +    /// A <see cref="SqlBuilder"/> with {Input}.propertyName otherwise.
         1674  +    /// </returns>
         1675  +    public override ISqlFragment Visit(DbPropertyExpression e)
         1676  +    {
         1677  +      SqlBuilder result;
         1678  +
         1679  +      ISqlFragment instanceSql = e.Instance.Accept(this);
         1680  +
         1681  +      // Since the DbVariableReferenceExpression is a proper child of ours, we can reset
         1682  +      // isVarSingle.
         1683  +      DbVariableReferenceExpression DbVariableReferenceExpression = e.Instance as DbVariableReferenceExpression;
         1684  +      if (DbVariableReferenceExpression != null)
         1685  +      {
         1686  +        isVarRefSingle = false;
         1687  +      }
         1688  +
         1689  +      // We need to flatten, and have not yet seen the first nested SELECT statement.
         1690  +      JoinSymbol joinSymbol = instanceSql as JoinSymbol;
         1691  +      if (joinSymbol != null)
         1692  +      {
         1693  +        Debug.Assert(joinSymbol.NameToExtent.ContainsKey(e.Property.Name));
         1694  +        if (joinSymbol.IsNestedJoin)
         1695  +        {
         1696  +          return new SymbolPair(joinSymbol, joinSymbol.NameToExtent[e.Property.Name]);
         1697  +        }
         1698  +        else
         1699  +        {
         1700  +          return joinSymbol.NameToExtent[e.Property.Name];
         1701  +        }
         1702  +      }
         1703  +
         1704  +      // ---------------------------------------
         1705  +      // We have seen the first nested SELECT statement, but not the column.
         1706  +      SymbolPair symbolPair = instanceSql as SymbolPair;
         1707  +      if (symbolPair != null)
         1708  +      {
         1709  +        JoinSymbol columnJoinSymbol = symbolPair.Column as JoinSymbol;
         1710  +        if (columnJoinSymbol != null)
         1711  +        {
         1712  +          symbolPair.Column = columnJoinSymbol.NameToExtent[e.Property.Name];
         1713  +          return symbolPair;
         1714  +        }
         1715  +        else
         1716  +        {
         1717  +          // symbolPair.Column has the base extent.
         1718  +          // we need the symbol for the column, since it might have been renamed
         1719  +          // when handling a JOIN.
         1720  +          if (symbolPair.Column.Columns.ContainsKey(e.Property.Name))
         1721  +          {
         1722  +            result = new SqlBuilder();
         1723  +            result.Append(symbolPair.Source);
         1724  +            result.Append(".");
         1725  +            result.Append(symbolPair.Column.Columns[e.Property.Name]);
         1726  +            return result;
         1727  +          }
         1728  +        }
         1729  +      }
         1730  +      // ---------------------------------------
         1731  +
         1732  +      result = new SqlBuilder();
         1733  +      result.Append(instanceSql);
         1734  +      result.Append(".");
         1735  +
         1736  +      // At this point the column name cannot be renamed, so we do
         1737  +      // not use a symbol.
         1738  +      result.Append(QuoteIdentifier(e.Property.Name));
         1739  +
         1740  +      return result;
         1741  +    }
         1742  +
         1743  +    /// <summary>
         1744  +    /// Any(input, x) => Exists(Filter(input,x))
         1745  +    /// All(input, x) => Not Exists(Filter(input, not(x))
         1746  +    /// </summary>
         1747  +    /// <param name="e"></param>
         1748  +    /// <returns></returns>
         1749  +    public override ISqlFragment Visit(DbQuantifierExpression e)
         1750  +    {
         1751  +      SqlBuilder result = new SqlBuilder();
         1752  +
         1753  +      bool negatePredicate = (e.ExpressionKind == DbExpressionKind.All);
         1754  +      if (e.ExpressionKind == DbExpressionKind.Any)
         1755  +      {
         1756  +        result.Append("EXISTS (");
         1757  +      }
         1758  +      else
         1759  +      {
         1760  +        Debug.Assert(e.ExpressionKind == DbExpressionKind.All);
         1761  +        result.Append("NOT EXISTS (");
         1762  +      }
         1763  +
         1764  +      SqlSelectStatement filter = VisitFilterExpression(e.Input, e.Predicate, negatePredicate);
         1765  +      if (filter.Select.IsEmpty)
         1766  +      {
         1767  +        AddDefaultColumns(filter);
         1768  +      }
         1769  +
         1770  +      result.Append(filter);
         1771  +      result.Append(")");
         1772  +
         1773  +      return result;
         1774  +    }
         1775  +
         1776  +    /// <summary>
         1777  +    /// <see cref="DbRefExpression"/> is illegal at this stage
         1778  +    /// </summary>
         1779  +    /// <param name="e"></param>
         1780  +    /// <returns></returns>
         1781  +    public override ISqlFragment Visit(DbRefExpression e)
         1782  +    {
         1783  +      throw new NotSupportedException();
         1784  +    }
         1785  +
         1786  +    /// <summary>
         1787  +    /// <see cref="DbRelationshipNavigationExpression"/> is illegal at this stage
         1788  +    /// </summary>
         1789  +    /// <param name="e"></param>
         1790  +    /// <returns></returns>
         1791  +    public override ISqlFragment Visit(DbRelationshipNavigationExpression e)
         1792  +    {
         1793  +      throw new NotSupportedException();
         1794  +    }
         1795  +
         1796  +    /// <summary>
         1797  +    /// For Sql9 it translates to:
         1798  +    /// SELECT Y.x1, Y.x2, ..., Y.xn
         1799  +    /// FROM (
         1800  +    ///     SELECT X.x1, X.x2, ..., X.xn, row_number() OVER (ORDER BY sk1, sk2, ...) AS [row_number] 
         1801  +    ///     FROM input as X 
         1802  +    ///     ) as Y
         1803  +    /// WHERE Y.[row_number] > count 
         1804  +    /// ORDER BY sk1, sk2, ...
         1805  +    /// </summary>
         1806  +    /// <param name="e"></param>
         1807  +    /// <returns>A <see cref="SqlBuilder"/></returns>
         1808  +    public override ISqlFragment Visit(DbSkipExpression e)
         1809  +    {
         1810  +      // Should never get here.  The Sql2000 rewriter would've rewritten the command tree not to use this
         1811  +      throw new NotSupportedException();
         1812  +    }
         1813  +
         1814  +    /// <summary>
         1815  +    /// <see cref="Visit(DbFilterExpression)"/>
         1816  +    /// </summary>
         1817  +    /// <param name="e"></param>
         1818  +    /// <returns>A <see cref="SqlSelectStatement"/></returns>
         1819  +    /// <seealso cref="Visit(DbFilterExpression)"/>
         1820  +    public override ISqlFragment Visit(DbSortExpression e)
         1821  +    {
         1822  +      Symbol fromSymbol;
         1823  +      SqlSelectStatement result = VisitInputExpression(e.Input.Expression, e.Input.VariableName, e.Input.VariableType, out fromSymbol);
         1824  +
         1825  +      // OrderBy is compatible with Filter
         1826  +      // and nothing else
         1827  +      if (!IsCompatible(result, e.ExpressionKind))
         1828  +      {
         1829  +        result = CreateNewSelectStatement(result, e.Input.VariableName, e.Input.VariableType, out fromSymbol);
         1830  +      }
         1831  +
         1832  +      selectStatementStack.Push(result);
         1833  +      symbolTable.EnterScope();
         1834  +
         1835  +      AddFromSymbol(result, e.Input.VariableName, fromSymbol);
         1836  +
         1837  +      AddSortKeys(result.OrderBy, e.SortOrder);
         1838  +
         1839  +      symbolTable.ExitScope();
         1840  +      selectStatementStack.Pop();
         1841  +
         1842  +      return result;
         1843  +    }
         1844  +
         1845  +    /// <summary>
         1846  +    /// <see cref="DbTreatExpression"/> is illegal at this stage
         1847  +    /// </summary>
         1848  +    /// <param name="e"></param>
         1849  +    /// <returns>A <see cref="SqlBuilder"/></returns>
         1850  +    public override ISqlFragment Visit(DbTreatExpression e)
         1851  +    {
         1852  +      throw new NotSupportedException();
         1853  +    }
         1854  +
         1855  +    /// <summary>
         1856  +    /// This code is shared by <see cref="Visit(DbExceptExpression)"/>
         1857  +    /// and <see cref="Visit(DbIntersectExpression)"/>
         1858  +    ///
         1859  +    /// <see cref="VisitSetOpExpression"/>
         1860  +    /// Since the left and right expression may not be Sql select statements,
         1861  +    /// we must wrap them up to look like SQL select statements.
         1862  +    /// </summary>
         1863  +    /// <param name="e"></param>
         1864  +    /// <returns></returns>
         1865  +    public override ISqlFragment Visit(DbUnionAllExpression e)
         1866  +    {
         1867  +      return VisitSetOpExpression(e.Left, e.Right, "UNION ALL");
         1868  +    }
         1869  +
         1870  +    /// <summary>
         1871  +    /// This method determines whether an extent from an outer scope(free variable)
         1872  +    /// is used in the CurrentSelectStatement.
         1873  +    ///
         1874  +    /// An extent in an outer scope, if its symbol is not in the FromExtents
         1875  +    /// of the CurrentSelectStatement.
         1876  +    /// </summary>
         1877  +    /// <param name="e"></param>
         1878  +    /// <returns>A <see cref="Symbol"/>.</returns>
         1879  +    public override ISqlFragment Visit(DbVariableReferenceExpression e)
         1880  +    {
         1881  +      if (isVarRefSingle)
         1882  +      {
         1883  +        throw new NotSupportedException();
         1884  +        // A DbVariableReferenceExpression has to be a child of DbPropertyExpression or MethodExpression
         1885  +        // This is also checked in GenerateSql(...) at the end of the visiting.
         1886  +      }
         1887  +      isVarRefSingle = true; // This will be reset by DbPropertyExpression or MethodExpression
         1888  +
         1889  +      Symbol result = symbolTable.Lookup(e.VariableName);
         1890  +      if (!CurrentSelectStatement.FromExtents.Contains(result))
         1891  +      {
         1892  +        CurrentSelectStatement.OuterExtents[result] = true;
         1893  +      }
         1894  +
         1895  +      return result;
         1896  +    }
         1897  +
         1898  +    #region Visits shared by multiple nodes
         1899  +    /// <summary>
         1900  +    /// Aggregates are not visited by the normal visitor walk.
         1901  +    /// </summary>
         1902  +    /// <param name="aggregate">The aggreate to be translated</param>
         1903  +    /// <param name="aggregateArgument">The translated aggregate argument</param>
         1904  +    /// <returns></returns>
         1905  +    SqlBuilder VisitAggregate(DbAggregate aggregate, object aggregateArgument)
         1906  +    {
         1907  +      SqlBuilder aggregateResult = new SqlBuilder();
         1908  +      DbFunctionAggregate functionAggregate = aggregate as DbFunctionAggregate;
         1909  +
         1910  +      if (functionAggregate == null)
         1911  +      {
         1912  +        throw new NotSupportedException();
         1913  +      }
         1914  +
         1915  +      //The only aggregate function with different name is Big_Count
         1916  +      //Note: If another such function is to be added, a dictionary should be created
         1917  +      //if (MetadataHelpers.IsCanonicalFunction(functionAggregate.Function)
         1918  +      //    && String.Equals(functionAggregate.Function.Name, "BigCount", StringComparison.Ordinal))
         1919  +      //{
         1920  +      //  aggregateResult.Append("COUNT_BIG");
         1921  +      //}
         1922  +      //else
         1923  +      {
         1924  +        WriteFunctionName(aggregateResult, functionAggregate.Function);
         1925  +      }
         1926  +
         1927  +      aggregateResult.Append("(");
         1928  +
         1929  +      DbFunctionAggregate fnAggr = functionAggregate;
         1930  +      if ((null != fnAggr) && (fnAggr.Distinct))
         1931  +      {
         1932  +        aggregateResult.Append("DISTINCT ");
         1933  +      }
         1934  +
         1935  +      aggregateResult.Append(aggregateArgument);
         1936  +
         1937  +      aggregateResult.Append(")");
         1938  +      return aggregateResult;
         1939  +    }
         1940  +
         1941  +
         1942  +    SqlBuilder VisitBinaryExpression(string op, DbExpression left, DbExpression right)
         1943  +    {
         1944  +      SqlBuilder result = new SqlBuilder();
         1945  +      if (IsComplexExpression(left))
         1946  +      {
         1947  +        result.Append("(");
         1948  +      }
         1949  +
         1950  +      result.Append(left.Accept(this));
         1951  +
         1952  +      if (IsComplexExpression(left))
         1953  +      {
         1954  +        result.Append(")");
         1955  +      }
         1956  +
         1957  +      result.Append(op);
         1958  +
         1959  +      if (IsComplexExpression(right))
         1960  +      {
         1961  +        result.Append("(");
         1962  +      }
         1963  +
         1964  +      result.Append(right.Accept(this));
         1965  +
         1966  +      if (IsComplexExpression(right))
         1967  +      {
         1968  +        result.Append(")");
         1969  +      }
         1970  +
         1971  +      return result;
         1972  +    }
         1973  +
         1974  +    /// <summary>
         1975  +    /// This is called by the relational nodes.  It does the following
         1976  +    /// <list>
         1977  +    /// <item>If the input is not a SqlSelectStatement, it assumes that the input
         1978  +    /// is a collection expression, and creates a new SqlSelectStatement </item>
         1979  +    /// </list>
         1980  +    /// </summary>
         1981  +    /// <param name="inputExpression"></param>
         1982  +    /// <param name="inputVarName"></param>
         1983  +    /// <param name="inputVarType"></param>
         1984  +    /// <param name="fromSymbol"></param>
         1985  +    /// <returns>A <see cref="SqlSelectStatement"/> and the main fromSymbol
         1986  +    /// for this select statement.</returns>
         1987  +    SqlSelectStatement VisitInputExpression(DbExpression inputExpression,
         1988  +        string inputVarName, TypeUsage inputVarType, out Symbol fromSymbol)
         1989  +    {
         1990  +      SqlSelectStatement result;
         1991  +      ISqlFragment sqlFragment = inputExpression.Accept(this);
         1992  +      result = sqlFragment as SqlSelectStatement;
         1993  +
         1994  +      if (result == null)
         1995  +      {
         1996  +        result = new SqlSelectStatement();
         1997  +        WrapNonQueryExtent(result, sqlFragment, inputExpression.ExpressionKind);
         1998  +      }
         1999  +
         2000  +      if (result.FromExtents.Count == 0)
         2001  +      {
         2002  +        // input was an extent
         2003  +        fromSymbol = new Symbol(inputVarName, inputVarType);
         2004  +      }
         2005  +      else if (result.FromExtents.Count == 1)
         2006  +      {
         2007  +        // input was Filter/GroupBy/Project/OrderBy
         2008  +        // we are likely to reuse this statement.
         2009  +        fromSymbol = result.FromExtents[0];
         2010  +      }
         2011  +      else
         2012  +      {
         2013  +        // input was a join.
         2014  +        // we are reusing the select statement produced by a Join node
         2015  +        // we need to remove the original extents, and replace them with a
         2016  +        // new extent with just the Join symbol.
         2017  +        JoinSymbol joinSymbol = new JoinSymbol(inputVarName, inputVarType, result.FromExtents);
         2018  +        joinSymbol.FlattenedExtentList = result.AllJoinExtents;
         2019  +
         2020  +        fromSymbol = joinSymbol;
         2021  +        result.FromExtents.Clear();
         2022  +        result.FromExtents.Add(fromSymbol);
         2023  +      }
         2024  +
         2025  +      return result;
         2026  +    }
         2027  +
         2028  +    /// <summary>
         2029  +    /// <see cref="Visit(DbIsEmptyExpression)"/>
         2030  +    /// </summary>
         2031  +    /// <param name="e"></param>
         2032  +    /// <param name="negate">Was the parent a DbNotExpression?</param>
         2033  +    /// <returns></returns>
         2034  +    SqlBuilder VisitIsEmptyExpression(DbIsEmptyExpression e, bool negate)
         2035  +    {
         2036  +      SqlBuilder result = new SqlBuilder();
         2037  +      if (!negate)
         2038  +      {
         2039  +        result.Append(" NOT");
         2040  +      }
         2041  +      result.Append(" EXISTS (");
         2042  +      result.Append(VisitExpressionEnsureSqlStatement(e.Argument));
         2043  +      result.AppendLine();
         2044  +      result.Append(")");
         2045  +
         2046  +      return result;
         2047  +    }
         2048  +
         2049  +
         2050  +    /// <summary>
         2051  +    /// Translate a NewInstance(Element(X)) expression into
         2052  +    ///   "select top(1) * from X"
         2053  +    /// </summary>
         2054  +    /// <param name="e"></param>
         2055  +    /// <returns></returns>
         2056  +    private ISqlFragment VisitCollectionConstructor(DbNewInstanceExpression e)
         2057  +    {
         2058  +      Debug.Assert(e.Arguments.Count <= 1);
         2059  +
         2060  +      if (e.Arguments.Count == 1 && e.Arguments[0].ExpressionKind == DbExpressionKind.Element)
         2061  +      {
         2062  +        DbElementExpression elementExpr = e.Arguments[0] as DbElementExpression;
         2063  +        SqlSelectStatement result = VisitExpressionEnsureSqlStatement(elementExpr.Argument);
         2064  +
         2065  +        if (!IsCompatible(result, DbExpressionKind.Element))
         2066  +        {
         2067  +          Symbol fromSymbol;
         2068  +          TypeUsage inputType = MetadataHelpers.GetElementTypeUsage(elementExpr.Argument.ResultType);
         2069  +
         2070  +          result = CreateNewSelectStatement(result, "element", inputType, out fromSymbol);
         2071  +          AddFromSymbol(result, "element", fromSymbol, false);
         2072  +        }
         2073  +        result.Top = new TopClause(1, false);
         2074  +        return result;
         2075  +      }
         2076  +
         2077  +
         2078  +      // Otherwise simply build this out as a union-all ladder
         2079  +      CollectionType collectionType = MetadataHelpers.GetEdmType<CollectionType>(e.ResultType);
         2080  +      Debug.Assert(collectionType != null);
         2081  +      bool isScalarElement = MetadataHelpers.IsPrimitiveType(collectionType.TypeUsage);
         2082  +
         2083  +      SqlBuilder resultSql = new SqlBuilder();
         2084  +      string separator = "";
         2085  +
         2086  +      // handle empty table
         2087  +      if (e.Arguments.Count == 0)
         2088  +      {
         2089  +        Debug.Assert(isScalarElement);
         2090  +        resultSql.Append(" SELECT NULL");
         2091  +        resultSql.Append(" AS X FROM (SELECT 1) AS Y WHERE 1=0");
         2092  +      }
         2093  +
         2094  +      foreach (DbExpression arg in e.Arguments)
         2095  +      {
         2096  +        resultSql.Append(separator);
         2097  +        resultSql.Append(" SELECT ");
         2098  +        resultSql.Append(arg.Accept(this));
         2099  +        // For scalar elements, no alias is appended yet. Add this.
         2100  +        if (isScalarElement)
         2101  +        {
         2102  +          resultSql.Append(" AS X ");
         2103  +        }
         2104  +        separator = " UNION ALL ";
         2105  +      }
         2106  +
         2107  +      return resultSql;
         2108  +    }
         2109  +
         2110  +
         2111  +    /// <summary>
         2112  +    /// <see cref="Visit(DbIsNullExpression)"/>
         2113  +    /// </summary>
         2114  +    /// <param name="e"></param>
         2115  +    /// <param name="negate">Was the parent a DbNotExpression?</param>
         2116  +    /// <returns></returns>
         2117  +    SqlBuilder VisitIsNullExpression(DbIsNullExpression e, bool negate)
         2118  +    {
         2119  +      SqlBuilder result = new SqlBuilder();
         2120  +      result.Append(e.Argument.Accept(this));
         2121  +      if (!negate)
         2122  +      {
         2123  +        result.Append(" IS NULL");
         2124  +      }
         2125  +      else
         2126  +      {
         2127  +        result.Append(" IS NOT NULL");
         2128  +      }
         2129  +
         2130  +      return result;
         2131  +    }
         2132  +
         2133  +    /// <summary>
         2134  +    /// This handles the processing of join expressions.
         2135  +    /// The extents on a left spine are flattened, while joins
         2136  +    /// not on the left spine give rise to new nested sub queries.
         2137  +    ///
         2138  +    /// Joins work differently from the rest of the visiting, in that
         2139  +    /// the parent (i.e. the join node) creates the SqlSelectStatement
         2140  +    /// for the children to use.
         2141  +    ///
         2142  +    /// The "parameter" IsInJoinContext indicates whether a child extent should
         2143  +    /// add its stuff to the existing SqlSelectStatement, or create a new SqlSelectStatement
         2144  +    /// By passing true, we ask the children to add themselves to the parent join,
         2145  +    /// by passing false, we ask the children to create new Select statements for
         2146  +    /// themselves.
         2147  +    ///
         2148  +    /// This method is called from <see cref="Visit(DbApplyExpression)"/> and
         2149  +    /// <see cref="Visit(DbJoinExpression)"/>.
         2150  +    /// </summary>
         2151  +    /// <param name="inputs"></param>
         2152  +    /// <param name="joinKind"></param>
         2153  +    /// <param name="joinString"></param>
         2154  +    /// <param name="joinCondition"></param>
         2155  +    /// <returns> A <see cref="SqlSelectStatement"/></returns>
         2156  +    ISqlFragment VisitJoinExpression(IList<DbExpressionBinding> inputs, DbExpressionKind joinKind,
         2157  +        string joinString, DbExpression joinCondition)
         2158  +    {
         2159  +      SqlSelectStatement result;
         2160  +      // If the parent is not a join( or says that it is not),
         2161  +      // we should create a new SqlSelectStatement.
         2162  +      // otherwise, we add our child extents to the parent's FROM clause.
         2163  +      if (!IsParentAJoin)
         2164  +      {
         2165  +        result = new SqlSelectStatement();
         2166  +        result.AllJoinExtents = new List<Symbol>();
         2167  +        selectStatementStack.Push(result);
         2168  +      }
         2169  +      else
         2170  +      {
         2171  +        result = CurrentSelectStatement;
         2172  +      }
         2173  +
         2174  +      // Process each of the inputs, and then the joinCondition if it exists.
         2175  +      // It would be nice if we could call VisitInputExpression - that would
         2176  +      // avoid some code duplication
         2177  +      // but the Join postprocessing is messy and prevents this reuse.
         2178  +      symbolTable.EnterScope();
         2179  +
         2180  +      string separator = "";
         2181  +      bool isLeftMostInput = true;
         2182  +      int inputCount = inputs.Count;
         2183  +      for (int idx = 0; idx < inputCount; idx++)
         2184  +      {
         2185  +        DbExpressionBinding input = inputs[idx];
         2186  +
         2187  +        if (separator != "")
         2188  +        {
         2189  +          result.From.AppendLine();
         2190  +        }
         2191  +        result.From.Append(separator + " ");
         2192  +        // Change this if other conditions are required
         2193  +        // to force the child to produce a nested SqlStatement.
         2194  +        bool needsJoinContext = (input.Expression.ExpressionKind == DbExpressionKind.Scan)
         2195  +                                || (isLeftMostInput &&
         2196  +                                    (IsJoinExpression(input.Expression)
         2197  +                                     || IsApplyExpression(input.Expression)))
         2198  +                                ;
         2199  +
         2200  +        isParentAJoinStack.Push(needsJoinContext ? true : false);
         2201  +        // if the child reuses our select statement, it will append the from
         2202  +        // symbols to our FromExtents list.  So, we need to remember the
         2203  +        // start of the child's entries.
         2204  +        int fromSymbolStart = result.FromExtents.Count;
         2205  +
         2206  +        ISqlFragment fromExtentFragment = input.Expression.Accept(this);
         2207  +
         2208  +        isParentAJoinStack.Pop();
         2209  +
         2210  +        ProcessJoinInputResult(fromExtentFragment, result, input, fromSymbolStart);
         2211  +        separator = joinString;
         2212  +
         2213  +        isLeftMostInput = false;
         2214  +      }
         2215  +
         2216  +      // Visit the on clause/join condition.
         2217  +      switch (joinKind)
         2218  +      {
         2219  +        case DbExpressionKind.FullOuterJoin:
         2220  +        case DbExpressionKind.InnerJoin:
         2221  +        case DbExpressionKind.LeftOuterJoin:
         2222  +          result.From.Append(" ON ");
         2223  +          isParentAJoinStack.Push(false);
         2224  +          result.From.Append(joinCondition.Accept(this));
         2225  +          isParentAJoinStack.Pop();
         2226  +          break;
         2227  +      }
         2228  +
         2229  +      symbolTable.ExitScope();
         2230  +
         2231  +      if (!IsParentAJoin)
         2232  +      {
         2233  +        selectStatementStack.Pop();
         2234  +      }
         2235  +
         2236  +      return result;
         2237  +    }
         2238  +
         2239  +    /// <summary>
         2240  +    /// This is called from <see cref="VisitJoinExpression"/>.
         2241  +    ///
         2242  +    /// This is responsible for maintaining the symbol table after visiting
         2243  +    /// a child of a join expression.
         2244  +    ///
         2245  +    /// The child's sql statement may need to be completed.
         2246  +    ///
         2247  +    /// The child's result could be one of
         2248  +    /// <list type="number">
         2249  +    /// <item>The same as the parent's - this is treated specially.</item>
         2250  +    /// <item>A sql select statement, which may need to be completed</item>
         2251  +    /// <item>An extent - just copy it to the from clause</item>
         2252  +    /// <item>Anything else (from a collection-valued expression) -
         2253  +    /// unnest and copy it.</item>
         2254  +    /// </list>
         2255  +    ///
         2256  +    /// If the input was a Join, we need to create a new join symbol,
         2257  +    /// otherwise, we create a normal symbol.
         2258  +    ///
         2259  +    /// We then call AddFromSymbol to add the AS clause, and update the symbol table.
         2260  +    ///
         2261  +    ///
         2262  +    ///
         2263  +    /// If the child's result was the same as the parent's, we have to clean up
         2264  +    /// the list of symbols in the FromExtents list, since this contains symbols from
         2265  +    /// the children of both the parent and the child.
         2266  +    /// The happens when the child visited is a Join, and is the leftmost child of
         2267  +    /// the parent.
         2268  +    /// </summary>
         2269  +    /// <param name="fromExtentFragment"></param>
         2270  +    /// <param name="result"></param>
         2271  +    /// <param name="input"></param>
         2272  +    /// <param name="fromSymbolStart"></param>
         2273  +    void ProcessJoinInputResult(ISqlFragment fromExtentFragment, SqlSelectStatement result,
         2274  +        DbExpressionBinding input, int fromSymbolStart)
         2275  +    {
         2276  +      Symbol fromSymbol = null;
         2277  +
         2278  +      if (result != fromExtentFragment)
         2279  +      {
         2280  +        // The child has its own select statement, and is not reusing
         2281  +        // our select statement.
         2282  +        // This should look a lot like VisitInputExpression().
         2283  +        SqlSelectStatement sqlSelectStatement = fromExtentFragment as SqlSelectStatement;
         2284  +        if (sqlSelectStatement != null)
         2285  +        {
         2286  +          if (sqlSelectStatement.Select.IsEmpty)
         2287  +          {
         2288  +            List<Symbol> columns = AddDefaultColumns(sqlSelectStatement);
         2289  +
         2290  +            if (IsJoinExpression(input.Expression)
         2291  +                || IsApplyExpression(input.Expression))
         2292  +            {
         2293  +              List<Symbol> extents = sqlSelectStatement.FromExtents;
         2294  +              JoinSymbol newJoinSymbol = new JoinSymbol(input.VariableName, input.VariableType, extents);
         2295  +              newJoinSymbol.IsNestedJoin = true;
         2296  +              newJoinSymbol.ColumnList = columns;
         2297  +
         2298  +              fromSymbol = newJoinSymbol;
         2299  +            }
         2300  +            else
         2301  +            {
         2302  +              // this is a copy of the code in CreateNewSelectStatement.
         2303  +
         2304  +              // if the oldStatement has a join as its input, ...
         2305  +              // clone the join symbol, so that we "reuse" the
         2306  +              // join symbol.  Normally, we create a new symbol - see the next block
         2307  +              // of code.
         2308  +              JoinSymbol oldJoinSymbol = sqlSelectStatement.FromExtents[0] as JoinSymbol;
         2309  +              if (oldJoinSymbol != null)
         2310  +              {
         2311  +                // Note: sqlSelectStatement.FromExtents will not do, since it might
         2312  +                // just be an alias of joinSymbol, and we want an actual JoinSymbol.
         2313  +                JoinSymbol newJoinSymbol = new JoinSymbol(input.VariableName, input.VariableType, oldJoinSymbol.ExtentList);
         2314  +                // This indicates that the sqlSelectStatement is a blocking scope
         2315  +                // i.e. it hides/renames extent columns
         2316  +                newJoinSymbol.IsNestedJoin = true;
         2317  +                newJoinSymbol.ColumnList = columns;
         2318  +                newJoinSymbol.FlattenedExtentList = oldJoinSymbol.FlattenedExtentList;
         2319  +
         2320  +                fromSymbol = newJoinSymbol;
         2321  +              }
         2322  +            }
         2323  +
         2324  +          }
         2325  +          result.From.Append(" (");
         2326  +          result.From.Append(sqlSelectStatement);
         2327  +          result.From.Append(" )");
         2328  +        }
         2329  +        else if (input.Expression is DbScanExpression)
         2330  +        {
         2331  +          result.From.Append(fromExtentFragment);
         2332  +        }
         2333  +        else // bracket it
         2334  +        {
         2335  +          WrapNonQueryExtent(result, fromExtentFragment, input.Expression.ExpressionKind);
         2336  +        }
         2337  +
         2338  +        if (fromSymbol == null) // i.e. not a join symbol
         2339  +        {
         2340  +          fromSymbol = new Symbol(input.VariableName, input.VariableType);
         2341  +        }
         2342  +
         2343  +
         2344  +        AddFromSymbol(result, input.VariableName, fromSymbol);
         2345  +        result.AllJoinExtents.Add(fromSymbol);
         2346  +      }
         2347  +      else // result == fromExtentFragment.  The child extents have been merged into the parent's.
         2348  +      {
         2349  +        // we are adding extents to the current sql statement via flattening.
         2350  +        // We are replacing the child's extents with a single Join symbol.
         2351  +        // The child's extents are all those following the index fromSymbolStart.
         2352  +        //
         2353  +        List<Symbol> extents = new List<Symbol>();
         2354  +
         2355  +        // We cannot call extents.AddRange, since the is no simple way to
         2356  +        // get the range of symbols fromSymbolStart..result.FromExtents.Count
         2357  +        // from result.FromExtents.
         2358  +        // We copy these symbols to create the JoinSymbol later.
         2359  +        for (int i = fromSymbolStart; i < result.FromExtents.Count; ++i)
         2360  +        {
         2361  +          extents.Add(result.FromExtents[i]);
         2362  +        }
         2363  +        result.FromExtents.RemoveRange(fromSymbolStart, result.FromExtents.Count - fromSymbolStart);
         2364  +        fromSymbol = new JoinSymbol(input.VariableName, input.VariableType, extents);
         2365  +        result.FromExtents.Add(fromSymbol);
         2366  +        // this Join Symbol does not have its own select statement, so we
         2367  +        // do not set IsNestedJoin
         2368  +
         2369  +
         2370  +        // We do not call AddFromSymbol(), since we do not want to add
         2371  +        // "AS alias" to the FROM clause- it has been done when the extent was added earlier.
         2372  +        symbolTable.Add(input.VariableName, fromSymbol);
         2373  +      }
         2374  +    }
         2375  +
         2376  +    /// <summary>
         2377  +    /// We assume that this is only called as a child of a Project.
         2378  +    ///
         2379  +    /// This replaces <see cref="Visit(DbNewInstanceExpression)"/>, since
         2380  +    /// we do not allow DbNewInstanceExpression as a child of any node other than
         2381  +    /// DbProjectExpression.
         2382  +    ///
         2383  +    /// We write out the translation of each of the columns in the record.
         2384  +    /// </summary>
         2385  +    /// <param name="e"></param>
         2386  +
         2387  +    /// <returns>A <see cref="SqlBuilder"/></returns>
         2388  +    ISqlFragment VisitNewInstanceExpression(DbNewInstanceExpression e)
         2389  +    {
         2390  +      SqlBuilder result = new SqlBuilder();
         2391  +      RowType rowType = e.ResultType.EdmType as RowType;
         2392  +
         2393  +      if (null != rowType)
         2394  +      {
         2395  +        //_typeDefs.Length = 0;
         2396  +        ReadOnlyMetadataCollection<EdmProperty> members = rowType.Properties;
         2397  +        string separator = "";
         2398  +        for (int i = 0; i < e.Arguments.Count; ++i)
         2399  +        {
         2400  +          DbExpression argument = e.Arguments[i];
         2401  +          if (MetadataHelpers.IsRowType(argument.ResultType))
         2402  +          {
         2403  +            // We do not support nested records or other complex objects.
         2404  +            throw new NotSupportedException();
         2405  +          }
         2406  +
         2407  +          EdmProperty member = members[i];
         2408  +          //_typeDefs.Append(separator);
         2409  +          //_typeDefs.Append(GetSqlPrimitiveType(member.TypeUsage));
         2410  +          result.Append(separator);
         2411  +          result.AppendLine();
         2412  +          result.Append(argument.Accept(this));
         2413  +          result.Append(" AS ");
         2414  +          result.Append(QuoteIdentifier(member.Name));
         2415  +          separator = ", ";
         2416  +        }
         2417  +      }
         2418  +      else
         2419  +      {
         2420  +        //
         2421  +        // Types other then RowType (such as UDTs for instance) are not supported.
         2422  +        //
         2423  +        throw new NotSupportedException();
         2424  +      }
         2425  +
         2426  +      return result;
         2427  +    }
         2428  +
         2429  +    ISqlFragment VisitSetOpExpression(DbExpression left, DbExpression right, string separator)
         2430  +    {
         2431  +
         2432  +      SqlSelectStatement leftSelectStatement = VisitExpressionEnsureSqlStatement(left);
         2433  +      SqlSelectStatement rightSelectStatement = VisitExpressionEnsureSqlStatement(right);
         2434  +
         2435  +      SqlBuilder setStatement = new SqlBuilder();
         2436  +      setStatement.Append(leftSelectStatement);
         2437  +      setStatement.AppendLine();
         2438  +      setStatement.Append(separator); // e.g. UNION ALL
         2439  +      setStatement.AppendLine();
         2440  +      setStatement.Append(rightSelectStatement);
         2441  +
         2442  +      return setStatement;
         2443  +    }
         2444  +
         2445  +
         2446  +    #endregion
         2447  +
         2448  +
         2449  +    #region Function Handling Helpers
         2450  +    /// <summary>
         2451  +    /// Determines whether the given function is a built-in function that requires special handling
         2452  +    /// </summary>
         2453  +    /// <param name="e"></param>
         2454  +    /// <returns></returns>
         2455  +    private bool IsSpecialBuiltInFunction(DbFunctionExpression e)
         2456  +    {
         2457  +      return IsBuiltinFunction(e.Function) && _builtInFunctionHandlers.ContainsKey(e.Function.Name);
         2458  +    }
         2459  +
         2460  +    /// <summary>
         2461  +    /// Determines whether the given function is a canonical function that requires special handling
         2462  +    /// </summary>
         2463  +    /// <param name="e"></param>
         2464  +    /// <returns></returns>
         2465  +    private bool IsSpecialCanonicalFunction(DbFunctionExpression e)
         2466  +    {
         2467  +      return MetadataHelpers.IsCanonicalFunction(e.Function) && _canonicalFunctionHandlers.ContainsKey(e.Function.Name);
         2468  +    }
         2469  +
         2470  +    /// <summary>
         2471  +    /// Default handling for functions
         2472  +    /// Translates them to FunctionName(arg1, arg2, ..., argn)
         2473  +    /// </summary>
         2474  +    /// <param name="e"></param>
         2475  +    /// <returns></returns>
         2476  +    private ISqlFragment HandleFunctionDefault(DbFunctionExpression e)
         2477  +    {
         2478  +      SqlBuilder result = new SqlBuilder();
         2479  +      WriteFunctionName(result, e.Function);
         2480  +      HandleFunctionArgumentsDefault(e, result);
         2481  +      return result;
         2482  +    }
         2483  +
         2484  +    /// <summary>
         2485  +    /// Default handling for functions with a given name.
         2486  +    /// Translates them to functionName(arg1, arg2, ..., argn)
         2487  +    /// </summary>
         2488  +    /// <param name="e"></param>
         2489  +    /// <param name="functionName"></param>
         2490  +    /// <returns></returns>
         2491  +    private ISqlFragment HandleFunctionDefaultGivenName(DbFunctionExpression e, string functionName)
         2492  +    {
         2493  +      SqlBuilder result = new SqlBuilder();
         2494  +      result.Append(functionName);
         2495  +      HandleFunctionArgumentsDefault(e, result);
         2496  +      return result;
         2497  +    }
         2498  +
         2499  +    /// <summary>
         2500  +    /// Default handling on function arguments
         2501  +    /// Appends the list of arguments to the given result
         2502  +    /// If the function is niladic it does not append anything,
         2503  +    /// otherwise it appends (arg1, arg2, ..., argn)
         2504  +    /// </summary>
         2505  +    /// <param name="e"></param>
         2506  +    /// <param name="result"></param>
         2507  +    private void HandleFunctionArgumentsDefault(DbFunctionExpression e, SqlBuilder result)
         2508  +    {
         2509  +      bool isNiladicFunction = MetadataHelpers.TryGetValueForMetadataProperty<bool>(e.Function, "NiladicFunctionAttribute");
         2510  +      if (isNiladicFunction && e.Arguments.Count > 0)
         2511  +      {
         2512  +        throw new InvalidOperationException("Niladic functions cannot have parameters");
         2513  +      }
         2514  +
         2515  +      if (!isNiladicFunction)
         2516  +      {
         2517  +        result.Append("(");
         2518  +        string separator = "";
         2519  +        foreach (DbExpression arg in e.Arguments)
         2520  +        {
         2521  +          result.Append(separator);
         2522  +          result.Append(arg.Accept(this));
         2523  +          separator = ", ";
         2524  +        }
         2525  +        result.Append(")");
         2526  +      }
         2527  +    }
         2528  +
         2529  +    /// <summary>
         2530  +    /// Handler for special built in functions
         2531  +    /// </summary>
         2532  +    /// <param name="e"></param>
         2533  +    /// <returns></returns>
         2534  +    private ISqlFragment HandleSpecialBuiltInFunction(DbFunctionExpression e)
         2535  +    {
         2536  +      return HandleSpecialFunction(_builtInFunctionHandlers, e);
         2537  +    }
         2538  +
         2539  +    /// <summary>
         2540  +    /// Handler for special canonical functions
         2541  +    /// </summary>
         2542  +    /// <param name="e"></param>
         2543  +    /// <returns></returns>
         2544  +    private ISqlFragment HandleSpecialCanonicalFunction(DbFunctionExpression e)
         2545  +    {
         2546  +      return HandleSpecialFunction(_canonicalFunctionHandlers, e);
         2547  +    }
         2548  +
         2549  +    /// <summary>
         2550  +    /// Dispatches the special function processing to the appropriate handler
         2551  +    /// </summary>
         2552  +    /// <param name="handlers"></param>
         2553  +    /// <param name="e"></param>
         2554  +    /// <returns></returns>
         2555  +    private ISqlFragment HandleSpecialFunction(Dictionary<string, FunctionHandler> handlers, DbFunctionExpression e)
         2556  +    {
         2557  +      if (!handlers.ContainsKey(e.Function.Name))
         2558  +        throw new InvalidOperationException("Special handling should be called only for functions in the list of special functions");
         2559  +
         2560  +      return handlers[e.Function.Name](this, e);
         2561  +    }
         2562  +
         2563  +    /// <summary>
         2564  +    /// Handles functions that are translated into TSQL operators.
         2565  +    /// The given function should have one or two arguments. 
         2566  +    /// Functions with one arguemnt are translated into 
         2567  +    ///     op arg
         2568  +    /// Functions with two arguments are translated into
         2569  +    ///     arg0 op arg1
         2570  +    /// Also, the arguments can be optionaly enclosed in parethesis
         2571  +    /// </summary>
         2572  +    /// <param name="e"></param>
         2573  +    /// <param name="parenthesiseArguments">Whether the arguments should be enclosed in parethesis</param>
         2574  +    /// <returns></returns>
         2575  +    private ISqlFragment HandleSpecialFunctionToOperator(DbFunctionExpression e, bool parenthesiseArguments)
         2576  +    {
         2577  +      SqlBuilder result = new SqlBuilder();
         2578  +      Debug.Assert(e.Arguments.Count > 0 && e.Arguments.Count <= 2, "There should be 1 or 2 arguments for operator");
         2579  +
         2580  +      if (e.Arguments.Count > 1)
         2581  +      {
         2582  +        if (parenthesiseArguments)
         2583  +        {
         2584  +          result.Append("(");
         2585  +        }
         2586  +        result.Append(e.Arguments[0].Accept(this));
         2587  +        if (parenthesiseArguments)
         2588  +        {
         2589  +          result.Append(")");
         2590  +        }
         2591  +      }
         2592  +      result.Append(" ");
         2593  +      Debug.Assert(_functionNameToOperatorDictionary.ContainsKey(e.Function.Name), "The function can not be mapped to an operator");
         2594  +      result.Append(_functionNameToOperatorDictionary[e.Function.Name]);
         2595  +      result.Append(" ");
         2596  +
         2597  +      if (parenthesiseArguments)
         2598  +      {
         2599  +        result.Append("(");
         2600  +      }
         2601  +      result.Append(e.Arguments[e.Arguments.Count - 1].Accept(this));
         2602  +      if (parenthesiseArguments)
         2603  +      {
         2604  +        result.Append(")");
         2605  +      }
         2606  +      return result;
         2607  +    }
         2608  +
         2609  +
         2610  +    /// <summary>
         2611  +    /// <see cref="HandleSpecialFunctionToOperator"></see>
         2612  +    /// </summary>
         2613  +    /// <param name="sqlgen"></param>
         2614  +    /// <param name="e"></param>
         2615  +    /// <returns></returns>
         2616  +    private static ISqlFragment HandleConcatFunction(SqlGenerator sqlgen, DbFunctionExpression e)
         2617  +    {
         2618  +      return sqlgen.HandleSpecialFunctionToOperator(e, false);
         2619  +    }
         2620  +
         2621  +    /// <summary>
         2622  +    /// <see cref="HandleSpecialFunctionToOperator"></see>
         2623  +    /// </summary>
         2624  +    /// <param name="sqlgen"></param>
         2625  +    /// <param name="e"></param>
         2626  +    /// <returns></returns>
         2627  +    private static ISqlFragment HandleCanonicalFunctionBitwise(SqlGenerator sqlgen, DbFunctionExpression e)
         2628  +    {
         2629  +      return sqlgen.HandleSpecialFunctionToOperator(e, true);
         2630  +    }
         2631  +
         2632  +    private static ISqlFragment HandleGetDateFunction(SqlGenerator sqlgen, DbFunctionExpression e)
         2633  +    {
         2634  +      SqlBuilder result = new SqlBuilder();
         2635  +      Debug.Assert(e.Arguments.Count == 0, "Canonical getdate function should have no arguments");
         2636  +
         2637  +      switch (sqlgen._manifest._dateFormat)
         2638  +      {
         2639  +        case SQLiteDateFormats.Ticks:
         2640  +          result.Append("(STRFTIME('%s', 'now') * 10000000 + 621355968000000000)");
         2641  +          break;
         2642  +        case SQLiteDateFormats.JulianDay:
         2643  +          result.Append("CAST(STRFTIME('%J', 'now') AS double)");
         2644  +          break;
         2645  +        default:
         2646  +          result.Append("STRFTIME('%Y-%m-%d %H:%M:%S', 'now')");
         2647  +          break;
         2648  +      }
         2649  +
         2650  +      return result;
         2651  +    }
         2652  +
         2653  +    private static ISqlFragment HandleGetUtcDateFunction(SqlGenerator sqlgen, DbFunctionExpression e)
         2654  +    {
         2655  +      SqlBuilder result = new SqlBuilder();
         2656  +      Debug.Assert(e.Arguments.Count == 0, "Canonical getutcdate function should have no arguments");
         2657  +
         2658  +      switch (sqlgen._manifest._dateFormat)
         2659  +      {
         2660  +        case SQLiteDateFormats.Ticks:
         2661  +          result.Append("(STRFTIME('%s', 'now', 'utc') * 10000000 + 621355968000000000)");
         2662  +          break;
         2663  +        case SQLiteDateFormats.JulianDay:
         2664  +          result.Append("CAST(STRFTIME('%J', 'now', 'utc') AS double)");
         2665  +          break;
         2666  +        default:
         2667  +          result.Append("STRFTIME('%Y-%m-%d %H:%M:%S', 'now', 'utc')");
         2668  +          break;
         2669  +      }
         2670  +
         2671  +      return result;
         2672  +    }
         2673  +
         2674  +    /// <summary>
         2675  +    /// Handles special case in which datepart 'type' parameter is present. all the functions
         2676  +    /// handles here have *only* the 1st parameter as datepart. datepart value is passed along
         2677  +    /// the QP as string and has to be expanded as TSQL keyword.
         2678  +    /// </summary>
         2679  +    /// <param name="sqlgen"></param>
         2680  +    /// <param name="e"></param>
         2681  +    /// <returns></returns>
         2682  +    private static ISqlFragment HandleDatepartDateFunction(SqlGenerator sqlgen, DbFunctionExpression e)
         2683  +    {
         2684  +      Debug.Assert(e.Arguments.Count == 2, "datepart function must have 2 arguments");
         2685  +
         2686  +      DbConstantExpression constExpr = e.Arguments[0] as DbConstantExpression;
         2687  +      if (null == constExpr)
         2688  +      {
         2689  +        throw new InvalidOperationException(String.Format("DATEPART argument to function '{0}.{1}' must be a literal string", e.Function.NamespaceName, e.Function.Name));
         2690  +      }
         2691  +
         2692  +      string datepart = constExpr.Value as string;
         2693  +      if (null == datepart)
         2694  +      {
         2695  +        throw new InvalidOperationException(String.Format("DATEPART argument to function '{0}.{1}' must be a literal string", e.Function.NamespaceName, e.Function.Name));
         2696  +      }
         2697  +
         2698  +      SqlBuilder result = new SqlBuilder();
         2699  +
         2700  +      //
         2701  +      // check if datepart value is valid
         2702  +      //
         2703  +      string trans;
         2704  +      if (!_datepartKeywords.TryGetValue(datepart, out trans))
         2705  +      {
         2706  +        throw new InvalidOperationException(String.Format("{0}' is not a valid value for DATEPART argument in '{1}.{2}' function", datepart, e.Function.NamespaceName, e.Function.Name));
         2707  +      }
         2708  +
         2709  +      if (trans != "%f")
         2710  +      {
         2711  +        result.Append("CAST(STRFTIME('");
         2712  +
         2713  +        // expand the datepart literal as tsql kword
         2714  +        result.Append(trans);
         2715  +        result.Append("', ");
         2716  +
         2717  +        switch (sqlgen._manifest._dateFormat)
         2718  +        {
         2719  +          case SQLiteDateFormats.Ticks:
         2720  +            result.Append(String.Format("(({0} - 621355968000000000) / 10000000.0)", e.Arguments[1].Accept(sqlgen)));
         2721  +            break;
         2722  +          default:
         2723  +            result.Append(e.Arguments[1].Accept(sqlgen));
         2724  +            break;
         2725  +        }
         2726  +
         2727  +        result.Append(") AS integer)");
         2728  +      }
         2729  +      else
         2730  +      {
         2731  +        result.Append("CAST(SUBSTR(STRFTIME('%f', ");
         2732  +
         2733  +        switch (sqlgen._manifest._dateFormat)
         2734  +        {
         2735  +          case SQLiteDateFormats.Ticks:
         2736  +            result.Append(String.Format("(({0} - 621355968000000000) / 10000000.0)", e.Arguments[1].Accept(sqlgen)));
         2737  +            break;
         2738  +          default:
         2739  +            result.Append(e.Arguments[1].Accept(sqlgen));
         2740  +            break;
         2741  +        }
         2742  +
         2743  +        result.Append("), 4) AS integer)");
         2744  +      }
         2745  +
         2746  +      return result;
         2747  +    }
         2748  +
         2749  +    /// <summary>
         2750  +    /// DateAdd(datetime, secondsToAdd) -> DATEADD ( seconds , number,  date)
         2751  +    /// </summary>
         2752  +    /// <param name="sqlgen"></param>
         2753  +    /// <param name="e"></param>
         2754  +    /// <returns></returns>
         2755  +    private static ISqlFragment HandleCanonicalFunctionDateAdd(SqlGenerator sqlgen, DbFunctionExpression e)
         2756  +    {
         2757  +      SqlBuilder result = new SqlBuilder();
         2758  +      Debug.Assert(e.Arguments.Count == 2, "Canonical datepart functions should have exactly two arguments");
         2759  +
         2760  +      switch (sqlgen._manifest._dateFormat)
         2761  +      {
         2762  +        case SQLiteDateFormats.Ticks:
         2763  +          result.Append(String.Format("(STRFTIME('%s', JULIANDAY({1}) + ({0} / 86400.0)) * 10000000 + 621355968000000000)", e.Arguments[0].Accept(sqlgen), e.Arguments[1].Accept(sqlgen)));
         2764  +          break;
         2765  +        case SQLiteDateFormats.JulianDay:
         2766  +          result.Append(String.Format("CAST(STRFTIME('%J', JULIANDAY({1}) + ({0} / 86400.0)) AS double)", e.Arguments[0].Accept(sqlgen), e.Arguments[1].Accept(sqlgen)));
         2767  +          break;
         2768  +        default:
         2769  +          result.Append(String.Format("STRFTIME('%Y-%m-%d %H:%M:%S', JULIANDAY({1}) + ({0} / 86400.0))", e.Arguments[0].Accept(sqlgen), e.Arguments[1].Accept(sqlgen)));
         2770  +          break;
         2771  +      }
         2772  +
         2773  +      return result;
         2774  +    }
         2775  +
         2776  +    /// <summary>
         2777  +    /// DateSubtract(datetime1, datetime2) -> DATEDIFF ( seconds , startdate , enddate ) 
         2778  +    /// </summary>
         2779  +    /// <param name="sqlgen"></param>
         2780  +    /// <param name="e"></param>
         2781  +    /// <returns></returns>
         2782  +    private static ISqlFragment HandleCanonicalFunctionDateSubtract(SqlGenerator sqlgen, DbFunctionExpression e)
         2783  +    {
         2784  +      SqlBuilder result = new SqlBuilder();
         2785  +      Debug.Assert(e.Arguments.Count == 2, "Canonical datepart functions should have exactly two arguments");
         2786  +
         2787  +      switch (sqlgen._manifest._dateFormat)
         2788  +      {
         2789  +        case SQLiteDateFormats.Ticks:
         2790  +          result.Append(String.Format("CAST((({0} - 621355968000000000) / 10000000.0)  - (({1} - 621355968000000000) / 10000000.0) * 86400.0 AS integer)", e.Arguments[0].Accept(sqlgen), e.Arguments[1].Accept(sqlgen)));
         2791  +          break;
         2792  +        default:
         2793  +          result.Append(String.Format("CAST((JULIANDAY({1}) - JULIANDAY({0})) * 86400.0 AS integer)", e.Arguments[0].Accept(sqlgen), e.Arguments[1].Accept(sqlgen)));
         2794  +          break;
         2795  +      }
         2796  +
         2797  +      return result;
         2798  +    }
         2799  +
         2800  +    /// <summary>
         2801  +    /// Handler for canonical functions for extracting date parts. 
         2802  +    /// For example:
         2803  +    ///     Year(date) -> DATEPART( year, date)
         2804  +    /// </summary>
         2805  +    /// <param name="sqlgen"></param>
         2806  +    /// <param name="e"></param>
         2807  +    /// <returns></returns>
         2808  +    private static ISqlFragment HandleCanonicalFunctionDatepart(SqlGenerator sqlgen, DbFunctionExpression e)
         2809  +    {
         2810  +      string trans;
         2811  +      if (!_datepartKeywords.TryGetValue(e.Function.Name, out trans))
         2812  +      {
         2813  +        throw new InvalidOperationException(String.Format("{0}' is not a valid value for STRFTIME argument", e.Function.Name));
         2814  +      }
         2815  +
         2816  +      SqlBuilder result = new SqlBuilder();
         2817  +      result.Append("CAST(STRFTIME('");
         2818  +      result.Append(trans);
         2819  +      result.Append("', ");
         2820  +
         2821  +      Debug.Assert(e.Arguments.Count == 1, "Canonical datepart functions should have exactly one argument");
         2822  +
         2823  +      switch (sqlgen._manifest._dateFormat)
         2824  +      {
         2825  +        case SQLiteDateFormats.Ticks:
         2826  +          result.Append(String.Format("(({0} - 621355968000000000) / 10000000.0)", e.Arguments[0].Accept(sqlgen)));
         2827  +          break;
         2828  +        default:
         2829  +          result.Append(e.Arguments[0].Accept(sqlgen));
         2830  +          break;
         2831  +      }
         2832  +
         2833  +      result.Append(") AS integer)");
         2834  +
         2835  +      return result;
         2836  +    }
         2837  +
         2838  +    /// <summary>
         2839  +    ///  Function rename IndexOf -> CHARINDEX
         2840  +    /// </summary>
         2841  +    /// <param name="sqlgen"></param>
         2842  +    /// <param name="e"></param>
         2843  +    /// <returns></returns>
         2844  +    private static ISqlFragment HandleCanonicalFunctionIndexOf(SqlGenerator sqlgen, DbFunctionExpression e)
         2845  +    {
         2846  +      return sqlgen.HandleFunctionDefaultGivenName(e, "CHARINDEX");
         2847  +    }
         2848  +
         2849  +    /// <summary>
         2850  +    ///  Function rename NewGuid -> NEWID
         2851  +    /// </summary>
         2852  +    /// <param name="sqlgen"></param>
         2853  +    /// <param name="e"></param>
         2854  +    /// <returns></returns>
         2855  +    private static ISqlFragment HandleCanonicalFunctionNewGuid(SqlGenerator sqlgen, DbFunctionExpression e)
         2856  +    {
         2857  +      SqlBuilder result = new SqlBuilder();
         2858  +      result.Append("RANDOMBLOB(16)");
         2859  +      return result;
         2860  +    }
         2861  +
         2862  +    /// <summary>
         2863  +    ///  Length(arg) -> LEN(arg + '.') - LEN('.')
         2864  +    /// </summary>
         2865  +    /// <param name="sqlgen"></param>
         2866  +    /// <param name="e"></param>
         2867  +    /// <returns></returns>
         2868  +    private static ISqlFragment HandleCanonicalFunctionLength(SqlGenerator sqlgen, DbFunctionExpression e)
         2869  +    {
         2870  +      SqlBuilder result = new SqlBuilder();
         2871  +
         2872  +      result.Append("LENGTH(");
         2873  +
         2874  +      Debug.Assert(e.Arguments.Count == 1, "Len should have one argument");
         2875  +      result.Append(e.Arguments[0].Accept(sqlgen));
         2876  +
         2877  +      result.Append(")");
         2878  +      //result.Append(" + '.') - LEN('.')");
         2879  +
         2880  +      return result;
         2881  +    }
         2882  +
         2883  +    /// <summary>
         2884  +    /// Round(numericExpression) -> Round(numericExpression, 0);
         2885  +    /// </summary>
         2886  +    /// <param name="sqlgen"></param>
         2887  +    /// <param name="e"></param>
         2888  +    /// <returns></returns>
         2889  +    private static ISqlFragment HandleCanonicalFunctionRound(SqlGenerator sqlgen, DbFunctionExpression e)
         2890  +    {
         2891  +      SqlBuilder result = new SqlBuilder();
         2892  +
         2893  +      result.Append("ROUND(");
         2894  +
         2895  +      Debug.Assert(e.Arguments.Count == 1, "Round should have one argument");
         2896  +      result.Append(e.Arguments[0].Accept(sqlgen));
         2897  +
         2898  +      result.Append(", 0)");
         2899  +
         2900  +      return result;
         2901  +    }
         2902  +
         2903  +    /// <summary>
         2904  +    /// TRIM(string) -> LTRIM(RTRIM(string))
         2905  +    /// </summary>
         2906  +    /// <param name="sqlgen"></param>
         2907  +    /// <param name="e"></param>
         2908  +    /// <returns></returns>
         2909  +    private static ISqlFragment HandleCanonicalFunctionTrim(SqlGenerator sqlgen, DbFunctionExpression e)
         2910  +    {
         2911  +      SqlBuilder result = new SqlBuilder();
         2912  +
         2913  +      result.Append("TRIM(");
         2914  +
         2915  +      Debug.Assert(e.Arguments.Count == 1, "Trim should have one argument");
         2916  +      result.Append(e.Arguments[0].Accept(sqlgen));
         2917  +
         2918  +      result.Append(")");
         2919  +
         2920  +      return result;
         2921  +    }
         2922  +
         2923  +    /// <summary>
         2924  +    ///  Function rename ToLower -> LOWER
         2925  +    /// </summary>
         2926  +    /// <param name="sqlgen"></param>
         2927  +    /// <param name="e"></param>
         2928  +    /// <returns></returns>
         2929  +    private static ISqlFragment HandleCanonicalFunctionToLower(SqlGenerator sqlgen, DbFunctionExpression e)
         2930  +    {
         2931  +      return sqlgen.HandleFunctionDefaultGivenName(e, "LOWER");
         2932  +    }
         2933  +
         2934  +    /// <summary>
         2935  +    ///  Function rename ToUpper -> UPPER
         2936  +    /// </summary>
         2937  +    /// <param name="sqlgen"></param>
         2938  +    /// <param name="e"></param>
         2939  +    /// <returns></returns>
         2940  +    private static ISqlFragment HandleCanonicalFunctionToUpper(SqlGenerator sqlgen, DbFunctionExpression e)
         2941  +    {
         2942  +      return sqlgen.HandleFunctionDefaultGivenName(e, "UPPER");
         2943  +    }
         2944  +
         2945  +    #endregion
         2946  +
         2947  +
         2948  +    #endregion
         2949  +
         2950  +    #region Helper methods for the DbExpressionVisitor
         2951  +    /// <summary>
         2952  +    /// <see cref="AddDefaultColumns"/>
         2953  +    /// Add the column names from the referenced extent/join to the
         2954  +    /// select statement.
         2955  +    ///
         2956  +    /// If the symbol is a JoinSymbol, we recursively visit all the extents,
         2957  +    /// halting at real extents and JoinSymbols that have an associated SqlSelectStatement.
         2958  +    ///
         2959  +    /// The column names for a real extent can be derived from its type.
         2960  +    /// The column names for a Join Select statement can be got from the
         2961  +    /// list of columns that was created when the Join's select statement
         2962  +    /// was created.
         2963  +    ///
         2964  +    /// We do the following for each column.
         2965  +    /// <list type="number">
         2966  +    /// <item>Add the SQL string for each column to the SELECT clause</item>
         2967  +    /// <item>Add the column to the list of columns - so that it can
         2968  +    /// become part of the "type" of a JoinSymbol</item>
         2969  +    /// <item>Check if the column name collides with a previous column added
         2970  +    /// to the same select statement.  Flag both the columns for renaming if true.</item>
         2971  +    /// <item>Add the column to a name lookup dictionary for collision detection.</item>
         2972  +    /// </list>
         2973  +    /// </summary>
         2974  +    /// <param name="selectStatement">The select statement that started off as SELECT *</param>
         2975  +    /// <param name="symbol">The symbol containing the type information for
         2976  +    /// the columns to be added.</param>
         2977  +    /// <param name="columnList">Columns that have been added to the Select statement.
         2978  +    /// This is created in <see cref="AddDefaultColumns"/>.</param>
         2979  +    /// <param name="columnDictionary">A dictionary of the columns above.</param>
         2980  +    /// <param name="separator">Comma or nothing, depending on whether the SELECT
         2981  +    /// clause is empty.</param>
         2982  +    void AddColumns(SqlSelectStatement selectStatement, Symbol symbol,
         2983  +        List<Symbol> columnList, Dictionary<string, Symbol> columnDictionary, ref string separator)
         2984  +    {
         2985  +      JoinSymbol joinSymbol = symbol as JoinSymbol;
         2986  +      if (joinSymbol != null)
         2987  +      {
         2988  +        if (!joinSymbol.IsNestedJoin)
         2989  +        {
         2990  +          // Recurse if the join symbol is a collection of flattened extents
         2991  +          foreach (Symbol sym in joinSymbol.ExtentList)
         2992  +          {
         2993  +            // if sym is ScalarType means we are at base case in the
         2994  +            // recursion and there are not columns to add, just skip
         2995  +            if (MetadataHelpers.IsPrimitiveType(sym.Type))
         2996  +            {
         2997  +              continue;
         2998  +            }
         2999  +
         3000  +            AddColumns(selectStatement, sym, columnList, columnDictionary, ref separator);
         3001  +          }
         3002  +        }
         3003  +        else
         3004  +        {
         3005  +          foreach (Symbol joinColumn in joinSymbol.ColumnList)
         3006  +          {
         3007  +            // we write tableName.columnName
         3008  +            // rather than tableName.columnName as alias
         3009  +            // since the column name is unique (by the way we generate new column names)
         3010  +            //
         3011  +            // We use the symbols for both the table and the column,
         3012  +            // since they are subject to renaming.
         3013  +            selectStatement.Select.Append(separator);
         3014  +            selectStatement.Select.Append(symbol);
         3015  +            selectStatement.Select.Append(".");
         3016  +            selectStatement.Select.Append(joinColumn);
         3017  +
         3018  +            // check for name collisions.  If there is,
         3019  +            // flag both the colliding symbols.
         3020  +            if (columnDictionary.ContainsKey(joinColumn.Name))
         3021  +            {
         3022  +              columnDictionary[joinColumn.Name].NeedsRenaming = true; // the original symbol
         3023  +              joinColumn.NeedsRenaming = true; // the current symbol.
         3024  +            }
         3025  +            else
         3026  +            {
         3027  +              columnDictionary[joinColumn.Name] = joinColumn;
         3028  +            }
         3029  +
         3030  +            columnList.Add(joinColumn);
         3031  +
         3032  +            separator = ", ";
         3033  +          }
         3034  +        }
         3035  +      }
         3036  +      else
         3037  +      {
         3038  +        // This is a non-join extent/select statement, and the CQT type has
         3039  +        // the relevant column information.
         3040  +
         3041  +        // The type could be a record type(e.g. Project(...),
         3042  +        // or an entity type ( e.g. EntityExpression(...)
         3043  +        // so, we check whether it is a structuralType.
         3044  +
         3045  +        // Consider an expression of the form J(a, b=P(E))
         3046  +        // The inner P(E) would have been translated to a SQL statement
         3047  +        // We should not use the raw names from the type, but the equivalent
         3048  +        // symbols (they are present in symbol.Columns) if they exist.
         3049  +        //
         3050  +        // We add the new columns to the symbol's columns if they do
         3051  +        // not already exist.
         3052  +        //
         3053  +
         3054  +        foreach (EdmProperty property in MetadataHelpers.GetProperties(symbol.Type))
         3055  +        {
         3056  +          string recordMemberName = property.Name;
         3057  +          // Since all renaming happens in the second phase
         3058  +          // we lose nothing by setting the next column name index to 0
         3059  +          // many times.
         3060  +          allColumnNames[recordMemberName] = 0;
         3061  +
         3062  +          // Create a new symbol/reuse existing symbol for the column
         3063  +          Symbol columnSymbol;
         3064  +          if (!symbol.Columns.TryGetValue(recordMemberName, out columnSymbol))
         3065  +          {
         3066  +            // we do not care about the types of columns, so we pass null
         3067  +            // when construction the symbol.
         3068  +            columnSymbol = new Symbol(recordMemberName, null);
         3069  +            symbol.Columns.Add(recordMemberName, columnSymbol);
         3070  +          }
         3071  +
         3072  +          selectStatement.Select.Append(separator);
         3073  +          selectStatement.Select.Append(symbol);
         3074  +          selectStatement.Select.Append(".");
         3075  +
         3076  +          // We use the actual name before the "AS", the new name goes
         3077  +          // after the AS.
         3078  +          selectStatement.Select.Append(QuoteIdentifier(recordMemberName));
         3079  +
         3080  +          selectStatement.Select.Append(" AS ");
         3081  +          selectStatement.Select.Append(columnSymbol);
         3082  +
         3083  +          // Check for column name collisions.
         3084  +          if (columnDictionary.ContainsKey(recordMemberName))
         3085  +          {
         3086  +            columnDictionary[recordMemberName].NeedsRenaming = true;
         3087  +            columnSymbol.NeedsRenaming = true;
         3088  +          }
         3089  +          else
         3090  +          {
         3091  +            columnDictionary[recordMemberName] = symbol.Columns[recordMemberName];
         3092  +          }
         3093  +
         3094  +          columnList.Add(columnSymbol);
         3095  +
         3096  +          separator = ", ";
         3097  +        }
         3098  +      }
         3099  +    }
         3100  +
         3101  +    /// <summary>
         3102  +    /// Expands Select * to "select the_list_of_columns"
         3103  +    /// If the columns are taken from an extent, they are written as
         3104  +    /// {original_column_name AS Symbol(original_column)} to allow renaming.
         3105  +    ///
         3106  +    /// If the columns are taken from a Join, they are written as just
         3107  +    /// {original_column_name}, since there cannot be a name collision.
         3108  +    ///
         3109  +    /// We concatenate the columns from each of the inputs to the select statement.
         3110  +    /// Since the inputs may be joins that are flattened, we need to recurse.
         3111  +    /// The inputs are inferred from the symbols in FromExtents.
         3112  +    /// </summary>
         3113  +    /// <param name="selectStatement"></param>
         3114  +    /// <returns></returns>
         3115  +    List<Symbol> AddDefaultColumns(SqlSelectStatement selectStatement)
         3116  +    {
         3117  +      // This is the list of columns added in this select statement
         3118  +      // This forms the "type" of the Select statement, if it has to
         3119  +      // be expanded in another SELECT *
         3120  +      List<Symbol> columnList = new List<Symbol>();
         3121  +
         3122  +      // A lookup for the previous set of columns to aid column name
         3123  +      // collision detection.
         3124  +      Dictionary<string, Symbol> columnDictionary = new Dictionary<string, Symbol>(StringComparer.OrdinalIgnoreCase);
         3125  +
         3126  +      string separator = "";
         3127  +      // The Select should usually be empty before we are called,
         3128  +      // but we do not mind if it is not.
         3129  +      if (!selectStatement.Select.IsEmpty)
         3130  +      {
         3131  +        separator = ", ";
         3132  +      }
         3133  +
         3134  +      foreach (Symbol symbol in selectStatement.FromExtents)
         3135  +      {
         3136  +        AddColumns(selectStatement, symbol, columnList, columnDictionary, ref separator);
         3137  +      }
         3138  +
         3139  +      return columnList;
         3140  +    }
         3141  +
         3142  +    /// <summary>
         3143  +    /// <see cref="AddFromSymbol(SqlSelectStatement, string, Symbol, bool)"/>
         3144  +    /// </summary>
         3145  +    /// <param name="selectStatement"></param>
         3146  +    /// <param name="inputVarName"></param>
         3147  +    /// <param name="fromSymbol"></param>
         3148  +    void AddFromSymbol(SqlSelectStatement selectStatement, string inputVarName, Symbol fromSymbol)
         3149  +    {
         3150  +      AddFromSymbol(selectStatement, inputVarName, fromSymbol, true);
         3151  +    }
         3152  +
         3153  +    /// <summary>
         3154  +    /// This method is called after the input to a relational node is visited.
         3155  +    /// <see cref="Visit(DbProjectExpression)"/> and <see cref="ProcessJoinInputResult"/>
         3156  +    /// There are 2 scenarios
         3157  +    /// <list type="number">
         3158  +    /// <item>The fromSymbol is new i.e. the select statement has just been
         3159  +    /// created, or a join extent has been added.</item>
         3160  +    /// <item>The fromSymbol is old i.e. we are reusing a select statement.</item>
         3161  +    /// </list>
         3162  +    ///
         3163  +    /// If we are not reusing the select statement, we have to complete the
         3164  +    /// FROM clause with the alias
         3165  +    /// <code>
         3166  +    /// -- if the input was an extent
         3167  +    /// FROM = [SchemaName].[TableName]
         3168  +    /// -- if the input was a Project
         3169  +    /// FROM = (SELECT ... FROM ... WHERE ...)
         3170  +    /// </code>
         3171  +    ///
         3172  +    /// These become
         3173  +    /// <code>
         3174  +    /// -- if the input was an extent
         3175  +    /// FROM = [SchemaName].[TableName] AS alias
         3176  +    /// -- if the input was a Project
         3177  +    /// FROM = (SELECT ... FROM ... WHERE ...) AS alias
         3178  +    /// </code>
         3179  +    /// and look like valid FROM clauses.
         3180  +    ///
         3181  +    /// Finally, we have to add the alias to the global list of aliases used,
         3182  +    /// and also to the current symbol table.
         3183  +    /// </summary>
         3184  +    /// <param name="selectStatement"></param>
         3185  +    /// <param name="inputVarName">The alias to be used.</param>
         3186  +    /// <param name="fromSymbol"></param>
         3187  +    /// <param name="addToSymbolTable"></param>
         3188  +    void AddFromSymbol(SqlSelectStatement selectStatement, string inputVarName, Symbol fromSymbol, bool addToSymbolTable)
         3189  +    {
         3190  +      // the first check is true if this is a new statement
         3191  +      // the second check is true if we are in a join - we do not
         3192  +      // check if we are in a join context.
         3193  +      // We do not want to add "AS alias" if it has been done already
         3194  +      // e.g. when we are reusing the Sql statement.
         3195  +      if (selectStatement.FromExtents.Count == 0 || fromSymbol != selectStatement.FromExtents[0])
         3196  +      {
         3197  +        selectStatement.FromExtents.Add(fromSymbol);
         3198  +        selectStatement.From.Append(" AS ");
         3199  +        selectStatement.From.Append(fromSymbol);
         3200  +
         3201  +        // We have this inside the if statement, since
         3202  +        // we only want to add extents that are actually used.
         3203  +        allExtentNames[fromSymbol.Name] = 0;
         3204  +      }
         3205  +
         3206  +      if (addToSymbolTable)
         3207  +      {
         3208  +        symbolTable.Add(inputVarName, fromSymbol);
         3209  +      }
         3210  +    }
         3211  +
         3212  +    /// <summary>
         3213  +    /// Translates a list of SortClauses.
         3214  +    /// Used in the translation of OrderBy 
         3215  +    /// </summary>
         3216  +    /// <param name="orderByClause">The SqlBuilder to which the sort keys should be appended</param>
         3217  +    /// <param name="sortKeys"></param>
         3218  +    void AddSortKeys(SqlBuilder orderByClause, IList<DbSortClause> sortKeys)
         3219  +    {
         3220  +      string separator = "";
         3221  +      foreach (DbSortClause sortClause in sortKeys)
         3222  +      {
         3223  +        orderByClause.Append(separator);
         3224  +        orderByClause.Append(sortClause.Expression.Accept(this));
         3225  +        Debug.Assert(sortClause.Collation != null);
         3226  +        if (!String.IsNullOrEmpty(sortClause.Collation))
         3227  +        {
         3228  +          orderByClause.Append(" COLLATE ");
         3229  +          orderByClause.Append(sortClause.Collation);
         3230  +        }
         3231  +
         3232  +        orderByClause.Append(sortClause.Ascending ? " ASC" : " DESC");
         3233  +
         3234  +        separator = ", ";
         3235  +      }
         3236  +    }
         3237  +
         3238  +    /// <summary>
         3239  +    /// <see cref="CreateNewSelectStatement(SqlSelectStatement oldStatement, string inputVarName, TypeUsage inputVarType, bool finalizeOldStatement, out Symbol fromSymbol) "/>
         3240  +    /// </summary>
         3241  +    /// <param name="oldStatement"></param>
         3242  +    /// <param name="inputVarName"></param>
         3243  +    /// <param name="inputVarType"></param>
         3244  +    /// <param name="fromSymbol"></param>
         3245  +    /// <returns>A new select statement, with the old one as the from clause.</returns>
         3246  +    SqlSelectStatement CreateNewSelectStatement(SqlSelectStatement oldStatement,
         3247  +        string inputVarName, TypeUsage inputVarType, out Symbol fromSymbol)
         3248  +    {
         3249  +      return CreateNewSelectStatement(oldStatement, inputVarName, inputVarType, true, out fromSymbol);
         3250  +    }
         3251  +
         3252  +
         3253  +    /// <summary>
         3254  +    /// This is called after a relational node's input has been visited, and the
         3255  +    /// input's sql statement cannot be reused.  <see cref="Visit(DbProjectExpression)"/>
         3256  +    ///
         3257  +    /// When the input's sql statement cannot be reused, we create a new sql
         3258  +    /// statement, with the old one as the from clause of the new statement.
         3259  +    ///
         3260  +    /// The old statement must be completed i.e. if it has an empty select list,
         3261  +    /// the list of columns must be projected out.
         3262  +    ///
         3263  +    /// If the old statement being completed has a join symbol as its from extent,
         3264  +    /// the new statement must have a clone of the join symbol as its extent.
         3265  +    /// We cannot reuse the old symbol, but the new select statement must behave
         3266  +    /// as though it is working over the "join" record.
         3267  +    /// </summary>
         3268  +    /// <param name="oldStatement"></param>
         3269  +    /// <param name="inputVarName"></param>
         3270  +    /// <param name="inputVarType"></param>
         3271  +    /// <param name="finalizeOldStatement"></param>
         3272  +    /// <param name="fromSymbol"></param>
         3273  +    /// <returns>A new select statement, with the old one as the from clause.</returns>
         3274  +    SqlSelectStatement CreateNewSelectStatement(SqlSelectStatement oldStatement,
         3275  +        string inputVarName, TypeUsage inputVarType, bool finalizeOldStatement, out Symbol fromSymbol)
         3276  +    {
         3277  +      fromSymbol = null;
         3278  +
         3279  +      // Finalize the old statement
         3280  +      if (finalizeOldStatement && oldStatement.Select.IsEmpty)
         3281  +      {
         3282  +        List<Symbol> columns = AddDefaultColumns(oldStatement);
         3283  +
         3284  +        // Thid could not have been called from a join node.
         3285  +        Debug.Assert(oldStatement.FromExtents.Count == 1);
         3286  +
         3287  +        // if the oldStatement has a join as its input, ...
         3288  +        // clone the join symbol, so that we "reuse" the
         3289  +        // join symbol.  Normally, we create a new symbol - see the next block
         3290  +        // of code.
         3291  +        JoinSymbol oldJoinSymbol = oldStatement.FromExtents[0] as JoinSymbol;
         3292  +        if (oldJoinSymbol != null)
         3293  +        {
         3294  +          // Note: oldStatement.FromExtents will not do, since it might
         3295  +          // just be an alias of joinSymbol, and we want an actual JoinSymbol.
         3296  +          JoinSymbol newJoinSymbol = new JoinSymbol(inputVarName, inputVarType, oldJoinSymbol.ExtentList);
         3297  +          // This indicates that the oldStatement is a blocking scope
         3298  +          // i.e. it hides/renames extent columns
         3299  +          newJoinSymbol.IsNestedJoin = true;
         3300  +          newJoinSymbol.ColumnList = columns;
         3301  +          newJoinSymbol.FlattenedExtentList = oldJoinSymbol.FlattenedExtentList;
         3302  +
         3303  +          fromSymbol = newJoinSymbol;
         3304  +        }
         3305  +      }
         3306  +
         3307  +      if (fromSymbol == null)
         3308  +      {
         3309  +        // This is just a simple extent/SqlSelectStatement,
         3310  +        // and we can get the column list from the type.
         3311  +        fromSymbol = new Symbol(inputVarName, inputVarType);
         3312  +      }
         3313  +
         3314  +      // Observe that the following looks like the body of Visit(ExtentExpression).
         3315  +      SqlSelectStatement selectStatement = new SqlSelectStatement();
         3316  +      selectStatement.From.Append("( ");
         3317  +      selectStatement.From.Append(oldStatement);
         3318  +      selectStatement.From.AppendLine();
         3319  +      selectStatement.From.Append(") ");
         3320  +
         3321  +
         3322  +      return selectStatement;
         3323  +    }
         3324  +
         3325  +
         3326  +    /// <summary>
         3327  +    /// Before we embed a string literal in a SQL string, we should
         3328  +    /// convert all ' to '', and enclose the whole string in single quotes.
         3329  +    /// </summary>
         3330  +    /// <param name="s"></param>
         3331  +    /// <param name="isUnicode"></param>
         3332  +    /// <returns>The escaped sql string.</returns>
         3333  +    private static string EscapeSingleQuote(string s, bool isUnicode)
         3334  +    {
         3335  +      return "'" + s.Replace("'", "''") + "'";
         3336  +    }
         3337  +
         3338  +    /// <summary>
         3339  +    /// Returns the sql primitive/native type name. 
         3340  +    /// It will include size, precision or scale depending on type information present in the 
         3341  +    /// type facets
         3342  +    /// </summary>
         3343  +    /// <param name="type"></param>
         3344  +    /// <returns></returns>
         3345  +    private string GetSqlPrimitiveType(TypeUsage type)
         3346  +    {
         3347  +      PrimitiveType primitiveType = MetadataHelpers.GetEdmType<PrimitiveType>(type);
         3348  +
         3349  +      string typeName = primitiveType.Name;
         3350  +      bool isUnicode = true;
         3351  +      bool isFixedLength = false;
         3352  +      int maxLength = 0;
         3353  +      string length = "max";
         3354  +      bool preserveSeconds = true;
         3355  +      byte decimalPrecision = 0;
         3356  +      byte decimalScale = 0;
         3357  +
         3358  +      switch (primitiveType.PrimitiveTypeKind)
         3359  +      {
         3360  +        case PrimitiveTypeKind.Binary:
         3361  +          maxLength = MetadataHelpers.GetFacetValueOrDefault<int>(type, MetadataHelpers.MaxLengthFacetName, MetadataHelpers.BinaryMaxMaxLength);
         3362  +          if (maxLength == MetadataHelpers.BinaryMaxMaxLength)
         3363  +          {
         3364  +            length = "max";
         3365  +          }
         3366  +          else
         3367  +          {
         3368  +            length = maxLength.ToString(CultureInfo.InvariantCulture);
         3369  +          }
         3370  +          isFixedLength = MetadataHelpers.GetFacetValueOrDefault<bool>(type, MetadataHelpers.FixedLengthFacetName, false);
         3371  +          typeName = (isFixedLength ? "binary(" : "varbinary(") + length + ")";
         3372  +          break;
         3373  +
         3374  +        case PrimitiveTypeKind.String:
         3375  +          // Question: How do we handle ntext?
         3376  +          isUnicode = MetadataHelpers.GetFacetValueOrDefault<bool>(type, MetadataHelpers.UnicodeFacetName, true);
         3377  +          isFixedLength = MetadataHelpers.GetFacetValueOrDefault<bool>(type, MetadataHelpers.FixedLengthFacetName, false);
         3378  +          maxLength = MetadataHelpers.GetFacetValueOrDefault<int>(type, MetadataHelpers.MaxLengthFacetName, Int32.MinValue);
         3379  +          if (maxLength == Int32.MinValue)
         3380  +          {
         3381  +            length = "max";
         3382  +          }
         3383  +          else
         3384  +          {
         3385  +            length = maxLength.ToString(CultureInfo.InvariantCulture);
         3386  +          }
         3387  +          if (isUnicode && !isFixedLength && maxLength > 4000)
         3388  +            length = "max";
         3389  +          if (!isUnicode && !isFixedLength && maxLength > 8000)
         3390  +            length = "max";
         3391  +          if (isFixedLength)
         3392  +          {
         3393  +            typeName = (isUnicode ? "nchar(" : "char(") + length + ")";
         3394  +          }
         3395  +          else
         3396  +          {
         3397  +            typeName = (isUnicode ? "nvarchar(" : "varchar(") + length + ")";
         3398  +          }
         3399  +          break;
         3400  +
         3401  +        case PrimitiveTypeKind.DateTime:
         3402  +          preserveSeconds = MetadataHelpers.GetFacetValueOrDefault<bool>(type, MetadataHelpers.PreserveSecondsFacetName, false);
         3403  +          typeName = preserveSeconds ? "datetime" : "smalldatetime";
         3404  +          break;
         3405  +
         3406  +        case PrimitiveTypeKind.Decimal:
         3407  +          decimalPrecision = MetadataHelpers.GetFacetValueOrDefault<byte>(type, MetadataHelpers.PrecisionFacetName, 18);
         3408  +          Debug.Assert(decimalPrecision > 0, "decimal precision must be greater than zero");
         3409  +          decimalScale = MetadataHelpers.GetFacetValueOrDefault<byte>(type, MetadataHelpers.ScaleFacetName, 0);
         3410  +          Debug.Assert(decimalPrecision >= decimalScale, "decimalPrecision must be greater or equal to decimalScale");
         3411  +          Debug.Assert(decimalPrecision <= 53, "decimalPrecision must be less than or equal to 53");
         3412  +          typeName = typeName + "(" + decimalPrecision + "," + decimalScale + ")";
         3413  +          break;
         3414  +
         3415  +        case PrimitiveTypeKind.Int32:
         3416  +          typeName = "int";
         3417  +          break;
         3418  +
         3419  +        case PrimitiveTypeKind.Int64:
         3420  +          typeName = "bigint";
         3421  +          break;
         3422  +
         3423  +        case PrimitiveTypeKind.Int16:
         3424  +          typeName = "smallint";
         3425  +          break;
         3426  +
         3427  +        case PrimitiveTypeKind.Byte:
         3428  +          typeName = "tinyint";
         3429  +          break;
         3430  +
         3431  +        case PrimitiveTypeKind.Boolean:
         3432  +          typeName = "bit";
         3433  +          break;
         3434  +
         3435  +        case PrimitiveTypeKind.Single:
         3436  +          typeName = "real";
         3437  +          break;
         3438  +
         3439  +        case PrimitiveTypeKind.Double:
         3440  +          typeName = "float";
         3441  +          break;
         3442  +
         3443  +        case PrimitiveTypeKind.Guid:
         3444  +          typeName = "uniqueidentifier";
         3445  +          break;
         3446  +
         3447  +        default:
         3448  +          throw new NotSupportedException("Unsupported EdmType: " + primitiveType.PrimitiveTypeKind);
         3449  +      }
         3450  +
         3451  +      return typeName;
         3452  +    }
         3453  +
         3454  +    /// <summary>
         3455  +    /// Handles the expression represending DbLimitExpression.Limit and DbSkipExpression.Count.
         3456  +    /// If it is a constant expression, it simply does to string thus avoiding casting it to the specific value
         3457  +    /// (which would be done if <see cref="Visit(DbConstantExpression)"/> is called)
         3458  +    /// </summary>
         3459  +    /// <param name="e"></param>
         3460  +    /// <returns></returns>
         3461  +    private ISqlFragment HandleCountExpression(DbExpression e)
         3462  +    {
         3463  +      ISqlFragment result;
         3464  +
         3465  +      if (e.ExpressionKind == DbExpressionKind.Constant)
         3466  +      {
         3467  +        //For constant expression we should not cast the value, 
         3468  +        // thus we don't go throught the default DbConstantExpression handling
         3469  +        SqlBuilder sqlBuilder = new SqlBuilder();
         3470  +        sqlBuilder.Append(((DbConstantExpression)e).Value.ToString());
         3471  +        result = sqlBuilder;
         3472  +      }
         3473  +      else
         3474  +      {
         3475  +        result = e.Accept(this);
         3476  +      }
         3477  +
         3478  +      return result;
         3479  +    }
         3480  +
         3481  +    /// <summary>
         3482  +    /// This is used to determine if a particular expression is an Apply operation.
         3483  +    /// This is only the case when the DbExpressionKind is CrossApply or OuterApply.
         3484  +    /// </summary>
         3485  +    /// <param name="e"></param>
         3486  +    /// <returns></returns>
         3487  +    bool IsApplyExpression(DbExpression e)
         3488  +    {
         3489  +      return (DbExpressionKind.CrossApply == e.ExpressionKind || DbExpressionKind.OuterApply == e.ExpressionKind);
         3490  +    }
         3491  +
         3492  +    private bool IsKeyForIn(DbExpression e)
         3493  +    {
         3494  +      if ((e.ExpressionKind != DbExpressionKind.Property) && (e.ExpressionKind != DbExpressionKind.VariableReference))
         3495  +      {
         3496  +        return (e.ExpressionKind == DbExpressionKind.ParameterReference);
         3497  +      }
         3498  +      return true;
         3499  +    }
         3500  +
         3501  +    /// <summary>
         3502  +    /// This is used to determine if a particular expression is a Join operation.
         3503  +    /// This is true for DbCrossJoinExpression and DbJoinExpression, the
         3504  +    /// latter of which may have one of several different ExpressionKinds.
         3505  +    /// </summary>
         3506  +    /// <param name="e"></param>
         3507  +    /// <returns></returns>
         3508  +    bool IsJoinExpression(DbExpression e)
         3509  +    {
         3510  +      return (DbExpressionKind.CrossJoin == e.ExpressionKind ||
         3511  +              DbExpressionKind.FullOuterJoin == e.ExpressionKind ||
         3512  +              DbExpressionKind.InnerJoin == e.ExpressionKind ||
         3513  +              DbExpressionKind.LeftOuterJoin == e.ExpressionKind);
         3514  +    }
         3515  +
         3516  +    /// <summary>
         3517  +    /// This is used to determine if a calling expression needs to place
         3518  +    /// round brackets around the translation of the expression e.
         3519  +    ///
         3520  +    /// Constants, parameters and properties do not require brackets,
         3521  +    /// everything else does.
         3522  +    /// </summary>
         3523  +    /// <param name="e"></param>
         3524  +    /// <returns>true, if the expression needs brackets </returns>
         3525  +    bool IsComplexExpression(DbExpression e)
         3526  +    {
         3527  +      switch (e.ExpressionKind)
         3528  +      {
         3529  +        case DbExpressionKind.Constant:
         3530  +        case DbExpressionKind.ParameterReference:
         3531  +        case DbExpressionKind.Property:
         3532  +          return false;
         3533  +
         3534  +        default:
         3535  +          return true;
         3536  +      }
         3537  +    }
         3538  +
         3539  +    /// <summary>
         3540  +    /// Determine if the owner expression can add its unique sql to the input's
         3541  +    /// SqlSelectStatement
         3542  +    /// </summary>
         3543  +    /// <param name="result">The SqlSelectStatement of the input to the relational node.</param>
         3544  +    /// <param name="expressionKind">The kind of the expression node(not the input's)</param>
         3545  +    /// <returns></returns>
         3546  +    bool IsCompatible(SqlSelectStatement result, DbExpressionKind expressionKind)
         3547  +    {
         3548  +      switch (expressionKind)
         3549  +      {
         3550  +        case DbExpressionKind.Distinct:
         3551  +          return result.Top == null
         3552  +            // The projection after distinct may not project all 
         3553  +            // columns used in the Order By
         3554  +              && result.OrderBy.IsEmpty;
         3555  +
         3556  +        case DbExpressionKind.Filter:
         3557  +          return result.Select.IsEmpty
         3558  +                  && result.Where.IsEmpty
         3559  +                  && result.GroupBy.IsEmpty
         3560  +                  && result.Top == null;
         3561  +
         3562  +        case DbExpressionKind.GroupBy:
         3563  +          return result.Select.IsEmpty
         3564  +                  && result.GroupBy.IsEmpty
         3565  +                  && result.OrderBy.IsEmpty
         3566  +                  && result.Top == null;
         3567  +
         3568  +        case DbExpressionKind.Limit:
         3569  +        case DbExpressionKind.Element:
         3570  +          return result.Top == null;
         3571  +
         3572  +        case DbExpressionKind.Project:
         3573  +          return result.Select.IsEmpty
         3574  +                  && result.GroupBy.IsEmpty;
         3575  +
         3576  +        case DbExpressionKind.Skip:
         3577  +          return result.Select.IsEmpty
         3578  +                  && result.GroupBy.IsEmpty
         3579  +                  && result.OrderBy.IsEmpty
         3580  +                  && !result.IsDistinct;
         3581  +
         3582  +        case DbExpressionKind.Sort:
         3583  +          return result.Select.IsEmpty
         3584  +                  && result.GroupBy.IsEmpty
         3585  +                  && result.OrderBy.IsEmpty;
         3586  +
         3587  +        default:
         3588  +          Debug.Assert(false);
         3589  +          throw new InvalidOperationException();
         3590  +      }
         3591  +
         3592  +    }
         3593  +
         3594  +    private void ParenthesizeExpressionWithoutRedundantConstantCasts(DbExpression value, SqlBuilder sqlBuilder)
         3595  +    {
         3596  +      if (value.ExpressionKind == DbExpressionKind.Constant)
         3597  +      {
         3598  +        sqlBuilder.Append(this.Visit((DbConstantExpression)value));
         3599  +      }
         3600  +      else
         3601  +      {
         3602  +        this.ParanthesizeExpressionIfNeeded(value, sqlBuilder);
         3603  +		  }
         3604  +	  }
         3605  +
         3606  +    private void ParanthesizeExpressionIfNeeded(DbExpression e, SqlBuilder result)
         3607  +    {
         3608  +      if (IsComplexExpression(e))
         3609  +      {
         3610  +        result.Append("(");
         3611  +        result.Append(e.Accept<ISqlFragment>(this));
         3612  +        result.Append(")");
         3613  +      }
         3614  +      else
         3615  +      {
         3616  +        result.Append(e.Accept<ISqlFragment>(this));
         3617  +      }
         3618  +    }
         3619  +
         3620  +    /// <summary>
         3621  +    /// We use the normal box quotes for SQL server.  We do not deal with ANSI quotes
         3622  +    /// i.e. double quotes.
         3623  +    /// </summary>
         3624  +    /// <param name="name"></param>
         3625  +    /// <returns></returns>
         3626  +    internal static string QuoteIdentifier(string name)
         3627  +    {
         3628  +      Debug.Assert(!String.IsNullOrEmpty(name));
         3629  +      // We assume that the names are not quoted to begin with.
         3630  +      return "[" + name.Replace("]", "]]") + "]";
         3631  +    }
         3632  +
         3633  +    private bool TryAddExpressionForIn(DbBinaryExpression e, KeyToListMap<DbExpression, DbExpression> values)
         3634  +    {
         3635  +      if (this.IsKeyForIn(e.Left))
         3636  +      {
         3637  +        values.Add(e.Left, e.Right);
         3638  +        return true;
         3639  +      }
         3640  +      if (this.IsKeyForIn(e.Right))
         3641  +      {
         3642  +        values.Add(e.Right, e.Left);
         3643  +        return true;
         3644  +      }
         3645  +      return false;
         3646  +    }
         3647  +
         3648  +    /// <summary>
         3649  +    /// Simply calls <see cref="VisitExpressionEnsureSqlStatement(DbExpression, bool)"/>
         3650  +    /// with addDefaultColumns set to true
         3651  +    /// </summary>
         3652  +    /// <param name="e"></param>
         3653  +    /// <returns></returns>
         3654  +    SqlSelectStatement VisitExpressionEnsureSqlStatement(DbExpression e)
         3655  +    {
         3656  +      return VisitExpressionEnsureSqlStatement(e, true);
         3657  +    }
         3658  +
         3659  +    /// <summary>
         3660  +    /// This is called from <see cref="GenerateSql(DbQueryCommandTree)"/> and nodes which require a
         3661  +    /// select statement as an argument e.g. <see cref="Visit(DbIsEmptyExpression)"/>,
         3662  +    /// <see cref="Visit(DbUnionAllExpression)"/>.
         3663  +    ///
         3664  +    /// SqlGenerator needs its child to have a proper alias if the child is
         3665  +    /// just an extent or a join.
         3666  +    ///
         3667  +    /// The normal relational nodes result in complete valid SQL statements.
         3668  +    /// For the rest, we need to treat them as there was a dummy
         3669  +    /// <code>
         3670  +    /// -- originally {expression}
         3671  +    /// -- change that to
         3672  +    /// SELECT *
         3673  +    /// FROM {expression} as c
         3674  +    /// </code>
         3675  +    /// 
         3676  +    /// DbLimitExpression needs to start the statement but not add the default columns
         3677  +    /// </summary>
         3678  +    /// <param name="e"></param>
         3679  +    /// <param name="addDefaultColumns"></param>
         3680  +    /// <returns></returns>
         3681  +    SqlSelectStatement VisitExpressionEnsureSqlStatement(DbExpression e, bool addDefaultColumns)
         3682  +    {
         3683  +      Debug.Assert(MetadataHelpers.IsCollectionType(e.ResultType));
         3684  +
         3685  +      SqlSelectStatement result;
         3686  +      switch (e.ExpressionKind)
         3687  +      {
         3688  +        case DbExpressionKind.Project:
         3689  +        case DbExpressionKind.Filter:
         3690  +        case DbExpressionKind.GroupBy:
         3691  +        case DbExpressionKind.Sort:
         3692  +          result = e.Accept(this) as SqlSelectStatement;
         3693  +          break;
         3694  +
         3695  +        default:
         3696  +          Symbol fromSymbol;
         3697  +          string inputVarName = "c";  // any name will do - this is my random choice.
         3698  +          symbolTable.EnterScope();
         3699  +
         3700  +          TypeUsage type = null;
         3701  +          switch (e.ExpressionKind)
         3702  +          {
         3703  +            case DbExpressionKind.Scan:
         3704  +            case DbExpressionKind.CrossJoin:
         3705  +            case DbExpressionKind.FullOuterJoin:
         3706  +            case DbExpressionKind.InnerJoin:
         3707  +            case DbExpressionKind.LeftOuterJoin:
         3708  +            case DbExpressionKind.CrossApply:
         3709  +            case DbExpressionKind.OuterApply:
         3710  +              type = MetadataHelpers.GetElementTypeUsage(e.ResultType);
         3711  +              break;
         3712  +
         3713  +            default:
         3714  +              Debug.Assert(MetadataHelpers.IsCollectionType(e.ResultType));
         3715  +              type = MetadataHelpers.GetEdmType<CollectionType>(e.ResultType).TypeUsage;
         3716  +              break;
         3717  +          }
         3718  +
         3719  +          result = VisitInputExpression(e, inputVarName, type, out fromSymbol);
         3720  +          AddFromSymbol(result, inputVarName, fromSymbol);
         3721  +          symbolTable.ExitScope();
         3722  +          break;
         3723  +      }
         3724  +
         3725  +      if (addDefaultColumns && result.Select.IsEmpty)
         3726  +      {
         3727  +        AddDefaultColumns(result);
         3728  +      }
         3729  +
         3730  +      return result;
         3731  +    }
         3732  +
         3733  +    /// <summary>
         3734  +    /// This method is called by <see cref="Visit(DbFilterExpression)"/> and
         3735  +    /// <see cref="Visit(DbQuantifierExpression)"/>
         3736  +    ///
         3737  +    /// </summary>
         3738  +    /// <param name="input"></param>
         3739  +    /// <param name="predicate"></param>
         3740  +    /// <param name="negatePredicate">This is passed from <see cref="Visit(DbQuantifierExpression)"/>
         3741  +    /// in the All(...) case.</param>
         3742  +    /// <returns></returns>
         3743  +    SqlSelectStatement VisitFilterExpression(DbExpressionBinding input, DbExpression predicate, bool negatePredicate)
         3744  +    {
         3745  +      Symbol fromSymbol;
         3746  +      SqlSelectStatement result = VisitInputExpression(input.Expression,
         3747  +          input.VariableName, input.VariableType, out fromSymbol);
         3748  +
         3749  +      // Filter is compatible with OrderBy
         3750  +      // but not with Project, another Filter or GroupBy
         3751  +      if (!IsCompatible(result, DbExpressionKind.Filter))
         3752  +      {
         3753  +        result = CreateNewSelectStatement(result, input.VariableName, input.VariableType, out fromSymbol);
         3754  +      }
         3755  +
         3756  +      selectStatementStack.Push(result);
         3757  +      symbolTable.EnterScope();
         3758  +
         3759  +      AddFromSymbol(result, input.VariableName, fromSymbol);
         3760  +
         3761  +      if (negatePredicate)
         3762  +      {
         3763  +        result.Where.Append("NOT (");
         3764  +      }
         3765  +      result.Where.Append(predicate.Accept(this));
         3766  +      if (negatePredicate)
         3767  +      {
         3768  +        result.Where.Append(")");
         3769  +      }
         3770  +
         3771  +      symbolTable.ExitScope();
         3772  +      selectStatementStack.Pop();
         3773  +
         3774  +      return result;
         3775  +    }
         3776  +
         3777  +    /// <summary>
         3778  +    /// If the sql fragment for an input expression is not a SqlSelect statement
         3779  +    /// or other acceptable form (e.g. an extent as a SqlBuilder), we need
         3780  +    /// to wrap it in a form acceptable in a FROM clause.  These are
         3781  +    /// primarily the
         3782  +    /// <list type="bullet">
         3783  +    /// <item>The set operation expressions - union all, intersect, except</item>
         3784  +    /// <item>TVFs, which are conceptually similar to tables</item>
         3785  +    /// </list>
         3786  +    /// </summary>
         3787  +    /// <param name="result"></param>
         3788  +    /// <param name="sqlFragment"></param>
         3789  +    /// <param name="expressionKind"></param>
         3790  +    void WrapNonQueryExtent(SqlSelectStatement result, ISqlFragment sqlFragment, DbExpressionKind expressionKind)
         3791  +    {
         3792  +      switch (expressionKind)
         3793  +      {
         3794  +        case DbExpressionKind.Function:
         3795  +          // TVF
         3796  +          result.From.Append(sqlFragment);
         3797  +          break;
         3798  +
         3799  +        default:
         3800  +          result.From.Append(" (");
         3801  +          result.From.Append(sqlFragment);
         3802  +          result.From.Append(")");
         3803  +          break;
         3804  +      }
         3805  +    }
         3806  +
         3807  +    /// <summary>
         3808  +    /// Is this a builtin function (ie) does it have the builtinAttribute specified?
         3809  +    /// </summary>
         3810  +    /// <param name="function"></param>
         3811  +    /// <returns></returns>
         3812  +    private static bool IsBuiltinFunction(EdmFunction function)
         3813  +    {
         3814  +      return MetadataHelpers.TryGetValueForMetadataProperty<bool>(function, "BuiltInAttribute");
         3815  +    }
         3816  +
         3817  +    /// <summary>
         3818  +    ///
         3819  +    /// </summary>
         3820  +    /// <param name="function"></param>
         3821  +    /// <param name="result"></param>
         3822  +    void WriteFunctionName(SqlBuilder result, EdmFunction function)
         3823  +    {
         3824  +      string storeFunctionName = MetadataHelpers.TryGetValueForMetadataProperty<string>(function, "StoreFunctionNameAttribute");
         3825  +
         3826  +      if (string.IsNullOrEmpty(storeFunctionName))
         3827  +      {
         3828  +        storeFunctionName = function.Name;
         3829  +      }
         3830  +
         3831  +      // If the function is a builtin (ie) the BuiltIn attribute has been
         3832  +      // specified, then, the function name should not be quoted; additionally,
         3833  +      // no namespace should be used.
         3834  +      if (IsBuiltinFunction(function))
         3835  +      {
         3836  +        if (function.NamespaceName == "Edm")
         3837  +        {
         3838  +          switch (storeFunctionName.ToUpperInvariant())
         3839  +          {
         3840  +            default:
         3841  +              result.Append(storeFunctionName);
         3842  +              break;
         3843  +          }
         3844  +
         3845  +        }
         3846  +        else
         3847  +        {
         3848  +          result.Append(storeFunctionName);
         3849  +        }
         3850  +
         3851  +      }
         3852  +      else
         3853  +      {
         3854  +        // Should we actually support this?
         3855  +        //result.Append(QuoteIdentifier((string)function.MetadataProperties["Schema"].Value ?? "dbo"));
         3856  +        //result.Append(".");
         3857  +        result.Append(QuoteIdentifier(storeFunctionName));
         3858  +      }
         3859  +    }
         3860  +
         3861  +    static string ByteArrayToBinaryString(Byte[] binaryArray)
         3862  +    {
         3863  +      StringBuilder sb = new StringBuilder(binaryArray.Length * 2);
         3864  +      for (int i = 0; i < binaryArray.Length; i++)
         3865  +      {
         3866  +        sb.Append(hexDigits[(binaryArray[i] & 0xF0) >> 4]).Append(hexDigits[binaryArray[i] & 0x0F]);
         3867  +      }
         3868  +      return sb.ToString();
         3869  +    }
         3870  +
         3871  +    /// <summary>
         3872  +    /// Helper method for the Group By visitor
         3873  +    /// Returns true if at least one of the aggregates in the given list
         3874  +    /// has an argument that is not a <see cref="DbPropertyExpression"/> 
         3875  +    /// over <see cref="DbVariableReferenceExpression"/>
         3876  +    /// </summary>
         3877  +    /// <param name="aggregates"></param>
         3878  +    /// <returns></returns>
         3879  +    static bool NeedsInnerQuery(IList<DbAggregate> aggregates)
         3880  +    {
         3881  +      foreach (DbAggregate aggregate in aggregates)
         3882  +      {
         3883  +        Debug.Assert(aggregate.Arguments.Count == 1);
         3884  +        if (!IsPropertyOverVarRef(aggregate.Arguments[0]))
         3885  +        {
         3886  +          return true;
         3887  +        }
         3888  +      }
         3889  +      return false;
         3890  +    }
         3891  +
         3892  +    /// <summary>
         3893  +    /// Determines whether the given expression is a <see cref="DbPropertyExpression"/> 
         3894  +    /// over <see cref="DbVariableReferenceExpression"/>
         3895  +    /// </summary>
         3896  +    /// <param name="expression"></param>
         3897  +    /// <returns></returns>
         3898  +    static bool IsPropertyOverVarRef(DbExpression expression)
         3899  +    {
         3900  +      DbPropertyExpression propertyExpression = expression as DbPropertyExpression;
         3901  +      if (propertyExpression == null)
         3902  +      {
         3903  +        return false;
         3904  +      }
         3905  +      DbVariableReferenceExpression varRefExpression = propertyExpression.Instance as DbVariableReferenceExpression;
         3906  +      if (varRefExpression == null)
         3907  +      {
         3908  +        return false;
         3909  +      }
         3910  +      return true;
         3911  +    }
         3912  +
         3913  +    #endregion
         3914  +    
         3915  +    private class KeyFieldExpressionComparer : IEqualityComparer<DbExpression>
         3916  +    {
         3917  +      // Fields
         3918  +      internal static readonly SqlGenerator.KeyFieldExpressionComparer Singleton = new SqlGenerator.KeyFieldExpressionComparer();
         3919  +
         3920  +      // Methods
         3921  +      private KeyFieldExpressionComparer()
         3922  +      {
         3923  +      }
         3924  +
         3925  +      public bool Equals(DbExpression x, DbExpression y)
         3926  +      {
         3927  +        if (x.ExpressionKind == y.ExpressionKind)
         3928  +        {
         3929  +          DbExpressionKind expressionKind = x.ExpressionKind;
         3930  +          if (expressionKind <= DbExpressionKind.ParameterReference)
         3931  +          {
         3932  +            switch (expressionKind)
         3933  +            {
         3934  +              case DbExpressionKind.Cast:
         3935  +                {
         3936  +                  DbCastExpression expression5 = (DbCastExpression)x;
         3937  +                  DbCastExpression expression6 = (DbCastExpression)y;
         3938  +                  return ((expression5.ResultType == expression6.ResultType) && this.Equals(expression5.Argument, expression6.Argument));
         3939  +                }
         3940  +              case DbExpressionKind.ParameterReference:
         3941  +                {
         3942  +                  DbParameterReferenceExpression expression3 = (DbParameterReferenceExpression)x;
         3943  +                  DbParameterReferenceExpression expression4 = (DbParameterReferenceExpression)y;
         3944  +                  return (expression3.ParameterName == expression4.ParameterName);
         3945  +                }
         3946  +            }
         3947  +            goto Label_00CC;
         3948  +          }
         3949  +          if (expressionKind != DbExpressionKind.Property)
         3950  +          {
         3951  +            if (expressionKind == DbExpressionKind.VariableReference)
         3952  +            {
         3953  +              return (x == y);
         3954  +            }
         3955  +            goto Label_00CC;
         3956  +          }
         3957  +          DbPropertyExpression expression = (DbPropertyExpression)x;
         3958  +          DbPropertyExpression expression2 = (DbPropertyExpression)y;
         3959  +          if (expression.Property == expression2.Property)
         3960  +          {
         3961  +            return this.Equals(expression.Instance, expression2.Instance);
         3962  +          }
         3963  +        }
         3964  +        return false;
         3965  +      Label_00CC:
         3966  +        return false;
         3967  +      }
         3968  +
         3969  +      public int GetHashCode(DbExpression obj)
         3970  +      {
         3971  +        switch (obj.ExpressionKind)
         3972  +        {
         3973  +          case DbExpressionKind.Cast:
         3974  +            return this.GetHashCode(((DbCastExpression)obj).Argument);
         3975  +
         3976  +          case DbExpressionKind.ParameterReference:
         3977  +            return (((DbParameterReferenceExpression)obj).ParameterName.GetHashCode() ^ 0x7fffffff);
         3978  +
         3979  +          case DbExpressionKind.Property:
         3980  +            return ((DbPropertyExpression)obj).Property.GetHashCode();
         3981  +
         3982  +          case DbExpressionKind.VariableReference:
         3983  +            return ((DbVariableReferenceExpression)obj).VariableName.GetHashCode();
         3984  +        }
         3985  +        return obj.GetHashCode();
         3986  +      }
         3987  +    }
         3988  +  }
         3989  +}
         3990  +

Added System.Data.SQLite.Linq/SQL Generation/SqlSelectStatement.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="SqlSelectStatement.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Collections.Generic;
           15  +  using System.Diagnostics;
           16  +  using System.IO;
           17  +  using System.Text;
           18  +  using System.Data.Metadata.Edm;
           19  +  using System.Data.Common.CommandTrees;
           20  +
           21  +  /// <summary>
           22  +  /// A SqlSelectStatement represents a canonical SQL SELECT statement.
           23  +  /// It has fields for the 5 main clauses
           24  +  /// <list type="number">
           25  +  /// <item>SELECT</item>
           26  +  /// <item>FROM</item>
           27  +  /// <item>WHERE</item>
           28  +  /// <item>GROUP BY</item>
           29  +  /// <item>ORDER BY</item>
           30  +  /// </list>
           31  +  /// We do not have HAVING, since it does not correspond to anything in the DbCommandTree.
           32  +  /// Each of the fields is a SqlBuilder, so we can keep appending SQL strings
           33  +  /// or other fragments to build up the clause.
           34  +  ///
           35  +  /// We have a IsDistinct property to indicate that we want distict columns.
           36  +  /// This is given out of band, since the input expression to the select clause
           37  +  /// may already have some columns projected out, and we use append-only SqlBuilders.
           38  +  /// The DISTINCT is inserted when we finally write the object into a string.
           39  +  /// 
           40  +  /// Also, we have a Top property, which is non-null if the number of results should
           41  +  /// be limited to certain number. It is given out of band for the same reasons as DISTINCT.
           42  +  ///
           43  +  /// The FromExtents contains the list of inputs in use for the select statement.
           44  +  /// There is usually just one element in this - Select statements for joins may
           45  +  /// temporarily have more than one.
           46  +  ///
           47  +  /// If the select statement is created by a Join node, we maintain a list of
           48  +  /// all the extents that have been flattened in the join in AllJoinExtents
           49  +  /// <example>
           50  +  /// in J(j1= J(a,b), c)
           51  +  /// FromExtents has 2 nodes JoinSymbol(name=j1, ...) and Symbol(name=c)
           52  +  /// AllJoinExtents has 3 nodes Symbol(name=a), Symbol(name=b), Symbol(name=c)
           53  +  /// </example>
           54  +  ///
           55  +  /// If any expression in the non-FROM clause refers to an extent in a higher scope,
           56  +  /// we add that extent to the OuterExtents list.  This list denotes the list
           57  +  /// of extent aliases that may collide with the aliases used in this select statement.
           58  +  /// It is set by <see cref="SqlGenerator.Visit(DbVariableReferenceExpression)"/>.
           59  +  /// An extent is an outer extent if it is not one of the FromExtents.
           60  +  ///
           61  +  ///
           62  +  /// </summary>
           63  +  internal sealed class SqlSelectStatement : ISqlFragment
           64  +  {
           65  +    private bool isDistinct;
           66  +
           67  +    /// <summary>
           68  +    /// Do we need to add a DISTINCT at the beginning of the SELECT
           69  +    /// </summary>
           70  +    internal bool IsDistinct
           71  +    {
           72  +      get { return isDistinct; }
           73  +      set { isDistinct = value; }
           74  +    }
           75  +
           76  +    private List<Symbol> allJoinExtents;
           77  +    internal List<Symbol> AllJoinExtents
           78  +    {
           79  +      get { return allJoinExtents; }
           80  +      // We have a setter as well, even though this is a list,
           81  +      // since we use this field only in special cases.
           82  +      set { allJoinExtents = value; }
           83  +    }
           84  +
           85  +    private List<Symbol> fromExtents;
           86  +    internal List<Symbol> FromExtents
           87  +    {
           88  +      get
           89  +      {
           90  +        if (null == fromExtents)
           91  +        {
           92  +          fromExtents = new List<Symbol>();
           93  +        }
           94  +        return fromExtents;
           95  +      }
           96  +    }
           97  +
           98  +    private Dictionary<Symbol, bool> outerExtents;
           99  +    internal Dictionary<Symbol, bool> OuterExtents
          100  +    {
          101  +      get
          102  +      {
          103  +        if (null == outerExtents)
          104  +        {
          105  +          outerExtents = new Dictionary<Symbol, bool>();
          106  +        }
          107  +        return outerExtents;
          108  +      }
          109  +    }
          110  +
          111  +    private TopClause top;
          112  +    internal TopClause Top
          113  +    {
          114  +      get { return top; }
          115  +      set
          116  +      {
          117  +        Debug.Assert(top == null, "SqlSelectStatement.Top has already been set");
          118  +        top = value;
          119  +      }
          120  +    }
          121  +
          122  +    private SqlBuilder select = new SqlBuilder();
          123  +    internal SqlBuilder Select
          124  +    {
          125  +      get { return select; }
          126  +    }
          127  +
          128  +    private SqlBuilder from = new SqlBuilder();
          129  +    internal SqlBuilder From
          130  +    {
          131  +      get { return from; }
          132  +    }
          133  +
          134  +
          135  +    private SqlBuilder where;
          136  +    internal SqlBuilder Where
          137  +    {
          138  +      get
          139  +      {
          140  +        if (null == where)
          141  +        {
          142  +          where = new SqlBuilder();
          143  +        }
          144  +        return where;
          145  +      }
          146  +    }
          147  +
          148  +    private SqlBuilder groupBy;
          149  +    internal SqlBuilder GroupBy
          150  +    {
          151  +      get
          152  +      {
          153  +        if (null == groupBy)
          154  +        {
          155  +          groupBy = new SqlBuilder();
          156  +        }
          157  +        return groupBy;
          158  +      }
          159  +    }
          160  +
          161  +    private SqlBuilder orderBy;
          162  +    public SqlBuilder OrderBy
          163  +    {
          164  +      get
          165  +      {
          166  +        if (null == orderBy)
          167  +        {
          168  +          orderBy = new SqlBuilder();
          169  +        }
          170  +        return orderBy;
          171  +      }
          172  +    }
          173  +
          174  +    //indicates whether it is the top most select statement, 
          175  +    // if not Order By should be omitted unless there is a corresponding TOP
          176  +    private bool isTopMost;
          177  +    internal bool IsTopMost
          178  +    {
          179  +      get { return this.isTopMost; }
          180  +      set { this.isTopMost = value; }
          181  +    }
          182  +
          183  +    #region ISqlFragment Members
          184  +
          185  +    /// <summary>
          186  +    /// Write out a SQL select statement as a string.
          187  +    /// We have to
          188  +    /// <list type="number">
          189  +    /// <item>Check whether the aliases extents we use in this statement have
          190  +    /// to be renamed.
          191  +    /// We first create a list of all the aliases used by the outer extents.
          192  +    /// For each of the FromExtents( or AllJoinExtents if it is non-null),
          193  +    /// rename it if it collides with the previous list.
          194  +    /// </item>
          195  +    /// <item>Write each of the clauses (if it exists) as a string</item>
          196  +    /// </list>
          197  +    /// </summary>
          198  +    /// <param name="writer"></param>
          199  +    /// <param name="sqlGenerator"></param>
          200  +    public void WriteSql(SqlWriter writer, SqlGenerator sqlGenerator)
          201  +    {
          202  +      #region Check if FROM aliases need to be renamed
          203  +
          204  +      // Create a list of the aliases used by the outer extents
          205  +      // JoinSymbols have to be treated specially.
          206  +      List<string> outerExtentAliases = null;
          207  +      if ((null != outerExtents) && (0 < outerExtents.Count))
          208  +      {
          209  +        foreach (Symbol outerExtent in outerExtents.Keys)
          210  +        {
          211  +          JoinSymbol joinSymbol = outerExtent as JoinSymbol;
          212  +          if (joinSymbol != null)
          213  +          {
          214  +            foreach (Symbol symbol in joinSymbol.FlattenedExtentList)
          215  +            {
          216  +              if (null == outerExtentAliases) { outerExtentAliases = new List<string>(); }
          217  +              outerExtentAliases.Add(symbol.NewName);
          218  +            }
          219  +          }
          220  +          else
          221  +          {
          222  +            if (null == outerExtentAliases) { outerExtentAliases = new List<string>(); }
          223  +            outerExtentAliases.Add(outerExtent.NewName);
          224  +          }
          225  +        }
          226  +      }
          227  +
          228  +      // An then rename each of the FromExtents we have
          229  +      // If AllJoinExtents is non-null - it has precedence.
          230  +      // The new name is derived from the old name - we append an increasing int.
          231  +      List<Symbol> extentList = this.AllJoinExtents ?? this.fromExtents;
          232  +      if (null != extentList)
          233  +      {
          234  +        foreach (Symbol fromAlias in extentList)
          235  +        {
          236  +          if ((null != outerExtentAliases) && outerExtentAliases.Contains(fromAlias.Name))
          237  +          {
          238  +            int i = sqlGenerator.AllExtentNames[fromAlias.Name];
          239  +            string newName;
          240  +            do
          241  +            {
          242  +              ++i;
          243  +              newName = fromAlias.Name + i.ToString(System.Globalization.CultureInfo.InvariantCulture);
          244  +            }
          245  +            while (sqlGenerator.AllExtentNames.ContainsKey(newName));
          246  +            sqlGenerator.AllExtentNames[fromAlias.Name] = i;
          247  +            fromAlias.NewName = newName;
          248  +
          249  +            // Add extent to list of known names (although i is always incrementing, "prefix11" can
          250  +            // eventually collide with "prefix1" when it is extended)
          251  +            sqlGenerator.AllExtentNames[newName] = 0;
          252  +          }
          253  +
          254  +          // Add the current alias to the list, so that the extents
          255  +          // that follow do not collide with me.
          256  +          if (null == outerExtentAliases) { outerExtentAliases = new List<string>(); }
          257  +          outerExtentAliases.Add(fromAlias.NewName);
          258  +        }
          259  +      }
          260  +      #endregion
          261  +
          262  +      // Increase the indent, so that the Sql statement is nested by one tab.
          263  +      writer.Indent += 1; // ++ can be confusing in this context
          264  +
          265  +      writer.Write("SELECT ");
          266  +      if (IsDistinct)
          267  +      {
          268  +        writer.Write("DISTINCT ");
          269  +      }
          270  +
          271  +      if ((null == this.select) || this.Select.IsEmpty)
          272  +      {
          273  +        Debug.Assert(false);  // we have removed all possibilities of SELECT *.
          274  +        writer.Write("*");
          275  +      }
          276  +      else
          277  +      {
          278  +        this.Select.WriteSql(writer, sqlGenerator);
          279  +      }
          280  +
          281  +      writer.WriteLine();
          282  +      writer.Write("FROM ");
          283  +      this.From.WriteSql(writer, sqlGenerator);
          284  +
          285  +      if ((null != this.where) && !this.Where.IsEmpty)
          286  +      {
          287  +        writer.WriteLine();
          288  +        writer.Write("WHERE ");
          289  +        this.Where.WriteSql(writer, sqlGenerator);
          290  +      }
          291  +
          292  +      if ((null != this.groupBy) && !this.GroupBy.IsEmpty)
          293  +      {
          294  +        writer.WriteLine();
          295  +        writer.Write("GROUP BY ");
          296  +        this.GroupBy.WriteSql(writer, sqlGenerator);
          297  +      }
          298  +
          299  +      if ((null != this.orderBy) && !this.OrderBy.IsEmpty && (this.IsTopMost || this.Top != null))
          300  +      {
          301  +        writer.WriteLine();
          302  +        writer.Write("ORDER BY ");
          303  +        this.OrderBy.WriteSql(writer, sqlGenerator);
          304  +      }
          305  +
          306  +      if (this.Top != null)
          307  +      {
          308  +        this.Top.WriteSql(writer, sqlGenerator);
          309  +      }
          310  +
          311  +
          312  +      --writer.Indent;
          313  +    }
          314  +
          315  +    #endregion
          316  +  }
          317  +}

Added System.Data.SQLite.Linq/SQL Generation/SqlWriter.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="SqlWriter.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Collections.Generic;
           15  +  using System.Diagnostics;
           16  +  using System.IO;
           17  +  using System.Text;
           18  +  using System.Data.Metadata.Edm;
           19  +  using System.Data.Common.CommandTrees;
           20  +
           21  +  /// <summary>
           22  +  /// This extends StringWriter primarily to add the ability to add an indent
           23  +  /// to each line that is written out.
           24  +  /// </summary>
           25  +  class SqlWriter : StringWriter
           26  +  {
           27  +    // We start at -1, since the first select statement will increment it to 0.
           28  +    int indent = -1;
           29  +    /// <summary>
           30  +    /// The number of tabs to be added at the beginning of each new line.
           31  +    /// </summary>
           32  +    internal int Indent
           33  +    {
           34  +      get { return indent; }
           35  +      set { indent = value; }
           36  +    }
           37  +
           38  +    bool atBeginningOfLine = true;
           39  +
           40  +    /// <summary>
           41  +    /// 
           42  +    /// </summary>
           43  +    /// <param name="b"></param>
           44  +    public SqlWriter(StringBuilder b)
           45  +      : base(b, System.Globalization.CultureInfo.InvariantCulture)
           46  +    {
           47  +    }
           48  +
           49  +    /// <summary>
           50  +    /// Reset atBeginningofLine if we detect the newline string.
           51  +    /// <see cref="SqlBuilder.AppendLine"/>
           52  +    /// Add as many tabs as the value of indent if we are at the 
           53  +    /// beginning of a line.
           54  +    /// </summary>
           55  +    /// <param name="value"></param>
           56  +    public override void Write(string value)
           57  +    {
           58  +      if (value == "\r\n")
           59  +      {
           60  +        base.WriteLine();
           61  +        atBeginningOfLine = true;
           62  +      }
           63  +      else
           64  +      {
           65  +        if (atBeginningOfLine)
           66  +        {
           67  +          if (indent > 0)
           68  +          {
           69  +            base.Write(new string('\t', indent));
           70  +          }
           71  +          atBeginningOfLine = false;
           72  +        }
           73  +        base.Write(value);
           74  +      }
           75  +    }
           76  +
           77  +    /// <summary>
           78  +    /// 
           79  +    /// </summary>
           80  +    public override void WriteLine()
           81  +    {
           82  +      base.WriteLine();
           83  +      atBeginningOfLine = true;
           84  +    }
           85  +  }
           86  +}

Added System.Data.SQLite.Linq/SQL Generation/StringUtil.cs.

            1  +/********************************************************
            2  + * ADO.NET 2.0 Data Provider for SQLite Version 3.X
            3  + * Written by Robert Simpson (robert@blackcastlesoft.com)
            4  + * 
            5  + * Released to the public domain, use at your own risk!
            6  + ********************************************************/
            7  +
            8  +using System;
            9  +using System.Collections.Generic;
           10  +using System.Linq;
           11  +using System.Text;
           12  +using System.Globalization;
           13  +using System.Runtime;
           14  +using System.Collections;
           15  +
           16  +namespace System.Data.SQLite
           17  +{
           18  +	internal static class StringUtil
           19  +	{
           20  +		// Fields
           21  +		private const string s_defaultDelimiter = ", ";
           22  +
           23  +		// Methods
           24  +		internal static string BuildDelimitedList<T>(IEnumerable<T> values, ToStringConverter<T> converter, string delimiter)
           25  +		{
           26  +			if (values == null)
           27  +			{
           28  +				return string.Empty;
           29  +			}
           30  +			if (converter == null)
           31  +			{
           32  +				converter = new ToStringConverter<T>(StringUtil.InvariantConvertToString<T>);
           33  +			}
           34  +			if (delimiter == null)
           35  +			{
           36  +				delimiter = ", ";
           37  +			}
           38  +			StringBuilder builder = new StringBuilder();
           39  +			bool flag = true;
           40  +			foreach (T local in values)
           41  +			{
           42  +				if (flag)
           43  +				{
           44  +					flag = false;
           45  +				}
           46  +				else
           47  +				{
           48  +					builder.Append(delimiter);
           49  +				}
           50  +				builder.Append(converter(local));
           51  +			}
           52  +			return builder.ToString();
           53  +		}
           54  +
           55  +		internal static string FormatIndex(string arrayVarName, int index)
           56  +		{
           57  +			StringBuilder builder = new StringBuilder((arrayVarName.Length + 10) + 2);
           58  +			return builder.Append(arrayVarName).Append('[').Append(index).Append(']').ToString();
           59  +		}
           60  +
           61  +		internal static string FormatInvariant(string format, params object[] args)
           62  +		{
           63  +			return string.Format(CultureInfo.InvariantCulture, format, args);
           64  +		}
           65  +
           66  +		internal static StringBuilder FormatStringBuilder(StringBuilder builder, string format, params object[] args)
           67  +		{
           68  +			builder.AppendFormat(CultureInfo.InvariantCulture, format, args);
           69  +			return builder;
           70  +		}
           71  +
           72  +		internal static StringBuilder IndentNewLine(StringBuilder builder, int indent)
           73  +		{
           74  +			builder.AppendLine();
           75  +			for (int i = 0; i < indent; i++)
           76  +			{
           77  +				builder.Append("    ");
           78  +			}
           79  +			return builder;
           80  +		}
           81  +
           82  +		private static string InvariantConvertToString<T>(T value)
           83  +		{
           84  +			return string.Format(CultureInfo.InvariantCulture, "{0}", new object[] { value });
           85  +		}
           86  +
           87  +		[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
           88  +		internal static bool IsNullOrEmptyOrWhiteSpace(string value)
           89  +		{
           90  +			return IsNullOrEmptyOrWhiteSpace(value, 0);
           91  +		}
           92  +
           93  +		internal static bool IsNullOrEmptyOrWhiteSpace(string value, int offset)
           94  +		{
           95  +			if (value != null)
           96  +			{
           97  +				for (int i = offset; i < value.Length; i++)
           98  +				{
           99  +					if (!char.IsWhiteSpace(value[i]))
          100  +					{
          101  +						return false;
          102  +					}
          103  +				}
          104  +			}
          105  +			return true;
          106  +		}
          107  +
          108  +		internal static bool IsNullOrEmptyOrWhiteSpace(string value, int offset, int length)
          109  +		{
          110  +			if (value != null)
          111  +			{
          112  +				length = Math.Min(value.Length, length);
          113  +				for (int i = offset; i < length; i++)
          114  +				{
          115  +					if (!char.IsWhiteSpace(value[i]))
          116  +					{
          117  +						return false;
          118  +					}
          119  +				}
          120  +			}
          121  +			return true;
          122  +		}
          123  +
          124  +		internal static string MembersToCommaSeparatedString(IEnumerable members)
          125  +		{
          126  +			StringBuilder builder = new StringBuilder();
          127  +			builder.Append("{");
          128  +			ToCommaSeparatedString(builder, members);
          129  +			builder.Append("}");
          130  +			return builder.ToString();
          131  +		}
          132  +
          133  +		internal static string ToCommaSeparatedString(IEnumerable list)
          134  +		{
          135  +			return ToSeparatedString(list, ", ", string.Empty);
          136  +		}
          137  +
          138  +		internal static void ToCommaSeparatedString(StringBuilder builder, IEnumerable list)
          139  +		{
          140  +			ToSeparatedStringPrivate(builder, list, ", ", string.Empty, false);
          141  +		}
          142  +
          143  +		internal static string ToCommaSeparatedStringSorted(IEnumerable list)
          144  +		{
          145  +			return ToSeparatedStringSorted(list, ", ", string.Empty);
          146  +		}
          147  +
          148  +		internal static void ToCommaSeparatedStringSorted(StringBuilder builder, IEnumerable list)
          149  +		{
          150  +			ToSeparatedStringPrivate(builder, list, ", ", string.Empty, true);
          151  +		}
          152  +
          153  +		internal static string ToSeparatedString(IEnumerable list, string separator, string nullValue)
          154  +		{
          155  +			StringBuilder stringBuilder = new StringBuilder();
          156  +			ToSeparatedString(stringBuilder, list, separator, nullValue);
          157  +			return stringBuilder.ToString();
          158  +		}
          159  +
          160  +		internal static void ToSeparatedString(StringBuilder builder, IEnumerable list, string separator)
          161  +		{
          162  +			ToSeparatedStringPrivate(builder, list, separator, string.Empty, false);
          163  +		}
          164  +
          165  +		[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
          166  +		internal static void ToSeparatedString(StringBuilder stringBuilder, IEnumerable list, string separator, string nullValue)
          167  +		{
          168  +			ToSeparatedStringPrivate(stringBuilder, list, separator, nullValue, false);
          169  +		}
          170  +
          171  +		private static void ToSeparatedStringPrivate(StringBuilder stringBuilder, IEnumerable list, string separator, string nullValue, bool toSort)
          172  +		{
          173  +			if (list != null)
          174  +			{
          175  +				bool flag = true;
          176  +				List<string> list2 = new List<string>();
          177  +				foreach (object obj2 in list)
          178  +				{
          179  +					string str;
          180  +					if (obj2 == null)
          181  +					{
          182  +						str = nullValue;
          183  +					}
          184  +					else
          185  +					{
          186  +						str = FormatInvariant("{0}", new object[] { obj2 });
          187  +					}
          188  +					list2.Add(str);
          189  +				}
          190  +				if (toSort)
          191  +				{
          192  +					list2.Sort(StringComparer.Ordinal);
          193  +				}
          194  +				foreach (string str2 in list2)
          195  +				{
          196  +					if (!flag)
          197  +					{
          198  +						stringBuilder.Append(separator);
          199  +					}
          200  +					stringBuilder.Append(str2);
          201  +					flag = false;
          202  +				}
          203  +			}
          204  +		}
          205  +
          206  +		internal static string ToSeparatedStringSorted(IEnumerable list, string separator, string nullValue)
          207  +		{
          208  +			StringBuilder stringBuilder = new StringBuilder();
          209  +			ToSeparatedStringPrivate(stringBuilder, list, separator, nullValue, true);
          210  +			return stringBuilder.ToString();
          211  +		}
          212  +
          213  +		internal static void ToSeparatedStringSorted(StringBuilder builder, IEnumerable list, string separator)
          214  +		{
          215  +			ToSeparatedStringPrivate(builder, list, separator, string.Empty, true);
          216  +		}
          217  +
          218  +		// Nested Types
          219  +		internal delegate string ToStringConverter<T>(T value);
          220  +	}
          221  +}

Added System.Data.SQLite.Linq/SQL Generation/Symbol.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="Symbol.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Collections.Generic;
           15  +  using System.Diagnostics;
           16  +  using System.IO;
           17  +  using System.Text;
           18  +  using System.Data.Metadata.Edm;
           19  +  using System.Data.Common.CommandTrees;
           20  +
           21  +  /// <summary>
           22  +  /// <see cref="SymbolTable"/>
           23  +  /// This class represents an extent/nested select statement,
           24  +  /// or a column.
           25  +  ///
           26  +  /// The important fields are Name, Type and NewName.
           27  +  /// NewName starts off the same as Name, and is then modified as necessary.
           28  +  ///
           29  +  ///
           30  +  /// The rest are used by special symbols.
           31  +  /// e.g. NeedsRenaming is used by columns to indicate that a new name must
           32  +  /// be picked for the column in the second phase of translation.
           33  +  ///
           34  +  /// IsUnnest is used by symbols for a collection expression used as a from clause.
           35  +  /// This allows <see cref="SqlGenerator.AddFromSymbol(SqlSelectStatement, string, Symbol, bool)"/> to add the column list
           36  +  /// after the alias.
           37  +  ///
           38  +  /// </summary>
           39  +  class Symbol : ISqlFragment
           40  +  {
           41  +    private Dictionary<string, Symbol> columns = new Dictionary<string, Symbol>(StringComparer.CurrentCultureIgnoreCase);
           42  +    internal Dictionary<string, Symbol> Columns
           43  +    {
           44  +      get { return columns; }
           45  +    }
           46  +
           47  +    private bool needsRenaming = false;
           48  +    internal bool NeedsRenaming
           49  +    {
           50  +      get { return needsRenaming; }
           51  +      set { needsRenaming = value; }
           52  +    }
           53  +
           54  +    bool isUnnest = false;
           55  +    internal bool IsUnnest
           56  +    {
           57  +      get { return isUnnest; }
           58  +      set { isUnnest = value; }
           59  +    }
           60  +
           61  +    string name;
           62  +    public string Name
           63  +    {
           64  +      get { return name; }
           65  +    }
           66  +
           67  +    string newName;
           68  +    public string NewName
           69  +    {
           70  +      get { return newName; }
           71  +      set { newName = value; }
           72  +    }
           73  +
           74  +    private TypeUsage type;
           75  +    internal TypeUsage Type
           76  +    {
           77  +      get { return type; }
           78  +      set { type = value; }
           79  +    }
           80  +
           81  +    public Symbol(string name, TypeUsage type)
           82  +    {
           83  +      this.name = name;
           84  +      this.newName = name;
           85  +      this.Type = type;
           86  +    }
           87  +
           88  +    #region ISqlFragment Members
           89  +
           90  +    /// <summary>
           91  +    /// Write this symbol out as a string for sql.  This is just
           92  +    /// the new name of the symbol (which could be the same as the old name).
           93  +    ///
           94  +    /// We rename columns here if necessary.
           95  +    /// </summary>
           96  +    /// <param name="writer"></param>
           97  +    /// <param name="sqlGenerator"></param>
           98  +    public void WriteSql(SqlWriter writer, SqlGenerator sqlGenerator)
           99  +    {
          100  +      if (this.NeedsRenaming)
          101  +      {
          102  +        string newName;
          103  +        int i = sqlGenerator.AllColumnNames[this.NewName];
          104  +        do
          105  +        {
          106  +          ++i;
          107  +          newName = this.Name + i.ToString(System.Globalization.CultureInfo.InvariantCulture);
          108  +        } while (sqlGenerator.AllColumnNames.ContainsKey(newName));
          109  +        sqlGenerator.AllColumnNames[this.NewName] = i;
          110  +
          111  +        // Prevent it from being renamed repeatedly.
          112  +        this.NeedsRenaming = false;
          113  +        this.NewName = newName;
          114  +
          115  +        // Add this column name to list of known names so that there are no subsequent
          116  +        // collisions
          117  +        sqlGenerator.AllColumnNames[newName] = 0;
          118  +      }
          119  +      writer.Write(SqlGenerator.QuoteIdentifier(this.NewName));
          120  +    }
          121  +
          122  +    #endregion
          123  +  }
          124  +}

Added System.Data.SQLite.Linq/SQL Generation/SymbolPair.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="SymbolPair.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Collections.Generic;
           15  +  using System.Diagnostics;
           16  +  using System.IO;
           17  +  using System.Text;
           18  +  using System.Data.Metadata.Edm;
           19  +  using System.Data.Common.CommandTrees;
           20  +
           21  +  /// <summary>
           22  +  /// The SymbolPair exists to solve the record flattening problem.
           23  +  /// <see cref="SqlGenerator.Visit(DbPropertyExpression)"/>
           24  +  /// Consider a property expression D(v, "j3.j2.j1.a.x")
           25  +  /// where v is a VarRef, j1, j2, j3 are joins, a is an extent and x is a columns.
           26  +  /// This has to be translated eventually into {j'}.{x'}
           27  +  /// 
           28  +  /// The source field represents the outermost SqlStatement representing a join
           29  +  /// expression (say j2) - this is always a Join symbol.
           30  +  /// 
           31  +  /// The column field keeps moving from one join symbol to the next, until it
           32  +  /// stops at a non-join symbol.
           33  +  /// 
           34  +  /// This is returned by <see cref="SqlGenerator.Visit(DbPropertyExpression)"/>,
           35  +  /// but never makes it into a SqlBuilder.
           36  +  /// </summary>
           37  +  class SymbolPair : ISqlFragment
           38  +  {
           39  +    public Symbol Source;
           40  +    public Symbol Column;
           41  +
           42  +    public SymbolPair(Symbol source, Symbol column)
           43  +    {
           44  +      this.Source = source;
           45  +      this.Column = column;
           46  +    }
           47  +
           48  +    #region ISqlFragment Members
           49  +
           50  +    public void WriteSql(SqlWriter writer, SqlGenerator sqlGenerator)
           51  +    {
           52  +      // Symbol pair should never be part of a SqlBuilder.
           53  +      Debug.Assert(false);
           54  +    }
           55  +
           56  +    #endregion
           57  +  }
           58  +}

Added System.Data.SQLite.Linq/SQL Generation/SymbolTable.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="SymbolTable.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Collections.Generic;
           15  +  using System.Diagnostics;
           16  +  using System.IO;
           17  +  using System.Text;
           18  +  using System.Data.Metadata.Edm;
           19  +  using System.Data.Common.CommandTrees;
           20  +
           21  +  /// <summary>
           22  +  /// The symbol table is quite primitive - it is a stack with a new entry for
           23  +  /// each scope.  Lookups search from the top of the stack to the bottom, until
           24  +  /// an entry is found.
           25  +  /// 
           26  +  /// The symbols are of the following kinds
           27  +  /// <list type="bullet">
           28  +  /// <item><see cref="Symbol"/> represents tables (extents/nested selects/unnests)</item>
           29  +  /// <item><see cref="JoinSymbol"/> represents Join nodes</item>
           30  +  /// <item><see cref="Symbol"/> columns.</item>
           31  +  /// </list>
           32  +  /// 
           33  +  /// Symbols represent names <see cref="SqlGenerator.Visit(DbVariableReferenceExpression)"/> to be resolved, 
           34  +  /// or things to be renamed.
           35  +  /// </summary>
           36  +  internal sealed class SymbolTable
           37  +  {
           38  +    private List<Dictionary<string, Symbol>> symbols = new List<Dictionary<string, Symbol>>();
           39  +
           40  +    internal void EnterScope()
           41  +    {
           42  +      symbols.Add(new Dictionary<string, Symbol>(StringComparer.OrdinalIgnoreCase));
           43  +    }
           44  +
           45  +    internal void ExitScope()
           46  +    {
           47  +      symbols.RemoveAt(symbols.Count - 1);
           48  +    }
           49  +
           50  +    internal void Add(string name, Symbol value)
           51  +    {
           52  +      symbols[symbols.Count - 1][name] = value;
           53  +    }
           54  +
           55  +    internal Symbol Lookup(string name)
           56  +    {
           57  +      for (int i = symbols.Count - 1; i >= 0; --i)
           58  +      {
           59  +        if (symbols[i].ContainsKey(name))
           60  +        {
           61  +          return symbols[i][name];
           62  +        }
           63  +      }
           64  +
           65  +      return null;
           66  +    }
           67  +  }
           68  +}

Added System.Data.SQLite.Linq/SQL Generation/TopClause.cs.

            1  +//---------------------------------------------------------------------
            2  +// <copyright file="TopClause.cs" company="Microsoft">
            3  +//      Portions of this file copyright (c) Microsoft Corporation
            4  +//      and are released under the Microsoft Pulic License.  See
            5  +//      http://archive.msdn.microsoft.com/EFSampleProvider/Project/License.aspx
            6  +//      or License.txt for details.
            7  +//      All rights reserved.
            8  +// </copyright>
            9  +//---------------------------------------------------------------------
           10  +
           11  +namespace System.Data.SQLite
           12  +{
           13  +  using System;
           14  +  using System.Collections.Generic;
           15  +  using System.Diagnostics;
           16  +  using System.Globalization;
           17  +  using System.IO;
           18  +  using System.Text;
           19  +  using System.Data.Metadata.Edm;
           20  +  using System.Data.Common.CommandTrees;
           21  +
           22  +  /// <summary>
           23  +  /// TopClause represents the a TOP expression in a SqlSelectStatement. 
           24  +  /// It has a count property, which indicates how many TOP rows should be selected and a 
           25  +  /// boolen WithTies property.
           26  +  /// </summary>
           27  +  class TopClause : ISqlFragment
           28  +  {
           29  +    ISqlFragment topCount;
           30  +    bool withTies;
           31  +
           32  +    /// <summary>
           33  +    /// Do we need to add a WITH_TIES to the top statement
           34  +    /// </summary>
           35  +    internal bool WithTies
           36  +    {
           37  +      get { return withTies; }
           38  +    }
           39  +
           40  +    /// <summary>
           41  +    /// How many top rows should be selected.
           42  +    /// </summary>
           43  +    internal ISqlFragment TopCount
           44  +    {
           45  +      get { return topCount; }
           46  +    }
           47  +
           48  +    /// <summary>
           49  +    /// Creates a TopClause with the given topCount and withTies.
           50  +    /// </summary>
           51  +    /// <param name="topCount"></param>
           52  +    /// <param name="withTies"></param>
           53  +    internal TopClause(ISqlFragment topCount, bool withTies)
           54  +    {
           55  +      this.topCount = topCount;
           56  +      this.withTies = withTies;
           57  +    }
           58  +
           59  +    /// <summary>
           60  +    /// Creates a TopClause with the given topCount and withTies.
           61  +    /// </summary>
           62  +    /// <param name="topCount"></param>
           63  +    /// <param name="withTies"></param>
           64  +    internal TopClause(int topCount, bool withTies)
           65  +    {
           66  +      SqlBuilder sqlBuilder = new SqlBuilder();
           67  +      sqlBuilder.Append(topCount.ToString(CultureInfo.InvariantCulture));
           68  +      this.topCount = sqlBuilder;
           69  +      this.withTies = withTies;
           70  +    }
           71  +
           72  +    #region ISqlFragment Members
           73  +
           74  +    /// <summary>
           75  +    /// Write out the TOP part of sql select statement 
           76  +    /// It basically writes TOP (X) [WITH TIES].
           77  +    /// </summary>
           78  +    /// <param name="writer"></param>
           79  +    /// <param name="sqlGenerator"></param>
           80  +    public void WriteSql(SqlWriter writer, SqlGenerator sqlGenerator)
           81  +    {
           82  +      writer.Write(" LIMIT ");
           83  +      this.TopCount.WriteSql(writer, sqlGenerator);
           84  +
           85  +      if (this.WithTies)
           86  +        throw new NotSupportedException("WITH TIES");
           87  +
           88  +      //writer.Write(" ");
           89  +
           90  +      //if (this.WithTies)
           91  +      //{
           92  +      //    writer.Write("WITH TIES ");
           93  +      //}
           94  +    }
           95  +
           96  +    #endregion
           97  +  }
           98  +}