private bool IsEventProviding( ExprNode parameter, ExprValidationContext validationContext) { if (parameter is ExprEnumerationForgeProvider) { ExprEnumerationForgeProvider provider = (ExprEnumerationForgeProvider) parameter; ExprEnumerationForgeDesc desc = provider.GetEnumerationForge( validationContext.StreamTypeService, validationContext.ContextDescriptor); EventType eventType = desc?.Forge.GetEventTypeSingle(validationContext.StatementRawInfo, validationContext.StatementCompileTimeService); return eventType != null; } ExprForge forge = parameter.Forge; ExprEnumerationForge enumerationForge = forge as ExprEnumerationForge; return enumerationForge?.GetEventTypeSingle( validationContext.StatementRawInfo, validationContext.StatementCompileTimeService) != null; }
public override ExprNode Validate(ExprValidationContext validationContext) { this.exprValidationContext = validationContext; var prototype = PrototypeWVisibility; if (prototype.IsAlias) { if (!ChainParameters.IsEmpty()) { throw new ExprValidationException("Expression '" + prototype.Name + " is an expression-alias and does not allow parameters"); } try { ExpressionBodyCopy = ExprNodeUtilityValidate.GetValidatedSubtree( ExprNodeOrigin.ALIASEXPRBODY, ExpressionBodyCopy, validationContext); } catch (ExprValidationException ex) { var message = "Failed to validate expression alias '" + prototype.Name + "': " + ex.Message; throw new ExprValidationException(message, ex); } forge = ExpressionBodyCopy.Forge; return null; } if (forge != null) { return null; // already evaluated } if (ChildNodes.Length > 0) { throw new IllegalStateException("Execution node has its own child nodes"); } // validate chain IList<ExprNode> validated = new List<ExprNode>(); foreach (var expr in ChainParameters) { validated.Add( ExprNodeUtilityValidate.GetValidatedSubtree( ExprNodeOrigin.DECLAREDEXPRPARAM, expr, validationContext)); } ChainParameters = validated; // validate parameter count CheckParameterCount(); // collect event and value (non-event) parameters List<int> valueParameters = new List<int>(); List<int> eventParameters = new List<int>(); for (int i = 0; i < prototype.ParametersNames.Length; i++) { ExprNode parameter = ChainParameters[i]; if (parameter is ExprWildcard) { if (validationContext.StreamTypeService.EventTypes.Length != 1) { throw new ExprValidationException("Expression '" + prototype.Name + "' only allows a wildcard parameter if there is a single stream available, please use a stream or tag name instead"); } } if (IsEventProviding(parameter, validationContext)) { eventParameters.Add(i); } else { valueParameters.Add(i); } } // determine value event type for holding non-event parameter values, if any ObjectArrayEventType valueEventType = null; List<ExprNode> valueExpressions = new List<ExprNode>(valueParameters.Count); if (!valueParameters.IsEmpty()) { var valuePropertyTypes = new LinkedHashMap<string, object>(); foreach (int index in valueParameters) { String name = prototype.ParametersNames[index]; ExprNode expr = ChainParameters[index]; var result = Boxing.GetBoxedType(expr.Forge.EvaluationType); valuePropertyTypes.Put(name, result); valueExpressions.Add(expr); } valueEventType = ExprDotNodeUtility.MakeTransientOAType( PrototypeWVisibility.Name, valuePropertyTypes, validationContext.StatementRawInfo, validationContext.StatementCompileTimeService); } // create context for expression body int numEventTypes = eventParameters.Count + (valueEventType == null ? 0 : 1); EventType[] eventTypes = new EventType[numEventTypes]; String[] streamNames = new String[numEventTypes]; bool[] isIStreamOnly = new bool[numEventTypes]; ExprEnumerationForge[] eventEnumerationForges = new ExprEnumerationForge[numEventTypes]; allStreamIdsMatch = true; int offsetEventType = 0; if (valueEventType != null) { offsetEventType = 1; eventTypes[0] = valueEventType; streamNames[0] = INTERNAL_VALUE_STREAMNAME; isIStreamOnly[0] = true; allStreamIdsMatch = false; } bool forceOptionalStream = false; foreach (int index in eventParameters) { ExprNode parameter = ChainParameters[index]; streamNames[offsetEventType] = prototype.ParametersNames[index]; int streamId; bool istreamOnlyFlag; ExprEnumerationForge forge; if (parameter is ExprEnumerationForgeProvider) { ExprEnumerationForgeProvider enumerationForgeProvider = (ExprEnumerationForgeProvider) parameter; ExprEnumerationForgeDesc desc = enumerationForgeProvider.GetEnumerationForge( validationContext.StreamTypeService, validationContext.ContextDescriptor); forge = desc.Forge; streamId = desc.DirectIndexStreamNumber; istreamOnlyFlag = desc.IsIstreamOnly; } else { forge = (ExprEnumerationForge) parameter.Forge; istreamOnlyFlag = false; streamId = -1; forceOptionalStream = true; // since they may return null, i.e. subquery returning no row or multiple rows etc. } isIStreamOnly[offsetEventType] = istreamOnlyFlag; eventEnumerationForges[offsetEventType] = forge; eventTypes[offsetEventType] = forge.GetEventTypeSingle(validationContext.StatementRawInfo, validationContext.StatementCompileTimeService); if (streamId != index) { allStreamIdsMatch = false; } offsetEventType++; } var streamTypeService = validationContext.StreamTypeService; var optionalStream = forceOptionalStream || streamTypeService.IsOptionalStreams; var copyTypes = new StreamTypeServiceImpl( eventTypes, streamNames, isIStreamOnly, streamTypeService.IsOnDemandStreams, optionalStream); copyTypes.RequireStreamNames = true; // validate expression body in this context try { var expressionBodyContext = new ExprValidationContext(copyTypes, validationContext); ExpressionBodyCopy = ExprNodeUtilityValidate.GetValidatedSubtree( ExprNodeOrigin.DECLAREDEXPRBODY, ExpressionBodyCopy, expressionBodyContext); } catch (ExprValidationException ex) { var message = "Failed to validate expression declaration '" + prototype.Name + "': " + ex.Message; throw new ExprValidationException(message, ex); } // analyze child node var summaryVisitor = new ExprNodeSummaryVisitor(); ExpressionBodyCopy.Accept(summaryVisitor); var isCache = !(summaryVisitor.HasAggregation || summaryVisitor.HasPreviousPrior); isCache &= validationContext.StatementCompileTimeService.Configuration.Compiler.Execution .IsEnabledDeclaredExprValueCache; // determine a suitable evaluation var audit = AuditEnum.EXPRDEF.GetAudit(validationContext.Annotations) != null; var statementName = validationContext.StatementName; if (ExpressionBodyCopy.Forge.ForgeConstantType.IsConstant) { // pre-evaluated forge = new ExprDeclaredForgeConstant( this, ExpressionBodyCopy.Forge.EvaluationType, prototype, ExpressionBodyCopy.Forge.ExprEvaluator.Evaluate(null, true, null), audit, statementName); } else if (valueEventType == null && prototype.ParametersNames.Length == 0 || allStreamIdsMatch && prototype.ParametersNames.Length == streamTypeService.EventTypes.Length) { forge = new ExprDeclaredForgeNoRewrite( this, ExpressionBodyCopy.Forge, isCache, audit, statementName); } else if (valueEventType == null) { forge = new ExprDeclaredForgeRewrite( this, ExpressionBodyCopy.Forge, isCache, eventEnumerationForges, audit, statementName); } else { // cache is always false forge = new ExprDeclaredForgeRewriteWValue( this, ExpressionBodyCopy.Forge, false, audit, statementName, eventEnumerationForges, valueEventType, valueExpressions); } return null; }