/* * 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.systemmodel; import static org.junit.Assert.*; import java.io.IOException; import java.sql.CallableStatement; import java.sql.ParameterMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.teiid.adminapi.Model.Type; import org.teiid.adminapi.impl.ModelMetaData; import org.teiid.client.util.ResultsFuture; import org.teiid.core.util.ObjectConverterUtil; import org.teiid.core.util.UnitTestUtil; import org.teiid.jdbc.AbstractMMQueryTestCase; import org.teiid.jdbc.FakeServer; import org.teiid.jdbc.TestMMDatabaseMetaData; import org.teiid.runtime.HardCodedExecutionFactory; /** * Exercises each virtual table in the system model. */ @SuppressWarnings("nls") public class TestSystemVirtualModel extends AbstractMMQueryTestCase { private static final String VDB = "PartsSupplier"; //$NON-NLS-1$ private static FakeServer server; @BeforeClass public static void setup() throws Exception { server = new FakeServer(true); server.deployVDB(VDB, UnitTestUtil.getTestDataPath() + "/PartsSupplier.vdb"); ModelMetaData mmd = new ModelMetaData(); mmd.setName("x"); mmd.setModelType(Type.VIRTUAL); mmd.addSourceMetadata("DDL", "create view t as select 1"); ModelMetaData mmd1 = new ModelMetaData(); mmd1.setName("y"); mmd1.setModelType(Type.VIRTUAL); mmd1.addSourceMetadata("DDL", "create view T as select 1"); server.deployVDB("test", mmd, mmd1); ModelMetaData mmd2 = new ModelMetaData(); mmd2.setName("x"); mmd2.setModelType(Type.VIRTUAL); mmd2.addSourceMetadata("DDL", "create view t (g geometry options (\"teiid_spatial:srid\" 3819)) as select null;"); server.deployVDB("test1", mmd2); } @AfterClass public static void teardown() throws Exception { server.stop(); } public TestSystemVirtualModel() { // this is needed because the result files are generated // with another tool which uses tab as delimiter super.DELIMITER = "\t"; //$NON-NLS-1$ } @Before public void setUp() throws Exception { this.internalConnection = server.createConnection("jdbc:teiid:" + VDB); //$NON-NLS-1$ //$NON-NLS-2$ } protected void checkResult(String testName, String query) throws Exception { execute(query); TestMMDatabaseMetaData.compareResultSet("TestSystemVirtualModel/" + testName, this.internalResultSet); } @Test public void testModels() throws Exception { checkResult("testSchemas", "select* from SYS.Schemas order by Name"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testKeys() throws Exception { checkResult("testKeys", "select* from SYS.Keys order by Name"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testGroups() throws Exception { checkResult("testTables", "select* from SYS.Tables order by Name"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testDataTypes() throws Exception { checkResult("testDataTypes", "select * from SYS.DataTypes order by name"); //$NON-NLS-1$ //$NON-NLS-2$ execute("select * from SYS.DataTypes where name = 'string'"); //$NON-NLS-1$ //$NON-NLS-2$ assertRowCount(1); execute("select * from SYS.DataTypes where isstandard"); //$NON-NLS-1$ //$NON-NLS-2$ assertTrue(getRowCount() >= 20); } @Test public void testProcedureParams() throws Exception { checkResult("testProcedureParams", "select * from SYS.ProcedureParams order by Name"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testProcedures() throws Exception { checkResult("testProcedures", "select* from SYS.Procedures order by Name"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testProperties() throws Exception { checkResult("testProperties", "select* from SYS.Properties"); //$NON-NLS-1$ } @Test public void testVirtualDatabase() throws Exception { String[] expected = { "Name[string] Version[string] ", "PartsSupplier 1", //$NON-NLS-1$ //$NON-NLS-2$ }; executeAndAssertResults("select* from SYS.VirtualDatabases", //$NON-NLS-1$ expected); } @Test public void testKeyColumns() throws Exception { checkResult("testKeyColumns", "select* from SYS.KeyColumns order by Name, KeyName"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testVDBResources() throws IOException, SQLException { execute("select * from vdbresources order by resourcePath",new Object[] {}); //$NON-NLS-1$ TestMMDatabaseMetaData.compareResultSet(this.internalResultSet); } @Test public void testColumns() throws Exception { checkResult("testColumns", "select* from SYS.Columns order by Name, uid"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testTableType() throws Exception { String[] expected = { "Type[string] ", "Table", }; //$NON-NLS-1$ //$NON-NLS-2$ executeAndAssertResults( "select distinct Type from SYS.Tables order by Type", //$NON-NLS-1$ expected); } @Test public void testTableIsSystem() throws Exception { checkResult("testTableIsSystem", "select Name from SYS.Tables where IsSystem = 'false' order by Name"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testDefect12064() throws Exception { checkResult("testDefect12064", "select KeyName, RefKeyUID FROM SYS.KeyColumns WHERE RefKeyUID IS NULL order by KeyName"); //$NON-NLS-1$ } @Test public void testReferenceKeyColumns() throws Exception { checkResult("testReferenceKeyColumns", "select* FROM SYS.ReferenceKeyColumns order by PKTABLE_NAME"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testLogMsg() throws Exception { execute("call logMsg(level=>'DEBUG', context=>'org.teiid.foo', msg=>'hello world')"); //$NON-NLS-1$ } @Test(expected=SQLException.class) public void testLogMsg1() throws Exception { execute("call logMsg(level=>'foo', context=>'org.teiid.foo', msg=>'hello world')"); //$NON-NLS-1$ } @Test public void testCallableParametersByName() throws Exception { CallableStatement cs = this.internalConnection.prepareCall("{? = call logMsg(?, ?, ?)}"); ParameterMetaData pmd = cs.getParameterMetaData(); assertEquals(3, pmd.getParameterCount()); cs.registerOutParameter("logged", Types.BOOLEAN); //different case cs.setString("LEVEL", "DEBUG"); try { //invalid param cs.setString("n", ""); fail(); } catch (SQLException e) { } cs.setString("context", "org.teiid.foo"); cs.setString("msg", "hello world"); cs.execute(); assertEquals(cs.getBoolean(1), cs.getBoolean("logged")); } @Test public void testArrayAggType() throws Exception { String sql = "SELECT array_agg(name) from tables"; //$NON-NLS-1$ checkResult("testArrayAggType", sql); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testExecuteUpdateWithStoredProcedure() throws Exception { PreparedStatement cs = this.internalConnection.prepareStatement("call logMsg(?, ?, ?)"); //different case cs.setString(1, "DEBUG"); cs.setString(2, "org.teiid.foo"); cs.setString(3, "hello world"); assertEquals(0, cs.executeUpdate()); Statement s = this.internalConnection.createStatement(); assertEquals(0, s.executeUpdate("call logMsg('DEBUG', 'org.teiid.foo', 'hello world')")); } @Test public void testExpectedTypes() throws Exception { ResultSet rs = this.internalConnection.createStatement().executeQuery("select name from tables where schemaname in ('SYS', 'SYSADMIN')"); while (rs.next()) { String name = rs.getString(1); ResultSet rs1 = this.internalConnection.createStatement().executeQuery("select * from " + name + " limit 1"); ResultSetMetaData metadata = rs1.getMetaData(); if (rs1.next()) { for (int i = 1; i <= metadata.getColumnCount(); i++) { Object o = rs1.getObject(i); assertTrue("Type mismatch for " + name + " " + metadata.getColumnName(i), o == null || Class.forName(metadata.getColumnClassName(i)).isAssignableFrom(o.getClass())); } } } } @Test public void testPrefixSearches() throws Exception { this.execute("select name from schemas where ucase(name) >= 'BAZ_BAR' and ucase(name) <= 'A'"); //should be 0 rows rather than an exception assertRowCount(0); this.execute("select name from schemas where upper(name) like 'ab[_'"); //should be 0 rows rather than an exception assertRowCount(0); } @Test public void testColumnsIn() throws Exception { this.internalConnection.close(); this.internalConnection = server.createConnection("jdbc:teiid:test"); this.execute("select tablename, name from columns where tablename in ('t', 'T')"); //should be 2, not 4 rows assertRowCount(2); this.execute("select tablename, name from columns where upper(tablename) in ('t', 's')"); assertRowCount(0); } @Test public void testViews() throws Exception { checkResult("testViews", "select Name, Body from Views order by Name"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testStoredProcedures() throws Exception { checkResult("testStoredProcedures", "select Name, Body from StoredProcedures order by Name"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testUsage() throws Exception { checkResult("testUsgae", "select * from usage"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testFunctions() throws Exception { checkResult("testFunctions", "select * from functions"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testFunctionParameters() throws Exception { checkResult("testFunctionParams", "select * from FunctionParams"); //$NON-NLS-1$ //$NON-NLS-2$ assertFalse(ObjectConverterUtil.convertFileToString(UnitTestUtil.getTestDataFile("TestSystemVirtualModel/testFunctionParams.expected")).contains("Missing message")); } @Test public void testTriggers() throws Exception { this.internalConnection.close(); ModelMetaData mmd3 = new ModelMetaData(); mmd3.setName("x"); mmd3.setModelType(Type.PHYSICAL); mmd3.addSourceMapping("x", "x", null); mmd3.addSourceMetadata("DDL", "create foreign table t (intkey integer); " + " create trigger tr on t after insert as for each row begin select intkey from t where intkey = new.intkey; end; " + " create trigger tr1 on t after update as for each row begin select intkey from t where intkey = new.intkey + old.intkey; end;"); HardCodedExecutionFactory ef = new HardCodedExecutionFactory() { @Override public boolean supportsCompareCriteriaEquals() { return true; } }; ef.addData("SELECT t.intkey FROM t WHERE t.intkey = 1", new ArrayList<List<?>>()); server.addTranslator("x", ef); server.deployVDB("test3", mmd3); this.internalConnection = server.createConnection("jdbc:teiid:test3"); checkResult("testTriggers", "select * from sysadmin.triggers"); //$NON-NLS-1$ //$NON-NLS-2$ closeStatement(); //insert event ResultsFuture<?> future = server.getEventDistributor().dataModification("test3", "1", "x", "t", null, new Object[] {1}, null); future.get(2, TimeUnit.SECONDS); assertEquals("SELECT t.intkey FROM t WHERE t.intkey = 1", ef.getCommands().get(0).toString()); ef.addData("SELECT t.intkey FROM t WHERE t.intkey = 3", new ArrayList<List<?>>()); //update event future = server.getEventDistributor().dataModification("test3", "1", "x", "t", new Object[] {2}, new Object[] {1}, null); future.get(2, TimeUnit.SECONDS); assertEquals("SELECT t.intkey FROM t WHERE t.intkey = 3", ef.getCommands().get(1).toString()); //delete event future = server.getEventDistributor().dataModification("test3", "1", "x", "t", new Object[] {2}, null, null); future.get(2, TimeUnit.SECONDS); //no trigger assertEquals(2, ef.getCommands().size()); } @Test public void testSpatial() throws Exception { checkResult("testSpatial", "select * from spatial_ref_sys"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testGeometryColumns() throws Exception { this.internalConnection.close(); this.internalConnection = server.createConnection("jdbc:teiid:test1"); checkResult("testGeometryColumns", "select * from GEOMETRY_COLUMNS"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void testArrayIterate() throws Exception { String sql = "select array_get(cast(x.col as string[]), 2) from (exec arrayiterate((('a', 'b'),('c','d')))) x"; //$NON-NLS-1$ this.execute(sql); assertResults(new String[] {"expr1[string]", "b", "d"}); sql = "select array_get(cast(x.col as string[]), 2) from (exec arrayiterate(null)) x"; //$NON-NLS-1$ this.execute(sql); assertRowCount(0); } @Test public void testCloseOnCompletion() throws Exception { String sql = "values (1)"; //$NON-NLS-1$ this.execute(sql); this.internalStatement.closeOnCompletion(); this.internalResultSet.close(); assertTrue(this.internalStatement.isClosed()); sql = "values (1)"; //$NON-NLS-1$ this.execute(sql); this.internalStatement.closeOnCompletion(); try { this.internalStatement.execute(sql); fail(); } catch (SQLException e) { //implicitly closed } } @Test public void testImplicitResolvingWithParameter() throws Exception { this.execute("create local temporary table #x (e1 string)"); this.execute("insert into #x (e1) values (?)", "a"); } }