コード例 #1
0
 public function __call($m, $a)
 {
     $ignore_ofs_methods = array('__destruct');
     if (in_array($m, $ignore_ofs_methods)) {
         return 'IGNORE_OFS_COMMAND_COMPLETE';
     }
     // if the command is in the list of commands to run on all ofs objects, do so
     $all_ofs_methods = array('append_header', 'append_footer');
     if (in_array($m, $all_ofs_methods)) {
         foreach ($this->ofs as $set_id => $ofs) {
             call_user_func_array(array(&$ofs, $m), $a);
         }
         return 'ALL_OFS_COMMAND_COMPLETE';
     }
     $use_replica_set_id = format::get_context_replica_set_id();
     if ($use_replica_set_id == -10) {
         // context_replica_set_id -10 means object does not have slonySetId defined
         // use the natural first replica set as the replica context
         $first_replica_set = pgsql8::get_slony_replica_set_natural_first(dbsteward::$new_database);
         $use_replica_set_id = (int) $first_replica_set['id'];
     }
     // make sure replica set id to use is known
     if (!isset($this->ofs[$use_replica_set_id])) {
         if ($this->skip_unknown_set_ids) {
             dbsteward::notice("[OFS RSR] context replica set ID is " . $use_replica_set_id . ", but no replica set by that ID, skipping output");
             return FALSE;
         }
         throw new exception("context replica set ID " . $use_replica_set_id . " not defined");
     }
     $active_set_ofs = $this->ofs[$use_replica_set_id];
     dbsteward::debug("[OFS RSR] __call calling " . $use_replica_set_id . " ofs::" . $m);
     return call_user_func_array(array(&$active_set_ofs, $m), $a);
 }
コード例 #2
0
    public function testSlonikOutputIsCorrect()
    {
        $xml = <<<OUTXML
<?xml version="1.0" encoding="UTF-8"?>
<dbsteward>
  <database>
    <sqlformat>pgsql8</sqlformat>
    <role>
      <application>application</application>
      <owner>dba</owner>
      <replication>slony</replication>
      <readonly>readonly</readonly>
    </role>
    <slony clusterName="aim">
      <slonyNode id="1" comment="Master" dbPassword="******" dbUser="******" dbHost="db00" dbName="mrh"/>
      <slonyNode id="2" comment="Replica" dbPassword="******" dbUser="******" dbHost="db01" dbName="mrh"/>
      <slonyReplicaSet id="101" comment="only set" originNodeId="1" upgradeSetId="2">
        <slonyReplicaSetNode id="2" providerNodeId="1"/>
      </slonyReplicaSet>
      <slonyReplicaSet id="201" comment="only set" originNodeId="1" upgradeSetId="3">
        <slonyReplicaSetNode id="2" providerNodeId="1"/>
      </slonyReplicaSet>
    </slony>
  </database>
  <schema name="public" owner="ROLE_OWNER">
    <table name="log" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="log_pkey" slonySetId="101" slonyId="101">
      <column name="id" type="bigserial" slonySetId="101" slonyId="101"/>
      <grant role="ROLE_APPLICATION" operation="INSERT, SELECT, UPDATE, DELETE"/>
    </table>
    <table name="log" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="log_pkey" slonySetId="101" slonyId="102">
      <column name="id" type="bigserial" slonySetId="101" slonyId="102"/>
      <grant role="ROLE_APPLICATION" operation="INSERT, SELECT, UPDATE, DELETE"/>
    </table>
    <table name="log" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="log_pkey" slonySetId="201" slonyId="105">
      <column name="id" type="bigserial" slonySetId="201" slonyId="105"/>
      <grant role="ROLE_APPLICATION" operation="INSERT, SELECT, UPDATE, DELETE"/>
    </table>
    <table name="log" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="log_pkey" slonySetId="201" slonyId="106">
      <column name="id" type="bigserial" slonySetId="201" slonyId="106"/>
      <grant role="ROLE_APPLICATION" operation="INSERT, SELECT, UPDATE, DELETE"/>
    </table>
    <table name="log" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="log_pkey" slonyId="1098">
      <column name="id" type="bigserial" slonyId="1098"/>
      <grant role="ROLE_APPLICATION" operation="INSERT, SELECT, UPDATE, DELETE"/>
    </table>
    <!-- here for additional changes -->
  </schema>
</dbsteward>
OUTXML;
        $old_db_doc = simplexml_load_string($xml);
        dbsteward::$generate_slonik = TRUE;
        $output_prefix_path = dirname(__FILE__) . '/../testdata/' . 'slony_id_output';
        pgsql8::build($output_prefix_path, $old_db_doc);
        $this->assertLogged(Monolog\Logger::NOTICE, '/101:\\s101-102/');
        // before 1098 wasn't getting put into first natural order, now it should be
        $this->assertLogged(Monolog\Logger::NOTICE, '/101:\\s[\\d\\-]+,\\s*1098/', "SlonyIds without slonySetIds are not put into first natural order slonySet");
        $this->assertLogged(Monolog\Logger::NOTICE, '/201:\\s105-106/');
    }
コード例 #3
0
 /**
  * return SQL command for dropping the view
  *
  * @return string
  */
 public static function get_drop_sql($node_schema, $node_view)
 {
     // set replica set context for view
     if (pgsql8::set_context_replica_set_id($node_view) === -10) {
         // view doesn't specify one, set from for schema object
         pgsql8::set_context_replica_set_id($node_schema);
     }
     $ddl = "DROP VIEW IF EXISTS " . pgsql8::get_quoted_schema_name($node_schema['name']) . '.' . pgsql8::get_quoted_table_name($node_view['name']) . ";\n";
     return $ddl;
 }
コード例 #4
0
 /**
  * Creates and returns SQL for dropping the trigger.
  *
  * @return created SQL
  */
 public static function get_drop_sql($node_schema, $node_trigger)
 {
     $node_table = dbx::get_table($node_schema, $node_trigger['table']);
     if ($node_table == null) {
         throw new exception("Failed to find trigger table " . $node_trigger['table'] . " in schema node " . $node_schema['name']);
     }
     $table_name = pgsql8::get_quoted_schema_name($node_schema['name']) . '.' . pgsql8::get_quoted_table_name($node_table['name']);
     $ddl = "DROP TRIGGER " . pgsql8::get_quoted_object_name($node_trigger['name']) . " ON " . $table_name . ";\n";
     return $ddl;
 }
コード例 #5
0
ファイル: sql99_diff.php プロジェクト: williammoran/DBSteward
 /**
  * Creates new schemas (not the objects inside the schemas)
  *
  * @param  object  $ofs output file pointer
  * @return void
  */
 protected static function create_new_schemas($ofs)
 {
     foreach (dbx::get_schemas(dbsteward::$new_database) as $new_schema) {
         if (dbx::get_schema(dbsteward::$old_database, $new_schema['name']) == null) {
             dbsteward::info("Create New Schema " . $new_schema['name']);
             pgsql8::set_context_replica_set_id($new_schema);
             $ofs->write(format_schema::get_creation_sql($new_schema));
         }
     }
 }
