예제 #1
0
        public void Count_StringViewIsValid()
        {
            Assert.Equal("COUNT(pe.Name) AS TestAlias", SqlField <Person> .Count(p => p.Name, "TestAlias").ToString());
            var alias = new SqlAlias <Passport>("t");

            Assert.Equal("COUNT(t.Number) AS Passp", SqlField <Passport> .Count(alias, p => p.Number, "Passp").ToString());
        }
            private SqlJoin GetLeftOuterWithUnreferencedSingletonOnLeft(SqlSource source)
            {
                SqlAlias alias = source as SqlAlias;

                if (alias != null)
                {
                    SqlSelect select = alias.Node as SqlSelect;
                    if (select != null &&
                        select.Where == null &&
                        select.Top == null &&
                        select.GroupBy.Count == 0 &&
                        select.OrderBy.Count == 0)
                    {
                        return(this.GetLeftOuterWithUnreferencedSingletonOnLeft(select.From));
                    }
                }
                SqlJoin join = source as SqlJoin;

                if (join == null || join.JoinType != SqlJoinType.LeftOuter)
                {
                    return(null);
                }
                if (!this.IsSingletonSelect(join.Left))
                {
                    return(null);
                }
                HashSet <SqlAlias> p = SqlGatherProducedAliases.Gather(join.Left);
                HashSet <SqlAlias> c = SqlGatherConsumedAliases.Gather(join.Right);

                if (p.Overlaps(c))
                {
                    return(null);
                }
                return(join);
            }
예제 #3
0
        public void From_StringViewIsValid()
        {
            Assert.Equal("pe.Name AS TestAlias", SqlField <Person> .From(p => p.Name, "TestAlias").ToString());
            var alias = new SqlAlias <Passport>("t");

            Assert.Equal("t.Number AS Passp", SqlField <Passport> .From(alias, p => p.Number, "Passp").ToString());
        }
            internal SqlAlias VisitAliasConsumed(SqlAlias a)
            {
                if (a == null)
                {
                    return(a);
                }

                bool match = false;

                foreach (SqlAlias alias in aliases)
                {
                    if (alias == a)
                    {
                        match = true;
                        break;
                    }
                }

                if (match)
                {
                    this.referencesAnyMatchingAliases = true;
                }

                return(a);
            }
예제 #5
0
 internal override SqlAlias VisitAlias(SqlAlias sqlAlias) {
     SqlAlias save = this.alias;
     this.alias = sqlAlias;
     sqlAlias.Node = this.Visit(sqlAlias.Node);
     this.alias = save;
     return sqlAlias;
 }
예제 #6
0
 internal override SqlAlias VisitAlias(SqlAlias a) {
     SqlAlias n = new SqlAlias(a.Node);
     this.nodeMap[a] = n;
     n.Node = this.Visit(a.Node);
     n.Name = a.Name;
     return n;
 }
        internal override SqlExpression VisitMultiset(SqlSubSelect sms)
        {
            // allow one big-join per query?
            if ((this.options & SqlMultiplexerOptionType.EnableBigJoin) != 0 &&
                !this.hasBigJoin && this.canJoin && this.isTopLevel && this.outerSelect != null &&
                !MultisetChecker.HasMultiset(sms.Select.Selection) &&
                BigJoinChecker.CanBigJoin(sms.Select))
            {
                sms.Select = this.VisitSelect(sms.Select);

                SqlAlias alias = new SqlAlias(sms.Select);
                SqlJoin  join  = new SqlJoin(SqlJoinType.OuterApply, this.outerSelect.From, alias, null, sms.SourceExpression);
                this.outerSelect.From         = @join;
                this.outerSelect.OrderingType = SqlOrderingType.Always;

                // make joined expression
                SqlExpression expr = (SqlExpression)SqlDuplicator.Copy(sms.Select.Selection);

                // make count expression
                SqlSelect copySelect  = (SqlSelect)SqlDuplicator.Copy(sms.Select);
                SqlAlias  copyAlias   = new SqlAlias(copySelect);
                SqlSelect countSelect = new SqlSelect(sql.Unary(SqlNodeType.Count, null, sms.SourceExpression), copyAlias, sms.SourceExpression);
                countSelect.OrderingType = SqlOrderingType.Never;
                SqlExpression count = sql.SubSelect(SqlNodeType.ScalarSubSelect, countSelect);

                // make joined collection
                SqlJoinedCollection jc = new SqlJoinedCollection(sms.ClrType, sms.SqlType, expr, count, sms.SourceExpression);
                this.hasBigJoin = true;
                return(jc);
            }
            return(QueryExtractor.Extract(sms, this.parentParameters));
        }
예제 #8
0
            internal override SqlExpression VisitMultiset(SqlSubSelect sms) {
                // allow one big-join per query?
                if ((this.options & Options.EnableBigJoin) != 0 &&
                    !this.hasBigJoin && this.canJoin && this.isTopLevel && this.outerSelect != null
                    && !MultisetChecker.HasMultiset(sms.Select.Selection) 
                    && BigJoinChecker.CanBigJoin(sms.Select)) {

                    sms.Select = this.VisitSelect(sms.Select);

                    SqlAlias alias = new SqlAlias(sms.Select);
                    SqlJoin join = new SqlJoin(SqlJoinType.OuterApply, this.outerSelect.From, alias, null, sms.SourceExpression);
                    this.outerSelect.From = join;
                    this.outerSelect.OrderingType = SqlOrderingType.Always;

                    // make joined expression
                    SqlExpression expr = (SqlExpression)SqlDuplicator.Copy(sms.Select.Selection);

                    // make count expression
                    SqlSelect copySelect = (SqlSelect)SqlDuplicator.Copy(sms.Select);
                    SqlAlias copyAlias = new SqlAlias(copySelect);
                    SqlSelect countSelect = new SqlSelect(sql.Unary(SqlNodeType.Count, null, sms.SourceExpression), copyAlias, sms.SourceExpression);
                    countSelect.OrderingType = SqlOrderingType.Never;
                    SqlExpression count = sql.SubSelect(SqlNodeType.ScalarSubSelect, countSelect);

                    // make joined collection
                    SqlJoinedCollection jc = new SqlJoinedCollection(sms.ClrType, sms.SqlType, expr, count, sms.SourceExpression);
                    this.hasBigJoin = true;
                    return jc;
                }
                else {
                    return QueryExtractor.Extract(sms, this.parentParameters);
                }
            }
예제 #9
0
            protected override SqlExpression VisitAlias(SqlAlias alias)
            {
                bool isSelect = (alias.Expression is SqlSelect);

                int    depth     = _depth;
                string name      = String.Empty;
                string aliasName = null;

                SqlField field = (alias.Expression as SqlField);

                if (field != null)
                {
                    name = field.Name;
                }

                SqlTable table = (alias.Expression as SqlTable);

                if (table != null)
                {
                    name = table.Name;
                }

                if (alias.Name == null)
                {
                    if (!_nameMap.TryGetValue(alias, out aliasName))
                    {
                        aliasName       = "A" + _nameMap.Count;
                        _nameMap[alias] = aliasName;
                    }
                }
                else
                {
                    aliasName = alias.Name;
                }

                if (isSelect)
                {
                    _depth++;
                    _builder.Append("(");
                    this.NewLine();
                }

                Visit(alias.Expression);

                if (isSelect)
                {
                    this.NewLine();
                    _builder.Append(")");

                    _depth = depth;
                }
                if ((!_suppressedAliases.Contains(alias) && aliasName != null) && name != aliasName)
                {
                    _builder.Append(" AS ");
                    WriteName(aliasName);
                }

                return(alias);
            }
예제 #10
0
        protected override SqlSelect GenerateSkipTake(SqlSelect sequence, SqlExpression skipExp, SqlExpression takeExp)
        {
            //return base.GenerateSkipTake(sequence, skipExp, takeExp);
            SqlSelect node   = LockSelect(sequence);
            var       value2 = skipExp as SqlValue;

            if ((skipExp == null) || ((value2 != null) && (((int)value2.Value) <= 0)))
            {
                skipExp = sql.ValueFromObject(0, dominatingExpression);
            }
            var alias     = new SqlAlias(node);
            var selection = new SqlAliasRef(alias);

            if (UseConverterStrategy(ConverterStrategy.SkipWithRowNumber))
            {
                var col = new SqlColumn("ROW_NUMBER",
                                        this.sql.RowNumber(new List <SqlOrderExpression>(),
                                                           this.dominatingExpression));
                var expr = new SqlColumnRef(col);
                node.Row.Columns.Add(col);
                var select2 = new SqlSelect(selection, alias, this.dominatingExpression);
                if (takeExp != null)
                {
                    select2.Where = this.sql.Between(expr, this.sql.Add(skipExp, 1),
                                                     this.sql.Binary(SqlNodeType.Add,
                                                                     (SqlExpression)SqlDuplicator.Copy(skipExp),
                                                                     takeExp), this.dominatingExpression);
                    return(select2);
                }
                select2.Where = this.sql.Binary(SqlNodeType.GT, expr, skipExp);
                return(select2);
            }
            if (!this.CanSkipOnSelection(node.Selection))
            {
                throw SqlClient.Error.SkipNotSupportedForSequenceTypes();
            }
            var visitor = new SingleTableQueryVisitor();

            visitor.Visit(node);
            if (!visitor.IsValid)
            {
                throw ALinq.SqlClient.Error.SkipRequiresSingleTableQueryWithPKs();
            }
            var select3 = (SqlSelect)SqlDuplicator.Copy(node);

            select3.Top = skipExp;
            var alias2 = new SqlAlias(select3);
            var ref4   = new SqlAliasRef(alias2);
            var select = new SqlSelect(ref4, alias2, this.dominatingExpression);

            select.Where = this.sql.Binary(SqlNodeType.EQ2V, selection, ref4);
            SqlSubSelect expression = this.sql.SubSelect(SqlNodeType.Exists, select);
            var          select6    = new SqlSelect(selection, alias, this.dominatingExpression);

            select6.Where = this.sql.Unary(SqlNodeType.Not, expression, this.dominatingExpression);
            select6.Top   = takeExp;
            return(select6);
        }
