package com.tesora.dve.sql.statement.dml; /* * #%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.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import com.tesora.dve.sql.expression.ColumnKey; import com.tesora.dve.sql.expression.Scope; import com.tesora.dve.sql.expression.TableKey; import com.tesora.dve.sql.node.LanguageNode; import com.tesora.dve.sql.node.expression.ColumnInstance; import com.tesora.dve.sql.node.expression.FunctionCall; import com.tesora.dve.sql.node.expression.VariableInstance; import com.tesora.dve.sql.schema.Database; import com.tesora.dve.sql.schema.PEStorageGroup; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.schema.Table; import com.tesora.dve.sql.transform.ColumnInstanceCollector; import com.tesora.dve.sql.transform.CopyContext; import com.tesora.dve.sql.transform.constraints.PlanningConstraint; import com.tesora.dve.sql.util.ListSet; public class DerivedInfo { protected DMLStatement on; // there are some things we care about for pretty much all dml statements // local table keys, nested stmts, groups, databases protected ListSet<TableKey> localTableKeys; protected ListSet<ProjectingStatement> nestedQueries; protected ListSet<VariableInstance> localVariables; protected ListSet<FunctionCall> functions; // any constraints - not always computed protected List<PlanningConstraint> constraints = null; protected ListSet<ColumnKey> correlatedOuterColumns; protected boolean computedCorrelated = false; // used to set the timestamp variable on the backend protected boolean setTimestampVariable = false; public DerivedInfo(DMLStatement dmls) { on = dmls; localTableKeys = new ListSet<TableKey>(); nestedQueries = new ListSet<ProjectingStatement>(); localVariables = new ListSet<VariableInstance>(); functions = new ListSet<FunctionCall>(); correlatedOuterColumns = new ListSet<ColumnKey>(); } public void take(DerivedInfo other) { localTableKeys.addAll(other.localTableKeys); localVariables.addAll(other.localVariables); addNestedStatements(other.nestedQueries); setTimestampVariable = other.setTimestampVariable; constraints = (other.constraints == null ? null : new ArrayList<PlanningConstraint>(other.constraints)); correlatedOuterColumns.addAll(other.correlatedOuterColumns); computedCorrelated = other.computedCorrelated; } public void copyTake(DerivedInfo other) { localTableKeys.addAll(other.localTableKeys); localVariables.addAll(other.localVariables); setTimestampVariable = other.setTimestampVariable; constraints = (other.constraints == null ? null : new ArrayList<PlanningConstraint>(other.constraints)); correlatedOuterColumns.addAll(other.correlatedOuterColumns); computedCorrelated = other.computedCorrelated; } public void takeScope(Scope s) { localTableKeys.addAll(s.getLocalTables()); addNestedStatements(s.getNestedQueries()); localVariables.addAll(s.getVariables()); functions.addAll(s.getFunctions()); } public void takeCopy(CopyContext cc) { addNestedStatements(cc.getProjectingStatements()); localVariables.addAll(cc.getVariables()); } public void reload(SchemaContext sc) { for(TableKey tk : localTableKeys) tk.reload(sc); // also do all nested for(DMLStatement n : nestedQueries) { n.getDerivedInfo().reload(sc); } } public void addLocalTables(Collection<TableKey> localTabs) { if (localTabs != null) localTableKeys.addAll(localTabs); } public void addLocalTable(TableKey... local) { for(TableKey tk : local) localTableKeys.add(tk); } public void addNestedStatements(Collection<ProjectingStatement> ns) { if (ns != null) { nestedQueries.addAll(ns); } } public ListSet<TableKey> getLocalTableKeys() { return localTableKeys; } public ListSet<TableKey> getAllTableKeys() { ListSet<TableKey> all = new ListSet<TableKey>(); all.addAll(localTableKeys); for(DMLStatement ss : nestedQueries) { if (ss == on) continue; all.addAll(ss.getDerivedInfo().getAllTableKeys()); } return all; } public void addLocalTable(TableKey tk) { localTableKeys.add(tk); } // used in nested queries public void removeLocalTable(Table<?> vt) { for(Iterator<TableKey> iter = localTableKeys.iterator(); iter.hasNext();) { TableKey tk = iter.next(); if (tk.getTable() == vt) iter.remove(); } } public void clearLocalTables() { localTableKeys.clear(); } public List<PEStorageGroup> getStorageGroups(SchemaContext sc) { List<PEStorageGroup> out = new ListSet<PEStorageGroup>(); for(TableKey tk : getAllTableKeys()) { out.add(tk.getAbstractTable().getStorageGroup(sc)); } return out; } // statements can override this if they want public Database<?> getDatabase(SchemaContext sc) { if (localTableKeys.isEmpty()) { ListSet<TableKey> tabs = getAllTableKeys(); return tabs.get(0).getTable().getDatabase(sc); } return localTableKeys.get(0).getTable().getDatabase(sc); } public ListSet<Database<?>> getDatabases(SchemaContext sc) { ListSet<Database<?>> out = new ListSet<Database<?>>(); ListSet<TableKey> tabs = getAllTableKeys(); for(TableKey tk : tabs) out.add(tk.getTable().getDatabase(sc)); return out; } public ListSet<ProjectingStatement> getLocalNestedQueries() { return nestedQueries; } public ListSet<ProjectingStatement> getAllNestedQueries() { ListSet<ProjectingStatement> out = new ListSet<ProjectingStatement>(); for(DMLStatement ss : nestedQueries) { if (ss == on) continue; if (ss instanceof ProjectingStatement) out.add((ProjectingStatement)ss); out.addAll(ss.getDerivedInfo().getAllNestedQueries()); } return out; } public ListSet<ProjectingStatement> getNestedQueries(LanguageNode reachableFrom) { return getNestedQueries(Collections.singleton(reachableFrom)); } public <T extends LanguageNode> ListSet<ProjectingStatement> getNestedQueries(Collection<T> reachableFrom) { ListSet<ProjectingStatement> out = new ListSet<ProjectingStatement>(); if (nestedQueries.isEmpty()) return out; for(ProjectingStatement ss : nestedQueries) { if (reachableFrom == null) continue; if (ss.ifAncestor(reachableFrom) != null) out.add(ss); } return out; } public ListSet<VariableInstance> getLocalVariables() { return localVariables; } public ListSet<VariableInstance> getAllVariables() { ListSet<VariableInstance> out = new ListSet<VariableInstance>(); out.addAll(localVariables); if (nestedQueries.isEmpty()) return out; for(DMLStatement ss : nestedQueries) { if (ss == on) continue; out.addAll(ss.getDerivedInfo().getAllVariables()); } return out; } public ListSet<FunctionCall> getFunctions() { return functions; } public boolean doSetTimestampVariable() { return setTimestampVariable; } public void setSetTimestampVariable(boolean setTimestampVariable) { this.setTimestampVariable = setTimestampVariable; } public void setConstraints(List<PlanningConstraint> anything) { if (constraints == null) constraints = new ArrayList<PlanningConstraint>(anything); else constraints.addAll(anything); } public List<PlanningConstraint> getConstraints() { return constraints; } public ListSet<ColumnKey> getCorrelatedColumns() { if (!computedCorrelated) { computedCorrelated = true; ListSet<TableKey> mineAndDescendants = getAllTableKeys(); for(ColumnInstance ci : ColumnInstanceCollector.getColumnInstances(on)) { ColumnKey ck = ci.getColumnKey(); if (mineAndDescendants.contains(ck.getTableKey()) || ck.getTableKey().getAbstractTable().isVirtualTable() || ck.getTableKey().getAbstractTable().isView()) // one of mine continue; // someone else's correlatedOuterColumns.add(ck); } } return correlatedOuterColumns; } public void clearCorrelatedColumns(){ correlatedOuterColumns.clear(); computedCorrelated = false; } // view support public void remap(Map<Long,Long> forwarding) { for(TableKey tk : localTableKeys) { long oldn = tk.getNode(); Long newObj = forwarding.get(oldn); if (newObj == null) continue; tk.setNode(newObj); } for(ProjectingStatement ps : nestedQueries) { ps.getDerivedInfo().remap(forwarding); } } // temporary tables public boolean hasUserlandTemporaryTables() { for(TableKey tk : getAllTableKeys()) { if (tk.isUserlandTemporaryTable()) return true; } return false; } }