コード例 #6
0
    /**
     * There was a bug in streaker where it wasn't counting the entire first streak, output used to be for below: 1, 5-6, 98-98
     */
    public function testSlonikStreakerIsGood()
    {
        $xml = <<<SLONXML
<?xml version="1.0" encoding="UTF-8"?>
<dbsteward>
  <database>
    <sqlformat>pgsql8</sqlformat>
    <role>
      <application>application</application>
      <owner>dba</owner>
      <replication>slony</replication>
      <readonly>readonly</readonly>
    </role>
    <slony clusterName="aim">
      <slonyNode id="1" comment="Master" dbPassword="******" dbUser="******" dbHost="db00" dbName="mrh"/>
      <slonyNode id="2" comment="Replica" dbPassword="******" dbUser="******" dbHost="db01" dbName="mrh"/>
      <slonyReplicaSet id="1" comment="only set" originNodeId="1" upgradeSetId="2">
        <slonyReplicaSetNode id="2" providerNodeId="1"/>
      </slonyReplicaSet>
    </slony>
  </database>
  <schema name="public" owner="ROLE_OWNER">
    <table name="log_sl" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="log_pkey" slonyId="1">
      <column name="id" type="bigserial" slonyId="1"/>
      <grant role="ROLE_APPLICATION" operation="INSERT, SELECT, UPDATE, DELETE"/>
    </table>
    <table name="log_sl2" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="log_pkey" slonyId="2">
      <column name="id" type="bigserial" slonyId="2"/>
      <grant role="ROLE_APPLICATION" operation="INSERT, SELECT, UPDATE, DELETE"/>
    </table>
    <table name="log_sl3" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="log_pkey" slonyId="5">
      <column name="id" type="bigserial" slonyId="5"/>
      <grant role="ROLE_APPLICATION" operation="INSERT, SELECT, UPDATE, DELETE"/>
    </table>
    <table name="log_sl4" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="log_pkey" slonyId="6">
      <column name="id" type="bigserial" slonyId="6"/>
      <grant role="ROLE_APPLICATION" operation="INSERT, SELECT, UPDATE, DELETE"/>
    </table>
    <table name="log_sl5" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="log_pkey" slonyId="98">
      <column name="id" type="bigserial" slonyId="98"/>
      <grant role="ROLE_APPLICATION" operation="INSERT, SELECT, UPDATE, DELETE"/>
    </table>
    <!-- here for additional changes -->
  </schema>
</dbsteward>
SLONXML;
        $old_db_doc = simplexml_load_string($xml);
        dbsteward::$generate_slonik = TRUE;
        $output_prefix_path = dirname(__FILE__) . '/../testdata/' . 'slony_id_streak';
        pgsql8::build($output_prefix_path, $old_db_doc);
        $this->assertLogged(Monolog\Logger::NOTICE, '/sequence ID segments.*:\\s1-2, 5-6, 98/');
    }
コード例 #7
0
 /**
  * Creates views in dependency order
  * @param  output_file_segmenter $ofs        Output file segmenter to write to
  * @param  SimpleXMLElement      $db_doc_old Old database document
  * @param  SimpleXMLElement      $db_doc_new New database document
  */
 public static function create_views_ordered($ofs, $db_doc_old, $db_doc_new)
 {
     static::with_views_in_order($db_doc_new, function ($new_schema, $new_view) use($db_doc_new, $db_doc_old, $ofs) {
         $old_schema = dbx::get_schema($db_doc_old, $new_schema['name']);
         $old_view = dbx::get_view($old_schema, $new_view['name']);
         if (format_diff_views::should_create_view($old_schema, $old_view, $new_schema, $new_view)) {
             // set replica set context for view
             if (pgsql8::set_context_replica_set_id($new_view) === -10) {
                 // view doesn't specify one, set from for schema object
                 pgsql8::set_context_replica_set_id($new_schema);
             }
             $ofs->write(format_view::get_creation_sql($db_doc_new, $new_schema, $new_view) . "\n");
         }
     });
 }
コード例 #8
0
    private function getColumnValue($def, $data)
    {
        $defNode = simplexml_load_string($def);
        $defNodeName = $defNode['name'];
        $schemaXml = <<<XML
<schema name="test_schema">
  <table name="test_table" primaryKey="{$defNodeName}">
    {$def}
    <rows columns="{$defNodeName}">
      <row>{$data}</row>
    </rows>
  </table>
</schema>
XML;
        $schema = simplexml_load_string($schemaXml);
        return pgsql8::column_value_default($schema, $schema->table, $defNodeName, $schema->table->rows->row->col);
    }
コード例 #9
0
 /**
  * Parses definition of the column
  *
  * @param definition definition of the column
  */
 public static function parse_definition(&$node_schema, &$node_table, &$node_column, $definition)
 {
     $type = $definition;
     if (preg_match(self::PATTERN_NOT_NULL, $type, $matches) > 0) {
         $type = trim($matches[1]);
         dbx::set_attribute($node_column, 'null', 'false');
     } else {
         if (preg_match(self::PATTERN_NULL, $type, $matches) > 0 && preg_match(self::PATTERN_DEFAULT_NULL, $type) == 0) {
             // PATTERN_NULL match only if it is not a trailing DEFAULT NULL
             // as that is not a null designation just a default designation
             $type = trim($matches[1]);
             dbx::set_attribute($node_column, 'null', 'true');
         }
     }
     if (preg_match(self::PATTERN_DEFAULT, $type, $matches) > 0) {
         $type = trim($matches[1]);
         dbx::set_attribute($node_column, 'default', trim($matches[2]));
     }
     // post-parsing sanity checks
     if (preg_match('/[\\s]+/', $type) > 0) {
         // type contains whitespace
         // split the type and look for bad tokens
         $bad_keywords = array('DEFAULT', 'UNIQUE');
         $tokens = preg_split("/[\\s]+/", $type, -1, PREG_SPLIT_NO_EMPTY);
         foreach ($tokens as $token) {
             foreach ($bad_keywords as $bad_keyword) {
                 if (strcasecmp($token, $bad_keyword) == 0) {
                     var_dump($definition);
                     throw new exception($node_column['name'] . " column definition parse fail: type '" . $type . "' still contains '" . $bad_keyword . "' keyword -- look at callers for mis-handling of definition parameter");
                 }
             }
         }
     }
     dbx::set_attribute($node_column, 'type', $type);
     // for serial and bigserials, create the accompanying sequence that powers the serial
     if (preg_match(pgsql8::PATTERN_TABLE_LINKED_TYPES, $type) > 0) {
         $sequence_name = pgsql8::identifier_name($node_schema['name'], $node_table['name'], $node_column['name'], '_seq');
         $node_sequence =& dbx::get_sequence($node_schema, $sequence_name, TRUE);
         dbx::set_attribute($node_sequence, 'owner', $node_table['owner']);
         dbx::set_attribute($node_sequence, 'start', '1');
         dbx::set_attribute($node_sequence, 'min', '1');
         dbx::set_attribute($node_sequence, 'inc', '1');
         dbx::set_attribute($node_sequence, 'cycle', 'false');
     }
 }
コード例 #10
0
 /**
  * Modify sequence values if they have changed
  *
  * @param $ofs        output file pointer
  * @param $old_schema original schema
  * @param $new_schema new schema
  */
 private static function add_modified_sequences($ofs, $old_schema, $new_schema)
 {
     foreach (dbx::get_sequences($new_schema) as $new_sequence) {
         if ($old_schema != null && pgsql8_schema::contains_sequence($old_schema, $new_sequence['name'])) {
             $old_sequence = dbx::get_sequence($old_schema, $new_sequence['name']);
             $sql = '';
             if ($new_sequence['inc'] != null && strcasecmp($new_sequence['inc'], $old_sequence['inc']) != 0) {
                 $sql .= "\n\tINCREMENT BY " . $new_sequence['inc'];
             }
             if ($new_sequence['min'] == null && $old_sequence['min'] != null) {
                 $sql .= "\n\tNO MINVALUE";
             } else {
                 if ($new_sequence['min'] != null && strcasecmp($new_sequence['min'], $old_sequence['min']) != 0) {
                     $sql .= "\n\tMINVALUE " . $new_sequence['min'];
                 }
             }
             if ($new_sequence['max'] == null && $old_sequence['max'] != null) {
                 $sql .= "\n\tNO MAXVALUE";
             } else {
                 if ($new_sequence['max'] != null && strcasecmp($new_sequence['max'], $old_sequence['max']) != 0) {
                     $sql .= "\n\tMAXVALUE " . $new_sequence['max'];
                 }
             }
             if (!pgsql8_diff::$ignore_start_with) {
                 if ($new_sequence['start'] != null && strcasecmp($new_sequence['start'], $old_sequence['start']) != 0) {
                     $sql .= "\n\tRESTART WITH " . $new_sequence['start'];
                 }
             }
             if ($new_sequence['cache'] != null && strcasecmp($new_sequence['cache'], $old_sequence['cache']) != 0) {
                 $sql .= "\n\tCACHE " . $new_sequence['cache'];
             }
             if ($old_sequence['cycle'] && !$new_sequence['cycle']) {
                 $sql .= "\n\tNO CYCLE";
             } else {
                 if (!$old_sequence['cycle'] && $new_sequence['cycle']) {
                     $sql .= "\n\tCYCLE";
                 }
             }
             if (strlen($sql) > 0) {
                 $ofs->write("ALTER SEQUENCE " . pgsql8::get_quoted_schema_name($new_schema['name']) . '.' . pgsql8::get_quoted_object_name($new_sequence['name']) . $sql . ";\n");
             }
         }
     }
 }
