EMMA Coverage Report (generated Sun May 02 20:42:29 CEST 2010)
[all classes][hu.netmind.beankeeper.db.impl]

COVERAGE SUMMARY FOR SOURCE FILE [MysqlDatabaseImpl.java]

nameclass, %method, %block, %line, %
MysqlDatabaseImpl.java0%   (0/1)0%   (0/10)0%   (0/481)0%   (0/77)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class MysqlDatabaseImpl0%   (0/1)0%   (0/10)0%   (0/481)0%   (0/77)
<static initializer> 0%   (0/1)0%   (0/4)0%   (0/1)
MysqlDatabaseImpl (): void 0%   (0/1)0%   (0/3)0%   (0/2)
createTable (Connection, String, Map, List): TransactionStatistics 0%   (0/1)0%   (0/164)0%   (0/25)
getCreateIndexStatement (String, String, String, Class): String 0%   (0/1)0%   (0/34)0%   (0/3)
getJavaValue (Object, int, Class): Object 0%   (0/1)0%   (0/81)0%   (0/12)
getLimitStatement (String, Limits, List): String 0%   (0/1)0%   (0/42)0%   (0/6)
getSQLTypeName (int): String 0%   (0/1)0%   (0/10)0%   (0/4)
getSQLValue (Object): Object 0%   (0/1)0%   (0/10)0%   (0/3)
isStringType (Object): boolean 0%   (0/1)0%   (0/34)0%   (0/7)
transformExpression (Expression): Expression 0%   (0/1)0%   (0/99)0%   (0/14)