예제 #11
0
        internal override SqlAlias VisitAlias(SqlAlias a)
        {
            SqlAlias n = new SqlAlias(a.Node);

            this.nodeMap[a] = n;
            n.Node          = this.Visit(a.Node);
            n.Name          = a.Name;
            return(n);
        }
예제 #12
0
            internal override SqlAlias VisitAlias(SqlAlias sqlAlias)
            {
                SqlAlias save = this.alias;

                this.alias    = sqlAlias;
                sqlAlias.Node = this.Visit(sqlAlias.Node);
                this.alias    = save;
                return(sqlAlias);
            }
예제 #13
0
 internal SqlAliasRef(SqlAlias alias)
     : base(SqlNodeType.AliasRef, GetClrType(alias.Node), alias.SourceExpression)
 {
     if (alias == null)
     {
         throw Error.ArgumentNull("alias");
     }
     this.alias = alias;
 }
예제 #14
0
        internal override SqlAlias VisitAlias(SqlAlias a)
        {
            SqlAlias save = _currentAlias;

            _currentAlias = a;
            base.VisitAlias(a);
            _currentAlias = save;
            return(a);
        }
 internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss) {
     SqlSelect innerSelect = this.VisitSelect(ss.Select);
     if (!this.aggregateChecker.HasAggregates(innerSelect)) {
         innerSelect.Top = this.sql.ValueFromObject(1, ss.SourceExpression);
     }
     innerSelect.OrderingType = SqlOrderingType.Blocked;
     SqlAlias alias = new SqlAlias(innerSelect);
     this.currentSelect.From = new SqlJoin(SqlJoinType.OuterApply, this.currentSelect.From, alias, null, ss.SourceExpression);
     return new SqlColumnRef(innerSelect.Row.Columns[0]);
 }
예제 #16
0
        public void FullJoin()
        {
            var alias    = new SqlAlias <Passport>("pas");
            var expected =
                @"FULL JOIN
    Passport pas ON pe.Id = pas.PersonId";

            Assert.Equal(expected, new SqlJoin <Passport>(JoinType.Full,
                                                          SqlFilter <Person> .From(p => p.Id).EqualTo <Passport>(p => p.PersonId, alias), alias).ToString());
        }
예제 #17
0
        public void InnerJoin()
        {
            var alias    = new SqlAlias <Passport>("pas");
            var expected =
                @"INNER JOIN
    Passport pas ON pas.PersonId = pe.Id";

            Assert.Equal(expected, new SqlJoin <Passport>(JoinType.Inner,
                                                          SqlFilter <Passport> .From(p => p.PersonId, alias).EqualTo <Person>(p => p.Id), alias).ToString());
        }
예제 #18
0
        private bool HasTrivialSource(SqlSource node)
        {
            SqlAlias alias = node as SqlAlias;

            if (alias == null)
            {
                return(false);
            }
            return(alias.Node is SqlSelect);
        }
예제 #19
0
        internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
        {
            SqlAlias alias = aref.Alias;
            SqlAlias value;

            if (_removedMap.TryGetValue(alias, out value))
            {
                throw Error.InvalidReferenceToRemovedAliasDuringDeflation();
            }
            return(aref);
        }
예제 #20
0
        public void InnerJoinWithLongFilter()
        {
            var alias    = new SqlAlias <Passport>("pas");
            var expected =
                @"INNER JOIN
    Passport pas ON pas.PersonId = pe.Id AND pa.Number IS NOT NULL";

            Assert.Equal(expected,
                         new SqlJoin <Passport>(JoinType.Inner,
                                                SqlFilter <Passport> .From(p => p.PersonId, alias).EqualTo <Person>(p => p.Id)
                                                .And(p => p.Number).IsNotNull(), alias).ToString());
        }
예제 #21
0
        internal SqlSelect BuildDefaultQuery(MetaType rowType, bool allowDeferred, SqlLink link, Expression source) {
            System.Diagnostics.Debug.Assert(rowType != null && rowType.Table != null);
            if (rowType.HasInheritance && rowType.InheritanceRoot != rowType) {
                // RowType is expected to be an inheritance root.
                throw Error.ArgumentWrongValue("rowType");
            }
            SqlTable table = sql.Table(rowType.Table, rowType, source);
            SqlAlias tableAlias = new SqlAlias(table);
            SqlAliasRef tableAliasRef = new SqlAliasRef(tableAlias);

            SqlExpression projection = this.BuildProjection(tableAliasRef, table.RowType, allowDeferred, link, source);
            return new SqlSelect(projection, tableAlias, source);
        }
        internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
        {
            SqlExpression result = base.VisitAliasRef(aref);

            if (result != null && result == aref)
            {
                // reference to outer scope, don't propogate references to expressions or aliases
                SqlAlias alias    = aref.Alias;
                SqlAlias newalias = new SqlAlias(new SqlNop(aref.ClrType, aref.SqlType, null));
                return(new SqlAliasRef(newalias));
            }
            return(result);
        }
예제 #23
0
            protected virtual bool IsSimpleCrossJoinList(SqlExpression node)
            {
                SqlJoin join = (node as SqlJoin);

                if (join != null)
                {
                    return(join.JoinType == SqlJoinType.Cross &&
                           IsSimpleCrossJoinList(join.Left) && IsSimpleCrossJoinList(join.Right));
                }

                SqlAlias alias = (node as SqlAlias);

                return(alias != null && alias.Expression is SqlTable);
            }
        internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss)
        {
            SqlSelect innerSelect = this.VisitSelect(ss.Select);

            if (!this.aggregateChecker.HasAggregates(innerSelect))
            {
                innerSelect.Top = this.sql.ValueFromObject(1, ss.SourceExpression);
            }
            innerSelect.OrderingType = SqlOrderingType.Blocked;
            SqlAlias alias = new SqlAlias(innerSelect);

            this.currentSelect.From = new SqlJoin(SqlJoinType.OuterApply, this.currentSelect.From, alias, null, ss.SourceExpression);
            return(new SqlColumnRef(innerSelect.Row.Columns[0]));
        }
예제 #25
0
        private SqlUnion GetUnion(SqlSource source)
        {
            SqlAlias alias = source as SqlAlias;

            if (alias != null)
            {
                SqlUnion union = alias.Node as SqlUnion;
                if (union != null)
                {
                    return(union);
                }
            }
            return(null);
        }
예제 #26
0
        internal override SqlAlias VisitAlias(SqlAlias a)
        {
            SqlTable tab = a.Node as SqlTable;
            SqlTableValuedFunctionCall tvf = a.Node as SqlTableValuedFunctionCall;

            if (this.addPrimaryKeys && (tab != null || tvf != null))
            {
                List <SqlOrderExpression> list = new List <SqlOrderExpression>();

                bool     isTable = tab != null;
                MetaType rowType = isTable ? tab.RowType : tvf.RowType;
                foreach (MetaDataMember mm in rowType.IdentityMembers)
                {
                    string           name = mm.MappedName;
                    SqlColumn        col;
                    Expression       sourceExpression;
                    List <SqlColumn> columns;

                    if (isTable)
                    {
                        col = tab.Find(name);
                        sourceExpression = tab.SourceExpression;
                        columns          = tab.Columns;
                    }
                    else
                    {
                        col = tvf.Find(name);
                        sourceExpression = tvf.SourceExpression;
                        columns          = tvf.Columns;
                    }

                    if (col == null)
                    {
                        col       = new SqlColumn(mm.MemberAccessor.Type, typeProvider.From(mm.MemberAccessor.Type), name, mm, null, sourceExpression);
                        col.Alias = a;
                        columns.Add(col);
                    }
                    list.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(col)));
                }

                this.PrependOrderExpressions(list);

                return(a);
            }
            else
            {
                return(base.VisitAlias(a));
            }
        }
예제 #27
0
        internal override SqlSource VisitSource(SqlSource node)
        {
            node = (SqlSource)this.Visit(node);
            SqlAlias alias = node as SqlAlias;

            if (alias != null)
            {
                SqlSelect sel = alias.Node as SqlSelect;
                if (sel != null && this.IsTrivialSelect(sel))
                {
                    _removedMap[alias] = alias;
                    node = sel.From;
                }
            }
            return(node);
        }
예제 #28
0
        internal SqlSelect BuildDefaultQuery(MetaType rowType, bool allowDeferred, SqlLink link, Expression source)
        {
            System.Diagnostics.Debug.Assert(rowType != null && rowType.Table != null);
            if (rowType.HasInheritance && rowType.InheritanceRoot != rowType)
            {
                // RowType is expected to be an inheritance root.
                throw Error.ArgumentWrongValue("rowType");
            }
            SqlTable    table         = sql.Table(rowType.Table, rowType, source);
            SqlAlias    tableAlias    = new SqlAlias(table);
            SqlAliasRef tableAliasRef = new SqlAliasRef(tableAlias);

            SqlExpression projection = this.BuildProjection(tableAliasRef, table.RowType, allowDeferred, link, source);

            return(new SqlSelect(projection, tableAlias, source));
        }