コード例 #11
0
 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 (self::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) {
             pgsql8::set_context_replica_set_id($old_trigger);
             $ofs->write(pgsql8_trigger::get_drop_sql($old_schema, $old_trigger) . "\n");
         }
     }
     // add new triggers
     foreach (self::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) {
             pgsql8::set_context_replica_set_id($new_trigger);
             $ofs->write(pgsql8_trigger::get_creation_sql($new_schema, $new_trigger) . "\n");
         }
     }
 }
コード例 #12
0
 public function setUp()
 {
     parent::setUp();
     dbsteward::set_sql_format('pgsql8');
     // reset these flags before each test
     pgsql8_diff::$as_transaction = TRUE;
     dbsteward::$require_slony_set_id = FALSE;
     dbsteward::$require_slony_id = FALSE;
     dbsteward::$generate_slonik = FALSE;
     dbsteward::$slonyid_set_value = 1;
     dbsteward::$slonyid_start_value = 1;
     // clear these before each test so we don't run into conflicts
     pgsql8::$table_slony_ids = array();
     pgsql8::$sequence_slony_ids = array();
     pgsql8_diff::$new_table_dependency = null;
     pgsql8_diff::$old_table_dependency = null;
     // rest test fixtures
     $this->in_doc = null;
     $this->slonyid_doc = null;
 }
コード例 #13
0
 /**
  * Outputs commands for dropping types.
  *
  * @param $ofs          output file pointer
  * @param $old_schema   original schema
  * @param $new_schema   new schema
  */
 private static function drop_types($ofs, $old_schema, $new_schema)
 {
     if ($old_schema != NULL) {
         foreach (dbx::get_types($old_schema) as $type) {
             if (!pgsql8_schema::contains_type($new_schema, $type['name'])) {
                 pgsql8::set_context_replica_set_id($type);
                 $ofs->write(pgsql8_type::get_drop_sql($new_schema, $type) . "\n");
             }
         }
     }
 }
コード例 #14
0
    private function common_mismatch($a, $b, $expected)
    {
        $docxml = <<<XML
<dbsteward>
  <database>
    <host>db-host</host>
    <name>dbsteward</name>
    <role>
      <application>dbsteward_phpunit_app</application>
      <owner>deployment</owner>
      <replication/>
      <readonly/>
    </role>
    <slony clusterName="duplicate_slony_ids_testsuite">
      <slonyNode id="1" comment="DSI - Local Primary"  dbName="test" dbHost="db-dev1" dbUser="******" dbPassword="******"/>
      <slonyNode id="2" comment="DSI - Local Backup"   dbName="test" dbHost="db-dev1" dbUser="******" dbPassword="******"/>
      <slonyNode id="3" comment="DSI - Local Backup"   dbName="test" dbHost="db-dev1" dbUser="******" dbPassword="******"/>
      <slonyReplicaSet id="100" originNodeId="1" upgradeSetId="101" comment="common duplicate testing database definition">
        <slonyReplicaSetNode id="2" providerNodeId="1"/>
        <slonyReplicaSetNode id="3" providerNodeId="2"/>
      </slonyReplicaSet>
    </slony>
    <configurationParameter name="TIME ZONE" value="America/New_York"/>
  </database>
  <schema name="dbsteward" owner="ROLE_OWNER">
XML;
        $adoc = new SimpleXMLElement($docxml . $a . "</schema></dbsteward>");
        $bdoc = new SimpleXMLElement($docxml . $b . "</schema></dbsteward>");
        pgsql8::$table_slony_ids = array();
        pgsql8::$sequence_slony_ids = array();
        pgsql8::$known_pg_identifiers = array();
        // for ease in testing, since replica_sets will be the same between
        // adoc and bdoc, just use adoc for iterating over replica sets
        $replica_sets = pgsql8::get_slony_replica_sets($adoc);
        if ($expected !== false) {
            $this->expect_exception($expected, function () use($adoc, $bdoc, $replica_sets) {
                foreach ($replica_sets as $replica_set) {
                    pgsql8::build_upgrade_slonik_replica_set($adoc, $bdoc, $replica_set, $replica_set, __DIR__ . '/../testdata/DuplicateSlonyIdsTest');
                }
            });
        } else {
            $this->expect_no_exception(function () use($adoc, $bdoc, $replica_sets) {
                foreach ($replica_sets as $replica_set) {
                    pgsql8::build_upgrade_slonik_replica_set($adoc, $bdoc, $replica_set, $replica_set, __DIR__ . '/../testdata/DuplicateSlonyIdsTest');
                }
            });
        }
    }
コード例 #15
0
 /**
  * Creates and returns SQL command for dropping the sequence.
  *
  * @return string
  */
 public static function get_drop_sql($node_schema, $node_sequence)
 {
     format::set_context_replica_set_id($node_sequence);
     $ddl = "DROP SEQUENCE " . pgsql8::get_quoted_schema_name($node_schema['name']) . '.' . pgsql8::get_quoted_object_name($node_sequence['name']) . ";\n";
     return $ddl;
 }
コード例 #16
0
 public static function get_drop_sql($node_schema, $node_table, $node_index)
 {
     $ddl = "DROP INDEX " . pgsql8::get_quoted_schema_name($node_schema['name']) . "." . pgsql8::get_quoted_object_name($node_index['name']) . ";\n";
     return $ddl;
 }
コード例 #17
0
 /**
  * Parses all rows in ALTER TABLE command.
  *
  * @param table table being parsed
  * @param commands commands
  *
  * @throws ParserException Thrown if problem occured while parsing DDL.
  */
 private static function parse_rows(&$db_doc, &$node_schema, &$node_table, $commands)
 {
     $line = $commands;
     $subCommand = null;
     while (strlen($line) > 0) {
         $commandEnd = sql_parser::get_command_end($line, 0);
         $subCommand = trim(substr($line, 0, $commandEnd));
         $line = $commandEnd >= strlen($line) ? "" : substr($line, $commandEnd + 1);
         if (strlen($subCommand) > 0) {
             if (preg_match(self::PATTERN_ADD_CONSTRAINT_FOREIGN_KEY, $subCommand, $matches) > 0) {
                 $column_name = trim($matches[3]);
                 $constraint_name = trim($matches[1]);
                 $node_constraint = pgsql8_constraint::get_table_constraint($db_doc, $node_table, $constraint_name, true);
                 dbx::set_attribute($node_constraint, 'definition', trim($matches[2]));
                 $subCommand = "";
             }
         }
         if (preg_match(self::PATTERN_ADD_CONSTRAINT, $subCommand, $matches) > 0) {
             $constraint_name = trim($matches[1]);
             $node_constraint = pgsql8_constraint::get_table_constraint($db_doc, $node_table, $constraint_name, true);
             dbx::set_attribute($node_constraint, 'definition', trim($matches[2]));
             $subCommand = "";
         }
         if (strlen($subCommand) > 0) {
             if (preg_match(self::PATTERN_ADD_PRIMARY_KEY, $subCommand, $matches) > 0) {
                 $definition = trim($matches[1]);
                 $column_name = trim($matches[2]);
                 $constraint_name = $node_table['name'] . '_pkey';
                 dbx::set_attribute($node_table, 'primaryKey', $column_name);
                 $subCommand = "";
             }
         }
         if (strlen($subCommand) > 0) {
             if (preg_match(self::PATTERN_ADD_FOREIGN_KEY, $subCommand, $matches) > 0) {
                 $column_name = trim($matches[2]);
                 $constraint_name = pgsql8::identifier_name($node_schema['name'], $node_table['name'], $column_name, '_fkey');
                 $node_constraint = pgsql8_constraint::get_table_constraint($db_doc, $node_table, $constraint_name, true);
                 dbx::set_attribute($node_constraint, 'definition', trim($matches[1]));
                 $subCommand = "";
             }
         }
         if (strlen($subCommand) > 0) {
             if (preg_match(self::PATTERN_SET_DEFAULT, $subCommand, $matches) > 0) {
                 $column_name = trim($matches[1]);
                 $default_value = trim($matches[2]);
                 if ($node_table->contains_column($column_name)) {
                     $node_column =& dbx::get_column($node_table, $column_name);
                     dbx::set_attribute($node_column, 'default', $default_value);
                 } else {
                     throw new exception("Cannot find column '" . $column_name . " 'in table '" . $node_table['name'] . "'");
                 }
                 $subCommand = "";
             }
         }
         if (preg_match(self::PATTERN_ALTER_COLUMN_STATISTICS, $subCommand, $matches) > 0) {
             $column_name = trim($matches[2]);
             $value = trim($matches[3]);
             $node_column =& dbx::get_column($node_table, $column_name);
             dbx::set_attribute($node_column, 'statistics', $value);
             $subCommand = "";
         }
         if (preg_match(self::PATTERN_CLUSTER_ON, $subCommand, $matches) > 0) {
             $indexName = trim($matches[1]);
             dbx::set_attribute($node_column, 'clusterIndexName', $indexName);
             $subCommand = "";
         }
         if (strlen($subCommand) > 0) {
             if (preg_match(self::PATTERN_TRIGGER, $subCommand, $matches) > 0) {
                 $triggerName = trim($matches[2]);
                 throw new exception("@TODO: do something with ALTER TABLE ... ENABLE / DISABLE trigger statements");
                 $subCommand = "";
             }
         }
         if (strlen($subCommand) > 0) {
             throw new exception("Don't know how to parse: " . $subCommand);
         }
     }
 }
