001: /**
002: * Copyright (C) 2006 NetMind Consulting Bt.
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 3 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */package hu.netmind.persistence;
018:
019: import java.sql.*;
020: import java.util.*;
021: import org.apache.log4j.Logger;
022: import hu.netmind.persistence.parser.Expression;
023:
024: /**
025: * HSQL database implementation.
026: * @author Brautigam Robert
027: * @version CVS Revision: $Revision$
028: */
029: public class HSQLDatabaseImpl extends GenericDatabase {
030: private static Logger logger = Logger
031: .getLogger(HSQLDatabaseImpl.class);
032:
033: /**
034: * Issue a checkpoint to the server. This works with embedded
035: * and client-server case too, because it does not cause the
036: * server to exit.
037: */
038: public void release(ConnectionSource source) {
039: Connection connection = source.getConnection();
040: executeUpdate(connection, "checkpoint defrag");
041: }
042:
043: /**
044: * Get the limit component of statement, if it can be expressed in
045: * the current database with simple statement part.
046: * @param limits The limits to apply.
047: */
048: protected String getLimitStatement(String statement, Limits limits,
049: List types) {
050: StringBuffer result = new StringBuffer(statement);
051: if (limits.getLimit() > 0)
052: result.append(" limit " + limits.getLimit());
053: if (limits.getOffset() > 0)
054: result.append(" offset " + limits.getOffset());
055: return result.toString();
056: }
057:
058: /**
059: * Get the class for an sql type.
060: */
061: protected String getSQLTypeName(int sqltype) {
062: switch (sqltype) {
063: case Types.VARCHAR:
064: return "varchar";
065: case Types.BLOB:
066: case Types.BINARY:
067: case Types.VARBINARY:
068: return "binary";
069: default:
070: return super .getSQLTypeName(sqltype);
071: }
072: }
073:
074: /**
075: * Fix custom data types not supported by database.
076: */
077: protected int getTableAttributeType(ResultSet rs)
078: throws SQLException {
079: int columnType = rs.getInt("DATA_TYPE");
080: // Recognize boolean type
081: if ((columnType == Types.DECIMAL)
082: && (rs.getInt("COLUMN_SIZE") == 1))
083: columnType = Types.BOOLEAN;
084: return columnType;
085: }
086:
087: /**
088: * Get the data types of a given table.
089: * @return A map of names with the sql type number as value.
090: */
091: protected HashMap getTableAttributeTypes(Connection connection,
092: String tableName) throws SQLException {
093: return super .getTableAttributeTypes(connection, tableName
094: .toUpperCase());
095: }
096:
097: /**
098: * Transform 'ilike' to upper case like.
099: * @param expr The expression to possibly transform.
100: * @return A transformed expression.
101: */
102: protected Expression transformExpression(Expression expr) {
103: Expression result = new Expression(expr);
104: result.clear();
105: for (int i = 0; i < expr.size(); i++) {
106: Object item = expr.get(i);
107: if ("ilike".equals(item)) {
108: // Here we need to upper() the argument before and after like
109: Object arg = result.removeLast();
110: result.add("upper(");
111: result.add(arg);
112: result.add(")");
113: result.add("like");
114: result.add("upper(");
115: result.add(expr.get(i + 1));
116: result.add(")");
117: i++; // We used an argument
118: } else {
119: result.add(item);
120: }
121: }
122: return result;
123: }
124:
125: /**
126: * Get an unused index name.
127: */
128: protected String getCreateIndexName(Connection connection,
129: String tableName, String field) {
130: return super .getCreateIndexName(connection, tableName
131: .toUpperCase(), field);
132: }
133:
134: /**
135: * Drop a column from a table. HSQL does not drop the column if
136: * there are indexes to it, so first remove the indexes in question.
137: * @param connection The connection object.
138: * @param tableName The table to drop column from.
139: * @param columnName The column to drop.
140: */
141: protected DatabaseStatistics dropColumn(Connection connection,
142: String tableName, String columnName) {
143: DatabaseStatistics stats = new DatabaseStatistics();
144: try {
145: logger.debug("detemining indexes before dropping column: "
146: + columnName);
147: // Determine indexes for given column, and remove them mercilessly
148: long startTime = System.currentTimeMillis();
149: DatabaseMetaData dmd = connection.getMetaData();
150: ResultSet rs = dmd.getIndexInfo(null, null, tableName
151: .toUpperCase(), false, false);
152: while (rs.next()) {
153: if (logger.isDebugEnabled())
154: logger.debug("got index '"
155: + rs.getString("INDEX_NAME")
156: + "', it's column is: "
157: + rs.getString("COLUMN_NAME"));
158: // Got index, but only drop it, when it is about our petit column
159: if (columnName.equalsIgnoreCase(rs
160: .getString("COLUMN_NAME"))) {
161: // It is about the column given, so drop it, for great justice
162: executeUpdate(connection, "drop index "
163: + rs.getString("INDEX_NAME"));
164: stats.setSchemaCount(stats.getSchemaCount() + 1);
165: }
166: }
167: long endTime = System.currentTimeMillis();
168: stats.setSchemaCount(stats.getSchemaCount() + 1);
169: stats.setSchemaTime(endTime - startTime);
170: } catch (SQLException e) {
171: logger.error(
172: "error while trying to remove indexes for column: "
173: + tableName + "." + columnName, e);
174: }
175: // Now we can drop the column
176: stats.add(super .dropColumn(connection, tableName, columnName));
177: return stats;
178: }
179:
180: /**
181: * Get the create table statement before the attributes part.
182: */
183: protected String getCreateTableStatement(Connection connection,
184: String tableName) {
185: return "create cached table " + tableName;
186: }
187:
188: }
|