1/**
2 * Copyright (C) 2006 NetMind Consulting Bt.
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 3 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  USA
17 */
18 
19package hu.netmind.beankeeper.db.impl;
20 
21import java.util.Map;
22import java.util.Iterator;
23import java.util.List;
24import java.util.Date;
25import java.sql.Connection;
26import java.sql.Types;
27import hu.netmind.beankeeper.parser.*;
28import hu.netmind.beankeeper.common.StoreException;
29import hu.netmind.beankeeper.transaction.*;
30import hu.netmind.beankeeper.db.Database;
31import hu.netmind.beankeeper.db.Limits;
32import org.apache.log4j.Logger;
33 
34/**
35 * MySQL database implementation.
36 * Limitations:
37 * <ul>
38 *    <li>Date fields are stored only with seconds precision.</li>
39 *    <li>Can not support more than 255 characters of map keys.</li>
40 *    <li>InnoDB support must be compiled into MySQL to support
41 *    transactions.</li>
42 * </ul>
43 * @author Brautigam Robert
44 * @version CVS Revision: $Revision$
45 */
46public class MysqlDatabaseImpl extends GenericDatabase implements Database
47{
48   private static final int STRING_LENGTH = 255;
49 
50   private static Logger logger = Logger.getLogger(MysqlDatabaseImpl.class);
51 
52   public MysqlDatabaseImpl()
53   {
54      super();
55   }
56   
57   /**
58    * Get the limit component of statement, if it can be expressed in
59    * the current database with simple statement part.
60    * @param limits The limits to apply.
61    */
62   protected String getLimitStatement(String statement, Limits limits, List types)
63   {
64      StringBuffer result = new StringBuffer(statement);
65      if ( limits.getLimit() > 0 )
66         result.append(" limit "+limits.getLimit());
67      if ( limits.getOffset() > 0 )
68         result.append(" offset "+limits.getOffset());
69      return result.toString();
70   }
71 
72   /**
73    * Create table with given name, attribute types, and keys.
74    * Difference from generic: Mysql does not support 'text' type primary
75    * keys, so avoid in keys.
76    * @param tableName The table to create.
77    * @param attributeTypes The attribute names together with which
78    * java class they should hold.
79    */
80   protected TransactionStatistics createTable(Connection connection, String tableName,
81         Map attributeTypes, List keyAttributeNames)
82   {
83      TransactionStatistics stats = new TransactionStatistics();
84      // Create statement
85      StringBuffer statement = new StringBuffer("create table "+tableName+" (");
86      Iterator iterator = attributeTypes.entrySet().iterator();
87      while ( iterator.hasNext() )
88      {
89         Map.Entry entry = (Map.Entry) iterator.next();
90         String sqlTypeName = getSQLTypeName(getSQLType(((Class) entry.getValue())));
91         // If attribute was a text type and a key, then alter type to
92         // constrainted character string.
93         if ( (sqlTypeName.startsWith("text")) && (keyAttributeNames.contains(entry.getKey())) )
94            statement.append(entry.getKey().toString()+" varchar("+STRING_LENGTH+"),");
95         else
96            statement.append(entry.getKey().toString()+" "+sqlTypeName+",");
97      }
98      if ( (keyAttributeNames!=null) && (keyAttributeNames.size() > 0) )
99      {
100         statement.append(" primary key (");
101         for ( int i=0; i<keyAttributeNames.size(); i++ )
102            statement.append(keyAttributeNames.get(i)+",");
103         statement.delete(statement.length()-1,statement.length());
104         statement.append(")  ");
105      }
106      statement.delete(statement.length()-1,statement.length());
107      statement.append(") type innodb");
108      // Execute statement
109      long startTime = System.currentTimeMillis();
110      executeUpdate(connection,statement.toString());
111      long endTime = System.currentTimeMillis();
112      stats.setSchemaCount(1);
113      stats.setSchemaTime(endTime-startTime);
114      // Create initial indexes (currently all attributes will be indexed)
115      stats.add(createIndexes(connection, tableName, attributeTypes));
116      return stats;
117   }
118 
119   /**
120    * Convert incoming values into database acceptable format.
121    */
122   protected Object getSQLValue(Object value)
123   {
124      // Characters will be forwarded as strings
125      if ( value instanceof Character )
126         return value.toString();
127      return super.getSQLValue(value);
128   }
129  
130   /**
131    * Convert incoming value from database into java format.
132    */
133   protected Object getJavaValue(Object value, int type, Class javaType)
134   {
135      try
136      {
137         if ( value == null )
138            return null;
139         Class booleanClass = boolean.class;
140         if ( ((Boolean.class.equals(javaType)) || (booleanClass.equals(javaType))) &&
141               (value instanceof Integer) )
142            return new Boolean(((Integer) value).intValue() > 0);
143         if ( (value instanceof byte[]) && (type==Types.LONGVARBINARY) && (String.class.equals(javaType)) )
144            return new String((byte[]) value,"utf8");
145         return super.getJavaValue(value,type,javaType);
146      } catch ( StoreException e ) {
147         throw e;
148      } catch ( Exception e ) {
149         throw new StoreException("conversion error tried to convert: "+value+"("+value.getClass()+"), of sql type: "+type+", java type: "+javaType);
150      }
151   }
152 
153   /**
154    * Get the class for an sql type. Override timestamp to set default.
155    */
156   protected String getSQLTypeName(int sqltype)
157   {
158      switch ( sqltype )
159      {
160         case Types.TINYINT:
161            return "boolean";
162         case Types.TIMESTAMP:
163            return "datetime";
164         case Types.LONGVARCHAR:
165         default:
166            return super.getSQLTypeName(sqltype);
167      }
168   }
169 
170   /**
171    * Transform 'ilike' to 'like', and 'like' to 'like binary' operators.
172    * @param expr The expression to possibly transform.
173    * @return A transformed expression.
174    */
175   protected Expression transformExpression(Expression expr)
176   {
177      Expression result = new Expression(expr);
178      result.clear();
179      for ( int i=0; i<expr.size(); i++ )
180      {
181         Object item = expr.get(i);
182         if ( "like".equals(item) ||
183              "=".equals(item) ||
184              "!=".equals(item) ||
185              "<".equals(item) ||
186              "<=".equals(item) ||
187              ">=".equals(item) ||
188              ">".equals(item) ||
189              "<>".equals(item)
190               )
191         {
192            result.add(item);
193            // Now, if any of the arguments to the operator is
194            // a string, then we must apply 'binary' to make
195            // the operator case sensitive.
196            // Note: collection constant terms are not handled,
197            // because they may be empty anyway.
198            // Lhs and Rhs must exist, because these
199            // operators are infix operators.
200            Object lhs = expr.get(i-1);
201            Object rhs = expr.get(i+1);
202            if ( ("like".equals(item)) || (isStringType(lhs)) || 
203                  (isStringType(rhs)) )
204               result.add("binary");
205         } else if ( "ilike".equals(item) )
206            result.add("like");
207         else
208            result.add(item);
209      }
210      return result;
211   }
212 
213   /**
214    * Determine whether a term is string type or not.
215    * @return True if the term represents a String type, false if unknown.
216    */
217   private boolean isStringType(Object term)
218   {
219      if ( term instanceof ConstantTerm )
220      {
221         ConstantTerm constantTerm = (ConstantTerm) term;
222         return (constantTerm.getValue() != null) && (constantTerm.getValue() instanceof String);
223      }
224      if ( term instanceof ReferenceTerm )
225      {
226         ReferenceTerm refTerm = (ReferenceTerm) term;
227         return String.class.equals(getAttributeType(refTerm.getTableName(),refTerm.getColumnName()));
228      }
229      return false;
230   }
231 
232   /**
233    * Get index creation statement for a given table and field.
234    * @return The statement to use, or null, of no such index can be
235    * created.
236    */
237   protected String getCreateIndexStatement(String indexName,String tableName, String field,
238         Class fieldClass)
239   {
240      if ( fieldClass.equals(String.class) )
241         return "create index "+indexName+
242            " on "+tableName+" ("+field+"("+STRING_LENGTH+"))";
243      return super.getCreateIndexStatement(indexName,tableName,field,fieldClass);
244   }
245 
246}
247 
248 
249 

[all classes][hu.netmind.beankeeper.db.impl]
EMMA 2.0.5312debian (C) Vladimir Roubtsov