private void validate( VDBMetaData vdb, ModelMetaData model, AbstractMetadataRecord record, ValidatorReport report, IQueryMetadataInterface metadata, MetadataFactory mf) { ValidatorReport resolverReport = null; try { if (record instanceof Procedure) { Procedure p = (Procedure) record; Command command = queryParser.parseProcedure(p.getQueryPlan(), false); GroupSymbol gs = createASTNode(ASTNodes.GROUP_SYMBOL); gs.setName(p.getFullName()); QueryResolver resolver = new QueryResolver(queryParser); resolver.resolveCommand(command, gs, ICommand.TYPE_STORED_PROCEDURE, metadata, false); Validator validator = new Validator(); resolverReport = validator.validate(command, metadata); determineDependencies(p, command); } else if (record instanceof Table) { Table t = (Table) record; GroupSymbol symbol = createASTNode(ASTNodes.GROUP_SYMBOL); symbol.setName(t.getFullName()); ResolverUtil.resolveGroup(symbol, metadata); String selectTransformation = t.getSelectTransformation(); boolean columnsIsEmpty = t.getColumns() == null || t.getColumns().isEmpty(); // Consider columns if teid 8.11 or lower boolean considerColumns_811 = isTeiidOrGreater(Version.TEIID_8_12_4) ? true : columnsIsEmpty; // Consider columns if teiid 8.12.4+ boolean considerColumns_8124 = isTeiidOrGreater(Version.TEIID_8_12_4) ? columnsIsEmpty : true; if (t.isVirtual() && considerColumns_811) { QueryCommand command = (QueryCommand) queryParser.parseCommand(selectTransformation); QueryResolver resolver = new QueryResolver(queryParser); resolver.resolveCommand(command, metadata); Validator validator = new Validator(); resolverReport = validator.validate(command, metadata); if (!resolverReport.hasItems() && considerColumns_8124) { List<Expression> symbols = command.getProjectedSymbols(); for (Expression column : symbols) { try { addColumn(Symbol.getShortName(column), column.getType(), t, mf); } catch (Exception e) { log(report, model, e.getMessage()); } } } if (considerColumns_8124) { determineDependencies(t, command); if (t.getInsertPlan() != null && t.isInsertPlanEnabled()) { validateUpdatePlan( model, report, metadata, t, t.getInsertPlan(), Command.TYPE_INSERT); } if (t.getUpdatePlan() != null && t.isUpdatePlanEnabled()) { validateUpdatePlan( model, report, metadata, t, t.getUpdatePlan(), Command.TYPE_UPDATE); } if (t.getDeletePlan() != null && t.isDeletePlanEnabled()) { validateUpdatePlan( model, report, metadata, t, t.getDeletePlan(), Command.TYPE_DELETE); } } } boolean addCacheHint = false; if (t.isMaterialized() && t.getMaterializedTable() == null) { List<KeyRecord> fbis = t.getFunctionBasedIndexes(); List<GroupSymbol> groups = Arrays.asList(symbol); if (fbis != null && !fbis.isEmpty()) { for (KeyRecord fbi : fbis) { for (int j = 0; j < fbi.getColumns().size(); j++) { Column c = fbi.getColumns().get(j); if (c.getParent() != fbi) { continue; } String exprString = c.getNameInSource(); try { Expression ex = queryParser.parseExpression(exprString); ResolverVisitor resolverVisitor = new ResolverVisitor(teiidVersion); resolverVisitor.resolveLanguageObject(ex, groups, metadata); if (!ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(ex) .isEmpty()) { log( report, model, Messages.gs(Messages.TEIID.TEIID31114, exprString, fbi.getFullName())); } EvaluatableVisitor ev = new EvaluatableVisitor(teiidVersion); PreOrPostOrderNavigator.doVisit(ex, ev, PostOrderNavigator.PRE_ORDER); if (ev.getDeterminismLevel().compareTo(Determinism.VDB_DETERMINISTIC) < 0) { log( report, model, Messages.gs(Messages.TEIID.TEIID31115, exprString, fbi.getFullName())); } } catch (QueryResolverException e) { log( report, model, Messages.gs( Messages.TEIID.TEIID31116, exprString, fbi.getFullName(), e.getMessage())); } } } } } else { addCacheHint = true; } // this seems to parse, resolve and validate. QueryResolver resolver = new QueryResolver(queryParser); QueryNode node = resolver.resolveView( symbol, new QueryNode(t.getSelectTransformation()), SQLConstants.Reserved.SELECT, metadata); CacheHint cacheHint = node.getCommand().getCacheHint(); Long ttl = -1L; if (cacheHint != null && cacheHint.getTtl() != null && addCacheHint && t.getProperty(MATVIEW_TTL, false) == null) { ttl = cacheHint.getTtl(); t.setProperty(MATVIEW_TTL, String.valueOf(ttl)); } } if (resolverReport != null && resolverReport.hasItems()) { for (ValidatorFailure v : resolverReport.getItems()) { log( report, model, v.getStatus() == IValidatorFailure.VFStatus.ERROR ? Severity.ERROR : Severity.WARNING, v.getMessage()); } } processReport(model, record, report, resolverReport); } catch (Exception e) { log( report, model, Messages.gs(Messages.TEIID.TEIID31080, record.getFullName(), e.getMessage())); } }
/** * Helper to quickly get the ValueIteratorProvider instances from obj * * @param obj Language object * @return java.util.ArrayList of found ValueIteratorProvider */ public static final List<SubqueryContainer<?>> getValueIteratorProviders(LanguageObject obj) { ValueIteratorProviderCollectorVisitor visitor = new ValueIteratorProviderCollectorVisitor(); PreOrderNavigator.doVisit(obj, visitor); return visitor.getValueIteratorProviders(); }
private void resolveStatement( CreateProcedureCommand command, Statement statement, GroupContext externalGroups, GroupSymbol variables, TempMetadataAdapter metadata) throws QueryResolverException, QueryMetadataException, TeiidComponentException { LogManager.logTrace( org.teiid.logging.LogConstants.CTX_QUERY_RESOLVER, new Object[] {"Resolving statement", statement}); // $NON-NLS-1$ switch (statement.getType()) { case Statement.TYPE_IF: IfStatement ifStmt = (IfStatement) statement; Criteria ifCrit = ifStmt.getCondition(); for (SubqueryContainer container : ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(ifCrit)) { resolveEmbeddedCommand(metadata, externalGroups, container.getCommand()); } ResolverVisitor.resolveLanguageObject(ifCrit, null, externalGroups, metadata); resolveBlock(command, ifStmt.getIfBlock(), externalGroups, metadata); if (ifStmt.hasElseBlock()) { resolveBlock(command, ifStmt.getElseBlock(), externalGroups, metadata); } break; case Statement.TYPE_COMMAND: CommandStatement cmdStmt = (CommandStatement) statement; Command subCommand = cmdStmt.getCommand(); TempMetadataStore discoveredMetadata = resolveEmbeddedCommand(metadata, externalGroups, subCommand); if (subCommand instanceof StoredProcedure) { StoredProcedure sp = (StoredProcedure) subCommand; for (SPParameter param : sp.getParameters()) { switch (param.getParameterType()) { case ParameterInfo.OUT: case ParameterInfo.RETURN_VALUE: if (param.getExpression() != null && !isAssignable(metadata, param)) { throw new QueryResolverException( QueryPlugin.Event.TEIID30121, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30121, param.getExpression())); } sp.setCallableStatement(true); break; case ParameterInfo.INOUT: if (!isAssignable(metadata, param)) { continue; } sp.setCallableStatement(true); break; } } } if (discoveredMetadata != null) { metadata.getMetadataStore().getData().putAll(discoveredMetadata.getData()); } // dynamic commands need to be updated as to their implicitly expected projected symbols if (subCommand instanceof DynamicCommand) { DynamicCommand dynCommand = (DynamicCommand) subCommand; if (dynCommand.getIntoGroup() == null && !dynCommand.isAsClauseSet()) { if ((command.getResultSetColumns() != null && command.getResultSetColumns().isEmpty()) || !cmdStmt.isReturnable() || command.getResultSetColumns() == null) { // we're not interested in the resultset dynCommand.setAsColumns(Collections.EMPTY_LIST); } else { // should match the procedure dynCommand.setAsColumns(command.getResultSetColumns()); } } } if (command.getResultSetColumns() == null && cmdStmt.isReturnable() && subCommand.returnsResultSet() && subCommand.getResultSetColumns() != null && !subCommand.getResultSetColumns().isEmpty()) { command.setResultSetColumns(subCommand.getResultSetColumns()); if (command.getProjectedSymbols().isEmpty()) { command.setProjectedSymbols(subCommand.getResultSetColumns()); } } break; case Statement.TYPE_ERROR: case Statement.TYPE_ASSIGNMENT: case Statement.TYPE_DECLARE: case Statement.TYPE_RETURN: ExpressionStatement exprStmt = (ExpressionStatement) statement; // first resolve the value. this ensures the value cannot use the variable being defined if (exprStmt.getExpression() != null) { Expression expr = exprStmt.getExpression(); for (SubqueryContainer container : ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(expr)) { resolveEmbeddedCommand(metadata, externalGroups, container.getCommand()); } ResolverVisitor.resolveLanguageObject(expr, null, externalGroups, metadata); } // second resolve the variable switch (statement.getType()) { case Statement.TYPE_DECLARE: collectDeclareVariable( (DeclareStatement) statement, variables, metadata, externalGroups); break; case Statement.TYPE_ASSIGNMENT: AssignmentStatement assStmt = (AssignmentStatement) statement; ResolverVisitor.resolveLanguageObject( assStmt.getVariable(), null, externalGroups, metadata); if (!metadata.elementSupports( assStmt.getVariable().getMetadataID(), SupportConstants.Element.UPDATE)) { throw new QueryResolverException( QueryPlugin.Event.TEIID30121, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30121, assStmt.getVariable())); } // don't allow variable assignments to be external assStmt.getVariable().setIsExternalReference(false); break; case Statement.TYPE_RETURN: ReturnStatement rs = (ReturnStatement) statement; if (rs.getExpression() != null) { if (command.getReturnVariable() == null) { throw new QueryResolverException( QueryPlugin.Event.TEIID31125, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31125, rs)); } rs.setVariable(command.getReturnVariable().clone()); } // else - we don't currently require the use of return for backwards compatibility break; } // third ensure the type matches if (exprStmt.getExpression() != null) { Class<?> varType = exprStmt.getExpectedType(); Class<?> exprType = exprStmt.getExpression().getType(); if (exprType == null) { throw new QueryResolverException( QueryPlugin.Event.TEIID30123, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30123)); } String varTypeName = DataTypeManager.getDataTypeName(varType); exprStmt.setExpression( ResolverUtil.convertExpression(exprStmt.getExpression(), varTypeName, metadata)); if (statement.getType() == Statement.TYPE_ERROR) { ResolverVisitor.checkException(exprStmt.getExpression()); } } break; case Statement.TYPE_WHILE: WhileStatement whileStmt = (WhileStatement) statement; Criteria whileCrit = whileStmt.getCondition(); for (SubqueryContainer container : ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(whileCrit)) { resolveEmbeddedCommand(metadata, externalGroups, container.getCommand()); } ResolverVisitor.resolveLanguageObject(whileCrit, null, externalGroups, metadata); resolveBlock(command, whileStmt.getBlock(), externalGroups, metadata); break; case Statement.TYPE_LOOP: LoopStatement loopStmt = (LoopStatement) statement; String groupName = loopStmt.getCursorName(); isValidGroup(metadata, groupName); Command cmd = loopStmt.getCommand(); resolveEmbeddedCommand(metadata, externalGroups, cmd); List<Expression> symbols = cmd.getProjectedSymbols(); // add the loop cursor group into its own context TempMetadataStore store = metadata.getMetadataStore().clone(); metadata = new TempMetadataAdapter(metadata.getMetadata(), store); externalGroups = new GroupContext(externalGroups, null); ProcedureContainerResolver.addScalarGroup(groupName, store, externalGroups, symbols, false); resolveBlock(command, loopStmt.getBlock(), externalGroups, metadata); break; case Statement.TYPE_COMPOUND: resolveBlock(command, (Block) statement, externalGroups, metadata); break; } }