/* * Make a database connection with the given parameters. An * interactive password prompt is automatically issued if required. */ PGconn * connectDatabase(const char *dbname, const char *pghost, const char *pgport, const char *pguser, enum trivalue prompt_password, const char *progname) { PGconn *conn; char *password = NULL; bool new_pass; if (prompt_password == TRI_YES) password = simple_prompt("Password: "******"%s: could not connect to database %s\n"), progname, dbname); exit(1); } if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && password == NULL && prompt_password != TRI_NO) { PQfinish(conn); password = simple_prompt("Password: "******"%s: could not connect to database %s: %s"), progname, dbname, PQerrorMessage(conn)); exit(1); } return conn; }
bool yesno_prompt(const char *question) { char prompt[256]; /* * translator: This is a question followed by the translated options for * "yes" and "no". */ snprintf(prompt, sizeof(prompt), _("%s (%s/%s) "), _(question), _(PG_YESLETTER), _(PG_NOLETTER)); for (;;) { char *resp; resp = simple_prompt(prompt, 1, true); if (strcmp(resp, _(PG_YESLETTER)) == 0) { free(resp); return true; } else if (strcmp(resp, _(PG_NOLETTER)) == 0) { free(resp); return false; } free(resp); printf(_("Please answer \"%s\" or \"%s\".\n"), _(PG_YESLETTER), _(PG_NOLETTER)); } }
/* * Ask the user for a password; 'username' is the username the * password is for, if one has been explicitly specified. * Set malloc'd string to the global variable 'password'. */ static void prompt_for_password(const char *username) { if (password) { free(password); password = NULL; } if (username == NULL) password = simple_prompt("Password: "******"Password for user %s: ", username); password = simple_prompt(message, 100, false); } }
static char * prompt_for_password(void) #if PG_VERSION_NUM >= 100000 { char buf[100]; simple_prompt("Password: ", buf, sizeof(buf), false); return pg_strdup(buf); }
/* * Ask the user for a password; 'username' is the username the * password is for, if one has been explicitly specified. Returns a * malloc'd string. */ static char * prompt_for_password(const char *username) { char *result; if (username == NULL) result = simple_prompt("Password: "******"Password for user %s: "), username); result = simple_prompt(prompt_text, 100, false); free(prompt_text); } return result; }
/* establish connection with database. */ PGconn * sql_conn(struct options * my_opts) { PGconn *conn; char *password = NULL; bool new_pass; /* * Start the connection. Loop until we have a password if requested by * backend. */ do { new_pass = false; conn = PQsetdbLogin(my_opts->hostname, my_opts->port, NULL, /* options */ NULL, /* tty */ my_opts->dbname, my_opts->username, password); if (!conn) { fprintf(stderr, "%s: could not connect to database %s\n", "oid2name", my_opts->dbname); exit(1); } if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && password == NULL) { PQfinish(conn); password = simple_prompt("Password: "******"%s: could not connect to database %s: %s", "oid2name", my_opts->dbname, PQerrorMessage(conn)); PQfinish(conn); exit(1); } /* return the conn if good */ return conn; }
static PGconn * loginDatabase(char *host, int port, char *user, char *password, char *dbname, const char *progname, char *encoding, char *password_prompt) { bool new_pass = false; PGconn *coord_conn; char port_s[32]; #define PARAMS_ARRAY_SIZE 8 const char *keywords[PARAMS_ARRAY_SIZE]; const char *values[PARAMS_ARRAY_SIZE]; sprintf(port_s, "%d", port); keywords[0] = "host"; values[0] = host; keywords[1] = "port"; values[1] = port_s; keywords[2] = "user"; values[2] = user; keywords[3] = "password"; keywords[4] = "dbname"; values[4] = dbname; keywords[5] = "fallback_application_name"; values[5] = progname; keywords[6] = "client_encoding"; values[6] = encoding; keywords[7] = NULL; values[7] = NULL; /* Loop until we have a password if requested by backend */ do { values[3] = password; new_pass = false; coord_conn = PQconnectdbParams(keywords, values, true); if (PQstatus(coord_conn) == CONNECTION_BAD && PQconnectionNeedsPassword(coord_conn) && password == NULL && try_password_opt != TRI_NO) { PQfinish(coord_conn); password = simple_prompt(password_prompt, 100, false); new_pass = true; } } while (new_pass); return(coord_conn); }
/* * Open a database connection */ static PGconn * DBConnect(const char *host, const char *port, char *database, const char *user) { char *password = NULL; char *password_prompt = NULL; bool need_pass; PGconn *conn = NULL; /* loop until we have a password if requested by backend */ do { need_pass = false; conn = PQsetdbLogin(host, port, NULL, NULL, database, user, password); if (PQstatus(conn) == CONNECTION_BAD && strcmp(PQerrorMessage(conn), PQnoPasswordSupplied) == 0 && !feof(stdin)) { PQfinish(conn); need_pass = true; free(password); password = NULL; printf("\nPassword: "******"Connection to database failed: %s", PQerrorMessage(conn)); exit_gracefuly(1); } if (password) free(password); return conn; }
/* * Open a database connection */ bool DBConnect(const char *host, const char *port, char *database, const char *user) { pghost = strdup(host); pgport = strdup(port); pguser = strdup(user); pgpass = NULL; retry_login: conn = PQsetdbLogin(pghost, pgport, NULL, NULL, database, pguser, pgpass); if (PQstatus(conn) == CONNECTION_BAD) { /* wait a password if required to login, then retry. */ if (strcmp(PQerrorMessage(conn), PQnoPasswordSupplied) == 0 && !feof(stdin)) { PQfinish(conn); conn = NULL; pgpass = simple_prompt("Password: "******"Connection to database failed: %s", PQerrorMessage(conn)); PQfinish(conn); conn = NULL; return false; } return true; }
int main(int argc, char *argv[]) { static struct option long_options[] = { {"host", required_argument, NULL, 'h'}, {"port", required_argument, NULL, 'p'}, {"username", required_argument, NULL, 'U'}, {"no-password", no_argument, NULL, 'w'}, {"password", no_argument, NULL, 'W'}, {"echo", no_argument, NULL, 'e'}, {"interactive", no_argument, NULL, 'i'}, {NULL, 0, NULL, 0} }; const char *progname; int optindex; int c; char *dropuser = NULL; char *host = NULL; char *port = NULL; char *username = NULL; enum trivalue prompt_password = TRI_DEFAULT; bool echo = false; bool interactive = false; PQExpBufferData sql; PGconn *conn; PGresult *result; progname = get_progname(argv[0]); set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts")); handle_help_version_opts(argc, argv, "dropuser", help); while ((c = getopt_long(argc, argv, "h:p:U:wWei", long_options, &optindex)) != -1) { switch (c) { case 'h': host = optarg; break; case 'p': port = optarg; break; case 'U': username = optarg; break; case 'w': prompt_password = TRI_NO; break; case 'W': prompt_password = TRI_YES; break; case 'e': echo = true; break; case 'i': interactive = true; break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } switch (argc - optind) { case 0: break; case 1: dropuser = argv[optind]; break; default: fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind + 1]); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } if (dropuser == NULL) dropuser = simple_prompt("Enter name of role to drop: ", 128, true); if (interactive) { printf(_("Role \"%s\" will be permanently removed.\n"), dropuser); if (!yesno_prompt("Are you sure?")) exit(0); } initPQExpBuffer(&sql); appendPQExpBuffer(&sql, "DROP ROLE %s;\n", fmtId(dropuser)); conn = connectDatabase("postgres", host, port, username, prompt_password, progname); if (echo) printf("%s", sql.data); result = PQexec(conn, sql.data); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, _("%s: removal of role \"%s\" failed: %s"), progname, dropuser, PQerrorMessage(conn)); PQfinish(conn); exit(1); } PQclear(result); PQfinish(conn); exit(0); }
/* * GetMasterConnection: This function makes a database connection with the given parameters. * The connection handle is returned. * An interactive password prompt is automatically issued if required. * This is a copy of the one in pg_dump. */ PGconn * GetMasterConnection(const char *progName, const char *dbname, const char *pghost, const char *pgport, const char *username, int reqPwd, int ignoreVersion, bool bDispatch) { char *pszPassword = NULL; bool need_pass = false; PGconn *pConn = NULL; SegmentDatabase masterDB; if (reqPwd) { pszPassword = simple_prompt("Password: "******"ERROR", progName, "out of memory when allocating password"); return NULL; } } masterDB.dbid = 0; masterDB.role = 0; masterDB.port = pgport ? atoi(pgport) : 5432; masterDB.pszHost = (char *) pghost; masterDB.pszDBName = (char *) dbname; masterDB.pszDBUser = (char *) username; masterDB.pszDBPswd = pszPassword; /* * Start the connection. Loop until we have a password if requested by * backend. */ do { need_pass = false; pConn = MakeDBConnection(&masterDB, bDispatch); if (pConn == NULL) { mpp_err_msg_cache("ERROR", progName, "failed to connect to database"); return (NULL); } if (PQstatus(pConn) == CONNECTION_BAD && strcmp(PQerrorMessage(pConn), "fe_sendauth: no password supplied\n") == 0 && !feof(stdin)) { PQfinish(pConn); need_pass = true; free(pszPassword); pszPassword = NULL; pszPassword = simple_prompt("Password: "******"ERROR", progName, "connection to database \"%s\" failed : %s", PQdb(pConn), PQerrorMessage(pConn)); PQfinish(pConn); return (NULL); } return pConn; }
int main(int argc, char **argv) { PQExpBuffer valueBuf = NULL; PQExpBuffer escapeBuf = createPQExpBuffer(); RestoreOptions *opts; int c; int exit_code = 0; Archive *AH; char *inputFileSpec = NULL; extern int optind; extern char *optarg; static int use_setsessauth = 0; static int disable_triggers = 0; SegmentDatabase SegDB; StatusOp *pOp; struct sigaction act; pid_t newpid; /* int i; */ PQExpBuffer pszCmdLine; int status; int rc; char *pszErrorMsg; ArchiveHandle *pAH; int postDataSchemaOnly = 0; #ifdef USE_DDBOOST char *ddp_file_name = NULL; char *dd_boost_dir = NULL; #endif struct option cmdopts[] = { {"clean", 0, NULL, 'c'}, {"create", 0, NULL, 'C'}, {"data-only", 0, NULL, 'a'}, {"dbname", 1, NULL, 'd'}, {"exit-on-error", 0, NULL, 'e'}, {"file", 1, NULL, 'f'}, {"format", 1, NULL, 'F'}, {"function", 1, NULL, 'P'}, {"host", 1, NULL, 'h'}, {"ignore-version", 0, NULL, 'i'}, {"index", 1, NULL, 'I'}, {"list", 0, NULL, 'l'}, {"no-privileges", 0, NULL, 'x'}, {"no-acl", 0, NULL, 'x'}, {"no-owner", 0, NULL, 'O'}, {"no-reconnect", 0, NULL, 'R'}, {"port", 1, NULL, 'p'}, {"password", 0, NULL, 'W'}, {"schema-only", 0, NULL, 's'}, {"superuser", 1, NULL, 'S'}, {"table", 1, NULL, 't'}, {"trigger", 1, NULL, 'T'}, {"use-list", 1, NULL, 'L'}, {"username", 1, NULL, 'U'}, {"verbose", 0, NULL, 'v'}, /* * the following options don't have an equivalent short option letter, * but are available as '-X long-name' */ {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, {"disable-triggers", no_argument, &disable_triggers, 1}, /* * the following are cdb specific, and don't have an equivalent short * option */ {"gp-d", required_argument, NULL, 1}, {"gp-e", no_argument, NULL, 2}, {"gp-k", required_argument, NULL, 3}, {"gp-c", required_argument, NULL, 4}, {"target-dbid", required_argument, NULL, 5}, {"target-host", required_argument, NULL, 6}, {"target-port", required_argument, NULL, 7}, {"post-data-schema-only", no_argument, &postDataSchemaOnly, 1}, {"dd_boost_file", required_argument, NULL, 8}, {"dd_boost_enabled", no_argument, NULL, 9}, {"dd_boost_dir", required_argument, NULL, 10}, {"dd_boost_buf_size", required_argument, NULL, 11}, {"gp-f", required_argument, NULL, 12}, {"prefix", required_argument, NULL, 13}, {"status", required_argument, NULL, 14}, {"netbackup-service-host", required_argument, NULL, 15}, {"netbackup-block-size", required_argument, NULL, 16}, {"change-schema-file", required_argument, NULL, 17}, {"schema-level-file", required_argument, NULL, 18}, {"ddboost-storage-unit",required_argument, NULL, 19}, {NULL, 0, NULL, 0} }; set_pglocale_pgservice(argv[0], "pg_dump"); opts = NewRestoreOptions(); /* set format default */ opts->formatName = "p"; progname = get_progname(argv[0]); if (argc > 1) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { usage(progname); exit(0); } if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) { puts("pg_restore (Greenplum Database) " PG_VERSION); exit(0); } } while ((c = getopt_long(argc, argv, "acCd:ef:F:h:iI:lL:Op:P:RsS:t:T:uU:vwWxX:", cmdopts, NULL)) != -1) { switch (c) { case 'a': /* Dump data only */ opts->dataOnly = 1; break; case 'c': /* clean (i.e., drop) schema prior to create */ opts->dropSchema = 1; break; case 'C': opts->createDB = 1; break; case 'd': opts->dbname = strdup(optarg); break; case 'e': opts->exit_on_error = true; break; case 'f': /* output file name */ opts->filename = strdup(optarg); break; case 'F': if (strlen(optarg) != 0) opts->formatName = strdup(optarg); break; case 'h': if (strlen(optarg) != 0) opts->pghost = strdup(optarg); break; case 'i': /* obsolete option */ break; case 'l': /* Dump the TOC summary */ opts->tocSummary = 1; break; case 'L': /* input TOC summary file name */ opts->tocFile = strdup(optarg); break; case 'O': opts->noOwner = 1; break; case 'p': if (strlen(optarg) != 0) opts->pgport = strdup(optarg); break; case 'R': /* no-op, still accepted for backwards compatibility */ break; case 'P': /* Function */ opts->selTypes = 1; opts->selFunction = 1; opts->functionNames = strdup(optarg); break; case 'I': /* Index */ opts->selTypes = 1; opts->selIndex = 1; opts->indexNames = strdup(optarg); break; case 'T': /* Trigger */ opts->selTypes = 1; opts->selTrigger = 1; opts->triggerNames = strdup(optarg); break; case 's': /* dump schema only */ opts->schemaOnly = 1; break; case 'S': /* Superuser username */ if (strlen(optarg) != 0) opts->superuser = strdup(optarg); break; case 't': /* Dump data for this table only */ opts->selTypes = 1; opts->selTable = 1; opts->tableNames = strdup(optarg); break; case 'u': opts->promptPassword = TRI_YES; opts->username = simple_prompt("User name: ", 100, true); break; case 'U': opts->username = optarg; break; case 'v': /* verbose */ opts->verbose = 1; break; case 'w': opts->promptPassword = TRI_NO; break; case 'W': opts->promptPassword = TRI_YES; break; case 'x': /* skip ACL dump */ opts->aclsSkip = 1; break; case 'X': /* -X is a deprecated alternative to long options */ if (strcmp(optarg, "use-set-session-authorization") == 0) use_setsessauth = 1; else if (strcmp(optarg, "disable-triggers") == 0) disable_triggers = 1; else { fprintf(stderr, _("%s: invalid -X option -- %s\n"), progname, optarg); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } break; case 0: /* This covers the long options equivalent to -X xxx. */ break; case 1: /* --gp-d MPP Output Directory */ g_pszMPPOutputDirectory = strdup(optarg); break; case 2: /* --gp-e On Error Stop for psql */ g_bOnErrorStop = opts->exit_on_error = true; break; case 3: /* --gp-k MPP Dump Info Format is * Key_s-dbid_s-role_t-dbid */ g_gpdumpInfo = strdup(optarg); if (!ParseCDBDumpInfo(progname, g_gpdumpInfo, &g_gpdumpKey, &g_role, &g_sourceDBID, &g_MPPPassThroughCredentials)) { exit(1); } break; case 4: /* gp-c */ g_compPg = strdup(optarg); break; case 5: /* target-dbid */ g_targetDBID = atoi(strdup(optarg)); break; case 6: /* target-host */ g_targetHost = strdup(optarg); break; case 7: /* target-port */ g_targetPort = strdup(optarg); break; #ifdef USE_DDBOOST case 9: dd_boost_enabled = 1; break; case 10: dd_boost_dir = strdup(optarg); break; case 11: dd_boost_buf_size = strdup(optarg); break; #endif case 12: table_filter_file = strdup(optarg); break; case 13: dump_prefix = strdup(optarg); break; /* Hack to pass in the status_file name to cdbbackup.c (gp_restore_launch) */ case 14: break; case 15: netbackup_service_host = strdup(optarg); break; case 16: netbackup_block_size = strdup(optarg); break; case 17: change_schema_file = strdup(optarg); break; case 18: schema_level_file = strdup(optarg); break; #ifdef USE_DDBOOST case 19: ddboost_storage_unit = strdup(optarg); break; #endif default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } /* Should get at most one of -d and -f, else user is confused */ if (opts->dbname) { if (opts->filename) { fprintf(stderr, _("%s: cannot specify both -d and -f output\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } opts->useDB = 1; } opts->disable_triggers = disable_triggers; opts->use_setsessauth = use_setsessauth; if (opts->formatName) { switch (opts->formatName[0]) { case 'c': case 'C': opts->format = archCustom; break; case 'f': case 'F': opts->format = archFiles; break; case 't': case 'T': opts->format = archTar; break; case 'p': case 'P': bUsePSQL = true; break; default: mpp_err_msg(logInfo, progname, "unrecognized archive format '%s'; please specify 't' or 'c'\n", opts->formatName); exit(1); } } if (g_gpdumpInfo == NULL) { mpp_err_msg(logInfo, progname, "missing required parameter gp-k (backup key)\n"); exit(1); } #ifdef USE_DDBOOST if (dd_boost_enabled) { /* remote is always false when restoring from primary DDR */ int err = DD_ERR_NONE; err = ddp_init("gp_dump"); if (err != DD_ERR_NONE) { mpp_err_msg("ERROR", "ddboost", "ddboost init failed. Err = %d\n", err); exit(1); } if (initDDSystem(&ddp_inst, &ddp_conn, &dd_client_info, &ddboost_storage_unit, false, &DEFAULT_BACKUP_DIRECTORY, false)) { mpp_err_msg(logInfo, progname, "Initializing DD system failed\n"); exit(1); } mpp_err_msg(logInfo, progname, "ddboost is initialized\n"); ddp_file_name = formDDBoostFileName(g_gpdumpKey, postDataSchemaOnly, dd_boost_dir); if (ddp_file_name == NULL) { mpp_err_msg(logInfo, progname, "Error in opening ddboost file\n"); exit(1); } } #endif SegDB.dbid = g_sourceDBID; SegDB.role = g_role; SegDB.port = opts->pgport ? atoi(opts->pgport) : 5432; SegDB.pszHost = opts->pghost ? strdup(opts->pghost) : NULL; SegDB.pszDBName = opts->dbname ? strdup(opts->dbname) : NULL; SegDB.pszDBUser = opts->username ? strdup(opts->username) : NULL; SegDB.pszDBPswd = NULL; if (g_MPPPassThroughCredentials != NULL && *g_MPPPassThroughCredentials != '\0') { unsigned int nBytes; char *pszDBPswd = Base64ToData(g_MPPPassThroughCredentials, &nBytes); if (pszDBPswd == NULL) { mpp_err_msg(logError, progname, "Invalid Greenplum DB Credentials: %s\n", g_MPPPassThroughCredentials); exit(1); } if (nBytes > 0) { SegDB.pszDBPswd = malloc(nBytes + 1); if (SegDB.pszDBPswd == NULL) { mpp_err_msg(logInfo, progname, "Cannot allocate memory for Greenplum Database Credentials\n"); exit(1); } memcpy(SegDB.pszDBPswd, pszDBPswd, nBytes); SegDB.pszDBPswd[nBytes] = '\0'; } } if (g_role == ROLE_MASTER) g_conn = MakeDBConnection(&SegDB, true); else g_conn = MakeDBConnection(&SegDB, false); if (PQstatus(g_conn) == CONNECTION_BAD) { exit_horribly(NULL, NULL, "connection to database \"%s\" failed: %s", PQdb(g_conn), PQerrorMessage(g_conn)); } if (g_gpdumpKey != NULL) { /* * Open the database again, for writing status info */ g_conn_status = MakeDBConnection(&SegDB, false); if (PQstatus(g_conn_status) == CONNECTION_BAD) { exit_horribly(NULL, NULL, "Connection on host %s failed: %s", StringNotNull(SegDB.pszHost, "localhost"), PQerrorMessage(g_conn_status)); } g_main_tid = pthread_self(); g_pStatusOpList = CreateStatusOpList(); if (g_pStatusOpList == NULL) { exit_horribly(NULL, NULL, "cannot allocate memory for gp_backup_status operation\n"); } /* * Create thread for monitoring for cancel requests. If we're running * using PSQL, the monitor is not allowed to start until the worker * process is forked. This is done to prevent the forked process from * being blocked by locks held by library routines (__tz_convert, for * example). */ if (bUsePSQL) { pthread_mutex_lock(&g_threadSyncPoint); } pthread_create(&g_monitor_tid, NULL, monitorThreadProc, NULL); /* Install Ctrl-C interrupt handler, now that we have a connection */ if (!bUsePSQL) { act.sa_handler = myHandler; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_flags |= SA_RESTART; if (sigaction(SIGINT, &act, NULL) < 0) { mpp_err_msg(logInfo, progname, "Error trying to set SIGINT interrupt handler\n"); } act.sa_handler = myHandler; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_flags |= SA_RESTART; if (sigaction(SIGTERM, &act, NULL) < 0) { mpp_err_msg(logInfo, progname, "Error trying to set SIGTERM interrupt handler\n"); } } pOp = CreateStatusOp(TASK_START, TASK_RC_SUCCESS, SUFFIX_START, TASK_MSG_SUCCESS); if (pOp == NULL) { exit_horribly(NULL, NULL, "cannot allocate memory for gp_backup_status operation\n"); } AddToStatusOpList(g_pStatusOpList, pOp); } /* end cdb additions */ if (bUsePSQL) { /* Install Ctrl-C interrupt handler, now that we have a connection */ act.sa_handler = psqlHandler; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_flags |= SA_RESTART; if (sigaction(SIGINT, &act, NULL) < 0) { mpp_err_msg(logInfo, progname, "Error trying to set SIGINT interrupt handler\n"); } act.sa_handler = psqlHandler; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_flags |= SA_RESTART; if (sigaction(SIGTERM, &act, NULL) < 0) { mpp_err_msg(logInfo, progname, "Error trying to set SIGTERM interrupt handler\n"); } /* Establish a SIGCHLD handler to catch termination the psql process */ act.sa_handler = myChildHandler; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_flags |= SA_RESTART; if (sigaction(SIGCHLD, &act, NULL) < 0) { mpp_err_msg(logInfo, progname, "Error trying to set SIGCHLD interrupt handler\n"); exit(1); } mpp_err_msg(logInfo, progname, "Before fork of gp_restore_agent\n"); newpid = fork(); if (newpid < 0) { mpp_err_msg(logError, progname, "Failed to fork\n"); } else if (newpid == 0) { /* TODO: use findAcceptableBackupFilePathName(...) to look for the file name * if user invoked gp_restore_agent directly without supplying a file name. * If the agent is invoked from gp_restore_launch, then we are ok. */ if (optind < argc) { char *rawInputFile = argv[optind]; valueBuf = createPQExpBuffer(); inputFileSpec = shellEscape(rawInputFile, valueBuf, false, false); } if (inputFileSpec == NULL || inputFileSpec[0] == '\0') { mpp_err_msg(logError, progname, "dump file path is empty"); exit(1); } if (postDataSchemaOnly) { if (strstr(inputFileSpec,"_post_data") == NULL) { fprintf(stderr,"Adding _post_data to the end of the file name?\n"); char * newFS = malloc(strlen(inputFileSpec) + strlen("_post_data") + 1); strcpy(newFS, inputFileSpec); strcat(newFS, "_post_data"); inputFileSpec = newFS; } } pszCmdLine = createPQExpBuffer(); #ifdef USE_DDBOOST if (dd_boost_enabled) { formDDBoostPsqlCommandLine(pszCmdLine, argv[0], (postDataSchemaOnly == 1 ? true : false), g_role, g_compPg, ddp_file_name, dd_boost_buf_size, table_filter_file, change_schema_file, schema_level_file, ddboost_storage_unit); } else { #endif formPsqlCommandLine(pszCmdLine, argv[0], (postDataSchemaOnly == 1), g_role, inputFileSpec, g_compPg, table_filter_file, netbackup_service_host, netbackup_block_size, change_schema_file, schema_level_file); #ifdef USE_DDBOOST } #endif appendPQExpBuffer(pszCmdLine, " -h %s -p %s -U %s -d ", g_targetHost, g_targetPort, SegDB.pszDBUser); shellEscape(SegDB.pszDBName, pszCmdLine, true /* quote */, false /* reset */); appendPQExpBuffer(pszCmdLine, " -a "); if (g_bOnErrorStop) appendPQExpBuffer(pszCmdLine, " -v ON_ERROR_STOP="); if (g_role == ROLE_SEGDB) putenv("PGOPTIONS=-c gp_session_role=UTILITY"); if (g_role == ROLE_MASTER) putenv("PGOPTIONS=-c gp_session_role=DISPATCH"); mpp_err_msg(logInfo, progname, "Command Line: %s\n", pszCmdLine->data); /* * Make this new process the process group leader of the children * being launched. This allows a signal to be sent to all * processes in the group simultaneously. */ setpgid(newpid, newpid); execl("/bin/sh", "sh", "-c", pszCmdLine->data, NULL); mpp_err_msg(logInfo, progname, "Error in gp_restore_agent - execl of %s with Command Line %s failed", "/bin/sh", pszCmdLine->data); _exit(127); } else { /* * Make the new child process the process group leader of the * children being launched. This allows a signal to be sent to * all processes in the group simultaneously. * * This is a redundant call to avoid a race condition suggested by * Stevens. */ setpgid(newpid, newpid); /* Allow the monitor thread to begin execution. */ pthread_mutex_unlock(&g_threadSyncPoint); /* Parent . Lets sleep and wake up until we see it's done */ while (!bPSQLDone) { sleep(5); } /* * If this process has been sent a SIGINT or SIGTERM, we need to * send a SIGINT to the psql process GROUP. */ if (bKillPsql) { mpp_err_msg(logInfo, progname, "Terminating psql due to signal.\n"); kill(-newpid, SIGINT); } waitpid(newpid, &status, 0); if (WIFEXITED(status)) { rc = WEXITSTATUS(status); if (rc == 0) { mpp_err_msg(logInfo, progname, "psql finished with rc %d.\n", rc); /* Normal completion falls to end of routine. */ } else { if (rc >= 128) { /* * If the exit code has the 128-bit set, the exit code * represents a shell exited by signal where the * signal number is exitCode - 128. */ rc -= 128; pszErrorMsg = MakeString("psql finished abnormally with signal number %d.\n", rc); } else { pszErrorMsg = MakeString("psql finished abnormally with return code %d.\n", rc); } makeSureMonitorThreadEnds(TASK_RC_FAILURE, pszErrorMsg); free(pszErrorMsg); exit_code = 2; } } else if (WIFSIGNALED(status)) { pszErrorMsg = MakeString("psql finished abnormally with signal number %d.\n", WTERMSIG(status)); mpp_err_msg(logError, progname, pszErrorMsg); makeSureMonitorThreadEnds(TASK_RC_FAILURE, pszErrorMsg); free(pszErrorMsg); exit_code = 2; } else { pszErrorMsg = MakeString("psql crashed or finished badly; status=%#x.\n", status); mpp_err_msg(logError, progname, pszErrorMsg); makeSureMonitorThreadEnds(TASK_RC_FAILURE, pszErrorMsg); free(pszErrorMsg); exit_code = 2; } } } else { AH = OpenArchive(inputFileSpec, opts->format); /* Let the archiver know how noisy to be */ AH->verbose = opts->verbose; /* * Whether to keep submitting sql commands as "pg_restore ... | psql ... " */ AH->exit_on_error = opts->exit_on_error; if (opts->tocFile) SortTocFromFile(AH, opts); if (opts->tocSummary) PrintTOCSummary(AH, opts); else { pAH = (ArchiveHandle *) AH; if (opts->useDB) { /* check for version mismatch */ if (pAH->version < K_VERS_1_3) die_horribly(NULL, NULL, "direct database connections are not supported in pre-1.3 archives\n"); pAH->connection = g_conn; /* XXX Should get this from the archive */ AH->minRemoteVersion = 070100; AH->maxRemoteVersion = 999999; _check_database_version(pAH); } RestoreArchive(AH, opts); /* * The following is necessary when the -C option is used. A new * connection is gotten to the database within RestoreArchive */ if (pAH->connection != g_conn) g_conn = pAH->connection; } /* done, print a summary of ignored errors */ if (AH->n_errors) fprintf(stderr, _("WARNING: errors ignored on restore: %d\n"), AH->n_errors); /* AH may be freed in CloseArchive? */ exit_code = AH->n_errors ? 1 : 0; CloseArchive(AH); } #ifdef USE_DDBOOST if(dd_boost_enabled) cleanupDDSystem(); free(ddboost_storage_unit); #endif makeSureMonitorThreadEnds(TASK_RC_SUCCESS, TASK_MSG_SUCCESS); DestroyStatusOpList(g_pStatusOpList); if (change_schema_file) free(change_schema_file); if (schema_level_file) free(schema_level_file); if (SegDB.pszHost) free(SegDB.pszHost); if (SegDB.pszDBName) free(SegDB.pszDBName); if (SegDB.pszDBUser) free(SegDB.pszDBUser); if (SegDB.pszDBPswd) free(SegDB.pszDBPswd); if (valueBuf) destroyPQExpBuffer(valueBuf); if (escapeBuf) destroyPQExpBuffer(escapeBuf); PQfinish(g_conn); if (exit_code == 0) mpp_err_msg(logInfo, progname, "Finished successfully\n"); else mpp_err_msg(logError, progname, "Finished with errors\n"); return exit_code; }
/* * Make a database connection with the given parameters. An * interactive password prompt is automatically issued if required. */ PGconn * connectDatabase(const char *dbname, const char *pghost, const char *pgport, const char *pguser, enum trivalue prompt_password, const char *progname) { PGconn *conn; char *password = NULL; bool new_pass; if (prompt_password == TRI_YES) password = simple_prompt("Password: "******"%s: out of memory\n"), progname); exit(1); } keywords[0] = "host"; values[0] = pghost; keywords[1] = "port"; values[1] = pgport; keywords[2] = "user"; values[2] = pguser; keywords[3] = "password"; values[3] = password; keywords[4] = "dbname"; values[4] = dbname; keywords[5] = "fallback_application_name"; values[5] = progname; keywords[6] = NULL; values[6] = NULL; new_pass = false; conn = PQconnectdbParams(keywords, values, true); free(keywords); free(values); if (!conn) { fprintf(stderr, _("%s: could not connect to database %s\n"), progname, dbname); exit(1); } if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && password == NULL && prompt_password != TRI_NO) { PQfinish(conn); password = simple_prompt("Password: "******"%s: could not connect to database %s: %s"), progname, dbname, PQerrorMessage(conn)); exit(1); } return conn; }
/* * Make a database connection with the given parameters. An * interactive password prompt is automatically issued if required. * * If fail_on_error is false, we return NULL without printing any message * on failure, but preserve any prompted password for the next try. */ static PGconn * connectDatabase(const char *dbname, const char *pghost, const char *pgport, const char *pguser, enum trivalue prompt_password, bool fail_on_error) { PGconn *conn; bool new_pass; const char *remoteversion_str; int my_version; static char *password = NULL; if (prompt_password == TRI_YES && !password) password = simple_prompt("Password: "******"%s: out of memory\n"), progname); exit(1); } keywords[0] = "host"; values[0] = pghost; keywords[1] = "port"; values[1] = pgport; keywords[2] = "user"; values[2] = pguser; keywords[3] = "password"; values[3] = password; keywords[4] = "dbname"; values[4] = dbname; keywords[5] = "fallback_application_name"; values[5] = progname; keywords[6] = "options"; values[6] = "-c gp_session_role=utility"; keywords[7] = NULL; values[7] = NULL; new_pass = false; conn = PQconnectdbParams(keywords, values, true); free(keywords); free(values); if (!conn) { fprintf(stderr, _("%s: could not connect to database \"%s\"\n"), progname, dbname); exit(1); } if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && password == NULL && prompt_password != TRI_NO) { PQfinish(conn); password = simple_prompt("Password: "******"%s: could not connect to database \"%s\": %s\n"), progname, dbname, PQerrorMessage(conn)); exit(1); } else { PQfinish(conn); return NULL; } } remoteversion_str = PQparameterStatus(conn, "server_version"); if (!remoteversion_str) { fprintf(stderr, _("%s: could not get server version\n"), progname); exit(1); } server_version = parse_version(remoteversion_str); if (server_version < 0) { fprintf(stderr, _("%s: could not parse server version \"%s\"\n"), progname, remoteversion_str); exit(1); } my_version = parse_version(PG_VERSION); if (my_version < 0) { fprintf(stderr, _("%s: could not parse version \"%s\"\n"), progname, PG_VERSION); exit(1); } if (my_version != server_version && (server_version < 80200 /* we can handle back to 8.2 */ || server_version > my_version)) { fprintf(stderr, _("server version: %s; %s version: %s\n"), remoteversion_str, progname, PG_VERSION); if (ignoreVersion) fprintf(stderr, _("proceeding despite version mismatch\n")); else { fprintf(stderr, _("aborting because of version mismatch (Use the -i option to proceed anyway.)\n")); exit(1); } } /* * On 7.3 and later, make sure we are not fooled by non-system schemas in * the search path. */ executeCommand(conn, "SET search_path = pg_catalog"); return 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: "******"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 */ fprintf(outf, "Target databases:"); if (clean_all_databases) fprintf(outf, "(ALL)\n"); else { database_names *cur_name; for(cur_name = head_database_names; cur_name; cur_name = cur_name->next) fprintf(outf, " %s", cur_name->database_name); fprintf(outf, "\n"); } /* Username to use */ fprintf(outf, "Username: %s\n", username ? username : "******"); /* Status opt */ fprintf(outf, "Status opt: %s\n", status_opt ? "on" : "off"); /* No-dlean opt */ fprintf(outf, "no-clean: %s\n", no_clean_opt ? "on" : "off"); } /* Connect to XC server */ if (verbose_opt) { fprintf(outf, "%s: connecting to database \"%s\", host: \"%s\", port: %d\n", progname, clean_all_databases ? "postgres" : head_database_names->database_name, coordinator_host, coordinator_port); } coord_conn = loginDatabase(coordinator_host, coordinator_port, username, password, clean_all_databases ? "postgres" : head_database_names->database_name, progname, "auto", password_prompt); if (verbose_opt) { fprintf(outf, "%s: connected successfully\n", progname); } /* * Get my nodename (connected Coordinator) */ getMyNodename(coord_conn); if (verbose_opt) { fprintf(outf, "%s: Connected to the node \"%s\"\n", progname, my_nodename); } /* * Get available databases * * pgxc_clean assumes that all the database are available from the connecting Coordinator. * Some (expert) DBA can create a database local to subset of the node by EXECUTE DIRECT. * In this case, DBA may have to clean outstanding 2PC transactions manually or clean * 2PC transactions by connecting pgxc_clean to different Coordinators. * * If such node-subset database is found to be used widely, pgxc_clean may need * an extension to deal with this case. */ getDatabaseList(coord_conn); if (verbose_opt) { database_info *cur_database; fprintf(outf, "%s: Databases visible from the node \"%s\": ", progname, my_nodename); if (head_database_info) { for (cur_database = head_database_info; cur_database; cur_database = cur_database->next) { fprintf(outf, " \"%s\"", cur_database->database_name); } fputc('\n', outf); } } /* * Get list of Coordinators * * As in the case of database, we clean transactions in visible nodes from the * connecting Coordinator. DBA can also setup different node configuration * at different Coordinators. In this case, DBA should be careful to choose * appropriate Coordinator to clean up transactions. */ getNodeList(coord_conn); if (verbose_opt) { int ii; fprintf(outf, "%s: Node list visible from the node \"%s\"\n", progname, my_nodename); for (ii = 0; ii < pgxc_clean_node_count; ii++) { fprintf(outf, "Name: %s, host: %s, port: %d, type: %s\n", pgxc_clean_node_info[ii].node_name, pgxc_clean_node_info[ii].host, pgxc_clean_node_info[ii].port, pgxc_clean_node_info[ii].type == NODE_TYPE_COORD ? "coordinator" : "datanode"); } } /* * Get list of prepared statement */ getPreparedTxnList(coord_conn); /* * Check if there're any 2PC candidate to recover */ if (!check2PCExists()) { fprintf(errf, "%s: There's no prepared 2PC in this cluster. Exiting.\n", progname); exit(0); } /* * Check status of each prepared transaction. To do this, look into * nodes where the transaction is not recorded as "prepared". * Possible status are unknown (prepare has not been issued), committed or * aborted. */ getTxnInfoOnOtherNodesAll(coord_conn); if (verbose_opt) { /* Print all the prepared transaction list */ database_info *cur_db; fprintf(outf, "%s: 2PC transaction list.\n", progname); for (cur_db = head_database_info; cur_db; cur_db = cur_db->next) { txn_info *txn; fprintf(outf, "Database: \"%s\":\n", cur_db->database_name); for (txn = cur_db->head_txn_info; txn; txn = txn->next) { int ii; fprintf(outf, " gxid: %d, xid: \"%s\", owner: %s\n", txn->gxid, txn->xid, txn->owner); for (ii = 0; ii < pgxc_clean_node_count; ii++) { fprintf(outf, " node: %s, status: %s\n", pgxc_clean_node_info[ii].node_name, str_txn_stat(txn->txn_stat[ii])); } } } } /* * Then disconnect from the database. * I need to login to specified databases which 2PC is issued for. Again, we assume * that all the prepare is issued against the same database in each node, which * current Coordinator does and there seems to be no way to violate this assumption. */ if (verbose_opt) { fprintf(outf, "%s: disconnecting\n", progname); } PQfinish(coord_conn); /* * If --no-clean option is specified, we exit here. */ if (no_clean_opt) { fprintf(outf, "--no-clean opt is specified. Exiting.\n"); exit(0); } /* * Recover 2PC for specified databases */ if (clean_all_databases) { database_info *cur_database_info; for(cur_database_info = head_database_info; cur_database_info; cur_database_info = cur_database_info->next) { recover2PCForDatabase(cur_database_info); } } else { database_info *cur_database_info; database_names *cur_database_name; for(cur_database_name = head_database_names; cur_database_name; cur_database_name = cur_database_name->next) { cur_database_info = find_database_info(cur_database_name->database_name); if (cur_database_info) { recover2PCForDatabase(cur_database_info); } } } exit(0); }
/* * * main * */ int main(int argc, char *argv[]) { struct adhoc_opts options; int successResult; char *password = NULL; char *password_prompt = NULL; bool new_pass; set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql")); if (argc > 1) { if ((strcmp(argv[1], "-?") == 0) || (argc == 2 && (strcmp(argv[1], "--help") == 0))) { usage(NOPAGER); exit(EXIT_SUCCESS); } if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) { showVersion(); exit(EXIT_SUCCESS); } } #ifdef WIN32 setvbuf(stderr, NULL, _IONBF, 0); #endif pset.progname = get_progname(argv[0]); pset.db = NULL; setDecimalLocale(); pset.encoding = PQenv2encoding(); pset.queryFout = stdout; pset.queryFoutPipe = false; pset.copyStream = NULL; pset.cur_cmd_source = stdin; pset.cur_cmd_interactive = false; /* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */ pset.popt.topt.format = PRINT_ALIGNED; pset.popt.topt.border = 1; pset.popt.topt.pager = 1; pset.popt.topt.pager_min_lines = 0; pset.popt.topt.start_table = true; pset.popt.topt.stop_table = true; pset.popt.topt.default_footer = true; pset.popt.topt.unicode_border_linestyle = UNICODE_LINESTYLE_SINGLE; pset.popt.topt.unicode_column_linestyle = UNICODE_LINESTYLE_SINGLE; pset.popt.topt.unicode_header_linestyle = UNICODE_LINESTYLE_SINGLE; refresh_utf8format(&(pset.popt.topt)); /* We must get COLUMNS here before readline() sets it */ pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0; pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout))); pset.getPassword = TRI_DEFAULT; EstablishVariableSpace(); SetVariable(pset.vars, "VERSION", PG_VERSION_STR); /* Default values for variables */ SetVariableBool(pset.vars, "AUTOCOMMIT"); SetVariable(pset.vars, "VERBOSITY", "default"); SetVariable(pset.vars, "SHOW_CONTEXT", "errors"); SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1); SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2); SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3); parse_psql_options(argc, argv, &options); /* * If no action was specified and we're in non-interactive mode, treat it * as if the user had specified "-f -". This lets single-transaction mode * work in this case. */ if (options.action == ACT_NOTHING && pset.notty) { options.action = ACT_FILE; options.action_string = NULL; } /* Bail out if -1 was specified but will be ignored. */ if (options.single_txn && options.action != ACT_FILE && options.action == ACT_NOTHING) { fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname); exit(EXIT_FAILURE); } if (!pset.popt.topt.fieldSep.separator && !pset.popt.topt.fieldSep.separator_zero) { pset.popt.topt.fieldSep.separator = pg_strdup(DEFAULT_FIELD_SEP); pset.popt.topt.fieldSep.separator_zero = false; } if (!pset.popt.topt.recordSep.separator && !pset.popt.topt.recordSep.separator_zero) { pset.popt.topt.recordSep.separator = pg_strdup(DEFAULT_RECORD_SEP); pset.popt.topt.recordSep.separator_zero = false; } if (options.username == NULL) password_prompt = pg_strdup(_("Password: "******"Password for user %s: "), options.username); if (pset.getPassword == TRI_YES) password = simple_prompt(password_prompt, 100, false); /* loop until we have a password if requested by backend */ do { #define PARAMS_ARRAY_SIZE 8 const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); keywords[0] = "host"; values[0] = options.host; keywords[1] = "port"; values[1] = options.port; keywords[2] = "user"; values[2] = options.username; keywords[3] = "password"; values[3] = password; keywords[4] = "dbname"; values[4] = (options.action == ACT_LIST_DB && options.dbname == NULL) ? "postgres" : options.dbname; keywords[5] = "fallback_application_name"; values[5] = pset.progname; keywords[6] = "client_encoding"; values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto"; keywords[7] = NULL; values[7] = NULL; new_pass = false; pset.db = PQconnectdbParams(keywords, values, true); free(keywords); free(values); if (PQstatus(pset.db) == CONNECTION_BAD && PQconnectionNeedsPassword(pset.db) && password == NULL && pset.getPassword != TRI_NO) { PQfinish(pset.db); password = simple_prompt(password_prompt, 100, false); new_pass = true; } } while (new_pass); free(password); free(password_prompt); if (PQstatus(pset.db) == CONNECTION_BAD) { fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db)); PQfinish(pset.db); exit(EXIT_BADCONN); } setup_cancel_handler(); PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL); SyncVariables(); if (options.action == ACT_LIST_DB) { int success; if (!options.no_psqlrc) process_psqlrc(argv[0]); success = listAllDbs(NULL, false); PQfinish(pset.db); exit(success ? EXIT_SUCCESS : EXIT_FAILURE); } if (options.logfilename) { pset.logfile = fopen(options.logfilename, "a"); if (!pset.logfile) fprintf(stderr, _("%s: could not open log file \"%s\": %s\n"), pset.progname, options.logfilename, strerror(errno)); } /* * Now find something to do */ /* * process file given by -f */ if (options.action == ACT_FILE) { if (!options.no_psqlrc) process_psqlrc(argv[0]); successResult = process_file(options.action_string, options.single_txn, false); } /* * process slash command if one was given to -c */ else if (options.action == ACT_SINGLE_SLASH) { PsqlScanState scan_state; if (pset.echo == PSQL_ECHO_ALL) puts(options.action_string); scan_state = psql_scan_create(); psql_scan_setup(scan_state, options.action_string, strlen(options.action_string)); successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR ? EXIT_SUCCESS : EXIT_FAILURE; psql_scan_destroy(scan_state); } /* * If the query given to -c was a normal one, send it */ else if (options.action == ACT_SINGLE_QUERY) { if (pset.echo == PSQL_ECHO_ALL) puts(options.action_string); successResult = SendQuery(options.action_string) ? EXIT_SUCCESS : EXIT_FAILURE; } /* * or otherwise enter interactive main loop */ else { if (!options.no_psqlrc) process_psqlrc(argv[0]); connection_warnings(true); if (!pset.quiet) printf(_("Type \"help\" for help.\n\n")); initializeInput(options.no_readline ? 0 : 1); successResult = MainLoop(stdin); } /* clean up */ if (pset.logfile) fclose(pset.logfile); PQfinish(pset.db); setQFout(NULL); return successResult; }
int main(int argc, char *argv[]) { int append=0; int create=0; int slim=0; int sanitize=0; int long_usage_bool=0; int pass_prompt=0; int projection = PROJ_SPHERE_MERC; int expire_tiles_zoom = -1; int expire_tiles_zoom_min = -1; int enable_hstore = HSTORE_NONE; int enable_hstore_index = 0; int hstore_match_only = 0; int enable_multi = 0; int parallel_indexing = 1; int flat_node_cache_enabled = 0; #ifdef __amd64__ int alloc_chunkwise = ALLOC_SPARSE | ALLOC_DENSE; #else int alloc_chunkwise = ALLOC_SPARSE; #endif int num_procs = 1; int droptemp = 0; int unlogged = 0; int excludepoly = 0; time_t start, end; time_t overall_start, overall_end; time_t now; time_t end_nodes; time_t end_way; time_t end_rel; const char *expire_tiles_filename = "dirty_tiles"; const char *db = "gis"; const char *username=NULL; const char *host=NULL; const char *password=NULL; const char *port = "5432"; const char *tblsmain_index = NULL; /* no default TABLESPACE for index on main tables */ const char *tblsmain_data = NULL; /* no default TABLESPACE for main tables */ const char *tblsslim_index = NULL; /* no default TABLESPACE for index on slim mode tables */ const char *tblsslim_data = NULL; /* no default TABLESPACE for slim mode tables */ const char *conninfo = NULL; const char *prefix = "planet_osm"; const char *style = OSM2PGSQL_DATADIR "/default.style"; const char *temparg; const char *output_backend = "pgsql"; const char *input_reader = "auto"; const char **hstore_columns = NULL; const char *flat_nodes_file = NULL; const char *tag_transform_script = NULL; int n_hstore_columns = 0; int keep_coastlines=0; int cache = 800; struct output_options options; PGconn *sql_conn; int (*streamFile)(char *, int, struct osmdata_t *); fprintf(stderr, "osm2pgsql SVN version %s (%lubit id space)\n\n", VERSION, 8 * sizeof(osmid_t)); while (1) { int c, option_index = 0; static struct option long_options[] = { {"append", 0, 0, 'a'}, {"bbox", 1, 0, 'b'}, {"create", 0, 0, 'c'}, {"database", 1, 0, 'd'}, {"latlong", 0, 0, 'l'}, {"verbose", 0, 0, 'v'}, {"slim", 0, 0, 's'}, {"prefix", 1, 0, 'p'}, {"proj", 1, 0, 'E'}, {"merc", 0, 0, 'm'}, {"oldmerc", 0, 0, 'M'}, {"utf8-sanitize", 0, 0, 'u'}, {"cache", 1, 0, 'C'}, {"username", 1, 0, 'U'}, {"password", 0, 0, 'W'}, {"host", 1, 0, 'H'}, {"port", 1, 0, 'P'}, {"tablespace-index", 1, 0, 'i'}, {"tablespace-slim-data", 1, 0, 200}, {"tablespace-slim-index", 1, 0, 201}, {"tablespace-main-data", 1, 0, 202}, {"tablespace-main-index", 1, 0, 203}, {"help", 0, 0, 'h'}, {"style", 1, 0, 'S'}, {"expire-tiles", 1, 0, 'e'}, {"expire-output", 1, 0, 'o'}, {"output", 1, 0, 'O'}, {"extra-attributes", 0, 0, 'x'}, {"hstore", 0, 0, 'k'}, {"hstore-all", 0, 0, 'j'}, {"hstore-column", 1, 0, 'z'}, {"hstore-match-only", 0, 0, 208}, {"hstore-add-index",0,0,211}, {"multi-geometry", 0, 0, 'G'}, {"keep-coastlines", 0, 0, 'K'}, {"input-reader", 1, 0, 'r'}, {"version", 0, 0, 'V'}, {"disable-parallel-indexing", 0, 0, 'I'}, {"cache-strategy", 1, 0, 204}, {"number-processes", 1, 0, 205}, {"drop", 0, 0, 206}, {"unlogged", 0, 0, 207}, {"flat-nodes",1,0,209}, {"exclude-invalid-polygon",0,0,210}, {"tag-transform-script",1,0,212}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "ab:cd:KhlmMp:suvU:WH:P:i:IE:C:S:e:o:O:xkjGz:r:V", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': append=1; break; case 'b': osmdata.bbox=optarg; break; case 'c': create=1; break; case 'v': verbose=1; break; case 's': slim=1; break; case 'K': keep_coastlines=1; break; case 'u': sanitize=1; break; case 'l': projection=PROJ_LATLONG; break; case 'm': projection=PROJ_SPHERE_MERC; break; case 'M': projection=PROJ_MERC; break; case 'E': projection=-atoi(optarg); break; case 'p': prefix=optarg; break; case 'd': db=optarg; break; case 'C': cache = atoi(optarg); break; case 'U': username=optarg; break; case 'W': pass_prompt=1; break; case 'H': host=optarg; break; case 'P': port=optarg; break; case 'S': style=optarg; break; case 'i': tblsmain_index=tblsslim_index=optarg; break; case 200: tblsslim_data=optarg; break; case 201: tblsslim_index=optarg; break; case 202: tblsmain_data=optarg; break; case 203: tblsmain_index=optarg; break; case 'e': expire_tiles_zoom_min = atoi(optarg); temparg = strchr(optarg, '-'); if (temparg) expire_tiles_zoom = atoi(temparg + 1); if (expire_tiles_zoom < expire_tiles_zoom_min) expire_tiles_zoom = expire_tiles_zoom_min; break; case 'o': expire_tiles_filename=optarg; break; case 'O': output_backend = optarg; break; case 'x': osmdata.extra_attributes=1; break; case 'k': enable_hstore=HSTORE_NORM; break; case 208: hstore_match_only = 1; break; case 'j': enable_hstore=HSTORE_ALL; break; case 'z': n_hstore_columns++; hstore_columns = (const char**)realloc(hstore_columns, sizeof(char *) * n_hstore_columns); hstore_columns[n_hstore_columns-1] = optarg; break; case 'G': enable_multi=1; break; case 'r': input_reader = optarg; break; case 'h': long_usage_bool=1; break; case 'I': #ifdef HAVE_PTHREAD parallel_indexing=0; #endif break; case 204: if (strcmp(optarg,"dense") == 0) alloc_chunkwise = ALLOC_DENSE; else if (strcmp(optarg,"chunk") == 0) alloc_chunkwise = ALLOC_DENSE | ALLOC_DENSE_CHUNK; else if (strcmp(optarg,"sparse") == 0) alloc_chunkwise = ALLOC_SPARSE; else if (strcmp(optarg,"optimized") == 0) alloc_chunkwise = ALLOC_DENSE | ALLOC_SPARSE; else {fprintf(stderr, "ERROR: Unrecognized cache strategy %s.\n", optarg); exit(EXIT_FAILURE); } break; case 205: #ifdef HAVE_FORK num_procs = atoi(optarg); #else fprintf(stderr, "WARNING: osm2pgsql was compiled without fork, only using one process!\n"); #endif break; case 206: droptemp = 1; break; case 207: unlogged = 1; break; case 209: flat_node_cache_enabled = 1; flat_nodes_file = optarg; break; case 210: excludepoly = 1; exclude_broken_polygon(); break; case 211: enable_hstore_index = 1; break; case 212: tag_transform_script = optarg; break; case 'V': exit(EXIT_SUCCESS); case '?': default: short_usage(argv[0]); exit(EXIT_FAILURE); } } if (long_usage_bool) { long_usage(argv[0]); exit(EXIT_SUCCESS); } if (argc == optind) { /* No non-switch arguments */ short_usage(argv[0]); exit(EXIT_FAILURE); } if (append && create) { fprintf(stderr, "Error: --append and --create options can not be used at the same time!\n"); exit(EXIT_FAILURE); } if (droptemp && !slim) { fprintf(stderr, "Error: --drop only makes sense with --slim.\n"); exit(EXIT_FAILURE); } if (unlogged && !create) { fprintf(stderr, "Warning: --unlogged only makes sense with --create; ignored.\n"); unlogged = 0; } if (enable_hstore == HSTORE_NONE && !n_hstore_columns && hstore_match_only) { fprintf(stderr, "Warning: --hstore-match-only only makes sense with --hstore, --hstore-all, or --hstore-column; ignored.\n"); hstore_match_only = 0; } if (enable_hstore_index && enable_hstore == HSTORE_NONE && !n_hstore_columns) { fprintf(stderr, "Warning: --hstore-add-index only makes sense with hstore enabled.\n"); enable_hstore_index = 0; } if (cache < 0) cache = 0; if (num_procs < 1) num_procs = 1; if (pass_prompt) password = simple_prompt("Password:"******"PGPASS"); } conninfo = build_conninfo(db, username, password, host, port); sql_conn = PQconnectdb(conninfo); if (PQstatus(sql_conn) != CONNECTION_OK) { fprintf(stderr, "Error: Connection to database failed: %s\n", PQerrorMessage(sql_conn)); exit(EXIT_FAILURE); } if (unlogged && PQserverVersion(sql_conn) < 90100) { fprintf(stderr, "Error: --unlogged works only with PostgreSQL 9.1 and above, but\n"); fprintf(stderr, "you are using PostgreSQL %d.%d.%d.\n", PQserverVersion(sql_conn) / 10000, (PQserverVersion(sql_conn) / 100) % 100, PQserverVersion(sql_conn) % 100); exit(EXIT_FAILURE); } PQfinish(sql_conn); text_init(); initList(&osmdata.tags); osmdata.count_node = osmdata.max_node = 0; osmdata.count_way = osmdata.max_way = 0; osmdata.count_rel = osmdata.max_rel = 0; LIBXML_TEST_VERSION project_init(projection); fprintf(stderr, "Using projection SRS %d (%s)\n", project_getprojinfo()->srs, project_getprojinfo()->descr ); if (parse_bbox(&osmdata)) return 1; options.conninfo = conninfo; options.prefix = prefix; options.append = append; options.slim = slim; options.projection = project_getprojinfo()->srs; options.scale = (projection==PROJ_LATLONG)?10000000:100; options.mid = slim ? &mid_pgsql : &mid_ram; options.cache = cache; options.style = style; options.tblsmain_index = tblsmain_index; options.tblsmain_data = tblsmain_data; options.tblsslim_index = tblsslim_index; options.tblsslim_data = tblsslim_data; options.expire_tiles_zoom = expire_tiles_zoom; options.expire_tiles_zoom_min = expire_tiles_zoom_min; options.expire_tiles_filename = expire_tiles_filename; options.enable_multi = enable_multi; options.enable_hstore = enable_hstore; options.enable_hstore_index = enable_hstore_index; options.hstore_match_only = hstore_match_only; options.hstore_columns = hstore_columns; options.n_hstore_columns = n_hstore_columns; options.keep_coastlines = keep_coastlines; options.parallel_indexing = parallel_indexing; options.alloc_chunkwise = alloc_chunkwise; options.num_procs = num_procs; options.droptemp = droptemp; options.unlogged = unlogged; options.flat_node_cache_enabled = flat_node_cache_enabled; options.flat_node_file = flat_nodes_file; options.excludepoly = excludepoly; options.tag_transform_script = tag_transform_script; if (strcmp("pgsql", output_backend) == 0) { osmdata.out = &out_pgsql; } else if (strcmp("gazetteer", output_backend) == 0) { osmdata.out = &out_gazetteer; } else if (strcmp("null", output_backend) == 0) { osmdata.out = &out_null; } else { fprintf(stderr, "Output backend `%s' not recognised. Should be one of [pgsql, gazetteer, null].\n", output_backend); exit(EXIT_FAILURE); } options.out = osmdata.out; if (strcmp("auto", input_reader) != 0) { if (strcmp("libxml2", input_reader) == 0) { streamFile = &streamFileXML2; } else if (strcmp("primitive", input_reader) == 0) { streamFile = &streamFilePrimitive; #ifdef BUILD_READER_PBF } else if (strcmp("pbf", input_reader) == 0) { streamFile = &streamFilePbf; #endif } else if (strcmp("o5m", input_reader) == 0) { streamFile = &streamFileO5m; } else { fprintf(stderr, "Input parser `%s' not recognised. Should be one of [libxml2, primitive, o5m" #ifdef BUILD_READER_PBF ", pbf" #endif "].\n", input_reader); exit(EXIT_FAILURE); } } time(&overall_start); osmdata.out->start(&options); realloc_nodes(&osmdata); realloc_members(&osmdata); if (sizeof(int*) == 4 && options.slim != 1) { fprintf(stderr, "\n!! You are running this on 32bit system, so at most\n"); fprintf(stderr, "!! 3GB of RAM can be used. If you encounter unexpected\n"); fprintf(stderr, "!! exceptions during import, you should try running in slim\n"); fprintf(stderr, "!! mode using parameter -s.\n"); } while (optind < argc) { /* if input_reader is not forced by -r switch try to auto-detect it by file extension */ if (strcmp("auto", input_reader) == 0) { if (strcasecmp(".pbf",argv[optind]+strlen(argv[optind])-4) == 0) { #ifdef BUILD_READER_PBF streamFile = &streamFilePbf; #else fprintf(stderr, "ERROR: PBF support has not been compiled into this version of osm2pgsql, please either compile it with pbf support or use one of the other input formats\n"); exit(EXIT_FAILURE); #endif } else if (strcasecmp(".o5m",argv[optind]+strlen(argv[optind])-4) == 0 || strcasecmp(".o5c",argv[optind]+strlen(argv[optind])-4) == 0) { streamFile = &streamFileO5m; } else { streamFile = &streamFileXML2; } } fprintf(stderr, "\nReading in file: %s\n", argv[optind]); time(&start); if (streamFile(argv[optind], sanitize, &osmdata) != 0) exit_nicely(); time(&end); fprintf(stderr, " parse time: %ds\n", (int)(end - start)); optind++; } xmlCleanupParser(); xmlMemoryDump(); if (osmdata.count_node || osmdata.count_way || osmdata.count_rel) { time(&now); end_nodes = osmdata.start_way > 0 ? osmdata.start_way : now; end_way = osmdata.start_rel > 0 ? osmdata.start_rel : now; end_rel = now; fprintf(stderr, "\n"); fprintf(stderr, "Node stats: total(%" PRIdOSMID "), max(%" PRIdOSMID ") in %is\n", osmdata.count_node, osmdata.max_node, osmdata.count_node > 0 ? (int)(end_nodes - osmdata.start_node) : 0); fprintf(stderr, "Way stats: total(%" PRIdOSMID "), max(%" PRIdOSMID ") in %is\n", osmdata.count_way, osmdata.max_way, osmdata.count_way > 0 ? (int)(end_way - osmdata.start_way) : 0); fprintf(stderr, "Relation stats: total(%" PRIdOSMID "), max(%" PRIdOSMID ") in %is\n", osmdata.count_rel, osmdata.max_rel, osmdata.count_rel > 0 ? (int)(end_rel - osmdata.start_rel) : 0); } osmdata.out->stop(); free(osmdata.nds); free(osmdata.members); /* free the column pointer buffer */ free(hstore_columns); project_exit(); text_exit(); fprintf(stderr, "\n"); time(&overall_end); fprintf(stderr, "Osm2pgsql took %ds overall\n", (int)(overall_end - overall_start)); return 0; }
int main(int argc, char **argv) { int port = 0; char *user = NULL; char *passwd = NULL; char *host = NULL; char *dbname = NULL; int trace = 0; int describe = 0; int functions = 0; int useinserts = 0; int c; Mapi mid; int quiet = 0; stream *out; char user_set_as_flag = 0; char *table = NULL; static struct option long_options[] = { {"host", 1, 0, 'h'}, {"port", 1, 0, 'p'}, {"database", 1, 0, 'd'}, {"describe", 0, 0, 'D'}, {"functions", 0, 0, 'f'}, {"table", 1, 0, 't'}, {"inserts", 0, 0, 'N'}, {"Xdebug", 0, 0, 'X'}, {"user", 1, 0, 'u'}, {"quiet", 0, 0, 'q'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} }; parse_dotmonetdb(&user, &passwd, NULL, NULL, NULL, NULL); while ((c = getopt_long(argc, argv, "h:p:d:Dft:NXu:q?", long_options, NULL)) != -1) { switch (c) { case 'u': if (user) free(user); user = strdup(optarg); user_set_as_flag = 1; break; case 'h': host = optarg; break; case 'p': assert(optarg != NULL); port = atoi(optarg); break; case 'd': dbname = optarg; break; case 'D': describe = 1; break; case 'N': useinserts = 1; break; case 'f': if (table) usage(argv[0], -1); functions = 1; break; case 't': if (table || functions) usage(argv[0], -1); table = optarg; break; case 'q': quiet = 1; break; case 'X': trace = MAPI_TRACE; break; case '?': /* a bit of a hack: look at the option that the current `c' is based on and see if we recognize it: if -? or --help, exit with 0, else with -1 */ usage(argv[0], strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0 ? 0 : -1); default: usage(argv[0], -1); } } if (optind == argc - 1) dbname = argv[optind]; else if (optind != argc) usage(argv[0], -1); /* when config file would provide defaults */ if (user_set_as_flag) passwd = NULL; if (user == NULL) user = simple_prompt("user", BUFSIZ, 1, prompt_getlogin()); if (passwd == NULL) passwd = simple_prompt("password", BUFSIZ, 0, NULL); mid = mapi_connect(host, port, user, passwd, "sql", dbname); if (user) free(user); if (passwd) free(passwd); if (mid == NULL) { fprintf(stderr, "failed to allocate Mapi structure\n"); exit(2); } if (mapi_error(mid)) { mapi_explain(mid, stderr); exit(2); } if (!quiet) { char *motd = mapi_get_motd(mid); if (motd) fprintf(stderr, "%s", motd); } mapi_trace(mid, trace); mapi_cache_limit(mid, 10000); out = file_wastream(stdout, "stdout"); if (out == NULL) { fprintf(stderr, "failed to allocate stream\n"); exit(2); } if (!quiet) { char buf[27]; time_t t = time(0); char *p; #ifdef HAVE_CTIME_R3 ctime_r(&t, buf, sizeof(buf)); #else #ifdef HAVE_CTIME_R ctime_r(&t, buf); #else strncpy(buf, ctime(&t), sizeof(buf)); #endif #endif if ((p = strrchr(buf, '\n')) != NULL) *p = 0; mnstr_printf(out, "-- msqldump %s %s%s %s\n", describe ? "describe" : "dump", functions ? "functions" : table ? "table " : "database", table ? table : "", buf); dump_version(mid, out, "--"); } if (functions) c = dump_functions(mid, out, NULL, NULL); else if (table) c = dump_table(mid, NULL, table, out, describe, 1, useinserts); else c = dump_database(mid, out, describe, useinserts); mnstr_flush(out); mapi_destroy(mid); if (mnstr_errnr(out)) { fprintf(stderr, "%s: %s", argv[0], mnstr_error(out)); return 1; } mnstr_destroy(out); return c; }
int main(int argc, char *argv[]) { static struct option long_options[] = { {"host", required_argument, NULL, 'h'}, {"port", required_argument, NULL, 'p'}, {"username", required_argument, NULL, 'U'}, {"password", no_argument, NULL, 'W'}, {"echo", no_argument, NULL, 'e'}, {"quiet", no_argument, NULL, 'q'}, {"interactive", no_argument, NULL, 'i'}, {NULL, 0, NULL, 0} }; char *progname; int optindex; int c; char *dbname = NULL; char *host = NULL; char *port = NULL; char *username = NULL; bool password = false; bool echo = false; bool quiet = false; bool interactive = false; PQExpBufferData sql; PGconn *conn; PGresult *result; progname = get_progname(argv[0]); init_nls(); handle_help_version_opts(argc, argv, "dropdb", help); while ((c = getopt_long(argc, argv, "h:p:U:Weqi", long_options, &optindex)) != -1) { switch (c) { case 'h': host = optarg; break; case 'p': port = optarg; break; case 'U': username = optarg; break; case 'W': password = true; break; case 'e': echo = true; break; case 'q': quiet = true; break; case 'i': interactive = true; break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } switch (argc - optind) { case 0: fprintf(stderr, _("%s: missing required argument database name\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); case 1: dbname = argv[optind]; break; default: fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind + 1]); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } if (interactive) { char *reply; printf(_("Database \"%s\" will be permanently removed.\n"), dbname); reply = simple_prompt("Are you sure? (y/n) ", 1, true); if (check_yesno_response(reply) != 1) exit(0); } initPQExpBuffer(&sql); appendPQExpBuffer(&sql, "DROP DATABASE %s;\n", fmtId(dbname)); conn = connectDatabase("template1", host, port, username, password, progname); if (echo) printf("%s", sql.data); result = PQexec(conn, sql.data); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, _("%s: database removal failed: %s"), progname, PQerrorMessage(conn)); PQfinish(conn); exit(1); } PQfinish(conn); if (!quiet) { puts("DROP DATABASE"); fflush(stdout); } exit(0); }
/* * parse the given command line options and try to connect to the db. * * On success, the db conn is returned inside options->db */ int handle_options(int argc, char** argv, struct adhoc_opts * options) { char *password = NULL; char *password_prompt = NULL; bool new_pass = true; parse_psql_options(argc, argv, options); if (!options->action_string) { fprintf(stderr, "Error: Must specify an sql command\n\n"); usage(); exit(1); } if (options->username == NULL) password_prompt = pg_strdup(_("Password: "******"Password for user %s: "), options->username); if (pset.getPassword == TRI_YES) password = simple_prompt(password_prompt, 100, false); do { #define PARAMS_ARRAY_SIZE 8 const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); keywords[0] = "host"; values[0] = options->host; keywords[1] = "port"; values[1] = options->port; keywords[2] = "user"; values[2] = options->username; keywords[3] = "password"; values[3] = password; keywords[4] = "dbname"; values[4] = options->dbname; keywords[5] = "fallback_application_name"; values[5] = pset.progname; keywords[6] = "client_encoding"; values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto"; keywords[7] = NULL; values[7] = NULL; new_pass = false; pset.db = PQconnectdbParams(keywords, values, true); free(keywords); free(values); if (PQstatus(pset.db) == CONNECTION_BAD && PQconnectionNeedsPassword(pset.db) && password == NULL && pset.getPassword != TRI_NO) { PQfinish(pset.db); password = simple_prompt(password_prompt, 100, false); new_pass = true; } } while (new_pass); options->db = pset.db; return 0; }
/* * Subroutine to actually try to execute a backslash command. */ static backslashResult exec_command(const char *cmd, PsqlScanState scan_state, PQExpBuffer query_buf) { bool success = true; /* indicate here if the command ran ok or * failed */ backslashResult status = PSQL_CMD_SKIP_LINE; /* * \a -- toggle field alignment This makes little sense but we keep it * around. */ if (strcmp(cmd, "a") == 0) { if (pset.popt.topt.format != PRINT_ALIGNED) success = do_pset("format", "aligned", &pset.popt, pset.quiet); else success = do_pset("format", "unaligned", &pset.popt, pset.quiet); } /* \C -- override table title (formerly change HTML caption) */ else if (strcmp(cmd, "C") == 0) { char *opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); success = do_pset("title", opt, &pset.popt, pset.quiet); free(opt); } /* * \c or \connect -- connect to database using the specified parameters. * * \c dbname user host port * * If any of these parameters are omitted or specified as '-', the current * value of the parameter will be used instead. If the parameter has no * current value, the default value for that parameter will be used. Some * examples: * * \c - - hst Connect to current database on current port of host * "hst" as current user. \c - usr - prt Connect to current database on * "prt" port of current host as user "usr". \c dbs Connect to * "dbs" database on current port of current host as current user. */ else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0) { char *opt1, *opt2, *opt3, *opt4; opt1 = read_connect_arg(scan_state); opt2 = read_connect_arg(scan_state); opt3 = read_connect_arg(scan_state); opt4 = read_connect_arg(scan_state); success = do_connect(opt1, opt2, opt3, opt4); free(opt1); free(opt2); free(opt3); free(opt4); } /* \cd */ else if (strcmp(cmd, "cd") == 0) { char *opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); char *dir; if (opt) dir = opt; else { #ifndef WIN32 struct passwd *pw; pw = getpwuid(geteuid()); if (!pw) { psql_error("could not get home directory: %s\n", strerror(errno)); exit(EXIT_FAILURE); } dir = pw->pw_dir; #else /* WIN32 */ /* * On Windows, 'cd' without arguments prints the current * directory, so if someone wants to code this here instead... */ dir = "/"; #endif /* WIN32 */ } if (chdir(dir) == -1) { psql_error("\\%s: could not change directory to \"%s\": %s\n", cmd, dir, strerror(errno)); success = false; } if (pset.dirname) free(pset.dirname); pset.dirname = pg_strdup(dir); canonicalize_path(pset.dirname); if (opt) free(opt); } /* \conninfo -- display information about the current connection */ else if (strcmp(cmd, "conninfo") == 0) { char *db = PQdb(pset.db); char *host = PQhost(pset.db); if (db == NULL) printf(_("You are not connected.\n")); else { if (host == NULL) host = DEFAULT_PGSOCKET_DIR; /* If the host is an absolute path, the connection is via socket */ if (is_absolute_path(host)) printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"), db, PQuser(pset.db), host, PQport(pset.db)); else printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"), db, PQuser(pset.db), host, PQport(pset.db)); } } /* \copy */ else if (pg_strcasecmp(cmd, "copy") == 0) { /* Default fetch-it-all-and-print mode */ instr_time before, after; char *opt = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, false); if (pset.timing) INSTR_TIME_SET_CURRENT(before); success = do_copy(opt); if (pset.timing && success) { INSTR_TIME_SET_CURRENT(after); INSTR_TIME_SUBTRACT(after, before); printf(_("Time: %.3f ms\n"), INSTR_TIME_GET_MILLISEC(after)); } free(opt); } /* \copyright */ else if (strcmp(cmd, "copyright") == 0) print_copyright(); /* \d* commands */ else if (cmd[0] == 'd') { char *pattern; bool show_verbose, show_system; /* We don't do SQLID reduction on the pattern yet */ pattern = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); show_verbose = strchr(cmd, '+') ? true : false; show_system = strchr(cmd, 'S') ? true : false; switch (cmd[1]) { case '\0': case '+': case 'S': /* GPDB: This is a change from old behavior: We used to show just system tables */ if (pattern) success = describeTableDetails(pattern, show_verbose, show_system); else /* standard listing of interesting things */ success = listTables("tvsxr", NULL, show_verbose, show_system); break; case 'a': success = describeAggregates(pattern, show_verbose, show_system); break; case 'b': success = describeTablespaces(pattern, show_verbose); break; case 'c': success = listConversions(pattern, show_system); break; case 'C': success = listCasts(pattern); break; case 'd': if (strncmp(cmd, "ddp", 3) == 0) success = listDefaultACLs(pattern); else success = objectDescription(pattern, show_system); break; case 'D': success = listDomains(pattern, show_system); break; case 'f': /* function subsystem */ switch (cmd[2]) { case '\0': case '+': case 'S': case 'a': case 'n': case 't': case 'w': success = describeFunctions(&cmd[2], pattern, show_verbose, show_system); break; default: status = PSQL_CMD_UNKNOWN; break; } break; case 'g': /* no longer distinct from \du */ success = describeRoles(pattern, show_verbose); break; case 'l': success = do_lo_list(); break; case 'n': success = listSchemas(pattern, show_verbose); break; case 'o': success = describeOperators(pattern, show_system); break; case 'p': success = permissionsList(pattern); break; case 'T': success = describeTypes(pattern, show_verbose, show_system); break; case 't': case 'v': case 'i': case 's': case 'E': /* PostgreSQL use dx for extension, change to dE for foreign table */ /* case 'S': // GPDB: We used to show just system tables for this */ case 'P': /* GPDB: Parent-only tables, no children */ success = listTables(&cmd[1], pattern, show_verbose, show_system); break; case 'r': if (cmd[2] == 'd' && cmd[3] == 's') { char *pattern2 = NULL; if (pattern) pattern2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); success = listDbRoleSettings(pattern, pattern2); } else //success = PSQL_CMD_UNKNOWN; /* GPDB uses \dr for foreign tables ? */ success = listTables(&cmd[1], pattern, show_verbose, show_system); break; case 'u': success = describeRoles(pattern, show_verbose); break; case 'F': /* text search subsystem */ switch (cmd[2]) { case '\0': case '+': success = listTSConfigs(pattern, show_verbose); break; case 'p': success = listTSParsers(pattern, show_verbose); break; case 'd': success = listTSDictionaries(pattern, show_verbose); break; case 't': success = listTSTemplates(pattern, show_verbose); break; default: status = PSQL_CMD_UNKNOWN; break; } break; case 'x': /* Extensions */ if (show_verbose) success = listExtensionContents(pattern); else success = listExtensions(pattern); break; default: status = PSQL_CMD_UNKNOWN; } if (pattern) free(pattern); } /* * \e or \edit -- edit the current query buffer, or edit a file and make * it the query buffer */ else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0) { if (!query_buf) { psql_error("no query buffer\n"); status = PSQL_CMD_ERROR; } else { char *fname; fname = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); expand_tilde(&fname); if (fname) canonicalize_path(fname); if (do_edit(fname, query_buf, NULL)) status = PSQL_CMD_NEWEDIT; else status = PSQL_CMD_ERROR; free(fname); } } /* * \ef -- edit the named function, or present a blank CREATE FUNCTION * template if no argument is given */ else if (strcmp(cmd, "ef") == 0) { if (!query_buf) { psql_error("no query buffer\n"); status = PSQL_CMD_ERROR; } else { char *func; Oid foid = InvalidOid; func = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, true); if (!func) { /* set up an empty command to fill in */ printfPQExpBuffer(query_buf, "CREATE FUNCTION ( )\n" " RETURNS \n" " LANGUAGE \n" " -- common options: IMMUTABLE STABLE STRICT SECURITY DEFINER\n" "AS $function$\n" "\n$function$\n"); } else if (!lookup_function_oid(pset.db, func, &foid)) { /* error already reported */ status = PSQL_CMD_ERROR; } else if (!get_create_function_cmd(pset.db, foid, query_buf)) { /* error already reported */ status = PSQL_CMD_ERROR; } if (func) free(func); } if (status != PSQL_CMD_ERROR) { bool edited = false; if (!do_edit(0, query_buf, &edited)) status = PSQL_CMD_ERROR; else if (!edited) puts(_("No changes")); else status = PSQL_CMD_NEWEDIT; } } /* \echo and \qecho */ else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0) { char *value; char quoted; bool no_newline = false; bool first = true; FILE *fout; if (strcmp(cmd, "qecho") == 0) fout = pset.queryFout; else fout = stdout; while ((value = psql_scan_slash_option(scan_state, OT_NORMAL, "ed, false))) { if (!quoted && strcmp(value, "-n") == 0) no_newline = true; else { if (first) first = false; else fputc(' ', fout); fputs(value, fout); } free(value); } if (!no_newline) fputs("\n", fout); } /* \encoding -- set/show client side encoding */ else if (strcmp(cmd, "encoding") == 0) { char *encoding = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); if (!encoding) { /* show encoding */ puts(pg_encoding_to_char(pset.encoding)); } else { /* set encoding */ if (PQsetClientEncoding(pset.db, encoding) == -1) psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding); else { /* save encoding info into psql internal data */ pset.encoding = PQclientEncoding(pset.db); pset.popt.topt.encoding = pset.encoding; SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding)); } free(encoding); } } /* \f -- change field separator */ else if (strcmp(cmd, "f") == 0) { char *fname = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); success = do_pset("fieldsep", fname, &pset.popt, pset.quiet); free(fname); } /* \g means send query */ else if (strcmp(cmd, "g") == 0) { char *fname = psql_scan_slash_option(scan_state, OT_FILEPIPE, NULL, false); if (!fname) pset.gfname = NULL; else { expand_tilde(&fname); pset.gfname = pg_strdup(fname); } free(fname); status = PSQL_CMD_SEND; } /* help */ else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0) { char *opt = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, false); size_t len; /* strip any trailing spaces and semicolons */ if (opt) { len = strlen(opt); while (len > 0 && (isspace((unsigned char) opt[len - 1]) || opt[len - 1] == ';')) opt[--len] = '\0'; } helpSQL(opt, pset.popt.topt.pager); free(opt); } /* HTML mode */ else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0) { if (pset.popt.topt.format != PRINT_HTML) success = do_pset("format", "html", &pset.popt, pset.quiet); else success = do_pset("format", "aligned", &pset.popt, pset.quiet); } /* \i is include file */ else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0) { char *fname = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); if (!fname) { psql_error("\\%s: missing required argument\n", cmd); success = false; } else { expand_tilde(&fname); success = (process_file(fname, false) == EXIT_SUCCESS); free(fname); } } /* \l is list databases */ else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0) success = listAllDbs(false); else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0) success = listAllDbs(true); /* * large object things */ else if (strncmp(cmd, "lo_", 3) == 0) { char *opt1, *opt2; opt1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); opt2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); if (strcmp(cmd + 3, "export") == 0) { if (!opt2) { psql_error("\\%s: missing required argument\n", cmd); success = false; } else { expand_tilde(&opt2); success = do_lo_export(opt1, opt2); } } else if (strcmp(cmd + 3, "import") == 0) { if (!opt1) { psql_error("\\%s: missing required argument\n", cmd); success = false; } else { expand_tilde(&opt1); success = do_lo_import(opt1, opt2); } } else if (strcmp(cmd + 3, "list") == 0) success = do_lo_list(); else if (strcmp(cmd + 3, "unlink") == 0) { if (!opt1) { psql_error("\\%s: missing required argument\n", cmd); success = false; } else success = do_lo_unlink(opt1); } else status = PSQL_CMD_UNKNOWN; free(opt1); free(opt2); } /* \o -- set query output */ else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0) { char *fname = psql_scan_slash_option(scan_state, OT_FILEPIPE, NULL, true); expand_tilde(&fname); success = setQFout(fname); free(fname); } /* \p prints the current query buffer */ else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0) { if (query_buf && query_buf->len > 0) puts(query_buf->data); else if (!pset.quiet) puts(_("Query buffer is empty.")); fflush(stdout); } /* \password -- set user password */ else if (strcmp(cmd, "password") == 0) { char *pw1; char *pw2; pw1 = simple_prompt("Enter new password: "******"Enter it again: ", 100, false); if (strcmp(pw1, pw2) != 0) { fprintf(stderr, _("Passwords didn't match.\n")); success = false; } else { char *opt0 = psql_scan_slash_option(scan_state, OT_SQLID, NULL, true); char *user; char *encrypted_password; if (opt0) user = opt0; else user = PQuser(pset.db); encrypted_password = PQencryptPassword(pw1, user); if (!encrypted_password) { fprintf(stderr, _("Password encryption failed.\n")); success = false; } else { PQExpBufferData buf; PGresult *res; initPQExpBuffer(&buf); printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD ", fmtId(user)); appendStringLiteralConn(&buf, encrypted_password, pset.db); res = PSQLexec(buf.data, false); termPQExpBuffer(&buf); if (!res) success = false; else PQclear(res); PQfreemem(encrypted_password); } } free(pw1); free(pw2); } /* \prompt -- prompt and set variable */ else if (strcmp(cmd, "prompt") == 0) { char *opt, *prompt_text = NULL; char *arg1, *arg2; arg1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); arg2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); if (!arg1) { psql_error("\\%s: missing required argument\n", cmd); success = false; } else { char *result; if (arg2) { prompt_text = arg1; opt = arg2; } else opt = arg1; if (!pset.inputfile) result = simple_prompt(prompt_text, 4096, true); else { if (prompt_text) { fputs(prompt_text, stdout); fflush(stdout); } result = gets_fromFile(stdin); } if (!SetVariable(pset.vars, opt, result)) { psql_error("\\%s: error\n", cmd); success = false; } free(result); if (prompt_text) free(prompt_text); free(opt); } } /* \pset -- set printing parameters */ else if (strcmp(cmd, "pset") == 0) { char *opt0 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); char *opt1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); if (!opt0) { psql_error("\\%s: missing required argument\n", cmd); success = false; } else success = do_pset(opt0, opt1, &pset.popt, pset.quiet); free(opt0); free(opt1); } /* \q or \quit */ else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0) status = PSQL_CMD_TERMINATE; /* reset(clear) the buffer */ else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0) { resetPQExpBuffer(query_buf); psql_scan_reset(scan_state); if (!pset.quiet) puts(_("Query buffer reset (cleared).")); } /* \s save history in a file or show it on the screen */ else if (strcmp(cmd, "s") == 0) { char *fname = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); #if defined(WIN32) && !defined(__CYGWIN__) /* * XXX This does not work for all terminal environments or for output * containing non-ASCII characters; see comments in simple_prompt(). */ #define DEVTTY "con" #else #define DEVTTY "/dev/tty" #endif expand_tilde(&fname); /* This scrolls off the screen when using /dev/tty */ success = saveHistory(fname ? fname : DEVTTY, -1, false, false); if (success && !pset.quiet && fname) printf(gettext("Wrote history to file \"%s/%s\".\n"), pset.dirname ? pset.dirname : ".", fname); if (!fname) putchar('\n'); free(fname); } /* \set -- generalized set variable/option command */ else if (strcmp(cmd, "set") == 0) { char *opt0 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); if (!opt0) { /* list all variables */ PrintVariables(pset.vars); success = true; } else { /* * Set variable to the concatenation of the arguments. */ char *newval; char *opt; opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); newval = pg_strdup(opt ? opt : ""); free(opt); while ((opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false))) { newval = realloc(newval, strlen(newval) + strlen(opt) + 1); if (!newval) { psql_error("out of memory\n"); exit(EXIT_FAILURE); } strcat(newval, opt); free(opt); } if (!SetVariable(pset.vars, opt0, newval)) { psql_error("\\%s: error\n", cmd); success = false; } free(newval); } free(opt0); } /* \t -- turn off headers and row count */ else if (strcmp(cmd, "t") == 0) { char *opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); success = do_pset("tuples_only", opt, &pset.popt, pset.quiet); free(opt); } /* \T -- define html <table ...> attributes */ else if (strcmp(cmd, "T") == 0) { char *value = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); success = do_pset("tableattr", value, &pset.popt, pset.quiet); free(value); } /* \timing -- toggle timing of queries */ else if (strcmp(cmd, "timing") == 0) { char *opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); if (opt) pset.timing = ParseVariableBool(opt); else pset.timing = !pset.timing; if (!pset.quiet) { if (pset.timing) puts(_("Timing is on.")); else puts(_("Timing is off.")); } free(opt); } /* \unset */ else if (strcmp(cmd, "unset") == 0) { char *opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); if (!opt) { psql_error("\\%s: missing required argument\n", cmd); success = false; } else if (!SetVariable(pset.vars, opt, NULL)) { psql_error("\\%s: error\n", cmd); success = false; } free(opt); } /* \w -- write query buffer to file */ else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0) { FILE *fd = NULL; bool is_pipe = false; char *fname = NULL; if (!query_buf) { psql_error("no query buffer\n"); status = PSQL_CMD_ERROR; } else { fname = psql_scan_slash_option(scan_state, OT_FILEPIPE, NULL, true); expand_tilde(&fname); if (!fname) { psql_error("\\%s: missing required argument\n", cmd); success = false; } else { if (fname[0] == '|') { is_pipe = true; fd = popen(&fname[1], "w"); } else { canonicalize_path(fname); fd = fopen(fname, "w"); } if (!fd) { psql_error("%s: %s\n", fname, strerror(errno)); success = false; } } } if (fd) { int result; if (query_buf && query_buf->len > 0) fprintf(fd, "%s\n", query_buf->data); if (is_pipe) result = pclose(fd); else result = fclose(fd); if (result == EOF) { psql_error("%s: %s\n", fname, strerror(errno)); success = false; } } free(fname); } /* \x -- toggle expanded table representation */ else if (strcmp(cmd, "x") == 0) { char *opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); success = do_pset("expanded", opt, &pset.popt, pset.quiet); free(opt); } /* \z -- list table rights (equivalent to \dp) */ else if (strcmp(cmd, "z") == 0) { char *pattern = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); success = permissionsList(pattern); if (pattern) free(pattern); } /* \! -- shell escape */ else if (strcmp(cmd, "!") == 0) { char *opt = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, false); success = do_shell(opt); free(opt); } /* \? -- slash command help */ else if (strcmp(cmd, "?") == 0) slashUsage(pset.popt.topt.pager); #if 0 /* * These commands don't do anything. I just use them to test the parser. */ else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0) { int i = 0; char *value; while ((value = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true))) { fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value); free(value); } } #endif else status = PSQL_CMD_UNKNOWN; if (!success) status = PSQL_CMD_ERROR; return status; }
/* * Connect to the server. Returns a valid PGconn pointer if connected, * or NULL on non-permanent error. On permanent error, the function will * call exit(1) directly. */ PGconn * GetConnection(void) { PGconn *tmpconn; int argcount = 4; /* dbname, replication, fallback_app_name, * password */ int i; const char **keywords; const char **values; char *password = NULL; const char *tmpparam; if (dbhost) argcount++; if (dbuser) argcount++; if (dbport) argcount++; keywords = pg_malloc0((argcount + 1) * sizeof(*keywords)); values = pg_malloc0((argcount + 1) * sizeof(*values)); keywords[0] = "dbname"; values[0] = "replication"; keywords[1] = "replication"; values[1] = "true"; keywords[2] = "fallback_application_name"; values[2] = progname; i = 3; if (dbhost) { keywords[i] = "host"; values[i] = dbhost; i++; } if (dbuser) { keywords[i] = "user"; values[i] = dbuser; i++; } if (dbport) { keywords[i] = "port"; values[i] = dbport; i++; } while (true) { if (password) free(password); if (dbpassword) { /* * We've saved a password when a previous connection succeeded, * meaning this is the call for a second session to the same * database, so just forcibly reuse that password. */ keywords[argcount - 1] = "password"; values[argcount - 1] = dbpassword; dbgetpassword = -1; /* Don't try again if this fails */ } else if (dbgetpassword == 1) { password = simple_prompt(_("Password: "******"password"; values[argcount - 1] = password; } tmpconn = PQconnectdbParams(keywords, values, true); /* * If there is too little memory even to allocate the PGconn object * and PQconnectdbParams returns NULL, we call exit(1) directly. */ if (!tmpconn) { fprintf(stderr, _("%s: could not connect to server\n"), progname); exit(1); } if (PQstatus(tmpconn) == CONNECTION_BAD && PQconnectionNeedsPassword(tmpconn) && dbgetpassword != -1) { dbgetpassword = 1; /* ask for password next time */ PQfinish(tmpconn); continue; } if (PQstatus(tmpconn) != CONNECTION_OK) { fprintf(stderr, _("%s: could not connect to server: %s\n"), progname, PQerrorMessage(tmpconn)); PQfinish(tmpconn); free(values); free(keywords); return NULL; } /* Connection ok! */ free(values); free(keywords); /* * Ensure we have the same value of integer timestamps as the server * we are connecting to. */ tmpparam = PQparameterStatus(tmpconn, "integer_datetimes"); if (!tmpparam) { fprintf(stderr, _("%s: could not determine server setting for integer_datetimes\n"), progname); PQfinish(tmpconn); exit(1); } #ifdef HAVE_INT64_TIMESTAMP if (strcmp(tmpparam, "on") != 0) #else if (strcmp(tmpparam, "off") != 0) #endif { fprintf(stderr, _("%s: integer_datetimes compile flag does not match server\n"), progname); PQfinish(tmpconn); exit(1); } /* Store the password for next run */ if (password) dbpassword = password; return tmpconn; } }
/* establish connection with database. */ PGconn * sql_conn(struct options * my_opts) { PGconn *conn; char *password = NULL; bool new_pass; /* * Start the connection. Loop until we have a password if requested by * backend. */ do { #define PARAMS_ARRAY_SIZE 7 const char *keywords[PARAMS_ARRAY_SIZE]; const char *values[PARAMS_ARRAY_SIZE]; keywords[0] = "host"; values[0] = my_opts->hostname; keywords[1] = "port"; values[1] = my_opts->port; keywords[2] = "user"; values[2] = my_opts->username; keywords[3] = "password"; values[3] = password; keywords[4] = "dbname"; values[4] = my_opts->dbname; keywords[5] = "fallback_application_name"; values[5] = my_opts->progname; keywords[6] = NULL; values[6] = NULL; new_pass = false; conn = PQconnectdbParams(keywords, values, true); if (!conn) { fprintf(stderr, "%s: could not connect to database %s\n", "oid2name", my_opts->dbname); exit(1); } if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && password == NULL) { PQfinish(conn); password = simple_prompt("Password: "******"%s: could not connect to database %s: %s", "oid2name", my_opts->dbname, PQerrorMessage(conn)); PQfinish(conn); exit(1); } /* return the conn if good */ return conn; }
int main(int argc, char **argv) { char* host = NULL; int port = 9898; char* user = NULL; char* pass = NULL; int nodeID = -1; int processID = 0; int ch; char shutdown_mode = 's'; int optindex; int i; bool all = false; bool debug = false; bool need_password = true; bool gracefully = false; bool verbose = false; PCPConnInfo* pcpConn; PCPResultInfo* pcpResInfo; /* here we put all the allowed long options for all utilities */ static struct option long_options[] = { {"help", no_argument, NULL, '?'}, {"debug", no_argument, NULL, 'd'}, {"version", no_argument, NULL, 'V'}, {"host", required_argument, NULL, 'h'}, {"port", required_argument, NULL, 'p'}, {"process-id", required_argument, NULL, 'P'}, {"username", required_argument, NULL, 'U'}, {"no-password", no_argument, NULL, 'w'}, {"password", no_argument, NULL, 'W'}, {"mode", required_argument, NULL, 'm'}, {"gracefully", no_argument, NULL, 'g'}, {"verbose", no_argument, NULL, 'v'}, {"all", no_argument, NULL, 'a'}, {"node-id", required_argument, NULL, 'n'}, {"watchdog-id", required_argument, NULL, 'n'}, {NULL, 0, NULL, 0} }; /* Identify the utility app */ progname = get_progname(argv[0]); for( i =0; ;i++) { current_app_type = &AllAppTypes[i]; if(current_app_type->app_type == UNKNOWN) break; if (strcmp(current_app_type->app_name, progname) == 0) break; } if(current_app_type->app_type == UNKNOWN) { fprintf(stderr, "%s is a invalid PCP utility\n",progname); exit(1); } if (argc > 1) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { usage(); exit(0); } else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") == 0) { fprintf(stderr, "%s (%s) %s\n",progname,PACKAGE, VERSION); exit(0); } } while ((ch = getopt_long(argc, argv, current_app_type->allowed_options, long_options, &optindex)) != -1) { switch (ch) { case 'd': debug = true; break; case 'a': all = true; break; case 'w': need_password = false; break; case 'W': need_password = true; break; case 'g': gracefully = true; break; case 'm': if (current_app_type->app_type == PCP_STOP_PGPOOL) { if (strcmp(optarg, "s") == 0 || strcmp(optarg, "smart") == 0) shutdown_mode = 's'; else if (strcmp(optarg, "f") == 0 || strcmp(optarg, "fast") == 0) shutdown_mode = 'f'; else if (strcmp(optarg, "i") == 0 || strcmp(optarg, "immediate") == 0) shutdown_mode = 'i'; else { fprintf(stderr, "%s: Invalid shutdown mode \"%s\", must be either \"smart\" \"immediate\" or \"fast\" \n",progname,optarg); exit(1); } } else { fprintf(stderr, "Invalid argument \"%s\", Try \"%s --help\" for more information.\n",optarg,progname); exit(1); } break; case 'v': verbose = true; break; case 'n': nodeID = atoi(optarg); if (current_app_type->app_type == PCP_WATCHDOG_INFO) { if (nodeID < 0) { fprintf(stderr, "%s: Invalid watchdog-id \"%s\", must be a positive number or zero for a local watchdog node\n",progname,optarg); exit(0); } } else { if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS) { fprintf(stderr, "%s: Invalid node-id \"%s\", must be between 0 and %d\n",progname,optarg,MAX_NUM_BACKENDS); exit(0); } } break; case 'p': port = atoi(optarg); if (port <= 1024 || port > 65535) { fprintf(stderr, "%s: Invalid port number \"%s\", must be between 1024 and 65535\n",progname,optarg); exit(0); } break; case 'P': /* PID */ processID = atoi(optarg); if (processID <= 0 ) { fprintf(stderr, "%s: Invalid process-id \"%s\", must be greater than 0\n",progname,optarg); exit(0); } break; case 'h': host = strdup(optarg); break; case 'U': user = strdup(optarg); break; case '?': default: /* * getopt_long whould already have emitted a complaint */ fprintf(stderr, "Try \"%s --help\" for more information.\n\n",progname); exit(1); } } /* * if we still have arguments, use it */ while (argc - optind >= 1) { if (current_app_type->app_type == PCP_PROC_INFO && processID <= 0) { processID = atoi(argv[optind]); if (processID <= 0 ) { fprintf(stderr, "%s: Invalid process-id \"%s\", must be greater than 0\n",progname,optarg); exit(0); } } else if (current_app_type->app_type == PCP_WATCHDOG_INFO && nodeID < 0) { nodeID = atoi(argv[optind]); if (nodeID < 0 ) { fprintf(stderr, "%s: Invalid watchdog-id \"%s\", must be a positive number or zero for local watchdog node\n",progname,optarg); exit(0); } } else if (app_require_nodeID() && nodeID < 0) { nodeID = atoi(argv[optind]); if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS) { fprintf(stderr, "%s: Invalid node-id \"%s\", must be between 0 and %d\n",progname,optarg,MAX_NUM_BACKENDS); exit(0); } } else fprintf(stderr, "%s: Warning: extra command-line argument \"%s\" ignored\n", progname, argv[optind]); optind++; } if(nodeID < 0) { if (app_require_nodeID()) { fprintf(stderr, "%s: missing node-id\n",progname); fprintf(stderr, "Try \"%s --help\" for more information.\n\n",progname); exit(1); } else if (current_app_type->app_type == PCP_WATCHDOG_INFO) { nodeID = -1; } } /* Get a new password if appropriate */ if (need_password) { pass = simple_prompt("Password: "******"%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error"); exit(1); } /* * Okay the connection is successful not call the actual PCP function */ if (current_app_type->app_type == PCP_ATTACH_NODE) { pcpResInfo = pcp_attach_node(pcpConn,nodeID); } else if (current_app_type->app_type == PCP_DETACH_NODE) { if (gracefully) pcpResInfo = pcp_detach_node_gracefully(pcpConn,nodeID); else pcpResInfo = pcp_detach_node(pcpConn,nodeID); } else if (current_app_type->app_type == PCP_NODE_COUNT) { pcpResInfo = pcp_node_count(pcpConn); } else if (current_app_type->app_type == PCP_NODE_INFO) { pcpResInfo = pcp_node_info(pcpConn,nodeID); } else if (current_app_type->app_type == PCP_POOL_STATUS) { pcpResInfo = pcp_pool_status(pcpConn); } else if (current_app_type->app_type == PCP_PROC_COUNT) { pcpResInfo = pcp_process_count(pcpConn); } else if (current_app_type->app_type == PCP_PROC_INFO) { pcpResInfo = pcp_process_info(pcpConn, processID); } else if (current_app_type->app_type == PCP_PROMOTE_NODE) { if (gracefully) pcpResInfo = pcp_promote_node_gracefully(pcpConn,nodeID); else pcpResInfo = pcp_promote_node(pcpConn,nodeID); } else if (current_app_type->app_type == PCP_RECOVERY_NODE) { pcpResInfo = pcp_recovery_node(pcpConn, nodeID); } else if (current_app_type->app_type == PCP_STOP_PGPOOL) { pcpResInfo = pcp_terminate_pgpool(pcpConn, shutdown_mode); } else if (current_app_type->app_type == PCP_WATCHDOG_INFO) { pcpResInfo = pcp_watchdog_info(pcpConn,nodeID); } else { /* should never happen */ fprintf(stderr,"%s: Invalid pcp process\n",progname); goto DISCONNECT_AND_EXIT; } if(pcpResInfo == NULL || PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK) { fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error"); goto DISCONNECT_AND_EXIT; } if (pcp_result_is_empty(pcpResInfo)) { fprintf(stdout,"%s -- Command Successful\n",progname); } else { if (current_app_type->app_type == PCP_NODE_COUNT) output_nodecount_result(pcpResInfo, verbose); if (current_app_type->app_type == PCP_NODE_INFO) output_nodeinfo_result(pcpResInfo, verbose); if (current_app_type->app_type == PCP_POOL_STATUS) output_poolstatus_result(pcpResInfo, verbose); if (current_app_type->app_type == PCP_PROC_COUNT) output_proccount_result(pcpResInfo, verbose); if (current_app_type->app_type == PCP_PROC_INFO) output_procinfo_result(pcpResInfo, all, verbose); else if (current_app_type->app_type == PCP_WATCHDOG_INFO) output_watchdog_info_result(pcpResInfo, verbose); } DISCONNECT_AND_EXIT: pcp_disconnect(pcpConn); pcp_free_connection(pcpConn); return 0; }
/* * Connect to the db again. * * Note: it's not really all that sensible to use a single-entry password * cache if the username keeps changing. In current usage, however, the * username never does change, so one savedPassword is sufficient. We do * update the cache on the off chance that the password has changed since the * start of the run. */ static PGconn * _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) { PGconn *newConn; const char *newdb; const char *newuser; char *password; bool new_pass; if (!reqdb) newdb = PQdb(AH->connection); else newdb = reqdb; if (!requser || strlen(requser) == 0) newuser = PQuser(AH->connection); else newuser = requser; ahlog(AH, 1, "connecting to database \"%s\" as user \"%s\"\n", newdb, newuser); password = AH->savedPassword ? pg_strdup(AH->savedPassword) : NULL; if (AH->promptPassword == TRI_YES && password == NULL) { password = simple_prompt("Password: "******"out of memory\n"); } do { const char *keywords[7]; const char *values[7]; keywords[0] = "host"; values[0] = PQhost(AH->connection); keywords[1] = "port"; values[1] = PQport(AH->connection); keywords[2] = "user"; values[2] = newuser; keywords[3] = "password"; values[3] = password; keywords[4] = "dbname"; values[4] = newdb; keywords[5] = "fallback_application_name"; values[5] = progname; keywords[6] = NULL; values[6] = NULL; new_pass = false; newConn = PQconnectdbParams(keywords, values, true); if (!newConn) exit_horribly(modulename, "failed to reconnect to database\n"); if (PQstatus(newConn) == CONNECTION_BAD) { if (!PQconnectionNeedsPassword(newConn)) exit_horribly(modulename, "could not reconnect to database: %s", PQerrorMessage(newConn)); PQfinish(newConn); if (password) fprintf(stderr, "Password incorrect\n"); fprintf(stderr, "Connecting to %s as %s\n", newdb, newuser); if (password) free(password); if (AH->promptPassword != TRI_NO) password = simple_prompt("Password: "******"connection needs password\n"); if (password == NULL) exit_horribly(modulename, "out of memory\n"); new_pass = true; } } while (new_pass); /* * We want to remember connection's actual password, whether or not we got * it by prompting. So we don't just store the password variable. */ if (PQconnectionUsedPassword(newConn)) { if (AH->savedPassword) free(AH->savedPassword); AH->savedPassword = pg_strdup(PQpass(newConn)); } if (password) free(password); /* check for version mismatch */ _check_database_version(AH); PQsetNoticeProcessor(newConn, notice_processor, NULL); return newConn; }
int main(int argc, char *argv[]) { static struct option long_options[] = { {"host", required_argument, NULL, 'h'}, {"port", required_argument, NULL, 'p'}, {"username", required_argument, NULL, 'U'}, {"password", no_argument, NULL, 'W'}, {"echo", no_argument, NULL, 'e'}, {"quiet", no_argument, NULL, 'q'}, {"createdb", no_argument, NULL, 'd'}, {"no-createdb", no_argument, NULL, 'D'}, {"adduser", no_argument, NULL, 'a'}, {"no-adduser", no_argument, NULL, 'A'}, {"sysid", required_argument, NULL, 'i'}, {"pwprompt", no_argument, NULL, 'P'}, {"encrypted", no_argument, NULL, 'E'}, {"unencrypted", no_argument, NULL, 'N'}, {NULL, 0, NULL, 0} }; const char *progname; int optindex; int c; char *newuser = NULL; char *host = NULL; char *port = NULL; char *username = NULL; bool password = false; bool echo = false; bool quiet = false; int createdb = 0; int adduser = 0; char *sysid = NULL; bool pwprompt = false; int encrypted = 0; /* 0 uses server default */ char *newpassword = NULL; PQExpBufferData sql; PGconn *conn; PGresult *result; progname = get_progname(argv[0]); set_pglocale_pgservice(argv[0], "pgscripts"); handle_help_version_opts(argc, argv, "createuser", help); while ((c = getopt_long(argc, argv, "h:p:U:WeqaAdDi:PEN", long_options, &optindex)) != -1) { switch (c) { case 'h': host = optarg; break; case 'p': port = optarg; break; case 'U': username = optarg; break; case 'W': password = true; break; case 'e': echo = true; break; case 'q': quiet = true; break; case 'a': adduser = +1; break; case 'A': adduser = -1; break; case 'd': createdb = +1; break; case 'D': createdb = -1; break; case 'i': sysid = optarg; break; case 'P': pwprompt = true; break; case 'E': encrypted = +1; break; case 'N': encrypted = -1; break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } switch (argc - optind) { case 0: break; case 1: newuser = argv[optind]; break; default: fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind + 1]); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } if (sysid) { char *endptr; if (strtol(sysid, &endptr, 10) <= 0 || *endptr != '\0') { fprintf(stderr, _("%s: user ID must be a positive number\n"), progname); exit(1); } } if (newuser == NULL) newuser = simple_prompt("Enter name of user to add: ", 128, true); if (pwprompt) { char *pw1, *pw2; pw1 = simple_prompt("Enter password for new user: "******"Enter it again: ", 100, false); if (strcmp(pw1, pw2) != 0) { fprintf(stderr, _("Passwords didn't match.\n")); exit(1); } newpassword = pw1; free(pw2); } if (createdb == 0) { char *reply; reply = simple_prompt("Shall the new user be allowed to create databases? (y/n) ", 1, true); if (check_yesno_response(reply) == 1) createdb = +1; else createdb = -1; } if (adduser == 0) { char *reply; reply = simple_prompt("Shall the new user be allowed to create more new users? (y/n) ", 1, true); if (check_yesno_response(reply) == 1) adduser = +1; else adduser = -1; } initPQExpBuffer(&sql); printfPQExpBuffer(&sql, "CREATE USER %s", fmtId(newuser)); if (sysid) appendPQExpBuffer(&sql, " SYSID %s", sysid); if (newpassword) { if (encrypted == +1) appendPQExpBuffer(&sql, " ENCRYPTED"); if (encrypted == -1) appendPQExpBuffer(&sql, " UNENCRYPTED"); appendPQExpBuffer(&sql, " PASSWORD "); appendStringLiteral(&sql, newpassword, false); } if (createdb == +1) appendPQExpBuffer(&sql, " CREATEDB"); if (createdb == -1) appendPQExpBuffer(&sql, " NOCREATEDB"); if (adduser == +1) appendPQExpBuffer(&sql, " CREATEUSER"); if (adduser == -1) appendPQExpBuffer(&sql, " NOCREATEUSER"); appendPQExpBuffer(&sql, ";\n"); conn = connectDatabase("template1", host, port, username, password, progname); if (echo) printf("%s", sql.data); result = PQexec(conn, sql.data); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, _("%s: creation of new user failed: %s"), progname, PQerrorMessage(conn)); PQfinish(conn); exit(1); } PQfinish(conn); if (!quiet) { puts("CREATE USER"); fflush(stdout); } exit(0); }
/* * This vacuums LOs of one database. It returns 0 on success, -1 on failure. */ static int vacuumlo(const char *database, const struct _param *param) { PGconn *conn; PGresult *res, *res2; char buf[BUFSIZE]; long matched; long deleted; int i; bool new_pass; bool success = true; static bool have_password = false; static char password[100]; /* Note: password can be carried over from a previous call */ if (param->pg_prompt == TRI_YES && !have_password) { simple_prompt("Password: "******"host"; values[0] = param->pg_host; keywords[1] = "port"; values[1] = param->pg_port; keywords[2] = "user"; values[2] = param->pg_user; keywords[3] = "password"; values[3] = have_password ? password : NULL; keywords[4] = "dbname"; values[4] = database; keywords[5] = "fallback_application_name"; values[5] = param->progname; keywords[6] = NULL; values[6] = NULL; new_pass = false; conn = PQconnectdbParams(keywords, values, true); if (!conn) { fprintf(stderr, "Connection to database \"%s\" failed\n", database); return -1; } if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && !have_password && param->pg_prompt != TRI_NO) { PQfinish(conn); simple_prompt("Password: "******"Connection to database \"%s\" failed:\n%s", database, PQerrorMessage(conn)); PQfinish(conn); return -1; } if (param->verbose) { fprintf(stdout, "Connected to database \"%s\"\n", database); if (param->dry_run) fprintf(stdout, "Test run: no large objects will be removed!\n"); } res = PQexec(conn, ALWAYS_SECURE_SEARCH_PATH_SQL); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Failed to set search_path:\n"); fprintf(stderr, "%s", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return -1; } PQclear(res); /* * First we create and populate the LO temp table */ buf[0] = '\0'; strcat(buf, "CREATE TEMP TABLE vacuum_l AS "); if (PQserverVersion(conn) >= 90000) strcat(buf, "SELECT oid AS lo FROM pg_largeobject_metadata"); else strcat(buf, "SELECT DISTINCT loid AS lo FROM pg_largeobject"); res = PQexec(conn, buf); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "Failed to create temp table:\n"); fprintf(stderr, "%s", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return -1; } PQclear(res); /* * Analyze the temp table so that planner will generate decent plans for * the DELETEs below. */ buf[0] = '\0'; strcat(buf, "ANALYZE vacuum_l"); res = PQexec(conn, buf); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "Failed to vacuum temp table:\n"); fprintf(stderr, "%s", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return -1; } PQclear(res); /* * Now find any candidate tables that have columns of type oid. * * NOTE: we ignore system tables and temp tables by the expedient of * rejecting tables in schemas named 'pg_*'. In particular, the temp * table formed above is ignored, and pg_largeobject will be too. If * either of these were scanned, obviously we'd end up with nothing to * delete... * * NOTE: the system oid column is ignored, as it has attnum < 1. This * shouldn't matter for correctness, but it saves time. */ buf[0] = '\0'; strcat(buf, "SELECT s.nspname, c.relname, a.attname "); strcat(buf, "FROM pg_class c, pg_attribute a, pg_namespace s, pg_type t "); strcat(buf, "WHERE a.attnum > 0 AND NOT a.attisdropped "); strcat(buf, " AND a.attrelid = c.oid "); strcat(buf, " AND a.atttypid = t.oid "); strcat(buf, " AND c.relnamespace = s.oid "); strcat(buf, " AND t.typname in ('oid', 'lo') "); strcat(buf, " AND c.relkind in (" CppAsString2(RELKIND_RELATION) ", " CppAsString2(RELKIND_MATVIEW) ")"); strcat(buf, " AND s.nspname !~ '^pg_'"); res = PQexec(conn, buf); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Failed to find OID columns:\n"); fprintf(stderr, "%s", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return -1; } for (i = 0; i < PQntuples(res); i++) { char *schema, *table, *field; schema = PQgetvalue(res, i, 0); table = PQgetvalue(res, i, 1); field = PQgetvalue(res, i, 2); if (param->verbose) fprintf(stdout, "Checking %s in %s.%s\n", field, schema, table); schema = PQescapeIdentifier(conn, schema, strlen(schema)); table = PQescapeIdentifier(conn, table, strlen(table)); field = PQescapeIdentifier(conn, field, strlen(field)); if (!schema || !table || !field) { fprintf(stderr, "%s", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); if (schema != NULL) PQfreemem(schema); if (schema != NULL) PQfreemem(table); if (schema != NULL) PQfreemem(field); return -1; } snprintf(buf, BUFSIZE, "DELETE FROM vacuum_l " "WHERE lo IN (SELECT %s FROM %s.%s)", field, schema, table); res2 = PQexec(conn, buf); if (PQresultStatus(res2) != PGRES_COMMAND_OK) { fprintf(stderr, "Failed to check %s in table %s.%s:\n", field, schema, table); fprintf(stderr, "%s", PQerrorMessage(conn)); PQclear(res2); PQclear(res); PQfinish(conn); PQfreemem(schema); PQfreemem(table); PQfreemem(field); return -1; } PQclear(res2); PQfreemem(schema); PQfreemem(table); PQfreemem(field); } PQclear(res); /* * Now, those entries remaining in vacuum_l are orphans. Delete 'em. * * We don't want to run each delete as an individual transaction, because * the commit overhead would be high. However, since 9.0 the backend will * acquire a lock per deleted LO, so deleting too many LOs per transaction * risks running out of room in the shared-memory lock table. Accordingly, * we delete up to transaction_limit LOs per transaction. */ res = PQexec(conn, "begin"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "Failed to start transaction:\n"); fprintf(stderr, "%s", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return -1; } PQclear(res); buf[0] = '\0'; strcat(buf, "DECLARE myportal CURSOR WITH HOLD FOR SELECT lo FROM vacuum_l"); res = PQexec(conn, buf); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "DECLARE CURSOR failed: %s", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return -1; } PQclear(res); snprintf(buf, BUFSIZE, "FETCH FORWARD %ld IN myportal", param->transaction_limit > 0 ? param->transaction_limit : 1000L); deleted = 0; while (1) { res = PQexec(conn, buf); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "FETCH FORWARD failed: %s", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return -1; } matched = PQntuples(res); if (matched <= 0) { /* at end of resultset */ PQclear(res); break; } for (i = 0; i < matched; i++) { Oid lo = atooid(PQgetvalue(res, i, 0)); if (param->verbose) { fprintf(stdout, "\rRemoving lo %6u ", lo); fflush(stdout); } if (param->dry_run == 0) { if (lo_unlink(conn, lo) < 0) { fprintf(stderr, "\nFailed to remove lo %u: ", lo); fprintf(stderr, "%s", PQerrorMessage(conn)); if (PQtransactionStatus(conn) == PQTRANS_INERROR) { success = false; PQclear(res); break; } } else deleted++; } else deleted++; if (param->transaction_limit > 0 && (deleted % param->transaction_limit) == 0) { res2 = PQexec(conn, "commit"); if (PQresultStatus(res2) != PGRES_COMMAND_OK) { fprintf(stderr, "Failed to commit transaction:\n"); fprintf(stderr, "%s", PQerrorMessage(conn)); PQclear(res2); PQclear(res); PQfinish(conn); return -1; } PQclear(res2); res2 = PQexec(conn, "begin"); if (PQresultStatus(res2) != PGRES_COMMAND_OK) { fprintf(stderr, "Failed to start transaction:\n"); fprintf(stderr, "%s", PQerrorMessage(conn)); PQclear(res2); PQclear(res); PQfinish(conn); return -1; } PQclear(res2); } } PQclear(res); } /* * That's all folks! */ res = PQexec(conn, "commit"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "Failed to commit transaction:\n"); fprintf(stderr, "%s", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return -1; } PQclear(res); PQfinish(conn); if (param->verbose) { if (param->dry_run) fprintf(stdout, "\rWould remove %ld large objects from database \"%s\".\n", deleted, database); else if (success) fprintf(stdout, "\rSuccessfully removed %ld large objects from database \"%s\".\n", deleted, database); else fprintf(stdout, "\rRemoval from database \"%s\" failed at object %ld of %ld.\n", database, deleted, matched); } return ((param->dry_run || success) ? 0 : -1); }
/* * Make a database connection with the given parameters. The * connection handle is returned, the parameters are stored in AHX. * An interactive password prompt is automatically issued if required. * * Note: it's not really all that sensible to use a single-entry password * cache if the username keeps changing. In current usage, however, the * username never does change, so one savedPassword is sufficient. */ void ConnectDatabase(Archive *AHX, const char *dbname, const char *pghost, const char *pgport, const char *username, trivalue prompt_password) { ArchiveHandle *AH = (ArchiveHandle *) AHX; char *password; bool new_pass; if (AH->connection) exit_horribly(modulename, "already connected to a database\n"); password = AH->savedPassword ? pg_strdup(AH->savedPassword) : NULL; if (prompt_password == TRI_YES && password == NULL) { password = simple_prompt("Password: "******"out of memory\n"); } AH->promptPassword = prompt_password; /* * Start the connection. Loop until we have a password if requested by * backend. */ do { const char *keywords[7]; const char *values[7]; keywords[0] = "host"; values[0] = pghost; keywords[1] = "port"; values[1] = pgport; keywords[2] = "user"; values[2] = username; keywords[3] = "password"; values[3] = password; keywords[4] = "dbname"; values[4] = dbname; keywords[5] = "fallback_application_name"; values[5] = progname; keywords[6] = NULL; values[6] = NULL; new_pass = false; AH->connection = PQconnectdbParams(keywords, values, true); if (!AH->connection) exit_horribly(modulename, "failed to connect to database\n"); if (PQstatus(AH->connection) == CONNECTION_BAD && PQconnectionNeedsPassword(AH->connection) && password == NULL && prompt_password != TRI_NO) { PQfinish(AH->connection); password = simple_prompt("Password: "******"out of memory\n"); new_pass = true; } } while (new_pass); /* check to see that the backend connection was successfully made */ if (PQstatus(AH->connection) == CONNECTION_BAD) exit_horribly(modulename, "connection to database \"%s\" failed: %s", PQdb(AH->connection) ? PQdb(AH->connection) : "", PQerrorMessage(AH->connection)); /* * We want to remember connection's actual password, whether or not we got * it by prompting. So we don't just store the password variable. */ if (PQconnectionUsedPassword(AH->connection)) { if (AH->savedPassword) free(AH->savedPassword); AH->savedPassword = pg_strdup(PQpass(AH->connection)); } if (password) free(password); /* check for version mismatch */ _check_database_version(AH); PQsetNoticeProcessor(AH->connection, notice_processor, NULL); }
/* * Make a database connection with the given parameters. An * interactive password prompt is automatically issued if required. * * If fail_on_error is false, we return NULL without printing any message * on failure, but preserve any prompted password for the next try. */ static PGconn * connectDatabase(const char *dbname, const char *pghost, const char *pgport, const char *pguser, bool require_password, bool fail_on_error) { PGconn *conn; bool need_pass = false; const char *remoteversion_str; int my_version; static char *password = NULL; if (require_password && !password) password = simple_prompt("Password: "******"%s: could not connect to database \"%s\"\n"), progname, dbname); exit(1); } if (PQstatus(conn) == CONNECTION_BAD && strcmp(PQerrorMessage(conn), PQnoPasswordSupplied) == 0 && !feof(stdin)) { PQfinish(conn); need_pass = true; if (password) free(password); password = NULL; password = simple_prompt("Password: "******"%s: could not connect to database \"%s\": %s\n"), progname, dbname, PQerrorMessage(conn)); exit(1); } else { PQfinish(conn); return NULL; } } remoteversion_str = PQparameterStatus(conn, "server_version"); if (!remoteversion_str) { fprintf(stderr, _("%s: could not get server version\n"), progname); exit(1); } server_version = parse_version(remoteversion_str); if (server_version < 0) { fprintf(stderr, _("%s: could not parse server version \"%s\"\n"), progname, remoteversion_str); exit(1); } my_version = parse_version(PG_VERSION); if (my_version < 0) { fprintf(stderr, _("%s: could not parse version \"%s\"\n"), progname, PG_VERSION); exit(1); } if (my_version != server_version && (server_version < 70000 /* we can handle back to 7.0 */ || server_version > my_version)) { fprintf(stderr, _("server version: %s; %s version: %s\n"), remoteversion_str, progname, PG_VERSION); if (ignoreVersion) fprintf(stderr, _("proceeding despite version mismatch\n")); else { fprintf(stderr, _("aborting because of version mismatch (Use the -i option to proceed anyway.)\n")); exit(1); } } /* * On 7.3 and later, make sure we are not fooled by non-system schemas in * the search path. */ if (server_version >= 70300) executeCommand(conn, "SET search_path = pg_catalog"); return conn; }
int main(int argc, char *argv[]) { static struct option long_options[] = { {"host", required_argument, NULL, 'h'}, {"port", required_argument, NULL, 'p'}, {"username", required_argument, NULL, 'U'}, {"no-password", no_argument, NULL, 'w'}, {"password", no_argument, NULL, 'W'}, {"echo", no_argument, NULL, 'e'}, {"createdb", no_argument, NULL, 'd'}, {"no-createdb", no_argument, NULL, 'D'}, {"superuser", no_argument, NULL, 's'}, {"no-superuser", no_argument, NULL, 'S'}, {"createrole", no_argument, NULL, 'r'}, {"no-createrole", no_argument, NULL, 'R'}, {"inherit", no_argument, NULL, 'i'}, {"no-inherit", no_argument, NULL, 'I'}, {"login", no_argument, NULL, 'l'}, {"no-login", no_argument, NULL, 'L'}, /* adduser is obsolete, undocumented spelling of superuser */ {"adduser", no_argument, NULL, 'a'}, {"no-adduser", no_argument, NULL, 'A'}, {"connection-limit", required_argument, NULL, 'c'}, {"pwprompt", no_argument, NULL, 'P'}, {"encrypted", no_argument, NULL, 'E'}, {"unencrypted", no_argument, NULL, 'N'}, {NULL, 0, NULL, 0} }; const char *progname; int optindex; int c; char* newuser = NULL; char* host = NULL; char* port = NULL; char* username = NULL; enum trivalue prompt_password = TRI_DEFAULT; bool echo = false; char* conn_limit = NULL; bool pwprompt = false; char* newpassword = NULL; /* Tri-valued variables. */ enum trivalue createdb = TRI_DEFAULT; enum trivalue superuser = TRI_DEFAULT; enum trivalue createrole = TRI_DEFAULT; enum trivalue inherit = TRI_DEFAULT; enum trivalue login = TRI_DEFAULT; enum trivalue encrypted = TRI_DEFAULT; struct pqbuf sql; PGconn* conn; PGresult* result; progname = get_progname(argv[0]); set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts")); handle_help_version_opts(argc, argv, "createuser", help); while ((c = getopt_long(argc, argv, "h:p:U:wWedDsSaArRiIlLc:PEN", long_options, &optindex)) != -1) { switch (c) { case 'h': host = optarg; break; case 'p': port = optarg; break; case 'U': username = optarg; break; case 'w': prompt_password = TRI_NO; break; case 'W': prompt_password = TRI_YES; break; case 'e': echo = true; break; case 'd': createdb = TRI_YES; break; case 'D': createdb = TRI_NO; break; case 's': case 'a': superuser = TRI_YES; break; case 'S': case 'A': superuser = TRI_NO; break; case 'r': createrole = TRI_YES; break; case 'R': createrole = TRI_NO; break; case 'i': inherit = TRI_YES; break; case 'I': inherit = TRI_NO; break; case 'l': login = TRI_YES; break; case 'L': login = TRI_NO; break; case 'c': conn_limit = optarg; break; case 'P': pwprompt = true; break; case 'E': encrypted = TRI_YES; break; case 'N': encrypted = TRI_NO; break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } switch (argc - optind) { case 0: break; case 1: newuser = argv[optind]; break; default: fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind + 1]); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } if (newuser == NULL) newuser = simple_prompt("Enter name of role to add: ", 128, true); if (pwprompt) { char* pw1; char* pw2; pw1 = simple_prompt("Enter password for new role: ", 100, false); pw2 = simple_prompt("Enter it again: ", 100, false); if (strcmp(pw1, pw2) != 0) { fprintf(stderr, _("Passwords didn't match.\n")); exit(1); } newpassword = pw1; free(pw2); } if (superuser == 0) { if (yesno_prompt("Shall the new role be a superuser?")) superuser = TRI_YES; else superuser = TRI_NO; } if (superuser == TRI_YES) { /* Not much point in trying to restrict a superuser */ createdb = TRI_YES; createrole = TRI_YES; } if (createdb == 0) { if (yesno_prompt("Shall the new role be allowed to create databases?")) createdb = TRI_YES; else createdb = TRI_NO; } if (createrole == 0) { if (yesno_prompt("Shall the new role be allowed to create more new roles?")) createrole = TRI_YES; else createrole = TRI_NO; } if (inherit == 0) inherit = TRI_YES; if (login == 0) login = TRI_YES; conn = connectDatabase("postgres", host, port, username, prompt_password, progname); init_pqbuf(&sql); print_pqbuf(&sql, "CREATE ROLE %s", fmtId(newuser)); if (newpassword) { if (encrypted == TRI_YES) append_pqbuf(&sql, " ENCRYPTED"); if (encrypted == TRI_NO) append_pqbuf(&sql, " UNENCRYPTED"); append_pqbuf(&sql, " PASSWORD "); if (encrypted != TRI_NO) { char* encrypted_password; encrypted_password = PQencryptPassword(newpassword, newuser); if (!encrypted_password) { fprintf(stderr, _("Password encryption failed.\n")); exit(1); } appendStringLiteralConn(&sql, encrypted_password, conn); PQfreemem(encrypted_password); } else { appendStringLiteralConn(&sql, newpassword, conn); } } if (superuser == TRI_YES) append_pqbuf(&sql, " SUPERUSER"); if (superuser == TRI_NO) append_pqbuf(&sql, " NOSUPERUSER"); if (createdb == TRI_YES) append_pqbuf(&sql, " CREATEDB"); if (createdb == TRI_NO) append_pqbuf(&sql, " NOCREATEDB"); if (createrole == TRI_YES) append_pqbuf(&sql, " CREATEROLE"); if (createrole == TRI_NO) append_pqbuf(&sql, " NOCREATEROLE"); if (inherit == TRI_YES) append_pqbuf(&sql, " INHERIT"); if (inherit == TRI_NO) append_pqbuf(&sql, " NOINHERIT"); if (login == TRI_YES) append_pqbuf(&sql, " LOGIN"); if (login == TRI_NO) append_pqbuf(&sql, " NOLOGIN"); if (conn_limit != NULL) append_pqbuf(&sql, " CONNECTION LIMIT %s", conn_limit); append_pqbuf(&sql, ";\n"); if (echo) printf("%s", sql.data); result = PQexec(conn, sql.data); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, _("%s: creation of new role failed: %s"), progname, PQerrorMessage(conn)); PQfinish(conn); exit(1); } PQclear(result); PQfinish(conn); exit(0); }