예제 #1
0
 public LocalClient(String vdbName, int vdbVersion, Properties props) {
   this.vdbName = vdbName;
   this.vdbVersion = vdbVersion;
   this.batchSize =
       PropertiesUtils.getIntProperty(
           props, BATCH_SIZE, BufferManagerImpl.DEFAULT_PROCESSOR_BATCH_SIZE);
   this.cacheTime = PropertiesUtils.getLongProperty(props, SKIPTOKEN_TIME, 300000L);
   this.invalidCharacterReplacement = props.getProperty(INVALID_CHARACTER_REPLACEMENT);
   StringBuilder sb = new StringBuilder();
   sb.append("jdbc:teiid:")
       .append(this.vdbName)
       .append(".")
       .append(this.vdbVersion)
       .append(";"); // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
   this.initProperties = props;
   if (this.initProperties.getProperty(TeiidURL.CONNECTION.PASSTHROUGH_AUTHENTICATION) == null) {
     this.initProperties.put(
         TeiidURL.CONNECTION.PASSTHROUGH_AUTHENTICATION, "true"); // $NON-NLS-1$
   }
   if (this.initProperties.getProperty(EmbeddedProfile.TRANSPORT_NAME) == null) {
     this.initProperties.setProperty(EmbeddedProfile.TRANSPORT_NAME, "odata");
   }
   if (this.initProperties.getProperty(EmbeddedProfile.WAIT_FOR_LOAD) == null) {
     this.initProperties.put(EmbeddedProfile.WAIT_FOR_LOAD, "0"); // $NON-NLS-1$
   }
   this.connectionString = sb.toString();
 }
예제 #2
0
  @Override
  public ConnectionImpl connect(String url, Properties info) throws SQLException {
    ConnectionType conn = JDBCURL.acceptsUrl(url);
    if (conn == null) {
      return null;
    }
    if (info == null) {
      // create a properties obj if it is null
      info = new Properties();
    } else {
      // don't modify the original
      info = PropertiesUtils.clone(info);
    }
    parseURL(url, info);

    ConnectionImpl myConnection = null;

    /*
     * Add the teiid server version to the properties
     */
    info.setProperty(ITeiidServerVersion.TEIID_VERSION_PROPERTY, getTeiidVersion().toString());

    try {
      myConnection = socketProfile.connect(url, info);
    } catch (SQLException e) {
      logger.log(Level.SEVERE, "Could not create connection", e); // $NON-NLS-1$
      throw e;
    }

    // logging
    String logMsg = Messages.getString(Messages.JDBC.Connection_success);
    logger.fine(logMsg);

    return myConnection;
  }
예제 #3
0
  @Override
  public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
    if (info == null) {
      info = new Properties();
    } else {
      info = PropertiesUtils.clone(info);
    }

    // construct list of driverPropertyInfo objects
    List<DriverPropertyInfo> driverProps = new LinkedList<DriverPropertyInfo>();

    parseURL(url, info);

    for (String property : JDBCURL.KNOWN_PROPERTIES.keySet()) {
      DriverPropertyInfo dpi = new DriverPropertyInfo(property, info.getProperty(property));
      if (property.equals(TeiidURL.JDBC.VDB_NAME)) {
        dpi.required = true;
      }
      driverProps.add(dpi);
    }

    // create an array of DriverPropertyInfo objects
    DriverPropertyInfo[] propInfo = new DriverPropertyInfo[driverProps.size()];

    // copy the elements from the list to the array
    return driverProps.toArray(propInfo);
  }
예제 #4
0
  public LocalServerConnection(Properties connectionProperties, boolean useCallingThread)
      throws CommunicationException, ConnectionException {
    this.connectionProperties = connectionProperties;
    this.csr = getClientServiceRegistry();

    String vdbVersion = connectionProperties.getProperty(TeiidURL.JDBC.VDB_VERSION);
    String vdbName = connectionProperties.getProperty(TeiidURL.JDBC.VDB_NAME);
    int firstIndex = vdbName.indexOf('.');
    int lastIndex = vdbName.lastIndexOf('.');
    if (firstIndex != -1 && firstIndex == lastIndex) {
      vdbVersion = vdbName.substring(firstIndex + 1);
      vdbName = vdbName.substring(0, firstIndex);
    }
    if (vdbVersion != null) {
      int waitForLoad =
          PropertiesUtils.getIntProperty(connectionProperties, EmbeddedProfile.WAIT_FOR_LOAD, -1);
      if (waitForLoad != 0) {
        this.csr.waitForFinished(vdbName, Integer.valueOf(vdbVersion), waitForLoad);
      }
    }

    workContext.setSecurityHelper(csr.getSecurityHelper());
    workContext.setUseCallingThread(useCallingThread);
    workContext.setSecurityContext(csr.getSecurityHelper().getSecurityContext());
    authenticate();
    passthrough =
        Boolean.valueOf(
            connectionProperties.getProperty(
                TeiidURL.CONNECTION.PASSTHROUGH_AUTHENTICATION, "false")); // $NON-NLS-1$
  }
예제 #5
0
 /**
  * Implement to provide metadata to the metadata for use by the engine. This is the primary method
  * of creating metadata for dynamic VDBs.
  *
  * @param metadataFactory
  * @param conn may be null if the source is not required
  * @throws TranslatorException to indicate a recoverable error, otherwise a RuntimeException
  * @see #isSourceRequiredForMetadata()
  */
 public void getMetadata(MetadataFactory metadataFactory, C conn) throws TranslatorException {
   MetadataProcessor mp = getMetadataProcessor();
   if (mp != null) {
     PropertiesUtils.setBeanProperties(
         mp, metadataFactory.getModelProperties(), "importer"); // $NON-NLS-1$
     mp.process(metadataFactory, conn);
   }
 }
  public void initialize(Properties info) {
    PropertiesUtils.setBeanProperties(this, info, "org.teiid.sockets"); // $NON-NLS-1$
    this.pingTimer = new Timer("SocketPing", true); // $NON-NLS-1$
    this.pingTimer.schedule(
        new TimerTask() {

          @Override
          public void run() {
            Set<Map.Entry<HostInfo, Set<SessionToken>>> sessionEntries = null;
            synchronized (sessions) {
              sessionEntries =
                  new HashSet<Map.Entry<HostInfo, Set<SessionToken>>>(sessions.entrySet());
            }
            for (Map.Entry<HostInfo, Set<SessionToken>> entry : sessionEntries) {
              SocketServerInstance instance = null;
              HashSet<SessionToken> entries = null;
              synchronized (sessions) {
                entries = new HashSet<SessionToken>(entry.getValue());
              }
              try {
                instance = getServerInstance(entry.getKey());
                ILogon logon = instance.getService(ILogon.class);
                if ("07.01.01".compareTo(instance.getServerVersion()) > 0
                    || //$NON-NLS-1$
                    "7.1.1".compareTo(instance.getServerVersion()) > 0) { // $NON-NLS-1$
                  for (SessionToken session : entries) {
                    try {
                      logon.assertIdentity(session);
                      logon.ping();
                      log.log(Level.FINER, "issueing ping for session:", session); // $NON-NLS-1$
                    } catch (InvalidSessionException e) {
                    }
                  }
                } else {
                  ArrayList<String> sessionStrings = new ArrayList<String>(entry.getValue().size());
                  for (SessionToken session : entries) {
                    sessionStrings.add(session.getSessionID());
                  }
                  logon.ping(sessionStrings);
                  log.log(
                      Level.FINER, "issueing ping for sessions:", sessionStrings); // $NON-NLS-1$
                }
              } catch (Exception e) {
                log.log(Level.WARNING, "Error performing keep-alive ping", e); // $NON-NLS-1$
              } finally {
                if (instance != null) {
                  instance.shutdown();
                }
              }
            }
          }
        },
        ServerConnection.PING_INTERVAL,
        ServerConnection.PING_INTERVAL);
    this.channelFactory = new OioOjbectChannelFactory(info);
  }
  @BeforeClass
  public static void beforeEachClass() throws Exception {
    RemoteInfinispanTestHelper.createServer();

    System.out.println("Hostaddress " + RemoteInfinispanTestHelper.hostAddress());

    // read in the properties template file and set the server host:port and then save for use
    File f = new File("./src/test/resources/hotrod-client.properties");

    Properties props = PropertiesUtils.load(f.getAbsolutePath());
    props.setProperty(
        "infinispan.client.hotrod.server_list",
        RemoteInfinispanTestHelper.hostAddress() + ":" + RemoteInfinispanTestHelper.hostPort());

    PropertiesUtils.print("./target/hotrod-client.properties", props);

    factory = new InfinispanManagedConnectionFactory();

    factory.setHotRodClientPropertiesFile("./target/hotrod-client.properties");
    factory.setCacheTypeMap(RemoteInfinispanTestHelper.CACHE_NAME + ":" + "java.lang.String");
  }
