<commit_before>/*
 * ------------------------------------------------------------------------
 *
 * pgxc_clean utility
 *
 *	Recovers outstanding 2PC when after crashed nodes or entire cluster 
 *  is recovered.
 *
 *  Depending upon how nodes/XC cluster fail, there could be outstanding
 *  2PC transactions which are partly prepared and partly commited/borted.
 *  Such transactions must be commited/aborted to remove them from the
 *  snapshot.
 *
 *  This utility checks if there's such outstanding transactions and
 *  cleans them up.
 *
 * Command syntax
 *
 * pgxc_clean [option ... ] [database] [user]
 *
 * Options are:
 *
 *  -a, --all				cleanup all the database avilable
 *  -d, --dbname=DBNAME		database name to clean up.   Multiple -d option
 *                          can be specified.
 *  -h, --host=HOSTNAME		coordinator hostname to connect to.
 *  -N, --no-clean			only test.  no cleanup actually.
 *  -o, --output=FILENAME	output file name.
 *  -p, --port=PORT			coordinator port number.
 *  -q, --quiet				do not print messages except for error, default.
 *  -s, --status			prints out 2PC status.
 *  -U, --username=USERNAME	database user name
 *  -v, --verbose			same as -s, plus prints result of each cleanup.
 *  -V, --version			prints out the version,	
 *  -w, --no-password		never prompt for the password.
 *  -W, --password			prompt for the password,
 *  -?, --help				prints help message
 *
 * ------------------------------------------------------------------------
 */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <pwd.h>
#include <errno.h>
#include "libpq-fe.h"
#include "pg_config.h"
#include "getopt_long.h"
#include "pgxc_clean.h"
#include "txninfo.h"
#include "port.h"

/* Who I am */
const char *progname;
char *my_nodename;
int   my_nodeidx = -1;		/* Index in pgxc_clean_node_info */

/* Databases to clean */
bool clean_all_databases = false;		/* "--all" overrides specific database specification */

database_names *head_database_names = NULL;
database_names *last_database_names = NULL;

/* Coordinator to connect to */
char *coordinator_host = NULL;
int coordinator_port = -1;

typedef enum passwd_opt
{
	TRI_DEFAULT,
	TRI_YES,
	TRI_NO
} passwd_opt;

/* Miscellaneous */
char *output_filename = NULL;
char *username = NULL;
bool version_opt = false;
passwd_opt try_password_opt = TRI_DEFAULT;
bool status_opt = false;
bool no_clean_opt = false;
bool verbose_opt = false;
FILE *outf;
FILE *errf;

/* Global variables */
node_info	*pgxc_clean_node_info;
int			pgxc_clean_node_count;

database_info *head_database_info;
database_info *last_database_info;

static char *password = NULL;
static char password_prompt[256];

/* Funcs */
static void add_to_database_list(char *dbname);
static void parse_pgxc_clean_options(int argc, char *argv[]);
static void usage(void);
static char *GetUserName(void);
static void showVersion(void);
static PGconn *loginDatabase(char *host, int port, char *user, char *password,
							char *dbname, const char *progname, char *encoding, char *password_prompt);
static void getMyNodename(PGconn *conn);
static void recover2PCForDatabase(database_info *db_info);
static void recover2PC(PGconn *conn, txn_info *txn);
static void getDatabaseList(PGconn *conn);
static void getNodeList(PGconn *conn);
static void showVersion(void);
static void add_to_database_list(char *dbname);
static void parse_pgxc_clean_options(int argc, char *argv[]);
static void usage(void);
static void getPreparedTxnList(PGconn *conn);
static void getTxnInfoOnOtherNodesAll(PGconn *conn);
static void do_commit(PGconn *conn, txn_info *txn);
static void do_abort(PGconn *conn, txn_info *txn);
static void do_commit_abort(PGconn *conn, txn_info *txn, bool is_commit);
static bool setMaintenanceMode(PGconn *conn);

/*
 * Connection to the coordinator
 */