コード例 #18
0
    protected function setup_pgsql8()
    {
        $xml = <<<XML
<dbsteward>
  <database>
    <sqlformat>pgsql8</sqlformat>
    <role>
      <application>app_application</application>
      <owner>postgres</owner>
      <replication>app_slony</replication>
      <readonly>app_readonly</readonly>
    </role>
  </database>
  <schema name="app" owner="ROLE_OWNER">
    <table name="my_table" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="my_table_pk" slonyId="0">
      <column name="id" type="character varying(32)" null="false"/>
      <column name="action" type="character varying(32)"/>
      <column name="description" type="character varying(200)"/>
      <rows columns="id, action, description">
        <row>
          <col>1</col>
          <col>Row 1</col>
          <col>Action 1 Description</col>
        </row>
        <row>
          <col>2</col>
          <col>Row 2</col>
          <col>Action 2 Description</col>
        </row>
        <row>
          <col>3</col>
          <col>Row 3</col>
          <col>Action 3 Description</col>
        </row>
        <row>
          <col>4</col>
          <col>Row 4</col>
          <col>Action 4 Description</col>
        </row>
        <row>
          <col>5</col>
          <col>Row 5</col>
          <col>Action 5 Description</col>
        </row>
      </rows>
    </table>
  </schema>
</dbsteward>
XML;
        $xml_data_overlay = <<<XML
<dbsteward>
  <database>
    <role>
      <application>client_app_application</application>
      <owner>postgres</owner>
      <replication>client_app_slony</replication>
      <readonly>client_app_readonly</readonly>
    </role>
  </database>
  <schema name="app" owner="ROLE_OWNER">
    <table name="my_table" owner="ROLE_OWNER" primaryKey="id" primaryKeyName="my_table_pk" slonyId="0">
      <rows columns="id, description">
        <row>
          <col>2</col>
          <col>Action 2 Alternate Description</col>
        </row>
        <row>
          <col>4</col>
          <col>Action 4 Alternate Description</col>
        </row>
        <row>
          <col>5</col>
          <col>Action 5 Alternate Description</col>
        </row>          
      </rows>
    </table>
  </schema>
</dbsteward>
XML;
        $this->xml_file_a = dirname(__FILE__) . '/../testdata/pgsql8_unit_test_xml_a.xml';
        $this->xml_file_b = dirname(__FILE__) . '/../testdata/pgsql8_unit_test_xml_b.xml';
        $this->xml_file_c = dirname(__FILE__) . '/../testdata/pgsql8_unit_test_xml_c.xml';
        $this->set_xml_content_a($xml);
        $this->set_xml_content_b($xml);
        $this->set_xml_content_c($xml_data_overlay);
        $this->output_prefix = dirname(__FILE__) . '/../testdata/pgsql8_test_identical';
        dbsteward::$single_stage_upgrade = TRUE;
        dbsteward::$generate_slonik = FALSE;
        $old_db_doc_comp = xml_parser::xml_composite(array($this->xml_file_a, $this->xml_file_c));
        $new_db_doc_comp = xml_parser::xml_composite(array($this->xml_file_b, $this->xml_file_c));
        pgsql8::build_upgrade('', 'identical_diff_test_pgsql8_old', $old_db_doc_comp, array(), $this->output_prefix, 'identical_diff_test_pgsql8_new', $new_db_doc_comp, array());
    }
コード例 #19
0
 /**
  * alter_column_type_placeholder's companion - restore $columns list of columns to $node_type type
  *
  * @param $columns      reference columns returned by reference
  * @param $node_schema
  * @param $node_type
  * @return string DDL
  */
 public static function alter_column_type_restore($columns, $node_schema, $node_type)
 {
     $ddl = '';
     foreach ($columns as $column_map) {
         $ddl .= "ALTER TABLE " . pgsql8::get_quoted_schema_name($column_map['alter_column_schema']['name']) . '.' . pgsql8::get_quoted_table_name($column_map['alter_column_table']['name']) . " ALTER COLUMN " . pgsql8::get_quoted_column_name($column_map['alter_column_column']['name']) . " TYPE " . pgsql8::get_quoted_schema_name($node_schema['name']) . '.' . pgsql8::get_quoted_object_name($node_type['name']) . " USING " . pgsql8::get_quoted_column_name($column_map['alter_column_column']['name']) . "::" . pgsql8::get_quoted_schema_name($node_schema['name']) . '.' . pgsql8::get_quoted_object_name($node_type['name']) . ";\n";
     }
     return $ddl;
 }
コード例 #20
0
 /**
  * @group pgsql8
  */
 public function testGoodSerialIdPGSQL8()
 {
     // reset options
     $this->apply_options_pgsql8();
     dbsteward::$require_slony_id = TRUE;
     dbsteward::$generate_slonik = TRUE;
     $this->set_xml_content_a($this->pgsql8_xml_good_serial_id);
     // build the DDL first, incase dbsteward code wants to throw about something
     pgsql8::build($this->output_prefix, xml_parser::xml_composite(array($this->xml_file_a)));
     // if that worked, build a db with this definition
     $this->pgsql8->create_db();
     $this->assertStringNotEqualsFile($this->output_prefix . '_build.sql', '');
     $this->pgsql8->run_file($this->output_prefix . '_build.sql');
 }
コード例 #21
0
 protected static function clause_match($row, $clause)
 {
     // by default the row doesn't match
     // notice that we also break out of the match loop as soon as it doesn't match anymore
     // but make sure the default is false here
     $result = false;
     for ($i = 0; $i < count($clause); $i++) {
         // scan for arrays and recurse into them
         if (is_array($clause[$i])) {
             $result = self::clause_match($row, $clause[$i]);
         } else {
             if (strcasecmp('AND', $clause[$i]) == 0 || strcasecmp('OR', $clause[$i]) == 0) {
                 $before = array_slice($clause, 0, $i);
                 $after = array_slice($clause, $i + 1);
                 if (strcasecmp('AND', $clause[$i]) == 0) {
                     $result = self::clause_match($row, $before) && self::clause_match($row, $after);
                 } else {
                     if (strcasecmp('OR', $clause[$i]) == 0) {
                         $result = self::clause_match($row, $before) || self::clause_match($row, $after);
                     }
                 }
                 break;
             } else {
                 if (in_array($clause[$i], array('=', '!=', '<>'))) {
                     // evaluate the clause operator against the row
                     // is the left hand item a column in this row?
                     if (in_array($clause[$i - 1], array_keys($row))) {
                         // then compare that column to the right hand side of the oper
                         // SQL to PHP comparison operator filter
                         $operator = $clause[$i];
                         if ($operator == '=') {
                             $operator = '==';
                         } else {
                             if ($operator = '<>') {
                                 $operator = '!=';
                             }
                         }
                         $left_side = pgsql8::strip_escaping_e($row[$clause[$i - 1]]);
                         // row[col]'s value
                         $right_side = pgsql8::strip_escaping_e($clause[$i + 1]);
                         // comparison value
                         $expression = $left_side . ' ' . $operator . ' ' . $right_side;
                         $eval_expression = '$result = ( ' . $expression . ' ) ;';
                         if (eval($eval_expression) === false) {
                             throw new exception("eval() failed on eval_expression: " . $eval_expression);
                         }
                     }
                     // if the row doesn't match anymore, stop trying
                     if (!$result) {
                         break;
                     }
                 } else {
                     // dbsteward::console_line(6, "clause[$i] = " . $clause[$i]);
                     //$result = rand(1,5) != 2;
                 }
             }
         }
     }
     return $result;
 }
