/** @since 3.0 */
  @Override
  protected long longPkFromDatabase(DataNode node, DbEntity entity) throws Exception {
    // handle CAY-588 - get connection that is separate from the connection in the
    // current transaction.

    // TODO (andrus, 7/6/2006) Note that this will still work in a pool with a single
    // connection, as PK generator is invoked early in the transaction, before the
    // connection is grabbed for commit... So maybe promote this to other adapters in
    // 3.0?

    Transaction transaction = Transaction.getThreadTransaction();
    Transaction.bindThreadTransaction(null);

    try {

      Connection connection = node.getDataSource().getConnection();
      try {
        CallableStatement statement = connection.prepareCall("{call auto_pk_for_table(?, ?)}");
        try {
          statement.setString(1, entity.getName());
          statement.setInt(2, super.getPkCacheSize());

          // can't use "executeQuery"
          // per http://jtds.sourceforge.net/faq.html#expectingResultSet
          statement.execute();
          if (statement.getMoreResults()) {
            ResultSet rs = statement.getResultSet();

            try {
              if (rs.next()) {
                return rs.getLong(1);
              } else {
                throw new CayenneRuntimeException(
                    "Error generating pk for DbEntity " + entity.getName());
              }
            } finally {
              rs.close();
            }
          } else {
            throw new CayenneRuntimeException(
                "Error generating pk for DbEntity "
                    + entity.getName()
                    + ", no result set from stored procedure.");
          }
        } finally {
          statement.close();
        }
      } finally {
        connection.close();
      }
    } finally {
      Transaction.bindThreadTransaction(transaction);
    }
  }
  /**
   * Runs JDBC update over a Connection obtained from DataNode. Returns a number of objects returned
   * from update.
   *
   * @throws SQLException in case of query failure.
   */
  public int runUpdate(DataNode node, String sql) throws SQLException {
    adapter.getJdbcEventLogger().logQuery(sql, Collections.EMPTY_LIST);

    Connection con = node.getDataSource().getConnection();
    try {
      Statement upd = con.createStatement();
      try {
        return upd.executeUpdate(sql);
      } finally {
        upd.close();
      }
    } finally {
      con.close();
    }
  }
  /** Checks if AUTO_PK_TABLE already exists in the database. */
  protected boolean autoPkTableExists(DataNode node) throws SQLException {
    Connection con = node.getDataSource().getConnection();
    boolean exists = false;
    try {
      DatabaseMetaData md = con.getMetaData();
      ResultSet tables = md.getTables(null, null, "AUTO_PK_SUPPORT", null);
      try {
        exists = tables.next();
      } finally {
        tables.close();
      }
    } finally {
      // return connection to the pool
      con.close();
    }

    return exists;
  }
  @Override
  public Map<String, DataSource> dataSources() {

    Map<String, DataSource> dataSources = new HashMap<>();

    for (DataNode n : runtime.getDataDomain().getDataNodes()) {

      // this method is used to seed a special kind of JdbcConnector.
      // But note that the DataSource here is attached to the DataNode
      // transaction, so reading source data will happen over the same
      // connection as writing target data. Hopefully such multiplexing
      // the connection works ok...

      dataSources.put(n.getName(), n.getDataSource());
    }

    return dataSources;
  }
 private Map<String, Boolean> getNameTablesInDB(DataNode dataNode) {
   String tableLabel = dataNode.getAdapter().tableTypeForTable();
   Connection con = null;
   Map<String, Boolean> nameTables = new HashMap<String, Boolean>();
   try {
     con = dataNode.getDataSource().getConnection();
     ResultSet rs = con.getMetaData().getTables(null, null, "%", new String[] {tableLabel});
     while (rs.next()) {
       String name = rs.getString("TABLE_NAME");
       nameTables.put(name, false);
     }
     rs.close();
   } catch (SQLException e) {
     throw new CayenneRuntimeException(e);
   } finally {
     try {
       con.close();
     } catch (SQLException e) {
       throw new CayenneRuntimeException(e);
     }
   }
   return nameTables;
 }