MysqlDatabaseImpl.java :  » Database-ORM » beankeeper » hu » netmind » persistence » Java Open Source

Java Open Source » Database ORM » beankeeper 
beankeeper » hu » netmind » persistence » MysqlDatabaseImpl.java
/**
 * Copyright (C) 2006 NetMind Consulting Bt.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package hu.netmind.persistence;

import java.util.Map;
import java.util.Iterator;
import java.util.List;
import java.util.Date;
import java.sql.Connection;
import java.sql.Types;
import hu.netmind.persistence.parser.Expression;
import hu.netmind.persistence.parser.ConstantTerm;
import hu.netmind.persistence.parser.ReferenceTerm;
import org.apache.log4j.Logger;

/**
 * MySQL database implementation.
 * Limitations:
 * <ul>
 *    <li>Date fields are stored only with seconds precision.</li>
 *    <li>Can not support more than 255 characters of map keys.</li>
 *    <li>InnoDB support must be compiled into MySQL to support</li>
 *    transactions.</li>
 * </ul>
 * @author Brautigam Robert
 * @version CVS Revision: $Revision$
 */
public class MysqlDatabaseImpl extends GenericDatabase
{
   private static final int STRING_LENGTH = 255;

   private static Logger logger = Logger.getLogger(MysqlDatabaseImpl.class);

   public MysqlDatabaseImpl()
   {
      super();
   }
   
   /**
    * Get the limit component of statement, if it can be expressed in
    * the current database with simple statement part.
    * @param limits The limits to apply.
    */
   protected String getLimitStatement(String statement, Limits limits, List types)
   {
      StringBuffer result = new StringBuffer(statement);
      if ( limits.getLimit() > 0 )
         result.append(" limit "+limits.getLimit());
      if ( limits.getOffset() > 0 )
         result.append(" offset "+limits.getOffset());
      return result.toString();
   }

   /**
    * Create table with given name, attribute types, and keys.
    * Difference from generic: Mysql does not support 'text' type primary
    * keys, so avoid in keys.
    * @param tableName The table to create.
    * @param attributeTypes The attribute names together with which
    * java class they should hold.
    */
   protected DatabaseStatistics createTable(Connection connection, String tableName,
         Map attributeTypes, List keyAttributeNames)
   {
      DatabaseStatistics stats = new DatabaseStatistics();
      // Create statement
      StringBuffer statement = new StringBuffer("create table "+tableName+" (");
      Iterator iterator = attributeTypes.entrySet().iterator();
      while ( iterator.hasNext() )
      {
         Map.Entry entry = (Map.Entry) iterator.next();
         String sqlTypeName = getSQLTypeName(getSQLType(((Class) entry.getValue())));
         // If attribute was a text type and a key, then alter type to
         // constrainted character string.
         if ( (sqlTypeName.startsWith("text")) && (keyAttributeNames.contains(entry.getKey())) )
            statement.append(entry.getKey().toString()+" varchar("+STRING_LENGTH+"),");
         else
            statement.append(entry.getKey().toString()+" "+sqlTypeName+",");
      }
      if ( (keyAttributeNames!=null) && (keyAttributeNames.size() > 0) )
      {
         statement.append(" primary key (");
         for ( int i=0; i<keyAttributeNames.size(); i++ )
            statement.append(keyAttributeNames.get(i)+",");
         statement.delete(statement.length()-1,statement.length());
         statement.append(")  ");
      }
      statement.delete(statement.length()-1,statement.length());
      statement.append(") type innodb");
      // Execute statement
      long startTime = System.currentTimeMillis();
      executeUpdate(connection,statement.toString());
      long endTime = System.currentTimeMillis();
      stats.setSchemaCount(1);
      stats.setSchemaTime(endTime-startTime);
      // Create initial indexes (currently all attributes will be indexed)
      stats.add(createIndexes(connection, tableName, attributeTypes));
      return stats;
   }

