internal static SqlNode Reduce(SqlNode node, SqlNodeAnnotations annotations, Enum[] providerModesWithIncompatibilities) { Reducer r = new Reducer(providerModesWithIncompatibilities) { Annotations = annotations }; return(r.Visit(node)); }
/// <summary> /// Checks whether the given node is supported on the given server. /// </summary> /// <param name="node">The node.</param> /// <param name="annotations">The annotations.</param> /// <param name="providerMode">The provider mode to check for.</param> internal static void ThrowIfUnsupported(SqlNode node, SqlNodeAnnotations annotations, Enum providerMode) { // Check to see whether there's at least one SqlServerCompatibilityAnnotation. if(annotations.HasAnnotationType(typeof(CompatibilityAnnotation))) { Visitor visitor = new Visitor(providerMode) {annotations = annotations}; visitor.Visit(node); // If any messages were recorded, then throw an exception. if(visitor.reasons.Count > 0) { throw Error.ExpressionNotSupportedForSqlServerVersion(visitor.reasons); } } }
/// <summary> /// Checks whether the given node is supported on the given server. /// </summary> /// <param name="node">The node.</param> /// <param name="annotations">The annotations.</param> /// <param name="providerMode">The provider mode to check for.</param> internal static void ThrowIfUnsupported(SqlNode node, SqlNodeAnnotations annotations, Enum providerMode) { // Check to see whether there's at least one SqlServerCompatibilityAnnotation. if (annotations.HasAnnotationType(typeof(CompatibilityAnnotation))) { Visitor visitor = new Visitor(providerMode) { annotations = annotations }; visitor.Visit(node); // If any messages were recorded, then throw an exception. if (visitor.reasons.Count > 0) { throw Error.ExpressionNotSupportedForSqlServerVersion(visitor.reasons); } } }
private IObjectReaderFactory GetDefaultFactory(MetaType rowType) { if(rowType == null) { throw Error.ArgumentNull("rowType"); } SqlNodeAnnotations annotations = new SqlNodeAnnotations(); Expression tmp = Expression.Constant(null); SqlUserQuery suq = new SqlUserQuery(string.Empty, null, null, tmp); if(TypeSystem.IsSimpleType(rowType.Type)) { // if the element type is a simple type (int, bool, etc.) we create // a single column binding SqlUserColumn col = new SqlUserColumn(rowType.Type, _typeProvider.From(rowType.Type), suq, "", false, suq.SourceExpression); suq.Columns.Add(col); suq.Projection = col; } else { // ... otherwise we generate a default projection SqlUserRow rowExp = new SqlUserRow(rowType.InheritanceRoot, _typeProvider.GetApplicationType((int)ConverterSpecialTypes.Row), suq, tmp); suq.Projection = _translator.BuildProjection(rowExp, rowType, true, null, tmp); } Type resultType = TypeSystem.GetSequenceType(rowType.Type); QueryInfo[] qis = this.BuildQuery(ResultShape.Sequence, resultType, suq, null, annotations); return this.GetReaderFactory(qis[qis.Length - 1].Query, rowType.Type); }
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) }; } }
internal QueryInfo[] BuildQuery(Expression query, SqlNodeAnnotations annotations) { this.CheckDispose(); // apply maximal funcletization query = Funcletizer.Funcletize(query); // convert query nodes into sql nodes QueryConverter converter = new QueryConverter(_services, _typeProvider, _translator, _sqlFactory); switch(this.Mode) { case SqlServerProviderMode.Sql2000: converter.ConverterStrategy = ConverterStrategy.CanUseScopeIdentity | ConverterStrategy.CanUseJoinOn | ConverterStrategy.CanUseRowStatus; break; case SqlServerProviderMode.Sql2005: case SqlServerProviderMode.Sql2008: converter.ConverterStrategy = ConverterStrategy.CanUseScopeIdentity | ConverterStrategy.SkipWithRowNumber | ConverterStrategy.CanUseRowStatus | ConverterStrategy.CanUseJoinOn | ConverterStrategy.CanUseOuterApply | ConverterStrategy.CanOutputFromInsert; break; case SqlServerProviderMode.SqlCE: converter.ConverterStrategy = ConverterStrategy.CanUseOuterApply; // Can't set ConverterStrategy.CanUseJoinOn because scalar subqueries in the ON clause // can't be converted into anything. break; } SqlNode node = converter.ConvertOuter(query); return this.BuildQuery(this.GetResultShape(query), this.GetResultType(query), node, null, annotations); }
DbCommand IProvider.GetCommand(Expression query) { this.CheckDispose(); this.CheckInitialized(); if(query == null) { throw Error.ArgumentNull("query"); } this.InitializeProviderMode(); SqlNodeAnnotations annotations = new SqlNodeAnnotations(); QueryInfo[] qis = this.BuildQuery(query, annotations); QueryInfo qi = qis[qis.Length - 1]; DbCommand cmd = _conManager.Connection.CreateCommand(); cmd.CommandText = qi.CommandText; cmd.Transaction = _conManager.Transaction; cmd.CommandTimeout = _commandTimeout; AssignParameters(cmd, qi.Parameters, null, null); return cmd; }
/// <summary> /// Executes the query specified as a LINQ expression tree. /// </summary> /// <param name="query"></param> /// <returns> /// A result object from which you can obtain the return value and output parameters. /// </returns> private IExecuteResult Execute(Expression query) { this.CheckDispose(); this.CheckInitialized(); this.CheckNotDeleted(); if(query == null) { throw Error.ArgumentNull("query"); } this.InitializeProviderMode(); query = Funcletizer.Funcletize(query); if(this.EnableCacheLookup) { IExecuteResult cached = this.GetCachedResult(query); if(cached != null) { return cached; } } SqlNodeAnnotations annotations = new SqlNodeAnnotations(); QueryInfo[] qis = this.BuildQuery(query, annotations); CheckSqlCompatibility(qis, annotations); LambdaExpression lambda = query as LambdaExpression; if(lambda != null) { query = lambda.Body; } IObjectReaderFactory factory = null; ICompiledSubQuery[] subQueries = null; QueryInfo qi = qis[qis.Length - 1]; if(qi.ResultShape == ResultShape.Singleton) { subQueries = this.CompileSubQueries(qi.Query); factory = this.GetReaderFactory(qi.Query, qi.ResultType); } else if(qi.ResultShape == ResultShape.Sequence) { subQueries = this.CompileSubQueries(qi.Query); factory = this.GetReaderFactory(qi.Query, TypeSystem.GetElementType(qi.ResultType)); } IExecuteResult result = this.ExecuteAll(query, qis, factory, null, subQueries); return result; }
/// <summary> /// Look for compatibility annotations for the set of providers we /// add annotations for. /// </summary> private void CheckSqlCompatibility(QueryInfo[] queries, SqlNodeAnnotations annotations) { if(this.Mode == SqlServerProviderMode.Sql2000 || this.Mode == SqlServerProviderMode.SqlCE) { for(int i = 0, n = queries.Length; i < n; i++) { CompatibilityCheck.ThrowIfUnsupported(queries[i].Query, annotations, this.Mode); } } }
internal Visitor(NodeFactory factory, SqlNodeAnnotations annotations) { this.factory = factory; this.annotations = annotations; }
internal static SqlNode Reduce(SqlNode node, NodeFactory factory, SqlNodeAnnotations annotations) { Visitor r = new Visitor(factory, annotations); return(r.Visit(node)); }
internal static SqlNode Reduce(SqlNode node, NodeFactory factory, SqlNodeAnnotations annotations) { Visitor r = new Visitor(factory, annotations); return r.Visit(node); }
ICompiledQuery IProvider.Compile(Expression query) { this.CheckDispose(); this.CheckInitialized(); if(query == null) { throw Error.ArgumentNull("query"); } this.InitializeProviderMode(); #warning [FB] POSSIBLE CLONE OF CODE FOUND IN IProvider.Execute SqlNodeAnnotations annotations = new SqlNodeAnnotations(); QueryInfo[] qis = this.BuildQuery(query, annotations); CheckSqlCompatibility(qis, annotations); LambdaExpression lambda = query as LambdaExpression; if(lambda != null) { query = lambda.Body; } IObjectReaderFactory factory = null; ICompiledSubQuery[] subQueries = null; QueryInfo qi = qis[qis.Length - 1]; if(qi.ResultShape == ResultShape.Singleton) { subQueries = this.CompileSubQueries(qi.Query); factory = this.GetReaderFactory(qi.Query, qi.ResultType); } else if(qi.ResultShape == ResultShape.Sequence) { subQueries = this.CompileSubQueries(qi.Query); factory = this.GetReaderFactory(qi.Query, TypeSystem.GetElementType(qi.ResultType)); } return new AdoCompiledQuery(this, query, qis, factory, subQueries); }
internal Visitor(SqlNodeAnnotations annotations, NodeFactory sql) { this.annotations = annotations; this.sql = sql; }
private ICompiledSubQuery CompileSubQuery(SqlNode query, Type elementType, ReadOnlyCollection<System.Data.Linq.Provider.NodeTypes.SqlParameter> parameters) { query = SqlDuplicator.Copy(query); SqlNodeAnnotations annotations = new SqlNodeAnnotations(); QueryInfo[] qis = this.BuildQuery(ResultShape.Sequence, TypeSystem.GetSequenceType(elementType), query, parameters, annotations); System.Diagnostics.Debug.Assert(qis.Length == 1); QueryInfo qi = qis[0]; ICompiledSubQuery[] subQueries = this.CompileSubQueries(qi.Query); IObjectReaderFactory factory = this.GetReaderFactory(qi.Query, elementType); CheckSqlCompatibility(qis, annotations); return new CompiledSubQuery(qi, factory, parameters, subQueries); }
internal static SqlNode Reduce(SqlNode node, SqlNodeAnnotations annotations, NodeFactory sql) { return new Visitor(annotations, sql).Visit(node); }
string IProvider.GetQueryText(Expression query) { this.CheckDispose(); this.CheckInitialized(); if(query == null) { throw Error.ArgumentNull("query"); } this.InitializeProviderMode(); SqlNodeAnnotations annotations = new SqlNodeAnnotations(); QueryInfo[] qis = this.BuildQuery(query, annotations); StringBuilder sb = new StringBuilder(); for(int i = 0, n = qis.Length; i < n; i++) { QueryInfo qi = qis[i]; #if DEBUG StringWriter writer = new StringWriter(System.Globalization.CultureInfo.InvariantCulture); DbCommand cmd = _conManager.Connection.CreateCommand(); cmd.CommandText = qi.CommandText; AssignParameters(cmd, qi.Parameters, null, null); LogCommand(writer, cmd); sb.Append(writer.ToString()); #else sb.Append(qi.CommandText); sb.AppendLine(); #endif } return sb.ToString(); }
internal SqlParameterizer(TypeSystemProvider typeProvider, SqlNodeAnnotations annotations) { this._typeProvider = typeProvider; this._annotations = annotations; }
internal static SqlNode Reduce(SqlNode node, SqlNodeAnnotations annotations, Enum[] providerModesWithIncompatibilities) { Reducer r = new Reducer(providerModesWithIncompatibilities) {Annotations = annotations}; return r.Visit(node); }
internal SqlNode AddConversions(SqlNode node, SqlNodeAnnotations annotations) { visitor.Annotations = annotations; return visitor.Visit(node); }