예제 #8
0
/** Teiid's Connection implementation. */
public class ConnectionImpl extends WrapperImpl implements TeiidConnection {
  private static final int MAX_OPEN_STATEMENTS =
      PropertiesUtils.getIntProperty(
          System.getProperties(), "org.teiid.maxOpenStatements", 1000); // $NON-NLS-1$

  private static Logger logger = Logger.getLogger("org.teiid.jdbc"); // $NON-NLS-1$

  public static final int DEFAULT_ISOLATION = Connection.TRANSACTION_READ_COMMITTED;

  // constant value giving product name
  private static final String SERVER_NAME = "Teiid Server"; // $NON-NLS-1$
  private static final String EMBEDDED_NAME = "Teiid Embedded"; // $NON-NLS-1$

  // Unique request ID generator
  private long requestIDGenerator;

  // url used to create the connection
  private String url;

  // properties object containing the connection properties.
  protected Properties propInfo;

  // status of connection object
  private boolean closed = false;
  // determines if a statement executed should be immediately committed.
  private boolean autoCommitFlag = true;
  private boolean inLocalTxn;

  // collection of all open statements on this connection
  private Collection<StatementImpl> statements =
      Collections.newSetFromMap(new ConcurrentHashMap<StatementImpl, Boolean>());
  // cached DatabaseMetadata
  private DatabaseMetaDataImpl dbmm;

  // Xid for participating in TXN
  private XidImpl transactionXid;

  //  Flag to represent if the connection state needs to be readOnly, default value false.
  private boolean readOnly = false;

  private DQP dqp;
  protected ServerConnection serverConn;
  private int transactionIsolation = DEFAULT_ISOLATION;

  //  the last query plan description
  private PlanNode currentPlanDescription;
  // the last query debug log
  private String debugLog;
  // the last query annotations
  private Collection<Annotation> annotations;
  private Properties connectionProps;
  private Properties payload;

  public ConnectionImpl(ServerConnection serverConn, Properties info, String url) {
    this.connectionProps = info;
    this.serverConn = serverConn;
    this.url = url;
    this.dqp = serverConn.getService(DQP.class);

    logger.fine(JDBCPlugin.Util.getString("MMConnection.Session_success")); // $NON-NLS-1$
    logConnectionProperties(url, info);

    setExecutionProperties(info);
  }

  boolean isInLocalTxn() {
    return inLocalTxn;
  }

  private void setExecutionProperties(Properties info) {
    this.propInfo = new Properties();

    String defaultFetchSize = info.getProperty(ExecutionProperties.PROP_FETCH_SIZE);
    if (defaultFetchSize != null) {
      propInfo.put(ExecutionProperties.PROP_FETCH_SIZE, defaultFetchSize);
    } else {
      propInfo.put(
          ExecutionProperties.PROP_FETCH_SIZE, String.valueOf(BaseDataSource.DEFAULT_FETCH_SIZE));
    }

    String partialResultsMode = info.getProperty(ExecutionProperties.PROP_PARTIAL_RESULTS_MODE);
    if (partialResultsMode != null) {
      propInfo.put(ExecutionProperties.PROP_PARTIAL_RESULTS_MODE, partialResultsMode);
    } else {
      propInfo.put(
          ExecutionProperties.PROP_PARTIAL_RESULTS_MODE,
          BaseDataSource.DEFAULT_PARTIAL_RESULTS_MODE);
    }

    String resultSetCacheMode = info.getProperty(ExecutionProperties.RESULT_SET_CACHE_MODE);
    if (resultSetCacheMode != null) {
      propInfo.put(ExecutionProperties.RESULT_SET_CACHE_MODE, resultSetCacheMode);
    } else {
      propInfo.put(
          ExecutionProperties.RESULT_SET_CACHE_MODE, BaseDataSource.DEFAULT_RESULT_SET_CACHE_MODE);
    }

    String ansiQuotes = info.getProperty(ExecutionProperties.ANSI_QUOTED_IDENTIFIERS);
    if (ansiQuotes != null) {
      propInfo.put(ExecutionProperties.ANSI_QUOTED_IDENTIFIERS, ansiQuotes);
    } else {
      propInfo.put(ExecutionProperties.ANSI_QUOTED_IDENTIFIERS, Boolean.TRUE.toString());
    }

    for (String key : info.stringPropertyNames()) {
      String actualKey = JDBCURL.EXECUTION_PROPERTIES.get(key);
      if (actualKey != null) {
        propInfo.setProperty(actualKey, info.getProperty(key));
      }
    }
  }

  public Collection<Annotation> getAnnotations() {
    return annotations;
  }

  public void setAnnotations(Collection<Annotation> annotations) {
    this.annotations = annotations;
  }

  public String getDebugLog() {
    return debugLog;
  }

  public void setDebugLog(String debugLog) {
    this.debugLog = debugLog;
  }

  public PlanNode getCurrentPlanDescription() {
    return currentPlanDescription;
  }

  public void setCurrentPlanDescription(PlanNode currentPlanDescription) {
    this.currentPlanDescription = currentPlanDescription;
  }

  protected Properties getExecutionProperties() {
    return this.propInfo;
  }

  public void setExecutionProperty(String key, String value) {
    JDBCURL.addNormalizedProperty(key, value, getExecutionProperties());
  }

  public String getExecutionProperty(String key) {
    return this.getExecutionProperties().getProperty(JDBCURL.getValidKey(key));
  }

  DQP getDQP() {
    return this.dqp;
  }

  /**
   * Remove password & trusted token and log all other properties
   *
   * @param connUrl - URL used to connect to server
   * @param info - properties object supplied
   */
  private void logConnectionProperties(String connUrl, Properties info) {
    StringBuffer modifiedUrl = new StringBuffer();

    // If we have valid URL
    if (connUrl != null) {
      // We need wipe out the password here, before we write to the log
      int startIndex = connUrl.indexOf("password="******"password=***"); // $NON-NLS-1$
        int endIndex = connUrl.indexOf(";", startIndex + 9); // $NON-NLS-1$
        if (endIndex != -1) {
          modifiedUrl.append(";").append(connUrl.substring(endIndex)); // $NON-NLS-1$
        }
      }
      logger.fine("Connection Url=" + modifiedUrl); // $NON-NLS-1$
    }