コード例 #22
0
 /**
  * Updates data in table definitions
  *
  * @param ofs output file segmenter
  * @param $old_database original database
  * @param $new_database new database
  */
 private static function update_data($ofs, $delete_mode = false)
 {
     if (self::$new_table_dependency != null && count(self::$new_table_dependency) > 0) {
         for ($i = 0; $i < count(self::$new_table_dependency); $i++) {
             // go in reverse when in delete mode
             if ($delete_mode) {
                 $item = self::$new_table_dependency[count(self::$new_table_dependency) - 1 - $i];
             } else {
                 $item = self::$new_table_dependency[$i];
             }
             if ($item['table']['name'] === dbsteward::TABLE_DEPENDENCY_IGNORABLE_NAME) {
                 // don't do anything with this table, it is a magic internal DBSteward value
                 continue;
             }
             $old_schema = dbx::get_schema(dbsteward::$old_database, $item['schema']['name']);
             $old_table = null;
             if ($old_schema != null) {
                 $old_table = dbx::get_table($old_schema, $item['table']['name']);
             }
             $new_schema = dbx::get_schema(dbsteward::$new_database, $item['schema']['name']);
             if ($new_schema == null) {
                 throw new exception("schema " . $item['schema']['name'] . " not found in new database");
             }
             $new_table = dbx::get_table($new_schema, $item['table']['name']);
             if ($new_table == null) {
                 throw new exception("table " . $item['table']['name'] . " not found in new database schema " . $new_schema['name']);
             }
             pgsql8::set_context_replica_set_id($new_schema);
             // if the table was renamed, get old definition pointers for comparison
             if (pgsql8_diff_tables::is_renamed_table($new_schema, $new_table)) {
                 dbsteward::info("NOTICE: " . $new_schema['name'] . "." . $new_table['name'] . " used to be called " . $new_table['oldTableName'] . " -- will diff data against that definition");
                 $old_schema = pgsql8_table::get_old_table_schema($new_schema, $new_table);
                 $old_table = pgsql8_table::get_old_table($new_schema, $new_table);
             }
             $ofs->write(pgsql8_diff_tables::get_data_sql($old_schema, $old_table, $new_schema, $new_table, $delete_mode));
         }
     } else {
         // dependency order unknown, hit them in natural order
         foreach (dbx::get_schemas(dbsteward::$new_database) as $new_schema) {
             pgsql8::set_context_replica_set_id($new_schema);
             $old_schema = dbx::get_schema(dbsteward::$old_database, $new_schema['name']);
             pgsql8_diff_tables::diff_data($ofs, $old_schema, $new_schema);
         }
     }
 }
コード例 #23
0
ファイル: pgsql8.php プロジェクト: williammoran/DBSteward
 /**
  * Get the attribute of the specified replica set node
  * Ths resolves node inheritance and explicit configuration data 
  * such as alternate database service addresses in slony configurations
  * @param SimpleXMLElement $replica_set
  * @param integer $node_id
  * @param string $attribute
  */
 protected static function get_slony_replica_set_node_attribute($db_doc, $replica_set, $node_id, $attribute)
 {
     $replica_node = NULL;
     // is the node_id specified the origin node?
     if ((int) $replica_set['originNodeId'] == $node_id) {
         $replica_node = $replica_set;
     } else {
         foreach ($replica_set->slonyReplicaSetNode as $set_node) {
             if ((int) $set_node['id'] == $node_id) {
                 $replica_node = $set_node;
             }
         }
     }
     if (!is_object($replica_node)) {
         throw new exception("Replica set " . $replica_set['id'] . " node " . $node_id . " not found");
     }
     // if the replica_node defines this attribute, return it, if not return master node definition value
     if (isset($replica_node[$attribute])) {
         return (string) $replica_node[$attribute];
     }
     $slony_node = pgsql8::get_slony_node($db_doc, $node_id);
     return (string) $slony_node[$attribute];
 }
コード例 #24
0
 /**
  * @group pgsql8
  */
 public function testTableColumnTypeQuotingPgsql8()
 {
     dbsteward::set_sql_format('pgsql8');
     dbsteward::$quote_all_names = TRUE;
     dbsteward::$single_stage_upgrade = TRUE;
     $doc_empty = simplexml_load_string($this->xml_empty);
     $doc_empty = xml_parser::composite_doc(FALSE, $doc_empty);
     dbsteward::$old_database = $doc_empty;
     $doc = simplexml_load_string($this->xml);
     $doc = xml_parser::composite_doc(FALSE, $doc);
     dbsteward::$new_database = $doc;
     $table_dependency = xml_parser::table_dependency_order($doc);
     //var_dump(xml_parser::format_xml($doc_empty->saveXML()));
     //var_dump(xml_parser::format_xml($doc->saveXML()));
     $schema = $doc->schema;
     $table = $schema->table;
     // make sure the type is named with quoting as part of a definition build
     $expected = "CREATE TYPE \"schema1\".\"enumCamelCaseType\" AS ENUM ('Read','Write','Delete');";
     $mofs = new mock_output_file_segmenter();
     pgsql8::build_schema($doc, $mofs, $table_dependency);
     $actual = trim($mofs->_get_output());
     $this->assertContains($expected, $actual);
     // make sure the type is referred to with quoting in a table creation as part of a definition build
     $expected_column = '"table_shable_mode" "enumCamelCaseType"';
     $this->assertContains($expected_column, $actual);
     // make sure the type is referred to with quoting when generating table create statements
     $expected = '"table_shable_mode" "enumCamelCaseType"';
     $sql = pgsql8_table::get_creation_sql($schema, $table);
     $this->assertContains($expected, $sql);
     // make sure create table quotes the type name
     $expected = '"table_shable_mode" "enumCamelCaseType"';
     $mofs = new mock_output_file_segmenter();
     var_dump(dbx::get_tables($schema));
     pgsql8_diff_tables::diff_tables($mofs, $mofs, NULL, $schema);
     $actual = trim($mofs->_get_output());
     $this->assertContains($expected, $actual);
     // make sure insert statements are made that match the XML definition
     $expected = "INSERT INTO \"schema1\".\"table_shable\" (\"table_shable_id\", \"table_shable_value\", \"table_shable_mode\") VALUES (1, E'shim sham', BETA);";
     $actual = trim(pgsql8_diff_tables::get_data_sql(NULL, NULL, $schema, $table, FALSE));
     $this->assertContains($expected, $actual);
 }
コード例 #25
0
 public function setUp()
 {
     parent::setUp();
     dbsteward::set_sql_format('pgsql8');
     // reset these flags before each test
     pgsql8_diff::$as_transaction = TRUE;
     dbsteward::$generate_slonik = FALSE;
     // clear these before each test so we don't run into conflicts
     pgsql8::$table_slony_ids = array();
     pgsql8::$sequence_slony_ids = array();
     pgsql8_diff::$new_table_dependency = null;
     pgsql8_diff::$old_table_dependency = null;
 }
コード例 #26
0
    public function testNoTableSequencesBuilds()
    {
        // the base pgsql8 class keeps track of sequence columns linked to tables
        // (i.e. as primary keys, etc.)
        // during schema extraction so as to avoid creating duplicates; however,
        // if no tables link sequences, then the WHERE clause will contain an
        // empty string. this test should prove that this is no longer an issue.
        $xml = <<<XML
<dbsteward>
  <database>
    <role>
      <application>deployment</application>
      <owner>deployment</owner>
      <replication/>
      <readonly/>
    </role>
  </database>
  <schema name="public" owner="ROLE_OWNER">
    <!-- this sequence is just hanging around, not keyed to the table at all,
         so as to trigger an empty WHERE clause which should be handled
         properly now -->
    <sequence name="test_seq" start="1" inc="1" max="15" cycle="false" cache="1" owner="ROLE_OWNER">
      <grant operation="USAGE,SELECT,UPDATE" role="ROLE_APPLICATION"/>
    </sequence>
    <table name="user" owner="ROLE_OWNER" description="user logins" primaryKey="user_name">
      <column name="user_name" type="varchar(100)" null="false"/>
      <column name="user_role" type="varchar(100)" null="false"/>
      <column name="user_create_date" type="timestamp with time zone" null="false" default="NOW()"/>
      <grant role="ROLE_APPLICATION" operation="SELECT, INSERT, UPDATE"/>
      <rows columns="user_name, user_role">
        <tabrow>toor\tsuper_admin</tabrow>
      </rows>
    </table>
  </schema>
</dbsteward>
XML;
        //
        $this->xml_file_a = __DIR__ . '/../testdata/unit_test_xml_a.xml';
        file_put_contents($this->xml_file_a, $xml);
        $this->build_db_pgsql8();
        $extracted_xml = pgsql8::extract_schema($this->pgsql8->get_dbhost(), $this->pgsql8->get_dbport(), $this->pgsql8->get_dbname(), $this->pgsql8->get_dbuser(), $this->pgsql8->get_dbpass());
        // no errors thrown by this point? we should be fine, but let's do some
        // checks to prove DDL integrtiry
        $rebuilt_db = simplexml_load_string($extracted_xml);
        $schema_node = $rebuilt_db->xpath("schema[@name='public']");
        $table_node = $schema_node[0]->xpath("table");
        // just make sure the table was built for now, the other tests do more
        // advanced checking
        $this->assertEquals('user', (string) $table_node[0]['name']);
        // test the sequence to make sure it built properly
        $sequence_node = $schema_node[0]->xpath("sequence");
        $expected_seq = $sequence_node[0];
        $this->assertEquals('test_seq', (string) $expected_seq['name']);
        $this->assertEquals(1, (string) $expected_seq['min']);
        $this->assertEquals(15, (string) $expected_seq['max']);
        $this->assertEquals(1, (string) $expected_seq['cache']);
    }
