Exemple #1
0
        /// <summary>
        /// Add a Select clause to a query; may need to create a new subquery.
        /// </summary>
        /// <param name="select">Select clause to add.</param>
        /// <param name="inScope">Set of parameter names in scope.</param>
        /// <param name="currentCollection">Current input collection.</param>
        /// <param name="subqueryBinding">The subquery binding information.</param>
        /// <returns>A new query containing a select clause.</returns>
        public QueryUnderConstruction AddSelectClause(SqlSelectClause select, HashSet <ParameterExpression> inScope, Collection currentCollection, TranslationContext.SubqueryBinding subqueryBinding)
        {
            QueryUnderConstruction result = this;

            if (subqueryBinding.ShouldBeOnNewQuery)
            {
                result = this.PackageQuery(inScope, currentCollection);
                subqueryBinding.ShouldBeOnNewQuery = false;
            }

            // If result SelectClause is not null, or both result selectClause and select has Distinct
            // then it is unexpected since the SelectClause will be overwritten.
            if (!((result.selectClause != null && result.selectClause.HasDistinct && selectClause.HasDistinct) ||
                  result.selectClause == null))
            {
                throw new DocumentQueryException("Internal error: attempting to overwrite SELECT clause");
            }

            result.selectClause = select;
            foreach (Binding binding in subqueryBinding.TakeBindings())
            {
                result.AddBinding(binding);
            }

            return(result);
        }
Exemple #2
0
 public QueryUnderConstruction(Func <string, ParameterExpression> aliasCreatorFunc, QueryUnderConstruction inputQuery)
 {
     this.fromParameters   = new FromParameterBindings();
     this.aliasCreatorFunc = aliasCreatorFunc;
     this.inputQuery       = inputQuery;
     this.alias            = new Lazy <ParameterExpression>(() => aliasCreatorFunc(QueryUnderConstruction.DefaultSubqueryRoot));
 }
Exemple #3
0
        /// <summary>
        /// Create a new QueryUnderConstruction node that take the current query as its input
        /// </summary>
        /// <param name="inScope">The current context's parameters scope</param>
        /// <returns>The new query node</returns>
        public QueryUnderConstruction PackageQuery(HashSet <ParameterExpression> inScope)
        {
            QueryUnderConstruction result = new QueryUnderConstruction(this.aliasCreatorFunc);

            result.fromParameters.SetInputParameter(typeof(object), this.Alias.Name, inScope);
            result.inputQuery = this;
            return(result);
        }
 public TranslationContext()
 {
     this.InScope               = new HashSet <ParameterExpression>();
     this.substitutions         = new ParameterSubstitution();
     this.methodStack           = new List <MethodCallExpression>();
     this.lambdaParametersStack = new List <ParameterExpression>();
     this.collectionStack       = new List <Collection>();
     this.currentQuery          = new QueryUnderConstruction();
 }
Exemple #5
0
        /// <summary>
        /// Create a new QueryUnderConstruction node if indicated as neccesary by the subquery binding
        /// </summary>
        /// <returns>The current QueryUnderConstruction after the package query call if necessary</returns>
        public QueryUnderConstruction PackageCurrentQueryIfNeccessary()
        {
            if (this.CurrentSubqueryBinding.ShouldBeOnNewQuery)
            {
                this.currentQuery = this.currentQuery.PackageQuery(this.InScope);
                this.CurrentSubqueryBinding.ShouldBeOnNewQuery = false;
            }

            return(this.currentQuery);
        }
Exemple #6
0
 /// <summary>
 /// Verify that the current query is supported with non-subquery.
 /// As soon as the query has a TopSpec then after that, it cannot have a Distinct, OrderBy, or Where clause.
 /// That is because in those cases, the semantics of LINQ is Take() should be done first, whereas, due to the
 /// nature of SQL language, there is no equivalent in SQL as TOP clause in SQL is executed last.
 /// This limit will be lifted when we have the support sub query in LINQ translation.
 /// </summary>
 /// <param name="query"></param>
 private static void ValidateNonSubquerySupport(QueryUnderConstruction query)
 {
     while (query != null)
     {
         if (query.topSpec != null)
         {
             throw new DocumentQueryException("LINQ operations after a Take() is not supported yet.");
         }
         query = query.inputQuery;
     }
 }
Exemple #7
0
        public QueryUnderConstruction AddOrderByClause(SqlOrderbyClause orderBy, TranslationContext context)
        {
            QueryUnderConstruction result = context.PackageCurrentQueryIfNeccessary();

            result.orderByClause = orderBy;
            foreach (Binding binding in context.CurrentSubqueryBinding.TakeBindings())
            {
                result.AddBinding(binding);
            }

            return(result);
        }
