]> source.dussan.org Git - jackcess.git/commitdiff
lower log level for certain system table warnings; add contextual info to many errors...
authorJames Ahlborn <jtahlborn@yahoo.com>
Sun, 8 Mar 2015 19:24:02 +0000 (19:24 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Sun, 8 Mar 2015 19:24:02 +0000 (19:24 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@919 f203690c-595d-4dc9-a70b-905162fa7fd2

16 files changed:
src/changes/changes.xml
src/main/java/com/healthmarketscience/jackcess/BatchUpdateException.java
src/main/java/com/healthmarketscience/jackcess/ColumnBuilder.java
src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java
src/main/java/com/healthmarketscience/jackcess/impl/CalculatedColumnUtil.java
src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java
src/main/java/com/healthmarketscience/jackcess/impl/ComplexColumnSupport.java
src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java
src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java
src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
src/main/java/com/healthmarketscience/jackcess/impl/IndexPageCache.java
src/main/java/com/healthmarketscience/jackcess/impl/LongValueColumnImpl.java
src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java
src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java
src/main/java/com/healthmarketscience/jackcess/impl/query/QueryImpl.java
src/main/java/com/healthmarketscience/jackcess/util/Joiner.java

index 78bf4ea17ad02f94f3ce1d4dc4e41ef2a7f3aade..0c866c00d3d94d6e8ff882524c8233d31ccbb91e 100644 (file)
         selectively including different table types when iterating the tables
         in a Database.
       </action>
+      <action dev="jahlborn" type="add" system="SourceForge2Features" issue="29">
+        Lowered the log level for certain warnings related to system tables
+        which do not generally affect jackcess functionality.
+      </action>
+      <action dev="jahlborn" type="add" system="SourceForge2Features" issue="29">
+        Added contextual information to many errors and warnings.
+      </action>
     </release>
     <release version="2.0.8" date="2014-12-26">
       <action dev="jahlborn" type="fix" system="SourceForge2" issue="113">
index 1fb342639f040e9a62b42a171db6710a49fb6efc..ecb1fcf957bdb94821e326b8d16a6d7cf87c3149 100644 (file)
@@ -32,8 +32,8 @@ public class BatchUpdateException extends JackcessException
 
   private final int _updateCount;
 
-  public BatchUpdateException(int updateCount, Throwable cause) {
-    super(cause);
+  public BatchUpdateException(int updateCount, String msg, Throwable cause) {
+    super(msg + ": " + cause, cause);
     _updateCount = updateCount;
   }
 
index f013e3bfa2da201c81bcb4dac337cb2a37c9af2a..84092b4dde2f42ab6499ad382f5542fe1ef311ef 100644 (file)
@@ -368,80 +368,82 @@ public class ColumnBuilder {
    */
   public void validate(JetFormat format) {
     if(getType() == null) {
-      throw new IllegalArgumentException("must have type");
+      throw new IllegalArgumentException(withErrorContext("must have type"));
     }
     DatabaseImpl.validateIdentifierName(
         getName(), format.MAX_COLUMN_NAME_LENGTH, "column");
 
     if(getType().isUnsupported()) {
-      throw new IllegalArgumentException(
-          "Cannot create column with unsupported type " + getType());
+      throw new IllegalArgumentException(withErrorContext(
+          "Cannot create column with unsupported type " + getType()));
     }
     if(!format.isSupportedDataType(getType())) {
-      throw new IllegalArgumentException(
-          "Database format " + format + " does not support type " + getType());
+      throw new IllegalArgumentException(withErrorContext(
+          "Database format " + format + " does not support type " + getType()));
     }
     
     if(!getType().isVariableLength()) {
       if(getLength() != getType().getFixedSize()) {
         if(getLength() < getType().getFixedSize()) {
-          throw new IllegalArgumentException("invalid fixed length size");
+          throw new IllegalArgumentException(withErrorContext(
+              "invalid fixed length size"));
         }
-        LOG.warn("Column length " + getLength() + 
-                 " longer than expected fixed size " + 
-                 getType().getFixedSize());
+        LOG.warn(withErrorContext(
+                "Column length " + getLength() + 
+                " longer than expected fixed size " + getType().getFixedSize()));
       }
     } else if(!getType().isLongValue()) {
       if(!getType().isValidSize(getLength())) {
-        throw new IllegalArgumentException("var length out of range");
+        throw new IllegalArgumentException(withErrorContext(
+            "var length out of range"));
       }
     }
 
     if(getType().getHasScalePrecision()) {
       if(!getType().isValidScale(getScale())) {
-        throw new IllegalArgumentException(
+        throw new IllegalArgumentException(withErrorContext(
             "Scale must be from " + getType().getMinScale() + " to " +
-            getType().getMaxScale() + " inclusive");
+            getType().getMaxScale() + " inclusive"));
       }
       if(!getType().isValidPrecision(getPrecision())) {
-        throw new IllegalArgumentException(
+        throw new IllegalArgumentException(withErrorContext(
             "Precision must be from " + getType().getMinPrecision() + " to " +
-            getType().getMaxPrecision() + " inclusive");
+            getType().getMaxPrecision() + " inclusive"));
       }
     }
 
     if(isAutoNumber()) {
       if(!getType().mayBeAutoNumber()) {
-        throw new IllegalArgumentException(
-            "Auto number column must be long integer or guid");
+        throw new IllegalArgumentException(withErrorContext(
+            "Auto number column must be long integer or guid"));
       }
     }
 
     if(isCompressedUnicode()) {
       if(!getType().isTextual()) {
-        throw new IllegalArgumentException(
-            "Only textual columns allow unicode compression (text/memo)");
+        throw new IllegalArgumentException(withErrorContext(
+            "Only textual columns allow unicode compression (text/memo)"));
       }
     }
 
     if(isHyperlink()) {
       if(getType() != DataType.MEMO) {
-        throw new IllegalArgumentException(
-            "Only memo columns can be hyperlinks");
+        throw new IllegalArgumentException(withErrorContext(
+            "Only memo columns can be hyperlinks"));
       }
     }
 
     if(isCalculated()) {
       if(!format.isSupportedCalculatedDataType(getType())) {
-        throw new IllegalArgumentException(
+        throw new IllegalArgumentException(withErrorContext(
             "Database format " + format + " does not support calculated type " +
-            getType());
+            getType()));
       }
 
       // must have an expression
       if(getProperty(PropertyMap.EXPRESSION_PROP) == null) {
-        throw new IllegalArgumentException(
-            "No expression provided for calculated type " + getType());
+        throw new IllegalArgumentException(withErrorContext(
+            "No expression provided for calculated type " + getType()));
       }
 
       // must have result type (just fill in if missing)
@@ -458,5 +460,8 @@ public class ColumnBuilder {
     // for backwards compat w/ old code
     return this;
   }
-  
+
+  private String withErrorContext(String msg) {
+    return msg + "(Column=" + getName() + ")";
+  }
 }
index 4a55205211d5e1509ffe7129a1b7ffdd749516b6..391debbf760f60ab38add15d881522ffca4686df 100644 (file)
@@ -141,30 +141,32 @@ public class IndexBuilder
         getName(), format.MAX_INDEX_NAME_LENGTH, "index");
 
     if(getColumns().isEmpty()) {
-      throw new IllegalArgumentException("index " + getName() +
-                                         " has no columns");
+      throw new IllegalArgumentException(withErrorContext(
+          "index has no columns"));
     }
     if(getColumns().size() > IndexData.MAX_COLUMNS) {
-      throw new IllegalArgumentException("index " + getName() +
-                                         " has too many columns, max " +
-                                         IndexData.MAX_COLUMNS);
+      throw new IllegalArgumentException(withErrorContext(
+          "index has too many columns, max " + IndexData.MAX_COLUMNS));
     }
 
     Set<String> idxColNames = new HashSet<String>();
     for(Column col : getColumns()) {
       String idxColName = col.getName().toUpperCase();
       if(!idxColNames.add(idxColName)) {
-        throw new IllegalArgumentException("duplicate column name " +
-                                           col.getName() + " in index " +
-                                           getName());
+        throw new IllegalArgumentException(withErrorContext(
+            "duplicate column name " + col.getName() + " in index"));
       }
       if(!tableColNames.contains(idxColName)) {
-        throw new IllegalArgumentException("column named " + col.getName() +
-                                           " not found in table");
+        throw new IllegalArgumentException(withErrorContext(
+            "column named " + col.getName() + " not found in table"));
       }
     }
   }
 
+  private String withErrorContext(String msg) {
+    return msg + "(Index=" + getName() + ")";
+  }
+
   /**
    * Information about a column in this index (name and ordering).
    */
index 727818a2b0a30d79d2c19218b09252ae0c0b0f47..3b528f5bdf99183838f264ce3e28d83c460f34da 100644 (file)
@@ -55,9 +55,7 @@ class CalculatedColumnUtil
    * Creates the appropriate ColumnImpl class for a calculated column and
    * reads a column definition in from a buffer
    * 
-   * @param table owning table
-   * @param buffer Buffer containing column definition
-   * @param offset Offset in the buffer at which the column definition starts
+   * @param args column construction info
    * @usage _advanced_method_
    */
   static ColumnImpl create(ColumnImpl.InitArgs args) throws IOException
@@ -333,9 +331,9 @@ class CalculatedColumnUtil
         
         // check precision
         if(decVal.precision() > getType().getMaxPrecision()) {
-          throw new IOException(
+          throw new IOException(withErrorContext(
               "Numeric value is too big for specified precision "
-              + getType().getMaxPrecision() + ": " + decVal);
+              + getType().getMaxPrecision() + ": " + decVal));
         }
     
         // convert to unscaled BigInteger, big-endian bytes
index 0565cafe8779f8140b06379ee87ec27be373e493..676af4d488e66ef6a7f12227767137f812587467 100644 (file)
@@ -282,7 +282,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
     try {
       args.type = DataType.fromByte(colType);
     } catch(IOException e) {
-      LOG.warn("Unsupported column type " + colType);
+      LOG.warn(withErrorContext("Unsupported column type " + colType,
+                                table.getDatabase(), table.getName(), name));
       boolean variableLength = ((args.flags & FIXED_LEN_FLAG_MASK) == 0);
       args.type = (variableLength ? DataType.UNSUPPORTED_VARLEN :
                    DataType.UNSUPPORTED_FIXEDLEN);
@@ -496,8 +497,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
       // cannot set autonumber validator (autonumber values are controlled
       // internally)
       if(newValidator != null) {
-        throw new IllegalArgumentException(
-            "Cannot set ColumnValidator for autonumber columns");
+        throw new IllegalArgumentException(withErrorContext(
+                "Cannot set ColumnValidator for autonumber columns"));
       }
       // just leave default validator instance alone
       return;
@@ -530,7 +531,7 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
     case COMPLEX_TYPE:
       return new ComplexTypeAutoNumberGenerator();
     default:
-      LOG.warn("Unknown auto number column type " + _type);
+      LOG.warn(withErrorContext("Unknown auto number column type " + _type));
       return new UnsupportedAutoNumberGenerator(_type);
     }
   }
@@ -603,7 +604,7 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
 
     switch(getType()) {
     case BOOLEAN:
-      throw new IOException("Tried to read a boolean from data instead of null mask.");
+      throw new IOException(withErrorContext("Tried to read a boolean from data instead of null mask."));
     case BYTE:
       return Byte.valueOf(buffer.get());
     case INT:
@@ -633,7 +634,7 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
     case COMPLEX_TYPE:
       return new ComplexValueForeignKeyImpl(this, buffer.getInt());
     default:
-      throw new IOException("Unrecognized data type: " + _type);
+      throw new IOException(withErrorContext("Unrecognized data type: " + _type));
     }
   }
 
@@ -644,11 +645,11 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
    * @return BigDecimal representing the monetary value
    * @throws IOException if the value cannot be parsed 
    */
-  private static BigDecimal readCurrencyValue(ByteBuffer buffer)
+  private BigDecimal readCurrencyValue(ByteBuffer buffer)
     throws IOException
   {
     if(buffer.remaining() != 8) {
-      throw new IOException("Invalid money value.");
+      throw new IOException(withErrorContext("Invalid money value"));
     }
     
     return new BigDecimal(BigInteger.valueOf(buffer.getLong(0)), 4);
@@ -735,9 +736,9 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
 
       // check precision
       if(decVal.precision() > getPrecision()) {
-        throw new IOException(
+        throw new IOException(withErrorContext(
             "Numeric value is too big for specified precision "
-            + getPrecision() + ": " + decVal);
+            + getPrecision() + ": " + decVal));
       }
     
       // convert to unscaled BigInteger, big-endian bytes
@@ -754,7 +755,7 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
     }
   }
 