    // Now clone the properties object and remove password and trusted token
    if (info != null) {
      Enumeration enumeration = info.keys();
      while (enumeration.hasMoreElements()) {
        String key = (String) enumeration.nextElement();
        Object anObj = info.get(key);
        // Log each property except for password and token.
        if (!TeiidURL.CONNECTION.PASSWORD.equalsIgnoreCase(key)) {
          logger.fine(key + "=" + anObj); // $NON-NLS-1$
        }
      }
    }
  }

  String getUrl() {
    return this.url;
  }

  /**
   * Connection identifier of this connection
   *
   * @return identifier
   * @throws SQLException
   */
  public String getConnectionId() {
    return this.serverConn.getLogonResult().getSessionID();
  }

  /**
   * Generate the next unique requestID for matching up requests with responses. These IDs should be
   * unique only in the context of a ServerConnection instance.
   *
   * @return Request ID
   */
  protected synchronized long nextRequestID() {
    return requestIDGenerator++;
  }

  public void clearWarnings() throws SQLException {
    // do nothing
  }

  public void close() throws SQLException {
    Throwable firstException = null;

    if (closed) {
      return;
    }

    try {
      // close any statements that were created on this connection
      try {
        closeStatements();
      } catch (SQLException se) {
        firstException = se;
      } finally {
        this.serverConn.close();
        if (firstException != null) throw (SQLException) firstException;
      }
    } catch (SQLException se) {
      throw TeiidSQLException.create(
          se,
          JDBCPlugin.Util.getString(
              "MMConnection.Err_connection_close", se.getMessage())); // $NON-NLS-1$
    } finally {
      logger.fine(
          JDBCPlugin.Util.getString("MMConnection.Connection_close_success")); // $NON-NLS-1$
      // set the status of the connection to closed
      closed = true;
    }
  }

  /**
   * Close all the statements open on this connection
   *
   * @throws SQLException server statement object could not be closed.
   */
  void closeStatements() throws SQLException {
    // Closing the statement will cause the
    // MMConnection.closeStatement() method to be called,
    // which will modify this.statements.  So, we do this iteration
    // in a separate safe copy of the list
    List<StatementImpl> statementsSafe = new ArrayList<StatementImpl>(this.statements);
    SQLException ex = null;
    for (StatementImpl statement : statementsSafe) {
      try {
        statement.close();
      } catch (SQLException e) {
        ex = e;
      }
    }
    if (ex != null) {
      throw TeiidSQLException.create(
          ex, JDBCPlugin.Util.getString("MMConnection.Err_closing_stmts")); // $NON-NLS-1$
    }
  }

  /**
   * Called by MMStatement to notify the connection that the statement has been closed.
   *
   * @param statement
   */
  void closeStatement(Statement statement) {
    this.statements.remove(statement);
  }

  /**
   * This method makes any changes involved in a transaction permanent and releases any locks held
   * by the connection object. This is only used when auto-commit is set to false.
   *
   * @throws SQLException if the transaction had been rolled back or marked to roll back.
   */
  public void commit() throws SQLException {
    checkConnection();
    if (!autoCommitFlag) {
      try {
        directCommit();
      } finally {
        inLocalTxn = false;
      }
    }
  }

  private void directCommit() throws SQLException {
    if (inLocalTxn) {
      try {
        ResultsFuture<?> future = this.dqp.commit();
        future.get();
      } catch (Exception e) {
        throw TeiidSQLException.create(e);
      }
      logger.fine(JDBCPlugin.Util.getString("MMConnection.Commit_success")); // $NON-NLS-1$
    }
  }

  void beginLocalTxnIfNeeded() throws SQLException {
    if (this.transactionXid != null || inLocalTxn || this.autoCommitFlag || isDisableLocalTxn()) {
      return;
    }
    try {
      try {
        this.dqp.begin();
      } catch (XATransactionException e) {
        throw TeiidSQLException.create(e);
      }
      inLocalTxn = true;
    } finally {
      if (!inLocalTxn) {
        autoCommitFlag = true;
      }
    }
  }

  private boolean isDisableLocalTxn() {
    String prop = this.propInfo.getProperty(ExecutionProperties.DISABLE_LOCAL_TRANSACTIONS);
    return prop != null && Boolean.valueOf(prop);
  }

  public StatementImpl createStatement() throws SQLException {
    return createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
  }

  /**
   * Creates a Statement object that will produce ResultSet objects of the type resultSetType and
   * concurrency level resultSetConcurrency.
   *
   * @param intvalue indicating the ResultSet's type
   * @param intValue indicating the ResultSet's concurrency
   * @return Statement object.
   */
  public StatementImpl createStatement(int resultSetType, int resultSetConcurrency)
      throws SQLException {
    return createStatement(resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
  }

  /**
   * @param resultSetType
   * @throws TeiidSQLException
   * @since 4.3
   */
  private void validateResultSetType(int resultSetType) throws TeiidSQLException {
    if (resultSetType == ResultSet.TYPE_SCROLL_SENSITIVE) {
      String msg =
          JDBCPlugin.Util.getString(
              "MMConnection.Scrollable_type_not_supported",
              "ResultSet.TYPE_SCROLL_SENSITIVE"); //$NON-NLS-1$ //$NON-NLS-2$
      throw new TeiidSQLException(msg);
    }
  }

  /**
   * @param resultSetConcurrency
   * @throws TeiidSQLException
   * @since 4.3
   */
  private void validateResultSetConcurrency(int resultSetConcurrency) throws TeiidSQLException {
    if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE) {
      String msg =
          JDBCPlugin.Util.getString(
              "MMConnection.Concurrency_type_not_supported",
              "ResultSet.CONCUR_UPDATABLE"); //$NON-NLS-1$ //$NON-NLS-2$
      throw new TeiidSQLException(msg);
    }
  }

  public boolean getAutoCommit() throws SQLException {
    // Check to see the connection is open
    checkConnection();
    return autoCommitFlag;
  }

  public String getCatalog() throws SQLException {
    // Check to see the connection is open
    checkConnection();
    // catalogs are not supported
    return this.serverConn.getLogonResult().getVdbName();
  }

  /**
   * This method gets the ServerConnection object wrapped by this object.
   *
   * @return ServerConnection object
   */
  public ServerConnection getServerConnection() throws SQLException {
    // Check to see the connection is open
    checkConnection();
    return serverConn;
  }

  String getVDBName() throws SQLException {
    // Check to see the connection is open
    checkConnection();
    // get the virtual database name to which we are connected.

    return this.serverConn.getLogonResult().getVdbName();
  }

  public int getVDBVersion() throws SQLException {
    checkConnection();
    return this.serverConn.getLogonResult().getVdbVersion();
  }

  /**
   * Get's the name of the user who got this connection.
   *
   * @return Sring object giving the user name
   * @throws SQLException if the connection is closed
   */
  String getUserName() throws SQLException {
    checkConnection();

    return this.serverConn.getLogonResult().getUserName();
  }

  public DatabaseMetaDataImpl getMetaData() throws SQLException {
    // Check to see the connection is open
    checkConnection();

    if (dbmm == null) {
      dbmm = new DatabaseMetaDataImpl(this);
    }
    return dbmm;
  }

  /**
   * Get the database name that this connection is representing
   *
   * @return String name of the database
   */
  public String getDatabaseName() {
    if (this.serverConn instanceof SocketServerConnection) {
      return SERVER_NAME;
    }
    return EMBEDDED_NAME;
  }

  /**
   * Retrieves the current holdability of ResultSet objects created using this Connection object.
   *
   * @param holdability int indicating the holdability
   * @return int holdability
   * @throws SQLException
   */
  public int getHoldability() throws SQLException {
    return ResultSet.HOLD_CURSORS_OVER_COMMIT;
  }

  public int getTransactionIsolation() throws SQLException {
    return this.transactionIsolation;
  }

  @Override
  public Map<String, Class<?>> getTypeMap() throws SQLException {
    return Collections.emptyMap();
  }

  /**
   * This method will return the first warning reported by calls on this connection, or null if none
   * exist.
   *
   * @return A SQLWarning object if there are any warnings.
   * @throws SQLException, should never occur
   */
  public SQLWarning getWarnings() throws SQLException {
    // Check to see the connection is open
    checkConnection();
    return null; // we don't have any warnings
  }

  /**
   * This method will return whether this connection is closed or not.
   *
   * @return booleanvalue indicating if the connection is closed
   * @throws SQLException, should never occur
   */
  public boolean isClosed() throws SQLException {
    return closed;
  }

  public boolean isReadOnly() throws SQLException {
    return readOnly;
  }

  public String nativeSQL(String sql) throws SQLException {
    // return the string argument without any modifications.
    // escape syntaxes are directly supported in the server
    return sql;
  }

  /**
   * Creates a CallableStatement object that contains sql and that will produce ResultSet objects
   * that are non-scrollable and non-updatable. A SQL stored procedure call statement is handled by
   * creating a CallableStatement for it.
   *
   * @param sql String(escape syntax) for invoking a stored procedure.
   * @return CallableStatement object that can be used to execute the storedProcedure
   * @throws SQLException if there is an error creating the callable statement object
   */
  public CallableStatementImpl prepareCall(String sql) throws SQLException {
    // there is a problem setting the result set type to be non-scrollable
    // See defect 17768
    return prepareCall(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
  }

  /**
   * Creates a CallableStatement object that contains a sql and that will produce ResultSet objects
   * of the type resultSetType and with a concurrency level of resultSetConcurrency. A SQL stored
   * procedure call statement is handled by creating a CallableStatement for it.
   *
   * @param sql String(escape syntax) for invoking a stored procedure.
   * @param intvalue indicating the ResultSet's type
   * @param intValue indicating the ResultSet's concurrency
   * @return CallableStatement object that can be used to execute the storedProcedure
   */
  public CallableStatementImpl prepareCall(String sql, int resultSetType, int resultSetConcurrency)
      throws SQLException {
    return prepareCall(
        sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
  }

  /**
   * @param sql
   * @throws TeiidSQLException
   * @since 4.3
   */
  private void validateSQL(String sql) throws TeiidSQLException {
    if (sql == null) {
      String msg = JDBCPlugin.Util.getString("MMConnection.SQL_cannot_be_null"); // $NON-NLS-1$
      throw new TeiidSQLException(msg);
    }
  }

  public PreparedStatementImpl prepareStatement(String sql) throws SQLException {
    return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
  }

  public PreparedStatementImpl prepareStatement(
      String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
    return prepareStatement(
        sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
  }

  public PreparedStatementImpl prepareStatement(
      String sql,
      int resultSetType,
      int resultSetConcurrency,
      int resultSetHoldability,
      int autoGeneratedKeys)
      throws SQLException {
    // Check to see the connection is open
    checkConnection();

    validateResultSetType(resultSetType);
    validateResultSetConcurrency(resultSetConcurrency);
    validateSQL(sql);

    // add the statement object to the map
    PreparedStatementImpl newStatement =
        new PreparedStatementImpl(this, sql, resultSetType, resultSetConcurrency);
    newStatement.setAutoGeneratedKeys(autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS);
    addStatement(newStatement);
    return newStatement;
  }

  public PreparedStatementImpl prepareStatement(
      String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
      throws SQLException {
    return prepareStatement(
        sql,
        resultSetType,
        resultSetConcurrency,
        resultSetHoldability,
        Statement.NO_GENERATED_KEYS);
  }

  public void rollback() throws SQLException {
    rollback(true);
  }

  /**
   * Rollback the current local transaction
   *
   * @param startTxn
   * @throws SQLException
   */
  public void rollback(boolean startTxn) throws SQLException {

    // Check to see the connection is open
    checkConnection();
    if (!autoCommitFlag) {
      try {
        if (this.inLocalTxn) {
          this.inLocalTxn = false;
          try {
            ResultsFuture<?> future = this.dqp.rollback();
            future.get();
          } catch (Exception e) {
            throw TeiidSQLException.create(e);
          }
          logger.fine(JDBCPlugin.Util.getString("MMConnection.Rollback_success")); // $NON-NLS-1$
        }
      } finally {
        if (startTxn) {
          this.inLocalTxn = false;
        } else {
          this.autoCommitFlag = true;
        }
      }
    }
  }

  public ResultsFuture<?> submitSetAutoCommitTrue(boolean commit) throws SQLException {
    // Check to see the connection is open
    checkConnection();

    if (this.autoCommitFlag) {
      return ResultsFuture.NULL_FUTURE;
    }

    this.autoCommitFlag = true;

    if (isDisableLocalTxn()) {
      return ResultsFuture.NULL_FUTURE;
    }

    try {
      if (commit) {
        return dqp.commit();
      }
      return dqp.rollback();
    } catch (XATransactionException e) {
      throw TeiidSQLException.create(e);
    }
  }

  public void setAutoCommit(boolean autoCommit) throws SQLException {
    // Check to see the connection is open
    checkConnection();

    if (autoCommit == this.autoCommitFlag) {
      return;
    }

    this.autoCommitFlag = autoCommit;

    if (autoCommit) {
      directCommit();
    } else {
      inLocalTxn = false;
    }
  }

  /**
   * Teiid does not allow setting a catalog through a connection. This method silently ignores the
   * request as per the specification.
   *
   * @param The string values which sets the catalog name on the connection.
   * @throws SQLException This should never occur.
   */
  public void setCatalog(String catalog) throws SQLException {
    // do nothing, silently ignore the request
  }

  /**
   * @param A boolean value specifying whether the connection is readonly.
   * @throws throws SQLException.
   */
  public void setReadOnly(boolean readOnly) throws SQLException {
    if (this.readOnly == readOnly) {
      return;
    }
    // During transaction do not allow to change this flag
    if (!autoCommitFlag || this.transactionXid != null) {
      throw new TeiidSQLException(
          JDBCPlugin.Util.getString(
              "MMStatement.Invalid_During_Transaction",
              "setReadOnly(" + readOnly + ")")); // $NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
    }
    this.readOnly = readOnly;
  }

  /**
   * This utility method checks if the jdbc connection is closed and throws an exception if it is
   * closed.
   *
   * @throws SQLException if the connection object is closed.
   */
  void checkConnection() throws SQLException {
    // Check to see the connection is closed and proceed if it is not
    if (closed) {
      throw new TeiidSQLException(
          JDBCPlugin.Util.getString("MMConnection.Cant_use_closed_connection")); // $NON-NLS-1$
    }
  }

  protected void commitTransaction(XidImpl arg0, boolean arg1) throws SQLException {
    checkConnection();
    transactionXid = null;
    this.autoCommitFlag = true;
    try {
      ResultsFuture<?> future = this.dqp.commit(arg0, arg1);
      future.get();
    } catch (Exception e) {
      throw TeiidSQLException.create(e);
    }
  }

  protected void endTransaction(XidImpl arg0, int arg1) throws SQLException {
    checkConnection();
    this.autoCommitFlag = true;
    try {
      ResultsFuture<?> future = this.dqp.end(arg0, arg1);
      future.get();
    } catch (Exception e) {
      throw TeiidSQLException.create(e);
    }
  }

  protected void forgetTransaction(XidImpl arg0) throws SQLException {
    checkConnection();
    try {
      ResultsFuture<?> future = this.dqp.forget(arg0);
      future.get();
    } catch (Exception e) {
      throw TeiidSQLException.create(e);
    }
  }

  protected int prepareTransaction(XidImpl arg0) throws SQLException {
    checkConnection();
    transactionXid = null;
    try {
      ResultsFuture<Integer> future = this.dqp.prepare(arg0);
      return future.get();
    } catch (Exception e) {
      throw TeiidSQLException.create(e);
    }
  }

  protected Xid[] recoverTransaction(int arg0) throws SQLException {
    checkConnection();
    try {
      ResultsFuture<Xid[]> future = this.dqp.recover(arg0);
      return future.get();
    } catch (Exception e) {
      throw TeiidSQLException.create(e);
    }
  }

  protected void rollbackTransaction(XidImpl arg0) throws SQLException {
    checkConnection();
    transactionXid = null;
    this.autoCommitFlag = true;
    try {
      ResultsFuture<?> future = this.dqp.rollback(arg0);
      future.get();
    } catch (Exception e) {
      throw TeiidSQLException.create(e);
    }
  }

  protected void startTransaction(XidImpl arg0, int arg1, int timeout) throws SQLException {
    checkConnection();
    try {
      ResultsFuture<?> future = this.dqp.start(arg0, arg1, timeout);
      future.get();
    } catch (Exception e) {
      throw TeiidSQLException.create(e);
    }
    transactionXid = arg0;
    this.autoCommitFlag = false;
  }

  protected XidImpl getTransactionXid() {
    return transactionXid;
  }

  public boolean isValid(int timeout) throws SQLException {
    return this.getServerConnection().isOpen(timeout * 1000);
  }

  public void recycleConnection(boolean selectNewInstance) {
    this.payload = null;
    try {
      // close all open statements
      this.closeStatements();
    } catch (SQLException e) {
      logger.log(
          Level.WARNING,
          JDBCPlugin.Util.getString("MMXAConnection.rolling_back_error"),
          e); //$NON-NLS-1$
    }
    try {
      // rollback if still in a transaction
      if (!this.getAutoCommit()) {
        logger.warning(JDBCPlugin.Util.getString("MMXAConnection.rolling_back")); // $NON-NLS-1$

        if (this.getTransactionXid() == null) {
          this.rollback(false);
        } else {
          this.rollbackTransaction(getTransactionXid());
        }
      }
    } catch (SQLException e) {
      logger.log(
          Level.WARNING,
          JDBCPlugin.Util.getString("MMXAConnection.rolling_back_error"),
          e); //$NON-NLS-1$
    }

    if (selectNewInstance) {
      this.serverConn.cleanUp();
    }
  }

  public boolean isSameProcess(ConnectionImpl conn) throws CommunicationException {
    return this.serverConn.isSameInstance(conn.serverConn);
  }

  public void setClientInfo(Properties properties) throws SQLClientInfoException {}

  public void setClientInfo(String name, String value) throws SQLClientInfoException {}

  public Properties getClientInfo() throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public String getClientInfo(String name) throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
    return new ArrayImpl(elements);
  }

  public Blob createBlob() throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public Clob createClob() throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public NClob createNClob() throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public SQLXML createSQLXML() throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public StatementImpl createStatement(
      int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
    // Check to see the connection is open
    checkConnection();

    validateResultSetType(resultSetType);
    validateResultSetConcurrency(resultSetConcurrency);
    // TODO: implement close cursors at commit

    // add the statement object to the map
    StatementImpl newStatement = new StatementImpl(this, resultSetType, resultSetConcurrency);
    addStatement(newStatement);

    return newStatement;
  }

  private void addStatement(StatementImpl newStatement) throws SQLException {
    if (statements.size() > MAX_OPEN_STATEMENTS) {
      this.close();
      throw new TeiidSQLException(
          JDBCPlugin.Util.gs(JDBCPlugin.Event.TEIID20036, MAX_OPEN_STATEMENTS));
    }
    statements.add(newStatement);
  }

  public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public CallableStatementImpl prepareCall(
      String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
      throws SQLException {
    // Check to see the connection is open
    checkConnection();

    validateResultSetType(resultSetType);
    validateResultSetConcurrency(resultSetConcurrency);
    validateSQL(sql);
    // TODO: implement close cursors at commit

    // add the statement object to the map
    CallableStatementImpl newStatement =
        new CallableStatementImpl(this, sql, resultSetType, resultSetConcurrency);
    addStatement(newStatement);
    return newStatement;
  }

  public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
    return prepareStatement(
        sql,
        ResultSet.TYPE_FORWARD_ONLY,
        ResultSet.CONCUR_READ_ONLY,
        ResultSet.HOLD_CURSORS_OVER_COMMIT,
        Statement.RETURN_GENERATED_KEYS);
  }

  public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
    return prepareStatement(
        sql,
        ResultSet.TYPE_FORWARD_ONLY,
        ResultSet.CONCUR_READ_ONLY,
        ResultSet.HOLD_CURSORS_OVER_COMMIT,
        Statement.RETURN_GENERATED_KEYS);
  }

  public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
    return prepareStatement(
        sql,
        ResultSet.TYPE_FORWARD_ONLY,
        ResultSet.CONCUR_READ_ONLY,
        ResultSet.HOLD_CURSORS_OVER_COMMIT,
        Statement.RETURN_GENERATED_KEYS);
  }

  public void releaseSavepoint(Savepoint savepoint) throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public void rollback(Savepoint savepoint) throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public void setHoldability(int holdability) throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public Savepoint setSavepoint() throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public Savepoint setSavepoint(String name) throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public void setTransactionIsolation(int level) throws SQLException {
    this.transactionIsolation = level;
  }

  public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  Object setPassword(Object newPassword) {
    if (newPassword != null) {
      return this.connectionProps.put(TeiidURL.CONNECTION.PASSWORD, newPassword);
    }
    return this.connectionProps.remove(TeiidURL.CONNECTION.PASSWORD);
  }

  String getPassword() {
    Object result = this.connectionProps.get(TeiidURL.CONNECTION.PASSWORD);
    if (result == null) {
      return null;
    }
    return result.toString();
  }

  @Override
  public void changeUser(String userName, String newPassword) throws SQLException {
    // TODO: recycleConnection();
    Object oldName = null;
    Object oldPassword = null;
    if (userName != null) {
      oldName = this.connectionProps.put(TeiidURL.CONNECTION.USER_NAME, userName);
    } else {
      oldName = this.connectionProps.remove(TeiidURL.CONNECTION.USER_NAME);
    }
    oldPassword = setPassword(newPassword);
    boolean success = false;
    try {
      this.serverConn.authenticate();
      success = true;
    } catch (ConnectionException e) {
      throw TeiidSQLException.create(e);
    } catch (CommunicationException e) {
      throw TeiidSQLException.create(e);
    } finally {
      if (!success) {
        if (oldName != null) {
          this.connectionProps.put(TeiidURL.CONNECTION.USER_NAME, oldName);
        } else {
          this.connectionProps.remove(TeiidURL.CONNECTION.USER_NAME);
        }
        setPassword(oldPassword);
      }
    }
  }

  public void abort(Executor executor) throws SQLException {
    if (closed) {
      return;
    }
    // TODO: ensure that threads are released.  In theory they will be since close effectively
    // cancels current executions
    close();
  }

  public int getNetworkTimeout() throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public String getSchema() throws SQLException {
    return null;
  }

  /** @see query timeouts and the synchronousTtl setting if using socket connections */
  public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
    throw SqlUtil.createFeatureNotSupportedException();
  }

  public void setSchema(String schema) throws SQLException {}

  public Properties getPayload() {
    return payload;
  }

  public void setPayload(Properties payload) {
    this.payload = payload;
  }

  public Properties getConnectionProps() {
    return connectionProps;
  }
}
/**
 * The FunctionDescriptor describes a particular function instance enough to invoke the function.
 */
