package com.tesora.dve.sql.transform.strategy; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * 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/>. * #L% */ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.sql.node.expression.ActualLiteralExpression; import com.tesora.dve.sql.node.expression.ExpressionAlias; import com.tesora.dve.sql.node.expression.ExpressionNode; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.statement.dml.DMLStatement; import com.tesora.dve.sql.statement.dml.SelectStatement; import com.tesora.dve.sql.transform.CopyVisitor; import com.tesora.dve.sql.transform.behaviors.defaults.DefaultFeaturePlannerFilter; import com.tesora.dve.sql.transform.strategy.featureplan.FeatureStep; import com.tesora.dve.sql.transform.strategy.featureplan.ProjectingFeatureStep; /* * When the source select of a redist includes a null literal we are unable to * create the temp table because we cannot determine the type of the column. Work around * this by removing the column. */ public class NullLiteralColumnTransformFactory extends TransformFactory { @Override public FeaturePlannerIdentifier getFeaturePlannerID() { return FeaturePlannerIdentifier.NULL_LITERAL; } private static void addNullLiteralColumnToProjection(SchemaContext sc, SelectStatement ss, Map<Integer, ExpressionNode> nullLiterals) { List<ExpressionNode> newProj = new ArrayList<ExpressionNode>(); newProj.addAll(ss.getProjection()); for (Integer index : nullLiterals.keySet()) { newProj.add(index, nullLiterals.get(index)); } ss.setProjection(newProj); // call this to get the metadata updated ss.normalize(sc); } @Override public FeatureStep plan(DMLStatement stmt, PlannerContext ipc) throws PEException { if (ipc.getApplied().contains(FeaturePlannerIdentifier.INSERT_INTO_SELECT) || ipc.getApplied().contains(FeaturePlannerIdentifier.UNION)) return null; PlannerContext context = ipc.withTransform(getFeaturePlannerID()); Map<Integer, ExpressionNode> nullLiterals = new TreeMap<Integer, ExpressionNode>(); if (stmt instanceof SelectStatement) { SelectStatement ss = (SelectStatement) stmt; List<ExpressionNode> nodes = ss.getProjection(); for (int i = 0; i < nodes.size(); i++) { ExpressionNode node = nodes.get(i); if (node instanceof ExpressionAlias) { ExpressionAlias ci = (ExpressionAlias) node; ExpressionNode c = ci.getTarget(); if (c instanceof ActualLiteralExpression) { ActualLiteralExpression ale = (ActualLiteralExpression) c; if (ale.isNullLiteral()) { nullLiterals.put(i, node); } } } } } if (nullLiterals.isEmpty()) return null; SelectStatement pin = (SelectStatement) stmt; SelectStatement copy = CopyVisitor.copy(pin); List<ExpressionNode> newProj = new ArrayList<ExpressionNode>(); for (ExpressionNode node : copy.getProjection()) { boolean nullLiteral = false; for (ExpressionNode nullNode : nullLiterals.values()) { if (node.isSchemaEqual(nullNode)) { nullLiteral = true; break; } } if (!nullLiteral) { newProj.add(node); } } copy.setProjection(newProj); // call this to get the metadata updated copy.normalize(context.getContext()); ProjectingFeatureStep sub = (ProjectingFeatureStep) buildPlan(copy, context.withTransform(getFeaturePlannerID()), DefaultFeaturePlannerFilter.INSTANCE); addNullLiteralColumnToProjection(context.getContext(),(SelectStatement)sub.getPlannedStatement(), nullLiterals); return sub; } }