/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.query.metadata; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import org.teiid.core.types.DataTypeManagerService; import org.teiid.core.util.StringUtil; import org.teiid.designer.query.metadata.IQueryMetadataInterface; import org.teiid.designer.query.metadata.IQueryNode; import org.teiid.designer.xml.IMappingNode; import org.teiid.metadata.Column; import org.teiid.metadata.Procedure; import org.teiid.metadata.Table; import org.teiid.query.mapping.relational.QueryNode; import org.teiid.query.metadata.TempMetadataID.Type; import org.teiid.query.sql.symbol.Expression; import org.teiid.runtime.client.Messages; import org.teiid.runtime.client.TeiidClientException; /** * <p>This is an adapter class, it contains another instance of * IQueryMetadataInterface as well as a TempMetadataStore. It defers to * either one of these when appropriate.</p> * * <p>When a metadataID Object is requested for a group or element name, this * will first check the IQueryMetadataInterface. If an ID wasn't found there, * it will then check the TempMetadataStore.</p> * * <p>For methods that take a metadataID arg, this class may check whether it * is a TempMetadataID or not and react accordingly.</p> */ public class TempMetadataAdapter extends BasicQueryMetadataWrapper { private static final String SEPARATOR = "."; //$NON-NLS-1$ /** * Temp model object id */ public static final TempMetadataID TEMP_MODEL = new TempMetadataID("__TEMP__", Collections.EMPTY_LIST); //$NON-NLS-1$ private TempMetadataStore tempStore; private Map<Object, Object> materializationTables; private Map<Object, QueryNode> queryNodes; private boolean session; /** * @param metadata * @param tempStore */ public TempMetadataAdapter(IQueryMetadataInterface metadata, TempMetadataStore tempStore) { super(metadata); this.tempStore = tempStore; } /** * @param metadata * @param tempStore * @param materializationTables * @param queryNodes */ public TempMetadataAdapter(IQueryMetadataInterface metadata, TempMetadataStore tempStore, Map<Object, Object> materializationTables, Map<Object, QueryNode> queryNodes) { super(metadata); this.tempStore = tempStore; this.materializationTables = materializationTables; this.queryNodes = queryNodes; } /** * @return session */ public boolean isSession() { return session; } /** * @param session */ public void setSession(boolean session) { this.session = session; } @Override public IQueryMetadataInterface getSessionMetadata() { if (isSession()) { TempMetadataAdapter tma = new TempMetadataAdapter(new BasicQueryMetadata(getTeiidVersion()), this.tempStore); tma.session = true; return tma; } return this.actualMetadata.getSessionMetadata(); } @Override protected IQueryMetadataInterface createDesignTimeMetadata() { if (isSession()) { return new TempMetadataAdapter(this.actualMetadata.getDesignTimeMetadata(), new TempMetadataStore()); } return new TempMetadataAdapter(this.actualMetadata.getDesignTimeMetadata(), tempStore, materializationTables, queryNodes); } /** * @return temp metadata store */ public TempMetadataStore getMetadataStore() { return this.tempStore; } /** * @return metadata underlying adapter */ public IQueryMetadataInterface getMetadata() { return this.actualMetadata; } /** * Check metadata first, then check temp groups if not found */ @Override public Object getElementID(String elementName) throws Exception { Object tempID = null; try { tempID = this.actualMetadata.getElementID(elementName); } catch (Exception e) { //ignore } if (tempID == null){ tempID = this.tempStore.getTempElementID(elementName); } if(tempID != null) { return tempID; } throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID30350, elementName)); } /** * Check metadata first, then check temp groups if not found */ @Override public Object getGroupID(String groupName) throws Exception { Object tempID = null; try { tempID = this.actualMetadata.getGroupID(groupName); } catch (Exception e) { //ignore } if (tempID == null){ tempID = this.tempStore.getTempGroupID(groupName); } if(tempID != null) { return tempID; } throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID30351, groupName)); } @Override public Collection getGroupsForPartialName(String partialGroupName) throws Exception { Collection groups = super.getGroupsForPartialName(partialGroupName); List<String> allGroups = new ArrayList<String>(groups); for (Map.Entry<String, TempMetadataID> entry : tempStore.getData().entrySet()) { String name = entry.getKey(); if (StringUtil.endsWithIgnoreCase(name, partialGroupName) //don't want to match tables by anything less than the full name, //since this should be a temp or a global temp and in the latter case there's a real metadata entry //alternatively we could check to see if the name is already in the result list && (name.length() == partialGroupName.length() || (entry.getValue().getMetadataType() != Type.TEMP && name.length() > partialGroupName.length() && name.charAt(name.length() - partialGroupName.length() - 1) == '.'))) { allGroups.add(name); } } return allGroups; } @Override public Object getModelID(Object groupOrElementID) throws Exception { groupOrElementID = getActualMetadataId(groupOrElementID); if(groupOrElementID instanceof TempMetadataID) { TempMetadataID tid = (TempMetadataID)groupOrElementID; Object oid = tid.getOriginalMetadataID(); if (oid instanceof Procedure) { return actualMetadata.getModelID(oid); } return TempMetadataAdapter.TEMP_MODEL; } //special handling for global temp tables Object id = groupOrElementID; if (groupOrElementID instanceof Column) { id = ((Column)id).getParent(); } if (id instanceof Table) { Table t = (Table)id; if (t.getTableType() == Table.Type.TemporaryTable && t.isVirtual()) { return TempMetadataAdapter.TEMP_MODEL; } } return this.actualMetadata.getModelID(groupOrElementID); } // SPECIAL: Override for temp groups @Override public String getFullName(Object metadataID) throws Exception { if(metadataID instanceof TempMetadataID) { return ((TempMetadataID)metadataID).getID(); } return this.actualMetadata.getFullName(metadataID); } @Override public String getName(Object metadataID) throws Exception { if(metadataID instanceof TempMetadataID) { TempMetadataID tid = (TempMetadataID)metadataID; return tid.getName(); } return this.actualMetadata.getName(metadataID); } // SPECIAL: Override for temp groups @Override public List getElementIDsInGroupID(Object groupID) throws Exception { groupID = getActualMetadataId(groupID); if(groupID instanceof TempMetadataID) { return new ArrayList<Object>(((TempMetadataID)groupID).getElements()); } return this.actualMetadata.getElementIDsInGroupID(groupID); } // SPECIAL: Override for temp groups @Override public Object getGroupIDForElementID(Object elementID) throws Exception { if(elementID instanceof TempMetadataID) { String elementName = ((TempMetadataID)elementID).getID(); String groupName = elementName.substring(0, elementName.lastIndexOf(SEPARATOR)); return this.tempStore.getTempGroupID(groupName); } return this.actualMetadata.getGroupIDForElementID(elementID); } // SPECIAL: Override for temp groups @Override public String getElementType(Object elementID) throws Exception { if(elementID instanceof TempMetadataID) { TempMetadataID tempID = (TempMetadataID)elementID; if (tempID.getType() != null) { return DataTypeManagerService.getInstance(getTeiidVersion()).getDataTypeName( tempID.getType() ); } throw new AssertionError("No type set for element " + elementID); //$NON-NLS-1$ } return this.actualMetadata.getElementType(elementID); } @Override public String getDefaultValue(Object elementID) throws Exception { if(elementID instanceof TempMetadataID) { return null; } return this.actualMetadata.getDefaultValue(elementID); } @Override public Object getMaximumValue(Object elementID) throws Exception { if (elementID instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)elementID; elementID = id.getOriginalMetadataID(); if (elementID == null) { return null; } } return this.actualMetadata.getMaximumValue(elementID); } @Override public Object getMinimumValue(Object elementID) throws Exception { if (elementID instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)elementID; elementID = id.getOriginalMetadataID(); if (elementID == null) { return null; } } return this.actualMetadata.getMinimumValue(elementID); } /** * @see IQueryMetadataInterface#getDistinctValues(java.lang.Object) */ @Override public float getDistinctValues(Object elementID) throws Exception { if(elementID instanceof TempMetadataID) { return -1; } return this.actualMetadata.getDistinctValues(elementID); } /** * @see IQueryMetadataInterface#getNullValues(java.lang.Object) */ @Override public float getNullValues(Object elementID) throws Exception { if (elementID instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)elementID; elementID = id.getOriginalMetadataID(); if (elementID == null) { return -1; } } return this.actualMetadata.getNullValues(elementID); } @Override public IQueryNode getVirtualPlan(Object groupID) throws Exception { if (this.queryNodes != null) { QueryNode node = this.queryNodes.get(groupID); if (node != null) { return node; } } if(groupID instanceof TempMetadataID && !(actualMetadata instanceof TempMetadataAdapter)) { return ((TempMetadataID)groupID).getQueryNode(); } return this.actualMetadata.getVirtualPlan(groupID); } // SPECIAL: Override for temp groups @Override public boolean isVirtualGroup(Object groupID) throws Exception { if(groupID instanceof TempMetadataID) { return ((TempMetadataID)groupID).isVirtual(); } return this.actualMetadata.isVirtualGroup(groupID); } /** * @see IQueryMetadataInterface#hasMaterialization(java.lang.Object) * @since 4.2 */ @Override public boolean hasMaterialization(Object groupID) throws Exception { // check if any dynamic materialization tables are defined if (this.materializationTables != null && this.materializationTables.containsKey(groupID)) { return true; } if(groupID instanceof TempMetadataID && !(actualMetadata instanceof TempMetadataAdapter)) { return false; } return this.actualMetadata.hasMaterialization(groupID); } /** * @see IQueryMetadataInterface#getMaterialization(java.lang.Object) * @since 4.2 */ @Override public Object getMaterialization(Object groupID) throws Exception { // check if any dynamic materialization tables are defined if (this.materializationTables != null) { Object result = this.materializationTables.get(groupID); if (result != null) { return result; } } if(groupID instanceof TempMetadataID && !(actualMetadata instanceof TempMetadataAdapter)) { return null; } return this.actualMetadata.getMaterialization(groupID); } /** * @see IQueryMetadataInterface#getMaterializationStage(java.lang.Object) * @since 4.2 */ @Override public Object getMaterializationStage(Object groupID) throws Exception { if(groupID instanceof TempMetadataID) { return null; } // we do not care about the dynamic materialization tables here as they are loaded dynamically. return this.actualMetadata.getMaterializationStage(groupID); } @Override public boolean isVirtualModel(Object modelID) throws Exception { if(modelID.equals(TEMP_MODEL)) { return false; } return this.actualMetadata.isVirtualModel(modelID); } // --------------------- Implement OptimizerMetadata ------------------- @Override public boolean elementSupports(Object elementID, int supportConstant) throws Exception { if (elementID instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)elementID; switch(supportConstant) { case SupportConstants.Element.SEARCHABLE_LIKE: return true; case SupportConstants.Element.SEARCHABLE_COMPARE:return true; case SupportConstants.Element.SEARCHABLE_EQUALITY:return true; case SupportConstants.Element.SELECT: return true; case SupportConstants.Element.NULL: { if (id.isNotNull()) { return false; } if (id.isTempTable()) { return true; } break; } case SupportConstants.Element.AUTO_INCREMENT: return id.isAutoIncrement(); case SupportConstants.Element.UPDATE: return id.isTempTable() || id.isUpdatable(); } // If this is a temp table column or real metadata is unknown, return hard-coded values elementID = id.getOriginalMetadataID(); if(elementID == null || id.isTempTable()) { switch(supportConstant) { case SupportConstants.Element.NULL: return true; case SupportConstants.Element.SIGNED: return true; } return false; } } return this.actualMetadata.elementSupports(elementID, supportConstant); } /** * @see IQueryMetadataInterface#getIndexesInGroup(java.lang.Object) */ @Override public Collection getIndexesInGroup(Object groupID) throws Exception { groupID = getActualMetadataId(groupID); if(groupID instanceof TempMetadataID) { List<TempMetadataID> result = ((TempMetadataID)groupID).getIndexes(); if (result == null) { return Collections.emptyList(); } return result; } return this.actualMetadata.getIndexesInGroup(groupID); } @Override public Collection getUniqueKeysInGroup(Object groupID) throws Exception { groupID = getActualMetadataId(groupID); if(groupID instanceof TempMetadataID) { LinkedList<List<TempMetadataID>> result = new LinkedList<List<TempMetadataID>>(); TempMetadataID id = (TempMetadataID)groupID; if (id.getPrimaryKey() != null) { result.add(id.getPrimaryKey()); } if (id.getUniqueKeys() != null) { result.addAll(id.getUniqueKeys()); } return result; } return this.actualMetadata.getUniqueKeysInGroup(groupID); } @Override public Collection getForeignKeysInGroup(Object groupID) throws Exception { groupID = getActualMetadataId(groupID); if(groupID instanceof TempMetadataID) { return Collections.EMPTY_LIST; } return this.actualMetadata.getForeignKeysInGroup(groupID); } /** * @see IQueryMetadataInterface#getElementIDsInIndex(java.lang.Object) */ @Override public List getElementIDsInIndex(Object index) throws Exception { return this.actualMetadata.getElementIDsInIndex(index); } @Override public List getElementIDsInKey(Object keyID) throws Exception { if (keyID instanceof List) { return (List)keyID; } if (keyID instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)keyID; if (id.getMetadataType() == Type.INDEX) { return id.getElements(); } } return this.actualMetadata.getElementIDsInKey(keyID); } @Override public boolean groupSupports(Object groupID, int groupConstant) throws Exception { groupID = getActualMetadataId(groupID); if(groupID instanceof TempMetadataID){ return true; } return this.actualMetadata.groupSupports(groupID, groupConstant); } @Override public IMappingNode getMappingNode(Object groupID) throws Exception { return this.actualMetadata.getMappingNode(groupID); } @Override public boolean isXMLGroup(Object groupID) throws Exception { if(groupID instanceof TempMetadataID) { return ((TempMetadataID)groupID).getMetadataType() == Type.XML; } return this.actualMetadata.isXMLGroup(groupID); } /** * @see IQueryMetadataInterface#getVirtualDatabaseName() */ @Override public String getVirtualDatabaseName() throws Exception { return this.actualMetadata.getVirtualDatabaseName(); } /** * @see IQueryMetadataInterface#getAccessPatternsInGroup(Object) */ @Override public Collection getAccessPatternsInGroup(Object groupID) throws Exception { groupID = getActualMetadataId(groupID); if(groupID instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)groupID; return id.getAccessPatterns(); } return this.actualMetadata.getAccessPatternsInGroup(groupID); } /** * @see IQueryMetadataInterface#getElementIDsInAccessPattern(Object) */ @Override public List getElementIDsInAccessPattern(Object accessPattern) throws Exception { if (accessPattern instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)accessPattern; if (id.getElements() != null) { return id.getElements(); } return Collections.EMPTY_LIST; } return this.actualMetadata.getElementIDsInAccessPattern(accessPattern); } @Override public Collection getXMLTempGroups(Object groupID) throws Exception{ if(groupID instanceof TempMetadataID) { return Collections.EMPTY_SET; } return this.actualMetadata.getXMLTempGroups(groupID); } @Override public float getCardinality(Object groupID) throws Exception{ groupID = getActualMetadataId(groupID); if(groupID instanceof TempMetadataID) { return ((TempMetadataID)groupID).getCardinality(); } if (this.isSession() && groupID instanceof Table) { Table t = (Table)groupID; if (t.getTableType() == Table.Type.TemporaryTable && t.isVirtual()) { TempMetadataID id = this.tempStore.getTempGroupID(t.getName()); if (id != null) { return id.getCardinality(); } } } return this.actualMetadata.getCardinality(groupID); } @Override public List getXMLSchemas(Object groupID) throws Exception { if(groupID instanceof TempMetadataID) { return Collections.EMPTY_LIST; } return this.actualMetadata.getXMLSchemas(groupID); } @Override public Properties getExtensionProperties(Object metadataID) throws Exception { metadataID = getActualMetadataId(metadataID); if (metadataID instanceof TempMetadataID) { return IQueryMetadataInterface.EMPTY_PROPS; } return actualMetadata.getExtensionProperties(metadataID); } @Override public int getElementLength(Object elementID) throws Exception { if (elementID instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)elementID; Object origElementID = id.getOriginalMetadataID(); if (origElementID == null) { String type = getElementType(elementID); if(DataTypeManagerService.DefaultDataTypes.STRING.getId().equals(type)) { return 255; } return 10; } elementID = origElementID; } return actualMetadata.getElementLength(elementID); } @Override public int getPosition(Object elementID) throws Exception { if (elementID instanceof TempMetadataID) { return ((TempMetadataID)elementID).getPosition(); } return actualMetadata.getPosition(elementID); } @Override public int getPrecision(Object elementID) throws Exception { if (elementID instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)elementID; elementID = id.getOriginalMetadataID(); if (elementID == null) { return 0; } } return actualMetadata.getPrecision(elementID); } @Override public int getRadix(Object elementID) throws Exception { if (elementID instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)elementID; elementID = id.getOriginalMetadataID(); if (elementID == null) { return 0; } } return actualMetadata.getRadix(elementID); } @Override public int getScale(Object elementID) throws Exception { if (elementID instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)elementID; elementID = id.getOriginalMetadataID(); if (elementID == null) { return 0; } } return actualMetadata.getScale(elementID); } /** * Get the native type name for the element. * @since 4.2 */ @Override public String getNativeType(Object elementID) throws Exception { if (elementID instanceof TempMetadataID) { TempMetadataID id = (TempMetadataID)elementID; elementID = id.getOriginalMetadataID(); if (elementID == null) { return ""; //$NON-NLS-1$ } } return actualMetadata.getNativeType(elementID); } @Override public boolean isProcedure(Object elementID) throws Exception { if(elementID instanceof TempMetadataID) { Object oid = ((TempMetadataID) elementID).getOriginalMetadataID(); if (oid != null) { return actualMetadata.isProcedure(oid); } return false; } return actualMetadata.isProcedure(elementID); } @Override public boolean isTemporaryTable(Object groupID) throws Exception { if(groupID instanceof TempMetadataID) { return ((TempMetadataID)groupID).isTempTable(); } if (groupID instanceof Table) { Table t = (Table)groupID; if (t.getTableType() == Table.Type.TemporaryTable) { return true; } } if( actualMetadata.isTemporaryTable(groupID) ) { return true; } return false; } @Override public Object addToMetadataCache(Object metadataID, String key, Object value) throws Exception { if (metadataID instanceof TempMetadataID) { TempMetadataID tid = (TempMetadataID)metadataID; return tid.setProperty(key, value); } return this.actualMetadata.addToMetadataCache(metadataID, key, value); } @Override public Object getFromMetadataCache(Object metadataID, String key) throws Exception { if (metadataID instanceof TempMetadataID) { TempMetadataID tid = (TempMetadataID)metadataID; return tid.getProperty(key); } return this.actualMetadata.getFromMetadataCache(metadataID, key); } @Override public boolean isScalarGroup(Object groupID) throws Exception { if (groupID instanceof TempMetadataID) { TempMetadataID tid = (TempMetadataID)groupID; return tid.isScalarGroup(); } return this.actualMetadata.isScalarGroup(groupID); } @Override public Object getPrimaryKey(Object metadataID) { metadataID = getActualMetadataId(metadataID); if (metadataID instanceof TempMetadataID) { return ((TempMetadataID)metadataID).getPrimaryKey(); } return this.actualMetadata.getPrimaryKey(metadataID); } @Override public boolean isMultiSource(Object modelId) throws Exception { if (modelId instanceof TempMetadataID) { return false; } return this.actualMetadata.isMultiSource(modelId); } @Override public boolean isMultiSourceElement(Object elementId) throws Exception { if (elementId instanceof TempMetadataID) { return false; } return this.actualMetadata.isMultiSourceElement(elementId); } @Override public Map<Expression, Integer> getFunctionBasedExpressions(Object metadataID) { if (metadataID instanceof TempMetadataID) { return ((TempMetadataID)metadataID).getTableData().getFunctionBasedExpressions(); } return super.getFunctionBasedExpressions(metadataID); } /** * @param id * @return actual metadata id if the object is a {@link TempMetadataID} */ public static Object getActualMetadataId(Object id) { if (!(id instanceof TempMetadataID)) { return id; } TempMetadataID tid = (TempMetadataID)id; Object oid = tid.getOriginalMetadataID(); if (oid != null && tid.getTableData().getModel() != null) { return tid.getOriginalMetadataID(); } return tid; } @Override public String getExtensionProperty(Object metadataID, String key, boolean checkUnqualified) { metadataID = getActualMetadataId(metadataID); if (metadataID instanceof TempMetadataID) { return null; } return super.getExtensionProperty(metadataID, key, checkUnqualified); } }