   /**
    * Convert incoming values into database acceptable format.
    */
   protected Object getSQLValue(Object value)
   {
      // Characters will be forwarded as strings
      if ( value instanceof Character )
         return value.toString();
      return super.getSQLValue(value);
   }
  
   /**
    * Convert incoming value from database into java format.
    */
   protected Object getJavaValue(Object value, int type, Class javaType)
   {
      try
      {
         if ( value == null )
            return null;
         if ( ((Boolean.class.equals(javaType)) || (boolean.class.equals(javaType))) &&
               (value instanceof Integer) )
            return new Boolean(((Integer) value).intValue() > 0);
         if ( (value instanceof byte[]) && (type==Types.LONGVARBINARY) && (String.class.equals(javaType)) )
            return new String((byte[]) value,"utf8");
         return super.getJavaValue(value,type,javaType);
      } catch ( StoreException e ) {
         throw e;
      } catch ( Exception e ) {
         throw new StoreException("conversion error tried to convert: "+value+"("+value.getClass()+"), of sql type: "+type+", java type: "+javaType);
      }
   }

   /**
    * Get the class for an sql type. Override timestamp to set default.
    */
   protected String getSQLTypeName(int sqltype)
   {
      switch ( sqltype )
      {
         case Types.TINYINT:
            return "boolean";
         case Types.TIMESTAMP:
            return "datetime";
         case Types.LONGVARCHAR:
         default:
            return super.getSQLTypeName(sqltype);
      }
   }

   /**
    * Transform 'ilike' to 'like', and 'like' to 'like binary' operators.
    * @param expr The expression to possibly transform.
    * @return A transformed expression.
    */
   protected Expression transformExpression(Expression expr)
   {
      Expression result = new Expression(expr);
      result.clear();
      for ( int i=0; i<expr.size(); i++ )
      {
         Object item = expr.get(i);
         if ( "like".equals(item) ||
              "=".equals(item) ||
              "!=".equals(item) ||
              "<".equals(item) ||
              "<=".equals(item) ||
              ">=".equals(item) ||
              ">".equals(item) ||
              "<>".equals(item)
               )
         {
            result.add(item);
            // Now, if any of the arguments to the operator is
            // a string, then we must apply 'binary' to make
            // the operator case sensitive.
            // Note: collection constant terms are not handled,
            // because they may be empty anyway.
            // Lhs and Rhs must exist, because these
            // operators are infix operators.
            Object lhs = expr.get(i-1);
            Object rhs = expr.get(i+1);
            if ( ("like".equals(item)) || (isStringType(lhs)) || 
                  (isStringType(rhs)) )
               result.add("binary");
         } else if ( "ilike".equals(item) )
            result.add("like");
         else
            result.add(item);
      }
      return result;
   }

   /**
    * Determine whether a term is string type or not.
    * @return True if the term represents a String type, false if unknown.
    */
   private boolean isStringType(Object term)
   {
      if ( term instanceof ConstantTerm )
      {
         ConstantTerm constantTerm = (ConstantTerm) term;
         return (constantTerm.getValue() != null) && (constantTerm.getValue() instanceof String);
      }
      if ( term instanceof ReferenceTerm )
      {
         ReferenceTerm refTerm = (ReferenceTerm) term;
         return String.class.equals(getAttributeType(refTerm.getTableName(),refTerm.getColumnName()));
      }
      return false;
   }

   /**
    * Get index creation statement for a given table and field.
    * @return The statement to use, or null, of no such index can be
    * created.
    */
   protected String getCreateIndexStatement(String indexName,String tableName, String field,
         Class fieldClass)
   {
      if ( fieldClass.equals(String.class) )
         return "create index "+indexName+
            " on "+tableName+" ("+field+"("+STRING_LENGTH+"))";
      return super.getCreateIndexStatement(indexName,tableName,field,fieldClass);
   }

}



java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.