-  static byte[] toUnscaledByteArray(BigDecimal decVal, int maxByteLen)
+  byte[] toUnscaledByteArray(BigDecimal decVal, int maxByteLen)
     throws IOException
   {
     // convert to unscaled BigInteger, big-endian bytes
@@ -766,7 +767,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
         // with unsigned values, so we can drop the extra leading 0
         intValBytes = ByteUtil.copyOf(intValBytes, 1, maxByteLen);
       } else {
-        throw new IOException("Too many bytes for valid BigInteger?");
+        throw new IOException(withErrorContext(
+                                  "Too many bytes for valid BigInteger?"));
       }
     } else if(intValBytes.length < maxByteLen) {
       intValBytes = ByteUtil.copyOf(intValBytes, 0, maxByteLen, 
@@ -910,12 +912,12 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
   /**
    * Writes a GUID value.
    */
-  private static void writeGUIDValue(ByteBuffer buffer, Object value)
+  private void writeGUIDValue(ByteBuffer buffer, Object value)
     throws IOException
   {
     Matcher m = GUID_PATTERN.matcher(toCharSequence(value));
     if(!m.matches()) {
-      throw new IOException("Invalid GUID: " + value);
+      throw new IOException(withErrorContext("Invalid GUID: " + value));
     }
 
     ByteBuffer origBuffer = null;
@@ -1017,8 +1019,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
       // should already be "encoded"
       break;
     default:
-      throw new RuntimeException("unexpected inline var length type: " +
-                                 getType());
+      throw new RuntimeException(withErrorContext(
+              "unexpected inline var length type: " + getType()));
     }
 
     ByteBuffer buffer = ByteBuffer.wrap(toByteArray(obj)).order(order);
@@ -1099,13 +1101,15 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
     case UNSUPPORTED_FIXEDLEN:
       byte[] bytes = toByteArray(obj);
       if(bytes.length != getLength()) {
-        throw new IOException("Invalid fixed size binary data, size "
-                              + getLength() + ", got " + bytes.length);
+        throw new IOException(withErrorContext(
+                                  "Invalid fixed size binary data, size "
+                                  + getLength() + ", got " + bytes.length));
       }
       buffer.put(bytes);
       break;
     default:
-      throw new IOException("Unsupported data type: " + getType());
+      throw new IOException(withErrorContext(
+                                "Unsupported data type: " + getType()));
     }
     return buffer;
   }
@@ -1205,9 +1209,10 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
   {
     CharSequence text = toCharSequence(obj);
     if((text.length() > maxChars) || (text.length() < minChars)) {
-      throw new IOException("Text is wrong length for " + getType() +
+      throw new IOException(withErrorContext(
+                            "Text is wrong length for " + getType() +
                             " column, max " + maxChars
-                            + ", min " + minChars + ", got " + text.length());
+                            + ", min " + minChars + ", got " + text.length()));
     }
     
     // may only compress if column type allows it
@@ -1759,6 +1764,16 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
     }
   }
 
+  String withErrorContext(String msg) {
+    return withErrorContext(msg, getDatabase(), getTable().getName(), getName());
+  }
+
+  private static String withErrorContext(
+      String msg, DatabaseImpl db, String tableName, String colName) {
+    return msg + " (Db=" + db.getName() + ";Table=" + tableName + ";Column=" + 
+      colName + ")";
+  }
+
   /**
    * Date subclass which stashes the original date bits, in case we attempt to
    * re-write the value (will not lose precision).
index 469a720424d3e52efd745bbb0269ee3e75ecd377..7272f4a76b04a6e8f0d5d72f9e7325d7e5275a0e 100644 (file)
@@ -74,16 +74,16 @@ public class ComplexColumnSupport
     IndexCursor cursor = CursorBuilder.createCursor(
         complexColumns.getPrimaryKeyIndex());
     if(!cursor.findFirstRowByEntry(complexTypeId)) {
-      throw new IOException(
+      throw new IOException(column.withErrorContext(
           "Could not find complex column info for complex column with id " +
-          complexTypeId);
+          complexTypeId));
     }
     Row cColRow = cursor.getCurrentRow();
     int tableId = cColRow.getInt(COL_TABLE_ID);
     if(tableId != column.getTable().getTableDefPageNumber()) {
-      throw new IOException(
+      throw new IOException(column.withErrorContext(
           "Found complex column for table " + tableId + " but expected table " +
-          column.getTable().getTableDefPageNumber());
+          column.getTable().getTableDefPageNumber()));
     }
     int flatTableId = cColRow.getInt(COL_FLAT_TABLE_ID);
     int typeObjId = cColRow.getInt(COL_COMPLEX_TYPE_OBJECT_ID);
@@ -92,9 +92,9 @@ public class ComplexColumnSupport
     TableImpl flatTable = db.getTable(flatTableId);
 
     if((typeObjTable == null) || (flatTable == null)) {
-      throw new IOException(
+      throw new IOException(column.withErrorContext(
           "Could not find supporting tables (" + typeObjId + ", " + flatTableId
-          + ") for complex column with id " + complexTypeId);
+          + ") for complex column with id " + complexTypeId));
     }
     
     // we inspect the structore of the "type table" to determine what kind of
@@ -110,9 +110,10 @@ public class ComplexColumnSupport
                                           flatTable);
     }
     
-    LOG.warn("Unsupported complex column type " + typeObjTable.getName());
+    LOG.warn(column.withErrorContext(
+                 "Unsupported complex column type " + typeObjTable.getName()));
     return new UnsupportedColumnInfoImpl(column, complexTypeId, typeObjTable,
-                                     flatTable);
+                                         flatTable);
   }
 
 
index bb3bfacd5e85d777e457abd557aef3b453a53dd6..2823f629dba3f0d445bbe6bdd775e6fe20d23d46 100644 (file)
@@ -257,6 +257,8 @@ public class DatabaseImpl implements Database
   
   /** the File of the database */
   private final File _file;
