Package org.teiid.dqp.internal.process

Source Code of org.teiid.dqp.internal.process.Request

/*
* 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.dqp.internal.process;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.api.exception.query.QueryParserException;
import org.teiid.api.exception.query.QueryPlannerException;
import org.teiid.api.exception.query.QueryResolverException;
import org.teiid.api.exception.query.QueryValidatorException;
import org.teiid.client.RequestMessage;
import org.teiid.client.RequestMessage.ResultsMode;
import org.teiid.client.RequestMessage.ShowPlan;
import org.teiid.client.xa.XATransactionException;
import org.teiid.common.buffer.BufferManager;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.id.IDGenerator;
import org.teiid.core.id.IntegerIDFactory;
import org.teiid.core.types.DataTypeManager;
import org.teiid.core.util.Assertion;
import org.teiid.dqp.internal.datamgr.ConnectorManagerRepository;
import org.teiid.dqp.internal.process.multisource.MultiSourceCapabilitiesFinder;
import org.teiid.dqp.internal.process.multisource.MultiSourceMetadataWrapper;
import org.teiid.dqp.internal.process.multisource.MultiSourcePlanToProcessConverter;
import org.teiid.dqp.message.RequestID;
import org.teiid.dqp.service.TransactionContext;
import org.teiid.dqp.service.TransactionService;
import org.teiid.dqp.service.TransactionContext.Scope;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.logging.MessageLevel;
import org.teiid.metadata.FunctionMethod.Determinism;
import org.teiid.query.QueryPlugin;
import org.teiid.query.analysis.AnalysisRecord;
import org.teiid.query.eval.SecurityFunctionEvaluator;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.TempCapabilitiesFinder;
import org.teiid.query.metadata.TempMetadataAdapter;
import org.teiid.query.optimizer.QueryOptimizer;
import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
import org.teiid.query.parser.ParseInfo;
import org.teiid.query.parser.QueryParser;
import org.teiid.query.processor.ProcessorDataManager;
import org.teiid.query.processor.ProcessorPlan;
import org.teiid.query.processor.QueryProcessor;
import org.teiid.query.processor.xml.XMLPlan;
import org.teiid.query.resolver.QueryResolver;
import org.teiid.query.rewriter.QueryRewriter;
import org.teiid.query.sql.lang.BatchedUpdateCommand;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.Limit;
import org.teiid.query.sql.lang.QueryCommand;
import org.teiid.query.sql.lang.StoredProcedure;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.sql.symbol.Reference;
import org.teiid.query.sql.visitor.GroupCollectorVisitor;
import org.teiid.query.sql.visitor.ReferenceCollectorVisitor;
import org.teiid.query.tempdata.TempTableStore;
import org.teiid.query.util.CommandContext;
import org.teiid.query.util.ContextProperties;
import org.teiid.query.validator.AbstractValidationVisitor;
import org.teiid.query.validator.ValidationVisitor;
import org.teiid.query.validator.Validator;
import org.teiid.query.validator.ValidatorFailure;
import org.teiid.query.validator.ValidatorReport;


/**
* Server side representation of the RequestMessage.  Knows how to process itself.
*/
public class Request implements SecurityFunctionEvaluator {
   
  // init state
    protected RequestMessage requestMsg;
    private String vdbName;
    private int vdbVersion;
    private BufferManager bufferManager;
    private ProcessorDataManager processorDataManager;
    private TransactionService transactionService;
    private TempTableStore tempTableStore;
    protected IDGenerator idGenerator = new IDGenerator();
    DQPWorkContext workContext;
    RequestID requestId;

    // acquired state
    protected CapabilitiesFinder capabilitiesFinder;
    protected QueryMetadataInterface metadata;
    private Set<String> multiSourceModels;

    // internal results
    protected boolean addedLimit;
    protected ProcessorPlan processPlan;
    // external results
    protected AnalysisRecord analysisRecord;
    protected CommandContext context;
    protected QueryProcessor processor;
   
    protected TransactionContext transactionContext;
    protected ConnectorManagerRepository connectorManagerRepo;
   
    protected Command userCommand;
    protected boolean returnsUpdateCount;
  private TempTableStore globalTables;
  private SessionAwareCache<PreparedPlan> planCache;
  private boolean resultSetCacheEnabled = true;
  private int userRequestConcurrency;
  private AuthorizationValidator authorizationValidator;

