org.datanucleus.store.rdbms.table.ColumnImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of datanucleus-rdbms Show documentation
Show all versions of datanucleus-rdbms Show documentation
Plugin for DataNucleus providing persistence to RDBMS datastores.
The newest version!
/**********************************************************************
Copyright (c) 2002 Kelly Grizzle (TJDO) and others. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Contributors:
2003 Erik Bengtson - added a replaceAll operation in substitution for
java.lang.String.replaceAll of J2SDK 1.4. Now we
can compile with J2SDK 1.3.1
2003 Erik Bengtson - moved replaceAll to StringUtils class
2003 Andy Jefferson - updated the DEFAULT_MAX_STRING_LENGTH to be controllable
via a property.
2004 Andy Jefferson - updated the NULL/NOT NULL so that we always specify the
nullability of a column on creation
2004 Erik Bengtson - added columnOptions getters that can be read by
the SetTable or MapTable (Collection). columnOptions is
used for create an equivalent column on the set table
2004 Andy Jefferson - added Auto, Unique, Default, options to column SQL options
2006 Andy Jefferson - removed co, dba, lengthType, copying of ColumnMetaData
2008 Andy Jefferson - changed to implement interface, use byte "flags", cleanup
...
**********************************************************************/
package org.datanucleus.store.rdbms.table;
import java.sql.DatabaseMetaData;
import java.sql.Types;
import java.util.StringTokenizer;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.ColumnMetaData;
import org.datanucleus.metadata.JdbcType;
import org.datanucleus.store.rdbms.adapter.DatastoreAdapter;
import org.datanucleus.store.rdbms.exceptions.ColumnDefinitionException;
import org.datanucleus.store.rdbms.RDBMSPropertyNames;
import org.datanucleus.store.rdbms.RDBMSStoreManager;
import org.datanucleus.store.rdbms.exceptions.IncompatibleDataTypeException;
import org.datanucleus.store.rdbms.exceptions.WrongPrecisionException;
import org.datanucleus.store.rdbms.exceptions.WrongScaleException;
import org.datanucleus.store.rdbms.identifier.DatastoreIdentifier;
import org.datanucleus.store.rdbms.mapping.column.ColumnMapping;
import org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping;
import org.datanucleus.store.rdbms.schema.RDBMSColumnInfo;
import org.datanucleus.store.rdbms.schema.SQLTypeInfo;
import org.datanucleus.store.schema.naming.ColumnType;
import org.datanucleus.store.schema.table.MemberColumnMapping;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.StringUtils;
/**
* Implementation of a Column in an RDBMS datastore.
* Contains the full definition of the column, its type, size, whether it is identity, nullable, part of the PK etc.
* The SQL column definition is generated here.
*/
public class ColumnImpl implements Column
{
private static final byte PK = (byte) (1<<0); // Part of PK?
private static final byte NULLABLE = (byte) (1<<1); // Column can store nulls?
private static final byte UNIQUE = (byte) (1<<2); // Values are unique?
private static final byte DEFAULTABLE = (byte) (1<<3); // Defaultable column on inserts?
private static final byte IDENTITY = (byte) (1<<4); // AUTO_INCREMENT, SERIAL etc?
/** Identifier for the column in the datastore. */
protected DatastoreIdentifier identifier;
/** ColumnMetaData for this column. */
protected ColumnMetaData columnMetaData;
/** Table containing this column in the datastore. */
protected final Table table;
/** Mapping for this column. */
protected ColumnMapping columnMapping = null;
/** Java type that this column is storing. (can we just get this from the mapping above ?) */
protected final String storedJavaType;
/** Manual override of the type name for this column (optional). */
protected String typeName;
/** SQL Type info for the JDBC type being stored in this column */
protected SQLTypeInfo typeInfo;
/** CHECK constraints to apply to this column in its SQL specification (optional). */
protected String checkConstraints;
/** Operational flags, for nullability, PK, autoinc, etc. */
protected byte flags;
/** Default value accepted by the datastore for this column, from DatabaseMetaData. */
protected Object defaultValue;
/** Function wrapping the column (for example, SQRT(COLUMN)). */
protected String[] wrapperFunction;
/**
* Constructor.
* @param table The table in the datastore that this column belongs to.
* @param javaType The type of data being stored in this column
* @param identifier The identifier of the column (in the datastore).
* @param colmd The ColumnMetaData for this column
*/
public ColumnImpl(Table table, String javaType, DatastoreIdentifier identifier, ColumnMetaData colmd)
{
this.table = table;
this.storedJavaType = javaType;
typeInfo = null;
checkConstraints = null;
flags = 0;
setIdentifier(identifier);
if (colmd == null)
{
// Create a default ColumnMetaData since none provided
columnMetaData = new ColumnMetaData();
}
else
{
// TODO Consider making a copy here
columnMetaData = colmd;
}
// Nullability
if (columnMetaData.getAllowsNull() != null && columnMetaData.isAllowsNull())
{
// MetaData requires it to be nullable
setNullable(true);
}
// Uniqueness
if (columnMetaData.getUnique())
{
// MetaData requires it to be unique
setUnique(true);
}
wrapperFunction = new String[3];
wrapperFunction[WRAPPER_FUNCTION_SELECT]= "?";
wrapperFunction[WRAPPER_FUNCTION_INSERT]= "?";
wrapperFunction[WRAPPER_FUNCTION_UPDATE]= "?";
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#getName()
*/
@Override
public String getName()
{
return identifier.toString();
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#getMemberColumnMapping()
*/
@Override
public MemberColumnMapping getMemberColumnMapping()
{
throw new UnsupportedOperationException("Not supported on this Column");
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#getColumnType()
*/
@Override
public ColumnType getColumnType()
{
throw new UnsupportedOperationException("Not supported on this Column");
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#setJdbcType(org.datanucleus.metadata.JdbcType)
*/
@Override
public Column setJdbcType(JdbcType jdbcType)
{
throw new UnsupportedOperationException("Not supported on this Column");
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#getJdbcType()
*/
@Override
public JdbcType getJdbcType()
{
return typeInfo != null ? JdbcType.getEnumByValue(typeInfo.getDataType()) : null;
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#setTypeName(java.lang.String)
*/
@Override
public Column setTypeName(String type)
{
this.typeName = type;
return this;
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#getTypeName()
*/
@Override
public String getTypeName()
{
return (typeName != null) ? typeName : typeInfo.getTypeName();
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#setPosition(int)
*/
@Override
public Column setPosition(int pos)
{
throw new UnsupportedOperationException("Not supported on this Column");
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#getPosition()
*/
@Override
public int getPosition()
{
throw new UnsupportedOperationException("Not supported on this Column");
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#isUnlimitedLength()
*/
public boolean isUnlimitedLength()
{
// TODO Enable the two commented out lines so that we can allow people to have "BLOB(1024)" etc
if (columnMetaData.getJdbcType() != null && (columnMetaData.getJdbcType() == JdbcType.BLOB || columnMetaData.getJdbcType() == JdbcType.CLOB)/* &&
!typeInfo.isAllowsPrecisionSpec()*/)
{
// Allow for jdbc-type=BLOB/CLOB
return true;
}
else if (columnMetaData.getSqlType() != null && columnMetaData.getSqlType().toLowerCase().indexOf("lob") > 0/* &&
!typeInfo.isAllowsPrecisionSpec()*/)
{
// Allow for sql-type=BLOB/CLOB
return true;
}
return false;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getIdentifier()
*/
public DatastoreIdentifier getIdentifier()
{
return identifier;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#setIdentifier(org.datanucleus.store.rdbms.DatastoreIdentifier)
*/
public void setIdentifier(DatastoreIdentifier identifier)
{
this.identifier = identifier;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getTable()
*/
public Table getTable()
{
return table;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getColumnMapping()
*/
public ColumnMapping getColumnMapping()
{
return columnMapping;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#setColumnMapping(org.datanucleus.store.rdbms.mapping.column.ColumnMapping)
*/
public void setColumnMapping(ColumnMapping mapping)
{
columnMapping = mapping;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getJavaTypeMapping()
*/
public JavaTypeMapping getJavaTypeMapping()
{
return columnMapping.getJavaTypeMapping();
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getStoredJavaType()
*/
public String getStoredJavaType()
{
return storedJavaType;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#setTypeInfo(org.datanucleus.store.rdbms.schema.SQLTypeInfo)
*/
public final Column setTypeInfo(SQLTypeInfo typeInfo)
{
if (this.typeInfo == null)
{
this.typeInfo = typeInfo;
}
return this;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getTypeInfo()
*/
public final SQLTypeInfo getTypeInfo()
{
return typeInfo;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getStoreManager()
*/
public RDBMSStoreManager getStoreManager()
{
return table.getStoreManager();
}
/**
* Accessor for the precision of data in the column.
* @return The precision of data in the column
*/
private int getSQLPrecision()
{
int sqlPrecision = - 1;
if (columnMetaData.getLength() != null && columnMetaData.getLength().intValue() > 0)
{
// User-provided length, so use it
sqlPrecision = columnMetaData.getLength().intValue();
}
else if (isUnlimitedLength())
{
// Use the precision for "unlimited length" if defined
int ulpv = getStoreManager().getDatastoreAdapter().getUnlimitedLengthPrecisionValue(typeInfo);
if (ulpv > 0)
{
sqlPrecision = ulpv;
}
}
// Databases like Derby that use BIT types for binary need to have the length expressed in bits, not bytes.
if (typeInfo.getTypeName().toLowerCase().startsWith("bit"))
{
return sqlPrecision * 8;
}
return sqlPrecision;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getSQLDefinition()
*/
public String getSQLDefinition()
{
StringBuilder def = new StringBuilder(identifier.toString());
if (!StringUtils.isWhitespace(columnMetaData.getColumnDdl()))
{
// User-defined DDL, so assume they set the type etc to something sensible
// Note that the JPA spec doesn't explicitly specify if this has to include the type or not
def.append(" ").append(columnMetaData.getColumnDdl());
return def.toString();
}
DatastoreAdapter adapter = getStoreManager().getDatastoreAdapter();
// Add any type specification.
if (adapter.supportsOption(DatastoreAdapter.IDENTITY_COLUMNS) && isIdentity() && !adapter.supportsOption(DatastoreAdapter.IDENTITY_COLUMN_TYPE_SPECIFICATION))
{
// Don't add type
}
else if (typeName != null)
{
// Allow for manual override of "type" for things like MySQL ENUM where we want to define the type with its options
def.append(" " + typeName);
}
else
{
StringBuilder typeSpec = new StringBuilder(typeInfo.getTypeName());
// Parse and append createParams to the typeName if it looks like it's supposed to be appended,
// i.e. if it contains parentheses, and the type name itself doesn't. createParams is mighty ill-defined by the JDBC spec, but attempt to interpret it.
if (typeInfo.getCreateParams() != null && typeInfo.getCreateParams().indexOf('(') >= 0 && typeInfo.getTypeName().indexOf('(') < 0)
{
StringTokenizer toks = new StringTokenizer(typeInfo.getCreateParams());
while (toks.hasMoreTokens())
{
String tok = toks.nextToken();
if (tok.startsWith("[") && tok.endsWith("]"))
{
// The brackets look like they indicate an optional param so
// skip
continue;
}
typeSpec.append(" " + tok);
}
}
// Add any precision. We use the "allowsPrecisionSpec" flag for this
StringBuilder precSpec = new StringBuilder();
int sqlPrecision = getSQLPrecision();
if (sqlPrecision > 0 && typeInfo.isAllowsPrecisionSpec())
{
precSpec.append(sqlPrecision);
// Optional "scale" for the precision e.g BIGDECIMAL(8,3)
if (columnMetaData.getScale() != null)
{
precSpec.append("," + columnMetaData.getScale());
}
// Optional "type" for the precision, where the database supports it
if (adapter.supportsOption(DatastoreAdapter.COLUMN_LENGTH_SEMANTICS))
{
if (columnMetaData.hasExtension("column-length-semantic"))
{
precSpec.append(" " + columnMetaData.getValueForExtension("column-length-semantic"));
}
}
}
else if (sqlPrecision > 0 && !typeInfo.isAllowsPrecisionSpec())
{
NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("020183", this.toString()));
}
int lParenIdx = typeSpec.toString().indexOf('(');
int rParenIdx = typeSpec.toString().indexOf(')', lParenIdx);
if (lParenIdx > 0 && rParenIdx > 0)
{
// Some databases (like DB2) give you typeNames with ()'s already
// present ready for you to insert the values instead of appending them.
if (precSpec.length() > 0)
{
typeSpec.replace(lParenIdx + 1, rParenIdx, precSpec.toString());
}
else if (rParenIdx == lParenIdx + 1)
{
throw new ColumnDefinitionException(Localiser.msg("020184", this.toString()));
}
}
else if (precSpec.length() > 0)
{
typeSpec.append('(');
typeSpec.append(precSpec.toString());
typeSpec.append(')');
}
def.append(" " + typeSpec.toString());
}
// Add DEFAULT (if specifiable before NULL)
if (adapter.supportsOption(DatastoreAdapter.DEFAULT_BEFORE_NULL_IN_COLUMN_OPTIONS) &&
adapter.supportsOption(DatastoreAdapter.DEFAULT_KEYWORD_IN_COLUMN_OPTIONS) &&
columnMetaData.getDefaultValue() != null)
{
def.append(" ").append(getDefaultDefinition());
}
if (isIdentity() && isPrimaryKey() && adapter.supportsOption(DatastoreAdapter.IDENTITY_PK_IN_CREATE_TABLE_COLUMN_DEF))
{
def.append(" PRIMARY KEY");
}
// Nullability
if (adapter.supportsOption(DatastoreAdapter.IDENTITY_COLUMNS) && isIdentity() && !adapter.supportsOption(DatastoreAdapter.IDENTITY_KEYS_NULL_SPECIFICATION))
{
// Do nothing since the adapter doesn't allow NULL specifications with autoincrement/identity
}
else
{
if (!isNullable())
{
if (columnMetaData.getDefaultValue() == null || adapter.supportsOption(DatastoreAdapter.DEFAULT_KEYWORD_WITH_NOT_NULL_IN_COLUMN_OPTIONS))
{
def.append(" NOT NULL");
}
}
else if (typeInfo.getNullable() == DatabaseMetaData.columnNullable)
{
if (adapter.supportsOption(DatastoreAdapter.NULLS_KEYWORD_IN_COLUMN_OPTIONS))
{
def.append(" NULL");
}
}
}
// Add DEFAULT (if specifiable after NULL)
if (!adapter.supportsOption(DatastoreAdapter.DEFAULT_BEFORE_NULL_IN_COLUMN_OPTIONS) &&
adapter.supportsOption(DatastoreAdapter.DEFAULT_KEYWORD_IN_COLUMN_OPTIONS) &&
columnMetaData.getDefaultValue() != null)
{
def.append(" ").append(getDefaultDefinition());
}
// CHECK Constraints
if (adapter.supportsOption(DatastoreAdapter.CHECK_IN_CREATE_STATEMENTS) && checkConstraints != null)
{
def.append(" " + checkConstraints.toString());
}
// Auto Increment
if (adapter.supportsOption(DatastoreAdapter.IDENTITY_COLUMNS) && isIdentity())
{
def.append(" " + adapter.getIdentityKeyword(table.getStoreManager(), columnMapping));
}
// Uniqueness
if (isUnique() && !adapter.supportsOption(DatastoreAdapter.UNIQUE_IN_END_CREATE_STATEMENTS))
{
def.append(" UNIQUE");
}
return def.toString();
}
/**
* Convenience method to return the "DEFAULT" part of the column definition.
* @return The default part of the column definition.
*/
private String getDefaultDefinition()
{
if (columnMetaData.getDefaultValue().equalsIgnoreCase("#NULL"))
{
// Special case
// Note that this really ought to be coordinated with "DEFAULT_KEYWORD_WITH_NOT_NULL_IN_COLUMN_OPTIONS"
this.defaultValue = null;
return "DEFAULT NULL";
}
// Quote any character types (CHAR, VARCHAR, BLOB, CLOB)
if (typeInfo.getTypeName().toUpperCase().indexOf("CHAR") >= 0 || typeInfo.getTypeName().toUpperCase().indexOf("LOB") >= 0)
{
// NOTE We use single quote here but would be better to take
// some character from the DatabaseMetaData. The "identifierQuoteString"
// does not work for string quoting here for Postgres
this.defaultValue = columnMetaData.getDefaultValue();
return "DEFAULT '" + columnMetaData.getDefaultValue() + "'";
}
else if (typeInfo.getTypeName().toUpperCase().indexOf("BIT") == 0)
{
if (columnMetaData.getDefaultValue().equalsIgnoreCase("true") || columnMetaData.getDefaultValue().equalsIgnoreCase("false"))
{
// Quote any "true"/"false" values for BITs
this.defaultValue = columnMetaData.getDefaultValue();
return "DEFAULT '" + columnMetaData.getDefaultValue() + "'";
}
}
this.defaultValue = columnMetaData.getDefaultValue();
return "DEFAULT " + columnMetaData.getDefaultValue();
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#initializeColumnInfoFromDatastore(org.datanucleus.store.rdbms.schema.RDBMSColumnInfo)
*/
public void initializeColumnInfoFromDatastore(RDBMSColumnInfo ci)
{
String column_default = ci.getColumnDef();
if (!StringUtils.isWhitespace(column_default))
{
// Set column defaultValue using defaultValue defined on the datastore column
if (column_default.startsWith("'") && column_default.endsWith("'"))
{
// JDBC javadoc, if starts with single quotes then is a string
String colDefString = column_default.replace("'", "");
setDefaultable(colDefString);
}
else
{
if (!column_default.equalsIgnoreCase("null"))
{
// Non-null value so use it (null is the default so don't need that)
String columnDef = column_default.replace("'", "").replace("\"", "").replace(")", "").replace("(", "");
if (!columnDef.equalsIgnoreCase("null"))
{
setDefaultable(columnDef);
}
}
}
}
// TODO Make sure that this lines up with the defaultValue when set.
try
{
setIdentity(getStoreManager().getDatastoreAdapter().isIdentityFieldDataType(ci.getColumnDef()));
}
catch( UnsupportedOperationException ex)
{
//do nothing, or maybe log
}
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#validate(org.datanucleus.store.rdbms.schema.RDBMSColumnInfo)
*/
public void validate(RDBMSColumnInfo ci)
{
if (!typeInfo.isCompatibleWith(ci))
{
throw new IncompatibleDataTypeException(this, typeInfo.getDataType(), ci.getDataType());
}
if (ci.getDataType() == Types.OTHER)
{
return;
}
if (table instanceof TableImpl)
{
// Only validate precision/scale/nullability for tables
if (typeInfo.isAllowsPrecisionSpec())
{
int actualPrecision = ci.getColumnSize();
int actualScale = ci.getDecimalDigits();
int sqlPrecision = getSQLPrecision();
if (sqlPrecision > 0 && actualPrecision > 0)
{
if (sqlPrecision != actualPrecision)
{
if (this.columnMetaData != null && this.columnMetaData.getParent() != null &&
(this.columnMetaData.getParent() instanceof AbstractMemberMetaData))
{
//includes the field name in error msg
throw new WrongPrecisionException(this.toString(), sqlPrecision,
actualPrecision,
((AbstractMemberMetaData)this.columnMetaData.getParent()).getFullFieldName());
}
throw new WrongPrecisionException(this.toString(), sqlPrecision, actualPrecision);
}
}
if (this.columnMetaData != null && columnMetaData.getScale() != null && actualScale >= 0)
{
if (columnMetaData.getScale().intValue() != actualScale)
{
if (this.columnMetaData.getParent() != null && this.columnMetaData.getParent() instanceof AbstractMemberMetaData)
{
//includes the field name in error msg
throw new WrongScaleException(this.toString(), columnMetaData.getScale().intValue(), actualScale,
((AbstractMemberMetaData)this.columnMetaData.getParent()).getFullFieldName());
}
throw new WrongScaleException(this.toString(), columnMetaData.getScale().intValue(), actualScale);
}
}
}
String actualIsNullable = ci.getIsNullable();
if (actualIsNullable.length() > 0)
{
switch (Character.toUpperCase(actualIsNullable.charAt(0)))
{
case 'Y' :
if (!isNullable())
{
NucleusLogger.DATASTORE.warn(Localiser.msg("020025", this));
}
break;
case 'N' :
// TODO convert to default value somewhere at runtime if
// column has a default value and "default"
break;
default :
break;
}
}
try
{
if (isIdentity() != getStoreManager().getDatastoreAdapter().isIdentityFieldDataType(ci.getColumnDef()))
{
//TODO localise
if (isIdentity())
{
throw new NucleusException("Expected an auto increment column ("+getIdentifier()+
") in the database, but it is not").setFatal();
}
throw new NucleusException("According to the user metadata, the column ("+
getIdentifier()+") is not auto incremented, but the database says it is.").setFatal();
}
}
catch (UnsupportedOperationException ex)
{
//ignore this validation step
}
}
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#setCheckConstraints(java.lang.String)
*/
public final Column setCheckConstraints(String constraints)
{
this.checkConstraints = constraints;
return this;
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#setPrimaryKey()
*/
public final Column setPrimaryKey()
{
flags |= PK;
//primary keys cannot be null
flags &= ~NULLABLE;
return this;
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#setNullable(boolean)
*/
public final Column setNullable(boolean flag)
{
if (flag)
{
flags |= NULLABLE;
}
else
{
flags &= ~NULLABLE;
}
return this;
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#setDefaultable(java.lang.Object)
*/
public final Column setDefaultable(Object defaultValue)
{
if (!getStoreManager().getBooleanProperty(RDBMSPropertyNames.PROPERTY_RDBMS_COLUMN_DEFAULT_WHEN_NULL))
{
return this;
}
flags |= DEFAULTABLE;
this.defaultValue = defaultValue;
return this;
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#setUnique(boolean)
*/
public final Column setUnique(boolean flag)
{
if (flag)
{
flags |= UNIQUE;
}
else
{
flags &= ~UNIQUE;
}
return this;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#setIdentity(boolean)
*/
public Column setIdentity(boolean identity)
{
if (identity)
{
flags |= IDENTITY;
}
else
{
flags &= ~IDENTITY;
}
return this;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#isPrimaryKey()
*/
public final boolean isPrimaryKey()
{
return ((flags & PK) != 0);
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#isNullable()
*/
public final boolean isNullable()
{
return ((flags & NULLABLE) != 0);
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#isDefaultable()
*/
public final boolean isDefaultable()
{
return ((flags & DEFAULTABLE) != 0);
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#isUnique()
*/
public final boolean isUnique()
{
return ((flags & UNIQUE) != 0);
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#isIdentity()
*/
public boolean isIdentity()
{
return ((flags & IDENTITY) != 0);
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getDefaultValue()
*/
public Object getDefaultValue()
{
return defaultValue;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getColumnMetaData()
*/
public final ColumnMetaData getColumnMetaData()
{
return columnMetaData;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getFieldMetaData()
*/
public AbstractMemberMetaData getMemberMetaData()
{
if (columnMetaData != null && columnMetaData.getParent() instanceof AbstractMemberMetaData)
{
return (AbstractMemberMetaData)columnMetaData.getParent();
}
return null;
}
/* (non-Javadoc)
* @see org.datanucleus.store.schema.table.Column#setColumnMetaData(org.datanucleus.metadata.ColumnMetaData)
*/
public Column setColumnMetaData(ColumnMetaData colmd)
{
if (colmd == null)
{
// Nothing to do since no definition of requirements
return this;
}
if (colmd.getJdbcType() != null)
{
columnMetaData.setJdbcType(colmd.getJdbcType());
}
if (colmd.getSqlType() != null)
{
columnMetaData.setSqlType(colmd.getSqlType());
}
if (colmd.getName() != null)
{
columnMetaData.setName(colmd.getName());
}
if (colmd.getAllowsNull() != null)
{
columnMetaData.setAllowsNull(Boolean.valueOf(colmd.isAllowsNull()));
}
if (colmd.getLength() != null)
{
columnMetaData.setLength(colmd.getLength());
}
if (colmd.getScale() != null)
{
columnMetaData.setScale(colmd.getScale());
}
if (colmd.getAllowsNull() != null && colmd.isAllowsNull())
{
// MetaData requires it to be nullable
setNullable(true);
}
if (colmd.getUnique())
{
// MetaData requires it to be unique
setUnique(true);
}
return this;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getCheckConstraints()
*/
public String getCheckConstraints()
{
return checkConstraints;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#checkPrimitive()
*/
public final void checkPrimitive() throws ColumnDefinitionException
{
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#checkInteger()
*/
public final void checkInteger() throws ColumnDefinitionException
{
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#checkDecimal()
*/
public final void checkDecimal() throws ColumnDefinitionException
{
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#checkString()
*/
public final void checkString() throws ColumnDefinitionException
{
if (columnMetaData.getJdbcType() == null)
{
columnMetaData.setJdbcType(JdbcType.VARCHAR);
}
if (columnMetaData.getLength() == null)
{
// Use the default string length
columnMetaData.setLength(getStoreManager().getIntProperty(RDBMSPropertyNames.PROPERTY_RDBMS_STRING_DEFAULT_LENGTH));
}
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#copyConfigurationTo(org.datanucleus.store.rdbms.table.Column)
*/
public void copyConfigurationTo(Column colIn)
{
ColumnImpl col = (ColumnImpl) colIn;
col.typeInfo = this.typeInfo;
col.typeName = this.typeName;
col.flags |= this.flags;
col.flags &= ~PK;
col.flags &= ~UNIQUE;
col.flags &= ~NULLABLE;
col.flags &= ~IDENTITY;
col.flags &= ~DEFAULTABLE;
col.defaultValue = this.defaultValue;
col.wrapperFunction = this.wrapperFunction;
// Copy key aspects of ColumnMetaData across. May need to copy other parts in future
if (this.columnMetaData.getJdbcType() != null)
{
col.columnMetaData.setJdbcType(this.columnMetaData.getJdbcType());
}
if (this.columnMetaData.getSqlType() != null)
{
col.columnMetaData.setSqlType(this.columnMetaData.getSqlType());
}
if (this.columnMetaData.getLength() != null)
{
col.getColumnMetaData().setLength(this.columnMetaData.getLength());
}
if (this.columnMetaData.getScale() != null)
{
col.getColumnMetaData().setScale(this.getColumnMetaData().getScale());
}
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#applySelectFunction(java.lang.String)
*/
public String applySelectFunction(String replacementValue)
{
if (replacementValue == null)
{
return wrapperFunction[WRAPPER_FUNCTION_SELECT];
}
if (wrapperFunction[WRAPPER_FUNCTION_SELECT] != null)
{
return wrapperFunction[WRAPPER_FUNCTION_SELECT].replace("?", replacementValue);
}
return replacementValue;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#setWrapperFunction(java.lang.String, int)
*/
public void setWrapperFunction(String wrapperFunction, int wrapperMode)
{
if (wrapperFunction != null && wrapperMode == WRAPPER_FUNCTION_SELECT && wrapperFunction.indexOf("?") < 0)
{
throw new NucleusUserException("Wrapping function must have one '?'. e.g. SQRT(?)");
}
this.wrapperFunction[wrapperMode] = wrapperFunction;
}
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.table.Column#getWrapperFunction(int)
*/
public String getWrapperFunction(int wrapperMode)
{
return wrapperFunction[wrapperMode];
}
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (!(obj instanceof ColumnImpl))
{
return false;
}
ColumnImpl col = (ColumnImpl)obj;
return table.equals(col.table) && identifier.equals(col.identifier);
}
public int hashCode()
{
return table.hashCode() ^ identifier.hashCode();
}
public String toString()
{
return table.toString() + "." + identifier;
}
}