+  /** the simple name of the database */
+  private final String _name;
   /** Buffer to hold database pages */
   private ByteBuffer _buffer;
   /** ID of the Tables system object */
@@ -388,12 +390,12 @@ public class DatabaseImpl implements Database
 
         if(jetFormat.READ_ONLY) {
           throw new IOException("jet format '" + jetFormat +
-                                "' does not support writing");
+                                "' does not support writing for " + mdbFile);
         }
       }
 
       DatabaseImpl db = new DatabaseImpl(mdbFile, channel, closeChannel, autoSync, 
-                                 null, charset, timeZone, provider);
+                                         null, charset, timeZone, provider);
       success = true;
       return db;
 
@@ -433,7 +435,7 @@ public class DatabaseImpl implements Database
     FileFormatDetails details = getFileFormatDetails(fileFormat);
     if (details.getFormat().READ_ONLY) {
       throw new IOException("file format " + fileFormat +       
-                            " does not support writing");
+                            " does not support writing for " + mdbFile);
     }
 
     boolean closeChannel = false;
@@ -504,6 +506,7 @@ public class DatabaseImpl implements Database
     throws IOException
   {
     _file = file;
+    _name = getName(file);
     _format = JetFormat.getFormat(channel);
     _charset = ((charset == null) ? getDefaultCharset(_format) : charset);
     _columnOrder = getDefaultColumnOrder();
@@ -526,6 +529,10 @@ public class DatabaseImpl implements Database
     return _file;
   }
 
+  public String getName() {
+    return _name;
+  }
+
   /**
    * @usage _advanced_method_
    */
@@ -554,12 +561,7 @@ public class DatabaseImpl implements Database
    */
   public TableImpl getAccessControlEntries() throws IOException {
     if(_accessControlEntries == null) {
-      _accessControlEntries = getSystemTable(TABLE_SYSTEM_ACES);
-      if(_accessControlEntries == null) {
-        throw new IOException("Could not find system table " +
-                              TABLE_SYSTEM_ACES);
-      }
-
+      _accessControlEntries = getRequiredSystemTable(TABLE_SYSTEM_ACES);
     }
     return _accessControlEntries;
   }
@@ -570,11 +572,7 @@ public class DatabaseImpl implements Database
    */
   public TableImpl getSystemComplexColumns() throws IOException {
     if(_complexCols == null) {
-      _complexCols = getSystemTable(TABLE_SYSTEM_COMPLEX_COLS);
-      if(_complexCols == null) {
-        throw new IOException("Could not find system table " +
-                              TABLE_SYSTEM_COMPLEX_COLS);
-      }
+      _complexCols = getRequiredSystemTable(TABLE_SYSTEM_COMPLEX_COLS);
     }
     return _complexCols;
   }
@@ -735,7 +733,8 @@ public class DatabaseImpl implements Database
         _fileFormat = possibleFileFormats.get(accessVersion);
         
         if(_fileFormat == null) {
-          throw new IllegalStateException("Could not determine FileFormat");
+          throw new IllegalStateException(withErrorContext(
+                  "Could not determine FileFormat"));
         }
       }
     }
@@ -839,8 +838,11 @@ public class DatabaseImpl implements Database
             .setColumnMatcher(CaseInsensitiveColumnMatcher.INSTANCE)
             .toIndexCursor());
     } catch(IllegalArgumentException e) {
-      LOG.info("Could not find expected index on table " + 
-               _systemCatalog.getName());
+      if(LOG.isDebugEnabled()) {
+        LOG.debug(withErrorContext(
+                "Could not find expected index on table " +
+                _systemCatalog.getName()));
+      }
       // use table scan instead
       _tableFinder = new FallbackTableFinder(
           _systemCatalog.newCursor()
@@ -852,11 +854,13 @@ public class DatabaseImpl implements Database
                                                SYSTEM_OBJECT_NAME_TABLES);
 
     if(_tableParentId == null) {  
-      throw new IOException("Did not find required parent table id");
+      throw new IOException(withErrorContext(
+              "Did not find required parent table id"));
     }
 
     if (LOG.isDebugEnabled()) {
-      LOG.debug("Finished reading system catalog.  Tables: " + getTableNames());
+      LOG.debug(withErrorContext(
+          "Finished reading system catalog.  Tables: " + getTableNames()));
     }
   }
   
