Search in sources :

Example 31 with QueryResolverException

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;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) TeiidComponentException(org.teiid.core.TeiidComponentException) QueryResolverException(org.teiid.api.exception.query.QueryResolverException)

Example 32 with QueryResolverException

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;
}
Also used : QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) QueryResolverException(org.teiid.api.exception.query.QueryResolverException)

Example 33 with QueryResolverException

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;
}
Also used : TempMetadataAdapter(org.teiid.query.metadata.TempMetadataAdapter) AnalysisRecord(org.teiid.query.analysis.AnalysisRecord) Determinism(org.teiid.metadata.FunctionMethod.Determinism) CommandContext(org.teiid.query.util.CommandContext) CreateProcedureCommand(org.teiid.query.sql.proc.CreateProcedureCommand) TempMetadataID(org.teiid.query.metadata.TempMetadataID) TempCapabilitiesFinder(org.teiid.query.metadata.TempCapabilitiesFinder) TeiidRuntimeException(org.teiid.core.TeiidRuntimeException) Insert(org.teiid.query.sql.lang.Insert) QueryResolverException(org.teiid.api.exception.query.QueryResolverException) TeiidProcessingException(org.teiid.core.TeiidProcessingException) RelationalPlanner(org.teiid.query.optimizer.relational.RelationalPlanner) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) PreparedPlan(org.teiid.dqp.internal.process.PreparedPlan) Procedure(org.teiid.metadata.Procedure) ProcessorPlan(org.teiid.query.processor.ProcessorPlan) IDGenerator(org.teiid.core.id.IDGenerator) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) TempMetadataStore(org.teiid.query.metadata.TempMetadataStore)

Example 34 with QueryResolverException

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;
}
Also used : UnresolvedSymbolDescription(org.teiid.api.exception.query.UnresolvedSymbolDescription) QueryResolverException(org.teiid.api.exception.query.QueryResolverException)

Example 35 with QueryResolverException

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);
}
Also used : QueryParserException(org.teiid.api.exception.query.QueryParserException) LanguageObject(org.teiid.query.sql.LanguageObject) QueryMetadataException(org.teiid.api.exception.query.QueryMetadataException) QueryResolverException(org.teiid.api.exception.query.QueryResolverException)

Aggregations

QueryResolverException (org.teiid.api.exception.query.QueryResolverException)62 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)13 TempMetadataID (org.teiid.query.metadata.TempMetadataID)11 ExceptionExpression (org.teiid.query.sql.proc.ExceptionExpression)11 ArrayList (java.util.ArrayList)10 Test (org.junit.Test)10 TeiidComponentException (org.teiid.core.TeiidComponentException)10 Expression (org.teiid.query.sql.symbol.Expression)10 QueryMetadataException (org.teiid.api.exception.query.QueryMetadataException)8 CreateProcedureCommand (org.teiid.query.sql.proc.CreateProcedureCommand)7 Command (org.teiid.query.sql.lang.Command)6 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)6 QueryParserException (org.teiid.api.exception.query.QueryParserException)5 TempMetadataStore (org.teiid.query.metadata.TempMetadataStore)5 LanguageObject (org.teiid.query.sql.LanguageObject)5 List (java.util.List)4 UnresolvedSymbolDescription (org.teiid.api.exception.query.UnresolvedSymbolDescription)4 TempMetadataAdapter (org.teiid.query.metadata.TempMetadataAdapter)4 StoredProcedure (org.teiid.query.sql.lang.StoredProcedure)4 HashSet (java.util.HashSet)3