public class FunctionDescriptor implements Serializable, Cloneable {
  private static final long serialVersionUID = 5374103983118037242L;

  private static final boolean ALLOW_NAN_INFINITY =
      PropertiesUtils.getBooleanProperty(
          System.getProperties(), "org.teiid.allowNanInfinity", false); // $NON-NLS-1$

  private Class<?>[] types;
  private Class<?> returnType;
  private boolean requiresContext;
  private FunctionMethod method;
  private String
      schema; // TODO: remove me - we need to create a proper schema for udf and system functions
  private boolean hasWrappedArgs;
  private boolean
      calledWithVarArgArrayParam; // TODO: could store this on the function and pass to invoke

  // This is transient as it would be useless to invoke this method in
  // a different VM.  This function descriptor can be used to look up
  // the real VM descriptor for execution.
  private transient Method invocationMethod;

  FunctionDescriptor() {}

  FunctionDescriptor(
      FunctionMethod method,
      Class<?>[] types,
      Class<?> outputType,
      Method invocationMethod,
      boolean requiresContext) {
    this.types = types;
    this.returnType = outputType;
    this.invocationMethod = invocationMethod;
    this.requiresContext = requiresContext;
    this.method = method;
  }

  public Object newInstance() {
    try {
      return invocationMethod.getDeclaringClass().newInstance();
    } catch (InstantiationException e) {
      throw new TeiidRuntimeException(
          QueryPlugin.Event.TEIID30602,
          QueryPlugin.Util.gs(
              QueryPlugin.Event.TEIID30602, method.getName(), method.getInvocationClass()));
    } catch (IllegalAccessException e) {
      throw new TeiidRuntimeException(
          QueryPlugin.Event.TEIID30602,
          QueryPlugin.Util.gs(
              QueryPlugin.Event.TEIID30602, method.getName(), method.getInvocationClass()));
    }
  }

