/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.server.api.dml.scan; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; import com.foundationdb.server.rowdata.RowData; import com.foundationdb.server.rowdata.RowDataExtractor; import com.foundationdb.server.rowdata.RowDef; import com.foundationdb.server.api.dml.ColumnSelector; import com.foundationdb.server.api.dml.SetColumnSelector; import com.foundationdb.util.ArgumentValidation; public class NiceRow extends NewRow { private final static int INITIAL_ROW_DATA_SIZE = RowData.CREATE_ROW_INITIAL_SIZE; private final Map<Integer,Object> fields; private final int tableId; public NiceRow(int tableId, RowDef rowDef) { super(rowDef); ArgumentValidation.notNull("tableId", tableId); fields = new TreeMap<>(); this.tableId = tableId; } public NiceRow(NewRow copyFrom) { this(copyFrom.getTableId(), copyFrom.getRowDef()); fields.putAll( copyFrom.getFields() ); } @Override public Object put(int index, Object object) { return fields.put(index, object); } @Override public int getTableId() { return tableId; } @Override public Object get(int column) { return fields.get(column); } @Override public boolean hasValue(int columnId) { return fields.containsKey(columnId); } @Override public Object remove(int columnId) { return fields.remove(columnId); } @Override public Map<Integer,Object> getFields() { return fields; } public static NewRow fromRowData(RowData origData, RowDef rowDef) { Set<Integer> activeColumns = new HashSet<>(); for(int fieldIndex=0, fieldsCount=rowDef.getFieldCount(); fieldIndex < fieldsCount; ++fieldIndex) { final long location = rowDef.fieldLocation(origData, fieldIndex); // Null != not specified. NewRow, NiceRow, RowData all need the concept of specified vs not-specified // fields. if (true) { // location != 0) { activeColumns.add( fieldIndex ); } } NewRow retval = new NiceRow(rowDef.getRowDefId(), rowDef); RowDataExtractor extractor = new RowDataExtractor(origData, rowDef); for (int pos : activeColumns) { Object value = extractor.get(rowDef.getFieldDef(pos)); Object old = retval.put(pos, value); assert old == null : String.format("put(%s, %s) --> %s", pos, value, old); } return retval; } @Override public RowData toRowData() { final Object[] objects = new Object[ rowDef.getFieldCount() ]; for (Map.Entry<Integer,Object> entry : fields.entrySet()) { objects[ entry.getKey() ] = entry.getValue(); } final RowData retval = new RowData(new byte[INITIAL_ROW_DATA_SIZE]); retval.createRow(rowDef, objects, true); return retval; } @Override public ColumnSelector getActiveColumns() { return new SetColumnSelector(fields.keySet()); } @Override public boolean isColumnNull(int columnId) { return get(columnId) == null; } @Override public String toString() { StringBuilder sb = new StringBuilder().append("[{"); sb.append( rowDef.table().getName().getTableName() ); if (fields.isEmpty()) { return sb.append("} <empty>]").toString(); } sb.append("} "); int nextExpectedPos = 0; for (Map.Entry<Integer,Object> entry : fields.entrySet()) { final int pos = entry.getKey(); if (pos != nextExpectedPos) { sb.append("... "); } final Object value = entry.getValue(); sb.append('(').append(entry.getKey()).append(": "); if (value != null) { sb.append(value.getClass().getSimpleName()).append(' '); } sb.append(value).append(") "); nextExpectedPos = pos + 1; } sb.setCharAt(sb.length() - 1, ']'); return sb.toString(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; NiceRow niceRow = (NiceRow) o; return fields.equals(niceRow.fields) && (tableId == niceRow.tableId); } @Override public int hashCode() { int result = fields != null ? fields.hashCode() : 0; result = 31 * result + tableId; return result; } }