Exemple #8
0
        /// <summary>
        /// Add a Where clause to a query; may need to create a new query.
        /// </summary>
        /// <param name="whereClause">Clause to add.</param>
        /// <param name="context">The translation context.</param>
        /// <returns>A new query containing the specified Where clause.</returns>
        public QueryUnderConstruction AddWhereClause(SqlWhereClause whereClause, TranslationContext context)
        {
            QueryUnderConstruction result = context.PackageCurrentQueryIfNeccessary();

            whereClause        = QueryUnderConstruction.CombineWithConjunction(result.whereClause, whereClause);
            result.whereClause = whereClause;
            foreach (Binding binding in context.CurrentSubqueryBinding.TakeBindings())
            {
                result.AddBinding(binding);
            }

            return(result);
        }
 public TranslationContext(CosmosLinqSerializerOptions linqSerializerOptions, IDictionary <object, string> parameters = null)
 {
     this.InScope               = new HashSet <ParameterExpression>();
     this.substitutions         = new ParameterSubstitution();
     this.methodStack           = new List <MethodCallExpression>();
     this.lambdaParametersStack = new List <ParameterExpression>();
     this.collectionStack       = new List <Collection>();
     this.currentQuery          = new QueryUnderConstruction(this.GetGenFreshParameterFunc());
     this.subqueryBindingStack  = new Stack <SubqueryBinding>();
     this.linqSerializerOptions = linqSerializerOptions;
     this.parameters            = parameters;
     this.memberNames           = new MemberNames(linqSerializerOptions);
 }
Exemple #10
0
        /// <summary>
        /// Separate out the query branch, which makes up a subquery and is built on top of the parent query chain.
        /// E.g. Let the query chain at some point in time be q0 - q1 - q2. When a subquery is recognized, its expression is visited.
        /// Assume that adds 2 queries to the chain to q0 - q1 - q2 - q3 - q4. Invoking q4.GetSubquery(q2) would return q3 - q4
        /// after it's isolated from the rest of the chain.
        /// </summary>
        /// <param name="queryBeforeVisit">The last query in the chain before the collection expression is visited</param>
        /// <returns>The subquery that has been decoupled from the parent query chain</returns>
        public QueryUnderConstruction GetSubquery(QueryUnderConstruction queryBeforeVisit)
        {
            QueryUnderConstruction parentQuery = null;

            for (QueryUnderConstruction query = this;
                 query != queryBeforeVisit;
                 query = query.inputQuery)
            {
                parentQuery = query;
            }

            parentQuery.inputQuery = null;
            return(this);
        }
Exemple #11
0
        /// <summary>
        /// Add a Where clause to a query; may need to create a new query.
        /// </summary>
        /// <param name="whereClause">Clause to add.</param>
        /// <param name="elementType">Type of element in input collection.</param>
        /// <param name="inScope">Set of parameter names in scope.</param>
        /// <returns>A new query containing the specified Where clause.</returns>
        public QueryUnderConstruction AddWhereClause(SqlWhereClause whereClause, Type elementType, HashSet <ParameterExpression> inScope)
        {
            QueryUnderConstruction.ValidateNonSubquerySupport(this);

            QueryUnderConstruction result = this;

            if (this.selectClause != null)
            {
                result = this.PackageQuery(inScope);
            }

            whereClause        = QueryUnderConstruction.CombineWithConjunction(result.whereClause, whereClause);
            result.whereClause = whereClause;
            return(result);
        }
Exemple #12
0
        public QueryUnderConstruction AddLimitSpec(SqlLimitSpec limitSpec, TranslationContext context)
        {
            QueryUnderConstruction result = this;

            if (result.limitSpec != null)
            {
                result.limitSpec = (result.limitSpec.Limit < limitSpec.Limit) ? result.limitSpec : limitSpec;
            }
            else
            {
                result.limitSpec = limitSpec;
            }

            return(result);
        }
