Package org.teiid.query.tempdata

Source Code of org.teiid.query.tempdata.TempTableDataManager

/*
* 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.tempdata;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;

import org.teiid.api.exception.query.ExpressionEvaluationException;
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.api.exception.query.QueryProcessingException;
import org.teiid.api.exception.query.QueryResolverException;
import org.teiid.api.exception.query.QueryValidatorException;
import org.teiid.cache.Cache;
import org.teiid.cache.CacheConfiguration;
import org.teiid.cache.CacheFactory;
import org.teiid.cache.CacheConfiguration.Policy;
import org.teiid.common.buffer.BlockedException;
import org.teiid.common.buffer.BufferManager;
import org.teiid.common.buffer.TupleBuffer;
import org.teiid.common.buffer.TupleSource;
import org.teiid.core.CoreConstants;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.types.DataTypeManager;
import org.teiid.core.util.HashCodeUtil;
import org.teiid.core.util.StringUtil;
import org.teiid.dqp.internal.process.CachedResults;
import org.teiid.dqp.internal.process.SessionAwareCache;
import org.teiid.dqp.internal.process.SessionAwareCache.CacheID;
import org.teiid.events.EventDistributor;
import org.teiid.language.SQLConstants.Reserved;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.metadata.MetadataRepository;
import org.teiid.metadata.FunctionMethod.Determinism;
import org.teiid.query.QueryPlugin;
import org.teiid.query.eval.Evaluator;
import org.teiid.query.mapping.relational.QueryNode;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.optimizer.relational.RelationalPlanner;
import org.teiid.query.parser.ParseInfo;
import org.teiid.query.processor.BatchCollector;
import org.teiid.query.processor.CollectionTupleSource;
import org.teiid.query.processor.ProcessorDataManager;
import org.teiid.query.processor.QueryProcessor;
import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.sql.lang.CacheHint;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.CompareCriteria;
import org.teiid.query.sql.lang.Create;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.Delete;
import org.teiid.query.sql.lang.Drop;
import org.teiid.query.sql.lang.Insert;
import org.teiid.query.sql.lang.Option;
import org.teiid.query.sql.lang.ProcedureContainer;
import org.teiid.query.sql.lang.Query;
import org.teiid.query.sql.lang.SPParameter;
import org.teiid.query.sql.lang.StoredProcedure;
import org.teiid.query.sql.lang.Update;
import org.teiid.query.sql.navigator.PostOrderNavigator;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.sql.visitor.ExpressionMappingVisitor;
import org.teiid.query.tempdata.TempTableStore.MatState;
import org.teiid.query.tempdata.TempTableStore.MatTableInfo;
import org.teiid.query.util.CommandContext;
import org.teiid.vdb.runtime.VDBKey;

/**
* This proxy ProcessorDataManager is used to handle temporary tables.
*
* This isn't handled as a connector because of the temporary metadata and
* the create/drop handling (which doesn't have push down support)
*/
public class TempTableDataManager implements ProcessorDataManager {
 
    private static final String REFRESHMATVIEWROW = ".refreshmatviewrow"; //$NON-NLS-1$
  private static final String REFRESHMATVIEW = ".refreshmatview"; //$NON-NLS-1$
  private static final String CODE_PREFIX = "#CODE_"; //$NON-NLS-1$
 
  private ProcessorDataManager processorDataManager;
    private BufferManager bufferManager;
  private SessionAwareCache<CachedResults> cache;
    private Executor executor;
   
    private static class MatTableKey implements Serializable {
    private static final long serialVersionUID = 5481692896572663992L;
    String name;
      VDBKey vdb;
     
      @Override
      public int hashCode() {
        return HashCodeUtil.hashCode(name.hashCode(), vdb);
      }
     
      @Override
      public boolean equals(Object obj) {
        if (obj == this) {
          return true;
        }
        if (!(obj instanceof MatTableKey)) {
          return false;
        }
        MatTableKey other = (MatTableKey)obj;
        return this.name.equals(other.name) && this.vdb.equals(other.vdb);
      }
    }
   
