private static SelectExprProcessorWInsertTarget GetProcessorInternal(
            SelectProcessorArgs args,
            InsertIntoDesc insertIntoDesc)
        {
            // Wildcard not allowed when insert into specifies column order
            if (args.IsUsingWildcard && insertIntoDesc != null && !insertIntoDesc.ColumnNames.IsEmpty()) {
                throw new ExprValidationException("Wildcard not allowed when insert-into specifies column order");
            }

            var insertIntoTarget = insertIntoDesc == null
                ? null
                : args.EventTypeCompileTimeResolver.GetTypeByName(insertIntoDesc.EventTypeName);

            // Determine wildcard processor (select *)
            if (IsWildcardsOnly(args.SelectionList)) {
                // For joins
                if (args.TypeService.StreamNames.Length > 1 && !(insertIntoTarget is VariantEventType)) {
                    Log.Debug(".getProcessor Using SelectExprJoinWildcardProcessor");
                    SelectExprProcessorForgeWForgables pair = SelectExprJoinWildcardProcessorFactory.Create(args, insertIntoDesc, eventTypeName => eventTypeName);
                    SelectExprProcessorForge forgeX = pair.Forge;
                    return new SelectExprProcessorWInsertTarget(forgeX, null, pair.AdditionalForgeables);
                }

                if (insertIntoDesc == null) {
                    // Single-table selects with no insert-into
                    // don't need extra processing
                    Log.Debug(".getProcessor Using wildcard processor");
                    if (args.TypeService.HasTableTypes) {
                        var table = args.TableCompileTimeResolver.ResolveTableFromEventType(
                            args.TypeService.EventTypes[0]);
                        if (table != null) {
                            SelectExprProcessorForge forgeX = new SelectEvalWildcardTable(table);
                            return new SelectExprProcessorWInsertTarget(forgeX, null, EmptyList<StmtClassForgeableFactory>.Instance);
                        }
                    }

                    SelectExprProcessorForge forgeOuter = new SelectEvalWildcardNonJoin(args.TypeService.EventTypes[0]);
                    return new SelectExprProcessorWInsertTarget(forgeOuter, null, EmptyList<StmtClassForgeableFactory>.Instance);
                }
            }

            // Verify the assigned or name used is unique
            if (insertIntoDesc == null) {
                VerifyNameUniqueness(args.SelectionList);
            }

            // Construct processor
            var buckets = GetSelectExpressionBuckets(args.SelectionList);
            var factory = new SelectExprProcessorHelper(
                buckets.Expressions,
                buckets.SelectedStreams,
                args,
                insertIntoDesc);
            return factory.Forge;
        }
        public static SelectExprProcessorDescriptor GetProcessor(
            SelectProcessorArgs args,
            InsertIntoDesc insertIntoDesc,
            bool withSubscriber)
        {
            IList<StmtClassForgeableFactory> additionalForgeables = new List<StmtClassForgeableFactory>();

            SelectExprProcessorWInsertTarget synthetic = GetProcessorInternal(args, insertIntoDesc);
            additionalForgeables.AddAll(synthetic.AdditionalForgeables);

            // plan serdes for variant event types
            if (synthetic.InsertIntoTargetType is VariantEventType ||
                synthetic.InsertIntoTargetType is WrapperEventType && 
                (((WrapperEventType) synthetic.InsertIntoTargetType).UnderlyingEventType is VariantEventType)) {
                var serdeForgeables = SerdeEventTypeUtility.Plan(
                    synthetic.Forge.ResultEventType,
                    args.StatementRawInfo,
                    args.CompileTimeServices.SerdeEventTypeRegistry,
                    args.CompileTimeServices.SerdeResolver);
                additionalForgeables.AddAll(serdeForgeables);
                foreach (EventType eventType in args.TypeService.EventTypes) {
                    serdeForgeables = SerdeEventTypeUtility.Plan(
                        eventType,
                        args.StatementRawInfo,
                        args.CompileTimeServices.SerdeEventTypeRegistry,
                        args.CompileTimeServices.SerdeResolver);
                    additionalForgeables.AddAll(serdeForgeables);
                }
            }

            if (args.IsFireAndForget || !withSubscriber) {
                return new SelectExprProcessorDescriptor(new SelectSubscriberDescriptor(), synthetic.Forge, additionalForgeables);
            }

            // Handle for-clause delivery contract checking
            ExprNode[] groupedDeliveryExpr = null;
            MultiKeyClassRef groupedDeliveryMultiKey = null;

            var forDelivery = false;
            if (args.ForClauseSpec != null) {
                foreach (var item in args.ForClauseSpec.Clauses) {
                    if (item.Keyword == null) {
                        throw new ExprValidationException(
                            "Expected any of the " +
                            EnumHelper.GetValues<ForClauseKeyword>().RenderAny().ToLowerInvariant() +
                            " for-clause keywords after reserved keyword 'for'");
                    }

                    try {
                        var keyword = EnumHelper.Parse<ForClauseKeyword>(item.Keyword);
                        if (keyword == ForClauseKeyword.GROUPED_DELIVERY && item.Expressions.IsEmpty()) {
                            throw new ExprValidationException(
                                "The for-clause with the " +
                                ForClauseKeyword.GROUPED_DELIVERY.GetName() +
                                " keyword requires one or more grouping expressions");
                        }

                        if (keyword == ForClauseKeyword.DISCRETE_DELIVERY && !item.Expressions.IsEmpty()) {
                            throw new ExprValidationException(
                                "The for-clause with the " +
                                ForClauseKeyword.DISCRETE_DELIVERY.GetName() +
                                " keyword does not allow grouping expressions");
                        }

                        if (forDelivery) {
                            throw new ExprValidationException(
                                "The for-clause with delivery keywords may only occur once in a statement");
                        }
                    }
                    catch (ExprValidationException) {
                        throw;
                    }
                    catch (EPException) {
                        throw;
                    }
                    catch (Exception) {
                        throw new ExprValidationException(
                            "Expected any of the " +
                            EnumHelper.GetValues<ForClauseKeyword>().RenderAny().ToLowerInvariant() +
                            " for-clause keywords after reserved keyword 'for'");
                    }

                    StreamTypeService type = new StreamTypeServiceImpl(synthetic.Forge.ResultEventType, null, false);
                    groupedDeliveryExpr = new ExprNode[item.Expressions.Count];
                    var validationContext = new ExprValidationContextBuilder(
                            type,
                            args.StatementRawInfo,
                            args.CompileTimeServices)
                        .WithAllowBindingConsumption(true)
                        .Build();
                    for (var i = 0; i < item.Expressions.Count; i++) {
                        groupedDeliveryExpr[i] = ExprNodeUtilityValidate.GetValidatedSubtree(
                            ExprNodeOrigin.FORCLAUSE,
                            item.Expressions[i],
                            validationContext);
                    }

                    forDelivery = true;
                    
                    MultiKeyPlan multiKeyPlan = MultiKeyPlanner.PlanMultiKey(
                        groupedDeliveryExpr, false, args.StatementRawInfo, args.SerdeResolver);
                    groupedDeliveryMultiKey = multiKeyPlan.ClassRef;
                    additionalForgeables = multiKeyPlan.MultiKeyForgeables;
                }

                if (groupedDeliveryExpr != null && groupedDeliveryExpr.Length == 0) {
                    groupedDeliveryExpr = null;
                }
            }

            var allowSubscriber = args.CompileTimeServices.Configuration.Compiler.ByteCode.IsAllowSubscriber;
            SelectSubscriberDescriptor descriptor;
            SelectExprProcessorForge forge;

            if (allowSubscriber) {
                BindProcessorForge bindProcessor = new BindProcessorForge(
                    synthetic.Forge,
                    args.SelectionList,
                    args.TypeService.EventTypes,
                    args.TypeService.StreamNames,
                    args.TableCompileTimeResolver);
                descriptor = new SelectSubscriberDescriptor(
                    bindProcessor.ExpressionTypes,
                    bindProcessor.ColumnNamesAssigned,
                    forDelivery,
                    groupedDeliveryExpr,
                    groupedDeliveryMultiKey);
                forge = new BindSelectExprProcessorForge(synthetic.Forge, bindProcessor);
            } else {
                descriptor = new SelectSubscriberDescriptor();
                forge = new ListenerOnlySelectExprProcessorForge(synthetic.Forge);
            }

            return new SelectExprProcessorDescriptor(descriptor, forge, additionalForgeables);
        }
        public static SelectExprProcessorForgeWForgables Create(
            SelectProcessorArgs args,
            InsertIntoDesc insertIntoDesc,
            Func<String, String> eventTypeNamePostfix) 
        {
            var streamNames = args.TypeService.StreamNames;
            var streamTypes = args.TypeService.EventTypes;
            var moduleName = args.ModuleName;
            var additionalForgeables = new List<StmtClassForgeableFactory>();
            
            if (streamNames.Length < 2 || streamTypes.Length < 2 || streamNames.Length != streamTypes.Length) {
                throw new ArgumentException(
                    "Stream names and types parameter length is invalid, expected use of this class is for join statements");
            }

            // Create EventType of result join events
            var selectProperties = new LinkedHashMap<string, object>();
            var streamTypesWTables = new EventType[streamTypes.Length];
            var hasTables = false;
            for (var i = 0; i < streamTypes.Length; i++) {
                streamTypesWTables[i] = streamTypes[i];
                var table = args.TableCompileTimeResolver.ResolveTableFromEventType(streamTypesWTables[i]);
                if (table != null) {
                    hasTables = true;
                    streamTypesWTables[i] = table.PublicEventType;
                }

                selectProperties.Put(streamNames[i], streamTypesWTables[i]);
            }

            // If we have a name for this type, add it
            var representation = EventRepresentationUtil.GetRepresentation(
                args.Annotations,
                args.Configuration,
                AssignedType.NONE);
            EventType resultEventType;

            SelectExprProcessorForge processor = null;
            if (insertIntoDesc != null) {
                var existingType = args.EventTypeCompileTimeResolver.GetTypeByName(insertIntoDesc.EventTypeName);
                if (existingType != null) {
                    processor = SelectExprInsertEventBeanFactory.GetInsertUnderlyingJoinWildcard(
                        existingType,
                        streamNames,
                        streamTypesWTables,
                        args.ImportService,
                        args.StatementName,
                        args.EventTypeAvroHandler);
                }
            }

            if (processor == null) {
                if (insertIntoDesc != null) {
                    var eventTypeName = eventTypeNamePostfix.Invoke(insertIntoDesc.EventTypeName);
                    var visibility =
                        args.CompileTimeServices.ModuleVisibilityRules.GetAccessModifierEventType(
                            args.StatementRawInfo,
                            eventTypeName);
                    var metadata = new Func<EventTypeApplicationType, EventTypeMetadata>(
                        apptype => new EventTypeMetadata(
                            eventTypeName,
                            moduleName,
                            EventTypeTypeClass.STREAM,
                            apptype,
                            visibility,
                            EventTypeBusModifier.NONBUS,
                            false,
                            EventTypeIdPair.Unassigned()));
                    if (representation == EventUnderlyingType.MAP) {
                        IDictionary<string, object> propertyTypes =
                            EventTypeUtility.GetPropertyTypesNonPrimitive(selectProperties);
                        resultEventType = BaseNestableEventUtil.MakeMapTypeCompileTime(
                            metadata.Invoke(EventTypeApplicationType.MAP),
                            propertyTypes,
                            null,
                            null,
                            null,
                            null,
                            args.BeanEventTypeFactoryPrivate,
                            args.EventTypeCompileTimeResolver);
                    }
                    else if (representation == EventUnderlyingType.OBJECTARRAY) {
                        IDictionary<string, object> propertyTypes =
                            EventTypeUtility.GetPropertyTypesNonPrimitive(selectProperties);
                        resultEventType = BaseNestableEventUtil.MakeOATypeCompileTime(
                            metadata.Invoke(EventTypeApplicationType.OBJECTARR),
                            propertyTypes,
                            null,
                            null,
                            null,
                            null,
                            args.BeanEventTypeFactoryPrivate,
                            args.EventTypeCompileTimeResolver);
                    }
                    else if (representation == EventUnderlyingType.AVRO) {
                        resultEventType = args.EventTypeAvroHandler.NewEventTypeFromNormalized(
                            metadata.Invoke(EventTypeApplicationType.AVRO),
                            args.EventTypeCompileTimeResolver,
                            EventBeanTypedEventFactoryCompileTime.INSTANCE,
                            selectProperties,
                            args.Annotations,
                            null,
                            null,
                            null,
                            args.StatementName);
                    } else if (representation == EventUnderlyingType.JSON) {
                        EventTypeForgeablesPair pair = JsonEventTypeUtility.MakeJsonTypeCompileTimeNewType(
                            metadata.Invoke(EventTypeApplicationType.JSON),
                            selectProperties,
                            null,
                            null,
                            args.StatementRawInfo,
                            args.CompileTimeServices);
                        resultEventType = pair.EventType;
                        additionalForgeables.AddAll(pair.AdditionalForgeables);
                    }
                    else {
                        throw new IllegalStateException("Unrecognized code " + representation);
                    }

                    args.EventTypeCompileTimeRegistry.NewType(resultEventType);
                }
                else {
                    var eventTypeName = eventTypeNamePostfix.Invoke(
                        args.CompileTimeServices.EventTypeNameGeneratorStatement.AnonymousTypeName);
                    IDictionary<string, object> propertyTypes =
                        EventTypeUtility.GetPropertyTypesNonPrimitive(selectProperties);
                    var metadata = new Func<EventTypeApplicationType, EventTypeMetadata>(
                        type => new EventTypeMetadata(
                            eventTypeName,
                            moduleName,
                            EventTypeTypeClass.STATEMENTOUT,
                            type,
                            NameAccessModifier.TRANSIENT,
                            EventTypeBusModifier.NONBUS,
                            false,
                            EventTypeIdPair.Unassigned()));
                    if (representation == EventUnderlyingType.MAP) {
                        resultEventType = BaseNestableEventUtil.MakeMapTypeCompileTime(
                            metadata.Invoke(EventTypeApplicationType.MAP),
                            propertyTypes,
                            null,
                            null,
                            null,
                            null,
                            args.BeanEventTypeFactoryPrivate,
                            args.EventTypeCompileTimeResolver);
                    }
                    else if (representation == EventUnderlyingType.OBJECTARRAY) {
                        resultEventType = BaseNestableEventUtil.MakeOATypeCompileTime(
                            metadata.Invoke(EventTypeApplicationType.OBJECTARR),
                            propertyTypes,
                            null,
                            null,
                            null,
                            null,
                            args.BeanEventTypeFactoryPrivate,
                            args.EventTypeCompileTimeResolver);
                    }
                    else if (representation == EventUnderlyingType.AVRO) {
                        resultEventType = args.EventTypeAvroHandler.NewEventTypeFromNormalized(
                            metadata.Invoke(EventTypeApplicationType.AVRO),
                            args.EventTypeCompileTimeResolver,
                            args.BeanEventTypeFactoryPrivate.EventBeanTypedEventFactory,
                            selectProperties,
                            args.Annotations,
                            null,
                            null,
                            null,
                            args.StatementName);
                    } else if (representation == EventUnderlyingType.JSON) {
                        EventTypeForgeablesPair pair = JsonEventTypeUtility.MakeJsonTypeCompileTimeNewType(
                            metadata.Invoke(EventTypeApplicationType.JSON),
                            propertyTypes,
                            null,
                            null,
                            args.StatementRawInfo,
                            args.CompileTimeServices);
                        resultEventType = pair.EventType;
                        additionalForgeables.AddAll(pair.AdditionalForgeables);
                    }
                    else {
                        throw new IllegalStateException("Unrecognized enum " + representation);
                    }

                    args.EventTypeCompileTimeRegistry.NewType(resultEventType);
                }

                // NOTE: Processors herein maintain their own result-event-type as they become inner types,
                //       for example "insert into VariantStream select * from A, B"
                if (resultEventType is ObjectArrayEventType) {
                    processor = new SelectEvalJoinWildcardProcessorObjectArray(streamNames, resultEventType);
                }
                else if (resultEventType is MapEventType) {
                    processor = new SelectEvalJoinWildcardProcessorMap(streamNames, resultEventType);
                }
                else if (resultEventType is AvroSchemaEventType) {
                    processor = args.EventTypeAvroHandler.OutputFactory.MakeJoinWildcard(streamNames, resultEventType);
                } else if (resultEventType is JsonEventType) {
                    processor = new SelectEvalJoinWildcardProcessorJson(streamNames, (JsonEventType) resultEventType);
                }
            }

            if (!hasTables) {
                return new SelectExprProcessorForgeWForgables(processor, additionalForgeables);
            }
            processor = new SelectEvalJoinWildcardProcessorTableRows(streamTypes, processor, args.TableCompileTimeResolver);
            return new SelectExprProcessorForgeWForgables(processor, additionalForgeables);
        }