Ejemplo n.º 1
0
        private void GatherUnionExpressions(SqlNode node, List <SqlExpression> exprs)
        {
            SqlUnion union = node as SqlUnion;

            if (union != null)
            {
                this.GatherUnionExpressions(union.Left, exprs);
                this.GatherUnionExpressions(union.Right, exprs);
            }
            else
            {
                SqlSelect sel = node as SqlSelect;
                if (sel != null)
                {
                    SqlAliasRef aref = sel.Selection as SqlAliasRef;
                    if (aref != null)
                    {
                        this.GatherUnionExpressions(aref.Alias.Node, exprs);
                    }
                    else
                    {
                        exprs.Add(sel.Selection);
                    }
                }
            }
        }
Ejemplo n.º 2
0
        internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
        {
            SqlNode node = aref.Alias.Node;

            if (node is SqlTable || node is SqlTableValuedFunctionCall)
            {
                return(aref);
            }
            SqlUnion union = node as SqlUnion;

            if (union != null)
            {
                return(this.ExpandUnion(union));
            }
            SqlSelect ss = node as SqlSelect;

            if (ss != null)
            {
                return(this.VisitExpression(ss.Selection));
            }
            SqlExpression exp = node as SqlExpression;

            if (exp != null)
            {
                return(this.VisitExpression(exp));
            }
            throw Error.CouldNotHandleAliasRef(node.NodeType);
        }
Ejemplo n.º 3
0
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
 {
     if (this.ingoreExternalRefs && !this.nodeMap.ContainsKey(aref.Alias))
     {
         return(aref);
     }
     return(new SqlAliasRef((SqlAlias)this.Visit(aref.Alias)));
 }
Ejemplo n.º 4
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);
        }
Ejemplo n.º 5
0
        internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
        {
            SqlAlias alias = aref.Alias;
            SqlAlias value;

            if (_removedMap.TryGetValue(alias, out value))
            {
                throw Error.InvalidReferenceToRemovedAliasDuringDeflation();
            }
            return(aref);
        }
Ejemplo n.º 6
0
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
 {
     if ((UnwrapSequences != null) && UnwrapSequences.Unwrap)
     {
         UnwrapSequences = new UnwrapStack(UnwrapSequences, false);
         VisitAlias(aref.Alias);
         UnwrapSequences = UnwrapSequences.Last;
         return(aref);
     }
     VisitAlias(aref.Alias);
     return(aref);
 }
Ejemplo n.º 7
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);
        }
Ejemplo n.º 9
0
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
 {
     if (this.UnwrapSequences != null && this.UnwrapSequences.Unwrap)
     {
         this.UnwrapSequences = new UnwrapStack(this.UnwrapSequences, false);
         this.VisitAlias(aref.Alias);
         this.UnwrapSequences = this.UnwrapSequences.Last;
     }
     else
     {
         this.VisitAlias(aref.Alias);
     }
     return(aref);
 }
Ejemplo n.º 10
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));
        }
Ejemplo n.º 11
0
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
     SqlNode node = aref.Alias.Node;
     if (node is SqlTable || node is SqlTableValuedFunctionCall) {
         return aref;
     }
     SqlUnion union = node as SqlUnion;
     if (union != null) {
         return this.ExpandUnion(union);
     }
     SqlSelect ss = node as SqlSelect;
     if (ss != null) {
         return this.VisitExpression(ss.Selection);
     }
     SqlExpression exp = node as SqlExpression;
     if (exp != null)
         return this.VisitExpression(exp);
     throw Error.CouldNotHandleAliasRef(node.NodeType);
 }
Ejemplo n.º 12
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;
        }
Ejemplo n.º 13
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;
 }
Ejemplo n.º 14
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;
        }
Ejemplo n.º 15
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;
            }
        }
Ejemplo n.º 16
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;
        }
Ejemplo n.º 17
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);
 }