    private static class MatTableEntry implements Serializable {
    private static final long serialVersionUID = 8559613701442751579L;
      long lastUpdate = System.currentTimeMillis();
      boolean valid;
    }
   
    private Cache<MatTableKey, MatTableEntry> tables;
    private SessionAwareCache<CachedResults> distributedCache;
    private EventDistributor eventDistributor;

    public TempTableDataManager(ProcessorDataManager processorDataManager, BufferManager bufferManager,
        Executor executor, SessionAwareCache<CachedResults> cache, SessionAwareCache<CachedResults> distibutedCache, CacheFactory cacheFactory){
        this.processorDataManager = processorDataManager;
        this.bufferManager = bufferManager;
        this.executor = executor;
        this.cache = cache;
        this.distributedCache = distibutedCache;
        if (distibutedCache != null) {
          CacheConfiguration cc = new CacheConfiguration(Policy.LRU, -1, -1, "MaterializationUpdates"); //$NON-NLS-1$
          tables = cacheFactory.get(cc.getLocation(), cc);
        }
    }
   
    public void setEventDistributor(EventDistributor eventDistributor) {
    this.eventDistributor = eventDistributor;
  }
   
  public TupleSource registerRequest(
    CommandContext context,
    Command command,
    String modelName,
    String connectorBindingId, int nodeID, int limit)
    throws TeiidComponentException, TeiidProcessingException {         

    TempTableStore tempTableStore = context.getTempTableStore();
        if(tempTableStore != null) {
            TupleSource result = registerRequest(context, modelName, command);
            if (result != null) {
              return result;
            }
        }
        return this.processorDataManager.registerRequest(context, command, modelName, connectorBindingId, nodeID, limit);
  }
         
    TupleSource registerRequest(CommandContext context, String modelName, Command command) throws TeiidComponentException, TeiidProcessingException {
      TempTableStore contextStore = context.getTempTableStore();
        if (command instanceof Query) {
            Query query = (Query)command;
            return registerQuery(context, contextStore, query);
        }
        if (command instanceof ProcedureContainer) {
          if (command instanceof StoredProcedure) {
            StoredProcedure proc = (StoredProcedure)command;
            if (CoreConstants.SYSTEM_ADMIN_MODEL.equals(modelName)) {
              TupleSource result = handleSystemProcedures(context, proc);
              if (result != null) {
                return result;
              }
            } else if (proc.getGroup().isGlobalTable()) {
              return handleCachedProcedure(context, proc);
            }
            return null; //it's not a stored procedure we want to handle
          }
         
          GroupSymbol group = ((ProcedureContainer)command).getGroup();
          if (!group.isTempGroupSymbol()) {
            return null;
          }
          final String groupKey = group.getNonCorrelationName().toUpperCase();
            final TempTable table = contextStore.getOrCreateTempTable(groupKey, command, bufferManager, false);
          if (command instanceof Insert) {
            Insert insert = (Insert)command;
            TupleSource ts = insert.getTupleSource();
            if (ts == null) {
              List<Object> values = new ArrayList<Object>(insert.getValues().size());
              for (Expression expr : (List<Expression>)insert.getValues()) {
                values.add(Evaluator.evaluate(expr));
          }
              ts = new CollectionTupleSource(Arrays.asList(values).iterator());
            }
            return table.insert(ts, insert.getVariables());
          }
          if (command instanceof Update) {
            final Update update = (Update)command;
            final Criteria crit = update.getCriteria();
            return table.update(crit, update.getChangeList());
          }
          if (command instanceof Delete) {
            final Delete delete = (Delete)command;
            final Criteria crit = delete.getCriteria();
            if (crit == null) {
              //because we are non-transactional, just use a truncate
              int rows = table.truncate();
                    return CollectionTupleSource.createUpdateCountTupleSource(rows);
            }
            return table.delete(crit);
          }
        }
      if (command instanceof Create) {
        Create create = (Create)command;
        String tempTableName = create.getTable().getCanonicalName();
        if (contextStore.hasTempTable(tempTableName)) {
                throw new QueryProcessingException(QueryPlugin.Util.getString("TempTableStore.table_exist_error", tempTableName));//$NON-NLS-1$
            }
        contextStore.addTempTable(tempTableName, create, bufferManager, true);
            return CollectionTupleSource.createUpdateCountTupleSource(0)
      }
      if (command instanceof Drop) {
        String tempTableName = ((Drop)command).getTable().getCanonicalName();
        contextStore.removeTempTableByName(tempTableName);
            return CollectionTupleSource.createUpdateCountTupleSource(0);
      }
        return null;
    }

