package com.tesora.dve.sql.statement.ddl; /* * #%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.io.PrintStream; import java.util.Collections; import java.util.List; import com.tesora.dve.distribution.KeyValue; import com.tesora.dve.server.messaging.SQLCommand; import com.tesora.dve.sql.node.expression.ColumnInstance; import com.tesora.dve.sql.node.expression.ExpressionAlias; import com.tesora.dve.sql.node.expression.ExpressionNode; import com.tesora.dve.sql.node.expression.NameAlias; import com.tesora.dve.sql.node.expression.Parameter; import com.tesora.dve.sql.node.expression.TableInstance; import com.tesora.dve.sql.node.expression.TempTableInstance; import com.tesora.dve.sql.node.structural.LimitSpecification; import com.tesora.dve.sql.node.structural.SortingSpecification; import com.tesora.dve.sql.schema.*; import com.tesora.dve.sql.statement.dml.AliasInformation; import com.tesora.dve.sql.statement.dml.InsertIntoValuesStatement; import com.tesora.dve.sql.statement.dml.SelectStatement; import com.tesora.dve.sql.statement.dml.TruncateStatement; import com.tesora.dve.sql.util.Functional; import com.tesora.dve.sql.util.ListSet; import com.tesora.dve.sql.util.UnaryFunction; public abstract class AddStorageGenRangeTableInfo extends RebalanceInfo { protected final PETable srcTab; protected final Database srcDB; protected final KeyValue emptyDistKey; protected final List<PEColumn> distColumns; protected final int[] distKeyOffsets; public AddStorageGenRangeTableInfo(SchemaContext sc, PETable srcTab) { super(sc); this.srcTab = srcTab; this.srcDB = srcTab.getDatabase(sc); DistributionVector distributionVector = srcTab.getDistributionVector(sc); this.distColumns = distributionVector.getColumns(sc); this.distKeyOffsets = new int[distColumns.size()]; for(int i = 0; i < distKeyOffsets.length; i++) { distKeyOffsets[i] = i; } this.emptyDistKey = distributionVector.buildEmptyKeyValue(sc); } public PETable getSourceTable(){ return srcTab; } public Name getName(){ return srcTab.getName(); } public Database getDatabase(){ return srcDB; } public KeyValue getEmptyDistKey(){ return new KeyValue(emptyDistKey); } public abstract boolean hasSharedTable(); public abstract TempTable getSideTable(); public abstract SQLCommand getSideDelete(); public int[] getSideInsertOffsets() { return getDistKeyOffsets(); } public int[] getDistKeyOffsets() { return distKeyOffsets; } public SQLCommand getTruncateSideTableStmt() { TableInstance ti = buildSideTableInstance(); TruncateStatement trunc = new TruncateStatement(ti,null); return getCommand(trunc); } public SQLCommand getCreateSideTableStmt() { PECreateTableStatement stmt = new PECreateTableStatement(getSideTable(),true,false); return getCommand(stmt); } public SQLCommand getDropSideTableStmt() { PEDropTableStatement stmt = new PEDropTableStatement(cntxt,Collections.singletonList(buildSideTableInstance().getTableKey()), Collections.<Name> emptyList(),true,false); return getCommand(stmt); } public SQLCommand getChunkQuery() { SelectStatement q = buildSkeleton(false); TableInstance ti = q.getTables().get(0).getBaseTable(); q.setProjection(buildProjection(ti,distColumns)); return getCommand(q); } public SQLCommand getDataChunkQuery() { SelectStatement q = buildSkeleton(false); TableInstance ti = q.getTables().get(0).getBaseTable(); q.setProjection(buildProjection(ti,getFullColumns())); return getCommand(q); } // the insert column order is whatever getFullColumns returns, // which conveniently is also whatever comes back from the data chunk query public SQLCommand getSrcInsertPrefix() { final TableInstance ti = new TableInstance(srcTab,srcTab.getName().getUnqualified(), null, false); final List<ExpressionNode> columns = Functional.apply(getFullColumns(), new UnaryFunction<ExpressionNode,PEColumn>() { @Override public ExpressionNode evaluate(PEColumn object) { return new ColumnInstance(object,ti); } }); final InsertIntoValuesStatement iivs = new InsertIntoValuesStatement(ti,columns,Collections.<List<ExpressionNode>> emptyList(),Collections.<ExpressionNode> emptyList(),new AliasInformation(),null); return getInsertPrefix(iivs); } public SQLCommand getSideInsertPrefix() { final TableInstance ti = buildSideTableInstance(); final List<ExpressionNode> columns = Functional.apply(getSideTable().getColumns(cntxt), new UnaryFunction<ExpressionNode,PEColumn>() { @Override public ExpressionNode evaluate(PEColumn object) { return new ColumnInstance(object,ti); } }); final InsertIntoValuesStatement iivs = new InsertIntoValuesStatement(ti,columns,Collections.<List<ExpressionNode>> emptyList(),Collections.<ExpressionNode> emptyList(),new AliasInformation(),null); iivs.setIgnore(true); return getInsertPrefix(iivs); } public void display(String prefix, String tab, PrintStream ps) { String prefixWithIndent = prefix+tab; ps.println(); ps.println(prefix + srcTab.getPEDatabase(cntxt).getName().get() + "." + srcTab.getName().get() + ": "); if (!hasSharedTable()) { ps.println(prefix + "Side table:"); ps.println(prefixWithIndent+ getCreateSideTableStmt().getRawSQL()); ps.println(prefixWithIndent+ getDropSideTableStmt().getRawSQL()); } ps.println(prefix + "Chunk query"); ps.println(prefixWithIndent + getChunkQuery().getRawSQL()); ps.println(prefix + "Data chunk query"); ps.println(prefixWithIndent + getDataChunkQuery().getRawSQL()); ps.println(prefix + "Side insert offsets"); StringBuffer buf = new StringBuffer(); for(int i = 0; i < getSideInsertOffsets().length; i++) { if (i > 0) buf.append(", "); buf.append(getSideInsertOffsets()[i]); } ps.println(prefixWithIndent + buf.toString()); ps.println(prefix + "Side insert prefix"); ps.println(prefixWithIndent + getSideInsertPrefix().getRawSQL()); ps.println(prefix + "Src insert prefix"); ps.println(prefixWithIndent + getSrcInsertPrefix().getRawSQL()); ps.println(prefix + "Delete"); ps.println(prefixWithIndent + getSideDelete().getRawSQL()); } protected List<PEColumn> getFullColumns() { List<PEColumn> proj = new ListSet<PEColumn>(distColumns); for(PEColumn pec : srcTab.getColumns(cntxt)) proj.add(pec); return proj; } protected List<ExpressionNode> buildProjection(final TableInstance ti, List<PEColumn> columns) { List<ExpressionNode> proj = Functional.apply(columns, new UnaryFunction<ExpressionNode,PEColumn>() { @Override public ExpressionNode evaluate(PEColumn object) { ColumnInstance ci = new ColumnInstance(object,ti); return new ExpressionAlias(ci,new NameAlias(object.getName().getUnqualified()),false); } }); return proj; } protected SelectStatement buildSkeleton(boolean withLimitAndOffset) { final TableInstance ti = buildSrcTableInstance(); List<SortingSpecification> sorts = Functional.apply(distColumns, new UnaryFunction<SortingSpecification,PEColumn>() { @Override public SortingSpecification evaluate(PEColumn object) { SortingSpecification ss = new SortingSpecification(new ColumnInstance(object,ti),true); ss.setOrdering(true); return ss; } }); // do I need to set positions? hmmm //TODO: leave out the limits for now, since using them requires iteration inside the rebalance. -sgossard SelectStatement ss = new SelectStatement(new AliasInformation()); ss.setTables(ti); ss.setOrderBy(sorts); if (withLimitAndOffset) { LimitSpecification limit = new LimitSpecification(new Parameter(null),new Parameter(null)); ss.setLimit(limit); } return ss; } protected TableInstance buildSideTableInstance() { return new TempTableInstance(cntxt,getSideTable()); } protected TableInstance buildSrcTableInstance() { return new TableInstance(srcTab,srcTab.getName().getUnqualified(), new UnqualifiedName("q"), false); } }