public static function get_permission_sql($db_doc, $node_schema, $node_object, $node_permission, $action = 'grant') { 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"); } $object_name = ''; $object_type = strtoupper($node_object->getName()); $privileges = array_map(function ($p) use($object_type) { return mysql5_permission::get_real_privilege($p, $object_type); }, static::get_permission_privileges($node_permission)); $roles = static::get_permission_roles($db_doc, $node_permission); $with = static::get_permission_options_sql($node_permission); switch ($object_type) { case 'SCHEMA': // all tables on current database, because no schemas $object_name = '*'; break; case 'VIEW': return "-- Ignoring permissions on view '{$node_object['name']}' because MySQL uses SQL SECURITY DEFINER semantics\n"; case 'TABLE': $object_name = mysql5::get_fully_qualified_table_name($node_schema['name'], $node_object['name']); break; case 'FUNCTION': $object_name = "FUNCTION " . mysql5::get_fully_qualified_object_name($node_schema['name'], $node_object['name'], 'function'); break; case 'SEQUENCE': // sequences exist as rows in a table for mysql $object_name = mysql5::get_fully_qualified_table_name($node_schema['name'], mysql5_sequence::TABLE_NAME); break; default: throw new exception("unknown object type encountered: " . $object_type); } $sql = static::get_sql(strtoupper($action), $object_name, $privileges, array_map('mysql5::get_quoted_object_name', $roles), $with) . "\n"; return $sql; }
public static function update_permissions($ofs1, $ofs3) { foreach (dbx::get_schemas(dbsteward::$new_database) as $new_schema) { $permissions = $new_schema->xpath('.//grant'); foreach ($permissions as $node_permission) { $node_object = $node_permission->xpath('parent::*'); $node_object = $node_object[0]; if ($node_object === null) { // I have a hard time imagining this could actually happen this far along, but better safe than sorry... throw new Exception("Could not find parent node of permission GRANT {$node_permission['operation']} TO {$node_permission['role']}"); } $ofs1->write(mysql5_permission::get_permission_sql(dbsteward::$new_database, $new_schema, $node_object, $node_permission, 'grant') . "\n"); } } }
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 }
private function common($schema_xml, $obj = NULL, $expected) { $schema = new SimpleXMLElement($schema_xml); $node_obj = $obj ? $schema->{$obj} : $schema; $actual = mysql5_permission::get_permission_sql($this->dbdoc, $schema, $node_obj, $node_obj->grant); $this->assertEquals($expected, trim($actual)); }