  private TupleSource handleCachedProcedure(CommandContext context,
      StoredProcedure proc) throws TeiidComponentException,
      QueryMetadataException, TeiidProcessingException {
    String fullName = context.getMetadata().getFullName(proc.getProcedureID());
    LogManager.logDetail(LogConstants.CTX_DQP, "processing cached procedure request for", fullName); //$NON-NLS-1$
    LinkedList<Object> vals = new LinkedList<Object>();
    for (SPParameter param : proc.getInputParameters()) {
      vals.add(((Constant)param.getExpression()).getValue());
    }
    //collapse the hash to single byte for the key to restrict the possible results to 256
    int hash = vals.hashCode();
    hash |= (hash >>> 16);
    hash |= (hash >>> 8);
    hash &= 0x000000ff;
    CacheID cid = new CacheID(new ParseInfo(), fullName + hash, context.getVdbName(),
        context.getVdbVersion(), context.getConnectionID(), context.getUserName());
    cid.setParameters(vals);
    CachedResults results = cache.get(cid);
    if (results != null) {
      TupleBuffer buffer = results.getResults();
      return buffer.createIndexedTupleSource();
    }
    //construct a query with a no cache hint
    //note that it's safe to use the stringified form of the parameters because
    //it's not possible to use xml/clob/blob/object
    CacheHint hint = proc.getCacheHint();
    proc.setCacheHint(null);
    Option option = new Option();
    option.setNoCache(true);
    option.addNoCacheGroup(fullName);
    proc.setOption(option);
    Determinism determinismLevel = context.resetDeterminismLevel();
    QueryProcessor qp = context.getQueryProcessorFactory().createQueryProcessor(proc.toString(), fullName.toUpperCase(), context);
    qp.setNonBlocking(true);
    qp.getContext().setDataObjects(null);
    BatchCollector bc = qp.createBatchCollector();
    TupleBuffer tb = bc.collectTuples();
    CachedResults cr = new CachedResults();
    cr.setResults(tb, qp.getProcessorPlan());
    cr.setHint(hint);
    if (hint != null && hint.getDeterminism() != null) {
      LogManager.logTrace(LogConstants.CTX_DQP, new Object[] { "Cache hint modified the query determinism from ",determinismLevel, " to ", hint.getDeterminism() }); //$NON-NLS-1$ //$NON-NLS-2$
      determinismLevel = hint.getDeterminism();
    }
    cache.put(cid, determinismLevel, cr, hint != null?hint.getTtl():null);
    context.setDeterminismLevel(determinismLevel);
    return tb.createIndexedTupleSource();
  }

