X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fibex%2Fmail%2FSqliteMailbox.java;h=c880f752899164ae3bd1f0efd81274b534f3e926;hb=ac8259d995898c4ee36b18b7f2a065e00ed78af4;hp=66ed67474183df007bed05b3d45bbdc2149639fd;hpb=67ca42596372ee8d715696fa4bd3ad91cfc2c4d1;p=org.ibex.mail.git diff --git a/src/org/ibex/mail/SqliteMailbox.java b/src/org/ibex/mail/SqliteMailbox.java index 66ed674..c880f75 100644 --- a/src/org/ibex/mail/SqliteMailbox.java +++ b/src/org/ibex/mail/SqliteMailbox.java @@ -1,5 +1,6 @@ package org.ibex.mail; +import org.ibex.util.*; import org.ibex.io.Fountain; import org.ibex.io.Stream; import java.sql.Timestamp; @@ -8,15 +9,31 @@ import java.net.*; import java.io.*; import java.util.*; -// nntpNumber (column) -// uid (column) -// uidvalidity -public class SqliteMailbox extends Mailbox.Default { + +public class SqliteMailbox extends Mailbox.Default implements MailTree { + + public MailTree slash(String name, boolean create) { return null; } + public String[] children() { return new String[0]; } + public void rmdir(String subdir) { throw new RuntimeException("invalid"); } + public void rename(String subdir, MailTree newParent, String newName) { throw new RuntimeException("invalid"); } + public Mailbox getMailbox() { return this; } + private Connection conn; private static final String columns = " messageid_, from_,to_,date_,subject_,headers_,body_,flags_"; - + private static final String[] indexedColumns = new String[] { + "uid_", + "messageid_", + "flags_", + /* + "from_", + "to_", + "subject_", + "date_" + */ + }; + /** * from http://www.sqlite.org/autoinc.html * "If a column has the type INTEGER PRIMARY KEY AUTOINCREMENT @@ -29,26 +46,172 @@ public class SqliteMailbox extends Mailbox.Default { * allowed and any attempt to insert a new row will fail with an * SQLITE_FULL error. */ + // FIXME: should messageid_ be decared unique? private static final String columns_ = "uid_ INTEGER PRIMARY KEY AUTOINCREMENT, messageid_ unique,from_,to_,date_,subject_,headers_,body_,flags_"; - public SqliteMailbox(String filename) { + private final int uidValidity; + private final File file; + public int uidValidity() { return uidValidity; } + + public String toString() { return file.getName(); } + public SqliteMailbox(String filename) throws SQLException { try { + this.file = new File(filename); Class.forName("org.sqlite.JDBC"); conn = DriverManager.getConnection("jdbc:sqlite:"+filename); - conn.prepareStatement("create virtual table if not exists 'mail' using FTS2("+columns_+")").executeUpdate(); + conn.prepareStatement("create table if not exists uidvalidity (uidvalidity)").executeUpdate(); + ResultSet rs = conn.prepareStatement("select uidvalidity from uidvalidity").executeQuery(); + if (!rs.next()) { + this.uidValidity = new Random().nextInt(); + PreparedStatement ps = conn.prepareStatement("insert into uidvalidity (uidvalidity) values (?)"); + ps.setInt(1, uidValidity); + ps.executeUpdate(); + } else { + this.uidValidity = rs.getInt(1); + } + conn.prepareStatement("create table if not exists 'mail' ("+columns_+")").executeUpdate(); + for(String name : indexedColumns) + conn.prepareStatement("create index if not exists "+name+"index on mail("+name+");").executeUpdate(); } catch (SQLException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } - public int uidNext() { throw new RuntimeException("not supported"); } - public Mailbox.Iterator iterator() { return new SqliteJdbcIterator(); } + private HashMap imapToUid = new HashMap(); + private HashMap uidToImap = new HashMap(); + private boolean imapNumberCacheValid = false; + public void updateImapNumberCache() throws SQLException { + synchronized(this) { + Log.warn(this+"", "rebuilding imapNumberCache..."); + imapToUid.clear(); + uidToImap.clear(); + PreparedStatement q = conn.prepareStatement("select uid_ from mail"); + ResultSet rs = q.executeQuery(); + int num = 1; + while(rs.next()) { + imapToUid.put(num, rs.getInt(1)); + uidToImap.put(rs.getInt(1), num); + num++; + } + imapNumberCacheValid = true; + } + } + public int queryImapNumberCache(int uid) throws SQLException { + synchronized(this) { + if (!imapNumberCacheValid) updateImapNumberCache(); + Integer ret = uidToImap.get(uid); + if (ret == null) return -1; + return ret; + } + } + public int queryUidForImapNum(int imapNumber) throws SQLException { + synchronized(this) { + if (!imapNumberCacheValid) updateImapNumberCache(); + Integer ret = imapToUid.get(imapNumber); + if (ret == null) return -1; + return ret; + } + } + + + public int maxuid() { return uidNext(); } + public int uidNext() { + try { + PreparedStatement q = conn.prepareStatement("select max(uid_) from mail"); + ResultSet rs = q.executeQuery(); + if (!rs.next()) return -1; + return rs.getInt(1)+1; + } catch (Exception e) { throw new RuntimeException(e); } + } + + public Mailbox.Iterator iterator() { + Log.warn(this, "performance warning: called iterator() on entire mailbox"); + Log.printStackTrace(this, Log.WARN); + return new SqliteJdbcIterator(); + } + private String set(int[] set, String arg) { + String whereClause = ""; + boolean needsOr = false; + for(int i=0; i=" + set[i]; + whereClause += " and "; + while(i+2 < set.length && set[i+2] == (set[i+1]+1)) i += 2; + whereClause += arg+"<=" + set[i+1]; + whereClause += ")"; + needsOr = true; + } + return whereClause; + } + private static String joinWith(String op, Query[] q) throws UnsupportedQueryException { + boolean add = false; + StringBuffer sb = new StringBuffer(); + for(int i=0; i