public static SelectExprProcessor GetInsertUnderlyingNonJoin(
            EventAdapterService eventAdapterService,
            EventType eventType,
            bool isUsingWildcard,
            StreamTypeService typeService,
            ExprEvaluator[] expressionNodes,
            string[] columnNames,
            Object[] expressionReturnTypes,
            EngineImportService engineImportService,
            InsertIntoDesc insertIntoDesc,
            string[] columnNamesAsProvided,
            bool allowNestableTargetFragmentTypes,
            string statementName)
        {
            // handle single-column coercion to underlying, i.e. "insert into MapDefinedEvent select DoSomethingReturnMap() from MyEvent"
            if (expressionReturnTypes.Length == 1 &&
                expressionReturnTypes[0] is Type &&
                (eventType is BaseNestableEventType || eventType is AvroSchemaEventType) &&
                TypeHelper.IsSubclassOrImplementsInterface((Type)expressionReturnTypes[0], eventType.UnderlyingType) &&
                insertIntoDesc.ColumnNames.IsEmpty() &&
                columnNamesAsProvided[0] == null)
            {
                if (eventType is MapEventType)
                {
                    return(new SelectExprInsertNativeExpressionCoerceMap(
                               eventType, expressionNodes[0], eventAdapterService));
                }
                else if (eventType is ObjectArrayEventType)
                {
                    return(new SelectExprInsertNativeExpressionCoerceObjectArray(
                               eventType, expressionNodes[0], eventAdapterService));
                }
                else if (eventType is AvroSchemaEventType)
                {
                    return(new SelectExprInsertNativeExpressionCoerceAvro(
                               eventType, expressionNodes[0], eventAdapterService));
                }
                else
                {
                    throw new IllegalStateException("Unrecognied event type " + eventType);
                }
            }

            // handle special case where the target type has no properties and there is a single "null" value selected
            if (eventType.PropertyDescriptors.Count == 0 &&
                columnNames.Length == 1 &&
                columnNames[0].Equals("null") &&
                expressionReturnTypes[0] == null &&
                !isUsingWildcard)
            {
                EventBeanManufacturer eventManufacturer;
                try
                {
                    eventManufacturer = eventAdapterService.GetManufacturer(
                        eventType, new WriteablePropertyDescriptor[0], engineImportService, true);
                }
                catch (EventBeanManufactureException e)
                {
                    throw new ExprValidationException(e.Message, e);
                }
                return(new SelectExprInsertNativeNoEval(eventType, eventManufacturer));
            }

            // handle writing to defined columns
            var writableProps = eventAdapterService.GetWriteableProperties(eventType, false);
            var isEligible    = CheckEligible(eventType, writableProps, allowNestableTargetFragmentTypes);

            if (!isEligible)
            {
                return(null);
            }

            try
            {
                return(InitializeSetterManufactor(
                           eventType, writableProps, isUsingWildcard, typeService, expressionNodes, columnNames,
                           expressionReturnTypes, engineImportService, eventAdapterService, statementName));
            }
            catch (ExprValidationException)
            {
                if (!(eventType is BeanEventType))
                {
                    throw;
                }
                // Try constructor injection
                try
                {
                    return(InitializeCtorInjection(
                               (BeanEventType)eventType, expressionNodes, expressionReturnTypes, engineImportService,
                               eventAdapterService));
                }
                catch (ExprValidationException)
                {
                    if (writableProps.IsEmpty())
                    {
                        throw;
                    }
                }

                throw;
            }
        }
        private static SelectExprProcessor InitializeJoinWildcardInternal(
            EventType eventType,
            ICollection <WriteablePropertyDescriptor> writables,
            string[] streamNames,
            EventType[] streamTypes,
            EngineImportService engineImportService,
            EventAdapterService eventAdapterService,
            string statementName,
            string engineURI)
        {
            var typeWidenerCustomizer  = eventAdapterService.GetTypeWidenerCustomizer(eventType);
            var writablePropertiesList = new List <WriteablePropertyDescriptor>();
            var evaluatorsList         = new List <ExprEvaluator>();
            var widenersList           = new List <TypeWidener>();

            // loop over all columns selected, if any
            for (var i = 0; i < streamNames.Length; i++)
            {
                WriteablePropertyDescriptor selectedWritable = null;
                TypeWidener widener = null;

                foreach (var desc in writables)
                {
                    if (!desc.PropertyName.Equals(streamNames[i]))
                    {
                        continue;
                    }

                    widener = TypeWidenerFactory.GetCheckPropertyAssignType(
                        streamNames[i], streamTypes[i].UnderlyingType, desc.PropertyType, desc.PropertyName, false,
                        typeWidenerCustomizer, statementName, engineURI);
                    selectedWritable = desc;
                    break;
                }

                if (selectedWritable == null)
                {
                    var message = "Stream underlying object for stream '" + streamNames[i] +
                                  "' could not be assigned to any of the properties of the underlying type (missing column names, event property or setter method?)";
                    throw new ExprValidationException(message);
                }

                var streamNum  = i;
                var returnType = streamTypes[streamNum].UnderlyingType;
                var evaluator  = new ProxyExprEvaluator
                {
                    ProcEvaluate = evaluateParams =>
                    {
                        EventBean theEvent = evaluateParams.EventsPerStream[streamNum];
                        if (theEvent != null)
                        {
                            return(theEvent.Underlying);
                        }
                        return(null);
                    },

                    ProcReturnType = () => returnType
                };

                // add
                writablePropertiesList.Add(selectedWritable);
                evaluatorsList.Add(evaluator);
                widenersList.Add(widener);
            }

            // assign
            var writableProperties = writablePropertiesList.ToArray();
            var exprEvaluators     = evaluatorsList.ToArray();
            var wideners           = widenersList.ToArray();

            EventBeanManufacturer eventManufacturer;

            try
            {
                eventManufacturer = eventAdapterService.GetManufacturer(
                    eventType, writableProperties, engineImportService, false);
            }
            catch (EventBeanManufactureException e)
            {
                throw new ExprValidationException(e.Message, e);
            }

            return(new SelectExprInsertNativeWidening(eventType, eventManufacturer, exprEvaluators, wideners));
        }
        private static SelectExprProcessor InitializeSetterManufactor(
            EventType eventType,
            ICollection <WriteablePropertyDescriptor> writables,
            bool isUsingWildcard,
            StreamTypeService typeService,
            ExprEvaluator[] expressionNodes,
            string[] columnNames,
            Object[] expressionReturnTypes,
            EngineImportService engineImportService,
            EventAdapterService eventAdapterService,
            string statementName)
        {
            var typeWidenerCustomizer  = eventAdapterService.GetTypeWidenerCustomizer(eventType);
            var writablePropertiesList = new List <WriteablePropertyDescriptor>();
            var evaluatorsList         = new List <ExprEvaluator>();
            var widenersList           = new List <TypeWidener>();

            // loop over all columns selected, if any
            for (var i = 0; i < columnNames.Length; i++)
            {
                WriteablePropertyDescriptor selectedWritable = null;
                TypeWidener widener   = null;
                var         evaluator = expressionNodes[i];

                foreach (var desc in writables)
                {
                    if (!desc.PropertyName.Equals(columnNames[i]))
                    {
                        continue;
                    }

                    var columnType = expressionReturnTypes[i];
                    if (columnType == null)
                    {
                        TypeWidenerFactory.GetCheckPropertyAssignType(
                            columnNames[i], null, desc.PropertyType, desc.PropertyName, false, typeWidenerCustomizer,
                            statementName, typeService.EngineURIQualifier);
                    }
                    else if (columnType is EventType)
                    {
                        var columnEventType = (EventType)columnType;
                        var returnType      = columnEventType.UnderlyingType;
                        widener = TypeWidenerFactory.GetCheckPropertyAssignType(
                            columnNames[i], columnEventType.UnderlyingType, desc.PropertyType, desc.PropertyName, false,
                            typeWidenerCustomizer, statementName, typeService.EngineURIQualifier);

                        // handle evaluator returning an event
                        if (TypeHelper.IsSubclassOrImplementsInterface(returnType, desc.PropertyType))
                        {
                            selectedWritable = desc;
                            widener          = input =>
                            {
                                var eventBean = input as EventBean;
                                if (eventBean != null)
                                {
                                    return(eventBean.Underlying);
                                }
                                return(input);
                            };
                            continue;
                        }

                        // find stream
                        var streamNum = 0;
                        for (var j = 0; j < typeService.EventTypes.Length; j++)
                        {
                            if (Equals(typeService.EventTypes[j], columnEventType))
                            {
                                streamNum = j;
                                break;
                            }
                        }
                        var streamNumEval = streamNum;
                        evaluator = new ProxyExprEvaluator
                        {
                            ProcEvaluate = evaluateParams =>
                            {
                                EventBean theEvent = evaluateParams.EventsPerStream[streamNumEval];
                                if (theEvent != null)
                                {
                                    return(theEvent.Underlying);
                                }
                                return(null);
                            },

                            ProcReturnType = () => returnType
                        };
                    }
                    else if (columnType is EventType[])
                    {
                        // handle case where the select-clause contains an fragment array
                        var columnEventType     = ((EventType[])columnType)[0];
                        var componentReturnType = columnEventType.UnderlyingType;
                        var arrayReturnType     = Array.CreateInstance(componentReturnType, 0).GetType();

                        var allowObjectArrayToCollectionConversion = eventType is AvroSchemaEventType;
                        widener = TypeWidenerFactory.GetCheckPropertyAssignType(
                            columnNames[i], arrayReturnType, desc.PropertyType, desc.PropertyName,
                            allowObjectArrayToCollectionConversion, typeWidenerCustomizer, statementName,
                            typeService.EngineURIQualifier);
                        var inner = evaluator;
                        evaluator = new ProxyExprEvaluator
                        {
                            ProcEvaluate = evaluateParams =>
                            {
                                var result = inner.Evaluate(evaluateParams);
                                if (!(result is EventBean[]))
                                {
                                    return(null);
                                }
                                var events = (EventBean[])result;
                                var values = Array.CreateInstance(componentReturnType, events.Length);
                                for (var ii = 0; ii < events.Length; ii++)
                                {
                                    values.SetValue(events[ii].Underlying, ii);
                                }
                                return(values);
                            },

                            ProcReturnType = () => componentReturnType
                        };
                    }
                    else if (!(columnType is Type))
                    {
                        var message = "Invalid assignment of column '" + columnNames[i] +
                                      "' of type '" + columnType +
                                      "' to event property '" + desc.PropertyName +
                                      "' typed as '" + desc.PropertyType.FullName +
                                      "', column and parameter types mismatch";
                        throw new ExprValidationException(message);
                    }
                    else
                    {
                        widener = TypeWidenerFactory.GetCheckPropertyAssignType(
                            columnNames[i], (Type)columnType, desc.PropertyType, desc.PropertyName, false,
                            typeWidenerCustomizer, statementName, typeService.EngineURIQualifier);
                    }

                    selectedWritable = desc;
                    break;
                }

                if (selectedWritable == null)
                {
                    var message = "Column '" + columnNames[i] +
                                  "' could not be assigned to any of the properties of the underlying type (missing column names, event property, setter method or constructor?)";
                    throw new ExprValidationException(message);
                }

                // add
                writablePropertiesList.Add(selectedWritable);
                evaluatorsList.Add(evaluator);
                widenersList.Add(widener);
            }

            // handle wildcard
            if (isUsingWildcard)
            {
                var sourceType = typeService.EventTypes[0];
                foreach (var eventPropDescriptor in sourceType.PropertyDescriptors)
                {
                    if (eventPropDescriptor.RequiresIndex || (eventPropDescriptor.RequiresMapKey))
                    {
                        continue;
                    }

                    WriteablePropertyDescriptor selectedWritable = null;
                    TypeWidener   widener   = null;
                    ExprEvaluator evaluator = null;

                    foreach (var writableDesc in writables)
                    {
                        if (!writableDesc.PropertyName.Equals(eventPropDescriptor.PropertyName))
                        {
                            continue;
                        }

                        widener = TypeWidenerFactory.GetCheckPropertyAssignType(
                            eventPropDescriptor.PropertyName, eventPropDescriptor.PropertyType, writableDesc.PropertyType,
                            writableDesc.PropertyName, false, typeWidenerCustomizer, statementName,
                            typeService.EngineURIQualifier);
                        selectedWritable = writableDesc;

                        var propertyName = eventPropDescriptor.PropertyName;
                        var propertyType = eventPropDescriptor.PropertyType;
                        evaluator = new ProxyExprEvaluator
                        {
                            ProcEvaluate = evaluateParams =>
                            {
                                EventBean theEvent = evaluateParams.EventsPerStream[0];
                                if (theEvent != null)
                                {
                                    return(theEvent.Get(propertyName));
                                }
                                return(null);
                            },

                            ProcReturnType = () => propertyType
                        };
                        break;
                    }

                    if (selectedWritable == null)
                    {
                        var message = "Event property '" + eventPropDescriptor.PropertyName +
                                      "' could not be assigned to any of the properties of the underlying type (missing column names, event property, setter method or constructor?)";
                        throw new ExprValidationException(message);
                    }

                    writablePropertiesList.Add(selectedWritable);
                    evaluatorsList.Add(evaluator);
                    widenersList.Add(widener);
                }
            }

            // assign
            var writableProperties = writablePropertiesList.ToArray();
            var exprEvaluators     = evaluatorsList.ToArray();
            var wideners           = widenersList.ToArray();

            EventBeanManufacturer eventManufacturer;

            try
            {
                eventManufacturer = eventAdapterService.GetManufacturer(
                    eventType, writableProperties, engineImportService, false);
            }
            catch (EventBeanManufactureException e)
            {
                throw new ExprValidationException(e.Message, e);
            }

            return(new SelectExprInsertNativeWidening(eventType, eventManufacturer, exprEvaluators, wideners));
        }