예제 #29
0
        public void GreaterThanOrEqual()
        {
            Assert.Equal("pe.Id >= 5", SqlFilter <Person> .From(m => m.Id).GreaterThanOrEqual(5).RawSql);
            Assert.Equal("pe.Name >= pe.LastName", SqlFilter <Person> .From(m => m.Name).GreaterThanOrEqual(m => m.LastName).RawSql);
            Assert.Equal("pe.Id >= pa.PersonId", SqlFilter <Person> .From(m => m.Id).GreaterThanOrEqual <Passport>(m => m.PersonId).RawSql);

            var peAlias = new SqlAlias <Person>("per");
            var paAlias = new SqlAlias <Passport>("pas");

            Assert.Equal("pe.Name >= per.LastName", SqlFilter <Person> .From(m => m.Name).GreaterThanOrEqual(m => m.LastName, peAlias).RawSql);
            Assert.Equal("pe.Id >= pas.PersonId", SqlFilter <Person> .From(m => m.Id).GreaterThanOrEqual <Passport>(m => m.PersonId, paAlias).RawSql);

            Assert.Equal("pe.Id >= COUNT(pa.Id)", SqlFilter <Person> .From(p => p.Id).GreaterThanOrEqual(SqlField <Passport> .Count(p => p.Id)).RawSql);
            var alias = new SqlAlias <Passport>("pasp");

            Assert.Equal("pe.Id >= COUNT(pasp.Id)", SqlFilter <Person> .From(p => p.Id).GreaterThanOrEqual(SqlField <Passport> .Count(alias, p => p.Id)).ToString());
        }
            internal SqlAlias VisitAliasConsumed(SqlAlias a) {
                if (a == null)
                    return a;

                bool match = false;
                foreach (SqlAlias alias in aliases)
                    if (alias == a) {
                        match = true;
                        break;
                    }

                if (match) {
                    this.referencesAnyMatchingAliases = true;
                }

                return a;
            }
예제 #31
0
        public void NotEqualTo()
        {
            Assert.Equal("pe.Id <> 5", SqlFilter <Person> .From(m => m.Id).NotEqualTo(5).RawSql);
            Assert.Equal("pe.Name <> pe.LastName", SqlFilter <Person> .From(m => m.Name).NotEqualTo(m => m.LastName).RawSql);
            Assert.Equal("pe.Id <> pa.PersonId", SqlFilter <Person> .From(m => m.Id).NotEqualTo <Passport>(m => m.PersonId).RawSql);

            var peAlias = new SqlAlias <Person>("per");
            var paAlias = new SqlAlias <Passport>("pas");

            Assert.Equal("pe.Name <> per.LastName", SqlFilter <Person> .From(m => m.Name).NotEqualTo(m => m.LastName, peAlias).RawSql);
            Assert.Equal("pe.Id <> pas.PersonId", SqlFilter <Person> .From(m => m.Id).NotEqualTo <Passport>(m => m.PersonId, paAlias).RawSql);

            Assert.Equal("pe.Id <> COUNT(pa.Id)", SqlFilter <Person> .From(p => p.Id).NotEqualTo(SqlField <Passport> .Count(p => p.Id)).RawSql);
            var alias = new SqlAlias <Passport>("pasp");

            Assert.Equal("pe.Id <> COUNT(pasp.Id)", SqlFilter <Person> .From(p => p.Id).NotEqualTo(SqlField <Passport> .Count(alias, p => p.Id)).ToString());
        }
예제 #32
0
            internal override SqlExpression VisitColumnRef(SqlColumnRef cref)
            {
                string    str   = null;
                SqlColumn key   = cref.Column;
                SqlAlias  alias = key.Alias;

                if (alias == null)
                {
                    this.aliasMap.TryGetValue(key, out alias);
                }
                if (alias != null && !disableAlias)
                {
                    if (alias.Name == null)
                    {
                        if (!this.names.TryGetValue(alias, out str))
                        {
                            str = "A" + this.names.Count;
                            this.names[key.Alias] = str;
                        }
                    }
                    else
                    {
                        str = key.Alias.Name;
                    }
                }
                if ((!this.suppressedAliases.Contains(key.Alias) && (str != null)) && (str.Length != 0))
                {
                    this.WriteName(str);
                    this.sb.Append(".");
                }
                string name = key.Name;
                string str3 = this.InferName(key.Expression, null);

                if (name == null)
                {
                    name = str3;
                }
                if ((name == null) && !this.names.TryGetValue(key, out name))
                {
                    name            = "C" + this.names.Count;
                    this.names[key] = name;
                }
                this.WriteName(name);
                return(cref);
            }
예제 #33
0
            internal override SqlAlias VisitAlias(SqlAlias alias)
            {
                bool     flag        = alias.Node is SqlSelect;
                int      sourceDepth = this.depth;
                string   str;
                string   name = "";
                SqlTable node = alias.Node as SqlTable;

                if (node != null)
                {
                    name = node.Name;
                }
                if (alias.Name == null)
                {
                    if (!this.names.TryGetValue(alias, out str))
                    {
                        str = "A" + this.names.Count;
                        this.names[alias] = str;
                    }
                }
                else
                {
                    str = alias.Name;
                }
                if (flag)
                {
                    this.depth++;
                    this.sb.Append("(");
                    this.NewLine();
                }
                this.Visit(alias.Node);
                if (flag)
                {
                    this.NewLine();
                    this.sb.Append(")");
                    this.depth = sourceDepth;
                }
                if ((!this.suppressedAliases.Contains(alias) && (str != null)) && (name != str) && !disableAlias)
                {
                    this.sb.Append(" AS ");
                    this.WriteName(str);
                }
                return(alias);
            }
            private void GetSelectionsBeforeJoin(SqlSource source, List <List <SqlColumn> > selections)
            {
                SqlJoin join = source as SqlJoin;

                if (join != null)
                {
                    return;
                }
                SqlAlias alias = source as SqlAlias;

                if (alias != null)
                {
                    SqlSelect select = alias.Node as SqlSelect;
                    if (select != null)
                    {
                        this.GetSelectionsBeforeJoin(select.From, selections);
                        selections.Add(select.Row.Columns);
                    }
                }
            }
            private bool IsSingletonSelect(SqlSource source)
            {
                SqlAlias alias = source as SqlAlias;

                if (alias == null)
                {
                    return(false);
                }
                SqlSelect select = alias.Node as SqlSelect;

                if (select == null)
                {
                    return(false);
                }
                if (select.From != null)
                {
                    return(false);
                }
                return(true);
            }
예제 #36
0
 internal SqlJoin MakeJoin(SqlJoinType joinType, SqlSource location, SqlAlias alias, SqlExpression condition, Expression source)
 {
     // if the new item is on the right side of some outer join then fixup the projection to reflect that it can possibly be null
     if (joinType == SqlJoinType.LeftOuter)
     {
         SqlSelect sel = alias.Node as SqlSelect;
         if (sel != null && sel.Selection != null && sel.Selection.NodeType != SqlNodeType.OptionalValue)
         {
             // replace selection w/ optional + outer-joined-value
             sel.Selection = new SqlOptionalValue(
                 new SqlColumn(
                     "test",
                     this.Unary(SqlNodeType.OuterJoinedValue,
                                this.Value(typeof(int?), this.typeProvider.From(typeof(int)), 1, false, source))
                     ),
                 sel.Selection
                 );
         }
     }
     return(new SqlJoin(joinType, location, alias, condition, source));
 }
예제 #37
0
 private SqlExpression FoldSubquery(SqlSubSelect ss) {
     // convert ELEMENT(SELECT MULTISET(SELECT xxx FROM t1 WHERE p1) FROM t2 WHERE p2)
     // into MULTISET(SELECT xxx FROM t2 CA (SELECT xxx FROM t1 WHERE p1) WHERE p2))
     while (true) {
         if (ss.NodeType == SqlNodeType.Element && ss.Select.Selection.NodeType == SqlNodeType.Multiset) {
             SqlSubSelect msub = (SqlSubSelect)ss.Select.Selection;
             SqlAlias alias = new SqlAlias(msub.Select);
             SqlAliasRef aref = new SqlAliasRef(alias);
             SqlSelect sel = ss.Select;
             sel.Selection = this.ConvertLinks(this.VisitExpression(aref));
             sel.From = new SqlJoin(SqlJoinType.CrossApply, sel.From, alias, null, ss.SourceExpression);
             SqlSubSelect newss = sql.SubSelect(SqlNodeType.Multiset, sel, ss.ClrType);
             ss = newss;
         }
         else if (ss.NodeType == SqlNodeType.Element && ss.Select.Selection.NodeType == SqlNodeType.Element) {
             SqlSubSelect msub = (SqlSubSelect)ss.Select.Selection;
             SqlAlias alias = new SqlAlias(msub.Select);
             SqlAliasRef aref = new SqlAliasRef(alias);
             SqlSelect sel = ss.Select;
             sel.Selection = this.ConvertLinks(this.VisitExpression(aref));
             sel.From = new SqlJoin(SqlJoinType.CrossApply, sel.From, alias, null, ss.SourceExpression);
             SqlSubSelect newss = sql.SubSelect(SqlNodeType.Element, sel);
             ss = newss;
         }
         else {
             break;
         }
     }
     return ss;
 }
예제 #38
0
            protected override SqlExpression VisitAlias(SqlAlias alias)
            {
                bool isSelect = (alias.Expression is SqlSelect);
                
                int depth = _depth;
                string name = String.Empty;
                string aliasName = null;

                SqlField field = (alias.Expression as SqlField);
                if (field != null)
                    name = field.Name;

                SqlTable table = (alias.Expression as SqlTable);
                if (table != null)
                    name = table.Name;
                
                if (alias.Name == null)
                {
                    if (!_nameMap.TryGetValue(alias, out aliasName))
                    {
                        aliasName = "A" + _nameMap.Count;
                        _nameMap[alias] = aliasName;
                    }
                }
                else
                    aliasName = alias.Name;
                
                if (isSelect)
                {
                    _depth++;
                    _builder.Append("(");
                    this.NewLine();
                }
                
                Visit(alias.Expression);

                if (isSelect)
                {
                    this.NewLine();
                    _builder.Append(")");
                    
                    _depth = depth;
                }
                if ((!_suppressedAliases.Contains(alias) && aliasName != null) && name != aliasName)
                {
                    _builder.Append(" AS ");
                    WriteName(aliasName);
                }

                return alias;
            }