  private TupleSource handleSystemProcedures(CommandContext context, StoredProcedure proc)
      throws TeiidComponentException, QueryMetadataException,
      QueryProcessingException, QueryResolverException,
      QueryValidatorException, TeiidProcessingException,
      ExpressionEvaluationException {
    QueryMetadataInterface metadata = context.getMetadata();
    TempTableStore globalStore = context.getGlobalTableStore();
    if (StringUtil.endsWithIgnoreCase(proc.getProcedureCallableName(), REFRESHMATVIEW)) {
      Object groupID = validateMatView(metadata, proc);
      Object matTableId = context.getGlobalTableStore().getGlobalTempTableMetadataId(groupID, metadata);
      String matViewName = metadata.getFullName(groupID);
      String matTableName = metadata.getFullName(matTableId);
      LogManager.logDetail(LogConstants.CTX_MATVIEWS, "processing refreshmatview for", matViewName); //$NON-NLS-1$
      MatTableInfo info = globalStore.getMatTableInfo(matTableName);
      boolean invalidate = Boolean.TRUE.equals(((Constant)proc.getParameter(1).getExpression()).getValue());
      if (invalidate) {
        touchTable(context, matTableName, false);
      }
      MatState oldState = info.setState(MatState.NEEDS_LOADING, invalidate?Boolean.FALSE:null, null);
      if (oldState == MatState.LOADING) {
        return CollectionTupleSource.createUpdateCountTupleSource(-1);
      }
      GroupSymbol matTable = new GroupSymbol(matTableName);
      matTable.setMetadataID(matTableId);
      int rowCount = loadGlobalTable(context, matTable, matTableName, globalStore, info, null);
      return CollectionTupleSource.createUpdateCountTupleSource(rowCount);
    } else if (StringUtil.endsWithIgnoreCase(proc.getProcedureCallableName(), REFRESHMATVIEWROW)) {
      Object groupID = validateMatView(metadata, proc);
      Object pk = metadata.getPrimaryKey(groupID);
      String matViewName = metadata.getFullName(groupID);
      if (pk == null) {
        throw new QueryProcessingException(QueryPlugin.Util.getString("TempTableDataManager.row_refresh_pk", matViewName)); //$NON-NLS-1$
      }
      List<?> ids = metadata.getElementIDsInKey(pk);
      if (ids.size() > 1) {
        throw new QueryProcessingException(QueryPlugin.Util.getString("TempTableDataManager.row_refresh_composite", matViewName)); //$NON-NLS-1$
      }
      String matTableName = RelationalPlanner.MAT_PREFIX+matViewName.toUpperCase();
      MatTableInfo info = globalStore.getMatTableInfo(matTableName);
      if (!info.isValid()) {
        return CollectionTupleSource.createUpdateCountTupleSource(-1);
      }
      TempTable tempTable = globalStore.getOrCreateTempTable(matTableName, new Query(), bufferManager, false);
      if (!tempTable.isUpdatable()) {
        throw new QueryProcessingException(QueryPlugin.Util.getString("TempTableDataManager.row_refresh_updatable", matViewName)); //$NON-NLS-1$
      }
      Constant key = (Constant)proc.getParameter(2).getExpression();
      LogManager.logInfo(LogConstants.CTX_MATVIEWS, QueryPlugin.Util.getString("TempTableDataManager.row_refresh", matViewName, key)); //$NON-NLS-1$
      String queryString = Reserved.SELECT + " * " + Reserved.FROM + ' ' + matViewName + ' ' + Reserved.WHERE + ' ' + //$NON-NLS-1$
        metadata.getFullName(ids.iterator().next()) + " = ?" + ' ' + Reserved.OPTION + ' ' + Reserved.NOCACHE; //$NON-NLS-1$
      QueryProcessor qp = context.getQueryProcessorFactory().createQueryProcessor(queryString, matViewName.toUpperCase(), context, key.getValue());
      qp.setNonBlocking(true);
      qp.getContext().setDataObjects(null);
      TupleSource ts = new BatchCollector.BatchProducerTupleSource(qp);
      List<?> tuple = ts.nextTuple();
      boolean delete = false;
      if (tuple == null) {
        delete = true;
        tuple = Arrays.asList(key.getValue());
      }
      List<?> result = updateMatViewRow(globalStore, matTableName, tuple, delete);
      if (result != null && eventDistributor != null) {
        this.eventDistributor.updateMatViewRow(context.getVdbName(), context.getVdbVersion(), metadata.getName(metadata.getModelID(groupID)), metadata.getName(groupID), tuple, delete);
      }
      return CollectionTupleSource.createUpdateCountTupleSource(result != null ? 1 : 0);
    }
    return null;
  }

  public List<?> updateMatViewRow(TempTableStore globalStore,
      String matTableName, List<?> tuple, boolean delete)
      throws QueryProcessingException, TeiidComponentException {
    TempTable tempTable = globalStore.getOrCreateTempTable(matTableName, new Query(), bufferManager, false);
    return tempTable.updateTuple(tuple, delete);
  }

