Android Open Source - DKO Local Join






From Project

Back to project page DKO.

License

The source code is released under:

GNU Lesser General Public License

If you think the Android project DKO listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package org.kered.dko;
/*from  w ww .jav a 2  s.c o m*/
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Logger;

import javax.sql.DataSource;

import org.kered.dko.Condition.Visitor;
import org.kered.dko.Constants.DB_TYPE;
import org.kered.dko.Constants.DIRECTION;
import org.kered.dko.Constants.JOIN_TYPE;
import org.kered.dko.Field.FK;
import org.kered.dko.datasource.JDBCDriverDataSource;
import org.kered.dko.datasource.SingleThreadedDataSource;

class LocalJoin<T extends Table> extends AbstractQuery<T> {

  private static final Logger log = Logger.getLogger("org.kered.dko.LocalJoin");

  private Query<? extends Table> qL;
  private Query<? extends Table> qR;
  private Condition joinCondition;
  private final JOIN_TYPE joinType;
  private long limit = -1;

  private transient List<Field<?>> selectFields;


  public LocalJoin(final LocalJoin<T> q) {
    super(q.ofType);
    joinType = q.joinType;
    qL = q.qL;
    qR = q.qR;
    joinCondition = q.joinCondition;
    limit = q.limit;
  }

  public LocalJoin(final JOIN_TYPE joinType, final Class<? extends Table> type, final Query<? extends Table> q, final Class<? extends Table> t, final Condition on) {
    super(type);
    this.joinType = joinType;
    qL = q; // .top(83)
    qR = QueryFactory.IT.getQuery(t); // .top(98)
    if (on!=null) joinAwareWhere(on);
  }

  public LocalJoin(JOIN_TYPE joinType, Class<Join> type, Query<? extends Table> q, Query<? extends Table> other, final Condition on) {
    super(type);
    this.joinType = joinType;
    qL = q;
    qR = other;
    if (on!=null) joinAwareWhere(on);
  }

  private void joinAwareWhere(final Condition condition) {
    if (SoftJoinUtil.conditionIsAllReferencingQuery(condition, qL)) {
      qL = qL.where(condition);
    } else if (SoftJoinUtil.conditionIsAllReferencingQuery(condition, qR)) {
      qR = qR.where(condition);
    } else {
      if (this.joinCondition==null) this.joinCondition = condition;
      else this.joinCondition = this.joinCondition.and(condition);
    }
  }

  @Override
  public Query<T> where(final Condition... conditions) {
    Condition condition = new Condition.And(conditions);
    if (SoftJoinUtil.conditionIsAllReferencingQuery(condition, qL)) {
      LocalJoin<T> ret = new LocalJoin<T>(this);
      ret.qL = ret.qL.where(condition);
      return ret;
    }
    if (SoftJoinUtil.conditionIsAllReferencingQuery(condition, qR)) {
      LocalJoin<T> ret = new LocalJoin<T>(this);
      ret.qR = ret.qR.where(condition);
      return ret;
    }
    return new FilteringQuery<T>(this, conditions);
  }

  @Override
  public Query<T> limit(final long n) {
    final LocalJoin<T> q = new LocalJoin<T>(this);
    q.limit = n;
    if (joinType==JOIN_TYPE.LEFT || joinType==JOIN_TYPE.OUTER) q.qL = q.qL.top(n);
    if (joinType==JOIN_TYPE.RIGHT || joinType==JOIN_TYPE.OUTER) q.qR = q.qR.top(n);
    return q;
  }