예제 #39
0
 private SqlNode VisitUnion(Expression source1, Expression source2) {
     SqlSelect left = this.VisitSequence(source1);
     SqlSelect right = this.VisitSequence(source2);
     SqlUnion union = new SqlUnion(left, right, false);
     SqlAlias alias = new SqlAlias(union);
     SqlAliasRef aref = new SqlAliasRef(alias);
     SqlSelect result = new SqlSelect(aref, alias, this.dominatingExpression);
     result.OrderingType = SqlOrderingType.Blocked;
     return result;
 }
예제 #40
0
        private SqlSelect VisitGroupJoin(Expression outerSequence, Expression innerSequence, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector, LambdaExpression resultSelector) {
            SqlSelect outerSelect = this.VisitSequence(outerSequence);
            SqlSelect innerSelect = this.VisitSequence(innerSequence);

            SqlAlias outerAlias = new SqlAlias(outerSelect);
            SqlAliasRef outerRef = new SqlAliasRef(outerAlias);
            SqlAlias innerAlias = new SqlAlias(innerSelect);
            SqlAliasRef innerRef = new SqlAliasRef(innerAlias);

            this.map[outerKeySelector.Parameters[0]] = outerRef;
            SqlExpression outerKey = this.VisitExpression(outerKeySelector.Body);

            this.map[innerKeySelector.Parameters[0]] = innerRef;
            SqlExpression innerKey = this.VisitExpression(innerKeySelector.Body);

            // make multiset 
            SqlExpression pred = sql.Binary(SqlNodeType.EQ, outerKey, innerKey);
            SqlSelect select = new SqlSelect(innerRef, innerAlias, this.dominatingExpression);
            select.Where = pred;
            SqlSubSelect subquery = sql.SubSelect(SqlNodeType.Multiset, select);

            // make outer ref & multiset for result-selector params
            this.map[resultSelector.Parameters[0]] = outerRef;
            this.dupMap[resultSelector.Parameters[1]] = subquery;
            SqlExpression result = this.VisitExpression(resultSelector.Body);

            return new SqlSelect(result, outerAlias, this.dominatingExpression);
        }
예제 #41
0
        private SqlSelect VisitDefaultIfEmpty(Expression sequence) {
            SqlSelect select = this.VisitSequence(sequence);
            SqlAlias alias = new SqlAlias(select);
            SqlAliasRef aliasRef = new SqlAliasRef(alias);

            SqlExpression opt = new SqlOptionalValue(
                new SqlColumn(
                    "test",
                    sql.Unary(SqlNodeType.OuterJoinedValue,
                        sql.Value(typeof(int?), this.typeProvider.From(typeof(int)), 1, false, this.dominatingExpression)
                        )
                    ),
                    sql.Unary(SqlNodeType.OuterJoinedValue, aliasRef)
                );
            SqlSelect optSelect = new SqlSelect(opt, alias, this.dominatingExpression);

            alias = new SqlAlias(optSelect);
            aliasRef = new SqlAliasRef(alias);

            SqlExpression litNull = sql.TypedLiteralNull(typeof(string), this.dominatingExpression);
            SqlSelect selNull = new SqlSelect(litNull, null, this.dominatingExpression);
            SqlAlias aliasNull = new SqlAlias(selNull);

            SqlJoin join = new SqlJoin(SqlJoinType.OuterApply, aliasNull, alias, null, this.dominatingExpression);

            return new SqlSelect(aliasRef, join, this.dominatingExpression);
        }
예제 #42
0
        private SqlNode VisitGroupBy(Expression sequence, LambdaExpression keyLambda, LambdaExpression elemLambda, LambdaExpression resultSelector) {
            // Convert seq.Group(elem, key) into
            //
            // SELECT s.key, MULTISET(select s2.elem from seq AS s2 where s.key == s2.key)
            // FROM seq AS s
            //
            // where key and elem can be either simple scalars or object constructions
            //
            SqlSelect seq = this.VisitSequence(sequence);
            seq = this.LockSelect(seq);
            SqlAlias seqAlias = new SqlAlias(seq);
            SqlAliasRef seqAliasRef = new SqlAliasRef(seqAlias);

            // evaluate the key expression relative to original sequence
            this.map[keyLambda.Parameters[0]] = seqAliasRef;
            SqlExpression keyExpr = this.VisitExpression(keyLambda.Body);

            // make a duplicate of the original sequence to use as a foundation of our group multiset
            SqlDuplicator sd = new SqlDuplicator();
            SqlSelect selDup = (SqlSelect)sd.Duplicate(seq);

            // rebind key in relative to the duplicate sequence
            SqlAlias selDupAlias = new SqlAlias(selDup);
            SqlAliasRef selDupRef = new SqlAliasRef(selDupAlias);
            this.map[keyLambda.Parameters[0]] = selDupRef;
            SqlExpression keyDup = this.VisitExpression(keyLambda.Body);

            SqlExpression elemExpr = null;
            SqlExpression elemOnGroupSource = null;
            if (elemLambda != null) {
                // evaluate element expression relative to the duplicate sequence
                this.map[elemLambda.Parameters[0]] = selDupRef;
                elemExpr = this.VisitExpression(elemLambda.Body);

                // evaluate element expression relative to original sequence
                this.map[elemLambda.Parameters[0]] = seqAliasRef;
                elemOnGroupSource = this.VisitExpression(elemLambda.Body);
            }
            else {
                // no elem expression supplied, so just use an alias ref to the duplicate sequence.
                // this will resolve to whatever was being produced by the sequence
                elemExpr = selDupRef;
                elemOnGroupSource = seqAliasRef;
            }

            // Make a sub expression out of the key.  This will allow a single definition of the 
            // expression to be shared at multiple points in the tree (via SqlSharedExpressionRef's)
            SqlSharedExpression keySubExpr = new SqlSharedExpression(keyExpr);
            keyExpr = new SqlSharedExpressionRef(keySubExpr);

            // construct the select clause that picks out the elements (this may be redundant...)
            SqlSelect selElem = new SqlSelect(elemExpr, selDupAlias, this.dominatingExpression);
            selElem.Where = sql.Binary(SqlNodeType.EQ2V, keyExpr, keyDup);

            // Finally, make the MULTISET node. this will be used as part of the final select
            SqlSubSelect ss = sql.SubSelect(SqlNodeType.Multiset, selElem);

            // add a layer to the original sequence before applying the actual group-by clause
            SqlSelect gsel = new SqlSelect(new SqlSharedExpressionRef(keySubExpr), seqAlias, this.dominatingExpression);
            gsel.GroupBy.Add(keySubExpr);
            SqlAlias gselAlias = new SqlAlias(gsel);

            SqlSelect result = null;
            if (resultSelector != null) {
                // Create final select to include construction of group multiset
                // select new Grouping { Key = key, Group = Multiset(select elem from seq where match) } from ...
                Type elementType = typeof(IGrouping<,>).MakeGenericType(keyExpr.ClrType, elemExpr.ClrType);

                SqlExpression keyGroup = new SqlGrouping(elementType, this.typeProvider.From(elementType), keyExpr, ss, this.dominatingExpression);
                SqlSelect keyGroupSel = new SqlSelect(keyGroup, gselAlias, this.dominatingExpression);
                SqlAlias kgAlias = new SqlAlias(keyGroupSel);
                SqlAliasRef kgAliasRef = new SqlAliasRef(kgAlias);

                this.map[resultSelector.Parameters[0]] = sql.Member(kgAliasRef, elementType.GetProperty("Key"));
                this.map[resultSelector.Parameters[1]] = kgAliasRef;

                // remember the select that has the actual group (for optimizing aggregates later)
                this.gmap[kgAliasRef] = new GroupInfo { SelectWithGroup = gsel, ElementOnGroupSource = elemOnGroupSource };

                SqlExpression resultExpr = this.VisitExpression(resultSelector.Body);
                result = new SqlSelect(resultExpr, kgAlias, this.dominatingExpression);

                // remember the select that has the actual group (for optimizing aggregates later)
                this.gmap[resultExpr] = new GroupInfo { SelectWithGroup = gsel, ElementOnGroupSource = elemOnGroupSource };
            }
            else {
                // Create final select to include construction of group multiset
                // select new Grouping { Key = key, Group = Multiset(select elem from seq where match) } from ...
                Type elementType = typeof(IGrouping<,>).MakeGenericType(keyExpr.ClrType, elemExpr.ClrType);

                SqlExpression resultExpr = new SqlGrouping(elementType, this.typeProvider.From(elementType), keyExpr, ss, this.dominatingExpression);
                result = new SqlSelect(resultExpr, gselAlias, this.dominatingExpression);

                // remember the select that has the actual group (for optimizing aggregates later)
                this.gmap[resultExpr] = new GroupInfo { SelectWithGroup = gsel, ElementOnGroupSource = elemOnGroupSource };
            }

            return result;
        }
예제 #43
0
        /// <summary>
        /// Translate a call to a table valued function expression into a sql select.
        /// </summary>             
        private SqlNode TranslateTableValuedFunction(MethodCallExpression mce, MetaFunction function) {
            // translate method call into sql function call
            List<SqlExpression> sqlParams = GetFunctionParameters(mce, function);
            SqlTableValuedFunctionCall functionCall = sql.TableValuedFunctionCall(function.ResultRowTypes[0].InheritanceRoot, mce.Method.ReturnType, function.MappedName, sqlParams, mce);

            SqlAlias alias = new SqlAlias(functionCall);
            SqlAliasRef aref = new SqlAliasRef(alias);

            // Build default projection           
            SqlExpression projection = this.translator.BuildProjection(aref, function.ResultRowTypes[0].InheritanceRoot, this.allowDeferred, null, mce);

            SqlSelect select = new SqlSelect(projection, alias, mce);
            return select;
        }
