diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/DbDdlSyntax.java b/src/main/java/com/avaje/ebean/config/dbplatform/DbDdlSyntax.java index 8866ef78c..799bb507a 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/DbDdlSyntax.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/DbDdlSyntax.java @@ -7,30 +7,35 @@ import com.avaje.ebean.config.TableName; */ public class DbDdlSyntax { - private boolean renderIndexForFkey = true; + protected boolean renderIndexForFkey = true; - private boolean inlinePrimaryKeyConstraint = false; + protected boolean inlinePrimaryKeyConstraint = false; - private boolean addOneToOneUniqueContraint = true; + protected boolean addOneToOneUniqueContraint = true; - private int maxConstraintNameLength = 32; + protected int maxConstraintNameLength = 32; - private int columnNameWidth = 25; + protected int columnNameWidth = 25; - private String dropTableCascade; - private String dropIfExists; + /** + * Flag set when we want to disable constraints on each table (rather than globally). + */ + protected boolean dropKeyConstraints; - private String newLine = "\n"; + protected String dropTableCascade; + protected String dropIfExists; - private String identity = "auto_increment"; - private String identitySuffix = ""; + protected String newLine = "\n"; - private String pkPrefix = "pk_"; + protected String identity = "auto_increment"; + protected String identitySuffix = ""; - private String disableReferentialIntegrity; - private String enableReferentialIntegrity; + protected String pkPrefix = "pk_"; - private String foreignKeySuffix; + protected String disableReferentialIntegrity; + protected String enableReferentialIntegrity; + + protected String foreignKeySuffix; /** * Return the primary key name for a given bean descriptor. @@ -158,6 +163,20 @@ public class DbDdlSyntax { this.enableReferentialIntegrity = enableReferentialIntegrity; } + /** + * Return true to is constraints are disabled on each table. + */ + public boolean isDropKeyConstraints() { + return dropKeyConstraints; + } + + /** + * Return some DDL to disable constraints on the given table. + */ + public String dropKeyConstraintPrefix(String tableName, String fkName) { + return null; + } + /** * Return true if indexes should be created for the foreign keys. */ @@ -188,6 +207,13 @@ public class DbDdlSyntax { this.dropIfExists = dropIfExists; } + /** + * Return prefix text that goes before drop table. + */ + public String dropTablePrefix(String tableName) { + return ""; + } + /** * Return the cascade option for the drop table command. */ diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/MsSqlServer2005Platform.java b/src/main/java/com/avaje/ebean/config/dbplatform/MsSqlServer2005Platform.java index 65149df87..f7c1fc145 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/MsSqlServer2005Platform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/MsSqlServer2005Platform.java @@ -17,8 +17,12 @@ public class MsSqlServer2005Platform extends DatabasePlatform { public MsSqlServer2005Platform() { super(); this.name = "mssqlserver2005"; + // effectively disable persistBatchOnCascade mode for SQL Server + // due to lack of support for getGeneratedKeys in batch mode + this.disallowBatchOnCascade = true; + this.idInExpandedForm = true; this.sqlLimiter = new MsSqlServer2005SqlLimiter(); - this.dbDdlSyntax.setIdentity("identity(1,1)"); + this.dbDdlSyntax = new MsDdlSyntax(); this.dbIdentity.setIdType(IdType.IDENTITY); this.dbIdentity.setSupportsGetGeneratedKeys(true); this.dbIdentity.setSupportsIdentity(true); @@ -28,6 +32,7 @@ public class MsSqlServer2005Platform extends DatabasePlatform { dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0")); + dbTypeMap.put(Types.INTEGER, new DbType("integer", false)); dbTypeMap.put(Types.BIGINT, new DbType("numeric", 19)); dbTypeMap.put(Types.REAL, new DbType("float(16)")); dbTypeMap.put(Types.DOUBLE, new DbType("float(32)")); @@ -45,4 +50,30 @@ public class MsSqlServer2005Platform extends DatabasePlatform { } + /** + * MS SQL Server specific DDL Syntax. + */ + public class MsDdlSyntax extends DbDdlSyntax { + + MsDdlSyntax() { + this.identity = "identity(1,1)"; + this.dropKeyConstraints = true; + } + + /** + * Return some DDL to disable constraints on the given table. + */ + public String dropKeyConstraintPrefix(String tableName, String fkName) { + return "IF OBJECT_ID('"+fkName+"', 'F') IS NOT NULL"; + } + + /** + * Return prefix text that goes before drop table. + */ + public String dropTablePrefix(String tableName) { + return "IF OBJECT_ID('"+tableName+"', 'U') IS NOT NULL "; + } + + } + } diff --git a/src/main/java/com/avaje/ebeaninternal/server/ddl/AddForeignKeysVisitor.java b/src/main/java/com/avaje/ebeaninternal/server/ddl/AddForeignKeysVisitor.java index e662aba5d..a61476e5c 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/ddl/AddForeignKeysVisitor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/ddl/AddForeignKeysVisitor.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.ddl; +import com.avaje.ebean.config.dbplatform.DbDdlSyntax; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; import com.avaje.ebeaninternal.server.deploy.BeanProperty; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne; @@ -16,23 +17,23 @@ public class AddForeignKeysVisitor extends AbstractBeanVisitor { final FkeyPropertyVisitor pv; - public AddForeignKeysVisitor(DdlGenContext ctx) { + public AddForeignKeysVisitor(boolean addMode, DdlGenContext ctx) { this.ctx = ctx; - this.pv = new FkeyPropertyVisitor(this, ctx); + this.pv = new FkeyPropertyVisitor(addMode, this, ctx); } - public boolean visitBean(BeanDescriptor descriptor) { - if (!descriptor.isInheritanceRoot()){ - // ignore/skip if not a top level BeanDescriptor - return false; - } - return true; - } - - public void visitBeanEnd(BeanDescriptor descriptor) { - - visitInheritanceProperties(descriptor, pv); + public boolean visitBean(BeanDescriptor descriptor) { + if (!descriptor.isInheritanceRoot()) { + // ignore/skip if not a top level BeanDescriptor + return false; } + return true; + } + + public void visitBeanEnd(BeanDescriptor descriptor) { + + visitInheritanceProperties(descriptor, pv); + } public void visitBegin() { } @@ -48,11 +49,17 @@ public class AddForeignKeysVisitor extends AbstractBeanVisitor { public static class FkeyPropertyVisitor extends BaseTablePropertyVisitor { + /** + * Set to false when generating drop foreign key statements. + */ + final boolean addMode; + final DdlGenContext ctx; final AddForeignKeysVisitor parent; - public FkeyPropertyVisitor(AddForeignKeysVisitor parent, DdlGenContext ctx) { + public FkeyPropertyVisitor(boolean addMode, AddForeignKeysVisitor parent, DdlGenContext ctx) { + this.addMode = addMode; this.parent = parent; this.ctx = ctx; } @@ -69,51 +76,59 @@ public class AddForeignKeysVisitor extends AbstractBeanVisitor { // Alter table o_address add Foreign Key (country_code) references o_country (code) on delete restrict on update restrict; String baseTable = p.getBeanDescriptor().getBaseTable(); - TableJoin tableJoin = p.getTableJoin(); - TableJoinColumn[] columns = tableJoin.columns(); - String tableName = p.getBeanDescriptor().getBaseTable(); - String fkName = ctx.getDdlSyntax().getForeignKeyName(tableName, p.getName(), ctx.incrementFkCount()); - - ctx.write("alter table ").write(baseTable).write(" add "); + DbDdlSyntax ddlSyntax = ctx.getDdlSyntax(); + String fkName = ddlSyntax.getForeignKeyName(tableName, p.getName(), ctx.incrementFkCount()); + + if (!addMode) { + // look to generate drop foreign key statement + String dropKeyConstraintPrefix = ddlSyntax.dropKeyConstraintPrefix(tableName, fkName); + if (dropKeyConstraintPrefix != null && !dropKeyConstraintPrefix.isEmpty()) { + ctx.write(dropKeyConstraintPrefix).write(" "); + } + } + + ctx.write("alter table ").write(baseTable).write(addOrDrop()); if (fkName != null) { ctx.write("constraint ").write(fkName).write(" "); } - ctx.write("foreign key ("); - for (int i = 0; i < columns.length; i++) { - if (i > 0){ - ctx.write(","); - } - ctx.write(columns[i].getLocalDbColumn()); - } - ctx.write(")"); + if (addMode) { + ctx.write("foreign key ("); + for (int i = 0; i < columns.length; i++) { + if (i > 0) { + ctx.write(","); + } + ctx.write(columns[i].getLocalDbColumn()); + } + ctx.write(")"); - ctx.write(" references "); - ctx.write(tableJoin.getTable()); - ctx.write(" ("); - for (int i = 0; i < columns.length; i++) { - if (i > 0){ - ctx.write(","); - } - ctx.write(columns[i].getForeignDbColumn()); - } - ctx.write(")"); + ctx.write(" references "); + ctx.write(tableJoin.getTable()); + ctx.write(" ("); + for (int i = 0; i < columns.length; i++) { + if (i > 0) { + ctx.write(","); + } + ctx.write(columns[i].getForeignDbColumn()); + } + ctx.write(")"); - String fkeySuffix = ctx.getDdlSyntax().getForeignKeySuffix(); - if (fkeySuffix != null){ - ctx.write(" ").write(fkeySuffix); - } + String fkeySuffix = ctx.getDdlSyntax().getForeignKeySuffix(); + if (fkeySuffix != null) { + ctx.write(" ").write(fkeySuffix); + } + } ctx.write(";").writeNewLine(); - if (ctx.getDdlSyntax().isRenderIndexForFkey()){ + if (addMode && ddlSyntax.isRenderIndexForFkey()){ //create index idx_fk_o_address_ctry on o_address(country_code); ctx.write("create index "); - String idxName = ctx.getDdlSyntax().getIndexName(tableName, p.getName(), ctx.incrementIxCount()); + String idxName = ddlSyntax.getIndexName(tableName, p.getName(), ctx.incrementIxCount()); if (idxName != null){ ctx.write(idxName); } @@ -129,21 +144,27 @@ public class AddForeignKeysVisitor extends AbstractBeanVisitor { } } - @Override - public void visitScalar(BeanProperty p) { - // not interested - } + /** + * Return 'add' or 'drop' of foreign key. + */ + protected String addOrDrop() { + return addMode ? " add " : " drop " ; + } - @Override - public void visitCompound(BeanPropertyCompound p) { - // not interested - } + @Override + public void visitScalar(BeanProperty p) { + // not interested + } - @Override - public void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p) { - // not interested - } - - } + @Override + public void visitCompound(BeanPropertyCompound p) { + // not interested + } + + @Override + public void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p) { + // not interested + } + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/ddl/DdlGenerator.java b/src/main/java/com/avaje/ebeaninternal/server/ddl/DdlGenerator.java index 320c63529..bfa3ab33f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/ddl/DdlGenerator.java +++ b/src/main/java/com/avaje/ebeaninternal/server/ddl/DdlGenerator.java @@ -126,6 +126,13 @@ public class DdlGenerator implements SpiEbeanPlugin { DdlGenContext ctx = createContext(); + if (ctx.getDdlSyntax().isDropKeyConstraints()) { + // generate drop foreign key constraint statements (sql server joy) + AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(false, ctx); + VisitorUtil.visit(server, fkeys); + ctx.writeNewLine(); + } + DropTableVisitor drop = new DropTableVisitor(ctx); VisitorUtil.visit(server, drop); @@ -146,7 +153,7 @@ public class DdlGenerator implements SpiEbeanPlugin { CreateSequenceVisitor createSequence = new CreateSequenceVisitor(ctx); VisitorUtil.visit(server, createSequence); - AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(ctx); + AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(true, ctx); VisitorUtil.visit(server, fkeys); CreateIndexVisitor indexes = new CreateIndexVisitor(ctx); @@ -275,7 +282,6 @@ public class DdlGenerator implements SpiEbeanPlugin { } catch (Exception e) { if (expectErrors) { logger.info(" ... ignoring error executing " + getSummary(stmt) + " error: " + e.getMessage()); - e.printStackTrace(); } else { String msg = "Error executing stmt[" + stmt + "] error[" + e.getMessage() + "]"; throw new RuntimeException(msg, e); diff --git a/src/main/java/com/avaje/ebeaninternal/server/ddl/DropTableVisitor.java b/src/main/java/com/avaje/ebeaninternal/server/ddl/DropTableVisitor.java index 7978f39ca..19e0db9ff 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/ddl/DropTableVisitor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/ddl/DropTableVisitor.java @@ -24,6 +24,7 @@ public class DropTableVisitor implements BeanVisitor { } protected void writeDropTable(String tableName){ + ctx.write(ddlSyntax.dropTablePrefix(tableName)); ctx.write("drop table "); if (ddlSyntax.getDropIfExists() != null){ ctx.write(ddlSyntax.getDropIfExists()).write(" ");