    void initialize(RequestMessage requestMsg,
                              BufferManager bufferManager,
                              ProcessorDataManager processorDataManager,
                              TransactionService transactionService,
                              TempTableStore tempTableStore,
                              DQPWorkContext workContext,
                              SessionAwareCache<PreparedPlan> planCache) {

        this.requestMsg = requestMsg;
        this.vdbName = workContext.getVdbName();       
        this.vdbVersion = workContext.getVdbVersion();
        this.bufferManager = bufferManager;
        this.processorDataManager = processorDataManager;
        this.transactionService = transactionService;
        this.tempTableStore = tempTableStore;
        idGenerator.setDefaultFactory(new IntegerIDFactory());
        this.workContext = workContext;
        this.requestId = workContext.getRequestID(this.requestMsg.getExecutionId());
        this.connectorManagerRepo = workContext.getVDB().getAttachment(ConnectorManagerRepository.class);
        this.planCache = planCache;
    }
   
  void setMetadata(CapabilitiesFinder capabilitiesFinder, QueryMetadataInterface metadata, Set multiSourceModels) {
    this.capabilitiesFinder = capabilitiesFinder;
    this.metadata = metadata;
    this.multiSourceModels = multiSourceModels;
  }
 
  public void setResultSetCacheEnabled(boolean resultSetCacheEnabled) {
    this.resultSetCacheEnabled = resultSetCacheEnabled;
  }
 
  public void setAuthorizationValidator(
      AuthorizationValidator authorizationValidator) {
    this.authorizationValidator = authorizationValidator;
  }
 
  /**
   * if the metadata has not been supplied via setMetadata, this method will create the appropriate state
   *
   * @throws TeiidComponentException
   */
    protected void initMetadata() throws TeiidComponentException {
        if (this.metadata != null) {
          return;
        }
      // Prepare dependencies for running the optimizer       
        this.capabilitiesFinder = new CachedFinder(this.connectorManagerRepo, workContext.getVDB());       
        this.capabilitiesFinder = new TempCapabilitiesFinder(this.capabilitiesFinder);

        VDBMetaData vdbMetadata = workContext.getVDB();
        metadata = vdbMetadata.getAttachment(QueryMetadataInterface.class);
        globalTables = vdbMetadata.getAttachment(TempTableStore.class);

        if (metadata == null) {
            throw new TeiidComponentException(QueryPlugin.Util.getString("DQPCore.Unable_to_load_metadata_for_VDB_name__{0},_version__{1}", this.vdbName, this.vdbVersion)); //$NON-NLS-1$
        }
       
        // Check for multi-source models and further wrap the metadata interface
        Set<String> multiSourceModelList = workContext.getVDB().getMultiSourceModelNames();
        if(multiSourceModelList != null && multiSourceModelList.size() > 0) {
          this.multiSourceModels = multiSourceModelList;
            this.metadata = new MultiSourceMetadataWrapper(this.metadata, this.multiSourceModels);
        }
       
        TempMetadataAdapter tma = new TempMetadataAdapter(metadata, this.tempTableStore.getMetadataStore());
        tma.setSession(true);
        this.metadata = tma;
    }
   
    protected void createCommandContext() throws QueryValidatorException {
      boolean returnsResultSet = userCommand.returnsResultSet();
      this.returnsUpdateCount = !(userCommand instanceof StoredProcedure) && !returnsResultSet;
      if ((this.requestMsg.getResultsMode() == ResultsMode.UPDATECOUNT && !returnsUpdateCount)
          || (this.requestMsg.getResultsMode() == ResultsMode.RESULTSET && !returnsResultSet)) {
          throw new QueryValidatorException(QueryPlugin.Util.getString(this.requestMsg.getResultsMode()==ResultsMode.RESULTSET?"Request.no_result_set":"Request.result_set")); //$NON-NLS-1$ //$NON-NLS-2$
      }

      // Create command context, used in rewriting, planning, and processing
        // Identifies a "group" of requests on a per-connection basis to allow later
        // cleanup of all resources in the group on connection shutdown
        String groupName = workContext.getSessionId();

        RequestID reqID = workContext.getRequestID(this.requestMsg.getExecutionId());
       
        Properties props = new Properties();
        props.setProperty(ContextProperties.SESSION_ID, workContext.getSessionId());
       
        this.context =
            new CommandContext(
                reqID,
                groupName,
                workContext.getUserName(),
                requestMsg.getExecutionPayload(),
                workContext.getVdbName(),
                workContext.getVdbVersion(),
                props,
                this.requestMsg.getShowPlan() != ShowPlan.OFF);
        this.context.setProcessorBatchSize(bufferManager.getProcessorBatchSize());
        this.context.setConnectorBatchSize(bufferManager.getConnectorBatchSize());
        this.context.setGlobalTableStore(this.globalTables);
        if (multiSourceModels != null) {
            MultiSourcePlanToProcessConverter modifier = new MultiSourcePlanToProcessConverter(
          metadata, idGenerator, analysisRecord, capabilitiesFinder,
          multiSourceModels, workContext, context);
            context.setPlanToProcessConverter(modifier);
        }

        context.setSecurityFunctionEvaluator(this);
        context.setTempTableStore(tempTableStore);
        context.setQueryProcessorFactory(new QueryProcessorFactoryImpl(this.bufferManager, this.processorDataManager, this.capabilitiesFinder, idGenerator, metadata));
        context.setMetadata(this.metadata);
        context.setBufferManager(this.bufferManager);
        context.setPreparedPlanCache(planCache);
        context.setResultSetCacheEnabled(this.resultSetCacheEnabled);
        context.setUserRequestSourceConcurrency(this.userRequestConcurrency);
        context.setSubject(workContext.getSubject());
    }
   