@@ -996,8 +1000,8 @@ public class DatabaseImpl implements Database
     throws IOException
   {
     if(lookupTable(name) != null) {
-      throw new IllegalArgumentException(
-          "Cannot create table with name of existing table");
+      throw new IllegalArgumentException(withErrorContext(
+              "Cannot create table with name of existing table '" + name + "'"));
     }
 
     new TableCreator(this, name, columns, indexes).createTable();
@@ -1008,8 +1012,9 @@ public class DatabaseImpl implements Database
     throws IOException
   {
     if(lookupTable(name) != null) {
-      throw new IllegalArgumentException(
-          "Cannot create linked table with name of existing table");
+      throw new IllegalArgumentException(withErrorContext(
+          "Cannot create linked table with name of existing table '" + name +   
+          "'"));
     }
 
     validateIdentifierName(name, getFormat().MAX_TABLE_NAME_LENGTH, "table");
@@ -1060,7 +1065,8 @@ public class DatabaseImpl implements Database
   {
     int nameCmp = table1.getName().compareTo(table2.getName());
     if(nameCmp == 0) {
-      throw new IllegalArgumentException("Must provide two different tables");
+      throw new IllegalArgumentException(withErrorContext(
+              "Must provide two different tables"));
     }
     if(nameCmp > 0) {
       // we "order" the two tables given so that we will return a collection
@@ -1078,7 +1084,7 @@ public class DatabaseImpl implements Database
     throws IOException
   {
     if(table == null) {
-      throw new IllegalArgumentException("Must provide a table");
+      throw new IllegalArgumentException(withErrorContext("Must provide a table"));
     }
     // since we are getting relationships specific to certain table include
     // all tables
@@ -1103,10 +1109,7 @@ public class DatabaseImpl implements Database
   {
     // the relationships table does not get loaded until first accessed
     if(_relationships == null) {
-      _relationships = getSystemTable(TABLE_SYSTEM_RELATIONSHIPS);
-      if(_relationships == null) {
-        throw new IOException("Could not find system relationships table");
-      }
+      _relationships = getRequiredSystemTable(TABLE_SYSTEM_RELATIONSHIPS);
     }
 
     List<Relationship> relationships = new ArrayList<Relationship>();
@@ -1132,10 +1135,7 @@ public class DatabaseImpl implements Database
   {
     // the queries table does not get loaded until first accessed
     if(_queries == null) {
-      _queries = getSystemTable(TABLE_SYSTEM_QUERIES);
-      if(_queries == null) {
-        throw new IOException("Could not find system queries table");
-      }
+      _queries = getRequiredSystemTable(TABLE_SYSTEM_QUERIES);
     }
 
     // find all the queries from the system catalog
@@ -1159,8 +1159,9 @@ public class DatabaseImpl implements Database
       QueryImpl.Row queryRow = new QueryImpl.Row(row);
       List<QueryImpl.Row> queryRows = queryRowMap.get(queryRow.objectId);
       if(queryRows == null) {
-        LOG.warn("Found rows for query with id " + queryRow.objectId +
-                 " missing from system catalog");
+        LOG.warn(withErrorContext(
+                     "Found rows for query with id " + queryRow.objectId +
+                     " missing from system catalog"));
         continue;
       }
       queryRows.add(queryRow);
@@ -1184,6 +1185,16 @@ public class DatabaseImpl implements Database
     return getTable(tableName, true);
   }
 
+  private TableImpl getRequiredSystemTable(String tableName) throws IOException
+  {
+    TableImpl table = getSystemTable(tableName);
+    if(table == null) { 
+      throw new IOException(withErrorContext(
+              "Could not find system table " + tableName));
+    } 
+    return table;
+  }
+
   public PropertyMap getDatabaseProperties() throws IOException {
     if(_dbPropMaps == null) {
       _dbPropMaps = getPropertiesForDbObject(OBJECT_NAME_DB_PROPS);
@@ -1234,7 +1245,8 @@ public class DatabaseImpl implements Database
       _dbParentId = _tableFinder.findObjectId(DB_PARENT_ID, 
                                               SYSTEM_OBJECT_NAME_DATABASES);
       if(_dbParentId == null) {  
-        throw new IOException("Did not find required parent db id");
+        throw new IOException(withErrorContext(
+                "Did not find required parent db id"));
       }
     }
 
@@ -1483,9 +1495,9 @@ public class DatabaseImpl implements Database
       _pageChannel.readPage(buffer, pageNumber);
       byte pageType = buffer.get(0);
       if (pageType != PageTypes.TABLE_DEF) {
-        throw new IOException(
+        throw new IOException(withErrorContext(
             "Looking for " + name + " at page " + pageNumber +
-            ", but page type is " + pageType);
+            ", but page type is " + pageType));
       }
       return _tableCache.put(
           new TableImpl(this, buffer, pageNumber, name, flags));
@@ -1498,7 +1510,7 @@ public class DatabaseImpl implements Database
    * Creates a Cursor restricted to the given column value if possible (using
    * an existing index), otherwise a simple table cursor.
    */
-  private static Cursor createCursorWithOptionalIndex(
+  private Cursor createCursorWithOptionalIndex(
       TableImpl table, String colName, Object colValue)
     throws IOException
   {
@@ -1508,7 +1520,10 @@ public class DatabaseImpl implements Database
         .setSpecificEntry(colValue)
         .toCursor();
     } catch(IllegalArgumentException e) {
-      LOG.info("Could not find expected index on table " + table.getName());
+      if(LOG.isDebugEnabled()) {
+        LOG.debug(withErrorContext(
+            "Could not find expected index on table " + table.getName()));
+      } 
     }
     // use table scan instead
     return CursorImpl.createCursor(table);
@@ -1556,13 +1571,14 @@ public class DatabaseImpl implements Database
     // additional identifier validation
     if(INVALID_IDENTIFIER_CHARS.matcher(name).find()) {
       throw new IllegalArgumentException(
-          identifierType + " name contains invalid characters");
+          identifierType + " name '" + name + "' contains invalid characters");
     }
 
     // cannot start with spaces
     if(name.charAt(0) == ' ') {
       throw new IllegalArgumentException(
-          identifierType + " name cannot start with a space character");
+          identifierType + " name '" + name +
+          "' cannot start with a space character");
     }
   }
 
@@ -1818,6 +1834,21 @@ public class DatabaseImpl implements Database
     FILE_FORMAT_DETAILS.put(fileFormat, new FileFormatDetails(emptyFile, format));
   }
 
+  private static String getName(File file) {
+    if(file == null) {
+      return "<UNKNOWN.DB>";
+    } 
+    return file.getName();
+  }
+
+  private String withErrorContext(String msg) {
+    return withErrorContext(msg, getName());
+  }
+
+  private static String withErrorContext(String msg, String dbName) {
+    return msg + " (Db=" + dbName + ")";
+  }
+
   /**
    * Utility class for storing table page number and actual name.
    */
@@ -1989,7 +2020,8 @@ public class DatabaseImpl implements Database
       int maxSynthId = findMaxSyntheticId();
       if(maxSynthId >= -1) {
         // bummer, no more ids available
-        throw new IllegalStateException("Too many database objects!");
+        throw new IllegalStateException(withErrorContext(
+                "Too many database objects!"));
       }
       return maxSynthId + 1;
     }
index 579deef5a6e0fd5296e26006402a498c7bed21fc..a6970a9009de34b7d206c698f47f20c3bd6b702f 100644 (file)
@@ -144,6 +144,8 @@ public class IndexData {
     };
         
   
+  /** name, generated on demand */
+  private String _name;
   /** owning table */
   private final TableImpl _table;
   /** 0-based index data number */
@@ -212,6 +214,23 @@ public class IndexData {
     return new IndexData(table, number, uniqueEntryCount, uniqueEntryCountOffset);
   }
 
+  public String getName() {
+    if(_name == null) {
+      if(_indexes.size() == 1) {
+        _name = _indexes.get(0).getName();
+      } else if(!_indexes.isEmpty()) {
+        List<String> names = new ArrayList<String>(_indexes.size());
+        for(Index idx : _indexes) {
+          names.add(idx.getName());
+        }
+        _name = names.toString();
+      } else {
+        _name = String.valueOf(_number);
+      }
+    } 
+    return _name;
+  }
+
   public TableImpl getTable() {
     return _table;
   }
@@ -260,6 +279,9 @@ public class IndexData {
       // also, keep track of whether or not this is a primary key index
       _primaryKey |= index.isPrimaryKey();
     }
+
+    // force name to be regenerated
+    _name = null;
   }
 
   public byte getIndexFlags() {
@@ -323,9 +345,15 @@ public class IndexData {
     return _rootPageNumber;
   }
 
-  private void setUnsupportedReason(String reason) {
-    _unsupportedReason = reason;
-    LOG.warn(reason + ", making read-only");
+  private void setUnsupportedReason(String reason, ColumnImpl col) {    
+    _unsupportedReason = withErrorContext(reason);
+    if(!col.getTable().isSystem()) {
+      LOG.warn(_unsupportedReason + ", making read-only");
+    } else {
+      if(LOG.isDebugEnabled()) {
+        LOG.debug(_unsupportedReason + ", making read-only");
+      }
+    }
   }
 
   String getUnsupportedReason() {
@@ -429,8 +457,9 @@ public class IndexData {
           }
         }
         if(idxCol == null) {
-          throw new IOException("Could not find column with number "
-                                + columnNumber + " for index");
+          throw new IOException(withErrorContext(
+                  "Could not find column with number "
+                  + columnNumber + " for index"));
         }
         _columns.add(newColumnDescriptor(idxCol, colFlags));
       }
@@ -447,8 +476,8 @@ public class IndexData {
 
   /**
    * Writes the index row count definitions into a table definition buffer.
+   * @param creator description of the indexes to write
    * @param buffer Buffer to write to
-   * @param indexes List of IndexBuilders to write definitions for
    */
   protected static void writeRowCountDefinitions(
       TableCreator creator, ByteBuffer buffer)
@@ -460,8 +489,8 @@ public class IndexData {
 
   /**
    * Writes the index definitions into a table definition buffer.
+   * @param creator description of the indexes to write
    * @param buffer Buffer to write to
-   * @param indexes List of IndexBuilders to write definitions for
    */
   protected static void writeDefinitions(
       TableCreator creator, ByteBuffer buffer)
@@ -497,7 +526,9 @@ public class IndexData {
           if(columnNumber == COLUMN_UNUSED) {
             // should never happen as this is validated before
             throw new IllegalArgumentException(
-                "Column with name " + idxCol.getName() + " not found");
+                withErrorContext(
+                    "Column with name " + idxCol.getName() + " not found",
+                    creator.getDatabase(), creator.getName(), idx.getName()));
           }
         }
          
@@ -550,9 +581,9 @@ public class IndexData {
       return change;
     }
     if(isBackingPrimaryKey() && (nullCount > 0)) {
-      throw new ConstraintViolationException(
+      throw new ConstraintViolationException(withErrorContext(
           "Null value found in row " + Arrays.asList(row) +
-          " for primary key index " + this);
+          " for primary key index"));
     }
     
     // make sure we've parsed the entries
@@ -589,9 +620,9 @@ public class IndexData {
           ((prevPos != null) &&
            newEntry.equalsEntryBytes(prevPos.getEntry())));
       if(isUnique() && !isNullEntry && isDupeEntry) {
-        throw new ConstraintViolationException(
+        throw new ConstraintViolationException(withErrorContext(
             "New row " + Arrays.asList(row) +
-            " violates uniqueness constraint for index " + this);
+            " violates uniqueness constraint for index"));
       }
 
       change.setAddRow(newEntry, dataPage, idx, isDupeEntry);
@@ -617,7 +648,7 @@ public class IndexData {
       }
       ++_modCount;
     } else {
-      LOG.warn("Added duplicate index entry " + oldEntry);
+      LOG.warn(withErrorContext("Added duplicate index entry " + oldEntry));
     }
   }
 
@@ -682,8 +713,9 @@ public class IndexData {
     if(removedEntry != null) {
       ++_modCount;
     } else {
-      LOG.warn("Failed removing index entry " + oldEntry + " for row: " +
-               Arrays.asList(row));
+      LOG.warn(withErrorContext(
+          "Failed removing index entry " + oldEntry + " for row: " + 
+          Arrays.asList(row)));
     }
     return removedEntry;
   }
@@ -906,9 +938,9 @@ public class IndexData {
   public Object[] constructIndexRowFromEntry(Object... values)
   {
     if(values.length != _columns.size()) {
-      throw new IllegalArgumentException(
+      throw new IllegalArgumentException(withErrorContext(
           "Wrong number of column values given " + values.length +
-          ", expected " + _columns.size());
+          ", expected " + _columns.size()));
     }
     int valIdx = 0;
     Object[] idxRow = new Object[getTable().getColumnCount()];
@@ -978,7 +1010,7 @@ public class IndexData {
     throws IOException
   {
     if(dataPage.getCompressedEntrySize() > _maxPageEntrySize) {
-      throw new IllegalStateException("data page is too large");
+      throw new IllegalStateException(withErrorContext("data page is too large"));
     }
     
     ByteBuffer buffer = _indexBufferH.getPageBuffer(getPageChannel());
@@ -1082,8 +1114,9 @@ public class IndexData {
 
           Entry entry = newEntry(curEntryBuffer, curEntryLen, isLeaf);
           if(prevEntry.compareTo(entry) >= 0) {
-            throw new IOException("Unexpected order in index entries, " +
-                                  prevEntry + " >= " + entry);
+            throw new IOException(withErrorContext(
+                    "Unexpected order in index entries, " +
+                    prevEntry + " >= " + entry));
           }
           
           entries.add(entry);
@@ -1151,7 +1184,7 @@ public class IndexData {
   /**
    * Determines if the given index page is a leaf or node page.
    */
-  private static boolean isLeafPage(ByteBuffer buffer)
+  private boolean isLeafPage(ByteBuffer buffer)
     throws IOException
   {
     byte pageType = buffer.get(0);
@@ -1160,7 +1193,7 @@ public class IndexData {
     } else if(pageType == PageTypes.INDEX_NODE) {
       return false;
     }
-    throw new IOException("Unexpected page type " + pageType);
+    throw new IOException(withErrorContext("Unexpected page type " + pageType));
   }
   
   /**
@@ -1305,7 +1338,7 @@ public class IndexData {
       }
       // unsupported sort order
       setUnsupportedReason("unsupported collating sort order " + sortOrder +
-                           " for text index");
+                           " for text index", col);
       return new ReadOnlyColumnDescriptor(col, flags);
     case INT:
     case LONG:
@@ -1330,7 +1363,7 @@ public class IndexData {
     default:
       // we can't modify this index at this point in time
       setUnsupportedReason("unsupported data type " + col.getType() + 
-                           " for index");
+                           " for index", col);
       return new ReadOnlyColumnDescriptor(col, flags);
     }
   }
@@ -1338,8 +1371,7 @@ public class IndexData {
   /**
    * Returns the EntryType based on the given entry info.
    */
-  private static EntryType determineEntryType(byte[] entryBytes, 
-                                              RowIdImpl rowId)
+  private static EntryType determineEntryType(byte[] entryBytes, RowIdImpl rowId)
   {
     if(entryBytes != null) {
       return ((rowId.getType() == RowIdImpl.Type.NORMAL) ?
@@ -1368,6 +1400,17 @@ public class IndexData {
     int entryMaskSize = (format.SIZE_INDEX_ENTRY_MASK * 8);
     return Math.min(pageDataSize, entryMaskSize);
   }
+
+  String withErrorContext(String msg) {
+    return withErrorContext(msg, getTable().getDatabase(), getTable().getName(),
+                            getName());
+  }
+
+  private static String withErrorContext(String msg, DatabaseImpl db,
+                                         String tableName, String idxName) {
+    return msg + " (Db=" + db.getName() + ";Table=" + tableName +
+      ";Index=" + idxName + ")";
+  }
   
   /**
    * Information about the columns in an index.  Also encodes new index
@@ -2227,7 +2270,8 @@ public class IndexData {
         } else if(_lastPos.equalsEntry(entry)) {
           return _lastPos;
         } else {
-          throw new IllegalArgumentException("Invalid entry given " + entry);
+          throw new IllegalArgumentException(
+              withErrorContext("Invalid entry given " + entry));
         }
       }
       
index 0f3bb7263ab24d1304948cc91027b627f89605f0..e6024414995d1a3ba178ee1ba27e5fa4c48ec368 100644 (file)
@@ -176,8 +176,8 @@ public class IndexImpl implements Index, Comparable<IndexImpl>
         _reference.getOtherTablePageNumber());
 
     if(refTable == null) {
-      throw new IOException("Reference to missing table " + 
-                            _reference.getOtherTablePageNumber());
+      throw new IOException(withErrorContext(
+              "Reference to missing table " + _reference.getOtherTablePageNumber()));
     }
 
     IndexImpl refIndex = null;
@@ -190,8 +190,9 @@ public class IndexImpl implements Index, Comparable<IndexImpl>
     }
     
     if(refIndex == null) {
-      throw new IOException("Reference to missing index " + idxNumber + 
-                            " on table " + refTable.getName());
+      throw new IOException(withErrorContext(
+              "Reference to missing index " + idxNumber + 
+              " on table " + refTable.getName()));
     }
 
     // finally verify that we found the expected index (should reference this
@@ -201,9 +202,9 @@ public class IndexImpl implements Index, Comparable<IndexImpl>
        (otherRef.getOtherTablePageNumber() != 
         getTable().getTableDefPageNumber()) ||
        (otherRef.getOtherIndexNumber() != _indexNumber)) {
-      throw new IOException("Found unexpected index " + refIndex.getName() +
-                            " on table " + refTable.getName() +
-                            " with reference " + otherRef);
+      throw new IOException(withErrorContext(
+              "Found unexpected index " + refIndex.getName() +
+              " on table " + refTable.getName() + " with reference " + otherRef));
     }
 
     return refIndex;
@@ -335,8 +336,8 @@ public class IndexImpl implements Index, Comparable<IndexImpl>
 
   /**
    * Writes the logical index definitions into a table definition buffer.
+   * @param creator description of the indexes to write
    * @param buffer Buffer to write to
-   * @param indexes List of IndexBuilders to write definitions for
    */
   protected static void writeDefinitions(
       TableCreator creator, ByteBuffer buffer)
@@ -363,6 +364,16 @@ public class IndexImpl implements Index, Comparable<IndexImpl>
     }
   }
 
+  private String withErrorContext(String msg) {
+    return withErrorContext(msg, getTable().getDatabase(), getName());
+  }
+
+  private static String withErrorContext(String msg, DatabaseImpl db,
+                                         String idxName) {
+    return msg + " (Db=" + db.getName() + ";Index=" + idxName + ")";
+  }
+  
+
   /**
    * Information about a foreign key reference defined in an index (when
    * referential integrity should be enforced).
index c741a8d4e3d3c712dc507b4e125a03a908cd8693..cf58e6a16dadc90d4297f2bd42ad74e164eefa9b 100644 (file)
@@ -204,8 +204,8 @@ public class IndexPageCache
   {
     for(CacheDataPage cacheDataPage : _modifiedPages) {
       if(cacheDataPage._extra._entryView.isEmpty()) {
-        throw new IllegalStateException("Unexpected empty page " +
-                                        cacheDataPage);
+        throw new IllegalStateException(withErrorContext(
+                "Unexpected empty page " + cacheDataPage));
       }
       writeDataPage(cacheDataPage);
     }
@@ -358,7 +358,8 @@ public class IndexPageCache
       break;
     }
     default:
-      throw new RuntimeException("unknown update type " + upType);
+      throw new RuntimeException(withErrorContext(
+              "unknown update type " + upType));
     }
 
     boolean updateLast = (oldLastEntry != dpExtra._entryView.getLast());
@@ -406,13 +407,13 @@ public class IndexPageCache
     DataPageExtra dpExtra = cacheDataPage._extra;
 
     if(dpMain.hasChildTail()) {
-      throw new IllegalStateException("Still has child tail?");
+      throw new IllegalStateException(withErrorContext("Still has child tail?"));
     }
 
     if(dpExtra._totalEntrySize != 0) {
-      throw new IllegalStateException("Empty page but size is not 0? " +
-                                      dpExtra._totalEntrySize + ", " +
-                                      cacheDataPage);
+      throw new IllegalStateException(withErrorContext(
+              "Empty page but size is not 0? " + dpExtra._totalEntrySize + ", " +
+              cacheDataPage));
     }
     
     if(dpMain.isRoot()) {
@@ -536,21 +537,22 @@ public class IndexPageCache
       break;
     
     default:
-      throw new RuntimeException("unknown update type " + upType);
+      throw new RuntimeException(withErrorContext(
+              "unknown update type " + upType));
     }
         
     if(idx < 0) {
       if(expectFound) {
-        throw new IllegalStateException(
+        throw new IllegalStateException(withErrorContext(
             "Could not find child entry in parent; childEntry " + oldEntry +
-            "; parent " + parentDataPage);
+            "; parent " + parentDataPage));
       }
       idx = missingIndexToInsertionPoint(idx);
     } else {
       if(!expectFound) {
-        throw new IllegalStateException(
+        throw new IllegalStateException(withErrorContext(
             "Unexpectedly found child entry in parent; childEntry " +
-            newEntry + "; parent " + parentDataPage);
+            newEntry + "; parent " + parentDataPage));
       }
     }
     updateEntry(parentDataPage, idx, newEntry, upType);
@@ -596,11 +598,11 @@ public class IndexPageCache
    * @throws IllegalStateException if the entry type does not match the page
    *         type
    */
-  private static void validateEntryForPage(DataPageMain dpMain, Entry entry) {
+  private void validateEntryForPage(DataPageMain dpMain, Entry entry) {
     if(dpMain._leaf != entry.isLeafEntry()) {
-      throw new IllegalStateException(
+      throw new IllegalStateException(withErrorContext(
           "Trying to update page with wrong entry type; pageLeaf " +
-          dpMain._leaf + ", entryLeaf " + entry.isLeafEntry());
+          dpMain._leaf + ", entryLeaf " + entry.isLeafEntry()));
     }
   }
 
@@ -619,8 +621,8 @@ public class IndexPageCache
     
     int numEntries = origExtra._entries.size();
     if(numEntries < 2) {
-      throw new IllegalStateException(
-          "Cannot split page with less than 2 entries " + origDataPage);
+      throw new IllegalStateException(withErrorContext(
+              "Cannot split page with less than 2 entries " + origDataPage));
     }
     
     if(origMain.isRoot()) {
@@ -702,7 +704,8 @@ public class IndexPageCache
     DataPageExtra rootExtra = rootDataPage._extra;
 
     if(!rootMain.isRoot()) {
-      throw new IllegalArgumentException("should be called with root, duh");
+      throw new IllegalArgumentException(withErrorContext(
+              "should be called with root, duh"));
     }
     
     CacheDataPage newDataPage =
@@ -1000,20 +1003,21 @@ public class IndexPageCache
    *
    * @param dpExtra the entries to validate
    */
-  private static void validateEntries(DataPageExtra dpExtra) throws IOException {
+  private void validateEntries(DataPageExtra dpExtra) throws IOException {
     int entrySize = 0;
     Entry prevEntry = IndexData.FIRST_ENTRY;
     for(Entry e : dpExtra._entries) {
       entrySize += e.size();
       if(prevEntry.compareTo(e) >= 0) {
-        throw new IOException("Unexpected order in index entries, " +
-                              prevEntry + " >= " + e);
+        throw new IOException(withErrorContext(
+                "Unexpected order in index entries, " + prevEntry + " >= " + e));
       }
       prevEntry = e;
     }
     if(entrySize != dpExtra._totalEntrySize) {
-      throw new IllegalStateException("Expected size " + entrySize +
-                                      " but was " + dpExtra._totalEntrySize);
+      throw new IllegalStateException(withErrorContext(
+              "Expected size " + entrySize +
+              " but was " + dpExtra._totalEntrySize));
     }
   }
 
@@ -1028,12 +1032,14 @@ public class IndexPageCache
     int childTailPageNumber = dpMain._childTailPageNumber;
     if(dpMain._leaf) {
       if(childTailPageNumber != INVALID_INDEX_PAGE_NUMBER) {
-        throw new IllegalStateException("Leaf page has tail " + dpMain);
+        throw new IllegalStateException(withErrorContext(
+                "Leaf page has tail " + dpMain));
       }
       return;
     }
     if((dpExtra._entryView.size() == 1) && dpMain.hasChildTail()) {
-      throw new IllegalStateException("Single child is tail " + dpMain);
+      throw new IllegalStateException(withErrorContext(
+              "Single child is tail " + dpMain));
     }
     for(Entry e : dpExtra._entryView) {
       validateEntryForPage(dpMain, e);
@@ -1042,19 +1048,19 @@ public class IndexPageCache
       if(childMain != null) {
         if(childMain._parentPageNumber != null) {
           if(childMain._parentPageNumber != dpMain._pageNumber) {
-            throw new IllegalStateException("Child's parent is incorrect " +
-                                            childMain);
+            throw new IllegalStateException(withErrorContext(
+                    "Child's parent is incorrect " + childMain));
           }
-          boolean expectTail = ((int)subPageNumber == childTailPageNumber);
+          boolean expectTail = (subPageNumber == childTailPageNumber);
           if(expectTail != childMain._tail) {
-            throw new IllegalStateException("Child tail status incorrect " +
-                                            childMain);
+            throw new IllegalStateException(withErrorContext(
+                    "Child tail status incorrect " + childMain));
           }
         }
         Entry lastEntry = childMain.getExtra()._entryView.getLast();
         if(e.compareTo(lastEntry) != 0) {
-          throw new IllegalStateException("Invalid entry " + e +
-                                          " but child is " + lastEntry);
+          throw new IllegalStateException(withErrorContext(
+                  "Invalid entry " + e + " but child is " + lastEntry));
         }
       }
     }
@@ -1068,18 +1074,18 @@ public class IndexPageCache
   private void validatePeers(DataPageMain dpMain) throws IOException {
     DataPageMain prevMain = _dataPages.get(dpMain._prevPageNumber);
     if(prevMain != null) {
-      if((int)prevMain._nextPageNumber != dpMain._pageNumber) {
-        throw new IllegalStateException("Prev page " + prevMain +
-                                        " does not ref " + dpMain);
+      if(prevMain._nextPageNumber != dpMain._pageNumber) {
+        throw new IllegalStateException(withErrorContext(
+                "Prev page " + prevMain + " does not ref " + dpMain));
       }
       validatePeerStatus(dpMain, prevMain);
     }
     
     DataPageMain nextMain = _dataPages.get(dpMain._nextPageNumber);
     if(nextMain != null) {
-      if((int)nextMain._prevPageNumber != dpMain._pageNumber) {
-        throw new IllegalStateException("Next page " + nextMain +
-                                        " does not ref " + dpMain);
+      if(nextMain._prevPageNumber != dpMain._pageNumber) {
+        throw new IllegalStateException(withErrorContext(
+                "Next page " + nextMain + " does not ref " + dpMain));
       }
       validatePeerStatus(dpMain, nextMain);
     }
@@ -1091,20 +1097,20 @@ public class IndexPageCache
    * @param dpMain the index page
    * @param peerMain the peer index page
    */
-  private static void validatePeerStatus(DataPageMain dpMain, DataPageMain peerMain)
+  private void validatePeerStatus(DataPageMain dpMain, DataPageMain peerMain)
     throws IOException
   {
     if(dpMain._leaf != peerMain._leaf) {
-      throw new IllegalStateException("Mismatched peer status " +
-                                      dpMain._leaf + " " + peerMain._leaf);
+      throw new IllegalStateException(withErrorContext(
+              "Mismatched peer status " + dpMain._leaf + " " + peerMain._leaf));
     }
     if(!dpMain._leaf) {
       if((dpMain._parentPageNumber != null) &&
          (peerMain._parentPageNumber != null) &&
          ((int)dpMain._parentPageNumber != (int)peerMain._parentPageNumber)) {
-        throw new IllegalStateException("Mismatched node parents " +
-                                        dpMain._parentPageNumber + " " +
-                                        peerMain._parentPageNumber);
+        throw new IllegalStateException(withErrorContext(
+                "Mismatched node parents " + dpMain._parentPageNumber + " " +
+                peerMain._parentPageNumber));
       }
     }
   }
@@ -1112,7 +1118,7 @@ public class IndexPageCache
   /**
    * Collects all the cache pages in the cache.
    *
-   * @param paages the List to update
+   * @param pages the List to update
    * @param dpMain the index page to collect
    */
   private List<Object> collectPages(List<Object> pages, DataPageMain dpMain) {
@@ -1160,6 +1166,11 @@ public class IndexPageCache
     return sb.toString();
   }
 
+  private String withErrorContext(String msg) {
+    return _indexData.withErrorContext(msg);
+  }
+  
+
   /**
    * Keeps track of the main info for an index page.
    */
@@ -1193,11 +1204,11 @@ public class IndexPageCache
     }
 
     public boolean hasChildTail() {
-      return((int)_childTailPageNumber != INVALID_INDEX_PAGE_NUMBER);
+      return(_childTailPageNumber != INVALID_INDEX_PAGE_NUMBER);
     }
 
     public boolean isChildTailPageNumber(int pageNumber) {
-      return((int)_childTailPageNumber == pageNumber);
+      return(_childTailPageNumber == pageNumber);
     }
     
     public DataPageMain getParentPage() throws IOException
@@ -1278,7 +1289,8 @@ public class IndexPageCache
         // pages along the path
         findCacheDataPage(getExtra()._entryView.getLast());
         if(_parentPageNumber == null) {
-          throw new IllegalStateException("Parent was not resolved");
+          throw new IllegalStateException(withErrorContext(
+                  "Parent was not resolved"));
         }
       }
     }
index 89accffca791dd532f01dd966639adf2e7652d2b..2b54ee347470a5306cf377a02c8213057136f058 100644 (file)
@@ -98,8 +98,8 @@ class LongValueColumnImpl extends ColumnImpl
       }
       return null;
     default:
-      throw new RuntimeException("unexpected var length, long value type: " +
-                                 getType());
+      throw new RuntimeException(withErrorContext(
+              "unexpected var length, long value type: " + getType()));
     }    
   }
 
@@ -116,8 +116,8 @@ class LongValueColumnImpl extends ColumnImpl
       obj = encodeTextValue(obj, 0, getMaxLengthInUnits(), false).array();
       break;
     default:
-      throw new RuntimeException("unexpected var length, long value type: " +
-                                 getType());
+      throw new RuntimeException(withErrorContext(
+              "unexpected var length, long value type: " + getType()));
     }    
 
     // create long value buffer
@@ -147,8 +147,9 @@ class LongValueColumnImpl extends ColumnImpl
       int rowLen = def.remaining();
       if(rowLen < length) {
         // warn the caller, but return whatever we can
-        LOG.warn(getName() + " value may be truncated: expected length " + 
-                 length + " found " + rowLen);
+        LOG.warn(withErrorContext(
+                "Value may be truncated: expected length " + 
+                length + " found " + rowLen));
         rtn = new byte[rowLen];
       }
 
@@ -158,9 +159,10 @@ class LongValueColumnImpl extends ColumnImpl
 
       // long value on other page(s)
       if (lvalDefinition.length != getFormat().SIZE_LONG_VALUE_DEF) {
-        throw new IOException("Expected " + getFormat().SIZE_LONG_VALUE_DEF +
-                              " bytes in long value definition, but found " +
-                              lvalDefinition.length);
+        throw new IOException(withErrorContext(
+                "Expected " + getFormat().SIZE_LONG_VALUE_DEF +
+                " bytes in long value definition, but found " +
+                lvalDefinition.length));
       }
 
       int rowNum = ByteUtil.getUnsignedByte(def);
@@ -178,8 +180,9 @@ class LongValueColumnImpl extends ColumnImpl
           int rowLen = rowEnd - rowStart;
           if(rowLen < length) {
             // warn the caller, but return whatever we can
-            LOG.warn(getName() + " value may be truncated: expected length " + 
-                     length + " found " + rowLen);
+            LOG.warn(withErrorContext(
+                    "Value may be truncated: expected length " + 
+                    length + " found " + rowLen));
             rtn = new byte[rowLen];
           }
         
@@ -219,7 +222,8 @@ class LongValueColumnImpl extends ColumnImpl
         break;
         
       default:
-        throw new IOException("Unrecognized long value type: " + type);
+        throw new IOException(withErrorContext(
+                "Unrecognized long value type: " + type));
       }
     }
     
@@ -255,9 +259,9 @@ class LongValueColumnImpl extends ColumnImpl
     throws IOException
   {
     if(value.length > getType().getMaxSize()) {
-      throw new IOException("value too big for column, max " +
-                            getType().getMaxSize() + ", got " +
-                            value.length);
+      throw new IOException(withErrorContext(
+              "value too big for column, max " +
+              getType().getMaxSize() + ", got " + value.length));
     }
 
     // determine which type to write
@@ -357,7 +361,8 @@ class LongValueColumnImpl extends ColumnImpl
         break;
 
       default:
-        throw new IOException("Unrecognized long value type: " + type);
+        throw new IOException(withErrorContext(
+                "Unrecognized long value type: " + type));
       }
 
       // update def
index c7206548b887df5656207e83972f51342832ab08..8d2dddba8cdce6fb481b83d6af2b0bc7b2e1b9b3 100644 (file)
@@ -65,6 +65,14 @@ class TableCreator
                 Collections.<IndexBuilder>emptyList());
   }
 
+  public String getName() {
+    return _name;
+  }
+
+  public DatabaseImpl getDatabase() {
+    return _database;
+  }
+
   public JetFormat getFormat() {
     return _database.getFormat();
   }
index a23886402e9b60ebf67369a6df824e34cfafd378..d64e4fd90efc74d427814a265a90e4deb508c852 100644 (file)
@@ -279,8 +279,8 @@ public class TableImpl implements Table
         colOwnedPages = null;
         colFreeSpacePages = null;
         tableBuffer.position(pos + 8);
-        LOG.warn("Table " + _name + " invalid column " + umapColNum + 
-                 " usage map definition: " + e);
+        LOG.warn(withErrorContext("Invalid column " + umapColNum + 
+                                  " usage map definition: " + e));
       }
       
       for(ColumnImpl col : _columns) {
@@ -426,8 +426,8 @@ public class TableImpl implements Table
         return column;
       }
     }
-    throw new IllegalArgumentException("Column with name " + name +
-                                       " does not exist in this table");
+    throw new IllegalArgumentException(withErrorContext(
+            "Column with name " + name + " does not exist in this table"));
   }
   
   public boolean hasColumn(String name) {
@@ -468,8 +468,8 @@ public class TableImpl implements Table
         return index;
       }
     }
