fix "limit" and "skip" logic in io (still not very good, though)
[org.ibex.io.git] / src / org / ibex / io / Fountain.java
index dd21658..d4c1a0d 100644 (file)
@@ -53,6 +53,36 @@ public interface Fountain {
         public StringFountain(String s)                  { super(s); }
     }
 
+    public static class SubFountain implements Fountain {
+        private final Fountain f;
+        private final int start;
+        private final int len;
+        public SubFountain(Fountain f, int start) { this(f, start, -1); }
+        public SubFountain(Fountain f, int start, int len) {
+            this.f = f;
+            this.start = start;
+            this.len = len;
+        }
+        public Stream getStream() {
+            Stream s = f.getStream();
+            // FIXME: this is really fragile and IMAP needs it
+            int remain = start;
+            while(remain > 0) {
+                long result = s.skip(start);
+                Log.error("skip", result + " / " + start);
+                if (result == -1) return s;
+                remain -= result;
+            }
+            if (len != -1) s.setLimit(len);
+            return s;
+        }
+        public long   getLength() {
+            if (len == -1) return f.getLength()-start;
+            return Math.min(f.getLength()-start, len);
+        }
+        public int    getNumLines() { return Stream.countLines(getStream()); }
+    }
+
     public static class Concatenate implements Fountain {
         private Fountain[] founts;
         public Concatenate(Fountain f1, Fountain f2)     { this(new Fountain[] { f1, f2 }); }
@@ -77,6 +107,55 @@ public interface Fountain {
         }
     }
 
+    // FIXME: untested
+    // note: only one ResultSet is allowed per Statement
+    public static class DatabaseColumn implements Fountain {
+        private ResultSet rs;
+        private int row;
+        private int column;
+        public DatabaseColumn(ResultSet rs, int column) throws SQLException {
+            this(rs, column, rs.getRow());
+        }
+        public DatabaseColumn(ResultSet rs, int column, int row) throws SQLException {
+            this.rs = rs;
+            this.row = row;
+            this.column = column;
+            synchronized(rs) {
+                int type = rs.getType();
+                if ((type | ResultSet.TYPE_SCROLL_INSENSITIVE) == 0)
+                    throw new RuntimeException("Fountain.DatabaseColumn(ResultSet,int) requires a SCROLL_INSENSITIVE ResultSet");
+                if ((type | ResultSet.TYPE_FORWARD_ONLY) != 0)
+                    throw new RuntimeException("Fountain.DatabaseColumn(ResultSet,int) cannot use TYPE_FORWARD_ONLY ResultSets");
+            }
+            // FIXME: do we want to check HOLD_CURSORS_OVER_COMMIT ?
+        }
+        private Blob getBlob() throws SQLException {
+            synchronized(rs) {
+                if (!rs.absolute(row))
+                    throw new RuntimeException("resultset was unable to move to desired row");
+                return rs.getBlob(column);
+            }
+        }
+        public Stream getStream() {
+            try {
+                synchronized(rs) {
+                    return new Stream(rs.getBinaryStream(column));
+                }
+            } catch (SQLException e) { throw new RuntimeException(e); }
+        }
+        public long getLength() {
+            try {
+                synchronized(rs) {
+                    return getBlob().length();
+                }
+            } catch (SQLException e) { throw new RuntimeException(e); }
+        }
+        public int getNumLines()       { 
+            throw new RuntimeException("not implemented");
+        } 
+    }
+
+
     //public static class LazyCachingStreamFountain implements Fountain {
     //}
 
@@ -97,6 +176,8 @@ public interface Fountain {
     */
 
     public static class Util {
+        public static Fountain subFountain(Fountain f, int start) { return new SubFountain(f, start); }
+        public static Fountain subFountain(Fountain f, int start, int len) { return new SubFountain(f, start, len); }
         public static Fountain create(String s) { return new StringFountain(s); }
         public static Fountain concat(Fountain[] f) { return new Concatenate(f); }
         public static Fountain concat(Fountain f1, Fountain f2) {