Ejemplo n.º 18
0
        protected override SqlSelect GenerateSkipTake(SqlSelect sequence, SqlExpression skipExp, SqlExpression takeExp)
        {
            if (skipExp == null)
            {
                return(base.GenerateSkipTake(sequence, skipExp, takeExp));
            }
            Debug.Assert(skipExp != null);

            var skipCount = (int)((SqlValue)skipExp).Value;

            var alias     = new SqlAlias(sequence);
            var selection = new SqlAliasRef(alias);
            var select    = new SqlSelect(selection, alias, dominatingExpression);

            if (takeExp == null)
            {
                return(base.GenerateSkipTake(sequence, skipExp, takeExp));
            }

            var type = sequence.SourceExpression.Type;

            if (type.IsGenericType)
            {
                var args = type.GetGenericArguments();
                if (args.Length == 1)
                {
                    var mappingTable = Services.Model.GetTable(args[0]);
                    if (mappingTable != null)
                    {
                        return(base.GenerateSkipTake(sequence, skipExp, takeExp));
                    }
                }
            }

            var takeCount = (int)((SqlValue)takeExp).Value;

            select.Top = sql.Value(typeof(int), typeProvider.From(typeof(int)), takeCount, false,
                                   dominatingExpression);
            sequence.Top = sql.Value(typeof(int), typeProvider.From(typeof(int)), takeCount + skipCount, false,
                                     dominatingExpression);
            var finder  = new OrderByFinder();
            var orderby = finder.GetOrderBy(sequence);

            foreach (var item in orderby)
            {
                if (item.OrderType == SqlOrderType.Descending)
                {
                    select.OrderBy.Add(new SqlOrderExpression(SqlOrderType.Ascending, orderby[0].Expression));
                }
                else
                {
                    select.OrderBy.Add(new SqlOrderExpression(SqlOrderType.Descending, orderby[0].Expression));
                }
            }
            alias     = new SqlAlias(select);
            selection = new SqlAliasRef(alias);
            select    = new SqlSelect(selection, alias, dominatingExpression);
            foreach (var item in orderby)
            {
                select.OrderBy.Add(new SqlOrderExpression(item.OrderType, item.Expression));
            }
            return(select);
        }
Ejemplo n.º 19
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);
        }
Ejemplo n.º 20
0
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
     if (this.ingoreExternalRefs && !this.nodeMap.ContainsKey(aref.Alias)) {
         return aref;
     }
     return new SqlAliasRef((SqlAlias)this.Visit(aref.Alias));
 }
Ejemplo n.º 21
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;
 }
Ejemplo n.º 22
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);
        }
Ejemplo n.º 23
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;
            }
        }
Ejemplo n.º 24
0
 internal virtual SqlExpression VisitAliasRef(SqlAliasRef aref) {
     return aref;
 }
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
     throw Error.UnexpectedNode(aref.NodeType);
 }
Ejemplo n.º 26
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;
        }
Ejemplo n.º 27
0
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
 {
     throw Error.UnexpectedNode(aref.NodeType);
 }
Ejemplo n.º 28
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);
            }
        }
