예제 #1
0
		internal MemberAccessBinder(SqlBinder binder, Translator translator, SqlColumnizer columnizer, NodeFactory sqlFactory, MetaModel model, DataLoadOptions shape, bool canUseOuterApply) {
			this.binder = binder;
			this.translator = translator;
			this.columnizer = columnizer;
			this.sql = sqlFactory;
			this.typeProvider = sqlFactory.TypeProvider;
			this.expander = new SqlExpander(this.sql);
			this.aggregateChecker = new SqlAggregateChecker();
			this.linkMap = new LinkOptimizationScope(null);
			this.outerAliasMap = new Dictionary<SqlAlias, SqlAlias>();
			this.model = model;
			this.shape = shape;
			this.canUseOuterApply = canUseOuterApply;
		}
예제 #2
0
		private QueryInfo[] BuildQuery(ResultShape resultShape, Type resultType, SqlNode node, ReadOnlyCollection<System.Data.Linq.Provider.NodeTypes.SqlParameter> parentParameters, SqlNodeAnnotations annotations)
		{
			System.Diagnostics.Debug.Assert(resultType != null);
			System.Diagnostics.Debug.Assert(node != null);

			SqlSupersetValidator validator = new SqlSupersetValidator();

			// These are the rules that apply to every SQL tree.
			if(_checkQueries)
			{
				validator.AddValidator(new ColumnTypeValidator()); /* Column CLR Type must agree with its Expressions CLR Type */
				validator.AddValidator(new LiteralValidator()); /* Constrain literal Types */
			}

			validator.Validate(node);

			SqlColumnizer columnizer = new SqlColumnizer();

			// resolve member references
			bool canUseOuterApply = (this.Mode == SqlServerProviderMode.Sql2005 || this.Mode == SqlServerProviderMode.Sql2008 || this.Mode == SqlServerProviderMode.SqlCE);
			SqlBinder binder = new SqlBinder(_translator, _sqlFactory, _services.Model, _services.Context.LoadOptions, columnizer, canUseOuterApply);
			binder.OptimizeLinkExpansions = (_optimizationFlags & OptimizationFlags.OptimizeLinkExpansions) != 0;
			binder.SimplifyCaseStatements = (_optimizationFlags & OptimizationFlags.SimplifyCaseStatements) != 0;
			binder.PreBinder = delegate(SqlNode n)
			{
				// convert methods into known reversable operators
				return PreBindDotNetConverter.Convert(n, _sqlFactory, _services.Model);
			};
			node = binder.Bind(node);
			if(_checkQueries)
			{
				validator.AddValidator(new ExpectNoAliasRefs());
				validator.AddValidator(new ExpectNoSharedExpressions());
			}
			validator.Validate(node);

			node = PostBindDotNetConverter.Convert(node, _sqlFactory, this.Mode);

			// identify true flow of sql data types 
			SqlRetyper retyper = new SqlRetyper(new SqlFactory(_typeProvider, _services.Model));
			node = retyper.Retype(node);
			validator.Validate(node);

			// change CONVERT to special conversions like UNICODE,CHAR,...
			SqlTypeConverter converter = new SqlTypeConverter(_sqlFactory);
			node = converter.Visit(node);
			validator.Validate(node);

			// transform type-sensitive methods such as LEN (to DATALENGTH), ...
			SqlMethodTransformer methodTransformer = new SqlMethodTransformer(_sqlFactory);
			node = methodTransformer.Visit(node);
			validator.Validate(node);

			// convert multisets into separate queries
			SqlMultiplexerOptionType options = (this.Mode == SqlServerProviderMode.Sql2008 ||
											  this.Mode == SqlServerProviderMode.Sql2005 ||
											  this.Mode == SqlServerProviderMode.SqlCE)
				? SqlMultiplexerOptionType.EnableBigJoin : SqlMultiplexerOptionType.None;
			SqlMultiplexer mux = new SqlMultiplexer(options, parentParameters, _sqlFactory);
			node = mux.Multiplex(node);
			validator.Validate(node);

			// convert object construction expressions into flat row projections
			SqlFlattener flattener = new SqlFlattener(_sqlFactory, columnizer);
			node = flattener.Flatten(node);
			validator.Validate(node);

			if(_mode == SqlServerProviderMode.SqlCE)
			{
				SqlRewriteScalarSubqueries rss = new SqlRewriteScalarSubqueries(_sqlFactory);
				node = rss.Rewrite(node);
			}

			// Simplify case statements where all alternatives map to the same thing.
			// Doing this before deflator because the simplified results may lead to
			// more deflation opportunities.
			// Doing this before booleanizer because it may convert CASE statements (non-predicates) into
			// predicate expressions.
			// Doing this before reorderer because it may reduce some orders to constant nodes which should not
			// be passed onto ROW_NUMBER.
			node = SqlCaseSimplifier.Simplify(node, _sqlFactory);

			// Rewrite order-by clauses so that they only occur at the top-most select 
			// or in selects with TOP
			SqlReorderer reorderer = new SqlReorderer(_typeProvider, _sqlFactory);
			node = reorderer.Reorder(node);
			validator.Validate(node);

			// Inject code to turn predicates into bits, and bits into predicates where necessary
			node = SqlBooleanizer.Rationalize(node, _typeProvider, _services.Model);
			if(_checkQueries)
			{
				validator.AddValidator(new ExpectRationalizedBooleans()); /* From now on all boolean expressions should remain rationalized. */
			}
			validator.Validate(node);

			if(_checkQueries)
			{
				validator.AddValidator(new ExpectNoFloatingColumns());
			}

			// turning predicates into bits/ints can change Sql types, propagate changes            
			node = retyper.Retype(node);
			validator.Validate(node);

			// assign aliases to columns
			// we need to do this now so that the sql2k lifters will work
			SqlAliaser aliaser = new SqlAliaser();
			node = aliaser.AssociateColumnsWithAliases(node);
			validator.Validate(node);

			// SQL2K enablers.
			node = SqlLiftWhereClauses.Lift(node, new SqlFactory(_typeProvider, _services.Model));
			node = SqlLiftIndependentRowExpressions.Lift(node);
			node = SqlOuterApplyReducer.Reduce(node, _sqlFactory, annotations);
			node = SqlTopReducer.Reduce(node, annotations, _sqlFactory);

			// resolve references to columns in other scopes by adding them
			// to the intermediate selects
			SqlResolver resolver = new SqlResolver();
			node = resolver.Resolve(node);
			validator.Validate(node);

			// re-assign aliases after resolving (new columns may have been added)
			node = aliaser.AssociateColumnsWithAliases(node);
			validator.Validate(node);

			// fixup union projections
			node = SqlUnionizer.Unionize(node);

			// remove order-by of literals
			node = SqlRemoveConstantOrderBy.Remove(node);

			// throw out unused columns and redundant sub-queries...
			SqlDeflator deflator = new SqlDeflator();
			node = deflator.Deflate(node);
			validator.Validate(node);

			// Positioning after deflator because it may remove unnecessary columns
			// from SELECT projection lists and allow more CROSS APPLYs to be reduced
			// to CROSS JOINs.
			node = SqlCrossApplyToCrossJoin.Reduce(node, annotations, new Enum[] { SqlServerProviderMode.Sql2000 });

			// fixup names for aliases, columns, locals, etc..
			SqlNamer namer = new SqlNamer();
			node = namer.AssignNames(node);
			validator.Validate(node);

			// Convert [N]Text,Image to [N]VarChar(MAX),VarBinary(MAX) where necessary.
			// These new types do not exist on SQL2k, so add annotations.
			LongTypeConverter longTypeConverter = new LongTypeConverter(_sqlFactory);
			node = longTypeConverter.AddConversions(node, annotations);

			// final validation            
			validator.AddValidator(new ExpectNoMethodCalls());
			validator.AddValidator(new ValidateNoInvalidComparison());
			validator.Validate(node);

			SqlParameterizer parameterizer = new SqlParameterizer(_typeProvider, annotations);
			SqlFormatter formatter = new SqlFormatter();
			if(_mode == SqlServerProviderMode.SqlCE ||
				_mode == SqlServerProviderMode.Sql2005 ||
				_mode == SqlServerProviderMode.Sql2008)
			{
				formatter.ParenthesizeTop = true;
			}

			SqlBlock block = node as SqlBlock;
			if(block != null && _mode == SqlServerProviderMode.SqlCE)
			{
				// SQLCE cannot batch multiple statements.
				ReadOnlyCollection<ReadOnlyCollection<SqlParameterInfo>> parameters = parameterizer.ParameterizeBlock(block);
				string[] commands = formatter.FormatBlock(block, false);
				QueryInfo[] queries = new QueryInfo[commands.Length];
				for(int i = 0, n = commands.Length; i < n; i++)
				{
					queries[i] = new QueryInfo(
						block.Statements[i],
						commands[i],
						parameters[i],
						(i < n - 1) ? ResultShape.Return : resultShape,
						(i < n - 1) ? typeof(int) : resultType
						);
				}
				return queries;
			}
			else
			{
				// build only one result
				ReadOnlyCollection<SqlParameterInfo> parameters = parameterizer.Parameterize(node);
				string commandText = formatter.Format(node);
				return new QueryInfo[] {
                    new QueryInfo(node, commandText, parameters, resultShape, resultType)
                    };
			}
		}