Exemple #13
0
        /// <summary>
        /// Find and flatten the prefix set of queries into a single query by substituting their expressions.
        /// </summary>
        /// <returns>The query that has been flatten</returns>
        public QueryUnderConstruction FlattenAsPossible()
        {
            // Flatten should be done when the current query can be translated without the need of using sub query
            // The cases that need to use sub query are:
            //     1. Select clause appears after Distinct
            //     2. There are any operations after Take
            //     3. There are nested Select, Where or OrderBy
            QueryUnderConstruction parentQuery  = null;
            QueryUnderConstruction flattenQuery = null;
            bool seenSelect = false;
            bool seenAnyOp  = false;

            for (QueryUnderConstruction query = this; query != null; query = query.inputQuery)
            {
                foreach (Binding binding in query.fromParameters.GetBindings())
                {
                    if ((binding.ParameterDefinition != null) && (binding.ParameterDefinition is SqlSubqueryCollection))
                    {
                        flattenQuery = this;
                        break;
                    }
                }

                if (flattenQuery != null)
                {
                    break;
                }

                if ((query.topSpec != null && seenAnyOp) ||
                    (query.selectClause != null && query.selectClause.HasDistinct && seenSelect))
                {
                    parentQuery.inputQuery = query.FlattenAsPossible();
                    flattenQuery           = this;
                    break;
                }

                seenSelect  = seenSelect || ((query.selectClause != null) && !(query.selectClause.HasDistinct));
                seenAnyOp   = true;
                parentQuery = query;
            }

            if (flattenQuery == null)
            {
                flattenQuery = this.Flatten();
            }

            return(flattenQuery);
        }
Exemple #14
0
        public QueryUnderConstruction AddOffsetSpec(SqlOffsetSpec offsetSpec, TranslationContext context)
        {
            QueryUnderConstruction result = context.PackageCurrentQueryIfNeccessary();

            if (result.offsetSpec != null)
            {
                // Skip(A).Skip(B) => Skip(A + B)
                result.offsetSpec = SqlOffsetSpec.Create(result.offsetSpec.Offset + offsetSpec.Offset);
            }
            else
            {
                result.offsetSpec = offsetSpec;
            }

            return(result);
        }
Exemple #15
0
        private QueryUnderConstruction PackageQuery(HashSet <ParameterExpression> inScope)
        {
            QueryUnderConstruction result = new QueryUnderConstruction();
            var inputParam = result.fromParameters.SetInputParameter(typeof(object), ParameterSubstitution.InputParameterName, inScope);

            inScope.Add(inputParam);

            result.inputQuery = this;
            if (this.selectClause == null)
            {
                var star = new SqlSelectStarSpec();
                this.selectClause = new SqlSelectClause(star, null);
            }

            return(result);
        }
Exemple #16
0
        public QueryUnderConstruction AddTopSpec(SqlTopSpec topSpec)
        {
            QueryUnderConstruction result = this;

            if (result.topSpec != null)
            {
                // Set the topSpec to the one with minimum Count value
                result.topSpec = (result.topSpec.Count < topSpec.Count) ? result.topSpec : topSpec;
            }
            else
            {
                result.topSpec = topSpec;
            }

            return(result);
        }
Exemple #17
0
        /// <summary>
        /// Flatten subqueries into a single query by substituting their expressions in the current query.
        /// </summary>
        /// <returns>A flattened query.</returns>
        public QueryUnderConstruction Flatten()
        {
            // SELECT fo(y) FROM y IN (SELECT fi(x) FROM x WHERE gi(x)) WHERE go(y)
            // is translated by substituting fi(x) for y in the outer query
            // producing
            // SELECT fo(fi(x)) FROM x WHERE gi(x) AND (go(fi(x))
            if (this.inputQuery == null)
            {
                // we are flat already
                if (this.selectClause == null)
                {
                    this.selectClause = new SqlSelectClause(new SqlSelectStarSpec(), this.topSpec);
                }
                else
                {
                    this.selectClause = new SqlSelectClause(this.selectClause.SelectSpec, this.topSpec, this.selectClause.HasDistinct);
                }

                return(this);
            }

            if (this.inputQuery.orderByClause != null && this.orderByClause != null)
            {
                throw new DocumentQueryException("Multiple OrderBy is not supported.");
            }

            var flatInput   = this.inputQuery.Flatten();
            var inputSelect = flatInput.selectClause;
            var inputwhere  = flatInput.whereClause;

            SqlIdentifier          replacement     = new SqlIdentifier(this.InputParameter().Name);
            var                    composedSelect  = Substitute(inputSelect, inputSelect.TopSpec ?? this.topSpec, replacement, this.selectClause);
            var                    composedWhere   = Substitute(inputSelect.SelectSpec, replacement, this.whereClause);
            var                    composedOrderBy = Substitute(inputSelect.SelectSpec, replacement, this.orderByClause);
            var                    and             = QueryUnderConstruction.CombineWithConjunction(inputwhere, composedWhere);
            QueryUnderConstruction result          = new QueryUnderConstruction
            {
                selectClause   = composedSelect,
                whereClause    = and,
                inputQuery     = null,
                fromParameters = flatInput.fromParameters,
                orderByClause  = composedOrderBy ?? this.inputQuery.orderByClause,
            };

            return(result);
        }
