private SqlJoin GetLeftOuterWithUnreferencedSingletonOnLeft(SqlSource source) { SqlAlias alias = source as SqlAlias; if (alias != null) { SqlSelect select = alias.Node as SqlSelect; if (select != null && select.Where == null && select.Top == null && select.GroupBy.Count == 0 && select.OrderBy.Count == 0) { return(this.GetLeftOuterWithUnreferencedSingletonOnLeft(select.From)); } } SqlJoin join = source as SqlJoin; if (join == null || join.JoinType != SqlJoinType.LeftOuter) { return(null); } if (!this.IsSingletonSelect(join.Left)) { return(null); } HashSet <SqlAlias> p = SqlGatherProducedAliases.Gather(join.Left); HashSet <SqlAlias> c = SqlGatherConsumedAliases.Gather(join.Right); if (p.Overlaps(c)) { return(null); } return(join); }
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 SqlAlias VisitAliasConsumed(SqlAlias a) { if (a == null) { return(a); } bool match = false; foreach (SqlAlias alias in aliases) { if (alias == a) { match = true; break; } } if (match) { this.referencesAnyMatchingAliases = true; } return(a); }
internal override SqlAlias VisitAlias(SqlAlias a) { SqlAlias n = new SqlAlias(a.Node); this.nodeMap[a] = n; n.Node = this.Visit(a.Node); n.Name = a.Name; return(n); }
internal override SqlAlias VisitAlias(SqlAlias a) { var sqlAlias = new SqlAlias(a.Node); nodeMap[a] = sqlAlias; sqlAlias.Node = Visit(a.Node); sqlAlias.Name = a.Name; return(sqlAlias); }
internal override SqlAlias VisitAlias(SqlAlias sqlAlias) { SqlAlias save = this.alias; this.alias = sqlAlias; sqlAlias.Node = this.Visit(sqlAlias.Node); this.alias = save; return(sqlAlias); }
private bool HasTrivialSource(SqlSource node) { SqlAlias alias = node as SqlAlias; if (alias == null) { return(false); } return(alias.Node is SqlSelect); }
internal override SqlExpression VisitAliasRef(SqlAliasRef aref) { SqlAlias alias = aref.Alias; SqlAlias value; if (this.removedMap.TryGetValue(alias, out value)) { throw Error.InvalidReferenceToRemovedAliasDuringDeflation(); } return(aref); }
internal SqlJoin MakeJoin(SqlJoinType joinType, SqlSource location, SqlAlias alias, SqlExpression condition, Expression source) { if (joinType == SqlJoinType.LeftOuter) { var sqlSelect = alias.Node as SqlSelect; if (sqlSelect != null && sqlSelect.Selection != null && sqlSelect.Selection.NodeType != SqlNodeType.OptionalValue) { sqlSelect.Selection = new SqlOptionalValue(new SqlColumn("test", Unary(SqlNodeType.OuterJoinedValue, Value(typeof(int?), TypeProvider.From(typeof(int)), 1, false, source))), sqlSelect.Selection); } } return(new SqlJoin(joinType, location, alias, condition, source)); }
internal SqlSelect BuildDefaultQuery(MetaType rowType, bool allowDeferred, SqlLink link, Expression source) { if (rowType.HasInheritance && rowType.InheritanceRoot != rowType) { throw Error.ArgumentWrongValue("rowType"); } var sqlTable = sql.Table(rowType.Table, rowType, source); var sqlAlias = new SqlAlias(sqlTable); var item = new SqlAliasRef(sqlAlias); var selection = BuildProjection(item, sqlTable.RowType, allowDeferred, link, source); return(new SqlSelect(selection, sqlAlias, source)); }
private SqlUnion GetUnion(SqlSource source) { SqlAlias alias = source as SqlAlias; if (alias != null) { SqlUnion union = alias.Node as SqlUnion; if (union != null) { return(union); } } return(null); }
internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss) { SqlSelect innerSelect = this.VisitSelect(ss.Select); if (!this.aggregateChecker.HasAggregates(innerSelect)) { innerSelect.Top = this.sql.ValueFromObject(1, ss.SourceExpression); } innerSelect.OrderingType = SqlOrderingType.Blocked; SqlAlias alias = new SqlAlias(innerSelect); this.currentSelect.From = new SqlJoin(SqlJoinType.OuterApply, this.currentSelect.From, alias, null, ss.SourceExpression); return(new SqlColumnRef(innerSelect.Row.Columns[0])); }
internal override SqlAlias VisitAlias(SqlAlias a) { SqlTable tab = a.Node as SqlTable; SqlTableValuedFunctionCall tvf = a.Node as SqlTableValuedFunctionCall; if (this.addPrimaryKeys && (tab != null || tvf != null)) { List <SqlOrderExpression> list = new List <SqlOrderExpression>(); bool isTable = tab != null; MetaType rowType = isTable ? tab.RowType : tvf.RowType; foreach (MetaDataMember mm in rowType.IdentityMembers) { string name = mm.MappedName; SqlColumn col; Expression sourceExpression; List <SqlColumn> columns; if (isTable) { col = tab.Find(name); sourceExpression = tab.SourceExpression; columns = tab.Columns; } else { col = tvf.Find(name); sourceExpression = tvf.SourceExpression; columns = tvf.Columns; } if (col == null) { col = new SqlColumn(mm.MemberAccessor.Type, typeProvider.From(mm.MemberAccessor.Type), name, mm, null, sourceExpression); col.Alias = a; columns.Add(col); } list.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(col))); } this.PrependOrderExpressions(list); return(a); } else { return(base.VisitAlias(a)); } }
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 override SqlSource VisitSource(SqlSource node) { node = (SqlSource)this.Visit(node); SqlAlias alias = node as SqlAlias; if (alias != null) { SqlSelect sel = alias.Node as SqlSelect; if (sel != null && this.IsTrivialSelect(sel)) { this.removedMap[alias] = alias; node = sel.From; } } return(node); }
private bool IsSingletonSelect(SqlSource source) { SqlAlias alias = source as SqlAlias; if (alias == null) { return(false); } SqlSelect select = alias.Node as SqlSelect; if (select == null) { return(false); } if (select.From != null) { return(false); } return(true); }
private void GetSelectionsBeforeJoin(SqlSource source, List <List <SqlColumn> > selections) { SqlJoin join = source as SqlJoin; if (join != null) { return; } SqlAlias alias = source as SqlAlias; if (alias != null) { SqlSelect select = alias.Node as SqlSelect; if (select != null) { this.GetSelectionsBeforeJoin(select.From, selections); selections.Add(select.Row.Columns); } } }
private bool HasEmptySource(SqlSource node) { SqlAlias alias = node as SqlAlias; if (alias == null) { return(false); } SqlSelect sel = alias.Node as SqlSelect; if (sel == null) { return(false); } return(sel.Row.Columns.Count == 0 && sel.From == null && sel.Where == null && sel.GroupBy.Count == 0 && sel.Having == null && sel.OrderBy.Count == 0); }
internal SqlJoin MakeJoin(SqlJoinType joinType, SqlSource location, SqlAlias alias, SqlExpression condition, Expression source) { // if the new item is on the right side of some outer join then fixup the projection to reflect that it can possibly be null if (joinType == SqlJoinType.LeftOuter) { SqlSelect sel = alias.Node as SqlSelect; if (sel != null && sel.Selection != null && sel.Selection.NodeType != SqlNodeType.OptionalValue) { // replace selection w/ optional + outer-joined-value sel.Selection = new SqlOptionalValue( new SqlColumn( "test", this.Unary(SqlNodeType.OuterJoinedValue, this.Value(typeof(int?), this.typeProvider.From(typeof(int)), 1, false, source)) ), sel.Selection ); } } return(new SqlJoin(joinType, location, alias, condition, source)); }
internal override SqlSource VisitJoin(SqlJoin join) { base.VisitJoin(join); switch (join.JoinType) { case SqlJoinType.Cross: case SqlJoinType.Inner: // reducing either side would effect cardinality of results break; case SqlJoinType.LeftOuter: case SqlJoinType.CrossApply: case SqlJoinType.OuterApply: // may reduce to left if no references to the right if (this.HasEmptySource(join.Right)) { SqlAlias a = (SqlAlias)join.Right; this.removedMap[a] = a; return(join.Left); } break; } return(join); }
internal SqlExpression TranslateEquals(SqlBinary expr) { var sqlExpression = expr.Left; var sqlExpression2 = expr.Right; if (sqlExpression2.NodeType == SqlNodeType.Element) { var sqlSubSelect = (SqlSubSelect)sqlExpression2; var sqlAlias = new SqlAlias(sqlSubSelect.Select); var sqlAliasRef = new SqlAliasRef(sqlAlias); var sqlSelect = new SqlSelect(sqlAliasRef, sqlAlias, expr.SourceExpression) { Where = sql.Binary(expr.NodeType, sql.DoNotVisitExpression(sqlExpression), sqlAliasRef) }; return(sql.SubSelect(SqlNodeType.Exists, sqlSelect)); } if (sqlExpression.NodeType == SqlNodeType.Element) { var sqlSubSelect2 = (SqlSubSelect)sqlExpression; var sqlAlias2 = new SqlAlias(sqlSubSelect2.Select); var sqlAliasRef2 = new SqlAliasRef(sqlAlias2); var sqlSelect2 = new SqlSelect(sqlAliasRef2, sqlAlias2, expr.SourceExpression) { Where = sql.Binary(expr.NodeType, sql.DoNotVisitExpression(sqlExpression2), sqlAliasRef2) }; return(sql.SubSelect(SqlNodeType.Exists, sqlSelect2)); } MetaType sourceMetaType = TypeSource.GetSourceMetaType(sqlExpression, services.Model); MetaType sourceMetaType2 = TypeSource.GetSourceMetaType(sqlExpression2, services.Model); if (sqlExpression.NodeType == SqlNodeType.TypeCase) { sqlExpression = BestIdentityNode((SqlTypeCase)sqlExpression); } if (sqlExpression2.NodeType == SqlNodeType.TypeCase) { sqlExpression2 = BestIdentityNode((SqlTypeCase)sqlExpression2); } if (sourceMetaType.IsEntity && sourceMetaType2.IsEntity && sourceMetaType.Table != sourceMetaType2.Table) { throw Error.CannotCompareItemsAssociatedWithDifferentTable(); } if (!sourceMetaType.IsEntity && !sourceMetaType2.IsEntity && (sqlExpression.NodeType != SqlNodeType.New || sqlExpression.SqlType.CanBeColumn) && (sqlExpression2.NodeType != SqlNodeType.New || sqlExpression2.SqlType.CanBeColumn)) { if (expr.NodeType == SqlNodeType.EQ2V || expr.NodeType == SqlNodeType.NE2V) { return(TranslateEqualsOp(expr.NodeType, sql.DoNotVisitExpression(expr.Left), sql.DoNotVisitExpression(expr.Right), false)); } return(expr); } if (sourceMetaType != sourceMetaType2 && sourceMetaType.InheritanceRoot != sourceMetaType2.InheritanceRoot) { return(sql.Binary(SqlNodeType.EQ, sql.ValueFromObject(0, expr.SourceExpression), sql.ValueFromObject(1, expr.SourceExpression))); } var sqlLink = sqlExpression as SqlLink; var list = (sqlLink == null || !sqlLink.Member.IsAssociation || !sqlLink.Member.Association.IsForeignKey) ? GetIdentityExpressions(sourceMetaType, sql.DoNotVisitExpression(sqlExpression)) : sqlLink.KeyExpressions; var sqlLink2 = sqlExpression2 as SqlLink; var list2 = (sqlLink2 == null || !sqlLink2.Member.IsAssociation || !sqlLink2.Member.Association.IsForeignKey) ? GetIdentityExpressions(sourceMetaType2, sql.DoNotVisitExpression(sqlExpression2)) : sqlLink2.KeyExpressions; SqlExpression sqlExpression3 = null; var op = (expr.NodeType == SqlNodeType.EQ2V || expr.NodeType == SqlNodeType.NE2V) ? SqlNodeType.EQ2V : SqlNodeType.EQ; var i = 0; for (var count = list.Count; i < count; i++) { var sqlExpression4 = TranslateEqualsOp(op, list[i], list2[i], !sourceMetaType.IsEntity); sqlExpression3 = ((sqlExpression3 != null) ? sql.Binary(SqlNodeType.And, sqlExpression3, sqlExpression4) : sqlExpression4); } if (expr.NodeType == SqlNodeType.NE || expr.NodeType == SqlNodeType.NE2V) { sqlExpression3 = sql.Unary(SqlNodeType.Not, sqlExpression3, sqlExpression3.SourceExpression); } return(sqlExpression3); }
internal SqlExpression TranslateEquals(SqlBinary expr) { System.Diagnostics.Debug.Assert( expr.NodeType == SqlNodeType.EQ || expr.NodeType == SqlNodeType.NE || expr.NodeType == SqlNodeType.EQ2V || expr.NodeType == SqlNodeType.NE2V); SqlExpression eLeft = expr.Left; SqlExpression eRight = expr.Right; if (eRight.NodeType == SqlNodeType.Element) { SqlSubSelect sub = (SqlSubSelect)eRight; SqlAlias alias = new SqlAlias(sub.Select); SqlAliasRef aref = new SqlAliasRef(alias); SqlSelect select = new SqlSelect(aref, alias, expr.SourceExpression); select.Where = sql.Binary(expr.NodeType, sql.DoNotVisitExpression(eLeft), aref); return(sql.SubSelect(SqlNodeType.Exists, select)); } else if (eLeft.NodeType == SqlNodeType.Element) { SqlSubSelect sub = (SqlSubSelect)eLeft; SqlAlias alias = new SqlAlias(sub.Select); SqlAliasRef aref = new SqlAliasRef(alias); SqlSelect select = new SqlSelect(aref, alias, expr.SourceExpression); select.Where = sql.Binary(expr.NodeType, sql.DoNotVisitExpression(eRight), aref); return(sql.SubSelect(SqlNodeType.Exists, select)); } MetaType mtLeft = TypeSource.GetSourceMetaType(eLeft, this.services.Model); MetaType mtRight = TypeSource.GetSourceMetaType(eRight, this.services.Model); if (eLeft.NodeType == SqlNodeType.TypeCase) { eLeft = BestIdentityNode((SqlTypeCase)eLeft); } if (eRight.NodeType == SqlNodeType.TypeCase) { eRight = BestIdentityNode((SqlTypeCase)eRight); } if (mtLeft.IsEntity && mtRight.IsEntity && mtLeft.Table != mtRight.Table) { throw Error.CannotCompareItemsAssociatedWithDifferentTable(); } // do simple or no translation for non-structural types if (!mtLeft.IsEntity && !mtRight.IsEntity && (eLeft.NodeType != SqlNodeType.New || eLeft.SqlType.CanBeColumn) && (eRight.NodeType != SqlNodeType.New || eRight.SqlType.CanBeColumn)) { if (expr.NodeType == SqlNodeType.EQ2V || expr.NodeType == SqlNodeType.NE2V) { return(this.TranslateEqualsOp(expr.NodeType, sql.DoNotVisitExpression(expr.Left), sql.DoNotVisitExpression(expr.Right), false)); } return(expr); } // If the two types are not comparable, we return the predicate "1=0". if ((mtLeft != mtRight) && (mtLeft.InheritanceRoot != mtRight.InheritanceRoot)) { return(sql.Binary(SqlNodeType.EQ, sql.ValueFromObject(0, expr.SourceExpression), sql.ValueFromObject(1, expr.SourceExpression))); } List <SqlExpression> exprs1; List <SqlExpression> exprs2; SqlLink link1 = eLeft as SqlLink; if (link1 != null && link1.Member.IsAssociation && link1.Member.Association.IsForeignKey) { exprs1 = link1.KeyExpressions; } else { exprs1 = this.GetIdentityExpressions(mtLeft, sql.DoNotVisitExpression(eLeft)); } SqlLink link2 = eRight as SqlLink; if (link2 != null && link2.Member.IsAssociation && link2.Member.Association.IsForeignKey) { exprs2 = link2.KeyExpressions; } else { exprs2 = this.GetIdentityExpressions(mtRight, sql.DoNotVisitExpression(eRight)); } System.Diagnostics.Debug.Assert(exprs1.Count > 0); System.Diagnostics.Debug.Assert(exprs2.Count > 0); System.Diagnostics.Debug.Assert(exprs1.Count == exprs2.Count); SqlExpression exp = null; SqlNodeType eqKind = (expr.NodeType == SqlNodeType.EQ2V || expr.NodeType == SqlNodeType.NE2V) ? SqlNodeType.EQ2V : SqlNodeType.EQ; for (int i = 0, n = exprs1.Count; i < n; i++) { SqlExpression eq = this.TranslateEqualsOp(eqKind, exprs1[i], exprs2[i], !mtLeft.IsEntity); if (exp == null) { exp = eq; } else { exp = sql.Binary(SqlNodeType.And, exp, eq); } } if (expr.NodeType == SqlNodeType.NE || expr.NodeType == SqlNodeType.NE2V) { exp = sql.Unary(SqlNodeType.Not, exp, exp.SourceExpression); } return(exp); }
internal override SqlAlias VisitAlias(SqlAlias a) { Produced.Add(a); return(base.VisitAlias(a)); }
internal void VisitAliasConsumed(SqlAlias a) { Consumed.Add(a); }
internal virtual SqlAlias VisitAlias(SqlAlias a) { a.Node = this.Visit(a.Node); return(a); }