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 */ 019 020package org.nuxeo.ecm.core.storage.sql.jdbc.db; 021 022import java.io.Serializable; 023import java.sql.PreparedStatement; 024import java.sql.ResultSet; 025import java.sql.SQLException; 026import java.sql.Types; 027import java.util.Calendar; 028 029import org.nuxeo.ecm.core.storage.sql.ColumnType; 030import org.nuxeo.ecm.core.storage.sql.jdbc.dialect.Dialect; 031import org.nuxeo.ecm.core.storage.sql.jdbc.dialect.Dialect.JDBCInfo; 032 033/** 034 * An SQL {@code column}. 035 * 036 * @author Florent Guillaume 037 */ 038public class Column implements Serializable { 039 040 private static final long serialVersionUID = 1L; 041 042 protected final Table table; 043 044 protected final Dialect dialect; 045 046 protected final String physicalName; 047 048 private final String quotedName; 049 050 private final String freeVariableSetter; 051 052 /** The abstract type. */ 053 private final ColumnType type; 054 055 /** 056 * The JDBC {@link java.sql.Types} type. Used for: - comparison with database introspected type - switch() to get 057 * from result set or set to prepared statement - setNull to prepared statement 058 */ 059 private int jdbcType; 060 061 /** The JDBC type string. */ 062 private final String jdbcTypeString; 063 064 /* 065 * {@see java.sql.Array.getBaseType() value is 0 if this is not an array column 066 */ 067 private int jdbcBaseType; 068 069 /* 070 * {@see java.sql.Array.getBaseTypeName() value is null if this is not an array column 071 */ 072 private final String jdbcBaseTypeString; 073 074 private final String key; 075 076 private boolean identity; 077 078 private boolean primary; 079 080 private boolean nullable = true; 081 082 private String defaultValue; 083 084 /** For foreign key reference. */ 085 private Table foreignTable; 086 087 private String foreignKey; 088 089 /** 090 * Creates a new column with the given name and type. 091 * 092 * @param table the column's table 093 * @param physicalName the column physical name 094 * @param type the column's type 095 * @param key the associated field name 096 */ 097 public Column(Table table, String physicalName, ColumnType type, String key) { 098 this.table = table; 099 dialect = table.getDialect(); 100 this.physicalName = physicalName; 101 this.type = type; 102 JDBCInfo jdbcInfo = dialect.getJDBCTypeAndString(type); 103 jdbcType = jdbcInfo.jdbcType; 104 jdbcTypeString = jdbcInfo.string; 105 jdbcBaseType = jdbcInfo.jdbcBaseType; 106 jdbcBaseTypeString = jdbcInfo.jdbcBaseTypeString; 107 this.key = key; 108 quotedName = dialect.openQuote() + physicalName + dialect.closeQuote(); 109 freeVariableSetter = dialect.getFreeVariableSetterForType(type); 110 } 111 112 /** 113 * Creates a column from an existing column and an aliased table. 114 */ 115 public Column(Column column, Table table) { 116 this(table, column.physicalName, column.type, column.key); 117 } 118 119 public Table getTable() { 120 return table; 121 } 122 123 public String getPhysicalName() { 124 return physicalName; 125 } 126 127 public String getQuotedName() { 128 return quotedName; 129 } 130 131 public String getFullQuotedName() { 132 return table.getQuotedName() + '.' + quotedName; 133 } 134 135 public int getJdbcType() { 136 return jdbcType; 137 } 138 139 public int getJdbcBaseType() { 140 return jdbcBaseType; 141 } 142 143 public ColumnType getType() { 144 return type; 145 } 146 147 public ColumnType getBaseType() { 148 ColumnType baseType; 149 if (type == ColumnType.ARRAY_BLOBID) { 150 baseType = ColumnType.BLOBID; 151 } else if (type == ColumnType.ARRAY_BOOLEAN) { 152 baseType = ColumnType.BOOLEAN; 153 } else if (type == ColumnType.ARRAY_CLOB) { 154 baseType = ColumnType.CLOB; 155 } else if (type == ColumnType.ARRAY_DOUBLE) { 156 baseType = ColumnType.DOUBLE; 157 } else if (type == ColumnType.ARRAY_INTEGER) { 158 baseType = ColumnType.INTEGER; 159 } else if (type == ColumnType.ARRAY_LONG) { 160 baseType = ColumnType.LONG; 161 } else if (type == ColumnType.ARRAY_STRING) { 162 baseType = ColumnType.STRING; 163 } else if (type == ColumnType.ARRAY_TIMESTAMP) { 164 baseType = ColumnType.TIMESTAMP; 165 } else { 166 baseType = type; 167 } 168 return baseType; 169 } 170 171 public String getFreeVariableSetter() { 172 return freeVariableSetter; 173 } 174 175 public boolean isArray() { 176 return type.isArray(); 177 } 178 179 public boolean isOpaque() { 180 return type == ColumnType.FTINDEXED || type == ColumnType.FTSTORED; 181 } 182 183 public boolean setJdbcType(int actual, String actualName, int actualSize) { 184 int expected = jdbcType; 185 if (actual == expected) { 186 return true; 187 } 188 if (dialect.isAllowedConversion(expected, actual, actualName, actualSize)) { 189 return true; 190 } 191 return false; 192 } 193 194 public String getKey() { 195 return key; 196 } 197 198 public void setIdentity(boolean identity) { 199 this.identity = identity; 200 } 201 202 public boolean isIdentity() { 203 return identity; 204 } 205 206 public void setPrimary(boolean primary) { 207 this.primary = primary; 208 } 209 210 public boolean isPrimary() { 211 return primary; 212 } 213 214 public void setNullable(boolean nullable) { 215 this.nullable = nullable; 216 } 217 218 public boolean isNullable() { 219 return nullable; 220 } 221 222 public String getDefaultValue() { 223 return defaultValue; 224 } 225 226 public void setDefaultValue(String defaultValue) { 227 this.defaultValue = defaultValue; 228 } 229 230 public void setReferences(Table foreignTable, String foreignKey) { 231 this.foreignTable = foreignTable; 232 this.foreignKey = foreignKey; 233 } 234 235 public Table getForeignTable() { 236 return foreignTable; 237 } 238 239 public String getForeignKey() { 240 return foreignKey; 241 } 242 243 public String getSqlTypeString() { 244 return jdbcTypeString; 245 } 246 247 public String getSqlBaseTypeString() { 248 return jdbcBaseTypeString; 249 } 250 251 public void setToPreparedStatement(PreparedStatement ps, int index, Serializable value) throws SQLException { 252 if (value == null) { 253 ps.setNull(index, jdbcType); 254 return; 255 } 256 if ((jdbcType == Types.ARRAY) && !(value instanceof Object[])) { 257 throw new SQLException("Expected an array value instead of: " + value); 258 } 259 dialect.setToPreparedStatement(ps, index, value, this); 260 } 261 262 public Serializable getFromResultSet(ResultSet rs, int index) throws SQLException { 263 Serializable result = dialect.getFromResultSet(rs, index, this); 264 if (rs.wasNull()) { 265 result = null; 266 } 267 return result; 268 } 269 270 @Override 271 public String toString() { 272 return getClass().getSimpleName() + '(' + physicalName + ')'; 273 } 274 275}