/*
***************************************************************************************
* 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.table.merge;
import com.espertech.esper.client.EventType;
import com.espertech.esper.client.annotation.AuditEnum;
import com.espertech.esper.core.service.ExprEvaluatorContextStatement;
import com.espertech.esper.core.service.InternalEventRouter;
import com.espertech.esper.core.service.StatementContext;
import com.espertech.esper.epl.core.*;
import com.espertech.esper.epl.expression.core.ExprEvaluator;
import com.espertech.esper.epl.expression.core.ExprValidationException;
import com.espertech.esper.epl.named.NamedWindowOnMergeHelper;
import com.espertech.esper.epl.spec.*;
import com.espertech.esper.epl.table.mgmt.TableMetadata;
import com.espertech.esper.epl.table.upd.TableUpdateStrategy;
import com.espertech.esper.epl.updatehelper.EventBeanUpdateHelper;
import com.espertech.esper.epl.updatehelper.EventBeanUpdateHelperFactory;
import com.espertech.esper.event.EventTypeMetadata;
import com.espertech.esper.event.map.MapEventType;
import com.espertech.esper.util.UuidGenerator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Factory for handles for updates/inserts/deletes/select
*/
public class TableOnMergeHelper {
private List<TableOnMergeMatch> matched;
private List<TableOnMergeMatch> unmatched;
private boolean requiresWriteLock;
public TableOnMergeHelper(StatementContext statementContext,
OnTriggerMergeDesc onTriggerDesc,
EventType triggeringEventType,
String triggeringStreamName,
InternalEventRouter internalEventRouter,
TableMetadata tableMetadata)
throws ExprValidationException {
matched = new ArrayList<TableOnMergeMatch>();
unmatched = new ArrayList<TableOnMergeMatch>();
int count = 1;
boolean hasDeleteAction = false;
boolean hasInsertIntoTableAction = false;
boolean hasUpdateAction = false;
for (OnTriggerMergeMatched matchedItem : onTriggerDesc.getItems()) {
List<TableOnMergeAction> actions = new ArrayList<TableOnMergeAction>();
for (OnTriggerMergeAction item : matchedItem.getActions()) {
try {
if (item instanceof OnTriggerMergeActionInsert) {
OnTriggerMergeActionInsert insertDesc = (OnTriggerMergeActionInsert) item;
TableOnMergeActionIns action = setupInsert(tableMetadata, internalEventRouter, count, insertDesc, triggeringEventType, triggeringStreamName, statementContext);
actions.add(action);
hasInsertIntoTableAction = action.isInsertIntoBinding();
} else if (item instanceof OnTriggerMergeActionUpdate) {
OnTriggerMergeActionUpdate updateDesc = (OnTriggerMergeActionUpdate) item;
EventBeanUpdateHelper updateHelper = EventBeanUpdateHelperFactory.make(tableMetadata.getTableName(), tableMetadata.getInternalEventType(), updateDesc.getAssignments(), onTriggerDesc.getOptionalAsName(), triggeringEventType, false, statementContext.getStatementName(), statementContext.getEngineURI(), statementContext.getEventAdapterService());
ExprEvaluator filterEval = updateDesc.getOptionalWhereClause() == null ? null : updateDesc.getOptionalWhereClause().getExprEvaluator();
TableUpdateStrategy tableUpdateStrategy = statementContext.getTableService().getTableUpdateStrategy(tableMetadata, updateHelper, true);
TableOnMergeActionUpd upd = new TableOnMergeActionUpd(filterEval, tableUpdateStrategy);
actions.add(upd);
statementContext.getTableService().addTableUpdateStrategyReceiver(tableMetadata, statementContext.getStatementName(), upd, updateHelper, true);
hasUpdateAction = true;
} else if (item instanceof OnTriggerMergeActionDelete) {
OnTriggerMergeActionDelete deleteDesc = (OnTriggerMergeActionDelete) item;
ExprEvaluator filterEval = deleteDesc.getOptionalWhereClause() == null ? null : deleteDesc.getOptionalWhereClause().getExprEvaluator();
actions.add(new TableOnMergeActionDel(filterEval));
hasDeleteAction = true;
} else {
throw new IllegalArgumentException("Invalid type of merge item '" + item.getClass() + "'");
}
count++;
} catch (ExprValidationException ex) {
boolean isNot = item instanceof OnTriggerMergeActionInsert;
String message = "Validation failed in when-" + (isNot ? "not-" : "") + "matched (clause " + count + "): " + ex.getMessage();
throw new ExprValidationException(message, ex);
}
}
if (matchedItem.isMatchedUnmatched()) {
matched.add(new TableOnMergeMatch(matchedItem.getOptionalMatchCond(), actions));
} else {
unmatched.add(new TableOnMergeMatch(matchedItem.getOptionalMatchCond(), actions));
}
}
// since updates may change future secondary keys
requiresWriteLock = hasDeleteAction || hasInsertIntoTableAction || hasUpdateAction;
}
private TableOnMergeActionIns setupInsert(TableMetadata tableMetadata, InternalEventRouter internalEventRouter, int selectClauseNumber, OnTriggerMergeActionInsert desc, EventType triggeringEventType, String triggeringStreamName, StatementContext statementContext)
throws ExprValidationException {
// Compile insert-into info
String streamName = desc.getOptionalStreamName() != null ? desc.getOptionalStreamName() : tableMetadata.getTableName();
InsertIntoDesc insertIntoDesc = InsertIntoDesc.fromColumns(streamName, desc.getColumns());
EventType insertIntoTargetType = streamName.equals(tableMetadata.getTableName()) ? tableMetadata.getInternalEventType() : null;
// rewrite any wildcards to use "stream.wildcard"
if (triggeringStreamName == null) {
triggeringStreamName = UuidGenerator.generate();
}
List<SelectClauseElementCompiled> selectNoWildcard = NamedWindowOnMergeHelper.compileSelectNoWildcard(triggeringStreamName, desc.getSelectClauseCompiled());
// Set up event types for select-clause evaluation: The first type does not contain anything as its the named window row which is not present for insert
EventType dummyTypeNoProperties = new MapEventType(EventTypeMetadata.createAnonymous("merge_named_window_insert", EventTypeMetadata.ApplicationType.MAP), "merge_named_window_insert", 0, null, Collections.<String, Object>emptyMap(), null, null, null);
EventType[] eventTypes = new EventType[]{dummyTypeNoProperties, triggeringEventType};
String[] streamNames = new String[]{UuidGenerator.generate(), triggeringStreamName};
StreamTypeService streamTypeService = new StreamTypeServiceImpl(eventTypes, streamNames, new boolean[1], statementContext.getEngineURI(), false);
// Get select expr processor
SelectExprEventTypeRegistry selectExprEventTypeRegistry = new SelectExprEventTypeRegistry(statementContext.getStatementName(), statementContext.getStatementEventTypeRef());
ExprEvaluatorContextStatement exprEvaluatorContext = new ExprEvaluatorContextStatement(statementContext, false);
SelectExprProcessor insertHelper = SelectExprProcessorFactory.getProcessor(Collections.singleton(selectClauseNumber),
selectNoWildcard.toArray(new SelectClauseElementCompiled[selectNoWildcard.size()]), false, insertIntoDesc, insertIntoTargetType, null, streamTypeService,
statementContext.getEventAdapterService(), statementContext.getStatementResultService(), statementContext.getValueAddEventService(), selectExprEventTypeRegistry,
statementContext.getEngineImportService(), exprEvaluatorContext, statementContext.getVariableService(), statementContext.getTableService(), statementContext.getTimeProvider(), statementContext.getEngineURI(), statementContext.getStatementId(), statementContext.getStatementName(), statementContext.getAnnotations(), statementContext.getContextDescriptor(), statementContext.getConfigSnapshot(), null, statementContext.getNamedWindowMgmtService(), null, null,
statementContext.getStatementExtensionServicesContext());
ExprEvaluator filterEval = desc.getOptionalWhereClause() == null ? null : desc.getOptionalWhereClause().getExprEvaluator();
InternalEventRouter routerToUser = streamName.equals(tableMetadata.getTableName()) ? null : internalEventRouter;
boolean audit = AuditEnum.INSERT.getAudit(statementContext.getAnnotations()) != null;
return new TableOnMergeActionIns(filterEval, insertHelper, routerToUser, statementContext.getEpStatementHandle(), statementContext.getInternalEventEngineRouteDest(), audit, tableMetadata.getRowFactory());
}
public List<TableOnMergeMatch> getMatched() {
return matched;
}
public List<TableOnMergeMatch> getUnmatched() {
return unmatched;
}
public boolean isRequiresWriteLock() {
return requiresWriteLock;
}
}