/*
* 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.processor;
import static org.junit.Assert.*;
import static org.teiid.query.processor.TestProcessor.*;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.teiid.common.buffer.TupleSource;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidException;
import org.teiid.dqp.internal.process.DQPWorkContext;
import org.teiid.metadata.MetadataStore;
import org.teiid.metadata.Schema;
import org.teiid.metadata.Table;
import org.teiid.query.mapping.relational.QueryNode;
import org.teiid.query.metadata.TransformationMetadata;
import org.teiid.query.optimizer.TestOptimizer;
import org.teiid.query.optimizer.capabilities.BasicSourceCapabilities;
import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.unittest.RealMetadataFactory;
import org.teiid.query.util.CommandContext;
@SuppressWarnings("nls")
public class TestSourceHints {
@Test public void testUserQueryHint() {
String sql = "SELECT /*+ sh:'foo' bar:'leading' */ e1 from pm1.g1 order by e1 limit 1"; //$NON-NLS-1$
ProcessorPlan plan = helpGetPlan(sql, RealMetadataFactory.example1Cached());
List<?>[] expected = new List[] {};
helpProcess(plan, manager("foo", "leading"), expected);
}
@Test public void testWithHint() {
String sql = "WITH x as /*+ no_inline */ (SELECT /*+ sh:'x' */ e1 from pm1.g2) " +
"SELECT /*+ sh:'foo' bar:'leading' */ g1.e1 from pm1.g1, x where g1.e1 = x.e1 order by g1.e1 limit 1"; //$NON-NLS-1$
ProcessorPlan plan = helpGetPlan(sql, RealMetadataFactory.example1Cached());
List<?>[] expected = new List[] {};
helpProcess(plan, manager("foo x", "leading", "foo x", "leading"), expected);
}
@Test public void testWithHintPushdown() throws TeiidException {
String sql = "WITH x as /*+ no_inline */ (SELECT /*+ sh:'x' */ e1 from pm1.g2) " +
"SELECT /*+ sh:'foo' bar:'leading' */ g1.e1 from pm1.g1, x where g1.e1 = x.e1 order by g1.e1 limit 1"; //$NON-NLS-1$
BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
caps.setCapabilitySupport(Capability.COMMON_TABLE_EXPRESSIONS, true);
CommandContext context = new CommandContext();
context.setDQPWorkContext(new DQPWorkContext());
context.getDQPWorkContext().getSession().setVdb(RealMetadataFactory.example1VDB());
ProcessorPlan plan = helpGetPlan(helpParse(sql), RealMetadataFactory.example1Cached(), new DefaultCapabilitiesFinder(caps), context);
List<?>[] expected = new List[] {};
helpProcess(plan, manager("foo x", "leading"), expected);
}
@Test public void testUnionHintPushdown() throws TeiidException {
String sql = "SELECT /*+ sh:'foo' bar:'leading' */ g1.e1 from pm1.g1 " +
"UNION ALL SELECT * from (SELECT /*+ sh:'x' bar:'z' */ g1.e1 from pm1.g1) as x"; //$NON-NLS-1$
BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
caps.setCapabilitySupport(Capability.QUERY_UNION, true);
CommandContext context = new CommandContext();
context.setDQPWorkContext(new DQPWorkContext());
context.getDQPWorkContext().getSession().setVdb(RealMetadataFactory.example1VDB());
ProcessorPlan plan = helpGetPlan(helpParse(sql), RealMetadataFactory.example1Cached(), new DefaultCapabilitiesFinder(caps), context);
List<?>[] expected = new List[] {};
helpProcess(plan, manager("foo x", "leading z"), expected);
}
@Test public void testKeepAliases() throws Exception {
String sql = "SELECT /*+ sh KEEP ALIASES bar:'leading(g)' */ e1 from pm1.g1 g order by e1 limit 1"; //$NON-NLS-1$
CommandContext cc = TestProcessor.createCommandContext();
cc.setDQPWorkContext(new DQPWorkContext());
cc.getDQPWorkContext().getSession().setVdb(RealMetadataFactory.example1VDB());
ProcessorPlan plan = TestOptimizer.getPlan(TestOptimizer.helpGetCommand(sql, RealMetadataFactory.example1Cached(), null), RealMetadataFactory.example1Cached(), TestOptimizer.getGenericFinder(), null, true, cc);
TestOptimizer.checkAtomicQueries(new String[] {"SELECT /*+sh KEEP ALIASES bar:'leading(g)' */ g.e1 AS c_0 FROM pm1.g1 AS g ORDER BY c_0"}, plan);
List<?>[] expected = new List[] {};
helpProcess(plan, manager(null, "leading(g)"), expected);
}
@Test public void testHintInView() {
MetadataStore metadataStore = new MetadataStore();
Schema p1 = RealMetadataFactory.createPhysicalModel("p1", metadataStore); //$NON-NLS-1$
Table t1 = RealMetadataFactory.createPhysicalGroup("t", p1); //$NON-NLS-1$
RealMetadataFactory.createElements(t1, new String[] {"a", "b" }, new String[] { "string", "string" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Schema v1 = RealMetadataFactory.createVirtualModel("v1", metadataStore); //$NON-NLS-1$
QueryNode n1 = new QueryNode("SELECT /*+ sh:'x' */ a as c, b FROM p1.t"); //$NON-NLS-1$ //$NON-NLS-2$
Table vt1 = RealMetadataFactory.createVirtualGroup("t1", v1, n1); //$NON-NLS-1$
RealMetadataFactory.createElements(vt1, new String[] {"c", "b" }, new String[] { "string", "string" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
TransformationMetadata metadata = RealMetadataFactory.createTransformationMetadata(metadataStore, "metadata");
//top level applies
HardcodedDataManager manager = manager("foo x", "leading");
String sql = "SELECT /*+ sh:'foo' bar:'leading' */ c from t1 order by c limit 1"; //$NON-NLS-1$
ProcessorPlan plan = helpGetPlan(sql, metadata);
List<?>[] expected = new List[] {};
helpProcess(plan, manager, expected);
//use the underlying hint
manager = manager("x", null);
sql = "SELECT c from t1 order by c limit 1"; //$NON-NLS-1$
plan = helpGetPlan(sql, metadata);
helpProcess(plan, manager, expected);
sql = "SELECT c from t1 union all select c from t1"; //$NON-NLS-1$
plan = helpGetPlan(sql, metadata);
helpProcess(plan, manager, expected);
}
@Test public void testInsertWithQueryExpression() throws TeiidException {
String sql = "INSERT /*+ sh:'append' */ into pm1.g1 (e1) select e1 from pm2.g1"; //$NON-NLS-1$
BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
CommandContext context = new CommandContext();
context.setDQPWorkContext(new DQPWorkContext());
context.getDQPWorkContext().getSession().setVdb(RealMetadataFactory.example1VDB());
ProcessorPlan plan = helpGetPlan(helpParse(sql), RealMetadataFactory.example1Cached(), new DefaultCapabilitiesFinder(caps), context);
HardcodedDataManager manager = manager("append", null);
manager.addData("SELECT /*+sh:'append' */ g_0.e1 FROM pm2.g1 AS g_0", Arrays.asList("a"));
manager.addData("INSERT /*+sh:'append' */ INTO pm1.g1 (e1) VALUES ('a')", Arrays.asList(1));
helpProcess(plan, manager, new List[] {Arrays.asList(1)});
}
private HardcodedDataManager manager(final String ... hints) {
HardcodedDataManager manager = new HardcodedDataManager() {
int i = 0;
@Override
public TupleSource registerRequest(CommandContext context,
Command command, String modelName,
RegisterRequestParameter parameterObject)
throws TeiidComponentException {
if (hints[i*2] == null && hints[i*2+1] == null) {
assertNull(command.getSourceHint());
} else {
assertEquals(hints[i*2], command.getSourceHint().getGeneralHint()); //$NON-NLS-1$
assertEquals(hints[i*2+1], command.getSourceHint().getSourceHint("bar")); //$NON-NLS-1$
}
i = ++i%(hints.length/2);
if (getData(command.toString()) != null) {
return super.registerRequest(context, command, modelName, parameterObject);
}
return CollectionTupleSource.createNullTupleSource();
}
};
return manager;
}
}