public static function build($output_prefix, $db_doc) { if (strlen($output_prefix) == 0) { throw new exception("pgsql8::build() sanity failure: output_prefix is blank"); } // build full db creation script $build_file = $output_prefix . '_build.sql'; dbsteward::info("Building complete file " . $build_file); $build_file_fp = fopen($build_file, 'w'); if ($build_file_fp === FALSE) { throw new exception("failed to open full file " . $build_file . ' for output'); } $build_file_ofs = new output_file_segmenter($build_file, 1, $build_file_fp, $build_file); if (count(dbsteward::$limit_to_tables) == 0) { $build_file_ofs->write("-- full database definition file generated " . date('r') . "\n"); } if (!dbsteward::$generate_slonik) { $build_file_ofs->write("BEGIN;\n\n"); } dbsteward::info("Calculating table foreign key dependency order.."); $table_dependency = xml_parser::table_dependency_order($db_doc); // database-specific implementation code refers to dbsteward::$new_database when looking up roles/values/conflicts etc dbsteward::$new_database = $db_doc; dbx::set_default_schema($db_doc, 'public'); // language defintions if (dbsteward::$create_languages) { foreach ($db_doc->language as $language) { $build_file_ofs->write(pgsql8_language::get_creation_sql($language)); } } // by default, postgresql will validate the contents of LANGUAGE SQL functions during creation // because we are creating all functions before tables, this doesn't work when LANGUAGE SQL functions // refer to tables yet to be created. // scan language="sql" functions for <functionDefiniton>s that contain FROM (<TABLE>) statements $set_check_function_bodies = TRUE; // on in default postgresql configs dbx::set_default_schema($db_doc, 'public'); foreach ($db_doc->schema as $schema) { foreach ($schema->function as $function) { if (pgsql8_function::has_definition($function)) { $definition = pgsql8_function::get_definition($function); if (strcasecmp($definition['language'], 'sql') == 0 && $definition['sqlFormat'] == 'pgsql8' && !is_null($referenced_table_name = static::function_definition_references_table($definition))) { $table_schema_name = sql_parser::get_schema_name($referenced_table_name, $db_doc); $node_schema = dbx::get_schema($db_doc, $table_schema_name); $node_table = dbx::get_table($node_schema, sql_parser::get_object_name($referenced_table_name)); if ($node_table) { // the referenced table is in the definition // turn off check_function_bodies $set_check_function_bodies = FALSE; $set_check_function_bodies_info = "Detected LANGUAGE SQL function " . $schema['name'] . '.' . $function['name'] . " referring to table " . $table_schema_name . '.' . $node_table['name'] . " in the database definition"; dbsteward::info($set_check_function_bodies_info); break 2; } } } } } if (!$set_check_function_bodies) { $build_file_ofs->write("\n"); $build_file_ofs->write("SET check_function_bodies = FALSE; -- DBSteward " . $set_check_function_bodies_info . "\n\n"); } if (dbsteward::$only_schema_sql || !dbsteward::$only_data_sql) { dbsteward::info("Defining structure"); pgsql8::build_schema($db_doc, $build_file_ofs, $table_dependency); } if (!dbsteward::$only_schema_sql || dbsteward::$only_data_sql) { dbsteward::info("Defining data inserts"); pgsql8::build_data($db_doc, $build_file_ofs, $table_dependency); } dbsteward::$new_database = NULL; if (!dbsteward::$generate_slonik) { $build_file_ofs->write("COMMIT;\n\n"); } if (dbsteward::$generate_slonik) { $replica_sets = static::get_slony_replica_sets($db_doc); foreach ($replica_sets as $replica_set) { // output preamble file standalone for tool chains that use the preamble to do additional slonik commands pgsql8::build_slonik_preamble($db_doc, $replica_set, $output_prefix . "_slony_replica_set_" . $replica_set['id'] . "_preamble.slonik"); // output paths specificity standalone for tool chains that use the store path slonik statements separately pgsql8::build_slonik_paths($db_doc, $replica_set, $output_prefix . "_slony_replica_set_" . $replica_set['id'] . "_paths.slonik"); // output create set file standalone for tool chains that use the create_set slonik separately $create_set_filename = $output_prefix . '_slony_replica_set_' . $replica_set['id'] . '_create_set.slonik'; pgsql8::build_slonik_create_set($db_doc, $replica_set, $create_set_filename); pgsql8::build_slonik_preamble($db_doc, $replica_set, $output_prefix . "_slony_replica_set_" . $replica_set['id'] . "_create_nodes.slonik"); pgsql8::build_slonik_store_nodes($db_doc, $replica_set, $output_prefix . "_slony_replica_set_" . $replica_set['id'] . "_create_nodes.slonik"); pgsql8::build_slonik_paths($db_doc, $replica_set, $output_prefix . "_slony_replica_set_" . $replica_set['id'] . "_create_nodes.slonik"); // build full subscribe steps that creates sets and subscribes nodes $subscribe_filename = $output_prefix . "_slony_replica_set_" . $replica_set['id'] . "_subscribe.slonik"; pgsql8::build_slonik_preamble($db_doc, $replica_set, $subscribe_filename); // create_set does one time slony configuration comparison. // so append the content of _create_set into _subscribe built earlier file_put_contents($subscribe_filename, file_get_contents($create_set_filename), FILE_APPEND); foreach ($replica_set->slonyReplicaSetNode as $replica_set_node) { pgsql8::build_slonik_subscribe_set_node($db_doc, $replica_set, $output_prefix . "_slony_replica_set_" . $replica_set['id'] . "_subscribe.slonik", $replica_set_node); } static::slony_ids_required_during_build($replica_set, $db_doc); } $count = 0; foreach (array_keys(self::$sequence_slony_ids) as $slony_set_id) { $count += count(self::$sequence_slony_ids[$slony_set_id]); } dbsteward::notice("[slony] ID summary: " . count(self::$table_slony_ids) . " tables " . $count . " sequences"); dbsteward::notice("[slony] table ID segments: " . static::slony_id_segment_summary(self::$table_slony_ids)); // keep this from bombing on there being no ids in $sequence_slony_ids // if there were none returned (i.e. either there weren't any defined // or they were all set to IGNORE_REQUIRED which hopefully doesn't happen // because why would you do that for all of them) if (!empty(self::$sequence_slony_ids)) { foreach (array_keys(self::$sequence_slony_ids) as $slony_set_id) { $console_line = "[slony] sequence ID segments"; if ($slony_set_id != 'NoSlonySet') { $console_line .= " for slonySetId {$slony_set_id}"; } $console_line .= ": "; dbsteward::notice($console_line . static::slony_id_segment_summary(self::$sequence_slony_ids[$slony_set_id])); } } } return $db_doc; }