-    throw new IllegalArgumentException("Index with name " + name +
-                                       " does not exist on this table");
+    throw new IllegalArgumentException(withErrorContext(
+            "Index with name " + name + " does not exist on this table"));
   }
 
   public IndexImpl getPrimaryKeyIndex() {
@@ -478,8 +478,8 @@ public class TableImpl implements Table
         return index;
       }
     }
-    throw new IllegalArgumentException("Table " + getName() +
-                                       " does not have a primary key index");
+    throw new IllegalArgumentException(withErrorContext(
+            "No primary key index found"));
   }
   
   public IndexImpl getForeignKeyIndex(Table otherTable) {
@@ -490,9 +490,9 @@ public class TableImpl implements Table
         return index;
       }
     }
-    throw new IllegalArgumentException(
-        "Table " + getName() + " does not have a foreign key reference to " +
-        otherTable.getName());
+    throw new IllegalArgumentException(withErrorContext(
+        "No foreign key reference to " +
+        otherTable.getName() + " found"));
   }
   
   /**
@@ -622,8 +622,8 @@ public class TableImpl implements Table
     throws IOException
   {
     if(this != column.getTable()) {
-      throw new IllegalArgumentException(
-          "Given column " + column + " is not from this table");
+      throw new IllegalArgumentException(withErrorContext(
+          "Given column " + column + " is not from this table"));
     }
     requireValidRowId(rowId);
     
@@ -933,7 +933,8 @@ public class TableImpl implements Table
       if (overflowRow) {
 
         if((rowEnd - rowStart) < 4) {
-          throw new IOException("invalid overflow row info");
+          throw new IOException(rowState.getTable().withErrorContext(
+                                    "invalid overflow row info"));
         }
       
         // Overflow page.  the "row" data in the current page points to
@@ -1568,7 +1569,8 @@ public class TableImpl implements Table
       
           int rowSize = rowData.remaining();
           if (rowSize > getFormat().MAX_ROW_SIZE) {
-            throw new IOException("Row size " + rowSize + " is too large");
+            throw new IOException(withErrorContext(
+                                      "Row size " + rowSize + " is too large"));
           }
 
           // get page with space
@@ -1662,14 +1664,17 @@ public class TableImpl implements Table
             // corruption (failed write vs. a row failure which was not a
             // write failure).  we don't know the status of any rows at this
             // point (and the original failure is probably irrelevant)
-            LOG.warn("Secondary row failure which preceded the write failure", 
+            LOG.warn(withErrorContext(
+                    "Secondary row failure which preceded the write failure"), 
                      rowWriteFailure);
             updateCount = 0;
             rowWriteFailure = flushFailure;
           }
         }
 
-        throw new BatchUpdateException(updateCount, rowWriteFailure);
+        throw new BatchUpdateException(
+            updateCount, withErrorContext("Failed adding rows"),
+            rowWriteFailure);
       }
 
     } finally {
@@ -1809,8 +1814,8 @@ public class TableImpl implements Table
           keepRawVarValues);
 
       if (newRowData.limit() > getFormat().MAX_ROW_SIZE) {
-        throw new IOException("Row size " + newRowData.limit() + 
-                              " is too large");
+        throw new IOException(withErrorContext(
+                "Row size " + newRowData.limit() + " is too large"));
       }
 
       if(!_indexDatas.isEmpty()) {
@@ -2364,23 +2369,25 @@ public class TableImpl implements Table
   /**
    * @throws IllegalStateException if the given rowId is invalid
    */
