/* *************************************************************************************** * Copyright (C) 2006 EsperTech, Inc. All rights reserved. * * http://www.espertech.com/esper * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * *************************************************************************************** */ package com.espertech.esper.epl.core; import com.espertech.esper.client.*; import com.espertech.esper.client.util.EventUnderlyingType; import com.espertech.esper.collection.Pair; import com.espertech.esper.epl.agg.service.AggregationGroupByRollupLevel; import com.espertech.esper.epl.core.eval.*; import com.espertech.esper.epl.expression.core.*; import com.espertech.esper.epl.named.NamedWindowMgmtService; import com.espertech.esper.epl.named.NamedWindowProcessor; import com.espertech.esper.epl.rettype.EPType; import com.espertech.esper.epl.rettype.EPTypeHelper; import com.espertech.esper.epl.rettype.EventEPType; import com.espertech.esper.epl.rettype.EventMultiValuedEPType; import com.espertech.esper.epl.spec.CreateSchemaDesc; import com.espertech.esper.epl.spec.InsertIntoDesc; import com.espertech.esper.epl.spec.SelectClauseExprCompiledSpec; import com.espertech.esper.epl.spec.SelectClauseStreamCompiledSpec; import com.espertech.esper.epl.table.mgmt.TableMetadata; import com.espertech.esper.epl.table.mgmt.TableService; import com.espertech.esper.event.*; import com.espertech.esper.event.arr.ObjectArrayEventType; import com.espertech.esper.event.avro.AvroConstantsNoDep; import com.espertech.esper.event.avro.AvroSchemaEventType; import com.espertech.esper.event.bean.BeanEventType; import com.espertech.esper.event.map.MapEventType; import com.espertech.esper.event.vaevent.ValueAddEventProcessor; import com.espertech.esper.event.vaevent.ValueAddEventService; import com.espertech.esper.event.vaevent.VariantEventType; import com.espertech.esper.util.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.annotation.Annotation; import java.util.*; /** * Processor for select-clause expressions that handles a list of selection items represented by * expression nodes. Computes results based on matching events. */ public class SelectExprProcessorHelper { private static final Logger log = LoggerFactory.getLogger(SelectExprProcessorHelper.class); private final Collection<Integer> assignedTypeNumberStack; private final List<SelectClauseExprCompiledSpec> selectionList; private final List<SelectExprStreamDesc> selectedStreams; private final InsertIntoDesc insertIntoDesc; private EventType optionalInsertIntoOverrideType; private final boolean isUsingWildcard; private final StreamTypeService typeService; private final EventAdapterService eventAdapterService; private final ValueAddEventService valueAddEventService; private final SelectExprEventTypeRegistry selectExprEventTypeRegistry; private final EngineImportService engineImportService; private final int statementId; private final String statementName; private final Annotation[] annotations; private final ConfigurationInformation configuration; private final NamedWindowMgmtService namedWindowMgmtService; private final TableService tableService; private final GroupByRollupInfo groupByRollupInfo; public SelectExprProcessorHelper(Collection<Integer> assignedTypeNumberStack, List<SelectClauseExprCompiledSpec> selectionList, List<SelectExprStreamDesc> selectedStreams, InsertIntoDesc insertIntoDesc, EventType optionalInsertIntoOverrideType, boolean isUsingWildcard, StreamTypeService typeService, EventAdapterService eventAdapterService, ValueAddEventService valueAddEventService, SelectExprEventTypeRegistry selectExprEventTypeRegistry, EngineImportService engineImportService, int statementId, String statementName, Annotation[] annotations, ConfigurationInformation configuration, NamedWindowMgmtService namedWindowMgmtService, TableService tableService, GroupByRollupInfo groupByRollupInfo) throws ExprValidationException { this.assignedTypeNumberStack = assignedTypeNumberStack; this.selectionList = selectionList; this.selectedStreams = selectedStreams; this.insertIntoDesc = insertIntoDesc; this.optionalInsertIntoOverrideType = optionalInsertIntoOverrideType; this.eventAdapterService = eventAdapterService; this.isUsingWildcard = isUsingWildcard; this.typeService = typeService; this.valueAddEventService = valueAddEventService; this.selectExprEventTypeRegistry = selectExprEventTypeRegistry; this.engineImportService = engineImportService; this.statementId = statementId; this.statementName = statementName; this.annotations = annotations; this.configuration = configuration; this.namedWindowMgmtService = namedWindowMgmtService; this.tableService = tableService; this.groupByRollupInfo = groupByRollupInfo; } public SelectExprProcessor getEvaluator() throws ExprValidationException { // Get the named and un-named stream selectors (i.e. select s0.* from S0 as s0), if any List<SelectClauseStreamCompiledSpec> namedStreams = new ArrayList<SelectClauseStreamCompiledSpec>(); List<SelectExprStreamDesc> unnamedStreams = new ArrayList<SelectExprStreamDesc>(); for (SelectExprStreamDesc spec : selectedStreams) { // handle special "transpose(...)" function if ((spec.getStreamSelected() != null && spec.getStreamSelected().getOptionalName() == null) || (spec.getExpressionSelectedAsStream() != null)) { unnamedStreams.add(spec); } else { namedStreams.add(spec.getStreamSelected()); if (spec.getStreamSelected().isProperty()) { throw new ExprValidationException("The property wildcard syntax must be used without column name"); } } } // Error if there are more then one un-named streams (i.e. select s0.*, s1.* from S0 as s0, S1 as s1) // Thus there is only 1 unnamed stream selector maximum. if (unnamedStreams.size() > 1) { throw new ExprValidationException("A column name must be supplied for all but one stream if multiple streams are selected via the stream.* notation"); } if (selectedStreams.isEmpty() && selectionList.isEmpty() && !isUsingWildcard) { throw new IllegalArgumentException("Empty selection list not supported"); } for (SelectClauseExprCompiledSpec entry : selectionList) { if (entry.getAssignedName() == null) { throw new IllegalArgumentException("Expected name for each expression has not been supplied"); } } // Verify insert into clause if (insertIntoDesc != null) { verifyInsertInto(insertIntoDesc, selectionList); } // Build a subordinate wildcard processor for joins SelectExprProcessor joinWildcardProcessor = null; if (typeService.getStreamNames().length > 1 && isUsingWildcard) { joinWildcardProcessor = SelectExprJoinWildcardProcessorFactory.create(assignedTypeNumberStack, statementId, statementName, typeService.getStreamNames(), typeService.getEventTypes(), eventAdapterService, null, selectExprEventTypeRegistry, engineImportService, annotations, configuration, tableService, typeService.getEngineURIQualifier()); } // Resolve underlying event type in the case of wildcard select EventType eventType = null; boolean singleStreamWrapper = false; if (isUsingWildcard) { if (joinWildcardProcessor != null) { eventType = joinWildcardProcessor.getResultEventType(); } else { eventType = typeService.getEventTypes()[0]; if (eventType instanceof WrapperEventType) { singleStreamWrapper = true; } } } // Find if there is any fragments selected EventType insertIntoTargetType = null; if (insertIntoDesc != null) { if (optionalInsertIntoOverrideType != null) { insertIntoTargetType = optionalInsertIntoOverrideType; } else { insertIntoTargetType = eventAdapterService.getExistsTypeByName(insertIntoDesc.getEventTypeName()); TableMetadata tableMetadata = tableService.getTableMetadata(insertIntoDesc.getEventTypeName()); if (tableMetadata != null) { insertIntoTargetType = tableMetadata.getInternalEventType(); optionalInsertIntoOverrideType = insertIntoTargetType; } } } // Obtain insert-into per-column type information, when available EPType[] insertIntoTargetsPerCol = determineInsertedEventTypeTargets(insertIntoTargetType, selectionList); // Get expression nodes ExprEvaluator[] exprEvaluators = new ExprEvaluator[selectionList.size()]; ExprNode[] exprNodes = new ExprNode[selectionList.size()]; Object[] expressionReturnTypes = new Object[selectionList.size()]; for (int i = 0; i < selectionList.size(); i++) { SelectClauseExprCompiledSpec spec = selectionList.get(i); ExprNode expr = spec.getSelectExpression(); ExprEvaluator evaluator = expr.getExprEvaluator(); exprNodes[i] = expr; // if there is insert-into specification, use that if (insertIntoDesc != null) { // handle insert-into, with well-defined target event-typed column, and enumeration TypeAndFunctionPair pair = handleInsertIntoEnumeration(spec.getProvidedName(), insertIntoTargetsPerCol[i], evaluator, engineImportService); if (pair != null) { expressionReturnTypes[i] = pair.getType(); exprEvaluators[i] = pair.getFunction(); continue; } // handle insert-into with well-defined target event-typed column, and typable expression pair = handleInsertIntoTypableExpression(insertIntoTargetsPerCol[i], evaluator, engineImportService); if (pair != null) { expressionReturnTypes[i] = pair.getType(); exprEvaluators[i] = pair.getFunction(); continue; } } // handle @eventbean annotation, i.e. well-defined type through enumeration TypeAndFunctionPair pair = handleAtEventbeanEnumeration(spec.isEvents(), evaluator); if (pair != null) { expressionReturnTypes[i] = pair.getType(); exprEvaluators[i] = pair.getFunction(); continue; } // handle typeable return, i.e. typable multi-column return without provided target type pair = handleTypableExpression(evaluator, i); if (pair != null) { expressionReturnTypes[i] = pair.getType(); exprEvaluators[i] = pair.getFunction(); continue; } // handle select-clause expressions that match group-by expressions with rollup and therefore should be boxed types as rollup can produce a null value if (groupByRollupInfo != null && groupByRollupInfo.getRollupDesc() != null) { Class returnType = evaluator.getType(); Class returnTypeBoxed = JavaClassHelper.getBoxedType(returnType); if (returnType != returnTypeBoxed && isGroupByRollupNullableExpression(expr, groupByRollupInfo)) { exprEvaluators[i] = evaluator; expressionReturnTypes[i] = returnTypeBoxed; continue; } } // assign normal expected return type exprEvaluators[i] = evaluator; expressionReturnTypes[i] = exprEvaluators[i].getType(); } // Get column names String[] columnNames; String[] columnNamesAsProvided; if ((insertIntoDesc != null) && (!insertIntoDesc.getColumnNames().isEmpty())) { columnNames = insertIntoDesc.getColumnNames().toArray(new String[insertIntoDesc.getColumnNames().size()]); columnNamesAsProvided = columnNames; } else if (!selectedStreams.isEmpty()) { // handle stream selection column names int numStreamColumnsJoin = 0; if (isUsingWildcard && typeService.getEventTypes().length > 1) { numStreamColumnsJoin = typeService.getEventTypes().length; } columnNames = new String[selectionList.size() + namedStreams.size() + numStreamColumnsJoin]; columnNamesAsProvided = new String[columnNames.length]; int count = 0; for (SelectClauseExprCompiledSpec aSelectionList : selectionList) { columnNames[count] = aSelectionList.getAssignedName(); columnNamesAsProvided[count] = aSelectionList.getProvidedName(); count++; } for (SelectClauseStreamCompiledSpec aSelectionList : namedStreams) { columnNames[count] = aSelectionList.getOptionalName(); columnNamesAsProvided[count] = aSelectionList.getOptionalName(); count++; } // for wildcard joins, add the streams themselves if (isUsingWildcard && typeService.getEventTypes().length > 1) { for (String streamName : typeService.getStreamNames()) { columnNames[count] = streamName; columnNamesAsProvided[count] = streamName; count++; } } } else { // handle regular column names columnNames = new String[selectionList.size()]; columnNamesAsProvided = new String[selectionList.size()]; for (int i = 0; i < selectionList.size(); i++) { columnNames[i] = selectionList.get(i).getAssignedName(); columnNamesAsProvided[i] = selectionList.get(i).getProvidedName(); } } // Find if there is any fragment event types: // This is a special case for fragments: select a, b from pattern [a=A -> b=B] // We'd like to maintain 'A' and 'B' EventType in the Map type, and 'a' and 'b' EventBeans in the event bean for (int i = 0; i < selectionList.size(); i++) { if (!(exprNodes[i] instanceof ExprIdentNode)) { continue; } ExprIdentNode identNode = (ExprIdentNode) exprNodes[i]; String propertyName = identNode.getResolvedPropertyName(); final int streamNum = identNode.getStreamId(); EventType eventTypeStream = typeService.getEventTypes()[streamNum]; if (eventTypeStream instanceof NativeEventType) { continue; // we do not transpose the native type for performance reasons } FragmentEventType fragmentType = eventTypeStream.getFragmentType(propertyName); if ((fragmentType == null) || (fragmentType.isNative())) { continue; // we also ignore native Java classes as fragments for performance reasons } // may need to unwrap the fragment if the target type has this underlying type FragmentEventType targetFragment = null; if (insertIntoTargetType != null) { targetFragment = insertIntoTargetType.getFragmentType(columnNames[i]); } if ((insertIntoTargetType != null) && (fragmentType.getFragmentType().getUnderlyingType() == expressionReturnTypes[i]) && ((targetFragment == null) || (targetFragment != null && targetFragment.isNative()))) { EventPropertyGetter getter = eventTypeStream.getGetter(propertyName); Class returnType = eventTypeStream.getPropertyType(propertyName); exprEvaluators[i] = new SelectExprProcessorEvalByGetter(streamNum, getter, returnType); } else if ((insertIntoTargetType != null) && expressionReturnTypes[i] instanceof Class && (fragmentType.getFragmentType().getUnderlyingType() == ((Class) expressionReturnTypes[i]).getComponentType()) && ((targetFragment == null) || (targetFragment != null && targetFragment.isNative()))) { // same for arrays: may need to unwrap the fragment if the target type has this underlying type EventPropertyGetter getter = eventTypeStream.getGetter(propertyName); Class returnType = JavaClassHelper.getArrayType(eventTypeStream.getPropertyType(propertyName)); exprEvaluators[i] = new SelectExprProcessorEvalByGetter(streamNum, getter, returnType); } else { EventPropertyGetter getter = eventTypeStream.getGetter(propertyName); FragmentEventType fragType = eventTypeStream.getFragmentType(propertyName); Class undType = fragType.getFragmentType().getUnderlyingType(); Class returnType = fragType.isIndexed() ? JavaClassHelper.getArrayType(undType) : undType; exprEvaluators[i] = new SelectExprProcessorEvalByGetterFragment(streamNum, getter, returnType); if (!fragmentType.isIndexed()) { expressionReturnTypes[i] = fragmentType.getFragmentType(); } else { expressionReturnTypes[i] = new EventType[]{fragmentType.getFragmentType()}; } } } // Find if there is any stream expression (ExprStreamNode) : // This is a special case for stream selection: select a, b from A as a, B as b // We'd like to maintain 'A' and 'B' EventType in the Map type, and 'a' and 'b' EventBeans in the event bean for (int i = 0; i < selectionList.size(); i++) { Pair<ExprEvaluator, Object> pair = handleUnderlyingStreamInsert(exprEvaluators[i], namedWindowMgmtService, eventAdapterService); if (pair != null) { exprEvaluators[i] = pair.getFirst(); expressionReturnTypes[i] = pair.getSecond(); } } // Build event type that reflects all selected properties Map<String, Object> selPropertyTypes = new LinkedHashMap<String, Object>(); int count = 0; for (int i = 0; i < exprEvaluators.length; i++) { Object expressionReturnType = expressionReturnTypes[count]; selPropertyTypes.put(columnNames[count], expressionReturnType); count++; } if (!selectedStreams.isEmpty()) { for (SelectClauseStreamCompiledSpec element : namedStreams) { EventType eventTypeStream; if (element.getTableMetadata() != null) { eventTypeStream = element.getTableMetadata().getPublicEventType(); } else { eventTypeStream = typeService.getEventTypes()[element.getStreamNumber()]; } selPropertyTypes.put(columnNames[count], eventTypeStream); count++; } if (isUsingWildcard && typeService.getEventTypes().length > 1) { for (int i = 0; i < typeService.getEventTypes().length; i++) { EventType eventTypeStream = typeService.getEventTypes()[i]; selPropertyTypes.put(columnNames[count], eventTypeStream); count++; } } } // Handle stream selection EventType underlyingEventType = null; int underlyingStreamNumber = 0; boolean underlyingIsFragmentEvent = false; EventPropertyGetter underlyingPropertyEventGetter = null; ExprEvaluator underlyingExprEvaluator = null; EventUnderlyingType representation = EventRepresentationUtil.getRepresentation(annotations, configuration, CreateSchemaDesc.AssignedType.NONE); if (!selectedStreams.isEmpty()) { // Resolve underlying event type in the case of wildcard or non-named stream select. // Determine if the we are considering a tagged event or a stream name. if (isUsingWildcard || (!unnamedStreams.isEmpty())) { if (!unnamedStreams.isEmpty()) { if (unnamedStreams.get(0).getStreamSelected() != null) { SelectClauseStreamCompiledSpec streamSpec = unnamedStreams.get(0).getStreamSelected(); // the tag.* syntax for : select tag.* from pattern [tag = A] underlyingStreamNumber = streamSpec.getStreamNumber(); if (streamSpec.isFragmentEvent()) { EventType compositeMap = typeService.getEventTypes()[underlyingStreamNumber]; FragmentEventType fragment = compositeMap.getFragmentType(streamSpec.getStreamName()); underlyingEventType = fragment.getFragmentType(); underlyingIsFragmentEvent = true; } else if (streamSpec.isProperty()) { // the property.* syntax for : select property.* from A String propertyName = streamSpec.getStreamName(); Class propertyType = streamSpec.getPropertyType(); int streamNumber = streamSpec.getStreamNumber(); if (JavaClassHelper.isJavaBuiltinDataType(streamSpec.getPropertyType())) { throw new ExprValidationException("The property wildcard syntax cannot be used on built-in types as returned by property '" + propertyName + "'"); } // create or get an underlying type for that Class underlyingEventType = eventAdapterService.addBeanType(propertyType.getName(), propertyType, false, false, false); selectExprEventTypeRegistry.add(underlyingEventType); underlyingPropertyEventGetter = typeService.getEventTypes()[streamNumber].getGetter(propertyName); if (underlyingPropertyEventGetter == null) { throw new ExprValidationException("Unexpected error resolving property getter for property " + propertyName); } } else { // the stream.* syntax for: select a.* from A as a underlyingEventType = typeService.getEventTypes()[underlyingStreamNumber]; } } else { // handle case where the unnamed stream is a "transpose" function, for non-insert-into if (insertIntoDesc == null || insertIntoTargetType == null) { ExprNode expression = unnamedStreams.get(0).getExpressionSelectedAsStream().getSelectExpression(); Class returnType = expression.getExprEvaluator().getType(); if (returnType == Object[].class || JavaClassHelper.isImplementsInterface(returnType, Map.class) || JavaClassHelper.isJavaBuiltinDataType(returnType)) { throw new ExprValidationException("Invalid expression return type '" + returnType.getName() + "' for transpose function"); } underlyingEventType = eventAdapterService.addBeanType(returnType.getName(), returnType, false, false, false); selectExprEventTypeRegistry.add(underlyingEventType); underlyingExprEvaluator = expression.getExprEvaluator(); } } } else { // no un-named stream selectors, but a wildcard was specified if (typeService.getEventTypes().length == 1) { // not a join, we are using the selected event underlyingEventType = typeService.getEventTypes()[0]; if (underlyingEventType instanceof WrapperEventType) { singleStreamWrapper = true; } } else { // For joins, all results are placed in a map with properties for each stream underlyingEventType = null; } } } } SelectExprContext selectExprContext = new SelectExprContext(exprEvaluators, columnNames, eventAdapterService); if (insertIntoDesc == null) { if (!selectedStreams.isEmpty()) { EventType resultEventType; if (underlyingEventType != null) { TableMetadata tableMetadata = tableService.getTableMetadataFromEventType(underlyingEventType); if (tableMetadata != null) { underlyingEventType = tableMetadata.getPublicEventType(); } resultEventType = eventAdapterService.createAnonymousWrapperType(statementId + "_wrapout_" + CollectionUtil.toString(assignedTypeNumberStack, "_"), underlyingEventType, selPropertyTypes); return new EvalSelectStreamWUnderlying(selectExprContext, resultEventType, namedStreams, isUsingWildcard, unnamedStreams, singleStreamWrapper, underlyingIsFragmentEvent, underlyingStreamNumber, underlyingPropertyEventGetter, underlyingExprEvaluator, tableMetadata); } else { resultEventType = eventAdapterService.createAnonymousMapType(statementId + "_mapout_" + CollectionUtil.toString(assignedTypeNumberStack, "_"), selPropertyTypes, true); return new EvalSelectStreamNoUnderlyingMap(selectExprContext, resultEventType, namedStreams, isUsingWildcard); } } if (isUsingWildcard) { EventType resultEventType = eventAdapterService.createAnonymousWrapperType(statementId + "_wrapoutwild_" + CollectionUtil.toString(assignedTypeNumberStack, "_"), eventType, selPropertyTypes); if (singleStreamWrapper) { return new EvalSelectWildcardSSWrapper(selectExprContext, resultEventType); } if (joinWildcardProcessor == null) { return new EvalSelectWildcard(selectExprContext, resultEventType); } return new EvalSelectWildcardJoin(selectExprContext, resultEventType, joinWildcardProcessor); } EventType resultEventType; if (representation == EventUnderlyingType.OBJECTARRAY) { resultEventType = eventAdapterService.createAnonymousObjectArrayType(statementId + "_result_" + CollectionUtil.toString(assignedTypeNumberStack, "_"), selPropertyTypes); } else if (representation == EventUnderlyingType.AVRO) { resultEventType = eventAdapterService.createAnonymousAvroType(statementId + "_result_" + CollectionUtil.toString(assignedTypeNumberStack, "_"), selPropertyTypes, annotations, statementName, typeService.getEngineURIQualifier()); } else { resultEventType = eventAdapterService.createAnonymousMapType(statementId + "_result_" + CollectionUtil.toString(assignedTypeNumberStack, "_"), selPropertyTypes, true); } if (selectExprContext.getExpressionNodes().length == 0) { return new EvalSelectNoWildcardEmptyProps(selectExprContext, resultEventType); } else { if (representation == EventUnderlyingType.OBJECTARRAY) { return new EvalSelectNoWildcardObjectArray(selectExprContext, resultEventType); } else if (representation == EventUnderlyingType.AVRO) { return eventAdapterService.getEventAdapterAvroHandler().getOutputFactory().makeSelectNoWildcard(selectExprContext, resultEventType, tableService, statementName, typeService.getEngineURIQualifier()); } return new EvalSelectNoWildcardMap(selectExprContext, resultEventType); } } EventType vaeInnerEventType = null; boolean singleColumnWrapOrBeanCoercion = false; // Additional single-column coercion for non-wrapped type done by SelectExprInsertEventBeanFactory boolean isRevisionEvent = false; try { if (!selectedStreams.isEmpty()) { EventType resultEventType; // handle "transpose" special function with predefined target type if (insertIntoTargetType != null && selectedStreams.get(0).getExpressionSelectedAsStream() != null) { if (exprEvaluators.length != 0) { throw new ExprValidationException("Cannot transpose additional properties in the select-clause to target event type '" + insertIntoTargetType.getName() + "' with underlying type '" + insertIntoTargetType.getUnderlyingType().getName() + "', the " + EngineImportService.EXT_SINGLEROW_FUNCTION_TRANSPOSE + " function must occur alone in the select clause"); } ExprNode expression = unnamedStreams.get(0).getExpressionSelectedAsStream().getSelectExpression(); Class returnType = expression.getExprEvaluator().getType(); if (insertIntoTargetType instanceof ObjectArrayEventType && returnType == Object[].class) { return new SelectExprInsertEventBeanFactory.SelectExprInsertNativeExpressionCoerceObjectArray(insertIntoTargetType, expression.getExprEvaluator(), eventAdapterService); } else if (insertIntoTargetType instanceof MapEventType && JavaClassHelper.isImplementsInterface(returnType, Map.class)) { return new SelectExprInsertEventBeanFactory.SelectExprInsertNativeExpressionCoerceMap(insertIntoTargetType, expression.getExprEvaluator(), eventAdapterService); } else if (insertIntoTargetType instanceof BeanEventType && JavaClassHelper.isSubclassOrImplementsInterface(returnType, insertIntoTargetType.getUnderlyingType())) { return new SelectExprInsertEventBeanFactory.SelectExprInsertNativeExpressionCoerceNative(insertIntoTargetType, expression.getExprEvaluator(), eventAdapterService); } else if (insertIntoTargetType instanceof AvroSchemaEventType && returnType.getName().equals(AvroConstantsNoDep.GENERIC_RECORD_CLASSNAME)) { return new SelectExprInsertEventBeanFactory.SelectExprInsertNativeExpressionCoerceAvro(insertIntoTargetType, expression.getExprEvaluator(), eventAdapterService); } else if (insertIntoTargetType instanceof WrapperEventType) { // for native event types as they got renamed, they become wrappers // check if the proposed wrapper is compatible with the existing wrapper WrapperEventType existing = (WrapperEventType) insertIntoTargetType; if (existing.getUnderlyingEventType() instanceof BeanEventType) { BeanEventType innerType = (BeanEventType) existing.getUnderlyingEventType(); ExprEvaluator evalExprEvaluator = unnamedStreams.get(0).getExpressionSelectedAsStream().getSelectExpression().getExprEvaluator(); if (!JavaClassHelper.isSubclassOrImplementsInterface(evalExprEvaluator.getType(), innerType.getUnderlyingType())) { throw new ExprValidationException("Invalid expression return type '" + evalExprEvaluator.getType() + "' for transpose function, expected '" + innerType.getUnderlyingType().getSimpleName() + "'"); } resultEventType = eventAdapterService.addWrapperType(insertIntoTargetType.getName(), existing.getUnderlyingEventType(), selPropertyTypes, false, true); return new EvalSelectStreamWUnderlying(selectExprContext, resultEventType, namedStreams, isUsingWildcard, unnamedStreams, false, false, underlyingStreamNumber, null, evalExprEvaluator, null); } } throw EvalInsertUtil.makeEventTypeCastException(returnType, insertIntoTargetType); } if (underlyingEventType != null) { // a single stream was selected via "stream.*" and there is no column name // recast as a Map-type if (underlyingEventType instanceof MapEventType && insertIntoTargetType instanceof MapEventType) { return EvalSelectStreamWUndRecastMapFactory.make(typeService.getEventTypes(), selectExprContext, selectedStreams.get(0).getStreamSelected().getStreamNumber(), insertIntoTargetType, exprNodes, engineImportService, statementName, typeService.getEngineURIQualifier()); } // recast as a Object-array-type if (underlyingEventType instanceof ObjectArrayEventType && insertIntoTargetType instanceof ObjectArrayEventType) { return EvalSelectStreamWUndRecastObjectArrayFactory.make(typeService.getEventTypes(), selectExprContext, selectedStreams.get(0).getStreamSelected().getStreamNumber(), insertIntoTargetType, exprNodes, engineImportService, statementName, typeService.getEngineURIQualifier()); } // recast as a Avro-type if (underlyingEventType instanceof AvroSchemaEventType && insertIntoTargetType instanceof AvroSchemaEventType) { return eventAdapterService.getEventAdapterAvroHandler().getOutputFactory().makeRecast(typeService.getEventTypes(), selectExprContext, selectedStreams.get(0).getStreamSelected().getStreamNumber(), (AvroSchemaEventType) insertIntoTargetType, exprNodes, statementName, typeService.getEngineURIQualifier()); } // recast as a Bean-type if (underlyingEventType instanceof BeanEventType && insertIntoTargetType instanceof BeanEventType) { return new EvalInsertBeanRecast(insertIntoTargetType, eventAdapterService, selectedStreams.get(0).getStreamSelected().getStreamNumber(), typeService.getEventTypes()); } // wrap if no recast possible TableMetadata tableMetadata = tableService.getTableMetadataFromEventType(underlyingEventType); if (tableMetadata != null) { underlyingEventType = tableMetadata.getPublicEventType(); } resultEventType = eventAdapterService.addWrapperType(insertIntoDesc.getEventTypeName(), underlyingEventType, selPropertyTypes, false, true); return new EvalSelectStreamWUnderlying(selectExprContext, resultEventType, namedStreams, isUsingWildcard, unnamedStreams, singleStreamWrapper, underlyingIsFragmentEvent, underlyingStreamNumber, underlyingPropertyEventGetter, underlyingExprEvaluator, tableMetadata); } else { // there are one or more streams selected with column name such as "stream.* as columnOne" if (insertIntoTargetType instanceof BeanEventType) { String name = selectedStreams.get(0).getStreamSelected().getStreamName(); String alias = selectedStreams.get(0).getStreamSelected().getOptionalName(); String syntaxUsed = name + ".*" + (alias != null ? " as " + alias : ""); String syntaxInstead = name + (alias != null ? " as " + alias : ""); throw new ExprValidationException("The '" + syntaxUsed + "' syntax is not allowed when inserting into an existing bean event type, use the '" + syntaxInstead + "' syntax instead"); } if (insertIntoTargetType == null || insertIntoTargetType instanceof MapEventType) { resultEventType = eventAdapterService.addNestableMapType(insertIntoDesc.getEventTypeName(), selPropertyTypes, null, false, false, false, false, true); Set<String> propertiesToUnwrap = getEventBeanToObjectProps(selPropertyTypes, resultEventType); if (propertiesToUnwrap.isEmpty()) { return new EvalSelectStreamNoUnderlyingMap(selectExprContext, resultEventType, namedStreams, isUsingWildcard); } else { return new EvalSelectStreamNoUndWEventBeanToObj(selectExprContext, resultEventType, namedStreams, isUsingWildcard, propertiesToUnwrap); } } else if (insertIntoTargetType instanceof ObjectArrayEventType) { Set<String> propertiesToUnwrap = getEventBeanToObjectProps(selPropertyTypes, insertIntoTargetType); if (propertiesToUnwrap.isEmpty()) { return new EvalSelectStreamNoUnderlyingObjectArray(selectExprContext, insertIntoTargetType, namedStreams, isUsingWildcard); } else { return new EvalSelectStreamNoUndWEventBeanToObjObjArray(selectExprContext, insertIntoTargetType, namedStreams, isUsingWildcard, propertiesToUnwrap); } } else if (insertIntoTargetType instanceof AvroSchemaEventType) { throw new ExprValidationException("Avro event type does not allow contained beans"); } else { throw new IllegalStateException("Unrecognized event type " + insertIntoTargetType); } } } ValueAddEventProcessor vaeProcessor = valueAddEventService.getValueAddProcessor(insertIntoDesc.getEventTypeName()); EventType resultEventType; if (isUsingWildcard) { if (vaeProcessor != null) { resultEventType = vaeProcessor.getValueAddEventType(); isRevisionEvent = true; vaeProcessor.validateEventType(eventType); } else { if (insertIntoTargetType != null) { // handle insert-into with fast coercion (no additional properties selected) if (selPropertyTypes.isEmpty()) { if (insertIntoTargetType instanceof BeanEventType && eventType instanceof BeanEventType) { return new EvalInsertBeanRecast(insertIntoTargetType, eventAdapterService, 0, typeService.getEventTypes()); } if (insertIntoTargetType instanceof ObjectArrayEventType && eventType instanceof ObjectArrayEventType) { ObjectArrayEventType target = (ObjectArrayEventType) insertIntoTargetType; ObjectArrayEventType source = (ObjectArrayEventType) eventType; String msg = BaseNestableEventType.isDeepEqualsProperties(eventType.getName(), source.getTypes(), target.getTypes()); if (msg == null) { return new EvalInsertCoercionObjectArray(insertIntoTargetType, eventAdapterService); } } if (insertIntoTargetType instanceof MapEventType && eventType instanceof MapEventType) { return new EvalInsertCoercionMap(insertIntoTargetType, eventAdapterService); } if (insertIntoTargetType instanceof AvroSchemaEventType && eventType instanceof AvroSchemaEventType) { return new EvalInsertCoercionAvro(insertIntoTargetType, eventAdapterService); } if (insertIntoTargetType instanceof WrapperEventType && eventType instanceof BeanEventType) { WrapperEventType wrapperType = (WrapperEventType) insertIntoTargetType; if (wrapperType.getUnderlyingEventType() instanceof BeanEventType) { return new EvalInsertBeanWrapRecast(wrapperType, eventAdapterService, 0, typeService.getEventTypes()); } } } // handle insert-into by generating the writer with possible additional properties SelectExprProcessor existingTypeProcessor = SelectExprInsertEventBeanFactory.getInsertUnderlyingNonJoin(eventAdapterService, insertIntoTargetType, isUsingWildcard, typeService, exprEvaluators, columnNames, expressionReturnTypes, engineImportService, insertIntoDesc, columnNamesAsProvided, true, statementName); if (existingTypeProcessor != null) { return existingTypeProcessor; } } if (selPropertyTypes.isEmpty() && eventType instanceof BeanEventType) { BeanEventType beanEventType = (BeanEventType) eventType; resultEventType = eventAdapterService.addBeanTypeByName(insertIntoDesc.getEventTypeName(), beanEventType.getUnderlyingType(), false); } else { resultEventType = eventAdapterService.addWrapperType(insertIntoDesc.getEventTypeName(), eventType, selPropertyTypes, false, true); } } if (singleStreamWrapper) { if (!isRevisionEvent) { return new EvalInsertWildcardSSWrapper(selectExprContext, resultEventType); } else { return new EvalInsertWildcardSSWrapperRevision(selectExprContext, resultEventType, vaeProcessor); } } if (joinWildcardProcessor == null) { if (!isRevisionEvent) { if (resultEventType instanceof WrapperEventType) { return new EvalInsertWildcardWrapper(selectExprContext, resultEventType); } else { return new EvalInsertWildcardBean(selectExprContext, resultEventType); } } else { if (exprEvaluators.length == 0) { return new EvalInsertWildcardRevision(selectExprContext, resultEventType, vaeProcessor); } else { EventType wrappingEventType = eventAdapterService.addWrapperType(insertIntoDesc.getEventTypeName() + "_wrapped", eventType, selPropertyTypes, false, true); return new EvalInsertWildcardRevisionWrapper(selectExprContext, resultEventType, vaeProcessor, wrappingEventType); } } } else { if (!isRevisionEvent) { return new EvalInsertWildcardJoin(selectExprContext, resultEventType, joinWildcardProcessor); } else { return new EvalInsertWildcardJoinRevision(selectExprContext, resultEventType, joinWildcardProcessor, vaeProcessor); } } } // not using wildcard resultEventType = null; if ((columnNames.length == 1) && (insertIntoDesc.getColumnNames().size() == 0)) { if (insertIntoTargetType != null) { // check if the existing type and new type are compatible Object columnOneType = expressionReturnTypes[0]; if (insertIntoTargetType instanceof WrapperEventType) { WrapperEventType wrapperType = (WrapperEventType) insertIntoTargetType; // Map and Object both supported if (wrapperType.getUnderlyingEventType().getUnderlyingType() == columnOneType) { singleColumnWrapOrBeanCoercion = true; resultEventType = insertIntoTargetType; } } if ((insertIntoTargetType instanceof BeanEventType) && (columnOneType instanceof Class)) { BeanEventType beanType = (BeanEventType) insertIntoTargetType; // Map and Object both supported if (JavaClassHelper.isSubclassOrImplementsInterface((Class) columnOneType, beanType.getUnderlyingType())) { singleColumnWrapOrBeanCoercion = true; resultEventType = insertIntoTargetType; } } } } if (singleColumnWrapOrBeanCoercion) { if (!isRevisionEvent) { if (resultEventType instanceof WrapperEventType) { WrapperEventType wrapper = (WrapperEventType) resultEventType; if (wrapper.getUnderlyingEventType() instanceof MapEventType) { return new EvalInsertNoWildcardSingleColCoercionMapWrap(selectExprContext, wrapper); } else if (wrapper.getUnderlyingEventType() instanceof ObjectArrayEventType) { return new EvalInsertNoWildcardSingleColCoercionObjectArrayWrap(selectExprContext, wrapper); } else if (wrapper.getUnderlyingEventType() instanceof AvroSchemaEventType) { return new EvalInsertNoWildcardSingleColCoercionAvroWrap(selectExprContext, wrapper); } else if (wrapper.getUnderlyingEventType() instanceof VariantEventType) { VariantEventType variantEventType = (VariantEventType) wrapper.getUnderlyingEventType(); vaeProcessor = valueAddEventService.getValueAddProcessor(variantEventType.getName()); return new EvalInsertNoWildcardSingleColCoercionBeanWrapVariant(selectExprContext, wrapper, vaeProcessor); } else { return new EvalInsertNoWildcardSingleColCoercionBeanWrap(selectExprContext, wrapper); } } else { if (resultEventType instanceof BeanEventType) { return new EvalInsertNoWildcardSingleColCoercionBean(selectExprContext, resultEventType); } } } else { if (resultEventType instanceof BeanEventType) { return new EvalInsertNoWildcardSingleColCoercionRevisionBean(selectExprContext, resultEventType, vaeProcessor, vaeInnerEventType); } else { TriFunction<EventAdapterService, Object, EventType, EventBean> func; if (resultEventType instanceof MapEventType) { func = new TriFunction<EventAdapterService, Object, EventType, EventBean>() { public EventBean apply(EventAdapterService eventAdapterService, Object und, EventType type) { return eventAdapterService.adapterForTypedMap((Map) und, type); } }; } else if (resultEventType instanceof ObjectArrayEventType) { func = new TriFunction<EventAdapterService, Object, EventType, EventBean>() { public EventBean apply(EventAdapterService eventAdapterService, Object und, EventType type) { return eventAdapterService.adapterForTypedObjectArray((Object[]) und, type); } }; } else if (resultEventType instanceof AvroSchemaEventType) { func = new TriFunction<EventAdapterService, Object, EventType, EventBean>() { public EventBean apply(EventAdapterService eventAdapterService, Object und, EventType type) { return eventAdapterService.adapterForTypedAvro(und, type); } }; } else { func = new TriFunction<EventAdapterService, Object, EventType, EventBean>() { public EventBean apply(EventAdapterService eventAdapterService, Object und, EventType type) { return eventAdapterService.adapterForTypedBean(und, type); } }; } return new EvalInsertNoWildcardSingleColCoercionRevisionFunc(selectExprContext, resultEventType, vaeProcessor, vaeInnerEventType, func); } } } if (resultEventType == null) { if (vaeProcessor != null) { // Use an anonymous type if the target is not a variant stream if (valueAddEventService.getValueAddProcessor(insertIntoDesc.getEventTypeName()) == null) { resultEventType = eventAdapterService.createAnonymousMapType(statementId + "_vae_" + CollectionUtil.toString(assignedTypeNumberStack, "_"), selPropertyTypes, true); } else { String statementName = "stmt_" + statementId + "_insert"; resultEventType = eventAdapterService.addNestableMapType(statementName, selPropertyTypes, null, false, false, false, false, true); } } else { EventType existingType = insertIntoTargetType; if (existingType == null) { // The type may however be an auto-import or fully-qualified class name Class clazz = null; try { clazz = this.engineImportService.resolveClass(insertIntoDesc.getEventTypeName(), false); } catch (EngineImportException e) { log.debug("Target stream name '" + insertIntoDesc.getEventTypeName() + "' is not resolved as a class name"); } if (clazz != null) { existingType = eventAdapterService.addBeanType(clazz.getName(), clazz, false, false, false); } } SelectExprProcessor selectExprInsertEventBean = null; if (existingType != null) { selectExprInsertEventBean = SelectExprInsertEventBeanFactory.getInsertUnderlyingNonJoin(eventAdapterService, existingType, isUsingWildcard, typeService, exprEvaluators, columnNames, expressionReturnTypes, engineImportService, insertIntoDesc, columnNamesAsProvided, false, statementName); } if (selectExprInsertEventBean != null) { return selectExprInsertEventBean; } else { // use the provided override-type if there is one if (optionalInsertIntoOverrideType != null) { resultEventType = insertIntoTargetType; } else if (existingType instanceof AvroSchemaEventType) { eventAdapterService.getEventAdapterAvroHandler().avroCompat(existingType, selPropertyTypes); resultEventType = existingType; } else { EventUnderlyingType out = EventRepresentationUtil.getRepresentation(annotations, configuration, CreateSchemaDesc.AssignedType.NONE); if (out == EventUnderlyingType.MAP) { resultEventType = eventAdapterService.addNestableMapType(insertIntoDesc.getEventTypeName(), selPropertyTypes, null, false, false, false, false, true); } else if (out == EventUnderlyingType.OBJECTARRAY) { resultEventType = eventAdapterService.addNestableObjectArrayType(insertIntoDesc.getEventTypeName(), selPropertyTypes, null, false, false, false, false, true, false, null); } else if (out == EventUnderlyingType.AVRO) { resultEventType = eventAdapterService.addAvroType(insertIntoDesc.getEventTypeName(), selPropertyTypes, false, false, false, false, true, annotations, null, statementName, typeService.getEngineURIQualifier()); } else { throw new IllegalStateException("Unrecognized code " + out); } } } } } if (vaeProcessor != null) { vaeProcessor.validateEventType(resultEventType); vaeInnerEventType = resultEventType; resultEventType = vaeProcessor.getValueAddEventType(); isRevisionEvent = true; } if (!isRevisionEvent) { if (resultEventType instanceof MapEventType) { return new EvalInsertNoWildcardMap(selectExprContext, resultEventType); } else if (resultEventType instanceof ObjectArrayEventType) { return makeObjectArrayConsiderReorder(selectExprContext, (ObjectArrayEventType) resultEventType, statementName, typeService.getEngineURIQualifier()); } else if (resultEventType instanceof AvroSchemaEventType) { return eventAdapterService.getEventAdapterAvroHandler().getOutputFactory().makeSelectNoWildcard(selectExprContext, resultEventType, tableService, statementName, typeService.getEngineURIQualifier()); } else { throw new IllegalStateException("Unrecognized output type " + resultEventType); } } else { return new EvalInsertNoWildcardRevision(selectExprContext, resultEventType, vaeProcessor, vaeInnerEventType); } } catch (EventAdapterException ex) { log.debug("Exception provided by event adapter: " + ex.getMessage(), ex); throw new ExprValidationException(ex.getMessage(), ex); } } private boolean isGroupByRollupNullableExpression(ExprNode expr, GroupByRollupInfo groupByRollupInfo) { // if all levels include this key, we are fine for (AggregationGroupByRollupLevel level : groupByRollupInfo.getRollupDesc().getLevels()) { if (level.isAggregationTop()) { return true; } boolean found = false; for (int rollupKeyIndex : level.getRollupKeys()) { ExprNode groupExpression = groupByRollupInfo.getExprNodes()[rollupKeyIndex]; if (ExprNodeUtility.deepEquals(groupExpression, expr, false)) { found = true; break; } } if (!found) { return true; } } return false; } private SelectExprProcessor makeObjectArrayConsiderReorder(SelectExprContext selectExprContext, ObjectArrayEventType resultEventType, String statementName, String engineURI) throws ExprValidationException { TypeWidener[] wideners = new TypeWidener[selectExprContext.getColumnNames().length]; int[] remapped = new int[selectExprContext.getColumnNames().length]; boolean needRemap = false; for (int i = 0; i < selectExprContext.getColumnNames().length; i++) { String colName = selectExprContext.getColumnNames()[i]; int index = CollectionUtil.findItem(resultEventType.getPropertyNames(), colName); if (index == -1) { throw new ExprValidationException("Could not find property '" + colName + "' in " + getTypeNameConsiderTable(resultEventType, tableService)); } remapped[i] = index; if (index != i) { needRemap = true; } Class sourceColumnType = selectExprContext.getExpressionNodes()[i].getType(); Class targetPropType = resultEventType.getPropertyType(colName); wideners[i] = TypeWidenerFactory.getCheckPropertyAssignType(colName, sourceColumnType, targetPropType, colName, false, eventAdapterService.getTypeWidenerCustomizer(resultEventType), statementName, engineURI); } if (!needRemap) { return new EvalInsertNoWildcardObjectArray(selectExprContext, resultEventType); } if (CollectionUtil.isAllNullArray(wideners)) { return new EvalInsertNoWildcardObjectArrayRemap(selectExprContext, resultEventType, remapped); } return new EvalInsertNoWildcardObjectArrayRemapWWiden(selectExprContext, resultEventType, remapped, wideners); } private String getTypeNameConsiderTable(ObjectArrayEventType resultEventType, TableService tableService) { TableMetadata metadata = tableService.getTableMetadataFromEventType(resultEventType); if (metadata != null) { return "table '" + metadata.getTableName() + "'"; } return "type '" + resultEventType.getName() + "'"; } private Pair<ExprEvaluator, Object> handleUnderlyingStreamInsert(ExprEvaluator exprEvaluator, NamedWindowMgmtService namedWindowMgmtService, final EventAdapterService eventAdapterService) { if (!(exprEvaluator instanceof ExprStreamUnderlyingNode)) { return null; } final ExprStreamUnderlyingNode undNode = (ExprStreamUnderlyingNode) exprEvaluator; final int streamNum = undNode.getStreamId(); final Class returnType = undNode.getExprEvaluator().getType(); final EventType namedWindowAsType = getNamedWindowUnderlyingType(namedWindowMgmtService, eventAdapterService, typeService.getEventTypes()[streamNum]); final TableMetadata tableMetadata = tableService.getTableMetadataFromEventType(typeService.getEventTypes()[streamNum]); EventType eventTypeStream; ExprEvaluator evaluator; if (tableMetadata != null) { eventTypeStream = tableMetadata.getPublicEventType(); evaluator = new SelectExprProcessorEvalStreamInsertTable(streamNum, undNode, tableMetadata, returnType); } else if (namedWindowAsType == null) { eventTypeStream = typeService.getEventTypes()[streamNum]; evaluator = new SelectExprProcessorEvalStreamInsertUnd(undNode, streamNum, returnType); } else { eventTypeStream = namedWindowAsType; evaluator = new SelectExprProcessorEvalStreamInsertNamedWindow(streamNum, namedWindowAsType, returnType, eventAdapterService); } return new Pair<ExprEvaluator, Object>(evaluator, eventTypeStream); } private EventType getNamedWindowUnderlyingType(NamedWindowMgmtService namedWindowMgmtService, EventAdapterService eventAdapterService, EventType eventType) { if (!namedWindowMgmtService.isNamedWindow(eventType.getName())) { return null; } NamedWindowProcessor processor = namedWindowMgmtService.getProcessor(eventType.getName()); if (processor.getEventTypeAsName() == null) { return null; } return eventAdapterService.getExistsTypeByName(processor.getEventTypeAsName()); } private static EPType[] determineInsertedEventTypeTargets(EventType targetType, List<SelectClauseExprCompiledSpec> selectionList) { EPType[] targets = new EPType[selectionList.size()]; if (targetType == null) { return targets; } for (int i = 0; i < selectionList.size(); i++) { SelectClauseExprCompiledSpec expr = selectionList.get(i); if (expr.getProvidedName() == null) { continue; } EventPropertyDescriptor desc = targetType.getPropertyDescriptor(expr.getProvidedName()); if (desc == null) { continue; } if (!desc.isFragment()) { continue; } FragmentEventType fragmentEventType = targetType.getFragmentType(expr.getProvidedName()); if (fragmentEventType == null) { continue; } if (fragmentEventType.isIndexed()) { targets[i] = EPTypeHelper.collectionOfEvents(fragmentEventType.getFragmentType()); } else { targets[i] = EPTypeHelper.singleEvent(fragmentEventType.getFragmentType()); } } return targets; } private TypeAndFunctionPair handleTypableExpression(ExprEvaluator exprEvaluator, int expressionNum) throws ExprValidationException { if (!(exprEvaluator instanceof ExprEvaluatorTypableReturn)) { return null; } ExprEvaluatorTypableReturn typable = (ExprEvaluatorTypableReturn) exprEvaluator; LinkedHashMap<String, Object> eventTypeExpr = typable.getRowProperties(); if (eventTypeExpr == null) { return null; } EventType mapType = eventAdapterService.createAnonymousMapType(statementId + "_innereval_" + CollectionUtil.toString(assignedTypeNumberStack, "_") + "_" + expressionNum, eventTypeExpr, true); ExprEvaluator evaluatorFragment = new SelectExprProcessorEvalTypableMap(mapType, exprEvaluator, eventAdapterService); return new TypeAndFunctionPair(mapType, evaluatorFragment); } private TypeAndFunctionPair handleInsertIntoEnumeration(String insertIntoColName, EPType insertIntoTarget, ExprEvaluator exprEvaluator, EngineImportService engineImportService) throws ExprValidationException { if (!(exprEvaluator instanceof ExprEvaluatorEnumeration) || insertIntoTarget == null || (!EPTypeHelper.isCarryEvent(insertIntoTarget))) { return null; } final ExprEvaluatorEnumeration enumeration = (ExprEvaluatorEnumeration) exprEvaluator; final EventType eventTypeSingle = enumeration.getEventTypeSingle(eventAdapterService, statementId); final EventType eventTypeColl = enumeration.getEventTypeCollection(eventAdapterService, statementId); final EventType sourceType = eventTypeSingle != null ? eventTypeSingle : eventTypeColl; if (eventTypeColl == null && eventTypeSingle == null) { return null; // enumeration is untyped events (select-clause provided to subquery or 'new' operator) } if (((EventTypeSPI) sourceType).getMetadata().getTypeClass() == EventTypeMetadata.TypeClass.ANONYMOUS) { return null; // we don't allow anonymous types here, thus excluding subquery multi-column selection } // check type info final EventType targetType = EPTypeHelper.getEventType(insertIntoTarget); checkTypeCompatible(insertIntoColName, targetType, sourceType); // handle collection target - produce EventBean[] if (insertIntoTarget instanceof EventMultiValuedEPType) { if (eventTypeColl != null) { ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Collection<EventBean> events = enumeration.evaluateGetROCollectionEvents(eventsPerStream, isNewData, exprEvaluatorContext); if (events == null) { return null; } return events.toArray(new EventBean[events.size()]); } public Class getType() { return JavaClassHelper.getArrayType(targetType.getUnderlyingType()); } }; return new TypeAndFunctionPair(new EventType[]{targetType}, evaluatorFragment); } ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { EventBean event = enumeration.evaluateGetEventBean(eventsPerStream, isNewData, exprEvaluatorContext); if (event == null) { return null; } return new EventBean[]{event}; } public Class getType() { return JavaClassHelper.getArrayType(targetType.getUnderlyingType()); } }; return new TypeAndFunctionPair(new EventType[]{targetType}, evaluatorFragment); } // handle single-bean target // handle single-source if (eventTypeSingle != null) { ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { return enumeration.evaluateGetEventBean(eventsPerStream, isNewData, exprEvaluatorContext); } public Class getType() { return targetType.getUnderlyingType(); } }; return new TypeAndFunctionPair(targetType, evaluatorFragment); } // handle collection-source by taking the first ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Collection<EventBean> events = enumeration.evaluateGetROCollectionEvents(eventsPerStream, isNewData, exprEvaluatorContext); if (events == null || events.size() == 0) { return null; } return EventBeanUtility.getNonemptyFirstEvent(events); } public Class getType() { return targetType.getUnderlyingType(); } }; return new TypeAndFunctionPair(targetType, evaluatorFragment); } private void checkTypeCompatible(String insertIntoCol, EventType targetType, EventType selectedType) throws ExprValidationException { if (!EventTypeUtility.isTypeOrSubTypeOf(targetType, selectedType)) { throw new ExprValidationException( "Incompatible type detected attempting to insert into column '" + insertIntoCol + "' type '" + targetType.getName() + "' compared to selected type '" + selectedType.getName() + "'"); } } private TypeAndFunctionPair handleInsertIntoTypableExpression(EPType insertIntoTarget, ExprEvaluator exprEvaluator, EngineImportService engineImportService) throws ExprValidationException { if (!(exprEvaluator instanceof ExprEvaluatorTypableReturn) || insertIntoTarget == null || (!EPTypeHelper.isCarryEvent(insertIntoTarget))) { return null; } final EventType targetType = EPTypeHelper.getEventType(insertIntoTarget); final ExprEvaluatorTypableReturn typable = (ExprEvaluatorTypableReturn) exprEvaluator; if (typable.isMultirow() == null) { // not typable after all return null; } LinkedHashMap<String, Object> eventTypeExpr = typable.getRowProperties(); if (eventTypeExpr == null) { return null; } Set<WriteablePropertyDescriptor> writables = eventAdapterService.getWriteableProperties(targetType, false); List<WriteablePropertyDescriptor> written = new ArrayList<WriteablePropertyDescriptor>(); List<Map.Entry<String, Object>> writtenOffered = new ArrayList<Map.Entry<String, Object>>(); // from Map<String, Object> determine properties and type widening that may be required for (Map.Entry<String, Object> offeredProperty : eventTypeExpr.entrySet()) { WriteablePropertyDescriptor writable = EventTypeUtility.findWritable(offeredProperty.getKey(), writables); if (writable == null) { throw new ExprValidationException("Failed to find property '" + offeredProperty.getKey() + "' among properties for target event type '" + targetType.getName() + "'"); } written.add(writable); writtenOffered.add(offeredProperty); } // determine widening and column type compatibility final TypeWidener[] wideners = new TypeWidener[written.size()]; TypeWidenerCustomizer typeWidenerCustomizer = eventAdapterService.getTypeWidenerCustomizer(targetType); for (int i = 0; i < written.size(); i++) { Class expected = written.get(i).getType(); Map.Entry<String, Object> provided = writtenOffered.get(i); if (provided.getValue() instanceof Class) { wideners[i] = TypeWidenerFactory.getCheckPropertyAssignType(provided.getKey(), (Class) provided.getValue(), expected, written.get(i).getPropertyName(), false, typeWidenerCustomizer, statementName, typeService.getEngineURIQualifier()); } } final boolean hasWideners = !CollectionUtil.isAllNullArray(wideners); // obtain factory WriteablePropertyDescriptor[] writtenArray = written.toArray(new WriteablePropertyDescriptor[written.size()]); EventBeanManufacturer manufacturer; try { manufacturer = eventAdapterService.getManufacturer(targetType, writtenArray, engineImportService, false); } catch (EventBeanManufactureException e) { throw new ExprValidationException("Failed to obtain eventbean factory: " + e.getMessage(), e); } // handle collection final EventBeanManufacturer factory = manufacturer; if (insertIntoTarget instanceof EventMultiValuedEPType && typable.isMultirow()) { ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Object[][] rows = typable.evaluateTypableMulti(eventsPerStream, isNewData, exprEvaluatorContext); if (rows == null) { return null; } if (rows.length == 0) { return new EventBean[0]; } if (hasWideners) { applyWideners(rows, wideners); } EventBean[] events = new EventBean[rows.length]; for (int i = 0; i < events.length; i++) { events[i] = factory.make(rows[i]); } return events; } public Class getType() { return JavaClassHelper.getArrayType(targetType.getUnderlyingType()); } }; return new TypeAndFunctionPair(new EventType[]{targetType}, evaluatorFragment); } else if (insertIntoTarget instanceof EventMultiValuedEPType && !typable.isMultirow()) { ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Object[] row = typable.evaluateTypableSingle(eventsPerStream, isNewData, exprEvaluatorContext); if (row == null) { return null; } if (hasWideners) { applyWideners(row, wideners); } return new EventBean[]{factory.make(row)}; } public Class getType() { return JavaClassHelper.getArrayType(targetType.getUnderlyingType()); } }; return new TypeAndFunctionPair(new EventType[]{targetType}, evaluatorFragment); } else if (insertIntoTarget instanceof EventEPType && !typable.isMultirow()) { ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Object[] row = typable.evaluateTypableSingle(eventsPerStream, isNewData, exprEvaluatorContext); if (row == null) { return null; } if (hasWideners) { applyWideners(row, wideners); } return factory.make(row); } public Class getType() { return JavaClassHelper.getArrayType(targetType.getUnderlyingType()); } }; return new TypeAndFunctionPair(targetType, evaluatorFragment); } // we are discarding all but the first row ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Object[][] rows = typable.evaluateTypableMulti(eventsPerStream, isNewData, exprEvaluatorContext); if (rows == null) { return null; } if (rows.length == 0) { return new EventBean[0]; } if (hasWideners) { applyWideners(rows[0], wideners); } return factory.make(rows[0]); } public Class getType() { return JavaClassHelper.getArrayType(targetType.getUnderlyingType()); } }; return new TypeAndFunctionPair(targetType, evaluatorFragment); } private void applyWideners(Object[] row, TypeWidener[] wideners) { for (int i = 0; i < wideners.length; i++) { if (wideners[i] != null) { row[i] = wideners[i].widen(row[i]); } } } private void applyWideners(Object[][] rows, TypeWidener[] wideners) { for (Object[] row : rows) { applyWideners(row, wideners); } } private TypeAndFunctionPair handleAtEventbeanEnumeration(boolean isEventBeans, ExprEvaluator evaluator) throws ExprValidationException { if (!(evaluator instanceof ExprEvaluatorEnumeration) || !isEventBeans) { return null; } final ExprEvaluatorEnumeration enumEval = (ExprEvaluatorEnumeration) evaluator; final EventType eventTypeSingle = enumEval.getEventTypeSingle(eventAdapterService, statementId); if (eventTypeSingle != null) { final TableMetadata tableMetadata = tableService.getTableMetadataFromEventType(eventTypeSingle); if (tableMetadata == null) { ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { return enumEval.evaluateGetEventBean(eventsPerStream, isNewData, exprEvaluatorContext); } public Class getType() { return eventTypeSingle.getUnderlyingType(); } }; return new TypeAndFunctionPair(eventTypeSingle, evaluatorFragment); } ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { EventBean event = enumEval.evaluateGetEventBean(eventsPerStream, isNewData, exprEvaluatorContext); if (event == null) { return null; } return tableMetadata.getEventToPublic().convert(event, eventsPerStream, isNewData, exprEvaluatorContext); } public Class getType() { return tableMetadata.getPublicEventType().getUnderlyingType(); } }; return new TypeAndFunctionPair(tableMetadata.getPublicEventType(), evaluatorFragment); } final EventType eventTypeColl = enumEval.getEventTypeCollection(eventAdapterService, statementId); if (eventTypeColl != null) { final TableMetadata tableMetadata = tableService.getTableMetadataFromEventType(eventTypeColl); if (tableMetadata == null) { ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { // the protocol is EventBean[] Object result = enumEval.evaluateGetROCollectionEvents(eventsPerStream, isNewData, exprEvaluatorContext); if (result != null && result instanceof Collection) { Collection<EventBean> events = (Collection<EventBean>) result; return events.toArray(new EventBean[events.size()]); } return result; } public Class getType() { return JavaClassHelper.getArrayType(eventTypeColl.getUnderlyingType()); } }; return new TypeAndFunctionPair(new EventType[]{eventTypeColl}, evaluatorFragment); } ExprEvaluator evaluatorFragment = new ExprEvaluator() { public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { // the protocol is EventBean[] Object result = enumEval.evaluateGetROCollectionEvents(eventsPerStream, isNewData, exprEvaluatorContext); if (result == null) { return null; } if (result instanceof Collection) { Collection<EventBean> events = (Collection<EventBean>) result; EventBean[] out = new EventBean[events.size()]; int index = 0; for (EventBean event : events) { out[index++] = tableMetadata.getEventToPublic().convert(event, eventsPerStream, isNewData, exprEvaluatorContext); } return out; } EventBean[] events = (EventBean[]) result; for (int i = 0; i < events.length; i++) { events[i] = tableMetadata.getEventToPublic().convert(events[i], eventsPerStream, isNewData, exprEvaluatorContext); } return events; } public Class getType() { return JavaClassHelper.getArrayType(tableMetadata.getPublicEventType().getUnderlyingType()); } }; return new TypeAndFunctionPair(new EventType[]{tableMetadata.getPublicEventType()}, evaluatorFragment); } return null; } // Determine which properties provided by the Map must be downcast from EventBean to Object private static Set<String> getEventBeanToObjectProps(Map<String, Object> selPropertyTypes, EventType resultEventType) { if (!(resultEventType instanceof BaseNestableEventType)) { return Collections.emptySet(); } BaseNestableEventType mapEventType = (BaseNestableEventType) resultEventType; Set<String> props = null; for (Map.Entry<String, Object> entry : selPropertyTypes.entrySet()) { if (entry.getValue() instanceof BeanEventType && mapEventType.getTypes().get(entry.getKey()) instanceof Class) { if (props == null) { props = new HashSet<String>(); } props.add(entry.getKey()); } } if (props == null) { return Collections.emptySet(); } return props; } private static void verifyInsertInto(InsertIntoDesc insertIntoDesc, List<SelectClauseExprCompiledSpec> selectionList) throws ExprValidationException { // Verify all column names are unique Set<String> names = new HashSet<String>(); for (String element : insertIntoDesc.getColumnNames()) { if (names.contains(element)) { throw new ExprValidationException("Property name '" + element + "' appears more then once in insert-into clause"); } names.add(element); } // Verify number of columns matches the select clause if ((!insertIntoDesc.getColumnNames().isEmpty()) && (insertIntoDesc.getColumnNames().size() != selectionList.size())) { throw new ExprValidationException("Number of supplied values in the select or values clause does not match insert-into clause"); } } private static class TypeAndFunctionPair { private final Object type; private final ExprEvaluator function; private TypeAndFunctionPair(Object type, ExprEvaluator function) { this.type = type; this.function = function; } public Object getType() { return type; } public ExprEvaluator getFunction() { return function; } } }