Ejemplo n.º 29
0
        internal SqlExpression TranslateEquals(SqlBinary expr)
        {
            System.Diagnostics.Debug.Assert(
                expr.NodeType == SqlNodeType.EQ || expr.NodeType == SqlNodeType.NE ||
                expr.NodeType == SqlNodeType.EQ2V || expr.NodeType == SqlNodeType.NE2V);
            SqlExpression eLeft  = expr.Left;
            SqlExpression eRight = expr.Right;

            if (eRight.NodeType == SqlNodeType.Element)
            {
                SqlSubSelect sub    = (SqlSubSelect)eRight;
                SqlAlias     alias  = new SqlAlias(sub.Select);
                SqlAliasRef  aref   = new SqlAliasRef(alias);
                SqlSelect    select = new SqlSelect(aref, alias, expr.SourceExpression);
                select.Where = sql.Binary(expr.NodeType, sql.DoNotVisitExpression(eLeft), aref);
                return(sql.SubSelect(SqlNodeType.Exists, select));
            }
            else if (eLeft.NodeType == SqlNodeType.Element)
            {
                SqlSubSelect sub    = (SqlSubSelect)eLeft;
                SqlAlias     alias  = new SqlAlias(sub.Select);
                SqlAliasRef  aref   = new SqlAliasRef(alias);
                SqlSelect    select = new SqlSelect(aref, alias, expr.SourceExpression);
                select.Where = sql.Binary(expr.NodeType, sql.DoNotVisitExpression(eRight), aref);
                return(sql.SubSelect(SqlNodeType.Exists, select));
            }

            MetaType mtLeft  = TypeSource.GetSourceMetaType(eLeft, this.services.Model);
            MetaType mtRight = TypeSource.GetSourceMetaType(eRight, this.services.Model);

            if (eLeft.NodeType == SqlNodeType.TypeCase)
            {
                eLeft = BestIdentityNode((SqlTypeCase)eLeft);
            }
            if (eRight.NodeType == SqlNodeType.TypeCase)
            {
                eRight = BestIdentityNode((SqlTypeCase)eRight);
            }

            if (mtLeft.IsEntity && mtRight.IsEntity && mtLeft.Table != mtRight.Table)
            {
                throw Error.CannotCompareItemsAssociatedWithDifferentTable();
            }

            // do simple or no translation for non-structural types
            if (!mtLeft.IsEntity && !mtRight.IsEntity &&
                (eLeft.NodeType != SqlNodeType.New || eLeft.SqlType.CanBeColumn) &&
                (eRight.NodeType != SqlNodeType.New || eRight.SqlType.CanBeColumn))
            {
                if (expr.NodeType == SqlNodeType.EQ2V || expr.NodeType == SqlNodeType.NE2V)
                {
                    return(this.TranslateEqualsOp(expr.NodeType, sql.DoNotVisitExpression(expr.Left), sql.DoNotVisitExpression(expr.Right), false));
                }
                return(expr);
            }

            // If the two types are not comparable, we return the predicate "1=0".
            if ((mtLeft != mtRight) && (mtLeft.InheritanceRoot != mtRight.InheritanceRoot))
            {
                return(sql.Binary(SqlNodeType.EQ, sql.ValueFromObject(0, expr.SourceExpression), sql.ValueFromObject(1, expr.SourceExpression)));
            }

            List <SqlExpression> exprs1;
            List <SqlExpression> exprs2;

            SqlLink link1 = eLeft as SqlLink;

            if (link1 != null && link1.Member.IsAssociation && link1.Member.Association.IsForeignKey)
            {
                exprs1 = link1.KeyExpressions;
            }
            else
            {
                exprs1 = this.GetIdentityExpressions(mtLeft, sql.DoNotVisitExpression(eLeft));
            }

            SqlLink link2 = eRight as SqlLink;

            if (link2 != null && link2.Member.IsAssociation && link2.Member.Association.IsForeignKey)
            {
                exprs2 = link2.KeyExpressions;
            }
            else
            {
                exprs2 = this.GetIdentityExpressions(mtRight, sql.DoNotVisitExpression(eRight));
            }

            System.Diagnostics.Debug.Assert(exprs1.Count > 0);
            System.Diagnostics.Debug.Assert(exprs2.Count > 0);
            System.Diagnostics.Debug.Assert(exprs1.Count == exprs2.Count);

            SqlExpression exp    = null;
            SqlNodeType   eqKind = (expr.NodeType == SqlNodeType.EQ2V || expr.NodeType == SqlNodeType.NE2V) ? SqlNodeType.EQ2V : SqlNodeType.EQ;

            for (int i = 0, n = exprs1.Count; i < n; i++)
            {
                SqlExpression eq = this.TranslateEqualsOp(eqKind, exprs1[i], exprs2[i], !mtLeft.IsEntity);
                if (exp == null)
                {
                    exp = eq;
                }
                else
                {
                    exp = sql.Binary(SqlNodeType.And, exp, eq);
                }
            }
            if (expr.NodeType == SqlNodeType.NE || expr.NodeType == SqlNodeType.NE2V)
            {
                exp = sql.Unary(SqlNodeType.Not, exp, exp.SourceExpression);
            }
            return(exp);
        }
Ejemplo n.º 30
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);
     }
 }
Ejemplo n.º 31
0
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
     SqlAlias alias = aref.Alias;
     SqlAlias value;
     if (this.removedMap.TryGetValue(alias, out value)) {
         throw Error.InvalidReferenceToRemovedAliasDuringDeflation();
     }
     return aref;
 }
Ejemplo n.º 32
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;
 }
Ejemplo n.º 33
0
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
     return this.ExpandExpression(aref);
 }
Ejemplo n.º 34
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();
                }
            }
        }
