private ProviderType timeProviderType; // for special case handling of DateTime parameters internal SqlParameterInfoProducer(SqlParameterizer parameterizer) { this.parameterizer = parameterizer; this.topLevel = true; this.map = new Dictionary<object, SqlParameterInfo>(); this.currentParams = new List<SqlParameterInfo>(); }
private ProviderType timeProviderType; // for special case handling of DateTime parameters internal SqlParameterInfoProducer(SqlParameterizer parameterizer) { this.parameterizer = parameterizer; this.topLevel = true; this.map = new Dictionary <object, SqlParameterInfo>(); this.currentParams = new List <SqlParameterInfo>(); }
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) }; } }