Coverage Report - org.melati.poem.dbms.MSAccess
 
Classes in this File Line Coverage Branch Coverage Complexity
MSAccess
65%
60/92
61%
60/98
4.619
MSAccess$MSAccessStringPoemType
0%
0/9
0%
0/16
4.619
 
 1  
 /*
 2  
  * $Source$
 3  
  * $Revision$
 4  
  *
 5  
  * Copyright (C) 2006 Tim Pizey
 6  
  *
 7  
  * Part of Melati (http://melati.org), a framework for the rapid
 8  
  * development of clean, maintainable web applications.
 9  
  *
 10  
  * Melati is free software; Permission is granted to copy, distribute
 11  
  * and/or modify this software under the terms either:
 12  
  *
 13  
  * a) the GNU General Public License as published by the Free Software
 14  
  *    Foundation; either version 2 of the License, or (at your option)
 15  
  *    any later version,
 16  
  *
 17  
  *    or
 18  
  *
 19  
  * b) any version of the Melati Software License, as published
 20  
  *    at http://melati.org
 21  
  *
 22  
  * You should have received a copy of the GNU General Public License and
 23  
  * the Melati Software License along with this program;
 24  
  * if not, write to the Free Software Foundation, Inc.,
 25  
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
 26  
  * GNU General Public License and visit http://melati.org to obtain the
 27  
  * Melati Software License.
 28  
  *
 29  
  * Feel free to contact the Developers of Melati (http://melati.org),
 30  
  * if you would like to work out a different arrangement than the options
 31  
  * outlined here.  It is our intention to allow Melati to be used by as
 32  
  * wide an audience as possible.
 33  
  *
 34  
  * This program is distributed in the hope that it will be useful,
 35  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 36  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 37  
  * GNU General Public License for more details.
 38  
  *
 39  
  * Contact details for copyright holder:
 40  
  *
 41  
  *     Tim Pizey (timp At paneris.org)
 42  
  *
 43  
  */
 44  
 package org.melati.poem.dbms;
 45  
 import java.sql.Connection;
 46  
 import java.sql.DatabaseMetaData;
 47  
 import java.sql.ResultSet;
 48  
 import java.sql.SQLException;
 49  
 
 50  
 import org.melati.poem.BigDecimalPoemType;
 51  
 import org.melati.poem.BinaryPoemType;
 52  
 import org.melati.poem.BooleanPoemType;
 53  
 import org.melati.poem.Column;
 54  
 import org.melati.poem.DatePoemType;
 55  
 import org.melati.poem.DoublePoemType;
 56  
 import org.melati.poem.IntegerPoemType;
 57  
 import org.melati.poem.LongPoemType;
 58  
 import org.melati.poem.PoemType;
 59  
 import org.melati.poem.SQLPoemType;
 60  
 import org.melati.poem.SQLType;
 61  
 import org.melati.poem.StringPoemType;
 62  
 import org.melati.poem.TimestampPoemType;
 63  
 import org.melati.poem.dbms.SQLServer.SQLServerBooleanPoemType;
 64  
 import org.melati.poem.util.StringUtils;
 65  
 /**
 66  
  * A Driver for the Microsoft Access database server.
 67  
  * http://www.tobychampion.co.uk/Access2000Dialect.java.txt
 68  
  * 
 69  
  */
 70  
 public class MSAccess extends AnsiStandard {
 71  
   /** Size of text fields. */
 72  
   public static final int msAccessTextHack = 250;
 73  
   /** Size of memo fields. */
 74  
   public static final int msAccessMemoSize = 1073741823;
 75  
   /** Size of binary fields. */
 76  
   public static final int msAccessBinarySize = 510;
 77  
 
 78  
   /** Constructor. */
 79  1
   public MSAccess() {
 80  
     // Appears to work 
 81  1
      setDriverClassName("sun.jdbc.odbc.JdbcOdbcDriver");
 82  
     // Worked once or twice
 83  
     // Need new licence keys all the time
 84  
     //setDriverClassName("easysoft.sql.jobDriver"); 
 85  1
   }
 86  
 
 87  
   /** 
 88  
    * {@inheritDoc}
 89  
    * @see org.melati.poem.dbms.AnsiStandard#canDropColumns()
 90  
    */
 91  
   public boolean canDropColumns() {
 92  1
     return false;
 93  
   }
 94  
   /** 
 95  
    * {@inheritDoc}
 96  
    * @see org.melati.poem.dbms.Dbms#canStoreBlobs()
 97  
    */
 98  
   public boolean canStoreBlobs(){
 99  0
     return false;
 100  
   }
 101  
 
 102  
 
 103  
   @Override
 104  
   public void shutdown(Connection connection) throws SQLException {
 105  
     // FIXME Something wrong here
 106  0
     connection.commit();
 107  0
   }
 108  
 
 109  
   @Override
 110  
   public String unreservedName(String name) {
 111  31
     if(name.equalsIgnoreCase("GROUP")) name = "MELATI_" + name.toUpperCase();
 112  31
     if(name.equalsIgnoreCase("USER")) name = "MELATI_" + name.toUpperCase();
 113  31
     return name;
 114  
   }
 115  
 
 116  
   /**
 117  
    * Ignore tables starting with '~', which should 
 118  
    * probably have a jdbc type of 'SYSTEM TABLE'.
 119  
    */
 120  
   @Override
 121  
   public String melatiName(String name) {
 122  3
     if (name == null) return name;
 123  2
     if (name.startsWith("~"))
 124  1
       return null;
 125  1
     if(name.equalsIgnoreCase("MELATI_GROUP")) name = "group";
 126  1
     if(name.equalsIgnoreCase("MELATI_USER")) name = "user";
 127  1
     return name;
 128  
   }
 129  
 
 130  
 
 131  
   @Override
 132  
   public String getSqlDefinition(String sqlTypeName) {
 133  5
     if (sqlTypeName.equals("BOOLEAN")) {
 134  1
       return ("BIT");
 135  
     }
 136  4
     if (sqlTypeName.equals("DOUBLE PRECISION")) {
 137  1
       return ("DOUBLE");
 138  
     }
 139  3
     if (sqlTypeName.equals("INT8")) {
 140  1
       return ("INTEGER");
 141  
     }
 142  2
     if (sqlTypeName.equals("Big Decimal")) {
 143  1
       return ("NUMERIC");
 144  
     }
 145  1
     return super.getSqlDefinition(sqlTypeName);
 146  
   }
 147  
 
 148  
   @Override
 149  
   public String getLongSqlDefinition() {
 150  1
     return "INTEGER";
 151  
   }
 152  
 
 153  
   @Override
 154  
   public String getStringSqlDefinition(int size) throws SQLException {
 155  2
     if (size < 0) { 
 156  
       // Don't use TEXT as it doesn't seem to work as documented
 157  1
       return "VARCHAR(" + msAccessTextHack + ")";
 158  
     }
 159  1
     return super.getStringSqlDefinition(size);
 160  
   }
 161  
   
 162  
   /**
 163  
    * Cludge?
 164  
    */
 165  
   @Override
 166  
   public String getFixedPtSqlDefinition(int scale, int precision)
 167  
   throws SQLException {
 168  3
     if (scale < 0 || precision <= 0)
 169  2
       throw new SQLException(
 170  
       "negative scale or nonpositive precision not supported in AnsiStandard DECIMALs");
 171  1
     return "NUMERIC";
 172  
   }
 173  
 
 174  
   @Override
 175  
   public String getBinarySqlDefinition(int size) throws SQLException {
 176  2
     if (size < 0)
 177  1
       return "BINARY"; // 512
 178  1
     return "BINARY(" + size + ")";
 179  
   }
 180  
 
 181  
   @Override
 182  
   public String sqlBooleanValueOfRaw(Object raw) {
 183  2
     if (((Boolean)raw).booleanValue())
 184  1
       return "1";
 185  
     else
 186  1
       return "0";
 187  
   }
 188  
 
 189  
   @Override
 190  
   public <S,O>PoemType<O> canRepresent(PoemType<S> storage, PoemType<O> type) {
 191  14
     if (storage instanceof StringPoemType && type instanceof StringPoemType) {
 192  4
       if (((StringPoemType)storage).getSize() == msAccessTextHack
 193  1
               && ((StringPoemType) type).getSize() == -1) {
 194  1
         return type;
 195  3
       } else if (((StringPoemType)storage).getSize() == msAccessMemoSize
 196  1
                  && ((StringPoemType)type).getSize() == -1) {
 197  1
               return type;
 198  
       } else {
 199  2
         return storage.canRepresent(type);
 200  
       }
 201  10
     } else if (storage instanceof BinaryPoemType && type instanceof BinaryPoemType) {
 202  0
       if (((BinaryPoemType)storage).getSize() == msAccessBinarySize
 203  0
               && ((BinaryPoemType) type).getSize() == -1) {
 204  0
         return type;
 205  
       } else {
 206  0
         return storage.canRepresent(type);
 207  
       }
 208  10
     } else if (storage instanceof TimestampPoemType && type instanceof DatePoemType) {
 209  1
       return type;
 210  9
     } else if (storage instanceof BooleanPoemType && type instanceof BooleanPoemType) {
 211  
       // ignore nullability
 212  1
       return type;
 213  8
     } else if (storage instanceof DoublePoemType && type instanceof BigDecimalPoemType
 214  2
             && !(!storage.getNullable() && type.getNullable())  // Nullable may represent not nullable
 215  
     ) {
 216  1
       return type;
 217  7
     } else if (storage instanceof IntegerPoemType && type instanceof LongPoemType
 218  2
             && !(!storage.getNullable() && type.getNullable())  // Nullable may represent not nullable
 219  
     ) {
 220  1
       return type;
 221  
     } else {
 222  6
       return storage.canRepresent(type);
 223  
     }
 224  
   }
 225  
 
 226  
   /**
 227  
    * Translates a MSSQL String into a Poem <code>StringPoemType</code>.
 228  
    */
 229  
   public static class MSAccessStringPoemType extends StringPoemType {
 230  
     /**
 231  
      * Constructor.
 232  
      * @param nullable nullability
 233  
      * @param size length normally
 234  
      */
 235  
     public MSAccessStringPoemType(boolean nullable, int size) {
 236  0
       super(nullable, size);
 237  0
     }
 238  
     // We set size to sqlServerTextHack for our Text type
 239  
     protected boolean _canRepresent(SQLPoemType<?> other) {
 240  0
       return sqlTypeCode() == other.sqlTypeCode() &&
 241  0
              (getSize() < 0 || 
 242  0
              getSize() == msAccessTextHack || 
 243  0
              getSize() >= ((StringPoemType) other).getSize());
 244  
     }
 245  
 
 246  
     @Override
 247  
     public <O>PoemType<O> canRepresent(PoemType<O> other) {
 248  0
       return other instanceof StringPoemType
 249  0
               && _canRepresent((StringPoemType) other)
 250  0
               && !(!getNullable() && ((StringPoemType) other).getNullable()) ? other
 251  
               : null;
 252  
     }
 253  
   }
 254  
 
 255  
   @Override
 256  
   public SQLPoemType<?> defaultPoemTypeOfColumnMetaData(ResultSet md)
 257  
       throws SQLException {
 258  
     /*<pre>
 259  
      * ResultSetMetaData rsmd = md.getMetaData(); 
 260  
      * int cols = rsmd.getColumnCount(); 
 261  
      * for (int i = 1; i <= cols; i++) { 
 262  
      *  String table = rsmd.getTableName(i); 
 263  
      *  System.err.println("table name: " + table); 
 264  
      *  String column = rsmd.getColumnName(i); 
 265  
      *  System.err.println("column name: " + column); 
 266  
      *  int type = rsmd.getColumnType(i); 
 267  
      *  System.err.println("type: " + type);
 268  
      *  String typeName = rsmd.getColumnTypeName(i);
 269  
      *  System.err.println("type Name: " + typeName); 
 270  
      *  String className = rsmd.getColumnClassName(i); 
 271  
      *  System.err.println("class Name: " + className);
 272  
      *  System.err.println("String val: " + md.getString(i));
 273  
      *  System.err.println(""); 
 274  
      * }
 275  
      * </pre>
 276  
      */
 277  0
     String typeName = md.getString("TYPE_NAME");
 278  0
     if (typeName.equals("text"))
 279  0
       return new MSAccessStringPoemType(
 280  0
                                      md.getInt("NULLABLE") == DatabaseMetaData.columnNullable,
 281  0
                                      md.getInt("COLUMN_SIZE"));
 282  
     // We use a magic number for text fields
 283  
 /*
 284  
     if (md.getString("TYPE_NAME").equals("VARCHAR")
 285  
             && md.getInt("COLUMN_SIZE") == msAccessTextHack)
 286  
       return new MSAccessStringPoemType(
 287  
       md.getInt("NULLABLE") == DatabaseMetaData.columnNullable, md
 288  
               .getInt("COLUMN_SIZE"));
 289  
     if (md.getString("TYPE_NAME").equals("CHAR"))
 290  
       return new StringPoemType(
 291  
                                 md.getInt("NULLABLE") == DatabaseMetaData.columnNullable,
 292  
                                 md.getInt("COLUMN_SIZE"));
 293  
 */                               
 294  0
     if (typeName.equals("BINARY"))
 295  0
       return new BinaryPoemType(
 296  0
                    md.getInt("NULLABLE") == DatabaseMetaData.columnNullable,
 297  0
                    md.getInt("COLUMN_SIZE"));
 298  0
     if (typeName.equals("INT"))
 299  0
       return new LongPoemType(
 300  0
                    md.getInt("NULLABLE") == DatabaseMetaData.columnNullable);
 301  0
     if (typeName.equals("SMALLINT"))
 302  0
       return new IntegerPoemType(
 303  0
                    md.getInt("NULLABLE") == DatabaseMetaData.columnNullable);
 304  0
     if (typeName.equals("bit"))
 305  0
       return new SQLServerBooleanPoemType(
 306  0
               md.getInt("NULLABLE") == DatabaseMetaData.columnNullable);
 307  0
     return super.defaultPoemTypeOfColumnMetaData(md);
 308  
   }
 309  
 
 310  
   @Override
 311  
   public String caseInsensitiveRegExpSQL(String term1, String term2) {
 312  3
     if (StringUtils.isQuoted(term2)) {
 313  1
       term2 = term2.substring(1, term2.length() - 1);
 314  
     }
 315  3
     term2 = StringUtils.quoted(StringUtils.quoted(term2, '%'), '\'');
 316  
 
 317  3
     return term1 + " LIKE " + term2;
 318  
   }
 319  
 
 320  
   
 321  
   /**
 322  
    * Accommodate SQLServer syntax. {@inheritDoc}
 323  
    */
 324  
   @Override
 325  
   public String alterColumnNotNullableSQL(String tableName, Column<?> column) {
 326  0
     return "ALTER TABLE " + getQuotedName(tableName) + " ALTER COLUMN "
 327  0
             + getQuotedName(column.getName()) + " "
 328  0
             + column.getSQLType().sqlDefinition(this);
 329  
   }
 330  
 
 331  
   @Override
 332  
   public String selectLimit(String querySelection, int limit) {
 333  1
     return "SELECT TOP " + limit + " " + querySelection;
 334  
   }
 335  
 
 336  
 
 337  
   @Override
 338  
   public String getSqlDefaultValue(SQLType<?> sqlType) {
 339  0
     if (sqlType instanceof BooleanPoemType) {
 340  0
       return ("0");
 341  
     }
 342  0
     return super.getSqlDefaultValue(sqlType);
 343  
   }
 344  
 }