internal override SqlExpression VisitTypeCase(SqlTypeCase tc) { tc.Discriminator = this.VisitExpression(tc.Discriminator); for (int i = 0, n = tc.Whens.Count; i < n; i++) { // Don't walk down the match side. This can't be a column. tc.Whens[i].TypeBinding = this.VisitExpression(tc.Whens[i].TypeBinding); } return tc; }
internal virtual SqlExpression VisitTypeCase(SqlTypeCase tc) { tc.Discriminator = this.VisitExpression(tc.Discriminator); for (int i = 0, n = tc.Whens.Count; i < n; i++) { SqlTypeCaseWhen when = tc.Whens[i]; when.Match = this.VisitExpression(when.Match); when.TypeBinding = this.VisitExpression(when.TypeBinding); } return tc; }
private Type GenerateTypeCase(SqlTypeCase stc) { LocalBuilder locDiscriminator = gen.DeclareLocal(stc.Discriminator.ClrType); this.GenerateExpressionForType(stc.Discriminator, stc.Discriminator.ClrType); gen.Emit(OpCodes.Stloc, locDiscriminator); Label labNext = gen.DefineLabel(); Label labEnd = gen.DefineLabel(); bool hasDefault = false; for(int i = 0, n = stc.Whens.Count; i < n; i++) { if(i > 0) { gen.MarkLabel(labNext); labNext = gen.DefineLabel(); } SqlTypeCaseWhen when = stc.Whens[i]; if(when.Match != null) { gen.Emit(OpCodes.Ldloc, locDiscriminator); SqlValue vMatch = when.Match as SqlValue; Diagnostics.Debug.Assert(vMatch != null); this.GenerateConstant(locDiscriminator.LocalType, vMatch.Value); this.GenerateEquals(locDiscriminator.LocalType); gen.Emit(OpCodes.Brfalse, labNext); } else { Diagnostics.Debug.Assert(i == n - 1); hasDefault = true; } this.GenerateExpressionForType(when.TypeBinding, stc.ClrType); gen.Emit(OpCodes.Br, labEnd); } gen.MarkLabel(labNext); if(!hasDefault) { this.GenerateConstant(stc.ClrType, null); } gen.MarkLabel(labEnd); return stc.ClrType; }
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); } }
internal override SqlExpression VisitTypeCase(SqlTypeCase c) { if(!_isDebugMode) { throw Error.InvalidFormatNode("TypeCase"); } _depth++; this.NewLine(); _commandStringBuilder.Append("(CASE"); _depth++; if(c.Discriminator != null) { _commandStringBuilder.Append(" "); this.Visit(c.Discriminator); } for(int i = 0, n = c.Whens.Count; i < n; i++) { SqlTypeCaseWhen when = c.Whens[i]; if(i == n - 1 && when.Match == null) { this.NewLine(); _commandStringBuilder.Append("ELSE "); this.Visit(when.TypeBinding); } else { this.NewLine(); _commandStringBuilder.Append("WHEN "); this.Visit(when.Match); _commandStringBuilder.Append(" THEN "); this.Visit(when.TypeBinding); } } _depth--; this.NewLine(); _commandStringBuilder.Append(" END)"); _depth--; return c; }
internal override SqlExpression VisitTypeCase(SqlTypeCase tc) { SqlExpression disc = VisitExpression(tc.Discriminator); List<SqlTypeCaseWhen> whens = new List<SqlTypeCaseWhen>(); foreach(SqlTypeCaseWhen when in tc.Whens) { whens.Add(new SqlTypeCaseWhen(VisitExpression(when.Match), VisitExpression(when.TypeBinding))); } return new SqlTypeCase(tc.ClrType, tc.SqlType, tc.RowType, disc, whens, tc.SourceExpression); }
internal override SqlExpression VisitTypeCase(SqlTypeCase tc) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitTypeCase(tc); } finally { this.canJoin = saveCanJoin; } }
// currently only happens for generated test cases with optimization SimplifyCaseStatements off internal override SqlExpression VisitTypeCase(SqlTypeCase tc) { tc.Discriminator = base.VisitExpression(tc.Discriminator); List<SqlExpression> matches = new List<SqlExpression>(); List<SqlExpression> values = new List<SqlExpression>(); bool remainsTypeCase = true; foreach(SqlTypeCaseWhen when in tc.Whens) { SqlExpression newMatch = this.VisitExpression(when.Match); SqlExpression newNew = this.VisitExpression(when.TypeBinding); remainsTypeCase = remainsTypeCase && (newNew is SqlNew); matches.Add(newMatch); values.Add(newNew); } if(remainsTypeCase) { for(int i = 0, n = tc.Whens.Count; i < n; i++) { SqlTypeCaseWhen when = tc.Whens[i]; when.Match = matches[i]; when.TypeBinding = (SqlNew)values[i]; } return tc; } else { return sql.Case(tc.ClrType, tc.Discriminator, matches, values, tc.SourceExpression); } }
/// <summary> /// Find the alternative in type case that will best identify the object. /// If there is a SqlNew it is expected to have all the identity fields. /// If there is no SqlNew then we must be dealing with all literal NULL alternatives. In this case, /// just return the first one. /// </summary> private static SqlExpression BestIdentityNode(SqlTypeCase tc) { foreach (SqlTypeCaseWhen when in tc.Whens) { if (when.TypeBinding.NodeType == SqlNodeType.New) { return when.TypeBinding; } } return tc.Whens[0].TypeBinding; // There were no SqlNews, take the first alternative }