コード例 #27
0
 /**
  * Creates and returns SQL for dropping the language.
  *
  * @return string
  */
 public static function get_drop_sql($node_language)
 {
     $ddl = "DROP " . (strcasecmp(dbsteward::string_cast($node_language['procedural']), 'true') == 0 ? "PROCEDURAL " : "") . " LANGUAGE " . pgsql8::get_quoted_object_name($node_language['name']) . " ;";
     return $ddl;
 }
コード例 #28
0
 /**
  * @group pgsql8
  */
 public function testUpgradeNewTablePgsql8()
 {
     $this->apply_options_pgsql8();
     $this->setup_pgsql8();
     // upgrade from base
     // to base + strict action table + new resolution table
     // check null specificity
     $base_db_doc = xml_parser::xml_composite(array($this->xml_file_a));
     $newtable_db_doc = xml_parser::xml_composite(array($this->xml_file_a, $this->xml_file_b, $this->xml_file_c));
     pgsql8::build_upgrade('', 'newtable_upgrade_test_pgsql8_base', $base_db_doc, array(), $this->output_prefix, 'newtable_upgrade_test_pgsql8_newtable', $newtable_db_doc, array());
     $text = file_get_contents($this->output_prefix . '_upgrade_single_stage.sql');
     // make sure NOT NULL is specified for description column
     $this->assertContains('ALTER COLUMN "description" SET NOT NULL', $text);
     // make sure NOT NULL is specified for resolution column
     $this->assertContains('ALTER COLUMN "resolution" SET NOT NULL', $text);
     // make sure NOT NULL is NOT specified for points column
     $this->assertNotContains('ALTER COLUMN "points" SET NOT NULL', $text);
 }
