use of org.teiid.api.exception.query.QueryResolverException in project teiid by teiid.
the class RulePushAggregates method execute.
/**
* @see org.teiid.query.optimizer.relational.OptimizerRule#execute(org.teiid.query.optimizer.relational.plantree.PlanNode,
* org.teiid.query.metadata.QueryMetadataInterface, org.teiid.query.optimizer.capabilities.CapabilitiesFinder,
* org.teiid.query.optimizer.relational.RuleStack, AnalysisRecord, CommandContext)
* @since 4.2
*/
public PlanNode execute(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext ctx) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
this.context = ctx;
groupingNodes = NodeEditor.findAllNodes(plan, NodeConstants.Types.GROUP, NodeConstants.Types.ACCESS);
outer: for (int i = 0; i < groupingNodes.size(); i++) {
PlanNode groupNode = groupingNodes.get(i);
if (groupNode.hasBooleanProperty(Info.ROLLUP)) {
continue;
}
PlanNode child = groupNode.getFirstChild();
List<Expression> groupingExpressions = (List<Expression>) groupNode.getProperty(NodeConstants.Info.GROUP_COLS);
if (groupingExpressions == null) {
groupingExpressions = Collections.emptyList();
}
try {
if (child.getType() == NodeConstants.Types.SOURCE) {
PlanNode setOp = child.getFirstChild();
pushGroupNodeOverUnion(metadata, capFinder, groupNode, child, groupingExpressions, setOp, analysisRecord);
continue;
} else if (child.getType() != NodeConstants.Types.JOIN) {
PlanNode access = NodeEditor.findNodePreOrder(child, NodeConstants.Types.ACCESS, NodeConstants.Types.SOURCE | NodeConstants.Types.JOIN | NodeConstants.Types.SET_OP);
if (access != null) {
PlanNode parent = access.getParent();
while (parent != groupNode) {
if (parent.getType() != NodeConstants.Types.SELECT) {
continue outer;
}
parent = parent.getParent();
}
Set<AggregateSymbol> aggregates = collectAggregates(groupNode);
// hybrid of the join/union/decompose pushing logic
if (access.hasBooleanProperty(Info.IS_MULTI_SOURCE)) {
if (!RuleRaiseAccess.isPartitioned(metadata, groupingExpressions, groupNode)) {
for (AggregateSymbol agg : aggregates) {
if (!agg.canStage()) {
continue outer;
}
}
boolean shouldPushdown = canPushGroupByToUnionChild(metadata, capFinder, groupingExpressions, aggregates, access, analysisRecord, groupNode);
if (!shouldPushdown) {
continue;
}
Set<Expression> stagedGroupingSymbols = new LinkedHashSet<Expression>();
stagedGroupingSymbols.addAll(groupingExpressions);
aggregates = stageAggregates(groupNode, metadata, stagedGroupingSymbols, aggregates, false);
if (aggregates.isEmpty() && stagedGroupingSymbols.isEmpty()) {
continue;
}
addGroupBy(child, new ArrayList<Expression>(stagedGroupingSymbols), aggregates, metadata, groupNode.getParent(), capFinder, false, stagedGroupingSymbols.isEmpty() && containsNullDependent(aggregates));
} else if (groupNode.getFirstChild() == access && RuleRaiseAccess.canRaiseOverGroupBy(groupNode, child, aggregates, metadata, capFinder, analysisRecord, false) && canFilterEmpty(metadata, capFinder, child, groupingExpressions)) {
if (groupingExpressions.isEmpty()) {
addEmptyFilter(aggregates, groupNode, metadata, capFinder, RuleRaiseAccess.getModelIDFromAccess(child, metadata));
}
access.getGroups().clear();
access.getGroups().addAll(groupNode.getGroups());
RuleRaiseAccess.performRaise(null, access, access.getParent());
if (groupingExpressions.isEmpty() && RuleRaiseAccess.canRaiseOverSelect(access, metadata, capFinder, access.getParent(), null)) {
RuleRaiseAccess.performRaise(null, access, access.getParent());
}
}
}
// TODO: consider pushing aggregate in general
}
continue;
}
} catch (QueryResolverException e) {
throw new TeiidComponentException(QueryPlugin.Event.TEIID30264, e);
}
Set<AggregateSymbol> aggregates = collectAggregates(groupNode);
pushGroupNode(groupNode, groupingExpressions, aggregates, metadata, capFinder, context);
}
return plan;
}
use of org.teiid.api.exception.query.QueryResolverException in project teiid by teiid.
the class RulePushAggregates method stageAggregates.
Set<AggregateSymbol> stageAggregates(PlanNode groupNode, QueryMetadataInterface metadata, Set<Expression> stagedGroupingSymbols, Collection<AggregateSymbol> aggregates, boolean join) throws TeiidComponentException, QueryPlannerException {
// remove any aggregates that are computed over a group by column
for (final Iterator<AggregateSymbol> iterator = aggregates.iterator(); iterator.hasNext(); ) {
final AggregateSymbol symbol = iterator.next();
if (symbol.getArgs().length != 1 || symbol.isCardinalityDependent()) {
continue;
}
Expression expr = symbol.getArg(0);
if (stagedGroupingSymbols.contains(expr)) {
iterator.remove();
}
}
if (aggregates.isEmpty()) {
return Collections.emptySet();
}
// Fix any aggregate expressions so they correctly recombine the staged aggregates
Set<AggregateSymbol> newAggs = new HashSet<AggregateSymbol>();
Map<AggregateSymbol, Expression> aggMap;
try {
aggMap = buildAggregateMap(aggregates, metadata, newAggs, join);
} catch (QueryResolverException e) {
throw new QueryPlannerException(QueryPlugin.Event.TEIID30266, e);
}
updateParentAggs(groupNode, aggMap, metadata);
return newAggs;
}
use of org.teiid.api.exception.query.QueryResolverException in project teiid by teiid.
the class QueryOptimizer method optimizePlan.
public static ProcessorPlan optimizePlan(Command command, QueryMetadataInterface metadata, IDGenerator idGenerator, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
if (analysisRecord == null) {
analysisRecord = new AnalysisRecord(false, false);
}
if (context == null) {
context = new CommandContext();
}
if (!(capFinder instanceof TempCapabilitiesFinder)) {
capFinder = new TempCapabilitiesFinder(capFinder);
}
boolean debug = analysisRecord.recordDebug();
if (!(metadata instanceof TempMetadataAdapter)) {
metadata = new TempMetadataAdapter(metadata, new TempMetadataStore());
}
if (context.getMetadata() == null) {
context.setMetadata(metadata);
}
// Create an ID generator that can be used for all plans to generate unique data node IDs
if (idGenerator == null) {
idGenerator = new IDGenerator();
}
if (debug) {
// $NON-NLS-1$
analysisRecord.println("\n----------------------------------------------------------------------------");
// $NON-NLS-1$
analysisRecord.println("OPTIMIZE: \n" + command);
}
if (command instanceof Insert) {
Insert insert = (Insert) command;
if (insert.isUpsert()) {
// if not supported or there are trigger actions, then rewrite as a procedure
// we do this here since we're changing the command type.
// TODO: we could push this back into the rewrite, but it will need to be capabilities aware
GroupSymbol group = insert.getGroup();
Object modelId = metadata.getModelID(group.getMetadataID());
boolean supportsUpsert = CapabilitiesUtil.supports(Capability.UPSERT, modelId, metadata, capFinder);
if (!supportsUpsert) {
try {
command = QueryRewriter.rewriteAsUpsertProcedure(insert, metadata, context);
} catch (TeiidProcessingException e) {
throw new QueryPlannerException(e);
}
if (debug) {
// $NON-NLS-1$
analysisRecord.println("\n----------------------------------------------------------------------------");
// $NON-NLS-1$
analysisRecord.println("OPTIMIZE UPSERT PROCEDURE: \n" + command);
}
}
}
}
ProcessorPlan result = null;
switch(command.getType()) {
case Command.TYPE_UPDATE_PROCEDURE:
CreateProcedureCommand cupc = (CreateProcedureCommand) command;
if (cupc.getUpdateType() != Command.TYPE_UNKNOWN || cupc.getVirtualGroup() == null) {
// row update procedure or anon block
result = planProcedure(command, metadata, idGenerator, capFinder, analysisRecord, context);
} else {
Object pid = cupc.getVirtualGroup().getMetadataID();
if (pid instanceof TempMetadataID) {
TempMetadataID tid = (TempMetadataID) pid;
if (tid.getOriginalMetadataID() != null) {
pid = tid.getOriginalMetadataID();
}
}
String fullName = metadata.getFullName(pid);
// $NON-NLS-1$
fullName = "procedure cache:" + fullName;
PreparedPlan pp = context.getPlan(fullName);
if (pp == null) {
Determinism determinismLevel = context.resetDeterminismLevel();
try {
CommandContext clone = context.clone();
ProcessorPlan plan = planProcedure(command, metadata, idGenerator, capFinder, analysisRecord, clone);
// note that this is not a full prepared plan. It is not usable by user queries.
if (pid instanceof Procedure) {
clone.accessedPlanningObject(pid);
}
pp = new PreparedPlan();
pp.setPlan(plan, clone);
context.putPlan(fullName, pp, context.getDeterminismLevel());
} finally {
context.setDeterminismLevel(determinismLevel);
}
}
result = pp.getPlan().clone();
for (Object id : pp.getAccessInfo().getObjectsAccessed()) {
context.accessedPlanningObject(id);
}
}
break;
case Command.TYPE_BATCHED_UPDATE:
result = BATCHED_UPDATE_PLANNER.optimize(command, idGenerator, metadata, capFinder, analysisRecord, context);
break;
case Command.TYPE_ALTER_PROC:
case Command.TYPE_ALTER_TRIGGER:
case Command.TYPE_ALTER_VIEW:
result = DDL_PLANNER.optimize(command, idGenerator, metadata, capFinder, analysisRecord, context);
break;
case Command.TYPE_SOURCE_EVENT:
result = SOURCE_EVENT_PLANNER.optimize(command, idGenerator, metadata, capFinder, analysisRecord, context);
break;
default:
try {
RelationalPlanner planner = new RelationalPlanner();
planner.initialize(command, idGenerator, metadata, capFinder, analysisRecord, context);
result = planner.optimize(command);
} catch (QueryResolverException e) {
throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30245, e);
}
}
if (debug) {
// $NON-NLS-1$
analysisRecord.println("\n----------------------------------------------------------------------------");
// $NON-NLS-1$
analysisRecord.println("OPTIMIZATION COMPLETE:");
// $NON-NLS-1$
analysisRecord.println("PROCESSOR PLAN:\n" + result);
// $NON-NLS-1$
analysisRecord.println("============================================================================");
}
return result;
}
use of org.teiid.api.exception.query.QueryResolverException in project teiid by teiid.
the class ResolverUtil method handleUnresolvedGroup.
private static QueryResolverException handleUnresolvedGroup(GroupSymbol symbol, String description) {
UnresolvedSymbolDescription usd = new UnresolvedSymbolDescription(symbol.toString(), description);
// $NON-NLS-1$
QueryResolverException e = new QueryResolverException(usd.getDescription() + ": " + usd.getSymbol());
e.setUnresolvedSymbols(Arrays.asList(usd));
return e;
}
use of org.teiid.api.exception.query.QueryResolverException in project teiid by teiid.
the class ResolverUtil method getDefault.
/**
* Get the default value for the parameter, which could be null
* if the parameter is set to NULLABLE. If no default is available,
* a QueryResolverException will be thrown.
*
* @param symbol ElementSymbol retrieved from metadata, fully-resolved
* @param metadata QueryMetadataInterface
* @return expr param (if it is non-null) or default value (if there is one)
* or null Constant (if parameter is optional and therefore allows this)
* @throws QueryResolverException if expr is null, parameter is required and no
* default value is defined
* @throws QueryMetadataException for error retrieving metadata
* @throws TeiidComponentException
* @throws QueryParserException
* @since 4.3
*/
public static Expression getDefault(ElementSymbol symbol, QueryMetadataInterface metadata) throws TeiidComponentException, QueryMetadataException, QueryResolverException {
// Check if there is a default value, if so use it
Object mid = symbol.getMetadataID();
Class<?> type = symbol.getType();
String defaultValue = metadata.getDefaultValue(mid);
boolean omit = false;
String extensionProperty = metadata.getExtensionProperty(mid, BaseColumn.DEFAULT_HANDLING, false);
if (BaseColumn.EXPRESSION_DEFAULT.equalsIgnoreCase(extensionProperty)) {
Expression ex = null;
try {
ex = QueryParser.getQueryParser().parseExpression(defaultValue);
} catch (QueryParserException e) {
// TODO: also validate this at load time
throw new QueryMetadataException(QueryPlugin.Event.TEIID31170, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31170, symbol));
}
List<SubqueryContainer<?>> subqueries = ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(ex);
ResolverVisitor.resolveLanguageObject(ex, metadata);
for (SubqueryContainer<?> container : subqueries) {
QueryResolver.resolveCommand(container.getCommand(), metadata);
}
return ResolverUtil.convertExpression(ex, DataTypeManager.getDataTypeName(type), metadata);
} else if (BaseColumn.OMIT_DEFAULT.equalsIgnoreCase(extensionProperty)) {
Object id = metadata.getGroupIDForElementID(symbol.getMetadataID());
if (!metadata.isVirtualGroup(id)) {
omit = true;
// for physical procedures we just need a dummy value
defaultValue = null;
}
}
if (!omit && defaultValue == null && !metadata.elementSupports(mid, SupportConstants.Element.NULL)) {
throw new QueryResolverException(QueryPlugin.Event.TEIID30089, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30089, symbol.getOutputName()));
}
return getProperlyTypedConstant(defaultValue, type);
}
Aggregations