-  private static void requireValidRowId(RowIdImpl rowId) {
+  private void requireValidRowId(RowIdImpl rowId) {
     if(!rowId.isValid()) {
-      throw new IllegalArgumentException("Given rowId is invalid: " + rowId);
+      throw new IllegalArgumentException(withErrorContext(
+              "Given rowId is invalid: " + rowId));
     }
   }
   
   /**
    * @throws IllegalStateException if the given row is invalid or deleted
    */
-  private static void requireNonDeletedRow(RowState rowState, RowIdImpl rowId)
+  private void requireNonDeletedRow(RowState rowState, RowIdImpl rowId)
   {
     if(!rowState.isValid()) {
-      throw new IllegalArgumentException(
-          "Given rowId is invalid for this table: " + rowId);
+      throw new IllegalArgumentException(withErrorContext(
+          "Given rowId is invalid for this table: " + rowId));
     }
     if(rowState.isDeleted()) {
-      throw new IllegalStateException("Row is deleted: " + rowId);
+      throw new IllegalStateException(withErrorContext(
+          "Row is deleted: " + rowId));
     }
   }
   
@@ -2485,6 +2492,15 @@ public class TableImpl implements Table
     return copy;
   }
 
+  private String withErrorContext(String msg) {
+    return withErrorContext(msg, getDatabase(), getName());
+  }
+
+  private static String withErrorContext(String msg, DatabaseImpl db,
+                                         String tableName) {
+    return msg + " (Db=" + db.getName() + ";Table=" + tableName + ")";
+  }
+
   /** various statuses for the row data */
   private enum RowStatus {
     INIT, INVALID_PAGE, INVALID_ROW, VALID, DELETED, NORMAL, OVERFLOW;
@@ -2722,10 +2738,12 @@ public class TableImpl implements Table
       // this should never see modifications because it only happens within
       // the positionAtRowData method
       if(!isUpToDate()) {
-        throw new IllegalStateException("Table modified while searching?");
+        throw new IllegalStateException(getTable().withErrorContext(
+                                            "Table modified while searching?"));
       }
       if(_rowStatus != RowStatus.OVERFLOW) {
-        throw new IllegalStateException("Row is not an overflow row?");
+        throw new IllegalStateException(getTable().withErrorContext(
+                                            "Row is not an overflow row?"));
       }
       _finalRowId = rowId;
       _finalRowBuffer = _overflowRowBufferH.setPage(getPageChannel(),
index a69503258326ac415d0b8a4acc9fba55cb605d36..6007a16d88d9a9e6f8d3e52a5b4f8139baae5c46 100644 (file)
@@ -78,7 +78,8 @@ public abstract class QueryImpl implements Query
       short foundType = getShortValue(getQueryType(rows),
                                       _type.getValue());
       if(foundType != _type.getValue()) {
-        throw new IllegalStateException("Unexpected query type " + foundType);
+        throw new IllegalStateException(withErrorContext(
+                "Unexpected query type " + foundType));
       }
     }
   }
