From 7b441fe62dc8b80725815ddadeb9cb85dfc0bdde Mon Sep 17 00:00:00 2001 From: shawkins Date: Fri, 6 Oct 2017 13:32:12 -0400 Subject: [PATCH] TEIID-5090 fixing issues with mat view scripts and adding support for aliased delete/update tables --- .../relational/rules/CapabilitiesUtil.java | 4 ++- .../teiid/query/rewriter/QueryRewriter.java | 27 +++++++++++++++++++ .../org/teiid/query/parser/SQLParser.jj | 20 ++++++++++---- .../resources/org/teiid/metadata/SYSADMIN.sql | 12 +++------ .../query/optimizer/TestSubqueryPushdown.java | 21 +++++++++++++++ .../teiid/query/resolver/TestResolver.java | 18 ++++++++++++- .../query/rewriter/TestQueryRewriter.java | 14 ++++++++++ .../testStoredProcedures.expected | 4 +-- 8 files changed, 103 insertions(+), 17 deletions(-) diff --git a/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CapabilitiesUtil.java b/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CapabilitiesUtil.java index f2867f451c..d7693f84f9 100644 --- a/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CapabilitiesUtil.java +++ b/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CapabilitiesUtil.java @@ -468,7 +468,9 @@ public static boolean supports(Capability cap, Object modelID, QueryMetadataInte // Find capabilities SourceCapabilities caps = getCapabilities(modelID, metadata, capFinder); - + if (caps == null) { + throw new AssertionError(modelID); + } return caps.supportsCapability(cap); } diff --git a/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java b/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java index 3fd59a8d22..5da4a0d0bd 100644 --- a/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java +++ b/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java @@ -59,6 +59,7 @@ import org.teiid.query.metadata.TempMetadataAdapter; import org.teiid.query.metadata.TempMetadataID; import org.teiid.query.metadata.TempMetadataStore; +import org.teiid.query.optimizer.relational.AliasGenerator; import org.teiid.query.optimizer.relational.rules.NewCalculateCostUtil; import org.teiid.query.optimizer.relational.rules.RuleMergeCriteria; import org.teiid.query.optimizer.relational.rules.RuleMergeCriteria.PlannedResult; @@ -3220,6 +3221,9 @@ public static void makeSelectUnique(Select select, boolean expressionSymbolsOnly } private Command rewriteUpdate(Update update) throws TeiidComponentException, TeiidProcessingException{ + if (update.getGroup().getDefinition() != null) { + removeAlias(update, update.getGroup()); + } Command c = rewriteForWriteThrough(update); if (c != null) { return c; @@ -3401,6 +3405,9 @@ private List createPkCriteria(GroupSymbol group, String correlationNam } private Command rewriteDelete(Delete delete) throws TeiidComponentException, TeiidProcessingException{ + if (delete.getGroup().getDefinition() != null) { + removeAlias(delete, delete.getGroup()); + } Command c = rewriteForWriteThrough(delete); if (c != null) { return c; @@ -3429,6 +3436,26 @@ private Command rewriteDelete(Delete delete) throws TeiidComponentException, Tei return delete; } + /** + * For backwards compatibility we strip the alias from delete/update + * @param command + * @param group + */ + private void removeAlias(ProcedureContainer command, GroupSymbol group) { + AliasGenerator ag = new AliasGenerator(true); + ag.setCorrelationGroups(Arrays.asList(group.getDefinition())); + command.acceptVisitor(ag); + final GroupSymbol clone = group.clone(); + DeepPostOrderNavigator.doVisit(command, new LanguageVisitor() { + public void visit(GroupSymbol obj) { + if (obj.equals(clone) && obj.getMetadataID() == group.getMetadataID()) { + obj.setName(obj.getDefinition()); + obj.setDefinition(null); + } + } + }); + } + private Command rewriteInherentDelete(Delete delete, UpdateInfo info) throws QueryMetadataException, TeiidComponentException, QueryResolverException, TeiidProcessingException { diff --git a/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj b/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj index 343023427f..c989dc0156 100644 --- a/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj +++ b/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj @@ -1765,10 +1765,12 @@ Update update(ParseInfo info) : SetClauseList setClauseList = null; Criteria criteria = null; Option option = null; + String aliasID = null; } { group = id(null) + [[] aliasID=id(Boolean.FALSE)] setClauseList = setClauseList(false, info) { @@ -1782,12 +1784,14 @@ Update update(ParseInfo info) : ] { // Store group - update.setGroup(new GroupSymbol( group) ); + if(aliasID != null) { + update.setGroup(new GroupSymbol(aliasID, group)); + } else { + update.setGroup(new GroupSymbol(group)); + } // Store optional criteria - if(criteria != null) { - update.setCriteria(criteria); - } + update.setCriteria(criteria); return update; } @@ -1804,10 +1808,12 @@ Delete delete(ParseInfo info) : Criteria criteria = null; Delete delete = new Delete(); Option option = null; + String aliasID = null; } { group = id(null) + [[] aliasID=id(Boolean.FALSE)] [criteria = where(info)] [option = option(info) { @@ -1815,7 +1821,11 @@ Delete delete(ParseInfo info) : } ] { - delete.setGroup(new GroupSymbol(group)); + if(aliasID != null) { + delete.setGroup(new GroupSymbol(aliasID, group)); + } else { + delete.setGroup(new GroupSymbol(group)); + } delete.setCriteria(criteria); return delete; diff --git a/engine/src/main/resources/org/teiid/metadata/SYSADMIN.sql b/engine/src/main/resources/org/teiid/metadata/SYSADMIN.sql index 35cb404411..9a0278cbb7 100644 --- a/engine/src/main/resources/org/teiid/metadata/SYSADMIN.sql +++ b/engine/src/main/resources/org/teiid/metadata/SYSADMIN.sql @@ -191,9 +191,7 @@ BEGIN EXECUTE logMsg(context=>'org.teiid.MATVIEWS', level=>'INFO', msg=>'Materialization of view ' || VARIABLES.fullViewName || ' started.'); - /* matViewTable is null hints View is Internal Mat View*/ - DECLARE string tempMatViewTable = '#MAT_' || UCASE(VARIABLES.fullViewName); - IF (matViewTable IS NULL OR matViewTable = tempMatViewTable) + IF (targetSchemaName IS NULL) BEGIN rowsUpdated = (EXECUTE SYSADMIN.refreshMatView(VARIABLES.fullViewName, loadMatView.invalidate)); EXECUTE logMsg(context=>'org.teiid.MATVIEWS', level=>'INFO', msg=>'Materialization of view ' || VARIABLES.fullViewName || ' completed. Rows updated = ' || VARIABLES.rowsUpdated); @@ -376,9 +374,7 @@ BEGIN DECLARE string matViewTable = array_get(targets, 1); DECLARE string targetSchemaName = array_get(targets, 2); - /* matViewTable is null hints View is Internal Mat View */ - DECLARE string tempMatViewTable = '#MAT_' || UCASE(VARIABLES.fullViewName); - IF (matViewTable IS NULL OR matViewTable = tempMatViewTable) + IF (targetSchemaName IS NULL) BEGIN DECLARE string KeyUID = (SELECT UID FROM SYS.Keys WHERE SchemaName = updateMatView.schemaName AND TableName = updateMatView.viewName AND (Type = 'Primary' OR Type = 'Unique')); IF (KeyUID IS NULL) @@ -447,7 +443,7 @@ BEGIN DECLARE string columns = (SELECT cast(string_agg('"' || replace(Name, '"', '""') || '"', ',') as string) FROM SYS.Columns WHERE SchemaName = updateMatView.schemaName AND TableName = updateMatView.viewName); IF(loadNumColumn IS null) BEGIN - EXECUTE IMMEDIATE 'DELETE FROM ' || targetSchemaName || '.' || matViewTable || ' WHERE ' || replace(refreshCriteria, viewName, matViewTable); + EXECUTE IMMEDIATE 'DELETE FROM ' || targetSchemaName || '.' || matViewTable || ' as ' || replace(viewName, '.', '_') || ' WHERE ' || refreshCriteria; VARIABLES.rowsUpdated = VARIABLES.ROWCOUNT; VARIABLES.updatedCardinality = VARIABLES.updatedCardinality - VARIABLES.ROWCOUNT; EXECUTE IMMEDIATE 'INSERT INTO ' || targetSchemaName || '.' || matViewTable || ' (' || columns || ') SELECT '|| columns ||' FROM '|| schemaName || '.' || viewName || ' WHERE ' || refreshCriteria || ' OPTION NOCACHE ' || schemaName || '.' || viewName; @@ -461,7 +457,7 @@ BEGIN EXECUTE IMMEDIATE 'UPSERT INTO ' || targetSchemaName || '.' || matViewTable || columnNames || ' SELECT ' || VARIABLES.columnValues || ' FROM '|| schemaName || '.' || viewName || ' WHERE ' || refreshCriteria || ' OPTION NOCACHE ' || schemaName || '.' || viewName; VARIABLES.rowsUpdated = VARIABLES.ROWCOUNT; VARIABLES.updatedCardinality = VARIABLES.updatedCardinality + VARIABLES.ROWCOUNT; - EXECUTE IMMEDIATE 'DELETE FROM ' || targetSchemaName || '.' || matViewTable || ' WHERE ' || VARIABLES.loadNumColumn || ' <= ' || VARIABLES.loadNumber || ' AND ' || replace(refreshCriteria, viewName, matViewTable); + EXECUTE IMMEDIATE 'DELETE FROM ' || targetSchemaName || '.' || matViewTable || ' as ' || replace(viewName, '.', '_') || ' WHERE ' || VARIABLES.loadNumColumn || ' <= ' || VARIABLES.loadNumber || ' AND ' || refreshCriteria; VARIABLES.rowsUpdated = VARIABLES.rowsUpdated + VARIABLES.ROWCOUNT; VARIABLES.updatedCardinality = VARIABLES.updatedCardinality - VARIABLES.ROWCOUNT; END diff --git a/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java b/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java index 83676f9848..9f76c097e2 100644 --- a/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java +++ b/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java @@ -1270,6 +1270,27 @@ void checkJoinCounts(ProcessorPlan plan, int semi, int antiSemi) { null, false); //$NON-NLS-1$ } + @Test public void testDeleteSubqueryCorrelated() throws Exception { + BasicSourceCapabilities bsc = getTypicalCapabilities(); + bsc.setCapabilitySupport(Capability.QUERY_SUBQUERIES_SCALAR, true); + bsc.setCapabilitySupport(Capability.QUERY_SUBQUERIES_CORRELATED, true); + TestOptimizer.helpPlan("delete FROM bqt1.smalla x where intkey = (select intkey from bqt1.smallb where intkey < x.intkey)", //$NON-NLS-1$ + RealMetadataFactory.exampleBQTCached(), null, new DefaultCapabilitiesFinder(bsc), + new String[] {"DELETE FROM BQT1.SmallA WHERE BQT1.SmallA.IntKey = (SELECT g_0.IntKey FROM BQT1.SmallB AS g_0 WHERE g_0.IntKey < BQT1.SmallA.IntKey)"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$ + } + + @Test public void testDeleteSubqueryCorrelatedCompensated() throws Exception { + BasicSourceCapabilities bsc = getTypicalCapabilities(); + ProcessorPlan plan = TestOptimizer.helpPlan("delete FROM pm1.g1 x where e1 = 'a' and e3 = (select e3 from pm1.g2 where e2 < x.e2)", //$NON-NLS-1$ + RealMetadataFactory.example4(), null, new DefaultCapabilitiesFinder(bsc), + new String[] {}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$ + HardcodedDataManager hcdm = new HardcodedDataManager(); + hcdm.addData("SELECT g_0.e3, g_0.e2, g_0.e1 FROM pm1.g1 AS g_0 WHERE g_0.e1 = 'a'", Arrays.asList(true, 1, 'a')); + hcdm.addData("SELECT g_0.e3 FROM pm1.g2 AS g_0 WHERE g_0.e2 < 1", Arrays.asList(true)); + hcdm.addData("DELETE FROM pm1.g1 WHERE pm1.g1.e1 = 'a'", Arrays.asList(1)); + TestProcessor.helpProcess(plan, hcdm, null); + } + @Test public void testSubqueryPlan() throws Exception { BasicSourceCapabilities bsc = getTypicalCapabilities(); ProcessorPlan plan = TestOptimizer.helpPlan("select 1, (select cast(stringkey as integer) from bqt1.smallb where intkey = smalla.intkey) from bqt1.smalla", //$NON-NLS-1$ diff --git a/engine/src/test/java/org/teiid/query/resolver/TestResolver.java b/engine/src/test/java/org/teiid/query/resolver/TestResolver.java index 2d8ad4377d..67c2d66b20 100644 --- a/engine/src/test/java/org/teiid/query/resolver/TestResolver.java +++ b/engine/src/test/java/org/teiid/query/resolver/TestResolver.java @@ -2593,7 +2593,23 @@ private void verifyProjectedTypes(Command c, Class[] types) { String sql = "{call pm4.spTest9(?, ?)}"; //$NON-NLS-1$ TestResolver.helpResolveException(sql, RealMetadataFactory.exampleBQTCached(), "TEIID31113 1 extra positional parameter(s) passed to pm4.spTest9."); //$NON-NLS-1$ - } + } + + @Test public void testUpdateAlias() { + String sql = "UPDATE pm1.g1 as x SET x.e1 = 1 where x.e2 = 2;"; //$NON-NLS-1$ + + Update update = (Update)helpResolve(sql, RealMetadataFactory.example1Cached()); + + assertEquals("UPDATE pm1.g1 AS x SET e1 = 1 WHERE x.e2 = 2", update.toString()); + } + + @Test public void testDeleteAlias() { + String sql = "DELETE from pm1.g1 as x where (select e2 from pm1.g2 where x.e1 = e1) = 2;"; //$NON-NLS-1$ + + Delete update = (Delete)helpResolve(sql, RealMetadataFactory.example1Cached()); + + assertEquals("DELETE FROM pm1.g1 AS x WHERE (SELECT e2 FROM pm1.g2 WHERE x.e1 = e1) = 2", update.toString()); + } @Test public void testUpdateSetClauseReferenceType() { String sql = "UPDATE pm1.g1 SET pm1.g1.e1 = 1, pm1.g1.e2 = ?;"; //$NON-NLS-1$ diff --git a/engine/src/test/java/org/teiid/query/rewriter/TestQueryRewriter.java b/engine/src/test/java/org/teiid/query/rewriter/TestQueryRewriter.java index d1ef5e09e6..20e73fb44f 100644 --- a/engine/src/test/java/org/teiid/query/rewriter/TestQueryRewriter.java +++ b/engine/src/test/java/org/teiid/query/rewriter/TestQueryRewriter.java @@ -1846,5 +1846,19 @@ private void addTestData() { @Test public void testRewriteSubstringNegativeIndex() throws TeiidComponentException, TeiidProcessingException { helpTestRewriteExpression("substring(pm1.g1.e1, -1, 5)", "substring(pm1.g1.e1, -1, 5)", RealMetadataFactory.example1Cached()); } + + @Test public void testRewriteAliasedDelete() { + String sql = "delete from pm1.g1 x where x.e1 = (select e1 from pm2.g1 where g1.e2 = x.e2)"; //$NON-NLS-1$ + String expected = "DELETE FROM pm1.g1 WHERE pm1.g1.e1 = (SELECT g_0.e1 FROM pm2.g1 AS g_0 WHERE g_0.e2 = pm1.g1.e2 LIMIT 2)"; //$NON-NLS-1$ + + helpTestRewriteCommand(sql, expected); + } + + @Test public void testRewriteAliasedUpdate() { + String sql = "update pm1.g1 y set e2 = (select e2 from pm1.g1 where e1 = y.e1 || 'a') where y.e1 = (select e1 from pm2.g1 where g1.e2 = y.e2)"; //$NON-NLS-1$ + String expected = "UPDATE pm1.g1 SET e2 = (SELECT g_0.e2 FROM pm1.g1 AS g_0 WHERE g_0.e1 = concat(pm1.g1.e1, 'a') LIMIT 2) WHERE pm1.g1.e1 = (SELECT g_1.e1 FROM pm2.g1 AS g_1 WHERE g_1.e2 = pm1.g1.e2 LIMIT 2)"; //$NON-NLS-1$ + + helpTestRewriteCommand(sql, expected); + } } diff --git a/test-integration/common/src/test/resources/TestSystemVirtualModel/testStoredProcedures.expected b/test-integration/common/src/test/resources/TestSystemVirtualModel/testStoredProcedures.expected index cb9f22e824..2046ca7f6d 100644 --- a/test-integration/common/src/test/resources/TestSystemVirtualModel/testStoredProcedures.expected +++ b/test-integration/common/src/test/resources/TestSystemVirtualModel/testStoredProcedures.expected @@ -1,8 +1,8 @@ string clob Name Body -loadMatView Clob[11708] +loadMatView Clob[11595] matViewStatus Clob[3119] -updateMatView Clob[8839] +updateMatView Clob[8751] updateStaleCount Clob[3474] Row Count : 4 getColumnName getColumnType getCatalogName getColumnClassName getColumnLabel getColumnTypeName getSchemaName getTableName getColumnDisplaySize getPrecision getScale isAutoIncrement isCaseSensitive isCurrency isDefinitelyWritable isNullable isReadOnly isSearchable isSigned isWritable