  public void setHasWrappedArgs(boolean hasWrappedArgs) {
    this.hasWrappedArgs = hasWrappedArgs;
  }

  public String getSchema() {
    return schema;
  }

  public void setSchema(String schema) {
    this.schema = schema;
  }

  public String getName() {
    return this.method.getName();
  }

  public String getFullName() {
    if (CoreConstants.SYSTEM_MODEL.equals(this.schema)) {
      return getName();
    }
    return this.schema + AbstractMetadataRecord.NAME_DELIM_CHAR + getName();
  }

  public PushDown getPushdown() {
    return this.method.getPushdown();
  }

  public Class<?>[] getTypes() {
    return this.types;
  }

  public Class<?> getReturnType() {
    return this.returnType;
  }

  Method getInvocationMethod() {
    return this.invocationMethod;
  }

  public boolean requiresContext() {
    return this.requiresContext;
  }

  @Override
  public String toString() {
    StringBuffer str = new StringBuffer(this.method.getName());
    str.append("("); // $NON-NLS-1$
    for (int i = 0; i < types.length; i++) {
      if (types[i] != null) {
        str.append(types[i].getName());
      } else {
        str.append("null"); // $NON-NLS-1$
      }
      if (i < (types.length - 1)) {
        str.append(", "); // $NON-NLS-1$
      }
    }
    str.append(") : "); // $NON-NLS-1$
    if (returnType == null) {
      str.append("null"); // $NON-NLS-1$
    } else {
      str.append(returnType.getName());
    }
    return str.toString();
  }

