in openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingInfo.java [650:832]
protected static Column mergeColumn(MetaDataContext context, String prefix,
Column tmplate, boolean compat, Column given, Table table,
boolean adapt, boolean fill) {
assertTable(context, table);
// if not adapting must provide column name at a minimum
DBIdentifier colName = (given == null) ? DBIdentifier.NULL : given.getIdentifier();
if (DBIdentifier.isNull(colName) && !adapt && !fill)
throw new MetaDataException(_loc.get(prefix + "-no-col-name",
context));
MappingRepository repos = (MappingRepository) context.getRepository();
DBDictionary dict = repos.getDBDictionary();
// determine the column name based on given info, or template if none;
// also make sure that if the user gave a column name, he didn't try
// to put the column in an unexpected table
if (DBIdentifier.isNull(colName))
colName = tmplate.getIdentifier();
QualifiedDBIdentifier path = QualifiedDBIdentifier.getPath(colName);
if (path.isUnqualifiedColumn()) {
colName = path.getIdentifier();
} else if (!DBIdentifier.isNull(path.getObjectTableName())) {
findTable(context, path.getObjectTableName(), table,
null, null);
colName = path.getUnqualifiedName();
}
// find existing column
Column col = table.getColumn(colName);
if (col == null && !adapt) {
//
// See if column name has already been validated in a dynamic table.
// If so then want to use that validated column name instead. This
// should seldom if ever occur as long as the database dictionaries
// are kept up-to-date.
//
if ((colName.getName().length() > dict.maxColumnNameLength) ||
dict.getInvalidColumnWordSet().contains(DBIdentifier.toUpper(colName).getName()) &&
!(table.getClass().getName().contains("DynamicTable"))) {
colName=dict.getValidColumnName(colName, new Table());
col = table.getColumn(colName);
if (col == null && !adapt) {
throw new MetaDataException(_loc.
get(prefix + "-bad-col-name", context, colName, table));
}
}
else {
throw new MetaDataException(_loc.
get(prefix + "-bad-col-name", context, colName, table));
}
}
// use information from template column by default, allowing any
// user-given specifics to override it
int type = tmplate.getType();
int size = tmplate.getSize();
if (type == Types.OTHER) {
int precis = 0;
int scale = 0;
if(given != null) {
precis = given.getSize();
scale = given.getDecimalDigits();
}
type =
dict.getJDBCType(tmplate.getJavaType(), size == -1, precis,
scale, tmplate.isXML());
}
boolean ttype = true;
int otype = type;
String typeName = tmplate.getTypeName();
Boolean notNull = null;
if (tmplate.isNotNullExplicit())
notNull = (tmplate.isNotNull()) ? Boolean.TRUE : Boolean.FALSE;
int decimals = tmplate.getDecimalDigits();
String defStr = tmplate.getDefaultString();
boolean autoAssign = tmplate.isAutoAssigned();
boolean relationId = tmplate.isRelationId();
boolean implicitRelation = tmplate.isImplicitRelation();
String targetField = tmplate.getTargetField();
if (given != null) {
// use given type if provided, but warn if it isn't compatible with
// the expected column type
if (given.getType() != Types.OTHER) {
ttype = false;
if (compat && !given.isCompatible(type, typeName, size,
decimals)) {
Log log = repos.getLog();
if (log.isWarnEnabled())
log.warn(_loc.get(prefix + "-incompat-col",
context, colName, Schemas.getJDBCName(type)));
}
otype = given.getType();
type = dict.getPreferredType(otype);
}
typeName = given.getTypeName();
if (given.getSize() > 0)
size = given.getSize();
decimals = given.getDecimalDigits();
// leave this info as the template defaults unless the user
// explicitly turns it on in the given column
if (given.isNotNullExplicit())
notNull = (given.isNotNull()) ? Boolean.TRUE : Boolean.FALSE;
if (given.getDefaultString() != null)
defStr = given.getDefaultString();
if (given.isAutoAssigned())
autoAssign = true;
if (given.isRelationId())
relationId = true;
if (given.isImplicitRelation())
implicitRelation = true;
}
// default char column size if original type is char (test original
// type rather than final type because orig might be clob, translated
// to an unsized varchar, which is supported by some dbs)
if (size == 0 && (otype == Types.VARCHAR || otype == Types.CHAR))
size = dict.characterColumnSize;
// create column, or make sure existing column matches expected type
if (col == null) {
col = table.addColumn(colName);
col.setType(type);
} else if ((compat || !ttype) &&
!col.isCompatible(type, typeName, size, decimals)) {
// if existing column isn't compatible with desired type, die if
// can't adapt, else warn and change the existing column type
Message msg = _loc.get(prefix + "-bad-col", context,
Schemas.getJDBCName(type), col.getDescription());
if (!adapt && !dict.disableSchemaFactoryColumnTypeErrors)
throw new MetaDataException(msg);
Log log = repos.getLog();
if (log.isWarnEnabled())
log.warn(msg);
col.setType(type);
} else if (given != null && given.getType() != Types.OTHER) {
// as long as types are compatible, set column to expected type
col.setType(type);
}
// always set the java type and autoassign to expected values, even on
// an existing column, since we don't get this from the DB
if (compat)
col.setJavaType(tmplate.getJavaType());
else if (col.getJavaType() == JavaTypes.OBJECT) {
if (given != null && given.getJavaType() != JavaTypes.OBJECT)
col.setJavaType(given.getJavaType());
else
col.setJavaType(JavaTypes.getTypeCode
(Schemas.getJavaType(col.getType(), col.getSize(),
col.getDecimalDigits())));
}
col.setAutoAssigned(autoAssign);
col.setRelationId(relationId);
col.setImplicitRelation(implicitRelation);
col.setTargetField(targetField);
// we need this for runtime, and the dynamic schema factory might
// not know it, so set it even if not adapting
if (defStr != null)
col.setDefaultString(defStr);
if (notNull != null)
col.setNotNull(notNull);
// add other details if adapting
if (adapt) {
if (typeName != null)
col.setTypeName(typeName);
if (size != 0)
col.setSize(size);
if (decimals != 0)
col.setDecimalDigits(decimals);
}
if (tmplate.hasComment())
col.setComment(tmplate.getComment());
if (tmplate.isXML())
col.setXML(tmplate.isXML());
return col;
}