예제 #44
0
            internal override SqlAlias VisitAlias(SqlAlias a) {

                SqlTable tab = a.Node as SqlTable;
                SqlTableValuedFunctionCall tvf = a.Node as SqlTableValuedFunctionCall;

                if (this.addPrimaryKeys && (tab != null || tvf != null)) {
                    List<SqlOrderExpression> list = new List<SqlOrderExpression>();

                    bool isTable = tab != null;
                    MetaType rowType = isTable ? tab.RowType : tvf.RowType;
                    foreach (MetaDataMember mm in rowType.IdentityMembers) {
                        string name = mm.MappedName;
                        SqlColumn col;
                        Expression sourceExpression;
                        List<SqlColumn> columns;

                        if (isTable) {
                            col = tab.Find(name);
                            sourceExpression = tab.SourceExpression;
                            columns = tab.Columns;
                        }
                        else {
                            col = tvf.Find(name);
                            sourceExpression = tvf.SourceExpression;
                            columns = tvf.Columns; 
                        }

                        if (col == null) {
                            col = new SqlColumn(mm.MemberAccessor.Type, typeProvider.From(mm.MemberAccessor.Type), name, mm, null, sourceExpression);
                            col.Alias = a;
                            columns.Add(col);
                        }
                        list.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(col)));
                    }

                    this.PrependOrderExpressions(list);

                    return a;
                }
                else {
                    return base.VisitAlias(a);
                }
            }
예제 #45
0
        private SqlNode VisitExcept(Expression source1, Expression source2) {
            Type type = TypeSystem.GetElementType(source1.Type);
            if (IsGrouping(type)) {
                throw Error.ExceptNotSupportedForHierarchicalTypes();
            }

            SqlSelect select1 = this.LockSelect(this.VisitSequence(source1));
            SqlSelect select2 = this.VisitSequence(source2);

            SqlAlias alias1 = new SqlAlias(select1);
            SqlAliasRef aref1 = new SqlAliasRef(alias1);

            SqlAlias alias2 = new SqlAlias(select2);
            SqlAliasRef aref2 = new SqlAliasRef(alias2);

            SqlExpression any = this.GenerateQuantifier(alias2, sql.Binary(SqlNodeType.EQ2V, aref1, aref2), true);

            SqlSelect result = new SqlSelect(aref1, alias1, select1.SourceExpression);
            result.Where = sql.Unary(SqlNodeType.Not, any);
            result.IsDistinct = true;
            result.OrderingType = SqlOrderingType.Blocked;
            return result;
        }
예제 #46
0
        private SqlStatement VisitInsert(Expression item, LambdaExpression resultSelector) {
            if (item == null) {
                throw Error.ArgumentNull("item");
            }
            this.dominatingExpression = item;

            MetaTable metaTable = this.services.Model.GetTable(item.Type);
            Expression source = this.services.Context.GetTable(metaTable.RowType.Type).Expression;

            MetaType itemMetaType = null;
            SqlNew sqlItem = null;

            // construct insert assignments from 'item' info
            ConstantExpression conItem = item as ConstantExpression;
            if (conItem == null) {
                throw Error.InsertItemMustBeConstant();
            }
            if (conItem.Value == null) {
                throw Error.ArgumentNull("item");
            }
            // construct insert based on constant value
            List<SqlMemberAssign> bindings = new List<SqlMemberAssign>();
            itemMetaType = metaTable.RowType.GetInheritanceType(conItem.Value.GetType());
            SqlExpression sqlExprItem = sql.ValueFromObject(conItem.Value, true, source);
            foreach (MetaDataMember mm in itemMetaType.PersistentDataMembers) {
                if (!mm.IsAssociation && !mm.IsDbGenerated && !mm.IsVersion) {
                    bindings.Add(new SqlMemberAssign(mm.Member, sql.Member(sqlExprItem, mm.Member)));
                }
            }
            ConstructorInfo cons = itemMetaType.Type.GetConstructor(Type.EmptyTypes);
            System.Diagnostics.Debug.Assert(cons != null);
            sqlItem = sql.New(itemMetaType, cons, null, null, bindings, item);

            SqlTable tab = sql.Table(metaTable, metaTable.RowType, this.dominatingExpression);
            SqlInsert sin = new SqlInsert(tab, sqlItem, item);

            if (resultSelector == null) {
                return sin;
            }
            else {
                MetaDataMember id = itemMetaType.DBGeneratedIdentityMember;
                bool isDbGenOnly = false;  
                if (id != null) {
                    isDbGenOnly = this.IsDbGeneratedKeyProjectionOnly(resultSelector.Body, id);
                    if (id.Type == typeof(Guid) && (this.converterStrategy & ConverterStrategy.CanOutputFromInsert) != 0) {
                        sin.OutputKey = new SqlColumn(id.Type, sql.Default(id), id.Name, id, null, this.dominatingExpression);
                        if (!isDbGenOnly) {
                            sin.OutputToLocal = true;
                        }
                    }
                }

                SqlSelect result = null;
                SqlSelect preResult = null;
                SqlAlias tableAlias = new SqlAlias(tab);
                SqlAliasRef tableAliasRef = new SqlAliasRef(tableAlias);
                System.Diagnostics.Debug.Assert(resultSelector.Parameters.Count == 1);
                this.map.Add(resultSelector.Parameters[0], tableAliasRef);
                SqlExpression projection = this.VisitExpression(resultSelector.Body);

                // build select to return result
                SqlExpression pred = null;
                if (id != null) {
                    pred = sql.Binary(
                            SqlNodeType.EQ,
                            sql.Member(tableAliasRef, id.Member),
                            this.GetIdentityExpression(id, sin.OutputKey != null)
                            );
                }
                else {
                    SqlExpression itemExpression = this.VisitExpression(item);
                    pred = sql.Binary(SqlNodeType.EQ2V, tableAliasRef, itemExpression);
                }
                result = new SqlSelect(projection, tableAlias, resultSelector);
                result.Where = pred;

                // Since we're only projecting back a single generated key, we can
                // optimize the query to a simple selection (e.g. SELECT @@IDENTITY)
                // rather than selecting back from the table.
                if (id != null && isDbGenOnly) {
                    if (sin.OutputKey == null) {
                        SqlExpression exp = this.GetIdentityExpression(id, false);
                        if (exp.ClrType != id.Type) {
                            ProviderType sqlType = sql.Default(id);
                            exp = sql.ConvertTo(id.Type, sqlType, exp);
                        }
                        // The result selector passed in was bound to the table -
                        // we need to rebind to the single result as an array projection
                        ParameterExpression p = Expression.Parameter(id.Type, "p");
                        Expression[] init = new Expression[1] { Expression.Convert(p, typeof(object)) };
                        NewArrayExpression arrExp = Expression.NewArrayInit(typeof(object), init);
                        LambdaExpression rs = Expression.Lambda(arrExp, p);
                        this.map.Add(p, exp);
                        SqlExpression proj = this.VisitExpression(rs.Body);
                        preResult = new SqlSelect(proj, null, rs);
                    }
                    else {
                        // case handled in formatter automatically
                    }
                    result.DoNotOutput = true;
                }

                // combine insert & result into block
                SqlBlock block = new SqlBlock(this.dominatingExpression);
                block.Statements.Add(sin);
                if (preResult != null) {
                    block.Statements.Add(preResult);
                }
                block.Statements.Add(result);
                return block;
            }
        }
예제 #47
0
 private SqlSelect LockSelect(SqlSelect sel) {
     if (sel.Selection.NodeType != SqlNodeType.AliasRef ||
         sel.Where != null ||
         sel.OrderBy.Count > 0 ||
         sel.GroupBy.Count > 0 ||
         sel.Having != null ||
         sel.Top != null ||
         sel.OrderingType != SqlOrderingType.Default ||
         sel.IsDistinct) {
         SqlAlias alias = new SqlAlias(sel);
         SqlAliasRef aref = new SqlAliasRef(alias);
         return new SqlSelect(aref, alias, this.dominatingExpression);
     }
     return sel;
 }
예제 #48
0
 private SqlExpression GenerateQuantifier(SqlAlias alias, SqlExpression cond, bool isAny) {
     SqlAliasRef aref = new SqlAliasRef(alias);
     if (isAny) {
         SqlSelect sel = new SqlSelect(aref, alias, this.dominatingExpression);
         sel.Where = cond;
         sel.OrderingType = SqlOrderingType.Never;
         SqlSubSelect exists = sql.SubSelect(SqlNodeType.Exists, sel);
         return exists;
     }
     else {
         SqlSelect sel = new SqlSelect(aref, alias, this.dominatingExpression);
         SqlSubSelect ss = sql.SubSelect(SqlNodeType.Exists, sel);
         sel.Where = sql.Unary(SqlNodeType.Not2V, cond, this.dominatingExpression);
         return sql.Unary(SqlNodeType.Not, ss, this.dominatingExpression);
     }
 }
예제 #49
0
 private SqlNode VisitQuantifier(SqlSelect select, LambdaExpression lambda, bool isAny) {
     SqlAlias alias = new SqlAlias(select);
     SqlAliasRef aref = new SqlAliasRef(alias);
     if (lambda != null) {
         this.map[lambda.Parameters[0]] = aref;
     }
     SqlExpression cond = lambda != null ? this.VisitExpression(lambda.Body) : null;
     return this.GenerateQuantifier(alias, cond, isAny);
 }
