public IExecuteResult Execute(IProvider provider, object[] parentArgs, object[] userArgs) { if(parentArgs == null && !(this.parameters == null || this.parameters.Count == 0)) { throw Error.ArgumentNull("arguments"); } // construct new copy of query info List<SqlParameterInfo> spis = new List<SqlParameterInfo>(this.queryInfo.Parameters); // add call arguments for(int i = 0, n = this.parameters.Count; i < n; i++) { spis.Add(new SqlParameterInfo(this.parameters[i], parentArgs[i])); } QueryInfo qi = new QueryInfo( this.queryInfo.Query, this.queryInfo.CommandText, spis.AsReadOnly(), this.queryInfo.ResultShape, this.queryInfo.ResultType ); // execute query return provider.Execute(null, qi, this.factory, parentArgs, userArgs, subQueries, null); }
internal AdoCompiledQuery(IReaderProvider provider, Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, ICompiledSubQuery[] subQueries) { this.originalShape = provider.Services.Context.LoadOptions; this.query = query; this.queryInfos = queryInfos; this.factory = factory; this.subQueries = subQueries; }
internal CompiledSubQuery(QueryInfo queryInfo, IObjectReaderFactory factory, ReadOnlyCollection<Provider.NodeTypes.SqlParameter> parameters, ICompiledSubQuery[] subQueries) { this.queryInfo = queryInfo; this.factory = factory; this.parameters = parameters; this.subQueries = subQueries; }
/// <summary> /// Executes all queries /// </summary> /// <param name="query">The query.</param> /// <param name="queryInfos">The query infos.</param> /// <param name="factory">The factory.</param> /// <param name="userArguments">The user arguments.</param> /// <param name="subQueries">The sub queries.</param> /// <returns></returns> IExecuteResult IProvider.ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, object[] userArguments, ICompiledSubQuery[] subQueries) { return this.ExecuteAll(query, queryInfos, factory, userArguments, subQueries); }
IExecuteResult IProvider.Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, object[] parentArgs, object[] userArgs, ICompiledSubQuery[] subQueries, object lastResult) { return this.Execute(query, queryInfo, factory, parentArgs, userArgs, subQueries, lastResult); }
/// <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); } } }
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) }; } }
private IExecuteResult ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, object[] userArguments, ICompiledSubQuery[] subQueries) { IExecuteResult result = null; object lastResult = null; for(int i = 0, n = queryInfos.Length; i < n; i++) { if(i < n - 1) { result = this.Execute(query, queryInfos[i], null, null, userArguments, subQueries, lastResult); } else { result = this.Execute(query, queryInfos[i], factory, null, userArguments, subQueries, lastResult); } if(queryInfos[i].ResultShape == ResultShape.Return) { lastResult = result.ReturnValue; } } return result; }
private IExecuteResult Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, object[] parentArgs, object[] userArgs, ICompiledSubQuery[] subQueries, object lastResult) { this.InitializeProviderMode(); DbConnection con = _conManager.UseConnection(this); try { DbCommand cmd = con.CreateCommand(); cmd.CommandText = queryInfo.CommandText; cmd.Transaction = _conManager.Transaction; cmd.CommandTimeout = _commandTimeout; AssignParameters(cmd, queryInfo.Parameters, userArgs, lastResult); LogCommand(_log, cmd); _queryCount += 1; switch(queryInfo.ResultShape) { default: case ResultShape.Return: { return new ExecuteResult(cmd, queryInfo.Parameters, null, cmd.ExecuteNonQuery(), true); } case ResultShape.Singleton: { DbDataReader reader = cmd.ExecuteReader(); IObjectReader objReader = factory.Create(reader, true, this, parentArgs, userArgs, subQueries); _conManager.UseConnection(objReader.Session); try { IEnumerable sequence = (IEnumerable)Activator.CreateInstance( typeof(OneTimeEnumerable<>).MakeGenericType(queryInfo.ResultType), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new object[] { objReader }, null ); object value = null; MethodCallExpression mce = query as MethodCallExpression; MethodInfo sequenceMethod = null; if(mce != null && ( mce.Method.DeclaringType == typeof(Queryable) || mce.Method.DeclaringType == typeof(Enumerable)) ) { switch(mce.Method.Name) { case "First": case "FirstOrDefault": case "SingleOrDefault": sequenceMethod = TypeSystem.FindSequenceMethod(mce.Method.Name, sequence); break; case "Single": default: sequenceMethod = TypeSystem.FindSequenceMethod("Single", sequence); break; } } else { sequenceMethod = TypeSystem.FindSequenceMethod("SingleOrDefault", sequence); } // When dynamically invoking the sequence method, we want to // return the inner exception if the invocation fails if(sequenceMethod != null) { try { value = sequenceMethod.Invoke(null, new object[] { sequence }); } catch(TargetInvocationException tie) { if(tie.InnerException != null) { throw tie.InnerException; } throw; } } return new ExecuteResult(cmd, queryInfo.Parameters, objReader.Session, value); } finally { objReader.Dispose(); } } case ResultShape.Sequence: { DbDataReader reader = cmd.ExecuteReader(); IObjectReader objReader = factory.Create(reader, true, this, parentArgs, userArgs, subQueries); _conManager.UseConnection(objReader.Session); IEnumerable sequence = (IEnumerable)Activator.CreateInstance( typeof(OneTimeEnumerable<>).MakeGenericType(TypeSystem.GetElementType(queryInfo.ResultType)), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new object[] { objReader }, null ); if(typeof(IQueryable).IsAssignableFrom(queryInfo.ResultType)) { sequence = sequence.AsQueryable(); } ExecuteResult result = new ExecuteResult(cmd, queryInfo.Parameters, objReader.Session); MetaFunction function = this.GetFunction(query); if(function != null && !function.IsComposable) { sequence = (IEnumerable)Activator.CreateInstance( typeof(SingleResult<>).MakeGenericType(TypeSystem.GetElementType(queryInfo.ResultType)), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new object[] { sequence, result, _services.Context }, null ); } result.ReturnValue = sequence; return result; } case ResultShape.MultipleResults: { DbDataReader reader = cmd.ExecuteReader(); IObjectReaderSession session = _readerCompiler.CreateSession(reader, this, parentArgs, userArgs, subQueries); _conManager.UseConnection(session); MetaFunction function = this.GetFunction(query); ExecuteResult result = new ExecuteResult(cmd, queryInfo.Parameters, session); result.ReturnValue = new MultipleResults(this, function, session, result); return result; } } } finally { _conManager.ReleaseConnection(this); } }