Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DLinq / Dlinq / SqlClient / Query / SqlMultiplexer.cs / 2 / SqlMultiplexer.cs
using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Data.Linq; namespace System.Data.Linq.SqlClient { // convert multiset & element expressions into separate queries internal class SqlMultiplexer { Visitor visitor; internal enum Options { None, EnableBigJoin } internal SqlMultiplexer(Options options, IEnumerableparentParameters, SqlFactory sqlFactory) { this.visitor = new Visitor(options, parentParameters, sqlFactory); } internal SqlNode Multiplex(SqlNode node) { return this.visitor.Visit(node); } class Visitor : SqlVisitor { Options options; SqlFactory sql; SqlSelect outerSelect; bool hasBigJoin; bool canJoin; bool isTopLevel; IEnumerable parentParameters; internal Visitor(Options options, IEnumerable parentParameters, SqlFactory sqlFactory) { this.options = options; this.sql = sqlFactory; this.canJoin = true; this.isTopLevel = true; this.parentParameters = parentParameters; } internal override SqlExpression VisitMultiset(SqlSubSelect sms) { // allow one big-join per query? if ((this.options & Options.EnableBigJoin) != 0 && !this.hasBigJoin && this.canJoin && this.isTopLevel && this.outerSelect != null && !MultisetChecker.HasMultiset(sms.Select.Selection) && BigJoinChecker.CanBigJoin(sms.Select)) { sms.Select = this.VisitSelect(sms.Select); SqlAlias alias = new SqlAlias(sms.Select); SqlJoin join = new SqlJoin(SqlJoinType.OuterApply, this.outerSelect.From, alias, null, sms.SourceExpression); this.outerSelect.From = join; this.outerSelect.OrderingType = SqlOrderingType.Always; // make joined expression SqlExpression expr = (SqlExpression)SqlDuplicator.Copy(sms.Select.Selection); // make count expression SqlSelect copySelect = (SqlSelect)SqlDuplicator.Copy(sms.Select); SqlAlias copyAlias = new SqlAlias(copySelect); SqlSelect countSelect = new SqlSelect(sql.Unary(SqlNodeType.Count, null, sms.SourceExpression), copyAlias, sms.SourceExpression); countSelect.OrderingType = SqlOrderingType.Never; SqlExpression count = sql.SubSelect(SqlNodeType.ScalarSubSelect, countSelect); // make joined collection SqlJoinedCollection jc = new SqlJoinedCollection(sms.ClrType, sms.SqlType, expr, count, sms.SourceExpression); this.hasBigJoin = true; return jc; } else { return QueryExtractor.Extract(sms, this.parentParameters); } } internal override SqlExpression VisitElement(SqlSubSelect elem) { return QueryExtractor.Extract(elem, this.parentParameters); } internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss) { bool saveIsTopLevel = this.isTopLevel; this.isTopLevel = false; bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitScalarSubSelect(ss); } finally { this.isTopLevel = saveIsTopLevel; this.canJoin = saveCanJoin; } } internal override SqlExpression VisitExists(SqlSubSelect ss) { bool saveIsTopLevel = this.isTopLevel; this.isTopLevel = false; bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitExists(ss); } finally { this.isTopLevel = saveIsTopLevel; this.canJoin = saveCanJoin; } } internal override SqlSelect VisitSelect(SqlSelect select) { SqlSelect saveSelect = this.outerSelect; this.outerSelect = select; // big-joins may need to lift PK's out for default ordering, so don't allow big-join if we see these this.canJoin &= select.GroupBy.Count == 0 && select.Top == null && !select.IsDistinct; bool saveIsTopLevel = this.isTopLevel; this.isTopLevel = false; select.From = this.VisitSource(select.From); select.Where = this.VisitExpression(select.Where); for (int i = 0, n = select.GroupBy.Count; i < n; i++) { select.GroupBy[i] = this.VisitExpression(select.GroupBy[i]); } select.Having = this.VisitExpression(select.Having); for (int i = 0, n = select.OrderBy.Count; i < n; i++) { select.OrderBy[i].Expression = this.VisitExpression(select.OrderBy[i].Expression); } select.Top = this.VisitExpression(select.Top); select.Row = (SqlRow)this.Visit(select.Row); this.isTopLevel = saveIsTopLevel; select.Selection = this.VisitExpression(select.Selection); this.isTopLevel = saveIsTopLevel; this.outerSelect = saveSelect; if (select.IsDistinct && HierarchyChecker.HasHierarchy(select.Selection)) { // distinct across heirarchy is a NO-OP select.IsDistinct = false; } return select; } internal override SqlNode VisitUnion(SqlUnion su) { this.canJoin = false; return base.VisitUnion(su); } internal override SqlExpression VisitClientCase(SqlClientCase c) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitClientCase(c); } finally { this.canJoin = saveCanJoin; } } internal override SqlExpression VisitSimpleCase(SqlSimpleCase c) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitSimpleCase(c); } finally { this.canJoin = saveCanJoin; } } internal override SqlExpression VisitSearchedCase(SqlSearchedCase c) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitSearchedCase(c); } finally { this.canJoin = saveCanJoin; } } internal override SqlExpression VisitTypeCase(SqlTypeCase tc) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitTypeCase(tc); } finally { this.canJoin = saveCanJoin; } } internal override SqlExpression VisitOptionalValue(SqlOptionalValue sov) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitOptionalValue(sov); } finally { this.canJoin = saveCanJoin; } } internal override SqlUserQuery VisitUserQuery(SqlUserQuery suq) { this.canJoin = false; return base.VisitUserQuery(suq); } } } internal class QueryExtractor { internal static SqlClientQuery Extract(SqlSubSelect subquery, IEnumerable parentParameters) { SqlClientQuery cq = new SqlClientQuery(subquery); if (parentParameters != null) { cq.Parameters.AddRange(parentParameters); } Visitor v = new Visitor(cq.Arguments, cq.Parameters); cq.Query = (SqlSubSelect)v.Visit(subquery); return cq; } class Visitor : SqlDuplicator.DuplicatingVisitor { List externals; List parameters; internal Visitor(List externals, List parameters) : base(true) { this.externals = externals; this.parameters = parameters; } internal override SqlExpression VisitColumnRef(SqlColumnRef cref) { SqlExpression result = base.VisitColumnRef(cref); if (result == cref) { // must be external return ExtractParameter(result); } return result; } internal override SqlExpression VisitUserColumn(SqlUserColumn suc) { SqlExpression result = base.VisitUserColumn(suc); if (result == suc) { // must be external return ExtractParameter(result); } return result; } private SqlExpression ExtractParameter(SqlExpression expr) { Type clrType = expr.ClrType; if (expr.ClrType.IsValueType && !TypeSystem.IsNullableType(expr.ClrType)) { clrType = typeof(Nullable<>).MakeGenericType(expr.ClrType); } this.externals.Add(expr); SqlParameter sp = new SqlParameter(clrType, expr.SqlType, "@x" + (this.parameters.Count + 1), expr.SourceExpression); this.parameters.Add(sp); return sp; } 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 class HierarchyChecker { internal static bool HasHierarchy(SqlExpression expr) { Visitor v = new Visitor(); v.Visit(expr); return v.foundHierarchy; } class Visitor : SqlVisitor { internal bool foundHierarchy; internal override SqlExpression VisitMultiset(SqlSubSelect sms) { this.foundHierarchy = true; return sms; } internal override SqlExpression VisitElement(SqlSubSelect elem) { this.foundHierarchy = true; return elem; } internal override SqlExpression VisitClientQuery(SqlClientQuery cq) { this.foundHierarchy = true; return cq; } internal override SqlExpression VisitExists(SqlSubSelect ss) { return ss; } internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss) { return ss; } } } internal class MultisetChecker { internal static bool HasMultiset(SqlExpression expr) { Visitor v = new Visitor(); v.Visit(expr); return v.foundMultiset; } class Visitor : SqlVisitor { internal bool foundMultiset; internal override SqlExpression VisitMultiset(SqlSubSelect sms) { this.foundMultiset = true; return sms; } internal override SqlExpression VisitElement(SqlSubSelect elem) { return elem; } internal override SqlExpression VisitClientQuery(SqlClientQuery cq) { return cq; } internal override SqlExpression VisitExists(SqlSubSelect ss) { return ss; } internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss) { return ss; } } } internal class BigJoinChecker { internal static bool CanBigJoin(SqlSelect select) { Visitor v = new Visitor(); v.Visit(select); return v.canBigJoin; } class Visitor : SqlVisitor { internal bool canBigJoin = true; internal override SqlExpression VisitMultiset(SqlSubSelect sms) { return sms; } internal override SqlExpression VisitElement(SqlSubSelect elem) { return elem; } internal override SqlExpression VisitClientQuery(SqlClientQuery cq) { return cq; } internal override SqlExpression VisitExists(SqlSubSelect ss) { return ss; } internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss) { return ss; } internal override SqlSelect VisitSelect(SqlSelect select) { // big-joins may need to lift PK's out for default ordering, so don't allow big-join if we see these this.canBigJoin &= select.GroupBy.Count == 0 && select.Top == null && !select.IsDistinct; if (!this.canBigJoin) { return select; } return base.VisitSelect(select); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Data.Linq; namespace System.Data.Linq.SqlClient { // convert multiset & element expressions into separate queries internal class SqlMultiplexer { Visitor visitor; internal enum Options { None, EnableBigJoin } internal SqlMultiplexer(Options options, IEnumerable parentParameters, SqlFactory sqlFactory) { this.visitor = new Visitor(options, parentParameters, sqlFactory); } internal SqlNode Multiplex(SqlNode node) { return this.visitor.Visit(node); } class Visitor : SqlVisitor { Options options; SqlFactory sql; SqlSelect outerSelect; bool hasBigJoin; bool canJoin; bool isTopLevel; IEnumerable parentParameters; internal Visitor(Options options, IEnumerable parentParameters, SqlFactory sqlFactory) { this.options = options; this.sql = sqlFactory; this.canJoin = true; this.isTopLevel = true; this.parentParameters = parentParameters; } internal override SqlExpression VisitMultiset(SqlSubSelect sms) { // allow one big-join per query? if ((this.options & Options.EnableBigJoin) != 0 && !this.hasBigJoin && this.canJoin && this.isTopLevel && this.outerSelect != null && !MultisetChecker.HasMultiset(sms.Select.Selection) && BigJoinChecker.CanBigJoin(sms.Select)) { sms.Select = this.VisitSelect(sms.Select); SqlAlias alias = new SqlAlias(sms.Select); SqlJoin join = new SqlJoin(SqlJoinType.OuterApply, this.outerSelect.From, alias, null, sms.SourceExpression); this.outerSelect.From = join; this.outerSelect.OrderingType = SqlOrderingType.Always; // make joined expression SqlExpression expr = (SqlExpression)SqlDuplicator.Copy(sms.Select.Selection); // make count expression SqlSelect copySelect = (SqlSelect)SqlDuplicator.Copy(sms.Select); SqlAlias copyAlias = new SqlAlias(copySelect); SqlSelect countSelect = new SqlSelect(sql.Unary(SqlNodeType.Count, null, sms.SourceExpression), copyAlias, sms.SourceExpression); countSelect.OrderingType = SqlOrderingType.Never; SqlExpression count = sql.SubSelect(SqlNodeType.ScalarSubSelect, countSelect); // make joined collection SqlJoinedCollection jc = new SqlJoinedCollection(sms.ClrType, sms.SqlType, expr, count, sms.SourceExpression); this.hasBigJoin = true; return jc; } else { return QueryExtractor.Extract(sms, this.parentParameters); } } internal override SqlExpression VisitElement(SqlSubSelect elem) { return QueryExtractor.Extract(elem, this.parentParameters); } internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss) { bool saveIsTopLevel = this.isTopLevel; this.isTopLevel = false; bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitScalarSubSelect(ss); } finally { this.isTopLevel = saveIsTopLevel; this.canJoin = saveCanJoin; } } internal override SqlExpression VisitExists(SqlSubSelect ss) { bool saveIsTopLevel = this.isTopLevel; this.isTopLevel = false; bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitExists(ss); } finally { this.isTopLevel = saveIsTopLevel; this.canJoin = saveCanJoin; } } internal override SqlSelect VisitSelect(SqlSelect select) { SqlSelect saveSelect = this.outerSelect; this.outerSelect = select; // big-joins may need to lift PK's out for default ordering, so don't allow big-join if we see these this.canJoin &= select.GroupBy.Count == 0 && select.Top == null && !select.IsDistinct; bool saveIsTopLevel = this.isTopLevel; this.isTopLevel = false; select.From = this.VisitSource(select.From); select.Where = this.VisitExpression(select.Where); for (int i = 0, n = select.GroupBy.Count; i < n; i++) { select.GroupBy[i] = this.VisitExpression(select.GroupBy[i]); } select.Having = this.VisitExpression(select.Having); for (int i = 0, n = select.OrderBy.Count; i < n; i++) { select.OrderBy[i].Expression = this.VisitExpression(select.OrderBy[i].Expression); } select.Top = this.VisitExpression(select.Top); select.Row = (SqlRow)this.Visit(select.Row); this.isTopLevel = saveIsTopLevel; select.Selection = this.VisitExpression(select.Selection); this.isTopLevel = saveIsTopLevel; this.outerSelect = saveSelect; if (select.IsDistinct && HierarchyChecker.HasHierarchy(select.Selection)) { // distinct across heirarchy is a NO-OP select.IsDistinct = false; } return select; } internal override SqlNode VisitUnion(SqlUnion su) { this.canJoin = false; return base.VisitUnion(su); } internal override SqlExpression VisitClientCase(SqlClientCase c) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitClientCase(c); } finally { this.canJoin = saveCanJoin; } } internal override SqlExpression VisitSimpleCase(SqlSimpleCase c) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitSimpleCase(c); } finally { this.canJoin = saveCanJoin; } } internal override SqlExpression VisitSearchedCase(SqlSearchedCase c) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitSearchedCase(c); } finally { this.canJoin = saveCanJoin; } } internal override SqlExpression VisitTypeCase(SqlTypeCase tc) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitTypeCase(tc); } finally { this.canJoin = saveCanJoin; } } internal override SqlExpression VisitOptionalValue(SqlOptionalValue sov) { bool saveCanJoin = this.canJoin; this.canJoin = false; try { return base.VisitOptionalValue(sov); } finally { this.canJoin = saveCanJoin; } } internal override SqlUserQuery VisitUserQuery(SqlUserQuery suq) { this.canJoin = false; return base.VisitUserQuery(suq); } } } internal class QueryExtractor { internal static SqlClientQuery Extract(SqlSubSelect subquery, IEnumerable parentParameters) { SqlClientQuery cq = new SqlClientQuery(subquery); if (parentParameters != null) { cq.Parameters.AddRange(parentParameters); } Visitor v = new Visitor(cq.Arguments, cq.Parameters); cq.Query = (SqlSubSelect)v.Visit(subquery); return cq; } class Visitor : SqlDuplicator.DuplicatingVisitor { List externals; List parameters; internal Visitor(List externals, List parameters) : base(true) { this.externals = externals; this.parameters = parameters; } internal override SqlExpression VisitColumnRef(SqlColumnRef cref) { SqlExpression result = base.VisitColumnRef(cref); if (result == cref) { // must be external return ExtractParameter(result); } return result; } internal override SqlExpression VisitUserColumn(SqlUserColumn suc) { SqlExpression result = base.VisitUserColumn(suc); if (result == suc) { // must be external return ExtractParameter(result); } return result; } private SqlExpression ExtractParameter(SqlExpression expr) { Type clrType = expr.ClrType; if (expr.ClrType.IsValueType && !TypeSystem.IsNullableType(expr.ClrType)) { clrType = typeof(Nullable<>).MakeGenericType(expr.ClrType); } this.externals.Add(expr); SqlParameter sp = new SqlParameter(clrType, expr.SqlType, "@x" + (this.parameters.Count + 1), expr.SourceExpression); this.parameters.Add(sp); return sp; } 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 class HierarchyChecker { internal static bool HasHierarchy(SqlExpression expr) { Visitor v = new Visitor(); v.Visit(expr); return v.foundHierarchy; } class Visitor : SqlVisitor { internal bool foundHierarchy; internal override SqlExpression VisitMultiset(SqlSubSelect sms) { this.foundHierarchy = true; return sms; } internal override SqlExpression VisitElement(SqlSubSelect elem) { this.foundHierarchy = true; return elem; } internal override SqlExpression VisitClientQuery(SqlClientQuery cq) { this.foundHierarchy = true; return cq; } internal override SqlExpression VisitExists(SqlSubSelect ss) { return ss; } internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss) { return ss; } } } internal class MultisetChecker { internal static bool HasMultiset(SqlExpression expr) { Visitor v = new Visitor(); v.Visit(expr); return v.foundMultiset; } class Visitor : SqlVisitor { internal bool foundMultiset; internal override SqlExpression VisitMultiset(SqlSubSelect sms) { this.foundMultiset = true; return sms; } internal override SqlExpression VisitElement(SqlSubSelect elem) { return elem; } internal override SqlExpression VisitClientQuery(SqlClientQuery cq) { return cq; } internal override SqlExpression VisitExists(SqlSubSelect ss) { return ss; } internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss) { return ss; } } } internal class BigJoinChecker { internal static bool CanBigJoin(SqlSelect select) { Visitor v = new Visitor(); v.Visit(select); return v.canBigJoin; } class Visitor : SqlVisitor { internal bool canBigJoin = true; internal override SqlExpression VisitMultiset(SqlSubSelect sms) { return sms; } internal override SqlExpression VisitElement(SqlSubSelect elem) { return elem; } internal override SqlExpression VisitClientQuery(SqlClientQuery cq) { return cq; } internal override SqlExpression VisitExists(SqlSubSelect ss) { return ss; } internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss) { return ss; } internal override SqlSelect VisitSelect(SqlSelect select) { // big-joins may need to lift PK's out for default ordering, so don't allow big-join if we see these this.canBigJoin &= select.GroupBy.Count == 0 && select.Top == null && !select.IsDistinct; if (!this.canBigJoin) { return select; } return base.VisitSelect(select); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DataGridViewRowsRemovedEventArgs.cs
- WebPartTracker.cs
- InternalBufferOverflowException.cs
- RuleSettingsCollection.cs
- SchemaCollectionPreprocessor.cs
- DeclarativeCatalogPartDesigner.cs
- ProxyElement.cs
- PartialTrustVisibleAssembly.cs
- ArglessEventHandlerProxy.cs
- NotifyInputEventArgs.cs
- ShellProvider.cs
- TraceUtility.cs
- PointConverter.cs
- BaseAppDomainProtocolHandler.cs
- MenuAutomationPeer.cs
- ObjectViewListener.cs
- XomlSerializationHelpers.cs
- XmlLinkedNode.cs
- XamlPathDataSerializer.cs
- TextTreeExtractElementUndoUnit.cs
- FamilyMap.cs
- EntityDescriptor.cs
- DataSourceCacheDurationConverter.cs
- X509CertificateChain.cs
- WebContext.cs
- Part.cs
- KeyTime.cs
- MatrixCamera.cs
- LoginName.cs
- WebEventCodes.cs
- Accessible.cs
- ServiceChannelProxy.cs
- BoolExpression.cs
- StatusBar.cs
- NoResizeHandleGlyph.cs
- StrongNameKeyPair.cs
- FormViewDeleteEventArgs.cs
- TdsParserSafeHandles.cs
- RoleGroup.cs
- ActiveDesignSurfaceEvent.cs
- HttpListenerPrefixCollection.cs
- propertytag.cs
- Int64AnimationUsingKeyFrames.cs
- _LazyAsyncResult.cs
- EntitySetRetriever.cs
- DetailsViewPagerRow.cs
- ScrollPattern.cs
- TextBox.cs
- Int32Converter.cs
- Mapping.cs
- VectorCollectionConverter.cs
- ExpressionWriter.cs
- NamedPipeHostedTransportConfiguration.cs
- SchemaTableColumn.cs
- TerminatorSinks.cs
- SqlCachedBuffer.cs
- DbBuffer.cs
- StyleBamlRecordReader.cs
- EventLogPermissionEntryCollection.cs
- ContentPlaceHolder.cs
- ProcessHostServerConfig.cs
- Thread.cs
- RectAnimationClockResource.cs
- UIElement3DAutomationPeer.cs
- RelatedImageListAttribute.cs
- GenericTextProperties.cs
- BuildManagerHost.cs
- ReflectionTypeLoadException.cs
- FormsAuthenticationTicket.cs
- Matrix3DStack.cs
- LifetimeServices.cs
- DataSetViewSchema.cs
- PageSettings.cs
- _Rfc2616CacheValidators.cs
- COMException.cs
- GradientStopCollection.cs
- QilCloneVisitor.cs
- DescendantQuery.cs
- SortDescription.cs
- GridLength.cs
- StylusEditingBehavior.cs
- GlyphRun.cs
- ConfigXmlSignificantWhitespace.cs
- EdmValidator.cs
- ProfilePropertySettingsCollection.cs
- ConsoleEntryPoint.cs
- InfoCardRSAPKCS1KeyExchangeDeformatter.cs
- OutputCacheProfileCollection.cs
- TextSelectionProcessor.cs
- WindowsStartMenu.cs
- RTTypeWrapper.cs
- VectorKeyFrameCollection.cs
- ValidationPropertyAttribute.cs
- Privilege.cs
- PackWebRequestFactory.cs
- EnterpriseServicesHelper.cs
- SubMenuStyle.cs
- GridViewColumn.cs
- HtmlInputSubmit.cs
- RawUIStateInputReport.cs