/* * 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.sql.CallableStatement; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.teiid.adminapi.Model.Type; import org.teiid.adminapi.impl.ModelMetaData; import org.teiid.adminapi.impl.VDBImportMetadata; import org.teiid.adminapi.impl.VDBMetaData; import org.teiid.core.TeiidRuntimeException; import org.teiid.core.types.DataTypeManager; import org.teiid.core.util.UnitTestUtil; import org.teiid.jdbc.FakeServer; import org.teiid.jdbc.FakeServer.DeployVDBParameter; import org.teiid.jdbc.TeiidSQLException; import org.teiid.metadata.FunctionMethod; import org.teiid.metadata.FunctionMethod.Determinism; import org.teiid.metadata.FunctionMethod.PushDown; import org.teiid.metadata.FunctionParameter; import org.teiid.runtime.HardCodedExecutionFactory; import org.teiid.translator.loopback.LoopbackExecutionFactory; @SuppressWarnings("nls") public class TestMatViews { private static final String MATVIEWS = "matviews"; private Connection conn; private FakeServer server; private static int count = 0; public static int pause() throws InterruptedException { synchronized (TestMatViews.class) { count++; TestMatViews.class.notify(); while (count < 2) { TestMatViews.class.wait(); } } return 1; } @Before public void setUp() throws Exception { server = new FakeServer(true); HashMap<String, Collection<FunctionMethod>> udfs = new HashMap<String, Collection<FunctionMethod>>(); udfs.put("funcs", Arrays.asList(new FunctionMethod("pause", null, null, PushDown.CANNOT_PUSHDOWN, TestMatViews.class.getName(), "pause", null, new FunctionParameter("return", DataTypeManager.DefaultDataTypes.INTEGER), true, Determinism.NONDETERMINISTIC))); server.deployVDB(MATVIEWS, UnitTestUtil.getTestDataPath() + "/matviews.vdb", new DeployVDBParameter(udfs, null)); conn = server.createConnection("jdbc:teiid:matviews"); } @After public void tearDown() throws Exception { conn.close(); server.stop(); } @Test public void testSystemMatViewsWithImplicitLoad() throws Exception { Statement s = conn.createStatement(); ResultSet rs = s.executeQuery("select * from MatViews order by name"); assertTrue(rs.next()); assertEquals("NEEDS_LOADING", rs.getString("loadstate")); assertEquals("#MAT_TEST.ERRORVIEW", rs.getString("targetName")); assertTrue(rs.next()); assertEquals("NEEDS_LOADING", rs.getString("loadstate")); assertEquals("#MAT_TEST.MATVIEW", rs.getString("targetName")); assertTrue(rs.next()); assertEquals(false, rs.getBoolean("valid")); assertEquals("#MAT_TEST.RANDOMVIEW", rs.getString("targetName")); rs = s.executeQuery("select * from MatView"); assertTrue(rs.next()); rs = s.executeQuery("select * from MatViews where name = 'MatView'"); assertTrue(rs.next()); assertEquals("LOADED", rs.getString("loadstate")); try { s.executeQuery("select * from ErrorView"); } catch (SQLException e) { } rs = s.executeQuery("select * from MatViews where name = 'ErrorView'"); assertTrue(rs.next()); assertEquals("FAILED_LOAD", rs.getString("loadstate")); } @Test public void testSystemMatViewsWithExplicitRefresh() throws Exception { Statement s = conn.createStatement(); ResultSet rs = s.executeQuery("select * from (call refreshMatView('TEST.RANDOMVIEW', false)) p"); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); rs = s.executeQuery("select * from MatViews where name = 'RandomView'"); assertTrue(rs.next()); assertEquals("LOADED", rs.getString("loadstate")); assertEquals(true, rs.getBoolean("valid")); rs = s.executeQuery("select x from TEST.RANDOMVIEW"); assertTrue(rs.next()); double key = rs.getDouble(1); rs = s.executeQuery("select * from (call refreshMatView('TEST.RANDOMVIEW', false)) p"); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); rs = s.executeQuery("select * from MatViews where name = 'RandomView'"); assertTrue(rs.next()); assertEquals("LOADED", rs.getString("loadstate")); assertEquals(true, rs.getBoolean("valid")); rs = s.executeQuery("select x from TEST.RANDOMVIEW"); assertTrue(rs.next()); double key1 = rs.getDouble(1); //ensure that invalidate with distributed caching works assertTrue(key1 != key); } @Test public void testSystemMatViewsWithExplictRefreshAndInvalidate() throws Exception { Statement s = conn.createStatement(); ResultSet rs = s.executeQuery("select * from (call refreshMatView('TEST.MATVIEW', false)) p"); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); rs = s.executeQuery("select * from MatViews where name = 'MatView'"); assertTrue(rs.next()); assertEquals("LOADED", rs.getString("loadstate")); assertEquals(true, rs.getBoolean("valid")); count = 0; s.execute("alter view TEST.MATVIEW as select pause() as x"); Thread t = new Thread() { public void run() { try { Statement s1 = conn.createStatement(); ResultSet rs = s1.executeQuery("select * from (call refreshMatView('TEST.MATVIEW', true)) p"); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); } catch (Exception e) { throw new TeiidRuntimeException(e); } } }; t.start(); synchronized (TestMatViews.class) { while (count < 1) { TestMatViews.class.wait(); } } rs = s.executeQuery("select * from MatViews where name = 'MatView'"); assertTrue(rs.next()); assertEquals("LOADING", rs.getString("loadstate")); assertEquals(false, rs.getBoolean("valid")); synchronized (TestMatViews.class) { count++; TestMatViews.class.notify(); } t.join(); rs = s.executeQuery("select * from MatViews where name = 'MatView'"); assertTrue(rs.next()); assertEquals("LOADED", rs.getString("loadstate")); assertEquals(true, rs.getBoolean("valid")); } @Test(expected=TeiidSQLException.class) public void testSystemMatViewsInvalidView() throws Exception { Statement s = conn.createStatement(); s.execute("call refreshMatView('TEST.NotMat', false)"); } @Test(expected=TeiidSQLException.class) public void testSystemMatViewsInvalidView1() throws Exception { Statement s = conn.createStatement(); s.execute("call refreshMatView('foo', false)"); } @Test(expected=TeiidSQLException.class) public void testSystemMatViewsWithRowRefreshNotAllowed() throws Exception { Statement s = conn.createStatement(); s.execute("alter view test.randomview as select rand() as x, rand() as y"); ResultSet rs = s.executeQuery("select * from (call refreshMatView('TEST.RANDOMVIEW', false)) p"); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); rs = s.executeQuery("select * from MatViews where name = 'RandomView'"); assertTrue(rs.next()); assertEquals("LOADED", rs.getString("loadstate")); assertEquals(true, rs.getBoolean("valid")); rs = s.executeQuery("select x from TEST.RANDOMVIEW"); assertTrue(rs.next()); double key = rs.getDouble(1); rs = s.executeQuery("select * from (call refreshMatViewRow('TEST.RANDOMVIEW', "+key+")) p"); } @Test public void testSystemMatViewsWithRowRefresh() throws Exception { Statement s = conn.createStatement(); s.execute("alter view test.randomview as /*+ cache(updatable) */ select rand() as x, rand() as y"); //prior to load refresh of a single row returns -1 ResultSet rs = s.executeQuery("select * from (call refreshMatViewRow('TEST.RANDOMVIEW', 0)) p"); assertTrue(rs.next()); assertEquals(-1, rs.getInt(1)); assertFalse(rs.next()); rs = s.executeQuery("select * from (call refreshMatView('TEST.RANDOMVIEW', false)) p"); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); rs = s.executeQuery("select * from MatViews where name = 'RandomView'"); assertTrue(rs.next()); assertEquals("LOADED", rs.getString("loadstate")); assertEquals(true, rs.getBoolean("valid")); rs = s.executeQuery("select x from TEST.RANDOMVIEW"); assertTrue(rs.next()); double key = rs.getDouble(1); rs = s.executeQuery("select * from (call refreshMatViewRow('TEST.RANDOMVIEW', "+key+")) p"); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); //1 row updated (removed) rs = s.executeQuery("select * from TEST.RANDOMVIEW"); assertFalse(rs.next()); rs = s.executeQuery("select * from (call refreshMatViewRow('TEST.RANDOMVIEW', "+key+")) p"); assertTrue(rs.next()); assertEquals(0, rs.getInt(1)); //no rows updated } @Test(expected=TeiidSQLException.class) public void testSystemMatViewsWithRowRefreshNoPk() throws Exception { Statement s = conn.createStatement(); s.executeQuery("select * from (call refreshMatView('TEST.MATVIEW', false)) p"); //prior to load refresh of a single row returns -1 s.executeQuery("select * from (call refreshMatViewRow('TEST.MATVIEW', 0)) p"); } @Test public void testMatViewWithImportedVDB() throws Exception { ModelMetaData mmd = new ModelMetaData(); mmd.setName("phy"); mmd.setSchemaSourceType("DDL"); mmd.setSchemaText("CREATE FOREIGN TABLE t1 ( col1 string, col2 integer )"); mmd.addSourceMapping("phy", "loopback", null); ModelMetaData mmd1 = new ModelMetaData(); mmd1.setName("phy_mv"); mmd1.setSchemaSourceType("DDL"); mmd1.setSchemaText("CREATE FOREIGN TABLE t1_mv ( col1 string, col2 integer )" + " create foreign table status (VDBNAME STRING, VDBVERSION STRING, " + " SCHEMANAME STRING, NAME STRING, TARGETSCHEMANAME STRING, TARGETNAME STRING, " + " VALID BOOLEAN, LOADSTATE STRING, CARDINALITY LONG, UPDATED TIMESTAMP, LOADNUMBER LONG, NODENAME STRING, STALECOUNT LONG)"); mmd1.addSourceMapping("phy_mv", "loopback", null); ModelMetaData mmd2 = new ModelMetaData(); mmd2.setName("view1"); mmd2.setModelType(Type.VIRTUAL); mmd2.setSchemaSourceType("DDL"); mmd2.setSchemaText("CREATE VIEW v1 ( col1 string, col2 integer ) OPTIONS (MATERIALIZED true, " + "MATERIALIZED_TABLE 'phy_mv.t1_mv', \"teiid_rel:MATVIEW_STATUS_TABLE\" 'phy_mv.status', \"teiid_rel:MATVIEW_LOAD_SCRIPT\" 'select 1') AS select t1.col1, t1.col2 FROM t1"); server.addTranslator(LoopbackExecutionFactory.class); server.deployVDB("base", mmd, mmd1, mmd2); VDBMetaData vdbMetaData = new VDBMetaData(); vdbMetaData.setXmlDeployment(true); VDBImportMetadata importVDB = new VDBImportMetadata(); importVDB.setName("base"); importVDB.setVersion("1"); vdbMetaData.getVDBImports().add(importVDB); vdbMetaData.setName("importing"); server.deployVDB(vdbMetaData); } @Test public void testImportedMatView() throws Exception { ModelMetaData mmd2 = new ModelMetaData(); mmd2.setName("view1"); mmd2.setModelType(Type.PHYSICAL); mmd2.setSchemaSourceType("DDL"); mmd2.setSchemaText("create foreign table x (col integer); CREATE VIEW v1 ( col1 string ) OPTIONS (MATERIALIZED true) AS select current_database() from x"); mmd2.addSourceMapping("a", "a", null); HardCodedExecutionFactory hcef = new HardCodedExecutionFactory(); hcef.addData("SELECT x.col FROM x", Arrays.asList(Collections.singletonList(1))); server.addTranslator("a", hcef); server.deployVDB("base", mmd2); VDBMetaData vdbMetaData = new VDBMetaData(); vdbMetaData.setXmlDeployment(true); VDBImportMetadata importVDB = new VDBImportMetadata(); importVDB.setName("base"); importVDB.setVersion("1"); vdbMetaData.getVDBImports().add(importVDB); vdbMetaData.setName("importing"); server.deployVDB(vdbMetaData); Connection c = server.getDriver().connect("jdbc:teiid:importing", null); Statement s = c.createStatement(); ResultSet rs = s.executeQuery("select * from v1"); rs.next(); assertEquals("base", rs.getString(1)); } @Test public void testSessionScoping() throws Exception { Statement s = conn.createStatement(); s.execute("alter view test.randomview as /*+ cache(scope:session) */ select rand() as x, rand() as y"); ResultSet rs = s.executeQuery("select * from MatViews where name = 'MatView'"); assertTrue(rs.next()); assertEquals("NEEDS_LOADING", rs.getString("loadstate")); assertEquals(false, rs.getBoolean("valid")); //should be the same rs = s.executeQuery("select * from randomview"); rs.next(); double d = rs.getDouble(1); rs = s.executeQuery("select * from randomview"); rs.next(); assertEquals(d, rs.getDouble(1), 0); rs = s.executeQuery("select * from MatViews where name = 'RandomView'"); assertTrue(rs.next()); assertEquals("LOADED", rs.getString("loadstate")); assertEquals(true, rs.getBoolean("valid")); //should be different in a new session Connection c = server.getDriver().connect("jdbc:teiid:matviews", null); rs = s.executeQuery("select * from MatViews where name = 'MatView'"); assertTrue(rs.next()); assertEquals("NEEDS_LOADING", rs.getString("loadstate")); assertEquals(false, rs.getBoolean("valid")); s = c.createStatement(); rs = s.executeQuery("select * from randomview"); rs.next(); assertFalse(d == rs.getDouble(1)); //should be different after a refresh s.execute("call refreshMatView('TEST.RANDOMVIEW', false)"); rs = s.executeQuery("select * from randomview"); rs.next(); assertFalse(d == rs.getDouble(1)); } @Test public void testCompositeRowUpdate() throws Exception { ModelMetaData mmd2 = new ModelMetaData(); mmd2.setName("view1"); mmd2.setModelType(Type.VIRTUAL); mmd2.setSchemaSourceType("DDL"); mmd2.setSchemaText("CREATE VIEW v1 ( col integer, col1 string, primary key (col, col1) ) OPTIONS (MATERIALIZED true) AS /*+ cache(updatable) */ select 1, current_database()"); server.deployVDB("comp", mmd2); Connection c = server.getDriver().connect("jdbc:teiid:comp", null); Statement s = c.createStatement(); ResultSet rs = s.executeQuery("select * from v1"); rs.next(); assertEquals("1", rs.getString(1)); try { rs = s.executeQuery("select * from (call refreshMatViewRow('view1.v1', 0)) p"); fail(); } catch (SQLException e) { //not enough key parameters } rs = s.executeQuery("select * from (call refreshMatViewRow('view1.v1', 0, 'a')) p"); assertTrue(rs.next()); //row doesn't exist assertEquals(0, rs.getInt(1)); assertFalse(rs.next()); rs = s.executeQuery("select * from (call refreshMatViewRow('view1.v1', '1', 'comp')) p"); assertTrue(rs.next()); //row does exist assertEquals(1, rs.getInt(1)); assertFalse(rs.next()); } @Test public void testCompositeRowsUpdate() throws Exception { ModelMetaData mmd2 = new ModelMetaData(); mmd2.setName("view1"); mmd2.setModelType(Type.VIRTUAL); mmd2.setSchemaSourceType("DDL"); mmd2.setSchemaText("CREATE VIEW v1 ( col integer, col1 string, primary key (col, col1) ) OPTIONS (MATERIALIZED true) AS /*+ cache(updatable) */ select 1, current_database()"); server.deployVDB("comp", mmd2); Connection c = server.getDriver().connect("jdbc:teiid:comp", null); Statement s = c.createStatement(); ResultSet rs = s.executeQuery("select * from v1"); rs.next(); assertEquals("1", rs.getString(1)); try { rs = s.executeQuery("select * from (call refreshMatViewRows('view1.v1', (0,))) p"); fail(); } catch (SQLException e) { //not enough key parameters } rs = s.executeQuery("select * from (call refreshMatViewRows('view1.v1', (0, 'a'))) p"); assertTrue(rs.next()); //row doesn't exist assertEquals(0, rs.getInt(1)); assertFalse(rs.next()); rs = s.executeQuery("select * from (call refreshMatViewRows('view1.v1', ('1', 'comp'), ('2', 'comp'))) p"); assertTrue(rs.next()); //row does exist assertEquals(1, rs.getInt(1)); assertFalse(rs.next()); } @Test public void testMatViewProceduresWithSameName() throws Exception { 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); Connection c = server.getDriver().connect("jdbc:teiid:test", null); Statement s = c.createStatement(); try { s.execute("call sysadmin.matviewstatus('x', 'T')"); } catch (TeiidSQLException e) { e.getTeiidCode().equals("TEIID30167"); } try { s.execute("call sysadmin.loadmatview('x', 'T')"); } catch (TeiidSQLException e) { e.getTeiidCode().equals("TEIID30167"); } try { s.execute("call sysadmin.updateMatView('x', 'T')"); } catch (TeiidSQLException e) { e.getTeiidCode().equals("TEIID30167"); } } @Test public void testMatViewStatusInternal() throws Exception { ModelMetaData mmd = new ModelMetaData(); mmd.setName("x"); mmd.setModelType(Type.VIRTUAL); mmd.addSourceMetadata("DDL", "create view T options (materialized true) as select 1"); server.deployVDB("test", mmd); Connection c = server.getDriver().connect("jdbc:teiid:test", null); Statement s = c.createStatement(); ResultSet rs = s.executeQuery("call sysadmin.matviewstatus('x', 'T')"); rs.next(); assertNull(rs.getString("TargetSchemaName")); assertEquals("NEEDS_LOADING", rs.getString("LoadState")); } @Test public void testloadMatViewInternal() throws Exception { ModelMetaData mmd = new ModelMetaData(); mmd.setName("x"); mmd.setModelType(Type.VIRTUAL); mmd.addSourceMetadata("DDL", "create view T options (materialized true) as select 1"); server.deployVDB("test", mmd); Connection c = server.getDriver().connect("jdbc:teiid:test", null); CallableStatement s = c.prepareCall("call sysadmin.loadMatView('x', 'T', true)"); assertFalse(s.execute()); assertEquals(1, s.getInt(1)); } @Test public void testUpdateMatViewInternal() throws Exception { ModelMetaData mmd2 = new ModelMetaData(); mmd2.setName("view1"); mmd2.setModelType(Type.VIRTUAL); mmd2.addSourceMetadata("DDL", "CREATE VIEW v1 ( col integer, col1 string, col2 double, primary key (col) ) OPTIONS (MATERIALIZED true) AS /*+ cache(updatable) */ select 1, current_database(), rand()"); server.deployVDB("comp", mmd2); Connection c = server.getDriver().connect("jdbc:teiid:comp", null); Statement s = c.createStatement(); ResultSet rs = s.executeQuery("select * from v1"); rs.next(); assertEquals(1, rs.getInt(1)); assertEquals("comp", rs.getString(2)); double previous = rs.getDouble(3); rs = s.executeQuery("select * from (call sysadmin.updateMatView('view1', 'v1', 'col = 0')) p"); rs.next(); assertEquals(0, rs.getInt(1)); rs = s.executeQuery("select * from (call sysadmin.updateMatView('view1', 'v1', 'col = 1')) p"); rs.next(); assertEquals(1, rs.getInt(1)); rs = s.executeQuery("select * from v1"); rs.next(); assertNotEquals(previous, rs.getDouble(3)); } @Test public void testCompositeupdateMatViewInternal() throws Exception { ModelMetaData mmd2 = new ModelMetaData(); mmd2.setName("view1"); mmd2.setModelType(Type.VIRTUAL); mmd2.addSourceMetadata("DDL", "CREATE VIEW v1 ( col integer, col1 string, col2 double, primary key (col, col1) ) OPTIONS (MATERIALIZED true) AS /*+ cache(updatable) */ select 1, current_database(), rand()"); server.deployVDB("comp", mmd2); Connection c = server.getDriver().connect("jdbc:teiid:comp", null); Statement s = c.createStatement(); ResultSet rs = s.executeQuery("select * from v1"); rs.next(); assertEquals(1, rs.getInt(1)); assertEquals("comp", rs.getString(2)); double previous = rs.getDouble(3); rs = s.executeQuery("select * from (call sysadmin.updateMatView('view1', 'v1', 'col = 0 AND col1 = ''comp''')) p"); rs.next(); assertEquals(0, rs.getInt(1)); rs = s.executeQuery("select * from (call sysadmin.updateMatView('view1', 'v1', 'col = 1 AND col1 = ''comp''')) p"); rs.next(); assertEquals(1, rs.getInt(1)); rs = s.executeQuery("select * from v1"); rs.next(); assertNotEquals(previous, rs.getDouble(3)); } @Test(expected=TeiidSQLException.class) public void testupdateMatViewInternalNoPK() throws Exception { ModelMetaData mmd2 = new ModelMetaData(); mmd2.setName("view1"); mmd2.setModelType(Type.VIRTUAL); mmd2.addSourceMetadata("DDL", "CREATE VIEW v1 ( col integer, col1 string, col2 double ) OPTIONS (MATERIALIZED true) AS /*+ cache(updatable) */ select 1, current_database(), rand()"); server.deployVDB("comp", mmd2); Connection c = server.getDriver().connect("jdbc:teiid:comp", null); Statement s = c.createStatement(); ResultSet rs = s.executeQuery("select * from v1"); rs.next(); assertEquals(1, rs.getInt(1)); assertEquals("comp", rs.getString(2)); s.execute("call sysadmin.updateMatView('view1', 'v1', 'col = 1')"); } @Test public void testInternalWithManagement() throws Exception { ModelMetaData mmd2 = new ModelMetaData(); mmd2.setName("view1"); mmd2.setModelType(Type.VIRTUAL); mmd2.addSourceMetadata("DDL", "CREATE VIEW v1 ( col integer, col1 string, primary key (col, col1) ) " + "OPTIONS (MATERIALIZED true, \"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true, \"teiid_rel:MATVIEW_TTL\" 200) AS select 1, current_database(); " + "CREATE VIEW v2 ( col integer, col1 string, primary key (col, col1) ) " + "OPTIONS (MATERIALIZED true, \"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true) AS select 1, current_database()"); VDBMetaData vdb = new VDBMetaData(); vdb.setXmlDeployment(true); vdb.setName("comp"); vdb.setModels(Arrays.asList(mmd2)); vdb.addProperty("lazy-invalidate", "true"); server.deployVDB(vdb); Connection c = server.getDriver().connect("jdbc:teiid:comp", null); Statement s = c.createStatement(); Thread.sleep(5000); //ensure that we are preloaded ResultSet rs = s.executeQuery("select * from MatViews where name = 'v1'"); assertTrue(rs.next()); assertTrue("LOADED".equals(rs.getString("loadstate"))); assertEquals(true, rs.getBoolean("valid")); Timestamp ts = rs.getTimestamp("updated"); rs = s.executeQuery("select * from MatViews where name = 'v2'"); assertTrue(rs.next()); assertEquals("LOADED", rs.getString("loadstate")); assertEquals(true, rs.getBoolean("valid")); Timestamp v2ts = rs.getTimestamp("updated"); //and queryable rs = s.executeQuery("select * from v1"); rs.next(); assertEquals("1", rs.getString(1)); rs = s.executeQuery("select * from v2"); rs.next(); assertEquals("1", rs.getString(1)); Thread.sleep(1000); //wait for ttl to expire rs = s.executeQuery("select * from MatViews where name = 'v1'"); assertTrue(rs.next()); assertTrue("LOADED".equals(rs.getString("loadstate")) || "NEEDS_LOADING".equals(rs.getString("loadstate"))); assertEquals(true, rs.getBoolean("valid")); Timestamp ts1 = rs.getTimestamp("updated"); assertTrue(ts1.compareTo(ts) > 0); rs = s.executeQuery("select * from MatViews where name = 'v2'"); assertTrue(rs.next()); assertEquals("LOADED", rs.getString("loadstate")); assertEquals(true, rs.getBoolean("valid")); Timestamp v2ts1 = rs.getTimestamp("updated"); assertEquals(v2ts, v2ts1); } @Test public void testInternalWriteThroughMativew() throws Exception { ModelMetaData mmd2 = new ModelMetaData(); mmd2.setName("m"); mmd2.setModelType(Type.PHYSICAL); mmd2.addSourceMapping("x", "x", null); mmd2.addSourceMetadata("DDL", "CREATE foreign TABLE t (col string, colx string) options (updatable true); " + "CREATE VIEW v1 (col1 string, col2 string, primary key (col1)) " + "OPTIONS (updatable true, MATERIALIZED true, \"teiid_rel:MATVIEW_WRITE_THROUGH\" true) AS /*+ cache(updatable) */ select col, colx from t;"); HardCodedExecutionFactory hcef = new HardCodedExecutionFactory() { @Override public boolean supportsCompareCriteriaEquals() { return true; } }; hcef.addData("SELECT t.col, t.colx FROM t", Arrays.asList(Arrays.asList("a", "ax"))); hcef.addData("SELECT t.col, t.colx FROM t WHERE t.col = 'b'", Arrays.asList(Arrays.asList("b", "d"))); hcef.addUpdate("INSERT INTO t (col, colx) VALUES ('b', 'd')", new int[] {1}); server.addTranslator("x", hcef); server.deployVDB("comp", mmd2); Connection c = server.getDriver().connect("jdbc:teiid:comp", null); Statement s = c.createStatement(); ResultSet rs = s.executeQuery("select * from v1"); rs.next(); assertEquals("a", rs.getString(1)); s.execute("insert into v1 (col1, col2) values ('b', 'd')"); assertEquals(1, s.getUpdateCount()); rs = s.executeQuery("select count(*) from v1"); rs.next(); assertEquals(2, rs.getInt(1)); hcef.addUpdate("DELETE FROM t WHERE t.col = 'b'", new int[] {1}); hcef.addData("SELECT t.col, t.colx FROM t WHERE t.col = 'b'", new ArrayList<List<?>>()); s.execute("delete from v1 where v1.col1 = 'b'"); assertEquals(1, s.getUpdateCount()); rs = s.executeQuery("select count(*) from v1"); rs.next(); assertEquals(1, rs.getInt(1)); hcef.addUpdate("UPDATE t SET colx = 'bx' WHERE t.colx = 'ax'", new int[] {1}); hcef.addData("SELECT t.col, t.colx FROM t WHERE t.col = 'a'", Arrays.asList(Arrays.asList("a", "ax"))); s.execute("update v1 set col2 = 'bx' where col2 = 'ax'"); assertEquals(1, s.getUpdateCount()); rs = s.executeQuery("select col2, col1 from v1"); rs.next(); assertEquals("ax", rs.getString(1)); } }