    @Override
    public boolean hasRole(String roleType, String roleName)
        throws TeiidComponentException {
        if (!DATA_ROLE.equalsIgnoreCase(roleType)) {
            return false;
        }
        return authorizationValidator.hasRole(roleName, workContext);
    }
   
    public void setUserRequestConcurrency(int userRequestConcurrency) {
    this.userRequestConcurrency = userRequestConcurrency;
  }

    protected void checkReferences(List<Reference> references) throws QueryValidatorException {
      referenceCheck(references);
    }
   
    static void referenceCheck(List<Reference> references) throws QueryValidatorException {
      if (references != null && !references.isEmpty()) {
        throw new QueryValidatorException(QueryPlugin.Util.getString("Request.Invalid_character_in_query")); //$NON-NLS-1$
      }
    }

    protected void resolveCommand(Command command) throws QueryResolverException, TeiidComponentException {
      //ensure that the user command is distinct from the processing command
        //rewrite and planning may alter options, symbols, etc.
      QueryResolver.resolveCommand(command, metadata);
     
      this.userCommand = (Command)command.clone();
    }
       
    private void validateQuery(Command command)
        throws QueryValidatorException, TeiidComponentException {
               
        // Create generic sql validation visitor
        AbstractValidationVisitor visitor = new ValidationVisitor();
        validateWithVisitor(visitor, metadata, command);
    }
   
    private Command parseCommand() throws QueryParserException {
        String[] commands = requestMsg.getCommands();
        ParseInfo parseInfo = createParseInfo(this.requestMsg);
        if (requestMsg.isPreparedStatement() || requestMsg.isCallableStatement() || !requestMsg.isBatchedUpdate()) {
          String commandStr = commands[0];
            return QueryParser.getQueryParser().parseCommand(commandStr, parseInfo);
        }
        List<Command> parsedCommands = new ArrayList<Command>(commands.length);
        for (int i = 0; i < commands.length; i++) {
          String updateCommand = commands[i];
            parsedCommands.add(QueryParser.getQueryParser().parseCommand(updateCommand, parseInfo));
        }
        return new BatchedUpdateCommand(parsedCommands);
    }

  public static ParseInfo createParseInfo(RequestMessage requestMsg) {
    ParseInfo parseInfo = new ParseInfo();
      parseInfo.ansiQuotedIdentifiers = requestMsg.isAnsiQuotedIdentifiers();
    return parseInfo;
  }

    public static void validateWithVisitor(
        AbstractValidationVisitor visitor,
        QueryMetadataInterface metadata,
        Command command)
        throws QueryValidatorException, TeiidComponentException {

        // Validate with visitor
        ValidatorReport report = Validator.validate(command, metadata, visitor);
        if (report.hasItems()) {
            ValidatorFailure firstFailure = report.getItems().iterator().next();
            throw new QueryValidatorException(firstFailure.getMessage());
        }
    }

    private void createProcessor() throws TeiidComponentException {
       
        TransactionContext tc = transactionService.getOrCreateTransactionContext(workContext.getSessionId());
       
        Assertion.assertTrue(tc.getTransactionType() != TransactionContext.Scope.REQUEST, "Transaction already associated with request."); //$NON-NLS-1$

        // If local or global transaction is not started.
        if (tc.getTransactionType() == Scope.NONE) {
           
            boolean startAutoWrapTxn = false;
           
            if(RequestMessage.TXN_WRAP_ON.equals(requestMsg.getTxnAutoWrapMode())){
                startAutoWrapTxn = true;
            } else if (RequestMessage.TXN_WRAP_DETECT.equals(requestMsg.getTxnAutoWrapMode())){
              boolean transactionalRead = requestMsg.getTransactionIsolation() == Connection.TRANSACTION_REPEATABLE_READ
            || requestMsg.getTransactionIsolation() == Connection.TRANSACTION_SERIALIZABLE;
            startAutoWrapTxn = processPlan.requiresTransaction(transactionalRead);
            }
           
            if (startAutoWrapTxn) {
                try {
                    tc = transactionService.begin(tc);
                } catch (XATransactionException err) {
                    throw new TeiidComponentException(err);
                }
            }
        }
       
        this.transactionContext = tc;
        this.processor = new QueryProcessor(processPlan, context, bufferManager, processorDataManager);
    }