  public boolean isNullDependent() {
    return !this.method.isNullOnNull();
  }

  public Determinism getDeterministic() {
    return this.method.getDeterminism();
  }

  @Override
  public FunctionDescriptor clone() {
    try {
      return (FunctionDescriptor) super.clone();
    } catch (CloneNotSupportedException e) {
      throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30381, e);
    }
  }

  public FunctionMethod getMethod() {
    return method;
  }

  void setReturnType(Class<?> returnType) {
    this.returnType = returnType;
  }

  /**
   * Invoke the function described in the function descriptor, using the values provided. Return the
   * result of the function.
   *
   * @param values Values that should match 1-to-1 with the types described in the function
   *     descriptor
   * @param context
   * @param functionTarget TODO
   * @param fd Function descriptor describing the name and types of the arguments
   * @return Result of invoking the function
   */
  public Object invokeFunction(Object[] values, CommandContext context, Object functionTarget)
      throws FunctionExecutionException, BlockedException {
    if (!isNullDependent()) {
      for (int i = requiresContext ? 1 : 0; i < values.length; i++) {
        if (values[i] == null) {
          return null;
        }
      }
    }

    // If descriptor is missing invokable method, find this VM's descriptor
    // give name and types from fd
    if (invocationMethod == null) {
      throw new FunctionExecutionException(
          QueryPlugin.Event.TEIID30382,
          QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30382, getFullName()));
    }

    // Invoke the method and return the result
    try {
      if (hasWrappedArgs) {
        for (int i = 0; i < values.length; i++) {
          Object val = values[i];
          if (val != null && types[i] == DataTypeManager.DefaultDataClasses.VARBINARY) {
            values[i] = ((BinaryType) val).getBytesDirect();
          }
        }
      }
      if (method.isVarArgs()) {
        if (calledWithVarArgArrayParam) {
          ArrayImpl av = (ArrayImpl) values[values.length - 1];
          if (av != null) {
            Object[] vals = av.getValues();
            values[values.length - 1] = vals;
            if (hasWrappedArgs
                && types[types.length - 1] == DataTypeManager.DefaultDataClasses.VARBINARY) {
              vals = Arrays.copyOf(vals, vals.length);
              for (int i = 0; i < vals.length; i++) {
                if (vals[i] != null) {
                  vals[i] = ((BinaryType) vals[i]).getBytesDirect();
                }
              }
              values[values.length - 1] = vals;
            }
            Class<?> arrayType = invocationMethod.getParameterTypes()[types.length - 1];
            if (arrayType.getComponentType() != Object.class && vals.getClass() != arrayType) {
              Object varArgs = Array.newInstance(arrayType.getComponentType(), vals.length);
              for (int i = 0; i < vals.length; i++) {
                Array.set(varArgs, i, vals[i]);
              }
              values[values.length - 1] = varArgs;
            }
          }
        } else {
          int i = invocationMethod.getParameterTypes().length;
          Object[] newValues = Arrays.copyOf(values, i);
          Object varArgs = null;
          if (invocationMethod.getParameterTypes()[i - 1].getComponentType() != Object.class) {
            int varArgCount = values.length - i + 1;
            varArgs =
                Array.newInstance(
                    invocationMethod.getParameterTypes()[i - 1].getComponentType(), varArgCount);
            for (int j = 0; j < varArgCount; j++) {
              Array.set(varArgs, j, values[i - 1 + j]);
            }
          } else {
            varArgs = Arrays.copyOfRange(values, i - 1, values.length);
          }
          newValues[i - 1] = varArgs;
          values = newValues;
        }
      }
      Object result = invocationMethod.invoke(functionTarget, values);
      if (context != null
          && getDeterministic().ordinal() <= Determinism.USER_DETERMINISTIC.ordinal()) {
        context.setDeterminismLevel(getDeterministic());
      }
      return importValue(result, getReturnType());
    } catch (ArithmeticException e) {
      throw new FunctionExecutionException(
          QueryPlugin.Event.TEIID30384,
          e,
          QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30384, getFullName()));
    } catch (InvocationTargetException e) {
      if (e.getTargetException() instanceof BlockedException) {
        throw (BlockedException) e.getTargetException();
      }
      throw new FunctionExecutionException(
          QueryPlugin.Event.TEIID30384,
          e.getTargetException(),
          QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30384, getFullName()));
    } catch (IllegalAccessException e) {
      throw new FunctionExecutionException(
          QueryPlugin.Event.TEIID30385,
          e,
          QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30385, method.toString()));
    } catch (TransformationException e) {
      throw new FunctionExecutionException(e);
    }
  }

  public static Object importValue(Object result, Class<?> expectedType)
      throws ArithmeticException, TransformationException {
    if (!ALLOW_NAN_INFINITY) {
      if (result instanceof Double) {
        Double floatVal = (Double) result;
        if (Double.isInfinite(floatVal) || Double.isNaN(floatVal)) {
          throw new ArithmeticException("Infinite or invalid result"); // $NON-NLS-1$
        }
      } else if (result instanceof Float) {
        Float floatVal = (Float) result;
        if (Float.isInfinite(floatVal) || Float.isNaN(floatVal)) {
          throw new ArithmeticException("Infinite or invalid result"); // $NON-NLS-1$
        }
      }
    }
    result =
        DataTypeManager.convertToRuntimeType(
            result, expectedType != DataTypeManager.DefaultDataClasses.OBJECT);
    if (expectedType.isArray() && result instanceof ArrayImpl) {
      return result;
    }
    result = DataTypeManager.transformValue(result, expectedType);
    if (result instanceof String) {
      String s = (String) result;
      if (s.length() > DataTypeManager.MAX_STRING_LENGTH) {
        return s.substring(0, DataTypeManager.MAX_STRING_LENGTH);
      }
    }
    return result;
  }

  public boolean isCalledWithVarArgArrayParam() {
    return calledWithVarArgArrayParam;
  }

  public void setCalledWithVarArgArrayParam(boolean calledWithVarArgArrayParam) {
    this.calledWithVarArgArrayParam = calledWithVarArgArrayParam;
  }

  public boolean isSystemFunction(String name) {
    return this.getName().equalsIgnoreCase(name)
        && CoreConstants.SYSTEM_MODEL.equals(this.getSchema());
  }
}
예제 #10
0
/** Represents the runtime state of a vdb that may aggregate several vdbs. */
public class CompositeVDB {