예제 #3
0
		internal SqlFlattener(NodeFactory sql, SqlColumnizer columnizer)
		{
			this.visitor = new ObjectExpressionFlattener(sql, columnizer);
		}
예제 #4
0
 internal SqlBinder(Translator translator, NodeFactory sqlFactory, MetaModel model, DataLoadOptions shape, SqlColumnizer columnizer, bool canUseOuterApply) {
     this.sql = sqlFactory;
     this.columnizer = columnizer;
     this.visitor = new MemberAccessBinder(this, translator, this.columnizer, this.sql, model, shape, canUseOuterApply);
 }
		internal ObjectExpressionFlattener(NodeFactory sql, SqlColumnizer columnizer)
		{
			this.sql = sql;
			this.columnizer = columnizer;
			this.isTopLevel = true;
		}
예제 #6
0
 internal SqlBinder(Translator translator, NodeFactory sqlFactory, MetaModel model, DataLoadOptions shape, SqlColumnizer columnizer, bool canUseOuterApply)
 {
     this.sql        = sqlFactory;
     this.columnizer = columnizer;
     this.visitor    = new MemberAccessBinder(this, translator, this.columnizer, this.sql, model, shape, canUseOuterApply);
 }
예제 #7
0
 internal SqlFlattener(NodeFactory sql, SqlColumnizer columnizer)
 {
     this.visitor = new ObjectExpressionFlattener(sql, columnizer);
 }