0001: /*
0002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
0003: * Distributed under the terms of either:
0004: * - the common development and distribution license (CDDL), v1.0; or
0005: * - the GNU Lesser General Public License, v2.1 or later
0006: * $Id: CreateTable.java 3750 2007-05-12 15:05:53Z gbevin $
0007: */
0008: package com.uwyn.rife.database.queries;
0009:
0010: import com.uwyn.rife.database.exceptions.*;
0011:
0012: import com.uwyn.rife.database.Datasource;
0013: import com.uwyn.rife.database.capabilities.Capabilities;
0014: import com.uwyn.rife.datastructures.EnumClass;
0015: import com.uwyn.rife.site.Constrained;
0016: import com.uwyn.rife.site.ConstrainedBean;
0017: import com.uwyn.rife.site.ConstrainedProperty;
0018: import com.uwyn.rife.site.ConstrainedUtils;
0019: import com.uwyn.rife.template.Template;
0020: import com.uwyn.rife.template.TemplateFactory;
0021: import com.uwyn.rife.tools.ClassUtils;
0022: import com.uwyn.rife.tools.StringUtils;
0023: import java.util.ArrayList;
0024: import java.util.LinkedHashMap;
0025: import java.util.List;
0026: import java.util.Map;
0027:
0028: /**
0029: * Object representation of a SQL "CREATE TABLE" query.
0030: *
0031: * <p>This object may be used to dynamically construct a SQL statement in a
0032: * database-independent fashion. After it is finished, it may be executed using
0033: * {@link com.uwyn.rife.database.DbQueryManager#executeUpdate(Query)
0034: * DbQueryManager.executeUpdate()}.
0035: *
0036: * @author Geert Bevin (gbevin[remove] at uwyn dot com)
0037: * @author Steven Grimm (koreth[remove] at midwinter dot com)
0038: * @version $Revision: 3750 $
0039: * @since 1.0
0040: */
0041: public class CreateTable extends AbstractQuery implements Cloneable {
0042: private String mTable = null;
0043: private boolean mTemporary = false;
0044: private Map<String, Column> mColumnMapping = null;
0045: private List<PrimaryKey> mPrimaryKeys = null;
0046: private List<ForeignKey> mForeignKeys = null;
0047: private List<UniqueConstraint> mUniqueConstraints = null;
0048: private List<CheckConstraint> mCheckConstraints = null;
0049:
0050: public static final Nullable NULL = new Nullable("NULL");
0051: public static final Nullable NOTNULL = new Nullable("NOTNULL");
0052:
0053: public static final ViolationAction NOACTION = new ViolationAction(
0054: "NOACTION");
0055: public static final ViolationAction RESTRICT = new ViolationAction(
0056: "RESTRICT");
0057: public static final ViolationAction CASCADE = new ViolationAction(
0058: "CASCADE");
0059: public static final ViolationAction SETNULL = new ViolationAction(
0060: "SETNULL");
0061: public static final ViolationAction SETDEFAULT = new ViolationAction(
0062: "SETDEFAULT");
0063:
0064: public CreateTable(Datasource datasource) {
0065: super (datasource);
0066:
0067: if (null == datasource)
0068: throw new IllegalArgumentException(
0069: "datasource can't be null.");
0070:
0071: clear();
0072: }
0073:
0074: public void clear() {
0075: super .clear();
0076:
0077: mTable = null;
0078: mTemporary = false;
0079: mColumnMapping = new LinkedHashMap<String, Column>();
0080: mPrimaryKeys = new ArrayList<PrimaryKey>();
0081: mForeignKeys = new ArrayList<ForeignKey>();
0082: mUniqueConstraints = new ArrayList<UniqueConstraint>();
0083: mCheckConstraints = new ArrayList<CheckConstraint>();
0084:
0085: assert 0 == mColumnMapping.size();
0086: assert 0 == mPrimaryKeys.size();
0087: assert 0 == mForeignKeys.size();
0088: assert 0 == mUniqueConstraints.size();
0089: assert 0 == mCheckConstraints.size();
0090: }
0091:
0092: public Capabilities getCapabilities() {
0093: return null;
0094: }
0095:
0096: public String getTable() {
0097: return mTable;
0098: }
0099:
0100: public boolean isTemporary() {
0101: return mTemporary;
0102: }
0103:
0104: public Map<String, Column> getColumnMapping() {
0105: return mColumnMapping;
0106: }
0107:
0108: public List<PrimaryKey> getPrimaryKeys() {
0109: return mPrimaryKeys;
0110: }
0111:
0112: public List<ForeignKey> getForeignKeys() {
0113: return mForeignKeys;
0114: }
0115:
0116: public List<UniqueConstraint> getUniqueConstraints() {
0117: return mUniqueConstraints;
0118: }
0119:
0120: public List<CheckConstraint> getCheckConstraints() {
0121: return mCheckConstraints;
0122: }
0123:
0124: public String getSql() throws DbQueryException {
0125: if (null == mSql) {
0126: if (null == getTable()) {
0127: throw new TableNameRequiredException("CreateTable");
0128: } else if (0 == mColumnMapping.size()) {
0129: throw new ColumnsRequiredException("CreateTable");
0130: } else {
0131: Template template = TemplateFactory.SQL.get("sql."
0132: + StringUtils.encodeClassname(mDatasource
0133: .getAliasedDriver()) + ".create_table");
0134: String block = null;
0135: String sql = null;
0136:
0137: String columns = null;
0138: ArrayList<String> column_list = new ArrayList<String>();
0139: for (Column column : mColumnMapping.values()) {
0140: column_list.add(column.getSql(template));
0141: }
0142: columns = StringUtils.join(column_list, template
0143: .getBlock("SEPERATOR"));
0144:
0145: if (mTemporary) {
0146: block = template.getBlock("TEMPORARY");
0147: if (0 == block.length()) {
0148: throw new UnsupportedSqlFeatureException(
0149: "TEMPORARY", mDatasource
0150: .getAliasedDriver());
0151: }
0152: template.setValue("TEMPORARY", block);
0153: }
0154:
0155: String primary = "";
0156: if (mPrimaryKeys.size() > 0) {
0157: ArrayList<String> constraints = new ArrayList<String>();
0158: for (PrimaryKey primary_key : mPrimaryKeys) {
0159: sql = primary_key.getSql(template);
0160: if (sql.length() > 0) {
0161: constraints.add(sql);
0162: }
0163: }
0164: if (constraints.size() > 0) {
0165: primary = template.getBlock("SEPERATOR")
0166: + StringUtils.join(constraints,
0167: template.getBlock("SEPERATOR"));
0168: }
0169: }
0170:
0171: String foreign = "";
0172: if (mForeignKeys.size() > 0) {
0173: ArrayList<String> constraints = new ArrayList<String>();
0174: for (ForeignKey foreign_key : mForeignKeys) {
0175: sql = foreign_key.getSql(template);
0176: if (sql.length() > 0) {
0177: constraints.add(sql);
0178: }
0179: }
0180: if (constraints.size() > 0) {
0181: foreign = template.getBlock("SEPERATOR")
0182: + StringUtils.join(constraints,
0183: template.getBlock("SEPERATOR"));
0184: }
0185: }
0186:
0187: String unique = "";
0188: if (mUniqueConstraints.size() > 0) {
0189: ArrayList<String> constraints = new ArrayList<String>();
0190: for (UniqueConstraint unique_constraint : mUniqueConstraints) {
0191: sql = unique_constraint.getSql(template);
0192: if (sql.length() > 0) {
0193: constraints.add(sql);
0194: }
0195: }
0196: if (constraints.size() > 0) {
0197: unique = template.getBlock("SEPERATOR")
0198: + StringUtils.join(constraints,
0199: template.getBlock("SEPERATOR"));
0200: }
0201: }
0202:
0203: String check = "";
0204: if (mCheckConstraints.size() > 0) {
0205: ArrayList<String> constraints = new ArrayList<String>();
0206: for (CheckConstraint check_constraint : mCheckConstraints) {
0207: sql = check_constraint.getSql(template);
0208: if (sql.length() > 0) {
0209: constraints.add(sql);
0210: }
0211: }
0212: if (constraints.size() > 0) {
0213: check = template.getBlock("SEPERATOR")
0214: + StringUtils.join(constraints,
0215: template.getBlock("SEPERATOR"));
0216: }
0217: }
0218:
0219: template.setValue("TABLE", mTable);
0220: template.setValue("COLUMNS", columns);
0221: template.setValue("PRIMARY_KEYS", primary);
0222: template.setValue("FOREIGN_KEYS", foreign);
0223: template.setValue("UNIQUE_CONSTRAINTS", unique);
0224: template.setValue("CHECKS", check);
0225:
0226: mSql = template.getBlock("QUERY");
0227:
0228: assert mSql != null;
0229: assert mSql.length() > 0;
0230: }
0231: }
0232:
0233: return mSql;
0234: }
0235:
0236: public CreateTable table(String table) {
0237: if (null == table)
0238: throw new IllegalArgumentException("table can't be null.");
0239: if (0 == table.length())
0240: throw new IllegalArgumentException("table can't be empty.");
0241:
0242: mTable = table;
0243: clearGenerated();
0244:
0245: return this ;
0246: }
0247:
0248: public CreateTable temporary(boolean temporary) {
0249: mTemporary = temporary;
0250: clearGenerated();
0251:
0252: return this ;
0253: }
0254:
0255: public CreateTable column(String name, Class type) {
0256: return column(name, type, -1, -1, null, null);
0257: }
0258:
0259: public CreateTable column(String name, Class type,
0260: String typeAttribute) {
0261: return column(name, type, -1, -1, typeAttribute, null);
0262: }
0263:
0264: public CreateTable column(String name, Class type, int precision) {
0265: return column(name, type, precision, -1, null, null);
0266: }
0267:
0268: public CreateTable column(String name, Class type, int precision,
0269: String typeAttribute) {
0270: return column(name, type, precision, -1, typeAttribute, null);
0271: }
0272:
0273: public CreateTable column(String name, Class type, int precision,
0274: int scale) {
0275: return column(name, type, precision, scale, null, null);
0276: }
0277:
0278: public CreateTable column(String name, Class type, int precision,
0279: int scale, String typeAttribute) {
0280: return column(name, type, precision, scale, typeAttribute, null);
0281: }
0282:
0283: public CreateTable column(String name, Class type, Nullable nullable) {
0284: return column(name, type, -1, -1, null, nullable);
0285: }
0286:
0287: public CreateTable column(String name, Class type,
0288: String typeAttribute, Nullable nullable) {
0289: return column(name, type, -1, -1, typeAttribute, nullable);
0290: }
0291:
0292: public CreateTable column(String name, Class type, int precision,
0293: Nullable nullable) {
0294: return column(name, type, precision, -1, null, nullable);
0295: }
0296:
0297: public CreateTable column(String name, Class type, int precision,
0298: String typeAttribute, Nullable nullable) {
0299: return column(name, type, precision, -1, typeAttribute,
0300: nullable);
0301: }
0302:
0303: public CreateTable column(String name, Class type, int precision,
0304: int scale, Nullable nullable) {
0305: return column(name, type, precision, scale, null, nullable);
0306: }
0307:
0308: public CreateTable column(String name, Class type, int precision,
0309: int scale, String typeAttribute, Nullable nullable) {
0310: if (null == name)
0311: throw new IllegalArgumentException("name can't be null.");
0312: if (0 == name.length())
0313: throw new IllegalArgumentException("name can't be empty.");
0314: if (null == type)
0315: throw new IllegalArgumentException("type can't be null.");
0316:
0317: mColumnMapping.put(name, new Column(name, type, precision,
0318: scale, typeAttribute, nullable));
0319: clearGenerated();
0320: return this ;
0321: }
0322:
0323: public CreateTable columns(Object[] keyValues) {
0324: if (null == keyValues)
0325: throw new IllegalArgumentException(
0326: "keyValues can't be null.");
0327:
0328: for (int i = 0; i < keyValues.length; i += 2) {
0329: if (null != keyValues[i]) {
0330: column(keyValues[i].toString(),
0331: (Class) keyValues[i + 1]);
0332: }
0333: }
0334:
0335: return this ;
0336: }
0337:
0338: public CreateTable precision(String name, int precision) {
0339: return precision(name, precision, -1);
0340: }
0341:
0342: public CreateTable precision(String name, int precision, int scale) {
0343: if (null == name)
0344: throw new IllegalArgumentException("name can't be null.");
0345: if (0 == name.length())
0346: throw new IllegalArgumentException("name can't be empty.");
0347: if (!mColumnMapping.containsKey(name))
0348: throw new IllegalArgumentException("the '" + name
0349: + "' column hasn't been defined.");
0350:
0351: Column column = mColumnMapping.get(name);
0352: column.setPrecision(precision);
0353: column.setScale(scale);
0354:
0355: return this ;
0356: }
0357:
0358: public CreateTable nullable(String name, Nullable nullable) {
0359: if (null == name)
0360: throw new IllegalArgumentException("name can't be null.");
0361: if (0 == name.length())
0362: throw new IllegalArgumentException("name can't be empty.");
0363: if (!mColumnMapping.containsKey(name))
0364: throw new IllegalArgumentException("the '" + name
0365: + "' column hasn't been defined.");
0366:
0367: Column column = mColumnMapping.get(name);
0368: column.setNullable(nullable);
0369:
0370: return this ;
0371: }
0372:
0373: public CreateTable defaultValue(String name, char value) {
0374: return defaultValue(name, new Character(value));
0375: }
0376:
0377: public CreateTable defaultValue(String name, boolean value) {
0378: return defaultValue(name, Boolean.valueOf(value));
0379: }
0380:
0381: public CreateTable defaultValue(String name, byte value) {
0382: return defaultValue(name, new Byte(value));
0383: }
0384:
0385: public CreateTable defaultValue(String name, double value) {
0386: return defaultValue(name, new Double(value));
0387: }
0388:
0389: public CreateTable defaultValue(String name, float value) {
0390: return defaultValue(name, new Float(value));
0391: }
0392:
0393: public CreateTable defaultValue(String name, int value) {
0394: return defaultValue(name, new Integer(value));
0395: }
0396:
0397: public CreateTable defaultValue(String name, long value) {
0398: return defaultValue(name, new Long(value));
0399: }
0400:
0401: public CreateTable defaultValue(String name, short value) {
0402: return defaultValue(name, new Short(value));
0403: }
0404:
0405: public CreateTable defaultValue(String name, Object value) {
0406: if (null == name)
0407: throw new IllegalArgumentException("name can't be null.");
0408: if (0 == name.length())
0409: throw new IllegalArgumentException("name can't be empty.");
0410: if (!mColumnMapping.containsKey(name))
0411: throw new IllegalArgumentException("the '" + name
0412: + "' column hasn't been defined.");
0413:
0414: Column column = mColumnMapping.get(name);
0415: column.setDefault(mDatasource.getSqlConversion().getSqlValue(
0416: value));
0417:
0418: return this ;
0419: }
0420:
0421: public CreateTable defaultFunction(String name,
0422: String defaultFunction) {
0423: if (null == name)
0424: throw new IllegalArgumentException("name can't be null.");
0425: if (0 == name.length())
0426: throw new IllegalArgumentException("name can't be empty.");
0427: if (!mColumnMapping.containsKey(name))
0428: throw new IllegalArgumentException("the '" + name
0429: + "' column hasn't been defined.");
0430: if (null == defaultFunction)
0431: throw new IllegalArgumentException(
0432: "defaultFunction can't be null.");
0433: if (0 == defaultFunction.length())
0434: throw new IllegalArgumentException(
0435: "defaultFunction can't be empty.");
0436:
0437: Column column = mColumnMapping.get(name);
0438: column.setDefault(defaultFunction);
0439:
0440: return this ;
0441: }
0442:
0443: public CreateTable customAttribute(String name, String attribute) {
0444: if (null == name)
0445: throw new IllegalArgumentException("name can't be null.");
0446: if (0 == name.length())
0447: throw new IllegalArgumentException("name can't be empty.");
0448: if (!mColumnMapping.containsKey(name))
0449: throw new IllegalArgumentException("the '" + name
0450: + "' column hasn't been defined.");
0451:
0452: Column column = mColumnMapping.get(name);
0453: column.addCustomAttribute(attribute);
0454:
0455: return this ;
0456: }
0457:
0458: public CreateTable columns(Class beanClass) throws DbQueryException {
0459: return columnsFiltered(beanClass, null, null);
0460: }
0461:
0462: public CreateTable columnsIncluded(Class beanClass,
0463: String[] includedFields) throws DbQueryException {
0464: return columnsFiltered(beanClass, includedFields, null);
0465: }
0466:
0467: public CreateTable columnsExcluded(Class beanClass,
0468: String[] excludedFields) throws DbQueryException {
0469: return columnsFiltered(beanClass, null, excludedFields);
0470: }
0471:
0472: public CreateTable columnsFiltered(Class beanClass,
0473: String[] includedFields, String[] excludedFields)
0474: throws DbQueryException {
0475: if (null == beanClass)
0476: throw new IllegalArgumentException(
0477: "beanClass can't be null.");
0478:
0479: Constrained constrained = ConstrainedUtils
0480: .getConstrainedInstance(beanClass);
0481:
0482: // handle constrained bean
0483: if (constrained != null) {
0484: ConstrainedBean constrained_bean = constrained
0485: .getConstrainedBean();
0486: if (constrained_bean != null) {
0487: // handle multi-column uniques
0488: if (constrained_bean.hasUniques()) {
0489: for (String[] o : (List<String[]>) constrained_bean
0490: .getUniques()) {
0491: unique(o);
0492: }
0493: }
0494: }
0495: }
0496:
0497: // handle properties
0498: ConstrainedProperty constrained_property = null;
0499: Map<String, Class> column_types = QueryHelper
0500: .getBeanPropertyTypes(beanClass, includedFields,
0501: excludedFields);
0502: Class column_type = null;
0503: Column column = null;
0504: for (String column_name : column_types.keySet()) {
0505: if (!ConstrainedUtils.persistConstrainedProperty(
0506: constrained, column_name, null)) {
0507: continue;
0508: }
0509:
0510: column_type = column_types.get(column_name);
0511: column = new Column(column_name, column_type);
0512: mColumnMapping.put(column_name, column);
0513:
0514: String[] in_list_values = null;
0515:
0516: in_list_values = ClassUtils.getEnumClassValues(column_type);
0517:
0518: if (constrained != null) {
0519: constrained_property = constrained
0520: .getConstrainedProperty(column_name);
0521: if (constrained_property != null) {
0522: if (constrained_property.isNotNull()) {
0523: nullable(column_name, NOTNULL);
0524: }
0525:
0526: if (constrained_property.isIdentifier()) {
0527: primaryKey(column_name);
0528: }
0529:
0530: if (constrained_property.isUnique()) {
0531: unique(column_name);
0532: }
0533:
0534: if (constrained_property.isNotEmpty()) {
0535: if (ClassUtils.isNumeric(column_type)) {
0536: check(column_name + " != 0");
0537: } else if (ClassUtils.isText(column_type)) {
0538: check(column_name + " != ''");
0539: }
0540: }
0541:
0542: if (constrained_property.isNotEqual()) {
0543: if (ClassUtils.isNumeric(column_type)) {
0544: check(column_name
0545: + " != "
0546: + constrained_property
0547: .getNotEqual());
0548: } else if (ClassUtils.isText(column_type)) {
0549: check(column_name
0550: + " != '"
0551: + StringUtils
0552: .encodeSql(constrained_property
0553: .getNotEqual()
0554: .toString()) + "'");
0555: }
0556: }
0557:
0558: if (constrained_property.hasPrecision()) {
0559: if (constrained_property.hasScale()) {
0560: precision(column_name, constrained_property
0561: .getPrecision(),
0562: constrained_property.getScale());
0563: } else {
0564: precision(column_name, constrained_property
0565: .getPrecision());
0566: }
0567: }
0568:
0569: if (constrained_property.isInList()) {
0570: in_list_values = constrained_property
0571: .getInList().clone();
0572: }
0573:
0574: if (constrained_property.hasDefaultValue()) {
0575: defaultValue(column_name, constrained_property
0576: .getDefaultValue());
0577: }
0578:
0579: if (constrained_property.hasManyToOne()
0580: && ClassUtils.isBasic(column_type)) {
0581: ConstrainedProperty.ManyToOne many_to_one = constrained_property
0582: .getManyToOne();
0583:
0584: if (null == many_to_one.getDerivedTable()) {
0585: throw new MissingManyToOneTableException(
0586: beanClass, constrained_property
0587: .getPropertyName());
0588: }
0589:
0590: if (null == many_to_one.getColumn()) {
0591: throw new MissingManyToOneColumnException(
0592: beanClass, constrained_property
0593: .getPropertyName());
0594: }
0595:
0596: foreignKey(many_to_one.getDerivedTable(),
0597: constrained_property.getPropertyName(),
0598: many_to_one.getColumn(), many_to_one
0599: .getOnUpdate(), many_to_one
0600: .getOnDelete());
0601: }
0602: }
0603: }
0604:
0605: // handle in list constraints
0606: if (in_list_values != null) {
0607: for (int i = 0; i < in_list_values.length; i++) {
0608: in_list_values[i] = StringUtils
0609: .encodeSql(in_list_values[i]);
0610: }
0611:
0612: StringBuilder check_constraint = new StringBuilder();
0613: String seperator = "";
0614: if (ClassUtils.isText(column_type)
0615: || column_type.isEnum()) {
0616: seperator = "'";
0617: }
0618: check_constraint.append(column_name);
0619: check_constraint.append(" IS NULL OR ");
0620: check_constraint.append(column_name);
0621: check_constraint.append(" IN (");
0622: check_constraint.append(seperator);
0623: check_constraint.append(StringUtils.join(
0624: in_list_values, seperator + "," + seperator));
0625: check_constraint.append(seperator);
0626: check_constraint.append(")");
0627: check(check_constraint.toString());
0628: }
0629: }
0630: clearGenerated();
0631:
0632: return this ;
0633: }
0634:
0635: public CreateTable primaryKey(String column) {
0636: return primaryKey(null, column);
0637: }
0638:
0639: public CreateTable primaryKey(String[] columns) {
0640: return primaryKey(null, columns);
0641: }
0642:
0643: public CreateTable primaryKey(String name, String column) {
0644: return primaryKey(name, new String[] { column });
0645: }
0646:
0647: public CreateTable primaryKey(String name, String[] columns) {
0648: if (name != null && 0 == name.length())
0649: throw new IllegalArgumentException("name can't be empty.");
0650: if (null == columns)
0651: throw new IllegalArgumentException(
0652: "columns array can't be null.");
0653: if (0 == columns.length)
0654: throw new IllegalArgumentException(
0655: "columns array can't be empty.");
0656:
0657: for (String column : columns) {
0658: nullable(column, CreateTable.NOTNULL);
0659: }
0660: mPrimaryKeys.add(new PrimaryKey(name, columns));
0661: clearGenerated();
0662:
0663: return this ;
0664: }
0665:
0666: public CreateTable foreignKey(String foreignTable,
0667: String localColumn, String foreignColumn) {
0668: return foreignKey(null, foreignTable, localColumn,
0669: foreignColumn, null, null);
0670: }
0671:
0672: public CreateTable foreignKey(String foreignTable,
0673: String localColumn, String foreignColumn,
0674: ViolationAction onUpdate, ViolationAction onDelete) {
0675: return foreignKey(null, foreignTable, new String[] {
0676: localColumn, foreignColumn }, onUpdate, onDelete);
0677: }
0678:
0679: public CreateTable foreignKey(String foreignTable,
0680: String[] columnsMapping) {
0681: return foreignKey(null, foreignTable, columnsMapping, null,
0682: null);
0683: }
0684:
0685: public CreateTable foreignKey(String foreignTable,
0686: String[] columnsMapping, ViolationAction onUpdate,
0687: ViolationAction onDelete) {
0688: return foreignKey(null, foreignTable, columnsMapping, onUpdate,
0689: onDelete);
0690: }
0691:
0692: public CreateTable foreignKey(String name, String foreignTable,
0693: String localColumn, String foreignColumn) {
0694: return foreignKey(name, foreignTable, localColumn,
0695: foreignColumn, null, null);
0696: }
0697:
0698: public CreateTable foreignKey(String name, String foreignTable,
0699: String localColumn, String foreignColumn,
0700: ViolationAction onUpdate, ViolationAction onDelete) {
0701: return foreignKey(name, foreignTable, new String[] {
0702: localColumn, foreignColumn }, onUpdate, onDelete);
0703: }
0704:
0705: public CreateTable foreignKey(String name, String foreignTable,
0706: String[] columnsMapping) {
0707: return foreignKey(name, foreignTable, columnsMapping, null,
0708: null);
0709: }
0710:
0711: public CreateTable foreignKey(String name, String foreignTable,
0712: String[] columnsMapping, ViolationAction onUpdate,
0713: ViolationAction onDelete) {
0714: if (name != null && 0 == name.length())
0715: throw new IllegalArgumentException("name can't be empty.");
0716: if (null == foreignTable)
0717: throw new IllegalArgumentException(
0718: "foreignTable can't be null.");
0719: if (0 == foreignTable.length())
0720: throw new IllegalArgumentException(
0721: "foreignTable can't be empty.");
0722: if (null == columnsMapping)
0723: throw new IllegalArgumentException(
0724: "columnsMapping array can't be null.");
0725: if (0 == columnsMapping.length)
0726: throw new IllegalArgumentException(
0727: "columnsMapping array can't be empty.");
0728: if (columnsMapping.length % 2 != 0)
0729: throw new IllegalArgumentException(
0730: "columnsMapping array isn't valid, each local column should be mapped to a foreign one.");
0731:
0732: mForeignKeys.add(new ForeignKey(name, foreignTable,
0733: columnsMapping, onUpdate, onDelete));
0734:
0735: clearGenerated();
0736: return this ;
0737: }
0738:
0739: public CreateTable unique(String column) {
0740: return unique(null, column);
0741: }
0742:
0743: public CreateTable unique(String[] columns) {
0744: return unique(null, columns);
0745: }
0746:
0747: public CreateTable unique(String name, String column) {
0748: return unique(name, new String[] { column });
0749: }
0750:
0751: public CreateTable unique(String name, String[] columns) {
0752: if (name != null && 0 == name.length())
0753: throw new IllegalArgumentException("name can't be empty.");
0754: if (null == columns)
0755: throw new IllegalArgumentException(
0756: "columns array can't be null.");
0757: if (0 == columns.length)
0758: throw new IllegalArgumentException(
0759: "columns array can't be empty.");
0760:
0761: mUniqueConstraints.add(new UniqueConstraint(name, columns));
0762:
0763: clearGenerated();
0764: return this ;
0765: }
0766:
0767: public CreateTable check(String expression) {
0768: return check(null, expression);
0769: }
0770:
0771: public CreateTable check(String name, String expression) {
0772: if (name != null && 0 == name.length())
0773: throw new IllegalArgumentException("name can't be empty.");
0774: if (null == expression)
0775: throw new IllegalArgumentException(
0776: "expression can't be null.");
0777: if (0 == expression.length())
0778: throw new IllegalArgumentException(
0779: "expression can't be empty.");
0780:
0781: mCheckConstraints.add(new CheckConstraint(name, expression));
0782:
0783: clearGenerated();
0784: return this ;
0785: }
0786:
0787: public CreateTable clone() {
0788: CreateTable new_instance = (CreateTable) super .clone();
0789: if (new_instance != null) {
0790: if (mColumnMapping != null) {
0791: new_instance.mColumnMapping = new LinkedHashMap<String, Column>();
0792:
0793: Column column = null;
0794: for (String name : mColumnMapping.keySet()) {
0795: column = mColumnMapping.get(name);
0796: new_instance.mColumnMapping.put(name, column
0797: .clone());
0798: }
0799: }
0800:
0801: if (mPrimaryKeys != null) {
0802: new_instance.mPrimaryKeys = new ArrayList<PrimaryKey>();
0803:
0804: for (PrimaryKey primary_key : mPrimaryKeys) {
0805: new_instance.mPrimaryKeys.add(primary_key.clone());
0806: }
0807: }
0808:
0809: if (mForeignKeys != null) {
0810: new_instance.mForeignKeys = new ArrayList<ForeignKey>();
0811:
0812: for (ForeignKey foreign_key : mForeignKeys) {
0813: new_instance.mForeignKeys.add(foreign_key.clone());
0814: }
0815: }
0816:
0817: if (mUniqueConstraints != null) {
0818: new_instance.mUniqueConstraints = new ArrayList<UniqueConstraint>();
0819:
0820: for (UniqueConstraint unique_constraint : mUniqueConstraints) {
0821: new_instance.mUniqueConstraints
0822: .add(unique_constraint.clone());
0823: }
0824: }
0825:
0826: if (mCheckConstraints != null) {
0827: new_instance.mCheckConstraints = new ArrayList<CheckConstraint>();
0828:
0829: for (CheckConstraint check_constraint : mCheckConstraints) {
0830: new_instance.mCheckConstraints.add(check_constraint
0831: .clone());
0832: }
0833: }
0834: }
0835:
0836: return new_instance;
0837: }
0838:
0839: public class PrimaryKey extends ColumnsConstraint implements
0840: Cloneable {
0841: PrimaryKey(String name, String[] columns) {
0842: super (name, columns);
0843: }
0844:
0845: String getSql(Template template) throws DbQueryException {
0846: assert template != null;
0847:
0848: String result = null;
0849:
0850: if (getName() != null
0851: && template.hasValueId("PRIMARY_KEY_NAME")) {
0852: template.setValue("NAME", getName());
0853: template.setValue("PRIMARY_KEY_NAME", template
0854: .getBlock("PRIMARY_KEY_NAME"));
0855: }
0856:
0857: template.setValue("COLUMN_NAMES", StringUtils.join(
0858: getColumns(), template.getBlock("SEPERATOR")));
0859:
0860: result = template.getBlock("PRIMARY_KEY");
0861: if (0 == result.length()) {
0862: throw new UnsupportedSqlFeatureException("PRIMARY KEY",
0863: mDatasource.getAliasedDriver());
0864: }
0865:
0866: assert result != null;
0867:
0868: return result;
0869: }
0870:
0871: public PrimaryKey clone() {
0872: return (PrimaryKey) super .clone();
0873: }
0874: }
0875:
0876: public class ForeignKey extends ColumnsConstraint implements
0877: Cloneable {
0878: private String mForeignTable = null;
0879: private ViolationAction mOnUpdate = null;
0880: private ViolationAction mOnDelete = null;
0881:
0882: ForeignKey(String name, String foreignTable,
0883: String[] columnsMapping, ViolationAction onUpdate,
0884: ViolationAction onDelete) {
0885: super (name, columnsMapping);
0886: setForeignTable(foreignTable);
0887: setOnUpdate(onUpdate);
0888: setOnDelete(onDelete);
0889: }
0890:
0891: String getSql(Template template) throws DbQueryException {
0892: assert template != null;
0893:
0894: String block = null;
0895: String result = null;
0896:
0897: if (getName() != null) {
0898: template.setValue("NAME", getName());
0899: template.setValue("FOREIGN_KEY_NAME", template
0900: .getBlock("FOREIGN_KEY_NAME"));
0901: }
0902:
0903: template.setValue("FOREIGN_TABLE", getForeignTable());
0904:
0905: String violations_actions = "";
0906: if (getOnUpdate() != null) {
0907: block = template.getBlock("ON_UPDATE_"
0908: + getOnUpdate().toString());
0909: if (0 == block.length()) {
0910: throw new UnsupportedSqlFeatureException(
0911: "ON UPDATE " + getOnUpdate().toString(),
0912: mDatasource.getAliasedDriver());
0913: }
0914: template.setValue("ON_UPDATE_ACTION", block);
0915: block = template.getBlock("ON_UPDATE");
0916: if (0 == block.length()) {
0917: throw new UnsupportedSqlFeatureException(
0918: "ON UPDATE", mDatasource.getAliasedDriver());
0919: }
0920: violations_actions += block;
0921: }
0922:
0923: if (getOnDelete() != null) {
0924: block = template.getBlock("ON_DELETE_"
0925: + getOnDelete().toString());
0926: if (0 == block.length()) {
0927: throw new UnsupportedSqlFeatureException(
0928: "ON DELETE " + getOnDelete().toString(),
0929: mDatasource.getAliasedDriver());
0930: }
0931: template.setValue("ON_DELETE_ACTION", block);
0932: block = template.getBlock("ON_DELETE");
0933: if (0 == block.length()) {
0934: throw new UnsupportedSqlFeatureException(
0935: "ON DELETE", mDatasource.getAliasedDriver());
0936: }
0937: violations_actions += block;
0938: }
0939: template.setValue("VIOLATION_ACTIONS", violations_actions);
0940:
0941: String[] local_columns = new String[getColumns().length / 2];
0942: String[] foreign_columns = new String[getColumns().length / 2];
0943: for (int i = 0; i < getColumns().length; i += 2) {
0944: local_columns[i / 2] = getColumns()[i];
0945: foreign_columns[i / 2] = getColumns()[i + 1];
0946: }
0947: template.setValue("LOCAL_COLUMN_NAMES", StringUtils.join(
0948: local_columns, template.getBlock("SEPERATOR")));
0949: template.setValue("FOREIGN_COLUMN_NAMES", StringUtils.join(
0950: foreign_columns, template.getBlock("SEPERATOR")));
0951:
0952: result = template.getBlock("FOREIGN_KEY");
0953: if (0 == result.length()) {
0954: throw new UnsupportedSqlFeatureException("FOREIGN KEY",
0955: mDatasource.getAliasedDriver());
0956: }
0957:
0958: assert result != null;
0959:
0960: return result;
0961: }
0962:
0963: public String getForeignTable() {
0964: return mForeignTable;
0965: }
0966:
0967: void setForeignTable(String foreignTable) {
0968: assert foreignTable != null;
0969: assert foreignTable.length() > 0;
0970:
0971: mForeignTable = foreignTable;
0972: }
0973:
0974: public ViolationAction getOnUpdate() {
0975: return mOnUpdate;
0976: }
0977:
0978: void setOnUpdate(ViolationAction onUpdate) {
0979: mOnUpdate = onUpdate;
0980: }
0981:
0982: public ViolationAction getOnDelete() {
0983: return mOnDelete;
0984: }
0985:
0986: void setOnDelete(ViolationAction onDelete) {
0987: mOnDelete = onDelete;
0988: }
0989:
0990: public ForeignKey clone() {
0991: return (ForeignKey) super .clone();
0992: }
0993: }
0994:
0995: public class UniqueConstraint extends ColumnsConstraint implements
0996: Cloneable {
0997: UniqueConstraint(String name, String[] columns) {
0998: super (name, columns);
0999: }
1000:
1001: String getSql(Template template) throws DbQueryException {
1002: assert template != null;
1003:
1004: String result = null;
1005:
1006: if (getName() != null) {
1007: template.setValue("NAME", getName());
1008: template.setValue("UNIQUE_CONSTRAINT_NAME", template
1009: .getBlock("UNIQUE_CONSTRAINT_NAME"));
1010: }
1011:
1012: template.setValue("COLUMN_NAMES", StringUtils.join(
1013: getColumns(), template.getBlock("SEPERATOR")));
1014:
1015: result = template.getBlock("UNIQUE_CONSTRAINT");
1016: if (0 == result.length()) {
1017: throw new UnsupportedSqlFeatureException("UNIQUE",
1018: mDatasource.getAliasedDriver());
1019: }
1020:
1021: return result;
1022: }
1023:
1024: public UniqueConstraint clone() {
1025: return (UniqueConstraint) super .clone();
1026: }
1027: }
1028:
1029: public class CheckConstraint extends Constraint implements
1030: Cloneable {
1031: private String mExpression = null;
1032:
1033: CheckConstraint(String name, String expression) {
1034: super (name);
1035: setExpression(expression);
1036: }
1037:
1038: String getSql(Template template) throws DbQueryException {
1039: assert template != null;
1040:
1041: String result = null;
1042:
1043: if (getName() != null && template.hasValueId("CHECK_NAME")) {
1044: template.setValue("NAME", getName());
1045: template.setValue("CHECK_NAME", template
1046: .getBlock("CHECK_NAME"));
1047: }
1048:
1049: if (template.hasValueId("EXPRESSION")) {
1050: template.setValue("EXPRESSION", getExpression());
1051: }
1052:
1053: result = template.getBlock("CHECK");
1054: if (0 == result.length()) {
1055: throw new UnsupportedSqlFeatureException("CHECK",
1056: mDatasource.getAliasedDriver());
1057: }
1058:
1059: return result;
1060: }
1061:
1062: public String getExpression() {
1063: return mExpression;
1064: }
1065:
1066: void setExpression(String expression) {
1067: mExpression = expression;
1068: }
1069:
1070: public CheckConstraint clone() {
1071: return (CheckConstraint) super .clone();
1072: }
1073: }
1074:
1075: public abstract class ColumnsConstraint extends Constraint
1076: implements Cloneable {
1077: private String[] mColumns = null;
1078:
1079: ColumnsConstraint(String name, String[] columns) {
1080: super (name);
1081:
1082: setColumns(columns);
1083: }
1084:
1085: public String[] getColumns() {
1086: return mColumns;
1087: }
1088:
1089: void setColumns(String[] columns) {
1090: assert columns != null;
1091: assert columns.length > 0;
1092:
1093: mColumns = columns;
1094: }
1095:
1096: public ColumnsConstraint clone() {
1097: return (ColumnsConstraint) super .clone();
1098: }
1099: }
1100:
1101: public abstract class Constraint implements Cloneable {
1102: private String mName = null;
1103:
1104: Constraint(String name) {
1105: setName(name);
1106: }
1107:
1108: abstract String getSql(Template template)
1109: throws DbQueryException;
1110:
1111: public String getName() {
1112: return mName;
1113: }
1114:
1115: void setName(String name) {
1116: assert null == name || name.length() > 0;
1117:
1118: mName = name;
1119: }
1120:
1121: public Constraint clone() {
1122: Constraint new_instance = null;
1123: try {
1124: new_instance = (Constraint) super .clone();
1125: } catch (CloneNotSupportedException e) {
1126: new_instance = null;
1127: }
1128:
1129: return new_instance;
1130: }
1131: }
1132:
1133: public class Column implements Cloneable {
1134: private String mName = null;
1135: private Class mType = null;
1136: private int mPrecision = -1;
1137: private int mScale = -1;
1138: private String mTypeAttribute = null;
1139: private Nullable mNullable = null;
1140: private String mDefault = null;
1141: private ArrayList<String> mCustomAttributes = new ArrayList<String>();
1142:
1143: Column(String name, Class type) {
1144: setName(name);
1145: setType(type);
1146: }
1147:
1148: Column(String name, Class type, int precision, int scale,
1149: String typeAttribute, Nullable nullable) {
1150: setName(name);
1151: setType(type);
1152: setPrecision(precision);
1153: setScale(scale);
1154: setTypeAttribute(typeAttribute);
1155: setNullable(nullable);
1156: }
1157:
1158: String getSql(Template template) throws DbQueryException {
1159: assert template != null;
1160:
1161: String block = null;
1162: String result = null;
1163:
1164: template.setValue("NAME", getName());
1165: template.setValue("TYPE", mDatasource.getSqlConversion()
1166: .getSqlType(getType(), getPrecision(), getScale()));
1167: if (mTypeAttribute != null) {
1168: template.appendValue("TYPE", " ");
1169: template.appendValue("TYPE", mTypeAttribute);
1170: }
1171:
1172: if (getNullable() != null) {
1173: block = template.getBlock(getNullable().toString());
1174: if (0 == block.length()) {
1175: throw new UnsupportedSqlFeatureException(
1176: "NULLABLE " + getNullable().toString(),
1177: mDatasource.getAliasedDriver());
1178: }
1179: template.setValue("NULLABLE", block);
1180: }
1181: if (getDefault() != null) {
1182: template.setValue("V", getDefault());
1183: block = template.getBlock("DEFAULT");
1184: if (0 == block.length()) {
1185: throw new UnsupportedSqlFeatureException("DEFAULT",
1186: mDatasource.getAliasedDriver());
1187: }
1188: template.setValue("DEFAULT", block);
1189: template.removeValue("V");
1190: }
1191: if (getCustomAttributes().size() > 0) {
1192: template.setValue("V", StringUtils.join(
1193: getCustomAttributes(), " "));
1194: block = template.getBlock("CUSTOM_ATTRIBUTES");
1195: if (0 == block.length()) {
1196: throw new UnsupportedSqlFeatureException(
1197: "CUSTOM_ATTRIBUTES", mDatasource
1198: .getAliasedDriver());
1199: }
1200: template.setValue("CUSTOM_ATTRIBUTES", block);
1201: template.removeValue("V");
1202: }
1203: result = template.getBlock("COLUMN");
1204: if (0 == result.length()) {
1205: throw new UnsupportedSqlFeatureException("COLUMN",
1206: mDatasource.getAliasedDriver());
1207: }
1208: template.removeValue("NAME");
1209: template.removeValue("TYPE");
1210: template.removeValue("NULLABLE");
1211: template.removeValue("DEFAULT");
1212: template.removeValue("CUSTOM_ATTRIBUTES");
1213:
1214: assert result.length() > 0;
1215:
1216: return result;
1217: }
1218:
1219: public String getName() {
1220: return mName;
1221: }
1222:
1223: void setName(String name) {
1224: assert name != null;
1225: assert name.length() > 0;
1226:
1227: mName = name;
1228: }
1229:
1230: public Class getType() {
1231: return mType;
1232: }
1233:
1234: void setType(Class type) {
1235: assert type != null;
1236:
1237: mType = type;
1238: }
1239:
1240: public int getPrecision() {
1241: return mPrecision;
1242: }
1243:
1244: void setPrecision(int precision) {
1245: assert precision >= -1;
1246:
1247: mPrecision = precision;
1248: }
1249:
1250: public int getScale() {
1251: return mScale;
1252: }
1253:
1254: void setScale(int scale) {
1255: assert scale >= -1;
1256:
1257: mScale = scale;
1258: }
1259:
1260: public String getTypeAttribute() {
1261: return mTypeAttribute;
1262: }
1263:
1264: void setTypeAttribute(String typeAttribute) {
1265: mTypeAttribute = typeAttribute;
1266: }
1267:
1268: public Nullable getNullable() {
1269: return mNullable;
1270: }
1271:
1272: void setNullable(Nullable nullable) {
1273: mNullable = nullable;
1274: }
1275:
1276: public String getDefault() {
1277: return mDefault;
1278: }
1279:
1280: void setDefault(String defaultStatement) {
1281: mDefault = defaultStatement;
1282: }
1283:
1284: void addCustomAttribute(String attribute) {
1285: assert attribute != null;
1286: assert attribute.length() > 0;
1287:
1288: mCustomAttributes.add(attribute);
1289: }
1290:
1291: public ArrayList<String> getCustomAttributes() {
1292: return mCustomAttributes;
1293: }
1294:
1295: public Column clone() {
1296: Column new_instance = null;
1297: try {
1298: new_instance = (Column) super .clone();
1299:
1300: if (mCustomAttributes != null) {
1301: new_instance.mCustomAttributes = new ArrayList<String>();
1302: new_instance.mCustomAttributes
1303: .addAll(mCustomAttributes);
1304: }
1305: } catch (CloneNotSupportedException e) {
1306: new_instance = null;
1307: }
1308:
1309: return new_instance;
1310: }
1311: }
1312:
1313: public static class ViolationAction extends EnumClass<String> {
1314: ViolationAction(String identifier) {
1315: super (identifier);
1316: }
1317: }
1318:
1319: public static class Nullable extends EnumClass<String> {
1320: Nullable(String identifier) {
1321: super(identifier);
1322: }
1323: }
1324: }
|