  private static final boolean WIDEN_COMPARISON_TO_STRING =
      PropertiesUtils.getBooleanProperty(
          System.getProperties(), "org.teiid.widenComparisonToString", true); // $NON-NLS-1$

  private VDBMetaData vdb;
  private MetadataStore store;
  private LinkedHashMap<String, VDBResources.Resource> visibilityMap;
  private UDFMetaData udf;
  LinkedHashMap<VDBKey, CompositeVDB> children;
  private MetadataStore[] additionalStores;
  private ConnectorManagerRepository cmr;
  private FunctionTree systemFunctions;
  private boolean metadataloadFinished = false;
  private VDBMetaData mergedVDB;
  private VDBMetaData originalVDB;
  private Collection<Future<?>> tasks = Collections.synchronizedSet(new HashSet<Future<?>>());

  public CompositeVDB(
      VDBMetaData vdb,
      MetadataStore metadataStore,
      LinkedHashMap<String, VDBResources.Resource> visibilityMap,
      UDFMetaData udf,
      FunctionTree systemFunctions,
      ConnectorManagerRepository cmr,
      VDBRepository vdbRepository,
      MetadataStore... additionalStores)
      throws VirtualDatabaseException {
    this.vdb = vdb;
    this.store = metadataStore;
    this.visibilityMap = visibilityMap;
    this.udf = udf;
    this.systemFunctions = systemFunctions;
    this.cmr = cmr;
    this.additionalStores = additionalStores;
    this.mergedVDB = vdb;
    this.originalVDB = vdb;
    buildCompositeState(vdbRepository);
  }

  private static TransformationMetadata buildTransformationMetaData(
      VDBMetaData vdb,
      LinkedHashMap<String, VDBResources.Resource> visibilityMap,
      MetadataStore store,
      UDFMetaData udf,
      FunctionTree systemFunctions,
      MetadataStore[] additionalStores) {
    Collection<FunctionTree> udfs = new ArrayList<FunctionTree>();
    if (udf != null) {
      for (Map.Entry<String, UDFSource> entry : udf.getFunctions().entrySet()) {
        udfs.add(new FunctionTree(entry.getKey(), entry.getValue(), true));
      }
    }

    CompositeMetadataStore compositeStore = new CompositeMetadataStore(store);
    for (MetadataStore s : additionalStores) {
      compositeStore.merge(s);
      for (Schema schema : s.getSchemas().values()) {
        if (!schema.getFunctions().isEmpty()) {
          UDFSource source = new UDFSource(schema.getFunctions().values());
          if (udf != null) {
            source.setClassLoader(udf.getClassLoader());
          }
          udfs.add(new FunctionTree(schema.getName(), source, true));
        }
        if (!schema.getProcedures().isEmpty()) {
          FunctionTree ft = FunctionTree.getFunctionProcedures(schema);
          if (ft != null) {
            udfs.add(ft);
          }
        }
      }
    }

    TransformationMetadata metadata =
        new TransformationMetadata(vdb, compositeStore, visibilityMap, systemFunctions, udfs);
    metadata.setUseOutputNames(false);
    metadata.setWidenComparisonToString(WIDEN_COMPARISON_TO_STRING);
    return metadata;
  }

  public VDBMetaData getVDB() {
    return this.mergedVDB;
  }