@@ -189,7 +190,8 @@ public abstract class QueryImpl implements Query
         @Override protected void format(StringBuilder builder, Row row) {
           String typeName = PARAM_TYPE_MAP.get(row.flag);
           if(typeName == null) {
-            throw new IllegalStateException("Unknown param type " + row.flag);
+            throw new IllegalStateException(withErrorContext(
+                "Unknown param type " + row.flag));
           }
               
           builder.append(row.name1).append(' ').append(typeName);
@@ -255,7 +257,8 @@ public abstract class QueryImpl implements Query
         Join toExpr = getJoinExpr(toTable, joinExprs);
         String joinType = JOIN_TYPE_MAP.get(join.flag);
         if(joinType == null) {
-            throw new IllegalStateException("Unknown join type " + join.flag);
+          throw new IllegalStateException(withErrorContext(
+                "Unknown join type " + join.flag));
         }
 
         String expr = new StringBuilder().append(fromExpr)
@@ -275,7 +278,7 @@ public abstract class QueryImpl implements Query
     return result;
   }
 
-  private static Join getJoinExpr(String table, List<Join> joinExprs)
+  private Join getJoinExpr(String table, List<Join> joinExprs)
   {
     for(Iterator<Join> iter = joinExprs.iterator(); iter.hasNext(); ) {
       Join joinExpr = iter.next();
@@ -284,10 +287,11 @@ public abstract class QueryImpl implements Query
         return joinExpr;
       }
     }