예제 #50
0
        private SqlNode VisitAggregate(Expression sequence, LambdaExpression lambda, SqlNodeType aggType, Type returnType) {
            // Convert seq.Agg(exp) into 
            //
            // 1) SELECT Agg(exp) FROM seq
            // 2) SELECT Agg1 FROM (SELECT Agg(exp) as Agg1 FROM group-seq GROUP BY ...)
            // 3) SCALAR(SELECT Agg(exp) FROM seq)
            //
            bool isCount = aggType == SqlNodeType.Count || aggType == SqlNodeType.LongCount;

            SqlNode source = this.Visit(sequence);
            SqlSelect select = this.CoerceToSequence(source);
            SqlAlias alias = new SqlAlias(select);
            SqlAliasRef aref = new SqlAliasRef(alias);

            // If the sequence is of the form x.Select(expr).Agg() and the lambda for the aggregate is null,
            // or is a no-op parameter expression (like u=>u), clone the group by selection lambda 
            // expression, and use for the aggregate.
            // Final form should be x.Agg(expr)
            MethodCallExpression mce = sequence as MethodCallExpression;
            if (!outerNode && !isCount && (lambda == null || (lambda.Parameters.Count == 1 && lambda.Parameters[0] == lambda.Body)) &&
                (mce != null) && IsSequenceOperatorCall(mce, "Select") && select.From is SqlAlias) {
                LambdaExpression selectionLambda = GetLambda(mce.Arguments[1]);

                lambda = Expression.Lambda(selectionLambda.Type, selectionLambda.Body, selectionLambda.Parameters);

                alias = (SqlAlias)select.From;
                aref = new SqlAliasRef(alias);
            }

            if (lambda != null && !TypeSystem.IsSimpleType(lambda.Body.Type)) {
                throw Error.CannotAggregateType(lambda.Body.Type);
            }

            //Empty parameter aggregates are not allowed on anonymous types
            //i.e. db.Customers.Select(c=>new{c.Age}).Max() instead it should be
            //     db.Customers.Select(c=>new{c.Age}).Max(c=>c.Age)
            if (select.Selection.SqlType.IsRuntimeOnlyType && !IsGrouping(sequence.Type) && !isCount && lambda == null) {
                throw Error.NonCountAggregateFunctionsAreNotValidOnProjections(aggType);
            }
            if (lambda != null)
                this.map[lambda.Parameters[0]] = aref;

            if (this.outerNode) {
                // If this aggregate is basically the last/outer-most operator of the query
                // 
                // produce SELECT Agg(exp) FROM seq
                //
                SqlExpression exp = (lambda != null) ? this.VisitExpression(lambda.Body) : null;
                SqlExpression where = null;
                if (isCount && exp != null) {
                    where = exp;
                    exp = null;
                }
                else if (exp == null && !isCount) {
                    exp = aref;
                }
                if (exp != null) {
                    // in case this contains another aggregate
                    exp = new SqlSimpleExpression(exp);
                }
                SqlSelect sel = new SqlSelect(
                    this.GetAggregate(aggType, returnType, exp),
                    alias,
                    this.dominatingExpression
                    );
                sel.Where = where;
                sel.OrderingType = SqlOrderingType.Never;
                return sel;
            }
            else if (!isCount || lambda == null) {
                // Look to optimize aggregate by pushing its evaluation down to the select node that has the
                // actual group-by operator.
                //
                // Produce:  SELECT Agg1 FROM (SELECT Agg(exp) as Agg1 FROM seq GROUP BY ...)
                //
                GroupInfo info = this.FindGroupInfo(source);
                if (info != null) {
                    SqlExpression exp = null;
                    if (lambda != null) {
                        // evaluate expression relative to the group-by select node
                        this.map[lambda.Parameters[0]] = (SqlExpression)SqlDuplicator.Copy(info.ElementOnGroupSource);
                        exp = this.VisitExpression(lambda.Body);
                    } else if (!isCount) {
                        // support aggregates w/o an explicit selector specified
                        exp = info.ElementOnGroupSource;
                    }
                    if (exp != null) {
                        // in case this contains another aggregate
                        exp = new SqlSimpleExpression(exp);
                    }
                    SqlExpression agg = this.GetAggregate(aggType, returnType, exp);
                    SqlColumn c = new SqlColumn(agg.ClrType, agg.SqlType, null, null, agg, this.dominatingExpression);
                    info.SelectWithGroup.Row.Columns.Add(c);
                    return new SqlColumnRef(c);
                }
            }
            // Otherwise, if we cannot optimize then fall back to generating a nested aggregate in a correlated sub query
            //
            // SCALAR(SELECT Agg(exp) FROM seq)
            {
                SqlExpression exp = (lambda != null) ? this.VisitExpression(lambda.Body) : null;
                if (exp != null) {
                    // in case this contains another aggregate
                    exp = new SqlSimpleExpression(exp);
                }
                SqlSelect sel = new SqlSelect(
                    this.GetAggregate(aggType, returnType, isCount ? null : (lambda == null) ? aref : exp),
                    alias,
                    this.dominatingExpression
                    );
                sel.Where = isCount ? exp : null;
                return sql.SubSelect(SqlNodeType.ScalarSubSelect, sel);
            }
        }
