/* * SendQuery: send the query string to the backend * (and print out results) * * Note: This is the "front door" way to send a query. That is, use it to * send queries actually entered by the user. These queries will be subject to * single step mode. * To send "back door" queries (generated by slash commands, etc.) in a * controlled way, use PSQLexec(). * * Returns true if the query executed successfully, false otherwise. */ bool SendQuery(const char *query) { PGresult *results; TimevalStruct before, after; bool OK; if (!pset.db) { psql_error("You are currently not connected to a database.\n"); return false; } if (GetVariableBool(pset.vars, "SINGLESTEP")) { char buf[3]; printf(gettext("***(Single step mode: verify command)*******************************************\n" "%s\n" "***(press return to proceed or enter x and return to cancel)********************\n"), query); fflush(stdout); if (fgets(buf, sizeof(buf), stdin) != NULL) if (buf[0] == 'x') return false; } else if (VariableEquals(pset.vars, "ECHO", "queries")) { puts(query); fflush(stdout); } SetCancelConn(); if (PQtransactionStatus(pset.db) == PQTRANS_IDLE && !GetVariableBool(pset.vars, "AUTOCOMMIT") && !is_transact_command(query)) { results = PQexec(pset.db, "BEGIN"); if (PQresultStatus(results) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(pset.db)); PQclear(results); ResetCancelConn(); return false; } PQclear(results); } if (pset.timing) GETTIMEOFDAY(&before); results = PQexec(pset.db, query); /* these operations are included in the timing result: */ OK = (AcceptResult(results) && ProcessCopyResult(results)); if (pset.timing) GETTIMEOFDAY(&after); /* but printing results isn't: */ if (OK) OK = PrintQueryResults(results); PQclear(results); /* Possible microtiming output */ if (OK && pset.timing) printf(gettext("Time: %.3f ms\n"), DIFF_MSEC(&after, &before)); /* check for events that may occur during query execution */ if (pset.encoding != PQclientEncoding(pset.db) && PQclientEncoding(pset.db) >= 0) { /* track effects of SET CLIENT_ENCODING */ pset.encoding = PQclientEncoding(pset.db); pset.popt.topt.encoding = pset.encoding; SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding)); } PrintNotifications(); return OK; }
/* * Convert a string value to an SQL string literal and append it to * the given buffer. Encoding and string syntax rules are as indicated * by current settings of the PGconn. */ void appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn) { size_t length = strlen(str); /* * XXX This is a kluge to silence escape_string_warning in our utility * programs. It should go away someday. */ if (strchr(str, '\\') != NULL && PQserverVersion(conn) >= 80100) { /* ensure we are not adjacent to an identifier */ if (buf->len > 0 && buf->data[buf->len - 1] != ' ') appendPQExpBufferChar(buf, ' '); appendPQExpBufferChar(buf, ESCAPE_STRING_SYNTAX); appendStringLiteral(buf, str, PQclientEncoding(conn), false); return; } /* XXX end kluge */ if (!enlargePQExpBuffer(buf, 2 * length + 2)) return; appendPQExpBufferChar(buf, '\''); buf->len += PQescapeStringConn(conn, buf->data + buf->len, str, length, NULL); appendPQExpBufferChar(buf, '\''); }
bool authpgsql_connection::do_connect() { if (pgconn) { time_t t_check; time(&t_check); if (t_check < last_time) last_time=t_check; /* System clock changed */ if (t_check < last_time + 60) return true; last_time=t_check; if (PQstatus(pgconn) == CONNECTION_OK) return true; DPRINTF("authpgsql: PQstatus failed, connection lost"); PQfinish(pgconn); pgconn=0; } pgconn = PQconnectdb(config_file.connection.c_str()); if (PQstatus(pgconn) == CONNECTION_BAD) { err("PGSQL_CONNECTION could not be established"); err("%s", PQerrorMessage(pgconn)); PQfinish(pgconn); pgconn=0; return false; } if (!config_file.character_set.empty()) { PQsetClientEncoding(pgconn, config_file.character_set.c_str()); std::string real_character_set= pg_encoding_to_char(PQclientEncoding(pgconn)); if (config_file.character_set != real_character_set) { err("Cannot set character set to \"%s\"," " using \"%s\"\n", config_file.character_set.c_str(), real_character_set.c_str()); } else { DPRINTF("Using character set: %s", config_file.character_set.c_str()); } } return true; }
/* * SyncVariables * * Make psql's internal variables agree with connection state upon * establishing a new connection. */ void SyncVariables(void) { /* get stuff from connection */ pset.encoding = PQclientEncoding(pset.db); pset.popt.topt.encoding = pset.encoding; pset.sversion = PQserverVersion(pset.db); SetVariable(pset.vars, "DBNAME", PQdb(pset.db)); SetVariable(pset.vars, "USER", PQuser(pset.db)); SetVariable(pset.vars, "HOST", PQhost(pset.db)); SetVariable(pset.vars, "PORT", PQport(pset.db)); SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding)); /* send stuff to it, too */ PQsetErrorVerbosity(pset.db, pset.verbosity); }
/* * cmd_open: attempts to open a named connection to the database. * * Inputs: * cmd->argv[0]: connection name * * Returns: * either a properly filled error modret_t if a connection could not be * opened, or a simple non-error modret_t. * * Notes: * mod_sql depends on these semantics -- a backend should not open * a connection unless mod_sql requests it, nor close one unless * mod_sql requests it. Connection counting is *REQUIRED* for complete * compatibility; a connection should not be closed unless the count * reaches 0, and ideally will not need to be re-opened for counts > 1. */ MODRET cmd_open(cmd_rec *cmd) { conn_entry_t *entry = NULL; db_conn_t *conn = NULL; const char *server_version = NULL; sql_log(DEBUG_FUNC, "%s", "entering \tpostgres cmd_open"); _sql_check_cmd(cmd, "cmd_open" ); if (cmd->argc < 1) { sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open"); return PR_ERROR_MSG(cmd, MOD_SQL_POSTGRES_VERSION, "badly formed request"); } /* get the named connection */ if (!(entry = _sql_get_connection(cmd->argv[0]))) { sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open"); return PR_ERROR_MSG(cmd, MOD_SQL_POSTGRES_VERSION, "unknown named connection"); } conn = (db_conn_t *) entry->data; /* if we're already open (connections > 0) increment connections * reset our timer if we have one, and return HANDLED */ if (entry->connections > 0) { if (PQstatus(conn->postgres) == CONNECTION_OK) { entry->connections++; if (entry->timer) { pr_timer_reset(entry->timer, &sql_postgres_module); } sql_log(DEBUG_INFO, "connection '%s' count is now %d", entry->name, entry->connections); sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open"); return PR_HANDLED(cmd); } else { char *reason; size_t reason_len; /* Unless we've been told not to reconnect, try to reconnect now. * We only try once; if it fails, we return an error. */ if (!(pr_sql_opts & SQL_OPT_NO_RECONNECT)) { PQreset(conn->postgres); if (PQstatus(conn->postgres) == CONNECTION_OK) { entry->connections++; if (entry->timer) { pr_timer_reset(entry->timer, &sql_postgres_module); } sql_log(DEBUG_INFO, "connection '%s' count is now %d", entry->name, entry->connections); sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open"); return PR_HANDLED(cmd); } } reason = PQerrorMessage(conn->postgres); reason_len = strlen(reason); /* Postgres might give us an empty string as the reason; not helpful. */ if (reason_len == 0) { reason = "(unknown)"; reason_len = strlen(reason); } /* The error message returned by Postgres is usually appended with * a newline. Let's prettify it by removing the newline. Note * that yes, we are overwriting the pointer given to us by Postgres, * but it's OK. The Postgres docs say that we're not supposed to * free the memory associated with the returned string anyway. */ reason = pstrdup(session.pool, reason); if (reason[reason_len-1] == '\n') { reason[reason_len-1] = '\0'; reason_len--; } sql_log(DEBUG_INFO, "lost connection to database: %s", reason); entry->connections = 0; if (entry->timer) { pr_timer_remove(entry->timer, &sql_postgres_module); entry->timer = 0; } sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open"); return PR_ERROR_MSG(cmd, MOD_SQL_POSTGRES_VERSION, "lost connection to database"); } } /* make sure we have a new conn struct */ conn->postgres = PQconnectdb(conn->connectstring); if (PQstatus(conn->postgres) == CONNECTION_BAD) { /* if it didn't work, return an error */ sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open"); return _build_error( cmd, conn ); } #if defined(PG_VERSION_STR) sql_log(DEBUG_FUNC, "Postgres client: %s", PG_VERSION_STR); #endif server_version = PQparameterStatus(conn->postgres, "server_version"); if (server_version != NULL) { sql_log(DEBUG_FUNC, "Postgres server version: %s", server_version); } #ifdef PR_USE_NLS if (pr_encode_get_encoding() != NULL) { const char *encoding; encoding = get_postgres_encoding(pr_encode_get_encoding()); /* Configure the connection for the current local character set. */ if (PQsetClientEncoding(conn->postgres, encoding) < 0) { /* if it didn't work, return an error */ sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open"); return _build_error(cmd, conn); } sql_log(DEBUG_FUNC, "Postgres connection character set now '%s' " "(from '%s')", pg_encoding_to_char(PQclientEncoding(conn->postgres)), pr_encode_get_encoding()); } #endif /* !PR_USE_NLS */ /* bump connections */ entry->connections++; if (pr_sql_conn_policy == SQL_CONN_POLICY_PERSESSION) { /* If the connection policy is PERSESSION... */ if (entry->connections == 1) { /* ...and we are actually opening the first connection to the database; * we want to make sure this connection stays open, after this first use * (as per Bug#3290). To do this, we re-bump the connection count. */ entry->connections++; } } else if (entry->ttl > 0) { /* Set up our timer if necessary */ entry->timer = pr_timer_add(entry->ttl, -1, &sql_postgres_module, sql_timer_cb, "postgres connection ttl"); sql_log(DEBUG_INFO, "connection '%s' - %d second timer started", entry->name, entry->ttl); /* Timed connections get re-bumped so they don't go away when cmd_close * is called. */ entry->connections++; } /* return HANDLED */ sql_log(DEBUG_INFO, "connection '%s' opened", entry->name); sql_log(DEBUG_INFO, "connection '%s' count is now %d", entry->name, entry->connections); sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open"); return PR_HANDLED(cmd); }
/* * SendQuery: send the query string to the backend * (and print out results) * * Note: This is the "front door" way to send a query. That is, use it to * send queries actually entered by the user. These queries will be subject to * single step mode. * To send "back door" queries (generated by slash commands, etc.) in a * controlled way, use PSQLexec(). * * Returns true if the query executed successfully, false otherwise. */ bool SendQuery(const char *query) { PGresult *results; PGTransactionStatusType transaction_status; double elapsed_msec = 0; bool OK, on_error_rollback_savepoint = false; static bool on_error_rollback_warning = false; if (!pset.db) { psql_error("You are currently not connected to a database.\n"); return false; } if (pset.singlestep) { char buf[3]; printf(_("***(Single step mode: verify command)*******************************************\n" "%s\n" "***(press return to proceed or enter x and return to cancel)********************\n"), query); fflush(stdout); if (fgets(buf, sizeof(buf), stdin) != NULL) if (buf[0] == 'x') return false; } else if (pset.echo == PSQL_ECHO_QUERIES) { puts(query); fflush(stdout); } if (pset.logfile) { fprintf(pset.logfile, _("********* QUERY **********\n" "%s\n" "**************************\n\n"), query); fflush(pset.logfile); } SetCancelConn(); transaction_status = PQtransactionStatus(pset.db); if (transaction_status == PQTRANS_IDLE && !pset.autocommit && !command_no_begin(query)) { results = PQexec(pset.db, "BEGIN"); if (PQresultStatus(results) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(pset.db)); PQclear(results); ResetCancelConn(); return false; } PQclear(results); transaction_status = PQtransactionStatus(pset.db); } if (transaction_status == PQTRANS_INTRANS && pset.on_error_rollback != PSQL_ERROR_ROLLBACK_OFF && (pset.cur_cmd_interactive || pset.on_error_rollback == PSQL_ERROR_ROLLBACK_ON)) { if (on_error_rollback_warning == false && pset.sversion < 80000) { fprintf(stderr, _("The server (version %d.%d) does not support savepoints for ON_ERROR_ROLLBACK.\n"), pset.sversion / 10000, (pset.sversion / 100) % 100); on_error_rollback_warning = true; } else { results = PQexec(pset.db, "SAVEPOINT pg_psql_temporary_savepoint"); if (PQresultStatus(results) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(pset.db)); PQclear(results); ResetCancelConn(); return false; } PQclear(results); on_error_rollback_savepoint = true; } } if (pset.fetch_count <= 0 || !is_select_command(query)) { /* Default fetch-it-all-and-print mode */ instr_time before, after; if (pset.timing) INSTR_TIME_SET_CURRENT(before); results = PQexec(pset.db, query); /* these operations are included in the timing result: */ ResetCancelConn(); OK = (AcceptResult(results) && ProcessCopyResult(results)); if (pset.timing) { INSTR_TIME_SET_CURRENT(after); INSTR_TIME_SUBTRACT(after, before); elapsed_msec = INSTR_TIME_GET_MILLISEC(after); } /* but printing results isn't: */ if (OK) OK = PrintQueryResults(results); } else { /* Fetch-in-segments mode */ OK = ExecQueryUsingCursor(query, &elapsed_msec); ResetCancelConn(); results = NULL; /* PQclear(NULL) does nothing */ } /* If we made a temporary savepoint, possibly release/rollback */ if (on_error_rollback_savepoint) { const char *svptcmd; transaction_status = PQtransactionStatus(pset.db); if (transaction_status == PQTRANS_INERROR) { /* We always rollback on an error */ svptcmd = "ROLLBACK TO pg_psql_temporary_savepoint"; } else if (transaction_status != PQTRANS_INTRANS) { /* If they are no longer in a transaction, then do nothing */ svptcmd = NULL; } else { /* * Do nothing if they are messing with savepoints themselves: If * the user did RELEASE or ROLLBACK, our savepoint is gone. If * they issued a SAVEPOINT, releasing ours would remove theirs. */ if (results && (strcmp(PQcmdStatus(results), "SAVEPOINT") == 0 || strcmp(PQcmdStatus(results), "RELEASE") == 0 || strcmp(PQcmdStatus(results), "ROLLBACK") == 0)) svptcmd = NULL; else svptcmd = "RELEASE pg_psql_temporary_savepoint"; } if (svptcmd) { PGresult *svptres; svptres = PQexec(pset.db, svptcmd); if (PQresultStatus(svptres) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(pset.db)); PQclear(svptres); PQclear(results); ResetCancelConn(); return false; } PQclear(svptres); } } PQclear(results); /* Possible microtiming output */ if (OK && pset.timing) printf(_("Time: %.3f ms\n"), elapsed_msec); /* check for events that may occur during query execution */ if (pset.encoding != PQclientEncoding(pset.db) && PQclientEncoding(pset.db) >= 0) { /* track effects of SET CLIENT_ENCODING */ pset.encoding = PQclientEncoding(pset.db); pset.popt.topt.encoding = pset.encoding; SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding)); } PrintNotifications(); return OK; }
/* * 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; }
int main(int argc, char *argv[]) { static struct option long_options[] = { {"list", no_argument, NULL, 'l'}, {"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'}, {"dbname", required_argument, NULL, 'd'}, {"echo", no_argument, NULL, 'e'}, {NULL, 0, NULL, 0} }; const char *progname; int optindex; int c; bool listlangs = false; const char *dbname = NULL; char *host = NULL; char *port = NULL; char *username = NULL; enum trivalue prompt_password = TRI_DEFAULT; bool echo = false; char *langname = NULL; char *p; 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, "createlang", help); while ((c = getopt_long(argc, argv, "lh:p:U:wWd:e", long_options, &optindex)) != -1) { switch (c) { case 'l': listlangs = true; break; case 'h': host = pg_strdup(optarg); break; case 'p': port = pg_strdup(optarg); break; case 'U': username = pg_strdup(optarg); break; case 'w': prompt_password = TRI_NO; break; case 'W': prompt_password = TRI_YES; break; case 'd': dbname = pg_strdup(optarg); break; case 'e': echo = true; break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } /* * We set dbname from positional arguments if it is not already set by * option arguments -d. If not doing listlangs, positional dbname must * follow positional langname. */ if (argc - optind > 0) { if (listlangs) { if (dbname == NULL) dbname = argv[optind++]; } else { langname = argv[optind++]; if (argc - optind > 0 && dbname == NULL) dbname = argv[optind++]; } } if (argc - optind > 0) { fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } if (dbname == NULL) { if (getenv("PGDATABASE")) dbname = getenv("PGDATABASE"); else if (getenv("PGUSER")) dbname = getenv("PGUSER"); else dbname = get_user_name_or_exit(progname); } initPQExpBuffer(&sql); /* * List option */ if (listlangs) { printQueryOpt popt; static const bool translate_columns[] = {false, true}; conn = connectDatabase(dbname, host, port, username, NULL, prompt_password, progname, false); printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", " "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" " "FROM pg_catalog.pg_language WHERE lanispl;", gettext_noop("Name"), gettext_noop("yes"), gettext_noop("no"), gettext_noop("Trusted?")); result = executeQuery(conn, sql.data, progname, echo); memset(&popt, 0, sizeof(popt)); popt.topt.format = PRINT_ALIGNED; popt.topt.border = 1; popt.topt.start_table = true; popt.topt.stop_table = true; popt.topt.encoding = PQclientEncoding(conn); popt.title = _("Procedural Languages"); popt.translate_header = true; popt.translate_columns = translate_columns; popt.n_translate_columns = lengthof(translate_columns); printQuery(result, &popt, stdout, NULL); PQfinish(conn); exit(0); } if (langname == NULL) { fprintf(stderr, _("%s: missing required argument language name\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } /* lower case language name */ for (p = langname; *p; p++) if (*p >= 'A' && *p <= 'Z') *p += ('a' - 'A'); conn = connectDatabase(dbname, host, port, username, NULL, prompt_password, progname, false); /* * Make sure the language isn't already installed */ printfPQExpBuffer(&sql, "SELECT oid FROM pg_catalog.pg_language WHERE lanname = '%s';", langname); result = executeQuery(conn, sql.data, progname, echo); if (PQntuples(result) > 0) { PQfinish(conn); fprintf(stderr, _("%s: language \"%s\" is already installed in database \"%s\"\n"), progname, langname, dbname); /* separate exit status for "already installed" */ exit(2); } PQclear(result); /* * In 9.1 and up, assume that languages should be installed using CREATE * EXTENSION. However, it's possible this tool could be used against an * older server, and it's easy enough to continue supporting the old way. */ if (PQserverVersion(conn) >= 90100) printfPQExpBuffer(&sql, "CREATE EXTENSION \"%s\";", langname); else printfPQExpBuffer(&sql, "CREATE LANGUAGE \"%s\";", langname); if (echo) printf("%s\n", sql.data); result = PQexec(conn, sql.data); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, _("%s: language installation failed: %s"), progname, PQerrorMessage(conn)); PQfinish(conn); exit(1); } PQclear(result); PQfinish(conn); exit(0); }
int main(int argc, char *argv[]) { char *pghost = NULL; char *pgport = NULL; char *pguser = NULL; char *pgdb = NULL; char *use_role = NULL; enum trivalue prompt_password = TRI_DEFAULT; bool data_only = false; bool globals_only = false; bool output_clean = false; bool roles_only = false; bool tablespaces_only = false; bool schema_only = false; PGconn *conn; int encoding; const char *std_strings; int c, ret; int optindex; static struct option long_options[] = { {"data-only", no_argument, NULL, 'a'}, {"clean", no_argument, NULL, 'c'}, {"file", required_argument, NULL, 'f'}, {"globals-only", no_argument, NULL, 'g'}, {"host", required_argument, NULL, 'h'}, {"ignore-version", no_argument, NULL, 'i'}, {"database", required_argument, NULL, 'l'}, {"oids", no_argument, NULL, 'o'}, {"no-owner", no_argument, NULL, 'O'}, {"port", required_argument, NULL, 'p'}, {"roles-only", no_argument, NULL, 'r'}, {"schema-only", no_argument, NULL, 's'}, {"superuser", required_argument, NULL, 'S'}, {"tablespaces-only", no_argument, NULL, 't'}, {"username", required_argument, NULL, 'U'}, {"verbose", no_argument, NULL, 'v'}, {"no-password", no_argument, NULL, 'w'}, {"password", no_argument, NULL, 'W'}, {"no-privileges", no_argument, NULL, 'x'}, {"no-acl", no_argument, NULL, 'x'}, /* * the following options don't have an equivalent short option letter */ {"attribute-inserts", no_argument, &column_inserts, 1}, {"binary-upgrade", no_argument, &binary_upgrade, 1}, {"column-inserts", no_argument, &column_inserts, 1}, {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1}, {"disable-triggers", no_argument, &disable_triggers, 1}, {"inserts", no_argument, &inserts, 1}, {"lock-wait-timeout", required_argument, NULL, 2}, {"no-tablespaces", no_argument, &no_tablespaces, 1}, {"role", required_argument, NULL, 3}, {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, {NULL, 0, NULL, 0} }; set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump")); progname = get_progname(argv[0]); if (argc > 1) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { help(); exit(0); } if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) { puts("pg_dumpall (PostgreSQL) " PG_VERSION); exit(0); } } if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR, pg_dump_bin)) < 0) { char full_path[MAXPGPATH]; if (find_my_exec(argv[0], full_path) < 0) strlcpy(full_path, progname, sizeof(full_path)); if (ret == -1) fprintf(stderr, _("The program \"pg_dump\" is needed by %s " "but was not found in the\n" "same directory as \"%s\".\n" "Check your installation.\n"), progname, full_path); else fprintf(stderr, _("The program \"pg_dump\" was found by \"%s\"\n" "but was not the same version as %s.\n" "Check your installation.\n"), full_path, progname); exit(1); } pgdumpopts = createPQExpBuffer(); while ((c = getopt_long(argc, argv, "acf:gh:il:oOp:rsS:tU:vwWxX:", long_options, &optindex)) != -1) { switch (c) { case 'a': data_only = true; appendPQExpBuffer(pgdumpopts, " -a"); break; case 'c': output_clean = true; break; case 'f': filename = optarg; appendPQExpBuffer(pgdumpopts, " -f "); doShellQuoting(pgdumpopts, filename); break; case 'g': globals_only = true; break; case 'h': pghost = optarg; appendPQExpBuffer(pgdumpopts, " -h "); doShellQuoting(pgdumpopts, pghost); break; case 'i': /* ignored, deprecated option */ break; case 'l': pgdb = optarg; break; case 'o': appendPQExpBuffer(pgdumpopts, " -o"); break; case 'O': appendPQExpBuffer(pgdumpopts, " -O"); break; case 'p': pgport = optarg; appendPQExpBuffer(pgdumpopts, " -p "); doShellQuoting(pgdumpopts, pgport); break; case 'r': roles_only = true; break; case 's': schema_only = true; appendPQExpBuffer(pgdumpopts, " -s"); break; case 'S': appendPQExpBuffer(pgdumpopts, " -S "); doShellQuoting(pgdumpopts, optarg); break; case 't': tablespaces_only = true; break; case 'U': pguser = optarg; appendPQExpBuffer(pgdumpopts, " -U "); doShellQuoting(pgdumpopts, pguser); break; case 'v': verbose = true; appendPQExpBuffer(pgdumpopts, " -v"); break; case 'w': prompt_password = TRI_NO; appendPQExpBuffer(pgdumpopts, " -w"); break; case 'W': prompt_password = TRI_YES; appendPQExpBuffer(pgdumpopts, " -W"); break; case 'x': skip_acls = true; appendPQExpBuffer(pgdumpopts, " -x"); break; case 'X': /* -X is a deprecated alternative to long options */ if (strcmp(optarg, "disable-dollar-quoting") == 0) disable_dollar_quoting = 1; else if (strcmp(optarg, "disable-triggers") == 0) disable_triggers = 1; else if (strcmp(optarg, "no-tablespaces") == 0) no_tablespaces = 1; else if (strcmp(optarg, "use-set-session-authorization") == 0) use_setsessauth = 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: break; case 2: appendPQExpBuffer(pgdumpopts, " --lock-wait-timeout "); doShellQuoting(pgdumpopts, optarg); break; case 3: use_role = optarg; appendPQExpBuffer(pgdumpopts, " --role "); doShellQuoting(pgdumpopts, use_role); break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } /* Add long options to the pg_dump argument list */ if (binary_upgrade) appendPQExpBuffer(pgdumpopts, " --binary-upgrade"); if (column_inserts) appendPQExpBuffer(pgdumpopts, " --column-inserts"); if (disable_dollar_quoting) appendPQExpBuffer(pgdumpopts, " --disable-dollar-quoting"); if (disable_triggers) appendPQExpBuffer(pgdumpopts, " --disable-triggers"); if (inserts) appendPQExpBuffer(pgdumpopts, " --inserts"); if (no_tablespaces) appendPQExpBuffer(pgdumpopts, " --no-tablespaces"); if (use_setsessauth) appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization"); if (optind < argc) { fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } /* Make sure the user hasn't specified a mix of globals-only options */ if (globals_only && roles_only) { fprintf(stderr, _("%s: options -g/--globals-only and -r/--roles-only cannot be used together\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } if (globals_only && tablespaces_only) { fprintf(stderr, _("%s: options -g/--globals-only and -t/--tablespaces-only cannot be used together\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } if (roles_only && tablespaces_only) { fprintf(stderr, _("%s: options -r/--roles-only and -t/--tablespaces-only cannot be used together\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } /* * If there was a database specified on the command line, use that, * otherwise try to connect to database "postgres", and failing that * "template1". "postgres" is the preferred choice for 8.1 and later * servers, but it usually will not exist on older ones. */ if (pgdb) { conn = connectDatabase(pgdb, pghost, pgport, pguser, prompt_password, false); if (!conn) { fprintf(stderr, _("%s: could not connect to database \"%s\"\n"), progname, pgdb); exit(1); } } else { conn = connectDatabase("postgres", pghost, pgport, pguser, prompt_password, false); if (!conn) conn = connectDatabase("template1", pghost, pgport, pguser, prompt_password, true); if (!conn) { fprintf(stderr, _("%s: could not connect to databases \"postgres\" or \"template1\"\n" "Please specify an alternative database.\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } /* * Open the output file if required, otherwise use stdout */ if (filename) { OPF = fopen(filename, PG_BINARY_W); if (!OPF) { fprintf(stderr, _("%s: could not open the output file \"%s\": %s\n"), progname, filename, strerror(errno)); exit(1); } } else OPF = stdout; /* * Get the active encoding and the standard_conforming_strings setting, so * we know how to escape strings. */ encoding = PQclientEncoding(conn); std_strings = PQparameterStatus(conn, "standard_conforming_strings"); if (!std_strings) std_strings = "off"; /* Set the role if requested */ if (use_role && server_version >= 80100) { PQExpBuffer query = createPQExpBuffer(); appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role)); executeCommand(conn, query->data); destroyPQExpBuffer(query); } fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n"); if (verbose) dumpTimestamp("Started on"); fprintf(OPF, "\\connect postgres\n\n"); /* Replicate encoding and std_strings in output */ fprintf(OPF, "SET client_encoding = '%s';\n", pg_encoding_to_char(encoding)); fprintf(OPF, "SET standard_conforming_strings = %s;\n", std_strings); if (strcmp(std_strings, "off") == 0) fprintf(OPF, "SET escape_string_warning = off;\n"); fprintf(OPF, "\n"); if (!data_only) { /* * If asked to --clean, do that first. We can avoid detailed * dependency analysis because databases never depend on each other, * and tablespaces never depend on each other. Roles could have * grants to each other, but DROP ROLE will clean those up silently. */ if (output_clean) { if (!globals_only && !roles_only && !tablespaces_only) dropDBs(conn); if (!roles_only && !no_tablespaces) { if (server_version >= 80000) dropTablespaces(conn); } if (!tablespaces_only) dropRoles(conn); } /* * Now create objects as requested. Be careful that option logic here * is the same as for drops above. */ if (!tablespaces_only) { /* Dump roles (users) */ dumpRoles(conn); /* Dump role memberships --- need different method for pre-8.1 */ if (server_version >= 80100) dumpRoleMembership(conn); else dumpGroups(conn); } if (!roles_only && !no_tablespaces) { /* Dump tablespaces */ if (server_version >= 80000) dumpTablespaces(conn); } /* Dump CREATE DATABASE commands */ if (!globals_only && !roles_only && !tablespaces_only) dumpCreateDB(conn); /* Dump role/database settings */ if (!tablespaces_only && !roles_only) { if (server_version >= 90000) dumpDbRoleConfig(conn); } } if (!globals_only && !roles_only && !tablespaces_only) dumpDatabases(conn); PQfinish(conn); if (verbose) dumpTimestamp("Completed on"); fprintf(OPF, "--\n-- PostgreSQL database cluster dump complete\n--\n\n"); if (filename) fclose(OPF); exit(0); }
/* * vacuum_one_database * * Process tables in the given database. If the 'tables' list is empty, * process all tables in the database. * * Note that this function is only concerned with running exactly one stage * when in analyze-in-stages mode; caller must iterate on us if necessary. * * If concurrentCons is > 1, multiple connections are used to vacuum tables * in parallel. In this case and if the table list is empty, we first obtain * a list of tables from the database. */ static void vacuum_one_database(const char *dbname, vacuumingOptions *vacopts, int stage, SimpleStringList *tables, const char *host, const char *port, const char *username, enum trivalue prompt_password, int concurrentCons, const char *progname, bool echo, bool quiet) { PQExpBufferData sql; PQExpBufferData buf; PQExpBufferData catalog_query; PGresult *res; PGconn *conn; SimpleStringListCell *cell; ParallelSlot *slots; SimpleStringList dbtables = {NULL, NULL}; int i; int ntups; bool failed = false; bool parallel = concurrentCons > 1; bool tables_listed = false; bool has_where = false; const char *stage_commands[] = { "SET default_statistics_target=1; SET vacuum_cost_delay=0;", "SET default_statistics_target=10; RESET vacuum_cost_delay;", "RESET default_statistics_target;" }; const char *stage_messages[] = { gettext_noop("Generating minimal optimizer statistics (1 target)"), gettext_noop("Generating medium optimizer statistics (10 targets)"), gettext_noop("Generating default (full) optimizer statistics") }; Assert(stage == ANALYZE_NO_STAGE || (stage >= 0 && stage < ANALYZE_NUM_STAGES)); conn = connectDatabase(dbname, host, port, username, prompt_password, progname, echo, false, true); if (vacopts->disable_page_skipping && PQserverVersion(conn) < 90600) { PQfinish(conn); fprintf(stderr, _("%s: cannot use the \"%s\" option on server versions older than PostgreSQL 9.6\n"), progname, "disable-page-skipping"); exit(1); } if (vacopts->skip_locked && PQserverVersion(conn) < 120000) { PQfinish(conn); fprintf(stderr, _("%s: cannot use the \"%s\" option on server versions older than PostgreSQL 12\n"), progname, "skip-locked"); exit(1); } if (vacopts->min_xid_age != 0 && PQserverVersion(conn) < 90600) { fprintf(stderr, _("%s: cannot use the \"%s\" option on server versions older than PostgreSQL 9.6\n"), progname, "--min-xid-age"); exit(1); } if (vacopts->min_mxid_age != 0 && PQserverVersion(conn) < 90600) { fprintf(stderr, _("%s: cannot use the \"%s\" option on server versions older than PostgreSQL 9.6\n"), progname, "--min-mxid-age"); exit(1); } if (!quiet) { if (stage != ANALYZE_NO_STAGE) printf(_("%s: processing database \"%s\": %s\n"), progname, PQdb(conn), _(stage_messages[stage])); else printf(_("%s: vacuuming database \"%s\"\n"), progname, PQdb(conn)); fflush(stdout); } /* * Prepare the list of tables to process by querying the catalogs. * * Since we execute the constructed query with the default search_path * (which could be unsafe), everything in this query MUST be fully * qualified. * * First, build a WITH clause for the catalog query if any tables were * specified, with a set of values made of relation names and their * optional set of columns. This is used to match any provided column * lists with the generated qualified identifiers and to filter for the * tables provided via --table. If a listed table does not exist, the * catalog query will fail. */ initPQExpBuffer(&catalog_query); for (cell = tables ? tables->head : NULL; cell; cell = cell->next) { char *just_table; const char *just_columns; /* * Split relation and column names given by the user, this is used to * feed the CTE with values on which are performed pre-run validity * checks as well. For now these happen only on the relation name. */ splitTableColumnsSpec(cell->val, PQclientEncoding(conn), &just_table, &just_columns); if (!tables_listed) { appendPQExpBuffer(&catalog_query, "WITH listed_tables (table_oid, column_list) " "AS (\n VALUES ("); tables_listed = true; } else appendPQExpBuffer(&catalog_query, ",\n ("); appendStringLiteralConn(&catalog_query, just_table, conn); appendPQExpBuffer(&catalog_query, "::pg_catalog.regclass, "); if (just_columns && just_columns[0] != '\0') appendStringLiteralConn(&catalog_query, just_columns, conn); else appendPQExpBufferStr(&catalog_query, "NULL"); appendPQExpBufferStr(&catalog_query, "::pg_catalog.text)"); pg_free(just_table); } /* Finish formatting the CTE */ if (tables_listed) appendPQExpBuffer(&catalog_query, "\n)\n"); appendPQExpBuffer(&catalog_query, "SELECT c.relname, ns.nspname"); if (tables_listed) appendPQExpBuffer(&catalog_query, ", listed_tables.column_list"); appendPQExpBuffer(&catalog_query, " FROM pg_catalog.pg_class c\n" " JOIN pg_catalog.pg_namespace ns" " ON c.relnamespace OPERATOR(pg_catalog.=) ns.oid\n" " LEFT JOIN pg_catalog.pg_class t" " ON c.reltoastrelid OPERATOR(pg_catalog.=) t.oid\n"); /* Used to match the tables listed by the user */ if (tables_listed) appendPQExpBuffer(&catalog_query, " JOIN listed_tables" " ON listed_tables.table_oid OPERATOR(pg_catalog.=) c.oid\n"); /* * If no tables were listed, filter for the relevant relation types. If * tables were given via --table, don't bother filtering by relation type. * Instead, let the server decide whether a given relation can be * processed in which case the user will know about it. */ if (!tables_listed) { appendPQExpBuffer(&catalog_query, " WHERE c.relkind OPERATOR(pg_catalog.=) ANY (array[" CppAsString2(RELKIND_RELATION) ", " CppAsString2(RELKIND_MATVIEW) "])\n"); has_where = true; } /* * For --min-xid-age and --min-mxid-age, the age of the relation is the * greatest of the ages of the main relation and its associated TOAST * table. The commands generated by vacuumdb will also process the TOAST * table for the relation if necessary, so it does not need to be * considered separately. */ if (vacopts->min_xid_age != 0) { appendPQExpBuffer(&catalog_query, " %s GREATEST(pg_catalog.age(c.relfrozenxid)," " pg_catalog.age(t.relfrozenxid)) " " OPERATOR(pg_catalog.>=) '%d'::pg_catalog.int4\n" " AND c.relfrozenxid OPERATOR(pg_catalog.!=)" " '0'::pg_catalog.xid\n", has_where ? "AND" : "WHERE", vacopts->min_xid_age); has_where = true; } if (vacopts->min_mxid_age != 0) { appendPQExpBuffer(&catalog_query, " %s GREATEST(pg_catalog.mxid_age(c.relminmxid)," " pg_catalog.mxid_age(t.relminmxid)) OPERATOR(pg_catalog.>=)" " '%d'::pg_catalog.int4\n" " AND c.relminmxid OPERATOR(pg_catalog.!=)" " '0'::pg_catalog.xid\n", has_where ? "AND" : "WHERE", vacopts->min_mxid_age); has_where = true; } /* * Execute the catalog query. We use the default search_path for this * query for consistency with table lookups done elsewhere by the user. */ appendPQExpBuffer(&catalog_query, " ORDER BY c.relpages DESC;"); executeCommand(conn, "RESET search_path;", progname, echo); res = executeQuery(conn, catalog_query.data, progname, echo); termPQExpBuffer(&catalog_query); PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, progname, echo)); /* * If no rows are returned, there are no matching tables, so we are done. */ ntups = PQntuples(res); if (ntups == 0) { PQclear(res); PQfinish(conn); return; } /* * Build qualified identifiers for each table, including the column list * if given. */ initPQExpBuffer(&buf); for (i = 0; i < ntups; i++) { appendPQExpBufferStr(&buf, fmtQualifiedId(PQgetvalue(res, i, 1), PQgetvalue(res, i, 0))); if (tables_listed && !PQgetisnull(res, i, 2)) appendPQExpBufferStr(&buf, PQgetvalue(res, i, 2)); simple_string_list_append(&dbtables, buf.data); resetPQExpBuffer(&buf); } termPQExpBuffer(&buf); PQclear(res); /* * If there are more connections than vacuumable relations, we don't need * to use them all. */ if (parallel) { if (concurrentCons > ntups) concurrentCons = ntups; if (concurrentCons <= 1) parallel = false; } /* * Setup the database connections. We reuse the connection we already have * for the first slot. If not in parallel mode, the first slot in the * array contains the connection. */ if (concurrentCons <= 0) concurrentCons = 1; slots = (ParallelSlot *) pg_malloc(sizeof(ParallelSlot) * concurrentCons); init_slot(slots, conn); if (parallel) { for (i = 1; i < concurrentCons; i++) { conn = connectDatabase(dbname, host, port, username, prompt_password, progname, echo, false, true); init_slot(slots + i, conn); } } /* * Prepare all the connections to run the appropriate analyze stage, if * caller requested that mode. */ if (stage != ANALYZE_NO_STAGE) { int j; /* We already emitted the message above */ for (j = 0; j < concurrentCons; j++) executeCommand((slots + j)->connection, stage_commands[stage], progname, echo); } initPQExpBuffer(&sql); cell = dbtables.head; do { const char *tabname = cell->val; ParallelSlot *free_slot; if (CancelRequested) { failed = true; goto finish; } /* * Get the connection slot to use. If in parallel mode, here we wait * for one connection to become available if none already is. In * non-parallel mode we simply use the only slot we have, which we * know to be free. */ if (parallel) { /* * Get a free slot, waiting until one becomes free if none * currently is. */ free_slot = GetIdleSlot(slots, concurrentCons, progname); if (!free_slot) { failed = true; goto finish; } free_slot->isFree = false; } else free_slot = slots; prepare_vacuum_command(&sql, PQserverVersion(free_slot->connection), vacopts, tabname); /* * Execute the vacuum. If not in parallel mode, this terminates the * program in case of an error. (The parallel case handles query * errors in ProcessQueryResult through GetIdleSlot.) */ run_vacuum_command(free_slot->connection, sql.data, echo, tabname, progname, parallel); cell = cell->next; } while (cell != NULL); if (parallel) { int j; /* wait for all connections to finish */ for (j = 0; j < concurrentCons; j++) { if (!GetQueryResult((slots + j)->connection, progname)) goto finish; } } finish: for (i = 0; i < concurrentCons; i++) DisconnectDatabase(slots + i); pfree(slots); termPQExpBuffer(&sql); if (failed) exit(1); }
string CDBManager::GetClientEncoding() { int nEncoding = PQclientEncoding(m_pdbConnection); string strtmp = pg_encoding_to_char(nEncoding); return strtmp; }
int main(int argc, char *argv[]) { static struct option long_options[] = { {"list", no_argument, NULL, 'l'}, {"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'}, {"dbname", required_argument, NULL, 'd'}, {"echo", no_argument, NULL, 'e'}, {NULL, 0, NULL, 0} }; const char *progname; int optindex; int c; bool listlangs = false; const char *dbname = NULL; char *host = NULL; char *port = NULL; char *username = NULL; enum trivalue prompt_password = TRI_DEFAULT; bool echo = false; char *langname = NULL; char *p; 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, "droplang", help); while ((c = getopt_long(argc, argv, "lh:p:U:wWd:e", long_options, &optindex)) != -1) { switch (c) { case 'l': listlangs = true; break; case 'h': host = pg_strdup(optarg); break; case 'p': port = pg_strdup(optarg); break; case 'U': username = pg_strdup(optarg); break; case 'w': prompt_password = TRI_NO; break; case 'W': prompt_password = TRI_YES; break; case 'd': dbname = pg_strdup(optarg); break; case 'e': echo = true; break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } /* * We set dbname from positional arguments if it is not already set by * option arguments -d. If not doing listlangs, positional dbname must * follow positional langname. */ if (argc - optind > 0) { if (listlangs) { if (dbname == NULL) dbname = argv[optind++]; } else { langname = argv[optind++]; if (argc - optind > 0 && dbname == NULL) dbname = argv[optind++]; } } if (argc - optind > 0) { fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } if (dbname == NULL) { if (getenv("PGDATABASE")) dbname = getenv("PGDATABASE"); else if (getenv("PGUSER")) dbname = getenv("PGUSER"); else dbname = get_user_name(progname); } initPQExpBuffer(&sql); /* * List option */ if (listlangs) { printQueryOpt popt; static const bool translate_columns[] = {false, true}; conn = connectDatabase(dbname, host, port, username, prompt_password, progname, false); printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", " "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" " "FROM pg_catalog.pg_language WHERE lanispl;", gettext_noop("Name"), gettext_noop("yes"), gettext_noop("no"), gettext_noop("Trusted?")); result = executeQuery(conn, sql.data, progname, echo); memset(&popt, 0, sizeof(popt)); popt.topt.format = PRINT_ALIGNED; popt.topt.border = 1; popt.topt.start_table = true; popt.topt.stop_table = true; popt.topt.encoding = PQclientEncoding(conn); popt.title = _("Procedural Languages"); popt.translate_header = true; popt.translate_columns = translate_columns; printQuery(result, &popt, stdout, NULL); PQfinish(conn); exit(0); } if (langname == NULL) { fprintf(stderr, _("%s: missing required argument language name\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } /* lower case language name */ for (p = langname; *p; p++) if (*p >= 'A' && *p <= 'Z') *p += ('a' - 'A'); conn = connectDatabase(dbname, host, port, username, prompt_password, progname, false); /* * Force schema search path to be just pg_catalog, so that we don't have * to be paranoid about search paths below. */ executeCommand(conn, "SET search_path = pg_catalog;", progname, echo); /* * Make sure the language is installed */ printfPQExpBuffer(&sql, "SELECT oid " "FROM pg_language WHERE lanname = '%s' AND lanispl;", langname); result = executeQuery(conn, sql.data, progname, echo); if (PQntuples(result) == 0) { PQfinish(conn); fprintf(stderr, _("%s: language \"%s\" is not installed in " "database \"%s\"\n"), progname, langname, dbname); exit(1); } PQclear(result); /* * Attempt to drop the language. We do not use CASCADE, so that the drop * will fail if there are any functions in the language. */ printfPQExpBuffer(&sql, "DROP EXTENSION \"%s\";\n", langname); if (echo) printf("%s", sql.data); result = PQexec(conn, sql.data); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, _("%s: language removal failed: %s"), progname, PQerrorMessage(conn)); PQfinish(conn); exit(1); } PQclear(result); PQfinish(conn); exit(0); }
/* * Get the client encoding of the specified connection handle and return it as a rb_encoding. */ rb_encoding * pg_conn_enc_get( PGconn *conn ) { int enc_id = PQclientEncoding( conn ); return pg_get_pg_encoding_as_rb_encoding( enc_id ); }
/* * SendQuery: send the query string to the backend * (and print out results) * * Note: This is the "front door" way to send a query. That is, use it to * send queries actually entered by the user. These queries will be subject to * single step mode. * To send "back door" queries (generated by slash commands, etc.) in a * controlled way, use PSQLexec(). * * Returns true if the query executed successfully, false otherwise. */ bool SendQuery(const char *query) { PGresult *results; PGTransactionStatusType transaction_status; double elapsed_msec = 0; bool OK = false; int i; bool on_error_rollback_savepoint = false; static bool on_error_rollback_warning = false; if (!pset.db) { psql_error("You are currently not connected to a database.\n"); goto sendquery_cleanup; } if (pset.singlestep) { char buf[3]; fflush(stderr); printf(_("***(Single step mode: verify command)*******************************************\n" "%s\n" "***(press return to proceed or enter x and return to cancel)********************\n"), query); fflush(stdout); if (fgets(buf, sizeof(buf), stdin) != NULL) if (buf[0] == 'x') goto sendquery_cleanup; if (cancel_pressed) goto sendquery_cleanup; } else if (pset.echo == PSQL_ECHO_QUERIES) { puts(query); fflush(stdout); } if (pset.logfile) { fprintf(pset.logfile, _("********* QUERY **********\n" "%s\n" "**************************\n\n"), query); fflush(pset.logfile); } SetCancelConn(); transaction_status = PQtransactionStatus(pset.db); if (transaction_status == PQTRANS_IDLE && !pset.autocommit && !command_no_begin(query)) { results = PQexec(pset.db, "BEGIN"); if (PQresultStatus(results) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(pset.db)); ClearOrSaveResult(results); ResetCancelConn(); goto sendquery_cleanup; } ClearOrSaveResult(results); transaction_status = PQtransactionStatus(pset.db); } if (transaction_status == PQTRANS_INTRANS && pset.on_error_rollback != PSQL_ERROR_ROLLBACK_OFF && (pset.cur_cmd_interactive || pset.on_error_rollback == PSQL_ERROR_ROLLBACK_ON)) { if (on_error_rollback_warning == false && pset.sversion < 80000) { char sverbuf[32]; psql_error("The server (version %s) does not support savepoints for ON_ERROR_ROLLBACK.\n", formatPGVersionNumber(pset.sversion, false, sverbuf, sizeof(sverbuf))); on_error_rollback_warning = true; } else { results = PQexec(pset.db, "SAVEPOINT pg_psql_temporary_savepoint"); if (PQresultStatus(results) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(pset.db)); ClearOrSaveResult(results); ResetCancelConn(); goto sendquery_cleanup; } ClearOrSaveResult(results); on_error_rollback_savepoint = true; } } if (pset.fetch_count <= 0 || pset.gexec_flag || pset.crosstab_flag || !is_select_command(query)) { /* Default fetch-it-all-and-print mode */ instr_time before, after; if (pset.timing) INSTR_TIME_SET_CURRENT(before); results = PQexec(pset.db, query); /* these operations are included in the timing result: */ ResetCancelConn(); OK = ProcessResult(&results); if (pset.timing) { INSTR_TIME_SET_CURRENT(after); INSTR_TIME_SUBTRACT(after, before); elapsed_msec = INSTR_TIME_GET_MILLISEC(after); } /* but printing results isn't: */ if (OK && results) OK = PrintQueryResults(results); } else { /* Fetch-in-segments mode */ OK = ExecQueryUsingCursor(query, &elapsed_msec); ResetCancelConn(); results = NULL; /* PQclear(NULL) does nothing */ } if (!OK && pset.echo == PSQL_ECHO_ERRORS) psql_error("STATEMENT: %s\n", query); /* If we made a temporary savepoint, possibly release/rollback */ if (on_error_rollback_savepoint) { const char *svptcmd = NULL; transaction_status = PQtransactionStatus(pset.db); switch (transaction_status) { case PQTRANS_INERROR: /* We always rollback on an error */ svptcmd = "ROLLBACK TO pg_psql_temporary_savepoint"; break; case PQTRANS_IDLE: /* If they are no longer in a transaction, then do nothing */ break; case PQTRANS_INTRANS: /* * Do nothing if they are messing with savepoints themselves: * If the user did RELEASE or ROLLBACK, our savepoint is gone. * If they issued a SAVEPOINT, releasing ours would remove * theirs. */ if (results && (strcmp(PQcmdStatus(results), "SAVEPOINT") == 0 || strcmp(PQcmdStatus(results), "RELEASE") == 0 || strcmp(PQcmdStatus(results), "ROLLBACK") == 0)) svptcmd = NULL; else svptcmd = "RELEASE pg_psql_temporary_savepoint"; break; case PQTRANS_ACTIVE: case PQTRANS_UNKNOWN: default: OK = false; /* PQTRANS_UNKNOWN is expected given a broken connection. */ if (transaction_status != PQTRANS_UNKNOWN || ConnectionUp()) psql_error("unexpected transaction status (%d)\n", transaction_status); break; } if (svptcmd) { PGresult *svptres; svptres = PQexec(pset.db, svptcmd); if (PQresultStatus(svptres) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(pset.db)); ClearOrSaveResult(svptres); OK = false; PQclear(results); ResetCancelConn(); goto sendquery_cleanup; } PQclear(svptres); } } ClearOrSaveResult(results); /* Possible microtiming output */ if (pset.timing) printf(_("Time: %.3f ms\n"), elapsed_msec); /* check for events that may occur during query execution */ if (pset.encoding != PQclientEncoding(pset.db) && PQclientEncoding(pset.db) >= 0) { /* track effects of SET CLIENT_ENCODING */ pset.encoding = PQclientEncoding(pset.db); pset.popt.topt.encoding = pset.encoding; SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding)); } PrintNotifications(); /* perform cleanup that should occur after any attempted query */ sendquery_cleanup: /* reset \g's output-to-filename trigger */ if (pset.gfname) { free(pset.gfname); pset.gfname = NULL; } /* reset \gset trigger */ if (pset.gset_prefix) { free(pset.gset_prefix); pset.gset_prefix = NULL; } /* reset \gexec trigger */ pset.gexec_flag = false; /* reset \crosstabview trigger */ pset.crosstab_flag = false; for (i = 0; i < lengthof(pset.ctv_args); i++) { pg_free(pset.ctv_args[i]); pset.ctv_args[i] = NULL; } return OK; }
int main(int argc, char *argv[]) { static struct option long_options[] = { {"list", no_argument, NULL, 'l'}, {"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'}, {"dbname", required_argument, NULL, 'd'}, {"echo", no_argument, NULL, 'e'}, {NULL, 0, NULL, 0} }; const char *progname; int optindex; int c; bool listlangs = false; const char *dbname = NULL; char *host = NULL; char *port = NULL; char *username = NULL; enum trivalue prompt_password = TRI_DEFAULT; bool echo = false; char *langname = NULL; char *p; Oid lanplcallfoid; Oid laninline; Oid lanvalidator; char *handler; char *inline_handler; char *validator; char *handler_ns; char *inline_ns; char *validator_ns; bool keephandler; bool keepinline; bool keepvalidator; 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, "droplang", help); while ((c = getopt_long(argc, argv, "lh:p:U:wWd:e", long_options, &optindex)) != -1) { switch (c) { case 'l': listlangs = true; break; 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 'd': dbname = optarg; break; case 'e': echo = true; break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } if (argc - optind > 0) { if (listlangs) dbname = argv[optind++]; else { langname = argv[optind++]; if (argc - optind > 0) dbname = argv[optind++]; } } if (argc - optind > 0) { fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } if (dbname == NULL) { if (getenv("PGDATABASE")) dbname = getenv("PGDATABASE"); else if (getenv("PGUSER")) dbname = getenv("PGUSER"); else dbname = get_user_name(progname); } initPQExpBuffer(&sql); /* * List option */ if (listlangs) { printQueryOpt popt; static const bool translate_columns[] = {false, true}; conn = connectDatabase(dbname, host, port, username, prompt_password, progname); printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", " "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" " "FROM pg_catalog.pg_language WHERE lanispl;", gettext_noop("Name"), gettext_noop("yes"), gettext_noop("no"), gettext_noop("Trusted?")); result = executeQuery(conn, sql.data, progname, echo); memset(&popt, 0, sizeof(popt)); popt.topt.format = PRINT_ALIGNED; popt.topt.border = 1; popt.topt.start_table = true; popt.topt.stop_table = true; popt.topt.encoding = PQclientEncoding(conn); popt.title = _("Procedural Languages"); popt.translate_header = true; popt.translate_columns = translate_columns; printQuery(result, &popt, stdout, NULL); PQfinish(conn); exit(0); } if (langname == NULL) { fprintf(stderr, _("%s: missing required argument language name\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } for (p = langname; *p; p++) if (*p >= 'A' && *p <= 'Z') *p += ('a' - 'A'); conn = connectDatabase(dbname, host, port, username, prompt_password, progname); /* * Force schema search path to be just pg_catalog, so that we don't have * to be paranoid about search paths below. */ executeCommand(conn, "SET search_path = pg_catalog;", progname, echo); /* * Make sure the language is installed and find the OIDs of the language * support functions */ printfPQExpBuffer(&sql, "SELECT lanplcallfoid, laninline, lanvalidator " "FROM pg_language WHERE lanname = '%s' AND lanispl;", langname); result = executeQuery(conn, sql.data, progname, echo); if (PQntuples(result) == 0) { PQfinish(conn); fprintf(stderr, _("%s: language \"%s\" is not installed in " "database \"%s\"\n"), progname, langname, dbname); exit(1); } lanplcallfoid = atooid(PQgetvalue(result, 0, 0)); laninline = atooid(PQgetvalue(result, 0, 1)); lanvalidator = atooid(PQgetvalue(result, 0, 2)); PQclear(result); /* * Check that there are no functions left defined in that language */ printfPQExpBuffer(&sql, "SELECT count(proname) FROM pg_proc P, " "pg_language L WHERE P.prolang = L.oid " "AND L.lanname = '%s';", langname); result = executeQuery(conn, sql.data, progname, echo); if (strcmp(PQgetvalue(result, 0, 0), "0") != 0) { PQfinish(conn); fprintf(stderr, _("%s: still %s functions declared in language \"%s\"; " "language not removed\n"), progname, PQgetvalue(result, 0, 0), langname); exit(1); } PQclear(result); /* * Check that the handler function isn't used by some other language */ printfPQExpBuffer(&sql, "SELECT count(*) FROM pg_language " "WHERE lanplcallfoid = %u AND lanname <> '%s';", lanplcallfoid, langname); result = executeQuery(conn, sql.data, progname, echo); if (strcmp(PQgetvalue(result, 0, 0), "0") == 0) keephandler = false; else keephandler = true; PQclear(result); /* * Find the handler name */ if (!keephandler) { printfPQExpBuffer(&sql, "SELECT proname, (SELECT nspname " "FROM pg_namespace ns WHERE ns.oid = pronamespace) " "AS prons FROM pg_proc WHERE oid = %u;", lanplcallfoid); result = executeQuery(conn, sql.data, progname, echo); handler = strdup(PQgetvalue(result, 0, 0)); handler_ns = strdup(PQgetvalue(result, 0, 1)); PQclear(result); } else { handler = NULL; handler_ns = NULL; } /* * Check that the inline function isn't used by some other language */ if (OidIsValid(laninline)) { printfPQExpBuffer(&sql, "SELECT count(*) FROM pg_language " "WHERE laninline = %u AND lanname <> '%s';", laninline, langname); result = executeQuery(conn, sql.data, progname, echo); if (strcmp(PQgetvalue(result, 0, 0), "0") == 0) keepinline = false; else keepinline = true; PQclear(result); } else keepinline = true; /* don't try to delete it */ /* * Find the inline handler name */ if (!keepinline) { printfPQExpBuffer(&sql, "SELECT proname, (SELECT nspname " "FROM pg_namespace ns WHERE ns.oid = pronamespace) " "AS prons FROM pg_proc WHERE oid = %u;", laninline); result = executeQuery(conn, sql.data, progname, echo); inline_handler = strdup(PQgetvalue(result, 0, 0)); inline_ns = strdup(PQgetvalue(result, 0, 1)); PQclear(result); } else { inline_handler = NULL; inline_ns = NULL; } /* * Check that the validator function isn't used by some other language */ if (OidIsValid(lanvalidator)) { printfPQExpBuffer(&sql, "SELECT count(*) FROM pg_language " "WHERE lanvalidator = %u AND lanname <> '%s';", lanvalidator, langname); result = executeQuery(conn, sql.data, progname, echo); if (strcmp(PQgetvalue(result, 0, 0), "0") == 0) keepvalidator = false; else keepvalidator = true; PQclear(result); } else keepvalidator = true; /* don't try to delete it */ /* * Find the validator name */ if (!keepvalidator) { printfPQExpBuffer(&sql, "SELECT proname, (SELECT nspname " "FROM pg_namespace ns WHERE ns.oid = pronamespace) " "AS prons FROM pg_proc WHERE oid = %u;", lanvalidator); result = executeQuery(conn, sql.data, progname, echo); validator = strdup(PQgetvalue(result, 0, 0)); validator_ns = strdup(PQgetvalue(result, 0, 1)); PQclear(result); } else { validator = NULL; validator_ns = NULL; } /* * Drop the language and the functions */ printfPQExpBuffer(&sql, "DROP LANGUAGE \"%s\";\n", langname); if (!keephandler) appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" ();\n", handler_ns, handler); if (!keepinline) appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" (internal);\n", inline_ns, inline_handler); if (!keepvalidator) appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" (oid);\n", validator_ns, validator); if (echo) printf("%s", sql.data); result = PQexec(conn, sql.data); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, _("%s: language removal failed: %s"), progname, PQerrorMessage(conn)); PQfinish(conn); exit(1); } PQclear(result); PQfinish(conn); exit(0); }
int main(int argc, char *argv[]) { char *pghost = NULL; char *pgport = NULL; char *pguser = NULL; char *pgdb = NULL; enum trivalue prompt_password = TRI_DEFAULT; bool data_only = false; bool globals_only = false; bool schema_only = false; static int gp_migrator = 0; bool gp_syntax = false; bool no_gp_syntax = false; PGconn *conn; int encoding; const char *std_strings; int c, ret; static struct option long_options[] = { {"data-only", no_argument, NULL, 'a'}, {"clean", no_argument, NULL, 'c'}, {"inserts", no_argument, NULL, 'd'}, {"attribute-inserts", no_argument, NULL, 'D'}, {"column-inserts", no_argument, NULL, 'D'}, {"file", required_argument, NULL, 'f'}, {"globals-only", no_argument, NULL, 'g'}, {"host", required_argument, NULL, 'h'}, {"ignore-version", no_argument, NULL, 'i'}, {"database", required_argument, NULL, 'l'}, {"oids", no_argument, NULL, 'o'}, {"no-owner", no_argument, NULL, 'O'}, {"port", required_argument, NULL, 'p'}, {"schema-only", no_argument, NULL, 's'}, {"superuser", required_argument, NULL, 'S'}, {"username", required_argument, NULL, 'U'}, {"verbose", no_argument, NULL, 'v'}, {"no-password", no_argument, NULL, 'w'}, {"password", no_argument, NULL, 'W'}, {"no-privileges", no_argument, NULL, 'x'}, {"no-acl", no_argument, NULL, 'x'}, {"resource-queues", no_argument, NULL, 'r'}, {"filespaces", no_argument, NULL, 'F'}, /* * the following options don't have an equivalent short option letter */ {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1}, {"disable-triggers", no_argument, &disable_triggers, 1}, {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, /* START MPP ADDITION */ {"gp-syntax", no_argument, NULL, 1}, {"no-gp-syntax", no_argument, NULL, 2}, {"gp-migrator", no_argument, &gp_migrator, 1}, /* END MPP ADDITION */ {NULL, 0, NULL, 0} }; int optindex; set_pglocale_pgservice(argv[0], "pg_dump"); progname = get_progname(argv[0]); if (argc > 1) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { help(); exit(0); } if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) { puts("pg_dumpall (PostgreSQL) " PG_VERSION); exit(0); } } if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR, pg_dump_bin)) < 0) { char full_path[MAXPGPATH]; if (find_my_exec(argv[0], full_path) < 0) strlcpy(full_path, progname, sizeof(full_path)); if (ret == -1) fprintf(stderr, _("The program \"pg_dump\" is needed by %s " "but was not found in the\n" "same directory as \"%s\".\n" "Check your installation.\n"), progname, full_path); else fprintf(stderr, _("The program \"pg_dump\" was found by \"%s\"\n" "but was not the same version as %s.\n" "Check your installation.\n"), full_path, progname); exit(1); } pgdumpopts = createPQExpBuffer(); while ((c = getopt_long(argc, argv, "acdDf:Fgh:il:oOp:rsS:U:vwWxX:", long_options, &optindex)) != -1) { switch (c) { case 'a': data_only = true; appendPQExpBuffer(pgdumpopts, " -a"); break; case 'c': output_clean = true; break; case 'd': case 'D': appendPQExpBuffer(pgdumpopts, " -%c", c); break; case 'f': filename = optarg; #ifndef WIN32 appendPQExpBuffer(pgdumpopts, " -f '%s'", filename); #else appendPQExpBuffer(pgdumpopts, " -f \"%s\"", filename); #endif break; case 'g': globals_only = true; break; case 'h': pghost = optarg; #ifndef WIN32 appendPQExpBuffer(pgdumpopts, " -h '%s'", pghost); #else appendPQExpBuffer(pgdumpopts, " -h \"%s\"", pghost); #endif break; case 'i': /* ignored, deprecated option */ break; case 'l': pgdb = optarg; break; case 'o': appendPQExpBuffer(pgdumpopts, " -o"); break; case 'O': appendPQExpBuffer(pgdumpopts, " -O"); break; case 'p': pgport = optarg; #ifndef WIN32 appendPQExpBuffer(pgdumpopts, " -p '%s'", pgport); #else appendPQExpBuffer(pgdumpopts, " -p \"%s\"", pgport); #endif break; case 'r': resource_queues = true; break; case 'F': filespaces = true; break; case 's': schema_only = true; appendPQExpBuffer(pgdumpopts, " -s"); break; case 'S': #ifndef WIN32 appendPQExpBuffer(pgdumpopts, " -S '%s'", optarg); #else appendPQExpBuffer(pgdumpopts, " -S \"%s\"", optarg); #endif break; case 'U': pguser = optarg; #ifndef WIN32 appendPQExpBuffer(pgdumpopts, " -U '%s'", pguser); #else appendPQExpBuffer(pgdumpopts, " -U \"%s\"", pguser); #endif break; case 'v': verbose = true; appendPQExpBuffer(pgdumpopts, " -v"); break; case 'w': prompt_password = TRI_NO; appendPQExpBuffer(pgdumpopts, " -w"); break; case 'W': prompt_password = TRI_YES; appendPQExpBuffer(pgdumpopts, " -W"); break; case 'x': skip_acls = true; appendPQExpBuffer(pgdumpopts, " -x"); break; case 'X': /* -X is a deprecated alternative to long options */ if (strcmp(optarg, "disable-dollar-quoting") == 0) appendPQExpBuffer(pgdumpopts, " --disable-dollar-quoting"); else if (strcmp(optarg, "disable-triggers") == 0) appendPQExpBuffer(pgdumpopts, " --disable-triggers"); else if (strcmp(optarg, "use-set-session-authorization") == 0) /* no-op, still allowed for compatibility */ ; 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: break; /* START MPP ADDITION */ case 1: /* gp-format */ appendPQExpBuffer(pgdumpopts, " --gp-syntax"); gp_syntax = true; resource_queues = true; /* -r is implied by --gp-syntax */ break; case 2: /* no-gp-format */ appendPQExpBuffer(pgdumpopts, " --no-gp-syntax"); no_gp_syntax = true; break; /* END MPP ADDITION */ default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } /* Add long options to the pg_dump argument list */ if (disable_dollar_quoting) appendPQExpBuffer(pgdumpopts, " --disable-dollar-quoting"); if (disable_triggers) appendPQExpBuffer(pgdumpopts, " --disable-triggers"); if (use_setsessauth) appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization"); /* Complain if any arguments remain */ if (optind < argc) { fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } if (gp_syntax && no_gp_syntax) { fprintf(stderr, _("%s: options \"--gp-syntax\" and \"--no-gp-syntax\" cannot be used together\n"), progname); exit(1); } /* * If there was a database specified on the command line, use that, * otherwise try to connect to database "postgres", and failing that * "template1". "postgres" is the preferred choice for 8.1 and later * servers, but it usually will not exist on older ones. */ if (pgdb) { conn = connectDatabase(pgdb, pghost, pgport, pguser, prompt_password, false); if (!conn) { fprintf(stderr, _("%s: could not connect to database \"%s\"\n"), progname, pgdb); exit(1); } } else { conn = connectDatabase("postgres", pghost, pgport, pguser, prompt_password, false); if (!conn) conn = connectDatabase("template1", pghost, pgport, pguser, prompt_password, true); if (!conn) { fprintf(stderr, _("%s: could not connect to databases \"postgres\" or \"template1\"\n" "Please specify an alternative database.\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } /* * Open the output file if required, otherwise use stdout */ if (filename) { OPF = fopen(filename, PG_BINARY_W); if (!OPF) { fprintf(stderr, _("%s: could not open the output file \"%s\": %s\n"), progname, filename, strerror(errno)); exit(1); } } else OPF = stdout; /* * Get the active encoding and the standard_conforming_strings setting, so * we know how to escape strings. */ encoding = PQclientEncoding(conn); std_strings = PQparameterStatus(conn, "standard_conforming_strings"); if (!std_strings) std_strings = "off"; fprintf(OPF,"--\n-- Greenplum Database cluster dump\n--\n\n"); if (verbose) dumpTimestamp("Started on"); fprintf(OPF, "\\connect postgres\n\n"); if (!data_only) { /* Replicate encoding and std_strings in output */ fprintf(OPF, "SET client_encoding = '%s';\n", pg_encoding_to_char(encoding)); fprintf(OPF, "SET standard_conforming_strings = %s;\n", std_strings); if (strcmp(std_strings, "off") == 0) fprintf(OPF, "SET escape_string_warning = 'off';\n"); fprintf(OPF, "\n"); /* Dump Resource Queues */ if (resource_queues) dumpResQueues(conn); /* Dump roles (users) */ dumpRoles(conn); /* Dump role memberships */ dumpRoleMembership(conn); /* Dump role constraints */ dumpRoleConstraints(conn); /* Dump filespaces and tablespaces */ if (filespaces) { dumpFilespaces(conn); dumpTablespaces(conn); } /* Dump CREATE DATABASE commands */ if (!globals_only) dumpCreateDB(conn); } if (!globals_only) dumpDatabases(conn); PQfinish(conn); if (verbose) dumpTimestamp("Completed on"); fprintf(OPF, "--\n-- PostgreSQL database cluster dump complete\n--\n\n"); if (filename) fclose(OPF); exit(0); }
/** * @brief Performs data loading. * * Invokes pg_bulkload() user-defined function with given parameters * in single transaction. * * @return exitcode (always 0). */ static int LoaderLoadMain(List *options) { PGresult *res; const char *params[1]; StringInfoData buf; int encoding; int errors; ListCell *cell; if (options == NIL) ereport(ERROR, (errcode(EXIT_FAILURE), errmsg("requires control file or command line options"))); initStringInfo(&buf); reconnect(ERROR); encoding = PQclientEncoding(connection); elog(NOTICE, "BULK LOAD START"); /* form options as text[] */ appendStringInfoString(&buf, "{\""); foreach (cell, options) { const char *item = lfirst(cell); if (buf.len > 2) appendStringInfoString(&buf, "\",\""); /* escape " and \ */ while (*item) { if (*item == '"' || *item == '\\') { appendStringInfoChar(&buf, '\\'); appendStringInfoChar(&buf, *item); item++; } else if (!IS_HIGHBIT_SET(*item)) { appendStringInfoChar(&buf, *item); item++; } else { int n = PQmblen(item, encoding); appendBinaryStringInfo(&buf, item, n); item += n; } } } appendStringInfoString(&buf, "\"}"); command("BEGIN", 0, NULL); params[0] = buf.data; res = execute("SELECT * FROM pg_bulkload($1)", 1, params); if (PQresultStatus(res) == PGRES_COPY_IN) { PQclear(res); res = RemoteLoad(connection, stdin, type_binary); if (PQresultStatus(res) != PGRES_TUPLES_OK) elog(ERROR, "copy failed: %s", PQerrorMessage(connection)); } command("COMMIT", 0, NULL); errors = atoi(PQgetvalue(res, 0, 2)) + /* parse errors */ atoi(PQgetvalue(res, 0, 3)); /* duplicate errors */ elog(NOTICE, "BULK LOAD END\n" "\t%s Rows skipped.\n" "\t%s Rows successfully loaded.\n" "\t%s Rows not loaded due to parse errors.\n" "\t%s Rows not loaded due to duplicate errors.\n" "\t%s Rows replaced with new rows.", PQgetvalue(res, 0, 0), PQgetvalue(res, 0, 1), PQgetvalue(res, 0, 2), PQgetvalue(res, 0, 3), PQgetvalue(res, 0, 4)); PQclear(res); disconnect(); termStringInfo(&buf); if (errors > 0) { elog(WARNING, "some rows were not loaded due to errors."); return E_PG_USER; } else return 0; /* succeeded without errors */ }
/* * processSQLNamePattern * * Scan a wildcard-pattern string and generate appropriate WHERE clauses * to limit the set of objects returned. The WHERE clauses are appended * to the already-partially-constructed query in buf. Returns whether * any clause was added. * * conn: connection query will be sent to (consulted for escaping rules). * buf: output parameter. * pattern: user-specified pattern option, or NULL if none ("*" is implied). * have_where: true if caller already emitted "WHERE" (clauses will be ANDed * onto the existing WHERE clause). * force_escape: always quote regexp special characters, even outside * double quotes (else they are quoted only between double quotes). * schemavar: name of query variable to match against a schema-name pattern. * Can be NULL if no schema. * namevar: name of query variable to match against an object-name pattern. * altnamevar: NULL, or name of an alternative variable to match against name. * visibilityrule: clause to use if we want to restrict to visible objects * (for example, "pg_catalog.pg_table_is_visible(p.oid)"). Can be NULL. * * Formatting note: the text already present in buf should end with a newline. * The appended text, if any, will end with one too. */ bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule) { PQExpBufferData schemabuf; PQExpBufferData namebuf; int encoding = PQclientEncoding(conn); bool inquotes; const char *cp; int i; bool added_clause = false; #define WHEREAND() \ (appendPQExpBufferStr(buf, have_where ? " AND " : "WHERE "), \ have_where = true, added_clause = true) if (pattern == NULL) { /* Default: select all visible objects */ if (visibilityrule) { WHEREAND(); appendPQExpBuffer(buf, "%s\n", visibilityrule); } return added_clause; } initPQExpBuffer(&schemabuf); initPQExpBuffer(&namebuf); /* * Parse the pattern, converting quotes and lower-casing unquoted letters. * Also, adjust shell-style wildcard characters into regexp notation. * * We surround the pattern with "^(...)$" to force it to match the whole * string, as per SQL practice. We have to have parens in case the string * contains "|", else the "^" and "$" will be bound into the first and * last alternatives which is not what we want. * * Note: the result of this pass is the actual regexp pattern(s) we want * to execute. Quoting/escaping into SQL literal format will be done * below using appendStringLiteralConn(). */ appendPQExpBufferStr(&namebuf, "^("); inquotes = false; cp = pattern; while (*cp) { char ch = *cp; if (ch == '"') { if (inquotes && cp[1] == '"') { /* emit one quote, stay in inquotes mode */ appendPQExpBufferChar(&namebuf, '"'); cp++; } else inquotes = !inquotes; cp++; } else if (!inquotes && isupper((unsigned char) ch)) { appendPQExpBufferChar(&namebuf, pg_tolower((unsigned char) ch)); cp++; } else if (!inquotes && ch == '*') { appendPQExpBufferStr(&namebuf, ".*"); cp++; } else if (!inquotes && ch == '?') { appendPQExpBufferChar(&namebuf, '.'); cp++; } else if (!inquotes && ch == '.') { /* Found schema/name separator, move current pattern to schema */ resetPQExpBuffer(&schemabuf); appendPQExpBufferStr(&schemabuf, namebuf.data); resetPQExpBuffer(&namebuf); appendPQExpBufferStr(&namebuf, "^("); cp++; } else if (ch == '$') { /* * Dollar is always quoted, whether inside quotes or not. The * reason is that it's allowed in SQL identifiers, so there's a * significant use-case for treating it literally, while because * we anchor the pattern automatically there is no use-case for * having it possess its regexp meaning. */ appendPQExpBufferStr(&namebuf, "\\$"); cp++; } else { /* * Ordinary data character, transfer to pattern * * Inside double quotes, or at all times if force_escape is true, * quote regexp special characters with a backslash to avoid * regexp errors. Outside quotes, however, let them pass through * as-is; this lets knowledgeable users build regexp expressions * that are more powerful than shell-style patterns. */ if ((inquotes || force_escape) && strchr("|*+?()[]{}.^$\\", ch)) appendPQExpBufferChar(&namebuf, '\\'); i = PQmblen(cp, encoding); while (i-- && *cp) { appendPQExpBufferChar(&namebuf, *cp); cp++; } } } /* * Now decide what we need to emit. Note there will be a leading "^(" in * the patterns in any case. */ if (namebuf.len > 2) { /* We have a name pattern, so constrain the namevar(s) */ appendPQExpBufferStr(&namebuf, ")$"); /* Optimize away a "*" pattern */ if (strcmp(namebuf.data, "^(.*)$") != 0) { WHEREAND(); if (altnamevar) { appendPQExpBuffer(buf, "(%s ~ ", namevar); appendStringLiteralConn(buf, namebuf.data, conn); appendPQExpBuffer(buf, "\n OR %s ~ ", altnamevar); appendStringLiteralConn(buf, namebuf.data, conn); appendPQExpBufferStr(buf, ")\n"); } else { appendPQExpBuffer(buf, "%s ~ ", namevar); appendStringLiteralConn(buf, namebuf.data, conn); appendPQExpBufferChar(buf, '\n'); } } } if (schemabuf.len > 2) { /* We have a schema pattern, so constrain the schemavar */ appendPQExpBufferStr(&schemabuf, ")$"); /* Optimize away a "*" pattern */ if (strcmp(schemabuf.data, "^(.*)$") != 0 && schemavar) { WHEREAND(); appendPQExpBuffer(buf, "%s ~ ", schemavar); appendStringLiteralConn(buf, schemabuf.data, conn); appendPQExpBufferChar(buf, '\n'); } } else { /* No schema pattern given, so select only visible objects */ if (visibilityrule) { WHEREAND(); appendPQExpBuffer(buf, "%s\n", visibilityrule); } } termPQExpBuffer(&schemabuf); termPQExpBuffer(&namebuf); return added_clause; #undef WHEREAND }
int main(int argc, char *argv[]) { char *pghost = NULL; char *pgport = NULL; char *pguser = NULL; bool force_password = false; bool data_only = false; bool globals_only = false; bool schema_only = false; PGconn *conn; int encoding; const char *std_strings; int c, ret; static struct option long_options[] = { {"data-only", no_argument, NULL, 'a'}, {"clean", no_argument, NULL, 'c'}, {"inserts", no_argument, NULL, 'd'}, {"attribute-inserts", no_argument, NULL, 'D'}, {"column-inserts", no_argument, NULL, 'D'}, {"globals-only", no_argument, NULL, 'g'}, {"host", required_argument, NULL, 'h'}, {"ignore-version", no_argument, NULL, 'i'}, {"oids", no_argument, NULL, 'o'}, {"no-owner", no_argument, NULL, 'O'}, {"port", required_argument, NULL, 'p'}, {"password", no_argument, NULL, 'W'}, {"schema-only", no_argument, NULL, 's'}, {"superuser", required_argument, NULL, 'S'}, {"username", required_argument, NULL, 'U'}, {"verbose", no_argument, NULL, 'v'}, {"no-privileges", no_argument, NULL, 'x'}, {"no-acl", no_argument, NULL, 'x'}, /* * the following options don't have an equivalent short option letter */ {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1}, {"disable-triggers", no_argument, &disable_triggers, 1}, {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, {NULL, 0, NULL, 0} }; int optindex; set_pglocale_pgservice(argv[0], "pg_dump"); progname = get_progname(argv[0]); if (argc > 1) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { help(); exit(0); } if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) { puts("pg_dumpall (PostgreSQL) " PG_VERSION); exit(0); } } if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR, pg_dump_bin)) < 0) { char full_path[MAXPGPATH]; if (find_my_exec(argv[0], full_path) < 0) StrNCpy(full_path, progname, MAXPGPATH); if (ret == -1) fprintf(stderr, _("The program \"pg_dump\" is needed by %s " "but was not found in the\n" "same directory as \"%s\".\n" "Check your installation.\n"), progname, full_path); else fprintf(stderr, _("The program \"pg_dump\" was found by \"%s\"\n" "but was not the same version as %s.\n" "Check your installation.\n"), full_path, progname); exit(1); } pgdumpopts = createPQExpBuffer(); while ((c = getopt_long(argc, argv, "acdDgh:ioOp:sS:U:vWxX:", long_options, &optindex)) != -1) { switch (c) { case 'a': data_only = true; appendPQExpBuffer(pgdumpopts, " -a"); break; case 'c': output_clean = true; break; case 'd': case 'D': appendPQExpBuffer(pgdumpopts, " -%c", c); break; case 'g': globals_only = true; break; case 'h': pghost = optarg; #ifndef WIN32 appendPQExpBuffer(pgdumpopts, " -h '%s'", pghost); #else appendPQExpBuffer(pgdumpopts, " -h \"%s\"", pghost); #endif break; case 'i': ignoreVersion = true; appendPQExpBuffer(pgdumpopts, " -i"); break; case 'o': appendPQExpBuffer(pgdumpopts, " -o"); break; case 'O': appendPQExpBuffer(pgdumpopts, " -O"); break; case 'p': pgport = optarg; #ifndef WIN32 appendPQExpBuffer(pgdumpopts, " -p '%s'", pgport); #else appendPQExpBuffer(pgdumpopts, " -p \"%s\"", pgport); #endif break; case 's': schema_only = true; appendPQExpBuffer(pgdumpopts, " -s"); break; case 'S': #ifndef WIN32 appendPQExpBuffer(pgdumpopts, " -S '%s'", optarg); #else appendPQExpBuffer(pgdumpopts, " -S \"%s\"", optarg); #endif break; case 'U': pguser = optarg; #ifndef WIN32 appendPQExpBuffer(pgdumpopts, " -U '%s'", pguser); #else appendPQExpBuffer(pgdumpopts, " -U \"%s\"", pguser); #endif break; case 'v': verbose = true; appendPQExpBuffer(pgdumpopts, " -v"); break; case 'W': force_password = true; appendPQExpBuffer(pgdumpopts, " -W"); break; case 'x': skip_acls = true; appendPQExpBuffer(pgdumpopts, " -x"); break; case 'X': /* -X is a deprecated alternative to long options */ if (strcmp(optarg, "disable-dollar-quoting") == 0) appendPQExpBuffer(pgdumpopts, " --disable-dollar-quoting"); else if (strcmp(optarg, "disable-triggers") == 0) appendPQExpBuffer(pgdumpopts, " --disable-triggers"); else if (strcmp(optarg, "use-set-session-authorization") == 0) /* no-op, still allowed for compatibility */ ; 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: break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } /* Add long options to the pg_dump argument list */ if (disable_dollar_quoting) appendPQExpBuffer(pgdumpopts, " --disable-dollar-quoting"); if (disable_triggers) appendPQExpBuffer(pgdumpopts, " --disable-triggers"); if (use_setsessauth) appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization"); if (optind < argc) { fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } /* * First try to connect to database "postgres", and failing that * "template1". "postgres" is the preferred choice for 8.1 and later * servers, but it usually will not exist on older ones. */ conn = connectDatabase("postgres", pghost, pgport, pguser, force_password, false); if (!conn) conn = connectDatabase("template1", pghost, pgport, pguser, force_password, true); /* * Get the active encoding and the standard_conforming_strings setting, so * we know how to escape strings. */ encoding = PQclientEncoding(conn); std_strings = PQparameterStatus(conn, "standard_conforming_strings"); if (!std_strings) std_strings = "off"; printf("--\n-- PostgreSQL database cluster dump\n--\n\n"); if (verbose) dumpTimestamp("Started on"); printf("\\connect postgres\n\n"); if (!data_only) { /* Replicate encoding and std_strings in output */ printf("SET client_encoding = '%s';\n", pg_encoding_to_char(encoding)); printf("SET standard_conforming_strings = %s;\n", std_strings); if (strcmp(std_strings, "off") == 0) printf("SET escape_string_warning = 'off';\n"); printf("\n"); /* Dump roles (users) */ dumpRoles(conn); /* Dump role memberships --- need different method for pre-8.1 */ if (server_version >= 80100) dumpRoleMembership(conn); else dumpGroups(conn); /* Dump tablespaces */ if (server_version >= 80000) dumpTablespaces(conn); /* Dump CREATE DATABASE commands */ if (!globals_only) dumpCreateDB(conn); } if (!globals_only) dumpDatabases(conn); PQfinish(conn); if (verbose) dumpTimestamp("Completed on"); printf("--\n-- PostgreSQL database cluster dump complete\n--\n\n"); exit(0); }