package com.tesora.dve.sql.schema; /* * #%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.Serializable; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.tesora.dve.db.DBNative; import com.tesora.dve.variables.VariableService; import com.tesora.dve.sql.infoschema.InformationSchemaService; import org.antlr.runtime.TokenStream; import com.tesora.dve.common.MultiMap; import com.tesora.dve.common.PEConstants; import com.tesora.dve.common.catalog.CatalogDAO; import com.tesora.dve.common.catalog.CatalogEntity; import com.tesora.dve.common.catalog.IDynamicPolicy; import com.tesora.dve.common.catalog.Key; import com.tesora.dve.common.catalog.PersistentGroup; import com.tesora.dve.common.catalog.PersistentTemplate; import com.tesora.dve.common.catalog.Priviledge; import com.tesora.dve.common.catalog.Project; import com.tesora.dve.common.catalog.RawPlan; import com.tesora.dve.common.catalog.TableVisibility; import com.tesora.dve.common.catalog.User; import com.tesora.dve.common.catalog.UserDatabase; import com.tesora.dve.common.catalog.UserTable; import com.tesora.dve.db.NativeTypeCatalog; import com.tesora.dve.errmap.AvailableErrors; import com.tesora.dve.errmap.ErrorInfo; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.infomessage.ConnectionMessageManager; import com.tesora.dve.lockmanager.LockSpecification; import com.tesora.dve.lockmanager.LockType; import com.tesora.dve.server.connectionmanager.SSConnection; import com.tesora.dve.server.global.HostService; import com.tesora.dve.singleton.Singletons; import com.tesora.dve.sql.ParserException.Pass; import com.tesora.dve.sql.SchemaException; import com.tesora.dve.sql.parser.ParserOptions; import com.tesora.dve.sql.schema.PEAbstractTable.TableCacheKey; import com.tesora.dve.sql.schema.PETrigger.TriggerCacheKey; import com.tesora.dve.sql.schema.cache.CacheType; import com.tesora.dve.sql.schema.cache.SchemaCacheKey; import com.tesora.dve.sql.schema.cache.SchemaEdge; import com.tesora.dve.sql.schema.cache.SchemaSource; import com.tesora.dve.sql.schema.cache.SchemaSourceFactory; import com.tesora.dve.sql.schema.mt.IPETenant; import com.tesora.dve.sql.schema.mt.PETenant; import com.tesora.dve.sql.schema.mt.TableScope; import com.tesora.dve.sql.schema.mt.TableScope.ScopeCacheKey; import com.tesora.dve.sql.transform.behaviors.BehaviorConfiguration; import com.tesora.dve.sql.util.Functional; import com.tesora.dve.sql.util.ListSet; import com.tesora.dve.sql.util.UnaryFunction; import com.tesora.dve.variables.AbstractVariableAccessor; import com.tesora.dve.variables.GlobalVariableStore; import com.tesora.dve.variables.KnownVariables; import com.tesora.dve.variables.LocalVariableStore; import com.tesora.dve.variables.VariableStoreSource; import com.tesora.dve.variables.VariableValueStore; import com.tesora.dve.worker.agent.Agent; public class SchemaContext { public static ThreadLocal<SchemaContext> threadContext = new ThreadLocal<SchemaContext>(); public static void clearThreadContext() { threadContext.set(null); } public static void setThreadContext(SchemaContext sc) { threadContext.set(sc); } private SchemaSource schemaSource; private final IdentityHashMap<Persistable<?,?>, Serializable> backing; private final Map<SchemaCacheKey<?>, Persistable<?,?>> loading = new HashMap<SchemaCacheKey<?>, Persistable<?,?>>(); private final Set<SchemaCacheKey<?>> cacheLoading = new HashSet<SchemaCacheKey<?>>(); private final NativeTypeCatalog types; private final TemporaryTableSchema temporaryTableSchema = new TemporaryTableSchema(); private CatalogContext catalog; private PersistContext saveContext; private ParserOptions opts; private SchemaEdge<PEProject> defaultProject = null; private ConnectionContext connection = null; private final Capability capability; private boolean mutableSource; private Boolean mutableSourceOverride; private SchemaPolicyContext perms; private BehaviorConfiguration configuration; private long tableCounter; private long objectCounter = 0; private ValueManager valueManager; private ConnectionValues values; private final TransientSessionState tss; private TokenStream tokens; private String origStmt; private String description = null; private static ConnectionContext buildConnectionContext(SSConnection conn) { if (conn == null) return new NullConnectionContext(null); return new SSConnectionContext(conn); } public static SchemaContext createContext(SSConnection conn) { if (conn == null) throw new IllegalArgumentException("Wrong constructor for null connection"); ConnectionContext cc = buildConnectionContext(conn); return new SchemaContext(new DAOContext(cc),cc, Singletons.require(DBNative.class).getTypeCatalog(),Capability.FULL); } public static SchemaContext createContext(CatalogDAO dao, NativeTypeCatalog typeCatalog) { ConnectionContext cc = new NullConnectionContext(dao); return new SchemaContext(new DAOContext(cc),cc, typeCatalog,Capability.TRANSIENT); } public static SchemaContext createContext(SchemaContext other) { return createContext(other.getCatalog(), other.getConnection(),other.getTypes(),other.getCapability()); } public static SchemaContext createContext(CatalogContext cntxt, ConnectionContext conn, NativeTypeCatalog typeCatalog, Capability cap) { return new SchemaContext(cntxt, conn,typeCatalog, cap); } public static Database<?> loadDB(SchemaContext pc, UserDatabase db) { if (db == null) return null; Database<?> peds = Singletons.require(InformationSchemaService.class).buildPEDatabase(pc, db); if (peds == null) peds = PEDatabase.load(db, pc); return peds; } // used in alter support public static SchemaContext createContext(SSConnection conn, SchemaContext basedOn) { SchemaContext out = SchemaContext.createContext(conn); out.setOptions(basedOn.getOptions()); out.valueManager = basedOn.valueManager; out.setValues(basedOn.values); return out; } // used in container tenant support public static SchemaContext makeMutableIndependentContext(SchemaContext basedOn) { ConnectionContext cc = basedOn.getConnection().copy(); SchemaContext out = new SchemaContext(basedOn.getCatalog().copy(cc), cc, basedOn.getTypes(), basedOn.getCapability()); out.forceMutableSource(); return out; } // used in raw plan support public static SchemaContext makeImmutableIndependentContext(SchemaContext basedOn) { ConnectionContext cc = basedOn.getConnection().copy(); SchemaContext out = new SchemaContext(basedOn.getCatalog().copy(cc), basedOn.getConnection().copy(), basedOn.getTypes(), basedOn.getCapability()); return out; } @SuppressWarnings("unchecked") private SchemaContext(CatalogContext cat, ConnectionContext conn, NativeTypeCatalog typeCatalog, Capability cap) { // always start out unmutable mutableSource = false; connection = conn; catalog = cat; capability = cap; schemaSource = null; setSource(buildSource()); defaultProject = StructuralUtils.buildEdge(this, null, false); cat.setContext(this); conn.setSchemaContext(this); types = typeCatalog; backing = new IdentityHashMap<Persistable<?,?>, Serializable>(); saveContext = null; opts = null; tableCounter = 0; valueManager = new ValueManager(); setValues(null); perms = null; tss = new TransientSessionState(); } // a partial refresh - clear all expensive fields that won't be accessed later public void cleanupPostPlanning() { tokens = null; origStmt = null; } public Capability getCapability() { return capability; } public SchemaSource getSource() { return schemaSource; } public void setSource(SchemaSource ss) { schemaSource = ss; } private SchemaSource buildSource() { return (mutableSource ? SchemaSourceFactory.getMutableSource() : SchemaSourceFactory.getSource(connection, schemaSource)); } public void forceMutableSource() { if (schemaSource.getType() != CacheType.MUTABLE) { mutableSource = true; setSource(buildSource()); } } public void forceImmutableSource() { if (schemaSource.getType() == CacheType.MUTABLE) { mutableSource = false; setSource(buildSource()); } } public boolean isMutableSource() { if (mutableSourceOverride != null) return mutableSourceOverride.booleanValue(); return schemaSource.getType() == CacheType.MUTABLE; } public void setMutableSourceOverride(Boolean b) { mutableSourceOverride = b; } public Boolean getMutableSourceOverride() { return mutableSourceOverride; } public <T> SchemaEdge<T> buildEdgeFromKey(SchemaCacheKey<T> sck, boolean persistent) { if (!persistent) throw new SchemaException(Pass.SECOND, "Invalid use of buildEdge - using key based build edge on a transient edge"); return getSource().buildEdgeFromKey(sck); } public void refresh() { refresh(true); } public void refresh(boolean clearValues) { // refreshing always forces it unmutable mutableSource = false; setSource(buildSource()); loading.clear(); cacheLoading.clear(); if (catalog.isPersistent()) { backing.clear(); } tableCounter = 0; if (clearValues) { valueManager = new ValueManager(); setValues(null); } perms = null; } public long getNextTable() { return (++tableCounter); } public long getNextObjectID() { return (++objectCounter); } public ParserOptions getOptions() { return opts; } public String describeContext() { if (description == null) { StringBuilder buf = new StringBuilder(); if (connection != null) { buf.append(connection.getName()); SchemaEdge<?> edge = connection.getCurrentDatabase(); Database<?> cdb = (edge == null ? null : connection.getCurrentDatabase().get(this)); IPETenant ct = getCurrentTenant().get(this); if (cdb != null) buf.append("/").append(cdb.getName()); if (ct != null) buf.append("/").append(ct.getUniqueIdentifier()); } description = buf.toString(); } return description; } public void setOptions(ParserOptions po) { opts = po; } public void setTokenStream(TokenStream tns, String sql) { if (tns == null) throw new SchemaException(Pass.FIRST, "Parser missing tokens"); tokens = tns; origStmt = sql; } public void clearOrigStmt() { origStmt = null; } public TokenStream getTokens() { return tokens; } public String getOrigStmt() { return origStmt; } public void setParameters(List<Object> params) { valueManager = new ValueManager(this,params); } public ValueManager getValueManager() { return valueManager; } public void setValueManager(ValueManager vm) { valueManager = vm; } public ConnectionValues getValues() { return values; } public void setValues(ConnectionValues cv) { values = cv; } public TransientSessionState getIntraStmtState() { return tss; } public BehaviorConfiguration getBehaviorConfiguration() { return configuration; } public Database<?> getCurrentDatabase(boolean mustExist, boolean domtchecks) { if ((connection.getCurrentDatabase() == null || connection.getCurrentDatabase().get(this) == null) && mustExist) throw new SchemaException(new ErrorInfo(AvailableErrors.NO_DATABASE_SELECTED)); if (connection.getCurrentDatabase() == null) return null; if (!domtchecks) return connection.getCurrentDatabase().get(this); return getPolicyContext().getCurrentDatabase(connection.getCurrentDatabase().get(this), mustExist); } public Database<?> getCurrentDatabase(boolean mustExist) { return getCurrentDatabase(mustExist,true); } public PEDatabase getCurrentPEDatabase(boolean mustExist) { return (PEDatabase)getCurrentDatabase(mustExist); } public boolean hasCurrentDatabase() { return connection.getCurrentDatabase() != null && connection.getCurrentDatabase().get(this) != null; } public Database<?> getCurrentDatabase() { return getCurrentDatabase(true); } public PEDatabase getCurrentPEDatabase() { return getCurrentPEDatabase(true); } public void setCurrentDatabase(Database<?> db) { connection.setCurrentDatabase(db); } public ConnectionContext getConnection() { return connection; } public SchemaEdge<PEUser> getCurrentUser() { return getConnection().getUser(); } public SchemaEdge<IPETenant> getCurrentTenant() { return getConnection().getCurrentTenant(); } public void invalidateCurrentTenant() { getConnection().setCurrentTenant(null); } public SchemaPolicyContext getPolicyContext() { if (perms == null) perms = SchemaPolicyContext.buildContext(this); return perms; } public void clearPolicyContext() { perms = null; } public TemporaryTableSchema getTemporaryTableSchema() { return temporaryTableSchema; } public PEPersistentGroup getPersistentGroup() { Database<?> db = getCurrentDatabase(false); if (db instanceof PEDatabase) { PEDatabase peds = (PEDatabase) db; if (peds != null) return peds.getDefaultStorage(this); } String currentDefault = KnownVariables.PERSISTENT_GROUP.getGlobalValue(getConnection().getVariableSource()); if (currentDefault == null) return null; return findStorageGroup(new UnqualifiedName(currentDefault)); } public PEPersistentGroup getSessionStatementStorageGroup() throws PEException { PEPersistentGroup pesg = getPersistentGroup(); if (pesg != null && !pesg.getSites(this).isEmpty()) return pesg.anySite(this); List<PersistentGroup> groups = catalog.findAllGroups(); if (groups.isEmpty()) return null; // make sure we choose a group that has at least one site in it ListSet<PersistentGroup> choices = new ListSet<PersistentGroup>(); choices.addAll(groups); PersistentGroup choice = null; while(choice == null) { if (choices.isEmpty()) return null; choice = choices.remove(Agent.getRandom(choices.size())); if (choice.getStorageSites().isEmpty()) choice = null; } pesg = PEPersistentGroup.load(choice, this); return pesg.anySite(this); } @SuppressWarnings("unchecked") public PEProject getDefaultProject() { if (!defaultProject.has()) { defaultProject = StructuralUtils.buildEdge(this, schemaSource.find(this,PEProject.getProjectKey(Singletons.require(HostService.class).getDefaultProjectName())),true); } return defaultProject.get(this); } public void setDefaultDatabase(Database<?> db) { getConnection().setCurrentDatabase(db); } @SuppressWarnings("unchecked") public void setDefaultProject(PEProject pep) { defaultProject = StructuralUtils.buildEdge(this,pep,false); } public boolean isPersistent() { return catalog.isPersistent(); } public PersistContext beginSaveContext() { return beginSaveContext(false); } public PersistContext beginSaveContext(boolean forceNew) { if (forceNew || saveContext == null) saveContext = new PersistContext(); saveContext.incrementRefCount(); return saveContext; } public PersistContext getSaveContext() { return saveContext; } public void endSaveContext() { if (saveContext == null) return; if (saveContext.decrementRefCount()) saveContext = null; } public Persistable<?,?> getLoaded(CatalogEntity cat, SchemaCacheKey<?> sck) { Persistable<?,?> candidate = loading.get(sck); if (candidate != null) return candidate; return (Persistable<?,?>) schemaSource.getLoaded(sck); } public void startLoading(Persistable<?,?> p, CatalogEntity ce) { SchemaCacheKey<?> sck = p.getCacheKey(); if (sck != null) loading.put(sck,p); } public void finishedLoading(Persistable<?,?> p, CatalogEntity cat) { SchemaCacheKey<?> sck = p.getCacheKey(); if (sck != null) loading.remove(sck); schemaSource.setLoaded(p, (cacheLoading.contains(sck) ? null : sck)); } public void addCacheLoading(SchemaCacheKey<?> sck) { cacheLoading.add(sck); } public void removeCacheLoading(SchemaCacheKey<?> sck) { cacheLoading.remove(sck); } public boolean isCacheLoading(SchemaCacheKey<?> sck) { return cacheLoading.contains(sck); } public void clearLoaded(SchemaCacheKey<?> sck) { schemaSource.setLoaded(null, sck); } public Serializable getBacking(Persistable<?,?> p) { return backing.get(p); } public void setBacking(Persistable<?,?> p, Serializable s) { backing.put(p,s); } public NativeTypeCatalog getTypes() { return types; } public CatalogContext getCatalog() { return catalog; } public void persist(Object o) { catalog.persistToCatalog(o); } public IDynamicPolicy getGroupPolicy() { // q: should this be the global or the session value? String defName = KnownVariables.DYNAMIC_POLICY.getValue(getConnection().getVariableSource(),VariableScopeKind.SESSION); if (defName == null) return null; return (IDynamicPolicy)schemaSource.find(this, PEPolicy.getPolicyKey(defName)); } public PEProject findProject(Name n) { String persistentName = n.getUnqualified().get(); Project proj = catalog.findProject(persistentName); if (proj == null) return null; return PEProject.load(proj, this); } public RangeDistribution findRange(Name rangeName, Name groupName) { return schemaSource.find(this, RangeDistribution.buildRangeKey(rangeName, groupName)); } public PEPersistentGroup findStorageGroup(Name n) { return schemaSource.find(this, PEPersistentGroup.getGroupKey(n)); } public PEStorageSite findStorageSite(Name n) { return schemaSource.find(this, PEStorageSite.getSiteKey(n)); } public PETemplate findTemplate(Name n) { return schemaSource.find(this, PETemplate.getTemplateKey(n.getUnqualified())); } public PERawPlan findRawPlan(Name n) { return schemaSource.find(this, PERawPlan.getRawPlanKey(n.getUnqualified())); } public List<PERawPlan> findEnabledRawPlans() { List<RawPlan> rps = catalog.findAllEnabledRawPlans(); final SchemaContext sc = this; return Functional.apply(rps, new UnaryFunction<PERawPlan,RawPlan>() { @Override public PERawPlan evaluate(RawPlan object) { return PERawPlan.load(object, sc); } }); } public PEDatabase findSingleMTDatabase() { List<UserDatabase> mtdbs = catalog.findAllMTDatabases(); if (mtdbs.isEmpty()) return null; if (mtdbs.size() > 1) throw new SchemaException(Pass.SECOND, "More than one mt database found"); return (PEDatabase) loadDB(this,mtdbs.get(0)); } public List<Database<?>> findDatabases() { List<UserDatabase> uds = catalog.findAllUserDatabases(); final SchemaContext sc = this; return Functional.apply(uds, new UnaryFunction<Database<?>, UserDatabase>() { @Override public Database<?> evaluate(UserDatabase object) { return loadDB(sc,object); } }); } public PEDatabase getAnyNonSchemaDatabase() { final List<UserDatabase> udbs = this.catalog.findAllUserDatabases(); for (final UserDatabase udb : udbs) { if (!udb.getName().equalsIgnoreCase(PEConstants.INFORMATION_SCHEMA_DBNAME)) { return PEDatabase.load(udb, this); } } return null; } public PEPersistentGroup findBalancedPersistentGroup(String prefix) { PersistentGroup uds = catalog.findBalancedPersistentGroup(prefix); return uds != null ? PEPersistentGroup.load(uds, this) : null; } public PESiteInstance findSiteInstance(Name n) { return schemaSource.find(this, PESiteInstance.getSiteInstanceKey(n)); } public Database<?> findDatabase(Name n) { return schemaSource.find(this, PEDatabase.getDatabaseKey(n)); } // used in tests public Database<?> findDatabase(String n) { return findDatabase(new UnqualifiedName(n)); } public PEUser findUser(String name, String accessSpec) { return schemaSource.find(this, PEUser.getUserKey(name, accessSpec)); } public PETenant findTenant(Name tenantName) { return schemaSource.find(this, PETenant.getTenantKey(tenantName)); } public PEPriviledge findPrivilege(PEUser user, Name onName) { return schemaSource.find(this, PEPriviledge.getPriviledgeKey(user, onName)); } public PEDatabase findPEDatabase(Name n) { return (PEDatabase)schemaSource.find(this, PEDatabase.getDatabaseKey(n)); } public PEContainer findContainer(Name n) { return (PEContainer)schemaSource.find(this, PEContainer.getContainerKey(n)); } public PEContainerTenant findContainerTenant(PEContainer cont, String disc) { return (PEContainerTenant)schemaSource.find(this, PEContainerTenant.getContainerTenantKey(cont, disc)); } public PEAbstractTable<?> findTable(TableCacheKey tck) { return schemaSource.find(this, tck); } public TableScope findScope(ScopeCacheKey sck) { return schemaSource.find(this, sck); } public PETrigger findTrigger(TriggerCacheKey tck) { return schemaSource.find(this,tck); } public ListSet<TableScope> findScopesReferencing(PETable pet) { List<TableVisibility> matching = catalog.findTenantsOf(pet.getPersistent(this)); ListSet<TableScope> out = new ListSet<TableScope>(); for(TableVisibility tv : matching) out.add(TableScope.load(tv, this)); return out; } public List<String> findTenantTableNames(PETenant onTenant) { return catalog.findTenantTableNames(onTenant.getPersistent(this)); } public List<PETable> findTablesWithUnresolvedFKSTargeting(UnqualifiedName dbName, UnqualifiedName tableName) { List<UserTable> unresolved = catalog.findTablesWithUnresolvedFKsTargeting(dbName.getUnquotedName().get(), tableName.getUnquotedName().get()); final SchemaContext me = this; return Functional.apply(unresolved, new UnaryFunction<PETable,UserTable>() { @Override public PETable evaluate(UserTable object) { return PETable.load(object, me).asTable(); } }); } public MultiMap<PETable,PEForeignKey> findFKSReferencing(PETable pet) { List<UserTable> containingTables = catalog.findTablesWithFKSReferencing(pet.getPersistentID()); MultiMap<PETable, PEForeignKey> out = new MultiMap<PETable, PEForeignKey>(); for(UserTable ut : containingTables) { PETable opet = PETable.load(ut, this).asTable(); for(PEForeignKey pefk : opet.getForeignKeys(this)) { if (pefk.getTargetTable(this) == pet) out.put(opet,pefk); } } return out; } // give me the scopes in the given tenant whose backing tables have forward foreign keys pointing to dbName.tableName public List<TableScope> findScopesWithUnresolvedFKsTargeting(UnqualifiedName dbName, UnqualifiedName tableName, PETenant onTenant) { List<TableVisibility> unresolved = catalog.findScopesWithUnresolvedFKsTargeting(dbName.getUnquotedName().get(), tableName.getUnquotedName().get(), onTenant.getPersistentID()); return loadScopes(unresolved); } // give me the scopes in the given tenant which represent the target tables of nonforward foreign keys of the given backing table. public List<TableScope> findScopesForFKTargets(PETable table, PETenant onTenant) { List<TableVisibility> refs = catalog.findScopesForFKTargets(table.getPersistentID(), onTenant.getPersistentID()); return loadScopes(refs); } // give me the scopes in the given tenant which represent the backing tables that refer to the given backing table. // (inverse of previous). public List<TableScope> findScopesForFKRefs(PETable backingTable, PETenant onTenant) { List<TableVisibility> refs = catalog.findScopesWithFKsReferencing(backingTable.getPersistentID(), onTenant.getPersistentID()); return loadScopes(refs); } private List<TableScope> loadScopes(List<TableVisibility> in) { final SchemaContext me = this; return Functional.apply(in, new UnaryFunction<TableScope,TableVisibility>() { @Override public TableScope evaluate(TableVisibility object) { return TableScope.load(object, me); } }); } public PEKey findForeignKey(Database<?> db, Integer tenantID, String name, String constraintName) throws PEException { Database<?> udb = db; if (db == null) { udb = getCurrentDatabase(false); if (udb == null) { return null; } } Key key = catalog.findForeignKey(udb.getPersistent(this), tenantID, name, constraintName); if (key == null) { return null; } PEKey peKey = PEKey.load(key, this, PEAbstractTable.load(key.getTable(), this).asTable()); return peKey; } public Collection<PEProvider> findAllProviders() { return PEProvider.AllProvidersCacheKey.get(this); } public Collection<PEStorageSite> findAllPersistentSites() { return PEStorageSite.AllPersistentSitesCacheKey.get(this); } public Collection<PEPersistentGroup> findAllPersistentGroups() { return PEPersistentGroup.AllPersistentGroupsCacheKey.get(this); } public MultiMap<PEUser,PEPriviledge> findUsersForGenAdd() { List<User> users = catalog.findAllUsers(); MultiMap<PEUser,PEPriviledge> out = new MultiMap<PEUser,PEPriviledge>(); for(User u : users) { PEUser peu = PEUser.load(u, this); for(Priviledge p : u.getPriviledges()) { out.put(peu,PEPriviledge.load(p, this)); } } return out; } public List<PETemplate> findMatchTemplates() { List<PersistentTemplate> any = catalog.findMatchTemplates(); final SchemaContext me = this; return Functional.apply(any, new UnaryFunction<PETemplate, PersistentTemplate>() { @Override public PETemplate evaluate(PersistentTemplate object) { return PETemplate.load(object, me); } }); } public List<PEAbstractTable<?>> findTablesOnGroup(String groupName) { List<UserTable> tabs = catalog.findTablesOnGroup(groupName); final SchemaContext me = this; return Functional.apply(tabs, new UnaryFunction<PEAbstractTable<?>,UserTable>() { @Override public PEAbstractTable<?> evaluate(UserTable object) { return PEAbstractTable.load(object, me); } }); } // catalog object collector, created for ddl purposes public static class PersistContext { private final Map<Persistable<?,?>, CatalogEntity> assoc; // ordering is important private final LinkedHashSet<CatalogEntity> objects; //NOPMD // keep track of how many refs there are to the persist context, and when the refs fall to 0 // make sure we free it from the enclosing schema context private int refcount; public PersistContext() { this.assoc = new HashMap<Persistable<?,?>, CatalogEntity>(); this.objects = new LinkedHashSet<CatalogEntity>(); this.refcount = 0; } protected void incrementRefCount() { refcount++; } protected boolean decrementRefCount() { return (--refcount <= 0); } public void add(Persistable<?,?> from, CatalogEntity o) { assoc.put(from, o); objects.add(o); } public LinkedHashSet<CatalogEntity> getObjects() { //NOPMD return objects; } public Map<Persistable<?,?>, CatalogEntity> getAssociation() { return assoc; } } // for dist key mapping public enum DistKeyOpType { QUERY, SELECT_FOR_UPDATE, UPDATE, INSERT; } // used when we don't have a connection, either transient impl or SSCon private static class NullConnectionContext implements ConnectionContext, VariableStoreSource { private SchemaContext sc = null; private SchemaEdge<PEUser> root = null; private SchemaEdge<IPETenant> currentTenant = null; private SchemaEdge<Database<?>> db = null; private final CatalogDAO dao; private LocalVariableStore sessionVariables; private GlobalVariableStore globalVariables = new TransientGlobalVariableStore(); private VariableValueStore userVariables = new VariableValueStore("User",true); public NullConnectionContext(CatalogDAO c) { dao = c; Singletons.require(VariableService.class).getVariableManager().initialiseTransient(globalVariables); sessionVariables = globalVariables.buildNewLocalStore(); } @SuppressWarnings("unchecked") @Override public SchemaEdge<IPETenant> getCurrentTenant() { if (currentTenant == null) currentTenant = StructuralUtils.buildEdge(sc,(PETenant)null,true); return currentTenant; } @Override public boolean allowTenantColumnDecls() { return false; } @Override public void setSchemaContext(SchemaContext sc) { this.sc = sc; } @SuppressWarnings("unchecked") @Override public void setCurrentTenant(IPETenant ten) { currentTenant = StructuralUtils.buildEdge(sc, ten, true); } @Override public String getVariableValue(AbstractVariableAccessor va) throws PEException { return null; } @Override public List<List<String>> getVariables(VariableScope vs) throws PEException { return null; } @SuppressWarnings("unchecked") @Override public SchemaEdge<PEUser> getUser() { if (root == null) { PEUser target = null; if (sc.getCatalog().isPersistent()) target = PEUser.load(sc.getCatalog().findUsers(PEConstants.ROOT, null).get(0), sc); else target = new PEUser(sc); root = StructuralUtils.buildEdge(sc,target, sc.getCatalog().isPersistent()); } return root; } @Override public SchemaEdge<Database<?>> getCurrentDatabase() { return db; } @Override public String getName() { return "NullConnectionContext"; } @Override public void acquireLock(LockSpecification ls, LockType type) { } @Override public boolean isInTxn() { return false; } @Override public ConnectionContext copy() { return new NullConnectionContext(dao); } @Override public boolean hasFilter() { return false; } @Override public boolean isFilteredTable(Name table) { return false; } @Override public boolean originatedFromReplicationSlave() { return false; } @Override public String getCacheName() { return null; } @Override public int getConnectionId() { return 0; } @Override public ConnectionMessageManager getMessageManager() { return new ConnectionMessageManager(); } @Override public long getLastInsertedId() { return -1; } @SuppressWarnings("unchecked") @Override public void setCurrentDatabase(Database<?> db) { this.db = StructuralUtils.buildEdge(sc, db, true); } @Override public CatalogDAO getDAO() { return dao; } @Override public boolean isInXATxn() { return false; } @Override public VariableStoreSource getVariableSource() { return this; } @Override public LocalVariableStore getSessionVariableStore() { return sessionVariables; } @Override public GlobalVariableStore getGlobalVariableStore() { return globalVariables; } @Override public VariableValueStore getUserVariableStore() { return userVariables; } } }