/* * Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com) * Licensed under the Apache License, Version 2.0 (the "License") * $Id: CreateTable.java 3918 2008-04-14 17:35:35Z gbevin $ */ package com.uwyn.rife.database.queries; import com.uwyn.rife.database.exceptions.*; import com.uwyn.rife.database.Datasource; import com.uwyn.rife.database.capabilities.Capabilities; import com.uwyn.rife.datastructures.EnumClass; import com.uwyn.rife.site.Constrained; import com.uwyn.rife.site.ConstrainedBean; import com.uwyn.rife.site.ConstrainedProperty; import com.uwyn.rife.site.ConstrainedUtils; import com.uwyn.rife.template.Template; import com.uwyn.rife.template.TemplateFactory; import com.uwyn.rife.tools.ClassUtils; import com.uwyn.rife.tools.StringUtils; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Object representation of a SQL "CREATE TABLE" query. * * <p>This object may be used to dynamically construct a SQL statement in a * database-independent fashion. After it is finished, it may be executed using * {@link com.uwyn.rife.database.DbQueryManager#executeUpdate(Query) * DbQueryManager.executeUpdate()}. * * @author Geert Bevin (gbevin[remove] at uwyn dot com) * @author Steven Grimm (koreth[remove] at midwinter dot com) * @version $Revision: 3918 $ * @since 1.0 */ public class CreateTable extends AbstractQuery implements Cloneable { private String mTable = null; private boolean mTemporary = false; private Map<String, Column> mColumnMapping = null; private List<PrimaryKey> mPrimaryKeys = null; private List<ForeignKey> mForeignKeys = null; private List<UniqueConstraint> mUniqueConstraints = null; private List<CheckConstraint> mCheckConstraints = null; public static final Nullable NULL = new Nullable("NULL"); public static final Nullable NOTNULL = new Nullable("NOTNULL"); public static final ViolationAction NOACTION = new ViolationAction("NOACTION"); public static final ViolationAction RESTRICT = new ViolationAction("RESTRICT"); public static final ViolationAction CASCADE = new ViolationAction("CASCADE"); public static final ViolationAction SETNULL = new ViolationAction("SETNULL"); public static final ViolationAction SETDEFAULT = new ViolationAction("SETDEFAULT"); public CreateTable(Datasource datasource) { super(datasource); if (null == datasource) throw new IllegalArgumentException("datasource can't be null."); clear(); } public void clear() { super.clear(); mTable = null; mTemporary = false; mColumnMapping = new LinkedHashMap<String, Column>(); mPrimaryKeys = new ArrayList<PrimaryKey>(); mForeignKeys = new ArrayList<ForeignKey>(); mUniqueConstraints = new ArrayList<UniqueConstraint>(); mCheckConstraints = new ArrayList<CheckConstraint>(); assert 0 == mColumnMapping.size(); assert 0 == mPrimaryKeys.size(); assert 0 == mForeignKeys.size(); assert 0 == mUniqueConstraints.size(); assert 0 == mCheckConstraints.size(); } public Capabilities getCapabilities() { return null; } public String getTable() { return mTable; } public boolean isTemporary() { return mTemporary; } public Map<String, Column> getColumnMapping() { return mColumnMapping; } public List<PrimaryKey> getPrimaryKeys() { return mPrimaryKeys; } public List<ForeignKey> getForeignKeys() { return mForeignKeys; } public List<UniqueConstraint> getUniqueConstraints() { return mUniqueConstraints; } public List<CheckConstraint> getCheckConstraints() { return mCheckConstraints; } public String getSql() throws DbQueryException { if (null == mSql) { if (null == getTable()) { throw new TableNameRequiredException("CreateTable"); } else if (0 == mColumnMapping.size()) { throw new ColumnsRequiredException("CreateTable"); } else { Template template = TemplateFactory.SQL.get("sql."+StringUtils.encodeClassname(mDatasource.getAliasedDriver())+".create_table"); String block = null; String sql = null; String columns = null; ArrayList<String> column_list = new ArrayList<String>(); for (Column column : mColumnMapping.values()) { column_list.add(column.getSql(template)); } columns = StringUtils.join(column_list, template.getBlock("SEPERATOR")); if (mTemporary) { block = template.getBlock("TEMPORARY"); if (0 == block.length()) { throw new UnsupportedSqlFeatureException("TEMPORARY", mDatasource.getAliasedDriver()); } template.setValue("TEMPORARY", block); } String primary = ""; if (mPrimaryKeys.size() > 0) { ArrayList<String> constraints = new ArrayList<String>(); for (PrimaryKey primary_key : mPrimaryKeys) { sql = primary_key.getSql(template); if (sql.length() > 0) { constraints.add(sql); } } if (constraints.size() > 0) { primary = template.getBlock("SEPERATOR")+StringUtils.join(constraints, template.getBlock("SEPERATOR")); } } String foreign = ""; if (mForeignKeys.size() > 0) { ArrayList<String> constraints = new ArrayList<String>(); for (ForeignKey foreign_key : mForeignKeys) { sql = foreign_key.getSql(template); if (sql.length() > 0) { constraints.add(sql); } } if (constraints.size() > 0) { foreign = template.getBlock("SEPERATOR")+StringUtils.join(constraints, template.getBlock("SEPERATOR")); } } String unique = ""; if (mUniqueConstraints.size() > 0) { ArrayList<String> constraints = new ArrayList<String>(); for (UniqueConstraint unique_constraint : mUniqueConstraints) { sql = unique_constraint.getSql(template); if (sql.length() > 0) { constraints.add(sql); } } if (constraints.size() > 0) { unique = template.getBlock("SEPERATOR")+StringUtils.join(constraints, template.getBlock("SEPERATOR")); } } String check = ""; if (mCheckConstraints.size() > 0) { ArrayList<String> constraints = new ArrayList<String>(); for (CheckConstraint check_constraint : mCheckConstraints) { sql = check_constraint.getSql(template); if (sql.length() > 0) { constraints.add(sql); } } if (constraints.size() > 0) { check = template.getBlock("SEPERATOR")+StringUtils.join(constraints, template.getBlock("SEPERATOR")); } } template.setValue("TABLE", mTable); template.setValue("COLUMNS", columns); template.setValue("PRIMARY_KEYS", primary); template.setValue("FOREIGN_KEYS", foreign); template.setValue("UNIQUE_CONSTRAINTS", unique); template.setValue("CHECKS", check); mSql = template.getBlock("QUERY"); assert mSql != null; assert mSql.length() > 0; } } return mSql; } public CreateTable table(String table) { if (null == table) throw new IllegalArgumentException("table can't be null."); if (0 == table.length()) throw new IllegalArgumentException("table can't be empty."); mTable = table; clearGenerated(); return this; } public CreateTable temporary(boolean temporary) { mTemporary = temporary; clearGenerated(); return this; } public CreateTable column(String name, Class type) { return column(name, type, -1, -1, null, null); } public CreateTable column(String name, Class type, String typeAttribute) { return column(name, type, -1, -1, typeAttribute, null); } public CreateTable column(String name, Class type, int precision) { return column(name, type, precision, -1, null, null); } public CreateTable column(String name, Class type, int precision, String typeAttribute) { return column(name, type, precision, -1, typeAttribute, null); } public CreateTable column(String name, Class type, int precision, int scale) { return column(name, type, precision, scale, null, null); } public CreateTable column(String name, Class type, int precision, int scale, String typeAttribute) { return column(name, type, precision, scale, typeAttribute, null); } public CreateTable column(String name, Class type, Nullable nullable) { return column(name, type, -1, -1, null, nullable); } public CreateTable column(String name, Class type, String typeAttribute, Nullable nullable) { return column(name, type, -1, -1, typeAttribute, nullable); } public CreateTable column(String name, Class type, int precision, Nullable nullable) { return column(name, type, precision, -1, null, nullable); } public CreateTable column(String name, Class type, int precision, String typeAttribute, Nullable nullable) { return column(name, type, precision, -1, typeAttribute, nullable); } public CreateTable column(String name, Class type, int precision, int scale, Nullable nullable) { return column(name, type, precision, scale, null, nullable); } public CreateTable column(String name, Class type, int precision, int scale, String typeAttribute, Nullable nullable) { if (null == name) throw new IllegalArgumentException("name can't be null."); if (0 == name.length()) throw new IllegalArgumentException("name can't be empty."); if (null == type) throw new IllegalArgumentException("type can't be null."); mColumnMapping.put(name, new Column(name, type, precision, scale, typeAttribute, nullable)); clearGenerated(); return this; } public CreateTable columns(Object[] keyValues) { if (null == keyValues) throw new IllegalArgumentException("keyValues can't be null."); for (int i = 0; i < keyValues.length; i+=2) { if (null != keyValues[i]) { column(keyValues[i].toString(), (Class)keyValues[i+1]); } } return this; } public CreateTable precision(String name, int precision) { return precision(name, precision, -1); } public CreateTable precision(String name, int precision, int scale) { if (null == name) throw new IllegalArgumentException("name can't be null."); if (0 == name.length()) throw new IllegalArgumentException("name can't be empty."); if (!mColumnMapping.containsKey(name)) throw new IllegalArgumentException("the '"+name+"' column hasn't been defined."); Column column = mColumnMapping.get(name); column.setPrecision(precision); column.setScale(scale); return this; } public CreateTable nullable(String name, Nullable nullable) { if (null == name) throw new IllegalArgumentException("name can't be null."); if (0 == name.length()) throw new IllegalArgumentException("name can't be empty."); if (!mColumnMapping.containsKey(name)) throw new IllegalArgumentException("the '"+name+"' column hasn't been defined."); Column column = mColumnMapping.get(name); column.setNullable(nullable); return this; } public CreateTable defaultValue(String name, char value) { return defaultValue(name, new Character(value)); } public CreateTable defaultValue(String name, boolean value) { return defaultValue(name, Boolean.valueOf(value)); } public CreateTable defaultValue(String name, byte value) { return defaultValue(name, new Byte(value)); } public CreateTable defaultValue(String name, double value) { return defaultValue(name, new Double(value)); } public CreateTable defaultValue(String name, float value) { return defaultValue(name, new Float(value)); } public CreateTable defaultValue(String name, int value) { return defaultValue(name, new Integer(value)); } public CreateTable defaultValue(String name, long value) { return defaultValue(name, new Long(value)); } public CreateTable defaultValue(String name, short value) { return defaultValue(name, new Short(value)); } public CreateTable defaultValue(String name, Object value) { if (null == name) throw new IllegalArgumentException("name can't be null."); if (0 == name.length()) throw new IllegalArgumentException("name can't be empty."); if (!mColumnMapping.containsKey(name)) throw new IllegalArgumentException("the '"+name+"' column hasn't been defined."); Column column = mColumnMapping.get(name); column.setDefault(mDatasource.getSqlConversion().getSqlValue(value)); return this; } public CreateTable defaultFunction(String name, String defaultFunction) { if (null == name) throw new IllegalArgumentException("name can't be null."); if (0 == name.length()) throw new IllegalArgumentException("name can't be empty."); if (!mColumnMapping.containsKey(name)) throw new IllegalArgumentException("the '"+name+"' column hasn't been defined."); if (null == defaultFunction) throw new IllegalArgumentException("defaultFunction can't be null."); if (0 == defaultFunction.length()) throw new IllegalArgumentException("defaultFunction can't be empty."); Column column = mColumnMapping.get(name); column.setDefault(defaultFunction); return this; } public CreateTable customAttribute(String name, String attribute) { if (null == name) throw new IllegalArgumentException("name can't be null."); if (0 == name.length()) throw new IllegalArgumentException("name can't be empty."); if (!mColumnMapping.containsKey(name)) throw new IllegalArgumentException("the '"+name+"' column hasn't been defined."); Column column = mColumnMapping.get(name); column.addCustomAttribute(attribute); return this; } public CreateTable columns(Class beanClass) throws DbQueryException { return columnsFiltered(beanClass, null, null); } public CreateTable columnsIncluded(Class beanClass, String[] includedFields) throws DbQueryException { return columnsFiltered(beanClass, includedFields, null); } public CreateTable columnsExcluded(Class beanClass, String[] excludedFields) throws DbQueryException { return columnsFiltered(beanClass, null, excludedFields); } public CreateTable columnsFiltered(Class beanClass, String[] includedFields, String[] excludedFields) throws DbQueryException { if (null == beanClass) throw new IllegalArgumentException("beanClass can't be null."); Constrained constrained = ConstrainedUtils.getConstrainedInstance(beanClass); // handle constrained bean if (constrained != null) { ConstrainedBean constrained_bean = constrained.getConstrainedBean(); if (constrained_bean != null) { // handle multi-column uniques if (constrained_bean.hasUniques()) { for (String[] o : (List<String[]>)constrained_bean.getUniques()) { unique(o); } } } } // handle properties ConstrainedProperty constrained_property = null; Map<String, Class> column_types = QueryHelper.getBeanPropertyTypes(beanClass, includedFields, excludedFields); Class column_type = null; Column column = null; for (String column_name : column_types.keySet()) { if (!ConstrainedUtils.persistConstrainedProperty(constrained, column_name, null)) { continue; } column_type = column_types.get(column_name); column = new Column(column_name, column_type); mColumnMapping.put(column_name, column); String[] in_list_values = null; in_list_values = ClassUtils.getEnumClassValues(column_type); if (constrained != null) { constrained_property = constrained.getConstrainedProperty(column_name); if (constrained_property != null) { if (constrained_property.isNotNull()) { nullable(column_name, NOTNULL); } if (constrained_property.isIdentifier()) { primaryKey(column_name); } if (constrained_property.isUnique()) { unique(column_name); } if (constrained_property.isNotEmpty()) { if (ClassUtils.isNumeric(column_type)) { check(column_name+" != 0"); } else if (ClassUtils.isText(column_type)) { check(column_name+" != ''"); } } if (constrained_property.isNotEqual()) { if (ClassUtils.isNumeric(column_type)) { check(column_name+" != "+constrained_property.getNotEqual()); } else if (ClassUtils.isText(column_type)) { check(column_name+" != '"+StringUtils.encodeSql(constrained_property.getNotEqual().toString())+"'"); } } if (constrained_property.hasPrecision()) { if (constrained_property.hasScale()) { precision(column_name, constrained_property.getPrecision(), constrained_property.getScale()); } else { precision(column_name, constrained_property.getPrecision()); } } if (constrained_property.isInList()) { in_list_values = constrained_property.getInList().clone(); } if (constrained_property.hasDefaultValue()) { defaultValue(column_name, constrained_property.getDefaultValue()); } if (constrained_property.hasManyToOne() && ClassUtils.isBasic(column_type)) { ConstrainedProperty.ManyToOne many_to_one = constrained_property.getManyToOne(); if (null == many_to_one.getDerivedTable()) { throw new MissingManyToOneTableException(beanClass, constrained_property.getPropertyName()); } if (null == many_to_one.getColumn()) { throw new MissingManyToOneColumnException(beanClass, constrained_property.getPropertyName()); } foreignKey(many_to_one.getDerivedTable(), constrained_property.getPropertyName(), many_to_one.getColumn(), many_to_one.getOnUpdate(), many_to_one.getOnDelete()); } } } // handle in list constraints if (in_list_values != null) { for (int i = 0; i < in_list_values.length; i++) { in_list_values[i] = StringUtils.encodeSql(in_list_values[i]); } StringBuilder check_constraint = new StringBuilder(); String seperator = ""; if (ClassUtils.isText(column_type) || column_type.isEnum()) { seperator = "'"; } check_constraint.append(column_name); check_constraint.append(" IS NULL OR "); check_constraint.append(column_name); check_constraint.append(" IN ("); check_constraint.append(seperator); check_constraint.append(StringUtils.join(in_list_values, seperator+","+seperator)); check_constraint.append(seperator); check_constraint.append(")"); check(check_constraint.toString()); } } clearGenerated(); return this; } public CreateTable primaryKey(String column) { return primaryKey(null, column); } public CreateTable primaryKey(String[] columns) { return primaryKey(null, columns); } public CreateTable primaryKey(String name, String column) { return primaryKey(name, new String[] {column}); } public CreateTable primaryKey(String name, String[] columns) { if (name != null && 0 == name.length()) throw new IllegalArgumentException("name can't be empty."); if (null == columns) throw new IllegalArgumentException("columns array can't be null."); if (0 == columns.length) throw new IllegalArgumentException("columns array can't be empty."); for (String column : columns) { nullable(column, CreateTable.NOTNULL); } mPrimaryKeys.add(new PrimaryKey(name, columns)); clearGenerated(); return this; } public CreateTable foreignKey(String foreignTable, String localColumn, String foreignColumn) { return foreignKey(null, foreignTable, localColumn, foreignColumn, null, null); } public CreateTable foreignKey(String foreignTable, String localColumn, String foreignColumn, ViolationAction onUpdate, ViolationAction onDelete) { return foreignKey(null, foreignTable, new String[] {localColumn, foreignColumn}, onUpdate, onDelete); } public CreateTable foreignKey(String foreignTable, String[] columnsMapping) { return foreignKey(null, foreignTable, columnsMapping, null, null); } public CreateTable foreignKey(String foreignTable, String[] columnsMapping, ViolationAction onUpdate, ViolationAction onDelete) { return foreignKey(null, foreignTable, columnsMapping, onUpdate, onDelete); } public CreateTable foreignKey(String name, String foreignTable, String localColumn, String foreignColumn) { return foreignKey(name, foreignTable, localColumn, foreignColumn, null, null); } public CreateTable foreignKey(String name, String foreignTable, String localColumn, String foreignColumn, ViolationAction onUpdate, ViolationAction onDelete) { return foreignKey(name, foreignTable, new String[] {localColumn, foreignColumn}, onUpdate, onDelete); } public CreateTable foreignKey(String name, String foreignTable, String[] columnsMapping) { return foreignKey(name, foreignTable, columnsMapping, null, null); } public CreateTable foreignKey(String name, String foreignTable, String[] columnsMapping, ViolationAction onUpdate, ViolationAction onDelete) { if (name != null && 0 == name.length()) throw new IllegalArgumentException("name can't be empty."); if (null == foreignTable) throw new IllegalArgumentException("foreignTable can't be null."); if (0 == foreignTable.length()) throw new IllegalArgumentException("foreignTable can't be empty."); if (null == columnsMapping) throw new IllegalArgumentException("columnsMapping array can't be null."); if (0 == columnsMapping.length) throw new IllegalArgumentException("columnsMapping array can't be empty."); if (columnsMapping.length%2 != 0) throw new IllegalArgumentException("columnsMapping array isn't valid, each local column should be mapped to a foreign one."); mForeignKeys.add(new ForeignKey(name, foreignTable, columnsMapping, onUpdate, onDelete)); clearGenerated(); return this; } public CreateTable unique(String column) { return unique(null, column); } public CreateTable unique(String[] columns) { return unique(null, columns); } public CreateTable unique(String name, String column) { return unique(name, new String[] {column}); } public CreateTable unique(String name, String[] columns) { if (name != null && 0 == name.length()) throw new IllegalArgumentException("name can't be empty."); if (null == columns) throw new IllegalArgumentException("columns array can't be null."); if (0 == columns.length) throw new IllegalArgumentException("columns array can't be empty."); mUniqueConstraints.add(new UniqueConstraint(name, columns)); clearGenerated(); return this; } public CreateTable check(String expression) { return check(null, expression); } public CreateTable check(String name, String expression) { if (name != null && 0 == name.length()) throw new IllegalArgumentException("name can't be empty."); if (null == expression) throw new IllegalArgumentException("expression can't be null."); if (0 == expression.length()) throw new IllegalArgumentException("expression can't be empty."); mCheckConstraints.add(new CheckConstraint(name, expression)); clearGenerated(); return this; } public CreateTable clone() { CreateTable new_instance = (CreateTable)super.clone(); if (new_instance != null) { if (mColumnMapping != null) { new_instance.mColumnMapping = new LinkedHashMap<String, Column>(); Column column = null; for (String name : mColumnMapping.keySet()) { column = mColumnMapping.get(name); new_instance.mColumnMapping.put(name, column.clone()); } } if (mPrimaryKeys != null) { new_instance.mPrimaryKeys = new ArrayList<PrimaryKey>(); for (PrimaryKey primary_key : mPrimaryKeys) { new_instance.mPrimaryKeys.add(primary_key.clone()); } } if (mForeignKeys != null) { new_instance.mForeignKeys = new ArrayList<ForeignKey>(); for (ForeignKey foreign_key : mForeignKeys) { new_instance.mForeignKeys.add(foreign_key.clone()); } } if (mUniqueConstraints != null) { new_instance.mUniqueConstraints = new ArrayList<UniqueConstraint>(); for (UniqueConstraint unique_constraint : mUniqueConstraints) { new_instance.mUniqueConstraints.add(unique_constraint.clone()); } } if (mCheckConstraints != null) { new_instance.mCheckConstraints = new ArrayList<CheckConstraint>(); for (CheckConstraint check_constraint : mCheckConstraints) { new_instance.mCheckConstraints.add(check_constraint.clone()); } } } return new_instance; } public class PrimaryKey extends ColumnsConstraint implements Cloneable { PrimaryKey(String name, String[] columns) { super(name, columns); } String getSql(Template template) throws DbQueryException { assert template != null; String result = null; if (getName() != null && template.hasValueId("PRIMARY_KEY_NAME")) { template.setValue("NAME", getName()); template.setValue("PRIMARY_KEY_NAME", template.getBlock("PRIMARY_KEY_NAME")); } template.setValue("COLUMN_NAMES", StringUtils.join(getColumns(), template.getBlock("SEPERATOR"))); result = template.getBlock("PRIMARY_KEY"); if (0 == result.length()) { throw new UnsupportedSqlFeatureException("PRIMARY KEY", mDatasource.getAliasedDriver()); } assert result != null; return result; } public PrimaryKey clone() { return (PrimaryKey)super.clone(); } } public class ForeignKey extends ColumnsConstraint implements Cloneable { private String mForeignTable = null; private ViolationAction mOnUpdate = null; private ViolationAction mOnDelete = null; ForeignKey(String name, String foreignTable, String[] columnsMapping, ViolationAction onUpdate, ViolationAction onDelete) { super(name, columnsMapping); setForeignTable(foreignTable); setOnUpdate(onUpdate); setOnDelete(onDelete); } String getSql(Template template) throws DbQueryException { assert template != null; String block = null; String result = null; if (getName() != null) { template.setValue("NAME", getName()); template.setValue("FOREIGN_KEY_NAME", template.getBlock("FOREIGN_KEY_NAME")); } template.setValue("FOREIGN_TABLE", getForeignTable()); String violations_actions = ""; if (getOnUpdate() != null) { block = template.getBlock("ON_UPDATE_"+getOnUpdate().toString()); if (0 == block.length()) { throw new UnsupportedSqlFeatureException("ON UPDATE "+getOnUpdate().toString(), mDatasource.getAliasedDriver()); } template.setValue("ON_UPDATE_ACTION", block); block = template.getBlock("ON_UPDATE"); if (0 == block.length()) { throw new UnsupportedSqlFeatureException("ON UPDATE", mDatasource.getAliasedDriver()); } violations_actions += block; } if (getOnDelete() != null) { block = template.getBlock("ON_DELETE_"+getOnDelete().toString()); if (0 == block.length()) { throw new UnsupportedSqlFeatureException("ON DELETE "+getOnDelete().toString(), mDatasource.getAliasedDriver()); } template.setValue("ON_DELETE_ACTION", block); block = template.getBlock("ON_DELETE"); if (0 == block.length()) { throw new UnsupportedSqlFeatureException("ON DELETE", mDatasource.getAliasedDriver()); } violations_actions += block; } template.setValue("VIOLATION_ACTIONS", violations_actions); String[] local_columns = new String[getColumns().length/2]; String[] foreign_columns = new String[getColumns().length/2]; for (int i = 0; i < getColumns().length; i+=2) { local_columns[i/2] = getColumns()[i]; foreign_columns[i/2] = getColumns()[i+1]; } template.setValue("LOCAL_COLUMN_NAMES", StringUtils.join(local_columns, template.getBlock("SEPERATOR"))); template.setValue("FOREIGN_COLUMN_NAMES", StringUtils.join(foreign_columns, template.getBlock("SEPERATOR"))); result = template.getBlock("FOREIGN_KEY"); if (0 == result.length()) { throw new UnsupportedSqlFeatureException("FOREIGN KEY", mDatasource.getAliasedDriver()); } assert result != null; return result; } public String getForeignTable() { return mForeignTable; } void setForeignTable(String foreignTable) { assert foreignTable != null; assert foreignTable.length() > 0; mForeignTable = foreignTable; } public ViolationAction getOnUpdate() { return mOnUpdate; } void setOnUpdate(ViolationAction onUpdate) { mOnUpdate = onUpdate; } public ViolationAction getOnDelete() { return mOnDelete; } void setOnDelete(ViolationAction onDelete) { mOnDelete = onDelete; } public ForeignKey clone() { return (ForeignKey)super.clone(); } } public class UniqueConstraint extends ColumnsConstraint implements Cloneable { UniqueConstraint(String name, String[] columns) { super(name, columns); } String getSql(Template template) throws DbQueryException { assert template != null; String result = null; if (getName() != null) { template.setValue("NAME", getName()); template.setValue("UNIQUE_CONSTRAINT_NAME", template.getBlock("UNIQUE_CONSTRAINT_NAME")); } template.setValue("COLUMN_NAMES", StringUtils.join(getColumns(), template.getBlock("SEPERATOR"))); result = template.getBlock("UNIQUE_CONSTRAINT"); if (0 == result.length()) { throw new UnsupportedSqlFeatureException("UNIQUE", mDatasource.getAliasedDriver()); } return result; } public UniqueConstraint clone() { return (UniqueConstraint)super.clone(); } } public class CheckConstraint extends Constraint implements Cloneable { private String mExpression = null; CheckConstraint(String name, String expression) { super(name); setExpression(expression); } String getSql(Template template) throws DbQueryException { assert template != null; String result = null; if (getName() != null && template.hasValueId("CHECK_NAME")) { template.setValue("NAME", getName()); template.setValue("CHECK_NAME", template.getBlock("CHECK_NAME")); } if (template.hasValueId("EXPRESSION")) { template.setValue("EXPRESSION", getExpression()); } result = template.getBlock("CHECK"); if (0 == result.length()) { throw new UnsupportedSqlFeatureException("CHECK", mDatasource.getAliasedDriver()); } return result; } public String getExpression() { return mExpression; } void setExpression(String expression) { mExpression = expression; } public CheckConstraint clone() { return (CheckConstraint)super.clone(); } } public abstract class ColumnsConstraint extends Constraint implements Cloneable { private String[] mColumns = null; ColumnsConstraint(String name, String[] columns) { super(name); setColumns(columns); } public String[] getColumns() { return mColumns; } void setColumns(String[] columns) { assert columns != null; assert columns.length > 0; mColumns = columns; } public ColumnsConstraint clone() { return (ColumnsConstraint)super.clone(); } } public abstract class Constraint implements Cloneable { private String mName = null; Constraint(String name) { setName(name); } abstract String getSql(Template template) throws DbQueryException; public String getName() { return mName; } void setName(String name) { assert null == name || name.length() > 0; mName = name; } public Constraint clone() { Constraint new_instance = null; try { new_instance = (Constraint)super.clone(); } catch (CloneNotSupportedException e) { new_instance = null; } return new_instance; } } public class Column implements Cloneable { private String mName = null; private Class mType = null; private int mPrecision = -1; private int mScale = -1; private String mTypeAttribute = null; private Nullable mNullable = null; private String mDefault = null; private ArrayList<String> mCustomAttributes = new ArrayList<String>(); Column(String name, Class type) { setName(name); setType(type); } Column(String name, Class type, int precision, int scale, String typeAttribute, Nullable nullable) { setName(name); setType(type); setPrecision(precision); setScale(scale); setTypeAttribute(typeAttribute); setNullable(nullable); } String getSql(Template template) throws DbQueryException { assert template != null; String block = null; String result = null; template.setValue("NAME", getName()); template.setValue("TYPE", mDatasource.getSqlConversion().getSqlType(getType(), getPrecision(), getScale())); if (mTypeAttribute != null) { template.appendValue("TYPE", " "); template.appendValue("TYPE", mTypeAttribute); } if (getNullable() != null) { block = template.getBlock(getNullable().toString()); if (0 == block.length()) { throw new UnsupportedSqlFeatureException("NULLABLE "+getNullable().toString(), mDatasource.getAliasedDriver()); } template.setValue("NULLABLE", block); } if (getDefault() != null) { template.setValue("V", getDefault()); block = template.getBlock("DEFAULT"); if (0 == block.length()) { throw new UnsupportedSqlFeatureException("DEFAULT", mDatasource.getAliasedDriver()); } template.setValue("DEFAULT", block); template.removeValue("V"); } if (getCustomAttributes().size() > 0) { template.setValue("V", StringUtils.join(getCustomAttributes(), " ")); block = template.getBlock("CUSTOM_ATTRIBUTES"); if (0 == block.length()) { throw new UnsupportedSqlFeatureException("CUSTOM_ATTRIBUTES", mDatasource.getAliasedDriver()); } template.setValue("CUSTOM_ATTRIBUTES", block); template.removeValue("V"); } result = template.getBlock("COLUMN"); if (0 == result.length()) { throw new UnsupportedSqlFeatureException("COLUMN", mDatasource.getAliasedDriver()); } template.removeValue("NAME"); template.removeValue("TYPE"); template.removeValue("NULLABLE"); template.removeValue("DEFAULT"); template.removeValue("CUSTOM_ATTRIBUTES"); assert result.length() > 0; return result; } public String getName() { return mName; } void setName(String name) { assert name != null; assert name.length() > 0; mName = name; } public Class getType() { return mType; } void setType(Class type) { assert type != null; mType = type; } public int getPrecision() { return mPrecision; } void setPrecision(int precision) { assert precision >= -1; mPrecision = precision; } public int getScale() { return mScale; } void setScale(int scale) { assert scale >= -1; mScale = scale; } public String getTypeAttribute() { return mTypeAttribute; } void setTypeAttribute(String typeAttribute) { mTypeAttribute = typeAttribute; } public Nullable getNullable() { return mNullable; } void setNullable(Nullable nullable) { mNullable = nullable; } public String getDefault() { return mDefault; } void setDefault(String defaultStatement) { mDefault = defaultStatement; } void addCustomAttribute(String attribute) { assert attribute != null; assert attribute.length() > 0; mCustomAttributes.add(attribute); } public ArrayList<String> getCustomAttributes() { return mCustomAttributes; } public Column clone() { Column new_instance = null; try { new_instance = (Column)super.clone(); if (mCustomAttributes != null) { new_instance.mCustomAttributes = new ArrayList<String>(); new_instance.mCustomAttributes.addAll(mCustomAttributes); } } catch (CloneNotSupportedException e) { new_instance = null; } return new_instance; } } public static class ViolationAction extends EnumClass<String> { ViolationAction(String identifier) { super(identifier); } } public static class Nullable extends EnumClass<String> { Nullable(String identifier) { super(identifier); } } }