PGconn *coord_conn;

/*
 *
 * Main
 *
 */
int main(int argc, char *argv[])
{

	/* Should setup pglocale when it is supported by XC core */

	if (argc > 1)
	{
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
		{
			usage();
			exit(0);
		}
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
		{
			showVersion();
			exit(0);
		}
	}
	parse_pgxc_clean_options(argc, argv);

	/*
	 * Arrange my environment
	 */
	if (output_filename)
	{
		/* Prepare output filename */
		outf = fopen(output_filename, "w");
		if (outf == NULL)
		{
			fprintf(stderr, "%s: Cannot ope output file %s (%s)\n", progname, output_filename, strerror(errno));
			exit(1);
		}
		errf = outf;
	}
	else
	{
		outf = stdout;
		errf = stderr;
	}
	if (coordinator_host == NULL)
	{
		/* Default coordinator host */
		if ((coordinator_host = getenv("PGHOST")) == NULL)
			coordinator_host = "localhost";
	}
	if (coordinator_port == -1)
	{
		/* Default coordinator port */
		char *pgport;
		if ((pgport = getenv("PGPORT")) == NULL)
			coordinator_port = DEF_PGPORT;		/* pg_config.h */
		else
			coordinator_port = atoi(pgport);
	}
	if (username == NULL)
		strcpy(password_prompt, "Password: ");
	else
		sprintf(password_prompt, "Password for user %s: ", username);
	if (try_password_opt == TRI_YES)
		password = simple_prompt(password_prompt, 100, false);

	if (verbose_opt)
	{
		/* Print environments */
		fprintf(outf, "%s (%s): Cleanup outstanding 2PCs.\n", progname, PG_VERSION);
		/* Target databaess */<commit_msg>Fix pgxc_clean crash when no options are specified<commit_after>/*
 * ------------------------------------------------------------------------
 *
 * pgxc_clean utility
 *
 *	Recovers outstanding 2PC when after crashed nodes or entire cluster 
 *  is recovered.
 *
 *  Depending upon how nodes/XC cluster fail, there could be outstanding
 *  2PC transactions which are partly prepared and partly commited/borted.
 *  Such transactions must be commited/aborted to remove them from the
 *  snapshot.
 *
 *  This utility checks if there's such outstanding transactions and
 *  cleans them up.
 *
 * Command syntax
 *
 * pgxc_clean [option ... ] [database] [user]
 *
 * Options are:
 *
 *  -a, --all				cleanup all the database avilable
 *  -d, --dbname=DBNAME		database name to clean up.   Multiple -d option
 *                          can be specified.
 *  -h, --host=HOSTNAME		coordinator hostname to connect to.
 *  -N, --no-clean			only test.  no cleanup actually.
 *  -o, --output=FILENAME	output file name.
 *  -p, --port=PORT			coordinator port number.
 *  -q, --quiet				do not print messages except for error, default.
 *  -s, --status			prints out 2PC status.
 *  -U, --username=USERNAME	database user name
 *  -v, --verbose			same as -s, plus prints result of each cleanup.
 *  -V, --version			prints out the version,	
 *  -w, --no-password		never prompt for the password.
 *  -W, --password			prompt for the password,
 *  -?, --help				prints help message
 *
 * ------------------------------------------------------------------------
 */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <pwd.h>
#include <errno.h>
#include "libpq-fe.h"
#include "pg_config.h"
#include "getopt_long.h"
#include "pgxc_clean.h"
#include "txninfo.h"
#include "port.h"

/* Who I am */
const char *progname;
char *my_nodename;
int   my_nodeidx = -1;		/* Index in pgxc_clean_node_info */

/* Databases to clean */
bool clean_all_databases = false;		/* "--all" overrides specific database specification */

database_names *head_database_names = NULL;
database_names *last_database_names = NULL;

/* Coordinator to connect to */
char *coordinator_host = NULL;
int coordinator_port = -1;

typedef enum passwd_opt
{
	TRI_DEFAULT,
	TRI_YES,
	TRI_NO
} passwd_opt;

/* Miscellaneous */
char *output_filename = NULL;
char *username = NULL;
bool version_opt = false;
passwd_opt try_password_opt = TRI_DEFAULT;
bool status_opt = false;
bool no_clean_opt = false;
bool verbose_opt = false;
FILE *outf;
FILE *errf;

/* Global variables */
node_info	*pgxc_clean_node_info;
int			pgxc_clean_node_count;

database_info *head_database_info;
database_info *last_database_info;

static char *password = <PASSWORD>;
static char password_prompt[256];

/* Funcs */
static void add_to_database_list(char *dbname);
static void parse_pgxc_clean_options(int argc, char *argv[]);
static void usage(void);
static char *GetUserName(void);
static void showVersion(void);
static PGconn *loginDatabase(char *host, int port, char *user, char *password,
							char *dbname, const char *progname, char *encoding, char *password_prompt);
static void getMyNodename(PGconn *conn);
static void recover2PCForDatabase(database_info *db_info);
static void recover2PC(PGconn *conn, txn_info *txn);
static void getDatabaseList(PGconn *conn);
static void getNodeList(PGconn *conn);
static void showVersion(void);
static void add_to_database_list(char *dbname);
static void parse_pgxc_clean_options(int argc, char *argv[]);
static void usage(void);
static void getPreparedTxnList(PGconn *conn);
static void getTxnInfoOnOtherNodesAll(PGconn *conn);
static void do_commit(PGconn *conn, txn_info *txn);
static void do_abort(PGconn *conn, txn_info *txn);
static void do_commit_abort(PGconn *conn, txn_info *txn, bool is_commit);
static bool setMaintenanceMode(PGconn *conn);

/*
 * Connection to the coordinator
 */
PGconn *coord_conn;

/*
 *
 * Main
 *
 */
int main(int argc, char *argv[])
{

	/* Should setup pglocale when it is supported by XC core */

	if (argc > 1)
	{
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
		{
			usage();
			exit(0);
		}
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
		{
			showVersion();
			exit(0);
		}
	}
	parse_pgxc_clean_options(argc, argv);

	/*
	 * Check missing arguments
	 */
	if (clean_all_databases == false && head_database_names == NULL)
	{
		fprintf(stderr, "%s: you must specify -a or -d option.\n", progname);
		exit(1);
	}

	/*
	 * Arrange my environment
	 */
	if (output_filename)
	{
		/* Prepare output filename */
		outf = fopen(output_filename, "w");
		if (outf == NULL)
		{
			fprintf(stderr, "%s: Cannot ope output file %s (%s)\n", progname, output_filename, strerror(errno));
			exit(1);
		}
		errf = outf;
	}
	else
	{
		outf = stdout;
		errf = stderr;
	}
	if (coordinator_host == NULL)
	{
		/* Default coordinator host */
		if ((coordinator_host = getenv("PGHOST")) == NULL)
			coordinator_host = "localhost";
	}
	if (coordinator_port == -1)
	{
		/* Default coordinator port */
		char *pgport;

		if ((pgport = getenv("PGPORT")) == NULL)
			coordinator_port = DEF_PGPORT;		/* pg_config.h */
		else
			coordinator_port = atoi(pgport);
	}
	if (username == NULL)
		strcpy(password_prompt, "Password: ");
	else
		sprintf(password_prompt, "Password for user %s: ", username);
	if (try_password_opt == TRI_YES)
		password = simple_prompt(password_prompt, 100, false);

	if (verbose_opt)
	{
		/* Print environments */
		fprintf(outf, "%s (%s): Cleanup outstanding 2PCs.\n", progname, PG_VERSION);
		/* Target databaess */
{'fraction_non_alphanumeric': 0.1515706566535397, 'fraction_numerical': 0.005037091308727906, 'mean_word_length': 3.4192634560906514, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '349805', 'n_tokens_mistral': 3893, 'n_tokens_neox': 3680, 'n_words': 1080}