Exemple #18
0
        public QueryUnderConstruction AddOrderByClause(SqlOrderbyClause orderBy, TranslationContext context)
        {
            QueryUnderConstruction result = this;

            if (context.CurrentSubqueryBinding.ShouldBeOnNewQuery)
            {
                result = this.PackageQuery(context.InScope, context.PeekCollection());
                context.CurrentSubqueryBinding.ShouldBeOnNewQuery = false;
            }

            result.orderByClause = orderBy;
            foreach (Binding binding in context.CurrentSubqueryBinding.TakeBindings())
            {
                result.AddBinding(binding);
            }

            return(result);
        }
Exemple #19
0
        public QueryUnderConstruction AddOffsetSpec(SqlOffsetSpec offsetSpec, TranslationContext context)
        {
            QueryUnderConstruction result = context.PackageCurrentQueryIfNeccessary();

            if (result.offsetSpec != null)
            {
                // Skip(A).Skip(B) => Skip(A + B)
                long offsetA = QueryUnderConstruction.GetOffsetCount(result.offsetSpec);
                long offsetB = QueryUnderConstruction.GetOffsetCount(offsetSpec);
                result.offsetSpec = SqlOffsetSpec.Create(SqlNumberLiteral.Create(offsetA + offsetB));
            }
            else
            {
                result.offsetSpec = offsetSpec;
            }

            return(result);
        }
Exemple #20
0
        /// <summary>
        /// Add a Where clause to a query; may need to create a new query.
        /// </summary>
        /// <param name="whereClause">Clause to add.</param>
        /// <param name="context">The translation context.</param>
        /// <returns>A new query containing the specified Where clause.</returns>
        public QueryUnderConstruction AddWhereClause(SqlWhereClause whereClause, TranslationContext context)
        {
            QueryUnderConstruction result = this;

            if (this.ShouldBeOnNewQuery(LinqMethods.Where, 2))
            {
                result = this.PackageQuery(context.InScope, context.PeekCollection());
                context.CurrentSubqueryBinding.ShouldBeOnNewQuery = false;
            }

            whereClause        = QueryUnderConstruction.CombineWithConjunction(result.whereClause, whereClause);
            result.whereClause = whereClause;
            foreach (Binding binding in context.CurrentSubqueryBinding.TakeBindings())
            {
                result.AddBinding(binding);
            }

            return(result);
        }
Exemple #21
0
        public QueryUnderConstruction AddOrderByClause(SqlOrderbyClause orderBy, HashSet <ParameterExpression> inScope)
        {
            QueryUnderConstruction.ValidateNonSubquerySupport(this);

            QueryUnderConstruction result = this;

            if (this.selectClause != null)
            {
                result = this.PackageQuery(inScope);
            }

            if (result.orderByClause != null)
            {
                throw new DocumentQueryException("Multiple OrderBy is not supported.");
            }

            result.orderByClause = orderBy;
            return(result);
        }
Exemple #22
0
        public QueryUnderConstruction AddTopSpec(SqlTopSpec topSpec)
        {
            QueryUnderConstruction result = this;

            if (result.topSpec != null)
            {
                long accumulatedTopCount = QueryUnderConstruction.GetTopCount(result.topSpec);
                long currentTopCount     = QueryUnderConstruction.GetTopCount(topSpec);
                if (currentTopCount < accumulatedTopCount)
                {
                    result.topSpec = topSpec;
                }
            }
            else
            {
                result.topSpec = topSpec;
            }

            return(result);
        }
Exemple #23
0
        public QueryUnderConstruction AddTopSpec(SqlTopSpec topSpec, HashSet <ParameterExpression> inScope, Collection currentCollection)
        {
            QueryUnderConstruction result = this;

            if (result.topSpec != null)
            {
                // Set the topSpec to the one with minimum Count value
                result.topSpec = (this.topSpec.Count < topSpec.Count) ? this.topSpec : topSpec;
            }
            else
            {
                result.topSpec = topSpec;
            }
            if (result.topSpec.Count < 0)
            {
                result.topSpec = SqlTopSpec.Create(0);
            }

            return(result);
        }
