protected override bool CanGenerateColumnar() { var typeOfTKey = typeof(TKey); var typeOfTSource = typeof(TPayload); var typeOfTResult = typeof(TResult); if (!typeOfTSource.CanRepresentAsColumnar()) { return(false); } if (!typeOfTResult.CanRepresentAsColumnar()) { return(false); } if (typeOfTKey.GetPartitionType() != null) { return(false); } var lookupKey = CacheKey.Create(this.Selector.ExpressionToCSharp(), this.HasStartEdge, this.HasKey); var generatedPipeType = cachedPipes.GetOrAdd(lookupKey, key => SelectTemplate.Generate(this)); this.errorMessages = generatedPipeType.Item2; return(generatedPipeType.Item1 != null); }
private UnaryPipe <TKey, TPayload, TResult> GetPipe(IStreamObserver <TKey, TResult> observer) { var lookupKey = CacheKey.Create(this.Selector.ExpressionToCSharp(), this.HasStartEdge, this.HasKey); var generatedPipeType = cachedPipes.GetOrAdd(lookupKey, key => SelectTemplate.Generate(this)); Func <PlanNode, IQueryObject, PlanNode> planNode = (PlanNode p, IQueryObject o) => new SelectPlanNode(p, o, typeof(TKey), typeof(TPayload), typeof(TResult), this.Selector, this.HasKey, this.HasStartEdge, true, generatedPipeType.Item2); var instance = Activator.CreateInstance(generatedPipeType.Item1, this, observer, planNode); var returnValue = (UnaryPipe <TKey, TPayload, TResult>)instance; return(returnValue); }
public static Tuple <Type, string> Generate <TKey, TPayload, TResult>(SelectStreamable <TKey, TPayload, TResult> stream) { Contract.Ensures(Contract.Result <Tuple <Type, string> >() == null || typeof(UnaryPipe <TKey, TPayload, TResult>).GetTypeInfo().IsAssignableFrom(Contract.Result <Tuple <Type, string> >().Item1)); string generatedClassName; string errorMessages = null; try { var keyType = typeof(TKey); var payloadType = typeof(TPayload); var resultType = typeof(TResult); generatedClassName = string.Format("Select_{0}_{1}_{2}_{3}", keyType.GetValidIdentifier(), payloadType.GetValidIdentifier(), resultType.GetValidIdentifier(), sequenceNumber++); var template = new SelectTemplate(generatedClassName, keyType, payloadType, resultType); var tm = new TypeMapper(keyType, payloadType, resultType); var gps = tm.GenericTypeVariables(keyType, payloadType, resultType); template.genericParameters = gps.BracketedCommaSeparatedString(); template.numberOfGenericParameters = gps.Count(); template.TKeyTResultGenericParameters = tm.GenericTypeVariables(keyType, resultType).BracketedCommaSeparatedString(); template.MemoryPoolGenericParameters = $"<{template.TKey}, {template.TResult}>"; if (resultType == typeof(int) || resultType == typeof(long) || resultType == typeof(string)) { template.MemoryPoolGenericParameters = string.Empty; } var payloadParameterIndex = 0; if (stream.HasKey && stream.HasStartEdge) { payloadParameterIndex = 2; } else if (stream.HasKey || stream.HasStartEdge) { payloadParameterIndex = 1; } template.PARAMETER = stream.Selector.Parameters[payloadParameterIndex].Name; template.resultPayloadRepresentation = new ColumnarRepresentation(resultType); template.destinationFields = template.resultPayloadRepresentation.AllFields; if (template.numberOfGenericParameters > 0) { generatedClassName = generatedClassName + "`" + template.numberOfGenericParameters.ToString(CultureInfo.InvariantCulture); } var resultSelector = stream.Selector; var sourceMessageType = StreamMessageManager.GetStreamMessageType <TKey, TPayload>(); var parameterSubsitutions = new List <Tuple <ParameterExpression, SelectParameterInformation> >(); // Don't create a parameter substitution for the start edge parameter. That will just remain in the // body of the result selector and will be set as a local variable in the generated code. if (stream.HasKey) { var keyRepresentation = new ColumnarRepresentation(keyType, "key"); var keyParameterIndex = stream.HasStartEdge ? 1 : 0; parameterSubsitutions.Add(Tuple.Create( resultSelector.Parameters.ElementAt(keyParameterIndex), new SelectParameterInformation() { BatchName = "sourceBatch", BatchType = sourceMessageType, IndexVariableName = "i", parameterRepresentation = keyRepresentation, })); } parameterSubsitutions.Add(Tuple.Create( resultSelector.Parameters.ElementAt(payloadParameterIndex), new SelectParameterInformation() { BatchName = "sourceBatch", BatchType = sourceMessageType, IndexVariableName = "i", parameterRepresentation = new ColumnarRepresentation(payloadType) })); var projectionResult = SelectTransformer.Transform(resultSelector, parameterSubsitutions, template.resultPayloadRepresentation, false, stream.HasStartEdge); if (projectionResult.Error) { if (Config.CodegenOptions.SuperStrictColumnar) { throw new InvalidOperationException("Code Generation couldn't transform a selector!"); } return(Tuple.Create((Type)null, errorMessages)); } template.StartEdgeParameterName = stream.HasStartEdge ? resultSelector.Parameters.ElementAt(0).Name : null; template.computedFields = projectionResult.ComputedFields; template.swingingFields = projectionResult.SwingingFields; template.unassignedFields = projectionResult.UnmentionedFields; template.ProjectionReturningResultInstance = projectionResult.ProjectionReturningResultInstance; template.multiStringOperations = projectionResult.MultiStringOperations; template.needSourceInstance = projectionResult.NeedsSourceInstance; var d = new Dictionary <MyFieldInfo, int>(); foreach (var f in template.swingingFields) { var target = f.Item1; var source = f.Item2; if (!d.ContainsKey(source)) { d.Add(source, 0); } d[source] = d[source] + 1; } template.swungFieldsCount = d; template.nonSwingingFields = template.fields.Where(sf => !template.swingingFields.Any(swingingField => swingingField.Item2.Equals(sf))); var expandedCode = template.TransformText(); var assemblyReferences = Transformer.AssemblyReferencesNeededFor( typeof(TKey), typeof(TPayload), typeof(TResult), typeof(IStreamable <,>)); assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TPayload>()); assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TResult>()); assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <TKey, TResult>()); assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(stream.Selector)); var a = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages); var t = a.GetType(generatedClassName); t = t.InstantiateAsNecessary(typeof(TKey), typeof(TPayload), typeof(TResult)); return(Tuple.Create(t, errorMessages)); } catch { if (Config.CodegenOptions.DontFallBackToRowBasedExecution) { throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!"); } return(Tuple.Create((Type)null, errorMessages)); } }