| /* |
| |
| Derby - Class org.apache.derbyTesting.functionTests.tests.upgradeTests.Changes10_4 |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| */ |
| package org.apache.derbyTesting.functionTests.tests.upgradeTests; |
| |
| import java.sql.Connection; |
| import java.sql.DatabaseMetaData; |
| import java.sql.PreparedStatement; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.text.Collator; |
| import java.util.Locale; |
| import javax.sql.DataSource; |
| import junit.framework.Test; |
| import org.apache.derbyTesting.junit.BaseTestSuite; |
| import org.apache.derbyTesting.junit.JDBC; |
| import org.apache.derbyTesting.junit.JDBCDataSource; |
| import org.apache.derbyTesting.junit.SupportFilesSetup; |
| |
| /** |
| * Upgrade test cases for 10.4. |
| * If the old version is 10.4 or later then these tests |
| * will not be run. |
| * <BR> |
| 10.4 Upgrade issues |
| |
| <UL> |
| <LI> testMetaDataQueryRunInSYScompilationSchema - DERBY-2946 |
| Make sure that metadata queries get run with SYS schema as the current |
| compilation schema rather than a user schema as the current compilation |
| schema. This is because if the user is inside a user schema in a collated |
| database and if the meta data query gets run inside the user schema, then |
| we will run into collation mismatch errors for a subclause like following |
| in the WHERE clause. |
| P.SELECTPRIV = 'Y' |
| The reason for error is that the left hand side of the = operation will |
| have collation type of UCS_BASIC because that column belongs to a table |
| from system schema. But the collation type of the right hand will be |
| territory based if the current compilation schema is user schema. But if |
| the current compilation schema is set to SYS schema, then right hand side |
| will also have collation of UCS_BASIC and hence there won't be any |
| collation mismatch. |
| Background info : character string constants pick up the collation of the |
| current compilation schema. |
| </UL> |
| |
| */ |
| public class Changes10_4 extends UpgradeChange { |
| |
| public Changes10_4(String name) { |
| super(name); |
| } |
| |
| /** |
| * Return the suite of tests to test the changes made in 10.4. |
| * @param phase an integer that indicates the current phase in |
| * the upgrade test. |
| * @return the test suite created. |
| */ |
| public static Test suite(int phase) { |
| BaseTestSuite suite = new BaseTestSuite("Upgrade test for 10.4"); |
| |
| suite.addTestSuite(Changes10_4.class); |
| return new SupportFilesSetup((Test) suite); |
| } |
| |
| /** |
| * Check that even though we have set schema to a user schema, the |
| * metadata queries get run with compilation schema as SYS. |
| * DERBY-2946 |
| * Test added for 10.4. |
| * @throws SQLException |
| * |
| */ |
| public void testMetaDataQueryRunInSYScompilationSchema() throws SQLException |
| { |
| //This test is for databases with territory based collation. That |
| //feature was added in 10.3 codeline and hence there is no point in |
| //doing any testing with pre-10.3 databases. |
| if (!oldAtLeast(10, 3)) |
| return; |
| |
| DataSource ds = JDBCDataSource.getDataSourceLogical("COLLATED_DB_10_3"); |
| |
| switch (getPhase()) |
| { |
| case PH_CREATE: |
| // create the database if it was not already created. Note the |
| // JDBC url attributes. |
| String locale = "en"; |
| Locale[] availableLocales = Collator.getAvailableLocales(); |
| for (int i = 0; i < availableLocales.length; i++) { |
| if ("no".equals(availableLocales[i].getLanguage())) { |
| locale="no"; // Use something different than 'en' |
| // if the JVM supports it. |
| break; |
| } |
| } |
| |
| JDBCDataSource.setBeanProperty( |
| ds, "ConnectionAttributes", |
| "create=true;territory="+locale+";" |
| +"collation=TERRITORY_BASED"); |
| ds.getConnection().close(); |
| break; |
| |
| case PH_SOFT_UPGRADE: |
| case PH_POST_SOFT_UPGRADE: |
| case PH_HARD_UPGRADE: |
| Connection con = ds.getConnection(); |
| //First make the current schema as a user schema. And then run a |
| //metadata query to make sure that it runs fine. If it does (which |
| //is the expected behavior), then it will mean that the metadata |
| //query is getting run with SYS as the compilation schema rather |
| //than the current schema which is APP. |
| Statement s = con.createStatement(); |
| s.execute("SET SCHEMA APP"); |
| |
| DatabaseMetaData dmd = con.getMetaData(); |
| ResultSet rs = dmd.getTables(null,"APP",null,null); |
| JDBC.assertDrainResults(rs); |
| s.close(); |
| break; |
| } |
| } |
| |
| |
| /** |
| * Check that you must be hard-upgraded to 10.4 or later in order to declare |
| * table functions. |
| * @throws SQLException |
| * |
| */ |
| public void testTableFunctionDeclaration() throws SQLException |
| { |
| Statement s = createStatement(); |
| String createTableFunctionText = |
| "create function svnLogReader( logFileName varchar( 32672 ) )\n" + |
| "returns TABLE\n" + |
| " (\n" + |
| " XID varchar( 15 ),\n" + |
| " committer varchar( 20 ),\n" + |
| " commit_time timestamp,\n" + |
| " line_count varchar( 10 ),\n" + |
| " description varchar( 32672 )\n" + |
| " )\n" + |
| "language java\n" + |
| "parameter style DERBY_JDBC_RESULT_SET\n" + |
| "no sql\n" + |
| "external name 'org.apache.derbyDemo.vtis.example.SubversionLogVTI.subversionLogVTI'\n" |
| ; |
| |
| switch (getPhase()) |
| { |
| case PH_CREATE: |
| assertStatementError("42X01", s, createTableFunctionText ); |
| break; |
| |
| case PH_SOFT_UPGRADE: |
| assertStatementError("XCL47", s, createTableFunctionText ); |
| break; |
| |
| case PH_POST_SOFT_UPGRADE: |
| assertStatementError("42X01", s, createTableFunctionText ); |
| break; |
| |
| case PH_HARD_UPGRADE: |
| s.execute( createTableFunctionText ); |
| break; |
| } |
| |
| s.close(); |
| } |
| |
| /** |
| * Test that routine parameters and return types are |
| * handled correctly with 10.4 creating a procedure |
| * in soft-upgrade. 10.4 simplified the stored |
| * format of the types by ensuring the catalog |
| * type was written. See DERBY-2917 for details. |
| * |
| * @throws SQLException |
| * |
| */ |
| public void testRoutineParameters() throws SQLException |
| { |
| |
| |
| switch (getPhase()) |
| { |
| case PH_CREATE: |
| break; |
| |
| case PH_SOFT_UPGRADE: |
| Statement s = createStatement(); |
| s.execute("CREATE FUNCTION TYPES_10_4" + |
| "(A INTEGER) RETURNS CHAR(10) " + |
| "LANGUAGE JAVA " + |
| "PARAMETER STYLE JAVA " + |
| "NO SQL " + |
| "EXTERNAL NAME 'java.lang.Integer.toHexString'"); |
| // fall through to test it |
| |
| case PH_HARD_UPGRADE: |
| case PH_POST_SOFT_UPGRADE: |
| PreparedStatement ps = prepareStatement( |
| "VALUES TYPES_10_4(?)"); |
| ps.setInt(1, 48879); |
| // Don't use the single value check method here |
| // because we want to check the returned value |
| // was converted to its correct type of CHAR(10) |
| // (so no trimming of values) |
| JDBC.assertFullResultSet(ps.executeQuery(), |
| new Object[][] {{"beef "}}, false); |
| break; |
| } |
| } |
| |
| /** |
| * Tests whether or not indexes are exibiting their expected behaviour. |
| * |
| * @param s Statement |
| * @param tableName table name to be used for testing |
| * @param val value to be used for insertion |
| * @param nulls if nulls are allowed |
| * @param duplicate if duplicates are allowed |
| */ |
| private void testIndexes (Statement s, String tableName, int val, |
| boolean nulls, boolean duplicate) throws Exception { |
| |
| //clean table first |
| s.executeUpdate("delete from " + tableName); |
| s.executeUpdate("insert into " + tableName + " values (" + val +")"); |
| |
| // verify insert of input value results in expected duplicate behavior |
| try { |
| s.executeUpdate( |
| "insert into " + tableName + " values (" + val +")"); |
| |
| if (!duplicate) |
| fail("no duplicates allowed"); |
| } |
| catch (SQLException e) { |
| //throw 23505 |
| if (!duplicate) { |
| assertSQLState("duplicate record", "23505", e); |
| } |
| else { |
| throw e; |
| } |
| } |
| |
| // verify insert of a null value results in expected behavior |
| try { |
| s.executeUpdate("insert into " + tableName + " values (null)"); |
| if (!nulls) |
| fail("null in a not null column"); |
| } |
| catch (SQLException e) { |
| if (!nulls) { //23502 |
| assertSQLState("null in not null column", "23502", e); |
| } |
| else { |
| throw e; |
| } |
| } |
| |
| // if nulls are allowed, verify expected behavior of 2nd null insert. |
| if (!nulls) |
| return; |
| try { |
| s.executeUpdate("insert into " + tableName + " values (null)"); |
| if (!duplicate) |
| fail("no duplicates allowed"); |
| } |
| catch (SQLException e) { |
| if (!duplicate) { |
| assertSQLState("duplicate record", "23505", e); |
| } |
| else { |
| throw e; |
| } |
| } |
| } |
| |
| /** |
| * Creates tables to test indexes during and after soft and hard |
| * upgrades |
| * @param s Statement |
| * @param prefix prefix for table names |
| */ |
| private void createTablesForIndexTesting (Statement s, String prefix) |
| throws Exception { |
| |
| // unique index on non-null column |
| s.executeUpdate("create table " + prefix + "_indextest1" + |
| "(col1 integer not null)"); |
| s.executeUpdate("create unique index "+ prefix |
| + "_uinn on " + prefix + "_indextest1 (col1)"); |
| |
| // unique index on nullable column |
| s.executeUpdate("create table " + prefix + "_indextest2" + |
| "(col1 integer)"); |
| s.executeUpdate("create unique index "+ prefix |
| + "_uin on " + prefix + "_indextest2 (col1)"); |
| |
| // non-unique index on non-nullable column |
| s.executeUpdate("create table " + prefix + "_indextest3" + |
| "(col1 integer not null)"); |
| s.executeUpdate("create index "+ prefix |
| + "_nuinn on " + prefix + "_indextest3 (col1)"); |
| |
| // non-unique index on nullable column |
| s.executeUpdate("create table " + prefix + "_indextest4" + |
| "(col1 integer)"); |
| s.executeUpdate("create index "+ prefix |
| + "_nuin on " + prefix + "_indextest4 (col1)"); |
| |
| // behavior of unique constraint on non-nullable columns |
| // should not change, should match behavior of unique index |
| // on non-null column. |
| s.executeUpdate("create table " + prefix + "_indextest5" + |
| "(col1 integer not null)"); |
| //try creating index without seting column as not null |
| s.executeUpdate("alter table " + prefix + "_indextest5 " + |
| "add constraint " + |
| prefix + "_cons1 unique(col1)"); |
| } |
| /** |
| * Test index created before upgrades to insure their behaviour |
| * remains same after soft and hard upgrades. This is an index |
| * test and does not apply to constraint behavior. |
| */ |
| public void testIndexes () throws Exception { |
| Statement s = createStatement(); |
| switch (getPhase()) { |
| case PH_CREATE: |
| //create tables for testing in soft and hard upgrade |
| createTablesForIndexTesting (s, "ph_create"); |
| //test if indexes are created properly |
| testIndexes(s, "ph_create_indextest1", 1, false, false); |
| testIndexes(s, "ph_create_indextest2", 1, true, false); |
| testIndexes(s, "ph_create_indextest3", 1, false, true); |
| testIndexes(s, "ph_create_indextest4", 1, true, true); |
| testIndexes(s, "ph_create_indextest5", 1, false, false); |
| break; |
| |
| case PH_SOFT_UPGRADE: |
| //test old tables |
| testIndexes(s, "ph_create_indextest1", 2, false, false); |
| testIndexes(s, "ph_create_indextest2", 2, true, false); |
| testIndexes(s, "ph_create_indextest3", 2, false, true); |
| testIndexes(s, "ph_create_indextest4", 2, true, true); |
| testIndexes(s, "ph_create_indextest5", 2, false, false); |
| //create one more set of tables |
| createTablesForIndexTesting (s, "ph__soft_upg"); |
| //test newly created tables |
| testIndexes(s, "ph__soft_upg_indextest1", 2, false, false); |
| testIndexes(s, "ph__soft_upg_indextest2", 2, true, false); |
| testIndexes(s, "ph__soft_upg_indextest3", 2, false, true); |
| testIndexes(s, "ph__soft_upg_indextest4", 2, true, true); |
| testIndexes(s, "ph__soft_upg_indextest5", 2, false, false); |
| break; |
| |
| case PH_POST_SOFT_UPGRADE: |
| //test tables created so far |
| testIndexes(s, "ph_create_indextest1", 3, false, false); |
| testIndexes(s, "ph_create_indextest2", 3, true, false); |
| testIndexes(s, "ph_create_indextest3", 3, false, true); |
| testIndexes(s, "ph_create_indextest4", 3, true, true); |
| testIndexes(s, "ph_create_indextest5", 3, false, false); |
| |
| |
| testIndexes(s, "ph__soft_upg_indextest1", 3, false, false); |
| testIndexes(s, "ph__soft_upg_indextest2", 3, true, false); |
| testIndexes(s, "ph__soft_upg_indextest3", 3, false, true); |
| testIndexes(s, "ph__soft_upg_indextest4", 3, true, true); |
| testIndexes(s, "ph__soft_upg_indextest5", 3, false, false); |
| break; |
| |
| case PH_HARD_UPGRADE: |
| //test tables created so far |
| testIndexes(s, "ph_create_indextest1", 4, false, false); |
| testIndexes(s, "ph_create_indextest2", 4, true, false); |
| testIndexes(s, "ph_create_indextest3", 4, false, true); |
| testIndexes(s, "ph_create_indextest4", 4, true, true); |
| testIndexes(s, "ph_create_indextest5", 4, false, false); |
| |
| |
| testIndexes(s, "ph__soft_upg_indextest1", 4, false, false); |
| testIndexes(s, "ph__soft_upg_indextest2", 4, true, false); |
| testIndexes(s, "ph__soft_upg_indextest3", 4, false, true); |
| testIndexes(s, "ph__soft_upg_indextest4", 4, true, true); |
| testIndexes(s, "ph__soft_upg_indextest5", 5, false, false); |
| |
| //create final set of tables |
| createTablesForIndexTesting (s, "ph_upgrade"); |
| //test them |
| testIndexes(s, "ph_upgrade_indextest1", 4, false, false); |
| testIndexes(s, "ph_upgrade_indextest2", 4, true, false); |
| testIndexes(s, "ph_upgrade_indextest3", 4, false, true); |
| testIndexes(s, "ph_upgrade_indextest4", 4, true, true); |
| testIndexes(s, "ph_upgrade_indextest5", 4, false, false); |
| break; |
| } |
| s.close(); |
| } |
| /** |
| * Tests Unique constraint in soft and hard upgrade enviornment. |
| * Under soft upgrade environment creation of unique constrant |
| * over nullable columns and setting columns from unique constraint |
| * to null should fail. Also the constraint created during soft |
| * upgrade run should work fine when running under previous version. |
| * @throws SQLException at any unexpected failure. |
| */ |
| public void testUniqueConstraint () throws SQLException { |
| Statement s = createStatement(); |
| switch (getPhase()) { |
| case PH_CREATE: |
| //create a table with unique constraint |
| s.executeUpdate( |
| "create table constraintest1 (i integer not null" + |
| ", j integer, k integer, constraint ucon unique (i))"); |
| //and one without constraint |
| s.executeUpdate("create table constraintest2 (i integer" + |
| ", j integer, k integer)"); |
| s.executeUpdate("create table constraintest3 (" + |
| "i integer not null, j integer, k integer)"); |
| break; |
| case PH_SOFT_UPGRADE: |
| //try setting i to nullable 42Z20 |
| assertStatementError("42Z20", s, "alter table constraintest1 " + |
| "alter column i null"); |
| //try creating index without seting column as not null |
| assertStatementError("42831", s, "alter table constraintest2 " + |
| "add constraint ucon1 unique(i, j)"); |
| //this should work fine |
| s.execute ("alter table constraintest3 add " + |
| "constraint ucon2 unique(i)"); |
| break; |
| case PH_POST_SOFT_UPGRADE: |
| //try violating ucon2 |
| s.executeUpdate ("insert into constraintest3 (i) values (1)"); |
| //duplicate key violation 23505 |
| assertStatementError ("23505", s, |
| "insert into constraintest3 (i) values (1)"); |
| break; |
| case PH_HARD_UPGRADE: |
| //test unique constraint |
| s.executeUpdate ("insert into constraintest1 (i) values (2)"); |
| //duplicate key violation 23505 |
| assertStatementError ("23505", s, |
| "insert into constraintest1 (i) values (2)"); |
| //should able to drop nullablity |
| s.executeUpdate("alter table constraintest1 " + |
| "alter column i null"); |
| //try creating index without seting column as not null |
| s.executeUpdate("alter table constraintest2 " + |
| "add constraint ucon1 unique(i, j)"); |
| //test null values in unique constraint |
| s.executeUpdate ("insert into constraintest1 (j) values (1)"); |
| s.executeUpdate ("insert into constraintest1 (j) values (1)"); |
| //test null values in new index |
| s.executeUpdate ("insert into constraintest2 (j) values (1)"); |
| s.executeUpdate ("insert into constraintest2 (j) values (1)"); |
| break; |
| } |
| s.close(); |
| } |
| |
| /** |
| * Verifies error messages priviously generated. |
| */ |
| private void verifyError() throws SQLException { |
| Statement stmt = createStatement(); |
| PreparedStatement ps = prepareStatement("select text " + |
| "from errormessage where state = ?"); |
| if (oldAtLeast(10,2)) { |
| try { |
| stmt.execute("alter table t1 alter column i null"); |
| fail ("expected error while setting primary key " + |
| "column to nullable"); |
| } catch (SQLException e) { |
| assertSQLState("expected state 42Z20", "42Z20", e); |
| ps.setString(1, e.getSQLState()); |
| ResultSet rs = ps.executeQuery(); |
| rs.next(); |
| assertEquals("error message mismatch", rs.getString(1), |
| e.getMessage()); |
| rs.close(); |
| } |
| } |
| try { |
| stmt.execute("alter table t1 add constraint uidx " + |
| "unique(j)"); |
| fail ("expected error while creating unique constraint " + |
| "over nullable column"); |
| |
| } catch (SQLException e) { |
| assertSQLState("expected state 42831", "42831", e); |
| ps.setString(1, e.getSQLState()); |
| ResultSet rs = ps.executeQuery(); |
| rs.next(); |
| assertEquals("error message mismatch", rs.getString(1), |
| e.getMessage()); |
| rs.close(); |
| } |
| stmt.close(); |
| ps.close(); |
| } |
| |
| /** |
| * Generates error messages and stores in a table. |
| */ |
| private void prepareTable() throws SQLException { |
| Statement stmt = createStatement(); |
| stmt.executeUpdate("create table errormessage (state varchar (6), " + |
| "text varchar (200))"); |
| PreparedStatement ps = prepareStatement("insert into errormessage " + |
| "(state, text) values (?, ?)"); |
| stmt.executeUpdate("create table t1 (i integer not null primary key, " + |
| "j integer)"); |
| if (oldAtLeast(10,2)) { |
| try { |
| stmt.execute("alter table t1 alter column i null"); |
| fail ("expected error while setting primary key " + |
| "column to nullable"); |
| } catch (SQLException e) { |
| assertSQLState("expected state 42Z20", "42Z20", e); |
| ps.setString(1, e.getSQLState()); |
| ps.setString(2, e.getMessage()); |
| ps.executeUpdate(); |
| } |
| } |
| try { |
| stmt.execute("alter table t1 add constraint uidx " + |
| "unique(j)"); |
| fail ("expected error while creating unique constraint " + |
| "over nullable column"); |
| } catch (SQLException e) { |
| assertSQLState("expected state 42831", "42831", e); |
| ps.setString(1, e.getSQLState()); |
| ps.setString(2, e.getMessage()); |
| ps.executeUpdate(); |
| } |
| stmt.close(); |
| ps.close(); |
| } |
| |
| /** |
| * check if error message generated during soft upgrade is |
| * same as privious version. |
| */ |
| public void testErrorMessage () throws Exception { |
| switch (getPhase()) { |
| case PH_CREATE: |
| prepareTable(); |
| break; |
| case PH_SOFT_UPGRADE: |
| verifyError(); |
| break; |
| } |
| } |
| |
| /** |
| * Tests if alter column works for a column in unique constraint. |
| */ |
| public void testAlterColumnOfUniqueConstraint () throws Exception { |
| Statement stmt = createStatement(); |
| switch (getPhase()) { |
| case PH_CREATE: |
| stmt.executeUpdate("create table datatype_test (fl1 varchar (2) " + |
| "not null)"); |
| stmt.executeUpdate("alter table datatype_test " + |
| "add constraint ucon_datatype_test unique (fl1)"); |
| stmt.executeUpdate("alter table datatype_test alter column fl1" + |
| " set data type varchar (3)"); |
| break; |
| case PH_SOFT_UPGRADE: |
| stmt.executeUpdate("alter table datatype_test alter column fl1 " + |
| " set data type varchar (4)"); |
| break; |
| |
| case PH_HARD_UPGRADE: |
| stmt.executeUpdate("alter table datatype_test alter column fl1 " + |
| " set data type varchar (5)"); |
| break; |
| } |
| stmt.close(); |
| } |
| } |