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, methodResolutionService.getEngineImportService());
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, methodResolutionService.getEngineImportService());
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;
}
// 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 fragments selected
EventType targetType= null;
if (insertIntoDesc != null)
{
targetType = eventAdapterService.getExistsTypeByName(insertIntoDesc.getEventTypeName());
}
// 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 (targetType != null)
{
targetFragment = targetType.getFragmentType(columnNames[i]);
}
if ((targetType != null) &&
(fragmentType.getFragmentType().getUnderlyingType() == expressionReturnTypes[i]) &&
((targetFragment == null) || (targetFragment != null && targetFragment.isNative())) )
{
ExprEvaluator evaluatorFragment;
// A match was found, we replace the expression
final EventPropertyGetter getter = eventTypeStream.getGetter(propertyName);
final Class returnType = eventTypeStream.getPropertyType(propertyName);
evaluatorFragment = new ExprEvaluator() {
public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
{
EventBean streamEvent = eventsPerStream[streamNum];
if (streamEvent == null)
{
return null;
}
return getter.get(streamEvent);
}
public Class getType()
{
return returnType;
}
};
exprEvaluators[i] = evaluatorFragment;
}
// same for arrays: may need to unwrap the fragment if the target type has this underlying type
else if ((targetType != null) && expressionReturnTypes[i] instanceof Class &&
(fragmentType.getFragmentType().getUnderlyingType() == ((Class) expressionReturnTypes[i]).getComponentType()) &&
((targetFragment == null) || (targetFragment != null && targetFragment.isNative())) )
{
ExprEvaluator evaluatorFragment;
final EventPropertyGetter getter = eventTypeStream.getGetter(propertyName);
final Class returnType = JavaClassHelper.getArrayType(eventTypeStream.getPropertyType(propertyName));
evaluatorFragment = new ExprEvaluator() {
public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
{
EventBean streamEvent = eventsPerStream[streamNum];
if (streamEvent == null)
{
return null;
}
return getter.get(streamEvent);
}
public Class getType()
{
return returnType;
}
};
exprEvaluators[i] = evaluatorFragment;
}
else
{
ExprEvaluator evaluatorFragment;
final EventPropertyGetter getter = eventTypeStream.getGetter(propertyName);
final Class returnType = eventTypeStream.getFragmentType(propertyName).getFragmentType().getUnderlyingType();
// A match was found, we replace the expression
evaluatorFragment = new ExprEvaluator() {
public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
{
EventBean streamEvent = eventsPerStream[streamNum];
if (streamEvent == null)
{
return null;
}
return getter.getFragment(streamEvent);
}
public Class getType()
{
return returnType;
}
};
exprEvaluators[i] = evaluatorFragment;
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++)
{
if (!(exprEvaluators[i] instanceof ExprStreamUnderlyingNode))
{
continue;
}
ExprStreamUnderlyingNode undNode = (ExprStreamUnderlyingNode) exprEvaluators[i];
final int streamNum = undNode.getStreamId();
final Class returnType = undNode.getExprEvaluator().getType();
EventType eventTypeStream = typeService.getEventTypes()[streamNum];
// A match was found, we replace the expression
ExprEvaluator evaluator = new ExprEvaluator() {
public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
{
return eventsPerStream[streamNum];
}
public Class getType()
{
return returnType;
}
};
exprEvaluators[i] = evaluator;
expressionReturnTypes[i] = eventTypeStream;
}
// 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 = 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;
boolean useMapOutput = EventRepresentationUtil.isMap(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;
}
// the property.* syntax for : select property.* from A
else if (streamSpec.isProperty())
{
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);
}
}
// the stream.* syntax for: select a.* from A as a
else
{
underlyingEventType = typeService.getEventTypes()[underlyingStreamNumber];
}
}
// handle case where the unnamed stream is a "transpose" function
else {
ExprNode expression = unnamedStreams.get(0).getExpressionSelectedAsStream().getSelectExpression();
Class returnType = expression.getExprEvaluator().getType();
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)
{
resultEventType = eventAdapterService.createAnonymousWrapperType(statementId + "_wrapout_" + CollectionUtil.toString(assignedTypeNumberStack, "_"), underlyingEventType, selPropertyTypes);
return new EvalSelectStreamWUnderlying(selectExprContext, resultEventType, namedStreams, isUsingWildcard,
unnamedStreams, singleStreamWrapper, underlyingIsFragmentEvent, underlyingStreamNumber, underlyingPropertyEventGetter, underlyingExprEvaluator);
}
else
{
resultEventType = eventAdapterService.createAnonymousMapType(statementId + "_mapout_" + CollectionUtil.toString(assignedTypeNumberStack, "_"), selPropertyTypes);
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 (!useMapOutput) {
resultEventType = eventAdapterService.createAnonymousObjectArrayType(statementId + "_result_" + CollectionUtil.toString(assignedTypeNumberStack, "_"), selPropertyTypes);
}
else {
resultEventType = eventAdapterService.createAnonymousMapType(statementId + "_result_" + CollectionUtil.toString(assignedTypeNumberStack, "_"), selPropertyTypes);
}
if (selectExprContext.getExpressionNodes().length == 0) {
return new EvalSelectNoWildcardEmptyProps(selectExprContext, resultEventType);
}
else {
if (!useMapOutput) {
return new EvalSelectNoWildcardObjectArray(selectExprContext, resultEventType);
}
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;
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 && targetType instanceof MapEventType) {
return EvalSelectStreamWUndRecastMapFactory.make(typeService.getEventTypes(), selectExprContext, selectedStreams.get(0).getStreamSelected().getStreamNumber(), targetType, exprNodes, methodResolutionService.getEngineImportService());
}
// recast as a Object-array-type
if (underlyingEventType instanceof ObjectArrayEventType && targetType instanceof ObjectArrayEventType) {
return EvalSelectStreamWUndRecastObjectArrayFactory.make(typeService.getEventTypes(), selectExprContext, selectedStreams.get(0).getStreamSelected().getStreamNumber(), targetType, exprNodes, methodResolutionService.getEngineImportService());
}
// recast as a Bean-type
if (underlyingEventType instanceof BeanEventType && targetType instanceof BeanEventType) {
SelectClauseExprCompiledSpec expressionAsStream = selectedStreams.get(0).getExpressionSelectedAsStream();
if (expressionAsStream != null) {
return new EvalSelectStreamWUnderlyingRecastBean(selectExprContext, expressionAsStream, underlyingEventType, targetType, exprEvaluators.length);
}
else {
return new EvalInsertBeanRecast(targetType, eventAdapterService, selectedStreams.get(0).getStreamSelected().getStreamNumber(), typeService.getEventTypes());