Exemple #24
0
        public QueryUnderConstruction AddLimitSpec(SqlLimitSpec limitSpec, TranslationContext context)
        {
            QueryUnderConstruction result = this;

            if (result.limitSpec != null)
            {
                long accumulatedLimitCount = QueryUnderConstruction.GetLimitCount(result.limitSpec);
                long currentLimitCount     = QueryUnderConstruction.GetLimitCount(limitSpec);
                if (currentLimitCount < accumulatedLimitCount)
                {
                    result.limitSpec = limitSpec;
                }
            }
            else
            {
                result.limitSpec = limitSpec;
            }

            return(result);
        }
Exemple #25
0
        /// <summary>
        /// Add a Select clause to a query; may need to create a new subquery.
        /// </summary>
        /// <param name="select">Select clause to add.</param>
        /// <param name="context">The translation context.</param>
        /// <returns>A new query containing a select clause.</returns>
        public QueryUnderConstruction AddSelectClause(SqlSelectClause select, TranslationContext context)
        {
            QueryUnderConstruction result = context.PackageCurrentQueryIfNeccessary();

            // If result SelectClause is not null, or both result selectClause and select has Distinct
            // then it is unexpected since the SelectClause will be overwritten.
            if (!((result.selectClause != null && result.selectClause.HasDistinct && selectClause.HasDistinct) ||
                  result.selectClause == null))
            {
                throw new DocumentQueryException("Internal error: attempting to overwrite SELECT clause");
            }

            result.selectClause = select;
            foreach (Binding binding in context.CurrentSubqueryBinding.TakeBindings())
            {
                result.AddBinding(binding);
            }

            return(result);
        }
Exemple #26
0
        /// <summary>
        /// Add a Select clause to a query; may need to create a new subquery.
        /// </summary>
        /// <param name="select">Select clause to add.</param>
        /// <param name="inputElementType">Type of element in the input collection.</param>
        /// <param name="outputElementType">Type of element in output collection.</param>
        /// <param name="inScope">Set of parameter names in scope.</param>
        /// <returns>A new query containing a select clause.</returns>
        public QueryUnderConstruction AddSelectClause(SqlSelectClause select, Type inputElementType, Type outputElementType, HashSet <ParameterExpression> inScope)
        {
            if (select.HasDistinct)
            {
                QueryUnderConstruction.ValidateNonSubquerySupport(this);
            }

            QueryUnderConstruction result = this;

            if (this.selectClause != null)
            {
                result = this.PackageQuery(inScope);
            }

            if (result.selectClause != null)
            {
                throw new DocumentQueryException("Internal error: attempting to overwrite SELECT clause");
            }

            result.selectClause = select;
            return(result);
        }
Exemple #27
0
        /// <summary>
        /// Find and flatten the prefix set of queries into a single query by substituting their expressions.
        /// </summary>
        /// <returns>The query that has been flatten</returns>
        public QueryUnderConstruction FlattenAsPossible()
        {
            // Flatten should be done when the current query can be translated without the need of using sub query
            // The cases that need to use sub query are:
            //     1. Select clause appears after Distinct
            //     2. There are any operations after Take that is not a pure Select.
            //     3. There are nested Select, Where or OrderBy
            QueryUnderConstruction parentQuery  = null;
            QueryUnderConstruction flattenQuery = null;
            bool seenSelect         = false;
            bool seenAnyNonSelectOp = false;

            for (QueryUnderConstruction query = this; query != null; query = query.inputQuery)
            {
                foreach (Binding binding in query.fromParameters.GetBindings())
                {
                    if ((binding.ParameterDefinition != null) && (binding.ParameterDefinition is SqlSubqueryCollection))
                    {
                        flattenQuery = this;
                        break;
                    }
                }

                // In Select -> SelectMany cases, fromParameter substitution is not yet supported .
                // Therefore these are un-flattenable.
                if (query.inputQuery != null &&
                    (query.fromParameters.GetBindings().First().Parameter.Name == query.inputQuery.Alias.Name) &&
                    query.fromParameters.GetBindings().Any(b => b.ParameterDefinition != null))
                {
                    flattenQuery = this;
                    break;
                }

                if (flattenQuery != null)
                {
                    break;
                }

                if (((query.topSpec != null || query.offsetSpec != null || query.limitSpec != null) && seenAnyNonSelectOp) ||
                    (query.selectClause != null && query.selectClause.HasDistinct && seenSelect))
                {
                    parentQuery.inputQuery = query.FlattenAsPossible();
                    flattenQuery           = this;
                    break;
                }

                seenSelect          = seenSelect || ((query.selectClause != null) && !(query.selectClause.HasDistinct));
                seenAnyNonSelectOp |=
                    (query.whereClause != null) ||
                    (query.orderByClause != null) ||
                    (query.topSpec != null) ||
                    (query.offsetSpec != null) ||
                    (query.fromParameters.GetBindings().Any(b => b.ParameterDefinition != null)) ||
                    ((query.selectClause != null) && ((query.selectClause.HasDistinct) || (this.HasSelectAggregate())));
                parentQuery = query;
            }

            if (flattenQuery == null)
            {
                flattenQuery = this.Flatten();
            }

            return(flattenQuery);
        }