  @Override
  public Query<T> distinct() {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> max() {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> min() {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> with(FK... fields) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> deferFields(Field<?>... fields) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> deferFields(Collection<Field<?>> fields) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> onlyFields(Collection<Field<?>> fields) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> onlyFields(Field<?>... fields) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> set(Field<?> key, Object value) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> set(Map<Field<?>, Object> values) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> use(DataSource ds) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> use(Connection conn) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> use(DB_TYPE type) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> in(Collection<T> set) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public DataSource getDataSource() {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public List<Field<?>> getSelectFields() {
    List<Field<?>> ret = new ArrayList<Field<?>>(qL.getSelectFields());
    ret.addAll(qR.getSelectFields());
    return ret;
  }

  @Override
  public Iterator<T> iterator() {
    return new ClosableIterator<T>() {
      
      private File tmpFile = null;
      private boolean deleteTmpFile = Util.truthy(System.getProperty(Constants.PROPERTY_DELETE_LOCAL_TMP_DATABASES, "true"));
      private List<Field<?>> qLfields;
      private List<Field<?>> qRfields;
      private ClosableIterator<Table> iL;
      private ClosableIterator<Table> iR;
      private DualIterator di;
      private Map<Field, String> fieldNameOverridesL;
      private Map<Field, String> fieldNameOverridesR;
      private long count = 0;

      {
          final boolean qLpk = SoftJoinUtil.doesConditionCoverPK(qL.getType(), joinCondition);
          final boolean qRpk = SoftJoinUtil.doesConditionCoverPK(qR.getType(), joinCondition);
          //System.err.println("qLpk:"+ qLpk +" qRpk:"+qRpk);

          boolean loadRFirst = false;
          if (qLpk || qRpk) {
            loadRFirst = qLpk && !qRpk;
          } else {
            final long qLCount = UsageStats.estimateRowCount(qL);
            final long qRCount = UsageStats.estimateRowCount(qR);
          //System.err.println("qLCount "+ qL.getType().getName() +" h:"+ qL.hashCode() +" c:"+ qLCount);
          //System.err.println("qRCount "+ qR.getType().getName() +" h:"+ qR.hashCode() +" c:"+ qRCount);
            loadRFirst = qLCount > qRCount;
          }

          DataSource ds = createDS();
          
          if (loadRFirst) {
            fieldNameOverridesR = load(qR, "tr", ds);
            Query<? extends Table> qLf = createFilteredQ(qL, joinCondition, "tr", ds);
            fieldNameOverridesL = load(qLf, "tl", ds);
          } else {
            fieldNameOverridesL = load(qL, "tl", ds);
            Query<? extends Table> qRf = createFilteredQ(qR, joinCondition, "tl", ds);
            fieldNameOverridesR = load(qRf, "tr", ds);
          }
          
          initQuery(ds);

      }

      @Override
      public boolean hasNext() {
        boolean ret = (count<limit || limit<0) && (iL.hasNext() || iR.hasNext());
        if (!ret) close();
        return ret;
      }

      private void initQuery(DataSource ds) {
        qLfields = qL.getSelectFields();
        qRfields = qR.getSelectFields();
        Map<Field,String> fieldNameOverrides = new HashMap<Field,String>();
        StringBuffer sb = new StringBuffer();
        sb.append("select ");
        for (Field<?> field : qLfields) {
          String fieldName = fieldNameOverridesL.get(field);
          if (fieldName==null) fieldName = "tl."+ field.NAME;
          sb.append(fieldName).append(", ");
          fieldNameOverrides.put(field, fieldName);
        }
        for (Field<?> field : qRfields) {
          String fieldName = fieldNameOverridesR.get(field);
          if (fieldName==null) fieldName = "tr."+ field.NAME;
          sb.append(fieldName).append(", ");
          fieldNameOverrides.put(field, fieldName);
        }
        sb.delete(sb.length()-2, sb.length()).append(" "); // delete the last comma
        SqlContext context = new SqlContext(DB_TYPE.SQLITE3);
        for (Entry<Field, String> e : fieldNameOverrides.entrySet()) {
          context.setFieldNameOverride(e.getKey(), e.getValue());
        }
        if (joinType == JOIN_TYPE.RIGHT) {
          // sqlite doesn't support right joins, so we fake it
          sb.append("from tr ").append(JOIN_TYPE.LEFT).append(" tl");
        } else {
          sb.append("from tl ").append(joinType).append(" tr");
        }
        if (joinCondition!=null) sb.append(" on ").append(joinCondition.getSQL(context));
        String sql = sb.toString();
          di = new DualIterator(ds, sql, qLfields, qRfields);
          if (qL instanceof DBQuery) iL = new SelectFromOAI((DBQuery) qL, di.getLeftIterator());
          else if (qL instanceof LocalJoin) iL = ((LocalJoin)qL).buildIteratorFrom(di.getLeftIterator());
          else iL = new SelectFromOAI(qL, di.getLeftIterator());
          if (qR instanceof DBQuery) iR = new SelectFromOAI((DBQuery) qR, di.getRightIterator());
          else if (qR instanceof LocalJoin) iR = ((LocalJoin)qR).buildIteratorFrom(di.getRightIterator());
          else iR = new SelectFromOAI(qR, di.getRightIterator());
      }

      @Override
      public T next() {
        ++count;
        Table left = iL.hasNext() ? iL.next() : null;
        Table right = iR.hasNext() ? iR.next() : null;
        return (T) new Join<Table,Table>(left, right);
      }

      @Override
      public void remove() {
        throw new UnsupportedOperationException();
      }

      @Override
      public synchronized void close() {
        di.close();
        if (deleteTmpFile && tmpFile.exists()) tmpFile.delete();
      }

      @Override
      protected void finalize() throws Throwable {
        close();
        super.finalize();
      }

      private DataSource createDS() {
        // make sure sqlite driver is loaded...
        org.kered.dko.persistence.Util.getDS();

        try {
          tmpFile  = File.createTempFile("dko_local_join_", ".db");
          if (deleteTmpFile) {
            log.fine("created "+ tmpFile.getPath());
            tmpFile.deleteOnExit();
          } else {
            log.warning("created "+ tmpFile.getPath() +" (not scheduled for deletion because "
                + Constants.PROPERTY_DELETE_LOCAL_TMP_DATABASES +"="
                + System.getProperty(Constants.PROPERTY_DELETE_LOCAL_TMP_DATABASES) +")");
          }
          String url = "jdbc:sqlite:" + tmpFile.getPath();
          DataSource ds = new SingleThreadedDataSource(new JDBCDriverDataSource(Constants.DB_TYPE.SQLITE3, url), 10000, false);
          return ds;
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
        
      }

    };
  }

  protected ClosableIterator<Table> buildIteratorFrom(PeekableClosableIterator<Object[]> iterator) {
    final DualIterator di = new DualIterator(iterator, qL.getSelectFields(), qR.getSelectFields());
      final ClosableIterator<Table> iL;
    if (qL instanceof DBQuery) iL = new SelectFromOAI((DBQuery) qL, di.getLeftIterator());
      else if (qL instanceof LocalJoin) iL = ((LocalJoin)qL).buildIteratorFrom(di.getLeftIterator());
      else iL = new SelectFromOAI(qL, di.getLeftIterator());
      final ClosableIterator<Table> iR;
    if (qR instanceof DBQuery) iR = new SelectFromOAI((DBQuery) qR, di.getRightIterator());
      else if (qR instanceof LocalJoin) iR = ((LocalJoin)qR).buildIteratorFrom(di.getRightIterator());
      else iR = new SelectFromOAI(qR, di.getRightIterator());
    return new ClosableIterator<Table>() {

      @Override
      public boolean hasNext() {
        return iL.hasNext() || iR.hasNext();
      }

      @Override
      public T next() {
        Table left = iL.hasNext() ? iL.next() : null;
        Table right = iR.hasNext() ? iR.next() : null;
        return (T) new Join<Table,Table>(left, right);
      }

      @Override
      public void remove() {
        throw new UnsupportedOperationException();
      }

      @Override
      public synchronized void close() {
        di.close();
      }

    };
  }

  static Map<Field, String> load(Query<? extends Table> q, String table, DataSource ds) {
    List<Field<?>> fields = q.getSelectFields();
    Map<Field, String> fieldNameOverrides = buildSchema(fields, table, ds);
    StringBuffer sb = new StringBuffer();
    sb.append("insert into ").append(table).append(" (");
    for (int i=0; i<fields.size(); ++i) {
      Field<?> field = fields.get(i);
      if (fieldNameOverrides.containsKey(field)) {
        sb.append(fieldNameOverrides.get(field));
      } else {
        sb.append(field.NAME);
      }
      if (i<fields.size()-1) sb.append(", ");
    }
    sb.append(") values (");
    for (int i=0; i<fields.size(); ++i) {
      sb.append("?");
      if (i<fields.size()-1) sb.append(", ");
    }
    sb.append(")");
    String sql = sb.toString();
    
    Connection conn = null;
    PreparedStatement ps = null;
    try {
      conn = ds.getConnection();
      conn.setAutoCommit(false);
      ps = conn.prepareStatement(sql);
      Util.log(sql, null);
      int count = 0;
      for (Table row : q) {
        for (int i=0; i<fields.size(); ++i) {
          Field<?> field = fields.get(i);
          Object o = row.get(field);
          o = row.__NOSCO_PRIVATE_mapType(o);
          Util.setBindingWithTypeFixes(ps, i+1, o);
        }
        ++count;
        ps.execute();
        //ps.addBatch();
        //if (count%256==0) ps.executeBatch();
      }
      //if (count%256!=0) ps.executeBatch();
      conn.commit();
      log.fine("loaded "+ count +" rows into "+ table);
    } catch (SQLException e) {
      throw new RuntimeException(e);
    } finally {
      try {
        if (conn!=null && !conn.isClosed()) conn.close();
      } catch (SQLException e) {
        throw new RuntimeException(e);
      }
    }
    return fieldNameOverrides;
  }

  private static Map<Field, String> buildSchema(List<Field<?>> fields, String table, DataSource ds) {
    Set<String> usedFieldNames = new HashSet<String>();
    Map<Field,String> fieldNameOverrides = new HashMap<Field,String>();
    StringBuffer sb = new StringBuffer();
    sb.append("create table ").append(table).append(" (");
    for (int i=0; i<fields.size(); ++i) {
      Field<?> field = fields.get(i);
      String fieldName = field.NAME;
      if (usedFieldNames.contains(fieldName)) {
        if (!fieldName.endsWith("_")) fieldName = fieldName + "_";
        while (usedFieldNames.contains(fieldName)) {
          char c = (char) ('A' + Math.random() * ('Z'-'A'));
          fieldName = fieldName + c;
        }
        fieldNameOverrides.put(field, fieldName);
      }
      usedFieldNames.add(fieldName);
      sb.append(fieldName).append(" ").append(field.SQL_TYPE);
      if (i<fields.size()-1) sb.append(", ");
    }
    sb.append(")");
    String sql = sb.toString();
    Connection conn = null;
    Statement stmt = null;
    try {
      conn = ds.getConnection();
      stmt = conn.createStatement();
      Util.log(sql, null);
      stmt.execute(sql);
    } catch (SQLException e) {
      throw new RuntimeException(e);
    } finally {
      try {
        if (conn!=null && !conn.isClosed()) conn.close();
      } catch (SQLException e) {
        throw new RuntimeException(e);
      }
    }
    return fieldNameOverrides;
  }

  private static List getDistinctFrom(Field<?> key, String otherTable, DataSource ds) {
    if (key==null) throw new RuntimeException("key field cannot be null");
    List ret = new ArrayList();
    String sql = "select distinct "+ key.NAME +" from "+ otherTable;
    Connection conn = null;
    Statement ps = null;
    try {
      conn = ds.getConnection();
      ps = conn.createStatement();
      Util.log(sql, null);
      ResultSet rs = ps.executeQuery(sql);
      while (rs.next()) {
        ret.add(rs.getObject(1));
      }
      rs.close();
    } catch (SQLException e) {
      throw new RuntimeException(e);
    } finally {
      try {
        if (conn!=null && !conn.isClosed()) conn.close();
      } catch (SQLException e) {
        throw new RuntimeException(e);
      }
    }
    return ret;
  }

  private static Query<? extends Table> createFilteredQ(Query<? extends Table> q, Condition condition, String otherTable, DataSource ds) {
    final Set<Field<?>> queryFields = new HashSet<Field<?>>(q.getSelectFields());
    final Map<Field<?>,Field<?>> fields = new LinkedHashMap<Field<?>,Field<?>>();
    if (condition!=null) condition.visit(new Visitor() {
      @Override
      public void visited(Condition c) {
        if (c instanceof Condition.Binary) {
          Condition.Binary o = (Condition.Binary) c;
          if (queryFields.contains(o.field)) fields.put(o.field, o.field2);
          if (queryFields.contains(o.field2)) fields.put(o.field2, o.field);
        }
        if (c instanceof Condition.Binary2) {
          Condition.Binary2 o = (Condition.Binary2) c;
          if (o.o1 instanceof Field && queryFields.contains(o.o1)) fields.put((Field<?>)o.o1, (Field<?>)o.o2);
          if (o.o2 instanceof Field && queryFields.contains(o.o2)) fields.put((Field<?>)o.o2, (Field<?>)o.o1);
        }
//        if (c instanceof Condition.Ternary) {
//          Condition.Ternary o = (Condition.Ternary) c;
//          if (o.v1 instanceof Field && fields.contains(o.v1)) fields.add((Field<?>)o.v1);
//          if (o.v2 instanceof Field && fields.contains(o.v2)) fields.add((Field<?>)o.v2);
//          if (o.v3 instanceof Field && fields.contains(o.v3)) fields.add((Field<?>)o.v3);
//        }
//        if (c instanceof Condition.Unary) {
//          Condition.Unary o = (Condition.Unary) c;
//          if (fields.contains(o.field)) fields.add(o.field);
//        }
      }
    });
    for (Entry<Field<?>, Field<?>> e : fields.entrySet()) {
      List values = getDistinctFrom(e.getValue(), otherTable, ds);
      q = q.where(e.getKey().in(values));
    }
    return q;
  }

  @Override
  public Query<T> avg() {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Query<T> orderBy(Expression.OrderBy<?>... obes) {
    // TODO Auto-generated method stub
    return null;
  }

}




Java Source Code List

.HelloWorld.java
org.kered.contactlensfinder.DB.java
org.kered.contactlensfinder.MainActivity.java
org.kered.contactlensfinder.ViewManufacturersActivity.java
org.kered.contactlensfinder.ViewProductsActivity.java
org.kered.contactlensfinder.ViewPropertiesActivity.java
org.kered.dko.AbstractQuery.java
org.kered.dko.Bulk.java
org.kered.dko.CSV.java
org.kered.dko.ClosableIterator.java
org.kered.dko.Condition.java
org.kered.dko.Constants.java
org.kered.dko.Context.java
org.kered.dko.DBQuery.java
org.kered.dko.DBRowIterator.java
org.kered.dko.Diff.java
org.kered.dko.DualIterator.java
org.kered.dko.Expression.java
org.kered.dko.Field.java
org.kered.dko.FilteringQuery.java
org.kered.dko.Function.java
org.kered.dko.InMemoryQuery.java
org.kered.dko.Join.java
org.kered.dko.LazyCacheIterable.java
org.kered.dko.LocalJoin.java
org.kered.dko.M.java
org.kered.dko.Main.java
org.kered.dko.MatryoshkaQuery.java
org.kered.dko.PeekableClosableIterator.java
org.kered.dko.PeekableIterator.java
org.kered.dko.QueryAddField.java
org.kered.dko.QueryFactory.java
org.kered.dko.QuerySnapshot.java
org.kered.dko.Query.java
org.kered.dko.SQLFunction.java
org.kered.dko.SelectAsMapIterable.java
org.kered.dko.SelectFromOAI.java
org.kered.dko.SelectSingleColumn.java
org.kered.dko.SoftJoinUtil.java
org.kered.dko.SoftJoin.java
org.kered.dko.SqlContext.java
org.kered.dko.Statistics.java
org.kered.dko.SubQueryField.java
org.kered.dko.TableInfo.java
org.kered.dko.TableWrapper.java
org.kered.dko.Table.java
org.kered.dko.TemporaryTableFactory.java
org.kered.dko.TmpTableBuilder.java
org.kered.dko.Tuple.java
org.kered.dko.UsageMonitor.java
org.kered.dko.UsageStats.java
org.kered.dko.Util.java
org.kered.dko.ant.ClassGenerator.java
org.kered.dko.ant.CodeGeneratorBase.java
org.kered.dko.ant.CodeGenerator.java
org.kered.dko.ant.DataSourceGenerator.java
org.kered.dko.ant.GsonGenerator.java
org.kered.dko.ant.JoinGenerator.java
org.kered.dko.ant.Main.java
org.kered.dko.ant.SchemaExtractorBase.java
org.kered.dko.ant.SchemaExtractor.java
org.kered.dko.ant.Util.java
org.kered.dko.datasource.CheapConnectionPoolingDataSource.java
org.kered.dko.datasource.ConnectionCountingDataSource.java
org.kered.dko.datasource.JDBCDriverDataSource.java
org.kered.dko.datasource.MatryoshkaDataSource.java
org.kered.dko.datasource.MirroredDataSource.java
org.kered.dko.datasource.ReflectedDataSource.java
org.kered.dko.datasource.SingleConnectionDataSource.java
org.kered.dko.datasource.SingleThreadedDataSource.java
org.kered.dko.datasource.UnClosableConnection.java
org.kered.dko.datasource.Util.java
org.kered.dko.json.CDL.java
org.kered.dko.json.CookieList.java
org.kered.dko.json.Cookie.java
org.kered.dko.json.HTTPTokener.java
org.kered.dko.json.HTTP.java
org.kered.dko.json.JSONArray.java
org.kered.dko.json.JSONException.java
org.kered.dko.json.JSONML.java
org.kered.dko.json.JSONObject.java
org.kered.dko.json.JSONString.java
org.kered.dko.json.JSONStringer.java
org.kered.dko.json.JSONTokener.java
org.kered.dko.json.JSONWriter.java
org.kered.dko.json.Pickle.java
org.kered.dko.json.XMLTokener.java
org.kered.dko.json.XML.java
org.kered.dko.junk.DerbyLoadTestSchema.java
org.kered.dko.junk.OracleCreateTestUser.java
org.kered.dko.junk.OracleLoadTestSchema.java
org.kered.dko.persistence.Util.java
org.kered.dko.util.DumpDatabase.java
sakila.Example0.java
sakila.Example1.java
sakila.Example2.java
sakila.Util.java