├── .gitignore ├── .gitreview ├── CHANGES ├── HACKING ├── LICENSE ├── README ├── README.md ├── build.sbt ├── project ├── build.properties └── plugins.sbt └── src ├── main └── scala │ └── com │ └── imageworks │ └── migration │ ├── CharacterSetName.scala │ ├── ColumnDefinition.scala │ ├── CommitBehavior.scala │ ├── ConnectionBuilder.scala │ ├── DatabaseAdapter.scala │ ├── DerbyDatabaseAdapter.scala │ ├── ForeignKeyConstraintAction.scala │ ├── JavaDatabaseAdapter.scala │ ├── JavaMigrator.scala │ ├── Migration.scala │ ├── MigrationDirection.scala │ ├── MigrationException.scala │ ├── MigrationStatuses.scala │ ├── Migrator.scala │ ├── MigratorOperation.scala │ ├── MysqlDatabaseAdapter.scala │ ├── Options.scala │ ├── OracleDatabaseAdapter.scala │ ├── PostgresqlDatabaseAdapter.scala │ ├── RichConnection.scala │ ├── SqlType.scala │ ├── TableColumnDefinition.scala │ ├── TableDefinition.scala │ ├── UnquotedNameConverter.scala │ ├── User.scala │ ├── Vendor.scala │ └── With.scala └── test ├── resources └── log4j.properties └── scala └── com └── imageworks └── migration └── tests ├── DatabaseAdapterTests.scala ├── JavaMigratorTests.scala ├── MigrationTests.scala ├── OptionsTests.scala ├── TestDatabase.scala ├── VendorTests.scala ├── WithTests.scala ├── alter_column ├── Migrate_20110214054347_CreateTable.scala └── Migrate_20110214060042_AlterColumn.scala ├── auto_increment └── Migrate_20121226170550_CreateTableWithAutoIncrementingColumn.scala ├── duplicate_descriptions ├── Migrate_20081118191214_FooBar.scala └── Migrate_20081118191215_FooBar.scala ├── duplicate_versions ├── Migrate_20081118191214_Bar.scala └── Migrate_20081118191214_Foo.scala ├── grant_and_revoke ├── Migrate_200811241940_CreateUser.scala ├── Migrate_200811261513_Grants.scala └── Migrate_20121013072344_EmptyPrivilegeList.scala ├── no_migrations └── Stamp.scala ├── scale_without_precision └── Migrate_200812041647_Foo.scala ├── types └── Migrate_20081212213908_CreateTypetestTable.scala ├── up_and_down ├── Migrate_20081118201000_CreateLocationTable.scala └── Migrate_20081118201742_CreatePeopleTable.scala └── vendor └── Migrate_20121104011043_CheckVendor.scala /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .idea_modules/ 3 | target/ 4 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=gerrit.orcaware.com 3 | port=29418 4 | project=scala-migrations.git 5 | defaultbranch=master 6 | defaultremote=origin 7 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | Version 1.1.1 - January 1st, 2013 2 | 3 | * Use slf4j-api as a library dependency and slf4j-log4j12 as a unit 4 | testing dependency. Using slf4j-log4j12 as a library dependency 5 | required that dependent libraries and applications load 6 | slf4j-log4j12 which defeats the purpose of SLF4J. Closes 7 | https://github.com/blair/scala-migrations/issues/1 . 8 | 9 | * Enable unit testing on PostgreSQL when the Java 10 | "scala-migrations.db.vendor" property is set to "postgresql". 11 | 12 | Patches by Alan LaMielle. 13 | 14 | Version 1.1.0 - December 28th, 2012 15 | * Migration adds #databaseVendor to get the database vendor which 16 | can be used for pattern matching for database specific code. 17 | 18 | * Add an AutoIncrement column option which is supported on Derby, 19 | MySQL and PostgreSQL for the SMALLINT, INTEGER and BIGINT column 20 | data types. It instructs the database to provide an 21 | auto-incrementing default value if the application does not 22 | provide one when inserting a new row to the table. 23 | 24 | Derby: 25 | Only supported on SMALLINT, INT and BIGINT data types using 26 | Derby's GENERATED BY DEFAULT AS IDENTITY. The alternate setting 27 | GENERATED ALWAYS AS IDENTITY is not used as it is not consistent 28 | with MySQL and PostgreSQL which permits the application to 29 | explicitly specify the column's value. 30 | 31 | http://db.apache.org/derby/docs/10.9/ref/rrefsqlj37836.html 32 | 33 | MySQL: 34 | Only supported on SMALLINT, INT and BIGINT data types using 35 | MySQL's AUTO_INCREMENT keyword. 36 | 37 | http://dev.mysql.com/doc/refman/5.5/en/create-table.html 38 | http://dev.mysql.com/doc/refman/5.5/en/example-auto-increment.html 39 | 40 | PostgreSQL: 41 | Only supported on SMALLINT, INT and BIGINT data types by 42 | replacing the data type name with SMALLSERIAL, SERIAL and 43 | BIGSERIAL, respectively. Support for SMALLSERIAL is only 44 | available in PostgreSQL 9.2 and greater. 45 | 46 | http://www.postgresql.org/docs/9.2/static/datatype-numeric.html#DATATYPE-SERIAL 47 | 48 | Oracle: 49 | No support is provided in this commit as it appears that 50 | equivalent functionality can only be provided by using triggers. 51 | 52 | * Add support for MySQL: 53 | - MySQL database adapter used if the JDBC driver class is named 54 | com.mysql.jdbc.Driver. 55 | - For grant and revoke operations, generalize the concept of a 56 | user to support MySQL style accounts, e.g. `username`@`hostname`. 57 | 58 | An abstract User base class with two concrete subclasses, 59 | PlainUser and MysqlUser, was added. String usernames, 60 | e.g. "foobar", used on MySQL are converted to the same user from 61 | localhost, e.g. `foobar`@`localhost`, as this is the most secure 62 | default. If database specific usernames are required, pattern 63 | match on the database vendor: 64 | 65 | def up() { 66 | val user = databaseVendor match { 67 | case Mysql => MysqlUser("foobar", "%") 68 | case _ => PlainUser("foobar") 69 | } 70 | ... 71 | ... 72 | } 73 | - Generalize the SQL that drops a drop foreign key constraint. 74 | - Generalize the character used to quote an identifier; MySQL uses '`'. 75 | - Generalize for databases which do not have table and column 76 | constraints, e.g. MySQL. 77 | - Add support for character sets having a collation. 78 | - The Unicode case object specifies the "utf8" character set with 79 | the "utf8_unicode_ci" collation. For an explanation why this 80 | slower collation is used instead the "utf8_general_ci" 81 | collation, which is MySQL's default collation for the "utf8" 82 | character set, see http://stackoverflow.com/questions/766809/ . 83 | - Unit tests run on MySQL. 84 | 85 | * On Derby: 86 | - A limit on the BLOB data type is now reflected in the generated 87 | SQL passed to Derby. 88 | - A limit on a TIMESTAMP is now not passed to Derby since Derby 89 | does not support it. 90 | - Unit tests now use an in memory database for faster turnaround. 91 | 92 | * On PostgreSQL: 93 | - Default values on the BLOB and VARBINARY data types are now 94 | reflected in the generated SQL passed to PostgreSQL. 95 | 96 | * To support PostgreSQL's ability to grant and revoke privileges on 97 | schemas and its USAGE privilege, the following was done: 98 | 99 | - Add a new sealed base Privilege trait that is the super-trait to 100 | all privileges. 101 | - Add a new sealed SchemaPrivilege trait that extends Privilege. 102 | - Add a new UsagePrivilege case object that extends SchemaPrivilege. 103 | - The existing GrantPrivilegeType trait now also extends Privilege. 104 | - The existing AllPrivileges case object now also extends SchemaPrivilege. 105 | - Migration adds #grantSchemaPrivilege() and #revokeSchemaPrivilege() 106 | to add or remove privileges from a schema. 107 | 108 | Patches by Alan LaMielle. 109 | 110 | * The With.*() methods properly handle the closure argument and/or 111 | close() throwing exceptions; functionality inspired by Java 7's 112 | try-with-resources where an exception thrown by closer is not 113 | suppressed if the body did not throw an exception. This ensures 114 | that the caller always is thrown an exception if one occurred. 115 | 116 | http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20.3 117 | 118 | * Scala 2.10.0: 119 | - Add support for 2.10.0. 120 | - Explicitly type exception classes in exception catching pattern 121 | matches. When catching Throwable always log it or rethrow it. 122 | - Fix minor bugs caught by Scala 2.10.0 compiler. 123 | 124 | * Code style cleanups to better match the Scala style guide: 125 | http://docs.scala-lang.org/style/scaladoc.html 126 | 127 | Version 1.0.3 - September 21st, 2012 128 | * Make log4jdbc optional by checking for it at runtime and using it 129 | if it is available. This is to workaround log4jdbc not present in 130 | any public Maven repositories, to make it easier for developers 131 | using build tools with automatic dependency resolution so they do 132 | not have to download log4jdbc themselves: 133 | http://code.google.com/p/log4jdbc/wiki/FAQ 134 | http://code.google.com/p/log4jdbc/issues/detail?id=19 135 | 136 | * For Scala 2.8.0 and greater, switch from ant/ivy to sbt to build 137 | the project. In addition to reducing the number of files checked 138 | into source control to build the project, it also supports easy 139 | publishing to Sonatype's open-source repository. 140 | 141 | Version 1.0.2 - November 8th, 2011 142 | * Issue #22: use java.lang.ClassLoader#getResources() instead of 143 | #getResource() in case there are multiple resources with the same 144 | package name. Now all resources providing the package name are 145 | searched. 146 | 147 | * Issue #23: fix a bug by URL decoding resource URLs so that 148 | resources in directories containing one or more space characters 149 | can be found. 150 | 151 | Version 1.0.1 - February 14th, 2010 152 | * New method Migration#alterColumn() which allows column definitions 153 | to be altered. 154 | 155 | * Initial support for building with Maven. It only builds jars for 156 | JDBC 4/JDK 1.6, not for JDBC 3/JDK 1.5. Build with ant to build 157 | JDBC 3/JDK 1.5 jars. 158 | 159 | * Usernames for Migration#grant() and #revoke() are now converted 160 | into the database's canonical case, e.g. lowercase or uppercase, 161 | and then quoted. 162 | 163 | * Refactor the unit tests to allow for testing with databases other 164 | than Derby. 165 | 166 | * The table names in the unit tests have been renamed to all start 167 | with "scala_migrations_". This makes it easier to unit test the 168 | project in an existing schema. The only table that doesn't start 169 | with "scala_migrations_" is "schema_migrations". 170 | 171 | * Lots of internal refactoring and code cleanup. 172 | 173 | Version 1.0.0 - February 11th, 2010 174 | * Provide Scala 2.8.0.Beta1 support. Code modifications that work 175 | under both Scala 2.7.x and 2.8.x were applied to the default 176 | (2.7.x) branch and merged to the scala-2.8 branch to minimize the 177 | differences between the branches. 178 | 179 | * Fix a bug in dropping indices in Oracle. 180 | 181 | * Index names are now quoted and potentially case converted in the 182 | same manner as column names. 183 | 184 | * Provide a addingForeignKeyConstraintCreatesIndex method in 185 | Migration and DatabaseAdaper that returns true if the database 186 | implicitly adds an index on the column that has a foreign key 187 | constraint added to it. This can be used to dynamically add an 188 | index for those databases that don't implicitly add an index on 189 | foreign key columns. 190 | 191 | * Switch to using scaladoc instead of vscaladoc when compiling with 192 | Scala 2.7.x to be consistent with compilation with Scala 2.8.x. 193 | 194 | * Update the test suite to run against Derby 10.5.3 instead of 195 | 10.5.1.1. 196 | 197 | * Switch code style to be more compliant with standard Scala code, 198 | specifically, remove the space before a : in type annotations. 199 | 200 | Version 0.9.2 - November 2nd, 2009 201 | * Build with Scala 2.7.7. 202 | 203 | Version 0.9.1 - September 2nd, 2009 204 | * Add the ability to add and drop columns in existing tables. The 205 | new methods are addColumn() and removeColumn() in the Migration 206 | class. 207 | 208 | Version 0.9.0 - August 1st, 2009 209 | * First public release. 210 | -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | ### Original Commit 2 | 3 | Please do original work on `master`. The `master` branch is for the 4 | latest stable branch of Scala, e.g. 2.9.Z where Z is the patch version 5 | number. Your commit should work with all Scala patch versions. 6 | 7 | ### Merge Commit For Older Scala Versions 8 | 9 | We maintain `scala-X.Y` branches for older stable Scala versions. 10 | 11 | At all times we support the current stable and previous stable Scala 12 | branches, e.g. 2.9.Z and 2.8.Z, so at a minimum merge your change from 13 | `master` to the branch for the previous stable Scala branch. 14 | 15 | We do this as a benefit for the community to add features for older 16 | Scala versions. Additionally, Sony Pictures Imageworks doesn't have 17 | the cycles to immediately upgrade to the latest Scala version, so for 18 | selfish reasons, we would like it merged back ;) 19 | 20 | ### Test Before Submitting Pull Request 21 | 22 | ##### Testing On a Branch Using sbt 23 | 24 | If you are on a branch that uses sbt, please run the unit tests on all 25 | the Scala versions that the branch supports by using `sbt "+ test"`. 26 | For example, the `scala-2.8` branch supports 2.8.0, 2.8.1 and 2.8.2, 27 | so all three versions would need to be tested. 28 | 29 | We request this since sometimes changes are made to Scala that break 30 | the build on a specific patch version. If the build does break then 31 | the pull request will not be accepted because we do a separate release 32 | for each Scala patch version. 33 | 34 | ##### Testing On a Branch Using ant 35 | 36 | For the `scala-2.7` branch, testing with Scala 2.7.7 is sufficient. 37 | 38 | ### Build and Test Commands 39 | 40 | ##### Scala 2.8 and Above 41 | 42 | The `master` and `scala-X.Y` branches for X.Y >= 2.8 use sbt to build, 43 | run unit tests, and package Scala Migrations. Find sbt at 44 | http://www.scala-sbt.org/ . 45 | 46 | * Install sbt 47 | * http://www.scala-sbt.org/release/docs/Getting-Started/Setup.html 48 | * To build: sbt compile 49 | * To test with the highest Scala version supported by the branch: sbt test 50 | * To test with all Scala versions supported by the branch: sbt "+ test" 51 | * To package all versions (instead of just one): sbt "+ package" 52 | * To generate IntelliJ project: sbt gen-idea 53 | 54 | ##### Scala 2.7 55 | 56 | The `scala-2.7` branch uses ant to build, run unit tests and package 57 | Scala Migrations. 58 | 59 | * Install ant 60 | * To build: ant compile 61 | * To test: ant test 62 | * To package: ant 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008,2009,2010 Sony Pictures Imageworks Inc. 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the 14 | distribution. Neither the name of Sony Pictures Imageworks nor the 15 | names of its contributors may be used to endorse or promote 16 | products derived from this software without specific prior written 17 | permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 30 | OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | import scalariform.formatter.preferences._ 2 | 3 | name := "scala-migrations" 4 | 5 | description := "Database migrations written in Scala." 6 | 7 | homepage := Some(url("http://opensource.imageworks.com/?p=scalamigrations")) 8 | 9 | startYear := Some(2008) 10 | 11 | organization := "com.imageworks.scala-migrations" 12 | 13 | organizationName := "Sony Pictures Imageworks" 14 | 15 | organizationHomepage := Some(url("http://www.imageworks.com/")) 16 | 17 | licenses += "New BSD License" -> url("http://opensource.org/licenses/BSD-3-Clause") 18 | 19 | version := "1.1.2-SNAPSHOT" 20 | 21 | scalaVersion := "2.11.12" 22 | 23 | // For a single major Scala release, e.g. 2.x.y, include at most one 24 | // Scala release candidate in crossScalaVersions, e.g. "2.x.y-RC3". 25 | // When the Scala final release has been published, then replace the 26 | // release candidate with the Scala final release. 27 | crossScalaVersions := Seq("2.9.0", "2.9.0-1", 28 | "2.9.1", "2.9.1-1", 29 | "2.9.2", "2.9.3", 30 | "2.10.4", 31 | "2.11.4") 32 | 33 | // Increase warnings generated by the Scala compiler. 34 | // 35 | // For Scala 2.10 and greater, pass "-feature" to scalac to enable 36 | // warnings for use of features that should be explicitly imported, 37 | // e.g. "import scala.language.implicitConversions" to enable implicit 38 | // conversions. However, since Scala Migrations uses implicit 39 | // conversions and to maintain source compatibility so that separate 40 | // branches are not needed, pass "-language:implicitConversions" so 41 | // that "-feature" can be used without generating spurious warnings. 42 | scalacOptions <++= scalaVersion map { v: String => 43 | val options1 = "-deprecation" :: "-unchecked" :: Nil 44 | if (v.startsWith("2.9.0")) { 45 | options1 46 | } 47 | else { 48 | val options2 = "-Xlint" :: options1 49 | if (v.startsWith("2.9")) 50 | options2 51 | else 52 | "-feature" :: "-language:implicitConversions" :: options2 53 | } 54 | } 55 | 56 | libraryDependencies ++= Seq( 57 | "com.google.code.findbugs" % "jsr305" % "2.0.3", 58 | "com.novocode" % "junit-interface" % "0.10-M4" % "test", 59 | "log4jdbc" % "log4jdbc" % "1.1" from "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/log4jdbc/log4jdbc4-1.1.jar", 60 | "mysql" % "mysql-connector-java" % "[5.1.0,5.2)" % "test", 61 | "org.apache.derby" % "derby" % "[10.5.3.0,10.12)" % "test", 62 | "org.hamcrest" % "hamcrest-core" % "1.3" % "test", 63 | "org.jmock" % "jmock-junit4" % "[2.8.0,3.0)" % "test", 64 | "org.slf4j" % "slf4j-api" % "[1.5.8,2.0)", 65 | "org.slf4j" % "slf4j-log4j12" % "[1.5.8,2.0)" % "test", 66 | "postgresql" % "postgresql" % "9.1-901.jdbc4" % "test") 67 | 68 | // Run unit tests serially otherwise races can occur between two 69 | // threads checking if the 'schema_migrations' table exists and 70 | // trying to create it. 71 | parallelExecution in Test := false 72 | 73 | testOptions += Tests.Argument(TestFrameworks.JUnit, "-v") 74 | 75 | scalariformSettings 76 | 77 | ScalariformKeys.preferences := FormattingPreferences(). 78 | setPreference(AlignParameters, true). 79 | setPreference(CompactControlReadability, true). 80 | setPreference(DoubleIndentClassDeclaration, true) 81 | 82 | publishMavenStyle := true 83 | 84 | publishArtifact in Test := false 85 | 86 | pomIncludeRepository := { _ => false } 87 | 88 | pomExtra := 89 | 90 | 91 | blair 92 | Blair Zajac 93 | blair@orcaware.com 94 | 95 | 96 | jrray 97 | J. Robert Ray 98 | jrobertray@gmail.com 99 | 100 | 101 | 102 | scm:git:git@github.com:imageworks/scala-migrations.git 103 | scm:git:git@github.com:imageworks/scala-migrations.git 104 | git@github.com:imageworks/scala-migrations.git 105 | 106 | 107 | // Do not include log4jdbc as a dependency. 108 | pomPostProcess := { (node: scala.xml.Node) => 109 | val rewriteRule = 110 | new scala.xml.transform.RewriteRule { 111 | override def transform(n: scala.xml.Node): scala.xml.NodeSeq = { 112 | val name = n.nameToString(new StringBuilder).toString 113 | if ( (name == "dependency") 114 | && ((n \ "groupId").text == "log4jdbc") 115 | && ((n \ "artifactId").text == "log4jdbc")) { 116 | scala.xml.NodeSeq.Empty 117 | } 118 | else { 119 | n 120 | } 121 | } 122 | } 123 | val transformer = new scala.xml.transform.RuleTransformer(rewriteRule) 124 | transformer.transform(node)(0) 125 | } 126 | 127 | publishTo := { 128 | val nexus = "https://oss.sonatype.org/" 129 | if (version.value.trim.endsWith("SNAPSHOT")) 130 | Some("snapshots" at nexus + "content/repositories/snapshots") 131 | else 132 | Some("releases" at nexus + "service/local/staging/deploy/maven2") 133 | } 134 | 135 | useGpg := true 136 | 137 | useGpgAgent := true 138 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.18 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.5.1") 2 | 3 | addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.1") 4 | 5 | addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.2.0") 6 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/CharacterSetName.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * The base trait for all character set names. 37 | */ 38 | sealed trait CharacterSetName 39 | 40 | /** 41 | * The character data types should be encoded using Unicode. 42 | * 43 | * On Derby, character data types are encoded using Unicode by 44 | * default so specifying this does not change the encoding. 45 | * 46 | * On MySQL, this case object specifies the "utf8" character set. If 47 | * the collation is not specified then the "utf8_unicode_ci" collation 48 | * is used. See http://stackoverflow.com/questions/766809/ why this 49 | * slower collation is used instead the "utf8_general_ci" collation, 50 | * which is MySQL's default collation for the "utf8" character set. 51 | * 52 | * On Oracle, this specifies that NCHAR is used for CharType and 53 | * NVARCHAR2 for VarcharType. 54 | * 55 | * On PostgreSQL, this case object is ignored as the character set 56 | * encoding can only be specified when the database is created; using 57 | * it generates a runtime warning. 58 | */ 59 | case object Unicode 60 | extends CharacterSetName 61 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/CommitBehavior.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * This sealed trait's specifies the commit behavior on a database 37 | * connection and its subobjects are used as arguments to the 38 | * Migrator#with*Connection() methods. The subobjects specify if a 39 | * new connection's auto-commit mode should be left on or disabled. 40 | * For connections with auto-commit mode disabled it specifies if the 41 | * current transaction should be rolled back or committed if the 42 | * closure passed to Migrator#with*Connection() throws an exception. 43 | */ 44 | private sealed trait CommitBehavior 45 | 46 | /** 47 | * The new database connection's auto-commit mode is left on. Because 48 | * the connection is in auto-commit mode the 49 | * Migrator#with*Connection() methods do not commit nor roll back the 50 | * transaction any before returning the result of the 51 | * Migrator#with*Connection()'s closure or rethrowing its exception. 52 | */ 53 | private case object AutoCommit 54 | extends CommitBehavior 55 | 56 | /** 57 | * The new database connection's auto-commit mode is turned off. 58 | * Regardless if the closure passed to Migrator#with*Connection() 59 | * returns or throws an exception the transaction is committed. 60 | */ 61 | private case object CommitUponReturnOrException 62 | extends CommitBehavior 63 | 64 | /** 65 | * The new database connection's auto-commit mode is turned off. If 66 | * the closure passed to the Migrator#with*Connection() returns 67 | * normally then transaction is committed; if it throws an exception 68 | * then the transaction is rolled back. 69 | */ 70 | private case object CommitUponReturnOrRollbackUponException 71 | extends CommitBehavior 72 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/ConnectionBuilder.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | import java.sql.{ 36 | Connection, 37 | DriverManager 38 | } 39 | import javax.sql.DataSource 40 | 41 | /** 42 | * Adapter class for getting a Connection from either the 43 | * DriverManager or a DataSource. 44 | */ 45 | class ConnectionBuilder private (either: Either[DataSource, String], 46 | loginOpt: Option[(String, String)]) { 47 | /** 48 | * Construct a connection builder for a database that does not need 49 | * a username and password. 50 | * 51 | * @param url the JDBC URL to connect to the database 52 | */ 53 | def this(url: String) { 54 | this(Right(url), None) 55 | } 56 | 57 | /** 58 | * Construct a connection builder for a database that needs a 59 | * username and password. 60 | * 61 | * @param url the JDBC URL to connect to the database 62 | * @param username the username to log into the database 63 | * @param password the password associated with the database 64 | * username 65 | */ 66 | def this(url: String, 67 | username: String, 68 | password: String) { 69 | this(Right(url), Some((username, password))) 70 | } 71 | 72 | /** 73 | * Construct a connection builder with a DataSource for a database 74 | * that does not need a username and password. 75 | * 76 | * @param datasource the JDBC DataSource to connect to the 77 | * database 78 | */ 79 | def this(datasource: DataSource) { 80 | this(Left(datasource), None) 81 | } 82 | 83 | /** 84 | * Construct a connection builder with a DataSource and override the 85 | * default username and password. 86 | * 87 | * @param datasource the JDBC DataSource to connect to the database 88 | * @param username the username to log into the database 89 | * @param password the password associated with the database 90 | * username 91 | */ 92 | def this(datasource: DataSource, 93 | username: String, 94 | password: String) { 95 | this(Left(datasource), Some((username, password))) 96 | } 97 | 98 | def withConnection[R](commitBehavior: CommitBehavior)(f: Function[Connection, R]): R = { 99 | val connection = 100 | (either, loginOpt) match { 101 | case (Left(datasource), Some((username, password))) => 102 | datasource.getConnection(username, password) 103 | case (Left(datasource), None) => 104 | datasource.getConnection 105 | case (Right(url), Some((username, password))) => 106 | DriverManager.getConnection(url, username, password) 107 | case (Right(url), None) => 108 | DriverManager.getConnection(url) 109 | } 110 | 111 | With.autoClosingConnection(connection) { c => 112 | With.autoCommittingConnection(c, commitBehavior)(f) 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/DerbyDatabaseAdapter.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | trait DerbyAutoIncrementingColumnDefinitionMixin 36 | extends ColumnDefinition 37 | with ColumnSupportsAutoIncrement { 38 | override protected abstract def sql: String = { 39 | if (isAutoIncrement) super.sql + " GENERATED BY DEFAULT AS IDENTITY" 40 | else super.sql 41 | } 42 | } 43 | 44 | // Derby 10.2 and greater support an optional limit on the BLOB's 45 | // size. 46 | class DerbyBlobColumnDefinition 47 | extends DefaultBlobColumnDefinition 48 | with ColumnSupportsLimit 49 | 50 | class DerbyBigintColumnDefinition 51 | extends DefaultBigintColumnDefinition 52 | with DerbyAutoIncrementingColumnDefinitionMixin 53 | 54 | class DerbyIntegerColumnDefinition 55 | extends DefaultIntegerColumnDefinition 56 | with DerbyAutoIncrementingColumnDefinitionMixin 57 | 58 | class DerbySmallintColumnDefinition 59 | extends DefaultSmallintColumnDefinition 60 | with DerbyAutoIncrementingColumnDefinitionMixin 61 | 62 | // Derby does not support size specifiers for the TIMESTAMP data type. 63 | class DerbyTimestampColumnDefinition 64 | extends ColumnDefinition 65 | with ColumnSupportsDefault { 66 | override protected def sql = "TIMESTAMP" 67 | } 68 | 69 | class DerbyVarbinaryColumnDefinition 70 | extends DefaultVarbinaryColumnDefinition { 71 | override protected def sql = { 72 | optionallyAddLimitToDataType("VARCHAR") + " FOR BIT DATA" 73 | } 74 | } 75 | 76 | class DerbyDatabaseAdapter(override val schemaNameOpt: Option[String]) 77 | extends DatabaseAdapter(schemaNameOpt) { 78 | override val vendor = Derby 79 | 80 | override val quoteCharacter = '"' 81 | 82 | override val unquotedNameConverter = UppercaseUnquotedNameConverter 83 | 84 | override val userFactory = PlainUserFactory 85 | 86 | override val alterTableDropForeignKeyConstraintPhrase = "CONSTRAINT" 87 | 88 | override val addingForeignKeyConstraintCreatesIndex = true 89 | 90 | override val supportsCheckConstraints = true 91 | 92 | override def columnDefinitionFactory(columnType: SqlType, 93 | characterSetOpt: Option[CharacterSet]): ColumnDefinition = { 94 | characterSetOpt match { 95 | case None => 96 | case Some(CharacterSet(Unicode, None)) => 97 | case Some(charset @ CharacterSet(Unicode, Some(collation))) => 98 | logger.warn("Ignoring collation '{}' in '{}' as Derby only " + 99 | "supports setting the collation when the database " + 100 | "is created.", 101 | Array[AnyRef](collation, charset): _*) 102 | case Some(charset @ CharacterSet(_, _)) => 103 | logger.warn("Ignoring '{}' as Derby uses Unicode sequences to " + 104 | "represent character data types.", 105 | charset) 106 | } 107 | 108 | columnType match { 109 | case BigintType => 110 | new DerbyBigintColumnDefinition 111 | case BlobType => 112 | new DerbyBlobColumnDefinition 113 | case BooleanType => { 114 | val message = "Derby 10.6 and older do not support BOOLEAN as a " + 115 | "legal data type, you must choose a mapping yourself." 116 | throw new UnsupportedColumnTypeException(message) 117 | } 118 | case CharType => 119 | new DefaultCharColumnDefinition 120 | case DecimalType => 121 | new DefaultDecimalColumnDefinition 122 | case IntegerType => 123 | new DerbyIntegerColumnDefinition 124 | case SmallintType => 125 | new DerbySmallintColumnDefinition 126 | case TimestampType => 127 | new DerbyTimestampColumnDefinition 128 | case VarbinaryType => 129 | new DerbyVarbinaryColumnDefinition 130 | case VarcharType => 131 | new DefaultVarcharColumnDefinition 132 | } 133 | } 134 | 135 | override protected def alterColumnSql(schemaNameOpt: Option[String], 136 | columnDefinition: ColumnDefinition): String = { 137 | new java.lang.StringBuilder(512) 138 | .append("ALTER TABLE ") 139 | .append(quoteTableName(schemaNameOpt, columnDefinition.getTableName)) 140 | .append(" ALTER ") 141 | .append(quoteColumnName(columnDefinition.getColumnName)) 142 | .append(" SET DATA TYPE ") 143 | .append(columnDefinition.toSql) 144 | .toString 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/ForeignKeyConstraintAction.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * The base trait for all foreign key actions upon delete or update. 37 | */ 38 | sealed trait ForeignKeyConstraintAction { 39 | val sql: String 40 | } 41 | 42 | /** 43 | * Delete any rows in the referencing table that refer to rows deleted 44 | * in the referenced table, or update the row's value to the new value 45 | * in the referenced row if it was updated. 46 | */ 47 | case object Cascade 48 | extends ForeignKeyConstraintAction { 49 | override val sql = "CASCADE" 50 | } 51 | 52 | /** 53 | * Generate an error that updating or deleting the row would cause a 54 | * foreign key constraint violation. In some databases, NO ACTION 55 | * implies a deferred check, after all deletes have been performed. 56 | */ 57 | case object NoAction 58 | extends ForeignKeyConstraintAction { 59 | override val sql = "NO ACTION" 60 | } 61 | 62 | /** 63 | * Generate an error that updating or deleting the row would cause a 64 | * foreign key constraint violation. This is the same as NoAction, 65 | * except that any checks are not deferred. 66 | */ 67 | case object Restrict 68 | extends ForeignKeyConstraintAction { 69 | override val sql = "RESTRICT" 70 | } 71 | 72 | /** 73 | * Set any rows in the referencing table to their default value when 74 | * the referenced rows are deleted or updated. Not all databases 75 | * support SET DEFAULT for ON UPDATE. 76 | */ 77 | case object SetDefault 78 | extends ForeignKeyConstraintAction { 79 | override val sql = "SET DEFAULT" 80 | } 81 | 82 | /** 83 | * Set any rows in the referencing table to NULL when the referenced 84 | * rows are deleted or updated. Not all databases support SET DEFAULT 85 | * for ON UPDATE. 86 | */ 87 | case object SetNull 88 | extends ForeignKeyConstraintAction { 89 | override val sql = "SET NULL" 90 | } 91 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/JavaDatabaseAdapter.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * The Scala Database Adapter classes uses Scala case classes in their public 37 | * constructors and public methods which makes it difficult to use from a pure 38 | * Java environment. This class provides Java-friendly factory functions to 39 | * create adapters. 40 | */ 41 | object JavaDatabaseAdapter { 42 | /** 43 | * Create a Derby Database Adapter. 44 | * 45 | * @return newly constructed DerbyDatabaseAdapter 46 | */ 47 | def getDerbyDatabaseAdapter: DerbyDatabaseAdapter = { 48 | new DerbyDatabaseAdapter(None) 49 | } 50 | 51 | /** 52 | * Create a Derby Database Adapter. 53 | * 54 | * @param schemaName the default schema name in the adapter 55 | * @return newly constructed DerbyDatabaseAdapter 56 | */ 57 | def getDerbyDatabaseAdapter(schemaName: String): DerbyDatabaseAdapter = { 58 | new DerbyDatabaseAdapter(Some(schemaName)) 59 | } 60 | 61 | /** 62 | * Create a MySQL Database Adapter. 63 | * 64 | * @return newly constructed MysqlDatabaseAdapter 65 | */ 66 | def getMysqlDatabaseAdapter: MysqlDatabaseAdapter = { 67 | new MysqlDatabaseAdapter(None) 68 | } 69 | 70 | /** 71 | * Create a MySQL Database Adapter. 72 | * 73 | * @param schemaName the default schema name in the adapter 74 | * @return newly constructed MysqlDatabaseAdapter 75 | */ 76 | def getMysqlDatabaseAdapter(schemaName: String): MysqlDatabaseAdapter = { 77 | new MysqlDatabaseAdapter(Some(schemaName)) 78 | } 79 | 80 | /** 81 | * Create an Oracle Database Adapter. 82 | * 83 | * @return newly constructed OracleDatabaseAdapter 84 | */ 85 | def getOracleDatabaseAdapter: OracleDatabaseAdapter = { 86 | new OracleDatabaseAdapter(None) 87 | } 88 | 89 | /** 90 | * Create an Oracle Database Adapter. 91 | * 92 | * @param schemaName the default schema name in the adapter 93 | * @return newly constructed OracleDatabaseAdapter 94 | */ 95 | def getOracleDatabaseAdapter(schemaName: String): OracleDatabaseAdapter = { 96 | new OracleDatabaseAdapter(Some(schemaName)) 97 | } 98 | 99 | /** 100 | * Create a PostgreSQL Database Adapter. 101 | * 102 | * @return newly constructed PostgresqlDatabaseAdapter 103 | */ 104 | def getPostgresqlDatabaseAdapter: PostgresqlDatabaseAdapter = { 105 | new PostgresqlDatabaseAdapter(None) 106 | } 107 | 108 | /** 109 | * Create a PostgreSQL Database Adapter. 110 | * 111 | * @param schemaName the default schema name in the adapter 112 | * @return newly constructed PostgresqlDatabaseAdapter 113 | */ 114 | def getPostgresqlDatabaseAdapter(schemaName: String): PostgresqlDatabaseAdapter = { 115 | new PostgresqlDatabaseAdapter(Some(schemaName)) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/JavaMigrator.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * The Scala Migrator class uses Scala case classes in its public 37 | * constructors and public methods which makes it difficult to use 38 | * from a pure Java environment. This class exposes a Java-style 39 | * interface and delegates to the Scala Migrator class. 40 | */ 41 | class JavaMigrator private (migrator: Migrator) { 42 | /** 43 | * JavaMigrator constructor. 44 | * 45 | * @param connectionBuilder a builder of connections to the 46 | * database 47 | * @param adapter a concrete DatabaseAdapter that the migrator uses 48 | * to handle database specific features 49 | */ 50 | def this(connectionBuilder: ConnectionBuilder, 51 | adapter: DatabaseAdapter) { 52 | this(new Migrator(connectionBuilder, adapter)) 53 | } 54 | 55 | /** 56 | * JavaMigrator constructor. 57 | * 58 | * @param jdbcUrl the JDBC URL to connect to the database 59 | * @param adapter a concrete DatabaseAdapter that the migrator uses 60 | * to handle database specific features 61 | */ 62 | def this(jdbcUrl: String, 63 | adapter: DatabaseAdapter) { 64 | this(new ConnectionBuilder(jdbcUrl), adapter) 65 | } 66 | 67 | /** 68 | * JavaMigrator constructor. 69 | * 70 | * @param jdbcUrl the JDBC URL to connect to the database 71 | * @param jdbcUsername the username to log into the database 72 | * @param jdbcPassword the password associated with the database 73 | * username 74 | * @param adapter a concrete DatabaseAdapter that the migrator uses 75 | * to handle database specific features 76 | */ 77 | def this(jdbcUrl: String, 78 | jdbcUsername: String, 79 | jdbcPassword: String, 80 | adapter: DatabaseAdapter) { 81 | this(new ConnectionBuilder(jdbcUrl, jdbcUsername, jdbcPassword), 82 | adapter) 83 | } 84 | 85 | /** 86 | * Get a list of table names. If the database adapter was given a 87 | * schema name then only the tables in that schema are returned. 88 | * 89 | * @return a set of table names; no modifications of the case of 90 | * table names is done 91 | */ 92 | def getTableNames: java.util.Set[String] = { 93 | val tableNames = migrator.getTableNames 94 | 95 | val set = new java.util.HashSet[String](tableNames.size) 96 | 97 | for (tableName <- tableNames) 98 | set.add(tableName) 99 | 100 | set 101 | } 102 | 103 | /** 104 | * Install all available migrations into the database. 105 | * 106 | * @param packageName the package name that the Migration subclasses 107 | * should be searched for 108 | * @param searchSubPackages true if sub-packages of packageName 109 | * should be searched 110 | */ 111 | def installAllMigrations(packageName: String, 112 | searchSubPackages: Boolean) { 113 | migrator.migrate(InstallAllMigrations, packageName, searchSubPackages) 114 | } 115 | 116 | /** 117 | * Remove all installed migrations from the database. 118 | * 119 | * @param packageName the package name that the Migration subclasses 120 | * should be searched for 121 | * @param searchSubPackages true if sub-packages of packageName 122 | * should be searched 123 | */ 124 | def removeAllMigrations(packageName: String, 125 | searchSubPackages: Boolean) { 126 | migrator.migrate(RemoveAllMigrations, packageName, searchSubPackages) 127 | } 128 | 129 | /** 130 | * Migrate the database to the given version. 131 | * 132 | * @param version the version number the database should be migrated 133 | * to 134 | * @param packageName the package name that the Migration subclasses 135 | * should be searched for 136 | * @param searchSubPackages true if sub-packages of packageName 137 | * should be searched 138 | */ 139 | def migrateTo(version: Long, 140 | packageName: String, 141 | searchSubPackages: Boolean) { 142 | migrator.migrate(MigrateToVersion(version), packageName, searchSubPackages) 143 | } 144 | 145 | /** 146 | * Rollback a given number of migrations in the database. 147 | * 148 | * @param count the number of migrations to rollback 149 | * to 150 | * @param packageName the package name that the Migration subclasses 151 | * should be searched for 152 | * @param searchSubPackages true if sub-packages of packageName 153 | * should be searched 154 | */ 155 | def rollback(count: Int, 156 | packageName: String, 157 | searchSubPackages: Boolean) { 158 | migrator.migrate(RollbackMigration(count), 159 | packageName, 160 | searchSubPackages) 161 | } 162 | 163 | /** 164 | * Determine if the database has all available migrations installed 165 | * in it and no migrations installed that do not have a 166 | * corresponding concrete Migration subclass; that is, the database 167 | * must have only those migrations installed that are found by 168 | * searching the package name for concrete Migration subclasses. 169 | * 170 | * Running this method does not modify the database in any way. The 171 | * schema migrations table is not created. 172 | * 173 | * @param packageName the Java package name to search for Migration 174 | * subclasses 175 | * @param searchSubPackages true if sub-packages of packageName 176 | * should be searched 177 | * @return null if all available migrations are installed and all 178 | * installed migrations have a corresponding Migration 179 | * subclass; a non-null message suitable for logging with 180 | * the not-installed migrations and the installed migrations 181 | * that do not have a matching Migration subclass 182 | */ 183 | def whyNotMigrated(packageName: String, 184 | searchSubPackages: Boolean): String = { 185 | migrator.whyNotMigrated(packageName, searchSubPackages) match { 186 | case Some(message) => message 187 | case None => null 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/MigrationDirection.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * Sealed abstract class that defines the direction to run a 37 | * migration. 38 | */ 39 | sealed abstract class MigrationDirection { 40 | /** 41 | * A human readable string representing the migration direction. 42 | */ 43 | val str: String 44 | } 45 | 46 | /** 47 | * Case object used to indicate that a migration should be installed. 48 | */ 49 | case object Up 50 | extends MigrationDirection { 51 | override val str = "up" 52 | } 53 | 54 | /** 55 | * Case object used to indicate that a migration should be removed. 56 | */ 57 | case object Down 58 | extends MigrationDirection { 59 | override val str = "down" 60 | } 61 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/MigrationException.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | class MigrationException(message: String) 36 | extends Exception(message) 37 | 38 | class DuplicateMigrationDescriptionException(message: String) 39 | extends MigrationException(message) 40 | 41 | class DuplicateMigrationVersionException(message: String) 42 | extends MigrationException(message) 43 | 44 | class IrreversibleMigrationException 45 | extends MigrationException("This migration is irreversible.") 46 | 47 | class MissingMigrationClass(message: String) 48 | extends MigrationException(message) 49 | 50 | class UnsupportedColumnTypeException(message: String) 51 | extends MigrationException(message) 52 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/MigrationStatuses.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * Container for the state of all the available and installed 37 | * migrations. 38 | * 39 | * @param notInstalled a sorted map of migration version numbers to 40 | * Migration subclasses that are not installed in the database 41 | * @param installedWithAvailableImplementation a sorted map of 42 | * migration version numbers to Migration subclasses that are 43 | * currently installed in the database that have a matching a 44 | * Migration subclass 45 | * @param installedWithoutAvailableImplementation a sorted set of 46 | * migration version numbers that are currently installed in 47 | * the database but do not have a matching a Migration subclass 48 | */ 49 | case class MigrationStatuses(notInstalled: scala.collection.SortedMap[Long, Class[_ <: Migration]], 50 | installedWithAvailableImplementation: scala.collection.SortedMap[Long, Class[_ <: Migration]], 51 | installedWithoutAvailableImplementation: scala.collection.SortedSet[Long]) 52 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/MigratorOperation.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * The set of migrator operations that can be performed. 37 | */ 38 | sealed abstract class MigratorOperation 39 | 40 | /** 41 | * Install all available migrations. 42 | */ 43 | case object InstallAllMigrations 44 | extends MigratorOperation 45 | 46 | /** 47 | * Remove all installed migrations. This should effectively return 48 | * the database to a pristine state, except if any migration throws a 49 | * IrreversibleMigrationException. 50 | */ 51 | case object RemoveAllMigrations 52 | extends MigratorOperation 53 | 54 | /** 55 | * Remove all migrations with versions greater than the given version 56 | * and install all migrations less then or equal to the given version. 57 | */ 58 | case class MigrateToVersion(version: Long) 59 | extends MigratorOperation 60 | 61 | /** 62 | * Rollback 'count' migrations in the database. This is different 63 | * than using MigrateToVersion to migrate to the same version, as 64 | * MigrateToVersion will also install any missing migration with a 65 | * version less then the target version. This rollback operation only 66 | * removes migrations from the database. 67 | */ 68 | case class RollbackMigration(count: Int) 69 | extends MigratorOperation { 70 | if (count < 1) { 71 | val message = "The number of migrations to rollback must be greater " + 72 | "than zero." 73 | throw new IllegalArgumentException(message) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/MysqlDatabaseAdapter.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * Map Unicode to the "utf8" UTF-8 character set. If Unicode is 37 | * specified without a collation then use the "utf8_unicode_ci" 38 | * collation. If a non-Unicode character set is specified then let 39 | * MySQL pick its default collation for the character set. See 40 | * http://dev.mysql.com/doc/refman/5.5/en/charset-charsets.html for 41 | * more information. 42 | */ 43 | trait MysqlAppendCharacterSetToColumnDefinitionMixin { 44 | /** 45 | * If a character set is specified, then append MySQL specific SQL 46 | * to the column definition. 47 | * 48 | * If Unicode is specified without a collation, then use the 49 | * utf8_unicode_ci collation. While utf8_general_ci is MySQL's 50 | * default utf8 collation (at least for 5.5), and is faster, it is 51 | * also incorrect; see http://stackoverflow.com/questions/766809/ . 52 | * 53 | * @param dataTypeSql the SQL for the data type 54 | * @param characterSetOpt an optional character set 55 | */ 56 | protected def sql(dataTypeSql: String, 57 | characterSetOpt: Option[CharacterSet]): String = { 58 | characterSetOpt match { 59 | case Some(charset) => { 60 | val sb = new java.lang.StringBuilder(64) 61 | sb.append(dataTypeSql) 62 | .append(" CHARACTER SET ") 63 | 64 | charset.name match { 65 | case Unicode => { 66 | sb.append("utf8 COLLATE ") 67 | .append(charset.collationOpt.getOrElse("utf8_unicode_ci")) 68 | } 69 | case name => { 70 | sb.append(name.toString) 71 | charset.collationOpt match { 72 | case Some(collation) => 73 | sb.append(" COLLATE ") 74 | .append(collation) 75 | case None => 76 | } 77 | } 78 | } 79 | sb.toString 80 | } 81 | case None => dataTypeSql 82 | } 83 | } 84 | } 85 | 86 | trait MysqlAutoIncrementingColumnDefinitionMixin 87 | extends ColumnDefinition 88 | with ColumnSupportsAutoIncrement { 89 | override protected abstract def sql: String = { 90 | if (isAutoIncrement) super.sql + " AUTO_INCREMENT" 91 | else super.sql 92 | } 93 | } 94 | 95 | class MysqlBigintColumnDefinition 96 | extends DefaultBigintColumnDefinition 97 | with MysqlAutoIncrementingColumnDefinitionMixin 98 | 99 | /** 100 | * Map BlobType to MySQL's LONGBLOB data type. 101 | * 102 | * MySQL supports four different BlobType data types with the 103 | * following properties: 104 | * 105 | * +------------+--------------------+------------------------------+ 106 | * | Data Type | Max Length (bytes) | Storage Requirements (bytes) | 107 | * +------------+--------------------+------------------------------+ 108 | * | TINYBLOB | 255 | length + 1 | 109 | * | BLOB | 65,535 | length + 2 | 110 | * | MEDIUMBLOB | 16,777,215 | length + 3 | 111 | * | LONGBLOB | 4,294,967,295 | length + 4 | 112 | * +------------+--------------------+------------------------------+ 113 | * 114 | * Since the intention of BlobType is to store large amounts of data 115 | * and the additional overhead from TINYBLOB to LONGBLOB is three 116 | * bytes, LONGBLOB is used. 117 | */ 118 | class MysqlBlobColumnDefinition 119 | extends DefaultBlobColumnDefinition { 120 | override val sql = "LONGBLOB" 121 | } 122 | 123 | class MysqlCharColumnDefinition(characterSetOpt: Option[CharacterSet]) 124 | extends DefaultCharColumnDefinition 125 | with MysqlAppendCharacterSetToColumnDefinitionMixin { 126 | override protected def sql: String = sql(super.sql, characterSetOpt) 127 | } 128 | 129 | class MysqlIntegerColumnDefinition 130 | extends DefaultIntegerColumnDefinition 131 | with MysqlAutoIncrementingColumnDefinitionMixin 132 | 133 | class MysqlSmallintColumnDefinition 134 | extends DefaultSmallintColumnDefinition 135 | with MysqlAutoIncrementingColumnDefinitionMixin 136 | 137 | // MySQL does not support size specifiers for the TIMESTAMP data type. 138 | class MysqlTimestampColumnDefinition 139 | extends ColumnDefinition 140 | with ColumnSupportsDefault { 141 | override val sql = "TIMESTAMP" 142 | } 143 | 144 | class MysqlVarcharColumnDefinition(characterSetOpt: Option[CharacterSet]) 145 | extends DefaultVarcharColumnDefinition 146 | with MysqlAppendCharacterSetToColumnDefinitionMixin { 147 | override protected def sql: String = sql(super.sql, characterSetOpt) 148 | } 149 | 150 | class MysqlDatabaseAdapter(override val schemaNameOpt: Option[String]) 151 | extends DatabaseAdapter(schemaNameOpt) { 152 | override val vendor = Mysql 153 | 154 | // https://dev.mysql.com/doc/refman/5.5/en/identifiers.html 155 | override val quoteCharacter = '`' 156 | 157 | // mysql> create table PaReNt (pk INT PRIMARY KEY); 158 | // Query OK, 0 rows affected (0.14 sec) 159 | // 160 | // mysql> show tables; 161 | // +----------------+ 162 | // | Tables_in_test | 163 | // +----------------+ 164 | // | PaReNt | 165 | // +----------------+ 166 | // 1 row in set (0.00 sec) 167 | // 168 | // mysql> select * from parent; 169 | // ERROR 1146 (42S02): Table 'test.parent' doesn't exist 170 | // mysql> select * from PARENT; 171 | // ERROR 1146 (42S02): Table 'test.PARENT' doesn't exist 172 | // mysql> select * from PaReNt; 173 | // Empty set (0.00 sec) 174 | override val unquotedNameConverter = CasePreservingUnquotedNameConverter 175 | 176 | override val userFactory = MysqlUserFactory 177 | 178 | // https://dev.mysql.com/doc/refman/5.5/en/alter-table.html 179 | override val alterTableDropForeignKeyConstraintPhrase = "FOREIGN KEY" 180 | 181 | // mysql> CREATE TABLE parent (pk INT PRIMARY KEY); 182 | // Query OK, 0 rows affected (0.13 sec) 183 | // 184 | // mysql> CREATE TABLE child (pk INT PRIMARY KEY, pk_parent INT NOT NULL); 185 | // Query OK, 0 rows affected (0.10 sec) 186 | // 187 | // mysql> ALTER TABLE child 188 | // -> ADD CONSTRAINT idx_child_pk_parent FOREIGN KEY (pk_parent) 189 | // -> REFERENCES parent (pk); 190 | // Query OK, 0 rows affected (0.22 sec) 191 | // Records: 0 Duplicates: 0 Warnings: 0 192 | // 193 | // mysql> SHOW CREATE TABLE child; 194 | // | Table | Create Table 195 | // | child | CREATE TABLE `child` ( 196 | // `pk` int(11) NOT NULL, 197 | // `pk_parent` int(11) NOT NULL, 198 | // PRIMARY KEY (`pk`), 199 | // KEY `idx_child_pk_parent` (`pk_parent`), 200 | // CONSTRAINT `idx_child_pk_parent` FOREIGN KEY (`pk_parent`) REFERENCES `parent` (`pk`) 201 | // ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | 202 | // 1 row in set (0.00 sec) 203 | // 204 | // mysql> CREATE INDEX idx_child_pk_parent ON child (pk_parent); 205 | // ERROR 1280 (42000): Incorrect index name 'idx_child_pk_parent' 206 | override val addingForeignKeyConstraintCreatesIndex = true 207 | 208 | // https://dev.mysql.com/doc/refman/5.5/en/alter-table.html 209 | override val supportsCheckConstraints = false 210 | 211 | override def columnDefinitionFactory(columnType: SqlType, 212 | characterSetOpt: Option[CharacterSet]): ColumnDefinition = { 213 | columnType match { 214 | case BigintType => 215 | new MysqlBigintColumnDefinition 216 | case BlobType => 217 | new MysqlBlobColumnDefinition 218 | case BooleanType => 219 | new DefaultBooleanColumnDefinition 220 | case CharType => 221 | new MysqlCharColumnDefinition(characterSetOpt) 222 | case DecimalType => 223 | new DefaultDecimalColumnDefinition 224 | case IntegerType => 225 | new MysqlIntegerColumnDefinition 226 | case SmallintType => 227 | new MysqlSmallintColumnDefinition 228 | case TimestampType => 229 | new MysqlTimestampColumnDefinition 230 | case VarbinaryType => 231 | new DefaultVarbinaryColumnDefinition 232 | case VarcharType => 233 | new MysqlVarcharColumnDefinition(characterSetOpt) 234 | } 235 | } 236 | 237 | override def lockTableSql(schemaNameOpt: Option[String], 238 | tableName: String): String = { 239 | val sb = new java.lang.StringBuilder(64) 240 | sb.append("LOCK TABLES ") 241 | .append(quoteTableName(schemaNameOpt, tableName)) 242 | .append(" WRITE") 243 | .toString 244 | } 245 | 246 | override protected def alterColumnSql(schemaNameOpt: Option[String], 247 | columnDefinition: ColumnDefinition): String = { 248 | new java.lang.StringBuilder(512) 249 | .append("ALTER TABLE ") 250 | .append(quoteTableName(schemaNameOpt, columnDefinition.getTableName)) 251 | .append(" MODIFY COLUMN ") 252 | .append(quoteColumnName(columnDefinition.getColumnName)) 253 | .append(columnDefinition.toSql) 254 | .toString 255 | } 256 | 257 | override def removeIndexSql(schemaNameOpt: Option[String], 258 | tableName: String, 259 | indexName: String): String = { 260 | new java.lang.StringBuilder(128) 261 | .append("ALTER TABLE ") 262 | .append(quoteTableName(schemaNameOpt, tableName)) 263 | .append(" DROP INDEX ") 264 | .append(quoteIndexName(None, indexName)) 265 | .toString 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/Options.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * This file contains all the case classes and case objects that act 37 | * as options to customize the SQL generated by the Migration methods. 38 | * 39 | * The design uses the Scala compiler to only allow valid options to 40 | * be passed to a Migration method. Some case classes may be used by 41 | * multiple methods and since the base trait for the method's option 42 | * type may be sealed, they all need to be defined in a single source 43 | * file. 44 | */ 45 | 46 | /** 47 | * The base trait for all column options. This is not a sealed class 48 | * so database specific column options can be defined. 49 | */ 50 | trait ColumnOption 51 | 52 | /** 53 | * The base trait for all foreign key options. 54 | */ 55 | sealed trait ForeignKeyOption 56 | 57 | /** 58 | * The base trait for all privileges. 59 | */ 60 | sealed trait Privilege 61 | 62 | /** 63 | * The base trait for all schema privileges. 64 | */ 65 | sealed trait SchemaPrivilege 66 | extends Privilege 67 | 68 | /** 69 | * The base trait for all table privileges. 70 | * 71 | * TODO: when an ABI breaking change is made to Scala Migrations, 72 | * rename GrantPrivilegeType to TablePrivilege. 73 | */ 74 | sealed trait GrantPrivilegeType 75 | extends Privilege 76 | 77 | /** 78 | * The base trait for all index options. 79 | */ 80 | sealed trait IndexOption 81 | 82 | /** 83 | * The base trait for all check options. 84 | */ 85 | sealed trait CheckOption 86 | 87 | /** 88 | * The base trait for all table options. 89 | */ 90 | sealed trait TableOption 91 | 92 | object CharacterSet { 93 | /** 94 | * Construct a CharacterSet with the given character set name and 95 | * collation name. 96 | * 97 | * @param name the name of the character set 98 | * @param collation the name of the collation 99 | */ 100 | def apply(name: CharacterSetName, 101 | collation: String): CharacterSet = { 102 | new CharacterSet(name, collation) 103 | } 104 | 105 | /** 106 | * Construct a CharacterSet with the given character set name and 107 | * leave the collation unspecified, thereby letting the database 108 | * choose the collation. 109 | * 110 | * @param name the name of the character set 111 | */ 112 | def apply(name: CharacterSetName): CharacterSet = { 113 | new CharacterSet(name) 114 | } 115 | } 116 | 117 | /** 118 | * A character set consists of a character set name and an optional 119 | * collation. A collation is a set of rules to compare characters in 120 | * a character set [1]. If the collation is unspecified then the 121 | * database will choose a default collation, which depending upon the 122 | * database vendor, can vary upon the given character set. 123 | * 124 | * [1] http://dev.mysql.com/doc/refman/5.5/en/charset-general.html 125 | * 126 | * @param name the name of the character set 127 | * @param collationOpt an optional collation for the character set 128 | */ 129 | case class CharacterSet(name: CharacterSetName, 130 | collationOpt: Option[String]) 131 | extends ColumnOption { 132 | /** 133 | * Construct a CharacterSet with the given character set name and 134 | * collation name. 135 | * 136 | * @param name the name of the character set 137 | * @param collation the name of the collation 138 | */ 139 | def this(name: CharacterSetName, 140 | collation: String) { 141 | this(name, Some(collation)) 142 | } 143 | 144 | /** 145 | * Construct a CharacterSet with no specified collation. 146 | * 147 | * @param name the name of the character set 148 | */ 149 | def this(name: CharacterSetName) { 150 | this(name, None) 151 | } 152 | } 153 | 154 | /** 155 | * A default value for a column. 156 | */ 157 | case class Default(value: String) 158 | extends ColumnOption 159 | 160 | /** 161 | * Default companion object allowing Defaults to be constructed with 162 | * integer values. 163 | */ 164 | object Default { 165 | def apply(i: Int): Default = { 166 | Default(i.toString) 167 | } 168 | 169 | def apply(i: Long): Default = { 170 | Default(i.toString) 171 | } 172 | } 173 | 174 | /** 175 | * A limit on the size of a column type. 176 | * 177 | * @throws IllegalArgumentException if the limit is less than zero; 178 | * zero is permitted for a limit on TIMESTAMP precision 179 | */ 180 | case class Limit(expr: String) 181 | extends ColumnOption { 182 | try { 183 | val length = Integer.parseInt(expr) 184 | if (length < 0) { 185 | val message = "The limit in " + 186 | this + 187 | " must be greater than or equal to zero." 188 | throw new IllegalArgumentException(message) 189 | } 190 | } 191 | catch { 192 | case _: NumberFormatException => 193 | } 194 | } 195 | 196 | /** 197 | * Limit companion object allowing Limits to be constructed with 198 | * integer values. 199 | */ 200 | object Limit { 201 | def apply(i: Int): Limit = { 202 | Limit(i.toString) 203 | } 204 | } 205 | 206 | /** 207 | * A name overriding the default index or foreign key constraint name 208 | * generated by Migration. 209 | */ 210 | case class Name(name: String) 211 | extends CheckOption 212 | with ForeignKeyOption 213 | with IndexOption { 214 | if (name eq null) { 215 | throw new IllegalArgumentException("The name cannot be null.") 216 | } 217 | 218 | if (name.isEmpty) { 219 | throw new IllegalArgumentException("The name cannot be empty.") 220 | } 221 | } 222 | 223 | /** 224 | * Specify a check constraint on a column. 225 | */ 226 | case class Check(expr: String) 227 | extends ColumnOption 228 | 229 | /** 230 | * Specify a named check constraint on a column. 231 | */ 232 | case class NamedCheck(name: String, expr: String) 233 | extends ColumnOption 234 | // NamedCheck cannot inherit from Check, it causes a compiler error. 235 | // http://lampsvn.epfl.ch/trac/scala/ticket/425 236 | // & http://lampsvn.epfl.ch/trac/scala/ticket/816 237 | 238 | /** 239 | * Specify that the column's values must not be NULL. 240 | */ 241 | case object NotNull 242 | extends ColumnOption 243 | 244 | /** 245 | * Specify that the column's values may be NULL. 246 | */ 247 | case object Nullable 248 | extends ColumnOption 249 | 250 | /** 251 | * Specify the action that occurs when a value referenced in a foreign 252 | * key constraint is deleted. 253 | */ 254 | case class OnDelete(action: ForeignKeyConstraintAction) 255 | extends ForeignKeyOption 256 | 257 | /** 258 | * Specify the action that occurs when a value referenced in a foreign 259 | * key constraint is updated. 260 | */ 261 | case class OnUpdate(action: ForeignKeyConstraintAction) 262 | extends ForeignKeyOption 263 | 264 | /** 265 | * Specify the precision for a DECIMAL column. 266 | */ 267 | case class Precision(value: Int) 268 | extends ColumnOption { 269 | if (value < 1) { 270 | val message = "The precision cannot be less than one." 271 | throw new IllegalArgumentException(message) 272 | } 273 | } 274 | 275 | /** 276 | * Specify that the column is a primary key. 277 | */ 278 | case object PrimaryKey 279 | extends ColumnOption 280 | 281 | /** 282 | * Specify the scale for a DECIMAL column. 283 | */ 284 | case class Scale(value: Int) 285 | extends ColumnOption { 286 | if (value < 0) { 287 | val message = "The scale cannot be less than zero." 288 | throw new IllegalArgumentException(message) 289 | } 290 | } 291 | 292 | /** 293 | * Specify that the index on the requires that all the values indexed 294 | * are unique. 295 | */ 296 | case object Unique 297 | extends ColumnOption 298 | with IndexOption 299 | 300 | /** 301 | * Specify that the default value for the column for a new row in the 302 | * table is provided by a sequence. Use of AutoIncrement does not 303 | * create an index on the column. If uniqueness needs to be 304 | * guaranteed then a PRIMARY KEY or UNIQUE constraint can be added on 305 | * the column. 306 | * 307 | * For Derby databases this uses GENERATED BY DEFAULT AS IDENTITY. 308 | * The alternate setting GENERATED ALWAYS AS IDENTITY is not used as 309 | * it is not consistent with MySQL and PostgreSQL which permits the 310 | * application to explicitly specify the column's value. See 311 | * http://db.apache.org/derby/docs/10.4/ref/rrefsqlj37836.html . 312 | * 313 | * For MySQL databases this uses the AUTO_INCREMENT attribute; see 314 | * http://dev.mysql.com/doc/refman/5.5/en/create-table.html and 315 | * http://dev.mysql.com/doc/refman/5.5/en/example-auto-increment.html . 316 | * 317 | * For PostgreSQL databases this replaces the SMALLINT data type with 318 | * SMALLSERIAL, INTEGER with SERIAL and BIGINT with BIGSERIAL; see 319 | * http://www.postgresql.org/docs/9.2/static/datatype-numeric.html#DATATYPE-SERIAL . 320 | * Support for SMALLSERIAL is only available in PostgreSQL 9.2 and 321 | * greater. 322 | */ 323 | case object AutoIncrement 324 | extends ColumnOption 325 | 326 | /** 327 | * Maps to GRANT ALL PRIVILEGES. 328 | * 329 | * Since PostgreSQL supports ALL PRIVILEGES on all object types [1], 330 | * AllPrivileges extends all sealed traits that represent privileges 331 | * on database object types, e.g. tables and schemas. 332 | * 333 | * [1] http://www.postgresql.org/docs/9.1/static/sql-grant.html . 334 | */ 335 | case object AllPrivileges 336 | extends GrantPrivilegeType 337 | with SchemaPrivilege 338 | 339 | /** 340 | * Maps to GRANT DELETE. 341 | */ 342 | case object DeletePrivilege 343 | extends GrantPrivilegeType 344 | 345 | /** 346 | * Maps to GRANT INSERT. 347 | */ 348 | case object InsertPrivilege 349 | extends GrantPrivilegeType 350 | 351 | /** 352 | * Maps to GRANT TRIGGER. 353 | */ 354 | case object TriggerPrivilege 355 | extends GrantPrivilegeType 356 | 357 | /** 358 | * Scala 2.8 deprecates case classes extending other case classes. 359 | * Instead of implementing PrivilegeWithColumns as a case class to get 360 | * an extractor for the column names implement it as a non-case class 361 | * with an explicit extractor. 362 | */ 363 | object PrivilegeWithColumns { 364 | /** 365 | * An extractor to return a sequence of column names. 366 | * 367 | * @param a any object 368 | * @return an optional sequence of column names 369 | */ 370 | def unapply(a: Any): Option[Seq[String]] = { 371 | a match { 372 | case p: PrivilegeWithColumns => Some(p.columns) 373 | case _ => None 374 | } 375 | } 376 | } 377 | 378 | /** 379 | * A base class for all privileges that take a list of columns to affect. 380 | */ 381 | sealed abstract class PrivilegeWithColumns 382 | extends GrantPrivilegeType { 383 | val columns: Seq[String] 384 | } 385 | 386 | /** 387 | * Maps to GRANT REFERENCES. 388 | */ 389 | case class ReferencesPrivilege(override val columns: Seq[String]) 390 | extends PrivilegeWithColumns 391 | 392 | /** 393 | * Maps to GRANT SELECT. 394 | */ 395 | case class SelectPrivilege(override val columns: Seq[String]) 396 | extends PrivilegeWithColumns 397 | 398 | /** 399 | * Maps to GRANT UPDATE. 400 | */ 401 | case class UpdatePrivilege(override val columns: Seq[String]) 402 | extends PrivilegeWithColumns 403 | 404 | // These next three are here as case objects to allow 405 | // a no-parameters form in user code 406 | case object ReferencesPrivilege 407 | extends GrantPrivilegeType 408 | 409 | case object SelectPrivilege 410 | extends GrantPrivilegeType 411 | 412 | case object UpdatePrivilege 413 | extends GrantPrivilegeType 414 | 415 | /** 416 | * Maps to GRANT USAGE. 417 | */ 418 | case object UsagePrivilege 419 | extends SchemaPrivilege 420 | 421 | /** 422 | * This class is defined to prevent ant from recompiling this source 423 | * file. 424 | */ 425 | private class Options 426 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/OracleDatabaseAdapter.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * Map the BIGINT SQL type to a NUMBER(19, 0). 37 | * 38 | * A few other databases, such as Derby, MySQL and PostgreSQL, treat 39 | * BIGINT as a 8-byte signed integer type. On Oracle a NUMBER(19, 0) 40 | * is large enough to store any integers from -9223372036854775808 to 41 | * 9223372036854775807 but not any integers with more digits. A 42 | * NUMBER(19, 0) does allow a larger range of values than the other 43 | * databases, from -9999999999999999999 to 9999999999999999999, but 44 | * this seems like an acceptable solution without using a CHECK 45 | * constraint. 46 | * 47 | * This behavior is different than Oracle's default. If a column is 48 | * defined using "INTEGER" and not a "NUMBER", Oracle uses a 49 | * NUMBER(38) to store it: 50 | * 51 | * http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements001.htm#sthref218 52 | * 53 | * Using a NUMBER(19, 0) helps ensure the compatibility of any code 54 | * running against an Oracle database so that is does not assume it 55 | * can use 38-digit integer values in case the data needs to be 56 | * exported to another database or if the code needs to work with 57 | * other databases. Columns wishing to use a NUMBER(38) should use a 58 | * DecimalType column. 59 | */ 60 | class OracleBigintColumnDefinition 61 | extends DefaultBigintColumnDefinition { 62 | override protected def sql = "NUMBER(19, 0)" 63 | } 64 | 65 | class OracleCharColumnDefinition(useNcharType: Boolean) 66 | extends DefaultCharColumnDefinition { 67 | override protected def sql = { 68 | optionallyAddLimitToDataType(if (useNcharType) "NCHAR" else "CHAR") 69 | } 70 | } 71 | 72 | class OracleDecimalColumnDefinition 73 | extends AbstractDecimalColumnDefinition { 74 | override val decimalSqlName = "NUMBER" 75 | } 76 | 77 | /** 78 | * Map the INTEGER SQL type to a NUMBER(10, 0). 79 | * 80 | * A few other databases, such as Derby, MySQL and PostgreSQL, treat 81 | * INTEGER as a 4-byte signed integer type. On Oracle a NUMBER(10, 0) 82 | * is large enough to store any integers from -2147483648 to 83 | * 2147483647 but not any integers with more digits. A NUMBER(10, 0) 84 | * does allow a larger range of values than the other databases, from 85 | * -9999999999 to 9999999999, but this seems like an acceptable 86 | * solution without using a CHECK constraint. 87 | * 88 | * This behavior is different than Oracle's default. If a column is 89 | * defined using "INTEGER" and not a "NUMBER", Oracle uses a 90 | * NUMBER(38) to store it: 91 | * 92 | * http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements001.htm#sthref218 93 | * 94 | * Using a NUMBER(10, 0) helps ensure the compatibility of any code 95 | * running against an Oracle database so that is does not assume it 96 | * can use 38-digit integer values in case the data needs to be 97 | * exported to another database or if the code needs to work with 98 | * other databases. Columns wishing to use a NUMBER(38) should use a 99 | * DecimalType column. 100 | */ 101 | class OracleIntegerColumnDefinition 102 | extends DefaultIntegerColumnDefinition { 103 | override protected def sql = "NUMBER(10, 0)" 104 | } 105 | 106 | /** 107 | * Map the SMALLINT SQL type to a NUMBER(5, 0). 108 | * 109 | * A few other databases, such as Derby, MySQL and PostgreSQL, treat 110 | * SMALLINT as a 2-byte signed integer type. On Oracle a NUMBER(5, 0) 111 | * is large enough to store any integers from -32768 to 32767 but not 112 | * any integers with more digits. A NUMBER(5, 0) does allow a larger 113 | * range of values than the other databases, from -99999 to 99999, but 114 | * this seems like an acceptable solution without using a CHECK 115 | * constraint. 116 | * 117 | * This behavior is different than Oracle's default. If a column is 118 | * defined using "INTEGER" and not a "NUMBER", Oracle uses a 119 | * NUMBER(38) to store it: 120 | * 121 | * http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements001.htm#sthref218 122 | * 123 | * Using a NUMBER(5, 0) helps ensure the compatibility of any code 124 | * running against an Oracle database so that is does not assume it 125 | * can use 38-digit integer values in case the data needs to be 126 | * exported to another database or if the code needs to work with 127 | * other databases. Columns wishing to use a NUMBER(38) should use a 128 | * DecimalType column. 129 | */ 130 | class OracleSmallintColumnDefinition 131 | extends DefaultSmallintColumnDefinition { 132 | override protected def sql = "NUMBER(5, 0)" 133 | } 134 | 135 | class OracleVarbinaryColumnDefinition 136 | extends DefaultVarbinaryColumnDefinition { 137 | override protected def sql = { 138 | if (!limit.isDefined) { 139 | val message = "In Oracle, a RAW column must always specify its size." 140 | throw new IllegalArgumentException(message) 141 | } 142 | 143 | optionallyAddLimitToDataType("RAW") 144 | } 145 | } 146 | 147 | class OracleVarcharColumnDefinition(useNcharType: Boolean) 148 | extends DefaultVarcharColumnDefinition { 149 | override protected def sql = { 150 | optionallyAddLimitToDataType(if (useNcharType) "NVARCHAR2" else "VARCHAR2") 151 | } 152 | } 153 | 154 | class OracleDatabaseAdapter(override val schemaNameOpt: Option[String]) 155 | extends DatabaseAdapter(schemaNameOpt) { 156 | override val vendor = Oracle 157 | 158 | override val quoteCharacter = '"' 159 | 160 | override val unquotedNameConverter = UppercaseUnquotedNameConverter 161 | 162 | override val userFactory = PlainUserFactory 163 | 164 | override val alterTableDropForeignKeyConstraintPhrase = "CONSTRAINT" 165 | 166 | override val addingForeignKeyConstraintCreatesIndex = false 167 | 168 | override val supportsCheckConstraints = true 169 | 170 | override def columnDefinitionFactory(columnType: SqlType, 171 | characterSetOpt: Option[CharacterSet]): ColumnDefinition = { 172 | val useNcharType = 173 | characterSetOpt match { 174 | case None => { 175 | false 176 | } 177 | case Some(CharacterSet(Unicode, None)) => { 178 | true 179 | } 180 | case Some(charset @ CharacterSet(Unicode, Some(collation))) => { 181 | logger.warn("Ignoring collation '{}' in '{}' as Oracle only " + 182 | "supports setting the collation using the NLS_SORT " + 183 | "session parameter.", 184 | Array[AnyRef](collation, charset): _*) 185 | true 186 | } 187 | case Some(charset @ CharacterSet(_, _)) => { 188 | logger.warn("Ignoring '{}' as Oracle only supports specifying no " + 189 | "explicit character set encoding, which defaults the " + 190 | "column to use the database's character set, or " + 191 | "Unicode.", 192 | charset) 193 | false 194 | } 195 | } 196 | 197 | columnType match { 198 | case BigintType => 199 | new OracleBigintColumnDefinition 200 | case BlobType => 201 | new DefaultBlobColumnDefinition 202 | case BooleanType => { 203 | val message = "Oracle does not support a boolean type, you must " + 204 | "choose a mapping your self." 205 | throw new UnsupportedColumnTypeException(message) 206 | } 207 | case CharType => 208 | new OracleCharColumnDefinition(useNcharType) 209 | case DecimalType => 210 | new OracleDecimalColumnDefinition 211 | case IntegerType => 212 | new OracleIntegerColumnDefinition 213 | case SmallintType => 214 | new OracleSmallintColumnDefinition 215 | case TimestampType => 216 | new DefaultTimestampColumnDefinition 217 | case VarbinaryType => 218 | new OracleVarbinaryColumnDefinition 219 | case VarcharType => 220 | new OracleVarcharColumnDefinition(useNcharType) 221 | } 222 | } 223 | 224 | override protected def alterColumnSql(schemaNameOpt: Option[String], 225 | columnDefinition: ColumnDefinition): String = { 226 | new java.lang.StringBuilder(512) 227 | .append("ALTER TABLE ") 228 | .append(quoteTableName(schemaNameOpt, columnDefinition.getTableName)) 229 | .append(" MODIFY (") 230 | .append(quoteColumnName(columnDefinition.getColumnName)) 231 | .append(' ') 232 | .append(columnDefinition.toSql) 233 | .append(')') 234 | .toString 235 | } 236 | 237 | override def removeColumnSql(schemaNameOpt: Option[String], 238 | tableName: String, 239 | columnName: String): String = { 240 | // Oracle requires COLUMN keyword. 241 | new java.lang.StringBuilder(512) 242 | .append("ALTER TABLE ") 243 | .append(quoteTableName(schemaNameOpt, tableName)) 244 | .append(" DROP COLUMN ") 245 | .append(quoteColumnName(columnName)) 246 | .toString 247 | } 248 | 249 | override def grantOnTableSql(schemaNameOpt: Option[String], 250 | tableName: String, 251 | grantees: Array[User], 252 | privileges: GrantPrivilegeType*): String = { 253 | // Check that no columns are defined for any SELECT privs 254 | for { 255 | SelectPrivilege(columns) <- privileges 256 | if !columns.isEmpty 257 | } { 258 | val message = "Oracle does not support granting select to " + 259 | "individual columns" 260 | throw new IllegalArgumentException(message) 261 | } 262 | 263 | super.grantOnTableSql(schemaNameOpt, tableName, grantees, privileges: _*) 264 | } 265 | 266 | override def revokeOnTableSql(schemaNameOpt: Option[String], 267 | tableName: String, 268 | grantees: Array[User], 269 | privileges: GrantPrivilegeType*): String = { 270 | // Check that no columns are defined for any privs with columns 271 | for { 272 | PrivilegeWithColumns(columns) <- privileges 273 | if !columns.isEmpty 274 | } { 275 | val message = "Oracle does not support revoking permissions from " + 276 | "individual columns" 277 | throw new IllegalArgumentException(message) 278 | } 279 | 280 | super.revokeOnTableSql(schemaNameOpt, tableName, grantees, privileges: _*) 281 | } 282 | 283 | /** 284 | * Return the SQL text for the ON DELETE clause for a foreign key 285 | * relationship. 286 | * 287 | * Oracle rejects adding a foreign key relationship containing the 288 | * "ON DELETE RESTRICT" text, so do not generate any SQL text for 289 | * it. The behavior is the same though. Let any other unsupported 290 | * options pass through, such as "ON DELETE NO ACTION", in case 291 | * Oracle ever does support that clause, which it does not in 10g. 292 | * 293 | * @param onDeleteOpt an Option[OnDelete] 294 | * @return the SQL text to append to the SQL to create a foreign key 295 | * relationship 296 | */ 297 | override def onDeleteSql(onDeleteOpt: Option[OnDelete]): String = { 298 | onDeleteOpt match { 299 | case Some(OnDelete(Restrict)) => "" 300 | case opt => super.onDeleteSql(opt) 301 | } 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/PostgresqlDatabaseAdapter.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | class PostgresqlBigintColumnDefinition 36 | extends DefaultBigintColumnDefinition 37 | with ColumnSupportsAutoIncrement { 38 | override protected def sql: String = { 39 | if (isAutoIncrement) "BIGSERIAL" 40 | else super.sql 41 | } 42 | } 43 | 44 | class PostgresqlByteaColumnDefinition 45 | extends DefaultBlobColumnDefinition 46 | with ColumnSupportsDefault { 47 | override protected def sql = "BYTEA" 48 | } 49 | 50 | class PostgresqlIntegerColumnDefinition 51 | extends DefaultIntegerColumnDefinition 52 | with ColumnSupportsAutoIncrement { 53 | override protected def sql: String = { 54 | if (isAutoIncrement) "SERIAL" 55 | else super.sql 56 | } 57 | } 58 | 59 | class PostgresqlSmallintColumnDefinition 60 | extends DefaultSmallintColumnDefinition 61 | with ColumnSupportsAutoIncrement { 62 | override protected def sql: String = { 63 | if (isAutoIncrement) "SMALLSERIAL" 64 | else super.sql 65 | } 66 | } 67 | 68 | class PostgresqlDatabaseAdapter(override val schemaNameOpt: Option[String]) 69 | extends DatabaseAdapter(schemaNameOpt) { 70 | override val vendor = Postgresql 71 | 72 | override val quoteCharacter = '"' 73 | 74 | override val unquotedNameConverter = LowercaseUnquotedNameConverter 75 | 76 | override val userFactory = PlainUserFactory 77 | 78 | override val alterTableDropForeignKeyConstraintPhrase = "CONSTRAINT" 79 | 80 | override val addingForeignKeyConstraintCreatesIndex = false 81 | 82 | override val supportsCheckConstraints = true 83 | 84 | override def columnDefinitionFactory(columnType: SqlType, 85 | characterSetOpt: Option[CharacterSet]): ColumnDefinition = { 86 | characterSetOpt match { 87 | case None => 88 | case Some(charset @ CharacterSet(_, _)) => 89 | logger.warn("Ignoring '{}' as the character set encoding can only " + 90 | "be specified in PostgreSQL when the database is created.", 91 | charset) 92 | } 93 | 94 | columnType match { 95 | case BigintType => 96 | new PostgresqlBigintColumnDefinition 97 | case BlobType => 98 | new PostgresqlByteaColumnDefinition 99 | case BooleanType => 100 | new DefaultBooleanColumnDefinition 101 | case CharType => 102 | new DefaultCharColumnDefinition 103 | case DecimalType => 104 | new DefaultDecimalColumnDefinition 105 | case IntegerType => 106 | new PostgresqlIntegerColumnDefinition 107 | case SmallintType => 108 | new PostgresqlSmallintColumnDefinition 109 | case TimestampType => 110 | new DefaultTimestampColumnDefinition 111 | case VarbinaryType => 112 | new PostgresqlByteaColumnDefinition 113 | case VarcharType => 114 | new DefaultVarcharColumnDefinition 115 | } 116 | } 117 | 118 | override protected def alterColumnSql(schemaNameOpt: Option[String], 119 | columnDefinition: ColumnDefinition): String = { 120 | new java.lang.StringBuilder(512) 121 | .append("ALTER TABLE ") 122 | .append(quoteTableName(schemaNameOpt, columnDefinition.getTableName)) 123 | .append(" ALTER COLUMN ") 124 | .append(quoteColumnName(columnDefinition.getColumnName)) 125 | .append(" TYPE ") 126 | .append(columnDefinition.toSql) 127 | .toString 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/RichConnection.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | import java.sql.{ 36 | Connection, 37 | PreparedStatement 38 | } 39 | 40 | object RichConnection { 41 | implicit def connectionToRichConnection(c: Connection): RichConnection = { 42 | new RichConnection(c) 43 | } 44 | } 45 | 46 | /** 47 | * A rich Connection class that provides a withPreparedStatement() 48 | * method. 49 | */ 50 | class RichConnection(self: Connection) { 51 | def withPreparedStatement[T](sql: String)(f: PreparedStatement => T): T = { 52 | With.autoClosingStatement(self.prepareStatement(sql))(f) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/SqlType.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * Sealed abstract base class for the case objects that represent the 37 | * supported SQL types. 38 | */ 39 | sealed abstract class SqlType 40 | 41 | case object BigintType extends SqlType 42 | case object BlobType extends SqlType 43 | case object BooleanType extends SqlType 44 | case object CharType extends SqlType 45 | case object DecimalType extends SqlType 46 | case object IntegerType extends SqlType 47 | case object SmallintType extends SqlType 48 | case object TimestampType extends SqlType 49 | case object VarbinaryType extends SqlType 50 | case object VarcharType extends SqlType 51 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/TableColumnDefinition.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * A two-tuple containing a table name and a list of column names. 37 | */ 38 | class TableColumnDefinition(val tableName: String, 39 | val columnNames: Array[String]) 40 | 41 | /** 42 | * A container class for storing the table and column names a foreign 43 | * key reference is on. 44 | */ 45 | class On(definition: TableColumnDefinition) { 46 | val tableName = definition.tableName 47 | val columnNames = definition.columnNames 48 | } 49 | 50 | /** 51 | * A container class for storing the table and column names a foreign 52 | * key reference references. 53 | */ 54 | class References(definition: TableColumnDefinition) { 55 | val tableName = definition.tableName 56 | val columnNames = definition.columnNames 57 | } 58 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/TableDefinition.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | import scala.collection.mutable 36 | 37 | /** 38 | * A builder to define a table. Its methods add the specified type of 39 | * column to the table's definition. 40 | */ 41 | class TableDefinition(adapter: DatabaseAdapter, 42 | tableName: String) { 43 | private val columnDefinitions = new mutable.ListBuffer[ColumnDefinition] 44 | 45 | /** 46 | * Generate a SQL string representation of the columns in the table. 47 | * 48 | * @return the SQL text that defines the columns in the table 49 | */ 50 | final def toSql: String = { 51 | val sb = new java.lang.StringBuilder(512) 52 | var firstColumn = true 53 | for (columnDefinition <- columnDefinitions) { 54 | if (firstColumn) { 55 | firstColumn = false 56 | } 57 | else { 58 | sb.append(", ") 59 | } 60 | sb.append(columnDefinition.getColumnName) 61 | .append(' ') 62 | .append(columnDefinition.toSql) 63 | } 64 | sb.toString 65 | } 66 | 67 | /** 68 | * Add any known column type to the table. The actual SQL text used 69 | * to create the column is chosen by the database adapter and may be 70 | * different than the name of the columnType argument. 71 | * 72 | * @param name the column's name 73 | * @param columnType the type of column being added 74 | * @param options a possibly empty array of column options to customize the 75 | * column 76 | * @return the same instance 77 | */ 78 | final def column(name: String, 79 | columnType: SqlType, 80 | options: ColumnOption*): TableDefinition = { 81 | val columnDefinition = adapter.newColumnDefinition(tableName, 82 | name, 83 | columnType, 84 | options: _*) 85 | columnDefinitions += columnDefinition 86 | this 87 | } 88 | 89 | /** 90 | * Add a BIGINT column type to the table. The actual SQL text used 91 | * to create the column is chosen by the database adapter and may be 92 | * different than the name of the columnType argument. 93 | * 94 | * @param name the column's name 95 | * @param options a possibly empty array of column options to customize the 96 | * column 97 | * @return the same instance 98 | */ 99 | final def bigint(name: String, 100 | options: ColumnOption*): TableDefinition = { 101 | column(name, BigintType, options: _*) 102 | } 103 | 104 | /** 105 | * Add a BLOB column type to the table. The actual SQL text used to 106 | * create the column is chosen by the database adapter and may be 107 | * different than the name of the columnType argument. 108 | * 109 | * @param name the column's name 110 | * @param options a possibly empty array of column options to customize the 111 | * column 112 | * @return the same instance 113 | */ 114 | final def blob(name: String, 115 | options: ColumnOption*): TableDefinition = { 116 | column(name, BlobType, options: _*) 117 | } 118 | 119 | /** 120 | * Add a BOOLEAN column type to the table. The actual SQL text used 121 | * to create the column is chosen by the database adapter and may be 122 | * different than the name of the columnType argument. 123 | * 124 | * @param name the column's name 125 | * @param options a possibly empty array of column options to customize the 126 | * column 127 | * @return the same instance 128 | */ 129 | final def boolean(name: String, 130 | options: ColumnOption*): TableDefinition = { 131 | column(name, BooleanType, options: _*) 132 | } 133 | 134 | /** 135 | * Add a CHAR column type to the table. The actual SQL text used to 136 | * create the column is chosen by the database adapter and may be 137 | * different than the name of the columnType argument. 138 | * 139 | * @param name the column's name 140 | * @param options a possibly empty array of column options to customize the 141 | * column 142 | * @return the same instance 143 | */ 144 | final def char(name: String, 145 | options: ColumnOption*): TableDefinition = { 146 | column(name, CharType, options: _*) 147 | } 148 | 149 | /** 150 | * Add a DECIMAL column type to the table. The actual SQL text used 151 | * to create the column is chosen by the database adapter and may be 152 | * different than the name of the columnType argument. 153 | * 154 | * @param name the column's name 155 | * @param options a possibly empty array of column options to customize the 156 | * column 157 | * @return the same instance 158 | */ 159 | final def decimal(name: String, 160 | options: ColumnOption*): TableDefinition = { 161 | column(name, DecimalType, options: _*) 162 | } 163 | 164 | /** 165 | * Add a INTEGER column type to the table. The actual SQL text used 166 | * to create the column is chosen by the database adapter and may be 167 | * different than the name of the columnType argument. 168 | * 169 | * @param name the column's name 170 | * @param options a possibly empty array of column options to customize the 171 | * column 172 | * @return the same instance 173 | */ 174 | final def integer(name: String, 175 | options: ColumnOption*): TableDefinition = { 176 | column(name, IntegerType, options: _*) 177 | } 178 | 179 | /** 180 | * Add a SMALLINT column type to the table. The actual SQL text 181 | * used to create the column is chosen by the database adapter and 182 | * may be different than the name of the columnType argument. 183 | * 184 | * @param name the column's name 185 | * @param options a possibly empty array of column options to customize the 186 | * column 187 | * @return the same instance 188 | */ 189 | final def smallint(name: String, 190 | options: ColumnOption*): TableDefinition = { 191 | column(name, SmallintType, options: _*) 192 | } 193 | 194 | /** 195 | * Add a TIMESTAMP column type to the table. The actual SQL text 196 | * used to create the column is chosen by the database adapter and 197 | * may be different than the name of the columnType argument. 198 | * 199 | * @param name the column's name 200 | * @param options a possibly empty array of column options to customize the 201 | * column 202 | * @return the same instance 203 | */ 204 | final def timestamp(name: String, 205 | options: ColumnOption*): TableDefinition = { 206 | column(name, TimestampType, options: _*) 207 | } 208 | 209 | /** 210 | * Add a VARBINARY column type to the table. The actual SQL text 211 | * used to create the column is chosen by the database adapter and 212 | * may be different than the name of the columnType argument. 213 | * 214 | * @param name the column's name 215 | * @param options a possibly empty array of column options to customize the 216 | * column 217 | * @return the same instance 218 | */ 219 | final def varbinary(name: String, 220 | options: ColumnOption*): TableDefinition = { 221 | column(name, VarbinaryType, options: _*) 222 | } 223 | 224 | /** 225 | * Add a VARCHAR column type to the table. The actual SQL text used 226 | * to create the column is chosen by the database adapter and may be 227 | * different than the name of the columnType argument. 228 | * 229 | * @param name the column's name 230 | * @param options a possibly empty array of column options to customize the 231 | * column 232 | * @return the same instance 233 | */ 234 | final def varchar(name: String, 235 | options: ColumnOption*): TableDefinition = { 236 | column(name, VarcharType, options: _*) 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/UnquotedNameConverter.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * Sealed trait that specifies how the database treats unquoted names 37 | * and has a method that performs the same conversion. 38 | */ 39 | sealed trait UnquotedNameConverter { 40 | /** 41 | * Apply the same conversion to the unquoted name that the database 42 | * does. 43 | * 44 | * @param name the name to convert 45 | * @return the converted name 46 | */ 47 | def apply(name: String): String 48 | } 49 | 50 | /** 51 | * The database does not modify the case of unquoted names. 52 | */ 53 | case object CasePreservingUnquotedNameConverter 54 | extends UnquotedNameConverter { 55 | def apply(name: String): String = { 56 | name 57 | } 58 | } 59 | 60 | /** 61 | * Unquoted names are implicitly converted into their lowercase 62 | * variant. 63 | */ 64 | case object LowercaseUnquotedNameConverter 65 | extends UnquotedNameConverter { 66 | def apply(name: String): String = { 67 | name.toLowerCase 68 | } 69 | } 70 | 71 | /** 72 | * Unquoted names are implicitly converted into their uppercase 73 | * variant. 74 | */ 75 | case object UppercaseUnquotedNameConverter 76 | extends UnquotedNameConverter { 77 | def apply(name: String): String = { 78 | name.toUpperCase 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/User.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * Representation of a SQL user. It provides a single #quoted() 37 | * method that returns the user properly quoted for inclusion in a SQL 38 | * statement. 39 | */ 40 | sealed abstract class User { 41 | /** 42 | * The user quoted for a SQL statement. 43 | * 44 | * @param unquotedNameConverter the unquoted name converter for the 45 | * database 46 | * @return the user quoted for a SQL statement 47 | */ 48 | def quoted(unquotedNameConverter: UnquotedNameConverter): String 49 | } 50 | 51 | /** 52 | * A user consisting only of a user name. Uses double quotation marks 53 | * to quote the user name. 54 | * 55 | * @param userName the user name 56 | */ 57 | class PlainUser(userName: String) 58 | extends User { 59 | override def quoted(unquotedNameConverter: UnquotedNameConverter): String = { 60 | '"' + unquotedNameConverter(userName) + '"' 61 | } 62 | } 63 | 64 | /** 65 | * Object to create PlainUser instances with a user name with a nice 66 | * syntax, e.g. User('foobar'). 67 | */ 68 | object User { 69 | /** 70 | * Given a user name, return a PlainUser instance. 71 | * 72 | * @param userName a user name 73 | * @return a PlainUser with the given name 74 | */ 75 | def apply(userName: String): PlainUser = new PlainUser(userName) 76 | } 77 | 78 | object MysqlUser { 79 | /** 80 | * Given a user name and a host name return a User appropriate for a 81 | * MySQL database, see 82 | * http://dev.mysql.com/doc/refman/5.5/en/account-names.html . 83 | * 84 | * @param userName a user name 85 | * @param hostName a host name 86 | */ 87 | def apply(userName: String, 88 | hostName: String): MysqlUser = { 89 | new MysqlUser(userName, hostName) 90 | } 91 | } 92 | 93 | /** 94 | * Representation of a SQL user for MySQL which consists of a user 95 | * name and a host name; see 96 | * http://dev.mysql.com/doc/refman/5.5/en/account-names.html . 97 | * 98 | * @param userName the user name 99 | * @param hostName the host name 100 | */ 101 | class MysqlUser(userName: String, 102 | hostName: String) 103 | extends User { 104 | override def quoted(unquotedNameConverter: UnquotedNameConverter): String = { 105 | val sb = new java.lang.StringBuilder(64) 106 | sb.append('\'') 107 | .append(unquotedNameConverter(userName)) 108 | .append("'@'") 109 | .append(unquotedNameConverter(hostName)) 110 | .append('\'') 111 | .toString 112 | } 113 | } 114 | 115 | /** 116 | * A factory for User instances that are built from a user name. 117 | */ 118 | abstract class UserFactory[T <: User] { 119 | /** 120 | * Given a user name, return a User instance. 121 | * 122 | * @param userName a user name 123 | * @return a User with the given name 124 | */ 125 | def nameToUser(userName: String): T 126 | } 127 | 128 | /** 129 | * Singleton UserFactory that creates PlainUser instances. 130 | */ 131 | object PlainUserFactory 132 | extends UserFactory[PlainUser] { 133 | override def nameToUser(userName: String) = User(userName) 134 | } 135 | 136 | /** 137 | * A singleton user factory to create MysqlUser instances. This 138 | * factory uses the input user name and defaults the host name to 139 | * "localhost". 140 | */ 141 | object MysqlUserFactory 142 | extends UserFactory[MysqlUser] { 143 | override def nameToUser(userName: String): MysqlUser = { 144 | new MysqlUser(userName, "localhost") 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/Vendor.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | /** 36 | * Base sealed trait for the objects that refer to different 37 | * databases. 38 | */ 39 | sealed trait Vendor 40 | 41 | case object Derby 42 | extends Vendor 43 | case object Mysql 44 | extends Vendor 45 | case object Oracle 46 | extends Vendor 47 | case object Postgresql 48 | extends Vendor 49 | 50 | object Vendor { 51 | /** 52 | * Return the database vendor for the given database driver class 53 | * name. 54 | * 55 | * @param driverClassName the class name of the JDBC database driver 56 | * @return the corresponding Vendor object for the database 57 | * @throws IllegalArgumentException if the argument is null, 58 | * scala.MatchError if an appropriate vendor cannot be found 59 | */ 60 | def forDriver(driverClassName: String): Vendor = { 61 | driverClassName match { 62 | case "com.mysql.jdbc.Driver" => 63 | Mysql 64 | 65 | case "oracle.jdbc.driver.OracleDriver" => 66 | Oracle 67 | 68 | case "oracle.jdbc.OracleDriver" => 69 | Oracle 70 | 71 | case "org.apache.derby.jdbc.EmbeddedDriver" => 72 | Derby 73 | 74 | case "org.apache.derby.jdbc.ClientDriver" => 75 | Derby 76 | 77 | case "org.postgresql.Driver" => 78 | Postgresql 79 | 80 | case null => 81 | throw new IllegalArgumentException("Must pass a non-null JDBC " + 82 | "driver class name to this " + 83 | "function.") 84 | 85 | case _ => 86 | throw new scala.MatchError("No vendor can be found for the JDBC " + 87 | "driver class '" + 88 | driverClassName + 89 | "'.'") 90 | } 91 | } 92 | 93 | /** 94 | * Return the database vendor for the given database driver class. 95 | * 96 | * @param driverClass the class of the JDBC database driver 97 | * @return the corresponding Vendor object for the database 98 | * @throws IllegalArgumentException if the argument is null, 99 | * scala.MatchError if an appropriate vendor cannot be found 100 | */ 101 | def forDriver(driverClass: Class[_]): Vendor = { 102 | if (driverClass eq null) { 103 | val message = "Must pass a non-null JDBC driver class to this function." 104 | throw new IllegalArgumentException(message) 105 | } 106 | else { 107 | forDriver(driverClass.getName) 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/scala/com/imageworks/migration/With.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration 34 | 35 | import org.slf4j.LoggerFactory 36 | 37 | import java.sql.{ 38 | Connection, 39 | ResultSet, 40 | Statement 41 | } 42 | import java.util.jar.JarFile 43 | 44 | /** 45 | * Utility object that contains functions that ensure a resource is 46 | * released once it has been used. Each function takes resource 47 | * object that has a method to release the resource, such as close(), 48 | * and a closure to that operates on the resource. After the closure 49 | * has completed, either normally via a return or by throwing an 50 | * exception, the resource is released. 51 | */ 52 | object With { 53 | private final val logger = LoggerFactory.getLogger(this.getClass) 54 | 55 | /** 56 | * Given a resource and two functions, the first, a closer function 57 | * that closes or releases the resource, and the second, a body 58 | * function that uses the resource, invoke the body function on the 59 | * resource and then ensure that the closer function closes the 60 | * resource, regardless if the body function returns normally or 61 | * throws an exception. 62 | * 63 | * @param resource a resource to use and then close 64 | * @param closerDescription a textual description of what the closer 65 | * does; used to log any exception thrown by closer when the 66 | * body also throws an exception since in that case the 67 | * closer's exception will be suppressed and not thrown to 68 | * the caller 69 | * @param closer the function that closes the resource 70 | * @param body the function that uses the resource 71 | * @return the result of invoking body on the resource 72 | * @throws any exception that invoking body on the resource throws 73 | */ 74 | def resource[A, B](resource: A, closerDescription: String)(closer: A => Unit)(body: A => B): B = { 75 | var primaryException: Throwable = null 76 | try { 77 | body(resource) 78 | } 79 | catch { 80 | case e: Throwable => { 81 | primaryException = e 82 | throw e 83 | } 84 | } 85 | finally { 86 | if (primaryException eq null) { 87 | closer(resource) 88 | } 89 | else { 90 | try { 91 | closer(resource) 92 | } 93 | catch { 94 | case e: Throwable => 95 | logger.warn("Suppressing exception when " + 96 | closerDescription + 97 | ':', 98 | e) 99 | } 100 | } 101 | } 102 | } 103 | 104 | /** 105 | * Take a SQL connection, pass it to a closure and ensure that the 106 | * connection is closed after the closure returns, either normally 107 | * or by an exception. If the closure returns normally, return its 108 | * result. 109 | * 110 | * @param connection a SQL connection 111 | * @param f a Function1[C <: Connection,R] that operates on the 112 | * connection 113 | * @return the result of f 114 | */ 115 | def autoClosingConnection[C <: Connection, R](connection: C)(f: C => R): R = { 116 | resource(connection, "closing connection")(_.close())(f) 117 | } 118 | 119 | /** 120 | * Take a SQL connection, save its current auto-commit mode, put the 121 | * connection into the requested auto-commit mode, pass the 122 | * connection to a closure and ensure that the connection's 123 | * auto-commit mode is restored after the closure returns, either 124 | * normally or by an exception. If the closure returns normally, 125 | * return its result. 126 | * 127 | * The connection's auto-commit mode is always set, even if it is 128 | * the same as the requested mode. This is done to ensure any work 129 | * the database would normally do when setting the auto-commit mode 130 | * is always done. 131 | * 132 | * @param connection a SQL connection 133 | * @param mode the auto-commit mode the connection's state should be 134 | * put in 135 | * @param f a Function1[C <: Connection,R] that operates on the 136 | * connection 137 | * @return the result of f 138 | */ 139 | def autoRestoringConnection[C <: Connection, R](connection: C, 140 | mode: Boolean)(f: C => R): R = { 141 | val currentMode = connection.getAutoCommit 142 | With.resource(connection, "restoring connection auto-commit")(_.setAutoCommit(currentMode)) { c => 143 | c.setAutoCommit(mode) 144 | f(c) 145 | } 146 | } 147 | 148 | /** 149 | * Take a SQL connection, pass it to a closure and ensure that any 150 | * work done on the connection after the closure returns is either 151 | * left alone, committed or rolled back depending upon the given 152 | * setting. If the closure returns normally, return its result. 153 | * The connection's auto-commit mode will be set and restored. 154 | * 155 | * @param connection a SQL connection 156 | * @param commitBehavior the operation to implement on the 157 | * connection after f returns normally or via throwing an 158 | * exception 159 | * @param f a Function1[C <: Connection,R] that operates on the 160 | * connection 161 | * @return the result of f 162 | */ 163 | def autoCommittingConnection[C <: Connection, R](connection: C, 164 | commitBehavior: CommitBehavior)(f: C => R): R = { 165 | val newCommitBehavior = 166 | commitBehavior match { 167 | case AutoCommit => true 168 | case CommitUponReturnOrException => false 169 | case CommitUponReturnOrRollbackUponException => false 170 | } 171 | 172 | With.autoRestoringConnection(connection, newCommitBehavior) { c => 173 | commitBehavior match { 174 | case AutoCommit => { 175 | f(connection) 176 | } 177 | 178 | case CommitUponReturnOrException => { 179 | With.resource(connection, "committing transaction")(_.commit())(f) 180 | } 181 | 182 | case CommitUponReturnOrRollbackUponException => { 183 | val result = 184 | try { 185 | f(connection) 186 | } 187 | catch { 188 | case e1: Throwable => { 189 | try { 190 | connection.rollback() 191 | } 192 | catch { 193 | case e2: Throwable => 194 | logger.warn("Suppressing exception when rolling back" + 195 | "transaction:", e2) 196 | } 197 | throw e1 198 | } 199 | } 200 | 201 | connection.commit() 202 | 203 | result 204 | } 205 | } 206 | } 207 | } 208 | 209 | /** 210 | * Take a SQL statement, pass it to a closure and ensure that the 211 | * statement is closed after the closure returns, either normally or 212 | * by an exception. If the closure returns normally, return its 213 | * result. 214 | * 215 | * @param statement a SQL statement 216 | * @param f a Function1[S <: Statement,R] that operates on the 217 | * statement 218 | * @return the result of f 219 | */ 220 | def autoClosingStatement[S <: Statement, R](statement: S)(f: S => R): R = { 221 | resource(statement, "closing statement")(_.close())(f) 222 | } 223 | 224 | /** 225 | * Take a SQL result set, pass it to a closure and ensure that the 226 | * result set is closed after the closure returns, either normally 227 | * or by an exception. If the closure returns normally, return its 228 | * result. 229 | * 230 | * @param resultSet a SQL result set 231 | * @param f a Function1[RS <: ResultSet,R] that operates on the 232 | * result set 233 | * @return the result of f 234 | */ 235 | def autoClosingResultSet[RS <: ResultSet, R](resultSet: RS)(f: RS => R): R = { 236 | resource(resultSet, "closing result set")(_.close())(f) 237 | } 238 | 239 | /** 240 | * Take a jar file, pass it to a closure and ensure that the jar 241 | * file is closed after the closure returns, either normally or by 242 | * an exception. If the closure returns normally, return its 243 | * result. 244 | * 245 | * @param jarFile a jar file 246 | * @param f a Function1[J <: JarFile,R] that operates on the jar 247 | * file 248 | * @return the result of f 249 | */ 250 | def jarFile[J <: JarFile, R](jarFile: J)(f: J => R): R = { 251 | resource(jarFile, "closing jar file")(_.close())(f) 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # This file is used to make the test suite generate no output. If the 2 | # test suite fails, then increase the logging level. There are some 3 | # expected failures generated during the test suite. 4 | 5 | log4j.rootLogger = FATAL,STDOUT 6 | 7 | # Keep the audit, resultset, and sqltiming loggers turned off by default. 8 | # See the log4jdbc docs for more information about these loggers. 9 | log4j.logger.jdbc.audit = FATAL,STDOUT 10 | log4j.logger.jdbc.resultset = FATAL,STDOUT 11 | log4j.logger.jdbc.sqltiming = FATAL,STDOUT 12 | 13 | log4j.appender.STDOUT = org.apache.log4j.ConsoleAppender 14 | log4j.appender.STDOUT.layout = org.apache.log4j.PatternLayout 15 | log4j.appender.STDOUT.layout.ConversionPattern = %d %p [%t] %C{1} - %m%n 16 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/DatabaseAdapterTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests 34 | 35 | import com.imageworks.migration.{ 36 | DatabaseAdapter, 37 | Derby, 38 | DerbyDatabaseAdapter, 39 | Mysql, 40 | MysqlDatabaseAdapter, 41 | Oracle, 42 | OracleDatabaseAdapter, 43 | Postgresql, 44 | PostgresqlDatabaseAdapter 45 | } 46 | 47 | import org.junit.Assert._ 48 | import org.junit.Test 49 | 50 | class DatabaseAdapterTests { 51 | @Test 52 | def forVendor() { 53 | assertEquals(classOf[DerbyDatabaseAdapter], 54 | DatabaseAdapter.forVendor(Derby, None).getClass) 55 | 56 | assertEquals(classOf[MysqlDatabaseAdapter], 57 | DatabaseAdapter.forVendor(Mysql, None).getClass) 58 | 59 | assertEquals(classOf[OracleDatabaseAdapter], 60 | DatabaseAdapter.forVendor(Oracle, None).getClass) 61 | 62 | assertEquals(classOf[PostgresqlDatabaseAdapter], 63 | DatabaseAdapter.forVendor(Postgresql, None).getClass) 64 | } 65 | 66 | @Test(expected = classOf[IllegalArgumentException]) 67 | def forNullDriverClassThrows() { 68 | DatabaseAdapter.forVendor(null, None) 69 | } 70 | 71 | @Test 72 | def roundTrip() { 73 | for (vendor <- List(Derby, Mysql, Postgresql, Oracle)) { 74 | val adapter = DatabaseAdapter.forVendor(vendor, None) 75 | assertSame(vendor, adapter.vendor) 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/JavaMigratorTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests 34 | 35 | import com.imageworks.migration.{ 36 | AutoCommit, 37 | DuplicateMigrationDescriptionException, 38 | DuplicateMigrationVersionException, 39 | JavaMigrator, 40 | With 41 | } 42 | 43 | import org.junit.Assert._ 44 | import org.junit.{ 45 | Before, 46 | Test 47 | } 48 | 49 | class JavaMigratorTests { 50 | private var javaMigrator: JavaMigrator = _ 51 | 52 | @Before 53 | def setUp() { 54 | val connectionBuilder = TestDatabase.getAdminConnectionBuilder 55 | val databaseAdapter = TestDatabase.getDatabaseAdapter 56 | 57 | javaMigrator = new JavaMigrator(connectionBuilder, databaseAdapter) 58 | 59 | connectionBuilder.withConnection(AutoCommit) { c => 60 | val tableNames = javaMigrator.getTableNames 61 | val iter = tableNames.iterator 62 | while (iter.hasNext) { 63 | val tableName = iter.next() 64 | val tn = tableName.toLowerCase 65 | if (tn == "schema_migrations" || tn.startsWith("scala_migrations_")) { 66 | val sql = "DROP TABLE " + databaseAdapter.quoteTableName(tn) 67 | With.autoClosingStatement(c.prepareStatement(sql)) { _.execute() } 68 | } 69 | } 70 | } 71 | } 72 | 73 | @Test(expected = classOf[DuplicateMigrationDescriptionException]) 74 | def duplicateDescriptionsThrows() { 75 | javaMigrator.installAllMigrations( 76 | "com.imageworks.migration.tests.duplicate_descriptions", 77 | false) 78 | } 79 | 80 | @Test(expected = classOf[DuplicateMigrationVersionException]) 81 | def duplicateVersionsThrows() { 82 | javaMigrator.installAllMigrations( 83 | "com.imageworks.migration.tests.duplicate_versions", 84 | false) 85 | } 86 | 87 | @Test 88 | def migrateUpAndDown() { 89 | // There should be no tables in the schema initially. 90 | assertEquals(0, javaMigrator.getTableNames.size) 91 | 92 | // Migrate down the whole way. 93 | javaMigrator.removeAllMigrations( 94 | "com.imageworks.migration.tests.up_and_down", 95 | false) 96 | 97 | // The database should not be completely migrated. 98 | assertNotNull(javaMigrator.whyNotMigrated( 99 | "com.imageworks.migration.tests.up_and_down", 100 | false)) 101 | 102 | // An empty array of Strings so that getTableNames.toArray returns 103 | // an Array[String] and not Array[AnyRef]. 104 | val ea = new Array[String](0) 105 | 106 | // There should only be the schema_migrations table now. 107 | assertEquals(1, javaMigrator.getTableNames.size) 108 | assertFalse(javaMigrator.getTableNames.toArray(ea).find(_.toLowerCase == "scala_migrations_people").isDefined) 109 | 110 | // Apply all the migrations. 111 | javaMigrator.installAllMigrations( 112 | "com.imageworks.migration.tests.up_and_down", 113 | false) 114 | 115 | assertEquals(3, javaMigrator.getTableNames.size) 116 | assertTrue(javaMigrator.getTableNames.toArray(ea).find(_.toLowerCase == "scala_migrations_people").isDefined) 117 | 118 | // The database should be completely migrated. 119 | assertNull(javaMigrator.whyNotMigrated( 120 | "com.imageworks.migration.tests.up_and_down", 121 | false)) 122 | 123 | // Migrate down the whole way. 124 | javaMigrator.removeAllMigrations( 125 | "com.imageworks.migration.tests.up_and_down", 126 | false) 127 | 128 | // There should only be the schema_migrations table now. 129 | assertEquals(1, javaMigrator.getTableNames.size) 130 | assertFalse(javaMigrator.getTableNames.toArray(ea).find(_.toLowerCase == "scala_migrations_people").isDefined) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/OptionsTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests 34 | 35 | import com.imageworks.migration.Limit 36 | 37 | import org.junit.Test 38 | 39 | class OptionsTests { 40 | @Test(expected = classOf[IllegalArgumentException]) 41 | def limitNegativeOneIntThrows() { 42 | Limit(-1) 43 | } 44 | 45 | @Test(expected = classOf[IllegalArgumentException]) 46 | def limitNegativeOneStringThrows() { 47 | Limit("-1") 48 | } 49 | 50 | @Test 51 | def limitZeroIntOk() { 52 | Limit(0) 53 | } 54 | 55 | @Test 56 | def limitZeroStringOk() { 57 | Limit("0") 58 | } 59 | 60 | @Test 61 | def limitOneIntOk() { 62 | Limit(1) 63 | } 64 | 65 | @Test 66 | def limitOneStringOk() { 67 | Limit("1") 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/TestDatabase.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests 34 | 35 | import com.imageworks.migration.{ 36 | AutoCommit, 37 | ConnectionBuilder, 38 | DatabaseAdapter, 39 | DerbyDatabaseAdapter, 40 | MysqlDatabaseAdapter, 41 | PostgresqlDatabaseAdapter, 42 | With 43 | } 44 | 45 | import java.sql.{ 46 | DriverManager, 47 | SQLException 48 | } 49 | 50 | /** 51 | * Sealed trait abstracting the database to use for testing. 52 | */ 53 | sealed trait TestDatabase { 54 | /** 55 | * Get the schema name the tests are being run in. 56 | */ 57 | def getSchemaName: String 58 | 59 | /** 60 | * Get the username of the admin account. 61 | */ 62 | def getAdminAccountName: String 63 | 64 | /** 65 | * Get a connection builder that builds connections with access to 66 | * the entire schema. 67 | */ 68 | def getAdminConnectionBuilder: ConnectionBuilder 69 | 70 | /** 71 | * Get the username of the user account. 72 | */ 73 | def getUserAccountName: String 74 | 75 | /** 76 | * Get a connection builder that builds connections that connect as 77 | * a user with restricted privileges. 78 | */ 79 | def getUserConnectionBuilder: ConnectionBuilder 80 | 81 | /** 82 | * The DatabaseAdapter to use for the test database. 83 | */ 84 | def getDatabaseAdapter: DatabaseAdapter 85 | } 86 | 87 | /** 88 | * Derby test database implementation. 89 | */ 90 | object DerbyTestDatabase 91 | extends TestDatabase { 92 | // Username of the admin account, which will be the owner of the 93 | // database. 94 | private val adminUsername = "admin" 95 | 96 | override def getAdminAccountName = adminUsername 97 | 98 | // Password for the admin account. 99 | private val adminPassword = "foobar" 100 | 101 | // Username of the user account. 102 | private val userUsername = "user" 103 | 104 | override def getUserAccountName = userUsername 105 | 106 | // Password for the user account. 107 | private val userPassword = "baz" 108 | 109 | // The base JDBC URL. 110 | private val url = { 111 | "jdbc:derby:memory:" + System.currentTimeMillis.toString 112 | } 113 | 114 | // Set the Derby system home directory to "target/test-databases" so 115 | // the derby.log file and all databases will be placed in there. 116 | System.getProperties.setProperty("derby.system.home", 117 | "target/test-databases") 118 | 119 | // Load the Derby database driver. 120 | Class.forName("org.apache.derby.jdbc.EmbeddedDriver") 121 | 122 | // Create the database, set it up for connection and SQL 123 | // authorization and then shut it down, so the next connection will 124 | // "boot" it with connection and SQL authorizations enabled. 125 | 126 | // Create the database. 127 | With.autoClosingConnection(DriverManager.getConnection( 128 | url + ";create=true", 129 | adminUsername, 130 | adminPassword)) { c => 131 | TestDatabase.execute( 132 | getAdminConnectionBuilder, 133 | """CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY( 134 | 'derby.connection.requireAuthentication', 'true')""") 135 | 136 | // Setting this property cannot be undone. See 137 | // http://db.apache.org/derby/docs/10.7/ref/rrefpropersqlauth.html . 138 | TestDatabase.execute( 139 | getAdminConnectionBuilder, 140 | """CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY( 141 | 'derby.database.sqlAuthorization', 'true')""") 142 | 143 | TestDatabase.execute( 144 | getAdminConnectionBuilder, 145 | """CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY( 146 | 'derby.authentication.provider', 'BUILTIN')""") 147 | 148 | TestDatabase.execute( 149 | getAdminConnectionBuilder, 150 | """CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY( 151 | 'derby.user.""" + adminUsername + """', '""" + adminPassword + """')""") 152 | 153 | TestDatabase.execute( 154 | getAdminConnectionBuilder, 155 | """CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY( 156 | 'derby.user.""" + userUsername + """', '""" + userPassword + """')""") 157 | } 158 | 159 | // Shutdown Derby. 160 | try { 161 | With.autoClosingConnection(DriverManager.getConnection( 162 | url + ";shutdown=true", 163 | adminUsername, 164 | adminPassword)) { _ => 165 | } 166 | } 167 | catch { 168 | // For JDBC4 (JDK 1.6), a 169 | // java.sql.SQLNonTransientConnectionException is thrown, but this 170 | // exception class does not exist in JDK 1.5, so catch a 171 | // java.sql.SQLException instead. 172 | case _: SQLException => 173 | } 174 | 175 | override def getSchemaName: String = { 176 | adminUsername 177 | } 178 | 179 | override def getAdminConnectionBuilder: ConnectionBuilder = { 180 | new ConnectionBuilder(url, adminUsername, adminPassword) 181 | } 182 | 183 | override def getUserConnectionBuilder: ConnectionBuilder = { 184 | new ConnectionBuilder(url, userUsername, userPassword) 185 | } 186 | 187 | override def getDatabaseAdapter: DatabaseAdapter = { 188 | new DerbyDatabaseAdapter(Some(getSchemaName)) 189 | } 190 | } 191 | 192 | /** 193 | * MySQL test database implementation. Enabled when the Java 194 | * "scala-migrations.db.vendor" property is set to "mysql". 195 | * 196 | * Assumes the following setup: 197 | * 198 | * 1) A user named "test-admin" with password "test-admin" exists. 199 | * 2) The "test-admin" user owns a database named "test". 200 | * 3) The "test-admin" user has rights to grant other rights in the 201 | * "test" database. 202 | * 4) A user named "test-user" with password "test-user" exists. 203 | * 5) The "test-user" has no rights to the "test" database. 204 | * 205 | * To override the defaults, set any of the following Java properties: 206 | * 207 | * "scala-migrations.db.db": database name to test with ("test") 208 | * "scala-migrations.db.admin.name": admin user username ("test-admin") 209 | * "scala-migrations.db.admin.passwd": admin user password ("test-admin") 210 | * "scala-migrations.db.user.name": plain user username ("test-user") 211 | * "scala-migrations.db.user.passwd": plain user password ("test-user") 212 | */ 213 | object MysqlTestDatabase 214 | extends TestDatabase { 215 | // Username of the admin account, which will be the owner of the 216 | // database. 217 | private val adminUsername = { 218 | System.getProperty(TestDatabase.adminUserNameProperty, "test-admin") 219 | } 220 | 221 | override def getAdminAccountName = adminUsername 222 | 223 | // Password for the admin account. 224 | private val adminPassword = { 225 | System.getProperty(TestDatabase.adminUserPasswordProperty, "test-admin") 226 | } 227 | 228 | // Username of the user account. 229 | private val userUsername = { 230 | System.getProperty(TestDatabase.userUserNameProperty, "test-user") 231 | } 232 | 233 | override def getUserAccountName = userUsername 234 | 235 | // Password for the user account. 236 | private val userPassword = { 237 | System.getProperty(TestDatabase.userUserPasswordProperty, "test-user") 238 | } 239 | 240 | // MySQL doesn't have a separate concept for schemas, in MySQL a 241 | // schema is a database, so use the database name property value for 242 | // the schema name. 243 | override def getSchemaName: String = { 244 | System.getProperty(TestDatabase.databaseNameProperty, "test") 245 | } 246 | 247 | // The base JDBC URL. 248 | private val url = { 249 | "jdbc:mysql://localhost/" + getSchemaName 250 | } 251 | 252 | // Load the MySQL database driver. 253 | Class.forName("com.mysql.jdbc.Driver") 254 | 255 | override def getAdminConnectionBuilder: ConnectionBuilder = { 256 | new ConnectionBuilder(url, adminUsername, adminPassword) 257 | } 258 | 259 | override def getUserConnectionBuilder: ConnectionBuilder = { 260 | new ConnectionBuilder(url, userUsername, userPassword) 261 | } 262 | 263 | override def getDatabaseAdapter: DatabaseAdapter = { 264 | new MysqlDatabaseAdapter(Some(getSchemaName)) 265 | } 266 | } 267 | 268 | /** 269 | * PostgreSQL test database implementation. Enabled when the Java 270 | * "scala-migrations.db.vendor" property is set to "postgresql". 271 | * 272 | * Assumes the following setup: 273 | * 274 | * 1) A user named "test-admin" with password "test-admin" exists. 275 | * 2) The "test-admin" user owns a database named "test". 276 | * 3) The "test-admin" user has rights to grant other rights in the 277 | * "test" database. 278 | * 4) A user named "test-user" with password "test-user" exists. 279 | * 5) The "test-user" has no rights to the "test" database. 280 | * 6) The unit tests are performed in the "public" schema. 281 | * 282 | * The above can be set up with the following commands, which are 283 | * known to work on PostgreSQL 9.1: 284 | * 285 | * $ su - postgres 286 | * $ createuser -e -D -E -P -R -S test-admin 287 | * $ createdb -e -E UTF-8 -O test-admin test 288 | * $ createuser -e -D -E -P -R -S test-user 289 | * 290 | * To override the defaults, set any of the following Java properties: 291 | * 292 | * "scala-migrations.db.db": database name to test with ("test") 293 | * "scala-migrations.db.schema": schema name to test with ("public") 294 | * "scala-migrations.db.admin.name": admin user username ("test-admin") 295 | * "scala-migrations.db.admin.passwd": admin user password ("test-admin") 296 | * "scala-migrations.db.user.name": plain user username ("test-user") 297 | * "scala-migrations.db.user.passwd": plain user password ("test-user") 298 | */ 299 | object PostgresqlTestDatabase 300 | extends TestDatabase { 301 | // Username of the admin account, which will be the owner of the 302 | // database. 303 | private val adminUsername = { 304 | System.getProperty(TestDatabase.adminUserNameProperty, "test-admin") 305 | } 306 | 307 | override def getAdminAccountName = adminUsername 308 | 309 | // Password for the admin account. 310 | private val adminPassword = { 311 | System.getProperty(TestDatabase.adminUserPasswordProperty, "test-admin") 312 | } 313 | 314 | // Username of the user account. 315 | private val userUsername = { 316 | System.getProperty(TestDatabase.userUserNameProperty, "test-user") 317 | } 318 | 319 | override def getUserAccountName = userUsername 320 | 321 | // Password for the user account. 322 | private val userPassword = { 323 | System.getProperty(TestDatabase.userUserPasswordProperty, "test-user") 324 | } 325 | 326 | override def getSchemaName: String = { 327 | System.getProperty(TestDatabase.schemaNameProperty, "public") 328 | } 329 | 330 | // The base JDBC URL. 331 | private val url = { 332 | "jdbc:postgresql://localhost/" + 333 | System.getProperty(TestDatabase.databaseNameProperty, "test") 334 | } 335 | 336 | // Load the PostgreSQL database driver. 337 | Class.forName("org.postgresql.Driver") 338 | 339 | override def getAdminConnectionBuilder: ConnectionBuilder = { 340 | new ConnectionBuilder(url, adminUsername, adminPassword) 341 | } 342 | 343 | override def getUserConnectionBuilder: ConnectionBuilder = { 344 | new ConnectionBuilder(url, userUsername, userPassword) 345 | } 346 | 347 | override def getDatabaseAdapter: DatabaseAdapter = { 348 | new PostgresqlDatabaseAdapter(Some(getSchemaName)) 349 | } 350 | } 351 | 352 | /** 353 | * Object which builds the correct TestDatabase according to the 354 | * system property "scala-migrations.db.vendor", defaulting to Derby if 355 | * the property is not set. 356 | */ 357 | object TestDatabase 358 | extends TestDatabase { 359 | val adminUserNameProperty = "scala-migrations.db.admin.name" 360 | val adminUserPasswordProperty = "scala-migrations.db.admin.passwd" 361 | val databaseNameProperty = "scala-migrations.db.db" 362 | val schemaNameProperty = "scala-migrations.db.schema" 363 | val userUserNameProperty = "scala-migrations.db.user.name" 364 | val userUserPasswordProperty = "scala-migrations.db.user.passwd" 365 | val vendorNameProperty = "scala-migrations.db.vendor" 366 | 367 | private val db: TestDatabase = { 368 | System.getProperty(vendorNameProperty, "derby") match { 369 | case "derby" => 370 | DerbyTestDatabase 371 | case "mysql" => 372 | MysqlTestDatabase 373 | case "postgresql" => 374 | PostgresqlTestDatabase 375 | case v => 376 | throw new RuntimeException("Unexpected value for \"" + 377 | vendorNameProperty + 378 | "\" property: " + 379 | v) 380 | } 381 | } 382 | 383 | override def getSchemaName = db.getSchemaName 384 | 385 | override def getAdminAccountName = db.getAdminAccountName 386 | 387 | override def getAdminConnectionBuilder = db.getAdminConnectionBuilder 388 | 389 | override def getUserAccountName = db.getUserAccountName 390 | 391 | override def getUserConnectionBuilder = db.getUserConnectionBuilder 392 | 393 | override def getDatabaseAdapter = db.getDatabaseAdapter 394 | 395 | def execute(connectionBuilder: ConnectionBuilder, 396 | sql: String): Boolean = { 397 | connectionBuilder.withConnection(AutoCommit) { c => 398 | With.autoClosingStatement(c.prepareStatement(sql)) { s => 399 | s.execute() 400 | } 401 | } 402 | } 403 | } 404 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/VendorTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests 34 | 35 | import com.imageworks.migration.{ 36 | Derby, 37 | Mysql, 38 | Oracle, 39 | Postgresql, 40 | Vendor 41 | } 42 | 43 | import org.junit.Assert._ 44 | import org.junit.Test 45 | 46 | class VendorTests { 47 | @Test 48 | def forDriver() { 49 | assertSame(Derby, 50 | Vendor.forDriver("org.apache.derby.jdbc.EmbeddedDriver")) 51 | 52 | assertSame(Derby, 53 | Vendor.forDriver(classOf[org.apache.derby.jdbc.EmbeddedDriver])) 54 | 55 | assertSame(Derby, 56 | Vendor.forDriver("org.apache.derby.jdbc.ClientDriver")) 57 | 58 | assertSame(Mysql, 59 | Vendor.forDriver("com.mysql.jdbc.Driver")) 60 | 61 | assertSame(Oracle, 62 | Vendor.forDriver("oracle.jdbc.OracleDriver")) 63 | 64 | assertSame(Postgresql, 65 | Vendor.forDriver("org.postgresql.Driver")) 66 | } 67 | 68 | @Test(expected = classOf[scala.MatchError]) 69 | def forNonExistentDriverThrows() { 70 | Vendor.forDriver("no.such.driver") 71 | } 72 | 73 | @Test(expected = classOf[scala.MatchError]) 74 | def forNonDriverClassThrows() { 75 | Vendor.forDriver(classOf[String]) 76 | } 77 | 78 | @Test(expected = classOf[IllegalArgumentException]) 79 | def forNullDriverClassThrows() { 80 | Vendor.forDriver(null: Class[_]) 81 | } 82 | 83 | @Test(expected = classOf[IllegalArgumentException]) 84 | def forNullDriverClassNameThrows() { 85 | Vendor.forDriver(null: String) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/WithTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests 34 | 35 | import com.imageworks.migration.With 36 | 37 | import org.jmock.{ 38 | AbstractExpectations, 39 | Expectations, 40 | Mockery 41 | } 42 | 43 | import org.junit.Assert._ 44 | import org.junit.{ 45 | Before, 46 | Test 47 | } 48 | 49 | import java.sql.{ 50 | ResultSet, 51 | SQLException 52 | } 53 | 54 | class WithTests { 55 | private val context = new Mockery 56 | 57 | @Test 58 | def withResultSetClosesOnNormalReturn() { 59 | val mockResultSet = context.mock(classOf[ResultSet]) 60 | 61 | context.checking(new Expectations { 62 | oneOf(mockResultSet).close() 63 | }) 64 | 65 | var rs1: ResultSet = null 66 | 67 | val result = With.autoClosingResultSet(mockResultSet) { rs2 => 68 | rs1 = rs2 69 | "foobar" 70 | } 71 | 72 | assertSame(mockResultSet, rs1) 73 | assertEquals("foobar", result) 74 | context.assertIsSatisfied() 75 | } 76 | 77 | @Test 78 | def withResultSetClosesOnThrow() { 79 | val mockResultSet = context.mock(classOf[ResultSet]) 80 | 81 | val e1 = new RuntimeException 82 | val e2 = new SQLException 83 | 84 | context.checking(new Expectations { 85 | oneOf(mockResultSet).close() 86 | will(AbstractExpectations.throwException(e2)) 87 | }) 88 | 89 | var caughtExceptionOpt: Option[Exception] = None 90 | var rs1: ResultSet = null 91 | 92 | try { 93 | With.autoClosingResultSet(mockResultSet) { rs2 => 94 | rs1 = rs2 95 | throw e1 96 | } 97 | } 98 | catch { 99 | case e: Exception => caughtExceptionOpt = Some(e) 100 | } 101 | 102 | assertSame(mockResultSet, rs1) 103 | assertTrue("Failed to catch exception.", caughtExceptionOpt.isDefined) 104 | assertSame("Failed to catch expected exception.", 105 | e1, caughtExceptionOpt.get) 106 | context.assertIsSatisfied() 107 | } 108 | 109 | @Test 110 | def closeExceptionIsNotSuppressedIfClosureReturnsNormally() { 111 | val mockResultSet = context.mock(classOf[ResultSet]) 112 | 113 | val e1 = new SQLException 114 | 115 | context.checking(new Expectations { 116 | oneOf(mockResultSet).close() 117 | will(AbstractExpectations.throwException(e1)) 118 | }) 119 | 120 | var caughtExceptionOpt: Option[Exception] = None 121 | var rs1: ResultSet = null 122 | 123 | try { 124 | With.autoClosingResultSet(mockResultSet) { rs2 => 125 | rs1 = rs2 126 | } 127 | } 128 | catch { 129 | case e: Exception => caughtExceptionOpt = Some(e) 130 | } 131 | 132 | assertSame(mockResultSet, rs1) 133 | assertTrue("Failed to catch exception.", caughtExceptionOpt.isDefined) 134 | assertSame("Failed to catch expected exception.", 135 | e1, caughtExceptionOpt.get) 136 | context.assertIsSatisfied() 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/alter_column/Migrate_20110214054347_CreateTable.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.alter_column 34 | 35 | import com.imageworks.migration.{ 36 | Limit, 37 | Migration, 38 | NotNull, 39 | Unique 40 | } 41 | 42 | class Migrate_20110214054347_CreateTable 43 | extends Migration { 44 | val tableName = "scala_migrations_altering" 45 | 46 | def up() { 47 | createTable(tableName) { t => 48 | t.varchar("name", Unique, Limit(127), NotNull) 49 | } 50 | } 51 | 52 | def down() { 53 | dropTable(tableName) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/alter_column/Migrate_20110214060042_AlterColumn.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.alter_column 34 | 35 | import com.imageworks.migration.{ 36 | IrreversibleMigrationException, 37 | Limit, 38 | Migration, 39 | VarcharType 40 | } 41 | 42 | class Migrate_20110214060042_AlterColumn 43 | extends Migration { 44 | val tableName = "scala_migrations_altering" 45 | 46 | def up() { 47 | alterColumn(tableName, "name", VarcharType, Limit(255)) 48 | } 49 | 50 | def down() { 51 | throw new IrreversibleMigrationException 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/auto_increment/Migrate_20121226170550_CreateTableWithAutoIncrementingColumn.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.auto_increment 34 | 35 | import com.imageworks.migration.{ 36 | AutoIncrement, 37 | Limit, 38 | Migration, 39 | NotNull, 40 | PrimaryKey, 41 | Unique 42 | } 43 | 44 | class Migrate_20121226170550_CreateTableWithAutoIncrementingColumn 45 | extends Migration { 46 | val tableName = "scala_migrations_auto_incr" 47 | 48 | def up() { 49 | createTable(tableName) { t => 50 | t.integer("pk_" + tableName, PrimaryKey, AutoIncrement) 51 | t.varchar("name", Unique, Limit(255), NotNull) 52 | } 53 | } 54 | 55 | def down() { 56 | dropTable(tableName) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/duplicate_descriptions/Migrate_20081118191214_FooBar.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.duplicate_descriptions 34 | 35 | import com.imageworks.migration.Migration 36 | 37 | class Migrate_20081118191214_FooBar 38 | extends Migration { 39 | def up() {} 40 | def down() {} 41 | } 42 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/duplicate_descriptions/Migrate_20081118191215_FooBar.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.duplicate_descriptions 34 | 35 | import com.imageworks.migration.Migration 36 | 37 | class Migrate_20081118191215_FooBar 38 | extends Migration { 39 | def up() {} 40 | def down() {} 41 | } 42 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/duplicate_versions/Migrate_20081118191214_Bar.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.duplicate_versions 34 | 35 | import com.imageworks.migration.Migration 36 | 37 | class Migrate_20081118191214_Bar 38 | extends Migration { 39 | def up() {} 40 | def down() {} 41 | } 42 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/duplicate_versions/Migrate_20081118191214_Foo.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.duplicate_versions 34 | 35 | import com.imageworks.migration.Migration 36 | 37 | class Migrate_20081118191214_Foo 38 | extends Migration { 39 | def up() {} 40 | def down() {} 41 | } 42 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/grant_and_revoke/Migrate_200811241940_CreateUser.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.grant_and_revoke 34 | 35 | import com.imageworks.migration.{ 36 | Limit, 37 | Migration, 38 | NotNull, 39 | PrimaryKey, 40 | Unique 41 | } 42 | 43 | class Migrate_200811241940_CreateUser 44 | extends Migration { 45 | val tableName = "scala_migrations_location" 46 | 47 | def up() { 48 | createTable(tableName) { t => 49 | t.varbinary("pk_" + tableName, PrimaryKey, Limit(16)) 50 | t.varchar("name", Unique, Limit(255), NotNull) 51 | } 52 | } 53 | 54 | def down() { 55 | dropTable(tableName) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/grant_and_revoke/Migrate_200811261513_Grants.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.grant_and_revoke 34 | 35 | import com.imageworks.migration.tests.TestDatabase 36 | import com.imageworks.migration.{ 37 | Migration, 38 | Postgresql, 39 | SelectPrivilege, 40 | UsagePrivilege 41 | } 42 | 43 | class Migrate_200811261513_Grants 44 | extends Migration { 45 | val tableName = "scala_migrations_location" 46 | 47 | def up() { 48 | databaseVendor match { 49 | case Postgresql => 50 | grantSchemaPrivilege(TestDatabase.getUserAccountName, UsagePrivilege) 51 | case _ => 52 | } 53 | grant(tableName, TestDatabase.getUserAccountName, SelectPrivilege) 54 | } 55 | 56 | def down() { 57 | revoke(tableName, TestDatabase.getUserAccountName, SelectPrivilege) 58 | databaseVendor match { 59 | case Postgresql => 60 | revokeSchemaPrivilege(TestDatabase.getUserAccountName, UsagePrivilege) 61 | case _ => 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/grant_and_revoke/Migrate_20121013072344_EmptyPrivilegeList.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.grant_and_revoke 34 | 35 | import com.imageworks.migration.tests.TestDatabase 36 | import com.imageworks.migration.Migration 37 | 38 | class Migrate_20121013072344_EmptyPrivilegeList 39 | extends Migration { 40 | val tableName = "scala_migrations_location" 41 | 42 | def up() { 43 | grant(tableName, TestDatabase.getUserAccountName) 44 | } 45 | 46 | def down() { 47 | revoke(tableName, TestDatabase.getUserAccountName) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/no_migrations/Stamp.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.no_migrations 34 | 35 | /** 36 | * This is an empty class that exists to ensure that the 37 | * com.imageworks.migration.tests.no_migrations package exists for 38 | * MigrationTests#test_is_migrated_does_not_create_schema_migrations(). 39 | */ 40 | class Stamp 41 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/scale_without_precision/Migrate_200812041647_Foo.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.scale_without_precision 34 | 35 | import com.imageworks.migration.{ 36 | Migration, 37 | Scale 38 | } 39 | 40 | class Migrate_200812041647_Foo 41 | extends Migration { 42 | def up() { 43 | createTable("foo") { t => 44 | t.decimal("bar", Scale(3)) 45 | } 46 | } 47 | 48 | def down() {} 49 | } 50 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/types/Migrate_20081212213908_CreateTypetestTable.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.types 34 | 35 | import com.imageworks.migration.{ 36 | Limit, 37 | Migration, 38 | Precision, 39 | Scale 40 | } 41 | 42 | class Migrate_20081212213908_CreateTypetestTable 43 | extends Migration { 44 | val tableName = "scala_migrations_types_test" 45 | 46 | def up() { 47 | createTable(tableName) { t => 48 | // The binary column is not tested because its representation is 49 | // database dependent. 50 | 51 | t.bigint("bigint_column") 52 | t.blob("blob_column") 53 | t.char("char_column", Limit(4)) 54 | t.decimal("decimal_column", Precision(22), Scale(2)) 55 | t.integer("integer_column") 56 | t.timestamp("timestamp_column") 57 | t.varbinary("varbinary_column", Limit(4)) 58 | t.varchar("varchar_column", Limit(4)) 59 | } 60 | } 61 | 62 | def down() { 63 | dropTable(tableName) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/up_and_down/Migrate_20081118201000_CreateLocationTable.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.up_and_down 34 | 35 | import com.imageworks.migration.{ 36 | Limit, 37 | Migration, 38 | NotNull, 39 | PrimaryKey, 40 | Unique 41 | } 42 | 43 | class Migrate_20081118201000_CreateLocationTable 44 | extends Migration { 45 | val tableName = "scala_migrations_location" 46 | 47 | def up() { 48 | createTable(tableName) { t => 49 | t.varbinary("pk_" + tableName, PrimaryKey, Limit(16)) 50 | t.varchar("name", Unique, Limit(255), NotNull) 51 | } 52 | } 53 | 54 | def down() { 55 | dropTable(tableName) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/up_and_down/Migrate_20081118201742_CreatePeopleTable.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.up_and_down 34 | 35 | import com.imageworks.migration.{ 36 | Cascade, 37 | CharacterSet, 38 | Check, 39 | Default, 40 | Limit, 41 | Migration, 42 | Name, 43 | NamedCheck, 44 | NotNull, 45 | Nullable, 46 | OnDelete, 47 | OnUpdate, 48 | Precision, 49 | PrimaryKey, 50 | Restrict, 51 | Scale, 52 | Unicode, 53 | Unique, 54 | VarbinaryType 55 | } 56 | 57 | class Migrate_20081118201742_CreatePeopleTable 58 | extends Migration { 59 | val tableName = "scala_migrations_people" 60 | 61 | def up() { 62 | createTable(tableName) { t => 63 | t.varbinary("pk_" + tableName, PrimaryKey, Limit(16)) 64 | t.varbinary("pk_scala_migrations_location", Limit(16), NotNull) 65 | t.integer("employee_id", Unique) 66 | t.integer("ssn", NotNull) 67 | t.varchar("first_name", Limit(255), NotNull, 68 | CharacterSet(Unicode, "utf8_unicode_ci")) 69 | t.char("middle_initial", Limit(1), Nullable) 70 | t.varchar("last_name", Limit(255), NotNull, CharacterSet(Unicode)) 71 | t.timestamp("birthdate", Limit(0), NotNull) 72 | t.smallint("height", NotNull, NamedCheck("chk_height_nonnegative", 73 | "height > 0")) 74 | t.smallint("weight", NotNull, Check("weight > 0")) 75 | t.integer("vacation_days", NotNull, Default("0")) 76 | t.bigint("hire_time_micros", NotNull) 77 | t.decimal("salary", Precision(7), Scale(2), Check("salary > 0")) 78 | t.blob("image") 79 | } 80 | 81 | addIndex(tableName, "ssn", Unique) 82 | 83 | addForeignKey(on(tableName -> 84 | "pk_scala_migrations_location"), 85 | references("scala_migrations_location" -> 86 | "pk_scala_migrations_location"), 87 | OnDelete(Cascade), 88 | OnUpdate(Restrict), 89 | Name("fk_smp_pk_sml_sml_pk_sml")) 90 | 91 | if (!addingForeignKeyConstraintCreatesIndex) { 92 | addIndex(tableName, 93 | "pk_scala_migrations_location", 94 | Name("idx_smp_pk_sml")) 95 | } 96 | 97 | addColumn(tableName, "secret_key", VarbinaryType, Limit(16)) 98 | 99 | addCheck(on(tableName -> "vacation_days"), "vacation_days >= 0") 100 | } 101 | 102 | def down() { 103 | removeCheck(on(tableName -> "vacation_days")) 104 | removeForeignKey(on(tableName -> 105 | "pk_scala_migrations_location"), 106 | references("scala_migrations_location" -> 107 | "pk_scala_migrations_location"), 108 | Name("fk_smp_pk_sml_sml_pk_sml")) 109 | if (!addingForeignKeyConstraintCreatesIndex) { 110 | removeIndex(tableName, 111 | "pk_scala_migrations_location", 112 | Name("idx_smp_pk_sml")) 113 | } 114 | 115 | removeIndex(tableName, "ssn") 116 | removeColumn(tableName, "secret_key") 117 | dropTable(tableName) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/test/scala/com/imageworks/migration/tests/vendor/Migrate_20121104011043_CheckVendor.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Sony Pictures Imageworks Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the 15 | * distribution. Neither the name of Sony Pictures Imageworks nor the 16 | * names of its contributors may be used to endorse or promote 17 | * products derived from this software without specific prior written 18 | * permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package com.imageworks.migration.tests.vendor 34 | 35 | import com.imageworks.migration.{ 36 | Derby, 37 | Migration, 38 | Mysql, 39 | Oracle, 40 | Postgresql 41 | } 42 | 43 | class Migrate_20121104011043_CheckVendor 44 | extends Migration { 45 | def up() { 46 | databaseVendor match { 47 | case Derby => 48 | case Mysql => 49 | case Oracle => 50 | case Postgresql => 51 | case v => throw new AssertionError("Database vendor '" + 52 | v + 53 | "' not handled.") 54 | } 55 | } 56 | 57 | def down() {} 58 | } 59 | --------------------------------------------------------------------------------