Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DLinq / Dlinq / SqlClient / Query / SqlMultiplexer.cs / 1305376 / 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 = this.VisitSelectCore(select); 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
- FirstMatchCodeGroup.cs
- WarningException.cs
- SQLChars.cs
- SqlReorderer.cs
- WorkflowDesignerMessageFilter.cs
- TakeQueryOptionExpression.cs
- ErrorActivity.cs
- TypeCodeDomSerializer.cs
- Material.cs
- DataBindingValueUIHandler.cs
- RouteValueDictionary.cs
- Int64.cs
- DataContract.cs
- PassportAuthentication.cs
- ColorTypeConverter.cs
- EnterpriseServicesHelper.cs
- Expr.cs
- ObjectViewListener.cs
- MailDefinition.cs
- XmlStreamedByteStreamReader.cs
- WebCodeGenerator.cs
- BufferModeSettings.cs
- CustomAttribute.cs
- WebPartManagerInternals.cs
- NotCondition.cs
- CellLabel.cs
- MimeBasePart.cs
- Rotation3DAnimationBase.cs
- ArglessEventHandlerProxy.cs
- SourceFileInfo.cs
- DragDeltaEventArgs.cs
- ToolStripScrollButton.cs
- MailDefinition.cs
- EntityDataSourceContainerNameItem.cs
- COM2TypeInfoProcessor.cs
- RelationHandler.cs
- ListControl.cs
- TextBoxLine.cs
- DocumentGridContextMenu.cs
- CommandPlan.cs
- RuntimeConfig.cs
- WorkflowInlining.cs
- BuilderPropertyEntry.cs
- FactoryGenerator.cs
- FontFamilyValueSerializer.cs
- QilIterator.cs
- CallbackValidatorAttribute.cs
- AccessDataSource.cs
- EDesignUtil.cs
- MethodBuilder.cs
- HiddenFieldPageStatePersister.cs
- HttpAsyncResult.cs
- WindowCollection.cs
- SQLGuidStorage.cs
- DbCommandDefinition.cs
- SoapFault.cs
- AllowedAudienceUriElement.cs
- TreeViewDesigner.cs
- MemberExpression.cs
- MdiWindowListStrip.cs
- _SecureChannel.cs
- InternalPermissions.cs
- PathSegmentCollection.cs
- SqlUtil.cs
- TypeExtensionConverter.cs
- BezierSegment.cs
- SHA1.cs
- SerTrace.cs
- AppAction.cs
- ObjectStorage.cs
- SqlNotificationEventArgs.cs
- X509ScopedServiceCertificateElementCollection.cs
- SecurityAccessDeniedException.cs
- _AuthenticationState.cs
- XmlObjectSerializer.cs
- SignedXml.cs
- OleDbRowUpdatedEvent.cs
- CustomAttributeSerializer.cs
- SqlClientWrapperSmiStreamChars.cs
- RowUpdatedEventArgs.cs
- TreeChangeInfo.cs
- QueryableFilterUserControl.cs
- WebPartUserCapability.cs
- DataServiceRequest.cs
- sqlstateclientmanager.cs
- SubqueryRules.cs
- Model3D.cs
- AnnotationAdorner.cs
- SqlParameter.cs
- SecurityHelper.cs
- SafeSecurityHandles.cs
- HyperlinkAutomationPeer.cs
- SafeMarshalContext.cs
- PathTooLongException.cs
- IdnMapping.cs
- EventsTab.cs
- AssemblyName.cs
- Brush.cs
- UIElement3D.cs
- WorkerRequest.cs