예제 #51
0
            private SqlNode AccessMember(SqlMember m, SqlExpression expo) {
                SqlExpression exp = expo;

                switch (exp.NodeType) {
                    case SqlNodeType.ClientCase: {
                            // Distribute into each case.
                            SqlClientCase sc = (SqlClientCase)exp;
                            Type newClrType = null;
                            List<SqlExpression> matches = new List<SqlExpression>();
                            List<SqlExpression> values = new List<SqlExpression>();
                            foreach (SqlClientWhen when in sc.Whens) {
                                SqlExpression newValue = (SqlExpression)AccessMember(m, when.Value);
                                if (newClrType == null) {
                                    newClrType = newValue.ClrType;
                                }
                                else if (newClrType != newValue.ClrType) {
                                    throw Error.ExpectedClrTypesToAgree(newClrType, newValue.ClrType);
                                }
                                matches.Add(when.Match);
                                values.Add(newValue);
                            }

                            SqlExpression result = sql.Case(newClrType, sc.Expression, matches, values, sc.SourceExpression);
                            return result;
                        }
                    case SqlNodeType.SimpleCase: {
                            // Distribute into each case.
                            SqlSimpleCase sc = (SqlSimpleCase)exp;
                            Type newClrType = null;
                            List<SqlExpression> newMatches = new List<SqlExpression>();
                            List<SqlExpression> newValues = new List<SqlExpression>();
                            foreach (SqlWhen when in sc.Whens) {
                                SqlExpression newValue = (SqlExpression)AccessMember(m, when.Value);
                                if (newClrType == null) {
                                    newClrType = newValue.ClrType;
                                }
                                else if (newClrType != newValue.ClrType) {
                                  throw Error.ExpectedClrTypesToAgree(newClrType, newValue.ClrType);
                                }
                                newMatches.Add(when.Match);
                                newValues.Add(newValue);
                            }
                            SqlExpression result = sql.Case(newClrType, sc.Expression, newMatches, newValues, sc.SourceExpression);
                            return result;
                        }
                    case SqlNodeType.SearchedCase: {
                            // Distribute into each case.
                            SqlSearchedCase sc = (SqlSearchedCase)exp;
                            List<SqlWhen> whens = new List<SqlWhen>(sc.Whens.Count);
                            foreach (SqlWhen when in sc.Whens) {
                                SqlExpression value = (SqlExpression)AccessMember(m, when.Value);
                                whens.Add(new SqlWhen(when.Match, value));
                            }
                            SqlExpression @else = (SqlExpression)AccessMember(m, sc.Else);
                            return sql.SearchedCase(whens.ToArray(), @else, sc.SourceExpression);
                        }
                    case SqlNodeType.TypeCase: {
                            // We don't allow derived types to map members to different database fields.
                            // Therefore, just pick the best SqlNew to call AccessMember on.
                            SqlTypeCase tc = (SqlTypeCase)exp;

                            // Find the best type binding for this member.
                            SqlNew tb = tc.Whens[0].TypeBinding as SqlNew;
                            foreach (SqlTypeCaseWhen when in tc.Whens) {
                                if (when.TypeBinding.NodeType == SqlNodeType.New) {
                                    SqlNew sn = (SqlNew)when.TypeBinding;
                                    if (m.Member.DeclaringType.IsAssignableFrom(sn.ClrType)) {
                                        tb = sn;
                                        break;
                                    }
                                }
                            }
                            return AccessMember(m, tb);
                        }
                    case SqlNodeType.AliasRef: {
                            // convert alias.Member => column
                            SqlAliasRef aref = (SqlAliasRef)exp;
                            // if its a table, find the matching column
                            SqlTable tab = aref.Alias.Node as SqlTable;
                            if (tab != null) {
                                MetaDataMember mm = GetRequiredInheritanceDataMember(tab.RowType, m.Member);
                                System.Diagnostics.Debug.Assert(mm != null);
                                string name = mm.MappedName;
                                SqlColumn c = tab.Find(name);
                                if (c == null) {
                                    ProviderType sqlType = sql.Default(mm);
                                    c = new SqlColumn(m.ClrType, sqlType, name, mm, null, m.SourceExpression);
                                    c.Alias = aref.Alias;
                                    tab.Columns.Add(c);
                                }
                                return new SqlColumnRef(c);
                            }
                            // if it is a table valued function, find the matching result column                                
                            SqlTableValuedFunctionCall fc = aref.Alias.Node as SqlTableValuedFunctionCall;
                            if (fc != null) {
                                MetaDataMember mm = GetRequiredInheritanceDataMember(fc.RowType, m.Member);
                                System.Diagnostics.Debug.Assert(mm != null);
                                string name = mm.MappedName;
                                SqlColumn c = fc.Find(name);
                                if (c == null) {
                                    ProviderType sqlType = sql.Default(mm);
                                    c = new SqlColumn(m.ClrType, sqlType, name, mm, null, m.SourceExpression);
                                    c.Alias = aref.Alias;
                                    fc.Columns.Add(c);
                                }
                                return new SqlColumnRef(c);
                            }
                            break;
                        }
                    case SqlNodeType.OptionalValue:
                        // convert option(exp).Member => exp.Member
                        return this.AccessMember(m, ((SqlOptionalValue)exp).Value);

                    case SqlNodeType.OuterJoinedValue: {
                            SqlNode n = this.AccessMember(m, ((SqlUnary)exp).Operand);
                            SqlExpression e = n as SqlExpression;
                            if (e != null) return sql.Unary(SqlNodeType.OuterJoinedValue, e);
                            return n;
                        }

                    case SqlNodeType.Lift:
                        return this.AccessMember(m, ((SqlLift)exp).Expression);

                    case SqlNodeType.UserRow: {
                            // convert UserRow.Member => UserColumn
                            SqlUserRow row = (SqlUserRow)exp;
                            SqlUserQuery suq = row.Query;
                            MetaDataMember mm = GetRequiredInheritanceDataMember(row.RowType, m.Member);
                            System.Diagnostics.Debug.Assert(mm != null);
                            string name = mm.MappedName;
                            SqlUserColumn c = suq.Find(name);
                            if (c == null) {
                                ProviderType sqlType = sql.Default(mm);
                                c = new SqlUserColumn(m.ClrType, sqlType, suq, name, mm.IsPrimaryKey, m.SourceExpression);
                                suq.Columns.Add(c);
                            }
                            return c;
                        }
                    case SqlNodeType.New: {
                            // convert (new {Member = expr}).Member => expr
                            SqlNew sn = (SqlNew)exp;
                            SqlExpression e = sn.Find(m.Member);
                            if (e != null) {
                                return e;
                            }
                            MetaDataMember mm = sn.MetaType.PersistentDataMembers.FirstOrDefault(p => p.Member == m.Member);
                            if (!sn.SqlType.CanBeColumn && mm != null) {
                                throw Error.MemberNotPartOfProjection(m.Member.DeclaringType, m.Member.Name);
                            }
                            break;
                        }
                    case SqlNodeType.Element:
                    case SqlNodeType.ScalarSubSelect: {
                            // convert Scalar/Element(select exp).Member => Scalar/Element(select exp.Member) / select exp.Member
                            SqlSubSelect sub = (SqlSubSelect)exp;
                            SqlAlias alias = new SqlAlias(sub.Select);
                            SqlAliasRef aref = new SqlAliasRef(alias);

                            SqlSelect saveSelect = this.currentSelect;
                            try {
                                SqlSelect newSelect = new SqlSelect(aref, alias, sub.SourceExpression);
                                this.currentSelect = newSelect;
                                SqlNode result = this.Visit(sql.Member(aref, m.Member));

                                SqlExpression rexp = result as SqlExpression;
                                if (rexp != null) {

                                    // If the expression is still a Member after being visited, but it cannot be a column, then it cannot be collapsed
                                    // into the SubSelect because we need to keep track of the fact that this member has to be accessed on the client.
                                    // This must be done after the expression has been Visited above, because otherwise we don't have
                                    // enough context to know if the member can be a column or not.
                                    if (rexp.NodeType == SqlNodeType.Member && !SqlColumnizer.CanBeColumn(rexp)) {
                                        // If the original member expression is an Element, optimize it by converting to an OuterApply if possible.
                                        // We have to do this here because we are creating a new member expression based on it, and there are no
                                        // subsequent visitors that will do this optimization.
                                        if (this.canUseOuterApply && exp.NodeType == SqlNodeType.Element && this.currentSelect != null) {
                                            // Reset the currentSelect since we are not going to use the previous SqlSelect that was created
                                            this.currentSelect = saveSelect;                                            
                                            this.currentSelect.From = sql.MakeJoin(SqlJoinType.OuterApply, this.currentSelect.From, alias, null, sub.SourceExpression);
                                            exp = this.VisitExpression(aref);
                                        }                                        
                                        return sql.Member(exp, m.Member);
                                    }

                                    // Since we are going to make a SubSelect out of this member expression, we need to make
                                    // sure it gets columnized before it gets to the PostBindDotNetConverter, otherwise only the
                                    // entire SubSelect will be columnized as a whole. Subsequent columnization does not know how to handle
                                    // any function calls that may be produced by the PostBindDotNetConverter, but we know how to handle it here.
                                    newSelect.Selection = rexp;
                                    newSelect.Selection = this.columnizer.ColumnizeSelection(newSelect.Selection);
                                    newSelect.Selection = this.ConvertLinks(newSelect.Selection);
                                    SqlNodeType subType = (rexp is SqlTypeCase || !rexp.SqlType.CanBeColumn) ? SqlNodeType.Element : SqlNodeType.ScalarSubSelect;
                                    SqlSubSelect subSel = sql.SubSelect(subType, newSelect);
                                    return this.FoldSubquery(subSel);
                                }

                                SqlSelect rselect = result as SqlSelect;
                                if (rselect != null) {
                                    SqlAlias ralias = new SqlAlias(rselect);
                                    SqlAliasRef rref = new SqlAliasRef(ralias);
                                    newSelect.Selection = this.ConvertLinks(this.VisitExpression(rref));
                                    newSelect.From = new SqlJoin(SqlJoinType.CrossApply, alias, ralias, null, m.SourceExpression);
                                    return newSelect;
                                }
                                throw Error.UnexpectedNode(result.NodeType);
                            }
                            finally {
                                this.currentSelect = saveSelect;
                            }
                        }
                    case SqlNodeType.Value: {
                            SqlValue val = (SqlValue)exp;
                            if (val.Value == null) {
                                return sql.Value(m.ClrType, m.SqlType, null, val.IsClientSpecified, m.SourceExpression);
                            }
                            else if (m.Member is PropertyInfo) {
                                PropertyInfo p = (PropertyInfo)m.Member;
                                return sql.Value(m.ClrType, m.SqlType, p.GetValue(val.Value, null), val.IsClientSpecified, m.SourceExpression);
                            }
                            else {
                                FieldInfo f = (FieldInfo)m.Member;
                                return sql.Value(m.ClrType, m.SqlType, f.GetValue(val.Value), val.IsClientSpecified, m.SourceExpression);
                            }
                        }
                    case SqlNodeType.Grouping: {
                            SqlGrouping g = ((SqlGrouping)exp);
                            if (m.Member.Name == "Key") {
                                return g.Key;
                            }
                            break;
                        }
                    case SqlNodeType.ClientParameter: {
                            SqlClientParameter cp = (SqlClientParameter)exp;
                            // create new accessor including this member access
                            LambdaExpression accessor =
                                Expression.Lambda(
                                    typeof(Func<,>).MakeGenericType(typeof(object[]), m.ClrType),
                                    Expression.MakeMemberAccess(cp.Accessor.Body, m.Member),
                                    cp.Accessor.Parameters
                                    );
                            return new SqlClientParameter(m.ClrType, m.SqlType, accessor, cp.SourceExpression);
                        }
                    default:
                        break;  
                }
                if (m.Expression == exp) {
                    return m;
                }
                else {
                    return sql.Member(exp, m.Member);
                }
            }
예제 #52
0
 internal override SqlAlias VisitAlias(SqlAlias alias) {
     bool isSelect = alias.Node is SqlSelect;
     int saveDepth = this.depth;
     string aliasName = null;
     string name = "";
     SqlTable table = alias.Node as SqlTable;
     if (table != null) {
         name = table.Name;
     }
     if (alias.Name == null) {
         if (!this.names.TryGetValue(alias, out aliasName)) {
             aliasName = "A" + this.names.Count;
             this.names[alias] = aliasName;
         }
     } else {
         aliasName = alias.Name;
     }
     if (isSelect) {
         this.depth++;
         sb.Append("(");
         this.NewLine();
     }
     this.Visit(alias.Node);
     if (isSelect) {
         this.NewLine();
         sb.Append(")");
         this.depth = saveDepth;
     }
     if (!this.suppressedAliases.Contains(alias) && aliasName != null && name != aliasName) {
         sb.Append(" AS ");
         this.WriteName(aliasName);
     }
     return alias;
 }
예제 #53
0
 private SqlSelect CoerceToSequence(SqlNode node) {
     SqlSelect select = node as SqlSelect;
     if (select == null) {
         if (node.NodeType == SqlNodeType.Value) {
             SqlValue sv = (SqlValue)node;
             // Check for ITables.
             ITable t = sv.Value as ITable;
             if (t != null) {
                 return this.CoerceToSequence(this.TranslateConstantTable(t, null));
             }
             // Check for IQueryable.
             IQueryable query = sv.Value as IQueryable;
             if (query != null) {
                 Expression fex = Funcletizer.Funcletize(query.Expression);
                 // IQueryables that return self-referencing Constant expressions cause infinite recursion
                 if (fex.NodeType != ExpressionType.Constant ||
                     ((ConstantExpression)fex).Value != query) {
                     return this.VisitSequence(fex);
                 }
                 throw Error.IQueryableCannotReturnSelfReferencingConstantExpression();
             }
             throw Error.CapturedValuesCannotBeSequences();
         }
         else if (node.NodeType == SqlNodeType.Multiset || node.NodeType == SqlNodeType.Element) {
             return ((SqlSubSelect)node).Select;
         }
         else if (node.NodeType == SqlNodeType.ClientArray) {
             throw Error.ConstructedArraysNotSupported();
         }
         else if (node.NodeType == SqlNodeType.ClientParameter) {
             throw Error.ParametersCannotBeSequences();
         }
         // this needs to be a sequence expression!
         SqlExpression sqlExpr = (SqlExpression)node;
         SqlAlias sa = new SqlAlias(sqlExpr);
         SqlAliasRef aref = new SqlAliasRef(sa);
         return new SqlSelect(aref, sa, this.dominatingExpression);
     }
     return select;
 }
