content: package org.sql2o;
  
  import org.sql2o.quirks.Quirks;
  
  import java.sql.ResultSet;
  import java.sql.ResultSetMetaData;
  import java.sql.SQLException;
  import java.util.Iterator;
  import java.util.NoSuchElementException;
  
  /**
   * Iterator for a {@link java.sql.ResultSet}. Tricky part here is getting {@link #hasNext()}
   * to work properly, meaning it can be called multiple times without calling {@link #next()}.
   *
   * @author aldenquimby@gmail.com
   * @param <T> the type of the objects that this iterator will return
   */
  public abstract class ResultSetIteratorBase<T> implements Iterator<T> {
      // fields needed to read result set
      protected ResultSet rs;
      protected boolean isCaseSensitive;
      protected Quirks quirks;
      protected ResultSetMetaData meta;
  
      public ResultSetIteratorBase(ResultSet rs, boolean isCaseSensitive, Quirks quirks) {
          this.rs = rs;
          this.isCaseSensitive = isCaseSensitive;
          this.quirks = quirks;
          try {
              meta = rs.getMetaData();
          }
          catch(SQLException ex) {
              throw new Sql2oException("Database error: " + ex.getMessage(), ex);
          }
      }
  
      // fields needed to properly implement
      private ResultSetValue<T> next; // keep track of next item in case hasNext() is called multiple times
      private boolean resultSetFinished; // used to note when result set exhausted
  
      public boolean hasNext() {
          // check if we already fetched next item
          if (next != null) {
              return true;
          }
  
          // check if result set already finished
          if (resultSetFinished) {
              return false;
          }
  
          // now fetch next item
          next = safeReadNext();
  
          // check if we got something
          if (next != null) {
              return true;
          }
  
          // no more items
          resultSetFinished = true;
  
          return false;
      }
  
      public T next() {
          if (!hasNext()) {
              throw new NoSuchElementException();
          }
  
          T result = next.value;
  
          next = null;
  
          return result;
      }
  
      public void remove() {
          throw new UnsupportedOperationException();
      }
  
      private ResultSetValue<T> safeReadNext()
      {
          try {
              if (!rs.next())
                  return null;
  
              @SuppressWarnings("unchecked")
              ResultSetValue<T> resultSetValue = new <T>ResultSetValue(readNext());
              return resultSetValue;
          }
          catch (SQLException ex) {
              throw new Sql2oException("Database error: " + ex.getMessage(), ex);
          }
      }
  
      protected abstract T readNext() throws SQLException;
  
      protected String getColumnName(int colIdx) throws SQLException {
          return quirks.getColumnName(meta, colIdx);
      }
  
      private final class ResultSetValue<T> {
          public final T value;
  
          public ResultSetValue(T value){
              this.value = value;
          }
      }
  }
  