  private Object validateMatView(QueryMetadataInterface metadata,
      StoredProcedure proc) throws TeiidComponentException,
      TeiidProcessingException {
    String name = (String)((Constant)proc.getParameter(1).getExpression()).getValue();
    try {
      Object groupID = metadata.getGroupID(name);
      if (!metadata.hasMaterialization(groupID) || metadata.getMaterialization(groupID) != null) {
        throw new QueryProcessingException(QueryPlugin.Util.getString("TempTableDataManager.not_implicit_matview", name)); //$NON-NLS-1$
      }
      return groupID;
    } catch (QueryMetadataException e) {
      throw new TeiidProcessingException(e);
    }
  }

  private TupleSource registerQuery(final CommandContext context,
      TempTableStore contextStore, Query query)
      throws TeiidComponentException, QueryMetadataException,
      TeiidProcessingException, ExpressionEvaluationException,
      QueryProcessingException {
    final GroupSymbol group = query.getFrom().getGroups().get(0);
    if (!group.isTempGroupSymbol()) {
      return null;
    }
    final String tableName = group.getNonCorrelationName().toUpperCase();
    boolean remapColumns = !tableName.equalsIgnoreCase(group.getName());
    TempTable table = null;
    if (group.isGlobalTable()) {
      final TempTableStore globalStore = context.getGlobalTableStore();
      final MatTableInfo info = globalStore.getMatTableInfo(tableName);
      Long loadTime = null;
      if (this.distributedCache != null) {
        MatTableKey key = new MatTableKey();
        key.name = tableName;
        key.vdb = new VDBKey(context.getVdbName(), context.getVdbVersion());
       
        MatTableEntry entry = this.tables.get(key);
        boolean firstload = !info.isValid();
        if (entry != null && entry.lastUpdate > info.getUpdateTime()
            && info.getState() != MatState.LOADING) {
          //remote load
          info.setState(MatState.NEEDS_LOADING, firstload?false:entry.valid, null);
          loadTime = entry.lastUpdate;
        }
      }
      boolean load = info.shouldLoad();
      if (load) {
        if (!info.isValid()) {
          //blocking load
          loadGlobalTable(context, group, tableName, globalStore, info, loadTime);
        } else {
          loadAsynch(context, group, tableName, globalStore, info, loadTime);
        }
      }
      table = globalStore.getOrCreateTempTable(tableName, query, bufferManager, false);
      context.accessedDataObject(group.getMetadataID());
    } else {
      table = contextStore.getOrCreateTempTable(tableName, query, bufferManager, true);
      if (context.getDataObjects() != null) {
        Object id = RelationalPlanner.getTrackableGroup(group, context.getMetadata());
        if (id != null) {
          context.accessedDataObject(group.getMetadataID());
        }
      }
    }
    if (remapColumns) {
      //convert to the actual table symbols (this is typically handled by the languagebridgefactory
      ExpressionMappingVisitor emv = new ExpressionMappingVisitor(null) {
        @Override
        public Expression replaceExpression(Expression element) {
          if (element instanceof ElementSymbol) {
            ElementSymbol es = (ElementSymbol)element;
            es.getGroupSymbol().setName(tableName);
            es.getGroupSymbol().setDefinition(null);
          }
          return element;
        }
      };
      PostOrderNavigator.doVisit(query, emv);
    }
    return table.createTupleSource(query.getProjectedSymbols(), query.getCriteria(), query.getOrderBy());
  }

  private void loadAsynch(final CommandContext context,
      final GroupSymbol group, final String tableName,
      final TempTableStore globalStore, final MatTableInfo info,
      final Long loadTime) {
    Callable<Integer> toCall = new Callable<Integer>() {
      @Override
      public Integer call() throws Exception {
        return loadGlobalTable(context, group, tableName, globalStore, info, loadTime);
      }
    };
    FutureTask<Integer> task = new FutureTask<Integer>(toCall);
    executor.execute(task);
  }