Ejemplo n.º 35
0
            internal SqlExpression ConvertToFetchedExpression(SqlNode node) {
                if (node == null) {
                    return null;
                }
                switch (node.NodeType) {
                    case SqlNodeType.OuterJoinedValue: {
                            SqlExpression o = ((SqlUnary)node).Operand;
                            SqlExpression e = this.ConvertLinks(o);
                            if (e == o) {
                                return (SqlExpression)node;
                            }
                            return e;
                        }
                    case SqlNodeType.ClientCase: {
                            // Need to recurse in case the object case has links.
                            SqlClientCase cc = (SqlClientCase)node;
                            List<SqlNode> fetchedValues = new List<SqlNode>();
                            bool allExprs = true;
                            foreach (SqlClientWhen when in cc.Whens) {
                                SqlNode fetchedValue = ConvertToFetchedExpression(when.Value);
                                allExprs = allExprs && (fetchedValue is SqlExpression);
                                fetchedValues.Add(fetchedValue);
                            }

                            if (allExprs) {
                                // All WHEN values are simple expressions (no sequences). 
                                List<SqlExpression> matches = new List<SqlExpression>();
                                List<SqlExpression> values = new List<SqlExpression>();
                                for (int i = 0, c = fetchedValues.Count; i < c; ++i) {
                                    SqlExpression fetchedValue = (SqlExpression)fetchedValues[i];
                                    if (!cc.ClrType.IsAssignableFrom(fetchedValue.ClrType)) {
                                        throw Error.DidNotExpectTypeChange(cc.ClrType, fetchedValue.ClrType);
                                    }
                                    matches.Add(cc.Whens[i].Match);
                                    values.Add(fetchedValue);
                                }
                                node = sql.Case(cc.ClrType, cc.Expression, matches, values, cc.SourceExpression);
                            }
                            else {
                                node = SimulateCaseOfSequences(cc, fetchedValues);
                            }
                            break;
                        }
                    case SqlNodeType.TypeCase: {
                            SqlTypeCase tc = (SqlTypeCase)node;
                            List<SqlNode> fetchedValues = new List<SqlNode>();
                            foreach (SqlTypeCaseWhen when in tc.Whens) {
                                SqlNode fetchedValue = ConvertToFetchedExpression(when.TypeBinding);
                                fetchedValues.Add(fetchedValue);
                            }

                            for (int i = 0, c = fetchedValues.Count; i < c; ++i) {
                                SqlExpression fetchedValue = (SqlExpression)fetchedValues[i];
                                tc.Whens[i].TypeBinding = fetchedValue;
                            }
                            break;
                        }
                    case SqlNodeType.SearchedCase: {
                            SqlSearchedCase sc = (SqlSearchedCase)node;
                            foreach (SqlWhen when in sc.Whens) {
                                when.Match = this.ConvertToFetchedExpression(when.Match);
                                when.Value = this.ConvertToFetchedExpression(when.Value);
                            }
                            sc.Else = this.ConvertToFetchedExpression(sc.Else);
                            break;
                        }
                    case SqlNodeType.Link: {
                            SqlLink link = (SqlLink)node;

                            if (link.Expansion != null) {
                                return this.VisitLinkExpansion(link);
                            }

                            SqlExpression cached;
                            if (this.linkMap.TryGetValue(link.Id, out cached)) {
                                return this.VisitExpression(cached);
                            }

                            // translate link into expanded form
                            node = this.translator.TranslateLink(link, true);

                            // New nodes may have been produced because of Subquery.
                            // Prebind again for method-call and static treat handling.
                            node = binder.Prebind(node);

                            // Make it an expression.
                            node = this.ConvertToExpression(node);

                            // bind the translation
                            node = this.Visit(node);

                            // Check for element node, rewrite as sql apply.
                            if (this.currentSelect != null 
                                && node != null 
                                && node.NodeType == SqlNodeType.Element 
                                && link.Member.IsAssociation
                                && this.binder.OptimizeLinkExpansions
                                ) {
                                // if link in a non-nullable foreign key association then inner-join is okay to use (since it must always exist)
                                // otherwise use left-outer-join 
                                SqlJoinType joinType = (link.Member.Association.IsForeignKey && !link.Member.Association.IsNullable)
                                    ? SqlJoinType.Inner : SqlJoinType.LeftOuter;
                                SqlSubSelect ss = (SqlSubSelect)node;
                                SqlExpression where = ss.Select.Where;
                                ss.Select.Where = null;
                                // form cross apply 
                                SqlAlias sa = new SqlAlias(ss.Select);
                                if (joinType == SqlJoinType.Inner && this.IsOuterDependent(this.currentSelect.From, sa, where))
                                {
                                    joinType = SqlJoinType.LeftOuter;
                                }
                                this.currentSelect.From = sql.MakeJoin(joinType, this.currentSelect.From, sa, where, ss.SourceExpression);
                                SqlExpression result = new SqlAliasRef(sa);
                                this.linkMap.Add(link.Id, result);
                                return this.VisitExpression(result);
                            }
                        }
                        break;
                }
                return (SqlExpression)node;
            }
