private void visit(Procedure procedure) { if (this.filter != null && !filter.matcher(procedure.getName()).matches()) { return; } append(CREATE).append(SPACE); if (procedure.isVirtual()) { append(VIRTUAL); } else { append(FOREIGN); } append(SPACE) .append(procedure.isFunction() ? FUNCTION : PROCEDURE) .append(SPACE) .append(SQLStringVisitor.escapeSinglePart(procedure.getName())); append(LPAREN); boolean first = true; for (ProcedureParameter pp : procedure.getParameters()) { if (first) { first = false; } else { append(COMMA).append(SPACE); } visit(pp); } append(RPAREN); if (procedure.getResultSet() != null) { append(SPACE).append(RETURNS); appendOptions(procedure.getResultSet()); append(SPACE).append(TABLE).append(SPACE); addColumns(procedure.getResultSet().getColumns(), true); } /* The parser treats the RETURN clause as optional for a procedure if using the RESULT param for (ProcedureParameter pp: procedure.getParameters()) { if (pp.getType().equals(Type.ReturnValue)) { append(SPACE).append(RETURNS).append(SPACE); appendColumn(buffer, pp, false, true); break; } }*/ // options String options = buildProcedureOptions(procedure); if (!options.isEmpty()) { append(NEWLINE).append(OPTIONS).append(SPACE).append(LPAREN).append(options).append(RPAREN); } // block if (procedure.isVirtual()) { append(NEWLINE).append(SQLConstants.Reserved.AS).append(NEWLINE); String plan = procedure.getQueryPlan(); append(plan); } append(SEMICOLON); }
@Test public void testVirtualProcedure() throws Exception { String ddl = "CREATE VIRTUAL PROCEDURE myProc(OUT p1 boolean, p2 varchar, INOUT p3 decimal) " + "RETURNS (r1 varchar, r2 decimal) " + "OPTIONS(RANDOM 'any', UUID 'uuid', NAMEINSOURCE 'nis', ANNOTATION 'desc', UPDATECOUNT '2') " + "AS /*+ cache */ BEGIN select * from foo; END"; Schema s = helpParse(ddl, "model").getSchema(); Procedure proc = s.getProcedure("myProc"); assertNotNull(proc); assertTrue(proc.isVirtual()); assertFalse(proc.isFunction()); assertEquals(3, proc.getParameters().size()); assertEquals("p1", proc.getParameters().get(0).getName()); assertEquals("boolean", proc.getParameters().get(0).getDatatype().getName()); assertEquals(ProcedureParameter.Type.Out, proc.getParameters().get(0).getType()); assertEquals("p2", proc.getParameters().get(1).getName()); assertEquals("string", proc.getParameters().get(1).getDatatype().getName()); assertEquals(ProcedureParameter.Type.In, proc.getParameters().get(1).getType()); assertEquals("p3", proc.getParameters().get(2).getName()); assertEquals("bigdecimal", proc.getParameters().get(2).getDatatype().getName()); assertEquals(ProcedureParameter.Type.InOut, proc.getParameters().get(2).getType()); ColumnSet<Procedure> ret = proc.getResultSet(); assertNotNull(ret); assertEquals(2, ret.getColumns().size()); assertEquals("r1", ret.getColumns().get(0).getName()); assertEquals("string", ret.getColumns().get(0).getDatatype().getName()); assertEquals("r2", ret.getColumns().get(1).getName()); assertEquals("bigdecimal", ret.getColumns().get(1).getDatatype().getName()); assertEquals("uuid", proc.getUUID()); assertEquals("nis", proc.getNameInSource()); assertEquals("desc", proc.getAnnotation()); assertEquals(2, proc.getUpdateCount()); assertEquals("any", proc.getProperties().get("RANDOM")); assertEquals("/*+ cache */ BEGIN\nSELECT * FROM foo;\nEND", proc.getQueryPlan()); }
@Override public void execute( VDBMetaData vdb, MetadataStore store, ValidatorReport report, MetadataValidator metadataValidator) { IQueryMetadataInterface metadata = vdb.getAttachment(IQueryMetadataInterface.class); metadata = new TempMetadataAdapter(metadata, new TempMetadataStore()); for (Schema schema : store.getSchemaList()) { if (vdb.getImportedModels().contains(schema.getName())) { continue; } ModelMetaData model = vdb.getModel(schema.getName()); MetadataFactory mf = new MetadataFactory( teiidVersion, vdb.getName(), vdb.getVersion(), metadataValidator.typeMap, model) { @Override protected void setUUID(AbstractMetadataRecord record) { if (count >= 0) { count = Integer.MIN_VALUE; } super.setUUID(record); } }; mf.setBuiltinDataTypes(store.getDatatypes()); for (AbstractMetadataRecord record : schema.getResolvingOrder()) { if (record instanceof Table) { Table t = (Table) record; // no need to verify the transformation of the xml mapping document, // as this is very specific and designer already validates it. if (t.getTableType() == Table.Type.Document || t.getTableType() == Table.Type.XmlMappingClass || t.getTableType() == Table.Type.XmlStagingTable) { continue; } if (t.isVirtual() && t.getTableType() != Table.Type.TemporaryTable) { if (t.getSelectTransformation() == null) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31079, t.getFullName(), model.getName())); } else { metadataValidator.validate(vdb, model, t, report, metadata, mf); } } } else if (record instanceof Procedure) { Procedure p = (Procedure) record; boolean test = p.isVirtual(); if (teiidVersion.isLessThan(Version.TEIID_8_11)) test = test && !p.isFunction(); if (test) { if (p.getQueryPlan() == null) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31081, p.getFullName(), model.getName())); } else { metadataValidator.validate(vdb, model, p, report, metadata, mf); } } } } } }
@Override public void execute( VDBMetaData vdb, MetadataStore store, ValidatorReport report, MetadataValidator metadataValidator) { for (Schema schema : store.getSchemaList()) { if (vdb.getImportedModels().contains(schema.getName())) { continue; } ModelMetaData model = vdb.getModel(schema.getName()); for (Table t : schema.getTables().values()) { if (t.isPhysical() && !model.isSource()) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31075, t.getFullName(), model.getName())); } } Set<String> names = new HashSet<String>(); for (Procedure p : schema.getProcedures().values()) { boolean hasReturn = false; names.clear(); for (int i = 0; i < p.getParameters().size(); i++) { ProcedureParameter param = p.getParameters().get(i); if (param.isVarArg() && param != p.getParameters().get(p.getParameters().size() - 1)) { // check that the rest of the parameters are optional // this accommodates variadic multi-source procedures // effective this and the resolving logic ensure that you can used named parameters // for everything, // or call the vararg procedure as normal if (isTeiidOrGreater(Version.TEIID_8_10)) { for (int j = i + 1; j < p.getParameters().size(); j++) { ProcedureParameter param1 = p.getParameters().get(j); if ((param1.getType() == Type.In || param1.getType() == Type.InOut) && (param1.isVarArg() || (param1.getNullType() != NullType.Nullable && param1.getDefaultValue() == null))) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31112, p.getFullName())); } } } else { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31112, p.getFullName())); } } if (param.getType() == ProcedureParameter.Type.ReturnValue) { if (hasReturn) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31107, p.getFullName())); } hasReturn = true; } else if (p.isFunction() && param.getType() != ProcedureParameter.Type.In && teiidVersion.isGreaterThanOrEqualTo(Version.TEIID_8_11)) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31165, p.getFullName(), param.getFullName())); } if (!names.add(param.getName())) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31106, p.getFullName(), param.getFullName())); } } if (!p.isVirtual() && !model.isSource()) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31077, p.getFullName(), model.getName())); } if (p.isFunction() && teiidVersion.isGreaterThanOrEqualTo(Version.TEIID_8_11)) { if (!hasReturn) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31166, p.getFullName())); } if (p.isVirtual() && p.getQueryPlan() == null) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31167, p.getFullName())); } } } for (FunctionMethod func : schema.getFunctions().values()) { for (FunctionParameter param : func.getInputParameters()) { if (param.isVarArg() && param != func.getInputParameters().get(func.getInputParameterCount() - 1)) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31112, func.getFullName())); } } if (func.getPushdown().equals(FunctionMethod.PushDown.MUST_PUSHDOWN) && !model.isSource()) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31078, func.getFullName(), model.getName())); } } } }