コード例 #29
0
ファイル: dbsteward.php プロジェクト: nkiraly/dbsteward
 public function arg_parse($argv)
 {
     $short_opts = 'hvq';
     $long_opts = array("sqlformat::", "xml::", "oldxml::", "newxml::", "pgdataxml::", "xmldatainsert::", "outputfile::", "dbschemadump::", "slonikconvert::", "slonycompare::", "slonydiffold::", "slonydiffnew::", "slonyidin::", "slonyidout::", "slonyidstartvalue::", "slonyidsetvalue::", "oldsql::", "newsql::", "dbhost::", "dbport::", "dbname::", "dbuser::", "dbpassword::", "requireslonyid::", "requireslonysetid::", "generateslonik::", "quoteschemanames::", "quotetablenames::", "quotecolumnnames::", "quoteallnames::", "quoteillegalnames::", "quotereservednames::", "onlyschemasql::", "onlydatasql::", "onlytable::", "singlestageupgrade::", "maxstatementsperfile::", "ignoreoldnames::", "ignorecustomroles::", "ignoreprimarykeyerrors::", "dbdatadiff::", "xmlsort::", "xmlconvert::", "xmlcollectdataaddendums::", "useautoincrementoptions::", "useschemaprefix::", "outputdir::", "outputfileprefix::", "debug");
     $options = getopt($short_opts, $long_opts);
     self::set_verbosity($options);
     if (count($argv) == 1 || isset($options['help']) || isset($options['h'])) {
         $c = new Colors\Color();
         $c->setTheme(array('header' => array('underline', 'dark_gray'), 'keyword' => array('green'), 'value' => array('yellow')));
         echo $c->colorize(self::usage()) . PHP_EOL;
         exit(1);
     }
     $files = array('old' => array(), 'new' => array(), 'pgdata' => array());
     ///// XML file parameter sanity checks
     if (isset($options['xml'])) {
         if (count($options['xml']) > 0 && isset($options['oldxml']) && count($options['oldxml']) > 0) {
             dbsteward::error("Parameter error: xml and oldxml options are not to be mixed. Did you mean newxml?");
             exit(1);
         }
         if (count($options['xml']) > 0 && isset($options['newxml']) && count($options['newxml']) > 0) {
             dbsteward::error("Parameter error: xml and newxml options are not to be mixed. Did you mean oldxml?");
             exit(1);
         }
     }
     if (isset($options['oldxml']) && count($options['oldxml']) > 0 && (!isset($options['newxml']) || count($options['newxml']) == 0)) {
         dbsteward::error("Parameter error: oldxml needs newxml specified for differencing to occur");
         exit(1);
     }
     if ((!isset($options['oldxml']) || count($options['oldxml']) == 0) && (isset($options['newxml']) && count($options['newxml']) > 0)) {
         dbsteward::error("Parameter error: oldxml needs newxml specified for differencing to occur");
         exit(1);
     }
     ///// database connectivity values
     $dbhost = FALSE;
     if (isset($options["dbhost"]) && strlen($options["dbhost"]) > 0) {
         $dbhost = $options["dbhost"];
     }
     // $dbport set in sql_format defaults section
     $dbport = NULL;
     if (isset($options["dbport"]) && strlen($options["dbport"]) > 0) {
         $dbport = $options["dbport"];
     }
     $dbname = FALSE;
     if (isset($options["dbname"]) && strlen($options["dbname"]) > 0) {
         $dbname = $options["dbname"];
     }
     $dbuser = FALSE;
     if (isset($options["dbuser"]) && strlen($options["dbuser"]) > 0) {
         $dbuser = $options["dbuser"];
     }
     if (isset($options['dbpassword'])) {
         if ($options['dbpassword'] === false) {
             // treat --dbpassword as the empty password, because
             // --dbpassword='' doesn't show up in $options
             $this->cli_dbpassword = '';
         } else {
             $this->cli_dbpassword = $options['dbpassword'];
         }
     }
     ///// SQL DDL DML DCL output flags
     if (isset($options["onlyschemasql"])) {
         dbsteward::$only_schema_sql = TRUE;
     }
     if (isset($options["onlydatasql"])) {
         dbsteward::$only_data_sql = TRUE;
     }
     if (isset($options['onlytable'])) {
         $onlytables = $options['onlytable'];
         if (!is_array($onlytables)) {
             $onlytables = array($onlytables);
         }
         foreach ($onlytables as $onlytable) {
             $onlytable_schema = 'public';
             $onlytable_table = $onlytable;
             if (strpos($onlytable_table, '.') !== FALSE) {
                 $chunks = explode('.', $onlytable_table);
                 $onlytable_schema = $chunks[0];
                 $onlytable_table = $chunks[1];
             }
             if (!isset(dbsteward::$limit_to_tables[$onlytable_schema])) {
                 dbsteward::$limit_to_tables[$onlytable_schema] = array();
             }
             dbsteward::$limit_to_tables[$onlytable_schema][] = $onlytable_table;
         }
     }
     ///// common parameter for output file for converter functions
     // for modes that can do it, omitting this parameter will cause output to be directed to stdout
     $output_file = FALSE;
     if (isset($options["outputfile"]) && strlen($options["outputfile"]) > 0) {
         $output_file = $options["outputfile"];
     }
     if (isset($options["maxstatementsperfile"])) {
         if (!is_numeric($options["maxstatementsperfile"])) {
             throw new exception("maxstatementsperfile passed is not a number");
         }
         dbsteward::$output_file_statement_limit = $options["maxstatementsperfile"];
     }
     ///// XML parsing switches
     if (isset($options["singlestageupgrade"])) {
         dbsteward::$single_stage_upgrade = TRUE;
         // don't recreate views when in single stage upgrade mode
         // @TODO: make view diffing smart enough that this doesn't need to be done
         dbsteward::$always_recreate_views = FALSE;
     }
     if (isset($options["ignoreoldnames"])) {
         dbsteward::$ignore_oldnames = TRUE;
     }
     if (isset($options["ignorecustomroles"])) {
         dbsteward::$ignore_custom_roles = TRUE;
     }
     if (isset($options["ignoreprimarykeyerrors"])) {
         dbsteward::$ignore_primary_key_errors = TRUE;
     }
     if (isset($options["requireslonyid"])) {
         dbsteward::$require_slony_id = TRUE;
     }
     if (isset($options["requireslonysetid"])) {
         dbsteward::$require_slony_set_id = TRUE;
     }
     if (isset($options["generateslonik"])) {
         dbsteward::$generate_slonik = TRUE;
     }
     if (isset($options["slonyidstartvalue"])) {
         if ($options["slonyidstartvalue"] < 1) {
             throw new exception("slonyidstartvalue must be greater than 0");
         }
         dbsteward::$slonyid_start_value = $options["slonyidstartvalue"];
     }
     if (isset($options["slonyidsetvalue"])) {
         if ($options["slonyidsetvalue"] < 1) {
             throw new exception("slonyidsetvalue must be greater than 0");
         }
         dbsteward::$slonyid_set_value = $options["slonyidsetvalue"];
     }
     ///// determine the operation and check arguments for each
     $mode = dbsteward::MODE_UNKNOWN;
     if (isset($options['xmldatainsert'])) {
         if (!isset($options['xml'])) {
             throw new exception("xmldatainsert needs xml parameter defined");
         }
         $mode = dbsteward::MODE_XML_DATA_INSERT;
     } elseif (isset($options["xmlsort"])) {
         $mode = dbsteward::MODE_XML_SORT;
     } elseif (isset($options["xmlconvert"])) {
         $mode = dbsteward::MODE_XML_CONVERT;
     } elseif (isset($options['xml']) && count($options['xml']) > 0) {
         $mode = dbsteward::MODE_BUILD;
     } elseif (isset($options['newxml']) && count($options['newxml']) > 0) {
         $mode = dbsteward::MODE_DIFF;
     } elseif (isset($options["dbschemadump"])) {
         if (strlen($dbhost) === FALSE) {
             throw new exception("dbschemadump error: dbhost not specified");
         } elseif (strlen($dbname) === FALSE) {
             throw new exception("dbschemadump error: dbname not specified");
         } elseif (strlen($dbuser) === FALSE) {
             throw new exception("dbschemadump error: dbuser not specified");
         } elseif ($output_file === FALSE) {
             throw new exception("dbschemadump error: outputfile not specified");
         }
         $mode = dbsteward::MODE_EXTRACT;
     } elseif (isset($options['dbdatadiff'])) {
         if (strlen($dbhost) === FALSE) {
             throw new exception("dbdatadiff error: dbhost not specified");
         } elseif (strlen($dbname) === FALSE) {
             throw new exception("dbdatadiff error: dbname not specified");
         } elseif (strlen($dbuser) === FALSE) {
             throw new exception("dbdatadiff error: dbuser not specified");
         }
         $mode = dbsteward::MODE_DB_DATA_DIFF;
     } elseif (isset($options["oldsql"]) || isset($options["newsql"])) {
         if ($output_file === FALSE) {
             throw new exception("sql diff error: you must specify an outputfile for this mode");
         }
         $mode = dbsteward::MODE_SQL_DIFF;
     } elseif (isset($options["slonikconvert"])) {
         $mode = dbsteward::MODE_SLONIK_CONVERT;
     } elseif (isset($options["slonycompare"])) {
         $mode = dbsteward::MODE_SLONY_COMPARE;
     } elseif (isset($options["slonydiffold"])) {
         $mode = dbsteward::MODE_SLONY_DIFF;
     } elseif (isset($options["slonyidin"])) {
         // check to make sure output is not same as input
         if (isset($options["slonyidout"])) {
             if (strcmp($options["slonyidin"], $options["slonyidout"]) == 0) {
                 throw new exception("slonyidin and slonyidout file paths should not be the same");
             }
         }
         $mode = dbsteward::MODE_XML_SLONY_ID;
     }
     ///// File output location specificity
     if (isset($options['outputdir'])) {
         if (strlen($options['outputdir']) == 0) {
             throw new exception("outputdir is blank, must specify a value for this option");
         }
         if (!is_dir($options['outputdir'])) {
             throw new exception("outputdir is not a directory; this must be a writable directory");
         }
         dbsteward::$file_output_directory = $options['outputdir'];
     }
     if (isset($options['outputfileprefix'])) {
         if (strlen($options['outputfileprefix']) == 0) {
             throw new exception("outputfileprefix is blank, must specify a value for this option");
         }
         dbsteward::$file_output_prefix = $options['outputfileprefix'];
     }
     ///// For the appropriate modes, composite the input XML
     ///// and figure out the SQL format of it
     $force_sql_format = FALSE;
     if (isset($options['sqlformat'])) {
         $force_sql_format = $options['sqlformat'];
     }
     $target_sql_format = FALSE;
     switch ($mode) {
         case dbsteward::MODE_BUILD:
             $files = (array) $options['xml'];
             $target_sql_format = xml_parser::get_sql_format($files);
             break;
         case dbsteward::MODE_DIFF:
             $old_files = (array) $options['oldxml'];
             $new_files = (array) $options['newxml'];
             $old_target = xml_parser::get_sql_format($old_files);
             $new_target = xml_parser::get_sql_format($new_files);
             // prefer the new sql_format
             $target_sql_format = $new_target ?: $old_target;
             break;
     }
     $xml_collect_data_addendums = 0;
     if (isset($options["xmlcollectdataaddendums"]) && $options["xmlcollectdataaddendums"] > 0) {
         $xml_collect_data_addendums = (int) $options["xmlcollectdataaddendums"];
         if ($mode != dbsteward::MODE_BUILD) {
             throw new Exception("--xmlcollectdataaddendums is only supported for fresh builds");
         }
         if ($xml_collect_data_addendums > count($files)) {
             throw new Exception("Cannot collect more data addendums then files provided");
         }
     }
     // announce our defined version before doing any configuration announcements or tasks
     dbsteward::notice("DBSteward Version " . self::VERSION);
     ///// set the global SQL format
     $sql_format = dbsteward::reconcile_sql_format($target_sql_format, $force_sql_format);
     dbsteward::notice("Using sqlformat={$sql_format}");
     dbsteward::set_sql_format($sql_format);
     if (is_null($dbport)) {
         $dbport = dbsteward::define_sql_format_default_values($sql_format, $options);
     }
     // user-specified overrides for identifier quoting
     if (isset($options["quoteschemanames"])) {
         dbsteward::$quote_schema_names = TRUE;
     }
     if (isset($options["quotetablenames"])) {
         dbsteward::$quote_table_names = TRUE;
     }
     if (isset($options["quotecolumnnames"])) {
         dbsteward::$quote_column_names = TRUE;
     }
     if (isset($options["quoteallnames"])) {
         dbsteward::$quote_all_names = TRUE;
     }
     if (isset($options["quoteillegalnames"])) {
         dbsteward::$quote_illegal_identifiers = TRUE;
     }
     if (isset($options["quotereservednames"])) {
         dbsteward::$quote_reserved_identifiers = TRUE;
     }
     switch ($mode) {
         case dbsteward::MODE_XML_DATA_INSERT:
             dbsteward::xml_data_insert($options['xml'], $options['xmldatainsert']);
             break;
         case dbsteward::MODE_XML_SORT:
             dbsteward::xml_sort($options['xmlsort']);
             break;
         case dbsteward::MODE_XML_CONVERT:
             dbsteward::xml_convert($options['xmlconvert']);
             break;
         case dbsteward::MODE_XML_SLONY_ID:
             dbsteward::info("Compositing XML file for Slony ID processing..");
             $files = (array) $options['slonyidin'];
             $db_doc = xml_parser::xml_composite($files);
             dbsteward::info("XML files " . implode(' ', $files) . " composited");
             $output_prefix = dbsteward::calculate_file_output_prefix($files);
             $composite_file = $output_prefix . '_composite.xml';
             $db_doc = xml_parser::sql_format_convert($db_doc);
             xml_parser::vendor_parse($db_doc);
             dbsteward::notice("Saving composite as " . $composite_file);
             xml_parser::save_doc($composite_file, $db_doc);
             dbsteward::notice("Slony ID numbering any missing attributes");
             dbsteward::info("slonyidstartvalue = " . dbsteward::$slonyid_start_value);
             dbsteward::info("slonyidsetvalue = " . dbsteward::$slonyid_set_value);
             $slonyid_doc = xml_parser::slonyid_number($db_doc);
             $slonyid_numbered_file = $output_prefix . '_slonyid_numbered.xml';
             // if specified, use output file value instead of auto suffix
             if (isset($options["slonyidout"])) {
                 $slonyid_numbered_file = $options["slonyidout"];
             }
             dbsteward::notice("Saving Slony ID numbered XML as " . $slonyid_numbered_file);
             xml_parser::save_doc($slonyid_numbered_file, $slonyid_doc);
             break;
         case dbsteward::MODE_BUILD:
             dbsteward::info("Compositing XML files..");
             $addendums_doc = NULL;
             if ($xml_collect_data_addendums > 0) {
                 dbsteward::info("Collecting {$xml_collect_data_addendums} data addendums");
             }
             $db_doc = xml_parser::xml_composite($files, $xml_collect_data_addendums, $addendums_doc);
             if (isset($options['pgdataxml']) && count($options['pgdataxml'])) {
                 $pg_data_files = (array) $options['pgdataxml'];
                 dbsteward::info("Compositing pgdata XML files on top of XML composite..");
                 xml_parser::xml_composite_pgdata($db_doc, $pg_data_files);
                 dbsteward::info("postgres data XML files [" . implode(' ', $pg_data_files) . "] composited.");
             }
             dbsteward::info("XML files " . implode(' ', $files) . " composited");
             $output_prefix = dbsteward::calculate_file_output_prefix($files);
             $composite_file = $output_prefix . '_composite.xml';
             $db_doc = xml_parser::sql_format_convert($db_doc);
             xml_parser::vendor_parse($db_doc);
             dbsteward::notice("Saving composite as " . $composite_file);
             xml_parser::save_doc($composite_file, $db_doc);
             if ($addendums_doc !== NULL) {
                 $addendums_file = $output_prefix . '_addendums.xml';
                 dbsteward::notice("Saving addendums as {$addendums_file}");
                 xml_parser::save_doc($addendums_file, $addendums_doc);
             }
             format::build($output_prefix, $db_doc);
             break;
         case dbsteward::MODE_DIFF:
             dbsteward::info("Compositing old XML files..");
             $old_db_doc = xml_parser::xml_composite($old_files);
             dbsteward::info("Old XML files " . implode(' ', $old_files) . " composited");
             dbsteward::info("Compositing new XML files..");
             $new_db_doc = xml_parser::xml_composite($new_files);
             if (isset($options['pgdataxml']) && count($options['pgdataxml'])) {
                 $pg_data_files = (array) $options['pgdataxml'];
                 dbsteward::info("Compositing pgdata XML files on top of new XML composite..");
                 xml_parser::xml_composite_pgdata($new_db_doc, $pg_data_files);
                 dbsteward::info("postgres data XML files [" . implode(' ', $pg_data_files) . "] composited");
             }
             dbsteward::info("New XML files " . implode(' ', $new_files) . " composited");
             $old_output_prefix = dbsteward::calculate_file_output_prefix($old_files);
             $old_composite_file = $old_output_prefix . '_composite.xml';
             $old_db_doc = xml_parser::sql_format_convert($old_db_doc);
             xml_parser::vendor_parse($old_db_doc);
             dbsteward::notice("Saving oldxml composite as " . $old_composite_file);
             xml_parser::save_doc($old_composite_file, $old_db_doc);
             $new_output_prefix = dbsteward::calculate_file_output_prefix($new_files);
             $new_composite_file = $new_output_prefix . '_composite.xml';
             $new_db_doc = xml_parser::sql_format_convert($new_db_doc);
             xml_parser::vendor_parse($new_db_doc);
             dbsteward::notice("Saving newxml composite as " . $new_composite_file);
             xml_parser::save_doc($new_composite_file, $new_db_doc);
             format::build_upgrade($old_output_prefix, $old_composite_file, $old_db_doc, $old_files, $new_output_prefix, $new_composite_file, $new_db_doc, $new_files);
             break;
         case dbsteward::MODE_EXTRACT:
             $output = format::extract_schema($dbhost, $dbport, $dbname, $dbuser, $this->cli_dbpassword);
             dbsteward::notice("Saving extracted database schema to " . $output_file);
             if (!file_put_contents($output_file, $output)) {
                 throw new exception("Failed to save extracted database schema to " . $output_file);
             }
             break;
         case dbsteward::MODE_DB_DATA_DIFF:
             // dbdatadiff files are defined with --dbdatadiff not --xml
             $dbdatadiff_files = (array) $options['dbdatadiff'];
             dbsteward::info("Compositing XML files..");
             $addendums_doc = NULL;
             if ($xml_collect_data_addendums > 0) {
                 dbsteward::info("Collecting {$xml_collect_data_addendums} data addendums");
             }
             $db_doc = xml_parser::xml_composite($dbdatadiff_files, $xml_collect_data_addendums, $addendums_doc);
             if (isset($options['pgdataxml']) && count($options['pgdataxml'])) {
                 $pg_data_files = (array) $options['pgdataxml'];
                 dbsteward::info("Compositing pgdata XML files on top of XML composite..");
                 xml_parser::xml_composite_pgdata($db_doc, $pg_data_files);
                 dbsteward::info("postgres data XML files [" . implode(' ', $pg_data_files) . "] composited.");
             }
             dbsteward::info("XML files " . implode(' ', $dbdatadiff_files) . " composited");
             $output_prefix = dbsteward::calculate_file_output_prefix($dbdatadiff_files);
             $composite_file = $output_prefix . '_composite.xml';
             $db_doc = xml_parser::sql_format_convert($db_doc);
             xml_parser::vendor_parse($db_doc);
             dbsteward::notice("Saving composite as " . $composite_file);
             xml_parser::save_doc($composite_file, $db_doc);
             $output = format::compare_db_data($db_doc, $dbhost, $dbport, $dbname, $dbuser, $this->cli_dbpassword);
             if (!file_put_contents($output_file, $output)) {
                 throw new exception("Failed to save extracted database schema to " . $output_file);
             }
             break;
         case dbsteward::MODE_SQL_DIFF:
             format::sql_diff($options["oldsql"], $options["newsql"], $output_file);
             break;
         case dbsteward::MODE_SLONIK_CONVERT:
             $output = slony1_slonik::convert($options["slonikconvert"]);
             if ($output_file !== FALSE) {
                 dbsteward::notice("Saving slonikconvert output to " . $output_file);
                 if (!file_put_contents($output, $output_file)) {
                     throw new exception("Failed to save slonikconvert output to " . $output_file);
                 }
             } else {
                 echo $output;
             }
             break;
         case dbsteward::MODE_SLONY_COMPARE:
             pgsql8::slony_compare($options["slonycompare"]);
             break;
         case dbsteward::MODE_SLONY_DIFF:
             pgsql8::slony_diff($options["slonydiffold"], $options["slonydiffnew"]);
             break;
         case dbsteward::MODE_UNKNOWN:
         default:
             throw new Exception("No operation specified!");
     }
 }
コード例 #30
0
 public static function column_type($db_doc, $schema, $table, $column, &$foreign)
 {
     // if it is a foreign keyed column, solve for the foreignKey type
     if (isset($column['foreignTable'])) {
         dbx::foreign_key($db_doc, $schema, $table, $column, $foreign);
         $column_type = $foreign['column']['type'];
         // for foreign keys, translate serial types to their integer base
         if (strcasecmp('serial', $column_type) == 0) {
             $column_type = 'int';
         } else {
             if (strcasecmp('bigserial', $column_type) == 0) {
                 $column_type = 'bigint';
             }
         }
     } else {
         if (!isset($column['type']) || strlen($column['type']) == 0) {
             throw new Exception("column missing type -- " . $schema['name'] . "." . $table['name'] . "." . $column['name']);
         }
         $column_type = $column['type'];
         if (dbx::get_type($schema, $column_type) != NULL) {
             // this is a user defined type or enum, enforce quoting if set
             $column_type = pgsql8::get_quoted_object_name($column_type);
         }
     }
     return $column_type;
 }