Coverage Report - com.healthmarketscience.jackcess.DataType
 
Classes in this File Line Coverage Branch Coverage Complexity
DataType
93%
93/100
69%
18/26
0
 
 1  
 /*
 2  
 Copyright (c) 2005 Health Market Science, Inc.
 3  
 
 4  
 This library is free software; you can redistribute it and/or
 5  
 modify it under the terms of the GNU Lesser General Public
 6  
 License as published by the Free Software Foundation; either
 7  
 version 2.1 of the License, or (at your option) any later version.
 8  
 
 9  
 This library is distributed in the hope that it will be useful,
 10  
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  
 Lesser General Public License for more details.
 13  
 
 14  
 You should have received a copy of the GNU Lesser General Public
 15  
 License along with this library; if not, write to the Free Software
 16  
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 17  
 USA
 18  
 
 19  
 You can contact Health Market Science at info@healthmarketscience.com
 20  
 or at the following address:
 21  
 
 22  
 Health Market Science
 23  
 2700 Horizon Drive
 24  
 Suite 200
 25  
 King of Prussia, PA 19406
 26  
 */
 27  
 
 28  
 package com.healthmarketscience.jackcess;
 29  
 
 30  
 import java.io.IOException;
 31  
 import java.sql.SQLException;
 32  
 import java.sql.Types;
 33  
 import java.util.HashMap;
 34  
 import java.util.Map;
 35  
 
 36  
 /**
 37  
  * Access data type
 38  
  * @author Tim McCune
 39  
  */
 40  5
 public enum DataType {
 41  
 
 42  
   /**
 43  
    * Corresponds to a java Boolean.  Accepts Boolean or {@code null} (which is
 44  
    * considered {@code false}).  Equivalent to SQL {@link Types#BOOLEAN}.
 45  
    */
 46  1
   BOOLEAN((byte) 0x01, Types.BOOLEAN, 0),
 47  
   /**
 48  
    * Corresponds to a java Byte.  Accepts any Number (using
 49  
    * {@link Number#byteValue}), Boolean as 1 or 0, any Object converted to a
 50  
    * String and parsed as Double, or {@code null}.  Equivalent to SQL
 51  
    * {@link Types#TINYINT}, {@link Types#BIT}.
 52  
    */
 53  1
   BYTE((byte) 0x02, Types.TINYINT, 1),
 54  
   /**
 55  
    * Corresponds to a java Short.  Accepts any Number (using
 56  
    * {@link Number#shortValue}), Boolean as 1 or 0, any Object converted to a
 57  
    * String and parsed as Double, or {@code null}.  Equivalent to SQL
 58  
    * {@link Types#SMALLINT}.
 59  
    */
 60  1
   INT((byte) 0x03, Types.SMALLINT, 2),
 61  
   /**
 62  
    * Corresponds to a java Integer.  Accepts any Number (using
 63  
    * {@link Number#intValue}), Boolean as 1 or 0, any Object converted to a
 64  
    * String and parsed as Double, or {@code null}.  Equivalent to SQL
 65  
    * {@link Types#INTEGER}, {@link Types#BIGINT}.
 66  
    */
 67  1
   LONG((byte) 0x04, Types.INTEGER, 4),
 68  
   /**
 69  
    * Corresponds to a java BigDecimal with at most 4 decimal places.  Accepts
 70  
    * any Number (using {@link Number#doubleValue}), a BigInteger, a BigDecimal
 71  
    * (with at most 4 decimal places), Boolean as 1 or 0, any Object converted
 72  
    * to a String and parsed as BigDecimal, or {@code null}.  Equivalent to SQL
 73  
    * {@link Types#DECIMAL}.
 74  
    */
 75  1
   MONEY((byte) 0x05, Types.DECIMAL, 8),
 76  
   /**
 77  
    * Corresponds to a java Float.  Accepts any Number (using
 78  
    * {@link Number#floatValue}), Boolean as 1 or 0, any Object converted to a
 79  
    * String and parsed as Double, or {@code null}.  Equivalent to SQL
 80  
    * {@link Types#FLOAT}.
 81  
    */
 82  1
   FLOAT((byte) 0x06, Types.FLOAT, 4),
 83  
   /**
 84  
    * Corresponds to a java Double.  Accepts any Number (using
 85  
    * {@link Number#doubleValue}), Boolean as 1 or 0, any Object converted to a
 86  
    * String and parsed as Double, or {@code null}.  Equivalent to SQL
 87  
    * {@link Types#DOUBLE}, {@link Types#REAL}.
 88  
    */
 89  1
   DOUBLE((byte) 0x07, Types.DOUBLE, 8),
 90  
   /**
 91  
    * Corresponds to a java Date.  Accepts a Date, any Number (using
 92  
    * {@link Number#longValue}), or {@code null}.  Equivalent to SQL
 93  
    * {@link Types#TIMESTAMP}, {@link Types#DATE}, {@link Types#TIME}.
 94  
    */
 95  1
   SHORT_DATE_TIME((byte) 0x08, Types.TIMESTAMP, 8),
 96  
   /**
 97  
    * Corresponds to a java {@code byte[]} of max length 255 bytes.  Accepts a
 98  
    * {@code byte[]}, or {@code null}.  Equivalent to SQL {@link Types#BINARY},
 99  
    * {@link Types#VARBINARY}.
 100  
    */
 101  1
   BINARY((byte) 0x09, Types.BINARY, null, true, false, 0, 255, 255, 1),
 102  
   /**
 103  
    * Corresponds to a java String of max length 255 chars.  Accepts any
 104  
    * CharSequence, any Object converted to a String , or {@code null}.
 105  
    * Equivalent to SQL {@link Types#VARCHAR}, {@link Types#CHAR}.
 106  
    */
 107  1
   TEXT((byte) 0x0A, Types.VARCHAR, null, true, false, 0,
 108  
        50 * JetFormat.TEXT_FIELD_UNIT_SIZE,
 109  
        (int)JetFormat.TEXT_FIELD_MAX_LENGTH, JetFormat.TEXT_FIELD_UNIT_SIZE),
 110  
   /**
 111  
    * Corresponds to a java {@code byte[]} of max length 16777215 bytes.
 112  
    * Accepts a {@code byte[]}, or {@code null}.  Equivalent to SQL
 113  
    * {@link Types#LONGVARBINARY}, {@link Types#BLOB}.
 114  
    */
 115  1
   OLE((byte) 0x0B, Types.LONGVARBINARY, null, true, true, 0, null, 0xFFFFFF,
 116  
       1),
 117  
   /**
 118  
    * Corresponds to a java String of max length 8388607 chars.  Accepts any
 119  
    * CharSequence, any Object converted to a String , or {@code null}.
 120  
    * Equivalent to SQL {@link Types#LONGVARCHAR}, {@link Types#CLOB}.
 121  
    */
 122  1
   MEMO((byte) 0x0C, Types.LONGVARCHAR, null, true, true, 0, null, 0xFFFFFF,
 123  
        JetFormat.TEXT_FIELD_UNIT_SIZE),
 124  
   /**
 125  
    * Unknown data.  Accepts {@code null}.
 126  
    */
 127  1
   UNKNOWN_0D((byte) 0x0D),
 128  
   /**
 129  
    * Corresponds to a java String with the pattern
 130  
    * <code>"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"</code>.  Accepts any
 131  
    * Object converted to a String matching this pattern (surrounding "{}" are
 132  
    * optional, so {@link java.util.UUID}s are supported), or {@code null}.
 133  
    */
 134  1
   GUID((byte) 0x0F, null, 16),
 135  
   /**
 136  
    * Corresponds to a java BigDecimal.  Accepts any Number (using
 137  
    * {@link Number#doubleValue}), a BigInteger, a BigDecimal, Boolean as 1 or
 138  
    * 0, any Object converted to a String and parsed as BigDecimal, or
 139  
    * {@code null}.  Equivalent to SQL {@link Types#NUMERIC}.
 140  
    */
 141  
   // for some reason numeric is "var len" even though it has a fixed size...
 142  1
   NUMERIC((byte) 0x10, Types.NUMERIC, 17, true, false, 17, 17, 17,
 143  
           true, 0, 0, 28, 1, 18, 28, 1);
 144  
 
 145  
   /** Map of SQL types to Access data types */
 146  1
   private static Map<Integer, DataType> SQL_TYPES = new HashMap<Integer, DataType>();
 147  
   /** Alternate map of SQL types to Access data types */
 148  1
   private static Map<Integer, DataType> ALT_SQL_TYPES = new HashMap<Integer, DataType>();
 149  
   static {
 150  16
     for (DataType type : DataType.values()) {
 151  15
       if (type._sqlType != null) {
 152  13
         SQL_TYPES.put(type._sqlType, type);
 153  
       }
 154  
     }
 155  1
     SQL_TYPES.put(Types.BIT, BYTE);
 156  1
     SQL_TYPES.put(Types.BLOB, OLE);
 157  1
     SQL_TYPES.put(Types.CLOB, MEMO);
 158  1
     SQL_TYPES.put(Types.BIGINT, LONG);
 159  1
     SQL_TYPES.put(Types.CHAR, TEXT);
 160  1
     SQL_TYPES.put(Types.DATE, SHORT_DATE_TIME);
 161  1
     SQL_TYPES.put(Types.REAL, DOUBLE);
 162  1
     SQL_TYPES.put(Types.TIME, SHORT_DATE_TIME);
 163  1
     SQL_TYPES.put(Types.VARBINARY, BINARY);
 164  
 
 165  
     // the "alternate" types allow for larger values
 166  1
     ALT_SQL_TYPES.put(Types.VARCHAR, MEMO);
 167  1
     ALT_SQL_TYPES.put(Types.VARBINARY, OLE);
 168  1
     ALT_SQL_TYPES.put(Types.BINARY, OLE);
 169  
   }
 170  
   
 171  1
   private static Map<Byte, DataType> DATA_TYPES = new HashMap<Byte, DataType>();
 172  
   static {
 173  16
     for (DataType type : DataType.values()) {
 174  15
       DATA_TYPES.put(type._value, type);
 175  
     }
 176  1
   }
 177  
 
 178  
   /** is this a variable length field */
 179  
   private boolean _variableLength;
 180  
   /** is this a long value field */
 181  
   private boolean _longValue;
 182  
   /** does this field have scale/precision */
 183  
   private boolean _hasScalePrecision;
 184  
   /** Internal Access value */
 185  
   private byte _value;
 186  
   /** Size in bytes of fixed length columns */
 187  
   private Integer _fixedSize;
 188  
   /** min in bytes size for var length columns */
 189  
   private Integer _minSize;
 190  
   /** default size in bytes for var length columns */
 191  
   private Integer _defaultSize;
 192  
   /** Max size in bytes for var length columns */
 193  
   private Integer _maxSize;
 194  
   /** SQL type equivalent, or null if none defined */
 195  
   private Integer _sqlType;
 196  
   /** min scale value */
 197  
   private Integer _minScale;
 198  
   /** the default scale value */
 199  
   private Integer _defaultScale;
 200  
   /** max scale value */
 201  
   private Integer _maxScale;
 202  
   /** min precision value */
 203  
   private Integer _minPrecision;
 204  
   /** the default precision value */
 205  
   private Integer _defaultPrecision;
 206  
   /** max precision value */
 207  
   private Integer _maxPrecision;
 208  
   /** the number of bytes per "unit" for this data type */
 209  
   private int _unitSize;
 210  
   
 211  
   private DataType(byte value) {
 212  1
     this(value, null, null);
 213  1
   }
 214  
   
 215  
   private DataType(byte value, Integer sqlType, Integer fixedSize) {
 216  10
     this(value, sqlType, fixedSize, false, false, null, null, null, 1);
 217  10
   }
 218  
 
 219  
   private DataType(byte value, Integer sqlType, Integer fixedSize,
 220  
                    boolean variableLength,
 221  
                    boolean longValue,
 222  
                    Integer minSize,
 223  
                    Integer defaultSize,
 224  
                    Integer maxSize,
 225  
                    int unitSize) {
 226  14
     this(value, sqlType, fixedSize, variableLength, longValue,
 227  
          minSize, defaultSize, maxSize,
 228  
          false, null, null, null, null, null, null, unitSize);
 229  14
   }
 230  
   
 231  
   private DataType(byte value, Integer sqlType, Integer fixedSize,
 232  
                    boolean variableLength,
 233  
                    boolean longValue,
 234  
                    Integer minSize,
 235  
                    Integer defaultSize,
 236  
                    Integer maxSize,
 237  
                    boolean hasScalePrecision,
 238  
                    Integer minScale,
 239  
                    Integer defaultScale,
 240  
                    Integer maxScale,
 241  
                    Integer minPrecision,
 242  
                    Integer defaultPrecision,
 243  
                    Integer maxPrecision,
 244  15
                    int unitSize) {
 245  15
     _value = value;
 246  15
     _sqlType = sqlType;
 247  15
     _fixedSize = fixedSize;
 248  15
     _variableLength = variableLength;
 249  15
     _longValue = longValue;
 250  15
     _minSize = minSize;
 251  15
     _defaultSize = defaultSize;
 252  15
     _maxSize = maxSize;
 253  15
     _hasScalePrecision = hasScalePrecision;
 254  15
     _minScale = minScale;
 255  15
     _defaultScale = defaultScale;
 256  15
     _maxScale = maxScale;
 257  15
     _minPrecision = minPrecision;
 258  15
     _defaultPrecision = defaultPrecision;
 259  15
     _maxPrecision = maxPrecision;
 260  15
     _unitSize = unitSize;
 261  15
   }
 262  
   
 263  
   public byte getValue() {
 264  323
     return _value;
 265  
   }
 266  
   
 267  
   public boolean isVariableLength() {
 268  5353
     return _variableLength;
 269  
   }
 270  
 
 271  
   public boolean isTrueVariableLength() {
 272  
     // some "var len" fields do not really have a variable length,
 273  
     // e.g. NUMERIC
 274  7
     return (isVariableLength() && (getMinSize() != getMaxSize()));
 275  
   }
 276  
   
 277  
   public boolean isLongValue() {
 278  87852
     return _longValue;
 279  
   }
 280  
 
 281  
   public boolean getHasScalePrecision() {
 282  5332
     return _hasScalePrecision;
 283  
   }
 284  
   
 285  
   public int getFixedSize() {
 286  59967
     if(_fixedSize != null) {
 287  59967
       return _fixedSize;
 288  
     }
 289  0
     throw new IllegalArgumentException("FIX ME");
 290  
   }
 291  
 
 292  
   public int getMinSize() {
 293  147
     return _minSize;
 294  
   }
 295  
 
 296  
   public int getDefaultSize() {
 297  875
     return _defaultSize;
 298  
   }
 299  
 
 300  
   public int getMaxSize() {
 301  925
     return _maxSize;
 302  
   }
 303  
   
 304  
   public int getSQLType() throws SQLException {
 305  0
     if (_sqlType != null) {
 306  0
       return _sqlType;
 307  
     }
 308  0
     throw new SQLException("Unsupported data type: " + toString());
 309  
   }
 310  
 
 311  
   public int getMinScale() {
 312  4
     return _minScale;
 313  
   }
 314  
 
 315  
   public int getDefaultScale() {
 316  15
     return _defaultScale;
 317  
   }
 318  
   
 319  
   public int getMaxScale() {
 320  4
     return _maxScale;
 321  
   }
 322  
   
 323  
   public int getMinPrecision() {
 324  4
     return _minPrecision;
 325  
   }
 326  
   
 327  
   public int getDefaultPrecision() {
 328  15
     return _defaultPrecision;
 329  
   }
 330  
   
 331  
   public int getMaxPrecision() {
 332  4
     return _maxPrecision;
 333  
   }
 334  
 
 335  
   public int getUnitSize() {
 336  27419
     return _unitSize;
 337  
   }
 338  
 
 339  
   public boolean isValidSize(int size) {
 340  141
     return isWithinRange(size, getMinSize(), getMaxSize());
 341  
   }
 342  
 
 343  
   public boolean isValidScale(int scale) {
 344  4
     return isWithinRange(scale, getMinScale(), getMaxScale());
 345  
   }
 346  
 
 347  
   public boolean isValidPrecision(int precision) {
 348  4
     return isWithinRange(precision, getMinPrecision(), getMaxPrecision());
 349  
   }
 350  
 
 351  
   private boolean isWithinRange(int value, int minValue, int maxValue) {
 352  149
     return((value >= minValue) && (value <= maxValue));
 353  
   }
 354  
   
 355  
   public static DataType fromByte(byte b) throws IOException {
 356  2208
     DataType rtn = DATA_TYPES.get(b);
 357  2208
     if (rtn != null) {
 358  2208
       return rtn;
 359  
     }
 360  0
     throw new IOException("Unrecognized data type: " + b);
 361  
   }
 362  
   
 363  
   public static DataType fromSQLType(int sqlType)
 364  
   throws SQLException
 365  
   {
 366  0
     return fromSQLType(sqlType, 0);
 367  
   }
 368  
   
 369  
   public static DataType fromSQLType(int sqlType, int lengthInUnits)
 370  
   throws SQLException
 371  
   {
 372  10
     DataType rtn = SQL_TYPES.get(sqlType);
 373  10
     if(rtn == null) {
 374  0
       throw new SQLException("Unsupported SQL type: " + sqlType);
 375  
     }
 376  
 
 377  
     // make sure size is reasonable
 378  10
     int size = lengthInUnits * rtn.getUnitSize();
 379  10
     if(rtn.isVariableLength() && !rtn.isValidSize(size)) {
 380  
       // try alternate type.  we always accept alternate "long value" types
 381  
       // regardless of the given lengthInUnits
 382  4
       DataType altRtn = ALT_SQL_TYPES.get(sqlType);
 383  4
       if((altRtn != null) &&
 384  
          (altRtn.isLongValue() || altRtn.isValidSize(size))) {
 385  
         // use alternate type
 386  3
         rtn = altRtn;
 387  
       }
 388  
     }
 389  
       
 390  10
     return rtn;
 391  
   }
 392  
 
 393  
 }