-    throw new IllegalStateException("Cannot find join table " + table);
+    throw new IllegalStateException(withErrorContext(
+            "Cannot find join table " + table));
   }
 
-  private static Collection<List<Row>> combineJoins(List<Row> joins)
+  private Collection<List<Row>> combineJoins(List<Row> joins)
   {
     // combine joins with the same to/from tables
     Map<List<String>,List<Row>> comboJoinMap = 
@@ -299,9 +303,9 @@ public abstract class QueryImpl implements Query
         comboJoins = new ArrayList<Row>();
         comboJoinMap.put(key, comboJoins);
       } else {
-        if((short)comboJoins.get(0).flag != join.flag) {
-          throw new IllegalStateException(
-              "Mismatched join flags for combo joins");
+        if(comboJoins.get(0).flag != join.flag) {
+          throw new IllegalStateException(withErrorContext(
+              "Mismatched join flags for combo joins"));
         }
       }
       comboJoins.add(join);
@@ -417,18 +421,18 @@ public abstract class QueryImpl implements Query
         return new UnionQueryImpl(name, rows, objectId, objectFlag);
       default:
         // unknown querytype
-        throw new IllegalStateException(
-            "unknown query object flag " + typeFlag);
+        throw new IllegalStateException(withErrorContext(
+                "unknown query object flag " + typeFlag, name));
       }
     } catch(IllegalStateException e) {
-      LOG.warn("Failed parsing query", e);
+      LOG.warn(withErrorContext("Failed parsing query", name), e);
     }
 
     // return unknown query
     return new UnknownQueryImpl(name, rows, objectId, objectFlag);
   }
 
-  private static Short getQueryType(List<Row> rows)
+  private Short getQueryType(List<Row> rows)
   {
     return getUniqueRow(getRowsByAttribute(rows, TYPE_ATTRIBUTE)).flag;
   }
@@ -443,14 +447,15 @@ public abstract class QueryImpl implements Query
     return result;
   }
 
-  protected static Row getUniqueRow(List<Row> rows) {
+  protected Row getUniqueRow(List<Row> rows) {
     if(rows.size() == 1) {
       return rows.get(0);
     }
     if(rows.isEmpty()) {
       return EMPTY_ROW;
     }
-    throw new IllegalStateException("Unexpected number of rows for" + rows);
+    throw new IllegalStateException(withErrorContext(
+            "Unexpected number of rows for" + rows));
   }
 
   protected static List<Row> filterRowsByFlag(
@@ -545,6 +550,15 @@ public abstract class QueryImpl implements Query
     return builder;
   }
 
+  private String withErrorContext(String msg) {
+    return withErrorContext(msg, getName());
+  }
+
+  private static String withErrorContext(String msg, String queryName) {
+    return msg + " (Query: " + queryName + ")";
+  }
+
+
   private static final class UnknownQueryImpl extends QueryImpl
   {
     private UnknownQueryImpl(String name, List<Row> rows, int objectId, 
index 65f644164aae18e3aab014ceb929d1caceef7aa9..dfd0ef4955c72bd49c1e4e099607d2feb6f150a2 100644 (file)
@@ -31,6 +31,7 @@ import com.healthmarketscience.jackcess.Index;
 import com.healthmarketscience.jackcess.IndexCursor;
 import com.healthmarketscience.jackcess.Row;
 import com.healthmarketscience.jackcess.Table;
+import com.healthmarketscience.jackcess.impl.DatabaseImpl;
 import com.healthmarketscience.jackcess.impl.IndexImpl;
 
 /**
@@ -291,7 +292,10 @@ public class Joiner
     for(int i = 1; i < toCols.size(); ++i) {
       sb.append(",").append(toCols.get(i).getName());
     }
-    sb.append(toType);
+    sb.append(toType)
+      .append(" (Db=")
+      .append(((DatabaseImpl)getFromTable().getDatabase()).getName())
+      .append(")");
     
     return sb.toString();
   }