public static function get_view_query($node_view) { $q = ''; foreach ($node_view->viewQuery as $query) { if (!isset($query['sqlFormat']) || strcasecmp($query['sqlFormat'], dbsteward::get_sql_format()) == 0) { // sanity check to make sure not more than one viewQuery is matching the sqlFormat scenario if (strlen($q) > 0) { throw new exception("query already matched for sqlFormat -- extra viewQuery elements present?"); } // sqlFormat is not present or // sqlFormat matches the current static run-time setting // use this viewQuery $q = (string) $query; } } if (strlen($q) == 0) { foreach ($node_view->viewQuery as $query) { var_dump($query); } throw new exception("view " . $node_view['name'] . " - failed to find viewQuery that matches active sql format " . dbsteward::get_sql_format()); } // if last char is ;, prune it if (substr($q, -1) == ';') { $q = substr($q, 0, -1); } return $q; }
public static function diff_triggers_table($ofs, $old_schema, $old_table, $new_schema, $new_table) { // drop triggers that no longer exist or are modified foreach (static::get_drop_triggers($old_schema, $old_table, $new_schema, $new_table) as $old_trigger) { // only do triggers set to the current sql_format if (strcasecmp($old_trigger['sqlFormat'], dbsteward::get_sql_format()) == 0) { $ofs->write(format_trigger::get_drop_sql($old_schema, $old_trigger) . "\n"); } } // add new triggers foreach (static::get_new_triggers($old_schema, $old_table, $new_schema, $new_table) as $new_trigger) { // only do triggers set to the current sql format if (strcasecmp($new_trigger['sqlFormat'], dbsteward::get_sql_format()) == 0) { $ofs->write(format_trigger::get_creation_sql($new_schema, $new_trigger) . "\n"); } } }
public static function get_drop_sql($node_schema, $node_trigger) { if (strcasecmp($node_trigger['sqlFormat'], dbsteward::get_sql_format())) { $note = "Ignoring {$node_trigger['sqlFormat']} trigger '{$node_trigger['name']}'"; dbsteward::warning($note); return "-- {$note}\n"; } $events = self::get_events($node_trigger); if (count($events) == 1) { return "DROP TRIGGER IF EXISTS " . mysql5::get_fully_qualified_table_name($node_schema['name'], $node_trigger['name']) . ";\n"; } else { $ddl = ""; foreach ($events as $event) { if ($event = self::validate_event($event)) { $ddl .= "DROP TRIGGER IF EXISTS " . mysql5::get_fully_qualified_table_name($node_schema['name'], $node_trigger['name'] . "_{$event}") . ";\n"; } } return $ddl; } }
public static function get_definition($node_function) { $definition = null; foreach ($node_function->functionDefinition as $def) { if (empty($def['sqlFormat']) || empty($def['language'])) { throw new Exception("Attributes sqlFormat and language are required on functionDefinitions, in function '{$node_function['name']}'"); } if ($def['sqlFormat'] == dbsteward::get_sql_format() && static::supported_language($def['language'])) { if ($definition !== null) { throw new Exception("duplicate function definition for {$def['sqlFormat']}/{$def['language']} in function '{$node_function['name']}'"); } $definition = $def; } } if ($definition === null) { foreach ($node_function->functionDefinition as $def) { var_dump($def); } $format = dbsteward::get_sql_format(); throw new Exception("no function definitions in a known language for format {$format} in function '{$node_function['name']}'"); } return $definition; }
public static function equals($node_index_a, $node_index_b) { $equal = true; if (strcasecmp($node_index_a['name'], $node_index_b['name']) != 0) { $equal = false; } else { if (strcasecmp($node_index_a['unique'], $node_index_b['unique']) != 0) { $equal = false; } else { if (strcasecmp($node_index_a['concurrently'], $node_index_b['concurrently']) != 0) { $equal = false; } else { if (strcasecmp($node_index_a['using'], $node_index_b['using']) != 0) { $equal = false; } else { $a_dimensions = ''; foreach ($node_index_a->indexDimension as $dimension) { $a_dimensions .= $dimension . '|'; } $b_dimensions = ''; foreach ($node_index_b->indexDimension as $dimension) { $b_dimensions .= $dimension . '|'; } if ($a_dimensions != $b_dimensions) { $equal = false; } // check indexWhere if the index is still determined to be equal if ($equal && (isset($node_index_a->indexWhere) || isset($node_index_b->indexWhere))) { $a_where = ''; if (isset($node_index_a->indexWhere)) { foreach ($node_index_a->indexWhere as $where) { if ($where['sqlFormat'] == dbsteward::get_sql_format()) { $a_where .= (string) $where; } } } $b_where = ''; if (isset($node_index_b->indexWhere)) { foreach ($node_index_b->indexWhere as $where) { if ($where['sqlFormat'] == dbsteward::get_sql_format()) { $b_where .= (string) $where; } } } if (strcmp($a_where, $b_where) != 0) { $equal = false; } } } } } } return $equal; }
/** * Database system convertions for specific supported sqlFormats * * @return converted $doc */ public static function sql_format_convert($doc) { // legacy 1.0 column add directive attribute conversion foreach ($doc->schema as $schema) { foreach ($schema->table as $table) { foreach ($table->column as $column) { if (isset($column['afterAddPreStage1'])) { $column['beforeAddStage1'] = (string) $column['afterAddPreStage1']; unset($column['afterAddPreStage1']); } if (isset($column['afterAddPostStage1'])) { $column['afterAddStage1'] = (string) $column['afterAddPostStage1']; unset($column['afterAddPostStage1']); } if (isset($column['afterAddPreStage2'])) { $column['beforeAddStage3'] = (string) $column['afterAddPreStage2']; unset($column['afterAddPreStage2']); } if (isset($column['afterAddPostStage2'])) { $column['afterAddStage3'] = (string) $column['afterAddPostStage2']; unset($column['afterAddPostStage2']); } if (isset($column['afterAddPreStage3'])) { $column['beforeAddStage3'] = (string) $column['afterAddPreStage3']; unset($column['afterAddPreStage3']); } if (isset($column['afterAddPostStage3'])) { $column['afterAddStage3'] = (string) $column['afterAddPostStage3']; unset($column['afterAddPostStage3']); } } } } // mssql10 sql format conversions // @TODO: apply mssql10_type_convert to function parameters/returns as well. see below mysql5 impl if (strcasecmp(dbsteward::get_sql_format(), 'mssql10') == 0) { foreach ($doc->schema as $schema) { // if objects are being placed in the public schema, move the schema definition to dbo if (strcasecmp($schema['name'], 'public') == 0) { if (dbx::get_schema($doc, 'dbo')) { throw new exception("sql_format_convert() attempting to move public schema to dbo but dbo schema already exists"); } $schema['name'] = 'dbo'; } foreach ($schema->table as $table) { foreach ($table->column as $column) { if (isset($column['foreignSchema']) && strcasecmp($column['foreignSchema'], 'public') == 0) { $column['foreignSchema'] = 'dbo'; } // column type conversion if (isset($column['type'])) { self::mssql10_type_convert($column); } } } } } elseif (strcasecmp(dbsteward::get_sql_format(), 'mysql5') == 0) { foreach ($doc->schema as $schema) { foreach ($schema->table as $table) { foreach ($table->column as $column) { if (isset($column['type'])) { list($column['type'], $column['default']) = self::mysql5_type_convert($column['type'], $column['default']); } } } foreach ($schema->function as $function) { list($function['returns'], $_) = self::mysql5_type_convert($function['returns']); foreach ($function->functionParameter as $param) { list($param['type'], $_) = self::mysql5_type_convert($param['type']); } } } } return $doc; }
public static function update_table_options($ofs1, $ofs3, $old_schema, $old_table, $new_schema, $new_table) { if (strcasecmp(dbsteward::get_sql_format(), 'mssql10') === 0) { dbsteward::warning("mssql10 tableOptions are not implemented yet"); return; } if ($new_schema && $new_table) { $alter_options = array(); $create_options = array(); $drop_options = array(); $old_options = format_table::get_table_options($old_schema, $old_table); $new_options = format_table::get_table_options($new_schema, $new_table); // dropped options are those present in the old table, but not in the new $drop_options = array_diff_key($old_options, $new_options); // added options are those present in the new table but not in the old $create_options = array_diff_key($new_options, $old_options); // altered options are those present in both but with different values $alter_options = array_intersect_ukey($new_options, $old_options, function ($new_key, $old_key) use($new_options, $old_options) { if ($new_key == $old_key && strcasecmp($new_options[$new_key], $old_options[$old_key]) !== 0) { return 0; } else { return -1; } }); static::apply_table_options_diff($ofs1, $ofs3, $new_schema, $new_table, $alter_options, $create_options, $drop_options); } }
/** * Retrieves an associative array of table options defined for a table * @param SimpleXMLElement $node_schema The schema * @param SimpleXMLElement $node_table The table * @return array Option name => option value */ public static function get_table_options($node_schema, $node_table) { $nodes = $node_table->tableOption; $sql_format = dbsteward::get_sql_format(); $opts = array(); foreach ($nodes as $node) { if ($node['sqlFormat'] != $sql_format) { continue; } $name = strtolower((string) $node['name']); $value = (string) $node['value']; if (empty($name)) { throw new Exception("tableOption of table {$node_schema['name']}.{$node_table['name']} cannot have an empty name"); } if (array_key_exists($name, $opts)) { throw new Exception("Duplicate tableOption '{$name}' in table {$node_schema['name']}.{$node_table['name']} is not allowed"); } $opts[$name] = $value; } return $opts; }
protected static function define_sql_format_default_values($sql_format, $options) { ///// sql_format-specific default options $dbport = FALSE; if (strcasecmp($sql_format, 'pgsql8') == 0) { dbsteward::$create_languages = TRUE; dbsteward::$quote_schema_names = FALSE; dbsteward::$quote_table_names = FALSE; dbsteward::$quote_column_names = FALSE; $dbport = '5432'; } else { if (strcasecmp($sql_format, 'mssql10') == 0) { // needed for MSSQL keyword-named-columns like system_user dbsteward::$quote_table_names = TRUE; dbsteward::$quote_column_names = TRUE; $dbport = '1433'; } else { if (strcasecmp($sql_format, 'mysql5') == 0) { dbsteward::$quote_schema_names = TRUE; dbsteward::$quote_table_names = TRUE; dbsteward::$quote_column_names = TRUE; $dbport = '3306'; if (isset($options['useautoincrementoptions'])) { mysql5::$use_auto_increment_table_options = TRUE; } if (isset($options['useschemaprefix'])) { mysql5::$use_schema_name_prefix = TRUE; } } } } if (strcasecmp($sql_format, 'pgsql8') != 0) { if (isset($options['pgdataxml'])) { dbsteward::error("pgdataxml parameter is not supported by " . dbsteward::get_sql_format() . " driver"); exit(1); } } return $dbport; }
public static function build_schema($db_doc, $ofs, $table_depends) { // schema creation if (static::$use_schema_name_prefix) { dbsteward::info("MySQL schema name prefixing mode turned on"); } else { if (count($db_doc->schema) > 1) { throw new Exception("You cannot use more than one schema in mysql5 without schema name prefixing\nPass the --useschemaprefix flag to turn this on"); } } foreach ($db_doc->schema as $schema) { // database grants foreach ($schema->grant as $grant) { $ofs->write(mysql5_permission::get_permission_sql($db_doc, $schema, $schema, $grant) . "\n"); } // enums foreach ($schema->type as $type) { $ofs->write(mysql5_type::get_creation_sql($schema, $type) . "\n"); } // function definitions foreach ($schema->function as $function) { if (mysql5_function::has_definition($function)) { $ofs->write(mysql5_function::get_creation_sql($schema, $function) . "\n\n"); } // function grants foreach ($function->grant as $grant) { $ofs->write(mysql5_permission::get_permission_sql($db_doc, $schema, $function, $grant) . "\n"); } } $sequences = array(); $triggers = array(); // create defined tables foreach ($schema->table as $table) { // get sequences and triggers needed to make this table work $sequences = array_merge($sequences, mysql5_table::get_sequences_needed($schema, $table)); $triggers = array_merge($triggers, mysql5_table::get_triggers_needed($schema, $table)); // table definition $ofs->write(mysql5_table::get_creation_sql($schema, $table) . "\n\n"); // table indexes // mysql5_diff_indexes::diff_indexes_table($ofs, NULL, NULL, $schema, $table); // table grants if (isset($table->grant)) { foreach ($table->grant as $grant) { $ofs->write(mysql5_permission::get_permission_sql($db_doc, $schema, $table, $grant) . "\n"); } } $ofs->write("\n"); } // sequences contained in the schema + sequences used by serials $sequences = array_merge($sequences, dbx::to_array($schema->sequence)); if (count($sequences) > 0) { $ofs->write(mysql5_sequence::get_shim_creation_sql() . "\n\n"); $ofs->write(mysql5_sequence::get_creation_sql($schema, $sequences) . "\n\n"); // sequence grants foreach ($sequences as $sequence) { foreach ($sequence->grant as $grant) { $ofs->write("-- grant for the {$sequence['name']} sequence applies to ALL sequences\n"); $ofs->write(mysql5_permission::get_permission_sql($db_doc, $schema, $sequence, $grant) . "\n"); } } } // trigger definitions + triggers used by serials $triggers = array_merge($triggers, dbx::to_array($schema->trigger)); $unique_triggers = array(); foreach ($triggers as $trigger) { // only do triggers set to the current sql format if (strcasecmp($trigger['sqlFormat'], dbsteward::get_sql_format()) == 0) { // check that this table/timing/event combo hasn't been defined, because MySQL only // allows one trigger per table per BEFORE/AFTER per action $unique_name = "{$trigger['table']}-{$trigger['when']}-{$trigger['event']}"; if (array_key_exists($unique_name, $unique_triggers)) { throw new Exception("MySQL will not allow trigger {$trigger['name']} to be created because it happens on the same table/timing/event as trigger {$unique_triggers[$unique_name]}"); } $unique_triggers[$unique_name] = $trigger['name']; $ofs->write(mysql5_trigger::get_creation_sql($schema, $trigger) . "\n"); } } } foreach ($db_doc->schema as $schema) { // define table primary keys before foreign keys so unique requirements are always met for FOREIGN KEY constraints foreach ($schema->table as $table) { mysql5_diff_constraints::diff_constraints_table($ofs, NULL, NULL, $schema, $table, 'primaryKey', FALSE); } $ofs->write("\n"); } // foreign key references // use the dependency order to specify foreign keys in an order that will satisfy nested foreign keys and etc for ($i = 0; $i < count($table_depends); $i++) { $dep_schema = $table_depends[$i]['schema']; $table = $table_depends[$i]['table']; if ($table['name'] === dbsteward::TABLE_DEPENDENCY_IGNORABLE_NAME) { // don't do anything with this table, it is a magic internal DBSteward value continue; } mysql5_diff_constraints::diff_constraints_table($ofs, NULL, NULL, $dep_schema, $table, 'constraint', FALSE); } $ofs->write("\n"); mysql5_diff_views::create_views_ordered($ofs, null, $db_doc); // view permission grants foreach ($db_doc->schema as $schema) { foreach ($schema->view as $view) { if (isset($view->grant)) { foreach ($view->grant as $grant) { $ofs->write(mysql5_permission::get_permission_sql($db_doc, $schema, $view, $grant) . "\n"); } } } } // @TODO: database configurationParameter support }
public static function build_schema($db_doc, $ofs, $table_depends) { // schema creation foreach ($db_doc->schema as $schema) { $ofs->write(pgsql8_schema::get_creation_sql($schema)); // schema grants if (isset($schema->grant)) { foreach ($schema->grant as $grant) { $ofs->write(pgsql8_permission::get_sql($db_doc, $schema, $schema, $grant) . "\n"); } } } // types: enumerated list, etc foreach ($db_doc->schema as $schema) { foreach ($schema->type as $type) { $ofs->write(pgsql8_type::get_creation_sql($schema, $type) . "\n"); } } // table structure creation foreach ($db_doc->schema as $schema) { // create defined tables pgsql8_table::$include_column_default_nextval_in_create_sql = FALSE; foreach ($schema->table as $table) { // table definition $ofs->write(pgsql8_table::get_creation_sql($schema, $table) . "\n"); // table indexes pgsql8_diff_indexes::diff_indexes_table($ofs, NULL, NULL, $schema, $table); // table grants if (isset($table->grant)) { foreach ($table->grant as $grant) { $ofs->write(pgsql8_permission::get_sql($db_doc, $schema, $table, $grant) . "\n"); } } $ofs->write("\n"); } pgsql8_table::$include_column_default_nextval_in_create_sql = TRUE; // sequences contained in the schema if (isset($schema->sequence)) { foreach ($schema->sequence as $sequence) { $ofs->write(pgsql8_sequence::get_creation_sql($schema, $sequence)); // sequence permission grants if (isset($sequence->grant)) { foreach ($sequence->grant as $grant) { $ofs->write(pgsql8_permission::get_sql($db_doc, $schema, $sequence, $grant) . "\n"); } } } } // add table nextvals that were omitted foreach ($schema->table as $table) { if (pgsql8_table::has_default_nextval($table)) { $ofs->write(pgsql8_table::get_default_nextval_sql($schema, $table) . "\n"); } } } $ofs->write("\n"); // function definitions foreach ($db_doc->schema as $schema) { foreach ($schema->function as $function) { if (pgsql8_function::has_definition($function)) { $ofs->write(pgsql8_function::get_creation_sql($schema, $function)); // when pg:build_schema() is doing its thing for straight builds, include function permissions // they are not included in pg_function::get_creation_sql() foreach (dbx::get_permissions($function) as $function_permission) { $ofs->write(pgsql8_permission::get_sql($db_doc, $schema, $function, $function_permission) . "\n"); } } } } $ofs->write("\n"); // maybe move this but here we're defining column defaults fo realz foreach ($db_doc->schema as $schema) { foreach ($schema->table as $table) { $ofs->write(pgsql8_table::define_table_column_defaults($schema, $table)); } } // define table primary keys before foreign keys so unique requirements are always met for FOREIGN KEY constraints foreach ($db_doc->schema as $schema) { foreach ($schema->table as $table) { pgsql8_diff_tables::diff_constraints_table($ofs, NULL, NULL, $schema, $table, 'primaryKey', FALSE); } } $ofs->write("\n"); // foreign key references // use the dependency order to specify foreign keys in an order that will satisfy nested foreign keys and etc for ($i = 0; $i < count($table_depends); $i++) { $schema = $table_depends[$i]['schema']; $table = $table_depends[$i]['table']; if ($table['name'] === dbsteward::TABLE_DEPENDENCY_IGNORABLE_NAME) { // don't do anything with this table, it is a magic internal DBSteward value continue; } pgsql8_diff_tables::diff_constraints_table($ofs, NULL, NULL, $schema, $table, 'constraint', FALSE); } $ofs->write("\n"); // trigger definitions foreach ($db_doc->schema as $schema) { foreach ($schema->trigger as $trigger) { // only do triggers set to the current sql format if (strcasecmp($trigger['sqlFormat'], dbsteward::get_sql_format()) == 0) { $ofs->write(pgsql8_trigger::get_creation_sql($schema, $trigger)); } } } $ofs->write("\n"); pgsql8_diff_views::create_views_ordered($ofs, null, $db_doc); // view permission grants foreach ($db_doc->schema as $schema) { foreach ($schema->view as $view) { if (isset($view->grant)) { foreach ($view->grant as $grant) { $ofs->write(pgsql8_permission::get_sql($db_doc, $schema, $view, $grant) . "\n"); } } } } $ofs->write("\n"); // use pgdiff to add any configurationParameters that are defined pgsql8_diff::update_database_config_parameters($ofs, null, $db_doc); }
public function build_schema($db_doc, $ofs, $table_depends) { // explicitly create the ROLE_APPLICATION // webservers connect as a user granted this role $ofs->write("CREATE ROLE " . $db_doc->database->role->application . ";\n"); // schema creation foreach ($db_doc->schema as $schema) { $ofs->write(mssql10_schema::get_creation_sql($schema)); // schema grants if (isset($schema->grant)) { foreach ($schema->grant as $grant) { $ofs->write(mssql10_permission::get_sql($db_doc, $schema, $schema, $grant) . "\n"); } } } // types: enumerated list, etc foreach ($db_doc->schema as $schema) { foreach ($schema->type as $type) { $ofs->write(mssql10_type::get_creation_sql($schema, $type) . "\n"); } } // function definitions foreach ($db_doc->schema as $schema) { foreach ($schema->function as $function) { if (mssql10_function::has_definition($function)) { $ofs->write(mssql10_function::get_creation_sql($schema, $function)); } } } $ofs->write("\n"); // table structure creation foreach ($db_doc->schema as $schema) { // create defined tables foreach ($schema->table as $table) { // table definition $ofs->write(mssql10_table::get_creation_sql($schema, $table) . "\n"); // table indexes mssql10_diff_indexes::diff_indexes_table($ofs, NULL, NULL, $schema, $table); // table grants if (isset($table->grant)) { foreach ($table->grant as $grant) { $ofs->write(mssql10_permission::get_sql($db_doc, $schema, $table, $grant) . "\n"); } } $ofs->write("\n"); } // sequences contained in the schema if (isset($schema->sequence)) { foreach ($schema->sequence as $sequence) { $ofs->write(mssql10_bit_table::get_creation_sql($schema, $sequence) . "\n"); // sequence permission grants if (isset($sequence->grant)) { foreach ($sequence->grant as $grant) { $ofs->write(mssql10_permission::get_sql($db_doc, $schema, $sequence, $grant) . "\n"); } } } } } $ofs->write("\n"); // define table primary keys before foreign keys so unique requirements are always met for FOREIGN KEY constraints foreach ($db_doc->schema as $schema) { foreach ($schema->table as $table) { mssql10_diff_tables::diff_constraints_table($ofs, NULL, NULL, $schema, $table, 'primaryKey', FALSE); } } $ofs->write("\n"); // foreign key references // use the dependency order to specify foreign keys in an order that will satisfy nested foreign keys and etc for ($i = 0; $i < count($table_depends); $i++) { $schema = $table_depends[$i]['schema']; $table = $table_depends[$i]['table']; if ($table['name'] === dbsteward::TABLE_DEPENDENCY_IGNORABLE_NAME) { // don't do anything with this table, it is a magic internal DBSteward value continue; } mssql10_diff_tables::diff_constraints_table($ofs, NULL, NULL, $schema, $table, 'constraint', FALSE); } $ofs->write("\n"); // trigger definitions foreach ($db_doc->schema as $schema) { foreach ($schema->trigger as $trigger) { // only do triggers set to the current sql format if (strcasecmp($trigger['sqlFormat'], dbsteward::get_sql_format()) == 0) { $ofs->write(mssql10_trigger::get_creation_sql($schema, $trigger)); } } } $ofs->write("\n"); // view creation foreach ($db_doc->schema as $schema) { foreach ($schema->view as $view) { $ofs->write(mssql10_view::get_creation_sql($schema, $view)); // view permission grants if (isset($view->grant)) { foreach ($view->grant as $grant) { $ofs->write(mssql10_permission::get_sql($db_doc, $schema, $view, $grant) . "\n"); } } } } $ofs->write("\n"); // @TODO: database configurationParameter support needed ? }
public static function get_permission_operations($node_permission) { if (strcasecmp($node_permission->getName(), 'grant') != 0 && strcasecmp($node_permission->getName(), 'revoke') != 0) { throw new exception("Cannot extract permission rights from node that is not grant or revoke"); } if (!isset($node_permission['operation']) || strlen($node_permission['operation']) == 0) { throw new exception("node_permission operation definition is empty"); } $valid_permission_operations = array('USAGE', 'SELECT', 'DELETE', 'INSERT', 'UPDATE', 'TRIGGER', 'ALL', 'EXECUTE', 'REFERENCES', 'CREATE TABLE', 'ALTER', 'TRUNCATE'); $list = array(); $operation_chunks = preg_split(dbsteward::PATTERN_SPLIT_OPERATION, $node_permission['operation'], -1, PREG_SPLIT_NO_EMPTY); for ($i = 0; $i < count($operation_chunks); $i++) { $chunk = strtoupper(trim($operation_chunks[$i])); // ignore mssql specific operation grants when not generating for it if (strcasecmp(dbsteward::get_sql_format(), 'mssql') != 0) { if (strcasecmp($chunk, 'REFERENCES') == 0) { continue; } if (strcasecmp($chunk, 'CREATE TABLE') == 0) { continue; } if (strcasecmp($chunk, 'ALTER') == 0) { continue; } } if (in_array($chunk, $valid_permission_operations)) { $list[] = $chunk; } else { throw new exception("Unknown permission operation: " . $operation_chunks[$i]); } } return $list; }