  private int loadGlobalTable(CommandContext context,
      GroupSymbol group, final String tableName,
      TempTableStore globalStore, MatTableInfo info, Long loadTime)
      throws TeiidComponentException, TeiidProcessingException {
    LogManager.logInfo(LogConstants.CTX_MATVIEWS, QueryPlugin.Util.getString("TempTableDataManager.loading", tableName)); //$NON-NLS-1$
    QueryMetadataInterface metadata = context.getMetadata();
    Create create = new Create();
    create.setTable(group);
    List<ElementSymbol> allColumns = ResolverUtil.resolveElementsInGroup(group, metadata);
    create.setElementSymbolsAsColumns(allColumns);
    Object pk = metadata.getPrimaryKey(group.getMetadataID());
    if (pk != null) {
      List<ElementSymbol> pkColumns = resolveIndex(metadata, allColumns, pk);
      create.getPrimaryKey().addAll(pkColumns);
    }
    TempTable table = globalStore.addTempTable(tableName, create, bufferManager, false);
    table.setUpdatable(false);
    CacheHint hint = table.getCacheHint();
    boolean updatable = false;
    if (hint != null) {
      table.setPreferMemory(hint.getPrefersMemory());
      if (hint.getTtl() != null) {
        info.setTtl(hint.getTtl());
      }
      if (pk != null) {
        updatable = hint.isUpdatable();
      }
    }
    int rowCount = -1;
    try {
      String fullName = metadata.getFullName(group.getMetadataID());
      TupleSource ts = null;
      CacheID cid = null;
      if (distributedCache != null) {
        cid = new CacheID(new ParseInfo(), fullName, context.getVdbName(),
            context.getVdbVersion(), context.getConnectionID(), context.getUserName());
        CachedResults cr = this.distributedCache.get(cid);
        if (cr != null) {
          ts = cr.getResults().createIndexedTupleSource();
        }
      }
     
      List<ElementSymbol> variables = table.getColumns();
     
      if (ts == null) {
        variables = allColumns;
        //TODO: coordinate a distributed load
        //TODO: order by primary key nulls first - then have an insert ordered optimization
        String transformation = metadata.getVirtualPlan(group.getMetadataID()).getQuery();
        QueryProcessor qp = context.getQueryProcessorFactory().createQueryProcessor(transformation, fullName, context);
        qp.setNonBlocking(true);
        qp.getContext().setDataObjects(null);
        if (distributedCache != null) {
          CachedResults cr = new CachedResults();
          BatchCollector bc = qp.createBatchCollector();
          TupleBuffer tb = bc.collectTuples();
          cr.setResults(tb, qp.getProcessorPlan());
          touchTable(context, fullName, true);
          this.distributedCache.put(cid, Determinism.VDB_DETERMINISTIC, cr, info.getTtl());
          ts = tb.createIndexedTupleSource();
        } else {
          ts = new BatchCollector.BatchProducerTupleSource(qp);
        }
      }
     
      //TODO: if this insert fails, it's unnecessary to do the undo processing
      table.insert(ts, variables);
      table.getTree().compact();
      rowCount = table.getRowCount();
      //TODO: could pre-process indexes to remove overlap
      for (Object index : metadata.getIndexesInGroup(group.getMetadataID())) {
        List<ElementSymbol> columns = resolveIndex(metadata, allColumns, index);
        table.addIndex(columns, false);
      }
      for (Object key : metadata.getUniqueKeysInGroup(group.getMetadataID())) {
        List<ElementSymbol> columns = resolveIndex(metadata, allColumns, key);
        table.addIndex(columns, true);
      }
      table.setUpdatable(updatable);
    } catch (TeiidComponentException e) {
      LogManager.logError(LogConstants.CTX_MATVIEWS, e, QueryPlugin.Util.getString("TempTableDataManager.failed_load", tableName)); //$NON-NLS-1$
      throw e;
    } catch (TeiidProcessingException e) {
      LogManager.logError(LogConstants.CTX_MATVIEWS, e, QueryPlugin.Util.getString("TempTableDataManager.failed_load", tableName)); //$NON-NLS-1$
      throw e;
    } finally {
      if (rowCount == -1) {
        info.setState(MatState.FAILED_LOAD, null, null);
      } else {
        globalStore.swapTempTable(tableName, table);
        info.setState(MatState.LOADED, true, loadTime);
        LogManager.logInfo(LogConstants.CTX_MATVIEWS, QueryPlugin.Util.getString("TempTableDataManager.loaded", tableName, rowCount)); //$NON-NLS-1$
      }
    }
    return rowCount;
  }

