From fefc08596f2fd8e2c51150d14d78b0caa417ed4e Mon Sep 17 00:00:00 2001 From: James Ahlborn Date: Mon, 24 Mar 2008 17:06:24 +0000 Subject: [PATCH] Need to store auto-number values back into row so that indexes can be updated correctly. git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@296 f203690c-595d-4dc9-a70b-905162fa7fd2 --- src/changes/changes.xml | 6 ++ .../jackcess/Database.java | 4 +- .../healthmarketscience/jackcess/Table.java | 85 +++++++++++++----- test/data/test.mdb | Bin 2904064 -> 3035136 bytes .../jackcess/DatabaseTest.java | 25 ++++-- 5 files changed, 89 insertions(+), 31 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 7225789..0223e4b 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -5,6 +5,12 @@ James Ahlborn + + + Need to store auto-number values back into row so that indexes can be + updated correctly. + + More fixes for index parsing. Believe index names are now correctly diff --git a/src/java/com/healthmarketscience/jackcess/Database.java b/src/java/com/healthmarketscience/jackcess/Database.java index d3485d8..f49972d 100644 --- a/src/java/com/healthmarketscience/jackcess/Database.java +++ b/src/java/com/healthmarketscience/jackcess/Database.java @@ -851,9 +851,7 @@ public class Database // may have null fields. We always want to add the // same number of columns to the table each time. // - Object[] data = new Object[columnNames.length]; - String[] splitData = line.split(delim); - System.arraycopy(splitData, 0, data, 0, splitData.length); + Object[] data = Table.dupeRow(line.split(delim), columnNames.length); rows.add(filter.filterRow(data)); if (rows.size() == COPY_TABLE_BATCH_SIZE) { table.addRows(rows); diff --git a/src/java/com/healthmarketscience/jackcess/Table.java b/src/java/com/healthmarketscience/jackcess/Table.java index c69fc89..5e8a247 100644 --- a/src/java/com/healthmarketscience/jackcess/Table.java +++ b/src/java/com/healthmarketscience/jackcess/Table.java @@ -1102,6 +1102,13 @@ public class Table /** * Add a single row to this table and write it to disk + *

