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;
		}
Exemple #3
0
 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);
		}