]> source.dussan.org Git - jackcess.git/commitdiff
create ComplexValue.Id and stash RowId for simpler updates/deletes
authorJames Ahlborn <jtahlborn@yahoo.com>
Tue, 19 Mar 2013 04:28:28 +0000 (04:28 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Tue, 19 Mar 2013 04:28:28 +0000 (04:28 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/jackcess-2@697 f203690c-595d-4dc9-a70b-905162fa7fd2

TODO.txt
src/java/com/healthmarketscience/jackcess/complex/AttachmentColumnInfo.java
src/java/com/healthmarketscience/jackcess/complex/ComplexColumnInfo.java
src/java/com/healthmarketscience/jackcess/complex/ComplexValue.java
src/java/com/healthmarketscience/jackcess/complex/MultiValueColumnInfo.java
src/java/com/healthmarketscience/jackcess/complex/UnsupportedColumnInfo.java
src/java/com/healthmarketscience/jackcess/complex/VersionHistoryColumnInfo.java
src/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java
src/java/com/healthmarketscience/jackcess/impl/RowImpl.java
src/java/com/healthmarketscience/jackcess/impl/TableImpl.java
src/java/com/healthmarketscience/jackcess/util/Joiner.java

index 3e896a0530589558fe62ae65f331fd38f27af46d..4c86b7ab656b2399cd553cf0fdabc2168229440e 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -45,4 +45,4 @@ Refactor goals:
 * add unit tests for Row update/delete methods, add/update *FromMap methods
 * add reason to unsupop throws for indexes
 * remove static methods in CursorImpl/IndexCursorImpl
-- add RowId to ComplexValue
+* create ComplexValue.Id and keep RowId
index 0a07e9ded705d0e07cfa54d94354f66d71464ca8..f715d7c6d5acbfebbaf4ac1afd3f565f5b78a7a2 100644 (file)
@@ -21,7 +21,6 @@ package com.healthmarketscience.jackcess.complex;
 
 import java.io.IOException;
 import java.util.Date;
-import java.util.Map;
 
 import com.healthmarketscience.jackcess.Column;
 import com.healthmarketscience.jackcess.Row;
@@ -133,7 +132,7 @@ public class AttachmentColumnInfo extends ComplexColumnInfo<Attachment>
   @Override
   protected AttachmentImpl toValue(ComplexValueForeignKey complexValueFk,
                                    Row rawValue) {
-    int id = (Integer)getPrimaryKeyColumn().getRowValue(rawValue);
+    ComplexValue.Id id = getValueId(rawValue);
     String url = (String)getFileUrlColumn().getRowValue(rawValue);
     String name = (String)getFileNameColumn().getRowValue(rawValue);
     String type = (String)getFileTypeColumn().getRowValue(rawValue);
@@ -158,7 +157,7 @@ public class AttachmentColumnInfo extends ComplexColumnInfo<Attachment>
   }
 
   public static Attachment newAttachment(byte[] data) {
-    return newAttachment(INVALID_COMPLEX_VALUE_ID, data);
+    return newAttachment(INVALID_FK, data);
   }
   
   public static Attachment newAttachment(ComplexValueForeignKey complexValueFk,
@@ -170,7 +169,7 @@ public class AttachmentColumnInfo extends ComplexColumnInfo<Attachment>
       String url, String name, String type, byte[] data,
       Date timeStamp, Integer flags)
   {
-    return newAttachment(INVALID_COMPLEX_VALUE_ID, url, name, type, data,
+    return newAttachment(INVALID_FK, url, name, type, data,
                          timeStamp, flags);
   }
   
@@ -193,7 +192,7 @@ public class AttachmentColumnInfo extends ComplexColumnInfo<Attachment>
     private Date _timeStamp;
     private Integer _flags;
 
-    private AttachmentImpl(int id, ComplexValueForeignKey complexValueFk,
+    private AttachmentImpl(Id id, ComplexValueForeignKey complexValueFk,
                            String url, String name, String type, byte[] data,
                            Date timeStamp, Integer flags)
     {
index 376c25a6e0e94c7f73cc29af7ecf49620a7d0954..ae1751070ddf2ff42999f8fc41a206a71fdd8e7f 100644 (file)
@@ -32,8 +32,12 @@ import com.healthmarketscience.jackcess.CursorBuilder;
 import com.healthmarketscience.jackcess.DataType;
 import com.healthmarketscience.jackcess.Database;
 import com.healthmarketscience.jackcess.IndexCursor;
-import com.healthmarketscience.jackcess.Table;
 import com.healthmarketscience.jackcess.Row;
+import com.healthmarketscience.jackcess.RowId;
+import com.healthmarketscience.jackcess.RuntimeIOException;
+import com.healthmarketscience.jackcess.Table;
+import com.healthmarketscience.jackcess.impl.ColumnImpl;
+import com.healthmarketscience.jackcess.impl.TableImpl;
 
 /**
  * Base class for the additional information tracked for complex columns.
@@ -42,9 +46,11 @@ import com.healthmarketscience.jackcess.Row;
  */
 public abstract class ComplexColumnInfo<V extends ComplexValue>
 {
-  public static final int INVALID_ID = -1;
-  public static final ComplexValueForeignKey INVALID_COMPLEX_VALUE_ID =
-    new ComplexValueForeignKey(null, INVALID_ID);
+  private static final int INVALID_ID_VALUE = -1;
+  public static final ComplexValue.Id INVALID_ID = new ComplexValueIdImpl(
+      INVALID_ID_VALUE, null);
+  public static final ComplexValueForeignKey INVALID_FK =
+    new ComplexValueForeignKey(null, INVALID_ID_VALUE);
 
   private final Column _column;
   private final int _complexTypeId;
@@ -52,7 +58,6 @@ public abstract class ComplexColumnInfo<V extends ComplexValue>
   private final List<Column> _typeCols;
   private final Column _pkCol;
   private final Column _complexValFkCol;
-  private IndexCursor _pkCursor;
   private IndexCursor _complexValIdCursor;
   
   protected ComplexColumnInfo(Column column, int complexTypeId,
@@ -181,16 +186,18 @@ public abstract class ComplexColumnInfo<V extends ComplexValue>
     return values;
   }
 
-  public int addRawValue(Row rawValue) throws IOException {
-    Object[] row = _flatTable.asRow(rawValue);
+  public ComplexValue.Id addRawValue(Map<String,?> rawValue)
+    throws IOException 
+  {
+    Object[] row = ((TableImpl)_flatTable).asRowWithRowId(rawValue);
     _flatTable.addRow(row);
-    return (Integer)_pkCol.getRowValue(row);
+    return getValueId(row);
   }
 
-  public int addValue(V value) throws IOException {
+  public ComplexValue.Id addValue(V value) throws IOException {
     Object[] row = asRow(newRowArray(), value);
     _flatTable.addRow(row);
-    int id = (Integer)_pkCol.getRowValue(row);
+    ComplexValue.Id id = getValueId(row);
     value.setId(id);
     return id;
   }
@@ -201,14 +208,13 @@ public abstract class ComplexColumnInfo<V extends ComplexValue>
     }
   }
 
-  public int updateRawValue(Row rawValue) throws IOException {
-    Integer id = (Integer)_pkCol.getRowValue(rawValue);
-    updateRow(id, _flatTable.asUpdateRow(rawValue));
-    return id;
+  public ComplexValue.Id updateRawValue(Row rawValue) throws IOException {
+    _flatTable.updateRow(rawValue);
+    return getValueId(rawValue);
   }
   
-  public int updateValue(V value) throws IOException {
-    int id = value.getId();
+  public ComplexValue.Id updateValue(V value) throws IOException {
+    ComplexValue.Id id = value.getId();
     updateRow(id, asRow(newRowArray(), value));
     return id;
   }
@@ -220,11 +226,11 @@ public abstract class ComplexColumnInfo<V extends ComplexValue>
   }
 
   public void deleteRawValue(Row rawValue) throws IOException {
-    deleteRow((Integer)_pkCol.getRowValue(rawValue));
+    deleteRow(rawValue.getId());
   }
   
   public void deleteValue(V value) throws IOException {
-    deleteRow(value.getId());
+    deleteRow(value.getId().getRowId());
   }
 
   public void deleteValues(Collection<? extends V> values) throws IOException {
@@ -241,11 +247,8 @@ public abstract class ComplexColumnInfo<V extends ComplexValue>
         entryIter.next();
         entryIter.remove();
       }
-    } catch(RuntimeException e) {
-      if(e.getCause() instanceof IOException) {
-        throw (IOException)e.getCause();
-      }
-      throw e;
+    } catch(RuntimeIOException e) {
+      throw (IOException)e.getCause();
     }
   }
 
@@ -255,40 +258,38 @@ public abstract class ComplexColumnInfo<V extends ComplexValue>
     deleteAllValues(complexValueFk.get());
   }
 
-  private void moveToRow(Integer id) throws IOException {
-    if(_pkCursor == null) {
-      _pkCursor = new CursorBuilder(_flatTable)
-        .setIndexByColumns(_pkCol)
-        .toIndexCursor();
-    }
-
-    if(!_pkCursor.findFirstRowByEntry(id)) {
-      throw new IllegalArgumentException("Row with id " + id +
-                                         " does not exist");
-    }    
-  }
-
-  private void updateRow(Integer id, Object[] row) throws IOException {
-    moveToRow(id);
-    _pkCursor.updateCurrentRow(row);
+  private void updateRow(ComplexValue.Id id, Object[] row) throws IOException {
+    ((TableImpl)_flatTable).updateRow(id.getRowId(), row);
   }
   
-  private void deleteRow(Integer id) throws IOException {
-    moveToRow(id);
-    _pkCursor.deleteCurrentRow();
+  private void deleteRow(RowId rowId) throws IOException {
+    ((TableImpl)_flatTable).deleteRow(rowId);
   }
   
+  protected ComplexValueIdImpl getValueId(Row row) {
+    int idVal = (Integer)getPrimaryKeyColumn().getRowValue(row);
+    return new ComplexValueIdImpl(idVal, row.getId());
+  }
+
+  protected ComplexValueIdImpl getValueId(Object[] row) {
+    int idVal = (Integer)getPrimaryKeyColumn().getRowValue(row);
+    return new ComplexValueIdImpl(idVal, (RowId)row[row.length - 1]);
+  }
+
   protected Object[] asRow(Object[] row, V value) {
-    int id = value.getId();
-    _pkCol.setRowValue(row, ((id != INVALID_ID) ? id : Column.AUTO_NUMBER));
-    int cId = value.getComplexValueForeignKey().get();
+    ComplexValue.Id id = value.getId();
+    _pkCol.setRowValue(
+        row, ((id != INVALID_ID) ? id : Column.AUTO_NUMBER));
+    ComplexValueForeignKey cFk = value.getComplexValueForeignKey();
     _complexValFkCol.setRowValue(
-        row, ((cId != INVALID_ID) ? cId : Column.AUTO_NUMBER));
+        row, ((cFk != INVALID_FK) ? cFk : Column.AUTO_NUMBER));
     return row;
   }
 
   private Object[] newRowArray() {
-    return new Object[_flatTable.getColumnCount()];
+    Object[] row = new Object[_flatTable.getColumnCount() + 1];
+    row[row.length - 1] = ColumnImpl.RETURN_ROW_ID;
+    return row;
   }
   
   @Override
@@ -307,14 +308,7 @@ public abstract class ComplexColumnInfo<V extends ComplexValue>
     // each "flat"" table has the columns from the "type" table, plus some
     // others.  separate the "flat" columns into these 2 buckets
     for(Column col : flatTable.getColumns()) {
-      boolean found = false;
-      try {
-        typeObjTable.getColumn(col.getName());
-        found = true;
-      } catch(IllegalArgumentException e) {
-        // FIXME better way to test this?
-      }
-      if(found) {
+      if(((TableImpl)typeObjTable).hasColumn(col.getName())) {
         typeCols.add(col);
       } else {
         otherCols.add(col);
@@ -331,19 +325,23 @@ public abstract class ComplexColumnInfo<V extends ComplexValue>
   
   protected static abstract class ComplexValueImpl implements ComplexValue
   {
-    private int _id;
+    private Id _id;
     private ComplexValueForeignKey _complexValueFk;
 
-    protected ComplexValueImpl(int id, ComplexValueForeignKey complexValueFk) {
+    protected ComplexValueImpl(Id id, ComplexValueForeignKey complexValueFk) {
       _id = id;
       _complexValueFk = complexValueFk;
     }
 
-    public int getId() {
+    public Id getId() {
       return _id;
     }
 
-    public void setId(int id) {
+    public void setId(Id id) {
+      if(_id == id) {
+        // harmless, ignore
+        return;
+      }
       if(_id != INVALID_ID) {
         throw new IllegalStateException("id may not be reset");
       }
@@ -356,7 +354,11 @@ public abstract class ComplexColumnInfo<V extends ComplexValue>
 
     public void setComplexValueForeignKey(ComplexValueForeignKey complexValueFk)
     {
-      if(_complexValueFk != INVALID_COMPLEX_VALUE_ID) {
+      if(_complexValueFk == complexValueFk) {
+        // harmless, ignore
+        return;
+      }
+      if(_complexValueFk != INVALID_FK) {
         throw new IllegalStateException("complexValueFk may not be reset");
       }
       _complexValueFk = complexValueFk;
@@ -368,7 +370,7 @@ public abstract class ComplexColumnInfo<V extends ComplexValue>
     
     @Override
     public int hashCode() {
-      return ((_id * 37) ^ _complexValueFk.hashCode());
+      return ((_id.get() * 37) ^ _complexValueFk.hashCode());
     }
 
     @Override
@@ -379,5 +381,79 @@ public abstract class ComplexColumnInfo<V extends ComplexValue>
                _complexValueFk.equals(((ComplexValueImpl)o)._complexValueFk)));
     }
   }
+
+  /**
+   * Implementation of ComplexValue.Id.
+   */
+  private static final class ComplexValueIdImpl extends ComplexValue.Id
+  {
+    private static final long serialVersionUID = 20130318L;    
+
+    private final int _value;
+    private final RowId _rowId;
+
+    protected ComplexValueIdImpl(int value, RowId rowId) {
+      _value = value;
+      _rowId = rowId;
+    }
+    
+    @Override
+    public int get() {
+      return _value;
+    }
+
+    @Override
+    public RowId getRowId() {
+      return _rowId;
+    }
+  
+    @Override
+    public byte byteValue() {
+      return (byte)get();
+    }
+  
+    @Override
+    public short shortValue() {
+      return (short)get();
+    }
+  
+    @Override
+    public int intValue() {
+      return get();
+    }
+  
+    @Override
+    public long longValue() {
+      return get();
+    }
+  
+    @Override
+    public float floatValue() {
+      return get();
+    }
+  
+    @Override
+    public double doubleValue() {
+      return get();
+    }
+    
+    @Override
+    public int hashCode() {
+      return _value;
+    }
+  
+    @Override
+    public boolean equals(Object o) {
+      return ((this == o) ||
+              ((o != null) && (getClass() == o.getClass()) &&
+               (_value == ((ComplexValueIdImpl)o)._value)));
+    }
+
+    @Override
+    public String toString()
+    {
+      return String.valueOf(_value);
+    }  
+  }
   
 }
index beaea040d20446ee0723a320042961d8d8fa5fc8..4513f07102a9dc17a2fdc6083328b44ba25a462b 100644 (file)
@@ -22,6 +22,7 @@ package com.healthmarketscience.jackcess.complex;
 import java.io.IOException;
 
 import com.healthmarketscience.jackcess.Column;
+import com.healthmarketscience.jackcess.RowId;
 
 /**
  * Base interface for a value in a complex column (where there may be multiple
@@ -38,15 +39,19 @@ public interface ComplexValue
    * @return the current id or {@link ComplexColumnInfo#INVALID_ID} for a new,
    *         unsaved value.
    */
-  public int getId();
+  public Id getId();
 
-  public void setId(int newId);
+  /**
+   * Called once when a new ComplexValue is saved to set the new unique
+   * identifier.
+   */
+  public void setId(Id newId);
   
   /**
    * Returns the foreign key identifier for this complex value (this value is
    * the same for all values in the same row of the main table).
    * 
-   * @return the current id or {@link ComplexColumnInfo#INVALID_COMPLEX_VALUE_ID}
+   * @return the current id or {@link ComplexColumnInfo#INVALID_FK}
    *         for a new, unsaved value.
    */
   public ComplexValueForeignKey getComplexValueForeignKey();
@@ -69,4 +74,24 @@ public interface ComplexValue
    */
   public void delete() throws IOException;
 
+
+  /**
+   * Identifier for a ComplexValue.  Only valid for comparing complex values
+   * for the same column.
+   */
+  public abstract class Id extends Number 
+  {
+    private static final long serialVersionUID = 20130318L;    
+
+    /**
+     * Returns the unique identifier of this complex value (this value is unique
+     * among all values in all rows of the main table for the complex column).
+     */
+    public abstract int get();
+    
+    /**
+     * Returns the rowId of this ComplexValue within the secondary table.
+     */
+    public abstract RowId getRowId();
+  }
 }
index 9add8c745e7b14d258c77e7295f4caa762b0bae9..4089153040fd8df9690f6a9f0154395df386e4b5 100644 (file)
@@ -20,7 +20,6 @@ USA
 package com.healthmarketscience.jackcess.complex;
 
 import java.io.IOException;
-import java.util.Map;
 
 import com.healthmarketscience.jackcess.Column;
 import com.healthmarketscience.jackcess.Table;
@@ -59,7 +58,7 @@ public class MultiValueColumnInfo extends ComplexColumnInfo<SingleValue>
       ComplexValueForeignKey complexValueFk,
       Row rawValue)
   {
-    int id = (Integer)getPrimaryKeyColumn().getRowValue(rawValue);
+    ComplexValue.Id id = getValueId(rawValue);
     Object value = getValueColumn().getRowValue(rawValue);
 
     return new SingleValueImpl(id, complexValueFk, value);
@@ -73,7 +72,7 @@ public class MultiValueColumnInfo extends ComplexColumnInfo<SingleValue>
   }
   
   public static SingleValue newSingleValue(Object value) {
-    return newSingleValue(INVALID_COMPLEX_VALUE_ID, value);
+    return newSingleValue(INVALID_FK, value);
   }
 
   public static SingleValue newSingleValue(
@@ -87,7 +86,7 @@ public class MultiValueColumnInfo extends ComplexColumnInfo<SingleValue>
   {
     private Object _value;
 
-    private SingleValueImpl(int id, ComplexValueForeignKey complexValueFk,
+    private SingleValueImpl(Id id, ComplexValueForeignKey complexValueFk,
                             Object value)
     {
       super(id, complexValueFk);
index 071da0664d5d50dc7890e5837f848b44308e6a09..b0b692429c450b6580ba6222ef12ce751c76570e 100644 (file)
@@ -27,7 +27,6 @@ import java.util.Map;
 import com.healthmarketscience.jackcess.Column;
 import com.healthmarketscience.jackcess.Table;
 import com.healthmarketscience.jackcess.Row;
-import com.healthmarketscience.jackcess.impl.RowImpl;
 
 /**
  * Complex column info for an unsupported complex type.
@@ -59,7 +58,7 @@ public class UnsupportedColumnInfo extends ComplexColumnInfo<UnsupportedValue>
       ComplexValueForeignKey complexValueFk,
       Row rawValue)
   {
-    int id = (Integer)getPrimaryKeyColumn().getRowValue(rawValue);
+    ComplexValue.Id id = getValueId(rawValue);
 
     Map<String,Object> values = new LinkedHashMap<String,Object>();
     for(Column col : getValueColumns()) {
@@ -82,7 +81,7 @@ public class UnsupportedColumnInfo extends ComplexColumnInfo<UnsupportedValue>
   }
 
   public static UnsupportedValue newValue(Map<String,?> values) {
-    return newValue(INVALID_COMPLEX_VALUE_ID, values);
+    return newValue(INVALID_FK, values);
   }
 
   public static UnsupportedValue newValue(
@@ -96,7 +95,7 @@ public class UnsupportedColumnInfo extends ComplexColumnInfo<UnsupportedValue>
   {
     private Map<String,Object> _values;
 
-    private UnsupportedValueImpl(int id, ComplexValueForeignKey complexValueFk,
+    private UnsupportedValueImpl(Id id, ComplexValueForeignKey complexValueFk,
                                  Map<String,Object> values)
     {
       super(id, complexValueFk);
index e29dd3828b77727b94ba2e82922979de9ef0644b..60c6fb7cc4e82cb3966a2458b8dc5730750c3194 100644 (file)
@@ -23,7 +23,6 @@ import java.io.IOException;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
-import java.util.Map;
 
 import com.healthmarketscience.jackcess.Column;
 import com.healthmarketscience.jackcess.Row;
@@ -96,7 +95,7 @@ public class VersionHistoryColumnInfo extends ComplexColumnInfo<Version>
   }
 
   @Override
-  public int updateValue(Version value) throws IOException {
+  public ComplexValue.Id updateValue(Version value) throws IOException {
     throw new UnsupportedOperationException(
         "This column does not support value updates");
   }
@@ -129,7 +128,7 @@ public class VersionHistoryColumnInfo extends ComplexColumnInfo<Version>
   @Override
   protected VersionImpl toValue(ComplexValueForeignKey complexValueFk,
                                 Row rawValue) {
-    int id = (Integer)getPrimaryKeyColumn().getRowValue(rawValue);
+    ComplexValue.Id id = getValueId(rawValue);
     String value = (String)getValueColumn().getRowValue(rawValue);
     Date modifiedDate = (Date)getModifiedDateColumn().getRowValue(rawValue);
 
@@ -145,7 +144,7 @@ public class VersionHistoryColumnInfo extends ComplexColumnInfo<Version>
   }
   
   public static Version newVersion(String value, Date modifiedDate) {
-    return newVersion(INVALID_COMPLEX_VALUE_ID, value, modifiedDate);
+    return newVersion(INVALID_FK, value, modifiedDate);
   }
   
   public static Version newVersion(ComplexValueForeignKey complexValueFk,
@@ -159,7 +158,7 @@ public class VersionHistoryColumnInfo extends ComplexColumnInfo<Version>
     private final String _value;
     private final Date _modifiedDate;
 
-    private VersionImpl(int id, ComplexValueForeignKey complexValueFk,
+    private VersionImpl(Id id, ComplexValueForeignKey complexValueFk,
                         String value, Date modifiedDate)
     {
       super(id, complexValueFk);
@@ -187,8 +186,8 @@ public class VersionHistoryColumnInfo extends ComplexColumnInfo<Version>
 
       // use id, then complexValueFk to break ties (although we really
       // shouldn't be comparing across different columns)
-      int id1 = getId();
-      int id2 = o.getId();
+      int id1 = getId().get();
+      int id2 = o.getId().get();
       if(id1 != id2) {
         return ((id1 > id2) ? -1 : 1);
       }
index e46d0af48d8485daf0bf4cf639089314514a420f..2038556509f6dbacf0699cbb3e6d979d42e1d208 100644 (file)
@@ -73,6 +73,15 @@ import com.healthmarketscience.jackcess.ColumnBuilder;
 public class ColumnImpl implements Column, Comparable<ColumnImpl> {
   
   private static final Log LOG = LogFactory.getLog(ColumnImpl.class);
+  
+  /**
+   * Placeholder object for adding rows which indicates that the caller wants
+   * the RowId of the new row.  Must be added as an extra value at the end of
+   * the row values array.
+   * @see TableImpl#asRowWithRowId
+   * @usage _intermediate_field_
+   */
+  public static final Object RETURN_ROW_ID = "<RETURN_ROW_ID>";
 
   /**
    * Access stores numeric dates in days.  Java stores them in milliseconds.
index f24327fe35357ab05d4a9134dc2a32e6a8509643..898508ae21b032b500b656841677e8431b30a616 100644 (file)
@@ -60,6 +60,6 @@ public class RowImpl extends LinkedHashMap<String,Object> implements Row
 
   @Override
   public String toString() {
-    return "Row id=[" + _id + "], content=" + super.toString();
+    return "Row[" + _id + "] " + super.toString();
   }
 }
index 34b884603b8eeee88e5881db2ad2a93dc5fbe5d6..919c17ff8564cb9052131a75f25cbf67fad68506 100644 (file)
@@ -49,6 +49,7 @@ import com.healthmarketscience.jackcess.Index;
 import com.healthmarketscience.jackcess.IndexBuilder;
 import com.healthmarketscience.jackcess.PropertyMap;
 import com.healthmarketscience.jackcess.Row;
+import com.healthmarketscience.jackcess.RowId;
 import com.healthmarketscience.jackcess.Table;
 import com.healthmarketscience.jackcess.util.ErrorHandler;
 import org.apache.commons.logging.Log;
@@ -380,6 +381,15 @@ public class TableImpl implements Table
     throw new IllegalArgumentException("Column with name " + name +
                                        " does not exist in this table");
   }
+  
+  public boolean hasColumn(String name) {
+    for(ColumnImpl column : _columns) {
+      if(column.getName().equalsIgnoreCase(name)) {
+        return true;
+      }
+    }
+    return false;
+  }
 
   public PropertyMap getProperties() throws IOException {
     if(_props == null) {
@@ -465,10 +475,22 @@ public class TableImpl implements Table
   }
 
   public Row deleteRow(Row row) throws IOException {
-    deleteRow(getDefaultCursor().getRowState(), (RowIdImpl)row.getId());
+    deleteRow(row.getId());
     return row;
   }
 
+  /**
+   * Delete the row with the given id.  Provided RowId must have previously
+   * been returned from this Table.
+   * @return the given rowId
+   * @throws IllegalStateException if the given row is not valid
+   * @usage _intermediate_method_
+   */
+  public RowId deleteRow(RowId rowId) throws IOException {
+    deleteRow(getDefaultCursor().getRowState(), (RowIdImpl)rowId);
+    return rowId;
+  }
+
   /**
    * Delete the row for the given rowId.
    * @usage _advanced_method_
@@ -1241,22 +1263,41 @@ public class TableImpl implements Table
   }
   
   public Object[] asRow(Map<String,?> rowMap) {
-    return asRow(rowMap, null);
+    return asRow(rowMap, null, false);
+  }
+  
+  /**
+   * Converts a map of columnName -> columnValue to an array of row values
+   * appropriate for a call to {@link #addRow(Object...)}, where the generated
+   * RowId will be an extra value at the end of the array.
+   * @see ColumnImpl#RETURN_ROW_ID
+   * @usage _intermediate_method_
+   */
+  public Object[] asRowWithRowId(Map<String,?> rowMap) {
+    return asRow(rowMap, null, true);
   }
   
   public Object[] asUpdateRow(Map<String,?> rowMap) {
-    return asRow(rowMap, Column.KEEP_VALUE);
+    return asRow(rowMap, Column.KEEP_VALUE, false);
   }
 
   /**
    * Converts a map of columnName -> columnValue to an array of row values.
    */
-  private Object[] asRow(Map<String,?> rowMap, Object defaultValue)
+  private Object[] asRow(Map<String,?> rowMap, Object defaultValue, 
+                         boolean returnRowId)
   {
-    Object[] row = new Object[_columns.size()];
+    int len = _columns.size();
+    if(returnRowId) {
+      ++len;
+    }
+    Object[] row = new Object[len];
     if(defaultValue != null) {
       Arrays.fill(row, defaultValue);
     }
+    if(returnRowId) {
+      row[len - 1] = ColumnImpl.RETURN_ROW_ID;
+    }
     if(rowMap == null) {
       return row;
     }
@@ -1334,6 +1375,7 @@ public class TableImpl implements Table
 
     List<Object[]> dupeRows = null;
     ByteBuffer[] rowData = new ByteBuffer[rows.size()];
+    int numCols = _columns.size();
     for (int i = 0; i < rows.size(); i++) {
 
       // we need to make sure the row is the right length and is an Object[]
@@ -1342,8 +1384,8 @@ public class TableImpl implements Table
       // they need that info they should use a row array of the right
       // size/type!
       Object[] row = rows.get(i);
-      if((row.length < _columns.size()) || (row.getClass() != Object[].class)) {
-        row = dupeRow(row, _columns.size());
+      if((row.length < numCols) || (row.getClass() != Object[].class)) {
+        row = dupeRow(row, numCols);
         // copy the input rows to a modifiable list so we can update the
         // elements
         if(dupeRows == null) {
@@ -1390,6 +1432,11 @@ public class TableImpl implements Table
       for(IndexData indexData : _indexDatas) {
         indexData.addRow(row, rowId);
       }
+
+      // return rowTd if desired
+      if((row.length > numCols) && (row[numCols] == ColumnImpl.RETURN_ROW_ID)) {
+        row[numCols] = rowId;
+      }
     }
 
     writeDataPage(dataPage, pageNumber);
@@ -1405,6 +1452,18 @@ public class TableImpl implements Table
         getDefaultCursor().getRowState(), (RowIdImpl)row.getId(), row);
   }
 
+  /**
+   * Update the row with the given id.  Provided RowId must have previously
+   * been returned from this Table.
+   * @return the given row, updated with the current row values
+   * @throws IllegalStateException if the given row is not valid, or deleted.
+   * @usage _intermediate_method_
+   */
+  public Object[] updateRow(RowId rowId, Object... row) throws IOException {
+    return updateRow(
+        getDefaultCursor().getRowState(), (RowIdImpl)rowId, row);
+  }
+
   public <M extends Map<String,Object>> M updateRowFromMap(
       RowState rowState, RowIdImpl rowId, M row) 
      throws IOException 
index d43ff1b7237954ead19cf543be55b0e0fc25b9a4..91794db45371fdfad044f60f2b40dd879191198c 100644 (file)
@@ -29,8 +29,9 @@ import java.util.Map;
 import com.healthmarketscience.jackcess.CursorBuilder;
 import com.healthmarketscience.jackcess.Index;
 import com.healthmarketscience.jackcess.IndexCursor;
-import com.healthmarketscience.jackcess.Table;
 import com.healthmarketscience.jackcess.Row;
+import com.healthmarketscience.jackcess.RuntimeIOException;
+import com.healthmarketscience.jackcess.Table;
 import com.healthmarketscience.jackcess.impl.IndexImpl;
 
 /**
@@ -191,7 +192,7 @@ public class Joiner
    * @param columnNames desired columns in the from table row
    */
   public Iterator<Row> findRows(Map<String,?> fromRow,
-                                               Collection<String> columnNames)
+                                Collection<String> columnNames)
   {
     toEntryValues(fromRow);
     return _toCursor.entryIterator(columnNames, _entryValues);
@@ -207,7 +208,7 @@ public class Joiner
    * @usage _intermediate_method_
    */
   public Iterator<Row> findRows(Object[] fromRow,
-                                               Collection<String> columnNames)
+                                Collection<String> columnNames)
   {
     toEntryValues(fromRow);
     return _toCursor.entryIterator(columnNames, _entryValues);