internal override SqlExpression VisitClientCase(SqlClientCase c) { c.Expression = this.VisitExpression(c.Expression); for (int i = 0, n = c.Whens.Count; i < n; i++) { // Don't walk down the match side. This can't be a column. c.Whens[i].Value = this.VisitExpression(c.Whens[i].Value); } return c; }
internal virtual SqlExpression VisitClientCase(SqlClientCase c) { c.Expression = this.VisitExpression(c.Expression); for (int i = 0, n = c.Whens.Count; i < n; i++) { SqlClientWhen when = c.Whens[i]; when.Match = this.VisitExpression(when.Match); when.Value = this.VisitExpression(when.Value); } return c; }
private SqlExpression ExpandTogether(List<SqlExpression> exprs) { switch(exprs[0].NodeType) { case SqlNodeType.MethodCall: { SqlMethodCall[] mcs = new SqlMethodCall[exprs.Count]; for(int i = 0; i < mcs.Length; ++i) { mcs[i] = (SqlMethodCall)exprs[i]; } List<SqlExpression> expandedArgs = new List<SqlExpression>(); for(int i = 0; i < mcs[0].Arguments.Count; ++i) { List<SqlExpression> args = new List<SqlExpression>(); for(int j = 0; j < mcs.Length; ++j) { args.Add(mcs[j].Arguments[i]); } SqlExpression expanded = this.ExpandTogether(args); expandedArgs.Add(expanded); } return factory.MethodCall(mcs[0].Method, mcs[0].Object, expandedArgs.ToArray(), mcs[0].SourceExpression); } case SqlNodeType.ClientCase: { // Are they all the same? SqlClientCase[] scs = new SqlClientCase[exprs.Count]; scs[0] = (SqlClientCase)exprs[0]; for(int i = 1; i < scs.Length; ++i) { scs[i] = (SqlClientCase)exprs[i]; } // Expand expressions together. List<SqlExpression> expressions = new List<SqlExpression>(); for(int i = 0; i < scs.Length; ++i) { expressions.Add(scs[i].Expression); } SqlExpression expression = this.ExpandTogether(expressions); // Expand individual expressions together. List<SqlClientWhen> whens = new List<SqlClientWhen>(); for(int i = 0; i < scs[0].Whens.Count; ++i) { List<SqlExpression> scos = new List<SqlExpression>(); for(int j = 0; j < scs.Length; ++j) { SqlClientWhen when = scs[j].Whens[i]; scos.Add(when.Value); } whens.Add(new SqlClientWhen(scs[0].Whens[i].Match, this.ExpandTogether(scos))); } return new SqlClientCase(scs[0].ClrType, expression, whens, scs[0].SourceExpression); } case SqlNodeType.TypeCase: { // Are they all the same? SqlTypeCase[] tcs = new SqlTypeCase[exprs.Count]; tcs[0] = (SqlTypeCase)exprs[0]; for(int i = 1; i < tcs.Length; ++i) { tcs[i] = (SqlTypeCase)exprs[i]; } // Expand discriminators together. List<SqlExpression> discriminators = new List<SqlExpression>(); for(int i = 0; i < tcs.Length; ++i) { discriminators.Add(tcs[i].Discriminator); } SqlExpression discriminator = this.ExpandTogether(discriminators); // Write expanded discriminators back in. for(int i = 0; i < tcs.Length; ++i) { tcs[i].Discriminator = discriminators[i]; } // Expand individual type bindings together. List<SqlTypeCaseWhen> whens = new List<SqlTypeCaseWhen>(); for(int i = 0; i < tcs[0].Whens.Count; ++i) { List<SqlExpression> scos = new List<SqlExpression>(); for(int j = 0; j < tcs.Length; ++j) { SqlTypeCaseWhen when = tcs[j].Whens[i]; scos.Add(when.TypeBinding); } SqlExpression expanded = this.ExpandTogether(scos); whens.Add(new SqlTypeCaseWhen(tcs[0].Whens[i].Match, expanded)); } return factory.TypeCase(tcs[0].ClrType, tcs[0].RowType, discriminator, whens, tcs[0].SourceExpression); } case SqlNodeType.New: { // first verify all are similar client objects... SqlNew[] cobs = new SqlNew[exprs.Count]; cobs[0] = (SqlNew)exprs[0]; for(int i = 1, n = exprs.Count; i < n; i++) { if(exprs[i] == null || exprs[i].NodeType != SqlNodeType.New) throw Error.UnionIncompatibleConstruction(); cobs[i] = (SqlNew)exprs[1]; if(cobs[i].Members.Count != cobs[0].Members.Count) throw Error.UnionDifferentMembers(); for(int m = 0, mn = cobs[0].Members.Count; m < mn; m++) { if(cobs[i].Members[m].Member != cobs[0].Members[m].Member) { throw Error.UnionDifferentMemberOrder(); } } } SqlMemberAssign[] bindings = new SqlMemberAssign[cobs[0].Members.Count]; for(int m = 0, mn = bindings.Length; m < mn; m++) { List<SqlExpression> mexprs = new List<SqlExpression>(); for(int i = 0, n = exprs.Count; i < n; i++) { mexprs.Add(cobs[i].Members[m].Expression); } bindings[m] = new SqlMemberAssign(cobs[0].Members[m].Member, this.ExpandTogether(mexprs)); for(int i = 0, n = exprs.Count; i < n; i++) { cobs[i].Members[m].Expression = mexprs[i]; } } SqlExpression[] arguments = new SqlExpression[cobs[0].Args.Count]; for(int m = 0, mn = arguments.Length; m < mn; ++m) { List<SqlExpression> mexprs = new List<SqlExpression>(); for(int i = 0, n = exprs.Count; i < n; i++) { mexprs.Add(cobs[i].Args[m]); } arguments[m] = ExpandTogether(mexprs); } return factory.New(cobs[0].MetaType, cobs[0].Constructor, arguments, cobs[0].ArgMembers, bindings, exprs[0].SourceExpression); } case SqlNodeType.Link: { SqlLink[] links = new SqlLink[exprs.Count]; links[0] = (SqlLink)exprs[0]; for(int i = 1, n = exprs.Count; i < n; i++) { if(exprs[i] == null || exprs[i].NodeType != SqlNodeType.Link) throw Error.UnionIncompatibleConstruction(); links[i] = (SqlLink)exprs[i]; if(links[i].KeyExpressions.Count != links[0].KeyExpressions.Count || links[i].Member != links[0].Member || (links[i].Expansion != null) != (links[0].Expansion != null)) throw Error.UnionIncompatibleConstruction(); } SqlExpression[] kexprs = new SqlExpression[links[0].KeyExpressions.Count]; List<SqlExpression> lexprs = new List<SqlExpression>(); for(int k = 0, nk = links[0].KeyExpressions.Count; k < nk; k++) { lexprs.Clear(); for(int i = 0, n = exprs.Count; i < n; i++) { lexprs.Add(links[i].KeyExpressions[k]); } kexprs[k] = this.ExpandTogether(lexprs); for(int i = 0, n = exprs.Count; i < n; i++) { links[i].KeyExpressions[k] = lexprs[i]; } } SqlExpression expansion = null; if(links[0].Expansion != null) { lexprs.Clear(); for(int i = 0, n = exprs.Count; i < n; i++) { lexprs.Add(links[i].Expansion); } expansion = this.ExpandTogether(lexprs); for(int i = 0, n = exprs.Count; i < n; i++) { links[i].Expansion = lexprs[i]; } } return new SqlLink(links[0].Id, links[0].RowType, links[0].ClrType, links[0].SqlType, links[0].Expression, links[0].Member, kexprs, expansion, links[0].SourceExpression); } case SqlNodeType.Value: { /* * ExprSet of all literals of the same value reduce to just a single literal. */ SqlValue val0 = (SqlValue)exprs[0]; for(int i = 1; i < exprs.Count; ++i) { SqlValue val = (SqlValue)exprs[i]; if(!Equals(val.Value, val0.Value)) return this.ExpandIntoExprSet(exprs); } return val0; } case SqlNodeType.OptionalValue: { if(exprs[0].SqlType.CanBeColumn) { goto default; } List<SqlExpression> hvals = new List<SqlExpression>(exprs.Count); List<SqlExpression> vals = new List<SqlExpression>(exprs.Count); for(int i = 0, n = exprs.Count; i < n; i++) { if(exprs[i] == null || exprs[i].NodeType != SqlNodeType.OptionalValue) { throw Error.UnionIncompatibleConstruction(); } SqlOptionalValue sov = (SqlOptionalValue)exprs[i]; hvals.Add(sov.HasValue); vals.Add(sov.Value); } return new SqlOptionalValue(this.ExpandTogether(hvals), this.ExpandTogether(vals)); } case SqlNodeType.OuterJoinedValue: { if(exprs[0].SqlType.CanBeColumn) { goto default; } List<SqlExpression> values = new List<SqlExpression>(exprs.Count); for(int i = 0, n = exprs.Count; i < n; i++) { if(exprs[i] == null || exprs[i].NodeType != SqlNodeType.OuterJoinedValue) { throw Error.UnionIncompatibleConstruction(); } SqlUnary su = (SqlUnary)exprs[i]; values.Add(su.Operand); } return factory.Unary(SqlNodeType.OuterJoinedValue, this.ExpandTogether(values)); } case SqlNodeType.DiscriminatedType: { SqlDiscriminatedType sdt0 = (SqlDiscriminatedType)exprs[0]; List<SqlExpression> foos = new List<SqlExpression>(exprs.Count); foos.Add(sdt0.Discriminator); for(int i = 1, n = exprs.Count; i < n; i++) { SqlDiscriminatedType sdtN = (SqlDiscriminatedType)exprs[i]; if(sdtN.TargetType != sdt0.TargetType) { throw Error.UnionIncompatibleConstruction(); } foos.Add(sdtN.Discriminator); } return factory.DiscriminatedType(this.ExpandTogether(foos), ((SqlDiscriminatedType)exprs[0]).TargetType); } case SqlNodeType.ClientQuery: case SqlNodeType.Multiset: case SqlNodeType.Element: case SqlNodeType.Grouping: throw Error.UnionWithHierarchy(); default: return this.ExpandIntoExprSet(exprs); } }
private Type GenerateClientCase(SqlClientCase scc, bool isDeferred, LocalBuilder locInstance) { LocalBuilder locDiscriminator = gen.DeclareLocal(scc.Expression.ClrType); this.GenerateExpressionForType(scc.Expression, scc.Expression.ClrType); gen.Emit(OpCodes.Stloc, locDiscriminator); Label labNext = gen.DefineLabel(); Label labEnd = gen.DefineLabel(); for(int i = 0, n = scc.Whens.Count; i < n; i++) { if(i > 0) { gen.MarkLabel(labNext); labNext = gen.DefineLabel(); } SqlClientWhen when = scc.Whens[i]; if(when.Match != null) { gen.Emit(OpCodes.Ldloc, locDiscriminator); this.GenerateExpressionForType(when.Match, scc.Expression.ClrType); this.GenerateEquals(locDiscriminator.LocalType); gen.Emit(OpCodes.Brfalse, labNext); } if(isDeferred) { this.GenerateDeferredSource(when.Value, locInstance); } else { this.GenerateExpressionForType(when.Value, scc.ClrType); } gen.Emit(OpCodes.Br, labEnd); } gen.MarkLabel(labEnd); return scc.ClrType; }
internal override SqlExpression VisitClientCase(SqlClientCase c) { if(!_isDebugMode) { throw Error.InvalidFormatNode("ClientCase"); } _depth++; this.NewLine(); _commandStringBuilder.Append("(CASE"); _depth++; if(c.Expression != null) { _commandStringBuilder.Append(" "); this.Visit(c.Expression); } for(int i = 0, n = c.Whens.Count; i < n; i++) { SqlClientWhen when = c.Whens[i]; if(i == n - 1 && when.Match == null) { this.NewLine(); _commandStringBuilder.Append("ELSE "); this.Visit(when.Value); } else { this.NewLine(); _commandStringBuilder.Append("WHEN "); this.Visit(when.Match); _commandStringBuilder.Append(" THEN "); this.Visit(when.Value); } } _depth--; this.NewLine(); _commandStringBuilder.Append(" END)"); _depth--; return c; }
internal override SqlExpression VisitClientCase(SqlClientCase c) { SqlExpression expr = this.VisitExpression(c.Expression); SqlClientWhen[] whens = new SqlClientWhen[c.Whens.Count]; for(int i = 0, n = whens.Length; i < n; i++) { SqlClientWhen when = c.Whens[i]; whens[i] = new SqlClientWhen(this.VisitExpression(when.Match), this.VisitExpression(when.Value)); } return new SqlClientCase(c.ClrType, expr, whens, c.SourceExpression); }
internal override SqlExpression VisitClientCase(SqlClientCase c) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitClientCase(c); } finally { this.canJoin = saveCanJoin; } }
/// <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); } }