/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.query.validator;
import static org.junit.Assert.*;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.teiid.api.exception.query.QueryParserException;
import org.teiid.api.exception.query.QueryResolverException;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidException;
import org.teiid.core.types.DataTypeManager;
import org.teiid.metadata.Column;
import org.teiid.metadata.ColumnSet;
import org.teiid.metadata.KeyRecord;
import org.teiid.metadata.MetadataStore;
import org.teiid.metadata.Procedure;
import org.teiid.metadata.Schema;
import org.teiid.metadata.Table;
import org.teiid.metadata.BaseColumn.NullType;
import org.teiid.metadata.KeyRecord.Type;
import org.teiid.query.mapping.relational.QueryNode;
import org.teiid.query.metadata.TransformationMetadata;
import org.teiid.query.parser.QueryParser;
import org.teiid.query.resolver.QueryResolver;
import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.sql.symbol.SingleElementSymbol;
import org.teiid.query.unittest.RealMetadataFactory;
import org.teiid.query.validator.UpdateValidator.UpdateInfo;
import org.teiid.query.validator.UpdateValidator.UpdateType;
@SuppressWarnings("nls")
public class TestUpdateValidator {
private UpdateValidator helpTest(String sql, TransformationMetadata md, boolean shouldFail) {
return helpTest(sql, md, shouldFail, shouldFail, shouldFail);
}
private UpdateValidator helpTest(String sql, TransformationMetadata md, boolean failInsert, boolean failUpdate, boolean failDelete) {
try {
String vGroup = "gx";
Command command = createView(sql, md, vGroup);
UpdateValidator uv = new UpdateValidator(md, UpdateType.INHERENT, UpdateType.INHERENT, UpdateType.INHERENT);
GroupSymbol gs = new GroupSymbol(vGroup);
ResolverUtil.resolveGroup(gs, md);
uv.validate(command, ResolverUtil.resolveElementsInGroup(gs, md));
UpdateInfo info = uv.getUpdateInfo();
assertEquals(uv.getReport().getFailureMessage(), failInsert, info.isInsertValidationError());
assertEquals(uv.getReport().getFailureMessage(), failUpdate, info.isUpdateValidationError());
assertEquals(uv.getReport().getFailureMessage(), failDelete, info.isDeleteValidationError());
return uv;
} catch (TeiidException e) {
throw new RuntimeException(e);
}
}
public static Command createView(String sql, TransformationMetadata md, String vGroup)
throws QueryParserException, QueryResolverException,
TeiidComponentException {
QueryNode vm1g1n1 = new QueryNode(sql);
Table vm1g1 = RealMetadataFactory.createUpdatableVirtualGroup(vGroup, md.getMetadataStore().getSchema("VM1"), vm1g1n1);
Command command = QueryParser.getQueryParser().parseCommand(sql);
QueryResolver.resolveCommand(command, md);
List<SingleElementSymbol> symbols = command.getProjectedSymbols();
String[] names = new String[symbols.size()];
String[] types = new String[symbols.size()];
int i = 0;
for (SingleElementSymbol singleElementSymbol : symbols) {
names[i] = singleElementSymbol.getShortName();
types[i++] = DataTypeManager.getDataTypeName(singleElementSymbol.getType());
}
RealMetadataFactory.createElements(vm1g1, names, types);
return command;
}
public static TransformationMetadata example1() {
return example1(true);
}
public static TransformationMetadata example1(boolean allUpdatable) {
MetadataStore metadataStore = new MetadataStore();
// Create models
Schema pm1 = RealMetadataFactory.createPhysicalModel("pm1", metadataStore); //$NON-NLS-1$
Schema vm1 = RealMetadataFactory.createVirtualModel("vm1", metadataStore); //$NON-NLS-1$
// Create physical groups
Table pm1g1 = RealMetadataFactory.createPhysicalGroup("g1", pm1); //$NON-NLS-1$
Table pm1g2 = RealMetadataFactory.createPhysicalGroup("g2", pm1); //$NON-NLS-1$
Table pm1g3 = RealMetadataFactory.createPhysicalGroup("g3", pm1); //$NON-NLS-1$
// Create physical elements
List<Column> pm1g1e = RealMetadataFactory.createElements(pm1g1,
new String[] { "e1", "e2", "e3", "e4" }, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.BOOLEAN, DataTypeManager.DefaultDataTypes.DOUBLE });
if (!allUpdatable) {
pm1g1e.get(0).setUpdatable(false);
}
KeyRecord pk = RealMetadataFactory.createKey(Type.Primary, "pk", pm1g1, pm1g1e.subList(0, 1));
List<Column> pm1g2e = RealMetadataFactory.createElements(pm1g2,
new String[] { "e1", "e2", "e3", "e4" }, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.BOOLEAN, DataTypeManager.DefaultDataTypes.DOUBLE });
RealMetadataFactory.createKey(Type.Primary, "pk", pm1g2, pm1g1e.subList(1, 2));
RealMetadataFactory.createForeignKey("fk", pm1g2, pm1g2e.subList(0, 1), pk);
List<Column> pm1g3e = RealMetadataFactory.createElements(pm1g3,
new String[] { "e1", "e2", "e3", "e4" }, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.BOOLEAN, DataTypeManager.DefaultDataTypes.DOUBLE });
pm1g3e.get(0).setNullType(NullType.No_Nulls);
pm1g3e.get(0).setDefaultValue(null);
pm1g3e.get(1).setNullType(NullType.No_Nulls);
pm1g3e.get(1).setAutoIncremented(true);
pm1g3e.get(1).setDefaultValue(null);
pm1g3e.get(2).setNullType(NullType.No_Nulls);
pm1g3e.get(2).setDefaultValue("xyz"); //$NON-NLS-1$
// Create virtual groups
QueryNode vm1g1n1 = new QueryNode("SELECT e1 as a, e2 FROM pm1.g1 WHERE e3 > 5"); //$NON-NLS-1$ //$NON-NLS-2$
Table vm1g1 = RealMetadataFactory.createUpdatableVirtualGroup("g1", vm1, vm1g1n1); //$NON-NLS-1$
QueryNode vm1g2n1 = new QueryNode("SELECT e1, e2, e3, e4 FROM pm1.g2 WHERE e3 > 5"); //$NON-NLS-1$ //$NON-NLS-2$
Table vm1g2 = RealMetadataFactory.createUpdatableVirtualGroup("g2", vm1, vm1g2n1); //$NON-NLS-1$
QueryNode vm1g3n1 = new QueryNode("SELECT e1, e3 FROM pm1.g3"); //$NON-NLS-1$ //$NON-NLS-2$
Table vm1g3 = RealMetadataFactory.createUpdatableVirtualGroup("g3", vm1, vm1g3n1); //$NON-NLS-1$
QueryNode vm1g4n1 = new QueryNode("SELECT e1, e2 FROM pm1.g3"); //$NON-NLS-1$ //$NON-NLS-2$
Table vm1g4 = RealMetadataFactory.createUpdatableVirtualGroup("g4", vm1, vm1g4n1); //$NON-NLS-1$
QueryNode vm1g5n1 = new QueryNode("SELECT e2, e3 FROM pm1.g3"); //$NON-NLS-1$ //$NON-NLS-2$
Table vm1g5 = RealMetadataFactory.createVirtualGroup("g5", vm1, vm1g5n1); //$NON-NLS-1$
// Create virtual elements
RealMetadataFactory.createElements(vm1g1,
new String[] { "a", "e2"}, //$NON-NLS-1$ //$NON-NLS-2$
new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER});
RealMetadataFactory.createElements(vm1g2,
new String[] { "e1", "e2","e3", "e4"}, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.BOOLEAN, DataTypeManager.DefaultDataTypes.DOUBLE });
RealMetadataFactory.createElements(vm1g3,
new String[] { "e1", "e2"}, //$NON-NLS-1$ //$NON-NLS-2$
new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER, });
RealMetadataFactory.createElements(vm1g4,
new String[] { "e1", "e3"}, //$NON-NLS-1$ //$NON-NLS-2$
new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.BOOLEAN });
RealMetadataFactory.createElements(vm1g5,
new String[] { "e2","e3"}, //$NON-NLS-1$ //$NON-NLS-2$
new String[] { DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.BOOLEAN });
// Stored queries
ColumnSet<Procedure> rs1 = RealMetadataFactory.createResultSet("rs1", new String[] { "e1", "e2" }, new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
QueryNode sq1n1 = new QueryNode("CREATE VIRTUAL PROCEDURE BEGIN SELECT e1, e2 FROM pm1.g1; END"); //$NON-NLS-1$ //$NON-NLS-2$
Procedure sq1 = RealMetadataFactory.createVirtualProcedure("pm1.sq1", pm1, Collections.EMPTY_LIST, sq1n1); //$NON-NLS-1$
sq1.setResultSet(rs1);
// Create the facade from the store
return RealMetadataFactory.createTransformationMetadata(metadataStore, "example");
}
//actual tests
@Test public void testCreateInsertCommand(){
helpTest("select e1 as a, e2 from pm1.g1 where e4 > 5",
example1(), false); //$NON-NLS-1$
}
@Test public void testCreateInsertCommand2(){ //put a constant in select statement
helpTest("select e1 as a, 5 from pm1.g1 where e4 > 5",
example1(), false); //$NON-NLS-1$
}
@Test public void testCreateInsertCommand3(){
helpTest("select * from pm1.g2 where e4 > 5",
example1(), false); //$NON-NLS-1$
}
@Test public void testCreateInsertCommand4(){ //test group alias
helpTest("select * from pm1.g2 as g_alias",
example1(), false); //$NON-NLS-1$
}
@Test public void testCreateInsertCommand5(){
helpTest("select e1 as a, e2 from pm1.g1 as g_alias where e4 > 5",
example1(), false); //$NON-NLS-1$
}
@Test public void testCreateUpdateCommand(){
helpTest("select e1 as a, e2 from pm1.g1 where e4 > 5",
example1(), false); //$NON-NLS-1$
}
@Test public void testCreateDeleteCommand(){
helpTest("select e1 as a, e2 from pm1.g1 where e4 > 5",
example1(), false); //$NON-NLS-1$
}
@Test public void testCreateInsertCommand1(){
helpTest("SELECT pm1.g1.e1 FROM pm1.g1, pm1.g2",
example1(), true);
}
@Test public void testCreateInsertCommand14(){
helpTest("SELECT pm1.g2.e1 FROM pm1.g1, pm1.g2 where g1.e1 = g2.e1",
example1(), false);
}
@Test public void testCreateInsertCommand2_fail(){
helpTest("SELECT CONCAT(pm1.g1.e1, convert(pm1.g2.e1, string)) as x FROM pm1.g1, pm1.g2",
example1(), true);
}
@Test public void testCreateInsertCommand3_fail(){
helpTest("SELECT e1 FROM pm1.g1 UNION SELECT e1 FROM pm1.g2",
example1(), true);
}
@Test public void testCreateInsertCommand4_fail(){
helpTest("SELECT COUNT(*) FROM pm1.g1",
example1(), true);
}
@Test public void testCreateInsertCommand5_fail(){
helpTest("SELECT * FROM pm1.g1 GROUP BY e1",
example1(), true);
}
@Test public void testCreateInsertCommand6_fail(){
helpTest("EXEC pm1.sq1()",
example1(), true);
}
@Test public void testCreateInsertCommand7_fail(){
helpTest("INSERT INTO pm1.g1 (e1) VALUES ('x')",
example1(), true);
}
@Test public void testCreateInsertCommand8_fail(){
helpTest("UPDATE pm1.g1 SET e1='x'",
example1(), true);
}
@Test public void testCreateInsertCommand9_fail(){
helpTest("DELETE FROM pm1.g1",
example1(), true);
}
@Test public void testCreateInsertCommand10_fail(){
helpTest("SELECT COUNT(*) FROM pm1.g1",
example1(), true);
}
@Test public void testCreateInsertCommand11_fail(){
helpTest("SELECT COUNT(e1) as x FROM pm1.g1",
example1(), true);
}
@Test public void testCreateInsertCommand12_fail(){
helpTest("SELECT * FROM (EXEC pm1.sq1()) AS a",
example1(), true);
}
@Test public void testCreateInsertCommand13_fail(){
helpTest("SELECT 1",
example1(), true);
}
@Test public void testRequiredElements1() {
helpTest("SELECT e1, e2 FROM pm1.g3",
example1(), false); //$NON-NLS-1$
}
@Test public void testRequiredElements2() {
helpTest("SELECT e1, e3 FROM pm1.g3",
example1(), false); //$NON-NLS-1$
}
@Test public void testRequiredElements3() {
helpTest("SELECT e2, e3 FROM pm1.g3",
example1(), true, false, false);
}
@Test public void testNonUpdateableElements() {
helpTest("select e1 as a, e2 from pm1.g1 where e4 > 5",
example1(false), false); //$NON-NLS-1$
}
@Test public void testNonUpdateableElements2() {
helpTest("SELECT e1, e2 FROM pm1.g1",
example1(false), false); //$NON-NLS-1$
}
@Test public void testSelectDistinct() {
helpTest("SELECT distinct e1, e2 FROM pm1.g1",
example1(), true); //$NON-NLS-1$
}
@Test public void testNonUpdatable() {
helpTest("SELECT e2 FROM vm1.g5",
example1(), true); //$NON-NLS-1$
}
@Test public void testAnsiJoin() {
helpTest("SELECT g1.e1, x.e2 FROM pm1.g2 x inner join pm1.g1 on (x.e1 = g1.e1)",
example1(), false); //$NON-NLS-1$
}
@Test public void testUnionAll() {
helpTest("SELECT g1.e1, x.e2 FROM pm1.g2 x inner join pm1.g1 on (x.e1 = g1.e1) union all select pm1.g2.e1, pm1.g2.e2 from pm1.g2",
example1(), true, false, false); //$NON-NLS-1$
}
@Test public void testParitionedUnionAll() {
helpTest("SELECT g1.e1, x.e2 FROM pm1.g2 x inner join pm1.g1 on (x.e1 = g1.e1) where x.e2 in (1, 2) union all select pm1.g2.e1, pm1.g2.e2 from pm1.g2 where pm1.g2.e2 in (3, 4)",
example1(), false, false, false); //$NON-NLS-1$
}
}