001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Florent Guillaume 018 */ 019package org.nuxeo.ecm.core.storage.sql.jdbc.dialect; 020 021import java.io.Serializable; 022import java.sql.Connection; 023import java.sql.DatabaseMetaData; 024import java.sql.PreparedStatement; 025import java.sql.ResultSet; 026import java.sql.SQLException; 027import java.sql.Types; 028import java.util.HashMap; 029import java.util.List; 030import java.util.Map; 031 032import org.nuxeo.ecm.core.storage.sql.ColumnType; 033import org.nuxeo.ecm.core.storage.sql.Model; 034import org.nuxeo.ecm.core.storage.sql.RepositoryDescriptor; 035import org.nuxeo.ecm.core.storage.sql.jdbc.JDBCLogger; 036import org.nuxeo.ecm.core.storage.sql.jdbc.db.Column; 037import org.nuxeo.ecm.core.storage.sql.jdbc.db.Database; 038import org.nuxeo.ecm.core.storage.sql.jdbc.db.Table; 039 040/** 041 * HSQLDB-specific dialect. 042 * <p> 043 * Not used for VCS, only for directories, so many features don't matter. 044 */ 045public class DialectHSQLDB extends Dialect { 046 047 public DialectHSQLDB(DatabaseMetaData metadata, RepositoryDescriptor repositoryDescriptor) { 048 super(metadata, repositoryDescriptor); 049 } 050 051 @Override 052 public boolean supportsIfExistsAfterTableName() { 053 return true; 054 } 055 056 @Override 057 public JDBCInfo getJDBCTypeAndString(ColumnType type) { 058 switch (type.spec) { 059 case STRING: 060 if (type.isUnconstrained()) { 061 return jdbcInfo("VARCHAR", Types.VARCHAR); 062 } else if (type.isClob()) { 063 return jdbcInfo("CLOB", Types.CLOB); 064 } else { 065 return jdbcInfo("VARCHAR(%d)", type.length, Types.VARCHAR); 066 } 067 case BOOLEAN: 068 return jdbcInfo("BOOLEAN", Types.BOOLEAN); 069 case LONG: 070 return jdbcInfo("BIGINT", Types.BIGINT); 071 case DOUBLE: 072 return jdbcInfo("DOUBLE", Types.DOUBLE); 073 case TIMESTAMP: 074 return jdbcInfo("TIMESTAMP", Types.TIMESTAMP); 075 case BLOBID: 076 return jdbcInfo("VARCHAR(250)", Types.VARCHAR); 077 // ----- 078 case NODEID: 079 case NODEIDFK: 080 case NODEIDFKNP: 081 case NODEIDFKMUL: 082 case NODEIDFKNULL: 083 case NODEIDPK: 084 case NODEVAL: 085 return jdbcInfo("VARCHAR(36)", Types.VARCHAR); 086 case SYSNAME: 087 case SYSNAMEARRAY: 088 return jdbcInfo("VARCHAR(250)", Types.VARCHAR); 089 case TINYINT: 090 return jdbcInfo("TINYINT", Types.TINYINT); 091 case INTEGER: 092 return jdbcInfo("INTEGER", Types.INTEGER); 093 case AUTOINC: 094 return jdbcInfo("INTEGER IDENTITY", Types.INTEGER); 095 case FTINDEXED: 096 throw new AssertionError(type); 097 case FTSTORED: 098 return jdbcInfo("CLOB", Types.CLOB); 099 case CLUSTERNODE: 100 return jdbcInfo("INTEGER", Types.INTEGER); 101 case CLUSTERFRAGS: 102 return jdbcInfo("VARCHAR", Types.VARCHAR); 103 } 104 throw new AssertionError(type); 105 } 106 107 @Override 108 public boolean isAllowedConversion(int expected, int actual, String actualName, int actualSize) { 109 // CLOB vs VARCHAR compatibility 110 if (expected == Types.VARCHAR && actual == Types.CLOB) { 111 return true; 112 } 113 if (expected == Types.CLOB && actual == Types.VARCHAR) { 114 return true; 115 } 116 // INTEGER vs BIGINT compatibility 117 if (expected == Types.BIGINT && actual == Types.INTEGER) { 118 return true; 119 } 120 if (expected == Types.INTEGER && actual == Types.BIGINT) { 121 return true; 122 } 123 return false; 124 } 125 126 @Override 127 public void setToPreparedStatement(PreparedStatement ps, int index, Serializable value, Column column) 128 throws SQLException { 129 switch (column.getJdbcType()) { 130 case Types.VARCHAR: 131 case Types.CLOB: 132 setToPreparedStatementString(ps, index, value, column); 133 return; 134 case Types.BOOLEAN: 135 ps.setBoolean(index, ((Boolean) value).booleanValue()); 136 return; 137 case Types.TINYINT: 138 case Types.INTEGER: 139 case Types.BIGINT: 140 ps.setLong(index, ((Number) value).longValue()); 141 return; 142 case Types.DOUBLE: 143 ps.setDouble(index, ((Double) value).doubleValue()); 144 return; 145 case Types.TIMESTAMP: 146 setToPreparedStatementTimestamp(ps, index, value, column); 147 return; 148 default: 149 throw new SQLException("Unhandled JDBC type: " + column.getJdbcType()); 150 } 151 } 152 153 @Override 154 @SuppressWarnings("boxing") 155 public Serializable getFromResultSet(ResultSet rs, int index, Column column) throws SQLException { 156 switch (column.getJdbcType()) { 157 case Types.VARCHAR: 158 case Types.CLOB: 159 return getFromResultSetString(rs, index, column); 160 case Types.BOOLEAN: 161 return rs.getBoolean(index); 162 case Types.TINYINT: 163 case Types.INTEGER: 164 case Types.BIGINT: 165 return rs.getLong(index); 166 case Types.DOUBLE: 167 return rs.getDouble(index); 168 case Types.TIMESTAMP: 169 return getFromResultSetTimestamp(rs, index, column); 170 } 171 throw new SQLException("Unhandled JDBC type: " + column.getJdbcType()); 172 } 173 174 @Override 175 public String getCreateFulltextIndexSql(String indexName, String quotedIndexName, Table table, 176 List<Column> columns, Model model) { 177 throw new UnsupportedOperationException(); 178 } 179 180 @Override 181 public String getDialectFulltextQuery(String query) { 182 throw new UnsupportedOperationException(); 183 } 184 185 @Override 186 public FulltextMatchInfo getFulltextScoredMatchInfo(String fulltextQuery, String indexName, int nthMatch, 187 Column mainColumn, Model model, Database database) { 188 throw new UnsupportedOperationException(); 189 } 190 191 @Override 192 public boolean getMaterializeFulltextSyntheticColumn() { 193 return false; 194 } 195 196 @Override 197 public int getFulltextIndexedColumns() { 198 return 2; 199 } 200 201 @Override 202 public boolean supportsUpdateFrom() { 203 return false; 204 } 205 206 @Override 207 public boolean doesUpdateFromRepeatSelf() { 208 return true; 209 } 210 211 @Override 212 public boolean supportsReadAcl() { 213 return false; 214 } 215 216 @Override 217 public String getUpdateReadAclsSql() { 218 throw new UnsupportedOperationException(); 219 } 220 221 @Override 222 public String getRebuildReadAclsSql() { 223 throw new UnsupportedOperationException(); 224 } 225 226 @Override 227 public String getClobCast(boolean inOrderBy) { 228 if (!inOrderBy) { 229 return "CAST(%s AS VARCHAR)"; 230 } 231 return null; 232 } 233 234 @Override 235 public String getSecurityCheckSql(String idColumnName) { 236 throw new UnsupportedOperationException(); 237 } 238 239 @Override 240 public String getInTreeSql(String idColumnName, String id) { 241 throw new UnsupportedOperationException(); 242 } 243 244 @Override 245 public boolean supportsArrays() { 246 return false; 247 } 248 249 @Override 250 public String getSQLStatementsFilename() { 251 return "nuxeovcs/hsqldb.sql.txt"; // TODO VCS 252 } 253 254 @Override 255 public String getTestSQLStatementsFilename() { 256 return "nuxeovcs/hsqldb.test.sql.txt"; // TODO VCS 257 } 258 259 @Override 260 public Map<String, Serializable> getSQLStatementsProperties(Model model, Database database) { 261 return new HashMap<String, Serializable>(); 262 } 263 264 @Override 265 public boolean isClusteringSupported() { 266 return false; 267 } 268 269 @Override 270 public String getClusterInsertInvalidations() { 271 throw new UnsupportedOperationException(); 272 } 273 274 @Override 275 public String getClusterGetInvalidations() { 276 throw new UnsupportedOperationException(); 277 } 278 279 @Override 280 public boolean supportsPaging() { 281 return true; 282 } 283 284 @SuppressWarnings("boxing") 285 @Override 286 public String addPagingClause(String sql, long limit, long offset) { 287 return sql + String.format(" LIMIT %d OFFSET %d", limit, offset); 288 } 289 290 @Override 291 public List<String> checkStoredProcedure(String procName, String procCreate, String ddlMode, Connection connection, 292 JDBCLogger logger, Map<String, Serializable> properties) throws SQLException { 293 throw new UnsupportedOperationException(); 294 } 295 296}