예제 #1
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$
  }
예제 #2
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();
 }
예제 #3
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;
  }
}