package com.taobao.tddl.repo.mysql.spi; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.taobao.tddl.common.exception.TddlException; import com.taobao.tddl.common.utils.GeneralUtil; import com.taobao.tddl.executor.common.DuplicateKVPair; import com.taobao.tddl.executor.common.KVPair; import com.taobao.tddl.executor.cursor.Cursor; import com.taobao.tddl.executor.cursor.ICursorMeta; import com.taobao.tddl.executor.cursor.ISchematicCursor; import com.taobao.tddl.executor.cursor.impl.CursorMetaImp; import com.taobao.tddl.executor.record.CloneableRecord; import com.taobao.tddl.executor.record.FixedLengthRecord; import com.taobao.tddl.executor.record.NamedRecord; import com.taobao.tddl.executor.rowset.IRowSet; import com.taobao.tddl.executor.utils.ExecUtils; import com.taobao.tddl.optimizer.config.table.ColumnMeta; import com.taobao.tddl.optimizer.config.table.parse.TableMetaParser; import com.taobao.tddl.optimizer.core.ASTNodeFactory; import com.taobao.tddl.optimizer.core.datatype.DataType; import com.taobao.tddl.optimizer.core.expression.IBooleanFilter; import com.taobao.tddl.optimizer.core.expression.IColumn; import com.taobao.tddl.optimizer.core.expression.IFilter.OPERATION; import com.taobao.tddl.optimizer.core.plan.IDataNodeExecutor; import com.taobao.tddl.optimizer.core.plan.query.IQuery; import com.taobao.tddl.optimizer.utils.FilterUtils; /** * @author mengshi.sunmengshi 2013-12-6 下午6:13:21 * @since 5.0.0 */ public class My_Cursor implements Cursor { protected My_JdbcHandler myJdbcHandler; protected IDataNodeExecutor query; protected ICursorMeta meta; protected boolean inited = false; // private boolean directlyExecuteSql = false; protected boolean isStreaming = false; protected List<ColumnMeta> returnColumns = null; public My_Cursor(My_JdbcHandler myJdbcHandler, ICursorMeta meta, IDataNodeExecutor executor, boolean isStreaming){ super(); this.myJdbcHandler = myJdbcHandler; this.query = executor; this.meta = meta; this.isStreaming = isStreaming; } @Override public boolean skipTo(CloneableRecord key) throws TddlException { init(); return true; } @Override public boolean skipTo(KVPair key) throws TddlException { throw new UnsupportedOperationException("not support yet"); } @Override public IRowSet current() throws TddlException { init(); return myJdbcHandler.getCurrent(); } @Override public IRowSet next() throws TddlException { init(); try { return myJdbcHandler.next(); } catch (SQLException e) { throw new TddlException(e); } } public void init() throws TddlException { if (inited) { return; } try { myJdbcHandler.executeQuery(meta, isStreaming); // ResultSetMetaData rsmd = // this.myJdbcHandler.getResultSet().getMetaData(); returnColumns = new ArrayList(); // 使用meta做为returncolumns // resultset中返回的meta信是物理表名,会导致join在构造返回对象时找不到index(表名不同/为null) if (meta != null) { returnColumns.addAll(meta.getColumns()); } else { ResultSetMetaData rsmd = this.myJdbcHandler.getResultSet().getMetaData(); for (int i = 1; i <= rsmd.getColumnCount(); i++) { DataType type = TableMetaParser.jdbcTypeToDataType(rsmd.getColumnType(i)); String name = rsmd.getColumnLabel(i); ColumnMeta cm = new ColumnMeta(null, name, type, null, true); returnColumns.add(cm); } meta = CursorMetaImp.buildNew(returnColumns); myJdbcHandler.setContext(meta, isStreaming); } inited = true; } catch (SQLException e) { throw new TddlException(e); } } public ISchematicCursor getResultSet() throws TddlException { init(); return myJdbcHandler.getResultCursor(); } @Override public IRowSet prev() throws TddlException { isStreaming = false; init(); try { return myJdbcHandler.prev(); } catch (SQLException e) { throw new TddlException(e); } } @Override public IRowSet first() throws TddlException { init(); try { return myJdbcHandler.first(); } catch (SQLException e) { throw new TddlException(e); } } @Override public IRowSet last() throws TddlException { init(); try { return myJdbcHandler.last(); } catch (SQLException e) { throw new TddlException(e); } } @Override public boolean delete() throws TddlException { throw new UnsupportedOperationException("not support yet"); } @Override public IRowSet getNextDup() throws TddlException { throw new UnsupportedOperationException("not support yet"); } @Override public void put(CloneableRecord key, CloneableRecord value) throws TddlException { throw new UnsupportedOperationException("not support yet"); } public ICursorMeta getCursorMeta() { return meta; } public void setCursorMeta(ICursorMeta cursorMeta) { this.meta = cursorMeta; } public IDataNodeExecutor getiQuery() { return query; } public void setiQuery(IQuery iQuery) { this.query = iQuery; } @Override public List<TddlException> close(List<TddlException> exs) { if (exs == null) { exs = new ArrayList(); } try { myJdbcHandler.close(); } catch (Exception e) { exs.add(new TddlException(e)); } return exs; } public int sizeLimination = 10000; @Override public Map<CloneableRecord, DuplicateKVPair> mgetWithDuplicate(List<CloneableRecord> keys, boolean prefixMatch, boolean keyFilterOrValueFilter) throws TddlException { IQuery tmpQuery = (IQuery) query.copy(); List<Object> values = new ArrayList<Object>(); String cm = keys.get(0).getColumnList().get(0); for (CloneableRecord key : keys) { values.add(key.get(cm)); } IColumn ic = ASTNodeFactory.getInstance().createColumn(); ic.setColumnName(cm); IBooleanFilter targetFilter = ASTNodeFactory.getInstance().createBooleanFilter(); targetFilter.setOperation(OPERATION.IN); targetFilter.setColumn(ic); targetFilter.setValues(values); tmpQuery.setKeyFilter(FilterUtils.and(tmpQuery.getKeyFilter(), targetFilter)); myJdbcHandler.setPlan(tmpQuery); try { myJdbcHandler.executeQuery(this.meta, isStreaming); } catch (SQLException e) { throw new TddlException(e); } Map<CloneableRecord, DuplicateKVPair> res = buildDuplicateKVPair(keys); return res; } // ==============Getters and Setters======= public Map<CloneableRecord, DuplicateKVPair> buildDuplicateKVPair(List<CloneableRecord> keys) throws TddlException { String cmStr = keys.get(0).getColumnList().get(0); ColumnMeta cm = new ColumnMeta(getCursorMeta().getColumns().get(0).getTableName(), cmStr, null, null, true); List<ColumnMeta> cms = new LinkedList<ColumnMeta>(); cms.add(cm); IRowSet rowSet = null; int count = 0; Map<CloneableRecord, DuplicateKVPair> duplicateKeyMap = new HashMap<CloneableRecord, DuplicateKVPair>(); try { while ((rowSet = myJdbcHandler.next()) != null) { CloneableRecord value = new FixedLengthRecord(cms); CloneableRecord key = new NamedRecord(cmStr, value); rowSet = ExecUtils.fromIRowSetToArrayRowSet(rowSet); Object v = ExecUtils.getValueByColumnMeta(rowSet, cm); value.put(cmStr, v); DuplicateKVPair tempKVPair = duplicateKeyMap.get(key); if (tempKVPair == null) {// 加新列 tempKVPair = new DuplicateKVPair(rowSet); duplicateKeyMap.put(key, tempKVPair); } else {// 加重复列 while (tempKVPair.next != null) { tempKVPair = tempKVPair.next; } tempKVPair.next = new DuplicateKVPair(rowSet); } count++; if (count >= sizeLimination) {// 保护。。。别太多了 throw new IllegalArgumentException("size is more than limination " + sizeLimination); } } } catch (SQLException e) { throw new TddlException(e); } if (rowSet == null) { try { myJdbcHandler.close(); } catch (SQLException e) { throw new TddlException(e); } } return duplicateKeyMap; } @Override public List<DuplicateKVPair> mgetWithDuplicateList(List<CloneableRecord> keys, boolean prefixMatch, boolean keyFilterOrValueFilter) throws TddlException { Map<CloneableRecord, DuplicateKVPair> map = mgetWithDuplicate(keys, prefixMatch, keyFilterOrValueFilter); return new ArrayList<DuplicateKVPair>(map.values()); } @Override public String toStringWithInden(int inden) { String tabTittle = GeneralUtil.getTab(inden); String tabContent = GeneralUtil.getTab(inden + 1); StringBuilder sb = new StringBuilder(); GeneralUtil.printlnToStringBuilder(sb, tabTittle + "MyCursor "); if (meta != null) { GeneralUtil.printAFieldToStringBuilder(sb, "meta", this.meta, tabContent); } GeneralUtil.printAFieldToStringBuilder(sb, "isStreaming", this.isStreaming, tabContent); if (this.myJdbcHandler != null) GeneralUtil.printAFieldToStringBuilder(sb, "plan", this.myJdbcHandler.getPlan(), tabContent); return sb.toString(); } @Override public void beforeFirst() throws TddlException { init(); try { myJdbcHandler.beforeFirst(); } catch (SQLException e) { throw new TddlException(e); } } @Override public List<ColumnMeta> getReturnColumns() throws TddlException { init(); return this.returnColumns; } @Override public boolean isDone() { return true; } }