    /**
     * state side effects:
     *      creates the analysis record
     *     creates the command context
     *     sets the pre-rewrite command on the request
     *     adds a limit clause if the row limit is specified
     *     sets the processor plan
     *
     * @throws TeiidComponentException
     * @throws TeiidProcessingException
     */
    protected void generatePlan() throws TeiidComponentException, TeiidProcessingException {
        Command command = parseCommand();

        List<Reference> references = ReferenceCollectorVisitor.getReferences(command);
       
        checkReferences(references);
       
        this.analysisRecord = new AnalysisRecord(requestMsg.getShowPlan() != ShowPlan.OFF, requestMsg.getShowPlan() == ShowPlan.DEBUG);
               
        resolveCommand(command);
       
        validateAccess(userCommand);
       
        createCommandContext();

        Collection<GroupSymbol> groups = GroupCollectorVisitor.getGroups(command, true);
        for (GroupSymbol groupSymbol : groups) {
      if (groupSymbol.isTempTable()) {
        this.context.setDeterminismLevel(Determinism.SESSION_DETERMINISTIC);
        break;
      }
    }

        validateQuery(command);
       
        command = QueryRewriter.rewrite(command, metadata, context);
       
        /*
         * Adds a row limit to a query if Statement.setMaxRows has been called and the command
         * doesn't already have a limit clause.
         */
        if (requestMsg.getRowLimit() > 0 && command instanceof QueryCommand) {
            QueryCommand query = (QueryCommand)command;
            if (query.getLimit() == null) {
                query.setLimit(new Limit(null, new Constant(new Integer(requestMsg.getRowLimit()), DataTypeManager.DefaultDataClasses.INTEGER)));
                this.addedLimit = true;
            }
        }
       
        try {
          // If using multi-source models, insert a proxy to simplify the supported capabilities.  This is
            // done OUTSIDE the cache (wrapped around the cache) intentionally to avoid caching the simplified
            // capabilities which may be different for the same model in a different VDB used by this same DQP.
          CapabilitiesFinder finder = this.capabilitiesFinder;
            if(this.multiSourceModels != null) {
                finder = new MultiSourceCapabilitiesFinder(finder, this.multiSourceModels);
            }
           
            boolean debug = analysisRecord.recordDebug();
        if(debug) {
          analysisRecord.println("\n============================================================================"); //$NON-NLS-1$
                analysisRecord.println("USER COMMAND:\n" + command);     //$NON-NLS-1$
            }
            // Run the optimizer
            try {
                processPlan = QueryOptimizer.optimizePlan(command, metadata, idGenerator, finder, analysisRecord, context);
            } finally {
                String debugLog = analysisRecord.getDebugLog();
                if(debugLog != null && debugLog.length() > 0) {
                    LogManager.log(requestMsg.getShowPlan()==ShowPlan.DEBUG?MessageLevel.INFO:MessageLevel.TRACE, LogConstants.CTX_QUERY_PLANNER, debugLog);              
                }
                if (analysisRecord.recordAnnotations() && analysisRecord.getAnnotations() != null && !analysisRecord.getAnnotations().isEmpty()) {
                  LogManager.logDetail(LogConstants.CTX_QUERY_PLANNER, analysisRecord.getAnnotations());
                }
            }
            LogManager.logDetail(LogConstants.CTX_DQP, new Object[] { QueryPlugin.Util.getString("BasicInterceptor.ProcessTree_for__4"), requestId, processPlan }); //$NON-NLS-1$
        } catch (QueryMetadataException e) {
            throw new QueryPlannerException(e, QueryPlugin.Util.getString("DQPCore.Unknown_query_metadata_exception_while_registering_query__{0}.", requestId)); //$NON-NLS-1$
        }
    }

    public void processRequest()
        throws TeiidComponentException, TeiidProcessingException {
                   
      LogManager.logDetail(LogConstants.CTX_DQP, this.requestId, "executing", this.requestMsg.isPreparedStatement()?"prepared":"", this.requestMsg.getCommandString()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
     
        initMetadata();
       
        generatePlan();
       
        postProcessXML();
       
        createProcessor();
    }

  private void postProcessXML() {
        if (requestMsg.getXMLFormat() != null && processPlan instanceof XMLPlan) {
          ((XMLPlan)processPlan).setXMLFormat(requestMsg.getXMLFormat());
        }
        this.context.setValidateXML(requestMsg.getValidationMode());
  }

  protected void validateAccess(Command command) throws QueryValidatorException, TeiidComponentException {
    this.authorizationValidator.validate(command, metadata, workContext);
  }
 
}
TOP

Related Classes of org.teiid.dqp.internal.process.Request

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.