예제 #54
0
        private SqlSelect VisitOrderBy(Expression sequence, LambdaExpression expression, SqlOrderType orderType) {
            if (IsGrouping(expression.Body.Type)) {
                throw Error.GroupingNotSupportedAsOrderCriterion();
            }
            if (!this.typeProvider.From(expression.Body.Type).IsOrderable) {
                throw Error.TypeCannotBeOrdered(expression.Body.Type);
            }

            SqlSelect select = this.LockSelect(this.VisitSequence(sequence));

            if (select.Selection.NodeType != SqlNodeType.AliasRef || select.OrderBy.Count > 0) {
                SqlAlias alias = new SqlAlias(select);
                SqlAliasRef aref = new SqlAliasRef(alias);
                select = new SqlSelect(aref, alias, this.dominatingExpression);
            }

            this.map[expression.Parameters[0]] = (SqlAliasRef)select.Selection;
            SqlExpression expr = this.VisitExpression(expression.Body);

            select.OrderBy.Add(new SqlOrderExpression(orderType, expr));
            return select;
        }
예제 #55
0
        private SqlSelect VisitSelect(Expression sequence, LambdaExpression selector) {
            SqlSelect source = this.VisitSequence(sequence);
            SqlAlias alias = new SqlAlias(source);
            SqlAliasRef aref = new SqlAliasRef(alias);

            this.map[selector.Parameters[0]] = aref;
            SqlNode project = this.Visit(selector.Body);

            SqlSelect pselect = project as SqlSelect;
            if (pselect != null) {
                return new SqlSelect(sql.SubSelect(SqlNodeType.Multiset, pselect, selector.Body.Type), alias, this.dominatingExpression);
            }
            else if ((project.NodeType == SqlNodeType.Element || project.NodeType == SqlNodeType.ScalarSubSelect) &&
                     (this.converterStrategy & ConverterStrategy.CanUseOuterApply) != 0) {
                SqlSubSelect sub = (SqlSubSelect)project;
                SqlSelect inner = sub.Select;
                SqlAlias innerAlias = new SqlAlias(inner);
                SqlAliasRef innerRef = new SqlAliasRef(innerAlias);
                if (project.NodeType == SqlNodeType.Element) {
                    inner.Selection = new SqlOptionalValue(
                        new SqlColumn(
                            "test",
                            sql.Unary(
                                SqlNodeType.OuterJoinedValue,
                                sql.Value(typeof(int?), this.typeProvider.From(typeof(int)), 1, false, this.dominatingExpression)
                                )
                            ),
                            sql.Unary(SqlNodeType.OuterJoinedValue, inner.Selection)
                        );
                }
                else {
                    inner.Selection = sql.Unary(SqlNodeType.OuterJoinedValue, inner.Selection);
                }
                SqlJoin join = new SqlJoin(SqlJoinType.OuterApply, alias, innerAlias, null, this.dominatingExpression);
                return new SqlSelect(innerRef, join, this.dominatingExpression);
            }
            else {
                SqlExpression expr = project as SqlExpression;
                if (expr != null) {
                    return new SqlSelect(expr, alias, this.dominatingExpression);
                }
                else {
                    throw Error.BadProjectionInSelect();
                }
            }
        }
예제 #56
0
        private SqlSelect VisitSelectMany(Expression sequence, LambdaExpression colSelector, LambdaExpression resultSelector) {
            SqlSelect seqSelect = this.VisitSequence(sequence);
            SqlAlias seqAlias = new SqlAlias(seqSelect);
            SqlAliasRef seqRef = new SqlAliasRef(seqAlias);

            this.map[colSelector.Parameters[0]] = seqRef;

            SqlNode colSelectorNode = this.VisitSequence(colSelector.Body);
            SqlAlias selAlias = new SqlAlias(colSelectorNode);
            SqlAliasRef selRef = new SqlAliasRef(selAlias);
            SqlJoin join = new SqlJoin(SqlJoinType.CrossApply, seqAlias, selAlias, null, this.dominatingExpression);

            SqlExpression projection = selRef;

            if (resultSelector != null) {
                this.map[resultSelector.Parameters[0]] = seqRef;
                this.map[resultSelector.Parameters[1]] = selRef;
                projection = this.VisitExpression(resultSelector.Body);
            }

            return new SqlSelect(projection, join, this.dominatingExpression);
        }
예제 #57
0
 internal override SqlAlias VisitAlias(SqlAlias a) {
     SqlAlias save = this.currentAlias;
     this.currentAlias = a;
     base.VisitAlias(a);
     this.currentAlias = save;
     return a;
 }
예제 #58
0
        private SqlSelect VisitJoin(Expression outerSequence, Expression innerSequence, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector, LambdaExpression resultSelector) {
            SqlSelect outerSelect = this.VisitSequence(outerSequence);
            SqlSelect innerSelect = this.VisitSequence(innerSequence);

            SqlAlias outerAlias = new SqlAlias(outerSelect);
            SqlAliasRef outerRef = new SqlAliasRef(outerAlias);
            SqlAlias innerAlias = new SqlAlias(innerSelect);
            SqlAliasRef innerRef = new SqlAliasRef(innerAlias);

            this.map[outerKeySelector.Parameters[0]] = outerRef;
            SqlExpression outerKey = this.VisitExpression(outerKeySelector.Body);

            this.map[innerKeySelector.Parameters[0]] = innerRef;
            SqlExpression innerKey = this.VisitExpression(innerKeySelector.Body);

            this.map[resultSelector.Parameters[0]] = outerRef;
            this.map[resultSelector.Parameters[1]] = innerRef;
            SqlExpression result = this.VisitExpression(resultSelector.Body);

            SqlExpression condition = sql.Binary(SqlNodeType.EQ, outerKey, innerKey);
            SqlSelect select = null;
            if ((this.converterStrategy & ConverterStrategy.CanUseJoinOn) != 0) {
                SqlJoin join = new SqlJoin(SqlJoinType.Inner, outerAlias, innerAlias, condition, this.dominatingExpression);
                select = new SqlSelect(result, join, this.dominatingExpression);
            } else {
                SqlJoin join = new SqlJoin(SqlJoinType.Cross, outerAlias, innerAlias, null, this.dominatingExpression);
                select = new SqlSelect(result, join, this.dominatingExpression);
                select.Where = condition;
            }
            return select;
        }
예제 #59
0
 private void WriteAliasName(SqlAlias alias) {
     string aliasName = null;
     if (alias.Name == null) {
         if (!this.names.TryGetValue(alias, out aliasName)) {
             aliasName = "A" + this.names.Count;
             this.names[alias] = aliasName;
         }
     }
     else {
         aliasName = alias.Name;
     }
     this.WriteName(aliasName);
 }
예제 #60
0
        private SqlSelect GenerateSkipTake(SqlSelect sequence, SqlExpression skipExp, SqlExpression takeExp) {
            SqlSelect select = this.LockSelect(sequence);

            // no skip?
            if (skipExp == null) {
                if (takeExp != null) {
                    select.Top = takeExp;
                }
                return select;
            }

            SqlAlias alias = new SqlAlias(select);
            SqlAliasRef aref = new SqlAliasRef(alias);

            if (this.UseConverterStrategy(ConverterStrategy.SkipWithRowNumber)) {
                // use ROW_NUMBER() (preferred)
                SqlColumn rowNumber = new SqlColumn("ROW_NUMBER", sql.RowNumber(new List<SqlOrderExpression>(), this.dominatingExpression));
                SqlColumnRef rowNumberRef = new SqlColumnRef(rowNumber);

                select.Row.Columns.Add(rowNumber);

                SqlSelect final = new SqlSelect(aref, alias, this.dominatingExpression);

                if (takeExp != null) {
                    // use BETWEEN for skip+take combo (much faster)
                    final.Where = sql.Between(
                        rowNumberRef,
                        sql.Add(skipExp, 1),
                        sql.Binary(SqlNodeType.Add, (SqlExpression)SqlDuplicator.Copy(skipExp), takeExp),
                        this.dominatingExpression
                        );
                }
                else {
                    final.Where = sql.Binary(SqlNodeType.GT, rowNumberRef, skipExp);
                }

                return final;
            }
            else {
                // Ensure that the sequence contains elements that can be skipped
                if (!CanSkipOnSelection(select.Selection)) {
                    throw Error.SkipNotSupportedForSequenceTypes();
                }            

                // use NOT EXISTS

                // Supported cases:
                //  - Entities
                //  - Projections that contain all PK columns
                //
                // .. where there sequence can be traced back to a:
                //  - Single-table query
                //  - Distinct
                //  - Except
                //  - Intersect
                //  - Union, where union.All == false

                // Not supported: joins

                // Sequence should also be ordered, but we can't test for it at this 
                // point in processing, and we won't know that we need to test it, later.

                SingleTableQueryVisitor stqv = new SingleTableQueryVisitor();
                stqv.Visit(select);
                if (!stqv.IsValid) {
                    throw Error.SkipRequiresSingleTableQueryWithPKs();
                }

                SqlSelect dupsel = (SqlSelect)SqlDuplicator.Copy(select);               
                dupsel.Top = skipExp;

                SqlAlias dupAlias = new SqlAlias(dupsel);
                SqlAliasRef dupRef = new SqlAliasRef(dupAlias);

                SqlSelect eqsel = new SqlSelect(dupRef, dupAlias, this.dominatingExpression);
                eqsel.Where = sql.Binary(SqlNodeType.EQ2V, aref, dupRef);
                SqlSubSelect ss = sql.SubSelect(SqlNodeType.Exists, eqsel);

                SqlSelect final = new SqlSelect(aref, alias, this.dominatingExpression);
                final.Where = sql.Unary(SqlNodeType.Not, ss, this.dominatingExpression);
                final.Top = takeExp;

                return final;
            }
        }