internal override SqlExpression VisitMultiset(SqlSubSelect sms) { // allow one big-join per query? if((this.options & SqlMultiplexerOptionType.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; } return QueryExtractor.Extract(sms, this.parentParameters); }
internal override SqlExpression VisitJoinedCollection(SqlJoinedCollection jc) { this.hasSideEffect = true; return jc; }
internal virtual SqlExpression VisitJoinedCollection(SqlJoinedCollection jc) { jc.Expression = this.VisitExpression(jc.Expression); jc.Count = this.VisitExpression(jc.Count); return jc; }
private Type GenerateJoinedCollection(SqlJoinedCollection jc) { LocalBuilder locCount = gen.DeclareLocal(typeof(int)); LocalBuilder locHasRows = gen.DeclareLocal(typeof(bool)); Type joinElementType = jc.Expression.ClrType; Type listType = typeof(List<>).MakeGenericType(joinElementType); LocalBuilder locList = gen.DeclareLocal(listType); // count = xxx this.GenerateExpressionForType(jc.Count, typeof(int)); gen.Emit(OpCodes.Stloc, locCount); // list = new List<T>(count) gen.Emit(OpCodes.Ldloc, locCount); ConstructorInfo ci = listType.GetConstructor(new Type[] { typeof(int) }); Diagnostics.Debug.Assert(ci != null); gen.Emit(OpCodes.Newobj, ci); gen.Emit(OpCodes.Stloc, locList); // hasRows = true gen.Emit(OpCodes.Ldc_I4_1); gen.Emit(OpCodes.Stloc, locHasRows); // start loop Label labLoopTest = gen.DefineLabel(); Label labLoopTop = gen.DefineLabel(); LocalBuilder locI = gen.DeclareLocal(typeof(int)); gen.Emit(OpCodes.Ldc_I4_0); gen.Emit(OpCodes.Stloc, locI); gen.Emit(OpCodes.Br, labLoopTest); gen.MarkLabel(labLoopTop); // loop interior // if (i > 0 && hasRows) { hasRows = this.Read(); } gen.Emit(OpCodes.Ldloc, locI); gen.Emit(OpCodes.Ldc_I4_0); gen.Emit(OpCodes.Cgt); gen.Emit(OpCodes.Ldloc, locHasRows); gen.Emit(OpCodes.And); Label labNext = gen.DefineLabel(); gen.Emit(OpCodes.Brfalse, labNext); // this.Read() gen.Emit(OpCodes.Ldarg_0); Type orbType = typeof(ObjectMaterializer<>).MakeGenericType(this.compiler.DataReaderType); MethodInfo miRead = orbType.GetMethod("Read", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); Diagnostics.Debug.Assert(miRead != null); gen.Emit(GetMethodCallOpCode(miRead), miRead); gen.Emit(OpCodes.Stloc, locHasRows); gen.MarkLabel(labNext); // if (hasRows) { list.Add(expr); } Label labNext2 = gen.DefineLabel(); gen.Emit(OpCodes.Ldloc, locHasRows); gen.Emit(OpCodes.Brfalse, labNext2); gen.Emit(OpCodes.Ldloc, locList); this.GenerateExpressionForType(jc.Expression, joinElementType); MethodInfo miAdd = listType.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { joinElementType }, null); Diagnostics.Debug.Assert(miAdd != null); gen.Emit(GetMethodCallOpCode(miAdd), miAdd); gen.MarkLabel(labNext2); // loop bottom // i = i + 1 gen.Emit(OpCodes.Ldloc, locI); gen.Emit(OpCodes.Ldc_I4_1); gen.Emit(OpCodes.Add); gen.Emit(OpCodes.Stloc, locI); // loop test // i < count && hasRows gen.MarkLabel(labLoopTest); gen.Emit(OpCodes.Ldloc, locI); gen.Emit(OpCodes.Ldloc, locCount); gen.Emit(OpCodes.Clt); gen.Emit(OpCodes.Ldloc, locHasRows); gen.Emit(OpCodes.And); gen.Emit(OpCodes.Brtrue, labLoopTop); // return list; gen.Emit(OpCodes.Ldloc, locList); return listType; }
internal override SqlExpression VisitJoinedCollection(SqlJoinedCollection jc) { if(!_isDebugMode) { throw Error.InvalidFormatNode("JoinedCollection"); } _commandStringBuilder.Append("big-join("); this.Visit(jc.Expression); _commandStringBuilder.Append(", "); this.Visit(jc.Count); _commandStringBuilder.Append(")"); return jc; }
internal override SqlExpression VisitJoinedCollection(SqlJoinedCollection jc) { return new SqlJoinedCollection(jc.ClrType, jc.SqlType, this.VisitExpression(jc.Expression), this.VisitExpression(jc.Count), jc.SourceExpression); }