/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.query.metadata;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.StringReader;
import java.util.Map;
import java.util.Properties;
import org.junit.Before;
import org.junit.Test;
import org.teiid.adminapi.Model;
import org.teiid.adminapi.impl.ModelMetaData;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.designer.query.metadata.IQueryMetadataInterface;
import org.teiid.designer.runtime.version.spi.TeiidServerVersion.Version;
import org.teiid.designer.validator.IValidator.IValidatorFailure;
import org.teiid.metadata.Datatype;
import org.teiid.metadata.MetadataFactory;
import org.teiid.metadata.MetadataStore;
import org.teiid.metadata.Table;
import org.teiid.query.function.SystemFunctionManager;
import org.teiid.query.parser.TeiidParser;
import org.teiid.query.validator.ValidatorFailure;
import org.teiid.query.validator.ValidatorReport;
/**
*
*/
@SuppressWarnings( {"javadoc", "nls"} )
public abstract class AbstractTestMetadataValidator extends AbstractTest {
public final SystemFunctionManager SFM;
private VDBMetaData vdb;
private MetadataStore store;
public AbstractTestMetadataValidator(Version teiidVersion) {
super(teiidVersion);
SFM = new SystemFunctionManager(getTeiidVersion(), getClass().getClassLoader());
}
@Before
public void setUp() {
store = new MetadataStore();
vdb = new VDBMetaData();
vdb.setName("myVDB");
vdb.setVersion(1);
}
private Map<String, Datatype> getDataTypes() {
return SystemMetadata.getInstance(getTeiidVersion()).getRuntimeTypeMap();
}
private void buildTransformationMetadata() {
TransformationMetadata metadata = new TransformationMetadata(getTeiidVersion(), this.vdb, new CompositeMetadataStore(this.store),
null, SFM.getSystemFunctions(), null);
this.vdb.addAttchment(IQueryMetadataInterface.class, metadata);
this.vdb.addAttchment(TransformationMetadata.class, metadata);
}
private ModelMetaData buildModel(String modelName, boolean physical, VDBMetaData vdb, MetadataStore store, String ddl)
throws Exception {
ModelMetaData model = new ModelMetaData();
model.setName(modelName);
model.setModelType(physical ? Model.Type.PHYSICAL : Model.Type.VIRTUAL);
vdb.addModel(model);
MetadataFactory mf = new MetadataFactory(getTeiidVersion(), "myVDB", 1, modelName, getDataTypes(), new Properties(), ddl);
mf.setParser(getQueryParser());
mf.setBuiltinDataTypes(SystemMetadata.getInstance(getTeiidVersion()).getSystemStore().getDatatypes());
mf.getSchema().setPhysical(physical);
mf.parse(new StringReader(ddl));
mf.mergeInto(store);
model.addAttchment(MetadataFactory.class, mf);
return model;
}
@Test
public void testSourceModelArtifacts() throws Exception {
String ddl = "create foreign table g1(e1 integer, e2 varchar(12)); create view g2(e1 integer, e2 varchar(12)) AS select * from foo;";
buildModel("pm1", true, this.vdb, this.store, ddl);
ValidatorReport report = new ValidatorReport();
MetadataValidator metadataValidator = new MetadataValidator(getTeiidVersion());
metadataValidator.new SourceModelArtifacts().execute(vdb, store, report, newMetadataValidator());
assertFalse(printError(report), report.hasItems());
}
private String printError(ValidatorReport report) {
StringBuilder sb = new StringBuilder();
for (ValidatorFailure v : report.getItems()) {
if (v.getStatus() == IValidatorFailure.VFStatus.ERROR) {
sb.append(v);
sb.append("\n");
}
}
return sb.toString();
}
@Test
public void testViewModelArtifacts() throws Exception {
String ddl = "create foreign table g1(e1 integer, e2 varchar(12)); create view g2(e1 integer, e2 varchar(12)) AS select * from foo;";
buildModel("vm1", false, this.vdb, this.store, ddl);
ValidatorReport report = new ValidatorReport();
MetadataValidator metadataValidator = new MetadataValidator(getTeiidVersion());
metadataValidator.new SourceModelArtifacts().execute(vdb, store, report, newMetadataValidator());
assertTrue(printError(report), report.hasItems());
}
@Test
public void testModelArtifactsSucess() throws Exception {
buildModel("vm1", false, this.vdb, this.store, "create view g2(e1 integer, e2 varchar(12)) AS select * from foo;");
buildModel("pm1", true, this.vdb, this.store, "create foreign table g1(e1 integer, e2 varchar(12));");
ValidatorReport report = new ValidatorReport();
MetadataValidator metadataValidator = new MetadataValidator(getTeiidVersion());
metadataValidator.new SourceModelArtifacts().execute(vdb, store, report, newMetadataValidator());
assertFalse(printError(report), report.hasItems());
}
@Test
public void testMinimalDataNoColumns() throws Exception {
buildModel("pm1", true, this.vdb, this.store, "create foreign table g1;");
ValidatorReport report = new ValidatorReport();
MetadataValidator mv = newMetadataValidator();
mv.new MinimalMetadata().execute(vdb, store, report, newMetadataValidator());
assertTrue(printError(report), report.hasItems());
}
@Test
public void testResolveMetadata() throws Exception {
String ddl = "create view g1 (e1 integer, e2 varchar(12)) AS select * from pm1.g1; "
+ "create view g2 AS select * from pm1.g1; "
+ "create trigger on g1 INSTEAD OF UPDATE AS FOR EACH ROW BEGIN ATOMIC END; "
+ "create virtual procedure proc1(IN e1 varchar) RETURNS (e1 integer, e2 varchar(12)) AS select * from foo; ";
buildModel("pm1", true, this.vdb, this.store, "create foreign table g1(e1 integer, e2 varchar(12));");
buildModel("vm1", false, this.vdb, this.store, ddl);
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
MetadataValidator mv = newMetadataValidator();
mv.new ResolveQueryPlans().execute(vdb, store, report, newMetadataValidator());
assertTrue(printError(report), report.hasItems());
}
@Test
public void testProcWithMultipleReturn() throws Exception {
String ddl = "create foreign procedure x (out param1 string result, out param2 string result); ";
buildModel("pm1", true, this.vdb, this.store, ddl);
buildTransformationMetadata();
ValidatorReport report = newMetadataValidator().validate(vdb, store);
assertTrue(printError(report), report.hasItems());
}
@Test
public void testProcWithDuplicateParam() throws Exception {
String ddl = "create foreign procedure x (out param1 string, out param1 string); ";
buildModel("pm1", true, this.vdb, this.store, ddl);
buildTransformationMetadata();
ValidatorReport report = newMetadataValidator().validate(vdb, store);
assertTrue(printError(report), report.hasItems());
}
@Test
public void testProcMetadata() throws Exception {
String ddl = "create virtual procedure proc1(IN e1 varchar) RETURNS (e1 integer, e2 varchar(12)) AS begin create local temporary table x (e1 integer, e2 varchar); select * from x; end;"
+ "create virtual procedure proc2(IN e1 varchar) RETURNS (e1 integer, e2 varchar(12)) AS select x.* from (exec proc1('a')) as X; ";
buildModel("vm1", false, this.vdb, this.store, ddl);
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
MetadataValidator mv = newMetadataValidator();
mv.new ResolveQueryPlans().execute(vdb, store, report, newMetadataValidator());
assertFalse(printError(report), report.hasItems());
}
@Test
public void testProcMetadataValidationError() throws Exception {
String ddl = "create virtual procedure proc1(IN e1 varchar) RETURNS (e1 integer, e2 varchar(12)) AS begin create local temporary table x (e1 integer, e2 varchar not null); insert into x (e1) values (1); select * from x; end;";
buildModel("vm1", false, this.vdb, this.store, ddl);
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
MetadataValidator mv = newMetadataValidator();
mv.new ResolveQueryPlans().execute(vdb, store, report, newMetadataValidator());
assertEquals("Element x.e2 of x is neither nullable nor has a default value. A value must be specified in the insert.",
report.getItems().iterator().next().toString());
}
@Test
public void testResolveTempMetadata() throws Exception {
String ddl = "create virtual procedure proc1() RETURNS (e1 integer, e2 varchar(12)) AS begin create local temporary table x (e1 integer, e2 varchar); select * from x; end;"
+ "create view z (e1 integer, e2 varchar(12)) AS select x.* from (exec proc1()) as X, (exec proc1()) as Y; ";
buildModel("vm1", false, this.vdb, this.store, ddl);
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
MetadataValidator mv = newMetadataValidator();
mv.new ResolveQueryPlans().execute(vdb, store, report, newMetadataValidator());
assertFalse(printError(report), report.hasItems());
}
@Test
public void testResolveMetadataError() throws Exception {
buildModel("vm1",
false,
this.vdb,
this.store,
"create view g1 (e1 integer, e2 varchar(12)) AS select * from pm1.g1; create view g2 AS select * from pm1.g1;");
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
MetadataValidator mv = newMetadataValidator();
mv.new ResolveQueryPlans().execute(vdb, store, report, newMetadataValidator());
assertTrue(printError(report), report.hasItems());
}
@Test
public void testCrossReferenceFK() throws Exception {
String ddl = "CREATE FOREIGN TABLE G1(g1e1 integer, g1e2 varchar, PRIMARY KEY(g1e1, g1e2));";
String ddl2 = "CREATE FOREIGN TABLE G2( g2e1 integer, g2e2 varchar, PRIMARY KEY(g2e1, g2e2), FOREIGN KEY (g2e1, g2e2) REFERENCES pm1.G1(g1e1, g1e2))";
buildModel("pm1", true, this.vdb, this.store, ddl);
buildModel("pm2", true, this.vdb, this.store, ddl2);
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
report = newMetadataValidator().validate(this.vdb, this.store);
assertFalse(printError(report), report.hasItems());
assertNotNull(this.store.getSchema("pm2").getTable("G2").getForeignKeys().get(0).getReferenceKey());
assertEquals(2, this.store.getSchema("pm2").getTable("G2").getForeignKeys().get(0).getReferenceKey().getColumns().size());
assertEquals("g1e1",
this.store.getSchema("pm2").getTable("G2").getForeignKeys().get(0).getReferenceKey().getColumns().get(0).getName());
}
@Test
public void testEmptyKey() throws Exception {
String ddl = "CREATE FOREIGN TABLE G1(g1e1 integer, g1e2 varchar, PRIMARY KEY(g1e1, g1e2));";
buildModel("pm1", true, this.vdb, this.store, ddl);
buildTransformationMetadata();
this.store.getSchema("pm1").getTable("G1").getPrimaryKey().getColumns().clear();
ValidatorReport report = new ValidatorReport();
report = newMetadataValidator().validate(this.vdb, this.store);
assertTrue(printError(report), report.hasItems());
}
@Test
public void testCrossReferenceFKFromUniqueKey() throws Exception {
String ddl = "CREATE FOREIGN TABLE G1(g1e1 integer, g1e2 varchar, UNIQUE(g1e2));";
String ddl2 = "CREATE FOREIGN TABLE G2(g2e1 integer, g2e2 varchar, FOREIGN KEY (g2e2) REFERENCES pm1.G1(g1e2))";
buildModel("pm1", true, this.vdb, this.store, ddl);
buildModel("pm2", true, this.vdb, this.store, ddl2);
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
report = newMetadataValidator().validate(this.vdb, this.store);
assertFalse(printError(report), report.hasItems());
assertNotNull(this.store.getSchema("pm2").getTable("G2").getForeignKeys().get(0).getReferenceKey());
assertEquals(1, this.store.getSchema("pm2").getTable("G2").getForeignKeys().get(0).getReferenceKey().getColumns().size());
assertEquals("g1e2",
this.store.getSchema("pm2").getTable("G2").getForeignKeys().get(0).getReferenceKey().getColumns().get(0).getName());
}
@Test
public void testCrossReferenceResoveOptionalFK() throws Exception {
String ddl = "CREATE FOREIGN TABLE G1(g1e1 integer, g1e2 varchar, PRIMARY KEY(g1e1, g1e2));";
String ddl2 = "CREATE FOREIGN TABLE G2( g2e1 integer, g2e2 varchar, FOREIGN KEY (g2e1, g2e2) REFERENCES pm1.G1)";
buildModel("pm1", true, this.vdb, this.store, ddl);
buildModel("pm2", true, this.vdb, this.store, ddl2);
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
report = newMetadataValidator().validate(this.vdb, this.store);
assertFalse(printError(report), report.hasItems());
assertNotNull(this.store.getSchema("pm2").getTable("G2").getForeignKeys().get(0).getReferenceKey());
assertEquals(2, this.store.getSchema("pm2").getTable("G2").getForeignKeys().get(0).getReferenceKey().getColumns().size());
assertEquals("g1e1",
this.store.getSchema("pm2").getTable("G2").getForeignKeys().get(0).getReferenceKey().getColumns().get(0).getName());
}
@Test
public void testCrossReferenceFKNoPKonRefTable() throws Exception {
// note here the unique here does not matter for non-existent reference columns, only primary key counted.
String ddl = "CREATE FOREIGN TABLE G1(g1e1 integer, g1e2 varchar, UNIQUE(g1e1, g1e2));";
String ddl2 = "CREATE FOREIGN TABLE G2( g2e1 integer, g2e2 varchar, PRIMARY KEY(g2e1, g2e2), FOREIGN KEY (g2e1, g2e2) REFERENCES pm1.G1)";
buildModel("pm1", true, this.vdb, this.store, ddl);
buildModel("pm2", true, this.vdb, this.store, ddl2);
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
report = newMetadataValidator().validate(this.vdb, this.store);
assertTrue(printError(report), report.hasItems());
}
@Test
public void testInternalMaterializationValidate() throws Exception {
// note here the unique here does not matter for non-existent reference columns, only primary key counted.
String ddl = "CREATE FOREIGN TABLE G1(e1 integer, e2 varchar);";
String ddl2 = "CREATE VIEW G2 OPTIONS (MATERIALIZED 'YES') AS SELECT * FROM pm1.G1";
buildModel("pm1", true, this.vdb, this.store, ddl);
buildModel("vm1", false, this.vdb, this.store, ddl2);
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
report = newMetadataValidator().validate(this.vdb, this.store);
assertFalse(printError(report), report.hasItems());
}
@Test
public void testExternalMaterializationValidate() throws Exception {
// note here the unique here does not matter for non-existent reference columns, only primary key counted.
String ddl = "CREATE FOREIGN TABLE G1(e1 integer, e2 varchar);";
String ddl2 = "CREATE VIEW G2 OPTIONS (MATERIALIZED 'true', MATERIALIZED_TABLE 'pm1.G1') AS SELECT * FROM pm1.G1";
buildModel("pm1", true, this.vdb, this.store, ddl);
buildModel("vm1", false, this.vdb, this.store, ddl2);
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
report = newMetadataValidator().validate(this.vdb, this.store);
assertFalse(printError(report), report.hasItems());
assertNotNull("pm1.G1", store.getSchema("vm1").getTable("G2").getMaterializedTable());
assertEquals("G1", store.getSchema("vm1").getTable("G2").getMaterializedTable().getName());
}
@Test
public void testSkipDocumentModel() throws Exception {
ModelMetaData model = new ModelMetaData();
model.setName("xmlstuff");
model.setModelType(Model.Type.VIRTUAL);
vdb.addModel(model);
MetadataFactory mf = new MetadataFactory(getTeiidVersion(), "myVDB", 1, "xmlstuff", getDataTypes(), new Properties(),
null);
mf.getSchema().setPhysical(false);
Table t = mf.addTable("xmldoctable");
t.setTableType(Table.Type.Document);
mf.addColumn("c1", "string", t);
t.setSelectTransformation("some dummy stuff, should not be validated");
t.setVirtual(true);
Table t2 = mf.addTable("xmldoctable2");
t2.setTableType(Table.Type.XmlMappingClass);
mf.addColumn("c1", "string", t2);
t2.setSelectTransformation("some dummy stuff, should not be validated");
t2.setVirtual(true);
mf.mergeInto(store);
buildTransformationMetadata();
ValidatorReport report = newMetadataValidator().validate(this.vdb, this.store);
assertFalse(printError(report), report.hasItems());
}
@Test
public void testInvalidVarArgs() throws Exception {
// note here the unique here does not matter for non-existent reference columns, only primary key counted.
String ddl = "CREATE FOREIGN FUNCTION f1(VARIADIC e1 integer, e2 varchar) RETURNS varchar;";
helpTest(ddl, true);
}
@Test
public void testFBIResolveError() throws Exception {
String ddl = "CREATE view G1(e1 integer, e2 varchar, CONSTRAINT fbi INDEX (UPPER(e3))) options (materialized true) as select 1, 'a'";
helpTest(ddl, true);
}
@Test
public void testFBISubquery() throws Exception {
String ddl = "CREATE view G1(e1 integer, e2 varchar, CONSTRAINT fbi INDEX ((select 1))) options (materialized true) as select 1, 'a'";
helpTest(ddl, true);
}
@Test
public void testResultSet() throws Exception {
String ddl = "create virtual procedure vproc (x integer) returns table (y integer) as begin if (x = 1) select 1; else select 1, 2; end;";
helpTest(ddl, true);
}
@Test
public void testReturnResolving() throws Exception {
String ddl = "create procedure proc (x integer) returns string as return x;\n";
helpTest(ddl, false);
}
@Test
public void testReturnResolving1() throws Exception {
String ddl = "create procedure proc (x integer) as return x;\n";
helpTest(ddl, true);
}
@Test
public void testViewKeys() throws Exception {
buildModel("phy1",
true,
this.vdb,
this.store,
"CREATE FOREIGN TABLE t1 ( col1 string, col2 integer ) options (updatable true)");
buildModel("phy2",
true,
this.vdb,
this.store,
"CREATE FOREIGN TABLE t2 ( col1 string, col2 integer ) options (updatable true)");
buildModel("view1",
false,
this.vdb,
this.store,
"CREATE view vw_t1 ( col1 string, col2 integer primary key, foreign key (col2) references vw_t2 (col2) ) options (updatable true) as select * from t1;"
+ "CREATE view vw_t2 ( col1 string, col2 integer primary key, foreign key (col2) references vw_t1 (col2) ) options (updatable true) as select * from t2;"
+ "CREATE VIEW v1 ( col1 string, col2 integer ) OPTIONS (updatable 'true') AS select vw_t1.col1, vw_t1.col2 FROM vw_t1, vw_t2 where vw_t1.col2 = vw_t2.col2");
buildTransformationMetadata();
ValidatorReport report = newMetadataValidator().validate(this.vdb, this.store);
assertFalse(printError(report), report.hasItems());
}
@Test
public void testResolvingOrder() throws Exception {
buildModel("phy1",
true,
this.vdb,
this.store,
"CREATE FOREIGN TABLE t1 ( col1 string, col2 integer ) options (updatable true); CREATE view a as select * from t1;");
buildTransformationMetadata();
ValidatorReport report = newMetadataValidator().validate(this.vdb, this.store);
assertFalse(printError(report), report.hasItems());
}
private ValidatorReport helpTest(String ddl, boolean expectErrors) throws Exception {
buildModel("pm1", true, this.vdb, this.store, ddl);
buildTransformationMetadata();
ValidatorReport report = new ValidatorReport();
report = newMetadataValidator().validate(this.vdb, this.store);
if (expectErrors) {
assertTrue(printError(report), report.hasItems());
} else {
assertFalse(printError(report), report.hasItems());
}
return report;
}
}