package com.tesora.dve.sql.expression; /* * #%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.Set; import java.util.Stack; import com.tesora.dve.sql.SchemaException; import com.tesora.dve.sql.node.expression.Alias; import com.tesora.dve.sql.node.expression.ExpressionAlias; import com.tesora.dve.sql.node.expression.ExpressionNode; import com.tesora.dve.sql.node.expression.FunctionCall; import com.tesora.dve.sql.node.expression.NameInstance; import com.tesora.dve.sql.node.expression.TableInstance; import com.tesora.dve.sql.node.expression.VariableInstance; import com.tesora.dve.sql.parser.SourceLocation; import com.tesora.dve.sql.schema.LockInfo; import com.tesora.dve.sql.schema.Name; import com.tesora.dve.sql.schema.PEColumn; import com.tesora.dve.sql.schema.PETable; import com.tesora.dve.sql.schema.Schema; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.schema.SubqueryTable; import com.tesora.dve.sql.schema.Table; import com.tesora.dve.sql.schema.UnqualifiedName; import com.tesora.dve.sql.statement.dml.ProjectingStatement; import com.tesora.dve.sql.util.ListSet; import com.tesora.dve.sql.util.ResizableArray; public class ScopeStack implements Scope { private Stack<ScopeEntry> scopes; private ResizableArray<ScopeEntry> popped; private int counter; public ScopeStack() { scopes = new Stack<ScopeEntry>(); popped = new ResizableArray<ScopeEntry>(); counter = -1; } public void pushScope() { pushScope(new ScopeEntry(true,++counter)); } private void pushScope(ScopeEntry s) { Scope parent = null; if (!scopes.isEmpty()) parent = scopes.peek(); if (parent != null) parent.getNested().add(s); scopes.push(s); } public void pushUnresolvingScope() { pushScope(new ScopeEntry(false,++counter)); } @Override public void resolveProjection(SchemaContext sc) { getScope().resolveProjection(sc); } @Override public void storeProjection(List<ExpressionNode> exprs) { getScope().storeProjection(exprs); } @Override public void setPhase(ScopeParsePhase spp) { getScope().setPhase(spp); } @Override public ScopeParsePhase getPhase() { return getScope().getPhase(); } public void popScope() { ScopeEntry se = scopes.pop(); if (se.getUnresolved() != null && se.getUnresolved().size() > 0 && !isEmpty()) { for (NameInstance ni : se.getUnresolved()) { getScope().buildColumnInstance(null, ni.getName()); } getScope().getUnresolvedChildren().addAll(se.getUnresolvedChildren()); getScope().getUnresolvedChildren().addAll(se.getUnresolved()); } popped.set(se.getID(),se); } public int getLastPoppedScopeID() { if (popped.size() == 0) return -1; return popped.get(popped.size() - 1).getID(); } public void pushScopeID(int id) { pushScope(popped.get(id)); } private Scope getScope() { return scopes.peek(); } public boolean isEmpty() { return scopes.isEmpty(); } public Scope getParentScope() { if (scopes.size() > 1) return scopes.get(scopes.size() - 2); return null; } public List<Scope> getCurrentStack() { ArrayList<Scope> out = new ArrayList<Scope>(); for(ScopeEntry se : scopes) out.add(se); return out; } @Override public List<Scope> getNested() { return getScope().getNested(); } @Override public ListSet<ProjectingStatement> getNestedQueries() { return getScope().getNestedQueries(); } @Override public ListSet<VariableInstance> getVariables() { return getScope().getVariables(); } @Override public TableInstance buildTableInstance(final Name inTableName, final UnqualifiedName alias, final Schema<?> inSchema, final SchemaContext sc, final LockInfo info) { return lookup(new LookupFunction<TableInstance>() { @Override public TableInstance lookup(ScopeEntry e) throws SchemaException { return e.buildTableInstance(inTableName, alias, inSchema, sc, info); } }); } @Override public TableInstance buildTableInstance(final Name inTableName, final UnqualifiedName alias, final SchemaContext sc, final LockInfo info) { return lookup(new LookupFunction<TableInstance>() { @Override public TableInstance lookup(ScopeEntry entry) throws SchemaException { return entry.buildTableInstance(inTableName, alias, sc, info); } }); } private <ReturnType> ReturnType lookup(LookupFunction<ReturnType> f) { RuntimeException any = null; for(int i = scopes.size() - 1; i > -1; i--) { try { return f.lookup(scopes.get(i)); } catch (SchemaException e) { if (any == null) any = e; } } throw any; } interface LookupFunction<ReturnType> { ReturnType lookup(ScopeEntry e) throws SchemaException; } @Override public ExpressionNode buildColumnInstance(final SchemaContext sc, final Name given) { return lookup(new LookupFunction<ExpressionNode>() { @Override public ExpressionNode lookup(ScopeEntry e) throws SchemaException { return e.buildColumnInstance(sc, given); } }); } @Override public void insertColumn(UnqualifiedName alias, ExpressionAlias e) { getScope().insertColumn(alias, e); } @Override public ExpressionNode buildExpressionAlias(final ExpressionNode e, final Alias alias, final SourceLocation sloc) { return lookup(new LookupFunction<ExpressionNode>() { @Override public ExpressionNode lookup(ScopeEntry entry) throws SchemaException { return entry.buildExpressionAlias(e, alias, sloc); } }); } @Override public Set<String> getAllAliases() { return getScope().getAllAliases(); } @Override public ListSet<TableKey> getLocalTables() { return getScope().getLocalTables(); } @Override public ListSet<TableKey> getAllVisibleTables() { return getScope().getAllVisibleTables(); } @Override public ListSet<FunctionCall> getFunctions() { return getScope().getFunctions(); } @Override public void registerFunction(FunctionCall fc) { getScope().registerFunction(fc); } @Override public PEColumn registerColumn(PEColumn c) { return getScope().registerColumn(c); } @Override public void registerAlterColumns(SchemaContext sc, PETable tab) { getScope().registerAlterColumns(sc,tab); } @Override public PEColumn lookupInProcessColumn(Name n) { return getScope().lookupInProcessColumn(n); } @Override public Table<?> getAlteredTable() { return getScope().getAlteredTable(); } @Override public void pushVirtualTable(SubqueryTable sqt, UnqualifiedName alias, SchemaContext sc) { getScope().pushVirtualTable(sqt, alias, sc); } @Override public void insertTable(TableInstance ti) { getScope().insertTable(ti); } @Override public TableInstance lookupTableInstance(SchemaContext sc, Name given, boolean required) { return getScope().lookupTableInstance(sc, given, required); } @Override public ListSet<NameInstance> getUnresolvedChildren() { return getScope().getUnresolvedChildren(); } }