Exemple #28
0
        /// <summary>
        /// Flatten subqueries into a single query by substituting their expressions in the current query.
        /// </summary>
        /// <returns>A flattened query.</returns>
        private QueryUnderConstruction Flatten()
        {
            // SELECT fo(y) FROM y IN (SELECT fi(x) FROM x WHERE gi(x)) WHERE go(y)
            // is translated by substituting fi(x) for y in the outer query
            // producing
            // SELECT fo(fi(x)) FROM x WHERE gi(x) AND (go(fi(x))
            if (this.inputQuery == null)
            {
                // we are flat already
                if (this.selectClause == null)
                {
                    // If selectClause doesn't exists, use SELECT v0 where v0 is the input parameter, instead of SELECT *.
                    string parameterName = this.fromParameters.GetInputParameter().Name;
                    SqlScalarExpression parameterExpression = SqlPropertyRefScalarExpression.Create(null, SqlIdentifier.Create(parameterName));
                    this.selectClause = SqlSelectClause.Create(SqlSelectValueSpec.Create(parameterExpression));
                }
                else
                {
                    this.selectClause = SqlSelectClause.Create(this.selectClause.SelectSpec, this.topSpec, this.selectClause.HasDistinct);
                }

                return(this);
            }

            QueryUnderConstruction flatInput   = this.inputQuery.Flatten();
            SqlSelectClause        inputSelect = flatInput.selectClause;
            SqlWhereClause         inputwhere  = flatInput.whereClause;

            // Determine the paramName to be replaced in the current query
            // It should be the top input parameter name which is not binded in this collection.
            // That is because if it has been binded before, it has global scope and should not be replaced.
            string           paramName        = null;
            HashSet <string> inputQueryParams = new HashSet <string>();

            foreach (Binding binding in this.inputQuery.fromParameters.GetBindings())
            {
                inputQueryParams.Add(binding.Parameter.Name);
            }

            foreach (Binding binding in this.fromParameters.GetBindings())
            {
                if (binding.ParameterDefinition == null || inputQueryParams.Contains(binding.Parameter.Name))
                {
                    paramName = binding.Parameter.Name;
                }
            }

            SqlIdentifier         replacement     = SqlIdentifier.Create(paramName);
            SqlSelectClause       composedSelect  = Substitute(inputSelect, inputSelect.TopSpec ?? this.topSpec, replacement, this.selectClause);
            SqlWhereClause        composedWhere   = Substitute(inputSelect.SelectSpec, replacement, this.whereClause);
            SqlOrderbyClause      composedOrderBy = Substitute(inputSelect.SelectSpec, replacement, this.orderByClause);
            SqlWhereClause        and             = QueryUnderConstruction.CombineWithConjunction(inputwhere, composedWhere);
            FromParameterBindings fromParams      = QueryUnderConstruction.CombineInputParameters(flatInput.fromParameters, this.fromParameters);
            SqlOffsetSpec         offsetSpec;
            SqlLimitSpec          limitSpec;

            if (flatInput.offsetSpec != null)
            {
                offsetSpec = flatInput.offsetSpec;
                limitSpec  = flatInput.limitSpec;
            }
            else
            {
                offsetSpec = this.offsetSpec;
                limitSpec  = this.limitSpec;
            }
            QueryUnderConstruction result = new QueryUnderConstruction(this.aliasCreatorFunc)
            {
                selectClause   = composedSelect,
                whereClause    = and,
                inputQuery     = null,
                fromParameters = flatInput.fromParameters,
                orderByClause  = composedOrderBy ?? this.inputQuery.orderByClause,
                offsetSpec     = offsetSpec,
                limitSpec      = limitSpec,
                alias          = new Lazy <ParameterExpression>(() => this.Alias)
            };

            return(result);
        }