  private void touchTable(CommandContext context, String fullName, boolean valid) {
    MatTableKey key = new MatTableKey();
    key.name = fullName;
    key.vdb = new VDBKey(context.getVdbName(), context.getVdbVersion());
    MatTableEntry matTableEntry = new MatTableEntry();
    matTableEntry.valid = valid;
    tables.put(key, matTableEntry, null);
  }

  /**
   * Return a list of ElementSymbols for the given index/key object
   */
  private List<ElementSymbol> resolveIndex(QueryMetadataInterface metadata,
      List<ElementSymbol> allColumns, Object pk)
      throws TeiidComponentException, QueryMetadataException {
    Collection<?> pkIds = metadata.getElementIDsInKey(pk);
    List<ElementSymbol> pkColumns = new ArrayList<ElementSymbol>(pkIds.size());
    for (Object col : pkIds) {
      pkColumns.add(allColumns.get(metadata.getPosition(col)-1));
    }
    return pkColumns;
  }

  public Object lookupCodeValue(CommandContext context, String codeTableName,
      String returnElementName, String keyElementName, Object keyValue)
      throws BlockedException, TeiidComponentException,
      TeiidProcessingException {
      String matTableName = CODE_PREFIX + (codeTableName + ElementSymbol.SEPARATOR + keyElementName + ElementSymbol.SEPARATOR + returnElementName).toUpperCase();

      ElementSymbol keyElement = new ElementSymbol(matTableName + ElementSymbol.SEPARATOR + keyElementName);
      ElementSymbol returnElement = new ElementSymbol(matTableName + ElementSymbol.SEPARATOR + returnElementName);
     
      QueryMetadataInterface metadata = context.getMetadata();
     
      keyElement.setType(DataTypeManager.getDataTypeClass(metadata.getElementType(metadata.getElementID(codeTableName + ElementSymbol.SEPARATOR + keyElementName))));
      returnElement.setType(DataTypeManager.getDataTypeClass(metadata.getElementType(metadata.getElementID(codeTableName + ElementSymbol.SEPARATOR + returnElementName))));
     
      TempMetadataID id = context.getGlobalTableStore().getMetadataStore().getTempGroupID(matTableName);
      if (id == null) {
        id = context.getGlobalTableStore().getMetadataStore().addTempGroup(matTableName, Arrays.asList(keyElement, returnElement), false, true);
        String queryString = Reserved.SELECT + ' ' + keyElementName + " ," + returnElementName + ' ' + Reserved.FROM + ' ' + codeTableName; //$NON-NLS-1$
        id.setQueryNode(new QueryNode(queryString));
        id.setPrimaryKey(id.getElements().subList(0, 1));
        CacheHint hint = new CacheHint(true, null);
        id.setCacheHint(hint);
      }
      Query query = RelationalPlanner.createMatViewQuery(id, matTableName, Arrays.asList(returnElement), true);
      query.setCriteria(new CompareCriteria(keyElement, CompareCriteria.EQ, new Constant(keyValue)));
     
      TupleSource ts = registerQuery(context, context.getTempTableStore(), query);
      List<?> row = ts.nextTuple();
      Object result = null;
      if (row != null) {
        result = row.get(0);
      }
      ts.closeSource();
      return result;
    }

  @Override
  public EventDistributor getEventDistributor() {
    return this.eventDistributor;
  }

  @Override
  public MetadataRepository getMetadataRepository() {
    return this.processorDataManager.getMetadataRepository();
  }

}
TOP

Related Classes of org.teiid.query.tempdata.TempTableDataManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.