Browse files

Initial 0.10.0 branch

  • Loading branch information...
0 parents commit 38bd1c46f73f19186488baab138ca2df795c67cd @beaud76 committed Jun 7, 2011
Showing with 3,221 additions and 0 deletions.
  1. +261 −0 CHANGES
  2. +17 −0 LICENSE
  3. +50 −0 README
  4. +274 −0 php/emajParallelRollback.php
  5. +2,619 −0 sql/emaj.sql
@@ -0,0 +1,261 @@
+E-Maj - Release notes
+Bug fixes:
+ - emaj_snap_group(): avoid setting explicit locks on tables because it is
+ not necessary to get a coherent image of all tables of the group.
+ - the emaj_log_stat_group() function has been refactored. A new internal
+ _log_stat_table() function has been created.
+ - the group_creation_datetime column of the emaj_group table is now
+ initialized with the transaction timestamp instead of the clock timestamp.
+ - main functions set a lock on the emaj_group row representing the working
+ group to prevent simultaneous execution of these functions.
+ - in emaj_start_group() and emaj_set_mark_group() functions, a mark name may
+ contain '%' wild characters. They are automatically replaced by a sequence
+ of digits from the current time.
+ - while locking tables of a group, if a deadlock occurs, the locking
+ operation is cancelled and retried up to 5 times before the transaction
+ aborts.
+Bug fixes:
+ - in emaj_start_group() and emaj_set_mark_group() functions, avoid empty or
+ NULL mark names. If the supplied mark name is NULL or empty, a name is
+ automaticaly generated as "MARK_" followed by digits from the current time.
+ - a new emaj_estimate_rollback_duration() function computes an approximate
+ value for the duration of a rollback operation. It uses statistics
+ recorded in the new emaj_rlbk_stat table, as well as 4 new parameters.
+ - the emaj_set_mark_group function now returns the number of processed
+ tables and sequences as other main emaj functions.
+ - add a check in emaj_log_stat_group and emaj_detailed_log_stat_group
+ functions if the supplied first mark is greater than the last_mark.
+ - in emaj_detailed_log_stat_group function, change the INS/UPD/DEL values
+ returned for emaj_verb column into more explicit terms (INSERT/UPDATE/
+ - emaj_detailed_log_stat_group, emaj_delete_mark and emaj_rename_mark
+ functions now accept EMAJ_LAST_MARK keyword as existing mark names.
+ - add a check at mark creation times to forbide EMAJ_LAST_MARK name.
+ - split column hist_type from emaj_hist table into 2 columns: hist_function
+ and hist_event
+ - during rollback operations, move the rollback of application sequences at
+ the very end of the operation, as these rollback (ALTER SEQUENCE) are not
+ transaction safe.
+ - log sequences are now reset at emaj_reset_group or emaj_start_group time.
+ This should avoid potential long term issue if the log sequence reaches
+ the upper limit of serial id.
+ - starting from postgres version 8.4, a trigger is created on all tables
+ belonging to a group in order to forbid TRUNCATE SQL verb during E-Maj
+ logging time. These triggers are named <schema>_<table>_emaj_trunc_trg.
+ They all call a new emaj._forbid_truncate_fnct() function. The log trigger
+ names change also, becoming <schema>_<table>_emaj_log_trg.
+Bug Fixes:
+ - in rollback_and_stop_group function, an error was abnormaly returned when
+ not all tables of the group needed to be effectively rollbacked.
+ - 2 error messages in emaj_start_group() didn't include the right function
+ name.
+ - during rollback operations, do not rollback the sequences associated to
+ the log tables any more. Before, if a problem occurred during a rollback
+ operation, the sequences of already rollbacked tables were left in an
+ inconsistent state.
+ - fix grant issues for emaj_adm role.
+ - enlarge the usage of the emaj_delete_mark_group function. It is now
+ possible to delete the first mark of a group. As a result, all rows from
+ log tables that become useless are deleted. This permits to reclaim disk
+ space in tspemaj tablespace if needed. At least one mark must remain
+ active. But a mark cannot be deleted if the group is not in LOGGING state.
+ - a call to emaj_stop_group function for a group that is already in IDLE
+ state now only produces a warning instead of an error (exception).
+ - minor coding improvement in emajParallelRollback.php module (better checks
+ of supplied group and mark names).
+ - add a column in emaj_group to record the creation date and time of groups.
+ - decrease the level of locks set at emaj_set_mark_group time from EXCLUSIVE
+ to ROW EXCLUSIVE so that locks generated by vacuum don't conflict with
+ emaj activity.
+ - add an explicit ACCESS EXCLUSIVE lock at emaj_stop_group time to decrease
+ the risk of deadlock.
+ - rename all internal functions by removing the 'emaj' prefix. So all emaj_
+ functions are now the only functions callable by users.
+ - add identifier of the updating transactions (txid) in log tables and the
+ txid of the emaj_set_mark_group command in the emaj_mark table. This is
+ for information purpose until now.
+ - add a emaj_force_drop_group function to drop groups that cannot be dropped
+ with the standart emaj_drop_group function, because of any unconsistency
+ of these group. Create an internal _drop_group function to factorize the
+ common parts of both emaj_drop_group and emaj_force_drop_group functions.
+ - add 2 roles without logging capacity:
+ - emaj_viewer can look at the log and emaj tables' content (application
+ support role can be granted this role),
+ - emaj_adm can execute all (but emaj_snap_group) functions without being
+ superuser (an "emaj administrator" can be granted this role).
+ - add a emaj_rename_mark_group function to rename an existing mark.
+ - an uninstall.sql script is provided to ... uninstall E-Maj components from
+ a database.
+ - a minor change to execute E-Maj with PostgreSQL 9.0.
+ - in emaj_create_group function, improve the check that tables have no
+ triggers that could be a problem at rollback time.
+ - the name of deleted marks due to a rollback operation is recorded in the
+ history table.
+ - marks that are deleted either by an emaj_rollback_group function call or
+ by an emaj_delete_mark_group function call are now physicaly deleted.
+ - the primary key of emaj_mark table becomes (group-name, mark-name) instead
+ of the mark-timestamp.
+ - E-Maj can be used with postgres 9.0.
+ - rename emaj_log_stat_group into emaj_detailed_log_stat_group. The
+ associated emaj_log_stat_type type is renamed into
+ emaj_detailed_log_stat_type.
+ - The emaj_rlbk_stat_group is renamed into emaj_log_stat_group. An
+ additional end_mark parameter allows to ask for statistics on a period of
+ time between two marks.The associated emaj_rlbk_stat_type type is renamed
+ into emaj_log_stat_type.
+Bug fixes:
+ - in rollback, solve problem with a loss of mark for other groups than the
+ rollbacked one.
+ - in emaj_reset_group, the sequences related to log tables were not deleted
+ when application table name contained uppercase characters
+ - add a emaj_snap_group function for test purpose that snaps all tables
+ and sequences of a group on individual files located into a given
+ directory.
+ - add a warning at create_group time if tables have (non emaj) triggers.
+ - decrease the level of locks set at emaj_create_group or
+ emaj_set_mark_group time from ACCESS EXCLUSIVE (the default lock mode)
+ to EXCLUSIVE so that ACCESS SHARE locks generated by read accesses don't
+ conflict with emaj activity.
+ - minor coding improvement.
+ - this version is also tested with postgresql 9.0 beta 2.
+Bug fixes:
+ - in log_only mode, solve the problem encountered when creating log for
+ a table without primary key.
+ - fix the error occuring when a emaj_reset_group was not executed prior an
+ emaj_drop_group. Take the opportunity to use cascading deletes provided by
+ foreign keys referencing emaj_group table.
+ - fix the emaj_create_group function to get correct numbers of tables and
+ sequences in emaj_group table.
+ - fix rollback aborts on UPDATEs when several clients accessed the
+ database in parallel resulting in both log rows for each UPDATE (one for
+ old values and the other for new values) not strictly in sequence.
+ - when rollbacking a table, finaly also rollback the state of the sequence
+ associated to the log id so that the statistics produced by the
+ function emaj_rlbk_stat_group are correct after a rollback operation.
+ - fix error when rollbacking tables having foreign keys with case sensitive
+ name.
+ - add a feature to perform parallel rollbacks, in order to speed up the
+ rollback operations on multi-processor servers. A PHP command is created
+ for this purpose: emajParallelRollback.php.
+ - the emaj_reset_group function is not necessary anymore before starting
+ a group; the log purge is automaticaly done at emaj_start_group function;
+ But the emaj_reset_function remains so user can purge log tables sooner.
+ - issue a warning at emaj_create_group, emaj_start_group and
+ emaj_rollback_group if either a table of the group has a foreign key that
+ reference a table outside the group or a table of the group is referenced
+ by a table outside the group.
+ - before a rollback operation, drop the foreign keys belonging to or
+ referencing any group's table and recreate them after
+ - add a serial id to the emaj_hist table to avoid potential duplicate key
+ conditions if 2 events happen in the same micro-second.
+ - the table previsously named emaj_group becomes emaj_group_def, column
+ names being slightly changed. This impact ts E-maj usage.
+ - a new table emaj_relation, records working data about the relation
+ belonging to all created groups. It provides a stability of the group
+ composition during its entire life (between emaj_create_group and
+ emaj_drop_group function calls).
+ - a new internal table emaj_group maintain the state of managed groups.
+ - a new table emaj_param stores E-maj parameters. A first emaj_version
+ parameter records the current emaj version.
+ - the emaj_delete_group function has been renamed into emaj_drop_group.
+ This impacts E-maj usage.
+ - add a parameter named 'log_only' that allow to configure E-maj in a mode
+ that disables rollback operations. This permits users to test E-maj
+ logging with tables for which a primary key is not yet created.
+ - add an automatic deletion of oldest rows in the emaj_hist table. To
+ achieve this, a parameter, named 'history_retention' is created in the
+ emaj_param table, with a default value of 1 month. This value can be
+ changed by the user. This history purge is done at every emaj_start_group
+ time.
+ - enhance the checks of emaj environment, by checking the internal
+ consistency at group level.
+ - provide to users a function that checks that no residual functions or log
+ tables remain in the emaj environment.
+ - in all rollback functions (in parallel or not) it is possible for user to
+ use the keyword 'EMAJ_LAST_MARK' as mark name. This pseudo name is
+ equivalent to the last active mark that exists for the group. It can also
+ be used in emaj_rlbk_stat_group function
+Bug fixes:
+ - change emaj_delete_group, emaj_start_group and emaj_reset_group functions
+ to add a check that the group to process is not in logging state
+ - add an emaj_rollback_and_stop_group function to rollback a table_group and
+ stop it at the same time.
+ This allow to not delete the rollbacked rows from log tables and then
+ speed up the rollback function when there is no need to keep any previous
+ mark active.
+ - when an emaj_stop_group function is performed, the marks in emaj.marks
+ table are not physicaly deleted but their state just becomes "deleted".
+ The associated data in emaj_sequence table (that record the serial value
+ of each log table) are also not deleted.
+ This allow to find marks timestamps if log tables are used for application
+ debugging purpose.
+ The emaj_reset_group function physicaly deletes the marks for the group at
+ the same time it truncates the related log tables.
+ Note that deleted marks can be referenced in emaj_log_stat_group function
+ calls.
+ - change column names from emaj_hist table to get a better consistency
+ between table name and columns name prefix
+Bug fixes:
+ - in rollback operations, don't delete the mark used to rollback to, and its
+ associated data for sequences, because it can be useful for a future use
+ if the application continues after the rollback operation.
+Bug fixes:
+ - the UPDATE statements generated for the rollback functions did not handle
+ properly the columns list of the SET clause.
+ - supply the right test-emaj.sql file !
+Bug fixes:
+ - when a table has several indexes, the UPDATE or DELETE statements
+ generated by the emaj_rollback_group function was often erroneous.
+ - replace the current_timestamp default value for emaj_changed column of log
+ tables by clock_timestamp() so that every log row has its own creation
+ timestamp.
+First released version
@@ -0,0 +1,17 @@
+This file is part of E-Maj, contrib for PostgreSQL.
+E-Maj is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+E-Maj is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -0,0 +1,50 @@
+-- E-Maj : logs and rollbacks table updates : V 0.10.0
+1- License
+This software is distributed under the GNU General Public License.
+2- Objectives
+The main goal of E-Maj is to be able to logicaly restore a set of tables to a predefined stable state, without been obliged to restore a whole database or cluster.
+It brings a good solution to:
+ - set inter-batch savepoints on group of tables,
+ - easily "restore" this group of tables at a stable state, without being obliged to stop the cluster,
+ - handle several savepoints during batch windows, each of them been usable at any time as "restore point",
+It brings a good alternative to the management of several disk images.
+Used in development or test environments, it may also bring a good help in testing application, providing an easy way to rollback all updates generated by programs execution and replay these processings as many times as needed.
+3- Supplied files
+- README this readme file
+- CHANGES release notes
+- Emaj.0.9.0.en.pdf general E-Maj presentation
+- Emaj.0.9.0.User's.Guide.pdf E-Maj user's guide
+- emaj.sql installation script
+- uninstall.sql uninstallation script
+- emajParallelRollback.php external client for parallel rollback
+4- How to install and use E-Maj
+All the information needed to install and use E-Maj is provided in the user's guide that is included in the supplied tar file.
+Remark: The user's guide presents an emaj plugin for phpPgAdmin. In its current implementation, this plugin is very invasive
+inside phpPgAdmin code. For this reason, this plugin is currently not yet available on pgfoundry. But if you wish to get a copy,
+simply ask me.
+5- Support
+For additional support or bug report, please contact Philippe BEAUDOIN (phb07 <at> apra <dot> asso <dot> fr).
274 php/emajParallelRollback.php
@@ -0,0 +1,274 @@
+// emajParallelRollback.php
+// This php module belongs to the E-Maj PostgreSQL contrib.
+// This software is distributed under the GNU General Public License.
+// It performs a rollback operation for an E-Maj group, processing tables in parallel.
+// Users must supply the name of the E-Maj group and the number of parallel connections to use.
+// The tables to process are affected to sub_groups. Each sub_group use its own connection.
+ $EmajVersion='0.10.0';
+ $progName='emajParallelRollback';
+// Just asking for help
+ if ($argc==1 or $argv[1]=='--help' or $argv[1]=='?') {
+ print_help();
+ exit(0);
+ }
+// Just asking for version
+ if ($argv[1]=='--version') {
+ print_version();
+ exit(0);
+ }
+ echo " E-Maj (version ".$EmajVersion.") - launching parallel rollbacks for a group\n";
+ echo "------------------------------------------------------------------\n";
+// Collect and prepare parameters
+// long options (with -- ) are not used for portability reasons
+// Initialize parameters with their default values
+ $dbname=''; // -d PostgreSQL database name
+ $host=''; // -h PostgreSQL server host name
+ $port=''; // -p PostgreSQL server ip port
+ $username=''; // -U user name for the connection to PostgreSQL database
+ $password=''; // -W user password
+ $group=''; // -g E-maj group name (mandatory)
+ $mark=''; // -m E-maj mark name to rollback to (mandatory)
+ $nbSubgroup=1; // -s number of E-maj sub_groups to use for rollback (default=1)
+ $verbose=false; // -v flag for verbose mode
+// Get supplied parameters
+ $shortOptions="d:h:p:U:W:g:m:s:v";
+ $options = getopt($shortOptions);
+// ... and process them
+ $conn_string = '';
+ foreach (array_keys($options) as $opt) switch ($opt) {
+ case 'd':
+ $dbname=$options['d'];
+ $conn_string=$conn_string.'dbname='.$dbname.' ';
+ break;
+ case 'h':
+ $host=$options['h'];
+ $conn_string=$conn_string.'host='.$host.' ';
+ break;
+ case 'p':
+ $port=$options['p'];
+ $conn_string=$conn_string.'port='.$port.' ';
+ break;
+ case 'U':
+ $username=$options['U'];
+ $conn_string=$conn_string.'user='.$username.' ';
+ break;
+ case 'W':
+ $password=$options['W'];
+ $conn_string=$conn_string.'password='.$username.' ';
+ break;
+ case 'g':
+ $group=$options['g'];
+ break;
+ case 'm':
+ $mark=$options['m'];
+ break;
+ case 's':
+ if (! is_numeric($options['s']) )
+ die("Number of sub-groups (".$options['s'].") is not numeric !\n");
+ $nbSubgroup=$options['s'];
+ if ($nbSubgroup < 1)
+ die("Number of sub-groups (".$options['s'].") must be > 0 !\n");
+ if ($nbSubgroup > 100)
+ die("Number of sub-groups (".$options['s'].") must be <= 100 !\n");
+ break;
+ case 'v':
+ $verbose=true;
+ break;
+ }
+// check the group name has been supplied
+ if ($group==''){
+ die("a group name must be supplied with -g parameter !\n");
+ }
+// check the mark has been supplied
+ if ($mark==''){
+ die("a mark must be supplied with -m parameter !\n");
+ }
+// Open all required connections
+// There is 1 connection per corridor, the first being used also for global dialog with pg
+// They all use the same connection parameters.
+// Connection parameters are optional. If not supplied, the environment variables and PostgreSQL default values are used
+ for ($i=1;$i<=$nbSubgroup;$i++){
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." Connection #$i...\n";
+ $dbconn[$i] = pg_connect($conn_string,PGSQL_CONNECT_FORCE_NEW)
+ or die("Connection #$i failed".pg_last_error()."\n");
+ }
+ echo "$nbSubgroup opened connections\n";
+// Check the existence of the supplied group and its state
+// select mark_state from emaj.emaj_mark where mark_group = xxx and mark_name = yyy => doit être ACTIVE
+ $query="SELECT group_state FROM emaj.emaj_group WHERE group_name = '".pg_escape_string($group)."'";
+ $result = pg_query($dbconn[1],$query)
+ or die('Check group name failed '.pg_last_error()."\n");
+ if (pg_num_rows($result)==0) die('The supplied group $group doesn\'t exist');
+ $groupState=pg_fetch_result($result,0,0);
+ if ($groupState<>'LOGGING') die('The supplied group $group is not in LOGGING state');
+ pg_free_result($result);
+// Check the existence of the supplied mark and verify its state
+ $query="SELECT mark_state FROM emaj.emaj_mark WHERE mark_group = '".pg_escape_string($group)."' AND mark_name = '".pg_escape_string($mark)."'";
+ $result = pg_query($dbconn[1],$query)
+ or die('Check mark name failed '.pg_last_error()."\n");
+ if (pg_num_rows($result)==0) die('The supplied mark $mark doesn\'t exist');
+ $markState=pg_fetch_result($result,0,0);
+ if ($markState<>'ACTIVE') die('The supplied mark $mark is not in ACTIVE state');
+ pg_free_result($result);
+// Call for _rlbk_group_step1 on first connection
+// This prepares the parallel rollback by creating well balanced sub_groups
+ $query="SELECT emaj._rlbk_group_step1 ('".pg_escape_string($group)."','".pg_escape_string($mark)."',$nbSubgroup)";
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." _rlbk_group_step1 for group $group and mark $mark...\n";
+ $result = pg_query($dbconn[1],$query)
+ or die('Call for _rlbk_group_step1 function failed '.pg_last_error()."\n");
+ $totalNbTbl=pg_fetch_result($result,0,0);
+ pg_free_result($result);
+ echo "Number of tables needing rollback for group '$group' = $totalNbTbl\n";
+ echo "Rollback to mark '$mark' in progress...\n";
+// For each sub_group, start transactions
+ for ($i=1;$i<=$nbSubgroup;$i++){
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." Start Transaction #$i...\n";
+ $result = pg_query($dbconn[$i],"BEGIN TRANSACTION")
+ or die('Begin transaction #'.$i.' failed: '.pg_last_error()."\n");
+ }
+ pg_free_result($result);
+// For each subgroup, synchronous call for _rlbk_group_step2 to lock all tables
+ for ($i=1;$i<=$nbSubgroup;$i++){
+ $query="SELECT emaj._rlbk_group_step2 ('".pg_escape_string($group)."',$i)";
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." _rlbk_group_step2 for #$i -> lock tables...\n";
+ $result = pg_query($dbconn[$i],$query)
+ or die('Call for _rlbk_group_step2 function for #'.$i.' failed: '.pg_last_error()."\n");
+ }
+ pg_free_result($result);
+// Once all tables are locked, synchronous call for _rlbk_group_step3 to drop all foreign keys involved
+// in the sub-group before rollback
+ for ($i=1;$i<=$nbSubgroup;$i++){
+ $query="SELECT emaj._rlbk_group_step3 ('".pg_escape_string($group)."',$i)";
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." _rlbk_group_step3 for #$i -> drop foreign keys...\n";
+ $result = pg_query($dbconn[$i],$query)
+ or die('Call for j_rlbk_group_step3 function for #'.$i.' failed '.pg_last_error()."\n");
+ }
+ pg_free_result($result);
+// For each subgroup, asynchronous call for _rlbk_group_step4 to rollback tables
+ for ($i=1;$i<=$nbSubgroup;$i++){
+ $query="SELECT emaj._rlbk_group_step4 ('".pg_escape_string($group)."','".pg_escape_string($mark)."',$i, true)";
+ if (pg_connection_busy($dbconn[$i]))
+ die("Connection #$i is busy. Unable to call for _rlbk_group_step4\n");
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." _rlbk_group_step4 for #$i -> rollback tables...\n";
+ pg_send_query($dbconn[$i],$query)
+ or die('Call for _rlbk_group_step4 function for #'.$i.' failed: '.pg_last_error()."\n");
+ }
+// For each subgroup, get the result of the previous call for _rlbk_group_step4
+ $cumNbTbl=0;
+ for ($i=1;$i<=$nbSubgroup;$i++){
+ $result = pg_get_result($dbconn[$i]);
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." get result of _rlbk_group_step4 call for #$i...\n";
+ $nbTbl=pg_fetch_result($result,0,0);
+ if ($verbose) echo " => Number of rollbacked tables for the subgroup = $nbTbl\n";
+ $cumNbTbl=$cumNbTbl+$nbTbl;
+ }
+ pg_free_result($result);
+// Check the right number of tables and sequences have been processed
+ if ($cumNbTbl!=$totalNbTbl){
+ die("Internal error: sum of processed tables/sequences by sub-group ($cumNbTbl) is not equal the number of tables/sequences of the group ($totalNbTbl) !\n");
+ }
+// Once all tables are restored, synchronous call for _rlbk_group_step5 to recreate all foreign keys
+ for ($i=1;$i<=$nbSubgroup;$i++){
+ $query="SELECT emaj._rlbk_group_step5 ('".pg_escape_string($group)."',$i)";
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." _rlbk_group_step5 for #$i -> recreate foreign keys...\n";
+ $result = pg_query($dbconn[$i],$query)
+ or die('Call for _rlbk_group_step5 function for #'.$i.' failed '.pg_last_error()."\n");
+ }
+ pg_free_result($result);
+// Call for emaj_rlbk_group_step6 on first connection to complete the rollback operation
+ $query="SELECT emaj._rlbk_group_step6 ('".pg_escape_string($group)."','".pg_escape_string($mark)."',$totalNbTbl,true)";
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." _rlbk_group_step6 -> complete rollback operation...\n";
+ $result = pg_query($dbconn[1],$query)
+ or die('Call for _rlbk_group_step6 function failed '.pg_last_error()."\n");
+ $nbSeq=pg_fetch_result($result,0,0);
+ pg_free_result($result);
+ if ($verbose) echo " => Number of rollbacked sequences for group '$group' = $nbSeq\n";
+// Commit with 2PC to be sure that all subgroups can either commit or rollback in a single transaction
+// Phase 1 : Prepare transaction
+ for ($i=1;$i<=$nbSubgroup;$i++){
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." Prepare Transaction #$i...\n";
+ $result = pg_query($dbconn[$i],"PREPARE TRANSACTION 'emajtx".$i."'")
+ or die('Prepare transaction #'.$i.' failed: '.pg_last_error()."\n");
+ }
+// Phase 2 : Commit
+ for ($i=1;$i<=$nbSubgroup;$i++){
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." Commit transaction #$i...\n";
+ $result = pg_query($dbconn[$i],"COMMIT PREPARED 'emajtx".$i."'")
+ or die('Commit prepared #'.$i.' failed: '.pg_last_error()."\n");
+ }
+// Close the connections
+ if ($verbose) echo date("d/m/Y - H:i:s.u")." Closing all connections...\n";
+ for ($i=1;$i<=$nbSubgroup;$i++){
+ pg_close($dbconn[$i]);
+ }
+// And issue the final message
+ echo "Rollback completed\n";
+function print_help(){
+ global $progName,$EmajVersion;
+ echo "$progName belongs to the E-Maj PostgreSQL contrib (version $EmajVersion).\n";
+ echo "It performs E-Maj rollback for a group and a previously set mark, processing tables in parallel.\n\n";
+ echo "Usage:\n";
+ echo " $progName -g <E-Maj group name> -m <E-Maj mark> -s <number of sub_groups> [OPTION]... \n";
+ echo "\nOptions:\n";
+ echo " -v verbose mode; writes more information about the processing\n";
+ echo " --help shows this help, then exit\n";
+ echo " --version outputs version information, then exit\n";
+ echo "\nConnection options:\n";
+ echo " -d, database to connect to\n";
+ echo " -h, database server host or socket directory\n";
+ echo " -p, database server port\n";
+ echo " -U, user name to connect as\n";
+ echo " -W, password associated to the user, if needed\n";
+function print_version(){
+ global $progName,$EmajVersion;
+ echo "This version of $progName belongs to E-Maj version $EmajVersion.\n";
+ echo "Type '$progName --help' to get usage information\n\n";
2,619 sql/emaj.sql
2,619 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.

0 comments on commit 38bd1c4

Please sign in to comment.