internal override SqlNode VisitLink(SqlLink link) { SqlExpression expansion = this.VisitExpression(link.Expansion); SqlExpression[] exprs = new SqlExpression[link.KeyExpressions.Count]; for(int i = 0, n = exprs.Length; i < n; i++) { exprs[i] = this.VisitExpression(link.KeyExpressions[i]); } return new SqlLink(link.Id, link.RowType, link.ClrType, link.SqlType, link.Expression, link.Member, exprs, expansion, link.SourceExpression); }
internal override SqlNode VisitLink(SqlLink link) { // Don't visit the Expression/Expansion for this link. // Any additional external refs in these expressions // should be ignored SqlExpression[] exprs = new SqlExpression[link.KeyExpressions.Count]; for(int i = 0, n = exprs.Length; i < n; i++) { exprs[i] = this.VisitExpression(link.KeyExpressions[i]); } return new SqlLink(new object(), link.RowType, link.ClrType, link.SqlType, null, link.Member, exprs, null, link.SourceExpression); }
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 SqlExpression BuildProjection(SqlExpression item, MetaType rowType, bool allowDeferred, SqlLink link, Expression source) { if (!rowType.HasInheritance) { return this.BuildProjectionInternal(item, rowType, (rowType.Table != null) ? rowType.PersistentDataMembers : rowType.DataMembers, allowDeferred, link, source); } else { // Build a type case that represents a switch between the various type. List<MetaType> mappedTypes = new List<MetaType>(rowType.InheritanceTypes); List<SqlTypeCaseWhen> whens = new List<SqlTypeCaseWhen>(); SqlTypeCaseWhen @else = null; MetaType root = rowType.InheritanceRoot; MetaDataMember discriminator = root.Discriminator; Type dt = discriminator.Type; SqlMember dm = sql.Member(item, discriminator.Member); foreach (MetaType type in mappedTypes) { if (type.HasInheritanceCode) { SqlNew defaultProjection = this.BuildProjectionInternal(item, type, type.PersistentDataMembers, allowDeferred, link, source); if (type.IsInheritanceDefault) { @else = new SqlTypeCaseWhen(null, defaultProjection); } // Add an explicit case even for the default. // Redundant results will be optimized out later. object code = InheritanceRules.InheritanceCodeForClientCompare(type.InheritanceCode, dm.SqlType); SqlExpression match = sql.Value(dt, sql.Default(discriminator), code, true, source); whens.Add(new SqlTypeCaseWhen(match, defaultProjection)); } } if (@else == null) { throw Error.EmptyCaseNotSupported(); } whens.Add(@else); // Add the else at the end. return sql.TypeCase(root.Type, root, dm, whens.ToArray(), source); } }
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 GenerateLink(SqlLink link, LocalBuilder locInstance) { gen.Emit(OpCodes.Ldarg_0); // iGlobalLink arg int iGlobalLink = this.AddGlobal(typeof(MetaDataMember), link.Member); this.GenerateConstInt(iGlobalLink); // iLocalFactory arg int iLocalFactory = this.AllocateLocal(); this.GenerateConstInt(iLocalFactory); Type elemType = link.Member.IsAssociation && link.Member.Association.IsMany ? TypeSystem.GetElementType(link.Member.Type) : link.Member.Type; MethodInfo mi = null; if(locInstance != null) { // load instance for 'instance' arg gen.Emit(OpCodes.Ldloc, locInstance); // call GetNestedLinkSource on ObjectReaderBase mi = typeof(ObjectMaterializer<>).MakeGenericType(this.compiler.DataReaderType).GetMethod("GetNestedLinkSource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Diagnostics.Debug.Assert(mi != null); MethodInfo miGLS = mi.MakeGenericMethod(elemType); gen.Emit(GetMethodCallOpCode(miGLS), miGLS); } else { // create array of key values for 'keyValues' arg this.GenerateConstInt(link.KeyExpressions.Count); gen.Emit(OpCodes.Newarr, typeof(object)); // intialize key values for(int i = 0, n = link.KeyExpressions.Count; i < n; i++) { gen.Emit(OpCodes.Dup); this.GenerateConstInt(i); this.GenerateExpressionForType(link.KeyExpressions[i], typeof(object)); this.GenerateArrayAssign(typeof(object)); } // call GetLinkSource on ObjectReaderBase mi = typeof(ObjectMaterializer<>).MakeGenericType(this.compiler.DataReaderType).GetMethod("GetLinkSource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Diagnostics.Debug.Assert(mi != null); MethodInfo miGLS = mi.MakeGenericMethod(elemType); gen.Emit(GetMethodCallOpCode(miGLS), miGLS); } return typeof(IEnumerable<>).MakeGenericType(elemType); }
internal LinkedTableExpression(SqlLink link, ITable table, Type type) : base(InternalExpressionType.LinkedTable, type) { this.link = link; this.table = table; }
internal override SqlNode VisitLink(SqlLink link) { // don't visit expansion... for(int i = 0, n = link.KeyExpressions.Count; i < n; i++) { link.KeyExpressions[i] = this.VisitExpression(link.KeyExpressions[i]); } return link; }
internal override SqlNode VisitLink(SqlLink link) { if(!_isDebugMode) { throw Error.InvalidFormatNode("Link"); } if(link.Expansion != null) { _commandStringBuilder.Append("LINK("); this.Visit(link.Expansion); _commandStringBuilder.Append(")"); } else { _commandStringBuilder.Append("LINK("); for(int i = 0, n = link.KeyExpressions.Count; i < n; i++) { if(i > 0) _commandStringBuilder.Append(", "); this.Visit(link.KeyExpressions[i]); } _commandStringBuilder.Append(")"); } return link; }
internal SqlNode TranslateLink(SqlLink link, List<SqlExpression> keyExpressions, bool asExpression) { MetaDataMember mm = link.Member; if (mm.IsAssociation) { // Create the row source. MetaType otherType = mm.Association.OtherType; Type tableType = otherType.InheritanceRoot.Type; ITable table = this.services.Context.GetTable(tableType); Expression source = new LinkedTableExpression(link, table, typeof(IQueryable<>).MakeGenericType(otherType.Type)); // Build key expression nodes. Expression[] keyExprs = new Expression[keyExpressions.Count]; for (int i = 0; i < keyExpressions.Count; ++i) { MetaDataMember metaMember = mm.Association.OtherKey[i]; Type memberType = TypeSystem.GetMemberType(metaMember.Member); keyExprs[i] = InternalExpression.Known(keyExpressions[i], memberType); } Expression lex = link.Expression != null ? (Expression)InternalExpression.Known(link.Expression) : (Expression)Expression.Constant(null, link.Member.Member.DeclaringType); Expression expr = TranslateAssociation(this.services.Context, mm.Association, source, keyExprs, lex); // Convert QueryConverter qc = new QueryConverter(this.services, this.typeProvider, this, this.sql); SqlSelect sel = (SqlSelect)qc.ConvertInner(expr, link.SourceExpression); // Turn it into an expression is necessary SqlNode result = sel; if (asExpression) { if (mm.Association.IsMany) { result = new SqlSubSelect(SqlNodeType.Multiset, link.ClrType, link.SqlType, sel); } else { result = new SqlSubSelect(SqlNodeType.Element, link.ClrType, link.SqlType, sel); } } return result; } else { System.Diagnostics.Debug.Assert(link.Expansion != null); System.Diagnostics.Debug.Assert(link.KeyExpressions == keyExpressions); // deferred expression already defined... return link.Expansion; } }
internal override SqlNode VisitLink(SqlLink link) { link = (SqlLink)base.VisitLink(link); // prefetch all 'LoadWith' links if (!this.disableInclude && this.shape != null && this.alreadyIncluded != null) { MetaDataMember mdm = link.Member; MemberInfo mi = mdm.Member; if (this.shape.IsPreloaded(mi) && mdm.LoadMethod == null) { // Is the other side of the relation in the list already? MetaType otherType = mdm.DeclaringType.InheritanceRoot; if (!this.alreadyIncluded.Contains(otherType)) { this.alreadyIncluded.Add(otherType); SqlNode fetched = this.ConvertToFetchedExpression(link); this.alreadyIncluded.Remove(otherType); return fetched; } } } if (this.inGroupBy && link.Expansion != null) { return this.VisitLinkExpansion(link); } return link; }
private SqlExpression VisitLinkExpansion(SqlLink link) { SqlAliasRef aref = link.Expansion as SqlAliasRef; if (aref != null && aref.Alias.Node.NodeType == SqlNodeType.Table) { SqlAlias outerAlias; if (this.outerAliasMap.TryGetValue(aref.Alias, out outerAlias)) { return this.VisitAliasRef(new SqlAliasRef(outerAlias)); } // should not happen Diagnostics.Debug.Assert(false); } return this.VisitExpression(link.Expansion); }
private SqlNew BuildProjectionInternal(SqlExpression item, MetaType rowType, IEnumerable<MetaDataMember> members, bool allowDeferred, SqlLink link, Expression source) { List<SqlMemberAssign> bindings = new List<SqlMemberAssign>(); foreach (MetaDataMember mm in members) { if (allowDeferred && (mm.IsAssociation || mm.IsDeferred)) { // check if this member is the reverse association to the supplied link if (link != null && mm != link.Member && mm.IsAssociation && mm.MappedName == link.Member.MappedName && !mm.Association.IsMany && !IsPreloaded(link.Member.Member)) { // place a new link here with an expansion that is previous link's root expression. // this will allow joins caused by reverse association references to 'melt' away. :-) SqlLink mlink = this.BuildLink(item, mm, source); mlink.Expansion = link.Expression; bindings.Add(new SqlMemberAssign(mm.Member, mlink)); } else { bindings.Add(new SqlMemberAssign(mm.Member, this.BuildLink(item, mm, source))); } } else if (!mm.IsAssociation) { bindings.Add(new SqlMemberAssign(mm.Member, sql.Member(item, mm))); } } ConstructorInfo cons = rowType.Type.GetConstructor(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic, null, System.Type.EmptyTypes, null); if (cons == null) { throw Error.MappedTypeMustHaveDefaultConstructor(rowType.Type); } return sql.New(rowType, cons, null, null, bindings, source); }
/// <summary> /// Convert ITable into SqlNodes. If the hierarchy involves inheritance then /// a type case is built. Abstractly, a type case is a CASE where each WHEN is a possible /// a typebinding that may be instantianted. /// </summary> private SqlNode TranslateConstantTable(ITable table, SqlLink link) { if(table.Context != _services.Context) { throw Error.WrongDataContext(); } MetaTable metaTable = _services.Model.GetTable(table.ElementType); return _translator.BuildDefaultQuery(metaTable.RowType, _allowDeferred, link, _dominatingExpression); }
internal override SqlNode VisitLink(SqlLink link) { SqlExpression[] exprs = new SqlExpression[link.KeyExpressions.Count]; for(int i = 0, n = exprs.Length; i < n; i++) { exprs[i] = this.VisitExpression(link.KeyExpressions[i]); } SqlLink newLink = new SqlLink(new object(), link.RowType, link.ClrType, link.SqlType, null, link.Member, exprs, null, link.SourceExpression); this.nodeMap[link] = newLink; // break the potential cyclic tree by visiting these after adding to the map newLink.Expression = this.VisitExpression(link.Expression); newLink.Expansion = this.VisitExpression(link.Expansion); return newLink; }
internal virtual SqlNode VisitLink(SqlLink link) { // Don't visit the link's Expansion for (int i = 0, n = link.KeyExpressions.Count; i < n; i++) { link.KeyExpressions[i] = this.VisitExpression(link.KeyExpressions[i]); } return link; }
internal SqlNode TranslateLink(SqlLink link, bool asExpression) { return this.TranslateLink(link, link.KeyExpressions, asExpression); }