  private void buildCompositeState(VDBRepository vdbRepository) throws VirtualDatabaseException {
    if (vdb.getVDBImports().isEmpty()) {
      this.vdb.addAttchment(ConnectorManagerRepository.class, this.cmr);
      return;
    }

    VDBMetaData newMergedVDB = this.vdb.clone();
    ConnectorManagerRepository mergedRepo = this.cmr;
    if (!this.cmr.isShared()) {
      mergedRepo = new ConnectorManagerRepository();
      mergedRepo.getConnectorManagers().putAll(this.cmr.getConnectorManagers());
    }
    newMergedVDB.addAttchment(ConnectorManagerRepository.class, mergedRepo);
    ClassLoader[] toSearch = new ClassLoader[vdb.getVDBImports().size() + 1];
    toSearch[0] = this.vdb.getAttachment(ClassLoader.class);
    this.children = new LinkedHashMap<VDBKey, CompositeVDB>();
    newMergedVDB.setImportedModels(new TreeSet<String>(String.CASE_INSENSITIVE_ORDER));
    int i = 1;
    for (VDBImport vdbImport : vdb.getVDBImports()) {
      CompositeVDB importedVDB =
          vdbRepository.getCompositeVDB(new VDBKey(vdbImport.getName(), vdbImport.getVersion()));
      if (importedVDB == null) {
        throw new VirtualDatabaseException(
            RuntimePlugin.Event.TEIID40083,
            RuntimePlugin.Util.gs(
                RuntimePlugin.Event.TEIID40083,
                vdb.getName(),
                vdb.getVersion(),
                vdbImport.getName(),
                vdbImport.getVersion()));
      }
      VDBMetaData childVDB = importedVDB.getVDB();
      newMergedVDB.getVisibilityOverrides().putAll(childVDB.getVisibilityOverrides());
      toSearch[i++] = childVDB.getAttachment(ClassLoader.class);
      this.children.put(new VDBKey(childVDB.getName(), childVDB.getVersion()), importedVDB);

      if (vdbImport.isImportDataPolicies()) {
        for (DataPolicy dp : importedVDB.getVDB().getDataPolicies()) {
          DataPolicyMetadata role = (DataPolicyMetadata) dp;
          if (newMergedVDB.addDataPolicy(role) != null) {
            throw new VirtualDatabaseException(
                RuntimePlugin.Event.TEIID40084,
                RuntimePlugin.Util.gs(
                    RuntimePlugin.Event.TEIID40084,
                    vdb.getName(),
                    vdb.getVersion(),
                    vdbImport.getName(),
                    vdbImport.getVersion(),
                    role.getName()));
          }
          if (role.isGrantAll()) {
            role.setSchemas(childVDB.getModelMetaDatas().keySet());
          }
        }
      }

      // add models
      for (ModelMetaData m : childVDB.getModelMetaDatas().values()) {
        if (newMergedVDB.addModel(m) != null) {
          throw new VirtualDatabaseException(
              RuntimePlugin.Event.TEIID40085,
              RuntimePlugin.Util.gs(
                  RuntimePlugin.Event.TEIID40085,
                  vdb.getName(),
                  vdb.getVersion(),
                  vdbImport.getName(),
                  vdbImport.getVersion(),
                  m.getName()));
        }
        newMergedVDB.getImportedModels().add(m.getName());
        String visibilityOverride =
            newMergedVDB.getPropertyValue(m.getName() + ".visible"); // $NON-NLS-1$
        if (visibilityOverride != null) {
          boolean visible = Boolean.valueOf(visibilityOverride);
          newMergedVDB.setVisibilityOverride(m.getName(), visible);
        }
      }
      ConnectorManagerRepository childCmr =
          childVDB.getAttachment(ConnectorManagerRepository.class);
      if (childCmr == null) {
        throw new AssertionError("childVdb had not connector manager repository"); // $NON-NLS-1$
      }
      if (!this.cmr.isShared()) {
        for (Map.Entry<String, ConnectorManager> entry :
            childCmr.getConnectorManagers().entrySet()) {
          if (mergedRepo.getConnectorManagers().put(entry.getKey(), entry.getValue()) != null) {
            throw new VirtualDatabaseException(
                RuntimePlugin.Event.TEIID40086,
                RuntimePlugin.Util.gs(
                    RuntimePlugin.Event.TEIID40086,
                    vdb.getName(),
                    vdb.getVersion(),
                    vdbImport.getName(),
                    vdbImport.getVersion(),
                    entry.getKey()));
          }
        }
      }
    }
    if (toSearch[0] != null) {
      CombinedClassLoader ccl = new CombinedClassLoader(toSearch[0].getParent(), toSearch);
      this.mergedVDB.addAttchment(ClassLoader.class, ccl);
    }
    this.mergedVDB = newMergedVDB;
  }

  private UDFMetaData getUDF() {
    UDFMetaData mergedUDF = new UDFMetaData();
    if (this.udf != null) {
      mergedUDF.addFunctions(this.udf);
    }

    for (Schema schema : store.getSchemas().values()) {
      Collection<FunctionMethod> funcs = schema.getFunctions().values();
      mergedUDF.addFunctions(schema.getName(), funcs);
    }

    if (this.cmr != null) {
      // system scoped common source functions
      for (ConnectorManager cm : this.cmr.getConnectorManagers().values()) {
        List<FunctionMethod> funcs = cm.getPushDownFunctions();
        mergedUDF.addFunctions(CoreConstants.SYSTEM_MODEL, funcs);
      }
    }

    if (this.children != null) {
      // udf model functions - also scoped to the model
      for (CompositeVDB child : this.children.values()) {
        UDFMetaData funcs = child.getUDF();
        if (funcs != null) {
          mergedUDF.addFunctions(funcs);
        }
      }
    }
    return mergedUDF;
  }

  /** TODO: we are not checking for collisions here. */
  private LinkedHashMap<String, VDBResources.Resource> getVisibilityMap() {
    if (this.children == null || this.children.isEmpty()) {
      return this.visibilityMap;
    }

    LinkedHashMap<String, VDBResources.Resource> mergedvisibilityMap =
        new LinkedHashMap<String, VDBResources.Resource>();
    for (CompositeVDB child : this.children.values()) {
      LinkedHashMap<String, VDBResources.Resource> vm = child.getVisibilityMap();
      if (vm != null) {
        mergedvisibilityMap.putAll(vm);
      }
    }
    if (this.visibilityMap != null) {
      mergedvisibilityMap.putAll(this.visibilityMap);
    }
    return mergedvisibilityMap;
  }

  private MetadataStore getMetadataStore() {
    return this.store;
  }

  VDBMetaData getOriginalVDB() {
    return originalVDB;
  }

  public void metadataLoadFinished() {
    if (this.metadataloadFinished) {
      return;
    }
    this.metadataloadFinished = true;

    MetadataStore mergedStore = getMetadataStore();
    // the order of the models is important for resolving ddl
    // TODO we might consider not using the intermediate MetadataStore
    List<Schema> schemas = mergedStore.getSchemaList();
    schemas.clear();
    for (ModelMetaData model : this.vdb.getModelMetaDatas().values()) {
      Schema s = mergedStore.getSchema(model.getName());
      if (s != null) {
        schemas.add(s);
      } else {
        mergedStore.getSchemas().remove(model.getName());
      }
    }
    if (this.children != null && !this.children.isEmpty()) {
      for (CompositeVDB child : this.children.values()) {
        MetadataStore childStore = child.getMetadataStore();
        if (childStore != null) {
          mergedStore.merge(childStore);
        }
      }
    }

    TransformationMetadata metadata =
        buildTransformationMetaData(
            mergedVDB,
            getVisibilityMap(),
            mergedStore,
            getUDF(),
            systemFunctions,
            this.additionalStores);
    QueryMetadataInterface qmi = metadata;
    Map<String, String> multiSourceModels =
        MultiSourceMetadataWrapper.getMultiSourceModels(mergedVDB);
    if (multiSourceModels != null && !multiSourceModels.isEmpty()) {
      qmi = new MultiSourceMetadataWrapper(metadata, multiSourceModels);
    }
    mergedVDB.addAttchment(QueryMetadataInterface.class, qmi);
    mergedVDB.addAttchment(TransformationMetadata.class, metadata);
    mergedVDB.addAttchment(MetadataStore.class, mergedStore);
  }

  LinkedHashMap<VDBKey, CompositeVDB> getChildren() {
    return children;
  }

  public Collection<Future<?>> clearTasks() {
    ArrayList<Future<?>> copy = new ArrayList<Future<?>>(tasks);
    tasks.clear();
    return copy;
  }

  public void removeTask(Future<?> future) {
    tasks.remove(future);
  }

  public void addTask(Future<?> future) {
    tasks.add(future);
  }
}