Ejemplo n.º 36
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;
        }
Ejemplo n.º 37
0
            /// <summary>
            /// Given a ClientCase and a list of sequence (one for each case), construct a structure
            /// that is equivalent to a CASE of SELECTs. To accomplish this we use UNION ALL and attach
            /// a WHERE clause which will pick the SELECT that matches the discriminator in the Client Case.
            /// </summary>
            private SqlSelect SimulateCaseOfSequences(SqlClientCase clientCase, List<SqlNode> sequences) {
                /*
                   * There are two situations we may be in:
                   * (1) There is exactly one case alternative. 
                   *     Here, no where clause is needed.
                   * (2) There is more than case alternative.
                   *     Here, each WHERE clause needs to be ANDed with [Disc]=D where D
                   *     is the literal discriminanator value.
                   */
                if (sequences.Count == 1) {
                    return (SqlSelect)sequences[0];
                }
                else {
                    SqlNode union = null;
                    SqlSelect sel = null;
                    int elseIndex = clientCase.Whens.Count - 1;
                    int elseCount = clientCase.Whens[elseIndex].Match == null ? 1 : 0;
                    SqlExpression elseFilter = null;
                    for (int i = 0; i < sequences.Count - elseCount; ++i) {
                        sel = (SqlSelect)sequences[i];
                        SqlExpression discriminatorPredicate = sql.Binary(SqlNodeType.EQ, clientCase.Expression, clientCase.Whens[i].Match);
                        sel.Where = sql.AndAccumulate(sel.Where, discriminatorPredicate);
                        elseFilter = sql.AndAccumulate(elseFilter, sql.Binary(SqlNodeType.NE, clientCase.Expression, clientCase.Whens[i].Match));

                        if (union == null) {
                            union = sel;
                        }
                        else {
                            union = new SqlUnion(sel, union, true /* Union All */);
                        }
                    }
                    // Handle 'else' if present.
                    if (elseCount == 1) {
                        sel = (SqlSelect)sequences[elseIndex];
                        sel.Where = sql.AndAccumulate(sel.Where, elseFilter);

                        if (union == null) {
                            union = sel;
                        }
                        else {
                            union = new SqlUnion(sel, union, true /* Union All */);
                        }

                    }
                    SqlAlias alias = new SqlAlias(union);
                    SqlAliasRef aref = new SqlAliasRef(alias);
                    return new SqlSelect(aref, alias, union.SourceExpression);
                }
            }
Ejemplo n.º 38
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);
        }
Ejemplo n.º 39
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);
                }
            }
Ejemplo n.º 40
0
 internal virtual SqlExpression VisitAliasRef(SqlAliasRef aref) {
     return aref;
 }
Ejemplo n.º 41
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;
 }
Ejemplo n.º 42
0
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
     sb.Append("AREF(");
     this.WriteAliasName(aref.Alias);
     sb.Append(")");
     return aref;
 }
Ejemplo n.º 43
0
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
     if (this.UnwrapSequences != null && this.UnwrapSequences.Unwrap) {
         this.UnwrapSequences = new UnwrapStack(this.UnwrapSequences, false);
         this.VisitAlias(aref.Alias);
         this.UnwrapSequences = this.UnwrapSequences.Last;
     } else {
         this.VisitAlias(aref.Alias);
     }
     return aref;
 }