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