+ * Note, if this table has an auto-number column, the value written will be + * put back into the given row array. + * + * @param row row values for a single row. the row will be modified if + * this table contains an auto-number column, otherwise it + * will not be modified. */ public void addRow(Object... row) throws IOException { addRows(Collections.singletonList(row), _singleRowBufferH); @@ -1111,7 +1118,13 @@ public class Table * Add multiple rows to this table, only writing to disk after all * rows have been written, and every time a data page is filled. This * is much more efficient than calling addRow multiple times. - * @param rows List of Object[] row values + *

+ * Note, if this table has an auto-number column, the values written will be + * put back into the given row arrays. + * + * @param rows List of Object[] row values. the rows will be modified if + * this table contains an auto-number column, otherwise they + * will not be modified. */ public void addRows(List rows) throws IOException { addRows(rows, _multiRowBufferH); @@ -1119,21 +1132,35 @@ public class Table /** * Add multiple rows to this table, only writing to disk after all - * rows have been written, and every time a data page is filled. This - * is much more efficient than calling addRow multiple times. - * @param rows List of Object[] row values + * rows have been written, and every time a data page is filled. + * @param inRows List of Object[] row values * @param writeRowBufferH TempBufferHolder used to generate buffers for * writing the row data */ - private void addRows(List rows, + private void addRows(List inRows, TempBufferHolder writeRowBufferH) throws IOException { + // copy the input rows to a modifiable list so we can update the elements + List rows = new ArrayList(inRows); ByteBuffer[] rowData = new ByteBuffer[rows.size()]; - Iterator iter = rows.iterator(); - for (int i = 0; iter.hasNext(); i++) { - rowData[i] = createRow(iter.next(), getFormat().MAX_ROW_SIZE, + for (int i = 0; i < rows.size(); i++) { + + // we need to make sure the row is the right length (fill with null). + // note, if the row is copied the caller will not be able to access any + // generated auto-number value, but if they need that info they should + // use a row array of the right size! + Object[] row = rows.get(i); + if(row.length < _columns.size()) { + row = dupeRow(row, _columns.size()); + // we copied the row, so put the copy back into the rows list + rows.set(i, row); + } + + // write the row of data to a temporary buffer + rowData[i] = createRow(row, getFormat().MAX_ROW_SIZE, writeRowBufferH.getPageBuffer(getPageChannel())); + if (rowData[i].limit() > getFormat().MAX_ROW_SIZE) { throw new IOException("Row size " + rowData[i].limit() + " is too large"); @@ -1254,7 +1281,15 @@ public class Table } /** - * Serialize a row of Objects into a byte buffer + * Serialize a row of Objects into a byte buffer. + *

+ * Note, if this table has an auto-number column, the value written will be + * put back into the given row array. + * + * @param rowArray row data, expected to be correct length for this table + * @param maxRowSize max size the data can be for this row + * @param buffer buffer to which to write the row data + * @return the given buffer, filled with the row data */ ByteBuffer createRow(Object[] rowArray, int maxRowSize, ByteBuffer buffer) throws IOException @@ -1262,15 +1297,6 @@ public class Table buffer.putShort(_maxColumnCount); NullMask nullMask = new NullMask(_maxColumnCount); - List row = new ArrayList(_columns.size()); - for(Object rowValue : rowArray) { - row.add(rowValue); - } - //Append null for arrays that are too small - for (int i = rowArray.length; i < _columns.size(); i++) { - row.add(null); - } - //Fixed length column data comes first int fixedDataStart = buffer.position(); int fixedDataEnd = fixedDataStart; @@ -1278,7 +1304,7 @@ public class Table if(!col.isVariableLength()) { - Object rowValue = row.get(col.getColumnIndex()); + Object rowValue = rowArray[col.getColumnIndex()]; if (col.getType() == DataType.BOOLEAN) { @@ -1290,8 +1316,13 @@ public class Table } else { if(col.isAutoNumber()) { + // ignore given row value, use next autonumber rowValue = getNextAutoNumber(); + + // we need to stick this back in the row so that the indexes get + // updated correctly (and caller can get the generated value) + rowArray[col.getColumnIndex()] = rowValue; } if(rowValue != null) { @@ -1329,7 +1360,7 @@ public class Table int varColumnOffsetsIndex = 0; for (Column varCol : _varColumns) { short offset = (short) buffer.position(); - Object rowValue = row.get(varCol.getColumnIndex()); + Object rowValue = rowArray[varCol.getColumnIndex()]; if (rowValue != null) { // we have a value nullMask.markNotNull(varCol); @@ -1576,6 +1607,16 @@ public class Table } return numAutoNumCols; } + + /** + * Duplicates and returns a row of data, optionally with a longer length + * filled with {@code null}. + */ + static Object[] dupeRow(Object[] row, int newRowLength) { + Object[] copy = new Object[newRowLength]; + System.arraycopy(row, 0, copy, 0, row.length); + return copy; + } /** various statuses for the row data */ private enum RowStatus { @@ -1714,9 +1755,7 @@ public class Table } public Object[] getRowValues() { - Object[] copy = new Object[_rowValues.length]; - System.arraycopy(_rowValues, 0, copy, 0, _rowValues.length); - return copy; + return dupeRow(_rowValues, _rowValues.length); } public RowId getHeaderRowId() { diff --git a/test/data/test.mdb b/test/data/test.mdb index 89a05a1507b21b42fcb1b86c559631ed0a2208c8..23124d6793a6acdebc434e7e80086201173c0a59 100644 GIT binary patch delta 2447 zcmeH}Yiv_x7{{OI^sGH?*VA^iFv`ZdaT_qlfDh_G=pwjH7>wJ(0!lY0xB+7bB!1C$ z-Uxn>btmzNMpy-7B0*a#Ylu^UPe??T5Cp;{MeareBE}CO$N$?>z=aqSzWBlS^w;620$iNVr{^Q**7H5s7)cDZ?-% zK4Ta2KAEV|Oyt$v{z(q+9UD=36ZQVRPOjA46_a?7wzS@#XsOsbLHg6I$-&Vjd+ZDC zPWwUI8@7P$rnT3))>>x0qEz8xa+I-sZj&W9rNFs$u)~2^r$73~|NUdGMDu-4-J^R^tQ^jUfPvX&a$y{0H z=Nz!h*9y9Z#G|`dOLaz+FiEMjq~q0%4oGg=b$25RO_fP;`QyPm>>&m2q>EQ`q{d1~B_6F-LT*Z79Iha?Q!afuc}?B9z{!vM(zQ@8 zq$X;nRrEYfrVHC2BMPV2pats{LjGoXO*EX1! z81X`4QY&1_I`hq;uh)zz?5^7p*!|L54W+LOXUd@plaHz>d7_=iHrdaavcVgyJNmgu z_xE$IR4D6Jt9kt}VR8`3l&!;5KnJVK=>vHuQ4p_SH9JLMsc?dWg7NF8R@ z(MmmfoFk!oLGFhSM42F4i6u#-D?-gVqVXP)-AvtN`%YaXbXz}}czJ2d#o8T3@3t=a zXx~sVc7I}u{{6`*`b0ODesHVn@TX60IkqEz|7jj-c>#k1mugB&i9E}en=4=T*F?rI zT+~_rgV*u^Z8OG1U1S2ibV1 z>;EHt_u@ZPq&*Lcbh7;zcbB@Xe9f7?5s-xa@#y!w@eE7A1Z0o{%)kN^UD_*`KS-ky4 zVY13Z;{FsxCYzWL>qzMdNij9(Zx}`wJ}@vS;WR(ud{W?q zCoGKb*?0`&v|$8|;X>GG7}pJ>FKyIlg3&o))OWpclh#*Np!Lts(Nmpx@0{{`@{{9= zJ%`oaF8)Q8Qj)%J8&8kKQwR)Wcx_QiHN;Vf^(LYUzMB8*E jV>wTbME}tJIg*^{yk_GhS^+uflks7t2dz@zUy1$#6-2n- delta 660 zcmXxcO=}ZT6b9gXCSztMlbOk+F~&5eF}2^KwVQ%PNb3h#w6;(Xt6fBph_M!{xDmmq zpcWK6USUAgCO<&Uc!j~8o34b~ofRci7eZEMqYGEQsqKM>d${L4r(AhY<%&l&$)u#P z&0oYbrfC!9En@#mV$0SUVMn;-)Mjmo>U!%xDKj<`WGu$*%#ab=%C?@En96*xXqelB zLlot+QyFo7@Z~}2h{EMUclL|^RG-vC`bwxA8VUW;JZ(k<+xXUO?>0FBW~QeXE-$t!+6-WX9&}!QLlOzyUsF+XS|5r_O}%&r?0EHyjd}B zZ1j26b(NcqOTiP#cex4Tw;BZ{YqA{6F!8gI3hGTcu$4c|jplW)+LXoB-%BO^kvV>9 zbi6f7xJH2v5xMC>>A4?Sr#$(Ei}W?%M!u2Z7K+sAA1Kl*#eFa!neNDCs|KmIj zpVP;b?L(GptWk&mw@Z2$*o^sz#RLBQXL{0W5v|g8l33mUo~N7S)TZy(NrC{#umggi zfC?IfK!-3GV1fk^uptU<5QCi%hh30>-H?QKNWmURLkDDFFJz$;_CXhPLl5*qAN0e3 KU#I=qlm7r6_RWI; diff --git a/test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java b/test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java index 90c57b1..5592e8c 100644 --- a/test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java +++ b/test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java @@ -169,7 +169,7 @@ public class DatabaseTest extends TestCase { public void testGetNextRow() throws Exception { Database db = open(); - assertEquals(2, db.getTableNames().size()); + assertEquals(3, db.getTableNames().size()); Table table = db.getTable("Table1"); Map row = table.getNextRow(); @@ -702,6 +702,23 @@ public class DatabaseTest extends TestCase { .addColumn(new ColumnBuilder("b", DataType.TEXT).toColumn()) .toTable(db); + doTestAutoNumber(table); + + db.close(); + } + + public void testAutoNumberPK() throws Exception { + Database db = openCopy(new File("test/data/test.mdb")); + + Table table = db.getTable("Table3"); + + doTestAutoNumber(table); + + db.close(); + } + + private void doTestAutoNumber(Table table) throws Exception + { table.addRow(null, "row1"); table.addRow(13, "row2"); table.addRow("flubber", "row3"); @@ -732,10 +749,8 @@ public class DatabaseTest extends TestCase { "b", "row5")); assertTable(expectedRows, table); - - db.close(); - } - + } + public void testWriteAndReadDate() throws Exception { Database db = create(); -- 2.39.5