/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.sql.optimizer;
import com.foundationdb.junit.SelectedParameterizedRunner;
import com.foundationdb.qp.operator.SimpleQueryContext;
import com.foundationdb.sql.NamedParamsTestBase;
import com.foundationdb.sql.TestBase;
import com.foundationdb.sql.parser.DMLStatementNode;
import com.foundationdb.sql.parser.StatementNode;
import com.foundationdb.sql.parser.SQLParser;
import com.foundationdb.sql.optimizer.plan.BasePlannable;
import com.foundationdb.sql.optimizer.plan.PhysicalSelect.PhysicalResultColumn;
import com.foundationdb.sql.optimizer.plan.ResultSet.ResultField;
import com.foundationdb.sql.optimizer.rule.ExplainPlanContext;
import com.foundationdb.sql.optimizer.rule.RulesTestHelper;
import com.foundationdb.sql.optimizer.rule.PipelineConfiguration;
import com.foundationdb.sql.optimizer.rule.cost.TestCostEstimator;
import com.foundationdb.ais.model.AkibanInformationSchema;
import com.foundationdb.ais.model.Column;
import com.foundationdb.server.explain.format.DefaultFormatter;
import com.foundationdb.server.types.service.TypesRegistryServiceImpl;
import com.foundationdb.server.types.common.types.TypesTranslator;
import com.foundationdb.server.types.mcompat.mtypes.MTypesTranslator;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Properties;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
@RunWith(SelectedParameterizedRunner.class)
public class OperatorCompilerTest extends NamedParamsTestBase
implements TestBase.GenerateAndCheckResult
{
public static final File RESOURCE_DIR =
new File(OptimizerTestBase.RESOURCE_DIR, "operator");
protected File schemaFile, statsFile, propertiesFile;
protected SQLParser parser;
protected OperatorCompiler compiler;
@Before
public void makeCompiler() throws Exception {
parser = new SQLParser();
AkibanInformationSchema ais = OptimizerTestBase.parseSchema(schemaFile);
Properties properties = new Properties();
if (propertiesFile != null) {
FileInputStream fstr = new FileInputStream(propertiesFile);
try {
properties.load(fstr);
}
finally {
fstr.close();
}
}
compiler = TestOperatorCompiler.create(parser, ais, statsFile, properties);
}
static class TestResultColumn extends PhysicalResultColumn {
private String type;
public TestResultColumn(String name, String type) {
super(name);
this.type = type;
}
public String getType() {
return type;
}
@Override
public String toString() {
return getName() + ":" + getType();
}
}
public static class TestOperatorCompiler extends OperatorCompiler {
private TestOperatorCompiler() {
}
public static TestOperatorCompiler create(SQLParser parser,
AkibanInformationSchema ais,
File statsFile,
Properties properties)
throws IOException {
RulesTestHelper.ensureRowDefs(ais);
TestOperatorCompiler compiler = new TestOperatorCompiler();
compiler.initProperties(properties);
compiler.initAIS(ais, OptimizerTestBase.DEFAULT_SCHEMA);
compiler.initParser(parser);
compiler.initCostEstimator(new TestCostEstimator(ais, compiler.getSchema(), statsFile, false, properties));
compiler.initPipelineConfiguration(new PipelineConfiguration());
TypesRegistryServiceImpl typesRegistry = new TypesRegistryServiceImpl();
typesRegistry.start();
compiler.initTypesRegistry(typesRegistry);
TypesTranslator typesTranslator = MTypesTranslator.INSTANCE;
compiler.initTypesTranslator(typesTranslator);
compiler.initDone();
return compiler;
}
@Override
public PhysicalResultColumn getResultColumn(ResultField field) {
String type = String.valueOf(field.getSQLtype());
if (field.getType() != null) {
type = field.getType().toStringConcise(true);
}
Column column = field.getAIScolumn();
if (column != null) {
type = column.getTypeDescription();
}
return new TestResultColumn(field.getName(), type);
}
}
@Parameterized.Parameters(name="{0}")
public static Iterable<Object[]> statements() throws Exception {
Collection<Object[]> result = new ArrayList<>();
for (File subdir : RESOURCE_DIR.listFiles(new FileFilter() {
public boolean accept(File file) {
return file.isDirectory();
}
})) {
File schemaFile = new File(subdir, "schema.ddl");
if (schemaFile.exists()) {
File statsFile = new File(subdir, "stats.yaml");
if (!statsFile.exists())
statsFile = null;
File compilerPropertiesFile = new File(subdir, "compiler.properties");
if (!compilerPropertiesFile.exists())
compilerPropertiesFile = null;
for (Object[] args : sqlAndExpected(subdir)) {
File propertiesFile = new File(subdir, args[0] + ".properties");
if (!propertiesFile.exists())
propertiesFile = compilerPropertiesFile;
Object[] nargs = new Object[args.length+3];
nargs[0] = subdir.getName() + "/" + args[0];
nargs[1] = schemaFile;
nargs[2] = statsFile;
nargs[3] = propertiesFile;
System.arraycopy(args, 1, nargs, 4, args.length-1);
result.add(nargs);
}
}
}
return result;
}
public OperatorCompilerTest(String caseName,
File schemaFile, File statsFile, File propertiesFile,
String sql, String expected, String error) {
super(caseName, sql, expected, error);
this.schemaFile = schemaFile;
this.statsFile = statsFile;
this.propertiesFile = propertiesFile;
}
@Test
public void testOperator() throws Exception {
generateAndCheckResult();
}
@Override
public String generateResult() throws Exception {
StatementNode stmt = parser.parseStatement(sql);
ExplainPlanContext context = new ExplainPlanContext(compiler, new SimpleQueryContext(null));
BasePlannable result = compiler.compile((DMLStatementNode)stmt,
parser.getParameterList(), context);
return result.explainToString(context.getExplainContext(), OptimizerTestBase.DEFAULT_SCHEMA, DefaultFormatter.LevelOfDetail.VERBOSE_WITHOUT_COST);
}
@Override
public void checkResult(String result) throws IOException{
assertEqualsWithoutHashes(caseName, expected, result);
}
}