/*
* 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.FileInputStream;
import java.io.PrintWriter;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.Statement;
import java.sql.Types;
import java.util.Arrays;
import java.util.Properties;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.infinispan.transaction.tm.DummyTransactionManager;
import org.junit.After;
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.UnitTestUtil;
import org.teiid.events.EventDistributor;
import org.teiid.jdbc.FakeServer;
import org.teiid.jdbc.util.ResultSetUtil;
import org.teiid.language.Command;
import org.teiid.logging.LogManager;
import org.teiid.metadata.RuntimeMetadata;
import org.teiid.runtime.EmbeddedConfiguration;
import org.teiid.runtime.HardCodedExecutionFactory;
import org.teiid.translator.Execution;
import org.teiid.translator.ExecutionContext;
import org.teiid.translator.TranslatorException;
import org.teiid.translator.jdbc.h2.H2ExecutionFactory;
@SuppressWarnings("nls")
public class TestExternalMatViews {
private static final class DelayableHardCodedExectionFactory extends
HardCodedExecutionFactory {
private final boolean supportsEQ;
private int delay;
private DelayableHardCodedExectionFactory(boolean supportsEQ) {
this.supportsEQ = supportsEQ;
}
@Override
public boolean supportsCompareCriteriaEquals() {
return supportsEQ;
}
@Override
public Execution createExecution(Command command,
ExecutionContext executionContext,
RuntimeMetadata metadata, Object connection)
throws TranslatorException {
if (delay > 0) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
}
}
return super.createExecution(command, executionContext, metadata, connection);
}
}
private static boolean DEBUG = false;
@BeforeClass public static void oneTimeSetup() {
if (DEBUG) {
UnitTestUtil.enableTraceLogging("org.teiid");
}
System.setProperty("jgroups.bind_addr", "127.0.0.1");
}
private Connection conn;
private FakeServer server;
private static DataSource h2DataSource;
private static final String statusTable = "CREATE TABLE status\n" +
"(\n" +
" VDBName varchar(50) not null,\n" +
" VDBVersion varchar(50) not null,\n" +
" SchemaName varchar(50) not null,\n" +
" Name varchar(256) not null,\n" +
" TargetSchemaName varchar(50),\n" +
" TargetName varchar(256) not null,\n" +
" Valid boolean not null,\n" +
" LoadState varchar(25) not null,\n" +
" Cardinality long,\n" +
" Updated timestamp not null,\n" +
" LoadNumber long not null,\n" +
" NodeName varchar(25) not null,\n" +
" StaleCount long default 0,\n" +
" PRIMARY KEY (VDBName, VDBVersion, SchemaName, Name)\n" +
")";
@BeforeClass
public static void beforeClass() throws Exception {
h2DataSource = getDatasource();
Connection c = h2DataSource.getConnection();
assertNotNull(c);
c.createStatement().execute(statusTable);
String matView = "CREATE table mat_v1 (col int primary key, col1 varchar(50))";
String matView2 = "CREATE table mat_v2 (col int primary key, col1 varchar(50), loadnum long)";
String matView1a = "CREATE table mat_v1a (col int primary key, col1 varchar(50), loadnum long)";
String matViewStage = "CREATE table mat_v1_stage (col int primary key, col1 varchar(50))";
c.createStatement().execute(matView);
c.createStatement().execute(matViewStage);
c.createStatement().execute(matView2);
c.createStatement().execute("CREATE table G1 (e1 int primary key, e2 varchar(50), LoadNumber long)");
c.createStatement().execute(matView1a);
c.close();
}
@AfterClass
public static void afterClass() {
}
@Before
public void setUp() throws Exception {
server = new FakeServer(true);
if (DEBUG)
LogManager.setLogListener(new org.teiid.logging.Logger() {
@Override
public void shutdown() {
}
@Override
public void removeMdc(String key) {
}
@Override
public void putMdc(String key, String val) {
}
@Override
public void log(int level, String context, Throwable t, Object... msg) {
StringBuilder sb = new StringBuilder();
for (Object str:msg) {
sb.append(str.toString());
}
System.out.println(sb.toString());
}
@Override
public void log(int level, String context, Object... msg) {
StringBuilder sb = new StringBuilder();
for (Object str:msg) {
sb.append(str.toString());
}
System.out.println(sb.toString());
}
@Override
public boolean isEnabled(String context, int msgLevel) {
return msgLevel <= 4;
}
});
Connection c = h2DataSource.getConnection();
c.createStatement().execute("delete from status");
c.createStatement().execute("delete from mat_v1");
c.createStatement().execute("delete from mat_v1_stage");
c.createStatement().execute("delete from mat_v2");
}
@After
public void tearDown() throws Exception {
if (conn != null) {
conn.close();
}
if (server != null) {
server.stop();
}
}
@Test
public void testSwapScriptWithEagerUpdate() throws Exception {
withSwapScripts(true);
}
@Test
public void testSwapScriptWithFullRefresh() throws Exception {
withSwapScripts(false);
}
private void withSwapScripts(boolean useUpdateScript) throws Exception {
HardCodedExecutionFactory hcef = setupData(server);
ModelMetaData sourceModel = setupSourceModel();
ModelMetaData matViewModel = setupMatViewModel();
ModelMetaData viewModel = new ModelMetaData();
viewModel.setName("view1");
viewModel.setModelType(Type.VIRTUAL);
viewModel.addSourceMetadata("DDL", "CREATE VIEW v1 (col integer primary key, col1 string) "
+ "OPTIONS (MATERIALIZED true, "
+ "MATERIALIZED_TABLE 'matview.MAT_V1', "
+ "\"teiid_rel:MATVIEW_TTL\" 3000, "
+ "\"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true, "
+ "\"teiid_rel:MATVIEW_STATUS_TABLE\" 'matview.STATUS', "
+ "\"teiid_rel:MATERIALIZED_STAGE_TABLE\" 'matview.MAT_V1_STAGE', "
+ "\"teiid_rel:MATVIEW_BEFORE_LOAD_SCRIPT\" 'execute matview.native(''truncate table MAT_V1_STAGE'')', "
+ "\"teiid_rel:MATVIEW_AFTER_LOAD_SCRIPT\" "
+ "'begin "
+ "execute matview.native(''ALTER TABLE MAT_V1 RENAME TO MAT_V1_TEMP'');"
+ "execute matview.native(''ALTER TABLE MAT_V1_STAGE RENAME TO MAT_V1'');"
+ "execute matview.native(''ALTER TABLE MAT_V1_TEMP RENAME TO MAT_V1_STAGE''); "
+ "end', "
+ "\"teiid_rel:MATVIEW_ONERROR_ACTION\" 'THROW_EXCEPTION') "
+ "AS select col, col1 from source.physicalTbl");
server.deployVDB("comp", sourceModel, viewModel, matViewModel);
Thread.sleep(1000);
assertTest(useUpdateScript, hcef);
}
@Test
public void testViewChaining() throws Exception {
DelayableHardCodedExectionFactory hcef = setupData(server);
ModelMetaData sourceModel = setupSourceModel();
ModelMetaData matViewModel = setupMatViewModel();
ModelMetaData viewModel = new ModelMetaData();
viewModel.setName("view1");
viewModel.setModelType(Type.VIRTUAL);
viewModel.addSourceMetadata("DDL", "CREATE VIEW v1 (col integer primary key, col1 string) "
+ "OPTIONS (MATERIALIZED true, "
+ "MATERIALIZED_TABLE 'matview.MAT_V1a', "
+ "\"teiid_rel:MATVIEW_TTL\" 5000, "
+ "\"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true, "
+ "\"teiid_rel:MATVIEW_STATUS_TABLE\" 'matview.STATUS', "
+ "\"teiid_rel:MATVIEW_LOADNUMBER_COLUMN\" 'loadnum', "
+ "\"teiid_rel:MATVIEW_ONERROR_ACTION\" 'THROW_EXCEPTION') "
+ "AS select col, col1 from source.physicalTbl;"
+ "CREATE VIEW v2 (col integer primary key, col1 string) "
+ "OPTIONS (MATERIALIZED true, "
+ "MATERIALIZED_TABLE 'matview.MAT_V2', "
+ "\"teiid_rel:MATVIEW_TTL\" 5000, "
+ "\"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true, "
+ "\"teiid_rel:MATVIEW_STATUS_TABLE\" 'matview.STATUS', "
+ "\"teiid_rel:MATVIEW_LOADNUMBER_COLUMN\" 'loadnum',"
+ "\"teiid_rel:MATVIEW_ONERROR_ACTION\" 'THROW_EXCEPTION') "
+ "AS select col, col1 from v1");
server.deployVDB("chain", sourceModel, viewModel, matViewModel);
hcef.delay = 100;
Connection c = server.getDriver().connect("jdbc:teiid:chain", null);
Statement s = c.createStatement();
//should succeed before the ttl
for (int i = 0; i < 5; i++) {
try {
s.execute("select * from v2");
if (i == 0) {
System.out.println("expected first iteration to fail");
}
return;
} catch (SQLException e) {
}
Thread.sleep(400);
}
}
@Test
public void testMergeDeleteWithFullRefresh() throws Exception {
withMergeDelete(false);
}
@Test
public void testMergeDeleteWithEagarUpdates() throws Exception {
withMergeDelete(true);
}
private void withMergeDelete(boolean useUpdateScript) throws Exception {
HardCodedExecutionFactory hcef = setupData(server);
ModelMetaData sourceModel = setupSourceModel();
ModelMetaData matViewModel = setupMatViewModel();
ModelMetaData viewModel = new ModelMetaData();
viewModel.setName("view1");
viewModel.setModelType(Type.VIRTUAL);
viewModel.addSourceMetadata("DDL", "CREATE VIEW v1 (col integer primary key, col1 string) "
+ "OPTIONS (MATERIALIZED true, "
+ "MATERIALIZED_TABLE 'matview.MAT_V2', "
+ "\"teiid_rel:MATVIEW_TTL\" 3000, "
+ "\"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true, "
+ "\"teiid_rel:MATVIEW_STATUS_TABLE\" 'matview.STATUS', "
+ "\"teiid_rel:MATVIEW_LOADNUMBER_COLUMN\" 'loadnum') "
+ "AS select col, col1 from source.physicalTbl");
server.deployVDB("comp", sourceModel, viewModel, matViewModel);
Thread.sleep(1000);
assertTest(useUpdateScript, hcef);
}
@Test
public void testVDBImportScopeWarning() throws Exception {
H2ExecutionFactory executionFactory = new H2ExecutionFactory();
executionFactory.setSupportsDirectQueryProcedure(true);
executionFactory.start();
server.addTranslator("h2", executionFactory);
server.addConnectionFactory("java:/matview-ds", h2DataSource);
server.deployVDB(new FileInputStream(UnitTestUtil.getTestDataFile("child-vdb.xml")));
server.deployVDB(new FileInputStream(UnitTestUtil.getTestDataFile("parent-vdb.xml")));
Thread.sleep(1000);
String uidQuery = "SELECT UID FROM Sys.Tables WHERE VDBName = 'parent' AND SchemaName = 'VM1' AND Name = 'G1'";
conn = server.createConnection("jdbc:teiid:parent");
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery(uidQuery);
rs.next();
String uid = rs.getString(1);
String scopeQuery = "SELECT \"value\" from SYS.Properties WHERE UID = '"+uid
+"' AND Name = '{http://www.teiid.org/ext/relational/2012}MATVIEW_SHARE_SCOPE'";
s = conn.createStatement();
rs = s.executeQuery(scopeQuery);
rs.next();
assertEquals("IMPORTED", rs.getString(1)); // check if the default switching working
s = conn.createStatement();
rs = s.executeQuery("select * from VM1.G1");
rs.next();
assertEquals(1, rs.getInt(1));
assertEquals("2", rs.getString(2));
Connection c = h2DataSource.getConnection();
rs = c.createStatement().executeQuery("SELECT VDBVersion FROM Status WHERE VDBName = 'child'");
rs.next();
assertEquals(1, rs.getInt(1)); // 1 means IMPORTED
rs = s.executeQuery("select * from VM2.G1");
rs.next();
assertEquals(1, rs.getInt(1));
assertEquals("2", rs.getString(2));
rs = c.createStatement().executeQuery("SELECT VDBVersion FROm Status WHERE VDBName = 'parent'");
rs.next();
assertEquals(0, rs.getInt(1)); // 0 means FULL
conn.close();
c.close();
}
@Test
public void testInternalFullRefresh() throws Exception {
internalWithSameExternalProcedures(false);
}
@Test
public void testInternalWithEargerUpdates() throws Exception {
internalWithSameExternalProcedures(true);
}
private void internalWithSameExternalProcedures(boolean useUpdateScript) throws Exception {
HardCodedExecutionFactory hcef = setupData(server);
ModelMetaData sourceModel = setupSourceModel();
ModelMetaData matViewModel = setupMatViewModel();
ModelMetaData viewModel = new ModelMetaData();
viewModel.setName("view1");
viewModel.setModelType(Type.VIRTUAL);
viewModel.addSourceMetadata("DDL", "CREATE VIEW v1 (col integer primary key, col1 string) "
+ "OPTIONS (MATERIALIZED true, "
+ "\"teiid_rel:MATVIEW_TTL\" 3000, "
+ "\"teiid_rel:MATVIEW_UPDATABLE\" true, "
+ "\"teiid_rel:MATVIEW_STATUS_TABLE\" 'matview.STATUS', "
+ "\"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true) "
+ "AS select col, col1 from source.physicalTbl");
server.deployVDB("comp", sourceModel, viewModel, matViewModel);
Thread.sleep(1000);
assertTest(useUpdateScript, hcef);
}
@Test
public void testRestartServerInMiddleOfLoading() throws Exception {
HardCodedExecutionFactory hcef = setupData(server);
ModelMetaData sourceModel = setupSourceModel();
ModelMetaData matViewModel = setupMatViewModel();
ModelMetaData viewModel = new ModelMetaData();
viewModel.setName("view1");
viewModel.setModelType(Type.VIRTUAL);
viewModel.addSourceMetadata("DDL", "CREATE VIEW v1 (col integer primary key, col1 string) "
+ "OPTIONS (MATERIALIZED true, "
+ "MATERIALIZED_TABLE 'matview.MAT_V2', "
+ "\"teiid_rel:MATVIEW_TTL\" 3000, "
+ "\"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true, "
+ "\"teiid_rel:MATVIEW_STATUS_TABLE\" 'matview.STATUS', "
+ "\"teiid_rel:MATVIEW_LOADNUMBER_COLUMN\" 'loadnum') "
+ "AS select col, col1 from source.physicalTbl");
server.deployVDB("comp", sourceModel, viewModel, matViewModel);
Thread.sleep(1000);
// test that the matview loaded
conn = server.createConnection("jdbc:teiid:comp");
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery("select * from view1.v1 order by col");
rs.next();
assertEquals(1, rs.getInt(1));
assertEquals("town", rs.getString(2));
// now change the status table underneath
h2DataSource = getDatasource();
Connection c = h2DataSource.getConnection();
assertNotNull(c);
Statement stmt = c.createStatement();
boolean update = stmt.execute("UPDATE status SET LOADSTATE = 'LOADING' WHERE NAME = 'v1'");
assertFalse(update); // this is update
assertEquals(1, stmt.getUpdateCount());
rs = c.createStatement().executeQuery("SELECT LOADSTATE, NODENAME FROM status");
assertTrue(rs.next());
assertEquals("LOADING", rs.getString(1));
assertEquals("localhost", rs.getString(2));
server.stop();
server = new FakeServer(true);
setupData(server);
setupSourceModel();
setupMatViewModel();
server.deployVDB("comp", sourceModel, viewModel, matViewModel);
Thread.sleep(1000);
rs = c.createStatement().executeQuery("SELECT LOADSTATE, NODENAME FROM STATUS WHERE NAME = 'v1'");
assertTrue(rs.next());
assertEquals("LOADED", rs.getString(1));
assertEquals("localhost", rs.getString(2));
}
private void assertTest(boolean useUpdateScript, HardCodedExecutionFactory hcef)
throws Exception, SQLException, InterruptedException {
conn = server.createConnection("jdbc:teiid:comp");
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery("select * from view1.v1 order by col");
rs.next();
assertEquals(1, rs.getInt(1));
assertEquals("town", rs.getString(2));
rs.next();
assertEquals(2, rs.getInt(1));
assertEquals("state", rs.getString(2));
rs.next();
assertEquals(3, rs.getInt(1));
assertEquals("country", rs.getString(2));
rs.close();
s.close();
// 1st data change event, explicit update to matview using updateMatview, this should reset TTL
hcef.addData("SELECT physicalTbl.col, physicalTbl.col1 FROM physicalTbl",
Arrays.asList(
Arrays.asList(1, "city"), // update
Arrays.asList(2, "state"),
// delete
Arrays.asList(4, "USA"))); // insert
hcef.addData("SELECT physicalTbl.col FROM physicalTbl",
Arrays.asList(
Arrays.asList(1),
Arrays.asList(2),
Arrays.asList(4)));
if (useUpdateScript) {
Connection admin = server.createConnection("jdbc:teiid:comp");
CallableStatement stmt = admin.prepareCall("{? = call SYSADMIN.updateMatView(schemaName=>'view1', viewName=>'v1', refreshCriteria=>'v1.col in(1,3,4)')}");
stmt.registerOutParameter(1, Types.INTEGER);
stmt.execute();
assertTrue(stmt.getInt(1) <= 4);
admin.close();
} else {
Thread.sleep(3000);
}
Statement s1;
ResultSet rs1;
s1 = conn.createStatement();
rs1 = s1.executeQuery("select * from view1.v1 order by col");
rs1.next();
assertEquals(1, rs1.getInt(1));
assertEquals("city", rs1.getString(2));
rs1.next();
assertEquals(2, rs1.getInt(1));
assertEquals("state", rs1.getString(2));
rs1.next();
assertEquals(4, rs1.getInt(1));
assertEquals("USA", rs1.getString(2));
rs1.close();
s1.close();
}
private DelayableHardCodedExectionFactory setupData(FakeServer server) throws TranslatorException {
return setupData(false, server);
}
private DelayableHardCodedExectionFactory setupData(final boolean supportsEQ, FakeServer server) throws TranslatorException {
H2ExecutionFactory executionFactory = new H2ExecutionFactory();
executionFactory.setSupportsDirectQueryProcedure(true);
executionFactory.start();
server.addTranslator("translator-h2", executionFactory);
server.addConnectionFactory("java:/matview-ds", h2DataSource);
DelayableHardCodedExectionFactory hcef = new DelayableHardCodedExectionFactory(supportsEQ);
hcef.addData("SELECT physicalTbl.col, physicalTbl.col1 FROM physicalTbl",
Arrays.asList(
Arrays.asList(1, "town"),
Arrays.asList(2, "state"),
Arrays.asList(3, "country")));
hcef.addData("SELECT physicalTbl.col FROM physicalTbl",
Arrays.asList(
Arrays.asList(1),
Arrays.asList(2),
Arrays.asList(3)));
server.addTranslator("fixed", hcef);
return hcef;
}
private ModelMetaData setupMatViewModel() {
ModelMetaData matViewModel = new ModelMetaData();
matViewModel.setName("matview");
matViewModel.setModelType(Type.PHYSICAL);
matViewModel.addSourceMapping("s2", "translator-h2", "java:/matview-ds");
matViewModel.addProperty("importer.schemaPattern", "PUBLIC");
matViewModel.addProperty("importer.tableTypes", "TABLE");
matViewModel.addProperty("importer.useFullSchemaName", "false");
return matViewModel;
}
private ModelMetaData setupSourceModel() {
ModelMetaData sourceModel = new ModelMetaData();
sourceModel.setName("source");
sourceModel.setModelType(Type.PHYSICAL);
sourceModel.addSourceMetadata("DDL", "create foreign table physicalTbl (col integer, col1 string) options (updatable true);");
sourceModel.addSourceMapping("s1", "fixed", null);
return sourceModel;
}
private static DataSource getDatasource() throws SQLException {
final org.h2.Driver h2Driver = new org.h2.Driver();
final Properties props = new Properties();
DataSource ds = new DataSource() {
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public Connection getConnection() throws SQLException {
return h2Driver.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", props);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return h2Driver.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", props);
}
};
return ds;
}
@Test
public void test() throws Exception {
HardCodedExecutionFactory hcef = setupData(server);
ModelMetaData sourceModel = setupSourceModel();
ModelMetaData matViewModel = setupMatViewModel();
ModelMetaData viewModel = new ModelMetaData();
viewModel.setName("view1");
viewModel.setModelType(Type.VIRTUAL);
viewModel.addSourceMetadata("DDL", "CREATE VIEW v1 (col integer primary key, col1 string) "
+ "OPTIONS (MATERIALIZED true, "
+ "MATERIALIZED_TABLE 'matview.MAT_V2', "
+ "\"teiid_rel:MATVIEW_TTL\" 3000, "
+ "\"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true, "
+ "\"teiid_rel:MATVIEW_STATUS_TABLE\" 'matview.STATUS', "
+ "\"teiid_rel:MATVIEW_LOADNUMBER_COLUMN\" 'loadnum') "
+ "AS select col, col1 from source.physicalTbl");
server.deployVDB("comp", sourceModel, viewModel, matViewModel);
Connection admin = server.createConnection("jdbc:teiid:comp");
execute(admin, "select * from SYSADMIN.Usage where Name = 'mat_v1'");
admin.close();
}
@Test
public void testInternalWriteThroughMativew() throws Exception {
HardCodedExecutionFactory hcef = setupData(true, server);
ModelMetaData sourceModel = setupSourceModel();
ModelMetaData matViewModel = setupMatViewModel();
ModelMetaData viewModel = new ModelMetaData();
viewModel.setName("view1");
viewModel.setModelType(Type.VIRTUAL);
viewModel.addSourceMetadata("DDL", "CREATE VIEW v1 (col integer primary key, col1 string) "
+ "OPTIONS (MATERIALIZED true,"
+ "UPDATABLE true, "
+ "MATERIALIZED_TABLE 'matview.MAT_V2', "
+ "\"teiid_rel:MATVIEW_TTL\" 3000, "
+ "\"teiid_rel:MATVIEW_WRITE_THROUGH\" true, "
+ "\"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true, "
+ "\"teiid_rel:MATVIEW_STATUS_TABLE\" 'matview.STATUS', "
+ "\"teiid_rel:MATVIEW_LOADNUMBER_COLUMN\" 'loadnum') "
+ "AS select col, col1 from source.physicalTbl");
server.deployVDB("comp", sourceModel, viewModel, matViewModel);
Connection c = server.createConnection("jdbc:teiid:comp");
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("select count(*) from v1");
rs.next();
assertEquals(3, rs.getInt(1));
hcef.addUpdate("INSERT INTO physicalTbl (col, col1) VALUES (4, 'continent')", new int[] {1});
s.execute("insert into v1 (col, col1) values (4, 'continent')");
assertEquals(1, s.getUpdateCount());
rs = s.executeQuery("select count(*) from v1");
rs.next();
assertEquals(4, rs.getInt(1));
hcef.addUpdate("DELETE FROM physicalTbl WHERE physicalTbl.col1 = 'continent'", new int[] {1});
s.execute("delete from v1 where v1.col1 = 'continent'");
assertEquals(1, s.getUpdateCount());
rs = s.executeQuery("select count(*) from v1");
rs.next();
assertEquals(3, rs.getInt(1));
hcef.addUpdate("UPDATE physicalTbl SET col1 = 'town' WHERE physicalTbl.col1 = 'city'", new int[] {1});
s.execute("update v1 set col1 = 'town' where col1 = 'city'");
assertEquals(1, s.getUpdateCount());
rs = s.executeQuery("select col, col1 from v1 where col = 1");
rs.next();
assertEquals("town", rs.getString(2));
}
public static boolean execute(Connection connection, String sql) throws Exception {
boolean hasRs = true;
try {
Statement statement = connection.createStatement();
hasRs = statement.execute(sql);
if (!hasRs) {
int cnt = statement.getUpdateCount();
if (DEBUG) {
System.out.println("----------------\r");
System.out.println("Updated #rows: " + cnt);
System.out.println("----------------\r");
}
} else {
ResultSet results = statement.getResultSet();
if (DEBUG) {
ResultSetUtil.printResultSet(results);
}
results.close();
}
statement.close();
} finally {
if (connection != null) {
connection.close();
}
}
return hasRs;
}
private FakeServer createServer(String nodeName, String ispn, String jgroups) throws Exception {
FakeServer server = new FakeServer(false);
EmbeddedConfiguration config = new EmbeddedConfiguration();
config.setInfinispanConfigFile(ispn);
config.setJgroupsConfigFile(jgroups);
config.setNodeName(nodeName);
config.setTransactionManager(new DummyTransactionManager());
server.start(config, true);
return server;
}
@Test
public void testNodeFailure() throws Exception {
FakeServer server1 = createServer("server1", "infinispan-replicated-config.xml", "tcp-shared.xml");
HardCodedExecutionFactory hcef = setupData(server1);
ModelMetaData sourceModel = setupSourceModel();
ModelMetaData matViewModel = setupMatViewModel();
ModelMetaData viewModel = new ModelMetaData();
viewModel.setName("view1");
viewModel.setModelType(Type.VIRTUAL);
viewModel.addSourceMetadata("DDL", "CREATE VIEW v1 (col integer primary key, col1 string) "
+ "OPTIONS (MATERIALIZED true, "
+ "MATERIALIZED_TABLE 'matview.MAT_V2', "
+ "\"teiid_rel:MATVIEW_TTL\" 30000, "
+ "\"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true, "
+ "\"teiid_rel:MATVIEW_SHARE_SCOPE\" 'FULL', "
+ "\"teiid_rel:MATVIEW_STATUS_TABLE\" 'matview.STATUS', "
+ "\"teiid_rel:MATVIEW_LOADNUMBER_COLUMN\" 'loadnum') "
+ "AS select col, col1 from source.physicalTbl");
server1.deployVDB("comp", sourceModel, viewModel, matViewModel);
Thread.sleep(1000);
FakeServer server2 = createServer("server2", "infinispan-replicated-config-1.xml", "tcp-shared.xml");
setupData(server2);
server2.deployVDB("comp", sourceModel, viewModel, matViewModel);
Thread.sleep(5000);
Connection c = h2DataSource.getConnection();
ResultSet rs = c.createStatement().executeQuery("SELECT LoadState, Nodename FROM Status WHERE VDBName = 'comp'");
rs.next();
assertEquals("LOADED", rs.getString(1));
assertEquals("server1", rs.getString(2));
int update = c.createStatement().executeUpdate("UPDATE Status SET LoadState = 'LOADING' WHERE VDBName = 'comp' AND Nodename = 'server1'");
assertEquals(1, update);
server1.stop();
Thread.sleep(1000);
rs = c.createStatement().executeQuery("SELECT LoadState, Nodename FROM Status WHERE VDBName = 'comp'");
rs.next();
assertEquals("LOADED", rs.getString(1));
assertEquals("server2", rs.getString(2));
}
@Test
public void testLazyUpdate() throws Exception {
HardCodedExecutionFactory hcef = setupData(server);
ModelMetaData sourceModel = setupSourceModel();
ModelMetaData matViewModel = setupMatViewModel();
ModelMetaData viewModel = new ModelMetaData();
viewModel.setName("view1");
viewModel.setModelType(Type.VIRTUAL);
viewModel.addSourceMetadata("DDL", "CREATE VIEW v1 (col integer primary key, col1 string) "
+ "OPTIONS (MATERIALIZED true, "
+ "MATERIALIZED_TABLE 'matview.MAT_V2', "
+ "\"teiid_rel:ALLOW_MATVIEW_MANAGEMENT\" true, "
+ "\"teiid_rel:MATVIEW_STATUS_TABLE\" 'matview.STATUS', "
+ "\"teiid_rel:MATVIEW_MAX_STALENESS_PCT\" '10', "
+ "\"teiid_rel:MATVIEW_LOADNUMBER_COLUMN\" 'loadnum') "
+ "AS select col, col1 from source.physicalTbl");
server.deployVDB("comp", sourceModel, viewModel, matViewModel);
Thread.sleep(1000);
// check if materilization is loaded
Connection c = h2DataSource.getConnection();
ResultSet rs = c.createStatement().executeQuery("SELECT LoadState, StaleCount FROM Status WHERE VDBName = 'comp'");
rs.next();
assertEquals("LOADED", rs.getString(1));
assertEquals(0, rs.getInt(2));
// verify with querying the database.
conn = server.createConnection("jdbc:teiid:comp");
Statement s = conn.createStatement();
rs = s.executeQuery("select * from view1.v1 order by col");
rs.next();
assertEquals(1, rs.getInt(1));
assertEquals("town", rs.getString(2));
// send a row update
EventDistributor ed = server.getEventDistributor();
ResultsFuture<?> f = ed.dataModification("comp", "1", "source", "physicalTbl", new Object[] { 1, "town" },
new Object[] { 1, "town-modified" }, new String[] { "col1", "col2" });
f.get();
f = ed.dataModification("comp", "1", "source", "physicalTbl", new Object[] { 1, "town" },
new Object[] { 1, "town-modified" }, new String[] { "col1", "col2" });
f.get();
// check the stale count incremented
rs = c.createStatement().executeQuery("SELECT LoadState, StaleCount FROM Status WHERE VDBName = 'comp'");
rs.next();
assertEquals("NEEDS_LOADING", rs.getString(1));
assertEquals(1, rs.getInt(2));
// now reload the view, this should reset the stalecount. If you can wait one minute this occurs automatically
conn.createStatement().execute("exec SYSADMIN.loadMatView(schemaName=>'view1', viewName=>'v1', invalidate=>false)");
// check the stale count to zero
rs = c.createStatement().executeQuery("SELECT LoadState, StaleCount FROM Status WHERE VDBName = 'comp'");
rs.next();
assertEquals("LOADED", rs.getString(1));
assertEquals(0, rs.getInt(2));
String ddl = server.getAdmin().getSchema("comp", "1", "source", null, null);
assertFalse(ddl.contains("AFTER INSERT"));
}
}