/** * Outputs DDL for differences in functions * * @param $ofs1 stage1 output pointer * @param $ofs3 stage3 output pointer * @param $old_schema original schema * @param $new_schema new schema */ public static function diff_functions($ofs1, $ofs3, $old_schema, $new_schema) { // drop functions that no longer exist in stage 3 if ($old_schema != null) { foreach (dbx::get_functions($old_schema) as $old_function) { if (!mysql5_schema::contains_function($new_schema, mysql5_function::get_declaration($new_schema, $old_function))) { $ofs3->write(mysql5_function::get_drop_sql($old_schema, $old_function) . "\n"); } } } // Add new functions and replace modified functions foreach (dbx::get_functions($new_schema) as $new_function) { $old_function = null; if ($old_schema != null) { $old_function = dbx::get_function($old_schema, $new_function['name'], mysql5_function::get_declaration($new_schema, $new_function)); } if ($old_function == null || !mysql5_function::equals($new_schema, $new_function, $old_function, mysql5_diff::$ignore_function_whitespace)) { $ofs1->write(mysql5_function::get_creation_sql($new_schema, $new_function) . "\n"); } else { if (isset($new_function['forceRedefine']) && strcasecmp($new_function['forceRedefine'], 'true') == 0) { $ofs1->write("-- DBSteward insists on function recreation: {$new_schema['name']}.{$new_function['name']} has forceRedefine set to true\n"); $ofs1->write(mysql5_function::get_creation_sql($new_schema, $new_function) . "\n"); } else { if (mysql5_schema::contains_type($new_schema, $new_function['returns']) && mysql5_schema::contains_type($old_schema, $new_function['returns']) && !mysql5_type::equals(dbx::get_type($old_schema, $new_function['returns']), dbx::get_type($new_schema, $new_function['returns']))) { $ofs1->write("-- Force function re-creation {$new_function['name']} for type: {$new_function['returns']}\n"); $ofs1->write(mysql5_function::get_creation_sql($new_schema, $new_function) . "\n"); } } } } }
protected static function drop_old_schemas($ofs) { $drop_sequences = array(); if (is_array(mysql5_diff::$old_table_dependency)) { $deps = mysql5_diff::$old_table_dependency; $processed_schemas = array(); foreach ($deps as $dep) { $old_schema = $dep['schema']; if (!dbx::get_schema(dbsteward::$new_database, $old_schema['name'])) { // this schema is being dropped, drop all children objects in it if (!in_array(trim($old_schema['name']), $processed_schemas)) { // this schema hasn't been processed yet, go ahead and drop views, types, functions, sequences // only do it once per schema foreach ($old_schema->type as $node_type) { $ofs->write(mysql5_type::get_drop_sql($old_schema, $node_type) . "\n"); } foreach ($old_schema->function as $node_function) { $ofs->write(mysql5_function::get_drop_sql($old_schema, $node_function) . "\n"); } foreach ($old_schema->sequence as $node_sequence) { $ofs->write(mysql5_sequence::get_drop_sql($old_schema, $node_sequence) . "\n"); } $processed_schemas[] = trim($old_schema['name']); } if ($dep['table']['name'] === dbsteward::TABLE_DEPENDENCY_IGNORABLE_NAME) { // don't do anything with this table, it is a magic internal DBSteward value continue; } // constraints, indexes, triggers will be deleted along with the tables they're attached to // tables will drop themselves later on // $ofs->write(mysql5_table::get_drop_sql($old_schema, $dep['table']) . "\n"); $table_name = mysql5::get_fully_qualified_table_name($dep['schema']['name'], $dep['table']['name']); $ofs->write("-- {$table_name} triggers, indexes, constraints will be implicitly dropped when the table is dropped\n"); $ofs->write("-- {$table_name} will be dropped later according to table dependency order\n"); // table sequences need dropped separately foreach (mysql5_table::get_sequences_needed($old_schema, $dep['table']) as $node_sequence) { $ofs->write(mysql5_sequence::get_drop_sql($old_schema, $node_sequence) . "\n"); } } } } else { foreach (dbsteward::$old_database->schema as $old_schema) { if (!dbx::get_schema(dbsteward::$new_database, $old_schema['name'])) { foreach ($old_schema->type as $node_type) { $ofs->write(mysql5_type::get_drop_sql($old_schema, $node_type) . "\n"); } foreach ($old_schema->function as $node_function) { $ofs->write(mysql5_function::get_drop_sql($old_schema, $node_function) . "\n"); } foreach ($old_schema->sequence as $node_sequence) { $ofs->write(mysql5_sequence::get_drop_sql($old_schema, $node_sequence) . "\n"); } foreach ($old_schema->table as $node_table) { // tables will drop themselves later on // $ofs->write(mysql5_table::get_drop_sql($old_schema, $node_table) . "\n"); $table_name = mysql5::get_fully_qualified_table_name($old_schema['name'], $node_table['name']); $ofs->write("-- {$table_name} triggers, indexes, constraints will be implicitly dropped when the table is dropped\n"); $ofs->write("-- {$table_name} will be dropped later according to table dependency order\n"); foreach (mysql5_table::get_sequences_needed($old_schema, $node_table) as $node_sequence) { $ofs->write(mysql5_sequence::get_drop_sql($old_schema, $node_sequence) . "\n"); } } } } } }
public function testOtherFormats() { $xml = <<<XML <schema name="test" owner="ROLE_OWNER"> <function name="test_fn" returns="text" securityDefiner="true"> <functionParameter name="a" type="text"/> <functionParameter name="b" type="int"/> <functionParameter name="c" type="date"/> <functionDefinition language="tsql" sqlFormat="mssql10"> RETURN 'xyz'; </functionDefinition> </function> </schema> XML; $schema = new SimpleXMLElement($xml); $this->assertEquals("-- Not dropping function 'test_fn' - no definitions for mysql5", trim(mysql5_function::get_drop_sql($schema, $schema->function))); try { mysql5_function::get_creation_sql($schema, $schema->function); } catch (Exception $ex) { if (stripos($ex->getMessage(), 'no function definitions in a known language for format mysql5') === false) { throw $ex; } $xml = <<<XML <schema name="test" owner="ROLE_OWNER"> <function name="test_fn" returns="text" securityDefiner="true"> <functionParameter name="a" type="text"/> <functionParameter name="b" type="int"/> <functionParameter name="c" type="date"/> <functionDefinition language="sql" sqlFormat="mysql5"> RETURN 'xyz'; </functionDefinition> <functionDefinition language="sql" sqlFormat="mysql5"> RETURN 'xyz'; </functionDefinition> </function> </schema> XML; $schema = new SimpleXMLElement($xml); try { mysql5_function::get_creation_sql($schema, $schema->function); } catch (Exception $ex) { if (stripos($ex->getMessage(), 'duplicate function definition for mysql5/sql') === false) { throw $ex; } return; } $this->fail('Expected exception for duplicate function definitions'); } $this->fail('Expected exception for no function definitions'); }